Browse Source

Merge pull request #9485 from ArtemDzhereleiko/AD/imp/settings/radial-gauge

Improvement for gauge widgets settings
pull/9548/head
Igor Kulikov 3 years ago
committed by GitHub
parent
commit
26f99d54e0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      application/src/main/data/json/system/widget_types/compass.json
  2. 8
      application/src/main/data/json/system/widget_types/radial_gauge.json
  3. 8
      application/src/main/data/json/system/widget_types/speed_gauge.json
  4. 8
      application/src/main/data/json/system/widget_types/temperature_radial_gauge.json
  5. 8
      application/src/main/data/json/system/widget_types/thermometer_scale.json
  6. 18
      ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts
  7. 182
      ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/analog-gauge-basic-config.component.html
  8. 187
      ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/analog-gauge-basic-config.component.ts
  9. 154
      ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/compass-gauge-basic-config.component.html
  10. 171
      ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/compass-gauge-basic-config.component.ts
  11. 45
      ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/radial-gauge-basic-config.component.ts
  12. 59
      ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/thermometer-scale-gauge-basic-config.component.ts
  13. 2
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html
  14. 291
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-compass-widget-settings.component.html
  15. 42
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-compass-widget-settings.component.ts
  16. 614
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-gauge-widget-settings.component.html
  17. 70
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-gauge-widget-settings.component.ts
  18. 61
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.html
  19. 40
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.scss
  20. 116
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.ts
  21. 3
      ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts
  22. 39
      ui-ngx/src/assets/locale/locale.constant-en_US.json

8
application/src/main/data/json/system/widget_types/compass.json

@ -11,11 +11,11 @@
"resources": [],
"templateHtml": "<canvas id=\"compass\"></canvas>",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.gauge = new TbAnalogueCompass(self.ctx, 'compass');\n}\n\nself.onDataUpdated = function() {\n self.ctx.gauge.update();\n}\n\nself.onResize = function() {\n self.ctx.gauge.resize();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.gauge.mobileModeChanged();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true\n };\n}\n\nself.onDestroy = function() {\n self.ctx.gauge.destroy();\n}\n",
"settingsSchema": "{}",
"controllerScript": "self.onInit = function() {\n self.ctx.gauge = new TbAnalogueCompass(self.ctx, 'compass');\n}\n\nself.onDataUpdated = function() {\n self.ctx.gauge.update();\n}\n\nself.onResize = function() {\n self.ctx.gauge.resize();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.gauge.mobileModeChanged();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'direction', label: 'Direction', type: 'timeseries' }];\n }\n };\n}\n\nself.onDestroy = function() {\n self.ctx.gauge.destroy();\n}\n", "settingsSchema": "{}",
"dataKeySettingsSchema": "{}\n",
"settingsDirective": "tb-analogue-compass-widget-settings",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"minorTicks\":22,\"needleCircleSize\":15,\"showBorder\":true,\"borderOuterWidth\":10,\"colorPlate\":\"#222\",\"colorMajorTicks\":\"#f5f5f5\",\"colorMinorTicks\":\"#ddd\",\"colorNeedle\":\"#f08080\",\"colorNeedleCircle\":\"#e8e8e8\",\"colorBorder\":\"#ccc\",\"majorTickFont\":{\"family\":\"Roboto\",\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#ccc\"},\"animation\":true,\"animationDuration\":500,\"animationRule\":\"cycle\",\"animationTarget\":\"needle\",\"majorTicks\":[\"N\",\"NE\",\"E\",\"SE\",\"S\",\"SW\",\"W\",\"NW\"]},\"title\":\"Compass\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\"}"
},
"hasBasicMode": true,
"basicModeDirective": "tb-compass-gauge-basic-config",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"minorTicks\":22,\"needleCircleSize\":15,\"showBorder\":true,\"borderOuterWidth\":10,\"colorPlate\":\"#222\",\"colorMajorTicks\":\"#f5f5f5\",\"colorMinorTicks\":\"#ddd\",\"colorNeedle\":\"#f08080\",\"colorNeedleCircle\":\"#e8e8e8\",\"colorBorder\":\"#ccc\",\"majorTickFont\":{\"family\":\"Roboto\",\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#ccc\"},\"animation\":true,\"animationDuration\":500,\"animationRule\":\"cycle\",\"animationTarget\":\"needle\",\"majorTicks\":[\"N\",\"NE\",\"E\",\"SE\",\"S\",\"SW\",\"W\",\"NW\"]},\"title\":\"Compass\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\",\"configMode\":\"basic\"}" },
"externalId": null
}

8
application/src/main/data/json/system/widget_types/radial_gauge.json

@ -11,11 +11,11 @@
"resources": [],
"templateHtml": "<canvas id=\"radialGauge\"></canvas>\n",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.gauge = new TbAnalogueRadialGauge(self.ctx, 'radialGauge'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.gauge.update();\n}\n\nself.onResize = function() {\n self.ctx.gauge.resize();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.gauge.mobileModeChanged();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true\n };\n}\n\nself.onDestroy = function() {\n self.ctx.gauge.destroy();\n}\n",
"settingsSchema": "{}",
"controllerScript": "self.onInit = function() {\n self.ctx.gauge = new TbAnalogueRadialGauge(self.ctx, 'radialGauge'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.gauge.update();\n}\n\nself.onResize = function() {\n self.ctx.gauge.resize();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.gauge.mobileModeChanged();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'temperature', label: 'Temperature', type: 'timeseries' }];\n }\n };\n}\n\nself.onDestroy = function() {\n self.ctx.gauge.destroy();\n}\n", "settingsSchema": "{}",
"dataKeySettingsSchema": "{}\n",
"settingsDirective": "tb-analogue-radial-gauge-widget-settings",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temp\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7282710489093589,\"funcBody\":\"var value = prevValue + Math.random() * 50 - 25;\\nif (value < -100) {\\n\\tvalue = -100;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"maxValue\":100,\"startAngle\":45,\"ticksAngle\":270,\"showBorder\":true,\"defaultColor\":\"#e65100\",\"needleCircleSize\":10,\"highlights\":[],\"showUnitTitle\":true,\"colorPlate\":\"#fff\",\"colorMajorTicks\":\"#444\",\"colorMinorTicks\":\"#666\",\"minorTicks\":10,\"valueInt\":3,\"valueDec\":0,\"highlightsWidth\":15,\"valueBox\":true,\"animation\":true,\"animationDuration\":500,\"animationRule\":\"cycle\",\"colorNeedleShadowUp\":\"rgba(2, 255, 255, 0)\",\"numbersFont\":{\"family\":\"Roboto\",\"size\":18,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"titleFont\":{\"family\":\"Roboto\",\"size\":24,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#888\"},\"unitsFont\":{\"family\":\"Roboto\",\"size\":22,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"valueFont\":{\"family\":\"Segment7Standard\",\"size\":36,\"style\":\"normal\",\"weight\":\"normal\",\"shadowColor\":\"rgba(0, 0, 0, 0.49)\",\"color\":\"#444\"},\"minValue\":-100,\"colorNeedleShadowDown\":\"rgba(188,143,143,0.45)\",\"colorValueBoxRect\":\"#888\",\"colorValueBoxRectEnd\":\"#666\",\"colorValueBoxBackground\":\"#babab2\",\"colorValueBoxShadow\":\"rgba(0,0,0,1)\"},\"title\":\"Radial gauge\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\"}"
},
"hasBasicMode": true,
"basicModeDirective": "tb-radial-gauge-basic-config",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temp\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7282710489093589,\"funcBody\":\"var value = prevValue + Math.random() * 50 - 25;\\nif (value < -100) {\\n\\tvalue = -100;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"maxValue\":100,\"startAngle\":45,\"ticksAngle\":270,\"showBorder\":true,\"defaultColor\":\"#e65100\",\"needleCircleSize\":10,\"highlights\":[],\"showUnitTitle\":true,\"colorPlate\":\"#fff\",\"colorMajorTicks\":\"#444\",\"colorMinorTicks\":\"#666\",\"minorTicks\":10,\"valueInt\":3,\"valueDec\":0,\"highlightsWidth\":15,\"valueBox\":true,\"animation\":true,\"animationDuration\":500,\"animationRule\":\"cycle\",\"colorNeedleShadowUp\":\"rgba(2, 255, 255, 0)\",\"numbersFont\":{\"family\":\"Roboto\",\"size\":18,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"titleFont\":{\"family\":\"Roboto\",\"size\":24,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#888\"},\"unitsFont\":{\"family\":\"Roboto\",\"size\":22,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"valueFont\":{\"family\":\"Segment7Standard\",\"size\":36,\"style\":\"normal\",\"weight\":\"normal\",\"shadowColor\":\"rgba(0, 0, 0, 0.49)\",\"color\":\"#444\"},\"minValue\":-100,\"colorNeedleShadowDown\":\"rgba(188,143,143,0.45)\",\"colorValueBoxRect\":\"#888\",\"colorValueBoxRectEnd\":\"#666\",\"colorValueBoxBackground\":\"#babab2\",\"colorValueBoxShadow\":\"rgba(0,0,0,1)\"},\"title\":\"Radial gauge\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\",\"configMode\":\"basic\"}" },
"externalId": null
}

8
application/src/main/data/json/system/widget_types/speed_gauge.json

