thingsboard-aplcache
Changes
ui/src/app/api/data-aggregator.js 9(+8 -1)
ui/src/app/api/datasource.service.js 43(+43 -0)
ui/src/app/api/subscription.js 4(+2 -2)
ui/src/app/api/time.service.js 18(+16 -2)
ui/src/app/api/widget.service.js 6(+5 -1)
ui/src/app/widget/lib/flot-widget.js 14(+11 -3)
Details
ui/src/app/api/data-aggregator.js 9(+8 -1)
diff --git a/ui/src/app/api/data-aggregator.js b/ui/src/app/api/data-aggregator.js
index ec41536..43b2e93 100644
--- a/ui/src/app/api/data-aggregator.js
+++ b/ui/src/app/api/data-aggregator.js
@@ -16,7 +16,8 @@
export default class DataAggregator {
- constructor(onDataCb, tsKeyNames, startTs, limit, aggregationType, timeWindow, interval, types, $timeout, $filter) {
+ constructor(onDataCb, tsKeyNames, startTs, limit, aggregationType, timeWindow, interval,
+ steppedChart, types, $timeout, $filter) {
this.onDataCb = onDataCb;
this.tsKeyNames = tsKeyNames;
this.dataBuffer = {};
@@ -34,6 +35,8 @@ export default class DataAggregator {
this.limit = limit;
this.timeWindow = timeWindow;
this.interval = interval;
+ this.steppedChart = steppedChart;
+ this.firstStepDataReceived = !this.steppedChart;
this.aggregationTimeout = Math.max(this.interval, 1000);
switch (aggregationType) {
case types.aggregation.min.value:
@@ -78,6 +81,10 @@ export default class DataAggregator {
}, this.aggregationTimeout, false);
}
+ onFirstStepData(data) {
+ this.firstStepData = data;
+ }
+
onData(data, update, history, apply) {
if (!this.dataReceived || this.resetPending) {
var updateIntervalScheduledTime = true;
ui/src/app/api/datasource.service.js 43(+43 -0)
diff --git a/ui/src/app/api/datasource.service.js b/ui/src/app/api/datasource.service.js
index 1f265bb..a68e14c 100644
--- a/ui/src/app/api/datasource.service.js
+++ b/ui/src/app/api/datasource.service.js
@@ -23,6 +23,8 @@ export default angular.module('thingsboard.api.datasource', [thingsboardApiDevic
.factory('datasourceService', DatasourceService)
.name;
+const YEAR = 1000 * 60 * 60 * 24 * 365;
+
/*@ngInject*/
function DatasourceService($timeout, $filter, $log, telemetryWebsocketService, types, utils) {
@@ -280,6 +282,10 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
telemetryWebsocketService.subscribe(subscriber);
subscribers[subscriber.historyCommand.cmdId] = subscriber;
+ if (subsTw.aggregation.steppedChart) {
+ createFirstStepSubscription(subsTw, tsKeys);
+ }
+
} else {
subscriptionCommand = {
@@ -312,6 +318,11 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
updateRealtimeSubscriptionCommand(this.subscriptionCommand, newSubsTw);
dataAggregator.reset(newSubsTw.startTs, newSubsTw.aggregation.timeWindow, newSubsTw.aggregation.interval);
}
+
+ if (subsTw.aggregation.steppedChart) {
+ createFirstStepSubscription(subsTw, tsKeys);
+ }
+
} else {
subscriber.onReconnected = function() {}
subscriber.onData = function(data) {
@@ -377,6 +388,37 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
}
}
+ function createFirstStepSubscription(subsTw, tsKeys) {
+ var startStepCommand = {
+ entityType: datasourceSubscription.entityType,
+ entityId: datasourceSubscription.entityId,
+ keys: tsKeys,
+ startTs: subsTw.fixedWindow.startTimeMs - YEAR,
+ endTs: subsTw.fixedWindow.startTimeMs,
+ interval: subsTw.aggregation.interval,
+ limit: 1,
+ agg: subsTw.aggregation.type
+ };
+ var subscriber = {
+ historyCommand: startStepCommand,
+ type: types.dataKeyType.timeseries,
+ onData: function (data) {
+ if (data.data) {
+ for (var key in data.data) {
+ var keyData = data.data[key];
+ data.data[key] = $filter('orderBy')(keyData, '+this[0]');
+ }
+ //onData(data.data, types.dataKeyType.timeseries, true);
+ //TODO: onStartStepData
+ }
+ },
+ onReconnected: function() {}
+ };
+
+ telemetryWebsocketService.subscribe(subscriber);
+ subscribers[subscriber.historyCommand.cmdId] = subscriber;
+ }
+
function createRealtimeDataAggregator(subsTw, tsKeyNames, dataKeyType) {
return new DataAggregator(
function(data, apply) {
@@ -388,6 +430,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
subsTw.aggregation.type,
subsTw.aggregation.timeWindow,
subsTw.aggregation.interval,
+ subsTw.aggregation.steppedChart,
types,
$timeout,
$filter
ui/src/app/api/subscription.js 4(+2 -2)
diff --git a/ui/src/app/api/subscription.js b/ui/src/app/api/subscription.js
index fd26629..a464617 100644
--- a/ui/src/app/api/subscription.js
+++ b/ui/src/app/api/subscription.js
@@ -128,7 +128,7 @@ export default class Subscription {
stDiff: this.ctx.stDiff
}
this.useDashboardTimewindow = options.useDashboardTimewindow;
-
+ this.steppedChart = options.steppedChart;
if (this.useDashboardTimewindow) {
this.timeWindowConfig = angular.copy(options.dashboardTimewindow);
} else {
@@ -612,7 +612,7 @@ export default class Subscription {
this.subscriptionTimewindow =
this.ctx.timeService.createSubscriptionTimewindow(
this.timeWindowConfig,
- this.timeWindow.stDiff);
+ this.timeWindow.stDiff, this.steppedChart);
}
this.updateTimewindow();
return this.subscriptionTimewindow;
ui/src/app/api/time.service.js 18(+16 -2)
diff --git a/ui/src/app/api/time.service.js b/ui/src/app/api/time.service.js
index 1f42290..d34c77e 100644
--- a/ui/src/app/api/time.service.js
+++ b/ui/src/app/api/time.service.js
@@ -261,7 +261,7 @@ function TimeService($translate, types) {
return historyTimewindow;
}
- function createSubscriptionTimewindow(timewindow, stDiff) {
+ function createSubscriptionTimewindow(timewindow, stDiff, steppedChart) {
var subscriptionTimewindow = {
fixedWindow: null,
@@ -273,8 +273,22 @@ function TimeService($translate, types) {
}
};
var aggTimewindow = 0;
+ if (steppedChart) {
+ subscriptionTimewindow.aggregation = {
+ interval: SECOND,
+ limit: MAX_LIMIT,
+ type: types.aggregation.none.value,
+ steppedChart: true
+ };
+ } else {
+ subscriptionTimewindow.aggregation = {
+ interval: SECOND,
+ limit: AVG_LIMIT,
+ type: types.aggregation.avg.value
+ };
+ }
- if (angular.isDefined(timewindow.aggregation)) {
+ if (angular.isDefined(timewindow.aggregation) && !steppedChart) {
subscriptionTimewindow.aggregation = {
type: timewindow.aggregation.type || types.aggregation.avg.value,
limit: timewindow.aggregation.limit || AVG_LIMIT
ui/src/app/api/widget.service.js 6(+5 -1)
diff --git a/ui/src/app/api/widget.service.js b/ui/src/app/api/widget.service.js
index 842b976..9fbb819 100644
--- a/ui/src/app/api/widget.service.js
+++ b/ui/src/app/api/widget.service.js
@@ -560,7 +560,8 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, $tr
useCustomDatasources: false,
maxDatasources: -1, //unlimited
maxDataKeys: -1, //unlimited
- dataKeysOptional: false
+ dataKeysOptional: false,
+ steppedChart: false
};
' }\n\n' +
@@ -631,6 +632,9 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, $tr
if (angular.isUndefined(result.typeParameters.dataKeysOptional)) {
result.typeParameters.dataKeysOptional = false;
}
+ if (angular.isUndefined(result.typeParameters.steppedChart)) {
+ result.typeParameters.steppedChart = false;
+ }
if (angular.isFunction(widgetTypeInstance.actionSources)) {
result.actionSources = widgetTypeInstance.actionSources();
} else {
diff --git a/ui/src/app/components/widget/widget.controller.js b/ui/src/app/components/widget/widget.controller.js
index 8dde1fa..34a48f7 100644
--- a/ui/src/app/components/widget/widget.controller.js
+++ b/ui/src/app/components/widget/widget.controller.js
@@ -339,7 +339,8 @@ export default function WidgetController($scope, $state, $timeout, $window, $ele
var deferred = $q.defer();
if (widget.type !== types.widgetType.rpc.value && widget.type !== types.widgetType.static.value) {
options = {
- type: widget.type
+ type: widget.type,
+ steppedChart: vm.typeParameters.steppedChart
}
if (widget.type == types.widgetType.alarm.value) {
options.alarmSource = angular.copy(widget.config.alarmSource);
ui/src/app/widget/lib/flot-widget.js 14(+11 -3)
diff --git a/ui/src/app/widget/lib/flot-widget.js b/ui/src/app/widget/lib/flot-widget.js
index ff60bde..bf2b77e 100644
--- a/ui/src/app/widget/lib/flot-widget.js
+++ b/ui/src/app/widget/lib/flot-widget.js
@@ -168,7 +168,7 @@ export default class TbFlot {
}
};
- if (this.chartType === 'line' || this.chartType === 'bar') {
+ if (this.chartType === 'line' || this.chartType === 'bar' || this.chartType === 'stepped') {
options.xaxis = {
mode: 'time',
timezone: 'browser',
@@ -270,6 +270,14 @@ export default class TbFlot {
fill: 0.9
}
}
+
+ if (this.chartType === 'stepped') {
+ options.series.lines = {
+ steps: true,
+ show: true
+ }
+ }
+
} else if (this.chartType === 'pie') {
options.series = {
pie: {
@@ -381,7 +389,7 @@ export default class TbFlot {
this.options.colors = colors;
this.options.yaxes = angular.copy(this.yaxes);
- if (this.chartType === 'line' || this.chartType === 'bar') {
+ if (this.chartType === 'line' || this.chartType === 'bar' || this.chartType === 'stepped') {
if (this.chartType === 'bar') {
this.options.series.bars.barWidth = this.subscription.timeWindow.interval * 0.6;
}
@@ -434,7 +442,7 @@ export default class TbFlot {
}
if (this.subscription) {
if (!this.isMouseInteraction && this.ctx.plot) {
- if (this.chartType === 'line' || this.chartType === 'bar') {
+ if (this.chartType === 'line' || this.chartType === 'bar' || this.chartType === 'stepped') {
var axisVisibilityChanged = false;
if (this.yaxis) {