thingsboard-aplcache

UI: Improve data simulation performance. Improve processing

3/14/2017 10:23:08 AM

Details

diff --git a/ui/src/app/api/data-aggregator.js b/ui/src/app/api/data-aggregator.js
index 76d3b1c..68b0d91 100644
--- a/ui/src/app/api/data-aggregator.js
+++ b/ui/src/app/api/data-aggregator.js
@@ -19,6 +19,10 @@ export default class DataAggregator {
     constructor(onDataCb, tsKeyNames, startTs, limit, aggregationType, timeWindow, interval, types, $timeout, $filter) {
         this.onDataCb = onDataCb;
         this.tsKeyNames = tsKeyNames;
+        this.dataBuffer = {};
+        for (var k in tsKeyNames) {
+            this.dataBuffer[tsKeyNames[k]] = [];
+        }
         this.startTs = startTs;
         this.aggregationType = aggregationType;
         this.types = types;
@@ -120,11 +124,11 @@ export default class DataAggregator {
             if (delta || !this.data) {
                 this.startTs += delta * this.interval;
                 this.endTs += delta * this.interval;
-                this.data = toData(this.tsKeyNames, this.aggregationMap, this.startTs, this.endTs, this.$filter, this.limit);
+                this.data = this.updateData();
                 this.elapsed = this.elapsed - delta * this.interval;
             }
         } else {
-            this.data = toData(this.tsKeyNames, this.aggregationMap, this.startTs, this.endTs, this.$filter, this.limit);
+            this.data = this.updateData();
         }
         if (this.onDataCb) {
             this.onDataCb(this.data, this.startTs, this.endTs, apply);
@@ -138,6 +142,31 @@ export default class DataAggregator {
         }
     }
 
+    updateData() {
+        for (var k in this.tsKeyNames) {
+            this.dataBuffer[this.tsKeyNames[k]] = [];
+        }
+        for (var key in this.aggregationMap) {
+            var aggKeyData = this.aggregationMap[key];
+            var keyData = this.dataBuffer[key];
+            for (var aggTimestamp in aggKeyData) {
+                if (aggTimestamp <= this.startTs) {
+                    delete aggKeyData[aggTimestamp];
+                } else if (aggTimestamp <= this.endTs) {
+                    var aggData = aggKeyData[aggTimestamp];
+                    var kvPair = [Number(aggTimestamp), aggData.aggValue];
+                    keyData.push(kvPair);
+                }
+            }
+            keyData = this.$filter('orderBy')(keyData, '+this[0]');
+            if (keyData.length > this.limit) {
+                keyData = keyData.slice(keyData.length - this.limit);
+            }
+            this.dataBuffer[key] = keyData;
+        }
+        return this.dataBuffer;
+    }
+
     destroy() {
         if (this.intervalTimeoutHandle) {
             this.$timeout.cancel(this.intervalTimeoutHandle);
@@ -208,32 +237,6 @@ function updateAggregatedData(aggregationMap, isCount, noAggregation, aggFunctio
     }
 }
 
-function toData(tsKeyNames, aggregationMap, startTs, endTs, $filter, limit) {
-    var data = {};
-    for (var k in tsKeyNames) {
-        data[tsKeyNames[k]] = [];
-    }
-    for (var key in aggregationMap) {
-        var aggKeyData = aggregationMap[key];
-        var keyData = data[key];
-        for (var aggTimestamp in aggKeyData) {
-            if (aggTimestamp <= startTs) {
-                delete aggKeyData[aggTimestamp];
-            } else if (aggTimestamp <= endTs) {
-                var aggData = aggKeyData[aggTimestamp];
-                var kvPair = [Number(aggTimestamp), aggData.aggValue];
-                keyData.push(kvPair);
-            }
-        }
-        keyData = $filter('orderBy')(keyData, '+this[0]');
-        if (keyData.length > limit) {
-            keyData = keyData.slice(keyData.length - limit);
-        }
-        data[key] = keyData;
-    }
-    return data;
-}
-
 function convertValue(value, noAggregation) {
     if (!noAggregation || value && isNumeric(value)) {
         return Number(value);
diff --git a/ui/src/app/api/datasource.service.js b/ui/src/app/api/datasource.service.js
index 8b49cf4..7a2486d 100644
--- a/ui/src/app/api/datasource.service.js
+++ b/ui/src/app/api/datasource.service.js
@@ -110,6 +110,8 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
         datasourceSubscription.subscriptionTimewindow.realtimeWindowMs;
     var timer;
     var frequency;
+    var tickElapsed = 0;
+    var tickScheduledTime = 0;
     var dataAggregator;
 
     var subscription = {
@@ -353,11 +355,14 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
                 }
                 dataAggregator = createRealtimeDataAggregator(subsTw, tsKeyNames, types.dataKeyType.function);
             }
+            tickScheduledTime = currentTime();
             if (history) {
                 onTick(false);
             } else {
                 timer = $timeout(
-                    function() {onTick(true)},
+                    function() {
+                        onTick(true)
+                    },
                     0,
                     false
                 );
@@ -393,6 +398,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
     function unsubscribe() {
         if (timer) {
             $timeout.cancel(timer);
+            timer = null;
         }
         if (datasourceType === types.datasourceType.device) {
             for (var cmdId in subscribers) {
@@ -456,15 +462,39 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
         }
     }
 
+    /* eslint-disable */
+    function currentTime() {
+        return window.performance && window.performance.now ?
+            window.performance.now() : Date.now();
+    }
+    /* eslint-enable */
+
+
     function onTick(apply) {
+
+        var now = currentTime();
+        tickElapsed += now - tickScheduledTime;
+        tickScheduledTime = now;
+
+        if (timer) {
+            $timeout.cancel(timer);
+            timer = null;
+        }
+
         var key;
         if (datasourceSubscription.type === types.widgetType.timeseries.value) {
             var startTime;
             var endTime;
+            var delta;
             var generatedData = {
                 data: {
                 }
             };
+            if (!history) {
+                delta = Math.floor(tickElapsed / frequency);
+            }
+            var deltaElapsed = history ? frequency : delta * frequency;
+            tickElapsed = tickElapsed - deltaElapsed;
             for (key in dataKeys) {
                 var dataKeyList = dataKeys[key];
                 for (var index = 0; index < dataKeyList.length; index ++) {
@@ -472,11 +502,12 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
                     if (!startTime) {
                         if (realtime) {
                             if (dataKey.lastUpdateTime) {
-                                startTime = dataKey.lastUpdateTime + frequency
+                                startTime = dataKey.lastUpdateTime + frequency;
+                                endTime = dataKey.lastUpdateTime + deltaElapsed;
                             } else {
                                 startTime = datasourceSubscription.subscriptionTimewindow.startTs;
+                                endTime = startTime + datasourceSubscription.subscriptionTimewindow.realtimeWindowMs + frequency;
                             }
-                            endTime = startTime + datasourceSubscription.subscriptionTimewindow.realtimeWindowMs;
                         } else {
                             startTime = datasourceSubscription.subscriptionTimewindow.fixedWindow.startTimeMs;
                             endTime = datasourceSubscription.subscriptionTimewindow.fixedWindow.endTimeMs;
@@ -494,7 +525,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
         }
 
         if (!history) {
-            timer = $timeout(function() {onTick(true)}, frequency / 2, false);
+            timer = $timeout(function() {onTick(true)}, frequency, false);
         }
     }
 
diff --git a/ui/src/app/widget/lib/google-map.js b/ui/src/app/widget/lib/google-map.js
index 027b145..100f1b3 100644
--- a/ui/src/app/widget/lib/google-map.js
+++ b/ui/src/app/widget/lib/google-map.js
@@ -246,26 +246,31 @@ export default class TbGoogleMap {
     }
     /* eslint-enable no-undef */
 
+    /* eslint-disable no-undef */
     fitBounds(bounds) {
-        var tbMap = this;
-        google.maps.event.addListenerOnce(this.map, 'bounds_changed', function() { // eslint-disable-line no-undef
-            var newZoomLevel = tbMap.map.getZoom();
-            if (tbMap.dontFitMapBounds && tbMap.defaultZoomLevel) {
-                newZoomLevel = tbMap.defaultZoomLevel;
-            }
-            tbMap.map.setZoom(newZoomLevel);
-
-            if (!tbMap.defaultZoomLevel && tbMap.map.getZoom() > tbMap.minZoomLevel) {
-                tbMap.map.setZoom(tbMap.minZoomLevel);
-            }
-        });
-        this.map.fitBounds(bounds);
+        if (this.dontFitMapBounds && this.defaultZoomLevel) {
+            this.map.setZoom(this.defaultZoomLevel);
+            this.map.setCenter(bounds.getCenter());
+        } else {
+            var tbMap = this;
+            google.maps.event.addListenerOnce(this.map, 'bounds_changed', function() { // eslint-disable-line no-undef
+                if (!tbMap.defaultZoomLevel && tbMap.map.getZoom() > tbMap.minZoomLevel) {
+                    tbMap.map.setZoom(tbMap.minZoomLevel);
+                }
+            });
+            this.map.fitBounds(bounds);
+        }
     }
+    /* eslint-enable no-undef */
 
     createLatLng(lat, lng) {
         return new google.maps.LatLng(lat, lng); // eslint-disable-line no-undef
     }
 
+    extendBoundsWithMarker(bounds, marker) {
+        bounds.extend(marker.getPosition());
+    }
+
     getMarkerPosition(marker) {
         return marker.getPosition();
     }
diff --git a/ui/src/app/widget/lib/map-widget.js b/ui/src/app/widget/lib/map-widget.js
index 52079f3..7402ee6 100644
--- a/ui/src/app/widget/lib/map-widget.js
+++ b/ui/src/app/widget/lib/map-widget.js
@@ -386,7 +386,7 @@ export default class TbMapWidget {
                     if (location.polyline) {
                         tbMap.map.extendBounds(bounds, location.polyline);
                     } else if (location.marker) {
-                        bounds.extend(tbMap.map.getMarkerPosition(location.marker));
+                        tbMap.map.extendBoundsWithMarker(bounds, location.marker);
                     }
                 }
             }
@@ -403,10 +403,10 @@ export default class TbMapWidget {
                 if (location.polyline) {
                     tbMap.map.extendBounds(bounds, location.polyline);
                 } else if (location.marker) {
-                    bounds.extend(tbMap.map.getMarkerPosition(location.marker));
+                    tbMap.map.extendBoundsWithMarker(bounds, location.marker);
                 }
             }
-            if (!tbMap.dontFitMapBounds && locationsChanged) {
+            if (locationsChanged) {
                 tbMap.map.fitBounds(bounds);
             }
         }
@@ -448,10 +448,10 @@ export default class TbMapWidget {
     resize() {
         if (this.map && this.map.inited()) {
             this.map.invalidateSize();
-            if (!this.dontFitMapBounds && this.locations && this.locations.size > 0) {
+            if (this.locations && this.locations.size > 0) {
                 var bounds = this.map.createBounds();
                 for (var m in this.markers) {
-                    bounds.extend(this.map.getMarkerPosition(this.markers[m]));
+                    this.map.extendBoundsWithMarker(bounds, this.markers[m]);
                 }
                 if (this.polylines) {
                     for (var p in this.polylines) {
diff --git a/ui/src/app/widget/lib/openstreet-map.js b/ui/src/app/widget/lib/openstreet-map.js
index 4ebcf94..74438a4 100644
--- a/ui/src/app/widget/lib/openstreet-map.js
+++ b/ui/src/app/widget/lib/openstreet-map.js
@@ -146,25 +146,30 @@ export default class TbOpenStreetMap {
     }
 
     fitBounds(bounds) {
-        var tbMap = this;
-        this.map.once('zoomend', function() {
-            var newZoomLevel = tbMap.map.getZoom();
-            if (tbMap.dontFitMapBounds && tbMap.defaultZoomLevel) {
-                newZoomLevel = tbMap.defaultZoomLevel;
-            }
-            tbMap.map.setZoom(newZoomLevel, {animate: false});
-
-            if (!tbMap.defaultZoomLevel && tbMap.map.getZoom() > tbMap.minZoomLevel) {
-                tbMap.map.setZoom(tbMap.minZoomLevel, {animate: false});
+        if (bounds.isValid()) {
+            if (this.dontFitMapBounds && this.defaultZoomLevel) {
+                this.map.setZoom(this.defaultZoomLevel, {animate: false});
+                this.map.panTo(bounds.getCenter(), {animate: false});
+            } else {
+                var tbMap = this;
+                this.map.once('zoomend', function() {
+                    if (!tbMap.defaultZoomLevel && tbMap.map.getZoom() > tbMap.minZoomLevel) {
+                        tbMap.map.setZoom(tbMap.minZoomLevel, {animate: false});
+                    }
+                });
+                this.map.fitBounds(bounds, {padding: [50, 50], animate: false});
             }
-        });
-        this.map.fitBounds(bounds, {padding: [50, 50], animate: false});
+        }
     }
 
     createLatLng(lat, lng) {
         return L.latLng(lat, lng);
     }
 
+    extendBoundsWithMarker(bounds, marker) {
+        bounds.extend(marker.getLatLng());
+    }
+
     getMarkerPosition(marker) {
         return marker.getLatLng();
     }