Commit 2435ca5d0ff0dfd6e362de658311b00b853f759a

Authored by Andrew Shvayka
2 parents 10d39d20 34c6c30e

Merge remote-tracking branch 'origin/master' into asset-alarm-mgmt

... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>common</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.common</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>common</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.common</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>common</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.common</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard</groupId>
... ...
... ... @@ -22,7 +22,7 @@
22 22 <modelVersion>4.0.0</modelVersion>
23 23 <parent>
24 24 <groupId>org.thingsboard</groupId>
25   - <version>1.2.3</version>
  25 + <version>1.3.0-SNAPSHOT</version>
26 26 <artifactId>extensions</artifactId>
27 27 </parent>
28 28 <groupId>org.thingsboard.extensions</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>extensions</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.extensions</groupId>
... ...
... ... @@ -22,7 +22,7 @@
22 22 <modelVersion>4.0.0</modelVersion>
23 23 <parent>
24 24 <groupId>org.thingsboard</groupId>
25   - <version>1.2.3</version>
  25 + <version>1.3.0-SNAPSHOT</version>
26 26 <artifactId>extensions</artifactId>
27 27 </parent>
28 28 <groupId>org.thingsboard.extensions</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <groupId>org.thingsboard</groupId>
22 22 <artifactId>thingsboard</artifactId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <packaging>pom</packaging>
25 25
26 26 <name>Thingsboard</name>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>transport</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.transport</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>transport</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.transport</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>transport</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.transport</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard</groupId>
... ...
1 1 {
2 2 "name": "thingsboard",
3 3 "private": true,
4   - "version": "1.2.3",
  4 + "version": "1.3.0",
5 5 "description": "Thingsboard UI",
6 6 "licenses": [
7 7 {
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>1.2.3</version>
  23 + <version>1.3.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard</groupId>
... ...
... ... @@ -126,6 +126,7 @@ export default class Subscription {
126 126 dataKey: dataKey,
127 127 dataIndex: dataIndex++
128 128 };
  129 + legendKey.dataKey.hidden = false;
129 130 this.legendData.keys.push(legendKey);
130 131 var legendKeyData = {
131 132 min: null,
... ... @@ -146,11 +147,11 @@ export default class Subscription {
146 147 this.legendData.keys = this.ctx.$filter('orderBy')(this.legendData.keys, '+label');
147 148 registration = this.ctx.$scope.$watch(
148 149 function() {
149   - return subscription.legendData.data;
  150 + return subscription.legendData.keys;
150 151 },
151 152 function (newValue, oldValue) {
152 153 for(var i = 0; i < newValue.length; i++) {
153   - if(newValue[i].hidden != oldValue[i].hidden) {
  154 + if(newValue[i].dataKey.hidden != oldValue[i].dataKey.hidden) {
154 155 subscription.updateDataVisibility(i);
155 156 }
156 157 }
... ... @@ -307,7 +308,7 @@ export default class Subscription {
307 308 }
308 309
309 310 updateDataVisibility(index) {
310   - var hidden = this.legendData.data[index].hidden;
  311 + var hidden = this.legendData.keys[index].dataKey.hidden;
311 312 if (hidden) {
312 313 this.hiddenData[index].data = this.data[index].data;
313 314 this.data[index].data = [];
... ... @@ -418,7 +419,7 @@ export default class Subscription {
418 419 this.notifyDataLoaded();
419 420 var update = true;
420 421 var currentData;
421   - if (this.displayLegend && this.legendData.data[datasourceIndex + dataKeyIndex].hidden) {
  422 + if (this.displayLegend && this.legendData.keys[datasourceIndex + dataKeyIndex].dataKey.hidden) {
422 423 currentData = this.hiddenData[datasourceIndex + dataKeyIndex];
423 424 } else {
424 425 currentData = this.data[datasourceIndex + dataKeyIndex];
... ... @@ -445,18 +446,21 @@ export default class Subscription {
445 446 }
446 447
447 448 updateLegend(dataIndex, data, apply) {
  449 + var dataKey = this.legendData.keys[dataIndex].dataKey;
  450 + var decimals = angular.isDefined(dataKey.decimals) ? dataKey.decimals : this.decimals;
  451 + var units = dataKey.units && dataKey.units.length ? dataKey.units : this.units;
448 452 var legendKeyData = this.legendData.data[dataIndex];
449 453 if (this.legendConfig.showMin) {
450   - legendKeyData.min = this.ctx.widgetUtils.formatValue(calculateMin(data), this.decimals, this.units);
  454 + legendKeyData.min = this.ctx.widgetUtils.formatValue(calculateMin(data), decimals, units);
451 455 }
452 456 if (this.legendConfig.showMax) {
453   - legendKeyData.max = this.ctx.widgetUtils.formatValue(calculateMax(data), this.decimals, this.units);
  457 + legendKeyData.max = this.ctx.widgetUtils.formatValue(calculateMax(data), decimals, units);
454 458 }
455 459 if (this.legendConfig.showAvg) {
456   - legendKeyData.avg = this.ctx.widgetUtils.formatValue(calculateAvg(data), this.decimals, this.units);
  460 + legendKeyData.avg = this.ctx.widgetUtils.formatValue(calculateAvg(data), decimals, units);
457 461 }
458 462 if (this.legendConfig.showTotal) {
459   - legendKeyData.total = this.ctx.widgetUtils.formatValue(calculateTotal(data), this.decimals, this.units);
  463 + legendKeyData.total = this.ctx.widgetUtils.formatValue(calculateTotal(data), decimals, units);
460 464 }
461 465 this.callbacks.legendDataUpdated(this, apply !== false);
462 466 }
... ...
... ... @@ -76,6 +76,8 @@ function DatakeyConfig($compile, $templateCache, $q, types) {
76 76 scope.model.name = ngModelCtrl.$viewValue.name;
77 77 scope.model.label = ngModelCtrl.$viewValue.label;
78 78 scope.model.color = ngModelCtrl.$viewValue.color;
  79 + scope.model.units = ngModelCtrl.$viewValue.units;
  80 + scope.model.decimals = ngModelCtrl.$viewValue.decimals;
79 81 scope.model.funcBody = ngModelCtrl.$viewValue.funcBody;
80 82 scope.model.postFuncBody = ngModelCtrl.$viewValue.postFuncBody;
81 83 scope.model.usePostProcessing = scope.model.postFuncBody ? true : false;
... ... @@ -97,6 +99,8 @@ function DatakeyConfig($compile, $templateCache, $q, types) {
97 99 value.name = scope.model.name;
98 100 value.label = scope.model.label;
99 101 value.color = scope.model.color;
  102 + value.units = scope.model.units;
  103 + value.decimals = scope.model.decimals;
100 104 value.funcBody = scope.model.funcBody;
101 105 if (!scope.model.postFuncBody) {
102 106 delete value.postFuncBody;
... ...
... ... @@ -48,6 +48,16 @@
48 48 md-color-history="false">
49 49 </div>
50 50 </div>
  51 + <div layout="row" layout-align="start center">
  52 + <md-input-container flex>
  53 + <label translate>datakey.units</label>
  54 + <input name="units" ng-model="model.units">
  55 + </md-input-container>
  56 + <md-input-container flex>
  57 + <label translate>datakey.decimals</label>
  58 + <input name="decimals" ng-model="model.decimals" type="number" min="0" max="15" step="1" ng-pattern="/^\d*$/">
  59 + </md-input-container>
  60 + </div>
51 61 <section layout="column" ng-if="model.type === types.dataKeyType.function">
52 62 <span translate>datakey.data-generation-func</span>
53 63 <br/>
... ...
... ... @@ -45,7 +45,7 @@ function Legend($compile, $templateCache, types) {
45 45 scope.legendConfig.position === types.position.top.value;
46 46
47 47 scope.toggleHideData = function(index) {
48   - scope.legendData.data[index].hidden = !scope.legendData.data[index].hidden;
  48 + scope.legendData.keys[index].dataKey.hidden = !scope.legendData.keys[index].dataKey.hidden;
49 49 }
50 50
51 51 $compile(element.contents())(scope);
... ...
... ... @@ -30,7 +30,7 @@
30 30 <td><span class="tb-legend-line" ng-style="{backgroundColor: legendKey.dataKey.color}"></span></td>
31 31 <td class="tb-legend-label"
32 32 ng-click="toggleHideData(legendKey.dataIndex)"
33   - ng-class="{ 'tb-hidden-label': legendData.data[legendKey.dataIndex].hidden, 'tb-horizontal': isHorizontal }">
  33 + ng-class="{ 'tb-hidden-label': legendData.keys[legendKey.dataIndex].dataKey.hidden, 'tb-horizontal': isHorizontal }">
34 34 {{ legendKey.dataKey.label }}
35 35 </td>
36 36 <td class="tb-legend-value" ng-if="legendConfig.showMin === true">{{ legendData.data[legendKey.dataIndex].min }}</td>
... ...
... ... @@ -355,10 +355,10 @@ function WidgetConfig($compile, $templateCache, $rootScope, $timeout, types, uti
355 355 var matches = false;
356 356 do {
357 357 matches = false;
358   - if (value.datasources) {
359   - for (var d in value.datasources) {
360   - var datasource = value.datasources[d];
361   - for (var k in datasource.dataKeys) {
  358 + if (value.config.datasources) {
  359 + for (var d=0;d<value.config.datasources.length;d++) {
  360 + var datasource = value.config.datasources[d];
  361 + for (var k=0;k<datasource.dataKeys.length;k++) {
362 362 var dataKey = datasource.dataKeys[k];
363 363 if (dataKey.label === label) {
364 364 i++;
... ... @@ -375,9 +375,9 @@ function WidgetConfig($compile, $templateCache, $rootScope, $timeout, types, uti
375 375 scope.genNextColor = function () {
376 376 var i = 0;
377 377 var value = ngModelCtrl.$viewValue;
378   - if (value.datasources) {
379   - for (var d in value.datasources) {
380   - var datasource = value.datasources[d];
  378 + if (value.config.datasources) {
  379 + for (var d=0;d<value.config.datasources.length;d++) {
  380 + var datasource = value.config.datasources[d];
381 381 i += datasource.dataKeys.length;
382 382 }
383 383 }
... ...
... ... @@ -983,8 +983,11 @@ export default function DashboardController(types, dashboardUtils, widgetService
983 983 if (revert) {
984 984 vm.dashboard = vm.prevDashboard;
985 985 vm.dashboardConfiguration = vm.dashboard.configuration;
  986 + vm.dashboardCtx.dashboardTimewindow = vm.dashboardConfiguration.timewindow;
986 987 openDashboardState(vm.prevDashboardState);
987 988 entityAliasesUpdated();
  989 + } else {
  990 + vm.dashboard.configuration.timewindow = vm.dashboardCtx.dashboardTimewindow;
988 991 }
989 992 }
990 993 }
... ...
... ... @@ -63,7 +63,7 @@
63 63 is-toolbar
64 64 direction="left"
65 65 tooltip-direction="bottom" aggregation
66   - ng-model="vm.dashboardConfiguration.timewindow">
  66 + ng-model="vm.dashboardCtx.dashboardTimewindow">
67 67 </tb-timewindow>
68 68 <tb-aliases-entity-select ng-show="!vm.isEdit && vm.displayEntitiesSelect()"
69 69 tooltip-direction="bottom"
... ...
... ... @@ -385,6 +385,8 @@ export default angular.module('thingsboard.locale', [])
385 385 "advanced": "Advanced",
386 386 "label": "Label",
387 387 "color": "Color",
  388 + "units": "Special symbol to show next to value",
  389 + "decimals": "Number of digits after floating point",
388 390 "data-generation-func": "Data generation function",
389 391 "use-data-post-processing-func": "Use data post-processing function",
390 392 "configuration": "Data key configuration",
... ...
... ... @@ -41,8 +41,7 @@ export default class TbAnalogueLinearGauge {
41 41
42 42 var valueInt = settings.valueInt || 3;
43 43
44   - var valueDec = (angular.isDefined(settings.valueDec) && settings.valueDec !== null)
45   - ? settings.valueDec : ctx.decimals;
  44 + var valueDec = getValueDec(settings);
46 45
47 46 step = parseFloat(parseFloat(step).toFixed(valueDec));
48 47
... ... @@ -74,6 +73,32 @@ export default class TbAnalogueLinearGauge {
74 73 var progressColorStart = tinycolor(keyColor).setAlpha(0.05).toRgbString();
75 74 var progressColorEnd = tinycolor(keyColor).darken().toRgbString();
76 75
  76 + function getUnits(settings) {
  77 + var dataKey;
  78 + if (ctx.data && ctx.data[0]) {
  79 + dataKey = ctx.data[0].dataKey;
  80 + }
  81 + if (dataKey && dataKey.units && dataKey.units.length) {
  82 + return dataKey.units;
  83 + } else {
  84 + return angular.isDefined(settings.units) && settings.units.length > 0 ? settings.units : ctx.units;
  85 + }
  86 + }
  87 +
  88 + function getValueDec(settings) {
  89 + var dataKey;
  90 + if (ctx.data && ctx.data[0]) {
  91 + dataKey = ctx.data[0].dataKey;
  92 + }
  93 + if (dataKey && angular.isDefined(dataKey.decimals)) {
  94 + return dataKey.decimals;
  95 + } else {
  96 + return (angular.isDefined(settings.valueDec) && settings.valueDec !== null)
  97 + ? settings.valueDec : ctx.decimals;
  98 + }
  99 + }
  100 +
  101 +
77 102 function getFontFamily(fontSettings) {
78 103 var family = fontSettings && fontSettings.family ? fontSettings.family : 'Roboto';
79 104 if (family === 'RobotoDraft') {
... ... @@ -92,7 +117,7 @@ export default class TbAnalogueLinearGauge {
92 117 maxValue: maxValue,
93 118 majorTicks: majorTicks,
94 119 minorTicks: settings.minorTicks || 2,
95   - units: angular.isDefined(settings.units) && settings.units.length > 0 ? settings.units : ctx.units,
  120 + units: getUnits(settings),
96 121 title: ((settings.showUnitTitle !== false) ?
97 122 (settings.unitTitle && settings.unitTitle.length > 0 ?
98 123 settings.unitTitle : dataKey.label) : ''),
... ...
... ... @@ -42,8 +42,7 @@ export default class TbAnalogueRadialGauge {
42 42
43 43 var valueInt = settings.valueInt || 3;
44 44
45   - var valueDec = (angular.isDefined(settings.valueDec) && settings.valueDec !== null)
46   - ? settings.valueDec : ctx.decimals;
  45 + var valueDec = getValueDec(settings);
47 46
48 47 step = parseFloat(parseFloat(step).toFixed(valueDec));
49 48
... ... @@ -71,6 +70,31 @@ export default class TbAnalogueRadialGauge {
71 70
72 71 var colorNumbers = tinycolor(keyColor).darken(20).toRgbString();
73 72
  73 + function getUnits(settings) {
  74 + var dataKey;
  75 + if (ctx.data && ctx.data[0]) {
  76 + dataKey = ctx.data[0].dataKey;
  77 + }
  78 + if (dataKey && dataKey.units && dataKey.units.length) {
  79 + return dataKey.units;
  80 + } else {
  81 + return angular.isDefined(settings.units) && settings.units.length > 0 ? settings.units : ctx.units;
  82 + }
  83 + }
  84 +
  85 + function getValueDec(settings) {
  86 + var dataKey;
  87 + if (ctx.data && ctx.data[0]) {
  88 + dataKey = ctx.data[0].dataKey;
  89 + }
  90 + if (dataKey && angular.isDefined(dataKey.decimals)) {
  91 + return dataKey.decimals;
  92 + } else {
  93 + return (angular.isDefined(settings.valueDec) && settings.valueDec !== null)
  94 + ? settings.valueDec : ctx.decimals;
  95 + }
  96 + }
  97 +
74 98 function getFontFamily(fontSettings) {
75 99 var family = fontSettings && fontSettings.family ? fontSettings.family : 'Roboto';
76 100 if (family === 'RobotoDraft') {
... ... @@ -89,7 +113,7 @@ export default class TbAnalogueRadialGauge {
89 113 maxValue: maxValue,
90 114 majorTicks: majorTicks,
91 115 minorTicks: settings.minorTicks || 2,
92   - units: angular.isDefined(settings.units) && settings.units.length > 0 ? settings.units : ctx.units,
  116 + units: getUnits(settings),
93 117 title: ((settings.showUnitTitle !== false) ?
94 118 (settings.unitTitle && settings.unitTitle.length > 0 ?
95 119 settings.unitTitle : dataKey.label) : ''),
... ...
... ... @@ -54,10 +54,13 @@ export default class TbCanvasDigitalGauge {
54 54 this.localSettings.levelColors = settings.levelColors.slice();
55 55 }
56 56
57   - this.localSettings.decimals = (angular.isDefined(settings.decimals) && settings.decimals !== null)
58   - ? settings.decimals : ctx.decimals;
  57 + this.localSettings.decimals = angular.isDefined(dataKey.decimals) ? dataKey.decimals :
  58 + ((angular.isDefined(settings.decimals) && settings.decimals !== null)
  59 + ? settings.decimals : ctx.decimals);
  60 +
  61 + this.localSettings.units = dataKey.units && dataKey.units.length ? dataKey.units :
  62 + (angular.isDefined(settings.units) && settings.units.length > 0 ? settings.units : ctx.units);
59 63
60   - this.localSettings.units = angular.isDefined(settings.units) && settings.units.length > 0 ? settings.units : ctx.units;
61 64 this.localSettings.hideValue = settings.showValue !== true;
62 65 this.localSettings.hideMinMax = settings.showMinMax !== true;
63 66
... ...
... ... @@ -104,8 +104,10 @@ export default class TbFlot {
104 104
105 105 if (this.chartType === 'pie') {
106 106 ctx.tooltipFormatter = function(item) {
  107 + var units = item.series.dataKey.units && item.series.dataKey.units.length ? item.series.dataKey.units : tbFlot.ctx.trackUnits;
  108 + var decimals = angular.isDefined(item.series.dataKey.decimals) ? item.series.dataKey.decimals : tbFlot.ctx.trackDecimals;
107 109 var divElement = seriesInfoDiv(item.series.dataKey.label, item.series.dataKey.color,
108   - item.datapoint[1][0][1], tbFlot.ctx.trackUnits, tbFlot.ctx.trackDecimals, true, item.series.percent);
  110 + item.datapoint[1][0][1], units, decimals, true, item.series.percent);
109 111 return divElement.prop('outerHTML');
110 112 };
111 113 } else {
... ... @@ -127,18 +129,19 @@ export default class TbFlot {
127 129 if (tbFlot.ctx.tooltipIndividual && seriesHoverInfo.index !== seriesIndex) {
128 130 continue;
129 131 }
  132 + var units = seriesHoverInfo.units && seriesHoverInfo.units.length ? seriesHoverInfo.units : tbFlot.ctx.trackUnits;
  133 + var decimals = angular.isDefined(seriesHoverInfo.decimals) ? seriesHoverInfo.decimals : tbFlot.ctx.trackDecimals;
130 134 var divElement = seriesInfoDiv(seriesHoverInfo.label, seriesHoverInfo.color,
131   - seriesHoverInfo.value, tbFlot.ctx.trackUnits, tbFlot.ctx.trackDecimals, seriesHoverInfo.index === seriesIndex);
  135 + seriesHoverInfo.value, units, decimals, seriesHoverInfo.index === seriesIndex);
132 136 content += divElement.prop('outerHTML');
133 137 }
134 138 return content;
135 139 };
136 140 }
137 141
138   - ctx.trackDecimals = angular.isDefined(settings.decimals) ?
139   - settings.decimals : ctx.decimals;
  142 + ctx.trackDecimals = ctx.decimals;
140 143
141   - ctx.trackUnits = angular.isDefined(settings.units) ? settings.units : ctx.units;
  144 + ctx.trackUnits = ctx.units;
142 145
143 146 ctx.tooltipIndividual = this.chartType === 'pie' || (angular.isDefined(settings.tooltipIndividual) ? settings.tooltipIndividual : false);
144 147 ctx.tooltipCumulative = angular.isDefined(settings.tooltipCumulative) ? settings.tooltipCumulative : false;
... ... @@ -172,7 +175,7 @@ export default class TbFlot {
172 175 font: angular.copy(font),
173 176 labelFont: angular.copy(font)
174 177 };
175   - options.yaxis = {
  178 + this.yaxis = {
176 179 font: angular.copy(font),
177 180 labelFont: angular.copy(font)
178 181 };
... ... @@ -188,32 +191,33 @@ export default class TbFlot {
188 191 options.xaxis.labelFont.size = options.xaxis.font.size+2;
189 192 options.xaxis.labelFont.weight = "bold";
190 193 }
191   - if (settings.yaxis) {
  194 +
  195 + ctx.yAxisTickFormatter = function(value/*, axis*/) {
192 196 if (settings.yaxis.showLabels === false) {
193   - options.yaxis.tickFormatter = function() {
194   - return '';
195   - };
196   - } else if (ctx.trackUnits && ctx.trackUnits.length > 0) {
197   - options.yaxis.tickFormatter = function(value, axis) {
198   - var factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1,
199   - formatted = "" + Math.round(value * factor) / factor;
200   - if (axis.tickDecimals != null) {
201   - var decimal = formatted.indexOf("."),
202   - precision = decimal === -1 ? 0 : formatted.length - decimal - 1;
203   -
204   - if (precision < axis.tickDecimals) {
205   - formatted = (precision ? formatted : formatted + ".") + ("" + factor).substr(1, axis.tickDecimals - precision);
206   - }
207   - }
208   - formatted += ' ' + tbFlot.ctx.trackUnits;
209   - return formatted;
210   - };
  197 + return '';
  198 + }
  199 + var factor = this.tickDecimals ? Math.pow(10, this.tickDecimals) : 1,
  200 + formatted = "" + Math.round(value * factor) / factor;
  201 + if (this.tickDecimals != null) {
  202 + var decimal = formatted.indexOf("."),
  203 + precision = decimal === -1 ? 0 : formatted.length - decimal - 1;
  204 +
  205 + if (precision < this.tickDecimals) {
  206 + formatted = (precision ? formatted : formatted + ".") + ("" + factor).substr(1, this.tickDecimals - precision);
  207 + }
211 208 }
212   - options.yaxis.font.color = settings.yaxis.color || options.yaxis.font.color;
213   - options.yaxis.label = settings.yaxis.title || null;
214   - options.yaxis.labelFont.color = options.yaxis.font.color;
215   - options.yaxis.labelFont.size = options.yaxis.font.size+2;
216   - options.yaxis.labelFont.weight = "bold";
  209 + formatted += ' ' + this.tickUnits;
  210 + return formatted;
  211 + }
  212 +
  213 + this.yaxis.tickFormatter = ctx.yAxisTickFormatter;
  214 +
  215 + if (settings.yaxis) {
  216 + this.yaxis.font.color = settings.yaxis.color || this.yaxis.font.color;
  217 + this.yaxis.label = settings.yaxis.title || null;
  218 + this.yaxis.labelFont.color = this.yaxis.font.color;
  219 + this.yaxis.labelFont.size = this.yaxis.font.size+2;
  220 + this.yaxis.labelFont.weight = "bold";
217 221 }
218 222
219 223 options.grid.borderWidth = 1;
... ... @@ -229,7 +233,7 @@ export default class TbFlot {
229 233 options.xaxis.tickLength = 0;
230 234 }
231 235 if (settings.grid.horizontalLines === false) {
232   - options.yaxis.tickLength = 0;
  236 + this.yaxis.tickLength = 0;
233 237 }
234 238 }
235 239
... ... @@ -311,6 +315,8 @@ export default class TbFlot {
311 315 this.subscription = subscription;
312 316 this.$element = $element;
313 317 var colors = [];
  318 + this.yaxes = [];
  319 + var yaxesMap = {};
314 320 for (var i = 0; i < this.subscription.data.length; i++) {
315 321 var series = this.subscription.data[i];
316 322 colors.push(series.dataKey.color);
... ... @@ -342,8 +348,29 @@ export default class TbFlot {
342 348
343 349 series.highlightColor = lineColor.toRgbString();
344 350
  351 + if (this.yaxis) {
  352 + var units = series.dataKey.units && series.dataKey.units.length ? series.dataKey.units : this.ctx.trackUnits;
  353 + var yaxis;
  354 + if (keySettings.showSeparateAxis) {
  355 + yaxis = this.createYAxis(keySettings, units);
  356 + this.yaxes.push(yaxis);
  357 + } else {
  358 + yaxis = yaxesMap[units];
  359 + if (!yaxis) {
  360 + yaxis = this.createYAxis(keySettings, units);
  361 + yaxesMap[units] = yaxis;
  362 + this.yaxes.push(yaxis);
  363 + }
  364 + }
  365 + series.yaxisIndex = this.yaxes.indexOf(yaxis);
  366 + series.yaxis = series.yaxisIndex+1;
  367 + yaxis.keysInfo[i] = {hidden: false};
  368 + yaxis.hidden = false;
  369 + }
345 370 }
  371 +
346 372 this.options.colors = colors;
  373 + this.options.yaxes = angular.copy(this.yaxes);
347 374 if (this.chartType === 'line' || this.chartType === 'bar') {
348 375 if (this.chartType === 'bar') {
349 376 this.options.series.bars.barWidth = this.subscription.timeWindow.interval * 0.6;
... ... @@ -373,6 +400,23 @@ export default class TbFlot {
373 400 }
374 401 }
375 402
  403 + createYAxis(keySettings, units) {
  404 + var yaxis = angular.copy(this.yaxis);
  405 +
  406 + var label = keySettings.axisTitle && keySettings.axisTitle.length ? keySettings.axisTitle : yaxis.label;
  407 + var tickDecimals = angular.isDefined(keySettings.axisTickDecimals) ? keySettings.axisTickDecimals : 0;
  408 + var position = keySettings.axisPosition && keySettings.axisPosition.length ? keySettings.axisPosition : "left";
  409 +
  410 + yaxis.label = label;
  411 + yaxis.tickUnits = units;
  412 + yaxis.tickDecimals = tickDecimals;
  413 + yaxis.alignTicksWithAxis = position == "right" ? 1 : null;
  414 + yaxis.position = position;
  415 +
  416 + yaxis.keysInfo = [];
  417 + return yaxis;
  418 + }
  419 +
376 420 update() {
377 421 if (this.updateTimeoutHandle) {
378 422 this.ctx.$scope.$timeout.cancel(this.updateTimeoutHandle);
... ... @@ -381,17 +425,64 @@ export default class TbFlot {
381 425 if (this.subscription) {
382 426 if (!this.isMouseInteraction && this.ctx.plot) {
383 427 if (this.chartType === 'line' || this.chartType === 'bar') {
  428 +
  429 + var axisVisibilityChanged = false;
  430 + if (this.yaxis) {
  431 + for (var i = 0; i < this.subscription.data.length; i++) {
  432 + var series = this.subscription.data[i];
  433 + var yaxisIndex = series.yaxisIndex;
  434 + if (this.yaxes[yaxisIndex].keysInfo[i].hidden != series.dataKey.hidden) {
  435 + this.yaxes[yaxisIndex].keysInfo[i].hidden = series.dataKey.hidden;
  436 + axisVisibilityChanged = true;
  437 + }
  438 + }
  439 + if (axisVisibilityChanged) {
  440 + this.options.yaxes.length = 0;
  441 + for (var y = 0; y < this.yaxes.length; y++) {
  442 + var yaxis = this.yaxes[y];
  443 + var hidden = true;
  444 + for (var k = 0; k < yaxis.keysInfo.length; k++) {
  445 + if (yaxis.keysInfo[k]) {
  446 + hidden = hidden && yaxis.keysInfo[k].hidden;
  447 + }
  448 + }
  449 + yaxis.hidden = hidden
  450 + var newIndex = -1;
  451 + if (!yaxis.hidden) {
  452 + this.options.yaxes.push(yaxis);
  453 + newIndex = this.options.yaxes.length;
  454 + }
  455 + for (k = 0; k < yaxis.keysInfo.length; k++) {
  456 + if (yaxis.keysInfo[k]) {
  457 + this.subscription.data[k].yaxis = newIndex;
  458 + }
  459 + }
  460 +
  461 + }
  462 + this.options.yaxis = {
  463 + show: this.options.yaxes.length ? true : false
  464 + };
  465 + }
  466 + }
  467 +
384 468 this.options.xaxis.min = this.subscription.timeWindow.minTime;
385 469 this.options.xaxis.max = this.subscription.timeWindow.maxTime;
386   - this.ctx.plot.getOptions().xaxes[0].min = this.subscription.timeWindow.minTime;
387   - this.ctx.plot.getOptions().xaxes[0].max = this.subscription.timeWindow.maxTime;
388 470 if (this.chartType === 'bar') {
389 471 this.options.series.bars.barWidth = this.subscription.timeWindow.interval * 0.6;
390   - this.ctx.plot.getOptions().series.bars.barWidth = this.subscription.timeWindow.interval * 0.6;
391 472 }
392   - this.ctx.plot.setData(this.subscription.data);
393   - this.ctx.plot.setupGrid();
394   - this.ctx.plot.draw();
  473 +
  474 + if (axisVisibilityChanged) {
  475 + this.redrawPlot();
  476 + } else {
  477 + this.ctx.plot.getOptions().xaxes[0].min = this.subscription.timeWindow.minTime;
  478 + this.ctx.plot.getOptions().xaxes[0].max = this.subscription.timeWindow.maxTime;
  479 + if (this.chartType === 'bar') {
  480 + this.ctx.plot.getOptions().series.bars.barWidth = this.subscription.timeWindow.interval * 0.6;
  481 + }
  482 + this.ctx.plot.setData(this.subscription.data);
  483 + this.ctx.plot.setupGrid();
  484 + this.ctx.plot.draw();
  485 + }
395 486 } else if (this.chartType === 'pie') {
396 487 if (this.ctx.animatedPie) {
397 488 this.nextPieDataAnimation(true);
... ... @@ -720,6 +811,26 @@ export default class TbFlot {
720 811 "title": "Show points",
721 812 "type": "boolean",
722 813 "default": false
  814 + },
  815 + "showSeparateAxis": {
  816 + "title": "Show separate axis",
  817 + "type": "boolean",
  818 + "default": false
  819 + },
  820 + "axisTitle": {
  821 + "title": "Axis title",
  822 + "type": "string",
  823 + "default": ""
  824 + },
  825 + "axisTickDecimals": {
  826 + "title": "Axis tick number of digits after floating point",
  827 + "type": "number",
  828 + "default": 0
  829 + },
  830 + "axisPosition": {
  831 + "title": "Axis position",
  832 + "type": "string",
  833 + "default": "left"
723 834 }
724 835 },
725 836 "required": ["showLines", "fillLines", "showPoints"]
... ... @@ -727,7 +838,26 @@ export default class TbFlot {
727 838 "form": [
728 839 "showLines",
729 840 "fillLines",
730   - "showPoints"
  841 + "showPoints",
  842 + "showSeparateAxis",
  843 + "axisTitle",
  844 + "axisTickDecimals",
  845 + {
  846 + "key": "axisPosition",
  847 + "type": "rc-select",
  848 + "multiple": false,
  849 + "items": [
  850 + {
  851 + "value": "left",
  852 + "label": "Left"
  853 + },
  854 + {
  855 + "value": "right",
  856 + "label": "Right"
  857 + }
  858 + ]
  859 + }
  860 +
731 861 ]
732 862 }
733 863 }
... ... @@ -754,6 +884,17 @@ export default class TbFlot {
754 884 }
755 885 }
756 886
  887 + redrawPlot() {
  888 + if (this.ctx.plot) {
  889 + this.ctx.plot.destroy();
  890 + if (this.chartType === 'pie' && this.ctx.animatedPie) {
  891 + this.ctx.plot = $.plot(this.$element, this.pieData, this.options);
  892 + } else {
  893 + this.ctx.plot = $.plot(this.$element, this.subscription.data, this.options);
  894 + }
  895 + }
  896 + }
  897 +
757 898 destroy() {
758 899 if (this.ctx.plot) {
759 900 this.ctx.plot.destroy();
... ... @@ -968,6 +1109,8 @@ export default class TbFlot {
968 1109 hoverIndex: hoverIndex,
969 1110 color: series.dataKey.color,
970 1111 label: series.dataKey.label,
  1112 + units: series.dataKey.units,
  1113 + decimals: series.dataKey.decimals,
971 1114 time: pointTime,
972 1115 distance: hoverDistance,
973 1116 index: i
... ...