mirror of
https://github.com/timberjoegithub/grafana-statusmap.git
synced 2026-07-22 15:53:09 +00:00
fix bucket color, tooltip status shadow, undefined color error.
This commit is contained in:
+7
-63
@@ -76,7 +76,7 @@ mod.directive('statusHeatmapLegend', function() {
|
|||||||
drawOpacityLegend(elem, colorOptions, rangeFrom, rangeTo, maxValue, minValue);
|
drawOpacityLegend(elem, colorOptions, rangeFrom, rangeTo, maxValue, minValue);
|
||||||
} else if (panel.color.mode === 'discrete') {
|
} else if (panel.color.mode === 'discrete') {
|
||||||
let colorOptions = panel.color;
|
let colorOptions = panel.color;
|
||||||
drawDiscreteColorLegend(elem, colorOptions, rangeFrom, rangeTo, maxValue, minValue);
|
drawDiscreteColorLegend(elem, colorOptions, ctrl.discreteHelper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,7 +150,7 @@ function drawOpacityLegend(elem, options, rangeFrom, rangeTo, maxValue, minValue
|
|||||||
drawLegendValues(elem, opacityScale, rangeFrom, rangeTo, maxValue, minValue, legendWidth);
|
drawLegendValues(elem, opacityScale, rangeFrom, rangeTo, maxValue, minValue, legendWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawDiscreteColorLegend(elem, colorOptions, rangeFrom, rangeTo, maxValue, minValue) {
|
function drawDiscreteColorLegend(elem, colorOptions, discreteHelper) {
|
||||||
let legendElem = $(elem).find('svg');
|
let legendElem = $(elem).find('svg');
|
||||||
let legend = d3.select(legendElem.get(0));
|
let legend = d3.select(legendElem.get(0));
|
||||||
clearLegend(elem);
|
clearLegend(elem);
|
||||||
@@ -185,19 +185,18 @@ function drawDiscreteColorLegend(elem, colorOptions, rangeFrom, rangeTo, maxValu
|
|||||||
|
|
||||||
let legendHeight = legendElem.attr("height");
|
let legendHeight = legendElem.attr("height");
|
||||||
|
|
||||||
let rangeStep = Math.floor(legendWidth / valuesNumber);
|
let itemWidth = Math.floor(legendWidth / valuesNumber);
|
||||||
let valuesRange = d3.range(0, legendWidth, rangeStep);
|
let valuesRange = d3.range(valuesNumber); // from 0 to valuesNumber-1
|
||||||
|
|
||||||
let colorScale = getDiscreteColorScale(colorOptions, legendWidth);
|
|
||||||
legend.selectAll(".status-heatmap-color-legend-rect")
|
legend.selectAll(".status-heatmap-color-legend-rect")
|
||||||
.data(valuesRange)
|
.data(valuesRange)
|
||||||
.enter().append("rect")
|
.enter().append("rect")
|
||||||
.attr("x", d => d)
|
.attr("x", d => d*itemWidth)
|
||||||
.attr("y", 0)
|
.attr("y", 0)
|
||||||
.attr("width", rangeStep + 1) // Overlap rectangles to prevent gaps
|
.attr("width", itemWidth + 1) // Overlap rectangles to prevent gaps
|
||||||
.attr("height", legendHeight)
|
.attr("height", legendHeight)
|
||||||
.attr("stroke-width", 0)
|
.attr("stroke-width", 0)
|
||||||
.attr("fill", d => colorScale(d));
|
.attr("fill", d => discreteHelper.getDiscreteColor(d));
|
||||||
|
|
||||||
drawDiscreteLegendValues(elem, colorOptions, legendWidth);
|
drawDiscreteLegendValues(elem, colorOptions, legendWidth);
|
||||||
}
|
}
|
||||||
@@ -288,31 +287,6 @@ function drawDiscreteLegendValues(elem, colorOptions, legendWidth) {
|
|||||||
legend.select(".axis").select(".domain").remove();
|
legend.select(".axis").select(".domain").remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawSimpleColorLegend(elem, colorScale) {
|
|
||||||
let legendElem = $(elem).find('svg');
|
|
||||||
clearLegend(elem);
|
|
||||||
|
|
||||||
let legendWidth = Math.floor(legendElem.outerWidth());
|
|
||||||
let legendHeight = legendElem.attr("height");
|
|
||||||
|
|
||||||
if (legendWidth) {
|
|
||||||
let valuesNumber = Math.floor(legendWidth / 2);
|
|
||||||
let rangeStep = Math.floor(legendWidth / valuesNumber);
|
|
||||||
let valuesRange = d3.range(0, legendWidth, rangeStep);
|
|
||||||
|
|
||||||
let legend = d3.select(legendElem.get(0));
|
|
||||||
var legendRects = legend.selectAll(".status-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 drawSimpleOpacityLegend(elem, options) {
|
function drawSimpleOpacityLegend(elem, options) {
|
||||||
let legendElem = $(elem).find('svg');
|
let legendElem = $(elem).find('svg');
|
||||||
let graphElem = $(elem);
|
let graphElem = $(elem);
|
||||||
@@ -366,36 +340,6 @@ function getColorScale(colorScheme, maxValue, minValue = 0) {
|
|||||||
return d3.scaleSequential(colorInterpolator).domain([start, end]);
|
return d3.scaleSequential(colorInterpolator).domain([start, end]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// scale input range to discrete colors to draw a legend
|
|
||||||
function getDiscreteColorScale(colorOptions, maxValue, minValue = 0) {
|
|
||||||
let start = minValue;
|
|
||||||
let end = maxValue;
|
|
||||||
|
|
||||||
let thresholdValues = [];
|
|
||||||
let thresholdColors = [];
|
|
||||||
for (let i = 0; i < colorOptions.thresholds.length; i++) {
|
|
||||||
thresholdColors.push(colorOptions.thresholds[i].color);
|
|
||||||
thresholdValues.push(colorOptions.thresholds[i].value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO sort colors by value and index?
|
|
||||||
|
|
||||||
let thresholdScaler = (d) => {
|
|
||||||
let color = thresholdColors[Math.floor(d)];
|
|
||||||
if (color != undefined) {
|
|
||||||
return color
|
|
||||||
}
|
|
||||||
return 'rgba(0,0,0,0)';
|
|
||||||
};
|
|
||||||
|
|
||||||
let inputRangeScaler = d3.scaleLinear().domain([start, end]).range([0, thresholdColors.length+1]);
|
|
||||||
|
|
||||||
// scale min-max to 0 - max-thrs-value
|
|
||||||
return function(d) {
|
|
||||||
return thresholdScaler(inputRangeScaler(d));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getOpacityScale(options, maxValue, minValue = 0) {
|
function getOpacityScale(options, maxValue, minValue = 0) {
|
||||||
let legendOpacityScale;
|
let legendOpacityScale;
|
||||||
if (options.colorScale === 'linear') {
|
if (options.colorScale === 'linear') {
|
||||||
|
|||||||
+47
-11
@@ -17,7 +17,7 @@ export class ColorModeDiscrete {
|
|||||||
for (let j = 0; j < values.length; j++) {
|
for (let j = 0; j < values.length; j++) {
|
||||||
if (values[j] == thresholds[i].value) {
|
if (values[j] == thresholds[i].value) {
|
||||||
tooltips.push({
|
tooltips.push({
|
||||||
"tooltip": thresholds[i].tooltip,
|
"tooltip": thresholds[i].tooltip?thresholds[i].tooltip:values[j],
|
||||||
"color": thresholds[i].color
|
"color": thresholds[i].color
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -37,25 +37,49 @@ export class ColorModeDiscrete {
|
|||||||
return notMatched;
|
return notMatched;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDiscreteColorScale() {
|
getNotColoredValues(values) {
|
||||||
return (d) => {
|
let notMatched = [];
|
||||||
let threshold = this.getMatchedThreshold(d);
|
for (let j = 0; j < values.length; j++) {
|
||||||
if (!threshold) {
|
let threshold = this.getMatchedThreshold(values[j]);
|
||||||
// Error if value not in thresholds
|
if (!threshold || !threshold.color || threshold.color == "") {
|
||||||
return 'rgba(0,0,0,1)';
|
notMatched.push(values[j]);
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
return threshold.color;
|
return notMatched;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getDiscreteColor(index) {
|
||||||
|
let color = this.getThreshold(index).color;
|
||||||
|
if (!color || color == "") {
|
||||||
|
return 'rgba(0,0,0,1)';
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns color from first matched thresold in order from 0 to thresholds.length
|
||||||
|
getBucketColor(values) {
|
||||||
|
let thresholds = this.panel.color.thresholds;
|
||||||
|
|
||||||
|
for (let i = 0; i < thresholds.length; i++) {
|
||||||
|
for (let j = 0; j < values.length; j++) {
|
||||||
|
if (values[j] == thresholds[i].value) {
|
||||||
|
return this.getDiscreteColor(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
return 'rgba(0,0,0,1)';
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCardsValuesHasColorInfo() {
|
updateCardsValuesHasColorInfo() {
|
||||||
|
this.panelCtrl.cardsData.noColorDefined = false;
|
||||||
let cards = this.panelCtrl.cardsData.cards;
|
let cards = this.panelCtrl.cardsData.cards;
|
||||||
for (let i=0; i<cards.length; i++) {
|
for (let i=0; i<cards.length; i++) {
|
||||||
|
cards[i].noColorDefined = false;
|
||||||
let values = cards[i].values;
|
let values = cards[i].values;
|
||||||
for (let j=0; j<values.length; j++) {
|
for (let j=0; j<values.length; j++) {
|
||||||
if (!this.getMatchedThreshold(values[j])) {
|
let threshold = this.getMatchedThreshold(values[j]);
|
||||||
|
if (!threshold || !threshold.color || threshold.color == "") {
|
||||||
cards[i].noColorDefined = true;
|
cards[i].noColorDefined = true;
|
||||||
this.panelCtrl.cardsData.noColorDefined = true;
|
this.panelCtrl.cardsData.noColorDefined = true;
|
||||||
break;
|
break;
|
||||||
@@ -88,6 +112,18 @@ export class ColorModeDiscrete {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getThreshold(index) {
|
||||||
|
let thresholds = this.panel.color.thresholds;
|
||||||
|
if (index < 0 || index >= thresholds.length == null) {
|
||||||
|
return {
|
||||||
|
"color": "rgba(0,0,0,0)",
|
||||||
|
"value": "null",
|
||||||
|
"tooltip": "null",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return thresholds[index];
|
||||||
|
}
|
||||||
|
|
||||||
roundIntervalCeil(interval) {
|
roundIntervalCeil(interval) {
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case interval <= 10:
|
case interval <= 10:
|
||||||
|
|||||||
+2
-4
@@ -266,9 +266,7 @@ export default function link(scope, elem, attrs, ctrl) {
|
|||||||
let maxValue = panel.color.max || cardsData.maxValue;
|
let maxValue = panel.color.max || cardsData.maxValue;
|
||||||
let minValue = panel.color.min || cardsData.minValue;
|
let minValue = panel.color.min || cardsData.minValue;
|
||||||
|
|
||||||
if (panel.color.mode === 'discrete') {
|
if (panel.color.mode !== 'discrete') {
|
||||||
colorScale = ctrl.discreteHelper.getDiscreteColorScale();
|
|
||||||
} else {
|
|
||||||
colorScale = getColorScale(maxValue, minValue);
|
colorScale = getColorScale(maxValue, minValue);
|
||||||
}
|
}
|
||||||
setOpacityScale(maxValue);
|
setOpacityScale(maxValue);
|
||||||
@@ -421,7 +419,7 @@ export default function link(scope, elem, attrs, ctrl) {
|
|||||||
} else if (panel.color.mode === 'spectrum') {
|
} else if (panel.color.mode === 'spectrum') {
|
||||||
return colorScale(d.value);
|
return colorScale(d.value);
|
||||||
} else if (panel.color.mode === 'discrete') {
|
} else if (panel.color.mode === 'discrete') {
|
||||||
return colorScale(d.value);
|
return ctrl.discreteHelper.getBucketColor(d.values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-12
@@ -85,18 +85,17 @@ export class StatusHeatmapTooltip {
|
|||||||
let statuses = this.panelCtrl.discreteHelper.convertValuesToTooltips(values);
|
let statuses = this.panelCtrl.discreteHelper.convertValuesToTooltips(values);
|
||||||
let statusesHtml = '';
|
let statusesHtml = '';
|
||||||
if (statuses.length === 1) {
|
if (statuses.length === 1) {
|
||||||
statusesHtml = `
|
statusesHtml = "status:";
|
||||||
status: <b style="background-color: ${statuses[0].color}; padding: 1px;">${statuses[0].tooltip}</b>`;
|
|
||||||
} else if (statuses.length > 1) {
|
} else if (statuses.length > 1) {
|
||||||
statusesHtml = `
|
statusesHtml = "statuses:";
|
||||||
statuses:
|
|
||||||
<ul>
|
|
||||||
${_.join(_.map(statuses, v => `<li style="background-color: ${v.color}; padding: 1px; text-shadow: 0 0 0.2em #FFF, 0 0 0.2em #FFF, 0 0 0.2em #FFF">${v.tooltip}</li>`), "")}
|
|
||||||
</ul>`;
|
|
||||||
}
|
}
|
||||||
tooltipHtml += `<div>
|
tooltipHtml += `
|
||||||
name: <b>${y}</b> <br>
|
<div>
|
||||||
${statusesHtml}
|
name: <b>${y}</b> <br>
|
||||||
|
${statusesHtml}
|
||||||
|
<ul>
|
||||||
|
${_.join(_.map(statuses, v => `<li style="background-color: ${v.color}; padding: 1px; font-weight: bold; text-shadow: 0 0 0.2em #FFF, 0 0 0.2em #FFF, 0 0 0.2em #FFF">${v.tooltip}</li>`), "")}
|
||||||
|
</ul>
|
||||||
</div>`;
|
</div>`;
|
||||||
} else {
|
} else {
|
||||||
if (values.length === 1) {
|
if (values.length === 1) {
|
||||||
@@ -123,9 +122,9 @@ export class StatusHeatmapTooltip {
|
|||||||
// Discrete mode errors
|
// Discrete mode errors
|
||||||
if (this.panel.color.mode === 'discrete') {
|
if (this.panel.color.mode === 'discrete') {
|
||||||
if (card.noColorDefined) {
|
if (card.noColorDefined) {
|
||||||
let badValues = this.panelCtrl.discreteHelper.getNotMatchedValues(values);
|
let badValues = this.panelCtrl.discreteHelper.getNotColoredValues(values);
|
||||||
tooltipHtml += `<div><b>Error:</b> ${this.panelCtrl.dataWarnings.noColorDefined.title}
|
tooltipHtml += `<div><b>Error:</b> ${this.panelCtrl.dataWarnings.noColorDefined.title}
|
||||||
<br>bad values:
|
<br>not colored values:
|
||||||
<ul>
|
<ul>
|
||||||
${_.join(_.map(badValues, v => `<li>${v}</li>`), "")}
|
${_.join(_.map(badValues, v => `<li>${v}</li>`), "")}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
Reference in New Issue
Block a user