Просмотр исходного кода

heatmap: refactor, directive for color legend

Alexander Zobnin 8 лет назад
Родитель
Сommit
55b24be115

+ 136 - 0
public/app/plugins/panel/heatmap/color_legend.ts

@@ -0,0 +1,136 @@
+///<reference path="../../../headers/common.d.ts" />
+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: '<div class="heatmap-color-legend"><svg width="19em" height="2em"></svg></div>',
+    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: '<div class="heatmap-color-legend"><svg width="19em" height="2em"></svg></div>',
+    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]);
+}

+ 6 - 0
public/app/plugins/panel/heatmap/display_editor.ts

@@ -1,4 +1,10 @@
 ///<reference path="../../../headers/common.d.ts" />
+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;

+ 1 - 1
public/app/plugins/panel/heatmap/module.ts

@@ -1,5 +1,5 @@
 ///<reference path="../../../headers/common.d.ts" />
-
+import './color_legend';
 import {HeatmapCtrl} from './heatmap_ctrl';
 
 export {

+ 4 - 6
public/app/plugins/panel/heatmap/partials/display_editor.html

@@ -25,9 +25,6 @@
         <label class="gf-form-label width-9">Exponent</label>
         <input type="number" class="gf-form-input width-8" placeholder="auto" data-placement="right" bs-tooltip="''" ng-model="ctrl.panel.color.exponent" ng-change="ctrl.refresh()" ng-model-onblur>
       </div>
-      <div class="gf-form">
-        <svg id="heatmap-opacity-legend" width="19em" height="2em"></svg>
-      </div>
     </div>
 
     <div ng-show="ctrl.panel.color.mode === 'spectrum'">
@@ -37,9 +34,10 @@
           <select class="input-small gf-form-input" ng-model="ctrl.panel.color.colorScheme" ng-options="s.value as s.name for s in ctrl.colorSchemes" ng-change="ctrl.render()"></select>
         </div>
       </div>
-      <div class="gf-form">
-        <svg id="heatmap-color-legend" width="19em" height="2em"></svg>
-      </div>
+    </div>
+
+    <div class="gf-form">
+      <color-legend></color-legend>
     </div>
   </div>
 

+ 0 - 67
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;
     }