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,6 +19,10 @@ export default class DataAggregator {
19 constructor(onDataCb, tsKeyNames, startTs, limit, aggregationType, timeWindow, interval, types, $timeout, $filter) { 19 constructor(onDataCb, tsKeyNames, startTs, limit, aggregationType, timeWindow, interval, types, $timeout, $filter) {
20 this.onDataCb = onDataCb; 20 this.onDataCb = onDataCb;
21 this.tsKeyNames = tsKeyNames; 21 this.tsKeyNames = tsKeyNames;
  22 + this.dataBuffer = {};
  23 + for (var k in tsKeyNames) {
  24 + this.dataBuffer[tsKeyNames[k]] = [];
  25 + }
22 this.startTs = startTs; 26 this.startTs = startTs;
23 this.aggregationType = aggregationType; 27 this.aggregationType = aggregationType;
24 this.types = types; 28 this.types = types;
@@ -120,11 +124,11 @@ export default class DataAggregator { @@ -120,11 +124,11 @@ export default class DataAggregator {
120 if (delta || !this.data) { 124 if (delta || !this.data) {
121 this.startTs += delta * this.interval; 125 this.startTs += delta * this.interval;
122 this.endTs += delta * this.interval; 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 this.elapsed = this.elapsed - delta * this.interval; 128 this.elapsed = this.elapsed - delta * this.interval;
125 } 129 }
126 } else { 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 if (this.onDataCb) { 133 if (this.onDataCb) {
130 this.onDataCb(this.data, this.startTs, this.endTs, apply); 134 this.onDataCb(this.data, this.startTs, this.endTs, apply);
@@ -138,6 +142,31 @@ export default class DataAggregator { @@ -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 destroy() { 170 destroy() {
142 if (this.intervalTimeoutHandle) { 171 if (this.intervalTimeoutHandle) {
143 this.$timeout.cancel(this.intervalTimeoutHandle); 172 this.$timeout.cancel(this.intervalTimeoutHandle);
@@ -208,32 +237,6 @@ function updateAggregatedData(aggregationMap, isCount, noAggregation, aggFunctio @@ -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 function convertValue(value, noAggregation) { 240 function convertValue(value, noAggregation) {
238 if (!noAggregation || value && isNumeric(value)) { 241 if (!noAggregation || value && isNumeric(value)) {
239 return Number(value); 242 return Number(value);
@@ -110,6 +110,8 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic @@ -110,6 +110,8 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
110 datasourceSubscription.subscriptionTimewindow.realtimeWindowMs; 110 datasourceSubscription.subscriptionTimewindow.realtimeWindowMs;
111 var timer; 111 var timer;
112 var frequency; 112 var frequency;
  113 + var tickElapsed = 0;
  114 + var tickScheduledTime = 0;
113 var dataAggregator; 115 var dataAggregator;
114 116
115 var subscription = { 117 var subscription = {
@@ -353,11 +355,14 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic @@ -353,11 +355,14 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
353 } 355 }
354 dataAggregator = createRealtimeDataAggregator(subsTw, tsKeyNames, types.dataKeyType.function); 356 dataAggregator = createRealtimeDataAggregator(subsTw, tsKeyNames, types.dataKeyType.function);
355 } 357 }
  358 + tickScheduledTime = currentTime();
356 if (history) { 359 if (history) {
357 onTick(false); 360 onTick(false);
358 } else { 361 } else {
359 timer = $timeout( 362 timer = $timeout(
360 - function() {onTick(true)}, 363 + function() {
  364 + onTick(true)
  365 + },
361 0, 366 0,
362 false 367 false
363 ); 368 );
@@ -393,6 +398,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic @@ -393,6 +398,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
393 function unsubscribe() { 398 function unsubscribe() {
394 if (timer) { 399 if (timer) {
395 $timeout.cancel(timer); 400 $timeout.cancel(timer);
  401 + timer = null;
396 } 402 }
397 if (datasourceType === types.datasourceType.device) { 403 if (datasourceType === types.datasourceType.device) {
398 for (var cmdId in subscribers) { 404 for (var cmdId in subscribers) {
@@ -456,15 +462,39 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic @@ -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 function onTick(apply) { 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 var key; 484 var key;
461 if (datasourceSubscription.type === types.widgetType.timeseries.value) { 485 if (datasourceSubscription.type === types.widgetType.timeseries.value) {
462 var startTime; 486 var startTime;
463 var endTime; 487 var endTime;
  488 + var delta;
464 var generatedData = { 489 var generatedData = {
465 data: { 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 for (key in dataKeys) { 498 for (key in dataKeys) {
469 var dataKeyList = dataKeys[key]; 499 var dataKeyList = dataKeys[key];
470 for (var index = 0; index < dataKeyList.length; index ++) { 500 for (var index = 0; index < dataKeyList.length; index ++) {
@@ -472,11 +502,12 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic @@ -472,11 +502,12 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
472 if (!startTime) { 502 if (!startTime) {
473 if (realtime) { 503 if (realtime) {
474 if (dataKey.lastUpdateTime) { 504 if (dataKey.lastUpdateTime) {
475 - startTime = dataKey.lastUpdateTime + frequency 505 + startTime = dataKey.lastUpdateTime + frequency;
  506 + endTime = dataKey.lastUpdateTime + deltaElapsed;
476 } else { 507 } else {
477 startTime = datasourceSubscription.subscriptionTimewindow.startTs; 508 startTime = datasourceSubscription.subscriptionTimewindow.startTs;
  509 + endTime = startTime + datasourceSubscription.subscriptionTimewindow.realtimeWindowMs + frequency;
478 } 510 }
479 - endTime = startTime + datasourceSubscription.subscriptionTimewindow.realtimeWindowMs;  
480 } else { 511 } else {
481 startTime = datasourceSubscription.subscriptionTimewindow.fixedWindow.startTimeMs; 512 startTime = datasourceSubscription.subscriptionTimewindow.fixedWindow.startTimeMs;
482 endTime = datasourceSubscription.subscriptionTimewindow.fixedWindow.endTimeMs; 513 endTime = datasourceSubscription.subscriptionTimewindow.fixedWindow.endTimeMs;
@@ -494,7 +525,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic @@ -494,7 +525,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
494 } 525 }
495 526
496 if (!history) { 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,26 +246,31 @@ export default class TbGoogleMap {
246 } 246 }
247 /* eslint-enable no-undef */ 247 /* eslint-enable no-undef */
248 248
  249 + /* eslint-disable no-undef */
249 fitBounds(bounds) { 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 createLatLng(lat, lng) { 266 createLatLng(lat, lng) {
266 return new google.maps.LatLng(lat, lng); // eslint-disable-line no-undef 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 getMarkerPosition(marker) { 274 getMarkerPosition(marker) {
270 return marker.getPosition(); 275 return marker.getPosition();
271 } 276 }
@@ -386,7 +386,7 @@ export default class TbMapWidget { @@ -386,7 +386,7 @@ export default class TbMapWidget {
386 if (location.polyline) { 386 if (location.polyline) {
387 tbMap.map.extendBounds(bounds, location.polyline); 387 tbMap.map.extendBounds(bounds, location.polyline);
388 } else if (location.marker) { 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,10 +403,10 @@ export default class TbMapWidget {
403 if (location.polyline) { 403 if (location.polyline) {
404 tbMap.map.extendBounds(bounds, location.polyline); 404 tbMap.map.extendBounds(bounds, location.polyline);
405 } else if (location.marker) { 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 tbMap.map.fitBounds(bounds); 410 tbMap.map.fitBounds(bounds);
411 } 411 }
412 } 412 }
@@ -448,10 +448,10 @@ export default class TbMapWidget { @@ -448,10 +448,10 @@ export default class TbMapWidget {
448 resize() { 448 resize() {
449 if (this.map && this.map.inited()) { 449 if (this.map && this.map.inited()) {
450 this.map.invalidateSize(); 450 this.map.invalidateSize();
451 - if (!this.dontFitMapBounds && this.locations && this.locations.size > 0) { 451 + if (this.locations && this.locations.size > 0) {
452 var bounds = this.map.createBounds(); 452 var bounds = this.map.createBounds();
453 for (var m in this.markers) { 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 if (this.polylines) { 456 if (this.polylines) {
457 for (var p in this.polylines) { 457 for (var p in this.polylines) {
@@ -146,25 +146,30 @@ export default class TbOpenStreetMap { @@ -146,25 +146,30 @@ export default class TbOpenStreetMap {
146 } 146 }
147 147
148 fitBounds(bounds) { 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 createLatLng(lat, lng) { 165 createLatLng(lat, lng) {
165 return L.latLng(lat, lng); 166 return L.latLng(lat, lng);
166 } 167 }
167 168
  169 + extendBoundsWithMarker(bounds, marker) {
  170 + bounds.extend(marker.getLatLng());
  171 + }
  172 +
168 getMarkerPosition(marker) { 173 getMarkerPosition(marker) {
169 return marker.getLatLng(); 174 return marker.getLatLng();
170 } 175 }