@ -11,11 +11,11 @@
"resources": [],
"templateHtml": "<canvas id=\"radialGauge\"></canvas>\n",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.gauge = new TbAnalogueRadialGauge(self.ctx, 'radialGauge'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.gauge.update();\n}\n\nself.onResize = function() {\n self.ctx.gauge.resize();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.gauge.mobileModeChanged();\n}\n\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true\n };\n}\n\nself.onDestroy = function() {\n self.ctx.gauge.destroy();\n}\n",
"settingsSchema": "{}",
"controllerScript": "self.onInit = function() {\n self.ctx.gauge = new TbAnalogueRadialGauge(self.ctx, 'radialGauge'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.gauge.update();\n}\n\nself.onResize = function() {\n self.ctx.gauge.resize();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.gauge.mobileModeChanged();\n}\n\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'speed', label: 'Speed', type: 'timeseries' }];\n }\n };\n}\n\nself.onDestroy = function() {\n self.ctx.gauge.destroy();\n}\n", "settingsSchema": "{}",
"dataKeySettingsSchema": "{}\n",
"settingsDirective": "tb-analogue-radial-gauge-widget-settings",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Speed\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7282710489093589,\"funcBody\":\"var value = prevValue + Math.random() * 50 - 25;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 220) {\\n\\tvalue = 220;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"maxValue\":180,\"startAngle\":45,\"ticksAngle\":270,\"showBorder\":false,\"defaultColor\":\"#e65100\",\"needleCircleSize\":7,\"highlights\":[{\"from\":80,\"to\":120,\"color\":\"#fdd835\"},{\"color\":\"#e57373\",\"from\":120,\"to\":180}],\"showUnitTitle\":false,\"colorPlate\":\"#fff\",\"colorMajorTicks\":\"#444\",\"colorMinorTicks\":\"#666\",\"minorTicks\":2,\"valueInt\":3,\"minValue\":0,\"valueDec\":0,\"highlightsWidth\":15,\"valueBox\":true,\"animation\":true,\"animationDuration\":1500,\"animationRule\":\"linear\",\"colorNeedleShadowUp\":\"rgba(2, 255, 255, 0)\",\"colorNeedleShadowDown\":\"rgba(188, 143, 143, 0.78)\",\"units\":\"MPH\",\"majorTicksCount\":9,\"numbersFont\":{\"family\":\"Roboto\",\"size\":22,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"titleFont\":{\"family\":\"Roboto\",\"size\":24,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#888\"},\"unitsFont\":{\"family\":\"Roboto\",\"size\":28,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"valueFont\":{\"size\":32,\"style\":\"normal\",\"weight\":\"normal\",\"shadowColor\":\"rgba(0, 0, 0, 0.49)\",\"color\":\"#444\",\"family\":\"Segment7Standard\"},\"colorValueBoxRect\":\"#888\",\"colorValueBoxRectEnd\":\"#666\",\"colorValueBoxBackground\":\"#babab2\",\"colorValueBoxShadow\":\"rgba(0,0,0,1)\"},\"title\":\"Speed gauge\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\"}"
},
"hasBasicMode": true,
"basicModeDirective": "tb-radial-gauge-basic-config",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Speed\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7282710489093589,\"funcBody\":\"var value = prevValue + Math.random() * 50 - 25;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 220) {\\n\\tvalue = 220;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"maxValue\":180,\"startAngle\":45,\"ticksAngle\":270,\"showBorder\":false,\"defaultColor\":\"#e65100\",\"needleCircleSize\":7,\"highlights\":[{\"from\":80,\"to\":120,\"color\":\"#fdd835\"},{\"color\":\"#e57373\",\"from\":120,\"to\":180}],\"showUnitTitle\":false,\"colorPlate\":\"#fff\",\"colorMajorTicks\":\"#444\",\"colorMinorTicks\":\"#666\",\"minorTicks\":2,\"valueInt\":3,\"minValue\":0,\"valueDec\":0,\"highlightsWidth\":15,\"valueBox\":true,\"animation\":true,\"animationDuration\":1500,\"animationRule\":\"linear\",\"colorNeedleShadowUp\":\"rgba(2, 255, 255, 0)\",\"colorNeedleShadowDown\":\"rgba(188, 143, 143, 0.78)\",\"units\":\"MPH\",\"majorTicksCount\":9,\"numbersFont\":{\"family\":\"Roboto\",\"size\":22,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"titleFont\":{\"family\":\"Roboto\",\"size\":24,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#888\"},\"unitsFont\":{\"family\":\"Roboto\",\"size\":28,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"valueFont\":{\"size\":32,\"style\":\"normal\",\"weight\":\"normal\",\"shadowColor\":\"rgba(0, 0, 0, 0.49)\",\"color\":\"#444\",\"family\":\"Segment7Standard\"},\"colorValueBoxRect\":\"#888\",\"colorValueBoxRectEnd\":\"#666\",\"colorValueBoxBackground\":\"#babab2\",\"colorValueBoxShadow\":\"rgba(0,0,0,1)\"},\"title\":\"Speed gauge\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\",\"configMode\":\"basic\"}" },
"externalId": null
}

8
application/src/main/data/json/system/widget_types/temperature_radial_gauge.json

@ -11,11 +11,11 @@
"resources": [],
"templateHtml": "<canvas id=\"radialGauge\"></canvas>\n",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.gauge = new TbAnalogueRadialGauge(self.ctx, 'radialGauge'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.gauge.update();\n}\n\nself.onResize = function() {\n self.ctx.gauge.resize();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.gauge.mobileModeChanged();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true\n };\n}\n\nself.onDestroy = function() {\n self.ctx.gauge.destroy();\n}\n",
"settingsSchema": "{}",
"controllerScript": "self.onInit = function() {\n self.ctx.gauge = new TbAnalogueRadialGauge(self.ctx, 'radialGauge'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.gauge.update();\n}\n\nself.onResize = function() {\n self.ctx.gauge.resize();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.gauge.mobileModeChanged();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'temperature', label: 'Temperature', type: 'timeseries' }];\n }\n };\n}\n\nself.onDestroy = function() {\n self.ctx.gauge.destroy();\n}\n", "settingsSchema": "{}",
"dataKeySettingsSchema": "{}\n",
"settingsDirective": "tb-analogue-radial-gauge-widget-settings",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7282710489093589,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"maxValue\":60,\"startAngle\":67.5,\"ticksAngle\":225,\"showBorder\":true,\"defaultColor\":\"#e65100\",\"needleCircleSize\":7,\"highlights\":[{\"from\":-60,\"to\":-50,\"color\":\"#42a5f5\"},{\"from\":-50,\"to\":-40,\"color\":\"rgba(66, 165, 245, 0.83)\"},{\"from\":-40,\"to\":-30,\"color\":\"rgba(66, 165, 245, 0.66)\"},{\"from\":-30,\"to\":-20,\"color\":\"rgba(66, 165, 245, 0.5)\"},{\"from\":-20,\"to\":-10,\"color\":\"rgba(66, 165, 245, 0.33)\"},{\"from\":-10,\"to\":0,\"color\":\"rgba(66, 165, 245, 0.16)\"},{\"from\":0,\"to\":10,\"color\":\"rgba(229, 115, 115, 0.16)\"},{\"from\":10,\"to\":20,\"color\":\"rgba(229, 115, 115, 0.33)\"},{\"from\":20,\"to\":30,\"color\":\"rgba(229, 115, 115, 0.5)\"},{\"from\":30,\"to\":40,\"color\":\"rgba(229, 115, 115, 0.66)\"},{\"from\":40,\"to\":50,\"color\":\"rgba(229, 115, 115, 0.83)\"},{\"from\":50,\"to\":60,\"color\":\"#e57373\"}],\"showUnitTitle\":true,\"colorPlate\":\"#cfd8dc\",\"colorMajorTicks\":\"#444\",\"colorMinorTicks\":\"#666\",\"minorTicks\":2,\"valueInt\":3,\"valueDec\":1,\"highlightsWidth\":15,\"valueBox\":true,\"animation\":true,\"animationDuration\":1000,\"animationRule\":\"bounce\",\"colorNeedleShadowUp\":\"rgba(2, 255, 255, 0)\",\"colorNeedleShadowDown\":\"rgba(188, 143, 143, 0.78)\",\"units\":\"°C\",\"majorTicksCount\":12,\"numbersFont\":{\"family\":\"Roboto\",\"size\":20,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#263238\"},\"titleFont\":{\"family\":\"Roboto\",\"size\":24,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#263238\"},\"unitsFont\":{\"family\":\"Roboto\",\"size\":28,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"valueFont\":{\"family\":\"Segment7Standard\",\"size\":30,\"style\":\"normal\",\"weight\":\"normal\",\"shadowColor\":\"rgba(0, 0, 0, 0.49)\",\"color\":\"#444\"},\"colorValueBoxRect\":\"#888\",\"colorValueBoxRectEnd\":\"#666\",\"colorValueBoxBackground\":\"#babab2\",\"colorValueBoxShadow\":\"rgba(0,0,0,1)\",\"unitTitle\":\"Temperature\",\"minValue\":-60},\"title\":\"Temperature radial gauge\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\"}"
},
"hasBasicMode": true,
"basicModeDirective": "tb-radial-gauge-basic-config",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7282710489093589,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"maxValue\":60,\"startAngle\":67.5,\"ticksAngle\":225,\"showBorder\":true,\"defaultColor\":\"#e65100\",\"needleCircleSize\":7,\"highlights\":[{\"from\":-60,\"to\":-50,\"color\":\"#42a5f5\"},{\"from\":-50,\"to\":-40,\"color\":\"rgba(66, 165, 245, 0.83)\"},{\"from\":-40,\"to\":-30,\"color\":\"rgba(66, 165, 245, 0.66)\"},{\"from\":-30,\"to\":-20,\"color\":\"rgba(66, 165, 245, 0.5)\"},{\"from\":-20,\"to\":-10,\"color\":\"rgba(66, 165, 245, 0.33)\"},{\"from\":-10,\"to\":0,\"color\":\"rgba(66, 165, 245, 0.16)\"},{\"from\":0,\"to\":10,\"color\":\"rgba(229, 115, 115, 0.16)\"},{\"from\":10,\"to\":20,\"color\":\"rgba(229, 115, 115, 0.33)\"},{\"from\":20,\"to\":30,\"color\":\"rgba(229, 115, 115, 0.5)\"},{\"from\":30,\"to\":40,\"color\":\"rgba(229, 115, 115, 0.66)\"},{\"from\":40,\"to\":50,\"color\":\"rgba(229, 115, 115, 0.83)\"},{\"from\":50,\"to\":60,\"color\":\"#e57373\"}],\"showUnitTitle\":true,\"colorPlate\":\"#cfd8dc\",\"colorMajorTicks\":\"#444\",\"colorMinorTicks\":\"#666\",\"minorTicks\":2,\"valueInt\":3,\"valueDec\":1,\"highlightsWidth\":15,\"valueBox\":true,\"animation\":true,\"animationDuration\":1000,\"animationRule\":\"bounce\",\"colorNeedleShadowUp\":\"rgba(2, 255, 255, 0)\",\"colorNeedleShadowDown\":\"rgba(188, 143, 143, 0.78)\",\"units\":\"°C\",\"majorTicksCount\":12,\"numbersFont\":{\"family\":\"Roboto\",\"size\":20,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#263238\"},\"titleFont\":{\"family\":\"Roboto\",\"size\":24,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#263238\"},\"unitsFont\":{\"family\":\"Roboto\",\"size\":28,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"valueFont\":{\"family\":\"Segment7Standard\",\"size\":30,\"style\":\"normal\",\"weight\":\"normal\",\"shadowColor\":\"rgba(0, 0, 0, 0.49)\",\"color\":\"#444\"},\"colorValueBoxRect\":\"#888\",\"colorValueBoxRectEnd\":\"#666\",\"colorValueBoxBackground\":\"#babab2\",\"colorValueBoxShadow\":\"rgba(0,0,0,1)\",\"unitTitle\":\"Temperature\",\"minValue\":-60},\"title\":\"Temperature radial gauge\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\",\"configMode\":\"basic\"}" },
"externalId": null
}

8
application/src/main/data/json/system/widget_types/thermometer_scale.json

