Milimetric has submitted this change and it was merged. (
https://gerrit.wikimedia.org/r/348227 )
Change subject: Improve annotations
......................................................................
Improve annotations
This patch:
- Adds parsing and display of annotations to tabs layout
- Gives annotations a new (hopefully not ugly) look
- Gives annot. distinct letters (A, B, C... instead of A, A, A...)
- Fixes bug: Annotations being snapped to same date would not show
Bug: T162482
Change-Id: I5d0c9cab72aa713c7f0e6cd7b1f1d832c7aca5b8
---
M src/app/apis/aqs-api.js
M src/components/layouts/tabs/tabs.js
M src/components/visualizers/dygraphs-timeseries/bindings.js
M src/components/visualizers/dygraphs-timeseries/dygraphs-timeseries.html
M src/components/visualizers/visualizer/visualizer.js
5 files changed, 112 insertions(+), 27 deletions(-)
Approvals:
Milimetric: Verified; Looks good to me, approved
diff --git a/src/app/apis/aqs-api.js b/src/app/apis/aqs-api.js
index 8f339d2..280dbf9 100644
--- a/src/app/apis/aqs-api.js
+++ b/src/app/apis/aqs-api.js
@@ -92,7 +92,7 @@
// Datasets are disjoint but we need to add them so that
// the timeseries object makes sense.
- var ts = TimeseriesData.mergeAll(timeseries)
+ var ts = TimeseriesData.mergeAll(timeseries);
deferred.resolve(ts);
}, function (reason) {
diff --git a/src/components/layouts/tabs/tabs.js
b/src/components/layouts/tabs/tabs.js
index 6866983..3f0edc8 100644
--- a/src/components/layouts/tabs/tabs.js
+++ b/src/components/layouts/tabs/tabs.js
@@ -7,7 +7,8 @@
var ko = require('knockout'),
_ = require('lodash'),
templateMarkup = require('text!./tabs.html'),
- configApi = require('apis.config');
+ configApi = require('apis.config'),
+ annotationsApi = require('apis.annotations');
require('twix');
@@ -64,6 +65,15 @@
g.type === 'stacked-bars' ? 'bar' :
g.type === 'dygraphs-timeseries' ? 'line' :
g.type === 'table-timeseries' ? 'table' : '';
+
+ // Fetch annotations if present
+ var annotationsInfo = g.annotations;
+ g.annotations = ko.observable();
+ if (annotationsInfo) {
+ annotationsApi.getTimeseriesData(
+ {annotations: annotationsInfo}
+ ).then(g.annotations);
+ }
});
}, this);
diff --git a/src/components/visualizers/dygraphs-timeseries/bindings.js
b/src/components/visualizers/dygraphs-timeseries/bindings.js
index 78d5692..38322a4 100644
--- a/src/components/visualizers/dygraphs-timeseries/bindings.js
+++ b/src/components/visualizers/dygraphs-timeseries/bindings.js
@@ -2,7 +2,8 @@
define(function (require) {
var ko = require('knockout'),
- moment = require('moment');
+ moment = require('moment'),
+ _ = require("lodash");
require('dygraphs');
require('./dygraphs.patch');
@@ -73,44 +74,77 @@
if (annotations) {
dygraphChart.ready(function () {
- var i = 0,
- $roller = $(dygraphChart.roller_),
- $rollerHolder = $('<span
class="dygraph-roller">Averaging: </span>');
+ var $roller = $(dygraphChart.roller_),
+ $rollerHolder = $('<span
class="dygraph-roller">Averaging: </span>'),
+ charCode = 65,
+ snapIndex = -1;
-
dygraphChart.setAnnotations(annotations.rowData().map(function (a) {
- // find the closest date in the data that fits
- var closestDate = null;
- var lastDistance = Math.pow(2, 53) - 1;
- for (; i < rows.length; i++) {
- var date = rows[i][0];
- var thisDistance = Math.min(lastDistance,
Math.abs(date.getTime() - a[0]));
- // both arrays are sorted so the distance will
only get further now
- if (thisDistance === lastDistance) {
- i--;
- break;
- }
- lastDistance = thisDistance;
- closestDate = rows[i][0];
- // if we're at the end, and no date matched,
prefix annotation with date
- // Also, handle other future dates the same
by decrementing i
- if (i === rows.length - 1) {
- a[1] =
moment(a[0]).utc().format('YYYY-MM-DD ') + a[1];
- i--;
+ // Snap annotation dates to the closest data point
+ var snappedAnnotations =
annotations.rowData().map(function (a) {
+
+ // Efficiently iterate data points to find closest
one
+ for (var i = snapIndex + 1; i < rows.length; i++) {
+ if (a[0] >= rows[i][0].getTime()) {
+ snapIndex = i;
+ } else {
break;
}
}
+
+ // Format annotation
+ var snappedDate, message;
+ if (snapIndex === -1) {
+ // The annotation is set before the first data
point.
+ // Attach it to the first data point, prefixed
with its date.
+ snappedDate = rows[0][0].getTime();
+ message =
moment(a[0]).utc().format('YYYY-MM-DD ') + a[1];
+ } else if (snapIndex === rows.length - 1) {
+ // The annotation is set after the last data
point.
+ // Attach it to the last data point, prefixed
with its date.
+ snappedDate = rows[rows.length -
1][0].getTime();
+ message =
moment(a[0]).utc().format('YYYY-MM-DD ') + a[1];
+ } else {
+ // The annotation is set in between two data
points.
+ // Attach it to the earlier data point, no
prefix.
+ snappedDate = rows[snapIndex][0].getTime();
+ message = a[1];
+ }
+
+ return [snappedDate, message];
+ });
+
+ // Merge annotations that got snapped to the same date
+ var mergedAnnotations = _
+ .chain(snappedAnnotations)
+ .groupBy(function (a) { return a[0]; })
+ .toPairs()
+ .sortBy(function (g) { return g[0]; })
+ .map(function (g) {
+ return [
+ g[0],
+ g[1].map(function (a) {
+ return a[1];
+ }).join("\n\n")
+ ];
+ })
+ .value();
+
+ // Format annotations for dygraphs to parse
+
dygraphChart.setAnnotations(mergedAnnotations.map(function (a) {
return {
// just attach to the first series and show on
X axis
series: options.labels[1],
attachAtBottom: true,
- shortText: 'A',
+ tickHeight: 0,
+ shortText: String.fromCharCode(charCode++),
// annoying thing to learn through
experimentation:
// Dygraphs requires Date instances for the
data, but
// Dygraphs requires milliseconds since
epoch for the annotations
- x: closestDate.getTime(),
+ x: a[0],
text: a[1],
};
}));
+
// move the roller to the top and add a label
$rollerHolder.append($roller.detach()).append('
day(s)');
// remove the previous roller if any
diff --git
a/src/components/visualizers/dygraphs-timeseries/dygraphs-timeseries.html
b/src/components/visualizers/dygraphs-timeseries/dygraphs-timeseries.html
index 0252c03..f445727 100644
--- a/src/components/visualizers/dygraphs-timeseries/dygraphs-timeseries.html
+++ b/src/components/visualizers/dygraphs-timeseries/dygraphs-timeseries.html
@@ -8,6 +8,8 @@
margin-left: -120px;
pointer-events: none;
width: auto!important;
+ z-index: 15!important;
+ top: 1.5em!important;
}
div.dygraph-legend > span {
@@ -30,6 +32,44 @@
min-width: 300px;
background-color: white;
}
+ /* Patches appearance of annotations */
+ .dygraphDefaultAnnotation {
+ top: 0!important;
+ height: calc(100% - 1.6em)!important;
+ border: none!important;
+ border-left: 0.05em dashed!important;
+ background-color: transparent!important;
+ margin-left: 0.53em!important;
+ padding-left: 0.15em!important;
+ overflow: visible!important;
+ user-select: none;
+ width: 18px!important;
+ text-align: left;
+ }
+ .graph:hover .dygraphDefaultAnnotation {
+ opacity: 0.5;
+ }
+ .graph:hover .dygraphDefaultAnnotation:hover {
+ opacity: 1;
+ font-weight: bold;
+ }
+ .dygraphDefaultAnnotation:hover::before {
+ content: " ";
+ position: absolute;
+ padding: 1px;
+ top: 0px;
+ left: -1px;
+ border: 1px solid;
+ width: 18px;
+ height: 18px;
+ }
+ /* Presence of annotations messes with the averaging days control */
+ .dygraph-roller input {
+ position: relative!important;
+ left: auto!important;
+ top: auto!important;
+ display: inline!important;
+ }
</style>
<div class="columnar flexer flexed" data-bind="
diff --git a/src/components/visualizers/visualizer/visualizer.js
b/src/components/visualizers/visualizer/visualizer.js
index 19002a9..e28204b 100644
--- a/src/components/visualizers/visualizer/visualizer.js
+++ b/src/components/visualizers/visualizer/visualizer.js
@@ -141,6 +141,7 @@
format: numberUtils.numberFormatter(graph.format),
height: 500,
id: _.kebabCase([graph.metric, graph.submetric].join('-')),
+ annotations: graph.annotations,
};
this.params.downloadLink = graph.downloadLink;
this.legendHeight = this.params.height - 80 + 'px';
--
To view, visit https://gerrit.wikimedia.org/r/348227
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I5d0c9cab72aa713c7f0e6cd7b1f1d832c7aca5b8
Gerrit-PatchSet: 4
Gerrit-Project: analytics/dashiki
Gerrit-Branch: master
Gerrit-Owner: Mforns <[email protected]>
Gerrit-Reviewer: Mforns <[email protected]>
Gerrit-Reviewer: Milimetric <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits