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;
}