@ -11,11 +11,11 @@
"resources": [],
"templateHtml": "<canvas id=\"linearGauge\"></canvas>\n",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.gauge = new TbAnalogueLinearGauge(self.ctx, 'linearGauge'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.gauge.update();\n}\n\nself.onResize = function() {\n self.ctx.gauge.resize();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.gauge.mobileModeChanged();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true\n };\n}\n\nself.onDestroy = function() {\n self.ctx.gauge.destroy();\n}\n",
"settingsSchema": "{}",
"controllerScript": "self.onInit = function() {\n self.ctx.gauge = new TbAnalogueLinearGauge(self.ctx, 'linearGauge'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.gauge.update();\n}\n\nself.onResize = function() {\n self.ctx.gauge.resize();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.gauge.mobileModeChanged();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'temperature', label: 'Temperature', type: 'timeseries' }];\n }\n };\n}\n\nself.onDestroy = function() {\n self.ctx.gauge.destroy();\n}\n", "settingsSchema": "{}",
"dataKeySettingsSchema": "{}\n",
"settingsDirective": "tb-analogue-linear-gauge-widget-settings",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temp\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7282710489093589,\"funcBody\":\"var value = prevValue + Math.random() * 30 - 15;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"maxValue\":100,\"defaultColor\":\"#e64a19\",\"barStrokeWidth\":2.5,\"colorBar\":\"rgba(255, 255, 255, 0.4)\",\"colorBarEnd\":\"rgba(221, 221, 221, 0.38)\",\"showUnitTitle\":true,\"minorTicks\":2,\"valueBox\":true,\"valueInt\":3,\"colorPlate\":\"#fff\",\"colorMajorTicks\":\"#444\",\"colorMinorTicks\":\"#666\",\"colorNeedleShadowUp\":\"rgba(2,255,255,0.2)\",\"colorNeedleShadowDown\":\"rgba(188,143,143,0.45)\",\"colorValueBoxRect\":\"#888\",\"colorValueBoxRectEnd\":\"#666\",\"colorValueBoxBackground\":\"#babab2\",\"colorValueBoxShadow\":\"rgba(0,0,0,1)\",\"highlightsWidth\":10,\"animation\":true,\"animationDuration\":1500,\"animationRule\":\"linear\",\"showBorder\":false,\"majorTicksCount\":8,\"numbersFont\":{\"family\":\"Arial\",\"size\":18,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#263238\"},\"titleFont\":{\"family\":\"Roboto\",\"size\":24,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#78909c\"},\"unitsFont\":{\"family\":\"Roboto\",\"size\":26,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#37474f\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":40,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#444\",\"shadowColor\":\"rgba(0,0,0,0.3)\"},\"minValue\":-60,\"highlights\":[{\"from\":-60,\"to\":-40,\"color\":\"#90caf9\"},{\"from\":-40,\"to\":-20,\"color\":\"rgba(144, 202, 249, 0.66)\"},{\"from\":-20,\"to\":0,\"color\":\"rgba(144, 202, 249, 0.33)\"},{\"from\":0,\"to\":20,\"color\":\"rgba(244, 67, 54, 0.2)\"},{\"from\":20,\"to\":40,\"color\":\"rgba(244, 67, 54, 0.4)\"},{\"from\":40,\"to\":60,\"color\":\"rgba(244, 67, 54, 0.6)\"},{\"from\":60,\"to\":80,\"color\":\"rgba(244, 67, 54, 0.8)\"},{\"from\":80,\"to\":100,\"color\":\"#f44336\"}],\"unitTitle\":\"Temperature\",\"units\":\"°C\",\"colorBarProgress\":\"#90caf9\",\"colorBarProgressEnd\":\"#f44336\",\"colorBarStroke\":\"#b0bec5\",\"valueDec\":1},\"title\":\"Thermometer scale\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\"}"
},
"hasBasicMode": true,
"basicModeDirective": "tb-thermometer-scale-gauge-basic-config",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temp\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7282710489093589,\"funcBody\":\"var value = prevValue + Math.random() * 30 - 15;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"maxValue\":100,\"defaultColor\":\"#e64a19\",\"barStrokeWidth\":2.5,\"colorBar\":\"rgba(255, 255, 255, 0.4)\",\"colorBarEnd\":\"rgba(221, 221, 221, 0.38)\",\"showUnitTitle\":true,\"minorTicks\":2,\"valueBox\":true,\"valueInt\":3,\"colorPlate\":\"#fff\",\"colorMajorTicks\":\"#444\",\"colorMinorTicks\":\"#666\",\"colorNeedleShadowUp\":\"rgba(2,255,255,0.2)\",\"colorNeedleShadowDown\":\"rgba(188,143,143,0.45)\",\"colorValueBoxRect\":\"#888\",\"colorValueBoxRectEnd\":\"#666\",\"colorValueBoxBackground\":\"#babab2\",\"colorValueBoxShadow\":\"rgba(0,0,0,1)\",\"highlightsWidth\":10,\"animation\":true,\"animationDuration\":1500,\"animationRule\":\"linear\",\"showBorder\":false,\"majorTicksCount\":8,\"numbersFont\":{\"family\":\"Arial\",\"size\":18,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#263238\"},\"titleFont\":{\"family\":\"Roboto\",\"size\":24,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#78909c\"},\"unitsFont\":{\"family\":\"Roboto\",\"size\":26,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#37474f\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":40,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#444\",\"shadowColor\":\"rgba(0,0,0,0.3)\"},\"minValue\":-60,\"highlights\":[{\"from\":-60,\"to\":-40,\"color\":\"#90caf9\"},{\"from\":-40,\"to\":-20,\"color\":\"rgba(144, 202, 249, 0.66)\"},{\"from\":-20,\"to\":0,\"color\":\"rgba(144, 202, 249, 0.33)\"},{\"from\":0,\"to\":20,\"color\":\"rgba(244, 67, 54, 0.2)\"},{\"from\":20,\"to\":40,\"color\":\"rgba(244, 67, 54, 0.4)\"},{\"from\":40,\"to\":60,\"color\":\"rgba(244, 67, 54, 0.6)\"},{\"from\":60,\"to\":80,\"color\":\"rgba(244, 67, 54, 0.8)\"},{\"from\":80,\"to\":100,\"color\":\"#f44336\"}],\"unitTitle\":\"Temperature\",\"units\":\"°C\",\"colorBarProgress\":\"#90caf9\",\"colorBarProgressEnd\":\"#f44336\",\"colorBarStroke\":\"#b0bec5\",\"valueDec\":1},\"title\":\"Thermometer scale\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\",\"configMode\":\"basic\"}" },
"externalId": null
}

18
ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts

@ -70,6 +70,15 @@ import {
import {
ProgressBarBasicConfigComponent
} from '@home/components/widget/config/basic/cards/progress-bar-basic-config.component';
import {
RadialGaugeBasicConfigComponent
} from '@home/components/widget/config/basic/gauge/radial-gauge-basic-config.component';
import {
ThermometerScaleGaugeBasicConfigComponent
} from '@home/components/widget/config/basic/gauge/thermometer-scale-gauge-basic-config.component';
import {
CompassGaugeBasicConfigComponent
} from '@home/components/widget/config/basic/gauge/compass-gauge-basic-config.component';
import {
LiquidLevelCardBasicConfigComponent
} from '@home/components/widget/config/basic/indicator/liquid-level-card-basic-config.component';
@ -95,6 +104,9 @@ import {
SignalStrengthBasicConfigComponent,
ValueChartCardBasicConfigComponent,
ProgressBarBasicConfigComponent,
RadialGaugeBasicConfigComponent,
ThermometerScaleGaugeBasicConfigComponent,
CompassGaugeBasicConfigComponent,
LiquidLevelCardBasicConfigComponent
],
imports: [
@ -122,6 +134,9 @@ import {
SignalStrengthBasicConfigComponent,
ValueChartCardBasicConfigComponent,
ProgressBarBasicConfigComponent,
RadialGaugeBasicConfigComponent,
ThermometerScaleGaugeBasicConfigComponent,
CompassGaugeBasicConfigComponent,
LiquidLevelCardBasicConfigComponent
]
})
@ -143,5 +158,8 @@ export const basicWidgetConfigComponentsMap: {[key: string]: Type<IBasicWidgetCo
'tb-signal-strength-basic-config': SignalStrengthBasicConfigComponent,
'tb-value-chart-card-basic-config': ValueChartCardBasicConfigComponent,
'tb-progress-bar-basic-config': ProgressBarBasicConfigComponent,
'tb-radial-gauge-basic-config': RadialGaugeBasicConfigComponent,
'tb-thermometer-scale-gauge-basic-config': ThermometerScaleGaugeBasicConfigComponent,
'tb-compass-gauge-basic-config': CompassGaugeBasicConfigComponent,
'tb-liquid-level-card-basic-config': LiquidLevelCardBasicConfigComponent
};

182
ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/analog-gauge-basic-config.component.html

