From 55b24be11585737911fc990c7bc2e46ebae13bc6 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Mon, 31 Jul 2017 17:45:05 +0300 Subject: [PATCH] heatmap: refactor, directive for color legend --- .../app/plugins/panel/heatmap/color_legend.ts | 136 ++++++++++++++++++ .../plugins/panel/heatmap/display_editor.ts | 6 + public/app/plugins/panel/heatmap/module.ts | 2 +- .../heatmap/partials/display_editor.html | 10 +- public/app/plugins/panel/heatmap/rendering.ts | 67 --------- 5 files changed, 147 insertions(+), 74 deletions(-) create mode 100644 public/app/plugins/panel/heatmap/color_legend.ts diff --git a/public/app/plugins/panel/heatmap/color_legend.ts b/public/app/plugins/panel/heatmap/color_legend.ts new file mode 100644 index 00000000000..572d26c7330 --- /dev/null +++ b/public/app/plugins/panel/heatmap/color_legend.ts @@ -0,0 +1,136 @@ +/// +import angular from 'angular'; +import _ from 'lodash'; +import $ from 'jquery'; +import d3 from 'd3'; +import {contextSrv} from 'app/core/core'; + +let module = angular.module('grafana.directives'); +module.directive('colorLegend', function() { + return { + restrict: 'E', + template: '
', + link: function(scope, elem, attrs) { + let ctrl = scope.ctrl; + let panel = scope.ctrl.panel; + + render(); + + ctrl.events.on('render', function() { + render(); + }); + + function render() { + let legendElem = $(elem).find('svg'); + let legendWidth = Math.floor(legendElem.outerWidth()); + + if (panel.color.mode === 'spectrum') { + let colorScheme = _.find(ctrl.colorSchemes, {value: panel.color.colorScheme}); + let colorScale = getColorScale(colorScheme, legendWidth); + drawColorLegend(elem, colorScale); + } else if (panel.color.mode === 'opacity') { + let colorOptions = panel.color; + drawOpacityLegend(elem, colorOptions); + } + } + } + }; +}); + +module.directive('heatmapLegend', function() { + return { + restrict: 'E', + template: '
', + link: function(scope, elem, attrs) { + let ctrl = scope.ctrl; + let panel = scope.ctrl.panel; + + ctrl.events.on('render', function() { + if (!_.isEmpty(ctrl.data)) { + let legendElem = $(elem).find('svg'); + let legendWidth = Math.floor(legendElem.outerWidth()); + + if (panel.color.mode === 'spectrum') { + let colorScheme = _.find(ctrl.colorSchemes, {value: panel.color.colorScheme}); + let colorScale = getColorScale(colorScheme, legendWidth); + drawColorLegend(elem, colorScale); + } else if (panel.color.mode === 'opacity') { + let colorOptions = panel.color; + drawOpacityLegend(elem, colorOptions); + } + } + }); + } + }; +}); + +function drawColorLegend(elem, colorScale) { + let legendElem = $(elem).find('svg'); + legendElem.find("rect").remove(); + + let legendWidth = Math.floor(legendElem.outerWidth()); + let legendHeight = legendElem.attr("height"); + + let rangeStep = 2; + let valuesRange = d3.range(0, legendWidth, rangeStep); + + let legend = d3.select(legendElem.get(0)); + var legendRects = legend.selectAll(".heatmap-color-legend-rect").data(valuesRange); + + legendRects.enter().append("rect") + .attr("x", d => d) + .attr("y", 0) + .attr("width", rangeStep + 1) // Overlap rectangles to prevent gaps + .attr("height", legendHeight) + .attr("stroke-width", 0) + .attr("fill", d => colorScale(d)); +} + +function clearLegend(elem) { + let legendElem = $(elem).find('svg'); + legendElem.find("rect").remove(); +} + +function drawOpacityLegend(elem, options) { + let legendElem = $(elem).find('svg'); + clearLegend(elem); + + let legend = d3.select(legendElem.get(0)); + let legendWidth = Math.floor(legendElem.outerWidth()); + let legendHeight = legendElem.attr("height"); + + let legendOpacityScale; + if (options.colorScale === 'linear') { + legendOpacityScale = d3.scaleLinear() + .domain([0, legendWidth]) + .range([0, 1]); + } else if (options.colorScale === 'sqrt') { + legendOpacityScale = d3.scalePow().exponent(options.exponent) + .domain([0, legendWidth]) + .range([0, 1]); + } + + let rangeStep = 1; + let valuesRange = d3.range(0, legendWidth, rangeStep); + var legendRects = legend.selectAll(".heatmap-opacity-legend-rect").data(valuesRange); + + legendRects.enter().append("rect") + .attr("x", d => d) + .attr("y", 0) + .attr("width", rangeStep) + .attr("height", legendHeight) + .attr("stroke-width", 0) + .attr("fill", options.cardColor) + .style("opacity", d => legendOpacityScale(d)); +} + +function getColorScale(colorScheme, maxValue, minValue = 0) { + let colorInterpolator = d3[colorScheme.value]; + let colorScaleInverted = colorScheme.invert === 'always' || + (colorScheme.invert === 'dark' && !contextSrv.user.lightTheme); + + let start = colorScaleInverted ? maxValue : minValue; + let end = colorScaleInverted ? minValue : maxValue; + + return d3.scaleSequential(colorInterpolator).domain([start, end]); +} diff --git a/public/app/plugins/panel/heatmap/display_editor.ts b/public/app/plugins/panel/heatmap/display_editor.ts index 775017b00da..1cea9505567 100644 --- a/public/app/plugins/panel/heatmap/display_editor.ts +++ b/public/app/plugins/panel/heatmap/display_editor.ts @@ -1,4 +1,10 @@ /// +import _ from 'lodash'; +import $ from 'jquery'; +import d3 from 'd3'; +import {contextSrv} from 'app/core/core'; + +const COLOR_LEGEND_SELECTOR = '.heatmap-color-legend'; export class HeatmapDisplayEditorCtrl { panel: any; diff --git a/public/app/plugins/panel/heatmap/module.ts b/public/app/plugins/panel/heatmap/module.ts index d6926455563..d5ef7291308 100644 --- a/public/app/plugins/panel/heatmap/module.ts +++ b/public/app/plugins/panel/heatmap/module.ts @@ -1,5 +1,5 @@ /// - +import './color_legend'; import {HeatmapCtrl} from './heatmap_ctrl'; export { diff --git a/public/app/plugins/panel/heatmap/partials/display_editor.html b/public/app/plugins/panel/heatmap/partials/display_editor.html index 2c66b90b949..4f215f3fcce 100644 --- a/public/app/plugins/panel/heatmap/partials/display_editor.html +++ b/public/app/plugins/panel/heatmap/partials/display_editor.html @@ -25,9 +25,6 @@ -
- -
@@ -37,9 +34,10 @@
-
- -
+ + +
+
diff --git a/public/app/plugins/panel/heatmap/rendering.ts b/public/app/plugins/panel/heatmap/rendering.ts index c6f898fcb28..74b433653f1 100644 --- a/public/app/plugins/panel/heatmap/rendering.ts +++ b/public/app/plugins/panel/heatmap/rendering.ts @@ -706,78 +706,11 @@ export default function link(scope, elem, attrs, ctrl) { } } - function drawColorLegend() { - d3.select("#heatmap-color-legend").selectAll("rect").remove(); - - let legend = d3.select("#heatmap-color-legend"); - let legendWidth = Math.floor($(d3.select("#heatmap-color-legend").node()).outerWidth()); - let legendHeight = d3.select("#heatmap-color-legend").attr("height"); - - let legendColorScale = getColorScale(legendWidth); - - let rangeStep = 2; - let valuesRange = d3.range(0, legendWidth, rangeStep); - var legendRects = legend.selectAll(".heatmap-color-legend-rect").data(valuesRange); - - legendRects.enter().append("rect") - .attr("x", d => d) - .attr("y", 0) - .attr("width", rangeStep + 1) // Overlap rectangles to prevent gaps - .attr("height", legendHeight) - .attr("stroke-width", 0) - .attr("fill", d => { - return legendColorScale(d); - }); - } - - function drawOpacityLegend() { - d3.select("#heatmap-opacity-legend").selectAll("rect").remove(); - - let legend = d3.select("#heatmap-opacity-legend"); - let legendWidth = Math.floor($(d3.select("#heatmap-opacity-legend").node()).outerWidth()); - let legendHeight = d3.select("#heatmap-opacity-legend").attr("height"); - - let legendOpacityScale; - if (panel.color.colorScale === 'linear') { - legendOpacityScale = d3.scaleLinear() - .domain([0, legendWidth]) - .range([0, 1]); - } else if (panel.color.colorScale === 'sqrt') { - legendOpacityScale = d3.scalePow().exponent(panel.color.exponent) - .domain([0, legendWidth]) - .range([0, 1]); - } - - let rangeStep = 1; - let valuesRange = d3.range(0, legendWidth, rangeStep); - var legendRects = legend.selectAll(".heatmap-opacity-legend-rect").data(valuesRange); - - legendRects.enter().append("rect") - .attr("x", d => d) - .attr("y", 0) - .attr("width", rangeStep) - .attr("height", legendHeight) - .attr("stroke-width", 0) - .attr("fill", panel.color.cardColor) - .style("opacity", d => { - return legendOpacityScale(d); - }); - } - function render() { data = ctrl.data; panel = ctrl.panel; timeRange = ctrl.range; - // Draw only if color editor is opened - if (!d3.select("#heatmap-color-legend").empty()) { - drawColorLegend(); - } - - if (!d3.select("#heatmap-opacity-legend").empty()) { - drawOpacityLegend(); - } - if (!setElementHeight() || !data) { return; }