From 7bc210f8c990c280c9df01e2ecffbe9c7d8a5b1c Mon Sep 17 00:00:00 2001 From: Evelyn Turner Date: Thu, 1 Mar 2018 13:57:16 -0500 Subject: [PATCH 1/4] Fix how the annotation layer interpretes the timestamp string without timezone info; use it as UTC --- superset/assets/visualizations/nvd3_vis.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/superset/assets/visualizations/nvd3_vis.js b/superset/assets/visualizations/nvd3_vis.js index b60c32a0e57c0..1b1ba8decc1a7 100644 --- a/superset/assets/visualizations/nvd3_vis.js +++ b/superset/assets/visualizations/nvd3_vis.js @@ -4,6 +4,7 @@ import throttle from 'lodash.throttle'; import d3 from 'd3'; import nv from 'nvd3'; import mathjs from 'mathjs'; +import moment from 'moment'; import d3tip from 'd3-tip'; import { getColorFromScheme } from '../javascripts/modules/colors'; @@ -624,7 +625,7 @@ function nvd3Vis(slice, payload) { const tip = tipFactory(e); const records = (slice.annotationData[e.name].records || []).map((r) => { - const timeColumn = new Date(r[e.timeColumn]); + const timeColumn = new Date(moment.utc(r[e.timeColumn])); return { ...r, [e.timeColumn]: timeColumn, From 3a2bacf634f0cec0ec8aae361b3da7235ddda0b3 Mon Sep 17 00:00:00 2001 From: Evelyn Turner Date: Fri, 16 Mar 2018 16:15:03 -0400 Subject: [PATCH 2/4] [Bug fix] Fixed/Refactored annotation layer code so that non-timeseries annotations are applied based on the updated chart object after adding all data --- superset/assets/visualizations/nvd3_vis.js | 53 ++++++++++------------ 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/superset/assets/visualizations/nvd3_vis.js b/superset/assets/visualizations/nvd3_vis.js index 7cfb1c332076c..d16856f141e43 100644 --- a/superset/assets/visualizations/nvd3_vis.js +++ b/superset/assets/visualizations/nvd3_vis.js @@ -533,6 +533,28 @@ function nvd3Vis(slice, payload) { chart.yAxis.axisLabel(fd.y_axis_label).axisLabelDistance(distance); } + const annotationLayers = (slice.formData.annotation_layers || []).filter(x => x.show); + if (isTimeSeries && annotationLayers && slice.annotationData) { + // Time series annotations add additional data + const timeSeriesAnnotations = annotationLayers + .filter(a => a.annotationType === AnnotationTypes.TIME_SERIES).reduce((bushel, a) => + bushel.concat((slice.annotationData[a.name] || []).map((series) => { + if (!series) { + return {}; + } + const key = Array.isArray(series.key) ? + `${a.name}, ${series.key.join(', ')}` : a.name; + return { + ...series, + key, + color: a.color, + strokeWidth: a.width, + classed: `${a.opacity} ${a.style}`, + }; + })), []); + data.push(...timeSeriesAnnotations); + } + // render chart svg .datum(data) @@ -544,8 +566,7 @@ function nvd3Vis(slice, payload) { // on scroll, hide tooltips. throttle to only 4x/second. $(window).scroll(throttle(hideTooltips, 250)); - const annotationLayers = (slice.formData.annotation_layers || []).filter(x => x.show); - + // The below code should be run AFTER rendering because chart is updated in call() if (isTimeSeries && annotationLayers) { // Formula annotations const formulas = annotationLayers.filter(a => a.annotationType === AnnotationTypes.FORMULA) @@ -620,7 +641,7 @@ function nvd3Vis(slice, payload) { '
' + body.join(', ') + '
'; }); - if (slice.annotationData && Object.keys(slice.annotationData).length) { + if (slice.annotationData) { // Event annotations annotationLayers.filter(x => ( x.annotationType === AnnotationTypes.EVENT && @@ -674,7 +695,6 @@ function nvd3Vis(slice, payload) { } }); - // Interval annotations annotationLayers.filter(x => ( x.annotationType === AnnotationTypes.INTERVAL && @@ -737,33 +757,8 @@ function nvd3Vis(slice, payload) { .call(tip); } }); - - // Time series annotations - const timeSeriesAnnotations = annotationLayers - .filter(a => a.annotationType === AnnotationTypes.TIME_SERIES).reduce((bushel, a) => - bushel.concat((slice.annotationData[a.name] || []).map((series) => { - if (!series) { - return {}; - } - const key = Array.isArray(series.key) ? - `${a.name}, ${series.key.join(', ')}` : a.name; - return { - ...series, - key, - color: a.color, - strokeWidth: a.width, - classed: `${a.opacity} ${a.style}`, - }; - })), []); - data.push(...timeSeriesAnnotations); } } - - // rerender chart - svg.datum(data) - .attr('height', height) - .attr('width', width) - .call(chart); } return chart; }; From 5aae60e36366a36007375de9d03ab4055b6d90df Mon Sep 17 00:00:00 2001 From: Evelyn Turner Date: Fri, 16 Mar 2018 16:15:03 -0400 Subject: [PATCH 3/4] [Bug fix] Fixed/Refactored annotation layer code so that non-timeseries annotations are applied based on the updated chart object after adding all data --- superset/assets/visualizations/nvd3_vis.js | 53 ++++++++++------------ 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/superset/assets/visualizations/nvd3_vis.js b/superset/assets/visualizations/nvd3_vis.js index 7cfb1c332076c..d16856f141e43 100644 --- a/superset/assets/visualizations/nvd3_vis.js +++ b/superset/assets/visualizations/nvd3_vis.js @@ -533,6 +533,28 @@ function nvd3Vis(slice, payload) { chart.yAxis.axisLabel(fd.y_axis_label).axisLabelDistance(distance); } + const annotationLayers = (slice.formData.annotation_layers || []).filter(x => x.show); + if (isTimeSeries && annotationLayers && slice.annotationData) { + // Time series annotations add additional data + const timeSeriesAnnotations = annotationLayers + .filter(a => a.annotationType === AnnotationTypes.TIME_SERIES).reduce((bushel, a) => + bushel.concat((slice.annotationData[a.name] || []).map((series) => { + if (!series) { + return {}; + } + const key = Array.isArray(series.key) ? + `${a.name}, ${series.key.join(', ')}` : a.name; + return { + ...series, + key, + color: a.color, + strokeWidth: a.width, + classed: `${a.opacity} ${a.style}`, + }; + })), []); + data.push(...timeSeriesAnnotations); + } + // render chart svg .datum(data) @@ -544,8 +566,7 @@ function nvd3Vis(slice, payload) { // on scroll, hide tooltips. throttle to only 4x/second. $(window).scroll(throttle(hideTooltips, 250)); - const annotationLayers = (slice.formData.annotation_layers || []).filter(x => x.show); - + // The below code should be run AFTER rendering because chart is updated in call() if (isTimeSeries && annotationLayers) { // Formula annotations const formulas = annotationLayers.filter(a => a.annotationType === AnnotationTypes.FORMULA) @@ -620,7 +641,7 @@ function nvd3Vis(slice, payload) { '
' + body.join(', ') + '
'; }); - if (slice.annotationData && Object.keys(slice.annotationData).length) { + if (slice.annotationData) { // Event annotations annotationLayers.filter(x => ( x.annotationType === AnnotationTypes.EVENT && @@ -674,7 +695,6 @@ function nvd3Vis(slice, payload) { } }); - // Interval annotations annotationLayers.filter(x => ( x.annotationType === AnnotationTypes.INTERVAL && @@ -737,33 +757,8 @@ function nvd3Vis(slice, payload) { .call(tip); } }); - - // Time series annotations - const timeSeriesAnnotations = annotationLayers - .filter(a => a.annotationType === AnnotationTypes.TIME_SERIES).reduce((bushel, a) => - bushel.concat((slice.annotationData[a.name] || []).map((series) => { - if (!series) { - return {}; - } - const key = Array.isArray(series.key) ? - `${a.name}, ${series.key.join(', ')}` : a.name; - return { - ...series, - key, - color: a.color, - strokeWidth: a.width, - classed: `${a.opacity} ${a.style}`, - }; - })), []); - data.push(...timeSeriesAnnotations); } } - - // rerender chart - svg.datum(data) - .attr('height', height) - .attr('width', width) - .call(chart); } return chart; }; From f9134ec5332e96eb738c7428c33feb66fd6ab48d Mon Sep 17 00:00:00 2001 From: Evelyn Turner Date: Mon, 19 Mar 2018 15:21:46 -0400 Subject: [PATCH 4/4] Fixed indentation --- superset/assets/visualizations/nvd3_vis.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/superset/assets/visualizations/nvd3_vis.js b/superset/assets/visualizations/nvd3_vis.js index d16856f141e43..9ce02bd031d85 100644 --- a/superset/assets/visualizations/nvd3_vis.js +++ b/superset/assets/visualizations/nvd3_vis.js @@ -540,7 +540,7 @@ function nvd3Vis(slice, payload) { .filter(a => a.annotationType === AnnotationTypes.TIME_SERIES).reduce((bushel, a) => bushel.concat((slice.annotationData[a.name] || []).map((series) => { if (!series) { - return {}; + return {}; } const key = Array.isArray(series.key) ? `${a.name}, ${series.key.join(', ')}` : a.name;