@ -0,0 +1,182 @@
<!--
Copyright © 2016-2023 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.
-->
<ng-container [formGroup]="radialGaugeWidgetConfigForm">
<tb-timewindow-config-panel *ngIf="displayTimewindowConfig"
[onlyHistoryTimewindow]="onlyHistoryTimewindow()"
formControlName="timewindowConfig">
</tb-timewindow-config-panel>
<tb-datasources
[configMode]="basicMode"
hideDataKeyLabel
hideDataKeyColor
hideDataKeyUnits
hideDataKeyDecimals
formControlName="datasources">
</tb-datasources>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.gauge.gauge-appearance</div>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showUnitTitle">
{{ 'widgets.gauge.units-title' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="unitTitle" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="titleFont"
disabledLineHeight
[previewText]="radialGaugeWidgetConfigForm.get('unitTitle').value">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="titleColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widget-config.units-short</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-unit-input
formControlName="units">
</tb-unit-input>
<tb-font-settings formControlName="unitsFont"
disabledLineHeight
[previewText]="radialGaugeWidgetConfigForm.get('units').value">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="unitsColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="valueBox">
{{ 'widgets.gauge.value' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="flex number" subscriptSizing="dynamic">
<input matInput formControlName="valueInt" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix fxHide.lt-md translate>widget-config.decimals-suffix</div>
</mat-form-field>
<tb-font-settings formControlName="valueFont"
disabledLineHeight
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="valueColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.gauge.ticks</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<div class="tb-small-label" translate>widgets.gauge.min-value-short</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="minValue" type="number" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<div class="tb-small-label" translate>widgets.gauge.max-value-short</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="maxValue" type="number" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="numbersFont"
disabledLineHeight
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="numbersColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.arrow-and-scale-color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="defaultColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.plate-color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorPlate">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.scale-color</div>
<tb-color-range-settings formControlName="highlights">
</tb-color-range-settings>
</div>
<div class="tb-form-panel" *ngIf="gaugeType === 'linear'">
<div class="tb-form-panel-title" translate>widgets.gauge.progress-bar</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.progress-bar-color-start</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorBarProgress">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.progress-bar-color-end</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorBarProgressEnd">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.bar-stroke-color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorBarStroke">
</tb-color-input>
</div>
</div>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row space-between">
<div>{{ 'widget-config.background-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="backgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between column-lt-md">
<div translate>widget-config.show-card-buttons</div>
<mat-chip-listbox multiple formControlName="cardButtons">
<mat-chip-option value="fullscreen">{{ 'fullscreen.fullscreen' | translate }}</mat-chip-option>
</mat-chip-listbox>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widget-config.card-border-radius' | translate }}</div>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="borderRadius" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<tb-widget-actions-panel
formControlName="actions">
</tb-widget-actions-panel>
</ng-container>

187
ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/analog-gauge-basic-config.component.ts

@ -0,0 +1,187 @@
///
/// Copyright © 2016-2023 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 { UntypedFormBuilder, UntypedFormGroup } 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 {
datasourcesHasAggregation,
datasourcesHasOnlyComparisonAggregation,
WidgetConfig,
} from '@shared/models/widget.models';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import {
getTimewindowConfig,
setTimewindowConfig
} from '@home/components/widget/config/timewindow-config-panel.component';
import { formatValue, isUndefined } from '@core/utils';
import { ColorType } from '@shared/models/widget-settings.models';
export class GaugeBasicConfigComponent extends BasicWidgetConfigComponent {
public get displayTimewindowConfig(): boolean {
const datasources = this.radialGaugeWidgetConfigForm.get('datasources').value;
return datasourcesHasAggregation(datasources);
}
public onlyHistoryTimewindow(): boolean {
const datasources = this.radialGaugeWidgetConfigForm.get('datasources').value;
return datasourcesHasOnlyComparisonAggregation(datasources);
}
colorType = ColorType;
radialGaugeWidgetConfigForm: UntypedFormGroup;
valuePreviewFn = this._valuePreviewFn.bind(this);
constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent,
protected fb: UntypedFormBuilder) {
super(store, widgetConfigComponent);
}
protected configForm(): UntypedFormGroup {
return this.radialGaugeWidgetConfigForm;
}
protected setupDefaults(configData: WidgetConfigComponentData) {
super.setupDefaults(configData);
}
protected onConfigSet(configData: WidgetConfigComponentData) {
this.radialGaugeWidgetConfigForm = this.fb.group({
timewindowConfig: [getTimewindowConfig(configData.config), []],
datasources: [configData.config.datasources, []],
showUnitTitle: [configData.config.settings?.showUnitTitle, []],
unitTitle: [configData.config.settings?.unitTitle, []],
titleFont: [configData.config.settings?.titleFont, []],
titleColor: [configData.config.settings?.titleFont?.color, []],
units: [configData.config.units, []],
unitsFont: [configData.config.settings?.unitsFont, []],
unitsColor: [configData.config.settings?.unitsFont?.color, []],
valueBox: [configData.config.settings?.valueBox, []],
valueInt: [configData.config.settings?.valueInt, []],
valueFont: [configData.config.settings?.valueFont, []],
valueColor: [configData.config.settings?.valueFont?.color, []],
minValue: [configData.config.settings?.minValue, []],
maxValue: [configData.config.settings?.maxValue, []],
numbersFont: [configData.config.settings?.numbersFont, []],
numbersColor: [configData.config.settings?.numbersFont?.color, []],
colorBarStroke: [configData.config.settings?.colorBarStroke, []],
defaultColor: [configData.config.settings?.defaultColor, []],
colorPlate: [configData.config.settings?.colorPlate, []],
highlights: [configData.config.settings?.highlights, []],
cardButtons: [this.getCardButtons(configData.config), []],
borderRadius: [configData.config.borderRadius, []],
backgroundColor: [configData.config.backgroundColor, []],
actions: [configData.config.actions || {}, []]
});
}
protected prepareOutputConfig(config: any): WidgetConfigComponentData {
setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig);
this.widgetConfig.config.datasources = config.datasources;
this.widgetConfig.config.actions = config.actions;
this.widgetConfig.config.settings = this.widgetConfig.config.settings || {};
this.setCardButtons(config.cardButtons, this.widgetConfig.config);
this.widgetConfig.config.backgroundColor = config.backgroundColor;
this.widgetConfig.config.settings.showUnitTitle = config.showUnitTitle;
this.widgetConfig.config.settings.unitTitle = config.unitTitle;
this.widgetConfig.config.settings.titleFont = config.titleFont;
this.widgetConfig.config.settings.titleFont.color = config.titleColor;
this.widgetConfig.config.units = config.units;
this.widgetConfig.config.settings.unitsFont = config.unitsFont;
this.widgetConfig.config.settings.unitsFont.color = config.unitsColor;
this.widgetConfig.config.settings.valueBox = config.valueBox;
this.widgetConfig.config.settings.valueInt = config.valueInt;
this.widgetConfig.config.settings.valueFont = config.valueFont;
this.widgetConfig.config.settings.valueFont.color = config.valueColor;
this.widgetConfig.config.settings.minValue = config.minValue;
this.widgetConfig.config.settings.maxValue = config.maxValue;
this.widgetConfig.config.settings.numbersFont = config.numbersFont;
this.widgetConfig.config.settings.numbersFont.color = config.numbersColor;
this.widgetConfig.config.settings.defaultColor = config.defaultColor;
this.widgetConfig.config.settings.colorPlate = config.colorPlate;
this.widgetConfig.config.settings.highlights = config.highlights.rangeList;
return this.widgetConfig;
}
protected validatorTriggers(): string[] {
return ['showUnitTitle', 'valueBox'];
}
protected updateValidators(emitEvent: boolean, trigger?: string) {
const showUnitTitle: boolean = this.radialGaugeWidgetConfigForm.get('showUnitTitle').value;
const valueBox: boolean = this.radialGaugeWidgetConfigForm.get('valueBox').value;
if (showUnitTitle) {
this.radialGaugeWidgetConfigForm.get('unitTitle').enable();
this.radialGaugeWidgetConfigForm.get('titleFont').enable();
this.radialGaugeWidgetConfigForm.get('titleColor').enable();
} else {
this.radialGaugeWidgetConfigForm.get('unitTitle').disable();
this.radialGaugeWidgetConfigForm.get('titleFont').disable();
this.radialGaugeWidgetConfigForm.get('titleColor').disable();
}
if (valueBox) {
this.radialGaugeWidgetConfigForm.get('valueInt').enable();
this.radialGaugeWidgetConfigForm.get('valueFont').enable();
this.radialGaugeWidgetConfigForm.get('valueColor').enable();
} else {
this.radialGaugeWidgetConfigForm.get('valueInt').disable();
this.radialGaugeWidgetConfigForm.get('valueFont').disable();
this.radialGaugeWidgetConfigForm.get('valueColor').disable();
}
this.radialGaugeWidgetConfigForm.get('unitTitle').updateValueAndValidity({emitEvent});
this.radialGaugeWidgetConfigForm.get('titleFont').updateValueAndValidity({emitEvent});
this.radialGaugeWidgetConfigForm.get('titleColor').updateValueAndValidity({emitEvent});
this.radialGaugeWidgetConfigForm.get('valueInt').updateValueAndValidity({emitEvent});
this.radialGaugeWidgetConfigForm.get('valueFont').updateValueAndValidity({emitEvent});
this.radialGaugeWidgetConfigForm.get('valueColor').updateValueAndValidity({emitEvent});
}
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.radialGaugeWidgetConfigForm.get('units').value;
return formatValue(22, 0, units, true);
}
}

154
ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/compass-gauge-basic-config.component.html

@ -0,0 +1,154 @@
<!--
Copyright © 2016-2023 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.
-->
<ng-container [formGroup]="compassGaugeWidgetConfigForm">
<tb-timewindow-config-panel *ngIf="displayTimewindowConfig"
[onlyHistoryTimewindow]="onlyHistoryTimewindow()"
formControlName="timewindowConfig">
</tb-timewindow-config-panel>
<tb-datasources
[configMode]="basicMode"
hideDataKeyLabel
hideDataKeyColor
hideDataKeyUnits
hideDataKeyDecimals
formControlName="datasources">
</tb-datasources>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.appearance</div>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTitle">
{{ 'widget-config.title' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="title" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="titleFont"
clearButton
[previewText]="compassGaugeWidgetConfigForm.get('title').value"
[initialPreviewStyle]="widgetConfig.config.titleStyle">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="titleColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="showTitleIcon">
{{ 'widget-config.icon' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-material-icon-select asBoxInput
iconClearButton
[color]="compassGaugeWidgetConfigForm.get('iconColor').value"
formControlName="titleIcon">
</tb-material-icon-select>
<tb-color-input asBoxInput
colorClearButton
formControlName="iconColor">
</tb-color-input>
</div>
</div>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.gauge.compass-appearance</div>
<div class="tb-form-row">
<div class="fixed-title-width" translate>widgets.gauge.labels</div>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-string-items-list
style="display: flex"
fxFlex
appearance="outline"
subscriptSizing="dynamic"
editable
formControlName="majorTicks">
</tb-string-items-list>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.label-style</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="majorTickFont"
disabledLineHeight>
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="majorTickColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.major-ticks-color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorMajorTicks">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.minor-ticks-color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorMinorTicks">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.needle-color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorNeedle">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.plate-color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorPlate">
</tb-color-input>
</div>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row space-between">
<div>{{ 'widget-config.background-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="backgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between column-lt-md">
<div translate>widget-config.show-card-buttons</div>
<mat-chip-listbox multiple formControlName="cardButtons">
<mat-chip-option value="fullscreen">{{ 'fullscreen.fullscreen' | translate }}</mat-chip-option>
</mat-chip-listbox>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widget-config.card-border-radius' | translate }}</div>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="borderRadius" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<tb-widget-actions-panel
formControlName="actions">
</tb-widget-actions-panel>
</ng-container>

171
ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/compass-gauge-basic-config.component.ts

@ -0,0 +1,171 @@
///
/// Copyright © 2016-2023 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 } 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 {
datasourcesHasAggregation,
datasourcesHasOnlyComparisonAggregation,
WidgetConfig,
} from '@shared/models/widget.models';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import {
getTimewindowConfig,
setTimewindowConfig
} from '@home/components/widget/config/timewindow-config-panel.component';
import { isUndefined } from '@core/utils';
@Component({
selector: 'tb-compass-gauge-basic-config',
templateUrl: './compass-gauge-basic-config.component.html',
styleUrls: ['../basic-config.scss']
})
export class CompassGaugeBasicConfigComponent extends BasicWidgetConfigComponent {
public get displayTimewindowConfig(): boolean {
const datasources = this.compassGaugeWidgetConfigForm.get('datasources').value;
return datasourcesHasAggregation(datasources);
}
public onlyHistoryTimewindow(): boolean {
const datasources = this.compassGaugeWidgetConfigForm.get('datasources').value;
return datasourcesHasOnlyComparisonAggregation(datasources);
}
compassGaugeWidgetConfigForm: UntypedFormGroup;
constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent,
protected fb: UntypedFormBuilder) {
super(store, widgetConfigComponent);
}
protected configForm(): UntypedFormGroup {
return this.compassGaugeWidgetConfigForm;
}
protected setupDefaults(configData: WidgetConfigComponentData) {
super.setupDefaults(configData);
}
protected onConfigSet(configData: WidgetConfigComponentData) {
this.compassGaugeWidgetConfigForm = this.fb.group({
timewindowConfig: [getTimewindowConfig(configData.config), []],
datasources: [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, []],
majorTicks: [configData.config.settings?.majorTicks, []],
majorTickFont: [configData.config.settings?.majorTickFont, []],
majorTickColor: [configData.config.settings?.majorTickFont.color, []],
colorMajorTicks: [configData.config.settings?.colorMajorTicks, []],
colorMinorTicks: [configData.config.settings?.colorMinorTicks, []],
colorPlate: [configData.config.settings?.colorPlate, []],
colorNeedle: [configData.config.settings?.colorNeedle, []],
cardButtons: [this.getCardButtons(configData.config), []],
borderRadius: [configData.config.borderRadius, []],
backgroundColor: [configData.config.backgroundColor, []],
actions: [configData.config.actions || {}, []]
});
}
protected prepareOutputConfig(config: any): WidgetConfigComponentData {
setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig);
this.widgetConfig.config.datasources = config.datasources;
this.widgetConfig.config.actions = config.actions;
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.setCardButtons(config.cardButtons, this.widgetConfig.config);
this.widgetConfig.config.backgroundColor = config.backgroundColor;
this.widgetConfig.config.settings.majorTicks = config.majorTicks;
this.widgetConfig.config.settings.majorTickFont = config.majorTickFont;
this.widgetConfig.config.settings.majorTickFont.color = config.majorTickColor;
this.widgetConfig.config.settings.colorMajorTicks = config.colorMajorTicks;
this.widgetConfig.config.settings.colorMinorTicks = config.colorMinorTicks;
this.widgetConfig.config.settings.colorPlate = config.colorPlate;
this.widgetConfig.config.settings.colorNeedle = config.colorNeedle;
return this.widgetConfig;
}
protected validatorTriggers(): string[] {
return ['showTitle', 'showTitleIcon'];
}
protected updateValidators(emitEvent: boolean, trigger?: string) {
const showTitle: boolean = this.compassGaugeWidgetConfigForm.get('showTitle').value;
const showTitleIcon: boolean = this.compassGaugeWidgetConfigForm.get('showTitleIcon').value;
if (showTitle) {
this.compassGaugeWidgetConfigForm.get('title').enable();
this.compassGaugeWidgetConfigForm.get('titleFont').enable();
this.compassGaugeWidgetConfigForm.get('titleColor').enable();
this.compassGaugeWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false});
if (showTitleIcon) {
this.compassGaugeWidgetConfigForm.get('titleIcon').enable();
this.compassGaugeWidgetConfigForm.get('iconColor').enable();
} else {
this.compassGaugeWidgetConfigForm.get('titleIcon').disable();
this.compassGaugeWidgetConfigForm.get('iconColor').disable();
}
} else {
this.compassGaugeWidgetConfigForm.get('title').disable();
this.compassGaugeWidgetConfigForm.get('titleFont').disable();
this.compassGaugeWidgetConfigForm.get('titleColor').disable();
this.compassGaugeWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false});
this.compassGaugeWidgetConfigForm.get('titleIcon').disable();
this.compassGaugeWidgetConfigForm.get('iconColor').disable();
}
this.compassGaugeWidgetConfigForm.get('title').updateValueAndValidity({emitEvent});
this.compassGaugeWidgetConfigForm.get('titleFont').updateValueAndValidity({emitEvent});
this.compassGaugeWidgetConfigForm.get('titleColor').updateValueAndValidity({emitEvent});
this.compassGaugeWidgetConfigForm.get('showTitleIcon').updateValueAndValidity({emitEvent: false});
this.compassGaugeWidgetConfigForm.get('titleIcon').updateValueAndValidity({emitEvent});
this.compassGaugeWidgetConfigForm.get('iconColor').updateValueAndValidity({emitEvent});
}
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');
}
}

