From 34641d5395055b001b90e6cb6da0efab5016deda Mon Sep 17 00:00:00 2001 From: oleg Date: Wed, 27 Dec 2017 16:26:39 +0200 Subject: [PATCH 1/8] 'Timeseries table' widget improvements --- .../main/data/json/system/widget_bundles/cards.json | 4 ++-- ui/src/app/locale/locale.constant.js | 1 + ui/src/app/widget/lib/timeseries-table-widget.js | 6 +++++- .../app/widget/lib/timeseries-table-widget.tpl.html | 12 ++++++++---- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json index 0fc0085f12..ddb90dbaae 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -112,9 +112,9 @@ "templateHtml": "\n", "templateCss": "", "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n var id = self.ctx.$scope.$injector.get('utils').guid();\n scope.tableId = \"table-\"+id;\n scope.ctx = self.ctx;\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.$broadcast('timeseries-table-data-updated', self.ctx.$scope.tableId);\n}\n\nself.onDestroy = function() {\n}", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"TimeseriesTableSettings\",\n \"properties\": {\n \"showTimestamp\": {\n \"title\": \"Display timestamp column\",\n \"type\": \"boolean\",\n \"default\": true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"showTimestamp\"\n ]\n}", + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"TimeseriesTableSettings\",\n \"properties\": {\n \"showTimestamp\": {\n \"title\": \"Display timestamp column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n }, \n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n }\n },\n \"required\": []\n },\n \"form\": [\n \"showTimestamp\",\n \"displayPagination\",\n \"defaultPageSize\"\n ]\n}", "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, rowData, filter)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', amount = percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\"},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":false,\"showLegend\":false}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', amount = percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\"},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true,\"displayPagination\":true,\"defaultPageSize\":10},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{}}" } } ] diff --git a/ui/src/app/locale/locale.constant.js b/ui/src/app/locale/locale.constant.js index ab672de30d..7769b3dbda 100644 --- a/ui/src/app/locale/locale.constant.js +++ b/ui/src/app/locale/locale.constant.js @@ -1213,6 +1213,7 @@ export default angular.module('thingsboard.locale', []) "remove-widget-title": "Are you sure you want to remove the widget '{{widgetTitle}}'?", "remove-widget-text": "After the confirmation the widget and all related data will become unrecoverable.", "timeseries": "Time series", + "search-data": "Search data", "latest-values": "Latest values", "rpc": "Control widget", "alarm": "Alarm widget", diff --git a/ui/src/app/widget/lib/timeseries-table-widget.js b/ui/src/app/widget/lib/timeseries-table-widget.js index 0c23e027fe..58a626cb9b 100644 --- a/ui/src/app/widget/lib/timeseries-table-widget.js +++ b/ui/src/app/widget/lib/timeseries-table-widget.js @@ -50,6 +50,8 @@ function TimeseriesTableWidgetController($element, $scope, $filter) { vm.sources = []; vm.sourceIndex = 0; + vm.defaultPageSize = 10; + vm.defaultSortOrder = '-0'; $scope.$watch('vm.ctx', function() { if (vm.ctx) { @@ -108,6 +110,8 @@ function TimeseriesTableWidgetController($element, $scope, $filter) { cssParser.createStyleElement(namespace, cssString); $element.addClass(namespace); + vm.displayPagination = angular.isDefined(vm.settings.displayPagination) ? vm.settings.displayPagination : true; + function hashCode(str) { var hash = 0; var i, char; @@ -211,7 +215,7 @@ function TimeseriesTableWidgetController($element, $scope, $filter) { source.data = []; source.rawData = []; source.query = { - limit: 5, + limit: vm.settings.defaultPageSize || 10, page: 1, order: '-0' } diff --git a/ui/src/app/widget/lib/timeseries-table-widget.tpl.html b/ui/src/app/widget/lib/timeseries-table-widget.tpl.html index 2b6d72c10a..32fb8e438c 100644 --- a/ui/src/app/widget/lib/timeseries-table-widget.tpl.html +++ b/ui/src/app/widget/lib/timeseries-table-widget.tpl.html @@ -28,16 +28,20 @@ - + - + \ No newline at end of file From 2dba7f52f5d74dd5e19dac94c13a07f47c874c77 Mon Sep 17 00:00:00 2001 From: oleg Date: Fri, 29 Dec 2017 15:24:31 +0200 Subject: [PATCH 2/8] "Timeseries - Flot" widget improvements (search) --- .../app/widget/lib/timeseries-table-widget.js | 52 +++++++++- .../widget/lib/timeseries-table-widget.scss | 4 + .../lib/timeseries-table-widget.tpl.html | 96 +++++++++++++------ 3 files changed, 122 insertions(+), 30 deletions(-) diff --git a/ui/src/app/widget/lib/timeseries-table-widget.js b/ui/src/app/widget/lib/timeseries-table-widget.js index 58a626cb9b..28ac811f1b 100644 --- a/ui/src/app/widget/lib/timeseries-table-widget.js +++ b/ui/src/app/widget/lib/timeseries-table-widget.js @@ -47,11 +47,37 @@ function TimeseriesTableWidget() { /*@ngInject*/ function TimeseriesTableWidgetController($element, $scope, $filter) { var vm = this; + let dateFormatFilter = 'yyyy-MM-dd HH:mm:ss'; vm.sources = []; vm.sourceIndex = 0; vm.defaultPageSize = 10; vm.defaultSortOrder = '-0'; + vm.query = { + "search": null + }; + + vm.enterFilterMode = enterFilterMode; + vm.exitFilterMode = exitFilterMode; + + function enterFilterMode () { + vm.query.search = ''; + vm.ctx.hideTitlePanel = true; + } + + function exitFilterMode () { + vm.query.search = null; + vm.ctx.hideTitlePanel = false; + } + + vm.searchAction = { + name: 'action.search', + show: true, + onAction: function() { + vm.enterFilterMode(); + }, + icon: 'search' + }; $scope.$watch('vm.ctx', function() { if (vm.ctx) { @@ -64,6 +90,7 @@ function TimeseriesTableWidgetController($element, $scope, $filter) { }); function initialize() { + vm.ctx.widgetActions = [ vm.searchAction ]; vm.showTimestamp = vm.settings.showTimestamp !== false; var origColor = vm.widgetConfig.color || 'rgba(0, 0, 0, 0.87)'; var defaultColor = tinycolor(origColor); @@ -167,7 +194,7 @@ function TimeseriesTableWidgetController($element, $scope, $filter) { vm.cellContent = function(source, index, row, value) { if (index === 0) { - return $filter('date')(value, 'yyyy-MM-dd HH:mm:ss'); + return $filter('date')(value, dateFormatFilter); } else { var strContent = ''; if (angular.isDefined(value)) { @@ -291,7 +318,30 @@ function TimeseriesTableWidgetController($element, $scope, $filter) { } function reorder(source) { + let searchRegExp = new RegExp(vm.query.search); + source.data = $filter('orderBy')(source.data, source.query.order); + if (vm.query.search !== null) { + source.data = source.data.filter(function(item){ + for (let i = 0; i < item.length; i++) { + if (vm.showTimestamp) { + if (i === 0) { + if (searchRegExp.test($filter('date')(item[i], dateFormatFilter))) { + return true; + } + } else { + if (searchRegExp.test(item[i])) { + return true; + } + } + } else { + if (searchRegExp.test(item[i])) { + return true; + } + } + } + }); + } } function convertData(data) { diff --git a/ui/src/app/widget/lib/timeseries-table-widget.scss b/ui/src/app/widget/lib/timeseries-table-widget.scss index 99a06537e9..da3ee81644 100644 --- a/ui/src/app/widget/lib/timeseries-table-widget.scss +++ b/ui/src/app/widget/lib/timeseries-table-widget.scss @@ -26,4 +26,8 @@ tb-timeseries-table-widget { .md-table-pagination>* { height: 46px; } + + .tb-data-table md-toolbar { + z-index: 10; + } } diff --git a/ui/src/app/widget/lib/timeseries-table-widget.tpl.html b/ui/src/app/widget/lib/timeseries-table-widget.tpl.html index 32fb8e438c..2e7286c163 100644 --- a/ui/src/app/widget/lib/timeseries-table-widget.tpl.html +++ b/ui/src/app/widget/lib/timeseries-table-widget.tpl.html @@ -15,33 +15,71 @@ limitations under the License. --> +
+
+ +
+ + search + + {{'entity.search' | translate}} + + + + + + + + close + + {{ 'action.close' | translate }} + + +
+
- - - - - - - - - - - - - - - -
Timestamp{{ h.dataKey.label }}
-
-
- - -
-
\ No newline at end of file + + + + + + + + + + + + + + + + +
+ Timestamp + + {{ h.dataKey.label }} +
+
+ + +
+
+
+
\ No newline at end of file From 0637ed11644c9e277cd5541758b38a10f5373a87 Mon Sep 17 00:00:00 2001 From: Sergey Tarnavskiy Date: Wed, 3 Jan 2018 11:49:40 +0200 Subject: [PATCH 3/8] bug fix widgets-carousel --- ui/src/app/entity/attribute/attribute-table.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/app/entity/attribute/attribute-table.scss b/ui/src/app/entity/attribute/attribute-table.scss index cdf9ffdd0d..3f40cdf47e 100644 --- a/ui/src/app/entity/attribute/attribute-table.scss +++ b/ui/src/app/entity/attribute/attribute-table.scss @@ -47,7 +47,7 @@ md-toolbar.md-table-toolbar.alternate { .widgets-carousel { position: relative; margin: 0px; - + height: calc(100% - 100px); min-height: 150px !important; tb-dashboard { From 9e6acb7edeebbdf76905d343acbb1d589a7c1699 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 3 Jan 2018 12:24:20 +0200 Subject: [PATCH 4/8] Map widgets improvements. --- .../widget/lib/alarms-table-widget.tpl.html | 4 +- .../widget/lib/entities-table-widget.tpl.html | 2 +- ui/src/app/widget/lib/google-map.js | 123 ++++++++++-------- ui/src/app/widget/lib/image-map.js | 103 +++++++++++---- ui/src/app/widget/lib/map-widget.js | 65 +++++---- ui/src/app/widget/lib/map-widget2.js | 68 +++++----- ui/src/app/widget/lib/openstreet-map.js | 120 +++++++++-------- 7 files changed, 292 insertions(+), 193 deletions(-) diff --git a/ui/src/app/widget/lib/alarms-table-widget.tpl.html b/ui/src/app/widget/lib/alarms-table-widget.tpl.html index 860128d32f..34c7c1bfcb 100644 --- a/ui/src/app/widget/lib/alarms-table-widget.tpl.html +++ b/ui/src/app/widget/lib/alarms-table-widget.tpl.html @@ -77,7 +77,7 @@ + ng-click="vm.openAlarmDetails($event, alarm)" ng-disabled="$root.loading"> more_horiz {{ 'alarm.details' | translate }} @@ -90,7 +90,7 @@ width: vm.actionCellDescriptors.length*36+'px'}"> + ng-click="vm.onActionButtonClick($event, alarm, actionDescriptor)" ng-disabled="$root.loading"> {{actionDescriptor.icon}} {{ actionDescriptor.displayName }} diff --git a/ui/src/app/widget/lib/entities-table-widget.tpl.html b/ui/src/app/widget/lib/entities-table-widget.tpl.html index 2587da1779..7ef8c54de6 100644 --- a/ui/src/app/widget/lib/entities-table-widget.tpl.html +++ b/ui/src/app/widget/lib/entities-table-widget.tpl.html @@ -63,7 +63,7 @@ width: vm.actionCellDescriptors.length*36+'px'}"> + ng-click="vm.onActionButtonClick($event, entity, actionDescriptor)" ng-disabled="$root.loading"> {{actionDescriptor.icon}} {{ actionDescriptor.displayName }} diff --git a/ui/src/app/widget/lib/google-map.js b/ui/src/app/widget/lib/google-map.js index e2b4dc6015..48900bd078 100644 --- a/ui/src/app/widget/lib/google-map.js +++ b/ui/src/app/widget/lib/google-map.js @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - var gmGlobals = { loadingGmId: null, gmApiKeys: {} @@ -151,80 +150,100 @@ export default class TbGoogleMap { /* eslint-disable no-undef */ updateMarkerColor(marker, color) { - var pinColor = color.substr(1); - var pinImage = new google.maps.MarkerImage("https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|" + pinColor, - new google.maps.Size(21, 34), - new google.maps.Point(0,0), - new google.maps.Point(10, 34)); - marker.setIcon(pinImage); + this.createDefaultMarkerIcon(marker, color, (iconInfo) => { + marker.setIcon(iconInfo.icon); + }); } /* eslint-enable no-undef */ /* eslint-disable no-undef */ - updateMarkerImage(marker, settings, image, maxSize) { - var testImage = document.createElement('img'); // eslint-disable-line - testImage.style.visibility = 'hidden'; - testImage.onload = function() { - var width; - var height; - var aspect = testImage.width / testImage.height; - document.body.removeChild(testImage); //eslint-disable-line - if (aspect > 1) { - width = maxSize; - height = maxSize / aspect; - } else { - width = maxSize * aspect; - height = maxSize; - } - var pinImage = { - url: image, - scaledSize : new google.maps.Size(width, height) - } - marker.setIcon(pinImage); + updateMarkerIcon(marker, settings) { + this.createMarkerIcon(marker, settings, (iconInfo) => { + marker.setIcon(iconInfo.icon); if (settings.showLabel) { - marker.set('labelAnchor', new google.maps.Point(100, height + 20)); + marker.set('labelAnchor', new google.maps.Point(100, iconInfo.size[1] + 20)); } + }); + } + /* eslint-disable no-undef */ + + /* eslint-disable no-undef */ + createMarkerIcon(marker, settings, onMarkerIconReady) { + var currentImage = settings.currentImage; + var gMap = this; + if (currentImage && currentImage.url) { + var testImage = document.createElement('img'); // eslint-disable-line + testImage.style.visibility = 'hidden'; + testImage.onload = function() { + var width; + var height; + var aspect = testImage.width / testImage.height; + document.body.removeChild(testImage); //eslint-disable-line + if (aspect > 1) { + width = currentImage.size; + height = currentImage.size / aspect; + } else { + width = currentImage.size * aspect; + height = currentImage.size; + } + var icon = { + url: currentImage.url, + scaledSize : new google.maps.Size(width, height) + }; + var iconInfo = { + size: [width, height], + icon: icon + }; + onMarkerIconReady(iconInfo); + }; + testImage.onerror = function() { + gMap.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); + }; + document.body.appendChild(testImage); //eslint-disable-line + testImage.src = currentImage.url; + } else { + this.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); } - document.body.appendChild(testImage); //eslint-disable-line - testImage.src = image; } /* eslint-enable no-undef */ /* eslint-disable no-undef */ - createMarker(location, settings, onClickListener, markerArgs) { - var height = 34; - var pinColor = settings.color.substr(1); - var pinImage = new google.maps.MarkerImage("https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|" + pinColor, - new google.maps.Size(21, 34), - new google.maps.Point(0,0), - new google.maps.Point(10, 34)); - var pinShadow = new google.maps.MarkerImage("https://chart.apis.google.com/chart?chst=d_map_pin_shadow", + createDefaultMarkerIcon(marker, color, onMarkerIconReady) { + var pinColor = color.substr(1); + var icon = new google.maps.MarkerImage("https://chart.apis.google.com/chart?chst=d_map_pin_letter_withshadow&chld=%E2%80%A2|" + pinColor, new google.maps.Size(40, 37), - new google.maps.Point(0, 0), - new google.maps.Point(12, 35)); + new google.maps.Point(0,0), + new google.maps.Point(10, 37)); + var iconInfo = { + size: [40, 37], + icon: icon + }; + onMarkerIconReady(iconInfo); + } + /* eslint-enable no-undef */ + + /* eslint-disable no-undef */ + createMarker(location, settings, onClickListener, markerArgs) { var marker; if (settings.showLabel) { marker = new MarkerWithLabel({ position: location, - map: this.map, - icon: pinImage, - shadow: pinShadow, labelContent: '
'+settings.labelText+'
', - labelClass: "tb-labels", - labelAnchor: new google.maps.Point(100, height + 20) + labelClass: "tb-labels" }); } else { marker = new google.maps.Marker({ position: location, - map: this.map, - icon: pinImage, - shadow: pinShadow }); } - - if (settings.useMarkerImage) { - this.updateMarkerImage(marker, settings, settings.markerImage, settings.markerImageSize || 34); - } + var gMap = this; + this.createMarkerIcon(marker, settings, (iconInfo) => { + marker.setIcon(iconInfo.icon); + if (settings.showLabel) { + marker.set('labelAnchor', new google.maps.Point(100, iconInfo.size[1] + 20)); + } + marker.setMap(gMap.map); + }); if (settings.displayTooltip) { this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo, settings.autocloseTooltip, markerArgs); diff --git a/ui/src/app/widget/lib/image-map.js b/ui/src/app/widget/lib/image-map.js index e9d99765ce..21901880eb 100644 --- a/ui/src/app/widget/lib/image-map.js +++ b/ui/src/app/widget/lib/image-map.js @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import 'leaflet/dist/leaflet.css'; import * as L from 'leaflet'; @@ -229,20 +228,12 @@ export default class TbImageMap { } updateMarkerColor(marker, color) { - var pinColor = color.substr(1); - var icon = L.icon({ - iconUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|' + pinColor, - iconSize: [21, 34], - iconAnchor: [10, 34], - popupAnchor: [0, -34], - shadowUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_shadow', - shadowSize: [40, 37], - shadowAnchor: [12, 35] + this.createDefaultMarkerIcon(marker, color, (iconInfo) => { + marker.setIcon(iconInfo.icon); }); - marker.setIcon(icon); } - updateMarkerImage(marker, settings, image, maxSize) { + /*updateMarkerImage(marker, settings, image, maxSize) { var testImage = document.createElement('img'); // eslint-disable-line testImage.style.visibility = 'hidden'; testImage.onload = function() { @@ -273,39 +264,97 @@ export default class TbImageMap { } document.body.appendChild(testImage); //eslint-disable-line testImage.src = image; + }*/ + + updateMarkerIcon(marker, settings) { + this.createMarkerIcon(marker, settings, (iconInfo) => { + marker.setIcon(iconInfo.icon); + if (settings.showLabel) { + marker.unbindTooltip(); + marker.tooltipOffset = [0, -iconInfo.size[1] * marker.offsetY + 10]; + marker.bindTooltip('
'+settings.labelText+'
', + { className: 'tb-marker-label', permanent: true, direction: 'top', offset: marker.tooltipOffset }); + } + }); } - createMarker(position, settings, onClickListener, markerArgs) { - var height = 34; - var pinColor = settings.color.substr(1); + createMarkerIcon(marker, settings, onMarkerIconReady) { + var currentImage = settings.currentImage; + var opMap = this; + if (currentImage && currentImage.url) { + var testImage = document.createElement('img'); // eslint-disable-line + testImage.style.visibility = 'hidden'; + testImage.onload = function() { + var width; + var height; + var aspect = testImage.width / testImage.height; + document.body.removeChild(testImage); //eslint-disable-line + if (aspect > 1) { + width = currentImage.size; + height = currentImage.size / aspect; + } else { + width = currentImage.size * aspect; + height = currentImage.size; + } + var icon = L.icon({ + iconUrl: currentImage.url, + iconSize: [width, height], + iconAnchor: [marker.offsetX * width, marker.offsetY * height], + popupAnchor: [0, -height] + }); + var iconInfo = { + size: [width, height], + icon: icon + }; + onMarkerIconReady(iconInfo); + }; + testImage.onerror = function() { + opMap.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); + }; + document.body.appendChild(testImage); //eslint-disable-line + testImage.src = currentImage.url; + } else { + this.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); + } + } + + createDefaultMarkerIcon(marker, color, onMarkerIconReady) { + var pinColor = color.substr(1); var icon = L.icon({ iconUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|' + pinColor, iconSize: [21, 34], - iconAnchor: [21 * settings.markerOffsetX, 34 * settings.markerOffsetY], + iconAnchor: [21 * marker.offsetX, 34 * marker.offsetY], popupAnchor: [0, -34], shadowUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_shadow', shadowSize: [40, 37], shadowAnchor: [12, 35] }); + var iconInfo = { + size: [21, 34], + icon: icon + }; + onMarkerIconReady(iconInfo); + } + createMarker(position, settings, onClickListener, markerArgs) { var pos = this.posFunction(position.x, position.y); var x = pos.x * this.width; var y = pos.y * this.height; var location = this.pointToLatLng(x, y); - var marker = L.marker(location, {icon: icon}).addTo(this.map); + var marker = L.marker(location, {});//.addTo(this.map); marker.position = position; marker.offsetX = settings.markerOffsetX; marker.offsetY = settings.markerOffsetY; - - if (settings.showLabel) { - marker.tooltipOffset = [0, -height * marker.offsetY + 10]; - marker.bindTooltip('
'+settings.labelText+'
', - { className: 'tb-marker-label', permanent: true, direction: 'top', offset: marker.tooltipOffset }); - } - - if (settings.useMarkerImage) { - this.updateMarkerImage(marker, settings, settings.markerImage, settings.markerImageSize || 34); - } + var opMap = this; + this.createMarkerIcon(marker, settings, (iconInfo) => { + marker.setIcon(iconInfo.icon); + if (settings.showLabel) { + marker.tooltipOffset = [0, -iconInfo.size[1] * marker.offsetY + 10]; + marker.bindTooltip('
'+settings.labelText+'
', + { className: 'tb-marker-label', permanent: true, direction: 'top', offset: marker.tooltipOffset }); + } + marker.addTo(opMap.map); + }); if (settings.displayTooltip) { this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo, settings.autocloseTooltip, markerArgs); diff --git a/ui/src/app/widget/lib/map-widget.js b/ui/src/app/widget/lib/map-widget.js index f742514403..53e6ada781 100644 --- a/ui/src/app/widget/lib/map-widget.js +++ b/ui/src/app/widget/lib/map-widget.js @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import tinycolor from 'tinycolor2'; import TbGoogleMap from './google-map'; @@ -274,9 +273,13 @@ export default class TbMapWidget { if (!this.locationsSettings[i].useMarkerImageFunction && angular.isDefined(configuredLocationsSettings[i].markerImage) && configuredLocationsSettings[i].markerImage.length > 0) { - this.locationsSettings[i].markerImage = configuredLocationsSettings[i].markerImage; this.locationsSettings[i].useMarkerImage = true; - this.locationsSettings[i].markerImageSize = configuredLocationsSettings[i].markerImageSize || 34; + var url = this.ctx.settings.markerImage; + var size = this.ctx.settings.markerImageSize || 34; + this.locationSettings.currentImage = { + url: url, + size: size + }; } if (this.drawRoutes) { @@ -380,17 +383,41 @@ export default class TbMapWidget { } } - function updateLocationMarkerImage(location, dataMap) { + function updateLocationMarkerIcon(location, dataMap) { var image = calculateLocationMarkerImage(location, dataMap); - if (image != null && (!location.settings.calculatedImage || !angular.equals(location.settings.calculatedImage, image))) { - tbMap.map.updateMarkerImage(location.marker, location.settings, image.url, image.size); - location.settings.calculatedImage = image; + if (image && (!location.settings.currentImage || !angular.equals(location.settings.currentImage, image))) { + location.settings.currentImage = image; + tbMap.map.updateMarkerIcon(location.marker, location.settings); } } function updateLocationStyle(location, dataMap) { updateLocationColor(location, dataMap); - updateLocationMarkerImage(location, dataMap); + updateLocationMarkerIcon(location, dataMap); + } + + function createOrUpdateLocationMarker(location, markerLocation, dataMap) { + var changed = false; + if (!location.marker) { + var image = calculateLocationMarkerImage(location, dataMap); + if (image && (!location.settings.currentImage || !angular.equals(location.settings.currentImage, image))) { + location.settings.currentImage = image; + } + location.marker = tbMap.map.createMarker(markerLocation, location.settings, + function() { + tbMap.callbacks.onLocationClick(location); + } + ); + tbMap.markers.push(location.marker); + changed = true; + } else { + var prevPosition = tbMap.map.getMarkerPosition(location.marker); + if (!prevPosition.equals(markerLocation)) { + tbMap.map.setMarkerPosition(location.marker, markerLocation); + changed = true; + } + } + return changed; } function updateLocation(location, data, dataMap) { @@ -413,15 +440,7 @@ export default class TbMapWidget { } if (latLngs.length > 0) { var markerLocation = latLngs[latLngs.length-1]; - if (!location.marker) { - location.marker = tbMap.map.createMarker(markerLocation, location.settings, - function() { - tbMap.callbacks.onLocationClick(location); - } - ); - } else { - tbMap.map.setMarkerPosition(location.marker, markerLocation); - } + createOrUpdateLocationMarker(location, markerLocation, dataMap); } if (!location.polyline) { location.polyline = tbMap.map.createPolyline(latLngs, location.settings); @@ -439,18 +458,8 @@ export default class TbMapWidget { lat = latData[latData.length-1][1]; lng = lngData[lngData.length-1][1]; latLng = tbMap.map.createLatLng(lat, lng); - if (!location.marker) { - location.marker = tbMap.map.createMarker(latLng, location.settings, function() { - tbMap.callbacks.onLocationClick(location); - }); - tbMap.markers.push(location.marker); + if (createOrUpdateLocationMarker(location, latLng, dataMap)) { locationChanged = true; - } else { - var prevPosition = tbMap.map.getMarkerPosition(location.marker); - if (!prevPosition.equals(latLng)) { - tbMap.map.setMarkerPosition(location.marker, latLng); - locationChanged = true; - } } } updateLocationStyle(location, dataMap); diff --git a/ui/src/app/widget/lib/map-widget2.js b/ui/src/app/widget/lib/map-widget2.js index 44abb2b2ac..db880ca96d 100644 --- a/ui/src/app/widget/lib/map-widget2.js +++ b/ui/src/app/widget/lib/map-widget2.js @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import tinycolor from 'tinycolor2'; import TbGoogleMap from './google-map'; @@ -159,9 +158,13 @@ export default class TbMapWidgetV2 { if (!this.locationSettings.useMarkerImageFunction && angular.isDefined(this.ctx.settings.markerImage) && this.ctx.settings.markerImage.length > 0) { - this.locationSettings.markerImage = this.ctx.settings.markerImage; this.locationSettings.useMarkerImage = true; - this.locationSettings.markerImageSize = this.ctx.settings.markerImageSize || 34; + var url = this.ctx.settings.markerImage; + var size = this.ctx.settings.markerImageSize || 34; + this.locationSettings.currentImage = { + url: url, + size: size + }; } if (this.drawRoutes) { @@ -235,10 +238,10 @@ export default class TbMapWidgetV2 { } } - function updateLocationMarkerImage(location, image) { - if (image && (!location.settings.calculatedImage || !angular.equals(location.settings.calculatedImage, image))) { - tbMap.map.updateMarkerImage(location.marker, location.settings, image.url, image.size); - location.settings.calculatedImage = image; + function updateLocationMarkerIcon(location, image) { + if (image && (!location.settings.currentImage || !angular.equals(location.settings.currentImage, image))) { + location.settings.currentImage = image; + tbMap.map.updateMarkerIcon(location.marker, location.settings); } } @@ -247,7 +250,31 @@ export default class TbMapWidgetV2 { var color = calculateLocationColor(location, dataMap); var image = calculateLocationMarkerImage(location, dataMap); updateLocationColor(location, color, image); - updateLocationMarkerImage(location, image); + updateLocationMarkerIcon(location, image); + } + + function createOrUpdateLocationMarker(location, markerLocation, dataMap) { + var changed = false; + if (!location.marker) { + var image = calculateLocationMarkerImage(location, dataMap); + if (image && (!location.settings.currentImage || !angular.equals(location.settings.currentImage, image))) { + location.settings.currentImage = image; + } + location.marker = tbMap.map.createMarker(markerLocation, location.settings, + function (event) { + tbMap.callbacks.onLocationClick(location); + locationRowClick(event, location); + }, [location.dsIndex]); + tbMap.markers.push(location.marker); + changed = true; + } else { + var prevPosition = tbMap.map.getMarkerPosition(location.marker); + if (!prevPosition.equals(markerLocation)) { + tbMap.map.setMarkerPosition(location.marker, markerLocation); + changed = true; + } + } + return changed; } function locationRowClick($event, location) { @@ -284,16 +311,7 @@ export default class TbMapWidgetV2 { } if (latLngs.length > 0) { var markerLocation = latLngs[latLngs.length - 1]; - if (!location.marker) { - location.marker = tbMap.map.createMarker(markerLocation, location.settings, - function (event) { - tbMap.callbacks.onLocationClick(location); - locationRowClick(event, location); - }, [location.dsIndex] - ); - } else { - tbMap.map.setMarkerPosition(location.marker, markerLocation); - } + createOrUpdateLocationMarker(location, markerLocation, dataMap); } if (!location.polyline) { location.polyline = tbMap.map.createPolyline(latLngs, location.settings); @@ -312,20 +330,8 @@ export default class TbMapWidgetV2 { lng = lngData[lngData.length - 1][1]; if (angular.isDefined(lat) && lat != null && angular.isDefined(lng) && lng != null) { latLng = tbMap.map.createLatLng(lat, lng); - if (!location.marker) { - location.marker = tbMap.map.createMarker(latLng, location.settings, - function (event) { - tbMap.callbacks.onLocationClick(location); - locationRowClick(event, location); - }, [location.dsIndex]); - tbMap.markers.push(location.marker); + if (createOrUpdateLocationMarker(location, latLng, dataMap)) { locationChanged = true; - } else { - var prevPosition = tbMap.map.getMarkerPosition(location.marker); - if (!prevPosition.equals(latLng)) { - tbMap.map.setMarkerPosition(location.marker, latLng); - locationChanged = true; - } } } } diff --git a/ui/src/app/widget/lib/openstreet-map.js b/ui/src/app/widget/lib/openstreet-map.js index 1d1d3f7e5e..3403acfe99 100644 --- a/ui/src/app/widget/lib/openstreet-map.js +++ b/ui/src/app/widget/lib/openstreet-map.js @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import 'leaflet/dist/leaflet.css'; import * as L from 'leaflet'; import 'leaflet-providers'; @@ -54,55 +53,65 @@ export default class TbOpenStreetMap { } updateMarkerColor(marker, color) { - var pinColor = color.substr(1); - var icon = L.icon({ - iconUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|' + pinColor, - iconSize: [21, 34], - iconAnchor: [10, 34], - popupAnchor: [0, -34], - shadowUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_shadow', - shadowSize: [40, 37], - shadowAnchor: [12, 35] + this.createDefaultMarkerIcon(marker, color, (iconInfo) => { + marker.setIcon(iconInfo.icon); }); - marker.setIcon(icon); - } - - updateMarkerImage(marker, settings, image, maxSize) { - var testImage = document.createElement('img'); // eslint-disable-line - testImage.style.visibility = 'hidden'; - testImage.onload = function() { - var width; - var height; - var aspect = testImage.width / testImage.height; - document.body.removeChild(testImage); //eslint-disable-line - if (aspect > 1) { - width = maxSize; - height = maxSize / aspect; - } else { - width = maxSize * aspect; - height = maxSize; - } - var icon = L.icon({ - iconUrl: image, - iconSize: [width, height], - iconAnchor: [width/2, height], - popupAnchor: [0, -height] - }); - marker.setIcon(icon); + } + + updateMarkerIcon(marker, settings) { + this.createMarkerIcon(marker, settings, (iconInfo) => { + marker.setIcon(iconInfo.icon); if (settings.showLabel) { marker.unbindTooltip(); - marker.tooltipOffset = [0, -height + 10]; + marker.tooltipOffset = [0, -iconInfo.size[1] + 10]; marker.bindTooltip('
'+settings.labelText+'
', { className: 'tb-marker-label', permanent: true, direction: 'top', offset: marker.tooltipOffset }); } + }); + } + + createMarkerIcon(marker, settings, onMarkerIconReady) { + var currentImage = settings.currentImage; + var opMap = this; + if (currentImage && currentImage.url) { + var testImage = document.createElement('img'); // eslint-disable-line + testImage.style.visibility = 'hidden'; + testImage.onload = function() { + var width; + var height; + var aspect = testImage.width / testImage.height; + document.body.removeChild(testImage); //eslint-disable-line + if (aspect > 1) { + width = currentImage.size; + height = currentImage.size / aspect; + } else { + width = currentImage.size * aspect; + height = currentImage.size; + } + var icon = L.icon({ + iconUrl: currentImage.url, + iconSize: [width, height], + iconAnchor: [width/2, height], + popupAnchor: [0, -height] + }); + var iconInfo = { + size: [width, height], + icon: icon + }; + onMarkerIconReady(iconInfo); + }; + testImage.onerror = function() { + opMap.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); + }; + document.body.appendChild(testImage); //eslint-disable-line + testImage.src = currentImage.url; + } else { + this.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); } - document.body.appendChild(testImage); //eslint-disable-line - testImage.src = image; } - createMarker(location, settings, onClickListener, markerArgs) { - var height = 34; - var pinColor = settings.color.substr(1); + createDefaultMarkerIcon(marker, color, onMarkerIconReady) { + var pinColor = color.substr(1); var icon = L.icon({ iconUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|' + pinColor, iconSize: [21, 34], @@ -112,18 +121,25 @@ export default class TbOpenStreetMap { shadowSize: [40, 37], shadowAnchor: [12, 35] }); + var iconInfo = { + size: [21, 34], + icon: icon + }; + onMarkerIconReady(iconInfo); + } - var marker = L.marker(location, {icon: icon}).addTo(this.map); - - if (settings.showLabel) { - marker.tooltipOffset = [0, -height + 10]; - marker.bindTooltip('
'+settings.labelText+'
', - { className: 'tb-marker-label', permanent: true, direction: 'top', offset: marker.tooltipOffset }); - } - - if (settings.useMarkerImage) { - this.updateMarkerImage(marker, settings, settings.markerImage, settings.markerImageSize || 34); - } + createMarker(location, settings, onClickListener, markerArgs) { + var marker = L.marker(location, {}); + var opMap = this; + this.createMarkerIcon(marker, settings, (iconInfo) => { + marker.setIcon(iconInfo.icon); + if (settings.showLabel) { + marker.tooltipOffset = [0, -iconInfo.size[1] + 10]; + marker.bindTooltip('
'+settings.labelText+'
', + { className: 'tb-marker-label', permanent: true, direction: 'top', offset: marker.tooltipOffset }); + } + marker.addTo(opMap.map); + }); if (settings.displayTooltip) { this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo, settings.autocloseTooltip, markerArgs); From 89e4c9caf08bd11b7ecacd8562eed2ca9fdc4dec Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 3 Jan 2018 12:26:18 +0200 Subject: [PATCH 5/8] Map widgets improvements. --- ui/src/app/widget/lib/image-map.js | 33 ------------------------------ 1 file changed, 33 deletions(-) diff --git a/ui/src/app/widget/lib/image-map.js b/ui/src/app/widget/lib/image-map.js index 21901880eb..746d571668 100644 --- a/ui/src/app/widget/lib/image-map.js +++ b/ui/src/app/widget/lib/image-map.js @@ -233,39 +233,6 @@ export default class TbImageMap { }); } - /*updateMarkerImage(marker, settings, image, maxSize) { - var testImage = document.createElement('img'); // eslint-disable-line - testImage.style.visibility = 'hidden'; - testImage.onload = function() { - var width; - var height; - var aspect = testImage.width / testImage.height; - document.body.removeChild(testImage); //eslint-disable-line - if (aspect > 1) { - width = maxSize; - height = maxSize / aspect; - } else { - width = maxSize * aspect; - height = maxSize; - } - var icon = L.icon({ - iconUrl: image, - iconSize: [width, height], - iconAnchor: [marker.offsetX * width, marker.offsetY * height], - popupAnchor: [0, -height] - }); - marker.setIcon(icon); - if (settings.showLabel) { - marker.unbindTooltip(); - marker.tooltipOffset = [0, -height * marker.offsetY + 10]; - marker.bindTooltip('
'+settings.labelText+'
', - { className: 'tb-marker-label', permanent: true, direction: 'top', offset: marker.tooltipOffset }); - } - } - document.body.appendChild(testImage); //eslint-disable-line - testImage.src = image; - }*/ - updateMarkerIcon(marker, settings) { this.createMarkerIcon(marker, settings, (iconInfo) => { marker.setIcon(iconInfo.icon); From e63bb8875d9622c52cbd81f3946f37f53e8fc25a Mon Sep 17 00:00:00 2001 From: Sergey Tarnavskiy Date: Wed, 3 Jan 2018 12:46:35 +0200 Subject: [PATCH 6/8] fix bug in horizontal-bar widget --- ui/src/app/widget/lib/CanvasDigitalGauge.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/app/widget/lib/CanvasDigitalGauge.js b/ui/src/app/widget/lib/CanvasDigitalGauge.js index bd3ff986a8..200430c690 100644 --- a/ui/src/app/widget/lib/CanvasDigitalGauge.js +++ b/ui/src/app/widget/lib/CanvasDigitalGauge.js @@ -455,7 +455,7 @@ function barDimensions(context, options, x, y, w, h) { if (options.hideMinMax && options.label === '') { bd.labelY = bd.barBottom; bd.barLeft = bd.origBaseX + options.fontMinMaxSize/3 * bd.fontSizeFactor; - bd.barRight = bd.bd.origBaseX + w + /*bd.width*/ - options.fontMinMaxSize/3 * bd.fontSizeFactor; + bd.barRight = bd.origBaseX + w + /*bd.width*/ - options.fontMinMaxSize/3 * bd.fontSizeFactor; } else { context.font = canvasGauges.drawings.font(options, 'MinMax', bd.fontSizeFactor); var minTextWidth = context.measureText(options.minValue+'').width; From debbcc89c0e24c13f63e8d059ae7c39ee6f50e5f Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 3 Jan 2018 15:51:45 +0200 Subject: [PATCH 7/8] Map Markers images load improvements. --- ui/src/app/common/utils.service.js | 35 ++++++++++- ui/src/app/widget/lib/google-map.js | 56 +++++++++--------- ui/src/app/widget/lib/image-map.js | 79 ++++++++++++------------- ui/src/app/widget/lib/map-widget.js | 6 +- ui/src/app/widget/lib/map-widget2.js | 6 +- ui/src/app/widget/lib/openstreet-map.js | 60 +++++++++---------- 6 files changed, 133 insertions(+), 109 deletions(-) diff --git a/ui/src/app/common/utils.service.js b/ui/src/app/common/utils.service.js index 9d997816f6..085a28bad5 100644 --- a/ui/src/app/common/utils.service.js +++ b/ui/src/app/common/utils.service.js @@ -134,6 +134,8 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t defaultAlarmDataKeys.push(dataKey); } + var imageAspectMap = {}; + var service = { getDefaultDatasource: getDefaultDatasource, generateObjectFromJsonSchema: generateObjectFromJsonSchema, @@ -159,7 +161,8 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t insertVariable: insertVariable, customTranslation: customTranslation, objToBase64: objToBase64, - base64toObj: base64toObj + base64toObj: base64toObj, + loadImageAspect: loadImageAspect } return service; @@ -543,4 +546,34 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t return obj; } + function loadImageAspect(imageUrl) { + var deferred = $q.defer(); + if (imageUrl && imageUrl.length) { + var urlHashCode = hashCode(imageUrl); + var aspect = imageAspectMap[urlHashCode]; + if (angular.isUndefined(aspect)) { + var testImage = document.createElement('img'); // eslint-disable-line + testImage.style.visibility = 'hidden'; + testImage.onload = function() { + aspect = testImage.width / testImage.height; + document.body.removeChild(testImage); //eslint-disable-line + imageAspectMap[urlHashCode] = aspect; + deferred.resolve(aspect); + }; + testImage.onerror = function() { + aspect = 0; + imageAspectMap[urlHashCode] = aspect; + deferred.resolve(aspect); + }; + document.body.appendChild(testImage); //eslint-disable-line + testImage.src = imageUrl; + } else { + deferred.resolve(aspect); + } + } else { + deferred.resolve(0); + } + return deferred.promise; + } + } diff --git a/ui/src/app/widget/lib/google-map.js b/ui/src/app/widget/lib/google-map.js index 48900bd078..af11ac36fd 100644 --- a/ui/src/app/widget/lib/google-map.js +++ b/ui/src/app/widget/lib/google-map.js @@ -19,9 +19,10 @@ var gmGlobals = { } export default class TbGoogleMap { - constructor($containerElement, initCallback, defaultZoomLevel, dontFitMapBounds, minZoomLevel, gmApiKey, gmDefaultMapType) { + constructor($containerElement, utils, initCallback, defaultZoomLevel, dontFitMapBounds, minZoomLevel, gmApiKey, gmDefaultMapType) { var tbMap = this; + this.utils = utils; this.defaultZoomLevel = defaultZoomLevel; this.dontFitMapBounds = dontFitMapBounds; this.minZoomLevel = minZoomLevel; @@ -172,35 +173,32 @@ export default class TbGoogleMap { var currentImage = settings.currentImage; var gMap = this; if (currentImage && currentImage.url) { - var testImage = document.createElement('img'); // eslint-disable-line - testImage.style.visibility = 'hidden'; - testImage.onload = function() { - var width; - var height; - var aspect = testImage.width / testImage.height; - document.body.removeChild(testImage); //eslint-disable-line - if (aspect > 1) { - width = currentImage.size; - height = currentImage.size / aspect; - } else { - width = currentImage.size * aspect; - height = currentImage.size; + this.utils.loadImageAspect(currentImage.url).then( + (aspect) => { + if (aspect) { + var width; + var height; + if (aspect > 1) { + width = currentImage.size; + height = currentImage.size / aspect; + } else { + width = currentImage.size * aspect; + height = currentImage.size; + } + var icon = { + url: currentImage.url, + scaledSize : new google.maps.Size(width, height) + }; + var iconInfo = { + size: [width, height], + icon: icon + }; + onMarkerIconReady(iconInfo); + } else { + gMap.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); + } } - var icon = { - url: currentImage.url, - scaledSize : new google.maps.Size(width, height) - }; - var iconInfo = { - size: [width, height], - icon: icon - }; - onMarkerIconReady(iconInfo); - }; - testImage.onerror = function() { - gMap.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); - }; - document.body.appendChild(testImage); //eslint-disable-line - testImage.src = currentImage.url; + ); } else { this.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); } diff --git a/ui/src/app/widget/lib/image-map.js b/ui/src/app/widget/lib/image-map.js index 746d571668..c130539f6e 100644 --- a/ui/src/app/widget/lib/image-map.js +++ b/ui/src/app/widget/lib/image-map.js @@ -20,9 +20,10 @@ const maxZoom = 4; export default class TbImageMap { - constructor(ctx, $containerElement, initCallback, imageUrl, posFunction, imageEntityAlias, imageUrlAttribute) { + constructor(ctx, $containerElement, utils, initCallback, imageUrl, posFunction, imageEntityAlias, imageUrlAttribute) { this.ctx = ctx; + this.utils = utils; this.tooltips = []; this.$containerElement = $containerElement; @@ -116,18 +117,15 @@ export default class TbImageMap { } this.imageUrl = imageUrl; var imageMap = this; - var testImage = document.createElement('img'); // eslint-disable-line - testImage.style.visibility = 'hidden'; - testImage.onload = function() { - imageMap.aspect = testImage.width / testImage.height; - document.body.removeChild(testImage); //eslint-disable-line - imageMap.onresize(updateImage); - if (initCallback) { - setTimeout(initCallback, 0); //eslint-disable-line + this.utils.loadImageAspect(imageUrl).then( + (aspect) => { + imageMap.aspect = aspect; + imageMap.onresize(updateImage); + if (initCallback) { + setTimeout(initCallback, 0); //eslint-disable-line + } } - } - document.body.appendChild(testImage); //eslint-disable-line - testImage.src = imageUrl; + ); } onresize(updateImage) { @@ -249,37 +247,34 @@ export default class TbImageMap { var currentImage = settings.currentImage; var opMap = this; if (currentImage && currentImage.url) { - var testImage = document.createElement('img'); // eslint-disable-line - testImage.style.visibility = 'hidden'; - testImage.onload = function() { - var width; - var height; - var aspect = testImage.width / testImage.height; - document.body.removeChild(testImage); //eslint-disable-line - if (aspect > 1) { - width = currentImage.size; - height = currentImage.size / aspect; - } else { - width = currentImage.size * aspect; - height = currentImage.size; + this.utils.loadImageAspect(currentImage.url).then( + (aspect) => { + if (aspect) { + var width; + var height; + if (aspect > 1) { + width = currentImage.size; + height = currentImage.size / aspect; + } else { + width = currentImage.size * aspect; + height = currentImage.size; + } + var icon = L.icon({ + iconUrl: currentImage.url, + iconSize: [width, height], + iconAnchor: [marker.offsetX * width, marker.offsetY * height], + popupAnchor: [0, -height] + }); + var iconInfo = { + size: [width, height], + icon: icon + }; + onMarkerIconReady(iconInfo); + } else { + opMap.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); + } } - var icon = L.icon({ - iconUrl: currentImage.url, - iconSize: [width, height], - iconAnchor: [marker.offsetX * width, marker.offsetY * height], - popupAnchor: [0, -height] - }); - var iconInfo = { - size: [width, height], - icon: icon - }; - onMarkerIconReady(iconInfo); - }; - testImage.onerror = function() { - opMap.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); - }; - document.body.appendChild(testImage); //eslint-disable-line - testImage.src = currentImage.url; + ); } else { this.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); } diff --git a/ui/src/app/widget/lib/map-widget.js b/ui/src/app/widget/lib/map-widget.js index 53e6ada781..ef86381438 100644 --- a/ui/src/app/widget/lib/map-widget.js +++ b/ui/src/app/widget/lib/map-widget.js @@ -74,7 +74,7 @@ export default class TbMapWidget { if (!$element) { $element = ctx.$container; } - + this.utils = ctx.$scope.$injector.get('utils'); this.drawRoutes = drawRoutes; this.markers = []; if (this.drawRoutes) { @@ -109,9 +109,9 @@ export default class TbMapWidget { }; if (mapProvider === 'google-map') { - this.map = new TbGoogleMap($element, initCallback, this.defaultZoomLevel, this.dontFitMapBounds, minZoomLevel, settings.gmApiKey, settings.gmDefaultMapType); + this.map = new TbGoogleMap($element, this.utils, initCallback, this.defaultZoomLevel, this.dontFitMapBounds, minZoomLevel, settings.gmApiKey, settings.gmDefaultMapType); } else if (mapProvider === 'openstreet-map') { - this.map = new TbOpenStreetMap($element, initCallback, this.defaultZoomLevel, this.dontFitMapBounds, minZoomLevel); + this.map = new TbOpenStreetMap($element, this.utils, initCallback, this.defaultZoomLevel, this.dontFitMapBounds, minZoomLevel); } } diff --git a/ui/src/app/widget/lib/map-widget2.js b/ui/src/app/widget/lib/map-widget2.js index db880ca96d..6b589aa13a 100644 --- a/ui/src/app/widget/lib/map-widget2.js +++ b/ui/src/app/widget/lib/map-widget2.js @@ -74,11 +74,11 @@ export default class TbMapWidgetV2 { }); if (mapProvider === 'google-map') { - this.map = new TbGoogleMap($element, initCallback, this.defaultZoomLevel, this.dontFitMapBounds, minZoomLevel, settings.gmApiKey, settings.gmDefaultMapType); + this.map = new TbGoogleMap($element, this.utils, initCallback, this.defaultZoomLevel, this.dontFitMapBounds, minZoomLevel, settings.gmApiKey, settings.gmDefaultMapType); } else if (mapProvider === 'openstreet-map') { - this.map = new TbOpenStreetMap($element, initCallback, this.defaultZoomLevel, this.dontFitMapBounds, minZoomLevel, settings.mapProvider); + this.map = new TbOpenStreetMap($element, this.utils, initCallback, this.defaultZoomLevel, this.dontFitMapBounds, minZoomLevel, settings.mapProvider); } else if (mapProvider === 'image-map') { - this.map = new TbImageMap(this.ctx, $element, initCallback, + this.map = new TbImageMap(this.ctx, $element, this.utils, initCallback, settings.mapImageUrl, settings.posFunction, settings.imageEntityAlias, diff --git a/ui/src/app/widget/lib/openstreet-map.js b/ui/src/app/widget/lib/openstreet-map.js index 3403acfe99..8aafe69a7a 100644 --- a/ui/src/app/widget/lib/openstreet-map.js +++ b/ui/src/app/widget/lib/openstreet-map.js @@ -19,8 +19,9 @@ import 'leaflet-providers'; export default class TbOpenStreetMap { - constructor($containerElement, initCallback, defaultZoomLevel, dontFitMapBounds, minZoomLevel, mapProvider) { + constructor($containerElement, utils, initCallback, defaultZoomLevel, dontFitMapBounds, minZoomLevel, mapProvider) { + this.utils = utils; this.defaultZoomLevel = defaultZoomLevel; this.dontFitMapBounds = dontFitMapBounds; this.minZoomLevel = minZoomLevel; @@ -74,37 +75,34 @@ export default class TbOpenStreetMap { var currentImage = settings.currentImage; var opMap = this; if (currentImage && currentImage.url) { - var testImage = document.createElement('img'); // eslint-disable-line - testImage.style.visibility = 'hidden'; - testImage.onload = function() { - var width; - var height; - var aspect = testImage.width / testImage.height; - document.body.removeChild(testImage); //eslint-disable-line - if (aspect > 1) { - width = currentImage.size; - height = currentImage.size / aspect; - } else { - width = currentImage.size * aspect; - height = currentImage.size; + this.utils.loadImageAspect(currentImage.url).then( + (aspect) => { + if (aspect) { + var width; + var height; + if (aspect > 1) { + width = currentImage.size; + height = currentImage.size / aspect; + } else { + width = currentImage.size * aspect; + height = currentImage.size; + } + var icon = L.icon({ + iconUrl: currentImage.url, + iconSize: [width, height], + iconAnchor: [width/2, height], + popupAnchor: [0, -height] + }); + var iconInfo = { + size: [width, height], + icon: icon + }; + onMarkerIconReady(iconInfo); + } else { + opMap.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); + } } - var icon = L.icon({ - iconUrl: currentImage.url, - iconSize: [width, height], - iconAnchor: [width/2, height], - popupAnchor: [0, -height] - }); - var iconInfo = { - size: [width, height], - icon: icon - }; - onMarkerIconReady(iconInfo); - }; - testImage.onerror = function() { - opMap.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); - }; - document.body.appendChild(testImage); //eslint-disable-line - testImage.src = currentImage.url; + ); } else { this.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); } From bd4b0d78c3e640767cc573b50b2352871658b696 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 3 Jan 2018 18:37:28 +0200 Subject: [PATCH 8/8] UI: Improve WS publishing of subscription commands. --- .../server/config/WebSocketConfiguration.java | 4 +- ui/src/app/api/telemetry-websocket.service.js | 37 +++++++++++++++---- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java b/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java index 35d17732fe..9f7c08f511 100644 --- a/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java +++ b/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java @@ -47,8 +47,8 @@ public class WebSocketConfiguration implements WebSocketConfigurer { @Bean public ServletServerContainerFactoryBean createWebSocketContainer() { ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); - container.setMaxTextMessageBufferSize(8192); - container.setMaxBinaryMessageBufferSize(8192); + container.setMaxTextMessageBufferSize(32768); + container.setMaxBinaryMessageBufferSize(32768); return container; } diff --git a/ui/src/app/api/telemetry-websocket.service.js b/ui/src/app/api/telemetry-websocket.service.js index f84d66d3dd..b0e8ea91dd 100644 --- a/ui/src/app/api/telemetry-websocket.service.js +++ b/ui/src/app/api/telemetry-websocket.service.js @@ -23,6 +23,8 @@ export default angular.module('thingsboard.api.telemetryWebsocket', [thingsboard const RECONNECT_INTERVAL = 2000; const WS_IDLE_TIMEOUT = 90000; +const MAX_PUBLISH_COMMANDS = 10; + /*@ngInject*/ function TelemetryWebsocketService($rootScope, $websocket, $timeout, $window, types, userService) { @@ -75,19 +77,40 @@ function TelemetryWebsocketService($rootScope, $websocket, $timeout, $window, ty return service; function publishCommands () { - if (isOpened && (cmdsWrapper.tsSubCmds.length > 0 || - cmdsWrapper.historyCmds.length > 0 || - cmdsWrapper.attrSubCmds.length > 0)) { - dataStream.send(angular.copy(cmdsWrapper)).then(function () { + while(isOpened && hasCommands()) { + dataStream.send(preparePublishCommands()).then(function () { checkToClose(); }); - cmdsWrapper.tsSubCmds = []; - cmdsWrapper.historyCmds = []; - cmdsWrapper.attrSubCmds = []; } tryOpenSocket(); } + function hasCommands() { + return cmdsWrapper.tsSubCmds.length > 0 || + cmdsWrapper.historyCmds.length > 0 || + cmdsWrapper.attrSubCmds.length > 0; + } + + function preparePublishCommands() { + var preparedWrapper = {}; + var leftCount = MAX_PUBLISH_COMMANDS; + preparedWrapper.tsSubCmds = popCmds(cmdsWrapper.tsSubCmds, leftCount); + leftCount -= preparedWrapper.tsSubCmds.length; + preparedWrapper.historyCmds = popCmds(cmdsWrapper.historyCmds, leftCount); + leftCount -= preparedWrapper.historyCmds.length; + preparedWrapper.attrSubCmds = popCmds(cmdsWrapper.attrSubCmds, leftCount); + return preparedWrapper; + } + + function popCmds(cmds, leftCount) { + var toPublish = Math.min(cmds.length, leftCount); + if (toPublish > 0) { + return cmds.splice(0, toPublish); + } else { + return []; + } + } + function onError (/*message*/) { isOpening = false; }