Commit 70ddf204482424be4a0532c22a5e1de6df6060a7

Authored by Igor Kulikov
1 parent 3ef1a7d4

Stepped chart

... ... @@ -16,7 +16,8 @@
16 16
17 17 export default class DataAggregator {
18 18
19   - constructor(onDataCb, tsKeyNames, startTs, limit, aggregationType, timeWindow, interval, types, $timeout, $filter) {
  19 + constructor(onDataCb, tsKeyNames, startTs, limit, aggregationType, timeWindow, interval,
  20 + steppedChart, types, $timeout, $filter) {
20 21 this.onDataCb = onDataCb;
21 22 this.tsKeyNames = tsKeyNames;
22 23 this.dataBuffer = {};
... ... @@ -34,6 +35,8 @@ export default class DataAggregator {
34 35 this.limit = limit;
35 36 this.timeWindow = timeWindow;
36 37 this.interval = interval;
  38 + this.steppedChart = steppedChart;
  39 + this.firstStepDataReceived = !this.steppedChart;
37 40 this.aggregationTimeout = Math.max(this.interval, 1000);
38 41 switch (aggregationType) {
39 42 case types.aggregation.min.value:
... ... @@ -78,6 +81,10 @@ export default class DataAggregator {
78 81 }, this.aggregationTimeout, false);
79 82 }
80 83
  84 + onFirstStepData(data) {
  85 + this.firstStepData = data;
  86 + }
  87 +
81 88 onData(data, update, history, apply) {
82 89 if (!this.dataReceived || this.resetPending) {
83 90 var updateIntervalScheduledTime = true;
... ...
... ... @@ -23,6 +23,8 @@ export default angular.module('thingsboard.api.datasource', [thingsboardApiDevic
23 23 .factory('datasourceService', DatasourceService)
24 24 .name;
25 25
  26 +const YEAR = 1000 * 60 * 60 * 24 * 365;
  27 +
26 28 /*@ngInject*/
27 29 function DatasourceService($timeout, $filter, $log, telemetryWebsocketService, types, utils) {
28 30
... ... @@ -280,6 +282,10 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
280 282 telemetryWebsocketService.subscribe(subscriber);
281 283 subscribers[subscriber.historyCommand.cmdId] = subscriber;
282 284
  285 + if (subsTw.aggregation.steppedChart) {
  286 + createFirstStepSubscription(subsTw, tsKeys);
  287 + }
  288 +
283 289 } else {
284 290
285 291 subscriptionCommand = {
... ... @@ -312,6 +318,11 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
312 318 updateRealtimeSubscriptionCommand(this.subscriptionCommand, newSubsTw);
313 319 dataAggregator.reset(newSubsTw.startTs, newSubsTw.aggregation.timeWindow, newSubsTw.aggregation.interval);
314 320 }
  321 +
  322 + if (subsTw.aggregation.steppedChart) {
  323 + createFirstStepSubscription(subsTw, tsKeys);
  324 + }
  325 +
315 326 } else {
316 327 subscriber.onReconnected = function() {}
317 328 subscriber.onData = function(data) {
... ... @@ -377,6 +388,37 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
377 388 }
378 389 }
379 390
  391 + function createFirstStepSubscription(subsTw, tsKeys) {
  392 + var startStepCommand = {
  393 + entityType: datasourceSubscription.entityType,
  394 + entityId: datasourceSubscription.entityId,
  395 + keys: tsKeys,
  396 + startTs: subsTw.fixedWindow.startTimeMs - YEAR,
  397 + endTs: subsTw.fixedWindow.startTimeMs,
  398 + interval: subsTw.aggregation.interval,
  399 + limit: 1,
  400 + agg: subsTw.aggregation.type
  401 + };
  402 + var subscriber = {
  403 + historyCommand: startStepCommand,
  404 + type: types.dataKeyType.timeseries,
  405 + onData: function (data) {
  406 + if (data.data) {
  407 + for (var key in data.data) {
  408 + var keyData = data.data[key];
  409 + data.data[key] = $filter('orderBy')(keyData, '+this[0]');
  410 + }
  411 + //onData(data.data, types.dataKeyType.timeseries, true);
  412 + //TODO: onStartStepData
  413 + }
  414 + },
  415 + onReconnected: function() {}
  416 + };
  417 +
  418 + telemetryWebsocketService.subscribe(subscriber);
  419 + subscribers[subscriber.historyCommand.cmdId] = subscriber;
  420 + }
  421 +
380 422 function createRealtimeDataAggregator(subsTw, tsKeyNames, dataKeyType) {
381 423 return new DataAggregator(
382 424 function(data, apply) {
... ... @@ -388,6 +430,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
388 430 subsTw.aggregation.type,
389 431 subsTw.aggregation.timeWindow,
390 432 subsTw.aggregation.interval,
  433 + subsTw.aggregation.steppedChart,
391 434 types,
392 435 $timeout,
393 436 $filter
... ...
... ... @@ -128,7 +128,7 @@ export default class Subscription {
128 128 stDiff: this.ctx.stDiff
129 129 }
130 130 this.useDashboardTimewindow = options.useDashboardTimewindow;
131   -
  131 + this.steppedChart = options.steppedChart;
132 132 if (this.useDashboardTimewindow) {
133 133 this.timeWindowConfig = angular.copy(options.dashboardTimewindow);
134 134 } else {
... ... @@ -612,7 +612,7 @@ export default class Subscription {
612 612 this.subscriptionTimewindow =
613 613 this.ctx.timeService.createSubscriptionTimewindow(
614 614 this.timeWindowConfig,
615   - this.timeWindow.stDiff);
  615 + this.timeWindow.stDiff, this.steppedChart);
616 616 }
617 617 this.updateTimewindow();
618 618 return this.subscriptionTimewindow;
... ...
... ... @@ -261,7 +261,7 @@ function TimeService($translate, types) {
261 261 return historyTimewindow;
262 262 }
263 263
264   - function createSubscriptionTimewindow(timewindow, stDiff) {
  264 + function createSubscriptionTimewindow(timewindow, stDiff, steppedChart) {
265 265
266 266 var subscriptionTimewindow = {
267 267 fixedWindow: null,
... ... @@ -273,8 +273,22 @@ function TimeService($translate, types) {
273 273 }
274 274 };
275 275 var aggTimewindow = 0;
  276 + if (steppedChart) {
  277 + subscriptionTimewindow.aggregation = {
  278 + interval: SECOND,
  279 + limit: MAX_LIMIT,
  280 + type: types.aggregation.none.value,
  281 + steppedChart: true
  282 + };
  283 + } else {
  284 + subscriptionTimewindow.aggregation = {
  285 + interval: SECOND,
  286 + limit: AVG_LIMIT,
  287 + type: types.aggregation.avg.value
  288 + };
  289 + }
276 290
277   - if (angular.isDefined(timewindow.aggregation)) {
  291 + if (angular.isDefined(timewindow.aggregation) && !steppedChart) {
278 292 subscriptionTimewindow.aggregation = {
279 293 type: timewindow.aggregation.type || types.aggregation.avg.value,
280 294 limit: timewindow.aggregation.limit || AVG_LIMIT
... ...
... ... @@ -560,7 +560,8 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, $tr
560 560 useCustomDatasources: false,
561 561 maxDatasources: -1, //unlimited
562 562 maxDataKeys: -1, //unlimited
563   - dataKeysOptional: false
  563 + dataKeysOptional: false,
  564 + steppedChart: false
564 565 };
565 566 ' }\n\n' +
566 567
... ... @@ -631,6 +632,9 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, $tr
631 632 if (angular.isUndefined(result.typeParameters.dataKeysOptional)) {
632 633 result.typeParameters.dataKeysOptional = false;
633 634 }
  635 + if (angular.isUndefined(result.typeParameters.steppedChart)) {
  636 + result.typeParameters.steppedChart = false;
  637 + }
634 638 if (angular.isFunction(widgetTypeInstance.actionSources)) {
635 639 result.actionSources = widgetTypeInstance.actionSources();
636 640 } else {
... ...
... ... @@ -339,7 +339,8 @@ export default function WidgetController($scope, $state, $timeout, $window, $ele
339 339 var deferred = $q.defer();
340 340 if (widget.type !== types.widgetType.rpc.value && widget.type !== types.widgetType.static.value) {
341 341 options = {
342   - type: widget.type
  342 + type: widget.type,
  343 + steppedChart: vm.typeParameters.steppedChart
343 344 }
344 345 if (widget.type == types.widgetType.alarm.value) {
345 346 options.alarmSource = angular.copy(widget.config.alarmSource);
... ...
... ... @@ -168,7 +168,7 @@ export default class TbFlot {
168 168 }
169 169 };
170 170
171   - if (this.chartType === 'line' || this.chartType === 'bar') {
  171 + if (this.chartType === 'line' || this.chartType === 'bar' || this.chartType === 'stepped') {
172 172 options.xaxis = {
173 173 mode: 'time',
174 174 timezone: 'browser',
... ... @@ -270,6 +270,14 @@ export default class TbFlot {
270 270 fill: 0.9
271 271 }
272 272 }
  273 +
  274 + if (this.chartType === 'stepped') {
  275 + options.series.lines = {
  276 + steps: true,
  277 + show: true
  278 + }
  279 + }
  280 +
273 281 } else if (this.chartType === 'pie') {
274 282 options.series = {
275 283 pie: {
... ... @@ -381,7 +389,7 @@ export default class TbFlot {
381 389
382 390 this.options.colors = colors;
383 391 this.options.yaxes = angular.copy(this.yaxes);
384   - if (this.chartType === 'line' || this.chartType === 'bar') {
  392 + if (this.chartType === 'line' || this.chartType === 'bar' || this.chartType === 'stepped') {
385 393 if (this.chartType === 'bar') {
386 394 this.options.series.bars.barWidth = this.subscription.timeWindow.interval * 0.6;
387 395 }
... ... @@ -434,7 +442,7 @@ export default class TbFlot {
434 442 }
435 443 if (this.subscription) {
436 444 if (!this.isMouseInteraction && this.ctx.plot) {
437   - if (this.chartType === 'line' || this.chartType === 'bar') {
  445 + if (this.chartType === 'line' || this.chartType === 'bar' || this.chartType === 'stepped') {
438 446
439 447 var axisVisibilityChanged = false;
440 448 if (this.yaxis) {
... ...