45
ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/radial-gauge-basic-config.component.ts

@ -0,0 +1,45 @@
///
/// Copyright © 2016-2023 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 } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import {
GaugeBasicConfigComponent
} from '@home/components/widget/config/basic/gauge/analog-gauge-basic-config.component';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
@Component({
selector: 'tb-radial-gauge-basic-config',
templateUrl: './analog-gauge-basic-config.component.html',
styleUrls: ['../basic-config.scss']
})
export class RadialGaugeBasicConfigComponent extends GaugeBasicConfigComponent {
gaugeType = 'radial';
constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent,
protected fb: UntypedFormBuilder) {
super(store, widgetConfigComponent, fb);
}
protected onConfigSet(configData: WidgetConfigComponentData) {
super.onConfigSet(configData);
}
}

59
ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/thermometer-scale-gauge-basic-config.component.ts

@ -0,0 +1,59 @@
///
/// Copyright © 2016-2023 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 } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import {
GaugeBasicConfigComponent
} from '@home/components/widget/config/basic/gauge/analog-gauge-basic-config.component';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
@Component({
selector: 'tb-thermometer-scale-gauge-basic-config',
templateUrl: './analog-gauge-basic-config.component.html',
styleUrls: ['../basic-config.scss']
})
export class ThermometerScaleGaugeBasicConfigComponent extends GaugeBasicConfigComponent {
gaugeType = 'linear';
constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent,
protected fb: UntypedFormBuilder) {
super(store, widgetConfigComponent, fb);
}
protected onConfigSet(configData: WidgetConfigComponentData) {
super.onConfigSet(configData);
this.radialGaugeWidgetConfigForm.addControl('colorBarStroke',
this.fb.control(configData.config.settings?.colorBarStroke, []));
this.radialGaugeWidgetConfigForm.addControl('colorBarProgress',
this.fb.control(configData.config.settings?.colorBarProgress, []));
this.radialGaugeWidgetConfigForm.addControl('colorBarProgressEnd',
this.fb.control(configData.config.settings?.colorBarProgressEnd, []));
}
protected prepareOutputConfig(config): WidgetConfigComponentData {
const outputConfig = super.prepareOutputConfig(config);
this.widgetConfig.config.settings.colorBarStroke = config.colorBarStroke;
this.widgetConfig.config.settings.colorBarProgress = config.colorBarProgress;
this.widgetConfig.config.settings.colorBarProgressEnd = config.colorBarProgressEnd;
return outputConfig;
}
}

2
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html

@ -73,7 +73,7 @@
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row no-border no-padding" [fxHide]="disabledLineHeight">
<div class="tb-form-row no-border no-padding" *ngIf="!disabledLineHeight">
<div class="fixed-title-width" translate>widgets.widget-font.line-height</div>
<mat-form-field *ngIf="!autoScale" fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="lineHeight" placeholder="{{ 'widget-config.set' | translate }}">

291
ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-compass-widget-settings.component.html

