diff --git a/application/src/main/data/json/system/widget_bundles/charts.json b/application/src/main/data/json/system/widget_bundles/charts.json index 01e575ea9b..2e01cf6963 100644 --- a/application/src/main/data/json/system/widget_bundles/charts.json +++ b/application/src/main/data/json/system/widget_bundles/charts.json @@ -21,7 +21,7 @@ "doughnut", "horizontal_doughnut", "polar_area", - "charts.radar_chart_js", + "radar", "charts.basic_timeseries", "charts.state_chart", "charts.timeseries_bars_flot", @@ -29,6 +29,7 @@ "charts.pie", "charts.pie_chart_js", "charts.doughnut_chart_js", - "charts.polar_area_chart_js" + "charts.polar_area_chart_js", + "charts.radar_chart_js" ] } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/radar.json b/application/src/main/data/json/system/widget_types/radar.json index 18bc07ac98..06c51d6296 100644 --- a/application/src/main/data/json/system/widget_types/radar.json +++ b/application/src/main/data/json/system/widget_types/radar.json @@ -1,25 +1,26 @@ { - "fqn": "charts.radar_chart_js", + "fqn": "radar", "name": "Radar", "deprecated": false, - "image": "data:image/png;base64,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", - "description": "Displays the latest values of the attributes or time series data for multiple entities in a radar chart. Supports numeric values only.", + "image": "tb-image:cmFkYXIuc3Zn:IlJhZGFyIiBzeXN0ZW0gd2lkZ2V0IGltYWdl;data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE2MCIgdmlld0JveD0iMCAwIDIwMCAxNjAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyMDAiIGhlaWdodD0iMTYwIiByeD0iNCIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTMwLjk4NDQgMTQwLjA1MUw5OS40OTIxIDIwLjU3MzNMMTY4IDE0MC4wNTFIMzAuOTg0NFoiIHN0cm9rZT0iYmxhY2siIHN0cm9rZS1vcGFjaXR5PSIwLjM4IiBzdHJva2Utd2lkdGg9IjAuNTcwMzEzIi8+CjxwYXRoIGQ9Ik00OC42MzU2IDEyOS42MzdMOTkuNDkyIDQwLjI2NDFMMTUwLjM0OCAxMjkuNjM3SDQ4LjYzNTZaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjA0IiBzdHJva2U9IiNFMEUwRTAiIHN0cm9rZS13aWR0aD0iMC41NzAzMTMiLz4KPHBhdGggZD0iTTk5LjQ5MiA1Ny4xODc1TDEzNS45MDIgMTIxLjE3Mkg2My4wODI1TDk5LjQ5MiA1Ny4xODc1WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTYzLjU3MjkgMTIwLjg4N0w5OS40OTIgNTcuNzY0MUwxMzUuNDExIDEyMC44ODdINjMuNTcyOVoiIHN0cm9rZT0iYmxhY2siIHN0cm9rZS1vcGFjaXR5PSIwLjEyIiBzdHJva2Utd2lkdGg9IjAuNTcwMzEzIi8+CjxwYXRoIGQ9Ik03OS40NDM4IDExMS42MzdMOTkuNDkyMiA3Ni40MDUyTDExOS41NDEgMTExLjYzN0g3OS40NDM4WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC4wNCIgc3Ryb2tlPSIjRTBFMEUwIiBzdHJva2Utd2lkdGg9IjAuNTcwMzEzIi8+CjxwYXRoIGQ9Ik05OS40OTE5IDkzLjI4MTJMMTA1LjA5MyAxMDMuMTI1SDkzLjg5MDVMOTkuNDkxOSA5My4yODEyWiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTk0LjM4MDggMTAyLjg0TDk5LjQ5MTkgOTMuODU3OEwxMDQuNjAzIDEwMi44NEg5NC4zODA4WiIgc3Ryb2tlPSJibGFjayIgc3Ryb2tlLW9wYWNpdHk9IjAuMTIiIHN0cm9rZS13aWR0aD0iMC41NzAzMTMiLz4KPHBhdGggZD0iTTMxLjA2MjUgMTM5Ljc2Nkw5OS40OTQ1IDk5Ljk1ODUiIHN0cm9rZT0iIzlFOUU5RSIgc3Ryb2tlLXdpZHRoPSIwLjYxMzA5MSIvPgo8cGF0aCBkPSJNMTY3LjkyMiAxMzkuNzY2TDk5LjQ5MTkgOTkuOTU1NCIgc3Ryb2tlPSIjOUU5RTlFIiBzdHJva2Utd2lkdGg9IjAuNjEzMDkxIi8+CjxwYXRoIGQ9Ik05OS40OTIyIDIxLjE0MDFMOTkuNDkyMiA5OS44NDMzIiBzdHJva2U9IiM5RTlFOUUiIHN0cm9rZS13aWR0aD0iMC42MTMwOTEiLz4KPHBhdGggZD0iTTk5LjQyNzIgNTUuMzgyOEwxMTQuNzEgMTA4LjY5MyIgc3Ryb2tlPSIjM0Y1MkREIiBzdHJva2Utd2lkdGg9IjAuNjEzMDkxIi8+CjxwYXRoIGQ9Ik0xMTQuNzExIDEwOC42OTNMNTEuNjYyNyAxMjcuMjYxIiBzdHJva2U9IiMzRjUyREQiIHN0cm9rZS13aWR0aD0iMC42MTMwOTEiLz4KPHBhdGggZD0iTTk5LjQyNzIgNTUuMzgyOEw1MS42NjI0IDEyNy4yNjEiIHN0cm9rZT0iIzNGNTJERCIgc3Ryb2tlLXdpZHRoPSIwLjYxMzA5MSIvPgo8ZWxsaXBzZSBjeD0iNTEuNjYyOCIgY3k9IjEyNy4yNjEiIHJ4PSIyLjE3NDMyIiByeT0iMi4xODQ0NSIgZmlsbD0iIzNGNTJERCIvPgo8ZWxsaXBzZSBjeD0iOTkuNDkyMiIgY3k9IjU1LjE3NDIiIHJ4PSIyLjE3NDMyIiByeT0iMi4xODQ0NSIgZmlsbD0iIzNGNTJERCIvPgo8ZWxsaXBzZSBjeD0iMTE0LjcxMSIgY3k9IjEwOC42OTMiIHJ4PSIyLjE3NDMyIiByeT0iMi4xODQ0NSIgZmlsbD0iIzNGNTJERCIvPgo8cGF0aCBkPSJNMjguMTMyOCAxNDkuMTc2TDI2LjUxMTcgMTU0SDI1LjM3NUwyNy41IDE0OC4zMTJIMjguMjI2NkwyOC4xMzI4IDE0OS4xNzZaTTI5LjQ4ODMgMTU0TDI3Ljg1OTQgMTQ5LjE3NkwyNy43NjE3IDE0OC4zMTJIMjguNDkyMkwzMC42Mjg5IDE1NEgyOS40ODgzWk0yOS40MTQxIDE1MS44ODdWMTUyLjczNEgyNi4zNjMzVjE1MS44ODdIMjkuNDE0MVoiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuNzYiLz4KPHBhdGggZD0iTTE3Mi4yNTQgMTUyLjEyOUgxNzMuMzI4QzE3My4yOTkgMTUyLjUwOSAxNzMuMTk0IDE1Mi44NDYgMTczLjAxMiAxNTMuMTQxQzE3Mi44MjkgMTUzLjQzMiAxNzIuNTc2IDE1My42NjEgMTcyLjI1IDE1My44MjhDMTcxLjkyNCAxNTMuOTk1IDE3MS41MyAxNTQuMDc4IDE3MS4wNjYgMTU0LjA3OEMxNzAuNzEgMTU0LjA3OCAxNzAuMzg4IDE1NC4wMTYgMTcwLjEwMiAxNTMuODkxQzE2OS44MTggMTUzLjc2MyAxNjkuNTc0IDE1My41ODIgMTY5LjM3MSAxNTMuMzQ4QzE2OS4xNzEgMTUzLjExMSAxNjkuMDE3IDE1Mi44MjcgMTY4LjkxIDE1Mi40OTZDMTY4LjgwMyAxNTIuMTYzIDE2OC43NSAxNTEuNzg5IDE2OC43NSAxNTEuMzc1VjE1MC45NDFDMTY4Ljc1IDE1MC41MjcgMTY4LjgwNSAxNTAuMTU0IDE2OC45MTQgMTQ5LjgyQzE2OS4wMjMgMTQ5LjQ4NyAxNjkuMTggMTQ5LjIwMyAxNjkuMzgzIDE0OC45NjlDMTY5LjU4OSAxNDguNzMyIDE2OS44MzUgMTQ4LjU0OSAxNzAuMTIxIDE0OC40MjJDMTcwLjQxIDE0OC4yOTQgMTcwLjczMyAxNDguMjMgMTcxLjA5IDE0OC4yM0MxNzEuNTUzIDE0OC4yMyAxNzEuOTQ1IDE0OC4zMTYgMTcyLjI2NiAxNDguNDg4QzE3Mi41ODYgMTQ4LjY1OCAxNzIuODM1IDE0OC44OTEgMTczLjAxMiAxNDkuMTg4QzE3My4xODkgMTQ5LjQ4NCAxNzMuMjk2IDE0OS44MjYgMTczLjMzMiAxNTAuMjExSDE3Mi4yNThDMTcyLjIzNyAxNDkuOTcxIDE3Mi4xODUgMTQ5Ljc2OCAxNzIuMTAyIDE0OS42MDJDMTcyLjAyMSAxNDkuNDM1IDE3MS44OTggMTQ5LjMwOSAxNzEuNzM0IDE0OS4yMjNDMTcxLjU3MyAxNDkuMTM0IDE3MS4zNTggMTQ5LjA5IDE3MS4wOSAxNDkuMDlDMTcwLjg4MiAxNDkuMDkgMTcwLjY5OCAxNDkuMTI5IDE3MC41MzkgMTQ5LjIwN0MxNzAuMzgzIDE0OS4yODUgMTcwLjI1MyAxNDkuNDAyIDE3MC4xNDggMTQ5LjU1OUMxNzAuMDQ0IDE0OS43MTIgMTY5Ljk2NiAxNDkuOTA1IDE2OS45MTQgMTUwLjEzN0MxNjkuODYyIDE1MC4zNjYgMTY5LjgzNiAxNTAuNjMyIDE2OS44MzYgMTUwLjkzNFYxNTEuMzc1QzE2OS44MzYgMTUxLjY2NCAxNjkuODU5IDE1MS45MjMgMTY5LjkwNiAxNTIuMTUyQzE2OS45NTMgMTUyLjM4MiAxNzAuMDI2IDE1Mi41NzYgMTcwLjEyNSAxNTIuNzM0QzE3MC4yMjQgMTUyLjg5MyAxNzAuMzUyIDE1My4wMTQgMTcwLjUwOCAxNTMuMDk4QzE3MC42NjQgMTUzLjE4MSAxNzAuODUgMTUzLjIyMyAxNzEuMDY2IDE1My4yMjNDMTcxLjMyOSAxNTMuMjIzIDE3MS41NDMgMTUzLjE4MSAxNzEuNzA3IDE1My4wOThDMTcxLjg3NCAxNTMuMDE0IDE3MiAxNTIuODkyIDE3Mi4wODYgMTUyLjczQzE3Mi4xNzQgMTUyLjU2OSAxNzIuMjMgMTUyLjM2OCAxNzIuMjU0IDE1Mi4xMjlaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjc2Ii8+CjxwYXRoIGQ9Ik0xMDAuMTg0IDguNDY0ODRIOTguNzMwNUw5OC43MjI3IDcuNzA3MDNIOTkuOTY4OEMxMDAuMTgyIDcuNzA3MDMgMTAwLjM2MSA3LjY3NzA4IDEwMC41MDQgNy42MTcxOUMxMDAuNjQ3IDcuNTU3MjkgMTAwLjc1NSA3LjQ3MDA1IDEwMC44MjggNy4zNTU0N0MxMDAuOTA0IDcuMjQwODkgMTAwLjk0MSA3LjEwMTU2IDEwMC45NDEgNi45Mzc1QzEwMC45NDEgNi43NTUyMSAxMDAuOTA2IDYuNjA2NzcgMTAwLjgzNiA2LjQ5MjE5QzEwMC43NjggNi4zNzc2IDEwMC42NjEgNi4yOTQyNyAxMDAuNTE2IDYuMjQyMTlDMTAwLjM3IDYuMTg3NSAxMDAuMTg1IDYuMTYwMTYgOTkuOTYwOSA2LjE2MDE2SDk5LjA3ODFWMTFIOTguMDAzOVY1LjMxMjVIOTkuOTYwOUMxMDAuMjg0IDUuMzEyNSAxMDAuNTcyIDUuMzQzNzUgMTAwLjgyNCA1LjQwNjI1QzEwMS4wNzkgNS40NjYxNSAxMDEuMjk2IDUuNTU5OSAxMDEuNDczIDUuNjg3NUMxMDEuNjUgNS44MTUxIDEwMS43ODQgNS45NzUyNiAxMDEuODc1IDYuMTY3OTdDMTAxLjk2OSA2LjM2MDY4IDEwMi4wMTYgNi41ODk4NCAxMDIuMDE2IDYuODU1NDdDMTAyLjAxNiA3LjA4OTg0IDEwMS45NjEgNy4zMDU5OSAxMDEuODUyIDcuNTAzOTFDMTAxLjc0NSA3LjY5OTIyIDEwMS41NzkgNy44NTgwNyAxMDEuMzU1IDcuOTgwNDdDMTAxLjEzNCA4LjEwMjg2IDEwMC44NTMgOC4xNzMxOCAxMDAuNTEyIDguMTkxNDFMMTAwLjE4NCA4LjQ2NDg0Wk0xMDAuMTM3IDExSDk4LjQxNDFMOTguODYzMyAxMC4xNTYySDEwMC4xMzdDMTAwLjM1IDEwLjE1NjIgMTAwLjUyNiAxMC4xMjExIDEwMC42NjQgMTAuMDUwOEMxMDAuODA1IDkuOTgwNDcgMTAwLjkwOSA5Ljg4NDExIDEwMC45NzcgOS43NjE3MkMxMDEuMDQ3IDkuNjM2NzIgMTAxLjA4MiA5LjQ5MzQ5IDEwMS4wODIgOS4zMzIwM0MxMDEuMDgyIDkuMTU0OTUgMTAxLjA1MSA5LjAwMTMgMTAwLjk4OCA4Ljg3MTA5QzEwMC45MjggOC43NDA4OSAxMDAuODMyIDguNjQwNjIgMTAwLjY5OSA4LjU3MDMxQzEwMC41NjkgOC41IDEwMC4zOTcgOC40NjQ4NCAxMDAuMTg0IDguNDY0ODRIOTkuMDY2NEw5OS4wNzQyIDcuNzA3MDNIMTAwLjQ5NkwxMDAuNzQyIDhDMTAxLjA3IDguMDAyNiAxMDEuMzM3IDguMDY3NzEgMTAxLjU0MyA4LjE5NTMxQzEwMS43NTEgOC4zMjI5MiAxMDEuOTA1IDguNDg2OTggMTAyLjAwNCA4LjY4NzVDMTAyLjEwMyA4Ljg4ODAyIDEwMi4xNTIgOS4xMDQxNyAxMDIuMTUyIDkuMzM1OTRDMTAyLjE1MiA5LjcwMDUyIDEwMi4wNzMgMTAuMDA2NSAxMDEuOTE0IDEwLjI1MzlDMTAxLjc1OCAxMC41MDEzIDEwMS41MjkgMTAuNjg3NSAxMDEuMjI3IDEwLjgxMjVDMTAwLjkyNyAxMC45Mzc1IDEwMC41NjQgMTEgMTAwLjEzNyAxMVoiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuNzYiLz4KPC9zdmc+Cg==", + "description": "Displays the latest values of the attributes or time-series data in a radar chart. Supports numeric values only.", "descriptor": { "type": "latest", - "sizeX": 7, - "sizeY": 5, - "resources": [ - { - "url": "https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.min.js" - } - ], - "templateHtml": "\n", + "sizeX": 5, + "sizeY": 4, + "resources": [], + "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n $scope = self.ctx.$scope;\n utils = $scope.$injector.get(self.ctx.servicesMap.get('utils'));\n settings = utils.deepClone(self.ctx.settings) || {};\n settings.showTooltip = utils.defaultValue(settings.showTooltip, true);\n \n Chart.defaults.global.tooltips.enabled = settings.showTooltip;\n \n var barData = {\n labels: [],\n datasets: []\n };\n\n var backgroundColor = tinycolor(self.ctx.data[0].dataKey.color);\n backgroundColor.setAlpha(0.2);\n var borderColor = tinycolor(self.ctx.data[0].dataKey.color);\n borderColor.setAlpha(1);\n var dataset = {\n label: self.ctx.datasources[0].name,\n data: [],\n backgroundColor: backgroundColor.toRgbString(),\n borderColor: borderColor.toRgbString(),\n pointBackgroundColor: borderColor.toRgbString(),\n pointBorderColor: borderColor.darken().toRgbString(),\n borderWidth: 1\n }\n \n barData.datasets.push(dataset);\n \n for (var i = 0; i < self.ctx.data.length; i++) {\n var dataKey = self.ctx.data[i].dataKey;\n var units = dataKey.units && dataKey.units.length ? dataKey.units : self.ctx.units;\n units = units ? (' (' + units + ')') : '';\n barData.labels.push(dataKey.label + units);\n dataset.data.push(0);\n }\n \n var floatingPoint;\n if (typeof self.ctx.decimals !== 'undefined' && self.ctx.decimals !== null) {\n floatingPoint = self.ctx.widget.config.decimals;\n } else {\n floatingPoint = 2;\n }\n\n var ctx = $('#radarChart', self.ctx.$container);\n self.ctx.chart = new Chart(ctx, {\n type: 'radar',\n data: barData,\n options: {\n responsive: false,\n maintainAspectRatio: false,\n scale: {\n ticks: {\n callback: function(tick) {\n \treturn tick.toFixed(floatingPoint);\n }\n }\n }\n }\n });\n \n self.onResize();\n}\n\nself.onDataUpdated = function() {\n for (var i = 0; i < self.ctx.data.length; i++) {\n var cellData = self.ctx.data[i];\n if (cellData.data.length > 0) {\n var decimals;\n if (typeof cellData.dataKey.decimals !== 'undefined' \n && cellData.dataKey.decimals !== null ) {\n decimals = cellData.dataKey.decimals; \n } else {\n decimals = self.ctx.decimals;\n }\n var tvPair = cellData.data[cellData.data.length - 1];\n var value = self.ctx.utils.formatValue(tvPair[1], decimals);\n self.ctx.chart.data.datasets[0].data[i] = parseFloat(value);\n }\n } \n self.ctx.chart.update();\n}\n\nself.onResize = function() {\n if (self.ctx.height >= 70) {\n self.ctx.chart.resize();\n }\n}\n\nself.onDestroy = function() {\n self.ctx.chart.destroy();\n self.ctx.chart = null;\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.radarChartWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.radarChartWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n previewWidth: '500px',\n previewHeight: '380px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'windPower', label: 'Wind', type: 'timeseries', color: '#08872B' },\n { name: 'solarPower', label: 'Solar', type: 'timeseries', color: '#FF4D5A' },\n { name: 'hydroelectricPower', label: 'Hydroelectric', type: 'timeseries', color: '#FFDE30' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n\n", "settingsSchema": "", - "dataKeySettingsSchema": "{}\n", - "settingsDirective": "tb-chart-widget-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.545701115289893,\"funcBody\":\"var value = (prevValue-20) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+20;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Third\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.2592906835158064,\"funcBody\":\"var value = (prevValue-40) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+40;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Fourth\",\"color\":\"#ffc107\",\"settings\":{},\"_hash\":0.12880275585455747,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Radar\"}" + "dataKeySettingsSchema": "", + "settingsDirective": "tb-radar-chart-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-radar-chart-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Wind\",\"color\":\"#08872B\",\"settings\":{},\"_hash\":0.7227918773301678,\"funcBody\":\"if (prevValue === 0) {\\n prevValue = Math.random() * 200;\\n}\\nvar value = prevValue + Math.random() * 20 - 10;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 200) {\\n\\tvalue = 200;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Solar\",\"color\":\"#FF4D5A\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"if (prevValue === 0) {\\n prevValue = Math.random() * 200;\\n}\\nvar value = prevValue + Math.random() * 20 - 10;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 200) {\\n\\tvalue = 200;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Hydroelectric\",\"color\":\"#FFDE30\",\"settings\":{},\"_hash\":0.7051898468567794,\"funcBody\":\"if (prevValue === 0) {\\n prevValue = Math.random() * 200;\\n}\\nvar value = prevValue + Math.random() * 20 - 10;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 200) {\\n\\tvalue = 200;\\n}\\nreturn value;\",\"decimals\":0,\"aggregationType\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0px\",\"settings\":{},\"title\":\"Radar\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":null,\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{\"headerButton\":[]},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"radar\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"timewindowStyle\":{\"showIcon\":false,\"iconSize\":\"24px\",\"icon\":null,\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":true}}" }, - "externalId": null + "tags": [ + "radar", + "radar chart" + ] } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/radar_deprecated.json b/application/src/main/data/json/system/widget_types/radar_deprecated.json new file mode 100644 index 0000000000..0018c3d6a0 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/radar_deprecated.json @@ -0,0 +1,25 @@ +{ + "fqn": "charts.radar_chart_js", + "name": "Radar", + "deprecated": true, + "image": "tb-image:cmFkYXJfc3lzdGVtX3dpZGdldF9pbWFnZS5wbmc=:IlJhZGFyIiBzeXN0ZW0gd2lkZ2V0IGltYWdl;data:image/png;base64,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", + "description": "Displays the latest values of the attributes or time series data for multiple entities in a radar chart. Supports numeric values only.", + "descriptor": { + "type": "latest", + "sizeX": 7, + "sizeY": 5, + "resources": [ + { + "url": "https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.min.js" + } + ], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n $scope = self.ctx.$scope;\n utils = $scope.$injector.get(self.ctx.servicesMap.get('utils'));\n settings = utils.deepClone(self.ctx.settings) || {};\n settings.showTooltip = utils.defaultValue(settings.showTooltip, true);\n \n Chart.defaults.global.tooltips.enabled = settings.showTooltip;\n \n var barData = {\n labels: [],\n datasets: []\n };\n\n var backgroundColor = tinycolor(self.ctx.data[0].dataKey.color);\n backgroundColor.setAlpha(0.2);\n var borderColor = tinycolor(self.ctx.data[0].dataKey.color);\n borderColor.setAlpha(1);\n var dataset = {\n label: self.ctx.datasources[0].name,\n data: [],\n backgroundColor: backgroundColor.toRgbString(),\n borderColor: borderColor.toRgbString(),\n pointBackgroundColor: borderColor.toRgbString(),\n pointBorderColor: borderColor.darken().toRgbString(),\n borderWidth: 1\n }\n \n barData.datasets.push(dataset);\n \n for (var i = 0; i < self.ctx.data.length; i++) {\n var dataKey = self.ctx.data[i].dataKey;\n var units = dataKey.units && dataKey.units.length ? dataKey.units : self.ctx.units;\n units = units ? (' (' + units + ')') : '';\n barData.labels.push(dataKey.label + units);\n dataset.data.push(0);\n }\n \n var floatingPoint;\n if (typeof self.ctx.decimals !== 'undefined' && self.ctx.decimals !== null) {\n floatingPoint = self.ctx.widget.config.decimals;\n } else {\n floatingPoint = 2;\n }\n\n var ctx = $('#radarChart', self.ctx.$container);\n self.ctx.chart = new Chart(ctx, {\n type: 'radar',\n data: barData,\n options: {\n responsive: false,\n maintainAspectRatio: false,\n scale: {\n ticks: {\n callback: function(tick) {\n \treturn tick.toFixed(floatingPoint);\n }\n }\n }\n }\n });\n \n self.onResize();\n}\n\nself.onDataUpdated = function() {\n for (var i = 0; i < self.ctx.data.length; i++) {\n var cellData = self.ctx.data[i];\n if (cellData.data.length > 0) {\n var decimals;\n if (typeof cellData.dataKey.decimals !== 'undefined' \n && cellData.dataKey.decimals !== null ) {\n decimals = cellData.dataKey.decimals; \n } else {\n decimals = self.ctx.decimals;\n }\n var tvPair = cellData.data[cellData.data.length - 1];\n var value = self.ctx.utils.formatValue(tvPair[1], decimals);\n self.ctx.chart.data.datasets[0].data[i] = parseFloat(value);\n }\n } \n self.ctx.chart.update();\n}\n\nself.onResize = function() {\n if (self.ctx.height >= 70) {\n self.ctx.chart.resize();\n }\n}\n\nself.onDestroy = function() {\n self.ctx.chart.destroy();\n self.ctx.chart = null;\n}\n", + "settingsSchema": "", + "dataKeySettingsSchema": "{}\n", + "settingsDirective": "tb-chart-widget-settings", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.545701115289893,\"funcBody\":\"var value = (prevValue-20) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+20;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Third\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.2592906835158064,\"funcBody\":\"var value = (prevValue-40) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+40;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Fourth\",\"color\":\"#ffc107\",\"settings\":{},\"_hash\":0.12880275585455747,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Radar\"}" + }, + "tags": null +} \ No newline at end of file diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts index 0ce07406c9..18b80f86a5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts @@ -126,6 +126,9 @@ import { import { PolarAreaChartBasicConfigComponent } from '@home/components/widget/config/basic/chart/polar-area-chart-basic-config.component'; +import { + RadarChartBasicConfigComponent +} from '@home/components/widget/config/basic/chart/radar-chart-basic-config.component'; @NgModule({ declarations: [ @@ -167,7 +170,8 @@ import { StatusWidgetBasicConfigComponent, PieChartBasicConfigComponent, BarChartBasicConfigComponent, - PolarAreaChartBasicConfigComponent + PolarAreaChartBasicConfigComponent, + RadarChartBasicConfigComponent ], imports: [ CommonModule, @@ -211,7 +215,8 @@ import { StatusWidgetBasicConfigComponent, PieChartBasicConfigComponent, BarChartBasicConfigComponent, - PolarAreaChartBasicConfigComponent + PolarAreaChartBasicConfigComponent, + RadarChartBasicConfigComponent ] }) export class BasicWidgetConfigModule { @@ -249,5 +254,6 @@ export const basicWidgetConfigComponentsMap: {[key: string]: Type + + + + + + + +
+
widget-config.card-appearance
+
+ + {{ 'widget-config.card-title' | translate }} + +
+ + + + + + + +
+
+
+ + {{ 'widget-config.card-icon' | translate }} + +
+ + + + +
+
+
+ + {{ 'widgets.latest-chart.sort-series' | translate }} + +
+
+
widget-config.units-short
+ + +
+
+
widget-config.decimals-short
+ + + +
+
+
+
widgets.radar-chart.radar-appearance
+
+
{{ 'widgets.radar-chart.shape' | translate }}
+ + + + {{ radarChartShapeTranslations.get(shape) | translate }} + + + +
+
+
widgets.radar-chart.color
+ + +
+
+ + {{ 'widgets.radar-chart.line' | translate }} + +
+ + + + {{ chartLineTypeTranslations.get(type) | translate }} + + + + + + +
+
+
+ + {{ 'widgets.radar-chart.points' | translate }} + +
+ + + + {{ chartShapeTranslations.get(shape) | translate }} + + + + + + +
+
+
+ + {{ 'widgets.radar-chart.points-label' | translate }} + +
+ + + + {{ chartLabelPositionTranslations.get(position) | translate }} + + + + + + + +
+
+ + +
+
+
widgets.radar-chart.radar-axis
+
+ + {{ 'widgets.radar-chart.axis-label' | translate }} + + + +
+
+ + {{ 'widgets.radar-chart.ticks-label' | translate }} + +
+ + + + +
+
+
+
+ + + + + {{ 'widget-config.legend' | translate }} + + + + +
+
{{ 'legend.position' | translate }}
+ + + + {{ legendPositionTranslationMap.get(pos) | translate }} + + + +
+
+
{{ 'legend.label' | translate }}
+
+ + + + +
+
+
+
{{ 'legend.value' | translate }}
+
+ + + + +
+
+
+
+
+
+ + + + + {{ 'widget-config.tooltip' | translate }} + + + + +
+
{{ 'tooltip.value' | translate }}
+
+ + + + {{ latestChartTooltipValueTypeTranslationMap.get(type) | translate }} + + + + + +
widget-config.decimals-suffix
+
+ + + + +
+
+
+
{{ 'tooltip.background-color' | translate }}
+ + +
+
+
{{ 'tooltip.background-blur' | translate }}
+ + +
px
+
+
+
+
+
+ + +
+
widget-config.card-appearance
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.card-border-radius' | translate }}
+ + + +
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/radar-chart-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/radar-chart-basic-config.component.ts new file mode 100644 index 0000000000..68f66873d2 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/radar-chart-basic-config.component.ts @@ -0,0 +1,414 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { + DataKey, + Datasource, + datasourcesHasAggregation, + datasourcesHasOnlyComparisonAggregation, + legendPositions, + legendPositionTranslationMap, + WidgetConfig +} from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { formatValue, isUndefined, mergeDeep } from '@core/utils'; +import { + getTimewindowConfig, + setTimewindowConfig +} from '@home/components/widget/config/timewindow-config-panel.component'; +import { + LatestChartTooltipValueType, + latestChartTooltipValueTypes, + latestChartTooltipValueTypeTranslations +} from '@home/components/widget/lib/chart/latest-chart.models'; +import { + radarChartWidgetDefaultSettings, + RadarChartWidgetSettings +} from '@home/components/widget/lib/chart/radar-chart-widget.models'; +import { radarChartShapes, radarChartShapeTranslations } from '@home/components/widget/lib/chart/radar-chart.models'; +import { + chartLabelPositions, + chartLabelPositionTranslations, + chartLineTypes, + chartLineTypeTranslations, + chartShapes, + chartShapeTranslations +} from '@home/components/widget/lib/chart/chart.models'; + +@Component({ + selector: 'tb-radar-chart-basic-config', + templateUrl: './radar-chart-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class RadarChartBasicConfigComponent extends BasicWidgetConfigComponent { + + public get datasource(): Datasource { + const datasources: Datasource[] = this.radarChartWidgetConfigForm.get('datasources').value; + if (datasources && datasources.length) { + return datasources[0]; + } else { + return null; + } + } + + public get displayTimewindowConfig(): boolean { + const datasources = this.radarChartWidgetConfigForm.get('datasources').value; + return datasourcesHasAggregation(datasources); + } + + public onlyHistoryTimewindow(): boolean { + const datasources = this.radarChartWidgetConfigForm.get('datasources').value; + return datasourcesHasOnlyComparisonAggregation(datasources); + } + + radarChartShapes = radarChartShapes; + + radarChartShapeTranslations = radarChartShapeTranslations; + + chartLineTypes = chartLineTypes; + + chartLineTypeTranslations = chartLineTypeTranslations; + + chartShapes = chartShapes; + + chartShapeTranslations = chartShapeTranslations; + + chartLabelPositions = chartLabelPositions; + + chartLabelPositionTranslations = chartLabelPositionTranslations; + + legendPositions = legendPositions; + + legendPositionTranslationMap = legendPositionTranslationMap; + + latestChartTooltipValueTypes = latestChartTooltipValueTypes; + + latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations; + + radarChartWidgetConfigForm: UntypedFormGroup; + + valuePreviewFn = this._valuePreviewFn.bind(this); + + tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this); + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.radarChartWidgetConfigForm; + } + + protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return [{name: 'windPower', label: 'Wind', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#08872B'}, + {name: 'solarPower', label: 'Solar', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#FF4D5A'}, + {name: 'hydroelectricPower', label: 'Hydroelectric', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#FFDE30'}]; + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + const settings: RadarChartWidgetSettings = mergeDeep({} as RadarChartWidgetSettings, + radarChartWidgetDefaultSettings, configData.config.settings as RadarChartWidgetSettings); + this.radarChartWidgetConfigForm = this.fb.group({ + timewindowConfig: [getTimewindowConfig(configData.config), []], + datasources: [configData.config.datasources, []], + + series: [this.getSeries(configData.config.datasources), []], + + showTitle: [configData.config.showTitle, []], + title: [configData.config.title, []], + titleFont: [configData.config.titleFont, []], + titleColor: [configData.config.titleColor, []], + showTitleIcon: [configData.config.showTitleIcon, []], + titleIcon: [configData.config.titleIcon, []], + iconColor: [configData.config.iconColor, []], + + sortSeries: [settings.sortSeries, []], + + units: [configData.config.units, []], + decimals: [configData.config.decimals, []], + + shape: [settings.shape, []], + color: [settings.color, []], + showLine: [settings.showLine, []], + lineType: [settings.lineType, []], + lineWidth: [settings.lineWidth, [Validators.min(0)]], + showPoints: [settings.showPoints, []], + pointShape: [settings.pointShape, []], + pointSize: [settings.pointSize, [Validators.min(0)]], + showLabel: [settings.showLabel, []], + labelPosition: [settings.labelPosition, []], + labelFont: [settings.labelFont, []], + labelColor: [settings.labelColor, []], + fillAreaSettings: [settings.fillAreaSettings, []], + + axisShowLabel: [settings.axisShowLabel, []], + axisLabelFont: [settings.axisLabelFont, []], + axisShowTickLabels: [settings.axisShowTickLabels, []], + axisTickLabelFont: [settings.axisTickLabelFont, []], + axisTickLabelColor: [settings.axisTickLabelColor, []], + + animation: [settings.animation, []], + + showLegend: [settings.showLegend, []], + legendPosition: [settings.legendPosition, []], + legendLabelFont: [settings.legendLabelFont, []], + legendLabelColor: [settings.legendLabelColor, []], + legendValueFont: [settings.legendValueFont, []], + legendValueColor: [settings.legendValueColor, []], + + showTooltip: [settings.showTooltip, []], + tooltipValueType: [settings.tooltipValueType, []], + tooltipValueDecimals: [settings.tooltipValueDecimals, []], + tooltipValueFont: [settings.tooltipValueFont, []], + tooltipValueColor: [settings.tooltipValueColor, []], + tooltipBackgroundColor: [settings.tooltipBackgroundColor, []], + tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []], + + background: [settings.background, []], + + cardButtons: [this.getCardButtons(configData.config), []], + borderRadius: [configData.config.borderRadius, []], + + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); + this.widgetConfig.config.datasources = config.datasources; + this.setSeries(config.series, this.widgetConfig.config.datasources); + + this.widgetConfig.config.showTitle = config.showTitle; + this.widgetConfig.config.title = config.title; + this.widgetConfig.config.titleFont = config.titleFont; + this.widgetConfig.config.titleColor = config.titleColor; + + this.widgetConfig.config.showTitleIcon = config.showTitleIcon; + this.widgetConfig.config.titleIcon = config.titleIcon; + this.widgetConfig.config.iconColor = config.iconColor; + + this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + + this.widgetConfig.config.settings.sortSeries = config.sortSeries; + + this.widgetConfig.config.units = config.units; + this.widgetConfig.config.decimals = config.decimals; + + this.widgetConfig.config.settings.shape = config.shape; + this.widgetConfig.config.settings.color = config.color; + this.widgetConfig.config.settings.showLine = config.showLine; + this.widgetConfig.config.settings.lineType = config.lineType; + this.widgetConfig.config.settings.lineWidth = config.lineWidth; + this.widgetConfig.config.settings.showPoints = config.showPoints; + this.widgetConfig.config.settings.pointShape = config.pointShape; + this.widgetConfig.config.settings.pointSize = config.pointSize; + this.widgetConfig.config.settings.showLabel = config.showLabel; + this.widgetConfig.config.settings.labelPosition = config.labelPosition; + this.widgetConfig.config.settings.labelFont = config.labelFont; + this.widgetConfig.config.settings.labelColor = config.labelColor; + this.widgetConfig.config.settings.fillAreaSettings = config.fillAreaSettings; + + this.widgetConfig.config.settings.axisShowLabel = config.axisShowLabel; + this.widgetConfig.config.settings.axisLabelFont = config.axisLabelFont; + this.widgetConfig.config.settings.axisShowTickLabels = config.axisShowTickLabels; + this.widgetConfig.config.settings.axisTickLabelFont = config.axisTickLabelFont; + this.widgetConfig.config.settings.axisTickLabelColor = config.axisTickLabelColor; + + this.widgetConfig.config.settings.animation = config.animation; + + this.widgetConfig.config.settings.showLegend = config.showLegend; + this.widgetConfig.config.settings.legendPosition = config.legendPosition; + this.widgetConfig.config.settings.legendLabelFont = config.legendLabelFont; + this.widgetConfig.config.settings.legendLabelColor = config.legendLabelColor; + this.widgetConfig.config.settings.legendValueFont = config.legendValueFont; + this.widgetConfig.config.settings.legendValueColor = config.legendValueColor; + + this.widgetConfig.config.settings.showTooltip = config.showTooltip; + this.widgetConfig.config.settings.tooltipValueType = config.tooltipValueType; + this.widgetConfig.config.settings.tooltipValueDecimals = config.tooltipValueDecimals; + this.widgetConfig.config.settings.tooltipValueFont = config.tooltipValueFont; + this.widgetConfig.config.settings.tooltipValueColor = config.tooltipValueColor; + this.widgetConfig.config.settings.tooltipBackgroundColor = config.tooltipBackgroundColor; + this.widgetConfig.config.settings.tooltipBackgroundBlur = config.tooltipBackgroundBlur; + + this.widgetConfig.config.settings.background = config.background; + + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.borderRadius = config.borderRadius; + + this.widgetConfig.config.actions = config.actions; + + return this.widgetConfig; + } + + protected validatorTriggers(): string[] { + return ['showTitle', 'showTitleIcon', 'showLine', 'showPoints', 'showLabel', 'axisShowLabel', + 'axisShowTickLabels', 'showLegend', 'showTooltip']; + } + + protected updateValidators(emitEvent: boolean, trigger?: string) { + const showTitle: boolean = this.radarChartWidgetConfigForm.get('showTitle').value; + const showTitleIcon: boolean = this.radarChartWidgetConfigForm.get('showTitleIcon').value; + const showLine: boolean = this.radarChartWidgetConfigForm.get('showLine').value; + const showPoints: boolean = this.radarChartWidgetConfigForm.get('showPoints').value; + const showLabel: boolean = this.radarChartWidgetConfigForm.get('showLabel').value; + const axisShowLabel: boolean = this.radarChartWidgetConfigForm.get('axisShowLabel').value; + const axisShowTickLabels: boolean = this.radarChartWidgetConfigForm.get('axisShowTickLabels').value; + const showLegend: boolean = this.radarChartWidgetConfigForm.get('showLegend').value; + const showTooltip: boolean = this.radarChartWidgetConfigForm.get('showTooltip').value; + + if (showTitle) { + this.radarChartWidgetConfigForm.get('title').enable(); + this.radarChartWidgetConfigForm.get('titleFont').enable(); + this.radarChartWidgetConfigForm.get('titleColor').enable(); + this.radarChartWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false}); + if (showTitleIcon) { + this.radarChartWidgetConfigForm.get('titleIcon').enable(); + this.radarChartWidgetConfigForm.get('iconColor').enable(); + } else { + this.radarChartWidgetConfigForm.get('titleIcon').disable(); + this.radarChartWidgetConfigForm.get('iconColor').disable(); + } + } else { + this.radarChartWidgetConfigForm.get('title').disable(); + this.radarChartWidgetConfigForm.get('titleFont').disable(); + this.radarChartWidgetConfigForm.get('titleColor').disable(); + this.radarChartWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false}); + this.radarChartWidgetConfigForm.get('titleIcon').disable(); + this.radarChartWidgetConfigForm.get('iconColor').disable(); + } + + if (showLine) { + this.radarChartWidgetConfigForm.get('lineType').enable(); + this.radarChartWidgetConfigForm.get('lineWidth').enable(); + } else { + this.radarChartWidgetConfigForm.get('lineType').disable(); + this.radarChartWidgetConfigForm.get('lineWidth').disable(); + } + + if (showPoints) { + this.radarChartWidgetConfigForm.get('pointShape').enable(); + this.radarChartWidgetConfigForm.get('pointSize').enable(); + } else { + this.radarChartWidgetConfigForm.get('pointShape').disable(); + this.radarChartWidgetConfigForm.get('pointSize').disable(); + } + + if (showLabel) { + this.radarChartWidgetConfigForm.get('labelPosition').enable(); + this.radarChartWidgetConfigForm.get('labelFont').enable(); + this.radarChartWidgetConfigForm.get('labelColor').enable(); + } else { + this.radarChartWidgetConfigForm.get('labelPosition').disable(); + this.radarChartWidgetConfigForm.get('labelFont').disable(); + this.radarChartWidgetConfigForm.get('labelColor').disable(); + } + + if (axisShowLabel) { + this.radarChartWidgetConfigForm.get('axisLabelFont').enable(); + } else { + this.radarChartWidgetConfigForm.get('axisLabelFont').disable(); + } + + if (axisShowTickLabels) { + this.radarChartWidgetConfigForm.get('axisTickLabelFont').enable(); + this.radarChartWidgetConfigForm.get('axisTickLabelColor').enable(); + } else { + this.radarChartWidgetConfigForm.get('axisTickLabelFont').disable(); + this.radarChartWidgetConfigForm.get('axisTickLabelColor').disable(); + } + + if (showLegend) { + this.radarChartWidgetConfigForm.get('legendPosition').enable(); + this.radarChartWidgetConfigForm.get('legendLabelFont').enable(); + this.radarChartWidgetConfigForm.get('legendLabelColor').enable(); + this.radarChartWidgetConfigForm.get('legendValueFont').enable(); + this.radarChartWidgetConfigForm.get('legendValueColor').enable(); + } else { + this.radarChartWidgetConfigForm.get('legendPosition').disable(); + this.radarChartWidgetConfigForm.get('legendLabelFont').disable(); + this.radarChartWidgetConfigForm.get('legendLabelColor').disable(); + this.radarChartWidgetConfigForm.get('legendValueFont').disable(); + this.radarChartWidgetConfigForm.get('legendValueColor').disable(); + } + if (showTooltip) { + this.radarChartWidgetConfigForm.get('tooltipValueType').enable(); + this.radarChartWidgetConfigForm.get('tooltipValueDecimals').enable(); + this.radarChartWidgetConfigForm.get('tooltipValueFont').enable(); + this.radarChartWidgetConfigForm.get('tooltipValueColor').enable(); + this.radarChartWidgetConfigForm.get('tooltipBackgroundColor').enable(); + this.radarChartWidgetConfigForm.get('tooltipBackgroundBlur').enable(); + } else { + this.radarChartWidgetConfigForm.get('tooltipValueType').disable(); + this.radarChartWidgetConfigForm.get('tooltipValueDecimals').disable(); + this.radarChartWidgetConfigForm.get('tooltipValueFont').disable(); + this.radarChartWidgetConfigForm.get('tooltipValueColor').disable(); + this.radarChartWidgetConfigForm.get('tooltipBackgroundColor').disable(); + this.radarChartWidgetConfigForm.get('tooltipBackgroundBlur').disable(); + } + } + + private getSeries(datasources?: Datasource[]): DataKey[] { + if (datasources && datasources.length) { + return datasources[0].dataKeys || []; + } + return []; + } + + private setSeries(series: DataKey[], datasources?: Datasource[]) { + if (datasources && datasources.length) { + datasources[0].dataKeys = series; + } + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.enableFullscreen = buttons.includes('fullscreen'); + } + + private _valuePreviewFn(): string { + const units: string = this.radarChartWidgetConfigForm.get('units').value; + const decimals: number = this.radarChartWidgetConfigForm.get('decimals').value; + return formatValue(110, decimals, units, false); + } + + private _tooltipValuePreviewFn(): string { + const tooltipValueType: LatestChartTooltipValueType = this.radarChartWidgetConfigForm.get('tooltipValueType').value; + const decimals: number = this.radarChartWidgetConfigForm.get('tooltipValueDecimals').value; + if (tooltipValueType === LatestChartTooltipValueType.percentage) { + return formatValue(35, decimals, '%', false); + } else { + const units: string = this.radarChartWidgetConfigForm.get('units').value; + return formatValue(110, decimals, units, false); + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.html index 1ba564b3ba..eb1b2298a7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.html @@ -157,8 +157,8 @@
widgets.time-series-chart.line-type
- - {{ timeSeriesLineTypeTranslations.get(lineType) | translate }} + + {{ chartLineTypeTranslations.get(lineType) | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.ts index 985fd74624..8e29d43a3e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.ts @@ -46,11 +46,16 @@ import { } from '@home/components/widget/lib/chart/range-chart-widget.models'; import { lineSeriesStepTypes, - lineSeriesStepTypeTranslations, - timeSeriesLineTypes, - timeSeriesLineTypeTranslations + lineSeriesStepTypeTranslations } from '@home/components/widget/lib/chart/time-series-chart.models'; -import { chartLabelPositions, chartLabelPositionTranslations, chartShapes, chartShapeTranslations } from '@home/components/widget/lib/chart/chart.models'; +import { + chartLabelPositions, + chartLabelPositionTranslations, + chartLineTypes, + chartLineTypeTranslations, + chartShapes, + chartShapeTranslations +} from '@home/components/widget/lib/chart/chart.models'; @Component({ selector: 'tb-range-chart-basic-config', @@ -72,9 +77,9 @@ export class RangeChartBasicConfigComponent extends BasicWidgetConfigComponent { lineSeriesStepTypeTranslations = lineSeriesStepTypeTranslations; - timeSeriesLineTypes = timeSeriesLineTypes; + chartLineTypes = chartLineTypes; - timeSeriesLineTypeTranslations = timeSeriesLineTypeTranslations; + chartLineTypeTranslations = chartLineTypeTranslations; chartLabelPositions = chartLabelPositions; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/bars-chart.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/bars-chart.ts index f661223983..4458069eed 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/bars-chart.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/bars-chart.ts @@ -30,7 +30,7 @@ import { ChartFillType, ChartLabelPosition, createChartTextStyle, - createLinearOpacityGradient + createLinearOpacityGradient, toAnimationOption } from '@home/components/widget/lib/chart/chart.models'; import { ValueAxisBaseOption } from 'echarts/types/src/coord/axisCommonTypes'; import { RadiusAxisOption, YAXisOption } from 'echarts/types/dist/shared'; @@ -82,14 +82,7 @@ export class TbBarsChart extends TbLatestChart { }, coordinateSystem: this.settings.polar ? 'polar' : 'cartesian2d', label: labelOption, - animation: this.settings.animation.animation, - animationThreshold: this.settings.animation.animationThreshold, - animationDuration: this.settings.animation.animationDuration, - animationEasing: this.settings.animation.animationEasing, - animationDelay: this.settings.animation.animationDelay, - animationDurationUpdate: this.settings.animation.animationDurationUpdate, - animationEasingUpdate: this.settings.animation.animationEasingUpdate, - animationDelayUpdate: this.settings.animation.animationDelayUpdate + ...toAnimationOption(this.ctx, this.settings.animation) } ]; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/chart.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/chart.models.ts index 1f81f4bc3e..e52c7b77c8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/chart.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/chart.models.ts @@ -19,10 +19,11 @@ import { TbColorScheme } from '@shared/models/color.models'; import { LinearGradientObject } from 'zrender/lib/graphic/LinearGradient'; import tinycolor from 'tinycolor2'; import { ComponentStyle, Font, textStyle } from '@shared/models/widget-settings.models'; -import { LabelFormatterCallback } from 'echarts'; -import { LabelLayoutOption } from 'echarts/types/src/util/types'; +import { LabelFormatterCallback, RadialGradientObject } from 'echarts'; +import { AnimationOptionMixin, LabelLayoutOption } from 'echarts/types/src/util/types'; import { LabelLayoutOptionCallback } from 'echarts/types/dist/shared'; import { BuiltinTextPosition } from 'zrender/src/core/types'; +import { WidgetContext } from '@home/models/widget-component.models'; export const chartColorScheme: TbColorScheme = { 'threshold.line': { @@ -87,6 +88,22 @@ export const chartShapeTranslations = new Map( ] ); +export enum ChartLineType { + solid = 'solid', + dashed = 'dashed', + dotted = 'dotted' +} + +export const chartLineTypes = Object.keys(ChartLineType) as ChartLineType[]; + +export const chartLineTypeTranslations = new Map( + [ + [ChartLineType.solid, 'widgets.chart.line-type-solid'], + [ChartLineType.dashed, 'widgets.chart.line-type-dashed'], + [ChartLineType.dotted, 'widgets.chart.line-type-dotted'] + ] +); + export enum ChartAnimationEasing { linear = 'linear', quadraticIn = 'quadraticIn', @@ -287,6 +304,19 @@ export const createLinearOpacityGradient = (color: string, gradient: {start: num global: false }); +export const createRadialOpacityGradient = (color: string, gradient: {start: number; end: number}): RadialGradientObject => ({ + type: 'radial', + x: 0.5, + y: 0.5, + r: 0.5, + colorStops: [{ + offset: 0, color: tinycolor(color).setAlpha(gradient.end / 100).toRgbString() // color at 0% + }, { + offset: 1, color: tinycolor(color).setAlpha(gradient.start / 100).toRgbString() // color at 100% + }], + global: false +}); + export const createChartTextStyle = (font: Font, color: string, darkMode: boolean, colorKey?: string, fill = false): ComponentStyle => { const style = textStyle(font); delete style.lineHeight; @@ -314,3 +344,14 @@ export const prepareChartThemeColor = (color: string, darkMode: boolean, colorKe } return color; }; + +export const toAnimationOption = (ctx: WidgetContext, settings: ChartAnimationSettings): AnimationOptionMixin => ({ + animation: settings.animation, + animationThreshold: settings.animationThreshold, + animationDuration: settings.animationDuration, + animationEasing: settings.animationEasing, + animationDelay: settings.animationDelay, + animationDurationUpdate: settings.animationDurationUpdate, + animationEasingUpdate: settings.animationEasingUpdate, + animationDelayUpdate: settings.animationDelayUpdate +}); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/echarts-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/echarts-widget.models.ts index 121d46c86d..f68e8dbacb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/echarts-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/echarts-widget.models.ts @@ -26,6 +26,8 @@ import { MarkLineComponentOption, PolarComponent, PolarComponentOption, + RadarComponent, + RadarComponentOption, TooltipComponent, TooltipComponentOption, VisualMapComponent, @@ -39,7 +41,9 @@ import { LineChart, LineSeriesOption, PieChart, - PieSeriesOption + PieSeriesOption, + RadarChart, + RadarSeriesOption } from 'echarts/charts'; import { LabelLayout } from 'echarts/features'; import { CanvasRenderer, SVGRenderer } from 'echarts/renderers'; @@ -62,9 +66,11 @@ class EChartsModule { DataZoomComponent, MarkLineComponent, PolarComponent, + RadarComponent, LineChart, BarChart, PieChart, + RadarChart, CustomChart, LabelLayout, CanvasRenderer, @@ -84,10 +90,12 @@ export type EChartsOption = echarts.ComposeOption< | DataZoomComponentOption | MarkLineComponentOption | PolarComponentOption + | RadarComponentOption | LineSeriesOption | CustomSeriesOption | BarSeriesOption | PieSeriesOption + | RadarSeriesOption >; export type ECharts = echarts.ECharts; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.models.ts index 22de664154..dff371ec10 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.models.ts @@ -143,32 +143,83 @@ export const latestChartTooltipFormatter = (renderer: Renderer2, settings: LatestChartTooltipSettings, params: CallbackDataParams, units: string, - total: number): null | HTMLElement => { - if (!params.name) { + total: number, + dataItems: LatestChartDataItem[]): null | HTMLElement => { + if (params.value && Array.isArray(params.value)) { + const enabledDataItems = dataItems.filter(d => d.enabled && d.hasValue); + if (enabledDataItems.length && enabledDataItems.length === params.value.length) { + const tooltipElement: HTMLElement = renderer.createElement('div'); + renderer.setStyle(tooltipElement, 'display', 'flex'); + renderer.setStyle(tooltipElement, 'flex-direction', 'column'); + renderer.setStyle(tooltipElement, 'align-items', 'flex-start'); + renderer.setStyle(tooltipElement, 'gap', '4px'); + for (let i = 0; i < enabledDataItems.length; i++) { + const dataItem = enabledDataItems[i]; + const value = params.value[i]; + renderer.appendChild(tooltipElement, + constructTooltipSeriesElement(renderer, settings, dataItem.dataKey.label, value as number, null, + units, total, dataItem.dataKey.color)); + } + return tooltipElement; + } else { + return null; + } + } else if (params.name) { + return constructTooltipSeriesElement(renderer, settings, params.name, + params.value as number, params.percent, units, total); + } else { return null; } - let value: string; +}; + +const constructTooltipSeriesElement = (renderer: Renderer2, + settings: LatestChartTooltipSettings, + label: string, + value: number, + percent: number | undefined, + units: string, + total: number, + circleColor?: string): HTMLElement => { + let formattedValue: string; if (settings.tooltipValueType === LatestChartTooltipValueType.percentage) { - const percents = isDefinedAndNotNull(params.percent) ? params.percent : (params.value as number) / total * 100; - value = formatValue(percents, settings.tooltipValueDecimals, '%', false); + const percents = isDefinedAndNotNull(percent) ? percent : value / total * 100; + formattedValue = formatValue(percents, settings.tooltipValueDecimals, '%', false); } else { - value = formatValue(params.value, settings.tooltipValueDecimals, units, false); + formattedValue = formatValue(value, settings.tooltipValueDecimals, units, false); } const textElement: HTMLElement = renderer.createElement('div'); - renderer.setStyle(textElement, 'display', 'inline-flex'); + renderer.setStyle(textElement, 'display', 'flex'); + renderer.setStyle(textElement, 'flex-direction', 'row'); renderer.setStyle(textElement, 'align-items', 'center'); - renderer.setStyle(textElement, 'gap', '8px'); + renderer.setStyle(textElement, 'align-self', 'stretch'); + renderer.setStyle(textElement, 'gap', '12px'); const labelElement: HTMLElement = renderer.createElement('div'); - renderer.appendChild(labelElement, renderer.createText(params.name)); - renderer.setStyle(labelElement, 'font-family', 'Roboto'); - renderer.setStyle(labelElement, 'font-size', '11px'); - renderer.setStyle(labelElement, 'font-style', 'normal'); - renderer.setStyle(labelElement, 'font-weight', '400'); - renderer.setStyle(labelElement, 'line-height', '16px'); - renderer.setStyle(labelElement, 'letter-spacing', '0.25px'); - renderer.setStyle(labelElement, 'color', 'rgba(0, 0, 0, 0.38)'); + renderer.setStyle(labelElement, 'display', 'flex'); + renderer.setStyle(labelElement, 'align-items', 'center'); + renderer.setStyle(labelElement, 'gap', '8px'); + renderer.appendChild(textElement, labelElement); + if (circleColor) { + const circleElement: HTMLElement = renderer.createElement('div'); + renderer.setStyle(circleElement, 'width', '8px'); + renderer.setStyle(circleElement, 'height', '8px'); + renderer.setStyle(circleElement, 'border-radius', '50%'); + renderer.setStyle(circleElement, 'background', circleColor); + renderer.appendChild(labelElement, circleElement); + } + const labelTextElement: HTMLElement = renderer.createElement('div'); + renderer.appendChild(labelTextElement, renderer.createText(label)); + renderer.setStyle(labelTextElement, 'font-family', 'Roboto'); + renderer.setStyle(labelTextElement, 'font-size', '11px'); + renderer.setStyle(labelTextElement, 'font-style', 'normal'); + renderer.setStyle(labelTextElement, 'font-weight', '400'); + renderer.setStyle(labelTextElement, 'line-height', '16px'); + renderer.setStyle(labelTextElement, 'letter-spacing', '0.25px'); + renderer.setStyle(labelTextElement, 'color', 'rgba(0, 0, 0, 0.38)'); + renderer.appendChild(labelElement, labelTextElement); const valueElement: HTMLElement = renderer.createElement('div'); - renderer.appendChild(valueElement, renderer.createText(value)); + renderer.appendChild(valueElement, renderer.createText(formattedValue)); + renderer.setStyle(valueElement, 'flex', '1'); + renderer.setStyle(valueElement, 'text-align', 'end'); renderer.setStyle(valueElement, 'font-family', settings.tooltipValueFont.family); renderer.setStyle(valueElement, 'font-size', settings.tooltipValueFont.size + settings.tooltipValueFont.sizeUnit); renderer.setStyle(valueElement, 'font-style', settings.tooltipValueFont.style); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.ts index ddb6e47560..e041a69084 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.ts @@ -31,6 +31,7 @@ import { DataKey } from '@shared/models/widget.models'; import * as echarts from 'echarts/core'; import { CallbackDataParams } from 'echarts/types/dist/shared'; import { SVG, Svg } from '@svgdotjs/svg.js'; +import { toAnimationOption } from '@home/components/widget/lib/chart/chart.models'; export abstract class TbLatestChart { @@ -54,7 +55,7 @@ export abstract class TbLatestChart { private itemClick: ($event: Event, item: LatestChartDataItem) => void; - protected constructor(private ctx: WidgetContext, + protected constructor(protected ctx: WidgetContext, private readonly inputSettings: DeepPartial, protected chartElement: HTMLElement, private renderer: Renderer2, @@ -222,7 +223,7 @@ export abstract class TbLatestChart { this.itemClick = itemClick; } - private updateSeriesData(initial = false) { + protected updateSeriesData(initial = false) { this.total = 0; this.totalText = 'N/A'; let hasValue = false; @@ -274,21 +275,14 @@ export abstract class TbLatestChart { appendTo: 'body', formatter: (params: CallbackDataParams) => this.settings.showTooltip - ? latestChartTooltipFormatter(this.renderer, this.settings, params, this.units, this.total) + ? latestChartTooltipFormatter(this.renderer, this.settings, params, this.units, this.total, this.dataItems) : undefined, padding: [4, 8], backgroundColor: this.settings.tooltipBackgroundColor, extraCssText: `line-height: 1; backdrop-filter: blur(${this.settings.tooltipBackgroundBlur}px);`, position: (pos) => [pos[0] + 10, pos[1] + 10] }, - animation: this.settings.animation.animation, - animationThreshold: this.settings.animation.animationThreshold, - animationDuration: this.settings.animation.animationDuration, - animationEasing: this.settings.animation.animationEasing, - animationDelay: this.settings.animation.animationDelay, - animationDurationUpdate: this.settings.animation.animationDurationUpdate, - animationEasingUpdate: this.settings.animation.animationEasingUpdate, - animationDelayUpdate: this.settings.animation.animationDelayUpdate + ...toAnimationOption(this.ctx, this.settings.animation) }; this.prepareLatestChartOption(); this.updateSeriesData(true); @@ -330,7 +324,12 @@ export abstract class TbLatestChart { if (width !== shapeWidth || height !== shapeHeight) { this.beforeResize(shapeWidth, shapeHeight); if (!this.settings.autoScale) { - this.latestChart.resize(); + if (this.forceRedrawOnResize()) { + this.latestChart.dispose(); + this.drawChart(); + } else { + this.latestChart.resize(); + } } else { let scale: number; if (shapeWidth < shapeHeight) { @@ -357,6 +356,10 @@ export abstract class TbLatestChart { return 100; } + protected forceRedrawOnResize(): boolean { + return false; + } + protected beforeResize(_shapeWidth: number, _shapeHeight: number) {}; protected afterResize(_shapeWidth: number, _shapeHeight: number) {}; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/pie-chart.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/pie-chart.ts index cfe003732e..5bd0c5bcf3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/pie-chart.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/pie-chart.ts @@ -24,6 +24,7 @@ import { Text } from '@svgdotjs/svg.js'; import { TranslateService } from '@ngx-translate/core'; import { TbLatestChart } from '@home/components/widget/lib/chart/latest-chart'; import { formatValue } from '@core/utils'; +import { toAnimationOption } from '@home/components/widget/lib/chart/chart.models'; const shapeSize = 134; const shapeSegmentWidth = 13.4; @@ -98,14 +99,7 @@ export class TbPieChart extends TbLatestChart { show: this.settings.showLabel } }, - animation: this.settings.animation.animation, - animationThreshold: this.settings.animation.animationThreshold, - animationDuration: this.settings.animation.animationDuration, - animationEasing: this.settings.animation.animationEasing, - animationDelay: this.settings.animation.animationDelay, - animationDurationUpdate: this.settings.animation.animationDurationUpdate, - animationEasingUpdate: this.settings.animation.animationEasingUpdate, - animationDelayUpdate: this.settings.animation.animationDelayUpdate + ...toAnimationOption(this.ctx, this.settings.animation) } ]; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart-widget.component.ts new file mode 100644 index 0000000000..2ae614fd03 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart-widget.component.ts @@ -0,0 +1,75 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, Input, OnInit, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core'; +import { WidgetContext } from '@home/models/widget-component.models'; +import { WidgetComponent } from '@home/components/widget/widget.component'; +import { TranslateService } from '@ngx-translate/core'; +import { + LatestChartComponent, + LatestChartComponentCallbacks +} from '@home/components/widget/lib/chart/latest-chart.component'; +import { + radarChartWidgetDefaultSettings, + radarChartWidgetRadarChartSettings, + RadarChartWidgetSettings +} from '@home/components/widget/lib/chart/radar-chart-widget.models'; +import { TbRadarChart } from '@home/components/widget/lib/chart/radar-chart'; + +@Component({ + selector: 'tb-radar-chart-widget', + templateUrl: './latest-chart-widget.component.html', + styleUrls: [], + encapsulation: ViewEncapsulation.None +}) +export class RadarChartWidgetComponent implements OnInit { + + @ViewChild('latestChart') + latestChart: LatestChartComponent; + + @Input() + ctx: WidgetContext; + + @Input() + widgetTitlePanel: TemplateRef; + + settings: RadarChartWidgetSettings; + + callbacks: LatestChartComponentCallbacks; + + constructor(private widgetComponent: WidgetComponent, + private translate: TranslateService) { + } + + ngOnInit(): void { + this.ctx.$scope.radarChartWidget = this; + this.settings = {...radarChartWidgetDefaultSettings, ...this.ctx.settings}; + this.callbacks = { + createChart: (chartShape, renderer) => { + const settings = radarChartWidgetRadarChartSettings(this.settings); + return new TbRadarChart(this.ctx, settings, chartShape.nativeElement, renderer, this.translate, true); + } + }; + } + + public onInit() { + this.latestChart?.onInit(); + } + + public onDataUpdated() { + this.latestChart?.onDataUpdated(); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart-widget.models.ts new file mode 100644 index 0000000000..78275264cc --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart-widget.models.ts @@ -0,0 +1,142 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + latestChartWidgetDefaultSettings, + LatestChartWidgetSettings +} from '@home/components/widget/lib/chart/latest-chart.models'; +import { + ChartAnimationSettings, + chartColorScheme, + ChartFillSettings, + ChartFillType, + ChartLabelPosition, + ChartLineType, + ChartShape +} from '@home/components/widget/lib/chart/chart.models'; +import { Font } from '@shared/models/widget-settings.models'; +import { mergeDeep } from '@core/utils'; +import { + radarChartAnimationDefaultSettings, + RadarChartSettings, + RadarChartShape +} from '@home/components/widget/lib/chart/radar-chart.models'; +import { DeepPartial } from '@shared/models/common'; + +export interface RadarChartWidgetSettings extends LatestChartWidgetSettings { + shape: RadarChartShape; + color: string; + showLine: boolean; + lineType: ChartLineType; + lineWidth: number; + showPoints: boolean; + pointShape: ChartShape; + pointSize: number; + showLabel: boolean; + labelPosition: ChartLabelPosition; + labelFont: Font; + labelColor: string; + fillAreaSettings: ChartFillSettings; + axisShowLabel: boolean; + axisLabelFont: Font; + axisShowTickLabels: boolean; + axisTickLabelFont: Font; + axisTickLabelColor: string; +} + +export const radarChartWidgetDefaultSettings: RadarChartWidgetSettings = { + ...latestChartWidgetDefaultSettings, + animation: mergeDeep({} as ChartAnimationSettings, + radarChartAnimationDefaultSettings), + shape: RadarChartShape.polygon, + color: '#3F52DD', + showLine: true, + lineType: ChartLineType.solid, + lineWidth: 2, + showPoints: true, + pointShape: ChartShape.circle, + pointSize: 4, + showLabel: false, + labelPosition: ChartLabelPosition.top, + labelFont: { + family: 'Roboto', + size: 11, + sizeUnit: 'px', + style: 'normal', + weight: '400', + lineHeight: '1' + }, + labelColor: chartColorScheme['series.label'].light, + fillAreaSettings: { + type: ChartFillType.none, + opacity: 0.4, + gradient: { + start: 80, + end: 20 + } + }, + axisShowLabel: true, + axisLabelFont: { + family: 'Roboto', + size: 12, + sizeUnit: 'px', + style: 'normal', + weight: '600', + lineHeight: '1' + }, + axisShowTickLabels: false, + axisTickLabelFont: { + family: 'Roboto', + size: 11, + sizeUnit: 'px', + style: 'normal', + weight: '400', + lineHeight: '1' + }, + axisTickLabelColor: chartColorScheme['axis.tickLabel'].light +}; + +export const radarChartWidgetRadarChartSettings = (settings: RadarChartWidgetSettings): DeepPartial => ({ + shape: settings.shape, + color: settings.color, + showLine: settings.showLine, + lineType: settings.lineType, + lineWidth: settings.lineWidth, + showPoints: settings.showPoints, + pointShape: settings.pointShape, + pointSize: settings.pointSize, + showLabel: settings.showLabel, + labelPosition: settings.labelPosition, + labelFont: settings.labelFont, + labelColor: settings.labelColor, + fillAreaSettings: settings.fillAreaSettings, + axisShowLabel: settings.axisShowLabel, + axisLabelFont: settings.axisLabelFont, + axisShowTickLabels: settings.axisShowTickLabels, + axisTickLabelFont: settings.axisTickLabelFont, + axisTickLabelColor: settings.axisTickLabelColor, + sortSeries: settings.sortSeries, + showTotal: false, + animation: settings.animation, + showLegend: settings.showLegend, + showTooltip: settings.showTooltip, + tooltipValueType: settings.tooltipValueType, + tooltipValueDecimals: settings.tooltipValueDecimals, + tooltipValueFont: settings.tooltipValueFont, + tooltipValueColor: settings.tooltipValueColor, + tooltipBackgroundColor: settings.tooltipBackgroundColor, + tooltipBackgroundBlur: settings.tooltipBackgroundBlur +}); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart.models.ts new file mode 100644 index 0000000000..6ec3b001e9 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart.models.ts @@ -0,0 +1,122 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { latestChartDefaultSettings, LatestChartSettings } from '@home/components/widget/lib/chart/latest-chart.models'; +import { + chartAnimationDefaultSettings, + ChartAnimationSettings, + chartColorScheme, + ChartFillSettings, + ChartFillType, + ChartLabelPosition, + ChartLineType, + ChartShape +} from '@home/components/widget/lib/chart/chart.models'; +import { Font } from '@shared/models/widget-settings.models'; +import { mergeDeep } from '@core/utils'; + +export enum RadarChartShape { + polygon = 'polygon', + circle = 'circle' +} + +export const radarChartShapes = Object.keys(RadarChartShape) as RadarChartShape[]; + +export const radarChartShapeTranslations = new Map( + [ + [RadarChartShape.polygon, 'widgets.radar-chart.shape-polygon'], + [RadarChartShape.circle, 'widgets.radar-chart.shape-circle'] + ] +); + +export interface RadarChartSettings extends LatestChartSettings { + shape: RadarChartShape; + color: string; + showLine: boolean; + lineType: ChartLineType; + lineWidth: number; + showPoints: boolean; + pointShape: ChartShape; + pointSize: number; + showLabel: boolean; + labelPosition: ChartLabelPosition; + labelFont: Font; + labelColor: string; + fillAreaSettings: ChartFillSettings; + axisShowLabel: boolean; + axisLabelFont: Font; + axisShowTickLabels: boolean; + axisTickLabelFont: Font; + axisTickLabelColor: string; +} + +export const radarChartAnimationDefaultSettings: ChartAnimationSettings = + mergeDeep({} as ChartAnimationSettings, chartAnimationDefaultSettings, { + animationDuration: 1000, + animationDurationUpdate: 500 + } as ChartAnimationSettings); + +export const radarChartDefaultSettings: RadarChartSettings = { + ...latestChartDefaultSettings, + animation: mergeDeep({} as ChartAnimationSettings, + radarChartAnimationDefaultSettings), + shape: RadarChartShape.polygon, + color: '#3F52DD', + showLine: true, + lineType: ChartLineType.solid, + lineWidth: 2, + showPoints: true, + pointShape: ChartShape.circle, + pointSize: 4, + showLabel: false, + labelPosition: ChartLabelPosition.top, + labelFont: { + family: 'Roboto', + size: 11, + sizeUnit: 'px', + style: 'normal', + weight: '400', + lineHeight: '1' + }, + labelColor: chartColorScheme['series.label'].light, + fillAreaSettings: { + type: ChartFillType.none, + opacity: 0.4, + gradient: { + start: 80, + end: 20 + } + }, + axisShowLabel: true, + axisLabelFont: { + family: 'Roboto', + size: 12, + sizeUnit: 'px', + style: 'normal', + weight: '600', + lineHeight: '1' + }, + axisShowTickLabels: false, + axisTickLabelFont: { + family: 'Roboto', + size: 11, + sizeUnit: 'px', + style: 'normal', + weight: '400', + lineHeight: '1' + }, + axisTickLabelColor: chartColorScheme['axis.tickLabel'].light +}; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart.ts new file mode 100644 index 0000000000..6b01e4d904 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/radar-chart.ts @@ -0,0 +1,172 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { TbLatestChart } from '@home/components/widget/lib/chart/latest-chart'; +import { radarChartDefaultSettings, RadarChartSettings } from '@home/components/widget/lib/chart/radar-chart.models'; +import { WidgetContext } from '@home/models/widget-component.models'; +import { DeepPartial } from '@shared/models/common'; +import { Renderer2 } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { + ChartFillType, + createChartTextStyle, + createLinearOpacityGradient, createRadialOpacityGradient, toAnimationOption +} from '@home/components/widget/lib/chart/chart.models'; +import { formatValue, isDefinedAndNotNull, isEqual } from '@core/utils'; +import { ComponentStyle } from '@shared/models/widget-settings.models'; +import { AreaStyleOption, SeriesLabelOption } from 'echarts/types/src/util/types'; +import { RadarIndicatorOption } from 'echarts/types/src/coord/radar/RadarModel'; +import { DataKey } from '@shared/models/widget.models'; + +export class TbRadarChart extends TbLatestChart { + + constructor(ctx: WidgetContext, + inputSettings: DeepPartial, + chartElement: HTMLElement, + renderer: Renderer2, + translate: TranslateService, + autoResize = true) { + + super(ctx, inputSettings, chartElement, renderer, translate, autoResize); + } + + protected defaultSettings(): RadarChartSettings { + return radarChartDefaultSettings; + } + + protected prepareLatestChartOption() { + + const axisNameStyle = createChartTextStyle(this.settings.axisLabelFont, + '#000', false, 'axis.label'); + const axisTickLabelStyle = createChartTextStyle(this.settings.axisTickLabelFont, + this.settings.axisTickLabelColor, false, 'axis.tickLabel'); + + this.latestChartOption.radar = [{ + shape: this.settings.shape, + radius: '85%', + indicator: [{}], + axisName: { + show: this.settings.axisShowLabel, + fontStyle: axisNameStyle.fontStyle, + fontWeight: axisNameStyle.fontWeight, + fontFamily: axisNameStyle.fontFamily, + fontSize: axisNameStyle.fontSize + }, + axisLabel: { + show: this.settings.axisShowTickLabels, + color: axisTickLabelStyle.color, + fontStyle: axisTickLabelStyle.fontStyle, + fontWeight: axisTickLabelStyle.fontWeight, + fontFamily: axisTickLabelStyle.fontFamily, + fontSize: axisTickLabelStyle.fontSize, + formatter: (value: any) => formatValue(value, this.decimals, this.units, false) + } + }]; + + let labelStyle: ComponentStyle = {}; + if (this.settings.showLabel) { + labelStyle = createChartTextStyle(this.settings.labelFont, this.settings.labelColor, false, 'series.label'); + } + + const labelOption: SeriesLabelOption = { + show: this.settings.showLabel, + position: this.settings.labelPosition, + formatter: (params) => { + let result = ''; + if (isDefinedAndNotNull(params.value)) { + result = formatValue(params.value, this.decimals, this.units, false); + } + return `{value|${result}}`; + }, + rich: { + value: labelStyle + } + }; + + let areaStyleOption: AreaStyleOption; + if (this.settings.fillAreaSettings.type !== ChartFillType.none) { + areaStyleOption = {}; + if (this.settings.fillAreaSettings.type === ChartFillType.opacity) { + areaStyleOption.opacity = this.settings.fillAreaSettings.opacity; + } else if (this.settings.fillAreaSettings.type === ChartFillType.gradient) { + areaStyleOption.opacity = 1; + areaStyleOption.color = createRadialOpacityGradient(this.settings.color, this.settings.fillAreaSettings.gradient); + } + } + + this.latestChartOption.series = [ + { + type: 'radar', + data: [{ + id: 1, + itemStyle: { + color: this.settings.color + }, + label: labelOption, + symbol: this.settings.showPoints ? this.settings.pointShape : 'none', + symbolSize: this.settings.pointSize, + lineStyle: { + width: this.settings.showLine ? this.settings.lineWidth : 0, + type: this.settings.lineType + }, + areaStyle: areaStyleOption, + value: [] + }], + emphasis: { + focus: 'self' + }, + ...toAnimationOption(this.ctx, this.settings.animation) + } + ]; + } + + protected doUpdateSeriesData() { + const indicator: RadarIndicatorOption[] = []; + const value: number[] = []; + for (const dataItem of this.dataItems) { + if (dataItem.enabled && dataItem.hasValue) { + indicator.push({ + name: dataItem.dataKey.label, + color: dataItem.dataKey.color + }); + value.push(dataItem.value); + } + } + if (!indicator.length) { + indicator.push({}); + } + this.latestChartOption.radar[0].indicator = indicator; + this.latestChartOption.series[0].data[0].value = value; + } + + protected forceRedrawOnResize(): boolean { + return true; + } + + public keyEnter(dataKey: DataKey): void {} + + public keyLeave(dataKey: DataKey): void {} + + public toggleKey(dataKey: DataKey): void { + const enable = dataKey.hidden; + const dataItem = this.dataItems.find(d => d.dataKey === dataKey); + if (dataItem) { + dataItem.enabled = enable; + this.updateSeriesData(); + dataKey.hidden = !enable; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.models.ts index 45252bd7f6..be6be1bc1b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.models.ts @@ -33,7 +33,6 @@ import { timeSeriesChartGridDefaultSettings, TimeSeriesChartGridSettings, TimeSeriesChartKeySettings, - TimeSeriesChartLineType, TimeSeriesChartSeriesType, TimeSeriesChartSettings, TimeSeriesChartThreshold, @@ -51,7 +50,7 @@ import { ChartAnimationSettings, chartColorScheme, ChartFillType, - ChartLabelPosition, + ChartLabelPosition, ChartLineType, ChartShape } from '@home/components/widget/lib/chart/chart.models'; @@ -78,7 +77,7 @@ export interface RangeChartWidgetSettings extends TimeSeriesChartTooltipWidgetSe step: boolean; stepType: LineSeriesStepType; smooth: boolean; - lineType: TimeSeriesChartLineType; + lineType: ChartLineType; lineWidth: number; showPoints: boolean; showPointLabel: boolean; @@ -118,7 +117,7 @@ export const rangeChartDefaultSettings: RangeChartWidgetSettings = { rangeThreshold: mergeDeep({} as Partial, timeSeriesChartThresholdDefaultSettings, { lineColor: '#37383b', - lineType: TimeSeriesChartLineType.dashed, + lineType: ChartLineType.dashed, startSymbol: ChartShape.circle, startSymbolSize: 5, endSymbol: ChartShape.arrow, @@ -132,7 +131,7 @@ export const rangeChartDefaultSettings: RangeChartWidgetSettings = { step: false, stepType: LineSeriesStepType.start, smooth: false, - lineType: TimeSeriesChartLineType.solid, + lineType: ChartLineType.solid, lineWidth: 2, showPoints: false, showPointLabel: false, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts index a906fe0bed..e2792c1793 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts @@ -88,7 +88,7 @@ import { chartColorScheme, ChartFillSettings, ChartFillType, - ChartLabelPosition, + ChartLabelPosition, ChartLineType, ChartShape, createChartTextStyle, createLinearOpacityGradient, @@ -488,22 +488,6 @@ export const timeSeriesAxisPositionTranslations = new Map( ] ); -export enum TimeSeriesChartLineType { - solid = 'solid', - dashed = 'dashed', - dotted = 'dotted' -} - -export const timeSeriesLineTypes = Object.keys(TimeSeriesChartLineType) as TimeSeriesChartLineType[]; - -export const timeSeriesLineTypeTranslations = new Map( - [ - [TimeSeriesChartLineType.solid, 'widgets.time-series-chart.line-type-solid'], - [TimeSeriesChartLineType.dashed, 'widgets.time-series-chart.line-type-dashed'], - [TimeSeriesChartLineType.dotted, 'widgets.time-series-chart.line-type-dotted'] - ] -); - export enum ThresholdLabelPosition { start = 'start', middle = 'middle', @@ -765,7 +749,7 @@ export interface TimeSeriesChartThreshold { units?: string; decimals?: number; lineColor: string; - lineType: TimeSeriesChartLineType | number | number[]; + lineType: ChartLineType | number | number[]; lineWidth: number; startSymbol: ChartShape; startSymbolSize: number; @@ -820,7 +804,7 @@ export const timeSeriesChartThresholdDefaultSettings: TimeSeriesChartThreshold = units: null, decimals: 0, lineColor: chartColorScheme['threshold.line'].light, - lineType: TimeSeriesChartLineType.solid, + lineType: ChartLineType.solid, lineWidth: 1, startSymbol: ChartShape.none, startSymbolSize: 5, @@ -1055,7 +1039,7 @@ export interface LineSeriesSettings { step: boolean; stepType: LineSeriesStepType; smooth: boolean; - lineType: TimeSeriesChartLineType; + lineType: ChartLineType; lineWidth: number; showPoints: boolean; showPointLabel: boolean; @@ -1090,7 +1074,7 @@ export const timeSeriesChartKeyDefaultSettings: TimeSeriesChartKeySettings = { step: false, stepType: LineSeriesStepType.start, smooth: false, - lineType: TimeSeriesChartLineType.solid, + lineType: ChartLineType.solid, lineWidth: 2, showPoints: false, showPointLabel: false, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts index e1d9ca2324..86cf42de0c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts @@ -74,7 +74,7 @@ import { DataKeySettingsFunction } from '@home/components/widget/config/data-key import { DeepPartial } from '@shared/models/common'; import { BarRenderSharedContext } from '@home/components/widget/lib/chart/time-series-chart-bar.models'; import { TimeSeriesChartStateValueConverter } from '@home/components/widget/lib/chart/time-series-chart-state.models'; -import { ChartLabelPosition, ChartShape } from '@home/components/widget/lib/chart/chart.models'; +import { ChartLabelPosition, ChartShape, toAnimationOption } from '@home/components/widget/lib/chart/chart.models'; export class TbTimeSeriesChart { @@ -640,14 +640,7 @@ export class TbTimeSeriesChart { bottom: 10 } ], - animation: this.settings.animation.animation, - animationThreshold: this.settings.animation.animationThreshold, - animationDuration: this.settings.animation.animationDuration, - animationEasing: this.settings.animation.animationEasing, - animationDelay: this.settings.animation.animationDelay, - animationDurationUpdate: this.settings.animation.animationDurationUpdate, - animationEasingUpdate: this.settings.animation.animationEasingUpdate, - animationDelayUpdate: this.settings.animation.animationDelayUpdate + ...toAnimationOption(this.ctx, this.settings.animation) }; if (this.hasVisualMap) { this.timeSeriesChartOptions.visualMap = diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/radar-chart-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/radar-chart-widget-settings.component.html new file mode 100644 index 0000000000..33c0dc1173 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/radar-chart-widget-settings.component.html @@ -0,0 +1,248 @@ + + +
+
widgets.radar-chart.radar-chart-style
+
+ + {{ 'widgets.latest-chart.sort-series' | translate }} + +
+
+
widgets.radar-chart.radar-appearance
+
+
{{ 'widgets.radar-chart.shape' | translate }}
+ + + + {{ radarChartShapeTranslations.get(shape) | translate }} + + + +
+
+
widgets.radar-chart.color
+ + +
+
+ + {{ 'widgets.radar-chart.line' | translate }} + +
+ + + + {{ chartLineTypeTranslations.get(type) | translate }} + + + + + + +
+
+
+ + {{ 'widgets.radar-chart.points' | translate }} + +
+ + + + {{ chartShapeTranslations.get(shape) | translate }} + + + + + + +
+
+
+ + {{ 'widgets.radar-chart.points-label' | translate }} + +
+ + + + {{ chartLabelPositionTranslations.get(position) | translate }} + + + + + + + +
+
+ + +
+
+
widgets.radar-chart.radar-axis
+
+ + {{ 'widgets.radar-chart.axis-label' | translate }} + + + +
+
+ + {{ 'widgets.radar-chart.ticks-label' | translate }} + +
+ + + + +
+
+
+
+ + + + + {{ 'widget-config.legend' | translate }} + + + + +
+
{{ 'legend.position' | translate }}
+ + + + {{ legendPositionTranslationMap.get(pos) | translate }} + + + +
+
+
{{ 'legend.label' | translate }}
+
+ + + + +
+
+
+
{{ 'legend.value' | translate }}
+
+ + + + +
+
+
+
+
+
+ + + + + {{ 'widget-config.tooltip' | translate }} + + + + +
+
{{ 'tooltip.value' | translate }}
+
+ + + + {{ latestChartTooltipValueTypeTranslationMap.get(type) | translate }} + + + + + +
widget-config.decimals-suffix
+
+ + + + +
+
+
+
{{ 'tooltip.background-color' | translate }}
+ + +
+
+
{{ 'tooltip.background-blur' | translate }}
+ + +
px
+
+
+
+
+
+ + +
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/radar-chart-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/radar-chart-widget-settings.component.ts new file mode 100644 index 0000000000..a4900aa51b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/radar-chart-widget-settings.component.ts @@ -0,0 +1,244 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component } from '@angular/core'; +import { + legendPositions, + legendPositionTranslationMap, + WidgetSettings, + WidgetSettingsComponent +} from '@shared/models/widget.models'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { formatValue, mergeDeep } from '@core/utils'; +import { + LatestChartTooltipValueType, + latestChartTooltipValueTypes, + latestChartTooltipValueTypeTranslations +} from '@home/components/widget/lib/chart/latest-chart.models'; +import { + radarChartWidgetDefaultSettings, + RadarChartWidgetSettings +} from '@home/components/widget/lib/chart/radar-chart-widget.models'; +import { radarChartShapes, radarChartShapeTranslations } from '@home/components/widget/lib/chart/radar-chart.models'; +import { + chartLabelPositions, + chartLabelPositionTranslations, + chartLineTypes, + chartLineTypeTranslations, + chartShapes, + chartShapeTranslations +} from '@home/components/widget/lib/chart/chart.models'; + +@Component({ + selector: 'tb-radar-chart-widget-settings', + templateUrl: './radar-chart-widget-settings.component.html', + styleUrls: [] +}) +export class RadarChartWidgetSettingsComponent extends WidgetSettingsComponent { + + radarChartShapes = radarChartShapes; + + radarChartShapeTranslations = radarChartShapeTranslations; + + chartLineTypes = chartLineTypes; + + chartLineTypeTranslations = chartLineTypeTranslations; + + chartShapes = chartShapes; + + chartShapeTranslations = chartShapeTranslations; + + chartLabelPositions = chartLabelPositions; + + chartLabelPositionTranslations = chartLabelPositionTranslations; + + legendPositions = legendPositions; + + legendPositionTranslationMap = legendPositionTranslationMap; + + latestChartTooltipValueTypes = latestChartTooltipValueTypes; + + latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations; + + radarChartWidgetSettingsForm: UntypedFormGroup; + + valuePreviewFn = this._valuePreviewFn.bind(this); + + tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this); + + constructor(protected store: Store, + private fb: UntypedFormBuilder) { + super(store); + } + + protected settingsForm(): UntypedFormGroup { + return this.radarChartWidgetSettingsForm; + } + + protected defaultSettings(): WidgetSettings { + return mergeDeep({} as RadarChartWidgetSettings, radarChartWidgetDefaultSettings); + } + + protected onSettingsSet(settings: WidgetSettings) { + this.radarChartWidgetSettingsForm = this.fb.group({ + + sortSeries: [settings.sortSeries, []], + + shape: [settings.shape, []], + color: [settings.color, []], + showLine: [settings.showLine, []], + lineType: [settings.lineType, []], + lineWidth: [settings.lineWidth, [Validators.min(0)]], + showPoints: [settings.showPoints, []], + pointShape: [settings.pointShape, []], + pointSize: [settings.pointSize, [Validators.min(0)]], + showLabel: [settings.showLabel, []], + labelPosition: [settings.labelPosition, []], + labelFont: [settings.labelFont, []], + labelColor: [settings.labelColor, []], + fillAreaSettings: [settings.fillAreaSettings, []], + + axisShowLabel: [settings.axisShowLabel, []], + axisLabelFont: [settings.axisLabelFont, []], + axisShowTickLabels: [settings.axisShowTickLabels, []], + axisTickLabelFont: [settings.axisTickLabelFont, []], + axisTickLabelColor: [settings.axisTickLabelColor, []], + + animation: [settings.animation, []], + + showLegend: [settings.showLegend, []], + legendPosition: [settings.legendPosition, []], + legendLabelFont: [settings.legendLabelFont, []], + legendLabelColor: [settings.legendLabelColor, []], + legendValueFont: [settings.legendValueFont, []], + legendValueColor: [settings.legendValueColor, []], + + showTooltip: [settings.showTooltip, []], + tooltipValueType: [settings.tooltipValueType, []], + tooltipValueDecimals: [settings.tooltipValueDecimals, []], + tooltipValueFont: [settings.tooltipValueFont, []], + tooltipValueColor: [settings.tooltipValueColor, []], + tooltipBackgroundColor: [settings.tooltipBackgroundColor, []], + tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []], + + background: [settings.background, []] + }); + } + + protected validatorTriggers(): string[] { + return ['showLine', 'showPoints', 'showLabel', 'axisShowLabel', + 'axisShowTickLabels', 'showLegend', 'showTooltip']; + } + + protected updateValidators(emitEvent: boolean) { + const showLine: boolean = this.radarChartWidgetSettingsForm.get('showLine').value; + const showPoints: boolean = this.radarChartWidgetSettingsForm.get('showPoints').value; + const showLabel: boolean = this.radarChartWidgetSettingsForm.get('showLabel').value; + const axisShowLabel: boolean = this.radarChartWidgetSettingsForm.get('axisShowLabel').value; + const axisShowTickLabels: boolean = this.radarChartWidgetSettingsForm.get('axisShowTickLabels').value; + const showLegend: boolean = this.radarChartWidgetSettingsForm.get('showLegend').value; + const showTooltip: boolean = this.radarChartWidgetSettingsForm.get('showTooltip').value; + + if (showLine) { + this.radarChartWidgetSettingsForm.get('lineType').enable(); + this.radarChartWidgetSettingsForm.get('lineWidth').enable(); + } else { + this.radarChartWidgetSettingsForm.get('lineType').disable(); + this.radarChartWidgetSettingsForm.get('lineWidth').disable(); + } + + if (showPoints) { + this.radarChartWidgetSettingsForm.get('pointShape').enable(); + this.radarChartWidgetSettingsForm.get('pointSize').enable(); + } else { + this.radarChartWidgetSettingsForm.get('pointShape').disable(); + this.radarChartWidgetSettingsForm.get('pointSize').disable(); + } + + if (showLabel) { + this.radarChartWidgetSettingsForm.get('labelPosition').enable(); + this.radarChartWidgetSettingsForm.get('labelFont').enable(); + this.radarChartWidgetSettingsForm.get('labelColor').enable(); + } else { + this.radarChartWidgetSettingsForm.get('labelPosition').disable(); + this.radarChartWidgetSettingsForm.get('labelFont').disable(); + this.radarChartWidgetSettingsForm.get('labelColor').disable(); + } + + if (axisShowLabel) { + this.radarChartWidgetSettingsForm.get('axisLabelFont').enable(); + } else { + this.radarChartWidgetSettingsForm.get('axisLabelFont').disable(); + } + + if (axisShowTickLabels) { + this.radarChartWidgetSettingsForm.get('axisTickLabelFont').enable(); + this.radarChartWidgetSettingsForm.get('axisTickLabelColor').enable(); + } else { + this.radarChartWidgetSettingsForm.get('axisTickLabelFont').disable(); + this.radarChartWidgetSettingsForm.get('axisTickLabelColor').disable(); + } + + if (showLegend) { + this.radarChartWidgetSettingsForm.get('legendPosition').enable(); + this.radarChartWidgetSettingsForm.get('legendLabelFont').enable(); + this.radarChartWidgetSettingsForm.get('legendLabelColor').enable(); + this.radarChartWidgetSettingsForm.get('legendValueFont').enable(); + this.radarChartWidgetSettingsForm.get('legendValueColor').enable(); + } else { + this.radarChartWidgetSettingsForm.get('legendPosition').disable(); + this.radarChartWidgetSettingsForm.get('legendLabelFont').disable(); + this.radarChartWidgetSettingsForm.get('legendLabelColor').disable(); + this.radarChartWidgetSettingsForm.get('legendValueFont').disable(); + this.radarChartWidgetSettingsForm.get('legendValueColor').disable(); + } + if (showTooltip) { + this.radarChartWidgetSettingsForm.get('tooltipValueType').enable(); + this.radarChartWidgetSettingsForm.get('tooltipValueDecimals').enable(); + this.radarChartWidgetSettingsForm.get('tooltipValueFont').enable(); + this.radarChartWidgetSettingsForm.get('tooltipValueColor').enable(); + this.radarChartWidgetSettingsForm.get('tooltipBackgroundColor').enable(); + this.radarChartWidgetSettingsForm.get('tooltipBackgroundBlur').enable(); + } else { + this.radarChartWidgetSettingsForm.get('tooltipValueType').disable(); + this.radarChartWidgetSettingsForm.get('tooltipValueDecimals').disable(); + this.radarChartWidgetSettingsForm.get('tooltipValueFont').disable(); + this.radarChartWidgetSettingsForm.get('tooltipValueColor').disable(); + this.radarChartWidgetSettingsForm.get('tooltipBackgroundColor').disable(); + this.radarChartWidgetSettingsForm.get('tooltipBackgroundBlur').disable(); + } + } + + private _valuePreviewFn(): string { + const units: string = this.widgetConfig.config.units; + const decimals: number = this.widgetConfig.config.decimals; + return formatValue(110, decimals, units, false); + } + + private _tooltipValuePreviewFn(): string { + const tooltipValueType: LatestChartTooltipValueType = this.radarChartWidgetSettingsForm.get('tooltipValueType').value; + const decimals: number = this.radarChartWidgetSettingsForm.get('tooltipValueDecimals').value; + if (tooltipValueType === LatestChartTooltipValueType.percentage) { + return formatValue(35, decimals, '%', false); + } else { + const units: string = this.widgetConfig.config.units; + return formatValue(110, decimals, units, false); + } + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.html index 87bbe59e1f..a7ced000bf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.html @@ -92,8 +92,8 @@
widgets.time-series-chart.line-type
- - {{ timeSeriesLineTypeTranslations.get(lineType) | translate }} + + {{ chartLineTypeTranslations.get(lineType) | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts index 895fc6888a..2dd34a10d7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts @@ -33,11 +33,16 @@ import { import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-settings.models'; import { lineSeriesStepTypes, - lineSeriesStepTypeTranslations, - timeSeriesLineTypes, - timeSeriesLineTypeTranslations + lineSeriesStepTypeTranslations } from '@home/components/widget/lib/chart/time-series-chart.models'; -import { chartLabelPositions, chartLabelPositionTranslations, chartShapes, chartShapeTranslations } from '@home/components/widget/lib/chart/chart.models'; +import { + chartLabelPositions, + chartLabelPositionTranslations, + chartLineTypes, + chartLineTypeTranslations, + chartShapes, + chartShapeTranslations +} from '@home/components/widget/lib/chart/chart.models'; @Component({ selector: 'tb-range-chart-widget-settings', @@ -59,9 +64,9 @@ export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent { lineSeriesStepTypeTranslations = lineSeriesStepTypeTranslations; - timeSeriesLineTypes = timeSeriesLineTypes; + chartLineTypes = chartLineTypes; - timeSeriesLineTypeTranslations = timeSeriesLineTypeTranslations; + chartLineTypeTranslations = chartLineTypeTranslations; chartLabelPositions = chartLabelPositions; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.html index 906c4148a2..e71113cdbf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.html @@ -44,8 +44,8 @@
widgets.time-series-chart.line-type
- - {{ timeSeriesLineTypeTranslations.get(lineType) | translate }} + + {{ chartLineTypeTranslations.get(lineType) | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts index 4e970a5198..2f0ca0197a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts @@ -26,9 +26,7 @@ import { LineSeriesSettings, lineSeriesStepTypes, lineSeriesStepTypeTranslations, - TimeSeriesChartType, - timeSeriesLineTypes, - timeSeriesLineTypeTranslations + TimeSeriesChartType } from '@home/components/widget/lib/chart/time-series-chart.models'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -38,6 +36,8 @@ import { DataKeyConfigComponent } from '@home/components/widget/config/data-key- import { chartLabelPositions, chartLabelPositionTranslations, + chartLineTypes, + chartLineTypeTranslations, chartShapes, chartShapeTranslations } from '@home/components/widget/lib/chart/chart.models'; @@ -62,9 +62,9 @@ export class TimeSeriesChartLineSettingsComponent implements OnInit, ControlValu lineSeriesStepTypeTranslations = lineSeriesStepTypeTranslations; - timeSeriesLineTypes = timeSeriesLineTypes; + chartLineTypes = chartLineTypes; - timeSeriesLineTypeTranslations = timeSeriesLineTypeTranslations; + chartLineTypeTranslations = chartLineTypeTranslations; chartLabelPositions = chartLabelPositions; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.html index 293952a342..196097e9e5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.html @@ -86,8 +86,8 @@
widgets.time-series-chart.line-type
- - {{ timeSeriesLineTypeTranslations.get(lineType) | translate }} + + {{ chartLineTypeTranslations.get(lineType) | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.ts index e868e1f2e9..eb0a2d79c8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.ts @@ -20,8 +20,6 @@ import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms import { TimeSeriesChartThreshold, TimeSeriesChartYAxisId, - timeSeriesLineTypes, - timeSeriesLineTypeTranslations, timeSeriesThresholdLabelPositions, timeSeriesThresholdLabelPositionTranslations } from '@home/components/widget/lib/chart/time-series-chart.models'; @@ -29,7 +27,12 @@ import { merge } from 'rxjs'; import { WidgetConfig } from '@shared/models/widget.models'; import { formatValue, isDefinedAndNotNull } from '@core/utils'; import { coerceBoolean } from '@shared/decorators/coercion'; -import { ChartShape, chartShapes, chartShapeTranslations } from '@home/components/widget/lib/chart/chart.models'; +import { + chartLineTypes, chartLineTypeTranslations, + ChartShape, + chartShapes, + chartShapeTranslations +} from '@home/components/widget/lib/chart/chart.models'; @Component({ selector: 'tb-time-series-chart-threshold-settings-panel', @@ -40,9 +43,9 @@ import { ChartShape, chartShapes, chartShapeTranslations } from '@home/component }) export class TimeSeriesChartThresholdSettingsPanelComponent implements OnInit { - timeSeriesLineTypes = timeSeriesLineTypes; + chartLineTypes = chartLineTypes; - timeSeriesLineTypeTranslations = timeSeriesLineTypeTranslations; + chartLineTypeTranslations = chartLineTypeTranslations; chartShapes = chartShapes; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts index db0973a5bc..c71f0fd658 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts @@ -351,6 +351,9 @@ import { import { PolarAreaChartWidgetSettingsComponent } from '@home/components/widget/lib/settings/chart/polar-area-chart-widget-settings.component'; +import { + RadarChartWidgetSettingsComponent +} from '@home/components/widget/lib/settings/chart/radar-chart-widget-settings.component'; @NgModule({ declarations: [ @@ -476,7 +479,8 @@ import { StatusWidgetSettingsComponent, PieChartWidgetSettingsComponent, BarChartWidgetSettingsComponent, - PolarAreaChartWidgetSettingsComponent + PolarAreaChartWidgetSettingsComponent, + RadarChartWidgetSettingsComponent ], imports: [ CommonModule, @@ -607,7 +611,8 @@ import { StatusWidgetSettingsComponent, PieChartWidgetSettingsComponent, BarChartWidgetSettingsComponent, - PolarAreaChartWidgetSettingsComponent + PolarAreaChartWidgetSettingsComponent, + RadarChartWidgetSettingsComponent ] }) export class WidgetSettingsModule { @@ -704,5 +709,6 @@ export const widgetSettingsComponentsMap: {[key: string]: Type