Browse Source

Stepped chart

pull/282/head
Igor Kulikov 9 years ago
parent
commit
70ddf20448
  1. 9
      ui/src/app/api/data-aggregator.js
  2. 43
      ui/src/app/api/datasource.service.js
  3. 4
      ui/src/app/api/subscription.js
  4. 18
      ui/src/app/api/time.service.js
  5. 6
      ui/src/app/api/widget.service.js
  6. 3
      ui/src/app/components/widget/widget.controller.js
  7. 14
      ui/src/app/widget/lib/flot-widget.js

9
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;

43
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

4
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;

18
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

6
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 {

3
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);

14
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) {

Loading…
Cancel
Save