Commit 5f606912fc6cd8262f5d6b598772aac972c7d850

Authored by Igor Kulikov
1 parent b38a4d2f

UI: Improve data simulation performance. Improve processing of default zoom level by map widgets.

... ... @@ -19,6 +19,10 @@ export default class DataAggregator {
19 19 constructor(onDataCb, tsKeyNames, startTs, limit, aggregationType, timeWindow, interval, types, $timeout, $filter) {
20 20 this.onDataCb = onDataCb;
21 21 this.tsKeyNames = tsKeyNames;
  22 + this.dataBuffer = {};
  23 + for (var k in tsKeyNames) {
  24 + this.dataBuffer[tsKeyNames[k]] = [];
  25 + }
22 26 this.startTs = startTs;
23 27 this.aggregationType = aggregationType;
24 28 this.types = types;
... ... @@ -120,11 +124,11 @@ export default class DataAggregator {
120 124 if (delta || !this.data) {
121 125 this.startTs += delta * this.interval;
122 126 this.endTs += delta * this.interval;
123   - this.data = toData(this.tsKeyNames, this.aggregationMap, this.startTs, this.endTs, this.$filter, this.limit);
  127 + this.data = this.updateData();
124 128 this.elapsed = this.elapsed - delta * this.interval;
125 129 }
126 130 } else {
127   - this.data = toData(this.tsKeyNames, this.aggregationMap, this.startTs, this.endTs, this.$filter, this.limit);
  131 + this.data = this.updateData();
128 132 }
129 133 if (this.onDataCb) {
130 134 this.onDataCb(this.data, this.startTs, this.endTs, apply);
... ... @@ -138,6 +142,31 @@ export default class DataAggregator {
138 142 }
139 143 }
140 144
  145 + updateData() {
  146 + for (var k in this.tsKeyNames) {
  147 + this.dataBuffer[this.tsKeyNames[k]] = [];
  148 + }
  149 + for (var key in this.aggregationMap) {
  150 + var aggKeyData = this.aggregationMap[key];
  151 + var keyData = this.dataBuffer[key];
  152 + for (var aggTimestamp in aggKeyData) {
  153 + if (aggTimestamp <= this.startTs) {
  154 + delete aggKeyData[aggTimestamp];
  155 + } else if (aggTimestamp <= this.endTs) {
  156 + var aggData = aggKeyData[aggTimestamp];
  157 + var kvPair = [Number(aggTimestamp), aggData.aggValue];
  158 + keyData.push(kvPair);
  159 + }
  160 + }
  161 + keyData = this.$filter('orderBy')(keyData, '+this[0]');
  162 + if (keyData.length > this.limit) {
  163 + keyData = keyData.slice(keyData.length - this.limit);
  164 + }
  165 + this.dataBuffer[key] = keyData;
  166 + }
  167 + return this.dataBuffer;
  168 + }
  169 +
141 170 destroy() {
142 171 if (this.intervalTimeoutHandle) {
143 172 this.$timeout.cancel(this.intervalTimeoutHandle);
... ... @@ -208,32 +237,6 @@ function updateAggregatedData(aggregationMap, isCount, noAggregation, aggFunctio
208 237 }
209 238 }
210 239
211   -function toData(tsKeyNames, aggregationMap, startTs, endTs, $filter, limit) {
212   - var data = {};
213   - for (var k in tsKeyNames) {
214   - data[tsKeyNames[k]] = [];
215   - }
216   - for (var key in aggregationMap) {
217   - var aggKeyData = aggregationMap[key];
218   - var keyData = data[key];
219   - for (var aggTimestamp in aggKeyData) {
220   - if (aggTimestamp <= startTs) {
221   - delete aggKeyData[aggTimestamp];
222   - } else if (aggTimestamp <= endTs) {
223   - var aggData = aggKeyData[aggTimestamp];
224   - var kvPair = [Number(aggTimestamp), aggData.aggValue];
225   - keyData.push(kvPair);
226   - }
227   - }
228   - keyData = $filter('orderBy')(keyData, '+this[0]');
229   - if (keyData.length > limit) {
230   - keyData = keyData.slice(keyData.length - limit);
231   - }
232   - data[key] = keyData;
233   - }
234   - return data;
235   -}
236   -
237 240 function convertValue(value, noAggregation) {
238 241 if (!noAggregation || value && isNumeric(value)) {
239 242 return Number(value);
... ...
... ... @@ -110,6 +110,8 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
110 110 datasourceSubscription.subscriptionTimewindow.realtimeWindowMs;
111 111 var timer;
112 112 var frequency;
  113 + var tickElapsed = 0;
  114 + var tickScheduledTime = 0;
113 115 var dataAggregator;
114 116
115 117 var subscription = {
... ... @@ -353,11 +355,14 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
353 355 }
354 356 dataAggregator = createRealtimeDataAggregator(subsTw, tsKeyNames, types.dataKeyType.function);
355 357 }
  358 + tickScheduledTime = currentTime();
356 359 if (history) {
357 360 onTick(false);
358 361 } else {
359 362 timer = $timeout(
360   - function() {onTick(true)},
  363 + function() {
  364 + onTick(true)
  365 + },
361 366 0,
362 367 false
363 368 );
... ... @@ -393,6 +398,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
393 398 function unsubscribe() {
394 399 if (timer) {
395 400 $timeout.cancel(timer);
  401 + timer = null;
396 402 }
397 403 if (datasourceType === types.datasourceType.device) {
398 404 for (var cmdId in subscribers) {
... ... @@ -456,15 +462,39 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
456 462 }
457 463 }
458 464
  465 + /* eslint-disable */
  466 + function currentTime() {
  467 + return window.performance && window.performance.now ?
  468 + window.performance.now() : Date.now();
  469 + }
  470 + /* eslint-enable */
  471 +
  472 +
459 473 function onTick(apply) {
  474 +
  475 + var now = currentTime();
  476 + tickElapsed += now - tickScheduledTime;
  477 + tickScheduledTime = now;
  478 +
  479 + if (timer) {
  480 + $timeout.cancel(timer);
  481 + timer = null;
  482 + }
  483 +
460 484 var key;
461 485 if (datasourceSubscription.type === types.widgetType.timeseries.value) {
462 486 var startTime;
463 487 var endTime;
  488 + var delta;
464 489 var generatedData = {
465 490 data: {
466 491 }
467 492 };
  493 + if (!history) {
  494 + delta = Math.floor(tickElapsed / frequency);
  495 + }
  496 + var deltaElapsed = history ? frequency : delta * frequency;
  497 + tickElapsed = tickElapsed - deltaElapsed;
468 498 for (key in dataKeys) {
469 499 var dataKeyList = dataKeys[key];
470 500 for (var index = 0; index < dataKeyList.length; index ++) {
... ... @@ -472,11 +502,12 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
472 502 if (!startTime) {
473 503 if (realtime) {
474 504 if (dataKey.lastUpdateTime) {
475   - startTime = dataKey.lastUpdateTime + frequency
  505 + startTime = dataKey.lastUpdateTime + frequency;
  506 + endTime = dataKey.lastUpdateTime + deltaElapsed;
476 507 } else {
477 508 startTime = datasourceSubscription.subscriptionTimewindow.startTs;
  509 + endTime = startTime + datasourceSubscription.subscriptionTimewindow.realtimeWindowMs + frequency;
478 510 }
479   - endTime = startTime + datasourceSubscription.subscriptionTimewindow.realtimeWindowMs;
480 511 } else {
481 512 startTime = datasourceSubscription.subscriptionTimewindow.fixedWindow.startTimeMs;
482 513 endTime = datasourceSubscription.subscriptionTimewindow.fixedWindow.endTimeMs;
... ... @@ -494,7 +525,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
494 525 }
495 526
496 527 if (!history) {
497   - timer = $timeout(function() {onTick(true)}, frequency / 2, false);
  528 + timer = $timeout(function() {onTick(true)}, frequency, false);
498 529 }
499 530 }
500 531
... ...
... ... @@ -246,26 +246,31 @@ export default class TbGoogleMap {
246 246 }
247 247 /* eslint-enable no-undef */
248 248
  249 + /* eslint-disable no-undef */
249 250 fitBounds(bounds) {
250   - var tbMap = this;
251   - google.maps.event.addListenerOnce(this.map, 'bounds_changed', function() { // eslint-disable-line no-undef
252   - var newZoomLevel = tbMap.map.getZoom();
253   - if (tbMap.dontFitMapBounds && tbMap.defaultZoomLevel) {
254   - newZoomLevel = tbMap.defaultZoomLevel;
255   - }
256   - tbMap.map.setZoom(newZoomLevel);
257   -
258   - if (!tbMap.defaultZoomLevel && tbMap.map.getZoom() > tbMap.minZoomLevel) {
259   - tbMap.map.setZoom(tbMap.minZoomLevel);
260   - }
261   - });
262   - this.map.fitBounds(bounds);
  251 + if (this.dontFitMapBounds && this.defaultZoomLevel) {
  252 + this.map.setZoom(this.defaultZoomLevel);
  253 + this.map.setCenter(bounds.getCenter());
  254 + } else {
  255 + var tbMap = this;
  256 + google.maps.event.addListenerOnce(this.map, 'bounds_changed', function() { // eslint-disable-line no-undef
  257 + if (!tbMap.defaultZoomLevel && tbMap.map.getZoom() > tbMap.minZoomLevel) {
  258 + tbMap.map.setZoom(tbMap.minZoomLevel);
  259 + }
  260 + });
  261 + this.map.fitBounds(bounds);
  262 + }
263 263 }
  264 + /* eslint-enable no-undef */
264 265
265 266 createLatLng(lat, lng) {
266 267 return new google.maps.LatLng(lat, lng); // eslint-disable-line no-undef
267 268 }
268 269
  270 + extendBoundsWithMarker(bounds, marker) {
  271 + bounds.extend(marker.getPosition());
  272 + }
  273 +
269 274 getMarkerPosition(marker) {
270 275 return marker.getPosition();
271 276 }
... ...
... ... @@ -386,7 +386,7 @@ export default class TbMapWidget {
386 386 if (location.polyline) {
387 387 tbMap.map.extendBounds(bounds, location.polyline);
388 388 } else if (location.marker) {
389   - bounds.extend(tbMap.map.getMarkerPosition(location.marker));
  389 + tbMap.map.extendBoundsWithMarker(bounds, location.marker);
390 390 }
391 391 }
392 392 }
... ... @@ -403,10 +403,10 @@ export default class TbMapWidget {
403 403 if (location.polyline) {
404 404 tbMap.map.extendBounds(bounds, location.polyline);
405 405 } else if (location.marker) {
406   - bounds.extend(tbMap.map.getMarkerPosition(location.marker));
  406 + tbMap.map.extendBoundsWithMarker(bounds, location.marker);
407 407 }
408 408 }
409   - if (!tbMap.dontFitMapBounds && locationsChanged) {
  409 + if (locationsChanged) {
410 410 tbMap.map.fitBounds(bounds);
411 411 }
412 412 }
... ... @@ -448,10 +448,10 @@ export default class TbMapWidget {
448 448 resize() {
449 449 if (this.map && this.map.inited()) {
450 450 this.map.invalidateSize();
451   - if (!this.dontFitMapBounds && this.locations && this.locations.size > 0) {
  451 + if (this.locations && this.locations.size > 0) {
452 452 var bounds = this.map.createBounds();
453 453 for (var m in this.markers) {
454   - bounds.extend(this.map.getMarkerPosition(this.markers[m]));
  454 + this.map.extendBoundsWithMarker(bounds, this.markers[m]);
455 455 }
456 456 if (this.polylines) {
457 457 for (var p in this.polylines) {
... ...
... ... @@ -146,25 +146,30 @@ export default class TbOpenStreetMap {
146 146 }
147 147
148 148 fitBounds(bounds) {
149   - var tbMap = this;
150   - this.map.once('zoomend', function() {
151   - var newZoomLevel = tbMap.map.getZoom();
152   - if (tbMap.dontFitMapBounds && tbMap.defaultZoomLevel) {
153   - newZoomLevel = tbMap.defaultZoomLevel;
154   - }
155   - tbMap.map.setZoom(newZoomLevel, {animate: false});
156   -
157   - if (!tbMap.defaultZoomLevel && tbMap.map.getZoom() > tbMap.minZoomLevel) {
158   - tbMap.map.setZoom(tbMap.minZoomLevel, {animate: false});
  149 + if (bounds.isValid()) {
  150 + if (this.dontFitMapBounds && this.defaultZoomLevel) {
  151 + this.map.setZoom(this.defaultZoomLevel, {animate: false});
  152 + this.map.panTo(bounds.getCenter(), {animate: false});
  153 + } else {
  154 + var tbMap = this;
  155 + this.map.once('zoomend', function() {
  156 + if (!tbMap.defaultZoomLevel && tbMap.map.getZoom() > tbMap.minZoomLevel) {
  157 + tbMap.map.setZoom(tbMap.minZoomLevel, {animate: false});
  158 + }
  159 + });
  160 + this.map.fitBounds(bounds, {padding: [50, 50], animate: false});
159 161 }
160   - });
161   - this.map.fitBounds(bounds, {padding: [50, 50], animate: false});
  162 + }
162 163 }
163 164
164 165 createLatLng(lat, lng) {
165 166 return L.latLng(lat, lng);
166 167 }
167 168
  169 + extendBoundsWithMarker(bounds, marker) {
  170 + bounds.extend(marker.getLatLng());
  171 + }
  172 +
168 173 getMarkerPosition(marker) {
169 174 return marker.getLatLng();
170 175 }
... ...