Commit 5f606912fc6cd8262f5d6b598772aac972c7d850
1 parent
b38a4d2f
UI: Improve data simulation performance. Improve processing of default zoom level by map widgets.
Showing
5 changed files
with
106 additions
and
62 deletions
... | ... | @@ -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 | } | ... | ... |