@ -15,153 +15,127 @@
limitations under the License.
-->
<section class="tb-widget-settings" [formGroup]="analogueCompassWidgetSettingsForm" fxLayout="column">
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.gauge.ticks-settings</legend>
<mat-form-field fxFlex class="mat-block" floatLabel="always">
<mat-label translate>widgets.gauge.major-ticks-names</mat-label>
<mat-chip-grid class="tb-drop-list"
#majorTicksNamesChipList
cdkDropList
cdkDropListOrientation="horizontal"
(cdkDropListDropped)="majorTickNameDrop($event)"
formControlName="majorTicks">
<mat-chip-row class="tb-draggable" cdkDrag *ngFor="let tickName of majorTicksNamesList()"
[removable]="true" (removed)="removeMajorTickName(tickName)">
{{tickName}}
<mat-icon matChipRemove>cancel</mat-icon>
</mat-chip-row>
<input [matChipInputFor]="majorTicksNamesChipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
matChipInputAddOnBlur
(matChipInputTokenEnd)="addMajorTickName($event)">
</mat-chip-grid>
</mat-form-field>
<tb-color-input fxFlex
formControlName="colorMajorTicks"
icon="format_color_fill"
label="{{ 'widgets.gauge.major-ticks-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
<section fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px" fxLayoutAlign.gt-xs="start center">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.minor-ticks-count</mat-label>
<input matInput type="number" min="0" formControlName="minorTicks">
</mat-form-field>
<tb-color-input fxFlex
formControlName="colorMinorTicks"
icon="format_color_fill"
label="{{ 'widgets.gauge.minor-ticks-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
</section>
<mat-slide-toggle formControlName="showStrokeTicks" class="slide-block">
{{ 'widgets.gauge.show-stroke-ticks' | translate }}
</mat-slide-toggle>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.gauge.major-ticks-font</legend>
<tb-widget-font formControlName="majorTickFont"></tb-widget-font>
</fieldset>
</fieldset>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.gauge.plate-settings</legend>
<tb-color-input fxFlex
formControlName="colorPlate"
icon="format_color_fill"
label="{{ 'widgets.gauge.plate-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
<mat-slide-toggle formControlName="showBorder" class="slide-block">
{{ 'widgets.gauge.show-plate-border' | translate }}
</mat-slide-toggle>
<section fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px" fxLayoutAlign.gt-xs="start center">
<tb-color-input fxFlex
formControlName="colorBorder"
icon="format_color_fill"
label="{{ 'widgets.gauge.border-color' | translate }}" openOnInput colorClearButton>
<ng-container [formGroup]="analogueCompassWidgetSettingsForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.gauge.ticks-settings</div>
<div class="tb-form-row">
<div class="fixed-title-width" translate>widgets.gauge.labels</div>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-string-items-list
style="display: flex"
fxFlex
appearance="outline"
subscriptSizing="dynamic"
editable
formControlName="majorTicks">
</tb-string-items-list>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.label-style</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="majorTickFont"
disabledLineHeight>
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="majorTickColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.major-ticks</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorMajorTicks">
</tb-color-input>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.border-width</mat-label>
<input matInput type="number" min="0" formControlName="borderOuterWidth">
</mat-form-field>
</section>
</fieldset>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.gauge.needle-settings</legend>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.needle-circle-size</mat-label>
<input matInput type="number" min="0" formControlName="needleCircleSize">
</mat-form-field>
<section fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px" fxLayoutAlign.gt-xs="start center">
<tb-color-input fxFlex
formControlName="colorNeedle"
icon="format_color_fill"
label="{{ 'widgets.gauge.needle-color' | translate }}" openOnInput colorClearButton>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.minor-ticks</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput type="number" min="0" formControlName="minorTicks">
</mat-form-field>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorMinorTicks">
</tb-color-input>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="showStrokeTicks">
{{ 'widgets.gauge.show-stroke-ticks' | translate }}
</mat-slide-toggle>
</div>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.gauge.plate-settings</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.plate-color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorPlate">
</tb-color-input>
<tb-color-input fxFlex
formControlName="colorNeedleCircle"
icon="format_color_fill"
label="{{ 'widgets.gauge.needle-circle-color' | translate }}" openOnInput colorClearButton>
</div>
<div class="tb-form-row space-between column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showBorder">
{{ 'widgets.gauge.show-plate-border' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="number" appearance="outline" subscriptSizing="dynamic">
<input matInput min="0" formControlName="borderOuterWidth" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorBorder">
</tb-color-input>
</div>
</div>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.gauge.needle-settings</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.gauge.needle-circle</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="number" appearance="outline" subscriptSizing="dynamic">
<input matInput min="0" formControlName="needleCircleSize" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorNeedleCircle">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.needle-color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorNeedle">
</tb-color-input>
</section>
</fieldset>
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.gauge.animation-settings</legend>
</div>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="analogueCompassWidgetSettingsForm.get('animation').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="animation" (click)="$event.stopPropagation()"
<mat-slide-toggle class="mat-slide" formControlName="animation" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.gauge.enable-animation' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
<mat-panel-description fxFlex="40" fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<section fxLayout="column">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.animation-duration</mat-label>
<input matInput type="number" min="0" formControlName="animationDuration">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.animation-rule</mat-label>
<mat-select formControlName="animationRule">
<mat-option [value]="'linear'">
{{ 'widgets.gauge.animation-linear' | translate }}
</mat-option>
<mat-option [value]="'quad'">
{{ 'widgets.gauge.animation-quad' | translate }}
</mat-option>
<mat-option [value]="'quint'">
{{ 'widgets.gauge.animation-quint' | translate }}
</mat-option>
<mat-option [value]="'cycle'">
{{ 'widgets.gauge.animation-cycle' | translate }}
</mat-option>
<mat-option [value]="'bounce'">
{{ 'widgets.gauge.animation-bounce' | translate }}
</mat-option>
<mat-option [value]="'elastic'">
{{ 'widgets.gauge.animation-elastic' | translate }}
</mat-option>
<mat-option [value]="'dequad'">
{{ 'widgets.gauge.animation-dequad' | translate }}
</mat-option>
<mat-option [value]="'dequint'">
{{ 'widgets.gauge.animation-dequint' | translate }}
</mat-option>
<mat-option [value]="'decycle'">
{{ 'widgets.gauge.animation-decycle' | translate }}
</mat-option>
<mat-option [value]="'debounce'">
{{ 'widgets.gauge.animation-debounce' | translate }}
</mat-option>
<mat-option [value]="'delastic'">
{{ 'widgets.gauge.animation-delastic' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.animation-target</mat-label>
<div class="tb-form-row">
<div class="fixed-title-width" translate>widgets.gauge.animation-target</div>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="animationTarget">
<mat-option [value]="'needle'">
{{ 'widgets.gauge.animation-target-needle' | translate }}
@ -171,8 +145,53 @@
</mat-option>
</mat-select>
</mat-form-field>
</section>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.animation-duration-rule</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput type="number" min="0" formControlName="animationDuration" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="animationRule">
<mat-option [value]="'linear'">
{{ 'widgets.gauge.animation-linear' | translate }}
</mat-option>
<mat-option [value]="'quad'">
{{ 'widgets.gauge.animation-quad' | translate }}
</mat-option>
<mat-option [value]="'quint'">
{{ 'widgets.gauge.animation-quint' | translate }}
</mat-option>
<mat-option [value]="'cycle'">
{{ 'widgets.gauge.animation-cycle' | translate }}
</mat-option>
<mat-option [value]="'bounce'">
{{ 'widgets.gauge.animation-bounce' | translate }}
</mat-option>
<mat-option [value]="'elastic'">
{{ 'widgets.gauge.animation-elastic' | translate }}
</mat-option>
<mat-option [value]="'dequad'">
{{ 'widgets.gauge.animation-dequad' | translate }}
</mat-option>
<mat-option [value]="'dequint'">
{{ 'widgets.gauge.animation-dequint' | translate }}
</mat-option>
<mat-option [value]="'decycle'">
{{ 'widgets.gauge.animation-decycle' | translate }}
</mat-option>
<mat-option [value]="'debounce'">
{{ 'widgets.gauge.animation-debounce' | translate }}
</mat-option>
<mat-option [value]="'delastic'">
{{ 'widgets.gauge.animation-delastic' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</fieldset>
</section>
</div>
</ng-container>

42
ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-compass-widget-settings.component.ts

@ -19,9 +19,7 @@ import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { Component } from '@angular/core';
import { MatChipInputEvent } from '@angular/material/chips';
import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
@Component({
selector: 'tb-analogue-compass-widget-settings',
@ -81,6 +79,7 @@ export class AnalogueCompassWidgetSettingsComponent extends WidgetSettingsCompon
colorMinorTicks: [settings.colorMinorTicks, []],
showStrokeTicks: [settings.showStrokeTicks, []],
majorTickFont: [settings.majorTickFont, []],
majorTickColor: [settings.majorTickFont.color, []],
// Plate settings
colorPlate: [settings.colorPlate, []],
@ -131,41 +130,8 @@ export class AnalogueCompassWidgetSettingsComponent extends WidgetSettingsCompon
this.analogueCompassWidgetSettingsForm.get('animationTarget').updateValueAndValidity({emitEvent});
}
majorTicksNamesList(): string[] {
return this.analogueCompassWidgetSettingsForm.get('majorTicks').value;
}
removeMajorTickName(tickName: string): void {
const tickNames: string[] = this.analogueCompassWidgetSettingsForm.get('majorTicks').value;
const index = tickNames.indexOf(tickName);
if (index >= 0) {
tickNames.splice(index, 1);
this.analogueCompassWidgetSettingsForm.get('majorTicks').setValue(tickNames);
this.analogueCompassWidgetSettingsForm.get('majorTicks').markAsDirty();
}
}
addMajorTickName(event: MatChipInputEvent): void {
const input = event.chipInput.inputElement;
const value = event.value;
const tickNames: string[] = this.analogueCompassWidgetSettingsForm.get('majorTicks').value;
if ((value || '').trim()) {
tickNames.push(value.trim());
this.analogueCompassWidgetSettingsForm.get('majorTicks').setValue(tickNames);
this.analogueCompassWidgetSettingsForm.get('majorTicks').markAsDirty();
}
if (input) {
input.value = '';
}
}
majorTickNameDrop(event: CdkDragDrop<string[]>): void {
const tickNames: string[] = this.analogueCompassWidgetSettingsForm.get('majorTicks').value;
moveItemInArray(tickNames, event.previousIndex, event.currentIndex);
this.analogueCompassWidgetSettingsForm.get('majorTicks').setValue(tickNames);
this.analogueCompassWidgetSettingsForm.get('majorTicks').markAsDirty();
protected prepareOutputSettings(settings) {
settings.majorTickFont.color = this.analogueCompassWidgetSettingsForm.get('majorTickColor').value;
return settings;
}
}

614
ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-gauge-widget-settings.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<section class="tb-widget-settings" [formGroup]="analogueGaugeWidgetSettingsForm" fxLayout="column">
<ng-container [formGroup]="analogueGaugeWidgetSettingsForm">
<ng-container [ngSwitch]="gaugeType">
<ng-container *ngSwitchCase="'radial'">
<ng-container *ngTemplateOutlet="radialGauge; context: ctx "></ng-container>
@ -24,330 +24,382 @@
<ng-container *ngTemplateOutlet="linearGauge; context: ctx "></ng-container>
</ng-container>
</ng-container>
<tb-color-input
formControlName="defaultColor"
icon="format_color_fill"
label="{{ 'widgets.gauge.default-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.gauge.ticks-settings</legend>
<section fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.min-value</mat-label>
<input matInput type="number" formControlName="minValue">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.max-value</mat-label>
<input matInput type="number" formControlName="maxValue">
</mat-form-field>
</section>
<section fxLayout="column" fxLayout.gt-xs="row" fxLayoutGap.gt-xs="8px" fxLayoutAlign.gt-xs="start center">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.major-ticks-count</mat-label>
<input matInput type="number" min="0" formControlName="majorTicksCount">
</mat-form-field>
<tb-color-input fxFlex
formControlName="colorMajorTicks"
icon="format_color_fill"
label="{{ 'widgets.gauge.major-ticks-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
</section>
<section fxLayout="column" fxLayout.gt-xs="row" fxLayoutGap.gt-xs="8px" fxLayoutAlign.gt-xs="start center">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.minor-ticks-count</mat-label>
<input matInput type="number" min="0" formControlName="minorTicks">
</mat-form-field>
<tb-color-input fxFlex
formControlName="colorMinorTicks"
icon="format_color_fill"
label="{{ 'widgets.gauge.minor-ticks-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
</section>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.gauge.tick-numbers-font</legend>
<tb-widget-font formControlName="numbersFont"></tb-widget-font>
</fieldset>
</fieldset>
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.gauge.unit-title-settings</legend>
<mat-expansion-panel class="tb-settings" [expanded]="analogueGaugeWidgetSettingsForm.get('showUnitTitle').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="showUnitTitle" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.gauge.show-unit-title' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<section fxLayout="column">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.unit-title</mat-label>
<input matInput formControlName="unitTitle">
</mat-form-field>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.gauge.title-font</legend>
<tb-widget-font formControlName="titleFont"></tb-widget-font>
</fieldset>
</section>
</ng-template>
</mat-expansion-panel>
</fieldset>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.gauge.units-settings</legend>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.gauge.units-font</legend>
<tb-widget-font formControlName="unitsFont"></tb-widget-font>
</fieldset>
</fieldset>
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.gauge.value-box-settings</legend>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.gauge.ticks-settings</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.gauge.ticks</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<div class="tb-small-label" translate>widgets.gauge.min-value-short</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="minValue" type="number" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<div class="tb-small-label" translate>widgets.gauge.max-value-short</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="maxValue" type="number" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="numbersFont"
disabledLineHeight>
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="numbersColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.gauge.major-ticks-count</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="majorTicksCount" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorMajorTicks">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.gauge.minor-ticks-count</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="minorTicks" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorMinorTicks">
</tb-color-input>
</div>
</div>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.gauge.units-settings</div>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showUnitTitle">
{{ 'widgets.gauge.units-title' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="unitTitle" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="titleFont"
disabledLineHeight
[previewText]="analogueGaugeWidgetSettingsForm.get('unitTitle').value">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="titleColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widget-config.units-short</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="unitsFont"
disabledLineHeight>
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="unitsColor">
</tb-color-input>
</div>
</div>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="analogueGaugeWidgetSettingsForm.get('valueBox').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="valueBox" (click)="$event.stopPropagation()"
<mat-slide-toggle class="mat-slide" formControlName="valueBox" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.gauge.show-value-box' | translate }}
{{ 'widgets.gauge.value-box' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
<mat-panel-description fxFlex="40" fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<section fxLayout="column">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.value-int</mat-label>
<input matInput type="number" min="0" step="1" formControlName="valueInt">
<div class="tb-form-row space-between">
<div translate>widgets.gauge.value-int</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput type="number" min="0" step="1" formControlName="valueInt" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.gauge.value-font</legend>
<tb-widget-font formControlName="valueFont" [hasShadowColor]="true"></tb-widget-font>
</fieldset>
<section fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
<tb-color-input fxFlex
formControlName="colorValueBoxRect"
icon="format_color_fill"
label="{{ 'widgets.gauge.value-box-rect-stroke-color' | translate }}" openOnInput colorClearButton>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.gauge.value-text</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.value-text</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="valueFont"
disabledLineHeight>
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="valueColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.value-text-shadow</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="valueColorShadow">
</tb-color-input>
<tb-color-input fxFlex
formControlName="colorValueBoxRectEnd"
icon="format_color_fill"
label="{{ 'widgets.gauge.value-box-rect-stroke-color-end' | translate }}" openOnInput colorClearButton>
</div>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.gauge.value-box</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.rect-stroke-color-start</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorValueBoxRect">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.rect-stroke-color-end</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorValueBoxRectEnd">
</tb-color-input>
</section>
<section fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
<tb-color-input fxFlex
formControlName="colorValueBoxBackground"
icon="format_color_fill"
label="{{ 'widgets.gauge.value-box-background-color' | translate }}" openOnInput colorClearButton>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.background-color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorValueBoxBackground">
</tb-color-input>
<tb-color-input fxFlex
formControlName="colorValueBoxShadow"
icon="format_color_fill"
label="{{ 'widgets.gauge.value-box-shadow-color' | translate }}" openOnInput colorClearButton>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.shadow-color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorValueBoxShadow">
</tb-color-input>
</section>
</section>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</fieldset>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.gauge.plate-settings</legend>
<tb-color-input fxFlex
formControlName="colorPlate"
icon="format_color_fill"
label="{{ 'widgets.gauge.plate-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
<mat-slide-toggle formControlName="showBorder">
{{ 'widgets.gauge.show-plate-border' | translate }}
</mat-slide-toggle>
</fieldset>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.gauge.needle-settings</legend>
<section fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
<tb-color-input fxFlex
formControlName="colorNeedle"
icon="format_color_fill"
label="{{ 'widgets.gauge.needle-color' | translate }}" openOnInput colorClearButton>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.gauge.plate-settings</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.plate-color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorPlate">
</tb-color-input>
<tb-color-input fxFlex
formControlName="colorNeedleEnd"
icon="format_color_fill"
label="{{ 'widgets.gauge.needle-color-end' | translate }}" openOnInput colorClearButton>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="showBorder">
{{ 'widgets.gauge.show-plate-border' | translate }}
</mat-slide-toggle>
</div>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.gauge.needle-settings</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.needle-color-start</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorNeedle">
</tb-color-input>
</section>
<section fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
<tb-color-input fxFlex
formControlName="colorNeedleShadowUp"
icon="format_color_fill"
label="{{ 'widgets.gauge.needle-color-shadow-up' | translate }}" openOnInput colorClearButton>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.needle-color-end</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorNeedleEnd">
</tb-color-input>
<tb-color-input fxFlex
formControlName="colorNeedleShadowDown"
icon="format_color_fill"
label="{{ 'widgets.gauge.needle-color-shadow-down' | translate }}" openOnInput colorClearButton>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.needle-color-shadow-up</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorNeedleShadowUp">
</tb-color-input>
</section>
</fieldset>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.gauge.highlights-settings</legend>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.highlights-width</mat-label>
<input matInput type="number" min="0" formControlName="highlightsWidth">
</mat-form-field>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.gauge.highlights</legend>
<div fxLayout="column">
<div class="tb-control-list tb-drop-list" cdkDropList cdkDropListOrientation="vertical"
(cdkDropListDropped)="highlightDrop($event)">
<div cdkDrag class="tb-draggable" *ngFor="let highlightControl of highlightsFormArray().controls; trackBy: trackByHighlightControl;
let $index = index; last as isLast;"
fxLayout="column" [ngStyle]="!isLast ? {paddingBottom: '8px'} : {}">
<tb-gauge-highlight [formControl]="highlightControl"
[expanded]="highlightControl.new"
(removeHighlight)="removeHighlight($index)">
</tb-gauge-highlight>
</div>
</div>
<div *ngIf="!highlightsFormArray().controls.length">
<span translate fxLayoutAlign="center center"
class="tb-prompt">widgets.gauge.no-highlights</span>
</div>
<div style="padding-top: 16px;">
<button mat-raised-button color="primary"
type="button"
(click)="addHighlight()">
<span translate>widgets.gauge.add-highlight</span>
</button>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.needle-color-shadow-down</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorNeedleShadowDown">
</tb-color-input>
</div>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.gauge.scale-settings</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.scale</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput type="number" min="0" formControlName="highlightsWidth">
</mat-form-field>
<tb-color-range-settings formControlName="highlights">
</tb-color-range-settings>
</div>
</fieldset>
</fieldset>
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.gauge.animation-settings</legend>
</div>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="analogueGaugeWidgetSettingsForm.get('animation').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle formControlName="animation" (click)="$event.stopPropagation()"
<mat-slide-toggle class="mat-slide" formControlName="animation" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.gauge.enable-animation' | translate }}
</mat-slide-toggle>
</mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
<mat-panel-description fxFlex="40" fxLayoutAlign="end center" fxHide.xs translate>
widget-config.advanced-settings
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<section fxLayout="column">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.animation-duration</mat-label>
<input matInput type="number" min="0" formControlName="animationDuration">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.animation-rule</mat-label>
<mat-select formControlName="animationRule">
<mat-option [value]="'linear'">
{{ 'widgets.gauge.animation-linear' | translate }}
</mat-option>
<mat-option [value]="'quad'">
{{ 'widgets.gauge.animation-quad' | translate }}
</mat-option>
<mat-option [value]="'quint'">
{{ 'widgets.gauge.animation-quint' | translate }}
</mat-option>
<mat-option [value]="'cycle'">
{{ 'widgets.gauge.animation-cycle' | translate }}
</mat-option>
<mat-option [value]="'bounce'">
{{ 'widgets.gauge.animation-bounce' | translate }}
</mat-option>
<mat-option [value]="'elastic'">
{{ 'widgets.gauge.animation-elastic' | translate }}
</mat-option>
<mat-option [value]="'dequad'">
{{ 'widgets.gauge.animation-dequad' | translate }}
</mat-option>
<mat-option [value]="'dequint'">
{{ 'widgets.gauge.animation-dequint' | translate }}
</mat-option>
<mat-option [value]="'decycle'">
{{ 'widgets.gauge.animation-decycle' | translate }}
</mat-option>
<mat-option [value]="'debounce'">
{{ 'widgets.gauge.animation-debounce' | translate }}
</mat-option>
<mat-option [value]="'delastic'">
{{ 'widgets.gauge.animation-delastic' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</section>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.animation-duration-rule</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput type="number" min="0" formControlName="animationDuration" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="animationRule">
<mat-option [value]="'linear'">
{{ 'widgets.gauge.animation-linear' | translate }}
</mat-option>
<mat-option [value]="'quad'">
{{ 'widgets.gauge.animation-quad' | translate }}
</mat-option>
<mat-option [value]="'quint'">
{{ 'widgets.gauge.animation-quint' | translate }}
</mat-option>
<mat-option [value]="'cycle'">
{{ 'widgets.gauge.animation-cycle' | translate }}
</mat-option>
<mat-option [value]="'bounce'">
{{ 'widgets.gauge.animation-bounce' | translate }}
</mat-option>
<mat-option [value]="'elastic'">
{{ 'widgets.gauge.animation-elastic' | translate }}
</mat-option>
<mat-option [value]="'dequad'">
{{ 'widgets.gauge.animation-dequad' | translate }}
</mat-option>
<mat-option [value]="'dequint'">
{{ 'widgets.gauge.animation-dequint' | translate }}
</mat-option>
<mat-option [value]="'decycle'">
{{ 'widgets.gauge.animation-decycle' | translate }}
</mat-option>
<mat-option [value]="'debounce'">
{{ 'widgets.gauge.animation-debounce' | translate }}
</mat-option>
<mat-option [value]="'delastic'">
{{ 'widgets.gauge.animation-delastic' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</fieldset>
</section>
</div>
</ng-container>
<ng-template #radialGauge let-settingsForm="settingsForm">
<fieldset class="fields-group" [formGroup]="settingsForm">
<legend class="group-title" translate>widgets.gauge.radial-gauge-settings</legend>
<section fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px" fxLayoutAlign.gt-xs="start center">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.start-ticks-angle</mat-label>
<input matInput type="number" min="0" max="360" formControlName="startAngle">
<div class="tb-form-panel" [formGroup]="settingsForm">
<div class="tb-form-panel-title" translate>widgets.gauge.radial-gauge-settings</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.start-ticks-angle</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="startAngle" type="number" min="0" max="360" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.ticks-angle</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="ticksAngle" type="number" min="0" max="360" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.ticks-angle</mat-label>
<input matInput type="number" min="0" max="360" formControlName="ticksAngle">
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.needle-circle-size</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="needleCircleSize" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</section>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.needle-circle-size</mat-label>
<input matInput type="number" min="0" formControlName="needleCircleSize">
</mat-form-field>
</fieldset>
</div>
<ng-container *ngTemplateOutlet="arrowScaleDefaultColor"></ng-container>
</div>
</ng-template>
<ng-template #linearGauge let-settingsForm="settingsForm">
<fieldset class="fields-group" [formGroup]="settingsForm">
<legend class="group-title" translate>widgets.gauge.linear-gauge-settings</legend>
<section fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.gauge.bar-stroke-width</mat-label>
<input matInput type="number" min="0" formControlName="barStrokeWidth">
</mat-form-field>
<tb-color-input fxFlex
formControlName="colorBarStroke"
icon="format_color_fill"
label="{{ 'widgets.gauge.bar-stroke-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
</section>
<section fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
<tb-color-input fxFlex
formControlName="colorBar"
icon="format_color_fill"
label="{{ 'widgets.gauge.bar-background-color' | translate }}" openOnInput colorClearButton>
<div class="tb-form-panel" [formGroup]="settingsForm">
<div class="tb-form-panel-title" translate>widgets.gauge.linear-gauge-settings</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.bar-stroke</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput type="number" min="0" formControlName="barStrokeWidth" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorBar">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.bar-background-color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorBar">
</tb-color-input>
<tb-color-input fxFlex
formControlName="colorBarEnd"
icon="format_color_fill"
label="{{ 'widgets.gauge.bar-background-color-end' | translate }}" openOnInput colorClearButton>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.bar-background-color-end</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorBarEnd">
</tb-color-input>
</section>
<section fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
<tb-color-input fxFlex
formControlName="colorBarProgress"
icon="format_color_fill"
label="{{ 'widgets.gauge.progress-bar-color' | translate }}" openOnInput colorClearButton>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.progress-bar-color-start</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorBarProgress">
</tb-color-input>
<tb-color-input fxFlex
formControlName="colorBarProgressEnd"
icon="format_color_fill"
label="{{ 'widgets.gauge.progress-bar-color-end' | translate }}" openOnInput colorClearButton>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.gauge.progress-bar-color-end</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="colorBarProgressEnd">
</tb-color-input>
</section>
</fieldset>
</div>
<ng-container *ngTemplateOutlet="arrowScaleDefaultColor"></ng-container>
</div>
</ng-template>
<ng-template #arrowScaleDefaultColor>
<div class="tb-form-row space-between" [formGroup]="analogueGaugeWidgetSettingsForm">
<div>{{ 'widgets.gauge.arrow-and-scale-color' | translate }}</div>
<tb-color-input asBoxInput
formControlName="defaultColor">
</tb-color-input>
</div>
</ng-template>

70
ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-gauge-widget-settings.component.ts

@ -15,11 +15,9 @@
///
import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models';
import { AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { GaugeHighlight } from '@home/components/widget/lib/settings/gauge/gauge-highlight.component';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
export class AnalogueGaugeWidgetSettingsComponent extends WidgetSettingsComponent {
@ -119,19 +117,24 @@ export class AnalogueGaugeWidgetSettingsComponent extends WidgetSettingsComponen
minorTicks: [settings.majorTicksCount, [Validators.min(0)]],
colorMinorTicks: [settings.colorMinorTicks, []],
numbersFont: [settings.numbersFont, []],
numbersColor: [settings.numbersFont.color, []],
// Unit title settings
showUnitTitle: [settings.showUnitTitle, []],
unitTitle: [settings.unitTitle, []],
titleFont: [settings.titleFont, []],
titleColor: [settings.titleFont.color, []],
// Units settings
unitsFont: [settings.unitsFont, []],
unitsColor: [settings.unitsFont.color, []],
// Value box settings
valueBox: [settings.valueBox, []],
valueInt: [settings.valueInt, [Validators.min(0)]],
valueFont: [settings.valueFont, []],
valueColor: [settings.valueFont.color, []],
valueColorShadow: [settings.valueFont.shadowColor, []],
colorValueBoxRect: [settings.colorValueBoxRect, []],
colorValueBoxRectEnd: [settings.colorValueBoxRectEnd, []],
colorValueBoxBackground: [settings.colorValueBoxBackground, []],
@ -149,7 +152,7 @@ export class AnalogueGaugeWidgetSettingsComponent extends WidgetSettingsComponen
// Highlights settings
highlightsWidth: [settings.highlightsWidth, [Validators.min(0)]],
highlights: this.prepareHighlightsFormArray(settings.highlights),
highlights: [settings.highlights, []],
// Animation settings
animation: [settings.animation, []],
@ -170,13 +173,16 @@ export class AnalogueGaugeWidgetSettingsComponent extends WidgetSettingsComponen
if (showUnitTitle) {
this.analogueGaugeWidgetSettingsForm.get('unitTitle').enable();
this.analogueGaugeWidgetSettingsForm.get('titleFont').enable();
this.analogueGaugeWidgetSettingsForm.get('titleColor').enable();
} else {
this.analogueGaugeWidgetSettingsForm.get('unitTitle').disable();
this.analogueGaugeWidgetSettingsForm.get('titleFont').disable();
this.analogueGaugeWidgetSettingsForm.get('titleColor').disable();
}
if (valueBox) {
this.analogueGaugeWidgetSettingsForm.get('valueInt').enable();
this.analogueGaugeWidgetSettingsForm.get('valueFont').enable();
this.analogueGaugeWidgetSettingsForm.get('valueColor').enable();
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxRect').enable();
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxRectEnd').enable();
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxBackground').enable();
@ -184,6 +190,7 @@ export class AnalogueGaugeWidgetSettingsComponent extends WidgetSettingsComponen
} else {
this.analogueGaugeWidgetSettingsForm.get('valueInt').disable();
this.analogueGaugeWidgetSettingsForm.get('valueFont').disable();
this.analogueGaugeWidgetSettingsForm.get('valueColor').disable();
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxRect').disable();
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxRectEnd').disable();
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxBackground').disable();
@ -198,8 +205,10 @@ export class AnalogueGaugeWidgetSettingsComponent extends WidgetSettingsComponen
}
this.analogueGaugeWidgetSettingsForm.get('unitTitle').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('titleFont').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('titleColor').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('valueInt').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('valueFont').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('valueColor').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxRect').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxRectEnd').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxBackground').updateValueAndValidity({emitEvent});
@ -208,50 +217,17 @@ export class AnalogueGaugeWidgetSettingsComponent extends WidgetSettingsComponen
this.analogueGaugeWidgetSettingsForm.get('animationRule').updateValueAndValidity({emitEvent});
}
protected doUpdateSettings(settingsForm: UntypedFormGroup, settings: WidgetSettings) {
settingsForm.setControl('highlights', this.prepareHighlightsFormArray(settings.highlights), {emitEvent: false});
}
private prepareHighlightsFormArray(highlights: GaugeHighlight[] | undefined): UntypedFormArray {
const highlightsControls: Array<AbstractControl> = [];
if (highlights) {
highlights.forEach((highlight) => {
highlightsControls.push(this.fb.control(highlight, [Validators.required]));
});
protected prepareOutputSettings(settings) {
settings.numbersFont.color = this.analogueGaugeWidgetSettingsForm.get('numbersColor').value;
if (settings.titleFont) {
settings.titleFont.color = this.analogueGaugeWidgetSettingsForm.get('titleColor').value;
}
return this.fb.array(highlightsControls);
}
highlightsFormArray(): UntypedFormArray {
return this.analogueGaugeWidgetSettingsForm.get('highlights') as UntypedFormArray;
}
public trackByHighlightControl(index: number, highlightControl: AbstractControl): any {
return highlightControl;
}
public removeHighlight(index: number) {
(this.analogueGaugeWidgetSettingsForm.get('highlights') as UntypedFormArray).removeAt(index);
}
public addHighlight() {
const highlight: GaugeHighlight = {
from: null,
to: null,
color: null
};
const highlightsArray = this.analogueGaugeWidgetSettingsForm.get('highlights') as UntypedFormArray;
const highlightControl = this.fb.control(highlight, [Validators.required]);
(highlightControl as any).new = true;
highlightsArray.push(highlightControl);
this.analogueGaugeWidgetSettingsForm.updateValueAndValidity();
}
highlightDrop(event: CdkDragDrop<string[]>) {
const highlightsArray = this.analogueGaugeWidgetSettingsForm.get('highlights') as UntypedFormArray;
const highlight = highlightsArray.at(event.previousIndex);
highlightsArray.removeAt(event.previousIndex);
highlightsArray.insert(event.currentIndex, highlight);
settings.unitsFont.color = this.analogueGaugeWidgetSettingsForm.get('unitsColor').value;
if (settings.valueFont) {
settings.valueFont.color = this.analogueGaugeWidgetSettingsForm.get('valueColor').value;
settings.valueFont.shadowColor = this.analogueGaugeWidgetSettingsForm.get('valueColorShadow').value;
}
return settings;
}
}

61
ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.html

@ -1,61 +0,0 @@
<!--
Copyright © 2016-2023 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.
-->
<mat-expansion-panel class="gauge-highlight" fxFlex [formGroup]="gaugeHighlightFormGroup" [(expanded)]="expanded">
<mat-expansion-panel-header>
<div fxFlex fxLayout="row" fxLayoutAlign="start center">
<mat-panel-title>
<div fxLayout="row" fxFlex fxLayoutAlign="start center">
<div>{{ highlightRangeText() }}</div>
<div class="tb-color-preview" style="margin-left: 6px;">
<div class="tb-color-result" [ngStyle]="{background: gaugeHighlightFormGroup.get('color').value}"></div>
</div>
</div>
</mat-panel-title>
<span fxFlex></span>
<button *ngIf="!disabled" mat-icon-button style="min-width: 40px;"
type="button"
(click)="removeHighlight.emit()"
matTooltip="{{ 'action.remove' | translate }}"
matTooltipPosition="above">
<mat-icon>delete</mat-icon>
</button>
</div>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div fxLayout="column" fxLayoutGap="0.5em">
<mat-divider></mat-divider>
<section class="tb-widget-settings" fxLayout="column">
<section fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px" fxLayoutAlign.gt-xs="start center">
<mat-form-field fxFlex>
<mat-label translate>widgets.gauge.highlight-from</mat-label>
<input matInput type="number" formControlName="from">
</mat-form-field>
<mat-form-field fxFlex>
<mat-label translate>widgets.gauge.highlight-to</mat-label>
<input matInput type="number" formControlName="to">
</mat-form-field>
</section>
<tb-color-input
formControlName="color"
icon="format_color_fill"
label="{{ 'widgets.gauge.highlight-color' | translate }}" openOnInput colorClearButton>
</tb-color-input>
</section>
</div>
</ng-template>
</mat-expansion-panel>

40
ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.scss

@ -1,40 +0,0 @@
/**
* Copyright © 2016-2023 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.
*/
:host {
display: block;
.mat-expansion-panel {
box-shadow: none;
&.gauge-highlight {
border: 1px groove rgba(0, 0, 0, .25);
.mat-expansion-panel-header {
padding: 0 24px 0 8px;
&.mat-expanded {
height: 48px;
}
}
}
}
}
:host ::ng-deep {
.mat-expansion-panel {
&.gauge-highlight {
.mat-expansion-panel-body {
padding: 0 8px 8px;
}
}
}
}

116
ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.ts

@ -1,116 +0,0 @@
///
/// Copyright © 2016-2023 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, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { TranslateService } from '@ngx-translate/core';
import { isNumber } from '@core/utils';
export interface GaugeHighlight {
from: number;
to: number;
color: string;
}
@Component({
selector: 'tb-gauge-highlight',
templateUrl: './gauge-highlight.component.html',
styleUrls: ['./gauge-highlight.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => GaugeHighlightComponent),
multi: true
}
]
})
export class GaugeHighlightComponent extends PageComponent implements OnInit, ControlValueAccessor {
@Input()
disabled: boolean;
@Input()
expanded = false;
@Output()
removeHighlight = new EventEmitter();
private modelValue: GaugeHighlight;
private propagateChange = null;
public gaugeHighlightFormGroup: UntypedFormGroup;
constructor(protected store: Store<AppState>,
private translate: TranslateService,
private fb: UntypedFormBuilder) {
super(store);
}
ngOnInit(): void {
this.gaugeHighlightFormGroup = this.fb.group({
from: [null, []],
to: [null, []],
color: [null, []]
});
this.gaugeHighlightFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (isDisabled) {
this.gaugeHighlightFormGroup.disable({emitEvent: false});
} else {
this.gaugeHighlightFormGroup.enable({emitEvent: false});
}
}
writeValue(value: GaugeHighlight): void {
this.modelValue = value;
this.gaugeHighlightFormGroup.patchValue(
value, {emitEvent: false}
);
}
highlightRangeText(): string {
const value: GaugeHighlight = this.gaugeHighlightFormGroup.value;
const from = isNumber(value.from) ? value.from : 0;
const to = isNumber(value.to) ? value.to : 0;
return `${from} - ${to}`;
}
private updateModel() {
const value: GaugeHighlight = this.gaugeHighlightFormGroup.value;
this.modelValue = value;
if (this.gaugeHighlightFormGroup.valid) {
this.propagateChange(this.modelValue);
} else {
this.propagateChange(null);
}
}
}

3
ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts

@ -58,7 +58,6 @@ import {
import {
AlarmsTableKeySettingsComponent
} from '@home/components/widget/lib/settings/alarm/alarms-table-key-settings.component';
import { GaugeHighlightComponent } from '@home/components/widget/lib/settings/gauge/gauge-highlight.component';
import {
AnalogueRadialGaugeWidgetSettingsComponent
} from '@home/components/widget/lib/settings/gauge/analogue-radial-gauge-widget-settings.component';
@ -321,7 +320,6 @@ import {
EntitiesTableKeySettingsComponent,
AlarmsTableWidgetSettingsComponent,
AlarmsTableKeySettingsComponent,
GaugeHighlightComponent,
AnalogueRadialGaugeWidgetSettingsComponent,
AnalogueLinearGaugeWidgetSettingsComponent,
AnalogueCompassWidgetSettingsComponent,
@ -438,7 +436,6 @@ import {
EntitiesTableKeySettingsComponent,
AlarmsTableWidgetSettingsComponent,
AlarmsTableKeySettingsComponent,
GaugeHighlightComponent,
AnalogueRadialGaugeWidgetSettingsComponent,
AnalogueLinearGaugeWidgetSettingsComponent,
AnalogueCompassWidgetSettingsComponent,

39
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -5008,6 +5008,7 @@
"title-icon": "Title icon",
"display-icon": "Display title icon",
"card-icon": "Card icon",
"icon": "Icon",
"icon-color": "Icon color",
"icon-size": "Icon size",
"advanced-settings": "Advanced settings",
@ -5354,10 +5355,14 @@
"ticks-settings": "Ticks settings",
"min-value": "Minimum value",
"max-value": "Maximum value",
"min-value-short": "min",
"max-value-short": "max",
"start-ticks-angle": "Start ticks angle",
"ticks-angle": "Ticks angle",
"major-ticks": "Major ticks",
"major-ticks-count": "Major ticks count",
"major-ticks-color": "Major ticks color",
"minor-ticks": "Minor ticks",
"minor-ticks-count": "Minor ticks count",
"minor-ticks-color": "Minor ticks color",
"tick-numbers-font": "Tick numbers font",
@ -5369,21 +5374,29 @@
"units-font": "Units text font",
"value-box-settings": "Value box settings",
"show-value-box": "Show value box",
"value-box": "Value box",
"value-int": "Digits count for integer part of value",
"value-text": "Value text",
"value-text-shadow": "Value text shadow",
"value-font": "Value text font",
"rect-stroke-color-start": "Rectangle stroke color - start gradient",
"rect-stroke-color-end": "Rectangle stroke color - end gradient",
"background-color": "Background color",
"shadow-color": "Shadow color",
"value-box-rect-stroke-color": "Value box rectangle stroke color",
"value-box-rect-stroke-color-end": "Value box rectangle stroke color - end gradient",
"value-box-background-color": "Value box background color",
"value-box-shadow-color": "Value box shadow color",
"plate-settings": "Plate settings",
"show-plate-border": "Show plate border",
"show-plate-border": "Plate border",
"plate-color": "Plate color",
"needle-settings": "Needle settings",
"needle-circle-size": "Needle circle size",
"needle-color": "Needle color",
"needle-color-start": "Needle color - start gradient",
"needle-color-end": "Needle color - end gradient",
"needle-color-shadow-up": "Upper half of the needle shadow color",
"needle-color-shadow-down": "Drop shadow needle color",
"needle-color-shadow-down": "Drop shadow",
"highlights-settings": "Highlights settings",
"highlights-width": "Highlights width",
"highlights": "Highlights",
@ -5393,7 +5406,8 @@
"no-highlights": "No highlights configured",
"add-highlight": "Add highlight",
"animation-settings": "Animation settings",
"enable-animation": "Enable animation",
"enable-animation": "Animation",
"animation-duration-rule": "Animation duration and rule",
"animation-duration": "Animation duration",
"animation-rule": "Animation rule",
"animation-linear": "Linear",
@ -5408,17 +5422,21 @@
"animation-debounce": "Debounce",
"animation-delastic": "Delastic",
"linear-gauge-settings": "Linear gauge settings",
"bar-stroke": "Bar stroke",
"bar-stroke-width": "Bar stroke width",
"bar-stroke-color": "Bar stroke color",
"bar-background-color": "Gauge bar background color",
"bar-background-color": "Bar background color - start gradient",
"bar-background-color-end": "Bar background color - end gradient",
"progress-bar-color": "Progress bar color",
"progress-bar": "Progress bar",
"progress-bar-color-start": "Progress bar color - start gradient",
"progress-bar-color-end": "Progress bar color - end gradient",
"major-ticks-names": "Major ticks names",
"show-stroke-ticks": "Show ticks stroke",
"major-ticks-font": "Major ticks font",
"border-color": "Border color",
"border-width": "Border width",
"needle-circle": "Needle circle",
"needle-circle-color": "Needle circle color",
"animation-target": "Animation target",
"animation-target-needle": "Needle",
@ -5462,7 +5480,18 @@
"tick-color": "Tick color",
"tick-values": "Tick values",
"no-tick-values": "No tick values configured",
"add-tick-value": "Add tick value"
"add-tick-value": "Add tick value",
"gauge-appearance": "Gauge appearance",
"units-title": "Units title",
"value": "Value",
"ticks": "Ticks",
"arrow-and-scale-color": "Arrow and scale default color",
"scale-settings": "Scale settings",
"scale": "Scale",
"scale-color": "Scale colors",
"compass-appearance": "Compass appearance",
"labels": "Labels",
"label-style": "Label style"
},
"gpio": {
"pin": "Pin",

Loading…
Cancel
Save