mirror of
https://github.com/timberjoegithub/grafana-statusmap.git
synced 2026-07-22 07:49:47 +00:00
feat: use timestamp to put values in buckets
- fix rendering for spreaded values - fix legend for spectrum and opacity
This commit is contained in:
@@ -2,3 +2,4 @@ node_modules
|
|||||||
.jshintrc
|
.jshintrc
|
||||||
.idea
|
.idea
|
||||||
.sass-cache
|
.sass-cache
|
||||||
|
.tscache
|
||||||
Vendored
+31
-9
@@ -21,7 +21,7 @@ System.register(["lodash", "jquery", "d3", "./libs/d3-scale-chromatic/index", "a
|
|||||||
legend.selectAll(".status-heatmap-color-legend-rect").data(valuesRange).enter().append("rect") // translate from range space into pixels
|
legend.selectAll(".status-heatmap-color-legend-rect").data(valuesRange).enter().append("rect") // translate from range space into pixels
|
||||||
// and shift all rectangles to the right by 10
|
// and shift all rectangles to the right by 10
|
||||||
.attr("x", function (d) {
|
.attr("x", function (d) {
|
||||||
return d * widthFactor + 10;
|
return (d - rangeFrom) * widthFactor + 10;
|
||||||
}).attr("y", 0) // rectangles are slightly overlaped to prevent gaps
|
}).attr("y", 0) // rectangles are slightly overlaped to prevent gaps
|
||||||
.attr("width", LEGEND_STEP_WIDTH + 1).attr("height", legendHeight).attr("stroke-width", 0).attr("fill", function (d) {
|
.attr("width", LEGEND_STEP_WIDTH + 1).attr("height", legendHeight).attr("stroke-width", 0).attr("fill", function (d) {
|
||||||
return colorScale(d);
|
return colorScale(d);
|
||||||
@@ -65,7 +65,7 @@ System.register(["lodash", "jquery", "d3", "./libs/d3-scale-chromatic/index", "a
|
|||||||
|
|
||||||
var valuesNumber = thresholds.length; // graph width as a fallback
|
var valuesNumber = thresholds.length; // graph width as a fallback
|
||||||
|
|
||||||
var $heatmap = $(elem).parent().parent().parent().find('.status-heatmap-panel');
|
var $heatmap = $(elem).parent().parent().parent().find('.statusmap-panel');
|
||||||
var graphWidthAttr = $heatmap.find('svg').attr("width");
|
var graphWidthAttr = $heatmap.find('svg').attr("width");
|
||||||
var graphWidth = parseInt(graphWidthAttr); // calculate max width of tooltip and use it as width for each item
|
var graphWidth = parseInt(graphWidthAttr); // calculate max width of tooltip and use it as width for each item
|
||||||
|
|
||||||
@@ -100,8 +100,8 @@ System.register(["lodash", "jquery", "d3", "./libs/d3-scale-chromatic/index", "a
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var legendValueScale = d3.scaleLinear().domain([0, rangeTo]).range([0, legendWidth]);
|
var legendValueScale = d3.scaleLinear().domain([rangeFrom, rangeTo]).range([0, legendWidth]);
|
||||||
var ticks = buildLegendTicks(0, rangeTo, maxValue, minValue);
|
var ticks = buildLegendTicks(rangeFrom, rangeTo, maxValue, minValue);
|
||||||
var xAxis = d3.axisBottom(legendValueScale).tickValues(ticks).tickSize(2);
|
var xAxis = d3.axisBottom(legendValueScale).tickValues(ticks).tickSize(2);
|
||||||
var colorRect = legendElem.find(":first-child");
|
var colorRect = legendElem.find(":first-child");
|
||||||
var posY = getSvgElemHeight(legendElem) + 2;
|
var posY = getSvgElemHeight(legendElem) + 2;
|
||||||
@@ -252,7 +252,7 @@ System.register(["lodash", "jquery", "d3", "./libs/d3-scale-chromatic/index", "a
|
|||||||
var ticks = [];
|
var ticks = [];
|
||||||
|
|
||||||
for (var i = 0; i < ticksNum; i++) {
|
for (var i = 0; i < ticksNum; i++) {
|
||||||
var current = tickStepSize * i; // Add user-defined min and max if it had been set
|
var current = tickStepSize * i + rangeFrom; // Add user-defined min and max if it had been set
|
||||||
|
|
||||||
if (isValueCloseTo(minValue, current, tickStepSize)) {
|
if (isValueCloseTo(minValue, current, tickStepSize)) {
|
||||||
ticks.push(minValue);
|
ticks.push(minValue);
|
||||||
@@ -268,7 +268,7 @@ System.register(["lodash", "jquery", "d3", "./libs/d3-scale-chromatic/index", "a
|
|||||||
ticks.push(maxValue);
|
ticks.push(maxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
ticks.push(tickStepSize * i);
|
ticks.push(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isValueCloseTo(maxValue, rangeTo, tickStepSize)) {
|
if (!isValueCloseTo(maxValue, rangeTo, tickStepSize)) {
|
||||||
@@ -361,12 +361,34 @@ System.register(["lodash", "jquery", "d3", "./libs/d3-scale-chromatic/index", "a
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isEmpty(ctrl.cardsData) && !_.isEmpty(ctrl.cardsData.cards)) {
|
if (ctrl.bucketMatrix) {
|
||||||
var rangeFrom = ctrl.cardsData.minValue;
|
var rangeFrom = ctrl.bucketMatrix.minValue;
|
||||||
var rangeTo = ctrl.cardsData.maxValue;
|
var rangeTo = ctrl.bucketMatrix.maxValue;
|
||||||
var maxValue = panel.color.max || rangeTo;
|
var maxValue = panel.color.max || rangeTo;
|
||||||
var minValue = panel.color.min || rangeFrom;
|
var minValue = panel.color.min || rangeFrom;
|
||||||
|
|
||||||
|
if (ctrl.bucketMatrix.noDatapoints) {
|
||||||
|
if (!panel.color.max) {
|
||||||
|
rangeTo = maxValue = 100;
|
||||||
|
} else {
|
||||||
|
rangeTo = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!panel.color.min) {
|
||||||
|
rangeFrom = minValue = 0;
|
||||||
|
} else {
|
||||||
|
rangeFrom = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("legent state:", {
|
||||||
|
rangeFrom: rangeFrom,
|
||||||
|
rangeTo: rangeTo,
|
||||||
|
maxValue: maxValue,
|
||||||
|
minValue: minValue,
|
||||||
|
colorMode: panel.color.mode
|
||||||
|
});
|
||||||
|
|
||||||
if (panel.color.mode === 'spectrum') {
|
if (panel.color.mode === 'spectrum') {
|
||||||
var colorScheme = _.find(ctrl.colorSchemes, {
|
var colorScheme = _.find(ctrl.colorSchemes, {
|
||||||
value: panel.color.colorScheme
|
value: panel.color.colorScheme
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+30
-27
@@ -174,48 +174,51 @@ System.register([], function (_export, _context) {
|
|||||||
}, {
|
}, {
|
||||||
key: "updateCardsValuesHasColorInfoSingle",
|
key: "updateCardsValuesHasColorInfoSingle",
|
||||||
value: function updateCardsValuesHasColorInfoSingle() {
|
value: function updateCardsValuesHasColorInfoSingle() {
|
||||||
if (!this.panelCtrl.cardsData) {
|
var _this = this;
|
||||||
|
|
||||||
|
if (!this.panelCtrl.bucketMatrix) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.panelCtrl.cardsData.noColorDefined = false;
|
this.panelCtrl.bucketMatrix.noColorDefined = false;
|
||||||
var cards = this.panelCtrl.cardsData.cards;
|
this.panelCtrl.bucketMatrix.targets.map(function (target) {
|
||||||
|
_this.panelCtrl.bucketMatrix.buckets[target].map(function (bucket) {
|
||||||
|
bucket.noColorDefined = false;
|
||||||
|
|
||||||
for (var i = 0; i < cards.length; i++) {
|
var threshold = _this.getMatchedThreshold(bucket.value);
|
||||||
cards[i].noColorDefined = false;
|
|
||||||
var values = cards[i].value;
|
|
||||||
var threshold = this.getMatchedThreshold(values);
|
|
||||||
|
|
||||||
if (!threshold || !threshold.color || threshold.color == "") {
|
if (!threshold || !threshold.color || threshold.color == "") {
|
||||||
cards[i].noColorDefined = true;
|
bucket.noColorDefined = true;
|
||||||
this.panelCtrl.cardsData.noColorDefined = true;
|
_this.panelCtrl.bucketMatrix.noColorDefined = true;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "updateCardsValuesHasColorInfo",
|
key: "updateCardsValuesHasColorInfo",
|
||||||
value: function updateCardsValuesHasColorInfo() {
|
value: function updateCardsValuesHasColorInfo() {
|
||||||
if (!this.panelCtrl.cardsData) {
|
var _this2 = this;
|
||||||
|
|
||||||
|
if (!this.panelCtrl.bucketMatrix) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.panelCtrl.cardsData.noColorDefined = false;
|
this.panelCtrl.bucketMatrix.noColorDefined = false;
|
||||||
var cards = this.panelCtrl.cardsData.cards;
|
this.panelCtrl.bucketMatrix.targets.map(function (target) {
|
||||||
|
_this2.panelCtrl.bucketMatrix.buckets[target].map(function (bucket) {
|
||||||
|
bucket.noColorDefined = false;
|
||||||
|
|
||||||
for (var i = 0; i < cards.length; i++) {
|
for (var j = 0; j < bucket.values.length; j++) {
|
||||||
cards[i].noColorDefined = false;
|
var threshold = _this2.getMatchedThreshold(bucket.values[j]);
|
||||||
var values = cards[i].values;
|
|
||||||
|
|
||||||
for (var j = 0; j < values.length; j++) {
|
if (!threshold || !threshold.color || threshold.color == "") {
|
||||||
var threshold = this.getMatchedThreshold(values[j]);
|
bucket.noColorDefined = true;
|
||||||
|
_this2.panelCtrl.bucketMatrix.noColorDefined = true;
|
||||||
if (!threshold || !threshold.color || threshold.color == "") {
|
break;
|
||||||
cards[i].noColorDefined = true;
|
}
|
||||||
this.panelCtrl.cardsData.noColorDefined = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "getMatchedThreshold",
|
key: "getMatchedThreshold",
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+5
-5
@@ -7,18 +7,18 @@
|
|||||||
color: #d8d9da;
|
color: #d8d9da;
|
||||||
padding: 1px; }
|
padding: 1px; }
|
||||||
|
|
||||||
.status-heatmap-panel {
|
.statusmap-panel {
|
||||||
position: relative; }
|
position: relative; }
|
||||||
.status-heatmap-panel .axis .tick text {
|
.statusmap-panel .axis .tick text {
|
||||||
fill: #d8d9da;
|
fill: #d8d9da;
|
||||||
color: #d8d9da;
|
color: #d8d9da;
|
||||||
font-size: 11px; }
|
font-size: 11px; }
|
||||||
.status-heatmap-panel .axis .tick line {
|
.statusmap-panel .axis .tick line {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
stroke: #8e8e8e; }
|
stroke: #8e8e8e; }
|
||||||
.status-heatmap-panel svg {
|
.statusmap-panel svg {
|
||||||
pointer-events: none; }
|
pointer-events: none; }
|
||||||
.status-heatmap-panel svg rect {
|
.statusmap-panel svg rect {
|
||||||
pointer-events: visiblePainted; }
|
pointer-events: visiblePainted; }
|
||||||
|
|
||||||
.statusmap-tooltip {
|
.statusmap-tooltip {
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": 3,
|
"version": 3,
|
||||||
"mappings": "AAAA,8BAA+B;EAE7B,MAAM,EAAE,SAAS;EAGjB,kDAAoB;IAClB,cAAc,EAAE,IAAI;EAGtB,uDAAyB;IACzB,gBAAgB,ECNL,OAAO;IDOlB,KAAK,ECVM,OAAO;IDWlB,OAAO,EAAE,GAAG;;AAId,qBAAsB;EACpB,QAAQ,EAAE,QAAQ;EAGhB,sCAAK;IACH,IAAI,ECpBG,OAAO;IDqBd,KAAK,ECrBE,OAAO;IDsBd,SAAS,EEtBE,IAAI;EFyBjB,sCAAK;IACH,OAAO,EAAE,GAAG;IACZ,MAAM,EC1BM,OAAO;ED+BvB,yBAAI;IACF,cAAc,EAAE,IAAI;IAEpB,8BAAK;MACH,cAAc,EAAE,cAAc;;AAKpC,kBAAmB;EACjB,WAAW,EAAE,MAAM;EACnB,SAAS,EE5CI,IAAI;EF6CjB,gBAAgB,EC1CC,OAAO;ED2CxB,KAAK,EC7CM,OAAO;ED+ClB,iCAAe;IACb,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,IAAI;IACjB,WAAW,EAAE,uDAAuD;;AAIxE,8BAA+B;EAC7B,WAAW,EAAE,MAAM;EACnB,SAAS,EE1DI,IAAI;EF2DjB,gBAAgB,ECxDC,OAAO;EDyDxB,KAAK,EC3DM,OAAO;ED6DlB,6CAAe;IACb,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,IAAI;IACjB,aAAa,EAAE,CAAC;IAChB,WAAW,EAAE,uDAAuD;;AAIxE,yBAA0B;EACxB,IAAI,ECtEY,OAAO;;AD0EvB,8BAAK;EACH,MAAM,EAAE,OAAgB;EACxB,YAAY,EAAE,CAAC;;AAInB,yBAA0B;EACxB,YAAY,EAAE,CAAC;EACf,IAAI,EAAE,wBAAwB;EAC9B,MAAM,EAAE,wBAAwB;;AAGlC,WAAY;EACV,KAAK,EAAE,gBACT;;AACA,WAAY;EACV,KAAK,EAAE,gBACT;;AACA,WAAY;EACV,KAAK,EAAE,gBACT;;AACA,WAAY;EACV,KAAK,EAAE,gBACT;;AAEA,8BAA+B;EAC7B,MAAM,EAAE,MAAM;EAEd,kCAAI;IACF,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,IAAI;IACX,WAAW,EAAE,MAAM;EAIrB,2DAA6B;IAC3B,UAAU,EAAE,GAAG;EAGjB,4DAA8B;IAC5B,OAAO,EAAE,YAAY;EAIrB,+CAAK;IACH,IAAI,ECxHG,OAAO;IDyHd,KAAK,ECzHE,OAAO;ID0Hd,SAAS,EE1HE,IAAI;EF6HjB,+CAAK;IACH,OAAO,EAAE,GAAG;IACZ,MAAM,EC9HM,OAAO;EDiIrB,kDAAQ;IACN,OAAO,EAAE,GAAG;IACZ,MAAM,ECnIM,OAAO",
|
"mappings": "AAAA,8BAA+B;EAE7B,MAAM,EAAE,SAAS;EAGjB,kDAAoB;IAClB,cAAc,EAAE,IAAI;EAGtB,uDAAyB;IACzB,gBAAgB,ECNL,OAAO;IDOlB,KAAK,ECVM,OAAO;IDWlB,OAAO,EAAE,GAAG;;AAId,gBAAiB;EACf,QAAQ,EAAE,QAAQ;EAGhB,iCAAK;IACH,IAAI,ECpBG,OAAO;IDqBd,KAAK,ECrBE,OAAO;IDsBd,SAAS,EEtBE,IAAI;EFyBjB,iCAAK;IACH,OAAO,EAAE,GAAG;IACZ,MAAM,EC1BM,OAAO;ED+BvB,oBAAI;IACF,cAAc,EAAE,IAAI;IAEpB,yBAAK;MACH,cAAc,EAAE,cAAc;;AAKpC,kBAAmB;EACjB,WAAW,EAAE,MAAM;EACnB,SAAS,EE5CI,IAAI;EF6CjB,gBAAgB,EC1CC,OAAO;ED2CxB,KAAK,EC7CM,OAAO;ED+ClB,iCAAe;IACb,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,IAAI;IACjB,WAAW,EAAE,uDAAuD;;AAIxE,8BAA+B;EAC7B,WAAW,EAAE,MAAM;EACnB,SAAS,EE1DI,IAAI;EF2DjB,gBAAgB,ECxDC,OAAO;EDyDxB,KAAK,EC3DM,OAAO;ED6DlB,6CAAe;IACb,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,IAAI;IACjB,aAAa,EAAE,CAAC;IAChB,WAAW,EAAE,uDAAuD;;AAIxE,yBAA0B;EACxB,IAAI,ECtEY,OAAO;;AD0EvB,8BAAK;EACH,MAAM,EAAE,OAAgB;EACxB,YAAY,EAAE,CAAC;;AAInB,yBAA0B;EACxB,YAAY,EAAE,CAAC;EACf,IAAI,EAAE,wBAAwB;EAC9B,MAAM,EAAE,wBAAwB;;AAGlC,WAAY;EACV,KAAK,EAAE,gBACT;;AACA,WAAY;EACV,KAAK,EAAE,gBACT;;AACA,WAAY;EACV,KAAK,EAAE,gBACT;;AACA,WAAY;EACV,KAAK,EAAE,gBACT;;AAEA,8BAA+B;EAC7B,MAAM,EAAE,MAAM;EAEd,kCAAI;IACF,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,IAAI;IACX,WAAW,EAAE,MAAM;EAIrB,2DAA6B;IAC3B,UAAU,EAAE,GAAG;EAGjB,4DAA8B;IAC5B,OAAO,EAAE,YAAY;EAIrB,+CAAK;IACH,IAAI,ECxHG,OAAO;IDyHd,KAAK,ECzHE,OAAO;ID0Hd,SAAS,EE1HE,IAAI;EF6HjB,+CAAK;IACH,OAAO,EAAE,GAAG;IACZ,MAAM,EC9HM,OAAO;EDiIrB,kDAAQ;IACN,OAAO,EAAE,GAAG;IACZ,MAAM,ECnIM,OAAO",
|
||||||
"sources": ["../../src/css/_statusmap.scss","../../src/css/_variables.dark.scss","../../src/css/_variables.scss"],
|
"sources": ["../../src/css/_statusmap.scss","../../src/css/_variables.dark.scss","../../src/css/_variables.scss"],
|
||||||
"names": [],
|
"names": [],
|
||||||
"file": "statusmap.dark.css"
|
"file": "statusmap.dark.css"
|
||||||
|
|||||||
Vendored
+5
-5
@@ -7,18 +7,18 @@
|
|||||||
color: #52545c;
|
color: #52545c;
|
||||||
padding: 1px; }
|
padding: 1px; }
|
||||||
|
|
||||||
.status-heatmap-panel {
|
.statusmap-panel {
|
||||||
position: relative; }
|
position: relative; }
|
||||||
.status-heatmap-panel .axis .tick text {
|
.statusmap-panel .axis .tick text {
|
||||||
fill: #52545c;
|
fill: #52545c;
|
||||||
color: #52545c;
|
color: #52545c;
|
||||||
font-size: 11px; }
|
font-size: 11px; }
|
||||||
.status-heatmap-panel .axis .tick line {
|
.statusmap-panel .axis .tick line {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
stroke: #767980; }
|
stroke: #767980; }
|
||||||
.status-heatmap-panel svg {
|
.statusmap-panel svg {
|
||||||
pointer-events: none; }
|
pointer-events: none; }
|
||||||
.status-heatmap-panel svg rect {
|
.statusmap-panel svg rect {
|
||||||
pointer-events: visiblePainted; }
|
pointer-events: visiblePainted; }
|
||||||
|
|
||||||
.statusmap-tooltip {
|
.statusmap-tooltip {
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": 3,
|
"version": 3,
|
||||||
"mappings": "AAAA,8BAA+B;EAE7B,MAAM,EAAE,SAAS;EAGjB,kDAAoB;IAClB,cAAc,EAAE,IAAI;EAGtB,uDAAyB;IACzB,gBAAgB,ECNL,OAAO;IDOlB,KAAK,ECVM,OAAO;IDWlB,OAAO,EAAE,GAAG;;AAId,qBAAsB;EACpB,QAAQ,EAAE,QAAQ;EAGhB,sCAAK;IACH,IAAI,ECpBG,OAAO;IDqBd,KAAK,ECrBE,OAAO;IDsBd,SAAS,EEtBE,IAAI;EFyBjB,sCAAK;IACH,OAAO,EAAE,GAAG;IACZ,MAAM,EC1BM,OAAO;ED+BvB,yBAAI;IACF,cAAc,EAAE,IAAI;IAEpB,8BAAK;MACH,cAAc,EAAE,cAAc;;AAKpC,kBAAmB;EACjB,WAAW,EAAE,MAAM;EACnB,SAAS,EE5CI,IAAI;EF6CjB,gBAAgB,EC1CC,OAAO;ED2CxB,KAAK,EC7CM,OAAO;ED+ClB,iCAAe;IACb,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,IAAI;IACjB,WAAW,EAAE,uDAAuD;;AAIxE,8BAA+B;EAC7B,WAAW,EAAE,MAAM;EACnB,SAAS,EE1DI,IAAI;EF2DjB,gBAAgB,ECxDC,OAAO;EDyDxB,KAAK,EC3DM,OAAO;ED6DlB,6CAAe;IACb,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,IAAI;IACjB,aAAa,EAAE,CAAC;IAChB,WAAW,EAAE,uDAAuD;;AAIxE,yBAA0B;EACxB,IAAI,ECtEY,OAAO;;AD0EvB,8BAAK;EACH,MAAM,EAAE,OAAgB;EACxB,YAAY,EAAE,CAAC;;AAInB,yBAA0B;EACxB,YAAY,EAAE,CAAC;EACf,IAAI,EAAE,wBAAwB;EAC9B,MAAM,EAAE,wBAAwB;;AAGlC,WAAY;EACV,KAAK,EAAE,gBACT;;AACA,WAAY;EACV,KAAK,EAAE,gBACT;;AACA,WAAY;EACV,KAAK,EAAE,gBACT;;AACA,WAAY;EACV,KAAK,EAAE,gBACT;;AAEA,8BAA+B;EAC7B,MAAM,EAAE,MAAM;EAEd,kCAAI;IACF,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,IAAI;IACX,WAAW,EAAE,MAAM;EAIrB,2DAA6B;IAC3B,UAAU,EAAE,GAAG;EAGjB,4DAA8B;IAC5B,OAAO,EAAE,YAAY;EAIrB,+CAAK;IACH,IAAI,ECxHG,OAAO;IDyHd,KAAK,ECzHE,OAAO;ID0Hd,SAAS,EE1HE,IAAI;EF6HjB,+CAAK;IACH,OAAO,EAAE,GAAG;IACZ,MAAM,EC9HM,OAAO;EDiIrB,kDAAQ;IACN,OAAO,EAAE,GAAG;IACZ,MAAM,ECnIM,OAAO",
|
"mappings": "AAAA,8BAA+B;EAE7B,MAAM,EAAE,SAAS;EAGjB,kDAAoB;IAClB,cAAc,EAAE,IAAI;EAGtB,uDAAyB;IACzB,gBAAgB,ECNL,OAAO;IDOlB,KAAK,ECVM,OAAO;IDWlB,OAAO,EAAE,GAAG;;AAId,gBAAiB;EACf,QAAQ,EAAE,QAAQ;EAGhB,iCAAK;IACH,IAAI,ECpBG,OAAO;IDqBd,KAAK,ECrBE,OAAO;IDsBd,SAAS,EEtBE,IAAI;EFyBjB,iCAAK;IACH,OAAO,EAAE,GAAG;IACZ,MAAM,EC1BM,OAAO;ED+BvB,oBAAI;IACF,cAAc,EAAE,IAAI;IAEpB,yBAAK;MACH,cAAc,EAAE,cAAc;;AAKpC,kBAAmB;EACjB,WAAW,EAAE,MAAM;EACnB,SAAS,EE5CI,IAAI;EF6CjB,gBAAgB,EC1CC,OAAO;ED2CxB,KAAK,EC7CM,OAAO;ED+ClB,iCAAe;IACb,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,IAAI;IACjB,WAAW,EAAE,uDAAuD;;AAIxE,8BAA+B;EAC7B,WAAW,EAAE,MAAM;EACnB,SAAS,EE1DI,IAAI;EF2DjB,gBAAgB,ECxDC,OAAO;EDyDxB,KAAK,EC3DM,OAAO;ED6DlB,6CAAe;IACb,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,IAAI;IACjB,aAAa,EAAE,CAAC;IAChB,WAAW,EAAE,uDAAuD;;AAIxE,yBAA0B;EACxB,IAAI,ECtEY,OAAO;;AD0EvB,8BAAK;EACH,MAAM,EAAE,OAAgB;EACxB,YAAY,EAAE,CAAC;;AAInB,yBAA0B;EACxB,YAAY,EAAE,CAAC;EACf,IAAI,EAAE,wBAAwB;EAC9B,MAAM,EAAE,wBAAwB;;AAGlC,WAAY;EACV,KAAK,EAAE,gBACT;;AACA,WAAY;EACV,KAAK,EAAE,gBACT;;AACA,WAAY;EACV,KAAK,EAAE,gBACT;;AACA,WAAY;EACV,KAAK,EAAE,gBACT;;AAEA,8BAA+B;EAC7B,MAAM,EAAE,MAAM;EAEd,kCAAI;IACF,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,IAAI;IACX,WAAW,EAAE,MAAM;EAIrB,2DAA6B;IAC3B,UAAU,EAAE,GAAG;EAGjB,4DAA8B;IAC5B,OAAO,EAAE,YAAY;EAIrB,+CAAK;IACH,IAAI,ECxHG,OAAO;IDyHd,KAAK,ECzHE,OAAO;ID0Hd,SAAS,EE1HE,IAAI;EF6HjB,+CAAK;IACH,OAAO,EAAE,GAAG;IACZ,MAAM,EC9HM,OAAO;EDiIrB,kDAAQ;IACN,OAAO,EAAE,GAAG;IACZ,MAAM,ECnIM,OAAO",
|
||||||
"sources": ["../../src/css/_statusmap.scss","../../src/css/_variables.light.scss","../../src/css/_variables.scss"],
|
"sources": ["../../src/css/_statusmap.scss","../../src/css/_variables.light.scss","../../src/css/_variables.scss"],
|
||||||
"names": [],
|
"names": [],
|
||||||
"file": "statusmap.light.css"
|
"file": "statusmap.light.css"
|
||||||
|
|||||||
Vendored
+4
-2
@@ -1,12 +1,14 @@
|
|||||||
<div class="status-heatmap-wrapper">
|
<div class="status-heatmap-wrapper">
|
||||||
<div class="status-heatmap-canvas-wrapper">
|
<div class="status-heatmap-canvas-wrapper">
|
||||||
|
|
||||||
<div class="datapoints-warning" ng-if="ctrl.multipleValues || ctrl.noColorDefined">
|
<div class="datapoints-warning" ng-if="ctrl.multipleValues || ctrl.noColorDefined || ctrl.noDatapoints">
|
||||||
<span class="small" ng-if="ctrl.multipleValues" bs-tooltip="'{{ctrl.dataWarnings.multipleValues.tip}}'">{{ctrl.dataWarnings.multipleValues.title}}</span>
|
<span class="small" ng-if="ctrl.multipleValues" bs-tooltip="'{{ctrl.dataWarnings.multipleValues.tip}}'">{{ctrl.dataWarnings.multipleValues.title}}</span>
|
||||||
<span class="small" ng-if="ctrl.noColorDefined" bs-tooltip="'{{ctrl.dataWarnings.noColorDefined.tip}}'">{{ctrl.dataWarnings.noColorDefined.title}}</span>
|
<span class="small" ng-if="ctrl.noColorDefined" bs-tooltip="'{{ctrl.dataWarnings.noColorDefined.tip}}'">{{ctrl.dataWarnings.noColorDefined.title}}</span>
|
||||||
|
<span class="small" ng-if="ctrl.noDatapoints" bs-tooltip="'{{ctrl.dataWarnings.noDatapoints.tip}}'">{{ctrl.dataWarnings.noDatapoints.title}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="status-heatmap-panel" ng-dblclick="ctrl.zoomOut()"></div>
|
|
||||||
|
<div class="statusmap-panel" ng-dblclick="ctrl.zoomOut()"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="status-heatmap-legend-wrapper" ng-if="ctrl.panel.legend.show">
|
<div class="status-heatmap-legend-wrapper" ng-if="ctrl.panel.legend.show">
|
||||||
<status-heatmap-legend></status-heatmap-legend>
|
<status-heatmap-legend></status-heatmap-legend>
|
||||||
|
|||||||
Vendored
+381
-111
@@ -3,7 +3,7 @@
|
|||||||
System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/sdk", "./statusmap_data", "./rendering", "./options_editor", "./color_mode_discrete", "./extra_series_format"], function (_export, _context) {
|
System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/sdk", "./statusmap_data", "./rendering", "./options_editor", "./color_mode_discrete", "./extra_series_format"], function (_export, _context) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var _, kbn, loadPluginCss, MetricsPanelCtrl, Card, rendering, statusHeatmapOptionsEditor, ColorModeDiscrete, ExtraSeriesFormat, ExtraSeriesFormatValue, CANVAS, SVG, VALUE_INDEX, TIME_INDEX, renderer, colorSchemes, colorModes, opacityScales, StatusHeatmapCtrl;
|
var _, kbn, loadPluginCss, MetricsPanelCtrl, Bucket, BucketMatrix, rendering, statusHeatmapOptionsEditor, ColorModeDiscrete, ExtraSeriesFormat, ExtraSeriesFormatValue, VALUE_INDEX, TIME_INDEX, colorSchemes, colorModes, opacityScales, StatusHeatmapCtrl;
|
||||||
|
|
||||||
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
||||||
|
|
||||||
@@ -38,7 +38,8 @@ System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/
|
|||||||
loadPluginCss = _appPluginsSdk.loadPluginCss;
|
loadPluginCss = _appPluginsSdk.loadPluginCss;
|
||||||
MetricsPanelCtrl = _appPluginsSdk.MetricsPanelCtrl;
|
MetricsPanelCtrl = _appPluginsSdk.MetricsPanelCtrl;
|
||||||
}, function (_statusmap_data) {
|
}, function (_statusmap_data) {
|
||||||
Card = _statusmap_data.Card;
|
Bucket = _statusmap_data.Bucket;
|
||||||
|
BucketMatrix = _statusmap_data.BucketMatrix;
|
||||||
}, function (_rendering) {
|
}, function (_rendering) {
|
||||||
rendering = _rendering.default;
|
rendering = _rendering.default;
|
||||||
}, function (_options_editor) {
|
}, function (_options_editor) {
|
||||||
@@ -50,11 +51,8 @@ System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/
|
|||||||
ExtraSeriesFormatValue = _extra_series_format.ExtraSeriesFormatValue;
|
ExtraSeriesFormatValue = _extra_series_format.ExtraSeriesFormatValue;
|
||||||
}],
|
}],
|
||||||
execute: function () {
|
execute: function () {
|
||||||
CANVAS = 'CANVAS';
|
|
||||||
SVG = 'SVG';
|
|
||||||
VALUE_INDEX = 0;
|
VALUE_INDEX = 0;
|
||||||
TIME_INDEX = 1;
|
TIME_INDEX = 1;
|
||||||
renderer = CANVAS;
|
|
||||||
colorSchemes = [// Diverging
|
colorSchemes = [// Diverging
|
||||||
{
|
{
|
||||||
name: 'Spectral',
|
name: 'Spectral',
|
||||||
@@ -166,6 +164,14 @@ System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/
|
|||||||
_this = _possibleConstructorReturn(this, _getPrototypeOf(StatusHeatmapCtrl).call(this, $scope, $injector));
|
_this = _possibleConstructorReturn(this, _getPrototypeOf(StatusHeatmapCtrl).call(this, $scope, $injector));
|
||||||
_this.annotationsSrv = annotationsSrv;
|
_this.annotationsSrv = annotationsSrv;
|
||||||
|
|
||||||
|
_defineProperty(_assertThisInitialized(_this), "data", void 0);
|
||||||
|
|
||||||
|
_defineProperty(_assertThisInitialized(_this), "bucketMatrix", void 0);
|
||||||
|
|
||||||
|
_defineProperty(_assertThisInitialized(_this), "graph", void 0);
|
||||||
|
|
||||||
|
_defineProperty(_assertThisInitialized(_this), "discreteHelper", void 0);
|
||||||
|
|
||||||
_defineProperty(_assertThisInitialized(_this), "opacityScales", []);
|
_defineProperty(_assertThisInitialized(_this), "opacityScales", []);
|
||||||
|
|
||||||
_defineProperty(_assertThisInitialized(_this), "colorModes", []);
|
_defineProperty(_assertThisInitialized(_this), "colorModes", []);
|
||||||
@@ -174,19 +180,15 @@ System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/
|
|||||||
|
|
||||||
_defineProperty(_assertThisInitialized(_this), "unitFormats", void 0);
|
_defineProperty(_assertThisInitialized(_this), "unitFormats", void 0);
|
||||||
|
|
||||||
_defineProperty(_assertThisInitialized(_this), "data", void 0);
|
_defineProperty(_assertThisInitialized(_this), "dataWarnings", {});
|
||||||
|
|
||||||
_defineProperty(_assertThisInitialized(_this), "cardsData", void 0);
|
|
||||||
|
|
||||||
_defineProperty(_assertThisInitialized(_this), "graph", void 0);
|
|
||||||
|
|
||||||
_defineProperty(_assertThisInitialized(_this), "multipleValues", void 0);
|
_defineProperty(_assertThisInitialized(_this), "multipleValues", void 0);
|
||||||
|
|
||||||
_defineProperty(_assertThisInitialized(_this), "noColorDefined", void 0);
|
_defineProperty(_assertThisInitialized(_this), "noColorDefined", void 0);
|
||||||
|
|
||||||
_defineProperty(_assertThisInitialized(_this), "discreteExtraSeries", void 0);
|
_defineProperty(_assertThisInitialized(_this), "noDatapoints", void 0);
|
||||||
|
|
||||||
_defineProperty(_assertThisInitialized(_this), "dataWarnings", void 0);
|
_defineProperty(_assertThisInitialized(_this), "discreteExtraSeries", void 0);
|
||||||
|
|
||||||
_defineProperty(_assertThisInitialized(_this), "extraSeriesFormats", []);
|
_defineProperty(_assertThisInitialized(_this), "extraSeriesFormats", []);
|
||||||
|
|
||||||
@@ -218,14 +220,12 @@ System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/
|
|||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
show: true,
|
show: true,
|
||||||
showWeekends: true,
|
|
||||||
minBucketWidthToShowWeekends: 4,
|
|
||||||
showCrosshair: true,
|
|
||||||
labelFormat: '%a %m/%d'
|
labelFormat: '%a %m/%d'
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
show: true,
|
show: true,
|
||||||
showCrosshair: false
|
minWidth: -1,
|
||||||
|
maxWidth: -1
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
show: true
|
show: true
|
||||||
@@ -318,13 +318,17 @@ System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/
|
|||||||
_this.noColorDefined = false;
|
_this.noColorDefined = false;
|
||||||
_this.discreteExtraSeries = new ColorModeDiscrete($scope);
|
_this.discreteExtraSeries = new ColorModeDiscrete($scope);
|
||||||
_this.dataWarnings = {
|
_this.dataWarnings = {
|
||||||
"noColorDefined": {
|
noColorDefined: {
|
||||||
title: 'Data has value with undefined color',
|
title: 'Data has value with undefined color',
|
||||||
tip: 'Check metric values, color values or define a new color'
|
tip: 'Check metric values, color values or define a new color'
|
||||||
},
|
},
|
||||||
"multipleValues": {
|
multipleValues: {
|
||||||
title: 'Data has multiple values for one target',
|
title: 'Data has multiple values for one target',
|
||||||
tip: 'Change targets definitions or set "use max value"'
|
tip: 'Change targets definitions or set "use max value"'
|
||||||
|
},
|
||||||
|
noDatapoints: {
|
||||||
|
title: 'No data points',
|
||||||
|
tip: 'No datapoints returned from data query'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
_this.annotations = [];
|
_this.annotations = [];
|
||||||
@@ -354,6 +358,13 @@ System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/
|
|||||||
_createClass(StatusHeatmapCtrl, [{
|
_createClass(StatusHeatmapCtrl, [{
|
||||||
key: "onRenderComplete",
|
key: "onRenderComplete",
|
||||||
value: function onRenderComplete(data) {
|
value: function onRenderComplete(data) {
|
||||||
|
// console.log({
|
||||||
|
// data: this.data,
|
||||||
|
// bucketMatrix: this.bucketMatrix,
|
||||||
|
// chartWidth: data.chartWidth,
|
||||||
|
// from: this.range.from.valueOf(),
|
||||||
|
// to: this.range.to.valueOf()
|
||||||
|
// })
|
||||||
this.graph.chartWidth = data.chartWidth;
|
this.graph.chartWidth = data.chartWidth;
|
||||||
this.renderingCompleted();
|
this.renderingCompleted();
|
||||||
}
|
}
|
||||||
@@ -373,19 +384,30 @@ System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/
|
|||||||
url.extraSeries.format = ExtraSeriesFormatValue.Raw;
|
url.extraSeries.format = ExtraSeriesFormatValue.Raw;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} // getChartWidth returns an approximation of chart canvas width or
|
||||||
|
// a saved value calculated during a render.
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
key: "getChartWidth",
|
key: "getChartWidth",
|
||||||
value: function getChartWidth() {
|
value: function getChartWidth() {
|
||||||
|
if (this.graph.chartWidth > 0) {
|
||||||
|
return this.graph.chartWidth;
|
||||||
|
}
|
||||||
|
|
||||||
var wndWidth = $(window).width(); // gripPos.w is a width in grid's measurements. Grid size in Grafana is 24.
|
var wndWidth = $(window).width(); // gripPos.w is a width in grid's measurements. Grid size in Grafana is 24.
|
||||||
|
|
||||||
var panelWidthFactor = this.panel.gridPos.w / 24;
|
var panelWidthFactor = this.panel.gridPos.w / 24;
|
||||||
var panelWidth = Math.ceil(wndWidth * panelWidthFactor); // approximate chartWidth because y axis ticks not rendered yet on first data receive.
|
var panelWidth = Math.ceil(wndWidth * panelWidthFactor); // approximate width of the chart draw canvas:
|
||||||
|
// - y axis ticks are not rendered yet on first data receive,
|
||||||
|
// so choose 200 as a decent value for y legend width
|
||||||
|
// - chartWidth can not be lower than the half of the panel width.
|
||||||
|
|
||||||
var chartWidth = _.max([panelWidth - 200, panelWidth / 2]);
|
var chartWidth = _.max([panelWidth - 200, panelWidth / 2]);
|
||||||
|
|
||||||
return chartWidth;
|
return chartWidth;
|
||||||
} // override calculateInterval for discrete color mode
|
} // calculateInterval is called on 'refresh' to calculate an interval
|
||||||
|
// for datasource.
|
||||||
|
// It is override of calculateInterval from MetricsPanelCtrl.
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
key: "calculateInterval",
|
key: "calculateInterval",
|
||||||
@@ -423,7 +445,17 @@ System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/
|
|||||||
|
|
||||||
var interval = kbn.secondsToHms(intervalMs / 1000);
|
var interval = kbn.secondsToHms(intervalMs / 1000);
|
||||||
this.intervalMs = intervalMs;
|
this.intervalMs = intervalMs;
|
||||||
this.interval = interval;
|
this.interval = interval; // Get final buckets count after interval is adjusted
|
||||||
|
//this.xBucketsCount = Math.floor(rangeMs / intervalMs);
|
||||||
|
// console.log("calculateInterval: ", {
|
||||||
|
// interval: this.interval,
|
||||||
|
// intervalMs: this.intervalMs,
|
||||||
|
// rangeMs: rangeMs,
|
||||||
|
// from: this.range.from.valueOf(),
|
||||||
|
// to: this.range.to.valueOf(),
|
||||||
|
// numIntervals: rangeMs/this.intervalMs,
|
||||||
|
// maxCardsCount: maxCardsCount,
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "issueQueries",
|
key: "issueQueries",
|
||||||
@@ -458,7 +490,7 @@ System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/
|
|||||||
key: "issueQueriesWithInterval",
|
key: "issueQueriesWithInterval",
|
||||||
value: function issueQueriesWithInterval(datasource, interval) {
|
value: function issueQueriesWithInterval(datasource, interval) {
|
||||||
var origInterval = this.panel.interval;
|
var origInterval = this.panel.interval;
|
||||||
this.panel.interval = this.interval;
|
this.panel.interval = interval;
|
||||||
|
|
||||||
var res = _get(_getPrototypeOf(StatusHeatmapCtrl.prototype), "issueQueries", this).call(this, datasource);
|
var res = _get(_getPrototypeOf(StatusHeatmapCtrl.prototype), "issueQueries", this).call(this, datasource);
|
||||||
|
|
||||||
@@ -471,7 +503,8 @@ System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/
|
|||||||
var _this3 = this;
|
var _this3 = this;
|
||||||
|
|
||||||
this.data = dataList;
|
this.data = dataList;
|
||||||
this.cardsData = this.convertToCards(this.data);
|
this.bucketMatrix = this.convertDataToBuckets(dataList, this.range.from.valueOf(), this.range.to.valueOf(), this.intervalMs, true);
|
||||||
|
this.noDatapoints = this.bucketMatrix.noDatapoints;
|
||||||
this.annotationsPromise.then(function (result) {
|
this.annotationsPromise.then(function (result) {
|
||||||
_this3.loading = false; //this.alertState = result.alertState;
|
_this3.loading = false; //this.alertState = result.alertState;
|
||||||
|
|
||||||
@@ -487,26 +520,30 @@ System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/
|
|||||||
_this3.annotations = [];
|
_this3.annotations = [];
|
||||||
|
|
||||||
_this3.render();
|
_this3.render();
|
||||||
}); //this.render();
|
});
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "onInitEditMode",
|
key: "onInitEditMode",
|
||||||
value: function onInitEditMode() {
|
value: function onInitEditMode() {
|
||||||
this.addEditorTab('Options', statusHeatmapOptionsEditor, 2);
|
this.addEditorTab('Options', statusHeatmapOptionsEditor, 2);
|
||||||
this.unitFormats = kbn.getUnitFormats();
|
this.unitFormats = kbn.getUnitFormats();
|
||||||
}
|
} // onRender will be called before StatusmapRenderer.onRender.
|
||||||
|
// Decide if warning should be displayed over cards.
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
key: "onRender",
|
key: "onRender",
|
||||||
value: function onRender() {
|
value: function onRender() {
|
||||||
|
//console.log('OnRender');
|
||||||
if (!this.range || !this.data) {
|
if (!this.range || !this.data) {
|
||||||
|
this.noDatapoints = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.multipleValues = false;
|
this.multipleValues = false;
|
||||||
|
|
||||||
if (!this.panel.useMax) {
|
if (!this.panel.useMax) {
|
||||||
if (this.cardsData) {
|
if (this.bucketMatrix) {
|
||||||
this.multipleValues = this.cardsData.multipleValues;
|
this.multipleValues = this.bucketMatrix.multipleValues;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -519,10 +556,17 @@ System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/
|
|||||||
this.discreteExtraSeries.updateCardsValuesHasColorInfoSingle();
|
this.discreteExtraSeries.updateCardsValuesHasColorInfoSingle();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.cardsData) {
|
if (this.bucketMatrix) {
|
||||||
this.noColorDefined = this.cardsData.noColorDefined;
|
this.noColorDefined = this.bucketMatrix.noColorDefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.noDatapoints = false;
|
||||||
|
|
||||||
|
if (this.bucketMatrix) {
|
||||||
|
this.noDatapoints = this.bucketMatrix.noDatapoints;
|
||||||
|
} //console.log(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "onCardColorChange",
|
key: "onCardColorChange",
|
||||||
@@ -640,94 +684,320 @@ System.register(["lodash", "./color_legend", "app/core/utils/kbn", "app/plugins/
|
|||||||
var time = this.timeSrv.timeRangeForUrl();
|
var time = this.timeSrv.timeRangeForUrl();
|
||||||
var var_time = '&from=' + time.from + '&to=' + time.to;
|
var var_time = '&from=' + time.from + '&to=' + time.to;
|
||||||
return var_time;
|
return var_time;
|
||||||
} // group values into buckets by target
|
} // convertToBuckets groups values in data into buckets by target and timestamp.
|
||||||
|
//
|
||||||
|
// data is a result from datasource. It is an array of timeseries and tables:
|
||||||
|
|
||||||
|
/* [
|
||||||
|
// timeseries
|
||||||
|
{
|
||||||
|
target: "query alias",
|
||||||
|
refId: "A",
|
||||||
|
datapoints: [
|
||||||
|
[0, 1582681239911],
|
||||||
|
[3, 158....],
|
||||||
|
...
|
||||||
|
],
|
||||||
|
tags?:{key: value,...}
|
||||||
|
},
|
||||||
|
// table
|
||||||
|
{
|
||||||
|
name: "table name",
|
||||||
|
refId: "B",
|
||||||
|
columns: [
|
||||||
|
{text: "id"},
|
||||||
|
{text: "info"},
|
||||||
|
...
|
||||||
|
],
|
||||||
|
rows: [
|
||||||
|
[1, "123"],
|
||||||
|
[2, "44411"],
|
||||||
|
...
|
||||||
|
]
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
to and from — a time range of the panel.
|
||||||
|
intervalMs — a calculated interval. It is used to split a time range.
|
||||||
|
*/
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
key: "convertToCards",
|
key: "convertDataToBuckets",
|
||||||
value: function convertToCards(data) {
|
value: function convertDataToBuckets(data, from, to, intervalMs, mostRecentBucket) {
|
||||||
var cardsData = {
|
var _this4 = this;
|
||||||
cards: [],
|
|
||||||
xBucketSize: 0,
|
|
||||||
yBucketSize: 0,
|
|
||||||
maxValue: 0,
|
|
||||||
minValue: 0,
|
|
||||||
multipleValues: false,
|
|
||||||
noColorDefined: false,
|
|
||||||
targets: [],
|
|
||||||
// array of available unique targets
|
|
||||||
targetIndex: {} // indices in data array for each of available unique targets
|
|
||||||
|
|
||||||
};
|
var bucketMatrix = new BucketMatrix();
|
||||||
|
bucketMatrix.rangeMs = to - from;
|
||||||
|
bucketMatrix.intervalMs = intervalMs;
|
||||||
|
|
||||||
if (!data || data.length == 0) {
|
if (!data || data.length == 0) {
|
||||||
return cardsData;
|
// Mimic heatmap and graph 'no data' labels.
|
||||||
} // Collect uniq timestamps from data and spread over targets and timestamps
|
bucketMatrix.targets = ["1.0", "0.0", "-1.0"];
|
||||||
// collect uniq targets and their indices
|
bucketMatrix.buckets["1.0"] = [];
|
||||||
|
bucketMatrix.buckets["0.0"] = [];
|
||||||
|
bucketMatrix.buckets["-1.0"] = [];
|
||||||
_.map(data, function (d, i) {
|
bucketMatrix.xBucketSize = 42;
|
||||||
cardsData.targetIndex[d.target] = _.concat(_.toArray(cardsData.targetIndex[d.target]), i);
|
bucketMatrix.noDatapoints = true;
|
||||||
}); // TODO add some logic for targets heirarchy
|
return bucketMatrix;
|
||||||
|
|
||||||
|
|
||||||
cardsData.targets = _.keys(cardsData.targetIndex);
|
|
||||||
cardsData.yBucketSize = cardsData.targets.length; // Maximum number of buckets over x axis
|
|
||||||
|
|
||||||
cardsData.xBucketSize = _.max(_.map(data, function (d) {
|
|
||||||
return d.datapoints.length;
|
|
||||||
})); // Collect all values for each bucket from datapoints with similar target.
|
|
||||||
// TODO aggregate values into buckets over datapoint[TIME_INDEX] not over datapoint index (j).
|
|
||||||
|
|
||||||
for (var i = 0; i < cardsData.targets.length; i++) {
|
|
||||||
var target = cardsData.targets[i];
|
|
||||||
|
|
||||||
for (var j = 0; j < cardsData.xBucketSize; j++) {
|
|
||||||
var card = new Card();
|
|
||||||
card.id = i * cardsData.xBucketSize + j;
|
|
||||||
card.values = [];
|
|
||||||
card.columns = [];
|
|
||||||
card.multipleValues = false;
|
|
||||||
card.noColorDefined = false;
|
|
||||||
card.y = target;
|
|
||||||
card.x = -1; // collect values from all timeseries with target
|
|
||||||
|
|
||||||
for (var si = 0; si < cardsData.targetIndex[target].length; si++) {
|
|
||||||
var s = data[cardsData.targetIndex[target][si]];
|
|
||||||
|
|
||||||
if (s.datapoints.length <= j) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var datapoint = s.datapoints[j];
|
|
||||||
|
|
||||||
if (card.values.length === 0) {
|
|
||||||
card.x = datapoint[TIME_INDEX];
|
|
||||||
}
|
|
||||||
|
|
||||||
card.values.push(datapoint[VALUE_INDEX]);
|
|
||||||
}
|
|
||||||
|
|
||||||
card.minValue = _.min(card.values);
|
|
||||||
card.maxValue = _.max(card.values);
|
|
||||||
|
|
||||||
if (card.values.length > 1) {
|
|
||||||
cardsData.multipleValues = true;
|
|
||||||
card.multipleValues = true;
|
|
||||||
card.value = this.panel.seriesFilterIndex != -1 ? card.values[this.panel.seriesFilterIndex] : card.maxValue;
|
|
||||||
} else {
|
|
||||||
card.value = card.maxValue; // max value by default
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cardsData.maxValue < card.maxValue) cardsData.maxValue = card.maxValue;
|
|
||||||
if (cardsData.minValue > card.minValue) cardsData.minValue = card.minValue;
|
|
||||||
|
|
||||||
if (card.x != -1) {
|
|
||||||
cardsData.cards.push(card);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cardsData;
|
var targetIndex = {}; // Group indicies of elements in data by target (y label).
|
||||||
|
// lodash version:
|
||||||
|
//_.map(data, (d, i) => {
|
||||||
|
// targetIndex[d.target] = _.concat(_.toArray(targetIndex[d.target]), i);
|
||||||
|
//});
|
||||||
|
|
||||||
|
data.map(function (queryResult, i) {
|
||||||
|
var yLabel = queryResult.target;
|
||||||
|
|
||||||
|
if (!targetIndex.hasOwnProperty(yLabel)) {
|
||||||
|
targetIndex[yLabel] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
targetIndex[yLabel].push(i);
|
||||||
|
});
|
||||||
|
|
||||||
|
var targetKeys = _.keys(targetIndex); //console.log ("targetIndex: ", targetIndex, "targetKeys: ", targetKeys);
|
||||||
|
|
||||||
|
|
||||||
|
var targetTimestampRanges = {}; // Collect all timestamps for each target.
|
||||||
|
// Make map timestamp => [from, to]. from == previous ts, to == ts from datapoint.
|
||||||
|
|
||||||
|
targetKeys.map(function (target) {
|
||||||
|
var targetTimestamps = [];
|
||||||
|
|
||||||
|
for (var si = 0; si < targetIndex[target].length; si++) {
|
||||||
|
var s = data[targetIndex[target][si]];
|
||||||
|
|
||||||
|
_.map(s.datapoints, function (datapoint, idx) {
|
||||||
|
targetTimestamps.push(datapoint[TIME_INDEX] - from);
|
||||||
|
});
|
||||||
|
} //console.log("timestamps['"+target+"'] = ", targetTimestamps);
|
||||||
|
|
||||||
|
|
||||||
|
targetTimestamps = _.uniq(targetTimestamps); //console.log("uniq timestamps['"+target+"'] = ", targetTimestamps);
|
||||||
|
|
||||||
|
targetTimestampRanges[target] = [];
|
||||||
|
|
||||||
|
for (var i = targetTimestamps.length - 1; i >= 0; i--) {
|
||||||
|
var tsTo = targetTimestamps[i];
|
||||||
|
var tsFrom = 0;
|
||||||
|
|
||||||
|
if (tsTo < 0) {
|
||||||
|
tsFrom = tsTo - intervalMs;
|
||||||
|
} else {
|
||||||
|
if (i - 1 >= 0) {
|
||||||
|
// Set from to previous timestamp + 1ms;
|
||||||
|
tsFrom = targetTimestamps[i - 1] + 1; // tfTo - tfFrom should not be more than intervalMs
|
||||||
|
|
||||||
|
var minFrom = tsTo - intervalMs;
|
||||||
|
|
||||||
|
if (tsFrom < minFrom) {
|
||||||
|
tsFrom = minFrom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
targetTimestampRanges[target][tsTo] = [tsFrom, tsTo];
|
||||||
|
}
|
||||||
|
}); // console.log ("targetTimestampRanges: ", targetTimestampRanges);
|
||||||
|
// Create empty buckets using intervalMs to calculate ranges.
|
||||||
|
// If mostRecentBucket is set, create a bucket with a range "to":"to"
|
||||||
|
// to store most recent values.
|
||||||
|
|
||||||
|
targetKeys.map(function (target) {
|
||||||
|
var targetEmptyBuckets = [];
|
||||||
|
var lastTs = to - from;
|
||||||
|
|
||||||
|
if (mostRecentBucket) {
|
||||||
|
var topBucket = new Bucket();
|
||||||
|
topBucket.yLabel = target;
|
||||||
|
topBucket.relTo = lastTs;
|
||||||
|
topBucket.relFrom = lastTs;
|
||||||
|
topBucket.values = [];
|
||||||
|
topBucket.mostRecent = true;
|
||||||
|
|
||||||
|
if (targetTimestampRanges[target].hasOwnProperty(lastTs)) {
|
||||||
|
topBucket.relFrom = targetTimestampRanges[target][lastTs][0];
|
||||||
|
lastTs = topBucket.relFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
topBucket.to = topBucket.relTo + from;
|
||||||
|
topBucket.from = topBucket.relFrom + from;
|
||||||
|
targetEmptyBuckets.push(topBucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
var idx = 0;
|
||||||
|
var bucketFrom = 0;
|
||||||
|
|
||||||
|
while (bucketFrom >= 0) {
|
||||||
|
var b = new Bucket();
|
||||||
|
b.yLabel = target;
|
||||||
|
b.relTo = lastTs - idx * intervalMs;
|
||||||
|
b.relFrom = lastTs - (idx + 1) * intervalMs;
|
||||||
|
b.to = b.relTo + from;
|
||||||
|
b.from = b.relFrom + from;
|
||||||
|
b.values = [];
|
||||||
|
bucketFrom = b.relFrom;
|
||||||
|
targetEmptyBuckets.push(b);
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetEmptyBuckets.map(function (bucket, i) {
|
||||||
|
bucket.xid = i;
|
||||||
|
});
|
||||||
|
bucketMatrix.buckets[target] = targetEmptyBuckets;
|
||||||
|
}); //console.log ("bucketMatrix: ", bucketMatrix);
|
||||||
|
// Put values into buckets.
|
||||||
|
|
||||||
|
bucketMatrix.minValue = Number.MAX_VALUE;
|
||||||
|
bucketMatrix.maxValue = Number.MIN_SAFE_INTEGER;
|
||||||
|
targetKeys.map(function (target) {
|
||||||
|
targetIndex[target].map(function (dataIndex) {
|
||||||
|
var s = data[dataIndex];
|
||||||
|
s.datapoints.map(function (dp) {
|
||||||
|
for (var i = 0; i < bucketMatrix.buckets[target].length; i++) {
|
||||||
|
if (bucketMatrix.buckets[target][i].belong(dp[TIME_INDEX])) {
|
||||||
|
bucketMatrix.buckets[target][i].put(dp[VALUE_INDEX]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
bucketMatrix.buckets[target].map(function (bucket) {
|
||||||
|
bucket.minValue = _.min(bucket.values);
|
||||||
|
bucket.maxValue = _.max(bucket.values);
|
||||||
|
|
||||||
|
if (bucket.minValue < bucketMatrix.minValue) {
|
||||||
|
bucketMatrix.minValue = bucket.minValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bucket.maxValue > bucketMatrix.maxValue) {
|
||||||
|
bucketMatrix.maxValue = bucket.maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bucket.value = bucket.maxValue;
|
||||||
|
|
||||||
|
if (bucket.values.length > 1) {
|
||||||
|
bucketMatrix.multipleValues = true;
|
||||||
|
bucket.multipleValues = true;
|
||||||
|
bucket.value = _this4.panel.seriesFilterIndex != -1 ? bucket.values[_this4.panel.seriesFilterIndex] : bucket.maxValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
bucketMatrix.xBucketSize = Number.MIN_SAFE_INTEGER;
|
||||||
|
targetKeys.map(function (target) {
|
||||||
|
var bucketsLen = bucketMatrix.buckets[target].length;
|
||||||
|
|
||||||
|
if (bucketsLen > bucketMatrix.xBucketSize) {
|
||||||
|
bucketMatrix.xBucketSize = bucketsLen;
|
||||||
|
}
|
||||||
|
}); //console.log ("bucketMatrix with values: ", bucketMatrix);
|
||||||
|
|
||||||
|
bucketMatrix.targets = targetKeys;
|
||||||
|
return bucketMatrix;
|
||||||
|
this.bucketMatrix = bucketMatrix; // Collect all values for each bucket from datapoints with similar target.
|
||||||
|
// TODO aggregate values into buckets over datapoint[TIME_INDEX] not over datapoint index (j).
|
||||||
|
// for(let i = 0; i < cardsData.targets.length; i++) {
|
||||||
|
// let target = cardsData.targets[i];
|
||||||
|
// for (let j = 0; j < cardsData.xBucketSize; j++) {
|
||||||
|
// let card = new Card();
|
||||||
|
// card.id = i*cardsData.xBucketSize + j;
|
||||||
|
// card.values = [];
|
||||||
|
// card.y = target;
|
||||||
|
// card.x = -1;
|
||||||
|
// // collect values from all timeseries with target
|
||||||
|
// for (let si = 0; si < cardsData.targetIndex[target].length; si++) {
|
||||||
|
// let s = data[cardsData.targetIndex[target][si]];
|
||||||
|
// if (s.datapoints.length <= j) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// let datapoint = s.datapoints[j];
|
||||||
|
// if (card.values.length === 0) {
|
||||||
|
// card.x = datapoint[TIME_INDEX];
|
||||||
|
// }
|
||||||
|
// card.values.push(datapoint[VALUE_INDEX]);
|
||||||
|
// }
|
||||||
|
// card.minValue = _.min(card.values);
|
||||||
|
// card.maxValue = _.max(card.values);
|
||||||
|
// if (card.values.length > 1) {
|
||||||
|
// cardsData.multipleValues = true;
|
||||||
|
// card.multipleValues = true;
|
||||||
|
// card.value = card.maxValue; // max value by default
|
||||||
|
// } else {
|
||||||
|
// card.value = card.maxValue; // max value by default
|
||||||
|
// }
|
||||||
|
// if (cardsData.maxValue < card.maxValue)
|
||||||
|
// cardsData.maxValue = card.maxValue;
|
||||||
|
// if (cardsData.minValue > card.minValue)
|
||||||
|
// cardsData.minValue = card.minValue;
|
||||||
|
// if (card.x != -1) {
|
||||||
|
// cardsData.cards.push(card);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// let cardsData = <CardsStorage> {
|
||||||
|
// cards: [],
|
||||||
|
// xBucketSize: 0,
|
||||||
|
// yBucketSize: 0,
|
||||||
|
// maxValue: 0,
|
||||||
|
// minValue: 0,
|
||||||
|
// multipleValues: false,
|
||||||
|
// noColorDefined: false,
|
||||||
|
// targets: [], // array of available unique targets
|
||||||
|
// targetIndex: {} // indices in data array for each of available unique targets
|
||||||
|
// };
|
||||||
|
// if (!data || data.length == 0) { return cardsData;}
|
||||||
|
// // Collect uniq timestamps from data and spread over targets and timestamps
|
||||||
|
// // collect uniq targets and their indices
|
||||||
|
// _.map(data, (d, i) => {
|
||||||
|
// cardsData.targetIndex[d.target] = _.concat(_.toArray(cardsData.targetIndex[d.target]), i)
|
||||||
|
// });
|
||||||
|
// // TODO add some logic for targets heirarchy
|
||||||
|
// cardsData.targets = _.keys(cardsData.targetIndex);
|
||||||
|
// cardsData.yBucketSize = cardsData.targets.length;
|
||||||
|
// // Maximum number of buckets over x axis
|
||||||
|
// cardsData.xBucketSize = _.max(_.map(data, d => d.datapoints.length));
|
||||||
|
// // Collect all values for each bucket from datapoints with similar target.
|
||||||
|
// // TODO aggregate values into buckets over datapoint[TIME_INDEX] not over datapoint index (j).
|
||||||
|
// for(let i = 0; i < cardsData.targets.length; i++) {
|
||||||
|
// let target = cardsData.targets[i];
|
||||||
|
// for (let j = 0; j < cardsData.xBucketSize; j++) {
|
||||||
|
// let card = new Card();
|
||||||
|
// card.id = i*cardsData.xBucketSize + j;
|
||||||
|
// card.values = [];
|
||||||
|
// card.y = target;
|
||||||
|
// card.x = -1;
|
||||||
|
// // collect values from all timeseries with target
|
||||||
|
// for (let si = 0; si < cardsData.targetIndex[target].length; si++) {
|
||||||
|
// let s = data[cardsData.targetIndex[target][si]];
|
||||||
|
// if (s.datapoints.length <= j) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// let datapoint = s.datapoints[j];
|
||||||
|
// if (card.values.length === 0) {
|
||||||
|
// card.x = datapoint[TIME_INDEX];
|
||||||
|
// }
|
||||||
|
// card.values.push(datapoint[VALUE_INDEX]);
|
||||||
|
// }
|
||||||
|
// card.minValue = _.min(card.values);
|
||||||
|
// card.maxValue = _.max(card.values);
|
||||||
|
// if (card.values.length > 1) {
|
||||||
|
// cardsData.multipleValues = true;
|
||||||
|
// card.multipleValues = true;
|
||||||
|
// card.value = card.maxValue; // max value by default
|
||||||
|
// } else {
|
||||||
|
// card.value = card.maxValue; // max value by default
|
||||||
|
// }
|
||||||
|
// if (cardsData.maxValue < card.maxValue)
|
||||||
|
// cardsData.maxValue = card.maxValue;
|
||||||
|
// if (cardsData.minValue > card.minValue)
|
||||||
|
// cardsData.minValue = card.minValue;
|
||||||
|
// if (card.x != -1) {
|
||||||
|
// cardsData.cards.push(card);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return cardsData;
|
||||||
}
|
}
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+30
-12
@@ -148,8 +148,30 @@
|
|||||||
label="Show tooltip"
|
label="Show tooltip"
|
||||||
checked="ctrl.panel.tooltip.show" on-change="ctrl.render()">
|
checked="ctrl.panel.tooltip.show" on-change="ctrl.render()">
|
||||||
</gf-form-switch>
|
</gf-form-switch>
|
||||||
<div class="gf-form">
|
<gf-form-switch class="gf-form" label-class="width-8"
|
||||||
<label class="gf-form-label width-8">Y axis sort</label>
|
label="Show X axis"
|
||||||
|
checked="ctrl.panel.xAxis.show" on-change="ctrl.render()">
|
||||||
|
</gf-form-switch>
|
||||||
|
<gf-form-switch class="gf-form" label-class="width-8"
|
||||||
|
label="Show Y axis"
|
||||||
|
checked="ctrl.panel.yAxis.show" on-change="ctrl.render()">
|
||||||
|
</gf-form-switch>
|
||||||
|
|
||||||
|
<div class="gf-form" ng-show="ctrl.panel.yAxis.show">
|
||||||
|
<label class="gf-form-label width-8">Min width</label>
|
||||||
|
<input type="number" ng-model="ctrl.panel.xAxis.minWidth" class="gf-form-input width-5" placeholder="auto" data-placement="right" bs-tooltip="''" ng-change="ctrl.render()" ng-model-onblur>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form" ng-show="ctrl.panel.yAxis.show">
|
||||||
|
<label class="gf-form-label width-8">Max width</label>
|
||||||
|
<input type="number" ng-model="ctrl.panel.xAxis.maxWidth" class="gf-form-input width-5" placeholder="auto" data-placement="right" bs-tooltip="''" ng-change="ctrl.render()" ng-model-onblur>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section gf-form-group">
|
||||||
|
<h5 class="section-heading">Buckets</h5>
|
||||||
|
|
||||||
|
<div class="gf-form" ng-show="ctrl.panel.yAxis.show">
|
||||||
|
<label class="gf-form-label width-8">Rows sort</label>
|
||||||
<div class="gf-form-select-wrapper">
|
<div class="gf-form-select-wrapper">
|
||||||
<select class="gf-form-input max-width-8"
|
<select class="gf-form-input max-width-8"
|
||||||
ng-model="ctrl.panel.yAxisSort"
|
ng-model="ctrl.panel.yAxisSort"
|
||||||
@@ -157,12 +179,8 @@
|
|||||||
ng-change="ctrl.render()"></select>
|
ng-change="ctrl.render()"></select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="section gf-form-group">
|
<gf-form-switch class="gf-form" label-class="width-8"
|
||||||
<h5 class="section-heading">Bucket</h5>
|
|
||||||
|
|
||||||
<gf-form-switch class="gf-form" label-class="width-9"
|
|
||||||
label="Multiple values"
|
label="Multiple values"
|
||||||
checked="ctrl.panel.useMax" on-change="ctrl.render()">
|
checked="ctrl.panel.useMax" on-change="ctrl.render()">
|
||||||
</gf-form-switch>
|
</gf-form-switch>
|
||||||
@@ -171,25 +189,25 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-9">Display nulls</label>
|
<label class="gf-form-label width-8">Display nulls</label>
|
||||||
<div class="gf-form-select-wrapper">
|
<div class="gf-form-select-wrapper">
|
||||||
<select class="gf-form-input max-width-9" ng-model="ctrl.panel.nullPointMode" ng-options="f for f in ['as empty', 'as zero']" ng-change="ctrl.render()"></select>
|
<select class="gf-form-input max-width-9" ng-model="ctrl.panel.nullPointMode" ng-options="f for f in ['as empty', 'as zero']" ng-change="ctrl.render()"></select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-9">Min width for 1/1</label>
|
<label class="gf-form-label width-8">Min width</label>
|
||||||
<input type="number" class="gf-form-input width-5" placeholder="5" data-placement="right" bs-tooltip="'Minimal card width for 1/1 resolution in pixels'" ng-model="ctrl.panel.cards.cardMinWidth" ng-change="ctrl.refresh()" ng-model-onblur>
|
<input type="number" class="gf-form-input width-5" placeholder="5" data-placement="right" bs-tooltip="'Minimal card width for 1/1 resolution in pixels'" ng-model="ctrl.panel.cards.cardMinWidth" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-9">V spacing</label>
|
<label class="gf-form-label width-8">V spacing</label>
|
||||||
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Cards vertical spacing in pixels'" ng-model="ctrl.panel.cards.cardVSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
|
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Cards vertical spacing in pixels'" ng-model="ctrl.panel.cards.cardVSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-9">H spacing</label>
|
<label class="gf-form-label width-8">H spacing</label>
|
||||||
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Cards horizontal spacing in pixels'" ng-model="ctrl.panel.cards.cardHSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
|
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Cards horizontal spacing in pixels'" ng-model="ctrl.panel.cards.cardHSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-9">Rounding</label>
|
<label class="gf-form-label width-8">Rounding</label>
|
||||||
<input type="number" class="gf-form-input width-5" placeholder="0" data-placement="right" bs-tooltip="'Cards rounding radius in pixels'" ng-model="ctrl.panel.cards.cardRound" ng-change="ctrl.refresh()" ng-model-onblur>
|
<input type="number" class="gf-form-input width-5" placeholder="0" data-placement="right" bs-tooltip="'Cards rounding radius in pixels'" ng-model="ctrl.panel.cards.cardRound" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Vendored
+87
-58
@@ -3,14 +3,14 @@
|
|||||||
System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/core", "d3", "./libs/d3-scale-chromatic/index", "./tooltip", "./tooltipextraseries", "./annotations"], function (_export, _context) {
|
System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/core", "d3", "./libs/d3-scale-chromatic/index", "./tooltip", "./tooltipextraseries", "./annotations"], function (_export, _context) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var _, $, moment, kbn, appEvents, contextSrv, d3, d3ScaleChromatic, StatusmapTooltip, StatusHeatmapTooltipExtraSeries, AnnotationTooltip, MIN_CARD_SIZE, CARD_H_SPACING, CARD_V_SPACING, CARD_ROUND, DATA_RANGE_WIDING_FACTOR, DEFAULT_X_TICK_SIZE_PX, DEFAULT_Y_TICK_SIZE_PX, X_AXIS_TICK_PADDING, Y_AXIS_TICK_PADDING, MIN_SELECTION_WIDTH, StatusmapRenderer;
|
var _, $, moment, kbn, appEvents, contextSrv, d3, d3ScaleChromatic, StatusmapTooltip, StatusHeatmapTooltipExtraSeries, AnnotationTooltip, MIN_CARD_SIZE, CARD_H_SPACING, CARD_V_SPACING, CARD_ROUND, DATA_RANGE_WIDING_FACTOR, DEFAULT_X_TICK_SIZE_PX, DEFAULT_Y_TICK_SIZE_PX, X_AXIS_TICK_PADDING, Y_AXIS_TICK_PADDING, MIN_SELECTION_WIDTH, Statusmap, StatusmapRenderer;
|
||||||
|
|
||||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
||||||
|
|
||||||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
||||||
|
|
||||||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||||
|
|
||||||
function rendering(scope, elem, attrs, ctrl) {
|
function rendering(scope, elem, attrs, ctrl) {
|
||||||
@@ -83,6 +83,21 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
Y_AXIS_TICK_PADDING = 5;
|
Y_AXIS_TICK_PADDING = 5;
|
||||||
MIN_SELECTION_WIDTH = 2;
|
MIN_SELECTION_WIDTH = 2;
|
||||||
|
|
||||||
|
Statusmap = function Statusmap() {
|
||||||
|
_classCallCheck(this, Statusmap);
|
||||||
|
|
||||||
|
_defineProperty(this, "$svg", void 0);
|
||||||
|
|
||||||
|
_defineProperty(this, "svg", void 0);
|
||||||
|
|
||||||
|
_defineProperty(this, "bucketMatrix", void 0);
|
||||||
|
|
||||||
|
_defineProperty(this, "timeRange", {
|
||||||
|
from: 0,
|
||||||
|
to: 0
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
_export("StatusmapRenderer", StatusmapRenderer =
|
_export("StatusmapRenderer", StatusmapRenderer =
|
||||||
/*#__PURE__*/
|
/*#__PURE__*/
|
||||||
function () {
|
function () {
|
||||||
@@ -133,9 +148,7 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
|
|
||||||
_defineProperty(this, "yGridSize", 0);
|
_defineProperty(this, "yGridSize", 0);
|
||||||
|
|
||||||
_defineProperty(this, "data", void 0);
|
_defineProperty(this, "bucketMatrix", void 0);
|
||||||
|
|
||||||
_defineProperty(this, "cardsData", void 0);
|
|
||||||
|
|
||||||
_defineProperty(this, "panel", void 0);
|
_defineProperty(this, "panel", void 0);
|
||||||
|
|
||||||
@@ -162,7 +175,7 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
_defineProperty(this, "dataRangeWidingFactor", DATA_RANGE_WIDING_FACTOR);
|
_defineProperty(this, "dataRangeWidingFactor", DATA_RANGE_WIDING_FACTOR);
|
||||||
|
|
||||||
// $heatmap is JQuery object, but heatmap is D3
|
// $heatmap is JQuery object, but heatmap is D3
|
||||||
this.$heatmap = this.elem.find('.status-heatmap-panel');
|
this.$heatmap = this.elem.find('.statusmap-panel');
|
||||||
this.tooltip = new StatusmapTooltip(this.$heatmap, this.scope);
|
this.tooltip = new StatusmapTooltip(this.$heatmap, this.scope);
|
||||||
this.tooltipExtraSeries = new StatusHeatmapTooltipExtraSeries(this.$heatmap, this.scope);
|
this.tooltipExtraSeries = new StatusHeatmapTooltipExtraSeries(this.$heatmap, this.scope);
|
||||||
this.annotationTooltip = new AnnotationTooltip(this.$heatmap, this.scope);
|
this.annotationTooltip = new AnnotationTooltip(this.$heatmap, this.scope);
|
||||||
@@ -188,7 +201,7 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
this.ctrl.tickValueFormatter = this.tickValueFormatter.bind(this); /////////////////////////////
|
this.ctrl.tickValueFormatter = this.tickValueFormatter.bind(this); /////////////////////////////
|
||||||
// Selection and crosshair //
|
// Selection and crosshair //
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
// Shared crosshair and tooltip
|
// Shared crosshair and tooltip this.empty = true;
|
||||||
|
|
||||||
appEvents.on('graph-hover', this.onGraphHover.bind(this), this.scope);
|
appEvents.on('graph-hover', this.onGraphHover.bind(this), this.scope);
|
||||||
appEvents.on('graph-hover-clear', this.onGraphHoverClear.bind(this), this.scope); // Register selection listeners
|
appEvents.on('graph-hover-clear', this.onGraphHoverClear.bind(this), this.scope); // Register selection listeners
|
||||||
@@ -264,6 +277,10 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
key: "addXAxis",
|
key: "addXAxis",
|
||||||
value: function addXAxis() {
|
value: function addXAxis() {
|
||||||
// Scale timestamps to cards centers
|
// Scale timestamps to cards centers
|
||||||
|
//this.scope.xScale = this.xScale = d3.scaleTime()
|
||||||
|
// .domain([this.timeRange.from, this.timeRange.to])
|
||||||
|
// .range([this.xGridSize/2, this.chartWidth-this.xGridSize/2]);
|
||||||
|
// Buckets without the most recent
|
||||||
this.scope.xScale = this.xScale = d3.scaleTime().domain([this.timeRange.from, this.timeRange.to]).range([this.xGridSize / 2, this.chartWidth - this.xGridSize / 2]);
|
this.scope.xScale = this.xScale = d3.scaleTime().domain([this.timeRange.from, this.timeRange.to]).range([this.xGridSize / 2, this.chartWidth - this.xGridSize / 2]);
|
||||||
var ticks = this.chartWidth / DEFAULT_X_TICK_SIZE_PX;
|
var ticks = this.chartWidth / DEFAULT_X_TICK_SIZE_PX;
|
||||||
var grafanaTimeFormatter = grafanaTimeFormat(ticks, this.timeRange.from, this.timeRange.to);
|
var grafanaTimeFormatter = grafanaTimeFormat(ticks, this.timeRange.from, this.timeRange.to);
|
||||||
@@ -317,14 +334,7 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
}, {
|
}, {
|
||||||
key: "addYAxis",
|
key: "addYAxis",
|
||||||
value: function addYAxis() {
|
value: function addYAxis() {
|
||||||
var ticks = _.uniq(_.map(this.data, function (d) {
|
var ticks = this.bucketMatrix.targets;
|
||||||
return d.target;
|
|
||||||
})); // Set default Y min and max if no data
|
|
||||||
|
|
||||||
|
|
||||||
if (_.isEmpty(this.data)) {
|
|
||||||
ticks = [''];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.panel.yAxisSort == 'a → z') {
|
if (this.panel.yAxisSort == 'a → z') {
|
||||||
ticks.sort(function (a, b) {
|
ticks.sort(function (a, b) {
|
||||||
@@ -392,8 +402,8 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
// calculate sizes for cards drawing
|
// calculate sizes for cards drawing
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
key: "addHeatmapCanvas",
|
key: "addStatusmapCanvas",
|
||||||
value: function addHeatmapCanvas() {
|
value: function addStatusmapCanvas() {
|
||||||
var heatmap_elem = this.$heatmap[0];
|
var heatmap_elem = this.$heatmap[0];
|
||||||
this.width = Math.floor(this.$heatmap.width()) - this.padding.right;
|
this.width = Math.floor(this.$heatmap.width()) - this.padding.right;
|
||||||
this.height = Math.floor(this.$heatmap.height()) - this.padding.bottom;
|
this.height = Math.floor(this.$heatmap.height()) - this.padding.bottom;
|
||||||
@@ -410,7 +420,12 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
this.cardVSpacing = this.panel.cards.cardVSpacing !== null ? this.panel.cards.cardVSpacing : CARD_V_SPACING;
|
this.cardVSpacing = this.panel.cards.cardVSpacing !== null ? this.panel.cards.cardVSpacing : CARD_V_SPACING;
|
||||||
this.cardRound = this.panel.cards.cardRound !== null ? this.panel.cards.cardRound : CARD_ROUND; // calculate yOffset for YAxis
|
this.cardRound = this.panel.cards.cardRound !== null ? this.panel.cards.cardRound : CARD_ROUND; // calculate yOffset for YAxis
|
||||||
|
|
||||||
this.yGridSize = Math.floor(this.chartHeight / this.cardsData.yBucketSize);
|
this.yGridSize = this.chartHeight;
|
||||||
|
|
||||||
|
if (this.bucketMatrix.targets.length > 0) {
|
||||||
|
this.yGridSize = Math.floor(this.chartHeight / this.bucketMatrix.targets.length);
|
||||||
|
}
|
||||||
|
|
||||||
this.cardHeight = this.yGridSize ? this.yGridSize - this.cardVSpacing : 0;
|
this.cardHeight = this.yGridSize ? this.yGridSize - this.cardVSpacing : 0;
|
||||||
this.yOffset = this.cardHeight / 2;
|
this.yOffset = this.cardHeight / 2;
|
||||||
this.addYAxis();
|
this.addYAxis();
|
||||||
@@ -418,7 +433,7 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
this.chartWidth = this.width - this.yAxisWidth - this.margin.right; // TODO allow per-y cardWidth!
|
this.chartWidth = this.width - this.yAxisWidth - this.margin.right; // TODO allow per-y cardWidth!
|
||||||
// we need to fill chartWidth with xBucketSize cards.
|
// we need to fill chartWidth with xBucketSize cards.
|
||||||
|
|
||||||
this.xGridSize = this.chartWidth / (this.cardsData.xBucketSize + 1);
|
this.xGridSize = this.chartWidth / (this.bucketMatrix.xBucketSize + 1);
|
||||||
this.cardWidth = this.xGridSize - this.cardHSpacing;
|
this.cardWidth = this.xGridSize - this.cardHSpacing;
|
||||||
this.addXAxis();
|
this.addXAxis();
|
||||||
this.xAxisHeight = this.getXAxisHeight(this.heatmap);
|
this.xAxisHeight = this.getXAxisHeight(this.heatmap);
|
||||||
@@ -432,27 +447,34 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "addHeatmap",
|
key: "addStatusmap",
|
||||||
value: function addHeatmap() {
|
value: function addStatusmap() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
|
||||||
this.addHeatmapCanvas();
|
var maxValue = this.panel.color.max || this.bucketMatrix.maxValue;
|
||||||
var maxValue = this.panel.color.max || this.cardsData.maxValue;
|
var minValue = this.panel.color.min || this.bucketMatrix.minValue;
|
||||||
var minValue = this.panel.color.min || this.cardsData.minValue;
|
|
||||||
|
|
||||||
if (this.panel.color.mode !== 'discrete') {
|
if (this.panel.color.mode !== 'discrete') {
|
||||||
this.colorScale = this.getColorScale(maxValue, minValue);
|
this.colorScale = this.getColorScale(maxValue, minValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setOpacityScale(maxValue);
|
this.setOpacityScale(maxValue); // Draw cards from buckets.
|
||||||
var cards = this.heatmap.selectAll(".status-heatmap-card").data(this.cardsData.cards);
|
|
||||||
cards.append("title");
|
this.heatmap.selectAll(".statusmap-cards-row").data(this.bucketMatrix.targets).enter().selectAll(".statustmap-card").data(function (target) {
|
||||||
cards = cards.enter().append("rect").attr("cardId", function (c) {
|
return _this.bucketMatrix.buckets[target];
|
||||||
return c.id;
|
}).enter().append("rect").attr("cardId", function (b) {
|
||||||
}).attr("x", this.getCardX.bind(this)).attr("width", this.getCardWidth.bind(this)).attr("y", this.getCardY.bind(this)).attr("height", this.getCardHeight.bind(this)).attr("rx", this.cardRound).attr("ry", this.cardRound).attr("class", "bordered status-heatmap-card").style("fill", this.getCardColor.bind(this)).style("stroke", this.getCardColor.bind(this)).style("stroke-width", 0) //.style("stroke-width", getCardStrokeWidth)
|
return b.id;
|
||||||
|
}).attr("xid", function (b) {
|
||||||
|
return b.xid;
|
||||||
|
}).attr("yid", function (b) {
|
||||||
|
return b.yLabel;
|
||||||
|
}).attr("x", this.getCardX.bind(this)).attr("width", this.getCardWidth.bind(this)).attr("y", this.getCardY.bind(this)).attr("height", this.getCardHeight.bind(this)).attr("rx", this.cardRound).attr("ry", this.cardRound).attr("class", function (b) {
|
||||||
|
return b.isEmpty() ? "empty-card" : "bordered statusmap-card";
|
||||||
|
}).style("fill", this.getCardColor.bind(this)).style("stroke", this.getCardColor.bind(this)).style("stroke-width", 0) //.style("stroke-width", getCardStrokeWidth)
|
||||||
//.style("stroke-dasharray", "3,3")
|
//.style("stroke-dasharray", "3,3")
|
||||||
.style("opacity", this.getCardOpacity.bind(this));
|
.style("opacity", this.getCardOpacity.bind(this)); // Set mouse events on cards.
|
||||||
var $cards = this.$heatmap.find(".status-heatmap-card");
|
|
||||||
|
var $cards = this.$heatmap.find(".statusmap-card + .bordered");
|
||||||
$cards.on("mouseenter", function (event) {
|
$cards.on("mouseenter", function (event) {
|
||||||
_this.tooltip.mouseOverBucket = true;
|
_this.tooltip.mouseOverBucket = true;
|
||||||
|
|
||||||
@@ -514,10 +536,12 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "getCardX",
|
key: "getCardX",
|
||||||
value: function getCardX(d) {
|
value: function getCardX(b) {
|
||||||
var x; // cx is the center of the card. Card should be placed to the left.
|
var x; // cx is the center of the card. Card should be placed to the left.
|
||||||
|
//let cx = this.xScale(d.x);
|
||||||
|
|
||||||
var cx = this.xScale(d.x);
|
var rightX = b.relTo / this.bucketMatrix.rangeMs * this.chartWidth;
|
||||||
|
var cx = rightX - this.cardWidth / 2;
|
||||||
|
|
||||||
if (cx - this.cardWidth / 2 < 0) {
|
if (cx - this.cardWidth / 2 < 0) {
|
||||||
x = this.yAxisWidth + this.cardHSpacing / 2;
|
x = this.yAxisWidth + this.cardHSpacing / 2;
|
||||||
@@ -530,9 +554,11 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
|
|
||||||
}, {
|
}, {
|
||||||
key: "getCardWidth",
|
key: "getCardWidth",
|
||||||
value: function getCardWidth(d) {
|
value: function getCardWidth(b) {
|
||||||
|
//return 20;
|
||||||
var w;
|
var w;
|
||||||
var cx = this.xScale(d.x);
|
var rightX = b.relTo / this.bucketMatrix.rangeMs * this.chartWidth;
|
||||||
|
var cx = rightX - this.cardWidth / 2; //let cx = this.xScale(d.x);
|
||||||
|
|
||||||
if (cx < this.cardWidth / 2) {
|
if (cx < this.cardWidth / 2) {
|
||||||
// Center should not exceed half of card.
|
// Center should not exceed half of card.
|
||||||
@@ -554,16 +580,20 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
}
|
}
|
||||||
|
|
||||||
return w;
|
return w;
|
||||||
}
|
} // Top y for card.
|
||||||
|
// yScale gives ???
|
||||||
|
//
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
key: "getCardY",
|
key: "getCardY",
|
||||||
value: function getCardY(d) {
|
value: function getCardY(b) {
|
||||||
return this.yScale(d.y) + this.chartTop - this.cardHeight - this.cardVSpacing / 2;
|
return this.yScale(b.yLabel) + this.chartTop - this.cardHeight - this.cardVSpacing / 2;
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "getCardHeight",
|
key: "getCardHeight",
|
||||||
value: function getCardHeight(d) {
|
value: function getCardHeight(b) {
|
||||||
var ys = this.yScale(d.y);
|
//return 20;
|
||||||
|
var ys = this.yScale(b.yLabel);
|
||||||
var y = ys + this.chartTop - this.cardHeight - this.cardVSpacing / 2;
|
var y = ys + this.chartTop - this.cardHeight - this.cardVSpacing / 2;
|
||||||
var h = this.cardHeight; // Cut card height to prevent overlay
|
var h = this.cardHeight; // Cut card height to prevent overlay
|
||||||
|
|
||||||
@@ -588,35 +618,35 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "getCardColor",
|
key: "getCardColor",
|
||||||
value: function getCardColor(d) {
|
value: function getCardColor(b) {
|
||||||
if (this.panel.color.mode === 'opacity') {
|
if (this.panel.color.mode === 'opacity') {
|
||||||
return this.panel.color.cardColor;
|
return this.panel.color.cardColor;
|
||||||
} else if (this.panel.color.mode === 'spectrum') {
|
} else if (this.panel.color.mode === 'spectrum') {
|
||||||
return this.colorScale(d.value);
|
return this.colorScale(b.value);
|
||||||
} else if (this.panel.color.mode === 'discrete') {
|
} else if (this.panel.color.mode === 'discrete') {
|
||||||
if (this.panel.seriesFilterIndex != -1 || this.panel.seriesFilterIndex != null) {
|
if (this.panel.seriesFilterIndex != -1 || this.panel.seriesFilterIndex != null) {
|
||||||
return this.ctrl.discreteExtraSeries.getBucketColorSingle(d.values[this.panel.seriesFilterIndex]);
|
return this.ctrl.discreteExtraSeries.getBucketColorSingle(b.values[this.panel.seriesFilterIndex]);
|
||||||
} else {
|
} else {
|
||||||
return this.ctrl.discreteExtraSeries.getBucketColor(d.values);
|
return this.ctrl.discreteExtraSeries.getBucketColor(b.values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "getCardOpacity",
|
key: "getCardOpacity",
|
||||||
value: function getCardOpacity(d) {
|
value: function getCardOpacity(b) {
|
||||||
if (this.panel.nullPointMode === 'as empty' && d.value == null) {
|
if (this.panel.nullPointMode === 'as empty' && b.value == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.panel.color.mode === 'opacity') {
|
if (this.panel.color.mode === 'opacity') {
|
||||||
return this.opacityScale(d.value);
|
return this.opacityScale(b.value);
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: "getCardStrokeWidth",
|
key: "getCardStrokeWidth",
|
||||||
value: function getCardStrokeWidth(d) {
|
value: function getCardStrokeWidth(b) {
|
||||||
if (this.panel.color.mode === 'discrete') {
|
if (this.panel.color.mode === 'discrete') {
|
||||||
return '1';
|
return '1';
|
||||||
}
|
}
|
||||||
@@ -705,8 +735,7 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
//const pos = this.getEventPos(event, offset);
|
//const pos = this.getEventPos(event, offset);
|
||||||
this.emitGraphHoverEvent(event);
|
this.emitGraphHoverEvent(event);
|
||||||
this.drawCrosshair(offset.x);
|
this.drawCrosshair(offset.x);
|
||||||
this.tooltip.show(event); //, data); // pos, this.data
|
this.tooltip.show(event);
|
||||||
|
|
||||||
this.annotationTooltip.show(event);
|
this.annotationTooltip.show(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -818,22 +847,22 @@ System.register(["lodash", "jquery", "moment", "app/core/utils/kbn", "app/core/c
|
|||||||
}, {
|
}, {
|
||||||
key: "render",
|
key: "render",
|
||||||
value: function render() {
|
value: function render() {
|
||||||
this.data = this.ctrl.data;
|
|
||||||
this.panel = this.ctrl.panel;
|
this.panel = this.ctrl.panel;
|
||||||
this.timeRange = this.ctrl.range;
|
this.timeRange = this.ctrl.range;
|
||||||
this.cardsData = this.ctrl.cardsData;
|
this.bucketMatrix = this.ctrl.bucketMatrix;
|
||||||
|
|
||||||
if (!this.data || !this.cardsData || !this.setElementHeight()) {
|
if (!this.bucketMatrix || !this.setElementHeight()) {
|
||||||
return;
|
return;
|
||||||
} // Draw default axes and return if no data
|
} // Draw default axes and return if no data
|
||||||
|
|
||||||
|
|
||||||
if (_.isEmpty(this.cardsData.cards)) {
|
this.addStatusmapCanvas();
|
||||||
this.addHeatmapCanvas();
|
|
||||||
|
if (this.bucketMatrix.noDatapoints) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addHeatmap();
|
this.addStatusmap();
|
||||||
this.scope.yAxisWidth = this.yAxisWidth;
|
this.scope.yAxisWidth = this.yAxisWidth;
|
||||||
this.scope.xAxisHeight = this.xAxisHeight;
|
this.scope.xAxisHeight = this.xAxisHeight;
|
||||||
this.scope.chartHeight = this.chartHeight;
|
this.scope.chartHeight = this.chartHeight;
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+123
-36
@@ -3,71 +3,158 @@
|
|||||||
System.register([], function (_export, _context) {
|
System.register([], function (_export, _context) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var Card, CardsStorage;
|
var Bucket, BucketMatrix;
|
||||||
|
|
||||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
||||||
|
|
||||||
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
||||||
|
|
||||||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setters: [],
|
setters: [],
|
||||||
execute: function () {
|
execute: function () {
|
||||||
// A holder of values
|
// A holder of a group of values
|
||||||
_export("Card", Card = // uniq
|
_export("Bucket", Bucket =
|
||||||
// Array of values in this bucket
|
/*#__PURE__*/
|
||||||
// card has multiple values
|
function () {
|
||||||
// card has values that has no color
|
// uniq id
|
||||||
//
|
// Array of values in this bucket
|
||||||
//
|
// From pr/86
|
||||||
//
|
// a bucket has multiple values
|
||||||
function Card() {
|
// a bucket has values that has no mapped color
|
||||||
_classCallCheck(this, Card);
|
// y label
|
||||||
|
// This value can be used to calculate a x coordinate on a graph
|
||||||
|
// a time range of this bucket
|
||||||
|
// to and from relative to real "from"
|
||||||
|
// Saved minimum and maximum of values in this bucket
|
||||||
|
// A value if multiple values is not allowed
|
||||||
|
function Bucket() {
|
||||||
|
_classCallCheck(this, Bucket);
|
||||||
|
|
||||||
_defineProperty(this, "id", 0);
|
_defineProperty(this, "id", 0);
|
||||||
|
|
||||||
_defineProperty(this, "values", []);
|
_defineProperty(this, "values", []);
|
||||||
|
|
||||||
_defineProperty(this, "columns", []);
|
_defineProperty(this, "columns", []);
|
||||||
|
|
||||||
_defineProperty(this, "multipleValues", false);
|
_defineProperty(this, "multipleValues", false);
|
||||||
|
|
||||||
_defineProperty(this, "noColorDefined", false);
|
_defineProperty(this, "noColorDefined", false);
|
||||||
|
|
||||||
_defineProperty(this, "y", "");
|
_defineProperty(this, "y", "");
|
||||||
|
|
||||||
_defineProperty(this, "x", 0);
|
_defineProperty(this, "yLabel", "");
|
||||||
|
|
||||||
_defineProperty(this, "minValue", 0);
|
_defineProperty(this, "x", 0);
|
||||||
|
|
||||||
_defineProperty(this, "maxValue", 0);
|
_defineProperty(this, "xid", 0);
|
||||||
|
|
||||||
_defineProperty(this, "value", 0);
|
_defineProperty(this, "from", 0);
|
||||||
});
|
|
||||||
|
|
||||||
_export("CardsStorage", CardsStorage = function CardsStorage() {
|
_defineProperty(this, "to", 0);
|
||||||
_classCallCheck(this, CardsStorage);
|
|
||||||
|
|
||||||
_defineProperty(this, "cards", []);
|
_defineProperty(this, "relFrom", 0);
|
||||||
|
|
||||||
_defineProperty(this, "xBucketSize", 0);
|
_defineProperty(this, "relTo", 0);
|
||||||
|
|
||||||
_defineProperty(this, "yBucketSize", 0);
|
_defineProperty(this, "mostRecent", false);
|
||||||
|
|
||||||
_defineProperty(this, "maxValue", void 0);
|
_defineProperty(this, "minValue", 0);
|
||||||
|
|
||||||
_defineProperty(this, "minValue", void 0);
|
_defineProperty(this, "maxValue", 0);
|
||||||
|
|
||||||
_defineProperty(this, "multipleValues", false);
|
_defineProperty(this, "value", 0);
|
||||||
|
}
|
||||||
|
|
||||||
_defineProperty(this, "noColorDefined", false);
|
_createClass(Bucket, [{
|
||||||
|
key: "belong",
|
||||||
|
value: function belong(ts) {
|
||||||
|
return ts >= this.from && ts <= this.to;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "put",
|
||||||
|
value: function put(value) {
|
||||||
|
this.values.push(value);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "done",
|
||||||
|
value: function done() {// calculate min, max, value
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "isEmpty",
|
||||||
|
value: function isEmpty() {
|
||||||
|
return this.values.length == 0;
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
_defineProperty(this, "targets", []);
|
return Bucket;
|
||||||
|
}());
|
||||||
|
|
||||||
_defineProperty(this, "targetIndex", void 0);
|
_export("BucketMatrix", BucketMatrix =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function () {
|
||||||
|
// buckets for each y label
|
||||||
|
// a flag that indicate that buckets has stub values
|
||||||
|
// TODO remove: a transition from CardsData
|
||||||
|
function BucketMatrix() {
|
||||||
|
_classCallCheck(this, BucketMatrix);
|
||||||
|
|
||||||
this.maxValue = 0;
|
_defineProperty(this, "buckets", {});
|
||||||
this.minValue = 0;
|
|
||||||
});
|
_defineProperty(this, "maxValue", 0);
|
||||||
|
|
||||||
|
_defineProperty(this, "minValue", 0);
|
||||||
|
|
||||||
|
_defineProperty(this, "multipleValues", false);
|
||||||
|
|
||||||
|
_defineProperty(this, "noColorDefined", false);
|
||||||
|
|
||||||
|
_defineProperty(this, "noDatapoints", false);
|
||||||
|
|
||||||
|
_defineProperty(this, "targets", []);
|
||||||
|
|
||||||
|
_defineProperty(this, "rangeMs", 0);
|
||||||
|
|
||||||
|
_defineProperty(this, "intervalMs", 0);
|
||||||
|
|
||||||
|
_defineProperty(this, "xBucketSize", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_createClass(BucketMatrix, [{
|
||||||
|
key: "get",
|
||||||
|
value: function get(yid, xid) {
|
||||||
|
if (yid in this.buckets) {
|
||||||
|
if (xid in this.buckets[yid]) {
|
||||||
|
return this.buckets[yid][xid];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Bucket();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: "hasData",
|
||||||
|
value: function hasData() {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
var hasData = false;
|
||||||
|
|
||||||
|
if (this.targets.length > 0) {
|
||||||
|
this.targets.map(function (target) {
|
||||||
|
if (_this.buckets[target].length > 0) {
|
||||||
|
hasData = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasData;
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return BucketMatrix;
|
||||||
|
}());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1 +1 @@
|
|||||||
{"version":3,"sources":["../src/statusmap_data.ts"],"names":["Card","CardsStorage","maxValue","minValue"],"mappings":";;;;;;;;;;;;;;AAEA;sBACMA,I,GACF;AAEA;AAGA;AAEA;AAEA;AAEA;AAEA;AAKA,sBAAc;AAAA;;AAAA,oCAjBD,CAiBC;;AAAA,wCAfE,EAeF;;AAAA,yCAdG,EAcH;;AAAA,gDAZY,KAYZ;;AAAA,gDAVY,KAUZ;;AAAA,mCARF,EAQE;;AAAA,mCANF,CAME;;AAAA,0CAJK,CAIL;;AAAA,0CAHK,CAGL;;AAAA,uCAFE,CAEF;AAEb,O;;8BAGCC,Y,GAWF,wBAAc;AAAA;;AAAA,uCAVE,EAUF;;AAAA,6CATQ,CASR;;AAAA,6CARQ,CAQR;;AAAA;;AAAA;;AAAA,gDALY,KAKZ;;AAAA,gDAJY,KAIZ;;AAAA,yCAHM,EAGN;;AAAA;;AACV,aAAKC,QAAL,GAAgB,CAAhB;AACA,aAAKC,QAAL,GAAgB,CAAhB;AAEH,O","sourcesContent":["\n\n// A holder of values\nclass Card {\n // uniq\n id: number = 0;\n // Array of values in this bucket\n values: any[] = [];\n columns: any[] = [];\n // card has multiple values\n multipleValues: boolean = false;\n // card has values that has no color\n noColorDefined: boolean = false;\n //\n y: string = \"\";\n //\n x: number = 0;\n //\n minValue: number = 0;\n maxValue: number = 0;\n value: number = 0;\n \n constructor() {\n\n }\n }\n \nclass CardsStorage {\n cards: Card[] = [];\n xBucketSize: number = 0;\n yBucketSize: number = 0;\n maxValue: number;\n minValue: number;\n multipleValues: boolean = false;\n noColorDefined: boolean = false;\n targets: string[] = [];\n targetIndex: any;\n\n constructor() {\n this.maxValue = 0;\n this.minValue = 0;\n\n }\n }\n\nexport {CardsStorage, Card};"],"file":"statusmap_data.js"}
|
{"version":3,"sources":["../src/statusmap_data.ts"],"names":["Bucket","ts","from","to","value","values","push","length","BucketMatrix","yid","xid","buckets","hasData","targets","map","target"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;wBACMA,M;;;AACJ;AAEA;AAEqB;AACrB;AAEA;AAEA;AAGA;AAGA;AAGA;AAMA;AAGA;AAGA,0BAAc;AAAA;;AAAA,sCA7BD,CA6BC;;AAAA,0CA3BE,EA2BF;;AAAA,2CA1BG,EA0BH;;AAAA,kDAxBY,KAwBZ;;AAAA,kDAtBY,KAsBZ;;AAAA,qCApBF,EAoBE;;AAAA,0CAnBG,EAmBH;;AAAA,qCAjBF,CAiBE;;AAAA,uCAhBA,CAgBA;;AAAA,wCAdC,CAcD;;AAAA,sCAbD,CAaC;;AAAA,2CAXI,CAWJ;;AAAA,yCAVE,CAUF;;AAAA,8CARQ,KAQR;;AAAA,4CALK,CAKL;;AAAA,4CAJK,CAIL;;AAAA,yCAFE,CAEF;AACb;;;;iCAEMC,E,EAAqB;AAC1B,mBAAOA,EAAE,IAAI,KAAKC,IAAX,IAAmBD,EAAE,IAAI,KAAKE,EAArC;AACD;;;8BAEGC,K,EAAY;AACd,iBAAKC,MAAL,CAAYC,IAAZ,CAAiBF,KAAjB;AACD;;;iCAEM,CACL;AACD;;;oCAEkB;AACjB,mBAAO,KAAKC,MAAL,CAAYE,MAAZ,IAAsB,CAA7B;AACD;;;;;;8BAKGC,Y;;;AACJ;AAMA;AAOyB;AAEzB,gCAAc;AAAA;;AAAA,2CAd0B,EAc1B;;AAAA,4CAbK,CAaL;;AAAA,4CAZK,CAYL;;AAAA,kDAXY,KAWZ;;AAAA,kDAVY,KAUZ;;AAAA,gDARU,KAQV;;AAAA,2CANM,EAMN;;AAAA,2CALI,CAKJ;;AAAA,8CAJO,CAIP;;AAAA,+CAFQ,CAER;AACb;;;;8BAEGC,G,EAAaC,G,EAAqB;AACpC,gBAAID,GAAG,IAAI,KAAKE,OAAhB,EAAyB;AACvB,kBAAID,GAAG,IAAI,KAAKC,OAAL,CAAaF,GAAb,CAAX,EAA8B;AAC5B,uBAAO,KAAKE,OAAL,CAAaF,GAAb,EAAkBC,GAAlB,CAAP;AACD;AACF;;AACD,mBAAO,IAAIV,MAAJ,EAAP;AACD;;;oCAEkB;AAAA;;AACjB,gBAAIY,OAAO,GAAG,KAAd;;AACA,gBAAI,KAAKC,OAAL,CAAaN,MAAb,GAAsB,CAA1B,EAA6B;AAC3B,mBAAKM,OAAL,CAAaC,GAAb,CAAiB,UAACC,MAAD,EAAmB;AAClC,oBAAI,KAAI,CAACJ,OAAL,CAAaI,MAAb,EAAqBR,MAArB,GAA8B,CAAlC,EAAqC;AACnCK,kBAAAA,OAAO,GAAG,IAAV;AACD;AACF,eAJD;AAKD;;AACD,mBAAOA,OAAP;AACD","sourcesContent":["// A holder of a group of values\nclass Bucket {\n // uniq id\n id: number = 0;\n // Array of values in this bucket\n values: any[] = [];\n columns: any[] = []; // From pr/86\n // a bucket has multiple values\n multipleValues: boolean = false;\n // a bucket has values that has no mapped color\n noColorDefined: boolean = false;\n // y label\n y: string = \"\";\n yLabel: string = \"\";\n // This value can be used to calculate a x coordinate on a graph\n x: number = 0;\n xid: number = 0;\n // a time range of this bucket\n from: number = 0;\n to: number = 0;\n // to and from relative to real \"from\"\n relFrom: number = 0;\n relTo: number = 0;\n\n mostRecent: boolean = false;\n\n // Saved minimum and maximum of values in this bucket\n minValue: number = 0;\n maxValue: number = 0;\n // A value if multiple values is not allowed\n value: number = 0;\n\n constructor() {\n }\n\n belong(ts: number): boolean {\n return ts >= this.from && ts <= this.to;\n }\n\n put(value: any) {\n this.values.push(value);\n }\n\n done() {\n // calculate min, max, value\n }\n\n isEmpty(): boolean {\n return this.values.length == 0;\n }\n\n}\n\n\nclass BucketMatrix {\n // buckets for each y label\n buckets: {[yLabel: string]: Bucket[]} = {};\n maxValue: number = 0;\n minValue: number = 0;\n multipleValues: boolean = false;\n noColorDefined: boolean = false;\n // a flag that indicate that buckets has stub values\n noDatapoints: boolean = false;\n\n targets: string[] = [];\n rangeMs: number = 0;\n intervalMs: number = 0;\n\n xBucketSize: number = 0; // TODO remove: a transition from CardsData\n\n constructor() {\n }\n\n get(yid: string, xid: number): Bucket {\n if (yid in this.buckets) {\n if (xid in this.buckets[yid]) {\n return this.buckets[yid][xid];\n }\n }\n return new Bucket();\n }\n\n hasData(): boolean {\n let hasData = false;\n if (this.targets.length > 0) {\n this.targets.map((target:string) => {\n if (this.buckets[target].length > 0) {\n hasData = true;\n }\n });\n }\n return hasData;\n }\n}\n\nexport {Bucket, BucketMatrix };"],"file":"statusmap_data.js"}
|
||||||
Vendored
+17
-21
@@ -103,38 +103,34 @@ System.register(["d3", "jquery", "lodash"], function (_export, _context) {
|
|||||||
value: function show(pos) {
|
value: function show(pos) {
|
||||||
if (!this.panel.tooltip.show || !this.tooltip) {
|
if (!this.panel.tooltip.show || !this.tooltip) {
|
||||||
return;
|
return;
|
||||||
} // shared tooltip mode
|
} // TODO support for shared tooltip mode
|
||||||
|
|
||||||
|
|
||||||
if (pos.panelRelY) {
|
if (pos.panelRelY) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var cardId = d3.select(pos.target).attr('cardId');
|
var cardEl = d3.select(pos.target);
|
||||||
|
var yid = cardEl.attr('yid');
|
||||||
|
var xid = cardEl.attr('xid');
|
||||||
|
var bucket = this.panelCtrl.bucketMatrix.get(yid, xid); // TODO string-to-number conversion for xid
|
||||||
|
|
||||||
if (!cardId) {
|
if (!bucket || bucket.isEmpty()) {
|
||||||
this.destroy();
|
this.destroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var card = this.panelCtrl.cardsData.cards[cardId];
|
var timestamp = bucket.to;
|
||||||
|
var name = bucket.yLabel;
|
||||||
if (!card) {
|
var value = bucket.value;
|
||||||
this.destroy();
|
var values = bucket.values;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var x = card.x;
|
|
||||||
var y = card.y;
|
|
||||||
var value = card.value;
|
|
||||||
var values = card.values;
|
|
||||||
var tooltipTimeFormat = 'YYYY-MM-DD HH:mm:ss';
|
var tooltipTimeFormat = 'YYYY-MM-DD HH:mm:ss';
|
||||||
var time = this.dashboard.formatDate(+x, tooltipTimeFormat);
|
var time = this.dashboard.formatDate(+timestamp, tooltipTimeFormat);
|
||||||
var tooltipHtml = "<div class=\"graph-tooltip-time\">".concat(time, "</div>\n <div class=\"statusmap-histogram\"></div>");
|
var tooltipHtml = "<div class=\"graph-tooltip-time\">".concat(time, "</div>\n <div class=\"statusmap-histogram\"></div>");
|
||||||
var statuses;
|
var statuses;
|
||||||
|
|
||||||
if (this.panel.color.mode === 'discrete') {
|
if (this.panel.color.mode === 'discrete') {
|
||||||
if (this.panel.seriesFilterIndex > 0) {
|
if (this.panel.seriesFilterIndex >= 0) {
|
||||||
statuses = this.panelCtrl.discreteExtraSeries.convertValueToTooltips(value);
|
statuses = this.panelCtrl.discreteExtraSeries.convertValueToTooltips(value);
|
||||||
} else {
|
} else {
|
||||||
statuses = this.panelCtrl.discreteExtraSeries.convertValuesToTooltips(values);
|
statuses = this.panelCtrl.discreteExtraSeries.convertValuesToTooltips(values);
|
||||||
@@ -148,27 +144,27 @@ System.register(["d3", "jquery", "lodash"], function (_export, _context) {
|
|||||||
statusesHtml = "statuses:";
|
statusesHtml = "statuses:";
|
||||||
}
|
}
|
||||||
|
|
||||||
tooltipHtml += "\n <div>\n name: <b>".concat(y, "</b> <br>\n ").concat(statusesHtml, "\n <ul>\n ").concat(_.join(_.map(statuses, function (v) {
|
tooltipHtml += "\n <div>\n name: <b>".concat(name, "</b> <br>\n ").concat(statusesHtml, "\n <ul>\n ").concat(_.join(_.map(statuses, function (v) {
|
||||||
return "<li style=\"background-color: ".concat(v.color, "\" class=\"discrete-item\">").concat(v.tooltip, "</li>");
|
return "<li style=\"background-color: ".concat(v.color, "\" class=\"discrete-item\">").concat(v.tooltip, "</li>");
|
||||||
}), ""), "\n </ul>\n </div>");
|
}), ""), "\n </ul>\n </div>");
|
||||||
} else {
|
} else {
|
||||||
if (values.length === 1) {
|
if (values.length === 1) {
|
||||||
tooltipHtml += "<div> \n name: <b>".concat(y, "</b> <br>\n value: <b>").concat(value, "</b> <br>\n </div>");
|
tooltipHtml += "<div> \n name: <b>".concat(name, "</b> <br>\n value: <b>").concat(value, "</b> <br>\n </div>");
|
||||||
} else {
|
} else {
|
||||||
tooltipHtml += "<div>\n name: <b>".concat(y, "</b> <br>\n values:\n <ul>\n ").concat(_.join(_.map(values, function (v) {
|
tooltipHtml += "<div>\n name: <b>".concat(name, "}</b> <br>\n values:\n <ul>\n ").concat(_.join(_.map(values, function (v) {
|
||||||
return "<li>".concat(v, "</li>");
|
return "<li>".concat(v, "</li>");
|
||||||
}), ""), "\n </ul>\n </div>");
|
}), ""), "\n </ul>\n </div>");
|
||||||
}
|
}
|
||||||
} // "Ambiguous bucket state: Multiple values!";
|
} // "Ambiguous bucket state: Multiple values!";
|
||||||
|
|
||||||
|
|
||||||
if (!this.panel.useMax && card.multipleValues) {
|
if (!this.panel.useMax && bucket.multipleValues) {
|
||||||
tooltipHtml += "<div><b>Error:</b> ".concat(this.panelCtrl.dataWarnings.multipleValues.title, "</div>");
|
tooltipHtml += "<div><b>Error:</b> ".concat(this.panelCtrl.dataWarnings.multipleValues.title, "</div>");
|
||||||
} // Discrete mode errors
|
} // Discrete mode errors
|
||||||
|
|
||||||
|
|
||||||
if (this.panel.color.mode === 'discrete') {
|
if (this.panel.color.mode === 'discrete') {
|
||||||
if (card.noColorDefined) {
|
if (bucket.noColorDefined) {
|
||||||
var badValues = this.panelCtrl.discreteExtraSeries.getNotColoredValues(values);
|
var badValues = this.panelCtrl.discreteExtraSeries.getNotColoredValues(values);
|
||||||
tooltipHtml += "<div><b>Error:</b> ".concat(this.panelCtrl.dataWarnings.noColorDefined.title, "\n <br>not colored values:\n <ul>\n ").concat(_.join(_.map(badValues, function (v) {
|
tooltipHtml += "<div><b>Error:</b> ".concat(this.panelCtrl.dataWarnings.noColorDefined.title, "\n <br>not colored values:\n <ul>\n ").concat(_.join(_.map(badValues, function (v) {
|
||||||
return "<li>".concat(v, "</li>");
|
return "<li>".concat(v, "</li>");
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Generated
+6
@@ -7917,6 +7917,12 @@
|
|||||||
"integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
|
"integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"tslib": {
|
||||||
|
"version": "1.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
|
||||||
|
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"type-check": {
|
"type-check": {
|
||||||
"version": "0.3.2",
|
"version": "0.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
|
||||||
|
|||||||
+2
-1
@@ -44,7 +44,8 @@
|
|||||||
"grunt-contrib-watch": "^1.0.0",
|
"grunt-contrib-watch": "^1.0.0",
|
||||||
"grunt-notify": "^0.4.5",
|
"grunt-notify": "^0.4.5",
|
||||||
"load-grunt-tasks": "^3.5.2",
|
"load-grunt-tasks": "^3.5.2",
|
||||||
"typescript": "3.7.2"
|
"typescript": "3.7.2",
|
||||||
|
"tslib": "1.10.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"d3": "4.13.0",
|
"d3": "4.13.0",
|
||||||
|
|||||||
+34
-12
@@ -5,6 +5,7 @@ import * as d3ScaleChromatic from './libs/d3-scale-chromatic/index';
|
|||||||
import {contextSrv} from 'app/core/core';
|
import {contextSrv} from 'app/core/core';
|
||||||
import {tickStep} from 'app/core/utils/ticks';
|
import {tickStep} from 'app/core/utils/ticks';
|
||||||
import coreModule from 'app/core/core_module';
|
import coreModule from 'app/core/core_module';
|
||||||
|
import { BucketMatrix } from './statusmap_data';
|
||||||
|
|
||||||
const LEGEND_STEP_WIDTH = 2;
|
const LEGEND_STEP_WIDTH = 2;
|
||||||
|
|
||||||
@@ -61,14 +62,35 @@ coreModule.directive('statusHeatmapLegend', function() {
|
|||||||
function render() {
|
function render() {
|
||||||
clearLegend(elem);
|
clearLegend(elem);
|
||||||
if (!ctrl.panel.legend.show) {
|
if (!ctrl.panel.legend.show) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (!_.isEmpty(ctrl.cardsData) && !_.isEmpty(ctrl.cardsData.cards)) {
|
if (ctrl.bucketMatrix) {
|
||||||
let rangeFrom = ctrl.cardsData.minValue;
|
let rangeFrom = ctrl.bucketMatrix.minValue;
|
||||||
let rangeTo = ctrl.cardsData.maxValue;
|
let rangeTo = ctrl.bucketMatrix.maxValue;
|
||||||
let maxValue = panel.color.max || rangeTo;
|
let maxValue = panel.color.max || rangeTo;
|
||||||
let minValue = panel.color.min || rangeFrom;
|
let minValue = panel.color.min || rangeFrom;
|
||||||
|
|
||||||
|
if (ctrl.bucketMatrix.noDatapoints) {
|
||||||
|
if (!panel.color.max) {
|
||||||
|
rangeTo = maxValue = 100;
|
||||||
|
} else {
|
||||||
|
rangeTo = 100;
|
||||||
|
}
|
||||||
|
if (!panel.color.min) {
|
||||||
|
rangeFrom = minValue = 0;
|
||||||
|
} else {
|
||||||
|
rangeFrom = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("legent state:", {
|
||||||
|
rangeFrom: rangeFrom,
|
||||||
|
rangeTo: rangeTo,
|
||||||
|
maxValue: maxValue,
|
||||||
|
minValue: minValue,
|
||||||
|
colorMode: panel.color.mode
|
||||||
|
});
|
||||||
|
|
||||||
if (panel.color.mode === 'spectrum') {
|
if (panel.color.mode === 'spectrum') {
|
||||||
let colorScheme = _.find(ctrl.colorSchemes, {value: panel.color.colorScheme});
|
let colorScheme = _.find(ctrl.colorSchemes, {value: panel.color.colorScheme});
|
||||||
drawColorLegend(elem, colorScheme, rangeFrom, rangeTo, maxValue, minValue);
|
drawColorLegend(elem, colorScheme, rangeFrom, rangeTo, maxValue, minValue);
|
||||||
@@ -85,7 +107,7 @@ coreModule.directive('statusHeatmapLegend', function() {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
function drawColorLegend(elem, colorScheme, rangeFrom, rangeTo, maxValue, minValue) {
|
function drawColorLegend(elem, colorScheme, rangeFrom: number, rangeTo:number, maxValue: number, minValue:number) {
|
||||||
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);
|
||||||
@@ -105,7 +127,7 @@ function drawColorLegend(elem, colorScheme, rangeFrom, rangeTo, maxValue, minVal
|
|||||||
.enter().append("rect")
|
.enter().append("rect")
|
||||||
// translate from range space into pixels
|
// translate from range space into pixels
|
||||||
// and shift all rectangles to the right by 10
|
// and shift all rectangles to the right by 10
|
||||||
.attr("x", d => d * widthFactor+10)
|
.attr("x", d => ((d - rangeFrom) * widthFactor)+10)
|
||||||
.attr("y", 0)
|
.attr("y", 0)
|
||||||
// rectangles are slightly overlaped to prevent gaps
|
// rectangles are slightly overlaped to prevent gaps
|
||||||
.attr("width", LEGEND_STEP_WIDTH+1)
|
.attr("width", LEGEND_STEP_WIDTH+1)
|
||||||
@@ -158,7 +180,7 @@ function drawDiscreteColorLegend(elem, colorOptions, discreteExtraSeries) {
|
|||||||
let valuesNumber = thresholds.length;
|
let valuesNumber = thresholds.length;
|
||||||
|
|
||||||
// graph width as a fallback
|
// graph width as a fallback
|
||||||
const $heatmap = $(elem).parent().parent().parent().find('.status-heatmap-panel');
|
const $heatmap = $(elem).parent().parent().parent().find('.statusmap-panel');
|
||||||
const graphWidthAttr = $heatmap.find('svg').attr("width");
|
const graphWidthAttr = $heatmap.find('svg').attr("width");
|
||||||
let graphWidth = parseInt(graphWidthAttr);
|
let graphWidth = parseInt(graphWidthAttr);
|
||||||
|
|
||||||
@@ -202,7 +224,7 @@ function drawDiscreteColorLegend(elem, colorOptions, discreteExtraSeries) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function drawLegendValues(elem, colorScale, rangeFrom, rangeTo, maxValue, minValue, legendWidth) {
|
function drawLegendValues(elem, colorScale, rangeFrom: number, rangeTo: number, maxValue: number, minValue: number, legendWidth: number) {
|
||||||
let legendElem = $(elem).find('svg');
|
let legendElem = $(elem).find('svg');
|
||||||
let legend = d3.select(legendElem.get(0));
|
let legend = d3.select(legendElem.get(0));
|
||||||
|
|
||||||
@@ -211,10 +233,10 @@ function drawLegendValues(elem, colorScale, rangeFrom, rangeTo, maxValue, minVal
|
|||||||
}
|
}
|
||||||
|
|
||||||
let legendValueScale = d3.scaleLinear()
|
let legendValueScale = d3.scaleLinear()
|
||||||
.domain([0, rangeTo])
|
.domain([rangeFrom, rangeTo])
|
||||||
.range([0, legendWidth]);
|
.range([0, legendWidth]);
|
||||||
|
|
||||||
let ticks = buildLegendTicks(0, rangeTo, maxValue, minValue);
|
let ticks = buildLegendTicks(rangeFrom, rangeTo, maxValue, minValue);
|
||||||
let xAxis = d3.axisBottom(legendValueScale)
|
let xAxis = d3.axisBottom(legendValueScale)
|
||||||
.tickValues(ticks)
|
.tickValues(ticks)
|
||||||
.tickSize(2);
|
.tickSize(2);
|
||||||
@@ -401,7 +423,7 @@ function buildLegendTicks(rangeFrom, rangeTo, maxValue, minValue) {
|
|||||||
let ticks:any = [];
|
let ticks:any = [];
|
||||||
|
|
||||||
for (let i = 0; i < ticksNum; i++) {
|
for (let i = 0; i < ticksNum; i++) {
|
||||||
let current = tickStepSize * i;
|
let current = tickStepSize * i + rangeFrom;
|
||||||
// Add user-defined min and max if it had been set
|
// Add user-defined min and max if it had been set
|
||||||
if (isValueCloseTo(minValue, current, tickStepSize)) {
|
if (isValueCloseTo(minValue, current, tickStepSize)) {
|
||||||
ticks.push(minValue);
|
ticks.push(minValue);
|
||||||
@@ -415,7 +437,7 @@ function buildLegendTicks(rangeFrom, rangeTo, maxValue, minValue) {
|
|||||||
} else if (maxValue < current) {
|
} else if (maxValue < current) {
|
||||||
ticks.push(maxValue);
|
ticks.push(maxValue);
|
||||||
}
|
}
|
||||||
ticks.push(tickStepSize * i);
|
ticks.push(current);
|
||||||
}
|
}
|
||||||
if (!isValueCloseTo(maxValue, rangeTo, tickStepSize)) {
|
if (!isValueCloseTo(maxValue, rangeTo, tickStepSize)) {
|
||||||
ticks.push(maxValue);
|
ticks.push(maxValue);
|
||||||
|
|||||||
+30
-27
@@ -1,5 +1,6 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import {StatusHeatmapCtrl} from "./status_heatmap_ctrl";
|
import { Bucket } from "./statusmap_data";
|
||||||
|
import { StatusHeatmapCtrl } from "./module";
|
||||||
|
|
||||||
interface Tooltip {
|
interface Tooltip {
|
||||||
tooltip: string;
|
tooltip: string;
|
||||||
@@ -144,40 +145,42 @@ export class ColorModeDiscrete {
|
|||||||
|
|
||||||
|
|
||||||
updateCardsValuesHasColorInfoSingle() {
|
updateCardsValuesHasColorInfoSingle() {
|
||||||
if (!this.panelCtrl.cardsData) {
|
if (!this.panelCtrl.bucketMatrix) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.panelCtrl.cardsData.noColorDefined = false;
|
this.panelCtrl.bucketMatrix.noColorDefined = false;
|
||||||
var cards = this.panelCtrl.cardsData.cards;
|
|
||||||
for (var i = 0; i < cards.length; i++) {
|
this.panelCtrl.bucketMatrix.targets.map((target:string) => {
|
||||||
cards[i].noColorDefined = false;
|
this.panelCtrl.bucketMatrix.buckets[target].map((bucket:Bucket) => {
|
||||||
var values = cards[i].value;
|
bucket.noColorDefined = false;
|
||||||
var threshold = this.getMatchedThreshold(values);
|
let threshold = this.getMatchedThreshold(bucket.value);
|
||||||
if (!threshold || !threshold.color || threshold.color == "") {
|
if (!threshold || !threshold.color || threshold.color == "") {
|
||||||
cards[i].noColorDefined = true;
|
bucket.noColorDefined = true;
|
||||||
this.panelCtrl.cardsData.noColorDefined = true;
|
this.panelCtrl.bucketMatrix.noColorDefined = true;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCardsValuesHasColorInfo() {
|
updateCardsValuesHasColorInfo() {
|
||||||
if (!this.panelCtrl.cardsData) {
|
if (!this.panelCtrl.bucketMatrix) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.panelCtrl.cardsData.noColorDefined = false;
|
this.panelCtrl.bucketMatrix.noColorDefined = false;
|
||||||
let cards = this.panelCtrl.cardsData.cards;
|
|
||||||
for (let i=0; i<cards.length; i++) {
|
this.panelCtrl.bucketMatrix.targets.map((target:string) => {
|
||||||
cards[i].noColorDefined = false;
|
this.panelCtrl.bucketMatrix.buckets[target].map((bucket:Bucket) => {
|
||||||
let values = cards[i].values;
|
bucket.noColorDefined = false;
|
||||||
for (let j=0; j<values.length; j++) {
|
for (let j=0; j<bucket.values.length; j++) {
|
||||||
let threshold = this.getMatchedThreshold(values[j]);
|
let threshold = this.getMatchedThreshold(bucket.values[j]);
|
||||||
if (!threshold || !threshold.color || threshold.color == "") {
|
if (!threshold || !threshold.color || threshold.color == "") {
|
||||||
cards[i].noColorDefined = true;
|
bucket.noColorDefined = true;
|
||||||
this.panelCtrl.cardsData.noColorDefined = true;
|
this.panelCtrl.bucketMatrix.noColorDefined = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getMatchedThreshold(value) {
|
getMatchedThreshold(value) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-heatmap-panel {
|
.statusmap-panel {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.axis .tick {
|
.axis .tick {
|
||||||
|
|||||||
+4
-2
@@ -1,12 +1,14 @@
|
|||||||
<div class="status-heatmap-wrapper">
|
<div class="status-heatmap-wrapper">
|
||||||
<div class="status-heatmap-canvas-wrapper">
|
<div class="status-heatmap-canvas-wrapper">
|
||||||
|
|
||||||
<div class="datapoints-warning" ng-if="ctrl.multipleValues || ctrl.noColorDefined">
|
<div class="datapoints-warning" ng-if="ctrl.multipleValues || ctrl.noColorDefined || ctrl.noDatapoints">
|
||||||
<span class="small" ng-if="ctrl.multipleValues" bs-tooltip="'{{ctrl.dataWarnings.multipleValues.tip}}'">{{ctrl.dataWarnings.multipleValues.title}}</span>
|
<span class="small" ng-if="ctrl.multipleValues" bs-tooltip="'{{ctrl.dataWarnings.multipleValues.tip}}'">{{ctrl.dataWarnings.multipleValues.title}}</span>
|
||||||
<span class="small" ng-if="ctrl.noColorDefined" bs-tooltip="'{{ctrl.dataWarnings.noColorDefined.tip}}'">{{ctrl.dataWarnings.noColorDefined.title}}</span>
|
<span class="small" ng-if="ctrl.noColorDefined" bs-tooltip="'{{ctrl.dataWarnings.noColorDefined.tip}}'">{{ctrl.dataWarnings.noColorDefined.title}}</span>
|
||||||
|
<span class="small" ng-if="ctrl.noDatapoints" bs-tooltip="'{{ctrl.dataWarnings.noDatapoints.tip}}'">{{ctrl.dataWarnings.noDatapoints.title}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="status-heatmap-panel" ng-dblclick="ctrl.zoomOut()"></div>
|
|
||||||
|
<div class="statusmap-panel" ng-dblclick="ctrl.zoomOut()"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="status-heatmap-legend-wrapper" ng-if="ctrl.panel.legend.show">
|
<div class="status-heatmap-legend-wrapper" ng-if="ctrl.panel.legend.show">
|
||||||
<status-heatmap-legend></status-heatmap-legend>
|
<status-heatmap-legend></status-heatmap-legend>
|
||||||
|
|||||||
+409
-119
@@ -12,7 +12,7 @@ import {loadPluginCss} from 'app/plugins/sdk';
|
|||||||
// Types
|
// Types
|
||||||
import { MetricsPanelCtrl } from 'app/plugins/sdk';
|
import { MetricsPanelCtrl } from 'app/plugins/sdk';
|
||||||
import { AnnotationsSrv } from 'app/features/annotations/annotations_srv';
|
import { AnnotationsSrv } from 'app/features/annotations/annotations_srv';
|
||||||
import {CardsStorage, Card} from './statusmap_data';
|
import { Bucket, BucketMatrix } from './statusmap_data';
|
||||||
import rendering from './rendering';
|
import rendering from './rendering';
|
||||||
// import aggregates, { aggregatesMap } from './aggregates';
|
// import aggregates, { aggregatesMap } from './aggregates';
|
||||||
// import fragments, { fragmentsMap } from './fragments';
|
// import fragments, { fragmentsMap } from './fragments';
|
||||||
@@ -21,13 +21,9 @@ import {statusHeatmapOptionsEditor} from './options_editor';
|
|||||||
import {ColorModeDiscrete} from "./color_mode_discrete";
|
import {ColorModeDiscrete} from "./color_mode_discrete";
|
||||||
import { ExtraSeriesFormat, ExtraSeriesFormatValue } from './extra_series_format';
|
import { ExtraSeriesFormat, ExtraSeriesFormatValue } from './extra_series_format';
|
||||||
|
|
||||||
const CANVAS = 'CANVAS';
|
|
||||||
const SVG = 'SVG';
|
|
||||||
const VALUE_INDEX = 0,
|
const VALUE_INDEX = 0,
|
||||||
TIME_INDEX = 1;
|
TIME_INDEX = 1;
|
||||||
|
|
||||||
const renderer = CANVAS;
|
|
||||||
|
|
||||||
const colorSchemes = [
|
const colorSchemes = [
|
||||||
// Diverging
|
// Diverging
|
||||||
{ name: 'Spectral', value: 'interpolateSpectral', invert: 'always' },
|
{ name: 'Spectral', value: 'interpolateSpectral', invert: 'always' },
|
||||||
@@ -60,22 +56,6 @@ const colorSchemes = [
|
|||||||
let colorModes = ['opacity', 'spectrum', 'discrete'];
|
let colorModes = ['opacity', 'spectrum', 'discrete'];
|
||||||
let opacityScales = ['linear', 'sqrt'];
|
let opacityScales = ['linear', 'sqrt'];
|
||||||
|
|
||||||
interface DataWarning {
|
|
||||||
title: string;
|
|
||||||
tip: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DataWarnings {
|
|
||||||
noColorDefined: DataWarning;
|
|
||||||
multipleValues: DataWarning;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ColorThreshold {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
loadPluginCss({
|
loadPluginCss({
|
||||||
dark: 'plugins/flant-statusmap-panel/css/statusmap.dark.css',
|
dark: 'plugins/flant-statusmap-panel/css/statusmap.dark.css',
|
||||||
@@ -85,17 +65,22 @@ loadPluginCss({
|
|||||||
class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
||||||
static templateUrl = 'module.html';
|
static templateUrl = 'module.html';
|
||||||
|
|
||||||
|
data: any;
|
||||||
|
bucketMatrix: BucketMatrix;
|
||||||
|
|
||||||
|
graph: any;
|
||||||
|
discreteHelper: ColorModeDiscrete;
|
||||||
opacityScales: any = [];
|
opacityScales: any = [];
|
||||||
colorModes: any = [];
|
colorModes: any = [];
|
||||||
colorSchemes: any = [];
|
colorSchemes: any = [];
|
||||||
unitFormats: any;
|
unitFormats: any;
|
||||||
data: any;
|
|
||||||
cardsData: any;
|
dataWarnings: {[warningId: string]: {title: string, tip: string}} = {};
|
||||||
graph: any;
|
|
||||||
multipleValues: boolean;
|
multipleValues: boolean;
|
||||||
noColorDefined: boolean;
|
noColorDefined: boolean;
|
||||||
|
noDatapoints: boolean;
|
||||||
|
|
||||||
discreteExtraSeries: ColorModeDiscrete;
|
discreteExtraSeries: ColorModeDiscrete;
|
||||||
dataWarnings: DataWarnings;
|
|
||||||
extraSeriesFormats: any = [];
|
extraSeriesFormats: any = [];
|
||||||
|
|
||||||
annotations: object[] = [];
|
annotations: object[] = [];
|
||||||
@@ -124,14 +109,12 @@ class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
show: true,
|
show: true,
|
||||||
showWeekends: true,
|
|
||||||
minBucketWidthToShowWeekends: 4,
|
|
||||||
showCrosshair: true,
|
|
||||||
labelFormat: '%a %m/%d'
|
labelFormat: '%a %m/%d'
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
show: true,
|
show: true,
|
||||||
showCrosshair: false
|
minWidth: -1,
|
||||||
|
maxWidth: -1,
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
show: true
|
show: true
|
||||||
@@ -199,13 +182,17 @@ class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
this.discreteExtraSeries = new ColorModeDiscrete($scope);
|
this.discreteExtraSeries = new ColorModeDiscrete($scope);
|
||||||
|
|
||||||
this.dataWarnings = {
|
this.dataWarnings = {
|
||||||
"noColorDefined": {
|
noColorDefined: {
|
||||||
title: 'Data has value with undefined color',
|
title: 'Data has value with undefined color',
|
||||||
tip: 'Check metric values, color values or define a new color',
|
tip: 'Check metric values, color values or define a new color',
|
||||||
},
|
},
|
||||||
"multipleValues": {
|
multipleValues: {
|
||||||
title: 'Data has multiple values for one target',
|
title: 'Data has multiple values for one target',
|
||||||
tip: 'Change targets definitions or set "use max value"',
|
tip: 'Change targets definitions or set "use max value"',
|
||||||
|
},
|
||||||
|
noDatapoints: {
|
||||||
|
title: 'No data points',
|
||||||
|
tip: 'No datapoints returned from data query',
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -225,7 +212,15 @@ class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
this.events.on('onChangeType', this.onChangeType.bind(this));
|
this.events.on('onChangeType', this.onChangeType.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
onRenderComplete(data):void {
|
onRenderComplete(data: any):void {
|
||||||
|
// console.log({
|
||||||
|
// data: this.data,
|
||||||
|
// bucketMatrix: this.bucketMatrix,
|
||||||
|
// chartWidth: data.chartWidth,
|
||||||
|
// from: this.range.from.valueOf(),
|
||||||
|
// to: this.range.to.valueOf()
|
||||||
|
// })
|
||||||
|
|
||||||
this.graph.chartWidth = data.chartWidth;
|
this.graph.chartWidth = data.chartWidth;
|
||||||
this.renderingCompleted();
|
this.renderingCompleted();
|
||||||
}
|
}
|
||||||
@@ -244,12 +239,21 @@ class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getChartWidth returns an approximation of chart canvas width or
|
||||||
|
// a saved value calculated during a render.
|
||||||
getChartWidth():number {
|
getChartWidth():number {
|
||||||
|
if (this.graph.chartWidth > 0) {
|
||||||
|
return this.graph.chartWidth;
|
||||||
|
}
|
||||||
|
|
||||||
const wndWidth = $(window).width();
|
const wndWidth = $(window).width();
|
||||||
// gripPos.w is a width in grid's measurements. Grid size in Grafana is 24.
|
// gripPos.w is a width in grid's measurements. Grid size in Grafana is 24.
|
||||||
const panelWidthFactor = this.panel.gridPos.w / 24;
|
const panelWidthFactor = this.panel.gridPos.w / 24;
|
||||||
const panelWidth = Math.ceil(wndWidth * panelWidthFactor);
|
const panelWidth = Math.ceil(wndWidth * panelWidthFactor);
|
||||||
// approximate chartWidth because y axis ticks not rendered yet on first data receive.
|
// approximate width of the chart draw canvas:
|
||||||
|
// - y axis ticks are not rendered yet on first data receive,
|
||||||
|
// so choose 200 as a decent value for y legend width
|
||||||
|
// - chartWidth can not be lower than the half of the panel width.
|
||||||
const chartWidth = _.max([
|
const chartWidth = _.max([
|
||||||
panelWidth - 200,
|
panelWidth - 200,
|
||||||
panelWidth/2
|
panelWidth/2
|
||||||
@@ -258,7 +262,9 @@ class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
return chartWidth!;
|
return chartWidth!;
|
||||||
}
|
}
|
||||||
|
|
||||||
// override calculateInterval for discrete color mode
|
// calculateInterval is called on 'refresh' to calculate an interval
|
||||||
|
// for datasource.
|
||||||
|
// It is override of calculateInterval from MetricsPanelCtrl.
|
||||||
calculateInterval() {
|
calculateInterval() {
|
||||||
let chartWidth = this.getChartWidth();
|
let chartWidth = this.getChartWidth();
|
||||||
|
|
||||||
@@ -298,6 +304,19 @@ class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
|
|
||||||
this.intervalMs = intervalMs;
|
this.intervalMs = intervalMs;
|
||||||
this.interval = interval;
|
this.interval = interval;
|
||||||
|
|
||||||
|
// Get final buckets count after interval is adjusted
|
||||||
|
//this.xBucketsCount = Math.floor(rangeMs / intervalMs);
|
||||||
|
|
||||||
|
// console.log("calculateInterval: ", {
|
||||||
|
// interval: this.interval,
|
||||||
|
// intervalMs: this.intervalMs,
|
||||||
|
// rangeMs: rangeMs,
|
||||||
|
// from: this.range.from.valueOf(),
|
||||||
|
// to: this.range.to.valueOf(),
|
||||||
|
// numIntervals: rangeMs/this.intervalMs,
|
||||||
|
// maxCardsCount: maxCardsCount,
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
issueQueries(datasource: any) {
|
issueQueries(datasource: any) {
|
||||||
@@ -329,7 +348,7 @@ class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
// so we need to save-restore this.panel.interval.
|
// so we need to save-restore this.panel.interval.
|
||||||
issueQueriesWithInterval(datasource: any, interval: any) {
|
issueQueriesWithInterval(datasource: any, interval: any) {
|
||||||
var origInterval = this.panel.interval;
|
var origInterval = this.panel.interval;
|
||||||
this.panel.interval = this.interval;
|
this.panel.interval = interval;
|
||||||
var res = super.issueQueries(datasource);
|
var res = super.issueQueries(datasource);
|
||||||
this.panel.interval = origInterval;
|
this.panel.interval = origInterval;
|
||||||
return res;
|
return res;
|
||||||
@@ -337,8 +356,9 @@ class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
|
|
||||||
|
|
||||||
onDataReceived(dataList: any) {
|
onDataReceived(dataList: any) {
|
||||||
this.data = dataList;
|
this.data = dataList;
|
||||||
this.cardsData = this.convertToCards(this.data);
|
this.bucketMatrix = this.convertDataToBuckets(dataList, this.range.from.valueOf(), this.range.to.valueOf(), this.intervalMs, true);
|
||||||
|
this.noDatapoints = this.bucketMatrix.noDatapoints;
|
||||||
|
|
||||||
this.annotationsPromise.then(
|
this.annotationsPromise.then(
|
||||||
(result: { alertState: any; annotations: any }) => {
|
(result: { alertState: any; annotations: any }) => {
|
||||||
@@ -357,8 +377,6 @@ class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
//this.render();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onInitEditMode() {
|
onInitEditMode() {
|
||||||
@@ -366,13 +384,19 @@ class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
this.unitFormats = kbn.getUnitFormats();
|
this.unitFormats = kbn.getUnitFormats();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// onRender will be called before StatusmapRenderer.onRender.
|
||||||
|
// Decide if warning should be displayed over cards.
|
||||||
onRender() {
|
onRender() {
|
||||||
if (!this.range || !this.data) { return; }
|
//console.log('OnRender');
|
||||||
|
if (!this.range || !this.data) {
|
||||||
|
this.noDatapoints = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.multipleValues = false;
|
this.multipleValues = false;
|
||||||
if (!this.panel.useMax) {
|
if (!this.panel.useMax) {
|
||||||
if (this.cardsData) {
|
if (this.bucketMatrix) {
|
||||||
this.multipleValues = this.cardsData.multipleValues;
|
this.multipleValues = this.bucketMatrix.multipleValues;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,10 +407,17 @@ class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
} else {
|
} else {
|
||||||
this.discreteExtraSeries.updateCardsValuesHasColorInfoSingle();
|
this.discreteExtraSeries.updateCardsValuesHasColorInfoSingle();
|
||||||
}
|
}
|
||||||
if (this.cardsData) {
|
if (this.bucketMatrix) {
|
||||||
this.noColorDefined = this.cardsData.noColorDefined;
|
this.noColorDefined = this.bucketMatrix.noColorDefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.noDatapoints = false;
|
||||||
|
if (this.bucketMatrix) {
|
||||||
|
this.noDatapoints = this.bucketMatrix.noDatapoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
onCardColorChange(newColor) {
|
onCardColorChange(newColor) {
|
||||||
@@ -475,85 +506,344 @@ class StatusHeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
return var_time;
|
return var_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
// group values into buckets by target
|
// convertToBuckets groups values in data into buckets by target and timestamp.
|
||||||
convertToCards(data) {
|
//
|
||||||
let cardsData = <CardsStorage> {
|
// data is a result from datasource. It is an array of timeseries and tables:
|
||||||
cards: [],
|
/* [
|
||||||
xBucketSize: 0,
|
// timeseries
|
||||||
yBucketSize: 0,
|
{
|
||||||
maxValue: 0,
|
target: "query alias",
|
||||||
minValue: 0,
|
refId: "A",
|
||||||
multipleValues: false,
|
datapoints: [
|
||||||
noColorDefined: false,
|
[0, 1582681239911],
|
||||||
targets: [], // array of available unique targets
|
[3, 158....],
|
||||||
targetIndex: {} // indices in data array for each of available unique targets
|
...
|
||||||
};
|
],
|
||||||
|
tags?:{key: value,...}
|
||||||
|
},
|
||||||
|
// table
|
||||||
|
{
|
||||||
|
name: "table name",
|
||||||
|
refId: "B",
|
||||||
|
columns: [
|
||||||
|
{text: "id"},
|
||||||
|
{text: "info"},
|
||||||
|
...
|
||||||
|
],
|
||||||
|
rows: [
|
||||||
|
[1, "123"],
|
||||||
|
[2, "44411"],
|
||||||
|
...
|
||||||
|
]
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
|
||||||
if (!data || data.length == 0) { return cardsData;}
|
to and from — a time range of the panel.
|
||||||
|
intervalMs — a calculated interval. It is used to split a time range.
|
||||||
|
*/
|
||||||
|
convertDataToBuckets(data:any, from:number, to:number, intervalMs: number, mostRecentBucket: boolean):BucketMatrix {
|
||||||
|
let bucketMatrix = new BucketMatrix();
|
||||||
|
bucketMatrix.rangeMs = to - from;
|
||||||
|
bucketMatrix.intervalMs = intervalMs;
|
||||||
|
|
||||||
// Collect uniq timestamps from data and spread over targets and timestamps
|
if (!data || data.length == 0) {
|
||||||
|
// Mimic heatmap and graph 'no data' labels.
|
||||||
// collect uniq targets and their indices
|
bucketMatrix.targets = [
|
||||||
_.map(data, (d, i) => {
|
"1.0", "0.0", "-1.0"
|
||||||
cardsData.targetIndex[d.target] = _.concat(_.toArray(cardsData.targetIndex[d.target]), i)
|
];
|
||||||
});
|
bucketMatrix.buckets["1.0"] = [];
|
||||||
|
bucketMatrix.buckets["0.0"] = [];
|
||||||
// TODO add some logic for targets heirarchy
|
bucketMatrix.buckets["-1.0"] = [];
|
||||||
cardsData.targets = _.keys(cardsData.targetIndex);
|
bucketMatrix.xBucketSize = 42;
|
||||||
cardsData.yBucketSize = cardsData.targets.length;
|
bucketMatrix.noDatapoints = true;
|
||||||
// Maximum number of buckets over x axis
|
return bucketMatrix;
|
||||||
cardsData.xBucketSize = _.max(_.map(data, d => d.datapoints.length));
|
|
||||||
|
|
||||||
// Collect all values for each bucket from datapoints with similar target.
|
|
||||||
// TODO aggregate values into buckets over datapoint[TIME_INDEX] not over datapoint index (j).
|
|
||||||
for(let i = 0; i < cardsData.targets.length; i++) {
|
|
||||||
let target = cardsData.targets[i];
|
|
||||||
|
|
||||||
for (let j = 0; j < cardsData.xBucketSize; j++) {
|
|
||||||
let card = new Card();
|
|
||||||
card.id = i*cardsData.xBucketSize + j;
|
|
||||||
card.values = [];
|
|
||||||
card.columns = [];
|
|
||||||
card.multipleValues = false;
|
|
||||||
card.noColorDefined = false;
|
|
||||||
card.y = target;
|
|
||||||
card.x = -1;
|
|
||||||
|
|
||||||
// collect values from all timeseries with target
|
|
||||||
for (let si = 0; si < cardsData.targetIndex[target].length; si++) {
|
|
||||||
let s = data[cardsData.targetIndex[target][si]];
|
|
||||||
if (s.datapoints.length <= j) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let datapoint = s.datapoints[j];
|
|
||||||
if (card.values.length === 0) {
|
|
||||||
card.x = datapoint[TIME_INDEX];
|
|
||||||
}
|
|
||||||
card.values.push(datapoint[VALUE_INDEX]);
|
|
||||||
}
|
|
||||||
card.minValue = _.min(card.values);
|
|
||||||
card.maxValue = _.max(card.values);
|
|
||||||
if (card.values.length > 1) {
|
|
||||||
cardsData.multipleValues = true;
|
|
||||||
card.multipleValues = true;
|
|
||||||
card.value = this.panel.seriesFilterIndex != -1 ? card.values[this.panel.seriesFilterIndex] : card.maxValue;
|
|
||||||
} else {
|
|
||||||
card.value = card.maxValue; // max value by default
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cardsData.maxValue < card.maxValue)
|
|
||||||
cardsData.maxValue = card.maxValue;
|
|
||||||
|
|
||||||
if (cardsData.minValue > card.minValue)
|
|
||||||
cardsData.minValue = card.minValue;
|
|
||||||
|
|
||||||
if (card.x != -1) {
|
|
||||||
cardsData.cards.push(card);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cardsData;
|
let targetIndex: {[target: string]: number[]} = {};
|
||||||
|
|
||||||
|
// Group indicies of elements in data by target (y label).
|
||||||
|
|
||||||
|
// lodash version:
|
||||||
|
//_.map(data, (d, i) => {
|
||||||
|
// targetIndex[d.target] = _.concat(_.toArray(targetIndex[d.target]), i);
|
||||||
|
//});
|
||||||
|
|
||||||
|
data.map((queryResult: any, i: number) => {
|
||||||
|
let yLabel = queryResult.target;
|
||||||
|
if (!targetIndex.hasOwnProperty(yLabel)) {
|
||||||
|
targetIndex[yLabel] = [];
|
||||||
|
}
|
||||||
|
targetIndex[yLabel].push(i);
|
||||||
|
});
|
||||||
|
|
||||||
|
let targetKeys = _.keys(targetIndex);
|
||||||
|
|
||||||
|
//console.log ("targetIndex: ", targetIndex, "targetKeys: ", targetKeys);
|
||||||
|
|
||||||
|
let targetTimestampRanges: {[target: string]: {[timestamp: number]: number[]}} = {};
|
||||||
|
|
||||||
|
// Collect all timestamps for each target.
|
||||||
|
// Make map timestamp => [from, to]. from == previous ts, to == ts from datapoint.
|
||||||
|
targetKeys.map((target) => {
|
||||||
|
let targetTimestamps: any[] = [];
|
||||||
|
|
||||||
|
for (let si = 0; si < targetIndex[target].length; si++) {
|
||||||
|
let s = data[targetIndex[target][si]];
|
||||||
|
_.map(s.datapoints, (datapoint, idx) => {
|
||||||
|
targetTimestamps.push(datapoint[TIME_INDEX]-from);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log("timestamps['"+target+"'] = ", targetTimestamps);
|
||||||
|
|
||||||
|
targetTimestamps = _.uniq(targetTimestamps);
|
||||||
|
|
||||||
|
//console.log("uniq timestamps['"+target+"'] = ", targetTimestamps);
|
||||||
|
|
||||||
|
targetTimestampRanges[target] = [];
|
||||||
|
for (let i = targetTimestamps.length-1 ; i>=0; i-- ) {
|
||||||
|
let tsTo = targetTimestamps[i];
|
||||||
|
let tsFrom = 0;
|
||||||
|
if (tsTo < 0) {
|
||||||
|
tsFrom = tsTo - intervalMs;
|
||||||
|
} else {
|
||||||
|
if (i-1 >= 0) {
|
||||||
|
// Set from to previous timestamp + 1ms;
|
||||||
|
tsFrom = targetTimestamps[i-1]+1;
|
||||||
|
// tfTo - tfFrom should not be more than intervalMs
|
||||||
|
let minFrom = tsTo - intervalMs;
|
||||||
|
if (tsFrom < minFrom) {
|
||||||
|
tsFrom = minFrom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
targetTimestampRanges[target][tsTo] = [tsFrom, tsTo];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// console.log ("targetTimestampRanges: ", targetTimestampRanges);
|
||||||
|
|
||||||
|
// Create empty buckets using intervalMs to calculate ranges.
|
||||||
|
// If mostRecentBucket is set, create a bucket with a range "to":"to"
|
||||||
|
// to store most recent values.
|
||||||
|
targetKeys.map((target) => {
|
||||||
|
let targetEmptyBuckets: any[] = [];
|
||||||
|
|
||||||
|
let lastTs = to-from;
|
||||||
|
|
||||||
|
if (mostRecentBucket) {
|
||||||
|
let topBucket = new Bucket();
|
||||||
|
topBucket.yLabel = target;
|
||||||
|
topBucket.relTo = lastTs;
|
||||||
|
topBucket.relFrom = lastTs;
|
||||||
|
topBucket.values = [];
|
||||||
|
topBucket.mostRecent = true;
|
||||||
|
if (targetTimestampRanges[target].hasOwnProperty(lastTs)) {
|
||||||
|
topBucket.relFrom = targetTimestampRanges[target][lastTs][0];
|
||||||
|
lastTs = topBucket.relFrom;
|
||||||
|
}
|
||||||
|
topBucket.to = topBucket.relTo+from;
|
||||||
|
topBucket.from = topBucket.relFrom+from;
|
||||||
|
targetEmptyBuckets.push(topBucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
let idx = 0;
|
||||||
|
let bucketFrom: number = 0;
|
||||||
|
while (bucketFrom >= 0) {
|
||||||
|
let b = new Bucket();
|
||||||
|
b.yLabel = target;
|
||||||
|
b.relTo = lastTs - idx*intervalMs;
|
||||||
|
b.relFrom = lastTs - ((idx+1) * intervalMs);
|
||||||
|
b.to = b.relTo+from;
|
||||||
|
b.from = b.relFrom+from;
|
||||||
|
b.values = [];
|
||||||
|
bucketFrom = b.relFrom;
|
||||||
|
targetEmptyBuckets.push(b);
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetEmptyBuckets.map((bucket, i) => {
|
||||||
|
bucket.xid = i;
|
||||||
|
});
|
||||||
|
|
||||||
|
bucketMatrix.buckets[target] = targetEmptyBuckets;
|
||||||
|
});
|
||||||
|
|
||||||
|
//console.log ("bucketMatrix: ", bucketMatrix);
|
||||||
|
|
||||||
|
// Put values into buckets.
|
||||||
|
bucketMatrix.minValue = Number.MAX_VALUE;
|
||||||
|
bucketMatrix.maxValue = Number.MIN_SAFE_INTEGER;
|
||||||
|
targetKeys.map((target) => {
|
||||||
|
targetIndex[target].map((dataIndex) => {
|
||||||
|
let s = data[dataIndex];
|
||||||
|
s.datapoints.map((dp: any) => {
|
||||||
|
for (let i = 0; i < bucketMatrix.buckets[target].length; i++) {
|
||||||
|
if (bucketMatrix.buckets[target][i].belong(dp[TIME_INDEX])) {
|
||||||
|
bucketMatrix.buckets[target][i].put(dp[VALUE_INDEX]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
bucketMatrix.buckets[target].map((bucket) => {
|
||||||
|
bucket.minValue = _.min(bucket.values);
|
||||||
|
bucket.maxValue = _.max(bucket.values);
|
||||||
|
if (bucket.minValue < bucketMatrix.minValue) {
|
||||||
|
bucketMatrix.minValue = bucket.minValue;
|
||||||
|
}
|
||||||
|
if (bucket.maxValue > bucketMatrix.maxValue) {
|
||||||
|
bucketMatrix.maxValue = bucket.maxValue;
|
||||||
|
}
|
||||||
|
bucket.value = bucket.maxValue;
|
||||||
|
if (bucket.values.length > 1) {
|
||||||
|
bucketMatrix.multipleValues = true;
|
||||||
|
bucket.multipleValues = true;
|
||||||
|
|
||||||
|
bucket.value = this.panel.seriesFilterIndex != -1 ? bucket.values[this.panel.seriesFilterIndex] : bucket.maxValue;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
bucketMatrix.xBucketSize = Number.MIN_SAFE_INTEGER;
|
||||||
|
targetKeys.map((target) => {
|
||||||
|
let bucketsLen: number = bucketMatrix.buckets[target].length;
|
||||||
|
if (bucketsLen > bucketMatrix.xBucketSize) {
|
||||||
|
bucketMatrix.xBucketSize = bucketsLen;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//console.log ("bucketMatrix with values: ", bucketMatrix);
|
||||||
|
|
||||||
|
bucketMatrix.targets = targetKeys;
|
||||||
|
return bucketMatrix;
|
||||||
|
this.bucketMatrix = bucketMatrix;
|
||||||
|
|
||||||
|
// Collect all values for each bucket from datapoints with similar target.
|
||||||
|
// TODO aggregate values into buckets over datapoint[TIME_INDEX] not over datapoint index (j).
|
||||||
|
|
||||||
|
|
||||||
|
// for(let i = 0; i < cardsData.targets.length; i++) {
|
||||||
|
// let target = cardsData.targets[i];
|
||||||
|
|
||||||
|
// for (let j = 0; j < cardsData.xBucketSize; j++) {
|
||||||
|
// let card = new Card();
|
||||||
|
// card.id = i*cardsData.xBucketSize + j;
|
||||||
|
// card.values = [];
|
||||||
|
// card.y = target;
|
||||||
|
// card.x = -1;
|
||||||
|
|
||||||
|
// // collect values from all timeseries with target
|
||||||
|
// for (let si = 0; si < cardsData.targetIndex[target].length; si++) {
|
||||||
|
// let s = data[cardsData.targetIndex[target][si]];
|
||||||
|
// if (s.datapoints.length <= j) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// let datapoint = s.datapoints[j];
|
||||||
|
// if (card.values.length === 0) {
|
||||||
|
// card.x = datapoint[TIME_INDEX];
|
||||||
|
// }
|
||||||
|
// card.values.push(datapoint[VALUE_INDEX]);
|
||||||
|
// }
|
||||||
|
// card.minValue = _.min(card.values);
|
||||||
|
// card.maxValue = _.max(card.values);
|
||||||
|
// if (card.values.length > 1) {
|
||||||
|
// cardsData.multipleValues = true;
|
||||||
|
// card.multipleValues = true;
|
||||||
|
// card.value = card.maxValue; // max value by default
|
||||||
|
// } else {
|
||||||
|
// card.value = card.maxValue; // max value by default
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (cardsData.maxValue < card.maxValue)
|
||||||
|
// cardsData.maxValue = card.maxValue;
|
||||||
|
|
||||||
|
// if (cardsData.minValue > card.minValue)
|
||||||
|
// cardsData.minValue = card.minValue;
|
||||||
|
|
||||||
|
// if (card.x != -1) {
|
||||||
|
// cardsData.cards.push(card);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// let cardsData = <CardsStorage> {
|
||||||
|
// cards: [],
|
||||||
|
// xBucketSize: 0,
|
||||||
|
// yBucketSize: 0,
|
||||||
|
// maxValue: 0,
|
||||||
|
// minValue: 0,
|
||||||
|
// multipleValues: false,
|
||||||
|
// noColorDefined: false,
|
||||||
|
// targets: [], // array of available unique targets
|
||||||
|
// targetIndex: {} // indices in data array for each of available unique targets
|
||||||
|
// };
|
||||||
|
|
||||||
|
// if (!data || data.length == 0) { return cardsData;}
|
||||||
|
|
||||||
|
// // Collect uniq timestamps from data and spread over targets and timestamps
|
||||||
|
|
||||||
|
// // collect uniq targets and their indices
|
||||||
|
// _.map(data, (d, i) => {
|
||||||
|
// cardsData.targetIndex[d.target] = _.concat(_.toArray(cardsData.targetIndex[d.target]), i)
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // TODO add some logic for targets heirarchy
|
||||||
|
// cardsData.targets = _.keys(cardsData.targetIndex);
|
||||||
|
// cardsData.yBucketSize = cardsData.targets.length;
|
||||||
|
// // Maximum number of buckets over x axis
|
||||||
|
// cardsData.xBucketSize = _.max(_.map(data, d => d.datapoints.length));
|
||||||
|
|
||||||
|
// // Collect all values for each bucket from datapoints with similar target.
|
||||||
|
// // TODO aggregate values into buckets over datapoint[TIME_INDEX] not over datapoint index (j).
|
||||||
|
// for(let i = 0; i < cardsData.targets.length; i++) {
|
||||||
|
// let target = cardsData.targets[i];
|
||||||
|
|
||||||
|
// for (let j = 0; j < cardsData.xBucketSize; j++) {
|
||||||
|
// let card = new Card();
|
||||||
|
// card.id = i*cardsData.xBucketSize + j;
|
||||||
|
// card.values = [];
|
||||||
|
// card.y = target;
|
||||||
|
// card.x = -1;
|
||||||
|
|
||||||
|
// // collect values from all timeseries with target
|
||||||
|
// for (let si = 0; si < cardsData.targetIndex[target].length; si++) {
|
||||||
|
// let s = data[cardsData.targetIndex[target][si]];
|
||||||
|
// if (s.datapoints.length <= j) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// let datapoint = s.datapoints[j];
|
||||||
|
// if (card.values.length === 0) {
|
||||||
|
// card.x = datapoint[TIME_INDEX];
|
||||||
|
// }
|
||||||
|
// card.values.push(datapoint[VALUE_INDEX]);
|
||||||
|
// }
|
||||||
|
// card.minValue = _.min(card.values);
|
||||||
|
// card.maxValue = _.max(card.values);
|
||||||
|
// if (card.values.length > 1) {
|
||||||
|
// cardsData.multipleValues = true;
|
||||||
|
// card.multipleValues = true;
|
||||||
|
// card.value = card.maxValue; // max value by default
|
||||||
|
// } else {
|
||||||
|
// card.value = card.maxValue; // max value by default
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (cardsData.maxValue < card.maxValue)
|
||||||
|
// cardsData.maxValue = card.maxValue;
|
||||||
|
|
||||||
|
// if (cardsData.minValue > card.minValue)
|
||||||
|
// cardsData.minValue = card.minValue;
|
||||||
|
|
||||||
|
// if (card.x != -1) {
|
||||||
|
// cardsData.cards.push(card);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return cardsData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -148,8 +148,30 @@
|
|||||||
label="Show tooltip"
|
label="Show tooltip"
|
||||||
checked="ctrl.panel.tooltip.show" on-change="ctrl.render()">
|
checked="ctrl.panel.tooltip.show" on-change="ctrl.render()">
|
||||||
</gf-form-switch>
|
</gf-form-switch>
|
||||||
<div class="gf-form">
|
<gf-form-switch class="gf-form" label-class="width-8"
|
||||||
<label class="gf-form-label width-8">Y axis sort</label>
|
label="Show X axis"
|
||||||
|
checked="ctrl.panel.xAxis.show" on-change="ctrl.render()">
|
||||||
|
</gf-form-switch>
|
||||||
|
<gf-form-switch class="gf-form" label-class="width-8"
|
||||||
|
label="Show Y axis"
|
||||||
|
checked="ctrl.panel.yAxis.show" on-change="ctrl.render()">
|
||||||
|
</gf-form-switch>
|
||||||
|
|
||||||
|
<div class="gf-form" ng-show="ctrl.panel.yAxis.show">
|
||||||
|
<label class="gf-form-label width-8">Min width</label>
|
||||||
|
<input type="number" ng-model="ctrl.panel.xAxis.minWidth" class="gf-form-input width-5" placeholder="auto" data-placement="right" bs-tooltip="''" ng-change="ctrl.render()" ng-model-onblur>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form" ng-show="ctrl.panel.yAxis.show">
|
||||||
|
<label class="gf-form-label width-8">Max width</label>
|
||||||
|
<input type="number" ng-model="ctrl.panel.xAxis.maxWidth" class="gf-form-input width-5" placeholder="auto" data-placement="right" bs-tooltip="''" ng-change="ctrl.render()" ng-model-onblur>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section gf-form-group">
|
||||||
|
<h5 class="section-heading">Buckets</h5>
|
||||||
|
|
||||||
|
<div class="gf-form" ng-show="ctrl.panel.yAxis.show">
|
||||||
|
<label class="gf-form-label width-8">Rows sort</label>
|
||||||
<div class="gf-form-select-wrapper">
|
<div class="gf-form-select-wrapper">
|
||||||
<select class="gf-form-input max-width-8"
|
<select class="gf-form-input max-width-8"
|
||||||
ng-model="ctrl.panel.yAxisSort"
|
ng-model="ctrl.panel.yAxisSort"
|
||||||
@@ -157,12 +179,8 @@
|
|||||||
ng-change="ctrl.render()"></select>
|
ng-change="ctrl.render()"></select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="section gf-form-group">
|
<gf-form-switch class="gf-form" label-class="width-8"
|
||||||
<h5 class="section-heading">Bucket</h5>
|
|
||||||
|
|
||||||
<gf-form-switch class="gf-form" label-class="width-9"
|
|
||||||
label="Multiple values"
|
label="Multiple values"
|
||||||
checked="ctrl.panel.useMax" on-change="ctrl.render()">
|
checked="ctrl.panel.useMax" on-change="ctrl.render()">
|
||||||
</gf-form-switch>
|
</gf-form-switch>
|
||||||
@@ -171,25 +189,25 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-9">Display nulls</label>
|
<label class="gf-form-label width-8">Display nulls</label>
|
||||||
<div class="gf-form-select-wrapper">
|
<div class="gf-form-select-wrapper">
|
||||||
<select class="gf-form-input max-width-9" ng-model="ctrl.panel.nullPointMode" ng-options="f for f in ['as empty', 'as zero']" ng-change="ctrl.render()"></select>
|
<select class="gf-form-input max-width-9" ng-model="ctrl.panel.nullPointMode" ng-options="f for f in ['as empty', 'as zero']" ng-change="ctrl.render()"></select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-9">Min width for 1/1</label>
|
<label class="gf-form-label width-8">Min width</label>
|
||||||
<input type="number" class="gf-form-input width-5" placeholder="5" data-placement="right" bs-tooltip="'Minimal card width for 1/1 resolution in pixels'" ng-model="ctrl.panel.cards.cardMinWidth" ng-change="ctrl.refresh()" ng-model-onblur>
|
<input type="number" class="gf-form-input width-5" placeholder="5" data-placement="right" bs-tooltip="'Minimal card width for 1/1 resolution in pixels'" ng-model="ctrl.panel.cards.cardMinWidth" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-9">V spacing</label>
|
<label class="gf-form-label width-8">V spacing</label>
|
||||||
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Cards vertical spacing in pixels'" ng-model="ctrl.panel.cards.cardVSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
|
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Cards vertical spacing in pixels'" ng-model="ctrl.panel.cards.cardVSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-9">H spacing</label>
|
<label class="gf-form-label width-8">H spacing</label>
|
||||||
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Cards horizontal spacing in pixels'" ng-model="ctrl.panel.cards.cardHSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
|
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Cards horizontal spacing in pixels'" ng-model="ctrl.panel.cards.cardHSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-9">Rounding</label>
|
<label class="gf-form-label width-8">Rounding</label>
|
||||||
<input type="number" class="gf-form-input width-5" placeholder="0" data-placement="right" bs-tooltip="'Cards rounding radius in pixels'" ng-model="ctrl.panel.cards.cardRound" ng-change="ctrl.refresh()" ng-model-onblur>
|
<input type="number" class="gf-form-input width-5" placeholder="0" data-placement="right" bs-tooltip="'Cards rounding radius in pixels'" ng-model="ctrl.panel.cards.cardRound" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+97
-66
@@ -9,6 +9,8 @@ import * as d3ScaleChromatic from './libs/d3-scale-chromatic/index';
|
|||||||
import {StatusmapTooltip} from './tooltip';
|
import {StatusmapTooltip} from './tooltip';
|
||||||
import {StatusHeatmapTooltipExtraSeries} from './tooltipextraseries';
|
import {StatusHeatmapTooltipExtraSeries} from './tooltipextraseries';
|
||||||
import {AnnotationTooltip} from './annotations';
|
import {AnnotationTooltip} from './annotations';
|
||||||
|
import { Bucket, BucketMatrix } from './statusmap_data';
|
||||||
|
import { StatusHeatmapCtrl } from './module';
|
||||||
|
|
||||||
let MIN_CARD_SIZE = 5,
|
let MIN_CARD_SIZE = 5,
|
||||||
CARD_H_SPACING = 2,
|
CARD_H_SPACING = 2,
|
||||||
@@ -25,6 +27,18 @@ export default function rendering(scope: any, elem: any, attrs: any, ctrl: any)
|
|||||||
return new StatusmapRenderer(scope, elem, attrs, ctrl);
|
return new StatusmapRenderer(scope, elem, attrs, ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Statusmap {
|
||||||
|
$svg: any;
|
||||||
|
svg: any;
|
||||||
|
bucketMatrix: BucketMatrix;
|
||||||
|
|
||||||
|
timeRange: {from: number, to: number} = {from:0, to:0};
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class StatusmapRenderer {
|
export class StatusmapRenderer {
|
||||||
width: number = 0;
|
width: number = 0;
|
||||||
height: number = 0;
|
height: number = 0;
|
||||||
@@ -46,8 +60,8 @@ export class StatusmapRenderer {
|
|||||||
mouseUpHandler: any;
|
mouseUpHandler: any;
|
||||||
xGridSize: number = 0;
|
xGridSize: number = 0;
|
||||||
yGridSize: number = 0;
|
yGridSize: number = 0;
|
||||||
data: any;
|
|
||||||
cardsData: any;
|
bucketMatrix: BucketMatrix;
|
||||||
panel: any;
|
panel: any;
|
||||||
$heatmap: any;
|
$heatmap: any;
|
||||||
tooltip: StatusmapTooltip;
|
tooltip: StatusmapTooltip;
|
||||||
@@ -62,9 +76,9 @@ export class StatusmapRenderer {
|
|||||||
margin: any;
|
margin: any;
|
||||||
dataRangeWidingFactor: number = DATA_RANGE_WIDING_FACTOR;
|
dataRangeWidingFactor: number = DATA_RANGE_WIDING_FACTOR;
|
||||||
|
|
||||||
constructor(private scope: any, private elem: any, attrs: any, private ctrl: any) {
|
constructor(private scope: any, private elem: any, attrs: any, private ctrl: StatusHeatmapCtrl) {
|
||||||
// $heatmap is JQuery object, but heatmap is D3
|
// $heatmap is JQuery object, but heatmap is D3
|
||||||
this.$heatmap = this.elem.find('.status-heatmap-panel');
|
this.$heatmap = this.elem.find('.statusmap-panel');
|
||||||
this.tooltip = new StatusmapTooltip(this.$heatmap, this.scope);
|
this.tooltip = new StatusmapTooltip(this.$heatmap, this.scope);
|
||||||
this.tooltipExtraSeries = new StatusHeatmapTooltipExtraSeries(this.$heatmap, this.scope);
|
this.tooltipExtraSeries = new StatusHeatmapTooltipExtraSeries(this.$heatmap, this.scope);
|
||||||
this.annotationTooltip = new AnnotationTooltip(this.$heatmap, this.scope);
|
this.annotationTooltip = new AnnotationTooltip(this.$heatmap, this.scope);
|
||||||
@@ -88,7 +102,8 @@ export class StatusmapRenderer {
|
|||||||
// Selection and crosshair //
|
// Selection and crosshair //
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
|
|
||||||
// Shared crosshair and tooltip
|
// Shared crosshair and tooltip this.empty = true;
|
||||||
|
|
||||||
appEvents.on('graph-hover', this.onGraphHover.bind(this), this.scope);
|
appEvents.on('graph-hover', this.onGraphHover.bind(this), this.scope);
|
||||||
|
|
||||||
appEvents.on('graph-hover-clear', this.onGraphHoverClear.bind(this), this.scope);
|
appEvents.on('graph-hover-clear', this.onGraphHoverClear.bind(this), this.scope);
|
||||||
@@ -114,7 +129,7 @@ export class StatusmapRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
setElementHeight() {
|
setElementHeight(): boolean {
|
||||||
try {
|
try {
|
||||||
var height = this.ctrl.height || this.panel.height || this.ctrl.row.height;
|
var height = this.ctrl.height || this.panel.height || this.ctrl.row.height;
|
||||||
if (_.isString(height)) {
|
if (_.isString(height)) {
|
||||||
@@ -131,7 +146,7 @@ export class StatusmapRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getYAxisWidth(elem: any) {
|
getYAxisWidth(elem: any): number {
|
||||||
const axisText = elem.selectAll(".axis-y text").nodes();
|
const axisText = elem.selectAll(".axis-y text").nodes();
|
||||||
const maxTextWidth = _.max(_.map(axisText, text => {
|
const maxTextWidth = _.max(_.map(axisText, text => {
|
||||||
// Use SVG getBBox method
|
// Use SVG getBBox method
|
||||||
@@ -141,7 +156,7 @@ export class StatusmapRenderer {
|
|||||||
return Math.ceil(maxTextWidth);
|
return Math.ceil(maxTextWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
getXAxisHeight(elem: any) {
|
getXAxisHeight(elem: any): number {
|
||||||
let axisLine = elem.select(".axis-x line");
|
let axisLine = elem.select(".axis-x line");
|
||||||
if (!axisLine.empty()) {
|
if (!axisLine.empty()) {
|
||||||
let axisLinePosition = parseFloat(elem.select(".axis-x line").attr("y2"));
|
let axisLinePosition = parseFloat(elem.select(".axis-x line").attr("y2"));
|
||||||
@@ -155,6 +170,10 @@ export class StatusmapRenderer {
|
|||||||
|
|
||||||
addXAxis() {
|
addXAxis() {
|
||||||
// Scale timestamps to cards centers
|
// Scale timestamps to cards centers
|
||||||
|
//this.scope.xScale = this.xScale = d3.scaleTime()
|
||||||
|
// .domain([this.timeRange.from, this.timeRange.to])
|
||||||
|
// .range([this.xGridSize/2, this.chartWidth-this.xGridSize/2]);
|
||||||
|
// Buckets without the most recent
|
||||||
this.scope.xScale = this.xScale = d3.scaleTime()
|
this.scope.xScale = this.xScale = d3.scaleTime()
|
||||||
.domain([this.timeRange.from, this.timeRange.to])
|
.domain([this.timeRange.from, this.timeRange.to])
|
||||||
.range([this.xGridSize/2, this.chartWidth-this.xGridSize/2]);
|
.range([this.xGridSize/2, this.chartWidth-this.xGridSize/2]);
|
||||||
@@ -192,7 +211,7 @@ export class StatusmapRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// divide chart height by ticks for cards drawing
|
// divide chart height by ticks for cards drawing
|
||||||
getYScale(ticks) {
|
getYScale(ticks: any[]) {
|
||||||
let range:any[] = [];
|
let range:any[] = [];
|
||||||
let step = this.chartHeight / ticks.length;
|
let step = this.chartHeight / ticks.length;
|
||||||
// svg has y=0 on the top, so top card should have a minimal value in range
|
// svg has y=0 on the top, so top card should have a minimal value in range
|
||||||
@@ -206,7 +225,7 @@ export class StatusmapRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// divide chart height by ticks with offset for ticks drawing
|
// divide chart height by ticks with offset for ticks drawing
|
||||||
getYAxisScale(ticks) {
|
getYAxisScale(ticks: any[]) {
|
||||||
let range:any[] = [];
|
let range:any[] = [];
|
||||||
let step = this.chartHeight / ticks.length;
|
let step = this.chartHeight / ticks.length;
|
||||||
// svg has y=0 on the top, so top tick should have a minimal value in range
|
// svg has y=0 on the top, so top tick should have a minimal value in range
|
||||||
@@ -220,12 +239,7 @@ export class StatusmapRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addYAxis() {
|
addYAxis() {
|
||||||
let ticks = _.uniq(_.map(this.data, d => d.target));
|
let ticks = this.bucketMatrix.targets;
|
||||||
|
|
||||||
// Set default Y min and max if no data
|
|
||||||
if (_.isEmpty(this.data)) {
|
|
||||||
ticks = [''];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.panel.yAxisSort == 'a → z') {
|
if (this.panel.yAxisSort == 'a → z') {
|
||||||
ticks.sort((a, b) => a.localeCompare(b, 'en', {ignorePunctuation: false, numeric: true}));
|
ticks.sort((a, b) => a.localeCompare(b, 'en', {ignorePunctuation: false, numeric: true}));
|
||||||
@@ -258,7 +272,7 @@ export class StatusmapRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wide Y values range and adjust to bucket size
|
// Wide Y values range and adjust to bucket size
|
||||||
wideYAxisRange(min, max, tickInterval) {
|
wideYAxisRange(min: number, max: number, tickInterval: number) {
|
||||||
let y_widing = (max * (this.dataRangeWidingFactor - 1) - min * (this.dataRangeWidingFactor - 1)) / 2;
|
let y_widing = (max * (this.dataRangeWidingFactor - 1) - min * (this.dataRangeWidingFactor - 1)) / 2;
|
||||||
let y_min, y_max;
|
let y_min, y_max;
|
||||||
|
|
||||||
@@ -288,7 +302,7 @@ export class StatusmapRenderer {
|
|||||||
|
|
||||||
// Create svg element, add axes and
|
// Create svg element, add axes and
|
||||||
// calculate sizes for cards drawing
|
// calculate sizes for cards drawing
|
||||||
addHeatmapCanvas() {
|
addStatusmapCanvas() {
|
||||||
let heatmap_elem = this.$heatmap[0];
|
let heatmap_elem = this.$heatmap[0];
|
||||||
|
|
||||||
this.width = Math.floor(this.$heatmap.width()) - this.padding.right;
|
this.width = Math.floor(this.$heatmap.width()) - this.padding.right;
|
||||||
@@ -312,7 +326,10 @@ export class StatusmapRenderer {
|
|||||||
this.cardRound = this.panel.cards.cardRound !== null ? this.panel.cards.cardRound : CARD_ROUND;
|
this.cardRound = this.panel.cards.cardRound !== null ? this.panel.cards.cardRound : CARD_ROUND;
|
||||||
|
|
||||||
// calculate yOffset for YAxis
|
// calculate yOffset for YAxis
|
||||||
this.yGridSize = Math.floor(this.chartHeight / this.cardsData.yBucketSize);
|
this.yGridSize = this.chartHeight;
|
||||||
|
if (this.bucketMatrix.targets.length > 0) {
|
||||||
|
this.yGridSize = Math.floor(this.chartHeight / this.bucketMatrix.targets.length);
|
||||||
|
}
|
||||||
this.cardHeight = this.yGridSize ? this.yGridSize - this.cardVSpacing : 0;
|
this.cardHeight = this.yGridSize ? this.yGridSize - this.cardVSpacing : 0;
|
||||||
this.yOffset = this.cardHeight / 2;
|
this.yOffset = this.cardHeight / 2;
|
||||||
|
|
||||||
@@ -323,7 +340,7 @@ export class StatusmapRenderer {
|
|||||||
|
|
||||||
// TODO allow per-y cardWidth!
|
// TODO allow per-y cardWidth!
|
||||||
// we need to fill chartWidth with xBucketSize cards.
|
// we need to fill chartWidth with xBucketSize cards.
|
||||||
this.xGridSize = this.chartWidth / (this.cardsData.xBucketSize+1);
|
this.xGridSize = this.chartWidth / (this.bucketMatrix.xBucketSize+1);
|
||||||
this.cardWidth = this.xGridSize - this.cardHSpacing;
|
this.cardWidth = this.xGridSize - this.cardHSpacing;
|
||||||
|
|
||||||
this.addXAxis();
|
this.addXAxis();
|
||||||
@@ -338,36 +355,41 @@ export class StatusmapRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addHeatmap() {
|
addStatusmap():void {
|
||||||
this.addHeatmapCanvas();
|
let maxValue = this.panel.color.max || this.bucketMatrix.maxValue;
|
||||||
|
let minValue = this.panel.color.min || this.bucketMatrix.minValue;
|
||||||
let maxValue = this.panel.color.max || this.cardsData.maxValue;
|
|
||||||
let minValue = this.panel.color.min || this.cardsData.minValue;
|
|
||||||
|
|
||||||
if (this.panel.color.mode !== 'discrete') {
|
if (this.panel.color.mode !== 'discrete') {
|
||||||
this.colorScale = this.getColorScale(maxValue, minValue);
|
this.colorScale = this.getColorScale(maxValue, minValue);
|
||||||
}
|
}
|
||||||
this.setOpacityScale(maxValue);
|
this.setOpacityScale(maxValue);
|
||||||
|
|
||||||
let cards = this.heatmap.selectAll(".status-heatmap-card").data(this.cardsData.cards);
|
// Draw cards from buckets.
|
||||||
cards.append("title");
|
this.heatmap.selectAll(".statusmap-cards-row").data(this.bucketMatrix.targets)
|
||||||
cards = cards.enter().append("rect")
|
.enter()
|
||||||
.attr("cardId", c => c.id)
|
.selectAll(".statustmap-card")
|
||||||
.attr("x", this.getCardX.bind(this))
|
.data((target:string) => this.bucketMatrix.buckets[target])
|
||||||
.attr("width", this.getCardWidth.bind(this))
|
.enter()
|
||||||
.attr("y", this.getCardY.bind(this))
|
.append("rect")
|
||||||
.attr("height", this.getCardHeight.bind(this))
|
.attr("cardId", (b:Bucket) => b.id)
|
||||||
.attr("rx", this.cardRound)
|
.attr("xid", (b:Bucket) => b.xid)
|
||||||
.attr("ry", this.cardRound)
|
.attr("yid", (b:Bucket) => b.yLabel)
|
||||||
.attr("class", "bordered status-heatmap-card")
|
.attr("x", this.getCardX.bind(this))
|
||||||
.style("fill", this.getCardColor.bind(this))
|
.attr("width", this.getCardWidth.bind(this))
|
||||||
.style("stroke", this.getCardColor.bind(this))
|
.attr("y", this.getCardY.bind(this))
|
||||||
.style("stroke-width", 0)
|
.attr("height", this.getCardHeight.bind(this))
|
||||||
//.style("stroke-width", getCardStrokeWidth)
|
.attr("rx", this.cardRound)
|
||||||
//.style("stroke-dasharray", "3,3")
|
.attr("ry", this.cardRound)
|
||||||
.style("opacity", this.getCardOpacity.bind(this));
|
.attr("class", (b:Bucket) => b.isEmpty() ? "empty-card" : "bordered statusmap-card")
|
||||||
|
.style("fill", this.getCardColor.bind(this))
|
||||||
|
.style("stroke", this.getCardColor.bind(this))
|
||||||
|
.style("stroke-width", 0)
|
||||||
|
//.style("stroke-width", getCardStrokeWidth)
|
||||||
|
//.style("stroke-dasharray", "3,3")
|
||||||
|
.style("opacity", this.getCardOpacity.bind(this));
|
||||||
|
|
||||||
let $cards = this.$heatmap.find(".status-heatmap-card");
|
// Set mouse events on cards.
|
||||||
|
let $cards = this.$heatmap.find(".statusmap-card + .bordered");
|
||||||
$cards
|
$cards
|
||||||
.on("mouseenter", (event) => {
|
.on("mouseenter", (event) => {
|
||||||
this.tooltip.mouseOverBucket = true;
|
this.tooltip.mouseOverBucket = true;
|
||||||
@@ -434,10 +456,12 @@ export class StatusmapRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getCardX(d) {
|
getCardX(b: Bucket) {
|
||||||
let x;
|
let x;
|
||||||
// cx is the center of the card. Card should be placed to the left.
|
// cx is the center of the card. Card should be placed to the left.
|
||||||
let cx = this.xScale(d.x);
|
//let cx = this.xScale(d.x);
|
||||||
|
let rightX = (b.relTo / this.bucketMatrix.rangeMs) * this.chartWidth;
|
||||||
|
let cx = rightX - this.cardWidth/2;
|
||||||
|
|
||||||
if (cx - this.cardWidth/2 < 0) {
|
if (cx - this.cardWidth/2 < 0) {
|
||||||
x = this.yAxisWidth + this.cardHSpacing/2;
|
x = this.yAxisWidth + this.cardHSpacing/2;
|
||||||
@@ -449,9 +473,13 @@ export class StatusmapRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// xScale returns card center. Adjust cardWidth in case of overlaping.
|
// xScale returns card center. Adjust cardWidth in case of overlaping.
|
||||||
getCardWidth(d) {
|
getCardWidth(b: Bucket) {
|
||||||
|
//return 20;
|
||||||
let w;
|
let w;
|
||||||
let cx = this.xScale(d.x);
|
|
||||||
|
let rightX = (b.relTo / this.bucketMatrix.rangeMs) * this.chartWidth;
|
||||||
|
let cx = rightX - this.cardWidth/2;
|
||||||
|
//let cx = this.xScale(d.x);
|
||||||
|
|
||||||
if (cx < this.cardWidth/2) {
|
if (cx < this.cardWidth/2) {
|
||||||
// Center should not exceed half of card.
|
// Center should not exceed half of card.
|
||||||
@@ -475,12 +503,16 @@ export class StatusmapRenderer {
|
|||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCardY(d) {
|
// Top y for card.
|
||||||
return this.yScale(d.y) + this.chartTop - this.cardHeight - this.cardVSpacing/2;
|
// yScale gives ???
|
||||||
|
//
|
||||||
|
getCardY(b: Bucket) {
|
||||||
|
return this.yScale(b.yLabel) + this.chartTop - this.cardHeight - this.cardVSpacing/2;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCardHeight(d) {
|
getCardHeight(b: Bucket) {
|
||||||
let ys = this.yScale(d.y);
|
//return 20;
|
||||||
|
let ys = this.yScale(b.yLabel);
|
||||||
let y = ys + this.chartTop - this.cardHeight - this.cardVSpacing/2;
|
let y = ys + this.chartTop - this.cardHeight - this.cardVSpacing/2;
|
||||||
let h = this.cardHeight;
|
let h = this.cardHeight;
|
||||||
|
|
||||||
@@ -505,32 +537,32 @@ export class StatusmapRenderer {
|
|||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCardColor(d) {
|
getCardColor(b: Bucket) {
|
||||||
if (this.panel.color.mode === 'opacity') {
|
if (this.panel.color.mode === 'opacity') {
|
||||||
return this.panel.color.cardColor;
|
return this.panel.color.cardColor;
|
||||||
} else if (this.panel.color.mode === 'spectrum') {
|
} else if (this.panel.color.mode === 'spectrum') {
|
||||||
return this.colorScale(d.value);
|
return this.colorScale(b.value);
|
||||||
} else if (this.panel.color.mode === 'discrete') {
|
} else if (this.panel.color.mode === 'discrete') {
|
||||||
if (this.panel.seriesFilterIndex != -1 || this.panel.seriesFilterIndex != null) {
|
if (this.panel.seriesFilterIndex != -1 || this.panel.seriesFilterIndex != null) {
|
||||||
return this.ctrl.discreteExtraSeries.getBucketColorSingle(d.values[this.panel.seriesFilterIndex]);
|
return this.ctrl.discreteExtraSeries.getBucketColorSingle(b.values[this.panel.seriesFilterIndex]);
|
||||||
} else {
|
} else {
|
||||||
return this.ctrl.discreteExtraSeries.getBucketColor(d.values);
|
return this.ctrl.discreteExtraSeries.getBucketColor(b.values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getCardOpacity(d) {
|
getCardOpacity(b: Bucket) {
|
||||||
if (this.panel.nullPointMode === 'as empty' && d.value == null ) {
|
if (this.panel.nullPointMode === 'as empty' && b.value == null ) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (this.panel.color.mode === 'opacity') {
|
if (this.panel.color.mode === 'opacity') {
|
||||||
return this.opacityScale(d.value);
|
return this.opacityScale(b.value);
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getCardStrokeWidth(d) {
|
getCardStrokeWidth(b: Bucket) {
|
||||||
if (this.panel.color.mode === 'discrete') {
|
if (this.panel.color.mode === 'discrete') {
|
||||||
return '1';
|
return '1';
|
||||||
}
|
}
|
||||||
@@ -609,7 +641,7 @@ export class StatusmapRenderer {
|
|||||||
//const pos = this.getEventPos(event, offset);
|
//const pos = this.getEventPos(event, offset);
|
||||||
this.emitGraphHoverEvent(event);
|
this.emitGraphHoverEvent(event);
|
||||||
this.drawCrosshair(offset.x);
|
this.drawCrosshair(offset.x);
|
||||||
this.tooltip.show(event); //, data); // pos, this.data
|
this.tooltip.show(event);
|
||||||
this.annotationTooltip.show(event);
|
this.annotationTooltip.show(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -725,22 +757,21 @@ export class StatusmapRenderer {
|
|||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
this.data = this.ctrl.data;
|
|
||||||
this.panel = this.ctrl.panel;
|
this.panel = this.ctrl.panel;
|
||||||
this.timeRange = this.ctrl.range;
|
this.timeRange = this.ctrl.range;
|
||||||
this.cardsData = this.ctrl.cardsData;
|
this.bucketMatrix = this.ctrl.bucketMatrix;
|
||||||
|
|
||||||
if (!this.data || !this.cardsData || !this.setElementHeight()) {
|
if (!this.bucketMatrix || !this.setElementHeight()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw default axes and return if no data
|
// Draw default axes and return if no data
|
||||||
if (_.isEmpty(this.cardsData.cards)) {
|
this.addStatusmapCanvas();
|
||||||
this.addHeatmapCanvas();
|
if (this.bucketMatrix.noDatapoints) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addHeatmap();
|
this.addStatusmap();
|
||||||
this.scope.yAxisWidth = this.yAxisWidth;
|
this.scope.yAxisWidth = this.yAxisWidth;
|
||||||
this.scope.xAxisHeight = this.xAxisHeight;
|
this.scope.xAxisHeight = this.xAxisHeight;
|
||||||
this.scope.chartHeight = this.chartHeight;
|
this.scope.chartHeight = this.chartHeight;
|
||||||
|
|||||||
+91
-41
@@ -1,46 +1,96 @@
|
|||||||
|
// A holder of a group of values
|
||||||
|
class Bucket {
|
||||||
|
// uniq id
|
||||||
|
id: number = 0;
|
||||||
|
// Array of values in this bucket
|
||||||
|
values: any[] = [];
|
||||||
|
columns: any[] = []; // From pr/86
|
||||||
|
// a bucket has multiple values
|
||||||
|
multipleValues: boolean = false;
|
||||||
|
// a bucket has values that has no mapped color
|
||||||
|
noColorDefined: boolean = false;
|
||||||
|
// y label
|
||||||
|
y: string = "";
|
||||||
|
yLabel: string = "";
|
||||||
|
// This value can be used to calculate a x coordinate on a graph
|
||||||
|
x: number = 0;
|
||||||
|
xid: number = 0;
|
||||||
|
// a time range of this bucket
|
||||||
|
from: number = 0;
|
||||||
|
to: number = 0;
|
||||||
|
// to and from relative to real "from"
|
||||||
|
relFrom: number = 0;
|
||||||
|
relTo: number = 0;
|
||||||
|
|
||||||
|
mostRecent: boolean = false;
|
||||||
|
|
||||||
// A holder of values
|
// Saved minimum and maximum of values in this bucket
|
||||||
class Card {
|
minValue: number = 0;
|
||||||
// uniq
|
maxValue: number = 0;
|
||||||
id: number = 0;
|
// A value if multiple values is not allowed
|
||||||
// Array of values in this bucket
|
value: number = 0;
|
||||||
values: any[] = [];
|
|
||||||
columns: any[] = [];
|
|
||||||
// card has multiple values
|
|
||||||
multipleValues: boolean = false;
|
|
||||||
// card has values that has no color
|
|
||||||
noColorDefined: boolean = false;
|
|
||||||
//
|
|
||||||
y: string = "";
|
|
||||||
//
|
|
||||||
x: number = 0;
|
|
||||||
//
|
|
||||||
minValue: number = 0;
|
|
||||||
maxValue: number = 0;
|
|
||||||
value: number = 0;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
|
|
||||||
}
|
constructor() {
|
||||||
}
|
|
||||||
|
|
||||||
class CardsStorage {
|
|
||||||
cards: Card[] = [];
|
|
||||||
xBucketSize: number = 0;
|
|
||||||
yBucketSize: number = 0;
|
|
||||||
maxValue: number;
|
|
||||||
minValue: number;
|
|
||||||
multipleValues: boolean = false;
|
|
||||||
noColorDefined: boolean = false;
|
|
||||||
targets: string[] = [];
|
|
||||||
targetIndex: any;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.maxValue = 0;
|
|
||||||
this.minValue = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export {CardsStorage, Card};
|
belong(ts: number): boolean {
|
||||||
|
return ts >= this.from && ts <= this.to;
|
||||||
|
}
|
||||||
|
|
||||||
|
put(value: any) {
|
||||||
|
this.values.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
done() {
|
||||||
|
// calculate min, max, value
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmpty(): boolean {
|
||||||
|
return this.values.length == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class BucketMatrix {
|
||||||
|
// buckets for each y label
|
||||||
|
buckets: {[yLabel: string]: Bucket[]} = {};
|
||||||
|
maxValue: number = 0;
|
||||||
|
minValue: number = 0;
|
||||||
|
multipleValues: boolean = false;
|
||||||
|
noColorDefined: boolean = false;
|
||||||
|
// a flag that indicate that buckets has stub values
|
||||||
|
noDatapoints: boolean = false;
|
||||||
|
|
||||||
|
targets: string[] = [];
|
||||||
|
rangeMs: number = 0;
|
||||||
|
intervalMs: number = 0;
|
||||||
|
|
||||||
|
xBucketSize: number = 0; // TODO remove: a transition from CardsData
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
get(yid: string, xid: number): Bucket {
|
||||||
|
if (yid in this.buckets) {
|
||||||
|
if (xid in this.buckets[yid]) {
|
||||||
|
return this.buckets[yid][xid];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Bucket();
|
||||||
|
}
|
||||||
|
|
||||||
|
hasData(): boolean {
|
||||||
|
let hasData = false;
|
||||||
|
if (this.targets.length > 0) {
|
||||||
|
this.targets.map((target:string) => {
|
||||||
|
if (this.buckets[target].length > 0) {
|
||||||
|
hasData = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return hasData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {Bucket, BucketMatrix };
|
||||||
+22
-21
@@ -2,6 +2,8 @@ import d3 from 'd3';
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
import { StatusHeatmapCtrl } from './module';
|
||||||
|
|
||||||
let TOOLTIP_PADDING_X = 30;
|
let TOOLTIP_PADDING_X = 30;
|
||||||
let TOOLTIP_PADDING_Y = 5;
|
let TOOLTIP_PADDING_Y = 5;
|
||||||
|
|
||||||
@@ -9,7 +11,7 @@ export class StatusmapTooltip {
|
|||||||
tooltip: any;
|
tooltip: any;
|
||||||
scope: any;
|
scope: any;
|
||||||
dashboard: any;
|
dashboard: any;
|
||||||
panelCtrl: any;
|
panelCtrl: StatusHeatmapCtrl;
|
||||||
panel: any;
|
panel: any;
|
||||||
heatmapPanel: any;
|
heatmapPanel: any;
|
||||||
mouseOverBucket: any;
|
mouseOverBucket: any;
|
||||||
@@ -63,28 +65,26 @@ export class StatusmapTooltip {
|
|||||||
|
|
||||||
show(pos) {
|
show(pos) {
|
||||||
if (!this.panel.tooltip.show || !this.tooltip) { return; }
|
if (!this.panel.tooltip.show || !this.tooltip) { return; }
|
||||||
// shared tooltip mode
|
|
||||||
|
// TODO support for shared tooltip mode
|
||||||
if (pos.panelRelY) {
|
if (pos.panelRelY) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let cardId = d3.select(pos.target).attr('cardId');
|
let cardEl = d3.select(pos.target);
|
||||||
if (!cardId) {
|
let yid = cardEl.attr('yid');
|
||||||
|
let xid = cardEl.attr('xid');
|
||||||
|
let bucket = this.panelCtrl.bucketMatrix.get(yid, xid); // TODO string-to-number conversion for xid
|
||||||
|
if (!bucket || bucket.isEmpty()) {
|
||||||
this.destroy();
|
this.destroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let card = this.panelCtrl.cardsData.cards[cardId];
|
let timestamp = bucket.to;
|
||||||
if (!card) {
|
let name = bucket.yLabel;
|
||||||
this.destroy();
|
let value = bucket.value;
|
||||||
return;
|
let values = bucket.values;
|
||||||
}
|
|
||||||
|
|
||||||
let x = card.x;
|
|
||||||
let y = card.y;
|
|
||||||
let value = card.value;
|
|
||||||
let values = card.values;
|
|
||||||
let tooltipTimeFormat = 'YYYY-MM-DD HH:mm:ss';
|
let tooltipTimeFormat = 'YYYY-MM-DD HH:mm:ss';
|
||||||
let time = this.dashboard.formatDate(+x, tooltipTimeFormat);
|
let time = this.dashboard.formatDate(+timestamp, tooltipTimeFormat);
|
||||||
|
|
||||||
let tooltipHtml = `<div class="graph-tooltip-time">${time}</div>
|
let tooltipHtml = `<div class="graph-tooltip-time">${time}</div>
|
||||||
<div class="statusmap-histogram"></div>`;
|
<div class="statusmap-histogram"></div>`;
|
||||||
@@ -92,7 +92,7 @@ export class StatusmapTooltip {
|
|||||||
let statuses;
|
let statuses;
|
||||||
|
|
||||||
if (this.panel.color.mode === 'discrete') {
|
if (this.panel.color.mode === 'discrete') {
|
||||||
if (this.panel.seriesFilterIndex > 0) {
|
if (this.panel.seriesFilterIndex >= 0) {
|
||||||
statuses = this.panelCtrl.discreteExtraSeries.convertValueToTooltips(value);
|
statuses = this.panelCtrl.discreteExtraSeries.convertValueToTooltips(value);
|
||||||
} else {
|
} else {
|
||||||
statuses = this.panelCtrl.discreteExtraSeries.convertValuesToTooltips(values);
|
statuses = this.panelCtrl.discreteExtraSeries.convertValuesToTooltips(values);
|
||||||
@@ -106,7 +106,7 @@ export class StatusmapTooltip {
|
|||||||
}
|
}
|
||||||
tooltipHtml += `
|
tooltipHtml += `
|
||||||
<div>
|
<div>
|
||||||
name: <b>${y}</b> <br>
|
name: <b>${name}</b> <br>
|
||||||
${statusesHtml}
|
${statusesHtml}
|
||||||
<ul>
|
<ul>
|
||||||
${_.join(_.map(statuses, v => `<li style="background-color: ${v.color}" class="discrete-item">${v.tooltip}</li>`), "")}
|
${_.join(_.map(statuses, v => `<li style="background-color: ${v.color}" class="discrete-item">${v.tooltip}</li>`), "")}
|
||||||
@@ -115,12 +115,12 @@ export class StatusmapTooltip {
|
|||||||
} else {
|
} else {
|
||||||
if (values.length === 1) {
|
if (values.length === 1) {
|
||||||
tooltipHtml += `<div>
|
tooltipHtml += `<div>
|
||||||
name: <b>${y}</b> <br>
|
name: <b>${name}</b> <br>
|
||||||
value: <b>${value}</b> <br>
|
value: <b>${value}</b> <br>
|
||||||
</div>`;
|
</div>`;
|
||||||
} else {
|
} else {
|
||||||
tooltipHtml += `<div>
|
tooltipHtml += `<div>
|
||||||
name: <b>${y}</b> <br>
|
name: <b>${name}}</b> <br>
|
||||||
values:
|
values:
|
||||||
<ul>
|
<ul>
|
||||||
${_.join(_.map(values, v => `<li>${v}</li>`), "")}
|
${_.join(_.map(values, v => `<li>${v}</li>`), "")}
|
||||||
@@ -130,13 +130,14 @@ export class StatusmapTooltip {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// "Ambiguous bucket state: Multiple values!";
|
// "Ambiguous bucket state: Multiple values!";
|
||||||
if (!this.panel.useMax && card.multipleValues) {
|
if (!this.panel.useMax && bucket.multipleValues) {
|
||||||
tooltipHtml += `<div><b>Error:</b> ${this.panelCtrl.dataWarnings.multipleValues.title}</div>`;
|
tooltipHtml += `<div><b>Error:</b> ${this.panelCtrl.dataWarnings.multipleValues.title}</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Discrete mode errors
|
// Discrete mode errors
|
||||||
if (this.panel.color.mode === 'discrete') {
|
if (this.panel.color.mode === 'discrete') {
|
||||||
if (card.noColorDefined) {
|
|
||||||
|
if (bucket.noColorDefined) {
|
||||||
let badValues = this.panelCtrl.discreteExtraSeries.getNotColoredValues(values);
|
let badValues = this.panelCtrl.discreteExtraSeries.getNotColoredValues(values);
|
||||||
tooltipHtml += `<div><b>Error:</b> ${this.panelCtrl.dataWarnings.noColorDefined.title}
|
tooltipHtml += `<div><b>Error:</b> ${this.panelCtrl.dataWarnings.noColorDefined.title}
|
||||||
<br>not colored values:
|
<br>not colored values:
|
||||||
|
|||||||
Reference in New Issue
Block a user