Commit 37173bba100fe733911cfe19e9883aa8b4a6f981
Committed by
GitHub
1 parent
01108b89
Features/flot thresholds (#2412)
* Thresholds draft * Make generated thresholds unique * Code refactoring
Showing
1 changed file
with
205 additions
and
5 deletions
... | ... | @@ -33,7 +33,8 @@ export default class TbFlot { |
33 | 33 | this.ctx = ctx; |
34 | 34 | this.chartType = chartType || 'line'; |
35 | 35 | var settings = ctx.settings; |
36 | - var utils = this.ctx.$scope.$injector.get('utils'); | |
36 | + this.utils = this.ctx.$scope.$injector.get('utils'); | |
37 | + this.types = this.ctx.$scope.$injector.get('types'); | |
37 | 38 | |
38 | 39 | ctx.tooltip = $('#flot-series-tooltip'); |
39 | 40 | if (ctx.tooltip.length === 0) { |
... | ... | @@ -242,7 +243,8 @@ export default class TbFlot { |
242 | 243 | grid: { |
243 | 244 | hoverable: true, |
244 | 245 | mouseActiveRadius: 10, |
245 | - autoHighlight: ctx.tooltipIndividual === true | |
246 | + autoHighlight: ctx.tooltipIndividual === true, | |
247 | + markings: [] | |
246 | 248 | }, |
247 | 249 | selection : { mode : ctx.isMobile ? null : 'x' }, |
248 | 250 | legend : { |
... | ... | @@ -264,7 +266,7 @@ export default class TbFlot { |
264 | 266 | }; |
265 | 267 | if (settings.xaxis) { |
266 | 268 | this.xaxis.font.color = settings.xaxis.color || this.xaxis.font.color; |
267 | - this.xaxis.label = utils.customTranslation(settings.xaxis.title, settings.xaxis.title) || null; | |
269 | + this.xaxis.label = this.utils.customTranslation(settings.xaxis.title, settings.xaxis.title) || null; | |
268 | 270 | this.xaxis.labelFont.color = this.xaxis.font.color; |
269 | 271 | this.xaxis.labelFont.size = this.xaxis.font.size+2; |
270 | 272 | this.xaxis.labelFont.weight = "bold"; |
... | ... | @@ -301,7 +303,7 @@ export default class TbFlot { |
301 | 303 | this.yaxis.font.color = settings.yaxis.color || this.yaxis.font.color; |
302 | 304 | this.yaxis.min = angular.isDefined(settings.yaxis.min) ? settings.yaxis.min : null; |
303 | 305 | this.yaxis.max = angular.isDefined(settings.yaxis.max) ? settings.yaxis.max : null; |
304 | - this.yaxis.label = utils.customTranslation(settings.yaxis.title, settings.yaxis.title) || null; | |
306 | + this.yaxis.label = this.utils.customTranslation(settings.yaxis.title, settings.yaxis.title) || null; | |
305 | 307 | this.yaxis.labelFont.color = this.yaxis.font.color; |
306 | 308 | this.yaxis.labelFont.size = this.yaxis.font.size+2; |
307 | 309 | this.yaxis.labelFont.weight = "bold"; |
... | ... | @@ -364,7 +366,7 @@ export default class TbFlot { |
364 | 366 | return ''; |
365 | 367 | }; |
366 | 368 | } |
367 | - xaxis.label = utils.customTranslation(settings.xaxisSecond.title, settings.xaxisSecond.title) || null; | |
369 | + xaxis.label = this.utils.customTranslation(settings.xaxisSecond.title, settings.xaxisSecond.title) || null; | |
368 | 370 | xaxis.position = settings.xaxisSecond.axisPosition; |
369 | 371 | } |
370 | 372 | xaxis.tickLength = 0; |
... | ... | @@ -390,6 +392,10 @@ export default class TbFlot { |
390 | 392 | } |
391 | 393 | } |
392 | 394 | |
395 | + if (this.chartType === 'line' && isFinite(settings.thresholdsLineWidth)) { | |
396 | + options.grid.markingsLineWidth = settings.thresholdsLineWidth; | |
397 | + } | |
398 | + | |
393 | 399 | if (this.chartType === 'bar') { |
394 | 400 | options.series.lines = { |
395 | 401 | show: false, |
... | ... | @@ -471,6 +477,7 @@ export default class TbFlot { |
471 | 477 | var colors = []; |
472 | 478 | this.yaxes = []; |
473 | 479 | var yaxesMap = {}; |
480 | + let predefinedThresholds = [], thresholdsDatasources = []; | |
474 | 481 | |
475 | 482 | var tooltipValueFormatFunction = null; |
476 | 483 | if (this.ctx.settings.tooltipValueFormatter && this.ctx.settings.tooltipValueFormatter.length) { |
... | ... | @@ -485,6 +492,7 @@ export default class TbFlot { |
485 | 492 | var series = this.subscription.data[i]; |
486 | 493 | colors.push(series.dataKey.color); |
487 | 494 | var keySettings = series.dataKey.settings; |
495 | + | |
488 | 496 | series.dataKey.tooltipValueFormatFunction = tooltipValueFormatFunction; |
489 | 497 | if (keySettings.tooltipValueFormatter && keySettings.tooltipValueFormatter.length) { |
490 | 498 | try { |
... | ... | @@ -570,9 +578,58 @@ export default class TbFlot { |
570 | 578 | series.yaxis = series.yaxisIndex+1; |
571 | 579 | yaxis.keysInfo[i] = {hidden: false}; |
572 | 580 | yaxis.show = true; |
581 | + | |
582 | + if (keySettings.thresholds && keySettings.thresholds.length) { | |
583 | + for (let j = 0; j < keySettings.thresholds.length; j++) { | |
584 | + let threshold = keySettings.thresholds[j]; | |
585 | + if (threshold.thresholdValueSource === 'predefinedValue' && isFinite(threshold.thresholdValue)) { | |
586 | + let colorIndex = this.subscription.data.length + predefinedThresholds.length; | |
587 | + this.generateThreshold(predefinedThresholds, series.yaxis, threshold.lineWidth, threshold.color, colorIndex, threshold.thresholdValue); | |
588 | + } else if (threshold.thresholdEntityAlias && threshold.thresholdAttribute) { | |
589 | + let entityAliasId = this.ctx.aliasController.getEntityAliasId(threshold.thresholdEntityAlias); | |
590 | + if (!entityAliasId) { | |
591 | + continue; | |
592 | + } | |
593 | + | |
594 | + let datasource = thresholdsDatasources.filter((datasource) => { | |
595 | + return datasource.entityAliasId === entityAliasId; | |
596 | + })[0]; | |
597 | + | |
598 | + let dataKey = { | |
599 | + type: this.types.dataKeyType.attribute, | |
600 | + name: threshold.thresholdAttribute, | |
601 | + label: threshold.thresholdAttribute, | |
602 | + settings: { | |
603 | + yaxis: series.yaxis, | |
604 | + lineWidth: threshold.lineWidth, | |
605 | + color: threshold.color | |
606 | + }, | |
607 | + _hash: Math.random() | |
608 | + }; | |
609 | + | |
610 | + if (datasource) { | |
611 | + datasource.dataKeys.push(dataKey); | |
612 | + } else { | |
613 | + datasource = { | |
614 | + type: this.types.datasourceType.entity, | |
615 | + name: threshold.thresholdEntityAlias, | |
616 | + aliasName: threshold.thresholdEntityAlias, | |
617 | + entityAliasId: entityAliasId, | |
618 | + dataKeys: [ dataKey ] | |
619 | + }; | |
620 | + thresholdsDatasources.push(datasource); | |
621 | + } | |
622 | + } | |
623 | + } | |
624 | + } | |
573 | 625 | } |
574 | 626 | } |
575 | 627 | |
628 | + this.subscribeForThresholdsAttributes(thresholdsDatasources); | |
629 | + | |
630 | + this.options.grid.markings = predefinedThresholds; | |
631 | + this.predefinedThresholds = predefinedThresholds; | |
632 | + | |
576 | 633 | this.options.colors = colors; |
577 | 634 | this.options.yaxes = angular.copy(this.yaxes); |
578 | 635 | if (this.chartType === 'line' || this.chartType === 'bar' || this.chartType === 'state') { |
... | ... | @@ -657,6 +714,74 @@ export default class TbFlot { |
657 | 714 | return yaxis; |
658 | 715 | } |
659 | 716 | |
717 | + subscribeForThresholdsAttributes(datasources) { | |
718 | + let tbFlot = this; | |
719 | + let thresholdsSourcesSubscriptionOptions = { | |
720 | + datasources: datasources, | |
721 | + useDashboardTimewindow: false, | |
722 | + type: this.types.widgetType.latest.value, | |
723 | + callbacks: { | |
724 | + onDataUpdated: (subscription) => {tbFlot.thresholdsSourcesDataUpdated(subscription.data)} | |
725 | + } | |
726 | + }; | |
727 | + this.ctx.subscriptionApi.createSubscription(thresholdsSourcesSubscriptionOptions, true).then( | |
728 | + (subscription) => { | |
729 | + tbFlot.thresholdsSourcesSubscription = subscription; | |
730 | + } | |
731 | + ); | |
732 | + } | |
733 | + | |
734 | + thresholdsSourcesDataUpdated(data) { | |
735 | + let allThresholds = angular.copy(this.predefinedThresholds); | |
736 | + for (let i = 0; i < data.length; i++) { | |
737 | + let keyData = data[i]; | |
738 | + if (keyData && keyData.data && keyData.data[0]) { | |
739 | + let attrValue = keyData.data[0][1]; | |
740 | + if (isFinite(attrValue)) { | |
741 | + let settings = keyData.dataKey.settings; | |
742 | + let colorIndex = this.subscription.data.length + allThresholds.length; | |
743 | + this.generateThreshold(allThresholds, settings.yaxis, settings.lineWidth, settings.color, colorIndex, attrValue); | |
744 | + } | |
745 | + } | |
746 | + } | |
747 | + | |
748 | + this.options.grid.markings = allThresholds; | |
749 | + this.redrawPlot(); | |
750 | + } | |
751 | + | |
752 | + generateThreshold(existingThresholds, yaxis, lineWidth, color, defaultColorIndex, thresholdValue) { | |
753 | + let marking = {}; | |
754 | + let markingYAxis; | |
755 | + | |
756 | + if (yaxis !== 1) { | |
757 | + markingYAxis = 'y' + yaxis + 'axis'; | |
758 | + } else { | |
759 | + markingYAxis = 'yaxis'; | |
760 | + } | |
761 | + | |
762 | + if (isFinite(lineWidth)) { | |
763 | + marking.lineWidth = lineWidth; | |
764 | + } | |
765 | + | |
766 | + if (angular.isDefined(color)) { | |
767 | + marking.color = color; | |
768 | + } else { | |
769 | + marking.color = this.utils.getMaterialColor(defaultColorIndex); | |
770 | + } | |
771 | + | |
772 | + marking[markingYAxis] = { | |
773 | + from: thresholdValue, | |
774 | + to: thresholdValue | |
775 | + }; | |
776 | + | |
777 | + let similarMarkings = existingThresholds.filter((existingMarking) => { | |
778 | + return angular.equals(existingMarking[markingYAxis], marking[markingYAxis]); | |
779 | + }); | |
780 | + if (!similarMarkings.length) { | |
781 | + existingThresholds.push(marking); | |
782 | + } | |
783 | + } | |
784 | + | |
660 | 785 | update() { |
661 | 786 | if (this.updateTimeoutHandle) { |
662 | 787 | this.ctx.$scope.$timeout.cancel(this.updateTimeoutHandle); |
... | ... | @@ -982,6 +1107,12 @@ export default class TbFlot { |
982 | 1107 | "default": "left" |
983 | 1108 | }; |
984 | 1109 | } |
1110 | + if (chartType === 'graph' || chartType === 'bar') { | |
1111 | + properties["thresholdsLineWidth"] = { | |
1112 | + "title": "Default line width for all thresholds", | |
1113 | + "type": "number" | |
1114 | + }; | |
1115 | + } | |
985 | 1116 | properties["shadowSize"] = { |
986 | 1117 | "title": "Shadow size", |
987 | 1118 | "type": "number", |
... | ... | @@ -1151,6 +1282,9 @@ export default class TbFlot { |
1151 | 1282 | ] |
1152 | 1283 | }); |
1153 | 1284 | } |
1285 | + if (chartType === 'graph' || chartType === 'bar') { | |
1286 | + schema["form"].push("thresholdsLineWidth"); | |
1287 | + } | |
1154 | 1288 | schema["form"].push("shadowSize"); |
1155 | 1289 | schema["form"].push({ |
1156 | 1290 | "key": "fontColor", |
... | ... | @@ -1456,7 +1590,73 @@ export default class TbFlot { |
1456 | 1590 | }; |
1457 | 1591 | |
1458 | 1592 | var properties = schema["schema"]["properties"]; |
1593 | + | |
1459 | 1594 | if (chartType === 'graph' || chartType === 'bar') { |
1595 | + properties["thresholds"] = { | |
1596 | + "title": "Thresholds", | |
1597 | + "type": "array", | |
1598 | + "items": { | |
1599 | + "title": "Threshold", | |
1600 | + "type": "object", | |
1601 | + "properties": { | |
1602 | + "thresholdValueSource": { | |
1603 | + "title": "Threshold value source", | |
1604 | + "type": "string", | |
1605 | + "default": "predefinedValue" | |
1606 | + }, | |
1607 | + "thresholdEntityAlias": { | |
1608 | + "title": "Thresholds source entity alias", | |
1609 | + "type": "string" | |
1610 | + }, | |
1611 | + "thresholdAttribute": { | |
1612 | + "title": "Threshold source entity attribute", | |
1613 | + "type": "string" | |
1614 | + }, | |
1615 | + "thresholdValue": { | |
1616 | + "title": "Threshold value (if predefined value is selected)", | |
1617 | + "type": "number" | |
1618 | + }, | |
1619 | + "lineWidth": { | |
1620 | + "title": "Line width", | |
1621 | + "type": "number" | |
1622 | + }, | |
1623 | + "color": { | |
1624 | + "title": "Color", | |
1625 | + "type": "string" | |
1626 | + } | |
1627 | + } | |
1628 | + }, | |
1629 | + "required": [] | |
1630 | + }; | |
1631 | + schema["form"].push({ | |
1632 | + "key": "thresholds", | |
1633 | + "items": [ | |
1634 | + { | |
1635 | + "key": "thresholds[].thresholdValueSource", | |
1636 | + "type": "rc-select", | |
1637 | + "multiple": false, | |
1638 | + "items": [ | |
1639 | + { | |
1640 | + "value": "predefinedValue", | |
1641 | + "label": "Predefined value (Default)" | |
1642 | + }, | |
1643 | + { | |
1644 | + "value": "entityAttribute", | |
1645 | + "label": "Value taken from entity attribute" | |
1646 | + } | |
1647 | + ] | |
1648 | + }, | |
1649 | + "thresholds[].thresholdValue", | |
1650 | + "thresholds[].thresholdEntityAlias", | |
1651 | + "thresholds[].thresholdAttribute", | |
1652 | + { | |
1653 | + "key": "thresholds[].color", | |
1654 | + "type": "color" | |
1655 | + }, | |
1656 | + "thresholds[].lineWidth" | |
1657 | + ] | |
1658 | + }); | |
1659 | + | |
1460 | 1660 | properties["comparisonSettings"] = { |
1461 | 1661 | "title": "Comparison Settings", |
1462 | 1662 | "type": "object", | ... | ... |