UI: Add bars widget. Improve tooltips and aggregation.
This commit is contained in:
parent
e4963de151
commit
a0d7e4be05
@ -32,6 +32,13 @@ import org.thingsboard.server.exception.ThingsboardException;
|
|||||||
@RequestMapping("/api")
|
@RequestMapping("/api")
|
||||||
public class DashboardController extends BaseController {
|
public class DashboardController extends BaseController {
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
|
||||||
|
@RequestMapping(value = "/dashboard/serverTime", method = RequestMethod.GET)
|
||||||
|
@ResponseBody
|
||||||
|
public long getServerTime() throws ThingsboardException {
|
||||||
|
return System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
|
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
|
||||||
@RequestMapping(value = "/dashboard/{dashboardId}", method = RequestMethod.GET)
|
@RequestMapping(value = "/dashboard/{dashboardId}", method = RequestMethod.GET)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import org.thingsboard.server.extensions.core.plugin.telemetry.sub.SubscriptionT
|
|||||||
@Data
|
@Data
|
||||||
public class TimeseriesSubscriptionCmd extends SubscriptionCmd {
|
public class TimeseriesSubscriptionCmd extends SubscriptionCmd {
|
||||||
|
|
||||||
|
private long startTs;
|
||||||
private long timeWindow;
|
private long timeWindow;
|
||||||
private int limit;
|
private int limit;
|
||||||
private String agg;
|
private String agg;
|
||||||
|
|||||||
@ -191,8 +191,8 @@ public class TelemetryWebsocketMsgHandler extends DefaultWebsocketMsgHandler {
|
|||||||
if (cmd.getTimeWindow() > 0) {
|
if (cmd.getTimeWindow() > 0) {
|
||||||
List<String> keys = new ArrayList<>(getKeys(cmd).orElse(Collections.emptySet()));
|
List<String> keys = new ArrayList<>(getKeys(cmd).orElse(Collections.emptySet()));
|
||||||
log.debug("[{}] fetching timeseries data for last {} ms for keys: ({}) for device : {}", sessionId, cmd.getTimeWindow(), cmd.getKeys(), cmd.getDeviceId());
|
log.debug("[{}] fetching timeseries data for last {} ms for keys: ({}) for device : {}", sessionId, cmd.getTimeWindow(), cmd.getKeys(), cmd.getDeviceId());
|
||||||
long endTs = System.currentTimeMillis();
|
startTs = cmd.getStartTs();
|
||||||
startTs = endTs - cmd.getTimeWindow();
|
long endTs = cmd.getStartTs() + cmd.getTimeWindow();
|
||||||
List<TsKvQuery> queries = keys.stream().map(key -> new BaseTsKvQuery(key, startTs, endTs, getLimit(cmd.getLimit()), getAggregation(cmd.getAgg()))).collect(Collectors.toList());
|
List<TsKvQuery> queries = keys.stream().map(key -> new BaseTsKvQuery(key, startTs, endTs, getLimit(cmd.getLimit()), getAggregation(cmd.getAgg()))).collect(Collectors.toList());
|
||||||
ctx.loadTimeseries(deviceId, queries, getSubscriptionCallback(sessionRef, cmd, sessionId, deviceId, startTs, keys));
|
ctx.loadTimeseries(deviceId, queries, getSubscriptionCallback(sessionRef, cmd, sessionId, deviceId, startTs, keys));
|
||||||
} else {
|
} else {
|
||||||
@ -234,7 +234,7 @@ public class TelemetryWebsocketMsgHandler extends DefaultWebsocketMsgHandler {
|
|||||||
return new PluginCallback<List<TsKvEntry>>() {
|
return new PluginCallback<List<TsKvEntry>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(PluginContext ctx, List<TsKvEntry> data) {
|
public void onSuccess(PluginContext ctx, List<TsKvEntry> data) {
|
||||||
sendWsMsg(ctx, sessionRef, new SubscriptionUpdate(cmd.getCmdId(), startTs, data));
|
sendWsMsg(ctx, sessionRef, new SubscriptionUpdate(cmd.getCmdId(), data));
|
||||||
|
|
||||||
Map<String, Long> subState = new HashMap<>(keys.size());
|
Map<String, Long> subState = new HashMap<>(keys.size());
|
||||||
keys.forEach(key -> subState.put(key, startTs));
|
keys.forEach(key -> subState.put(key, startTs));
|
||||||
|
|||||||
@ -26,16 +26,10 @@ public class SubscriptionUpdate {
|
|||||||
private int errorCode;
|
private int errorCode;
|
||||||
private String errorMsg;
|
private String errorMsg;
|
||||||
private Map<String, List<Object>> data;
|
private Map<String, List<Object>> data;
|
||||||
private long serverStartTs;
|
|
||||||
|
|
||||||
public SubscriptionUpdate(int subscriptionId, List<TsKvEntry> data) {
|
public SubscriptionUpdate(int subscriptionId, List<TsKvEntry> data) {
|
||||||
this(subscriptionId, 0L, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SubscriptionUpdate(int subscriptionId, long serverStartTs, List<TsKvEntry> data) {
|
|
||||||
super();
|
super();
|
||||||
this.subscriptionId = subscriptionId;
|
this.subscriptionId = subscriptionId;
|
||||||
this.serverStartTs = serverStartTs;
|
|
||||||
this.data = new TreeMap<>();
|
this.data = new TreeMap<>();
|
||||||
for (TsKvEntry tsEntry : data) {
|
for (TsKvEntry tsEntry : data) {
|
||||||
List<Object> values = this.data.get(tsEntry.getKey());
|
List<Object> values = this.data.get(tsEntry.getKey());
|
||||||
@ -95,13 +89,9 @@ public class SubscriptionUpdate {
|
|||||||
return errorMsg;
|
return errorMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getServerStartTs() {
|
|
||||||
return serverStartTs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SubscriptionUpdate [subscriptionId=" + subscriptionId + ", errorCode=" + errorCode + ", errorMsg=" + errorMsg + ", data="
|
return "SubscriptionUpdate [subscriptionId=" + subscriptionId + ", errorCode=" + errorCode + ", errorMsg=" + errorMsg + ", data="
|
||||||
+ data + ", serverStartTs=" + serverStartTs+ "]";
|
+ data + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,7 @@ function DashboardService($http, $q) {
|
|||||||
var service = {
|
var service = {
|
||||||
assignDashboardToCustomer: assignDashboardToCustomer,
|
assignDashboardToCustomer: assignDashboardToCustomer,
|
||||||
getCustomerDashboards: getCustomerDashboards,
|
getCustomerDashboards: getCustomerDashboards,
|
||||||
|
getServerTimeDiff: getServerTimeDiff,
|
||||||
getDashboard: getDashboard,
|
getDashboard: getDashboard,
|
||||||
getTenantDashboards: getTenantDashboards,
|
getTenantDashboards: getTenantDashboards,
|
||||||
deleteDashboard: deleteDashboard,
|
deleteDashboard: deleteDashboard,
|
||||||
@ -71,6 +72,21 @@ function DashboardService($http, $q) {
|
|||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getServerTimeDiff() {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
var url = '/api/dashboard/serverTime';
|
||||||
|
var ct1 = Date.now();
|
||||||
|
$http.get(url, null).then(function success(response) {
|
||||||
|
var ct2 = Date.now();
|
||||||
|
var st = response.data;
|
||||||
|
var stDiff = Math.ceil(st - (ct1+ct2)/2);
|
||||||
|
deferred.resolve(stDiff);
|
||||||
|
}, function fail() {
|
||||||
|
deferred.reject();
|
||||||
|
});
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
|
||||||
function getDashboard(dashboardId) {
|
function getDashboard(dashboardId) {
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
var url = '/api/dashboard/' + dashboardId;
|
var url = '/api/dashboard/' + dashboardId;
|
||||||
|
|||||||
@ -16,31 +16,26 @@
|
|||||||
|
|
||||||
export default class DataAggregator {
|
export default class DataAggregator {
|
||||||
|
|
||||||
constructor(onDataCb, limit, aggregationType, timeWindow, types, $timeout, $filter) {
|
constructor(onDataCb, tsKeyNames, startTs, limit, aggregationType, timeWindow, interval, types, $timeout, $filter) {
|
||||||
this.onDataCb = onDataCb;
|
this.onDataCb = onDataCb;
|
||||||
|
this.tsKeyNames = tsKeyNames;
|
||||||
|
this.startTs = startTs;
|
||||||
this.aggregationType = aggregationType;
|
this.aggregationType = aggregationType;
|
||||||
this.types = types;
|
this.types = types;
|
||||||
this.$timeout = $timeout;
|
this.$timeout = $timeout;
|
||||||
this.$filter = $filter;
|
this.$filter = $filter;
|
||||||
this.dataReceived = false;
|
this.dataReceived = false;
|
||||||
this.noAggregation = aggregationType === types.aggregation.none.value;
|
this.noAggregation = aggregationType === types.aggregation.none.value;
|
||||||
var interval = Math.floor(timeWindow / limit);
|
this.limit = limit;
|
||||||
if (!this.noAggregation) {
|
this.timeWindow = timeWindow;
|
||||||
this.interval = Math.max(interval, 1000);
|
this.interval = interval;
|
||||||
this.limit = Math.ceil(interval/this.interval * limit);
|
|
||||||
this.timeWindow = this.interval * this.limit;
|
|
||||||
} else {
|
|
||||||
this.limit = limit;
|
|
||||||
this.timeWindow = interval * this.limit;
|
|
||||||
this.interval = 1000;
|
|
||||||
}
|
|
||||||
this.aggregationTimeout = this.interval;
|
this.aggregationTimeout = this.interval;
|
||||||
switch (aggregationType) {
|
switch (aggregationType) {
|
||||||
case types.aggregation.min.value:
|
case types.aggregation.min.value:
|
||||||
this.aggFunction = min;
|
this.aggFunction = min;
|
||||||
break;
|
break;
|
||||||
case types.aggregation.max.value:
|
case types.aggregation.max.value:
|
||||||
this.aggFunction = max
|
this.aggFunction = max;
|
||||||
break;
|
break;
|
||||||
case types.aggregation.avg.value:
|
case types.aggregation.avg.value:
|
||||||
this.aggFunction = avg;
|
this.aggFunction = avg;
|
||||||
@ -59,42 +54,56 @@ export default class DataAggregator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onData(data) {
|
onData(data, update, history) {
|
||||||
if (!this.dataReceived) {
|
if (!this.dataReceived) {
|
||||||
this.elapsed = 0;
|
this.elapsed = 0;
|
||||||
this.dataReceived = true;
|
this.dataReceived = true;
|
||||||
this.startTs = data.serverStartTs;
|
|
||||||
this.endTs = this.startTs + this.timeWindow;
|
this.endTs = this.startTs + this.timeWindow;
|
||||||
this.aggregationMap = processAggregatedData(data.data, this.aggregationType === this.types.aggregation.count.value, this.noAggregation);
|
if (update) {
|
||||||
this.onInterval(currentTime());
|
this.aggregationMap = {};
|
||||||
|
updateAggregatedData(this.aggregationMap, this.aggregationType === this.types.aggregation.count.value,
|
||||||
|
this.noAggregation, this.aggFunction, data.data, this.interval, this.startTs);
|
||||||
|
} else {
|
||||||
|
this.aggregationMap = processAggregatedData(data.data, this.aggregationType === this.types.aggregation.count.value, this.noAggregation);
|
||||||
|
}
|
||||||
|
this.onInterval(currentTime(), history);
|
||||||
} else {
|
} else {
|
||||||
updateAggregatedData(this.aggregationMap, this.aggregationType === this.types.aggregation.count.value,
|
updateAggregatedData(this.aggregationMap, this.aggregationType === this.types.aggregation.count.value,
|
||||||
this.noAggregation, this.aggFunction, data.data, this.interval, this.startTs);
|
this.noAggregation, this.aggFunction, data.data, this.interval, this.startTs);
|
||||||
|
if (history) {
|
||||||
|
this.onInterval(currentTime(), history);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onInterval(startedTime) {
|
onInterval(startedTime, history) {
|
||||||
var now = currentTime();
|
var now = currentTime();
|
||||||
this.elapsed += now - startedTime;
|
this.elapsed += now - startedTime;
|
||||||
if (this.intervalTimeoutHandle) {
|
if (this.intervalTimeoutHandle) {
|
||||||
this.$timeout.cancel(this.intervalTimeoutHandle);
|
this.$timeout.cancel(this.intervalTimeoutHandle);
|
||||||
this.intervalTimeoutHandle = null;
|
this.intervalTimeoutHandle = null;
|
||||||
}
|
}
|
||||||
var delta = Math.floor(this.elapsed / this.interval);
|
if (!history) {
|
||||||
if (delta || !this.data) {
|
var delta = Math.floor(this.elapsed / this.interval);
|
||||||
this.startTs += delta * this.interval;
|
if (delta || !this.data) {
|
||||||
this.endTs += delta * this.interval;
|
this.startTs += delta * this.interval;
|
||||||
this.data = toData(this.aggregationMap, this.startTs, this.endTs, this.$filter, this.limit);
|
this.endTs += delta * this.interval;
|
||||||
this.elapsed = this.elapsed - delta * this.interval;
|
this.data = toData(this.tsKeyNames, this.aggregationMap, this.startTs, this.endTs, this.$filter, this.limit);
|
||||||
|
this.elapsed = this.elapsed - delta * this.interval;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.data = toData(this.tsKeyNames, this.aggregationMap, this.startTs, this.endTs, this.$filter, this.limit);
|
||||||
}
|
}
|
||||||
if (this.onDataCb) {
|
if (this.onDataCb) {
|
||||||
this.onDataCb(this.data, this.startTs, this.endTs);
|
this.onDataCb(this.data, this.startTs, this.endTs);
|
||||||
}
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
this.intervalTimeoutHandle = this.$timeout(function() {
|
if (!history) {
|
||||||
self.onInterval(now);
|
this.intervalTimeoutHandle = this.$timeout(function() {
|
||||||
}, this.aggregationTimeout, false);
|
self.onInterval(now);
|
||||||
|
}, this.aggregationTimeout, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
@ -172,12 +181,12 @@ function updateAggregatedData(aggregationMap, isCount, noAggregation, aggFunctio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toData(aggregationMap, startTs, endTs, $filter, limit) {
|
function toData(tsKeyNames, aggregationMap, startTs, endTs, $filter, limit) {
|
||||||
var data = {};
|
var data = {};
|
||||||
|
for (var k in tsKeyNames) {
|
||||||
|
data[tsKeyNames[k]] = [];
|
||||||
|
}
|
||||||
for (var key in aggregationMap) {
|
for (var key in aggregationMap) {
|
||||||
if (!data[key]) {
|
|
||||||
data[key] = [];
|
|
||||||
}
|
|
||||||
var aggKeyData = aggregationMap[key];
|
var aggKeyData = aggregationMap[key];
|
||||||
var keyData = data[key];
|
var keyData = data[key];
|
||||||
for (var aggTimestamp in aggKeyData) {
|
for (var aggTimestamp in aggKeyData) {
|
||||||
@ -185,7 +194,7 @@ function toData(aggregationMap, startTs, endTs, $filter, limit) {
|
|||||||
delete aggKeyData[aggTimestamp];
|
delete aggKeyData[aggTimestamp];
|
||||||
} else if (aggTimestamp <= endTs) {
|
} else if (aggTimestamp <= endTs) {
|
||||||
var aggData = aggKeyData[aggTimestamp];
|
var aggData = aggKeyData[aggTimestamp];
|
||||||
var kvPair = [aggTimestamp, aggData.aggValue];
|
var kvPair = [Number(aggTimestamp), aggData.aggValue];
|
||||||
keyData.push(kvPair);
|
keyData.push(kvPair);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -108,9 +108,9 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
datasourceSubscription.subscriptionTimewindow.fixedWindow;
|
datasourceSubscription.subscriptionTimewindow.fixedWindow;
|
||||||
var realtime = datasourceSubscription.subscriptionTimewindow &&
|
var realtime = datasourceSubscription.subscriptionTimewindow &&
|
||||||
datasourceSubscription.subscriptionTimewindow.realtimeWindowMs;
|
datasourceSubscription.subscriptionTimewindow.realtimeWindowMs;
|
||||||
var dataGenFunction = null;
|
|
||||||
var timer;
|
var timer;
|
||||||
var frequency;
|
var frequency;
|
||||||
|
var dataAggregator;
|
||||||
|
|
||||||
var subscription = {
|
var subscription = {
|
||||||
addListener: addListener,
|
addListener: addListener,
|
||||||
@ -131,19 +131,20 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
dataKey.index = i;
|
dataKey.index = i;
|
||||||
var key;
|
var key;
|
||||||
if (datasourceType === types.datasourceType.function) {
|
if (datasourceType === types.datasourceType.function) {
|
||||||
key = utils.objectHashCode(dataKey);
|
|
||||||
if (!dataKey.func) {
|
if (!dataKey.func) {
|
||||||
dataKey.func = new Function("time", "prevValue", dataKey.funcBody);
|
dataKey.func = new Function("time", "prevValue", dataKey.funcBody);
|
||||||
}
|
}
|
||||||
datasourceData[key] = {
|
} else {
|
||||||
data: []
|
|
||||||
};
|
|
||||||
dataKeys[key] = dataKey;
|
|
||||||
} else if (datasourceType === types.datasourceType.device) {
|
|
||||||
key = dataKey.name + '_' + dataKey.type;
|
|
||||||
if (dataKey.postFuncBody && !dataKey.postFunc) {
|
if (dataKey.postFuncBody && !dataKey.postFunc) {
|
||||||
dataKey.postFunc = new Function("time", "value", "prevValue", dataKey.postFuncBody);
|
dataKey.postFunc = new Function("time", "value", "prevValue", dataKey.postFuncBody);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (datasourceType === types.datasourceType.device || datasourceSubscription.type === types.widgetType.timeseries.value) {
|
||||||
|
if (datasourceType === types.datasourceType.function) {
|
||||||
|
key = dataKey.name + '_' + dataKey.index + '_' + dataKey.type;
|
||||||
|
} else {
|
||||||
|
key = dataKey.name + '_' + dataKey.type;
|
||||||
|
}
|
||||||
var dataKeysList = dataKeys[key];
|
var dataKeysList = dataKeys[key];
|
||||||
if (!dataKeysList) {
|
if (!dataKeysList) {
|
||||||
dataKeysList = [];
|
dataKeysList = [];
|
||||||
@ -153,24 +154,19 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
datasourceData[key + '_' + index] = {
|
datasourceData[key + '_' + index] = {
|
||||||
data: []
|
data: []
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
key = utils.objectHashCode(dataKey);
|
||||||
|
datasourceData[key] = {
|
||||||
|
data: []
|
||||||
|
};
|
||||||
|
dataKeys[key] = dataKey;
|
||||||
}
|
}
|
||||||
dataKey.key = key;
|
dataKey.key = key;
|
||||||
}
|
}
|
||||||
if (datasourceType === types.datasourceType.function) {
|
if (datasourceType === types.datasourceType.function) {
|
||||||
frequency = 1000;
|
frequency = 1000;
|
||||||
if (datasourceSubscription.type === types.widgetType.timeseries.value) {
|
if (datasourceSubscription.type === types.widgetType.timeseries.value) {
|
||||||
dataGenFunction = generateSeries;
|
frequency = Math.min(datasourceSubscription.subscriptionTimewindow.aggregation.interval, 5000);
|
||||||
var window;
|
|
||||||
if (realtime) {
|
|
||||||
window = datasourceSubscription.subscriptionTimewindow.realtimeWindowMs;
|
|
||||||
} else {
|
|
||||||
window = datasourceSubscription.subscriptionTimewindow.fixedWindow.endTimeMs -
|
|
||||||
datasourceSubscription.subscriptionTimewindow.fixedWindow.startTimeMs;
|
|
||||||
}
|
|
||||||
frequency = window / 1000 * 20;
|
|
||||||
} else if (datasourceSubscription.type === types.widgetType.latest.value) {
|
|
||||||
dataGenFunction = generateLatest;
|
|
||||||
frequency = 1000;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -193,14 +189,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
function syncListener(listener) {
|
function syncListener(listener) {
|
||||||
var key;
|
var key;
|
||||||
var dataKey;
|
var dataKey;
|
||||||
if (datasourceType === types.datasourceType.function) {
|
if (datasourceType === types.datasourceType.device || datasourceSubscription.type === types.widgetType.timeseries.value) {
|
||||||
for (key in dataKeys) {
|
|
||||||
dataKey = dataKeys[key];
|
|
||||||
listener.dataUpdated(datasourceData[key],
|
|
||||||
listener.datasourceIndex,
|
|
||||||
dataKey.index);
|
|
||||||
}
|
|
||||||
} else if (datasourceType === types.datasourceType.device) {
|
|
||||||
for (key in dataKeys) {
|
for (key in dataKeys) {
|
||||||
var dataKeysList = dataKeys[key];
|
var dataKeysList = dataKeys[key];
|
||||||
for (var i = 0; i < dataKeysList.length; i++) {
|
for (var i = 0; i < dataKeysList.length; i++) {
|
||||||
@ -211,6 +200,13 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
dataKey.index);
|
dataKey.index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
for (key in dataKeys) {
|
||||||
|
dataKey = dataKeys[key];
|
||||||
|
listener.dataUpdated(datasourceData[key],
|
||||||
|
listener.datasourceIndex,
|
||||||
|
dataKey.index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +214,10 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
if (history && !hasListeners()) {
|
if (history && !hasListeners()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//$log.debug("started!");
|
var subsTw = datasourceSubscription.subscriptionTimewindow;
|
||||||
|
var tsKeyNames = [];
|
||||||
|
var dataKey;
|
||||||
|
|
||||||
if (datasourceType === types.datasourceType.device) {
|
if (datasourceType === types.datasourceType.device) {
|
||||||
|
|
||||||
//send subscribe command
|
//send subscribe command
|
||||||
@ -228,12 +227,13 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
|
|
||||||
for (var key in dataKeys) {
|
for (var key in dataKeys) {
|
||||||
var dataKeysList = dataKeys[key];
|
var dataKeysList = dataKeys[key];
|
||||||
var dataKey = dataKeysList[0];
|
dataKey = dataKeysList[0];
|
||||||
if (dataKey.type === types.dataKeyType.timeseries) {
|
if (dataKey.type === types.dataKeyType.timeseries) {
|
||||||
if (tsKeys.length > 0) {
|
if (tsKeys.length > 0) {
|
||||||
tsKeys += ',';
|
tsKeys += ',';
|
||||||
}
|
}
|
||||||
tsKeys += dataKey.name;
|
tsKeys += dataKey.name;
|
||||||
|
tsKeyNames.push(dataKey.name);
|
||||||
} else if (dataKey.type === types.dataKeyType.attribute) {
|
} else if (dataKey.type === types.dataKeyType.attribute) {
|
||||||
if (attrKeys.length > 0) {
|
if (attrKeys.length > 0) {
|
||||||
attrKeys += ',';
|
attrKeys += ',';
|
||||||
@ -252,10 +252,10 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
var historyCommand = {
|
var historyCommand = {
|
||||||
deviceId: datasourceSubscription.deviceId,
|
deviceId: datasourceSubscription.deviceId,
|
||||||
keys: tsKeys,
|
keys: tsKeys,
|
||||||
startTs: datasourceSubscription.subscriptionTimewindow.fixedWindow.startTimeMs,
|
startTs: subsTw.fixedWindow.startTimeMs,
|
||||||
endTs: datasourceSubscription.subscriptionTimewindow.fixedWindow.endTimeMs,
|
endTs: subsTw.fixedWindow.endTimeMs,
|
||||||
limit: datasourceSubscription.subscriptionTimewindow.aggregation.limit,
|
limit: subsTw.aggregation.limit,
|
||||||
agg: datasourceSubscription.subscriptionTimewindow.aggregation.type
|
agg: subsTw.aggregation.type
|
||||||
};
|
};
|
||||||
|
|
||||||
subscriber = {
|
subscriber = {
|
||||||
@ -287,16 +287,20 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (datasourceSubscription.type === types.widgetType.timeseries.value) {
|
if (datasourceSubscription.type === types.widgetType.timeseries.value) {
|
||||||
subscriptionCommand.timeWindow = datasourceSubscription.subscriptionTimewindow.realtimeWindowMs;
|
subscriptionCommand.startTs = subsTw.startTs;
|
||||||
subscriptionCommand.limit = datasourceSubscription.subscriptionTimewindow.aggregation.limit;
|
subscriptionCommand.timeWindow = subsTw.aggregation.timeWindow;
|
||||||
subscriptionCommand.agg = datasourceSubscription.subscriptionTimewindow.aggregation.type;
|
subscriptionCommand.limit = subsTw.aggregation.limit;
|
||||||
var dataAggregator = new DataAggregator(
|
subscriptionCommand.agg = subsTw.aggregation.type;
|
||||||
|
dataAggregator = new DataAggregator(
|
||||||
function(data, startTs, endTs) {
|
function(data, startTs, endTs) {
|
||||||
onData(data, types.dataKeyType.timeseries, startTs, endTs);
|
onData(data, types.dataKeyType.timeseries, startTs, endTs);
|
||||||
},
|
},
|
||||||
subscriptionCommand.limit,
|
tsKeyNames,
|
||||||
subscriptionCommand.agg,
|
subsTw.startTs,
|
||||||
subscriptionCommand.timeWindow,
|
subsTw.aggregation.limit,
|
||||||
|
subsTw.aggregation.type,
|
||||||
|
subsTw.aggregation.timeWindow,
|
||||||
|
subsTw.aggregation.interval,
|
||||||
types,
|
types,
|
||||||
$timeout,
|
$timeout,
|
||||||
$filter
|
$filter
|
||||||
@ -308,9 +312,6 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
dataAggregator.reset();
|
dataAggregator.reset();
|
||||||
onReconnected();
|
onReconnected();
|
||||||
}
|
}
|
||||||
subscriber.onDestroy = function() {
|
|
||||||
dataAggregator.destroy();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
subscriber.onReconnected = function() {
|
subscriber.onReconnected = function() {
|
||||||
onReconnected();
|
onReconnected();
|
||||||
@ -353,7 +354,30 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (dataGenFunction) {
|
} else if (datasourceType === types.datasourceType.function) {
|
||||||
|
if (datasourceSubscription.type === types.widgetType.timeseries.value) {
|
||||||
|
for (key in dataKeys) {
|
||||||
|
var dataKeyList = dataKeys[key];
|
||||||
|
for (var index = 0; index < dataKeyList.length; index++) {
|
||||||
|
dataKey = dataKeyList[index];
|
||||||
|
tsKeyNames.push(dataKey.name+'_'+dataKey.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataAggregator = new DataAggregator(
|
||||||
|
function (data, startTs, endTs) {
|
||||||
|
onData(data, types.dataKeyType.function, startTs, endTs);
|
||||||
|
},
|
||||||
|
tsKeyNames,
|
||||||
|
subsTw.startTs,
|
||||||
|
subsTw.aggregation.limit,
|
||||||
|
subsTw.aggregation.type,
|
||||||
|
subsTw.aggregation.timeWindow,
|
||||||
|
subsTw.aggregation.interval,
|
||||||
|
types,
|
||||||
|
$timeout,
|
||||||
|
$filter
|
||||||
|
);
|
||||||
|
}
|
||||||
if (history) {
|
if (history) {
|
||||||
onTick();
|
onTick();
|
||||||
} else {
|
} else {
|
||||||
@ -377,30 +401,17 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
}
|
}
|
||||||
subscribers = {};
|
subscribers = {};
|
||||||
}
|
}
|
||||||
}
|
if (dataAggregator) {
|
||||||
|
dataAggregator.destroy();
|
||||||
function boundToInterval(data, timewindowMs) {
|
dataAggregator = null;
|
||||||
if (data.length > 1) {
|
|
||||||
var start = data[0][0];
|
|
||||||
var end = data[data.length - 1][0];
|
|
||||||
var i = 0;
|
|
||||||
var currentInterval = end - start;
|
|
||||||
while (currentInterval > timewindowMs && i < data.length - 2) {
|
|
||||||
i++;
|
|
||||||
start = data[i][0];
|
|
||||||
currentInterval = end - start;
|
|
||||||
}
|
|
||||||
if (i > 1) {
|
|
||||||
data.splice(0, i - 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateSeries(dataKey, startTime, endTime) {
|
function generateSeries(dataKey, index, startTime, endTime) {
|
||||||
var data = [];
|
var data = [];
|
||||||
var prevSeries;
|
var prevSeries;
|
||||||
var datasourceKeyData = datasourceData[dataKey.key].data;
|
var datasourceDataKey = dataKey.key + '_' + index;
|
||||||
|
var datasourceKeyData = datasourceData[datasourceDataKey].data;
|
||||||
if (datasourceKeyData.length > 0) {
|
if (datasourceKeyData.length > 0) {
|
||||||
prevSeries = datasourceKeyData[datasourceKeyData.length - 1];
|
prevSeries = datasourceKeyData[datasourceKeyData.length - 1];
|
||||||
} else {
|
} else {
|
||||||
@ -417,18 +428,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
if (data.length > 0) {
|
if (data.length > 0) {
|
||||||
dataKey.lastUpdateTime = data[data.length - 1][0];
|
dataKey.lastUpdateTime = data[data.length - 1][0];
|
||||||
}
|
}
|
||||||
if (realtime) {
|
return data;
|
||||||
datasourceData[dataKey.key].data = boundToInterval(datasourceKeyData.concat(data),
|
|
||||||
datasourceSubscription.subscriptionTimewindow.realtimeWindowMs);
|
|
||||||
} else {
|
|
||||||
datasourceData[dataKey.key].data = data;
|
|
||||||
}
|
|
||||||
for (var i in listeners) {
|
|
||||||
var listener = listeners[i];
|
|
||||||
listener.dataUpdated(datasourceData[dataKey.key],
|
|
||||||
listener.datasourceIndex,
|
|
||||||
dataKey.index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateLatest(dataKey) {
|
function generateLatest(dataKey) {
|
||||||
@ -458,23 +458,32 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
if (datasourceSubscription.type === types.widgetType.timeseries.value) {
|
if (datasourceSubscription.type === types.widgetType.timeseries.value) {
|
||||||
var startTime;
|
var startTime;
|
||||||
var endTime;
|
var endTime;
|
||||||
for (key in dataKeys) {
|
var generatedData = {
|
||||||
var dataKey = dataKeys[key];
|
data: {
|
||||||
if (!startTime) {
|
}
|
||||||
if (realtime) {
|
};
|
||||||
endTime = (new Date).getTime();
|
for (key in dataKeys) {
|
||||||
if (dataKey.lastUpdateTime) {
|
var dataKeyList = dataKeys[key];
|
||||||
startTime = dataKey.lastUpdateTime + frequency;
|
for (var index = 0; index < dataKeyList.length; index ++) {
|
||||||
} else {
|
var dataKey = dataKeyList[index];
|
||||||
startTime = endTime - datasourceSubscription.subscriptionTimewindow.realtimeWindowMs;
|
if (!startTime) {
|
||||||
}
|
if (realtime) {
|
||||||
} else {
|
if (dataKey.lastUpdateTime) {
|
||||||
startTime = datasourceSubscription.subscriptionTimewindow.fixedWindow.startTimeMs;
|
startTime = dataKey.lastUpdateTime + frequency
|
||||||
endTime = datasourceSubscription.subscriptionTimewindow.fixedWindow.endTimeMs;
|
} else {
|
||||||
}
|
startTime = datasourceSubscription.subscriptionTimewindow.startTs;
|
||||||
|
}
|
||||||
|
endTime = startTime + datasourceSubscription.subscriptionTimewindow.realtimeWindowMs;
|
||||||
|
} else {
|
||||||
|
startTime = datasourceSubscription.subscriptionTimewindow.fixedWindow.startTimeMs;
|
||||||
|
endTime = datasourceSubscription.subscriptionTimewindow.fixedWindow.endTimeMs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var data = generateSeries(dataKey, index, startTime, endTime);
|
||||||
|
generatedData.data[dataKey.name+'_'+dataKey.index] = data;
|
||||||
}
|
}
|
||||||
generateSeries(dataKey, startTime, endTime);
|
|
||||||
}
|
}
|
||||||
|
dataAggregator.onData(generatedData, true, history);
|
||||||
} else if (datasourceSubscription.type === types.widgetType.latest.value) {
|
} else if (datasourceSubscription.type === types.widgetType.latest.value) {
|
||||||
for (key in dataKeys) {
|
for (key in dataKeys) {
|
||||||
generateLatest(dataKeys[key]);
|
generateLatest(dataKeys[key]);
|
||||||
@ -568,8 +577,6 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
}
|
}
|
||||||
if (data.length > 0 || (startTs && endTs)) {
|
if (data.length > 0 || (startTs && endTs)) {
|
||||||
datasourceData[datasourceKey].data = data;
|
datasourceData[datasourceKey].data = data;
|
||||||
datasourceData[datasourceKey].startTs = startTs;
|
|
||||||
datasourceData[datasourceKey].endTs = endTs;
|
|
||||||
for (var i2 in listeners) {
|
for (var i2 in listeners) {
|
||||||
var listener = listeners[i2];
|
var listener = listeners[i2];
|
||||||
listener.dataUpdated(datasourceData[datasourceKey],
|
listener.dataUpdated(datasourceData[datasourceKey],
|
||||||
|
|||||||
@ -68,6 +68,7 @@ function Dashboard() {
|
|||||||
prepareDashboardContextMenu: '&?',
|
prepareDashboardContextMenu: '&?',
|
||||||
prepareWidgetContextMenu: '&?',
|
prepareWidgetContextMenu: '&?',
|
||||||
loadWidgets: '&?',
|
loadWidgets: '&?',
|
||||||
|
getStDiff: '&?',
|
||||||
onInit: '&?',
|
onInit: '&?',
|
||||||
onInitFailed: '&?',
|
onInitFailed: '&?',
|
||||||
dashboardStyle: '=?'
|
dashboardStyle: '=?'
|
||||||
@ -94,6 +95,8 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
|
|||||||
|
|
||||||
vm.gridster = null;
|
vm.gridster = null;
|
||||||
|
|
||||||
|
vm.stDiff = 0;
|
||||||
|
|
||||||
vm.isMobileDisabled = angular.isDefined(vm.isMobileDisabled) ? vm.isMobileDisabled : false;
|
vm.isMobileDisabled = angular.isDefined(vm.isMobileDisabled) ? vm.isMobileDisabled : false;
|
||||||
|
|
||||||
vm.dashboardLoading = true;
|
vm.dashboardLoading = true;
|
||||||
@ -302,7 +305,28 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
loadDashboard();
|
loadStDiff();
|
||||||
|
|
||||||
|
function loadStDiff() {
|
||||||
|
if (vm.getStDiff) {
|
||||||
|
var promise = vm.getStDiff();
|
||||||
|
if (promise) {
|
||||||
|
promise.then(function (stDiff) {
|
||||||
|
vm.stDiff = stDiff;
|
||||||
|
loadDashboard();
|
||||||
|
}, function () {
|
||||||
|
vm.stDiff = 0;
|
||||||
|
loadDashboard();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
vm.stDiff = 0;
|
||||||
|
loadDashboard();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vm.stDiff = 0;
|
||||||
|
loadDashboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function loadDashboard() {
|
function loadDashboard() {
|
||||||
resetWidgetClick();
|
resetWidgetClick();
|
||||||
|
|||||||
@ -93,7 +93,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div flex layout="column" class="tb-widget-content">
|
<div flex layout="column" class="tb-widget-content">
|
||||||
<div flex tb-widget
|
<div flex tb-widget
|
||||||
locals="{ visibleRect: vm.visibleRect, widget: widget, deviceAliasList: vm.deviceAliasList, isEdit: vm.isEdit }">
|
locals="{ visibleRect: vm.visibleRect, widget: widget, deviceAliasList: vm.deviceAliasList, isEdit: vm.isEdit, stDiff: vm.stDiff }">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import 'javascript-detect-element-resize/detect-element-resize';
|
|||||||
|
|
||||||
/*@ngInject*/
|
/*@ngInject*/
|
||||||
export default function WidgetController($scope, $timeout, $window, $element, $q, $log, $injector, tbRaf, types, utils,
|
export default function WidgetController($scope, $timeout, $window, $element, $q, $log, $injector, tbRaf, types, utils,
|
||||||
datasourceService, deviceService, visibleRect, isEdit, widget, deviceAliasList, widgetType) {
|
datasourceService, deviceService, visibleRect, isEdit, stDiff, widget, deviceAliasList, widgetType) {
|
||||||
|
|
||||||
var vm = this;
|
var vm = this;
|
||||||
|
|
||||||
@ -46,7 +46,6 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
|
|||||||
realtimeWindowMs: null,
|
realtimeWindowMs: null,
|
||||||
aggregation: null
|
aggregation: null
|
||||||
};
|
};
|
||||||
var dataUpdateTimer = null;
|
|
||||||
var dataUpdateCaf = null;
|
var dataUpdateCaf = null;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -72,7 +71,9 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
|
|||||||
settings: widget.config.settings,
|
settings: widget.config.settings,
|
||||||
datasources: widget.config.datasources,
|
datasources: widget.config.datasources,
|
||||||
data: [],
|
data: [],
|
||||||
timeWindow: {},
|
timeWindow: {
|
||||||
|
stDiff: stDiff
|
||||||
|
},
|
||||||
timewindowFunctions: {
|
timewindowFunctions: {
|
||||||
onUpdateTimewindow: onUpdateTimewindow,
|
onUpdateTimewindow: onUpdateTimewindow,
|
||||||
onResetTimewindow: onResetTimewindow
|
onResetTimewindow: onResetTimewindow
|
||||||
@ -154,10 +155,11 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTimewindow(startTs, endTs) {
|
function updateTimewindow() {
|
||||||
|
widgetContext.timeWindow.interval = subscriptionTimewindow.aggregation.interval || 1000;
|
||||||
if (subscriptionTimewindow.realtimeWindowMs) {
|
if (subscriptionTimewindow.realtimeWindowMs) {
|
||||||
widgetContext.timeWindow.maxTime = endTs || (new Date).getTime();
|
widgetContext.timeWindow.maxTime = (new Date).getTime() + widgetContext.timeWindow.stDiff;
|
||||||
widgetContext.timeWindow.minTime = startTs || (widgetContext.timeWindow.maxTime - subscriptionTimewindow.realtimeWindowMs);
|
widgetContext.timeWindow.minTime = widgetContext.timeWindow.maxTime - subscriptionTimewindow.realtimeWindowMs;
|
||||||
} else if (subscriptionTimewindow.fixedWindow) {
|
} else if (subscriptionTimewindow.fixedWindow) {
|
||||||
widgetContext.timeWindow.maxTime = subscriptionTimewindow.fixedWindow.endTimeMs;
|
widgetContext.timeWindow.maxTime = subscriptionTimewindow.fixedWindow.endTimeMs;
|
||||||
widgetContext.timeWindow.minTime = subscriptionTimewindow.fixedWindow.startTimeMs;
|
widgetContext.timeWindow.minTime = subscriptionTimewindow.fixedWindow.startTimeMs;
|
||||||
@ -165,10 +167,6 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onDataUpdated() {
|
function onDataUpdated() {
|
||||||
if (dataUpdateTimer) {
|
|
||||||
$timeout.cancel(dataUpdateTimer);
|
|
||||||
dataUpdateTimer = null;
|
|
||||||
}
|
|
||||||
if (widgetContext.inited) {
|
if (widgetContext.inited) {
|
||||||
if (dataUpdateCaf) {
|
if (dataUpdateCaf) {
|
||||||
dataUpdateCaf();
|
dataUpdateCaf();
|
||||||
@ -496,7 +494,8 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
|
|||||||
startTimeMs: startTimeMs,
|
startTimeMs: startTimeMs,
|
||||||
endTimeMs: endTimeMs
|
endTimeMs: endTimeMs
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
aggregation: angular.copy(widget.config.timewindow.aggregation)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,14 +512,10 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
|
|||||||
}
|
}
|
||||||
if (update) {
|
if (update) {
|
||||||
if (subscriptionTimewindow.realtimeWindowMs) {
|
if (subscriptionTimewindow.realtimeWindowMs) {
|
||||||
updateTimewindow(sourceData.startTs, sourceData.endTs);
|
updateTimewindow();
|
||||||
}
|
}
|
||||||
widgetContext.data[datasourceIndex + dataKeyIndex].data = sourceData.data;
|
widgetContext.data[datasourceIndex + dataKeyIndex].data = sourceData.data;
|
||||||
if (widgetContext.data.length > 1 && !dataUpdateTimer) {
|
onDataUpdated();
|
||||||
dataUpdateTimer = $timeout(onDataUpdated, 300, false);
|
|
||||||
} else {
|
|
||||||
onDataUpdated();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,10 +547,6 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
|
|||||||
|
|
||||||
function unsubscribe() {
|
function unsubscribe() {
|
||||||
if (widget.type !== types.widgetType.rpc.value) {
|
if (widget.type !== types.widgetType.rpc.value) {
|
||||||
if (dataUpdateTimer) {
|
|
||||||
$timeout.cancel(dataUpdateTimer);
|
|
||||||
dataUpdateTimer = null;
|
|
||||||
}
|
|
||||||
for (var i in datasourceListeners) {
|
for (var i in datasourceListeners) {
|
||||||
var listener = datasourceListeners[i];
|
var listener = datasourceListeners[i];
|
||||||
datasourceService.unsubscribeFromDatasource(listener);
|
datasourceService.unsubscribeFromDatasource(listener);
|
||||||
@ -575,7 +566,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
|
|||||||
};
|
};
|
||||||
if (widget.type === types.widgetType.timeseries.value &&
|
if (widget.type === types.widgetType.timeseries.value &&
|
||||||
angular.isDefined(widget.config.timewindow)) {
|
angular.isDefined(widget.config.timewindow)) {
|
||||||
|
var timeWindow = 0;
|
||||||
if (angular.isDefined(widget.config.timewindow.aggregation)) {
|
if (angular.isDefined(widget.config.timewindow.aggregation)) {
|
||||||
subscriptionTimewindow.aggregation = {
|
subscriptionTimewindow.aggregation = {
|
||||||
limit: widget.config.timewindow.aggregation.limit || 200,
|
limit: widget.config.timewindow.aggregation.limit || 200,
|
||||||
@ -585,6 +576,8 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
|
|||||||
|
|
||||||
if (angular.isDefined(widget.config.timewindow.realtime)) {
|
if (angular.isDefined(widget.config.timewindow.realtime)) {
|
||||||
subscriptionTimewindow.realtimeWindowMs = widget.config.timewindow.realtime.timewindowMs;
|
subscriptionTimewindow.realtimeWindowMs = widget.config.timewindow.realtime.timewindowMs;
|
||||||
|
subscriptionTimewindow.startTs = (new Date).getTime() + widgetContext.timeWindow.stDiff - subscriptionTimewindow.realtimeWindowMs;
|
||||||
|
timeWindow = subscriptionTimewindow.realtimeWindowMs;
|
||||||
} else if (angular.isDefined(widget.config.timewindow.history)) {
|
} else if (angular.isDefined(widget.config.timewindow.history)) {
|
||||||
if (angular.isDefined(widget.config.timewindow.history.timewindowMs)) {
|
if (angular.isDefined(widget.config.timewindow.history.timewindowMs)) {
|
||||||
var currentTime = (new Date).getTime();
|
var currentTime = (new Date).getTime();
|
||||||
@ -592,14 +585,31 @@ export default function WidgetController($scope, $timeout, $window, $element, $q
|
|||||||
startTimeMs: currentTime - widget.config.timewindow.history.timewindowMs,
|
startTimeMs: currentTime - widget.config.timewindow.history.timewindowMs,
|
||||||
endTimeMs: currentTime
|
endTimeMs: currentTime
|
||||||
}
|
}
|
||||||
|
timeWindow = widget.config.timewindow.history.timewindowMs;
|
||||||
} else {
|
} else {
|
||||||
subscriptionTimewindow.fixedWindow = {
|
subscriptionTimewindow.fixedWindow = {
|
||||||
startTimeMs: widget.config.timewindow.history.fixedTimewindow.startTimeMs,
|
startTimeMs: widget.config.timewindow.history.fixedTimewindow.startTimeMs,
|
||||||
endTimeMs: widget.config.timewindow.history.fixedTimewindow.endTimeMs
|
endTimeMs: widget.config.timewindow.history.fixedTimewindow.endTimeMs
|
||||||
}
|
}
|
||||||
|
timeWindow = subscriptionTimewindow.fixedWindow.endTimeMs - subscriptionTimewindow.fixedWindow.startTimeMs;
|
||||||
}
|
}
|
||||||
|
subscriptionTimewindow.startTs = subscriptionTimewindow.fixedWindow.startTimeMs;
|
||||||
|
}
|
||||||
|
var aggregation = subscriptionTimewindow.aggregation;
|
||||||
|
var noAggregation = aggregation.type === types.aggregation.none.value;
|
||||||
|
var interval = Math.floor(timeWindow / aggregation.limit);
|
||||||
|
if (!noAggregation) {
|
||||||
|
aggregation.interval = Math.max(interval, 1000);
|
||||||
|
aggregation.limit = Math.ceil(interval/aggregation.interval * aggregation.limit);
|
||||||
|
aggregation.timeWindow = aggregation.interval * aggregation.limit;
|
||||||
|
} else {
|
||||||
|
aggregation.timeWindow = interval * aggregation.limit;
|
||||||
|
aggregation.interval = 1000;
|
||||||
}
|
}
|
||||||
updateTimewindow();
|
updateTimewindow();
|
||||||
|
if (subscriptionTimewindow.fixedWindow) {
|
||||||
|
onDataUpdated();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (var i in widget.config.datasources) {
|
for (var i in widget.config.datasources) {
|
||||||
var datasource = widget.config.datasources[i];
|
var datasource = widget.config.datasources[i];
|
||||||
|
|||||||
@ -61,6 +61,7 @@ export default function DashboardController(types, widgetService, userService,
|
|||||||
vm.isTenantAdmin = isTenantAdmin;
|
vm.isTenantAdmin = isTenantAdmin;
|
||||||
vm.isSystemAdmin = isSystemAdmin;
|
vm.isSystemAdmin = isSystemAdmin;
|
||||||
vm.loadDashboard = loadDashboard;
|
vm.loadDashboard = loadDashboard;
|
||||||
|
vm.getServerTimeDiff = getServerTimeDiff;
|
||||||
vm.noData = noData;
|
vm.noData = noData;
|
||||||
vm.onAddWidgetClosed = onAddWidgetClosed;
|
vm.onAddWidgetClosed = onAddWidgetClosed;
|
||||||
vm.onEditWidgetClosed = onEditWidgetClosed;
|
vm.onEditWidgetClosed = onEditWidgetClosed;
|
||||||
@ -94,10 +95,9 @@ export default function DashboardController(types, widgetService, userService,
|
|||||||
widgetService.getBundleWidgetTypes(bundleAlias, isSystem).then(
|
widgetService.getBundleWidgetTypes(bundleAlias, isSystem).then(
|
||||||
function (widgetTypes) {
|
function (widgetTypes) {
|
||||||
|
|
||||||
widgetTypes = $filter('orderBy')(widgetTypes, ['-name']);
|
widgetTypes = $filter('orderBy')(widgetTypes, ['-createdTime']);
|
||||||
|
|
||||||
var top = 0;
|
var top = 0;
|
||||||
var sizeY = 0;
|
|
||||||
|
|
||||||
if (widgetTypes.length > 0) {
|
if (widgetTypes.length > 0) {
|
||||||
loadNext(0);
|
loadNext(0);
|
||||||
@ -135,7 +135,7 @@ export default function DashboardController(types, widgetService, userService,
|
|||||||
} else if (widgetTypeInfo.type === types.widgetType.static.value) {
|
} else if (widgetTypeInfo.type === types.widgetType.static.value) {
|
||||||
vm.staticWidgetTypes.push(widget);
|
vm.staticWidgetTypes.push(widget);
|
||||||
}
|
}
|
||||||
top += sizeY;
|
top += widget.sizeY;
|
||||||
loadNextOrComplete(i);
|
loadNextOrComplete(i);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -144,6 +144,10 @@ export default function DashboardController(types, widgetService, userService,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getServerTimeDiff() {
|
||||||
|
return dashboardService.getServerTimeDiff();
|
||||||
|
}
|
||||||
|
|
||||||
function loadDashboard() {
|
function loadDashboard() {
|
||||||
|
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
|
|||||||
@ -91,6 +91,7 @@
|
|||||||
prepare-widget-context-menu="vm.prepareWidgetContextMenu(widget)"
|
prepare-widget-context-menu="vm.prepareWidgetContextMenu(widget)"
|
||||||
on-remove-widget="vm.removeWidget(event, widget)"
|
on-remove-widget="vm.removeWidget(event, widget)"
|
||||||
load-widgets="vm.loadDashboard()"
|
load-widgets="vm.loadDashboard()"
|
||||||
|
get-st-diff="vm.getServerTimeDiff()"
|
||||||
on-init="vm.dashboardInited(dashboard)"
|
on-init="vm.dashboardInited(dashboard)"
|
||||||
on-init-failed="vm.dashboardInitFailed(e)">
|
on-init-failed="vm.dashboardInitFailed(e)">
|
||||||
</tb-dashboard>
|
</tb-dashboard>
|
||||||
|
|||||||
@ -29,7 +29,7 @@ import EditAttributeValueController from './edit-attribute-value.controller';
|
|||||||
|
|
||||||
/*@ngInject*/
|
/*@ngInject*/
|
||||||
export default function AttributeTableDirective($compile, $templateCache, $rootScope, $q, $mdEditDialog, $mdDialog,
|
export default function AttributeTableDirective($compile, $templateCache, $rootScope, $q, $mdEditDialog, $mdDialog,
|
||||||
$document, $translate, utils, types, deviceService, widgetService) {
|
$document, $translate, utils, types, dashboardService, deviceService, widgetService) {
|
||||||
|
|
||||||
var linker = function (scope, element, attrs) {
|
var linker = function (scope, element, attrs) {
|
||||||
|
|
||||||
@ -357,6 +357,10 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
|
|||||||
scope.getDeviceAttributes(true);
|
scope.getDeviceAttributes(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope.getServerTimeDiff = function() {
|
||||||
|
return dashboardService.getServerTimeDiff();
|
||||||
|
}
|
||||||
|
|
||||||
scope.addWidgetToDashboard = function($event) {
|
scope.addWidgetToDashboard = function($event) {
|
||||||
if (scope.mode === 'widget' && scope.widgetsListCache.length > 0) {
|
if (scope.mode === 'widget' && scope.widgetsListCache.length > 0) {
|
||||||
var widget = scope.widgetsListCache[scope.widgetsCarousel.index][0];
|
var widget = scope.widgetsListCache[scope.widgetsCarousel.index][0];
|
||||||
|
|||||||
@ -158,8 +158,9 @@
|
|||||||
<tb-dashboard
|
<tb-dashboard
|
||||||
device-alias-list="deviceAliases"
|
device-alias-list="deviceAliases"
|
||||||
widgets="widgets"
|
widgets="widgets"
|
||||||
|
get-st-diff="getServerTimeDiff()"
|
||||||
columns="20"
|
columns="20"
|
||||||
is-edit="true"
|
is-edit="false"
|
||||||
is-mobile-disabled="true"
|
is-mobile-disabled="true"
|
||||||
is-edit-action-enabled="false"
|
is-edit-action-enabled="false"
|
||||||
is-remove-action-enabled="false">
|
is-remove-action-enabled="false">
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -54,7 +54,7 @@ export default function WidgetLibraryController($scope, $rootScope, $q, widgetSe
|
|||||||
widgetService.getBundleWidgetTypes(bundleAlias, isSystem).then(
|
widgetService.getBundleWidgetTypes(bundleAlias, isSystem).then(
|
||||||
function (widgetTypes) {
|
function (widgetTypes) {
|
||||||
|
|
||||||
widgetTypes = $filter('orderBy')(widgetTypes, ['-descriptor.type','name']);
|
widgetTypes = $filter('orderBy')(widgetTypes, ['-descriptor.type','-createdTime']);
|
||||||
|
|
||||||
var top = 0;
|
var top = 0;
|
||||||
var lastTop = [0, 0, 0];
|
var lastTop = [0, 0, 0];
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user