Browse Source

UI: Add analogue gauges widget settings forms

pull/6545/head
Igor Kulikov 5 years ago
parent
commit
8fa493eb1c
  1. 15
      application/src/main/data/json/system/widget_bundles/analogue_gauges.json
  2. 1
      ui-ngx/package.json
  3. 2
      ui-ngx/src/app/modules/home/components/widget/data-keys.component.html
  4. 67
      ui-ngx/src/app/modules/home/components/widget/data-keys.component.scss
  5. 319
      ui-ngx/src/app/modules/home/components/widget/lib/analogue-compass.models.ts
  6. 10
      ui-ngx/src/app/modules/home/components/widget/lib/analogue-compass.ts
  7. 771
      ui-ngx/src/app/modules/home/components/widget/lib/analogue-gauge.models.ts
  8. 64
      ui-ngx/src/app/modules/home/components/widget/lib/analogue-linear-gauge.models.ts
  9. 9
      ui-ngx/src/app/modules/home/components/widget/lib/analogue-linear-gauge.ts
  10. 31
      ui-ngx/src/app/modules/home/components/widget/lib/analogue-radial-gauge.models.ts
  11. 10
      ui-ngx/src/app/modules/home/components/widget/lib/analogue-radial-gauge.ts
  12. 6
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.html
  13. 4
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.ts
  14. 7
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-settings.component.html
  15. 19
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-settings.component.ts
  16. 30
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-font.component.html
  17. 38
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-font.component.ts
  18. 172
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-compass-widget-settings.component.html
  19. 171
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-compass-widget-settings.component.ts
  20. 336
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-gauge-widget-settings.component.html
  21. 250
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-gauge-widget-settings.component.ts
  22. 66
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-linear-gauge-widget-settings.component.ts
  23. 57
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/analogue-radial-gauge-widget-settings.component.ts
  24. 60
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.html
  25. 28
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.scss
  26. 116
      ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.ts
  27. 33
      ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts
  28. 19
      ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.scss
  29. 20
      ui-ngx/src/app/modules/home/components/widget/widget-config.component.html
  30. 13
      ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss
  31. 19
      ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts
  32. 6
      ui-ngx/src/app/shared/shared.module.ts
  33. 104
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  34. 14
      ui-ngx/src/styles.scss
  35. 7
      ui-ngx/yarn.lock

15
application/src/main/data/json/system/widget_bundles/analogue_gauges.json

@ -18,9 +18,10 @@
"resources": [], "resources": [],
"templateHtml": "<canvas id=\"compass\"></canvas>", "templateHtml": "<canvas id=\"compass\"></canvas>",
"templateCss": "", "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.getSettingsSchema = function() {\n return TbAnalogueCompass.settingsSchema;\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", "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": "{}", "settingsSchema": "{}",
"dataKeySettingsSchema": "{}\n", "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\":{}}" "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\":{}}"
} }
}, },
@ -36,9 +37,10 @@
"resources": [], "resources": [],
"templateHtml": "<canvas id=\"linearGauge\"></canvas>\n", "templateHtml": "<canvas id=\"linearGauge\"></canvas>\n",
"templateCss": "", "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.getSettingsSchema = function() {\n return TbAnalogueLinearGauge.settingsSchema;\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", "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": "{}", "settingsSchema": "{}",
"dataKeySettingsSchema": "{}\n", "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}}" "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}}"
} }
}, },
@ -54,9 +56,10 @@
"resources": [], "resources": [],
"templateHtml": "<canvas id=\"radialGauge\"></canvas>\n", "templateHtml": "<canvas id=\"radialGauge\"></canvas>\n",
"templateCss": "", "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.getSettingsSchema = function() {\n return TbAnalogueRadialGauge.settingsSchema;\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", "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": "{}", "settingsSchema": "{}",
"dataKeySettingsSchema": "{}\n", "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}}" "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}}"
} }
}, },
@ -72,9 +75,10 @@
"resources": [], "resources": [],
"templateHtml": "<canvas id=\"radialGauge\"></canvas>\n", "templateHtml": "<canvas id=\"radialGauge\"></canvas>\n",
"templateCss": "", "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.getSettingsSchema = function() {\n return TbAnalogueRadialGauge.settingsSchema;\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", "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": "{}", "settingsSchema": "{}",
"dataKeySettingsSchema": "{}\n", "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}}" "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}}"
} }
}, },
@ -90,9 +94,10 @@
"resources": [], "resources": [],
"templateHtml": "<canvas id=\"radialGauge\"></canvas>\n", "templateHtml": "<canvas id=\"radialGauge\"></canvas>\n",
"templateCss": "", "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.getSettingsSchema = function() {\n return TbAnalogueRadialGauge.settingsSchema;\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", "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": "{}", "settingsSchema": "{}",
"dataKeySettingsSchema": "{}\n", "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}}" "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}}"
} }
} }

1
ui-ngx/package.json

@ -68,7 +68,6 @@
"ngx-clipboard": "^14.0.2", "ngx-clipboard": "^14.0.2",
"ngx-color-picker": "^11.0.0", "ngx-color-picker": "^11.0.0",
"ngx-daterangepicker-material": "^5.0.1", "ngx-daterangepicker-material": "^5.0.1",
"ngx-drag-drop": "^2.0.0",
"ngx-flowchart": "https://github.com/thingsboard/ngx-flowchart.git#release/1.0.0", "ngx-flowchart": "https://github.com/thingsboard/ngx-flowchart.git#release/1.0.0",
"ngx-hm-carousel": "^2.0.1", "ngx-hm-carousel": "^2.0.1",
"ngx-markdown": "^12.0.1", "ngx-markdown": "^12.0.1",

2
ui-ngx/src/app/modules/home/components/widget/data-keys.component.html

@ -17,7 +17,7 @@
--> -->
<mat-form-field appearance="standard" [formGroup]="keysListFormGroup" class="mat-block"> <mat-form-field appearance="standard" [formGroup]="keysListFormGroup" class="mat-block">
<mat-chip-list #chipList formControlName="keys" tb-chip-draggable (chipDrop)="onChipDrop($event)"> <mat-chip-list #chipList formControlName="keys" tb-chip-draggable (chipDrop)="onChipDrop($event)">
<mat-chip <mat-chip class="tb-datakey-chip"
*ngFor="let key of keys; let $index = index" *ngFor="let key of keys; let $index = index"
[selectable]="!disabled" [selectable]="!disabled"
[removable]="!disabled && !isEntityCountDatasource" [removable]="!disabled && !isEntityCountDatasource"

67
ui-ngx/src/app/modules/home/components/widget/data-keys.component.scss

@ -13,49 +13,48 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
:host {
.mat-chip.mat-standard-chip {
overflow: hidden;
.tb-attribute-chip { .mat-chip.mat-standard-chip.tb-datakey-chip {
max-width: 100%; overflow: hidden;
color: rgb(66, 66, 66);
font-weight: normal;
font-size: 16px;
.tb-chip-drag-handle { .tb-attribute-chip {
cursor: move; max-width: 100%;
color: rgb(66, 66, 66);
font-weight: normal;
font-size: 16px;
mat-icon { .tb-chip-drag-handle {
pointer-events: none; cursor: move;
}
}
.tb-chip-labels { mat-icon {
display: flex; pointer-events: none;
flex-direction: row; }
align-items: flex-end; }
min-width: 0;
.tb-chip-label {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tb-chip-separator { .tb-chip-labels {
white-space: pre; display: flex;
} flex-direction: row;
align-items: flex-end;
min-width: 0;
.tb-chip-label {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
.mat-chip-remove.mat-icon { .tb-chip-separator {
width: 24px; white-space: pre;
height: 24px;
font-size: 24px;
margin-left: 0;
color: inherit;
opacity: inherit;
} }
} }
.mat-chip-remove.mat-icon {
width: 24px;
height: 24px;
font-size: 24px;
margin-left: 0;
color: inherit;
opacity: inherit;
}
} }
} }

319
ui-ngx/src/app/modules/home/components/widget/lib/analogue-compass.models.ts

@ -14,7 +14,6 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { JsonSettingsSchema } from '@shared/models/widget.models';
import { FontSettings } from '@home/components/widget/lib/settings.models'; import { FontSettings } from '@home/components/widget/lib/settings.models';
import { AnimationRule, AnimationTarget } from '@home/components/widget/lib/analogue-gauge.models'; import { AnimationRule, AnimationTarget } from '@home/components/widget/lib/analogue-gauge.models';
@ -37,321 +36,3 @@ export interface AnalogueCompassSettings {
animationRule: AnimationRule; animationRule: AnimationRule;
animationTarget: AnimationTarget; animationTarget: AnimationTarget;
} }
export const analogueCompassSettingsSchema: JsonSettingsSchema = {
schema: {
type: 'object',
title: 'Settings',
properties: {
majorTicks: {
title: 'Major ticks names',
type: 'array',
items: {
title: 'Tick name',
type: 'string'
}
},
minorTicks: {
title: 'Minor ticks count',
type: 'number',
default: 22
},
showStrokeTicks: {
title: 'Show ticks stroke',
type: 'boolean',
default: false
},
needleCircleSize: {
title: 'Needle circle size',
type: 'number',
default: 15
},
showBorder: {
title: 'Show border',
type: 'boolean',
default: true
},
borderOuterWidth: {
title: 'Border width',
type: 'number',
default: 10
},
colorPlate: {
title: 'Plate color',
type: 'string',
default: '#222'
},
colorMajorTicks: {
title: 'Major ticks color',
type: 'string',
default: '#f5f5f5'
},
colorMinorTicks: {
title: 'Minor ticks color',
type: 'string',
default: '#ddd'
},
colorNeedle: {
title: 'Needle color',
type: 'string',
default: '#f08080'
},
colorNeedleCircle: {
title: 'Needle circle color',
type: 'string',
default: '#e8e8e8'
},
colorBorder: {
title: 'Border color',
type: 'string',
default: '#ccc'
},
majorTickFont: {
title: 'Major tick font',
type: 'object',
properties: {
family: {
title: 'Font family',
type: 'string',
default: 'Roboto'
},
size: {
title: 'Size',
type: 'number',
default: 20
},
style: {
title: 'Style',
type: 'string',
default: 'normal'
},
weight: {
title: 'Weight',
type: 'string',
default: '500'
},
color: {
title: 'color',
type: 'string',
default: '#ccc'
}
}
},
animation: {
title: 'Enable animation',
type: 'boolean',
default: true
},
animationDuration: {
title: 'Animation duration',
type: 'number',
default: 500
},
animationRule: {
title: 'Animation rule',
type: 'string',
default: 'cycle'
},
animationTarget: {
title: 'Animation target',
type: 'string',
default: 'needle'
}
},
required: []
},
form: [
{
key: 'majorTicks',
items: [
'majorTicks[]'
]
},
'minorTicks',
'showStrokeTicks',
'needleCircleSize',
'showBorder',
'borderOuterWidth',
{
key: 'colorPlate',
type: 'color'
},
{
key: 'colorMajorTicks',
type: 'color'
},
{
key: 'colorMinorTicks',
type: 'color'
},
{
key: 'colorNeedle',
type: 'color'
},
{
key: 'colorNeedleCircle',
type: 'color'
},
{
key: 'colorBorder',
type: 'color'
},
{
key: 'majorTickFont',
items: [
'majorTickFont.family',
'majorTickFont.size',
{
key: 'majorTickFont.style',
type: 'rc-select',
multiple: false,
items: [
{
value: 'normal',
label: 'Normal'
},
{
value: 'italic',
label: 'Italic'
},
{
value: 'oblique',
label: 'Oblique'
}
]
},
{
key: 'majorTickFont.weight',
type: 'rc-select',
multiple: false,
items: [
{
value: 'normal',
label: 'Normal'
},
{
value: 'bold',
label: 'Bold'
},
{
value: 'bolder',
label: 'Bolder'
},
{
value: 'lighter',
label: 'Lighter'
},
{
value: '100',
label: '100'
},
{
value: '200',
label: '200'
},
{
value: '300',
label: '300'
},
{
value: '400',
label: '400'
},
{
value: '500',
label: '500'
},
{
value: '600',
label: '600'
},
{
value: '700',
label: '700'
},
{
value: '800',
label: '800'
},
{
value: '900',
label: '900'
}
]
},
{
key: 'majorTickFont.color',
type: 'color'
}
]
},
'animation',
'animationDuration',
{
key: 'animationRule',
type: 'rc-select',
multiple: false,
items: [
{
value: 'linear',
label: 'Linear'
},
{
value: 'quad',
label: 'Quad'
},
{
value: 'quint',
label: 'Quint'
},
{
value: 'cycle',
label: 'Cycle'
},
{
value: 'bounce',
label: 'Bounce'
},
{
value: 'elastic',
label: 'Elastic'
},
{
value: 'dequad',
label: 'Dequad'
},
{
value: 'dequint',
label: 'Dequint'
},
{
value: 'decycle',
label: 'Decycle'
},
{
value: 'debounce',
label: 'Debounce'
},
{
value: 'delastic',
label: 'Delastic'
}
]
},
{
key: 'animationTarget',
type: 'rc-select',
multiple: false,
items: [
{
value: 'needle',
label: 'Needle'
},
{
value: 'plate',
label: 'Plate'
}
]
}
]
};

10
ui-ngx/src/app/modules/home/components/widget/lib/analogue-compass.ts

@ -17,26 +17,18 @@
import { WidgetContext } from '@home/models/widget-component.models'; import { WidgetContext } from '@home/models/widget-component.models';
import * as CanvasGauges from 'canvas-gauges'; import * as CanvasGauges from 'canvas-gauges';
import { import {
AnalogueCompassSettings, AnalogueCompassSettings
analogueCompassSettingsSchema
} from '@home/components/widget/lib/analogue-compass.models'; } from '@home/components/widget/lib/analogue-compass.models';
import { deepClone, isDefined } from '@core/utils'; import { deepClone, isDefined } from '@core/utils';
import { JsonSettingsSchema } from '@shared/models/widget.models';
import { getFontFamily } from '@home/components/widget/lib/settings.models'; import { getFontFamily } from '@home/components/widget/lib/settings.models';
import { TbBaseGauge } from '@home/components/widget/lib/analogue-gauge.models'; import { TbBaseGauge } from '@home/components/widget/lib/analogue-gauge.models';
import RadialGaugeOptions = CanvasGauges.RadialGaugeOptions; import RadialGaugeOptions = CanvasGauges.RadialGaugeOptions;
import BaseGauge = CanvasGauges.BaseGauge; import BaseGauge = CanvasGauges.BaseGauge;
import RadialGauge = CanvasGauges.RadialGauge; import RadialGauge = CanvasGauges.RadialGauge;
const analogueCompassSettingsSchemaValue = analogueCompassSettingsSchema;
// @dynamic // @dynamic
export class TbAnalogueCompass extends TbBaseGauge<AnalogueCompassSettings, RadialGaugeOptions> { export class TbAnalogueCompass extends TbBaseGauge<AnalogueCompassSettings, RadialGaugeOptions> {
static get settingsSchema(): JsonSettingsSchema {
return analogueCompassSettingsSchemaValue;
}
constructor(ctx: WidgetContext, canvasId: string) { constructor(ctx: WidgetContext, canvasId: string) {
super(ctx, canvasId); super(ctx, canvasId);
} }

771
ui-ngx/src/app/modules/home/components/widget/lib/analogue-gauge.models.ts

@ -16,7 +16,6 @@
import * as CanvasGauges from 'canvas-gauges'; import * as CanvasGauges from 'canvas-gauges';
import { FontSettings, getFontFamily } from '@home/components/widget/lib/settings.models'; import { FontSettings, getFontFamily } from '@home/components/widget/lib/settings.models';
import { JsonSettingsSchema } from '@shared/models/widget.models';
import { WidgetContext } from '@home/models/widget-component.models'; import { WidgetContext } from '@home/models/widget-component.models';
import { isDefined } from '@core/utils'; import { isDefined } from '@core/utils';
import * as tinycolor_ from 'tinycolor2'; import * as tinycolor_ from 'tinycolor2';
@ -67,776 +66,6 @@ export interface AnalogueGaugeSettings {
animationRule: AnimationRule; animationRule: AnimationRule;
} }
export const analogueGaugeSettingsSchema: JsonSettingsSchema = {
schema: {
type: 'object',
title: 'Settings',
properties: {
minValue: {
title: 'Minimum value',
type: 'number',
default: 0
},
maxValue: {
title: 'Maximum value',
type: 'number',
default: 100
},
unitTitle: {
title: 'Unit title',
type: 'string',
default: null
},
showUnitTitle: {
title: 'Show unit title',
type: 'boolean',
default: true
},
majorTicksCount: {
title: 'Major ticks count',
type: 'number',
default: null
},
minorTicks: {
title: 'Minor ticks count',
type: 'number',
default: 2
},
valueBox: {
title: 'Show value box',
type: 'boolean',
default: true
},
valueInt: {
title: 'Digits count for integer part of value',
type: 'number',
default: 3
},
defaultColor: {
title: 'Default color',
type: 'string',
default: null
},
colorPlate: {
title: 'Plate color',
type: 'string',
default: '#fff'
},
colorMajorTicks: {
title: 'Major ticks color',
type: 'string',
default: '#444'
},
colorMinorTicks: {
title: 'Minor ticks color',
type: 'string',
default: '#666'
},
colorNeedle: {
title: 'Needle color',
type: 'string',
default: null
},
colorNeedleEnd: {
title: 'Needle color - end gradient',
type: 'string',
default: null
},
colorNeedleShadowUp: {
title: 'Upper half of the needle shadow color',
type: 'string',
default: 'rgba(2,255,255,0.2)'
},
colorNeedleShadowDown: {
title: 'Drop shadow needle color.',
type: 'string',
default: 'rgba(188,143,143,0.45)'
},
colorValueBoxRect: {
title: 'Value box rectangle stroke color',
type: 'string',
default: '#888'
},
colorValueBoxRectEnd: {
title: 'Value box rectangle stroke color - end gradient',
type: 'string',
default: '#666'
},
colorValueBoxBackground: {
title: 'Value box background color',
type: 'string',
default: '#babab2'
},
colorValueBoxShadow: {
title: 'Value box shadow color',
type: 'string',
default: 'rgba(0,0,0,1)'
},
highlights: {
title: 'Highlights',
type: 'array',
items: {
title: 'Highlight',
type: 'object',
properties: {
from: {
title: 'From',
type: 'number'
},
to: {
title: 'To',
type: 'number'
},
color: {
title: 'Color',
type: 'string'
}
}
}
},
highlightsWidth: {
title: 'Highlights width',
type: 'number',
default: 15
},
showBorder: {
title: 'Show border',
type: 'boolean',
default: true
},
numbersFont: {
title: 'Tick numbers font',
type: 'object',
properties: {
family: {
title: 'Font family',
type: 'string',
default: 'Roboto'
},
size: {
title: 'Size',
type: 'number',
default: 18
},
style: {
title: 'Style',
type: 'string',
default: 'normal'
},
weight: {
title: 'Weight',
type: 'string',
default: '500'
},
color: {
title: 'color',
type: 'string',
default: null
}
}
},
titleFont: {
title: 'Title text font',
type: 'object',
properties: {
family: {
title: 'Font family',
type: 'string',
default: 'Roboto'
},
size: {
title: 'Size',
type: 'number',
default: 24
},
style: {
title: 'Style',
type: 'string',
default: 'normal'
},
weight: {
title: 'Weight',
type: 'string',
default: '500'
},
color: {
title: 'color',
type: 'string',
default: '#888'
}
}
},
unitsFont: {
title: 'Units text font',
type: 'object',
properties: {
family: {
title: 'Font family',
type: 'string',
default: 'Roboto'
},
size: {
title: 'Size',
type: 'number',
default: 22
},
style: {
title: 'Style',
type: 'string',
default: 'normal'
},
weight: {
title: 'Weight',
type: 'string',
default: '500'
},
color: {
title: 'color',
type: 'string',
default: '#888'
}
}
},
valueFont: {
title: 'Value text font',
type: 'object',
properties: {
family: {
title: 'Font family',
type: 'string',
default: 'Roboto'
},
size: {
title: 'Size',
type: 'number',
default: 40
},
style: {
title: 'Style',
type: 'string',
default: 'normal'
},
weight: {
title: 'Weight',
type: 'string',
default: '500'
},
color: {
title: 'color',
type: 'string',
default: '#444'
},
shadowColor: {
title: 'Shadow color',
type: 'string',
default: 'rgba(0,0,0,0.3)'
}
}
},
animation: {
title: 'Enable animation',
type: 'boolean',
default: true
},
animationDuration: {
title: 'Animation duration',
type: 'number',
default: 500
},
animationRule: {
title: 'Animation rule',
type: 'string',
default: 'cycle'
}
},
required: []
},
form: [
'minValue',
'maxValue',
'unitTitle',
'showUnitTitle',
'majorTicksCount',
'minorTicks',
'valueBox',
'valueInt',
{
key: 'defaultColor',
type: 'color'
},
{
key: 'colorPlate',
type: 'color'
},
{
key: 'colorMajorTicks',
type: 'color'
},
{
key: 'colorMinorTicks',
type: 'color'
},
{
key: 'colorNeedle',
type: 'color'
},
{
key: 'colorNeedleEnd',
type: 'color'
},
{
key: 'colorNeedleShadowUp',
type: 'color'
},
{
key: 'colorNeedleShadowDown',
type: 'color'
},
{
key: 'colorValueBoxRect',
type: 'color'
},
{
key: 'colorValueBoxRectEnd',
type: 'color'
},
{
key: 'colorValueBoxBackground',
type: 'color'
},
{
key: 'colorValueBoxShadow',
type: 'color'
},
{
key: 'highlights',
items: [
'highlights[].from',
'highlights[].to',
{
key: 'highlights[].color',
type: 'color'
}
]
},
'highlightsWidth',
'showBorder',
{
key: 'numbersFont',
items: [
'numbersFont.family',
'numbersFont.size',
{
key: 'numbersFont.style',
type: 'rc-select',
multiple: false,
items: [
{
value: 'normal',
label: 'Normal'
},
{
value: 'italic',
label: 'Italic'
},
{
value: 'oblique',
label: 'Oblique'
}
]
},
{
key: 'numbersFont.weight',
type: 'rc-select',
multiple: false,
items: [
{
value: 'normal',
label: 'Normal'
},
{
value: 'bold',
label: 'Bold'
},
{
value: 'bolder',
label: 'Bolder'
},
{
value: 'lighter',
label: 'Lighter'
},
{
value: '100',
label: '100'
},
{
value: '200',
label: '200'
},
{
value: '300',
label: '300'
},
{
value: '400',
label: '400'
},
{
value: '500',
label: '500'
},
{
value: '600',
label: '600'
},
{
value: '700',
label: '700'
},
{
value: '800',
label: '800'
},
{
value: '900',
label: '900'
}
]
},
{
key: 'numbersFont.color',
type: 'color'
}
]
},
{
key: 'titleFont',
items: [
'titleFont.family',
'titleFont.size',
{
key: 'titleFont.style',
type: 'rc-select',
multiple: false,
items: [
{
value: 'normal',
label: 'Normal'
},
{
value: 'italic',
label: 'Italic'
},
{
value: 'oblique',
label: 'Oblique'
}
]
},
{
key: 'titleFont.weight',
type: 'rc-select',
multiple: false,
items: [
{
value: 'normal',
label: 'Normal'
},
{
value: 'bold',
label: 'Bold'
},
{
value: 'bolder',
label: 'Bolder'
},
{
value: 'lighter',
label: 'Lighter'
},
{
value: '100',
label: '100'
},
{
value: '200',
label: '200'
},
{
value: '300',
label: '300'
},
{
value: '400',
label: '400'
},
{
value: '500',
label: '500'
},
{
value: '600',
label: '600'
},
{
value: '700',
label: '700'
},
{
value: '800',
label: '800'
},
{
value: '900',
label: '900'
}
]
},
{
key: 'titleFont.color',
type: 'color'
}
]
},
{
key: 'unitsFont',
items: [
'unitsFont.family',
'unitsFont.size',
{
key: 'unitsFont.style',
type: 'rc-select',
multiple: false,
items: [
{
value: 'normal',
label: 'Normal'
},
{
value: 'italic',
label: 'Italic'
},
{
value: 'oblique',
label: 'Oblique'
}
]
},
{
key: 'unitsFont.weight',
type: 'rc-select',
multiple: false,
items: [
{
value: 'normal',
label: 'Normal'
},
{
value: 'bold',
label: 'Bold'
},
{
value: 'bolder',
label: 'Bolder'
},
{
value: 'lighter',
label: 'Lighter'
},
{
value: '100',
label: '100'
},
{
value: '200',
label: '200'
},
{
value: '300',
label: '300'
},
{
value: '400',
label: '400'
},
{
value: '500',
label: '500'
},
{
value: '600',
label: '600'
},
{
value: '700',
label: '700'
},
{
value: '800',
label: '800'
},
{
value: '900',
label: '900'
}
]
},
{
key: 'unitsFont.color',
type: 'color'
}
]
},
{
key: 'valueFont',
items: [
'valueFont.family',
'valueFont.size',
{
key: 'valueFont.style',
type: 'rc-select',
multiple: false,
items: [
{
value: 'normal',
label: 'Normal'
},
{
value: 'italic',
label: 'Italic'
},
{
value: 'oblique',
label: 'Oblique'
}
]
},
{
key: 'valueFont.weight',
type: 'rc-select',
multiple: false,
items: [
{
value: 'normal',
label: 'Normal'
},
{
value: 'bold',
label: 'Bold'
},
{
value: 'bolder',
label: 'Bolder'
},
{
value: 'lighter',
label: 'Lighter'
},
{
value: '100',
label: '100'
},
{
value: '200',
label: '200'
},
{
value: '300',
label: '300'
},
{
value: '400',
label: '400'
},
{
value: '500',
label: '500'
},
{
value: '600',
label: '600'
},
{
value: '700',
label: '700'
},
{
value: '800',
label: '800'
},
{
value: '900',
label: '900'
}
]
},
{
key: 'valueFont.color',
type: 'color'
},
{
key: 'valueFont.shadowColor',
type: 'color'
}
]
},
'animation',
'animationDuration',
{
key: 'animationRule',
type: 'rc-select',
multiple: false,
items: [
{
value: 'linear',
label: 'Linear'
},
{
value: 'quad',
label: 'Quad'
},
{
value: 'quint',
label: 'Quint'
},
{
value: 'cycle',
label: 'Cycle'
},
{
value: 'bounce',
label: 'Bounce'
},
{
value: 'elastic',
label: 'Elastic'
},
{
value: 'dequad',
label: 'Dequad'
},
{
value: 'dequint',
label: 'Dequint'
},
{
value: 'decycle',
label: 'Decycle'
},
{
value: 'debounce',
label: 'Debounce'
},
{
value: 'delastic',
label: 'Delastic'
}
]
}
]
};
export abstract class TbBaseGauge<S, O extends GenericOptions> { export abstract class TbBaseGauge<S, O extends GenericOptions> {
private gauge: BaseGauge; private gauge: BaseGauge;

64
ui-ngx/src/app/modules/home/components/widget/lib/analogue-linear-gauge.models.ts

@ -14,9 +14,7 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { JsonSettingsSchema } from '@shared/models/widget.models'; import { AnalogueGaugeSettings } from '@home/components/widget/lib/analogue-gauge.models';
import { AnalogueGaugeSettings, analogueGaugeSettingsSchema } from '@home/components/widget/lib/analogue-gauge.models';
import { deepClone } from '@core/utils';
export interface AnalogueLinearGaugeSettings extends AnalogueGaugeSettings { export interface AnalogueLinearGaugeSettings extends AnalogueGaugeSettings {
barStrokeWidth: number; barStrokeWidth: number;
@ -26,63 +24,3 @@ export interface AnalogueLinearGaugeSettings extends AnalogueGaugeSettings {
colorBarProgress: string; colorBarProgress: string;
colorBarProgressEnd: string; colorBarProgressEnd: string;
} }
export function getAnalogueLinearGaugeSettingsSchema(): JsonSettingsSchema {
const analogueLinearGaugeSettingsSchema = deepClone(analogueGaugeSettingsSchema);
analogueLinearGaugeSettingsSchema.schema.properties =
{...analogueLinearGaugeSettingsSchema.schema.properties, ...{
barStrokeWidth: {
title: 'Bar stroke width',
type: 'number',
default: 2.5
},
colorBarStroke: {
title: 'Bar stroke color',
type: 'string',
default: null
},
colorBar: {
title: 'Bar background color',
type: 'string',
default: '#fff'
},
colorBarEnd: {
title: 'Bar background color - end gradient',
type: 'string',
default: '#ddd'
},
colorBarProgress: {
title: 'Progress bar color',
type: 'string',
default: null
},
colorBarProgressEnd: {
title: 'Progress bar color - end gradient',
type: 'string',
default: null
}}};
analogueLinearGaugeSettingsSchema.form.unshift(
'barStrokeWidth',
{
key: 'colorBarStroke',
type: 'color'
},
{
key: 'colorBar',
type: 'color'
},
{
key: 'colorBarEnd',
type: 'color'
},
{
key: 'colorBarProgress',
type: 'color'
},
{
key: 'colorBarProgressEnd',
type: 'color'
}
);
return analogueLinearGaugeSettingsSchema;
}

9
ui-ngx/src/app/modules/home/components/widget/lib/analogue-linear-gauge.ts

@ -19,8 +19,7 @@ import { JsonSettingsSchema } from '@shared/models/widget.models';
import { WidgetContext } from '@home/models/widget-component.models'; import { WidgetContext } from '@home/models/widget-component.models';
import { TbAnalogueGauge } from '@home/components/widget/lib/analogue-gauge.models'; import { TbAnalogueGauge } from '@home/components/widget/lib/analogue-gauge.models';
import { import {
AnalogueLinearGaugeSettings, AnalogueLinearGaugeSettings
getAnalogueLinearGaugeSettingsSchema
} from '@home/components/widget/lib/analogue-linear-gauge.models'; } from '@home/components/widget/lib/analogue-linear-gauge.models';
import { isDefined } from '@core/utils'; import { isDefined } from '@core/utils';
import * as tinycolor_ from 'tinycolor2'; import * as tinycolor_ from 'tinycolor2';
@ -30,15 +29,9 @@ import BaseGauge = CanvasGauges.BaseGauge;
const tinycolor = tinycolor_; const tinycolor = tinycolor_;
const analogueLinearGaugeSettingsSchemaValue = getAnalogueLinearGaugeSettingsSchema();
// @dynamic // @dynamic
export class TbAnalogueLinearGauge extends TbAnalogueGauge<AnalogueLinearGaugeSettings, LinearGaugeOptions>{ export class TbAnalogueLinearGauge extends TbAnalogueGauge<AnalogueLinearGaugeSettings, LinearGaugeOptions>{
static get settingsSchema(): JsonSettingsSchema {
return analogueLinearGaugeSettingsSchemaValue;
}
constructor(ctx: WidgetContext, canvasId: string) { constructor(ctx: WidgetContext, canvasId: string) {
super(ctx, canvasId); super(ctx, canvasId);
} }

31
ui-ngx/src/app/modules/home/components/widget/lib/analogue-radial-gauge.models.ts

@ -14,39 +14,10 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { JsonSettingsSchema } from '@shared/models/widget.models'; import { AnalogueGaugeSettings } from '@home/components/widget/lib/analogue-gauge.models';
import { AnalogueGaugeSettings, analogueGaugeSettingsSchema } from '@home/components/widget/lib/analogue-gauge.models';
import { deepClone } from '@core/utils';
export interface AnalogueRadialGaugeSettings extends AnalogueGaugeSettings { export interface AnalogueRadialGaugeSettings extends AnalogueGaugeSettings {
startAngle: number; startAngle: number;
ticksAngle: number; ticksAngle: number;
needleCircleSize: number; needleCircleSize: number;
} }
export function getAnalogueRadialGaugeSettingsSchema(): JsonSettingsSchema {
const analogueRadialGaugeSettingsSchema = deepClone(analogueGaugeSettingsSchema);
analogueRadialGaugeSettingsSchema.schema.properties =
{...analogueRadialGaugeSettingsSchema.schema.properties, ...{
startAngle: {
title: 'Start ticks angle',
type: 'number',
default: 45
},
ticksAngle: {
title: 'Ticks angle',
type: 'number',
default: 270
},
needleCircleSize: {
title: 'Needle circle size',
type: 'number',
default: 10
}}};
analogueRadialGaugeSettingsSchema.form.unshift(
'startAngle',
'ticksAngle',
'needleCircleSize'
);
return analogueRadialGaugeSettingsSchema;
}

10
ui-ngx/src/app/modules/home/components/widget/lib/analogue-radial-gauge.ts

@ -16,25 +16,17 @@
import * as CanvasGauges from 'canvas-gauges'; import * as CanvasGauges from 'canvas-gauges';
import { import {
AnalogueRadialGaugeSettings, AnalogueRadialGaugeSettings
getAnalogueRadialGaugeSettingsSchema
} from '@home/components/widget/lib/analogue-radial-gauge.models'; } from '@home/components/widget/lib/analogue-radial-gauge.models';
import { JsonSettingsSchema } from '@shared/models/widget.models';
import { WidgetContext } from '@home/models/widget-component.models'; import { WidgetContext } from '@home/models/widget-component.models';
import { TbAnalogueGauge } from '@home/components/widget/lib/analogue-gauge.models'; import { TbAnalogueGauge } from '@home/components/widget/lib/analogue-gauge.models';
import RadialGauge = CanvasGauges.RadialGauge; import RadialGauge = CanvasGauges.RadialGauge;
import RadialGaugeOptions = CanvasGauges.RadialGaugeOptions; import RadialGaugeOptions = CanvasGauges.RadialGaugeOptions;
import BaseGauge = CanvasGauges.BaseGauge; import BaseGauge = CanvasGauges.BaseGauge;
const analogueRadialGaugeSettingsSchemaValue = getAnalogueRadialGaugeSettingsSchema();
// @dynamic // @dynamic
export class TbAnalogueRadialGauge extends TbAnalogueGauge<AnalogueRadialGaugeSettings, RadialGaugeOptions>{ export class TbAnalogueRadialGauge extends TbAnalogueGauge<AnalogueRadialGaugeSettings, RadialGaugeOptions>{
static get settingsSchema(): JsonSettingsSchema {
return analogueRadialGaugeSettingsSchemaValue;
}
constructor(ctx: WidgetContext, canvasId: string) { constructor(ctx: WidgetContext, canvasId: string) {
super(ctx, canvasId); super(ctx, canvasId);
} }

6
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.html

@ -50,11 +50,11 @@
<section fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="8px"> <section fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="8px">
<mat-form-field fxFlex> <mat-form-field fxFlex>
<mat-label translate>widgets.label-widget.x-pos</mat-label> <mat-label translate>widgets.label-widget.x-pos</mat-label>
<input matInput type="number" min="0" max="100" step="1" formControlName="x"> <input matInput type="number" min="0" max="100" formControlName="x">
</mat-form-field> </mat-form-field>
<mat-form-field fxFlex> <mat-form-field fxFlex>
<mat-label translate>widgets.label-widget.y-pos</mat-label> <mat-label translate>widgets.label-widget.y-pos</mat-label>
<input matInput type="number" min="0" max="100" step="1" formControlName="y"> <input matInput type="number" min="0" max="100" formControlName="y">
</mat-form-field> </mat-form-field>
</section> </section>
</fieldset> </fieldset>
@ -64,7 +64,7 @@
</tb-color-input> </tb-color-input>
<fieldset class="fields-group"> <fieldset class="fields-group">
<legend class="group-title" translate>widgets.label-widget.font-settings</legend> <legend class="group-title" translate>widgets.label-widget.font-settings</legend>
<tb-label-widget-font formControlName="font"></tb-label-widget-font> <tb-widget-font formControlName="font" sizeTitle="widgets.widget-font.relative-font-size"></tb-widget-font>
</fieldset> </fieldset>
</section> </section>
</div> </div>

4
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.ts

@ -20,14 +20,14 @@ import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { LabelWidgetFont } from '@home/components/widget/lib/settings/cards/label-widget-font.component'; import { WidgetFont } from '@home/components/widget/lib/settings/common/widget-font.component';
export interface LabelWidgetLabel { export interface LabelWidgetLabel {
pattern: string; pattern: string;
x: number; x: number;
y: number; y: number;
backgroundColor: string; backgroundColor: string;
font: LabelWidgetFont; font: WidgetFont;
} }
@Component({ @Component({

7
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-settings.component.html

@ -23,12 +23,13 @@
<fieldset class="fields-group"> <fieldset class="fields-group">
<legend class="group-title" translate>widgets.label-widget.labels</legend> <legend class="group-title" translate>widgets.label-widget.labels</legend>
<div fxLayout="column"> <div fxLayout="column">
<div class="tb-label-widget-labels"> <div class="tb-control-list tb-drop-list" cdkDropList cdkDropListOrientation="vertical"
<div *ngFor="let labelControl of labelsFormArray().controls; trackBy: trackByLabel; (cdkDropListDropped)="labelDrop($event)">
<div cdkDrag class="tb-draggable" *ngFor="let labelControl of labelsFormArray().controls; trackBy: trackByLabel;
let $index = index; last as isLast;" let $index = index; last as isLast;"
fxLayout="column" [ngStyle]="!isLast ? {paddingBottom: '8px'} : {}"> fxLayout="column" [ngStyle]="!isLast ? {paddingBottom: '8px'} : {}">
<tb-label-widget-label [formControl]="labelControl" <tb-label-widget-label [formControl]="labelControl"
[expanded]="$index === 0" [expanded]="labelControl.new"
(removeLabel)="removeLabel($index)"> (removeLabel)="removeLabel($index)">
</tb-label-widget-label> </tb-label-widget-label>
</div> </div>

19
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-settings.component.ts

@ -20,11 +20,12 @@ import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { LabelWidgetLabel } from '@home/components/widget/lib/settings/cards/label-widget-label.component'; import { LabelWidgetLabel } from '@home/components/widget/lib/settings/cards/label-widget-label.component';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
@Component({ @Component({
selector: 'tb-label-widget-settings', selector: 'tb-label-widget-settings',
templateUrl: './label-widget-settings.component.html', templateUrl: './label-widget-settings.component.html',
styleUrls: ['./label-widget-settings.component.scss', './../widget-settings.scss'] styleUrls: ['./../widget-settings.scss']
}) })
export class LabelWidgetSettingsComponent extends WidgetSettingsComponent { export class LabelWidgetSettingsComponent extends WidgetSettingsComponent {
@ -63,8 +64,9 @@ export class LabelWidgetSettingsComponent extends WidgetSettingsComponent {
return this.labelWidgetSettingsForm.get('labels') as FormArray; return this.labelWidgetSettingsForm.get('labels') as FormArray;
} }
public trackByLabel(index: number, labelControl: AbstractControl): number { public trackByLabel(index: number, labelControl: AbstractControl): any {
return index; const label: LabelWidgetLabel = labelControl.value;
return label;
} }
public removeLabel(index: number) { public removeLabel(index: number) {
@ -86,7 +88,16 @@ export class LabelWidgetSettingsComponent extends WidgetSettingsComponent {
} }
}; };
const labelsArray = this.labelWidgetSettingsForm.get('labels') as FormArray; const labelsArray = this.labelWidgetSettingsForm.get('labels') as FormArray;
labelsArray.push(this.fb.control(label, [Validators.required])); const labelControl = this.fb.control(label, [Validators.required]);
(labelControl as any).new = true;
labelsArray.push(labelControl);
this.labelWidgetSettingsForm.updateValueAndValidity(); this.labelWidgetSettingsForm.updateValueAndValidity();
} }
labelDrop(event: CdkDragDrop<string[]>) {
const labelsArray = this.labelWidgetSettingsForm.get('labels') as FormArray;
const label = labelsArray.at(event.previousIndex);
labelsArray.removeAt(event.previousIndex);
labelsArray.insert(event.currentIndex, label);
}
} }

30
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-font.component.html → ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-font.component.html

@ -15,43 +15,43 @@
limitations under the License. limitations under the License.
--> -->
<section [formGroup]="labelWidgetFontFormGroup" fxLayout="column"> <section [formGroup]="widgetFontFormGroup" fxLayout="column">
<mat-form-field fxFlex class="mat-block"> <mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.label-widget.font-family</mat-label> <mat-label translate>widgets.widget-font.font-family</mat-label>
<input matInput formControlName="family"> <input matInput formControlName="family">
</mat-form-field> </mat-form-field>
<mat-form-field fxFlex class="mat-block"> <mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.label-widget.relative-font-size</mat-label> <mat-label translate>{{ sizeTitle }}</mat-label>
<input matInput type="number" min="1" step="1" formControlName="size"> <input matInput type="number" min="1" step="1" formControlName="size">
</mat-form-field> </mat-form-field>
<mat-form-field fxFlex class="mat-block"> <mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.label-widget.font-style</mat-label> <mat-label translate>widgets.widget-font.font-style</mat-label>
<mat-select formControlName="style"> <mat-select formControlName="style">
<mat-option [value]="'normal'"> <mat-option [value]="'normal'">
{{ 'widgets.label-widget.font-style-normal' | translate }} {{ 'widgets.widget-font.font-style-normal' | translate }}
</mat-option> </mat-option>
<mat-option [value]="'italic'"> <mat-option [value]="'italic'">
{{ 'widgets.label-widget.font-style-italic' | translate }} {{ 'widgets.widget-font.font-style-italic' | translate }}
</mat-option> </mat-option>
<mat-option [value]="'oblique'"> <mat-option [value]="'oblique'">
{{ 'widgets.label-widget.font-style-oblique' | translate }} {{ 'widgets.widget-font.font-style-oblique' | translate }}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field fxFlex class="mat-block"> <mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.label-widget.font-weight</mat-label> <mat-label translate>widgets.widget-font.font-weight</mat-label>
<mat-select formControlName="weight"> <mat-select formControlName="weight">
<mat-option [value]="'normal'"> <mat-option [value]="'normal'">
{{ 'widgets.label-widget.font-weight-normal' | translate }} {{ 'widgets.widget-font.font-weight-normal' | translate }}
</mat-option> </mat-option>
<mat-option [value]="'bold'"> <mat-option [value]="'bold'">
{{ 'widgets.label-widget.font-weight-bold' | translate }} {{ 'widgets.widget-font.font-weight-bold' | translate }}
</mat-option> </mat-option>
<mat-option [value]="'bolder'"> <mat-option [value]="'bolder'">
{{ 'widgets.label-widget.font-weight-bolder' | translate }} {{ 'widgets.widget-font.font-weight-bolder' | translate }}
</mat-option> </mat-option>
<mat-option [value]="'lighter'"> <mat-option [value]="'lighter'">
{{ 'widgets.label-widget.font-weight-lighter' | translate }} {{ 'widgets.widget-font.font-weight-lighter' | translate }}
</mat-option> </mat-option>
<mat-option [value]="'100'">100</mat-option> <mat-option [value]="'100'">100</mat-option>
<mat-option [value]="'200'">200</mat-option> <mat-option [value]="'200'">200</mat-option>
@ -66,6 +66,10 @@
</mat-form-field> </mat-form-field>
<tb-color-input <tb-color-input
formControlName="color" formControlName="color"
label="{{ 'widgets.label-widget.color' | translate }}"> label="{{ 'widgets.widget-font.color' | translate }}">
</tb-color-input>
<tb-color-input *ngIf="hasShadowColor"
formControlName="shadowColor"
label="{{ 'widgets.widget-font.shadow-color' | translate }}">
</tb-color-input> </tb-color-input>
</section> </section>

38
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-font.component.ts → ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-font.component.ts

@ -21,38 +21,45 @@ import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
export interface LabelWidgetFont { export interface WidgetFont {
family: string; family: string;
size: number; size: number;
style: 'normal' | 'italic' | 'oblique'; style: 'normal' | 'italic' | 'oblique';
weight: 'normal' | 'bold' | 'bolder' | 'lighter' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'; weight: 'normal' | 'bold' | 'bolder' | 'lighter' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900';
color: string; color: string;
shadowColor?: string;
} }
@Component({ @Component({
selector: 'tb-label-widget-font', selector: 'tb-widget-font',
templateUrl: './label-widget-font.component.html', templateUrl: './widget-font.component.html',
styleUrls: [], styleUrls: [],
providers: [ providers: [
{ {
provide: NG_VALUE_ACCESSOR, provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => LabelWidgetFontComponent), useExisting: forwardRef(() => WidgetFontComponent),
multi: true multi: true
} }
] ]
}) })
export class LabelWidgetFontComponent extends PageComponent implements OnInit, ControlValueAccessor { export class WidgetFontComponent extends PageComponent implements OnInit, ControlValueAccessor {
@HostBinding('style.display') display = 'block'; @HostBinding('style.display') display = 'block';
@Input() @Input()
disabled: boolean; disabled: boolean;
private modelValue: LabelWidgetFont; @Input()
hasShadowColor = false;
@Input()
sizeTitle = 'widgets.widget-font.size';
private modelValue: WidgetFont;
private propagateChange = null; private propagateChange = null;
public labelWidgetFontFormGroup: FormGroup; public widgetFontFormGroup: FormGroup;
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
private translate: TranslateService, private translate: TranslateService,
@ -61,14 +68,17 @@ export class LabelWidgetFontComponent extends PageComponent implements OnInit, C
} }
ngOnInit(): void { ngOnInit(): void {
this.labelWidgetFontFormGroup = this.fb.group({ this.widgetFontFormGroup = this.fb.group({
family: [null, []], family: [null, []],
size: [null, [Validators.min(1)]], size: [null, [Validators.min(1)]],
style: [null, []], style: [null, []],
weight: [null, []], weight: [null, []],
color: [null, []] color: [null, []]
}); });
this.labelWidgetFontFormGroup.valueChanges.subscribe(() => { if (this.hasShadowColor) {
this.widgetFontFormGroup.addControl('shadowColor', this.fb.control(null, []));
}
this.widgetFontFormGroup.valueChanges.subscribe(() => {
this.updateModel(); this.updateModel();
}); });
} }
@ -83,21 +93,21 @@ export class LabelWidgetFontComponent extends PageComponent implements OnInit, C
setDisabledState(isDisabled: boolean): void { setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled; this.disabled = isDisabled;
if (isDisabled) { if (isDisabled) {
this.labelWidgetFontFormGroup.disable({emitEvent: false}); this.widgetFontFormGroup.disable({emitEvent: false});
} else { } else {
this.labelWidgetFontFormGroup.enable({emitEvent: false}); this.widgetFontFormGroup.enable({emitEvent: false});
} }
} }
writeValue(value: LabelWidgetFont): void { writeValue(value: WidgetFont): void {
this.modelValue = value; this.modelValue = value;
this.labelWidgetFontFormGroup.patchValue( this.widgetFontFormGroup.patchValue(
value, {emitEvent: false} value, {emitEvent: false}
); );
} }
private updateModel() { private updateModel() {
const value: LabelWidgetFont = this.labelWidgetFontFormGroup.value; const value: WidgetFont = this.widgetFontFormGroup.value;
this.modelValue = value; this.modelValue = value;
this.propagateChange(this.modelValue); this.propagateChange(this.modelValue);
} }

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

@ -0,0 +1,172 @@
<!--
Copyright © 2016-2022 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.
-->
<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-list class="tb-drop-list"
#majorTicksNamesChipList
cdkDropList
cdkDropListOrientation="horizontal"
(cdkDropListDropped)="majorTickNameDrop($event)"
formControlName="majorTicks">
<mat-chip class="tb-draggable" cdkDrag *ngFor="let tickName of majorTicksNamesList()"
[removable]="true" (removed)="removeMajorTickName(tickName)">
{{tickName}}
<mat-icon matChipRemove>cancel</mat-icon>
</mat-chip>
<input [matChipInputFor]="majorTicksNamesChipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
matChipInputAddOnBlur
(matChipInputTokenEnd)="addMajorTickName($event)">
</mat-chip-list>
</mat-form-field>
<tb-color-input fxFlex
formControlName="colorMajorTicks"
label="{{ 'widgets.gauge.major-ticks-color' | translate }}">
</tb-color-input>
<section fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="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"
label="{{ 'widgets.gauge.minor-ticks-color' | translate }}">
</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"
label="{{ 'widgets.gauge.plate-color' | translate }}">
</tb-color-input>
<mat-slide-toggle formControlName="showBorder" class="slide-block">
{{ 'widgets.gauge.show-plate-border' | translate }}
</mat-slide-toggle>
<section fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="start center">
<tb-color-input fxFlex
formControlName="colorBorder"
label="{{ 'widgets.gauge.border-color' | translate }}">
</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" fxLayoutGap="8px" fxLayoutAlign="start center">
<tb-color-input fxFlex
formControlName="colorNeedle"
label="{{ 'widgets.gauge.needle-color' | translate }}">
</tb-color-input>
<tb-color-input fxFlex
formControlName="colorNeedleCircle"
label="{{ 'widgets.gauge.needle-circle-color' | translate }}">
</tb-color-input>
</section>
</fieldset>
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.gauge.animation-settings</legend>
<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()"
fxLayoutAlign="center">
{{ 'widgets.gauge.enable-animation' | 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.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>
<mat-select formControlName="animationTarget">
<mat-option [value]="'needle'">
{{ 'widgets.gauge.animation-target-needle' | translate }}
</mat-option>
<mat-option [value]="'plate'">
{{ 'widgets.gauge.animation-target-plate' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</section>
</ng-template>
</mat-expansion-panel>
</fieldset>
</section>

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

@ -0,0 +1,171 @@
///
/// Copyright © 2016-2022 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 { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models';
import { FormBuilder, FormGroup, 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',
templateUrl: './analogue-compass-widget-settings.component.html',
styleUrls: ['./../widget-settings.scss']
})
export class AnalogueCompassWidgetSettingsComponent extends WidgetSettingsComponent {
readonly separatorKeysCodes: number[] = [ENTER, COMMA, SEMICOLON];
analogueCompassWidgetSettingsForm: FormGroup;
constructor(protected store: Store<AppState>,
protected fb: FormBuilder) {
super(store);
}
protected settingsForm(): FormGroup {
return this.analogueCompassWidgetSettingsForm;
}
protected defaultSettings(): WidgetSettings {
return {
majorTicks: [],
minorTicks: 22,
showStrokeTicks: false,
needleCircleSize: 10,
showBorder: true,
borderOuterWidth: 10,
colorPlate: '#222',
colorMajorTicks: '#f5f5f5',
colorMinorTicks: '#ddd',
colorNeedle: '#f08080',
colorNeedleCircle: '#e8e8e8',
colorBorder: '#ccc',
majorTickFont: {
family: 'Roboto',
size: 20,
style: 'normal',
weight: '500',
color: '#ccc'
},
animation: true,
animationDuration: 500,
animationRule: 'cycle',
animationTarget: 'needle'
};
}
protected onSettingsSet(settings: WidgetSettings) {
this.analogueCompassWidgetSettingsForm = this.fb.group({
// Ticks settings
majorTicks: [settings.majorTicks, []],
colorMajorTicks: [settings.colorMajorTicks, []],
minorTicks: [settings.minorTicks, [Validators.min(0)]],
colorMinorTicks: [settings.colorMinorTicks, []],
showStrokeTicks: [settings.showStrokeTicks, []],
majorTickFont: [settings.majorTickFont, []],
// Plate settings
colorPlate: [settings.colorPlate, []],
showBorder: [settings.showBorder, []],
colorBorder: [settings.colorBorder, []],
borderOuterWidth: [settings.borderOuterWidth, [Validators.min(0)]],
// Needle settings
needleCircleSize: [settings.needleCircleSize, [Validators.min(0)]],
colorNeedle: [settings.colorNeedle, []],
colorNeedleCircle: [settings.colorNeedleCircle, []],
// Animation settings
animation: [settings.animation, []],
animationDuration: [settings.animationDuration, [Validators.min(0)]],
animationRule: [settings.animationRule, []],
animationTarget: [settings.animationTarget, []]
});
}
protected validatorTriggers(): string[] {
return ['showBorder', 'animation'];
}
protected updateValidators(emitEvent: boolean) {
const showBorder: boolean = this.analogueCompassWidgetSettingsForm.get('showBorder').value;
const animation: boolean = this.analogueCompassWidgetSettingsForm.get('animation').value;
if (showBorder) {
this.analogueCompassWidgetSettingsForm.get('colorBorder').enable();
this.analogueCompassWidgetSettingsForm.get('borderOuterWidth').enable();
} else {
this.analogueCompassWidgetSettingsForm.get('colorBorder').disable();
this.analogueCompassWidgetSettingsForm.get('borderOuterWidth').disable();
}
if (animation) {
this.analogueCompassWidgetSettingsForm.get('animationDuration').enable();
this.analogueCompassWidgetSettingsForm.get('animationRule').enable();
this.analogueCompassWidgetSettingsForm.get('animationTarget').enable();
} else {
this.analogueCompassWidgetSettingsForm.get('animationDuration').disable();
this.analogueCompassWidgetSettingsForm.get('animationRule').disable();
this.analogueCompassWidgetSettingsForm.get('animationTarget').disable();
}
this.analogueCompassWidgetSettingsForm.get('colorBorder').updateValueAndValidity({emitEvent});
this.analogueCompassWidgetSettingsForm.get('borderOuterWidth').updateValueAndValidity({emitEvent});
this.analogueCompassWidgetSettingsForm.get('animationDuration').updateValueAndValidity({emitEvent});
this.analogueCompassWidgetSettingsForm.get('animationRule').updateValueAndValidity({emitEvent});
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.input;
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();
}
}

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

@ -0,0 +1,336 @@
<!--
Copyright © 2016-2022 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.
-->
<section class="tb-widget-settings" [formGroup]="analogueGaugeWidgetSettingsForm" fxLayout="column">
<ng-container [ngSwitch]="gaugeType">
<ng-container *ngSwitchCase="'radial'">
<ng-container *ngTemplateOutlet="radialGauge; context: ctx "></ng-container>
</ng-container>
<ng-container *ngSwitchCase="'linear'">
<ng-container *ngTemplateOutlet="linearGauge; context: ctx "></ng-container>
</ng-container>
</ng-container>
<tb-color-input
formControlName="defaultColor"
label="{{ 'widgets.gauge.default-color' | translate }}">
</tb-color-input>
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.gauge.ticks-settings</legend>
<section fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="start center">
<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="row" fxLayoutGap="8px" fxLayoutAlign="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"
label="{{ 'widgets.gauge.major-ticks-color' | translate }}">
</tb-color-input>
</section>
<section fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="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"
label="{{ 'widgets.gauge.minor-ticks-color' | translate }}">
</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>
<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()"
fxLayoutAlign="center">
{{ 'widgets.gauge.show-value-box' | 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.value-int</mat-label>
<input matInput type="number" min="0" step="1" formControlName="valueInt">
</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" fxLayoutGap="8px" fxLayoutAlign="start center">
<tb-color-input fxFlex
formControlName="colorValueBoxRect"
label="{{ 'widgets.gauge.value-box-rect-stroke-color' | translate }}">
</tb-color-input>
<tb-color-input fxFlex
formControlName="colorValueBoxRectEnd"
label="{{ 'widgets.gauge.value-box-rect-stroke-color-end' | translate }}">
</tb-color-input>
</section>
<section fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="start center">
<tb-color-input fxFlex
formControlName="colorValueBoxBackground"
label="{{ 'widgets.gauge.value-box-background-color' | translate }}">
</tb-color-input>
<tb-color-input fxFlex
formControlName="colorValueBoxShadow"
label="{{ 'widgets.gauge.value-box-shadow-color' | translate }}">
</tb-color-input>
</section>
</section>
</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"
label="{{ 'widgets.gauge.plate-color' | translate }}">
</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" fxLayoutGap="8px" fxLayoutAlign="start center">
<tb-color-input fxFlex
formControlName="colorNeedle"
label="{{ 'widgets.gauge.needle-color' | translate }}">
</tb-color-input>
<tb-color-input fxFlex
formControlName="colorNeedleEnd"
label="{{ 'widgets.gauge.needle-color-end' | translate }}">
</tb-color-input>
</section>
<section fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="start center">
<tb-color-input fxFlex
formControlName="colorNeedleShadowUp"
label="{{ 'widgets.gauge.needle-color-shadow-up' | translate }}">
</tb-color-input>
<tb-color-input fxFlex
formControlName="colorNeedleShadowDown"
label="{{ 'widgets.gauge.needle-color-shadow-down' | translate }}">
</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: trackByHighlight;
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>
</fieldset>
</fieldset>
<fieldset class="fields-group fields-group-slider">
<legend class="group-title" translate>widgets.gauge.animation-settings</legend>
<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()"
fxLayoutAlign="center">
{{ 'widgets.gauge.enable-animation' | 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.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>
</ng-template>
</mat-expansion-panel>
</fieldset>
</section>
<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" fxLayoutGap="8px" fxLayoutAlign="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">
</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">
</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>
</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" fxLayoutGap="8px" fxLayoutAlign="start center">
<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"
label="{{ 'widgets.gauge.bar-stroke-color' | translate }}">
</tb-color-input>
</section>
<section fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="start center">
<tb-color-input fxFlex
formControlName="colorBar"
label="{{ 'widgets.gauge.bar-background-color' | translate }}">
</tb-color-input>
<tb-color-input fxFlex
formControlName="colorBarEnd"
label="{{ 'widgets.gauge.bar-background-color-end' | translate }}">
</tb-color-input>
</section>
<section fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="start center">
<tb-color-input fxFlex
formControlName="colorBarProgress"
label="{{ 'widgets.gauge.progress-bar-color' | translate }}">
</tb-color-input>
<tb-color-input fxFlex
formControlName="colorBarProgressEnd"
label="{{ 'widgets.gauge.progress-bar-color-end' | translate }}">
</tb-color-input>
</section>
</fieldset>
</ng-template>

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

@ -0,0 +1,250 @@
///
/// Copyright © 2016-2022 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 { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models';
import { AbstractControl, FormArray, FormBuilder, FormGroup, 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, moveItemInArray } from '@angular/cdk/drag-drop';
export class AnalogueGaugeWidgetSettingsComponent extends WidgetSettingsComponent {
analogueGaugeWidgetSettingsForm: FormGroup;
ctx = {
settingsForm: null
};
constructor(protected store: Store<AppState>,
protected fb: FormBuilder) {
super(store);
}
protected settingsForm(): FormGroup {
return this.analogueGaugeWidgetSettingsForm;
}
protected defaultSettings(): WidgetSettings {
return {
startAngle: 45,
ticksAngle: 270,
needleCircleSize: 10,
minValue: 0,
maxValue: 100,
showUnitTitle: true,
unitTitle: null,
majorTicksCount: null,
minorTicks: 2,
valueBox: true,
valueInt: 3,
defaultColor: null,
colorPlate: '#fff',
colorMajorTicks: '#444',
colorMinorTicks: '#666',
colorNeedle: null,
colorNeedleEnd: null,
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)',
highlights: [],
highlightsWidth: 15,
showBorder: true,
numbersFont: {
family: 'Roboto',
size: 18,
style: 'normal',
weight: '500',
color: null
},
titleFont: {
family: 'Roboto',
size: 24,
style: 'normal',
weight: '500',
color: '#888'
},
unitsFont: {
family: 'Roboto',
size: 22,
style: 'normal',
weight: '500',
color: '#888'
},
valueFont: {
family: 'Roboto',
size: 40,
style: 'normal',
weight: '500',
color: '#444',
shadowColor: 'rgba(0,0,0,0.3)'
},
animation: true,
animationDuration: 500,
animationRule: 'cycle'
};
}
protected onSettingsSet(settings: WidgetSettings) {
const highlightsControls: Array<AbstractControl> = [];
if (settings.highlights) {
settings.highlights.forEach((highlight) => {
highlightsControls.push(this.fb.control(highlight, [Validators.required]));
});
}
this.analogueGaugeWidgetSettingsForm = this.fb.group({
// Radial gauge settings
startAngle: [settings.startAngle, [Validators.min(0), Validators.max(360)]],
ticksAngle: [settings.ticksAngle, [Validators.min(0), Validators.max(360)]],
needleCircleSize: [settings.needleCircleSize, [Validators.min(0)]],
defaultColor: [settings.defaultColor, []],
// Ticks settings
minValue: [settings.minValue, []],
maxValue: [settings.maxValue, []],
majorTicksCount: [settings.majorTicksCount, [Validators.min(0)]],
colorMajorTicks: [settings.colorMajorTicks, []],
minorTicks: [settings.majorTicksCount, [Validators.min(0)]],
colorMinorTicks: [settings.colorMinorTicks, []],
numbersFont: [settings.numbersFont, []],
// Unit title settings
showUnitTitle: [settings.showUnitTitle, []],
unitTitle: [settings.unitTitle, []],
titleFont: [settings.titleFont, []],
// Units settings
unitsFont: [settings.unitsFont, []],
// Value box settings
valueBox: [settings.valueBox, []],
valueInt: [settings.valueInt, [Validators.min(0)]],
valueFont: [settings.valueFont, []],
colorValueBoxRect: [settings.colorValueBoxRect, []],
colorValueBoxRectEnd: [settings.colorValueBoxRectEnd, []],
colorValueBoxBackground: [settings.colorValueBoxBackground, []],
colorValueBoxShadow: [settings.colorValueBoxShadow, []],
// Plate settings
showBorder: [settings.showBorder, []],
colorPlate: [settings.colorPlate, []],
// Needle settings
colorNeedle: [settings.colorNeedle, []],
colorNeedleEnd: [settings.colorNeedleEnd, []],
colorNeedleShadowUp: [settings.colorNeedleShadowUp, []],
colorNeedleShadowDown: [settings.colorNeedleShadowDown, []],
// Highlights settings
highlightsWidth: [settings.highlightsWidth, [Validators.min(0)]],
highlights: this.fb.array(highlightsControls),
// Animation settings
animation: [settings.animation, []],
animationDuration: [settings.animationDuration, [Validators.min(0)]],
animationRule: [settings.animationRule, []],
});
this.ctx.settingsForm = this.analogueGaugeWidgetSettingsForm;
}
protected validatorTriggers(): string[] {
return ['showUnitTitle', 'valueBox', 'animation'];
}
protected updateValidators(emitEvent: boolean) {
const showUnitTitle: boolean = this.analogueGaugeWidgetSettingsForm.get('showUnitTitle').value;
const valueBox: boolean = this.analogueGaugeWidgetSettingsForm.get('valueBox').value;
const animation: boolean = this.analogueGaugeWidgetSettingsForm.get('animation').value;
if (showUnitTitle) {
this.analogueGaugeWidgetSettingsForm.get('unitTitle').enable();
this.analogueGaugeWidgetSettingsForm.get('titleFont').enable();
} else {
this.analogueGaugeWidgetSettingsForm.get('unitTitle').disable();
this.analogueGaugeWidgetSettingsForm.get('titleFont').disable();
}
if (valueBox) {
this.analogueGaugeWidgetSettingsForm.get('valueInt').enable();
this.analogueGaugeWidgetSettingsForm.get('valueFont').enable();
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxRect').enable();
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxRectEnd').enable();
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxBackground').enable();
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxShadow').enable();
} else {
this.analogueGaugeWidgetSettingsForm.get('valueInt').disable();
this.analogueGaugeWidgetSettingsForm.get('valueFont').disable();
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxRect').disable();
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxRectEnd').disable();
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxBackground').disable();
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxShadow').disable();
}
if (animation) {
this.analogueGaugeWidgetSettingsForm.get('animationDuration').enable();
this.analogueGaugeWidgetSettingsForm.get('animationRule').enable();
} else {
this.analogueGaugeWidgetSettingsForm.get('animationDuration').disable();
this.analogueGaugeWidgetSettingsForm.get('animationRule').disable();
}
this.analogueGaugeWidgetSettingsForm.get('unitTitle').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('titleFont').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('valueInt').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('valueFont').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxRect').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxRectEnd').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxBackground').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('colorValueBoxShadow').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('animationDuration').updateValueAndValidity({emitEvent});
this.analogueGaugeWidgetSettingsForm.get('animationRule').updateValueAndValidity({emitEvent});
}
highlightsFormArray(): FormArray {
return this.analogueGaugeWidgetSettingsForm.get('highlights') as FormArray;
}
public trackByHighlight(index: number, highlightControl: AbstractControl): any {
const highlight: GaugeHighlight = highlightControl.value;
return highlight;
}
public removeHighlight(index: number) {
(this.analogueGaugeWidgetSettingsForm.get('highlights') as FormArray).removeAt(index);
}
public addHighlight() {
const highlight: GaugeHighlight = {
from: null,
to: null,
color: null
};
const highlightsArray = this.analogueGaugeWidgetSettingsForm.get('highlights') as FormArray;
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 FormArray;
const highlight = highlightsArray.at(event.previousIndex);
highlightsArray.removeAt(event.previousIndex);
highlightsArray.insert(event.currentIndex, highlight);
}
}

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

@ -0,0 +1,66 @@
///
/// Copyright © 2016-2022 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 { WidgetSettings } from '@shared/models/widget.models';
import { FormBuilder, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import {
AnalogueGaugeWidgetSettingsComponent
} from '@home/components/widget/lib/settings/gauge/analogue-gauge-widget-settings.component';
@Component({
selector: 'tb-analogue-linear-gauge-widget-settings',
templateUrl: './analogue-gauge-widget-settings.component.html',
styleUrls: ['./../widget-settings.scss']
})
export class AnalogueLinearGaugeWidgetSettingsComponent extends AnalogueGaugeWidgetSettingsComponent {
gaugeType = 'linear';
constructor(protected store: Store<AppState>,
protected fb: FormBuilder) {
super(store, fb);
}
protected defaultSettings(): WidgetSettings {
const settings = super.defaultSettings();
settings.barStrokeWidth = 2.5;
settings.colorBarStroke = null;
settings.colorBar = '#fff';
settings.colorBarEnd = '#ddd';
settings.colorBarProgress = null;
settings.colorBarProgressEnd = null;
return settings;
}
protected onSettingsSet(settings: WidgetSettings) {
super.onSettingsSet(settings);
this.analogueGaugeWidgetSettingsForm.addControl('barStrokeWidth',
this.fb.control(settings.barStrokeWidth, [Validators.min(0)]));
this.analogueGaugeWidgetSettingsForm.addControl('colorBarStroke',
this.fb.control(settings.colorBarStroke, []));
this.analogueGaugeWidgetSettingsForm.addControl('colorBar',
this.fb.control(settings.colorBar, []));
this.analogueGaugeWidgetSettingsForm.addControl('colorBarEnd',
this.fb.control(settings.colorBarEnd, []));
this.analogueGaugeWidgetSettingsForm.addControl('colorBarProgress',
this.fb.control(settings.colorBarProgress, []));
this.analogueGaugeWidgetSettingsForm.addControl('colorBarProgressEnd',
this.fb.control(settings.colorBarProgressEnd, []));
}
}

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

@ -0,0 +1,57 @@
///
/// Copyright © 2016-2022 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 { WidgetSettings } from '@shared/models/widget.models';
import { FormBuilder, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import {
AnalogueGaugeWidgetSettingsComponent
} from '@home/components/widget/lib/settings/gauge/analogue-gauge-widget-settings.component';
@Component({
selector: 'tb-analogue-radial-gauge-widget-settings',
templateUrl: './analogue-gauge-widget-settings.component.html',
styleUrls: ['./../widget-settings.scss']
})
export class AnalogueRadialGaugeWidgetSettingsComponent extends AnalogueGaugeWidgetSettingsComponent {
gaugeType = 'radial';
constructor(protected store: Store<AppState>,
protected fb: FormBuilder) {
super(store, fb);
}
protected defaultSettings(): WidgetSettings {
const settings = super.defaultSettings();
settings.startAngle = 45;
settings.ticksAngle = 270;
settings.needleCircleSize = 10;
return settings;
}
protected onSettingsSet(settings: WidgetSettings) {
super.onSettingsSet(settings);
this.analogueGaugeWidgetSettingsForm.addControl('startAngle',
this.fb.control(settings.startAngle, [Validators.min(0), Validators.max(360)]));
this.analogueGaugeWidgetSettingsForm.addControl('ticksAngle',
this.fb.control(settings.ticksAngle, [Validators.min(0), Validators.max(360)]));
this.analogueGaugeWidgetSettingsForm.addControl('needleCircleSize',
this.fb.control(settings.needleCircleSize, [Validators.min(0)]));
}
}

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

@ -0,0 +1,60 @@
<!--
Copyright © 2016-2022 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" fxLayoutGap="8px" fxLayoutAlign="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"
label="{{ 'widgets.gauge.highlight-color' | translate }}">
</tb-color-input>
</section>
</div>
</ng-template>
</mat-expansion-panel>

28
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-settings.component.scss → ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.scss

@ -13,20 +13,28 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
@import '../../../../../../../../scss/constants';
:host { :host {
.tb-label-widget-labels { display: block;
overflow-y: auto; .mat-expansion-panel {
&.mat-padding { box-shadow: none;
padding: 8px; &.gauge-highlight {
@media #{$mat-gt-sm} { border: 1px groove rgba(0, 0, 0, .25);
padding: 16px; .mat-expansion-panel-header {
padding: 0 24px 0 8px;
&.mat-expanded {
height: 48px;
}
} }
} }
} }
}
.tb-prompt{ :host ::ng-deep {
margin: 30px 0; .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

@ -0,0 +1,116 @@
///
/// Copyright © 2016-2022 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, FormBuilder, FormGroup, 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', './../widget-settings.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: FormGroup;
constructor(protected store: Store<AppState>,
private translate: TranslateService,
private fb: FormBuilder) {
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);
}
}
}

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

@ -32,7 +32,7 @@ import {
import { import {
MarkdownWidgetSettingsComponent MarkdownWidgetSettingsComponent
} from '@home/components/widget/lib/settings/cards/markdown-widget-settings.component'; } from '@home/components/widget/lib/settings/cards/markdown-widget-settings.component';
import { LabelWidgetFontComponent } from '@home/components/widget/lib/settings/cards/label-widget-font.component'; import { WidgetFontComponent } from '@home/components/widget/lib/settings/common/widget-font.component';
import { LabelWidgetLabelComponent } from '@home/components/widget/lib/settings/cards/label-widget-label.component'; import { LabelWidgetLabelComponent } from '@home/components/widget/lib/settings/cards/label-widget-label.component';
import { LabelWidgetSettingsComponent } from '@home/components/widget/lib/settings/cards/label-widget-settings.component'; import { LabelWidgetSettingsComponent } from '@home/components/widget/lib/settings/cards/label-widget-settings.component';
import { import {
@ -59,6 +59,16 @@ import {
import { import {
AlarmsTableKeySettingsComponent AlarmsTableKeySettingsComponent
} from '@home/components/widget/lib/settings/alarm/alarms-table-key-settings.component'; } 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';
import {
AnalogueLinearGaugeWidgetSettingsComponent
} from '@home/components/widget/lib/settings/gauge/analogue-linear-gauge-widget-settings.component';
import {
AnalogueCompassWidgetSettingsComponent
} from '@home/components/widget/lib/settings/gauge/analogue-compass-widget-settings.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -67,7 +77,7 @@ import {
TimeseriesTableKeySettingsComponent, TimeseriesTableKeySettingsComponent,
TimeseriesTableLatestKeySettingsComponent, TimeseriesTableLatestKeySettingsComponent,
MarkdownWidgetSettingsComponent, MarkdownWidgetSettingsComponent,
LabelWidgetFontComponent, WidgetFontComponent,
LabelWidgetLabelComponent, LabelWidgetLabelComponent,
LabelWidgetSettingsComponent, LabelWidgetSettingsComponent,
SimpleCardWidgetSettingsComponent, SimpleCardWidgetSettingsComponent,
@ -77,7 +87,11 @@ import {
EntitiesTableWidgetSettingsComponent, EntitiesTableWidgetSettingsComponent,
EntitiesTableKeySettingsComponent, EntitiesTableKeySettingsComponent,
AlarmsTableWidgetSettingsComponent, AlarmsTableWidgetSettingsComponent,
AlarmsTableKeySettingsComponent AlarmsTableKeySettingsComponent,
GaugeHighlightComponent,
AnalogueRadialGaugeWidgetSettingsComponent,
AnalogueLinearGaugeWidgetSettingsComponent,
AnalogueCompassWidgetSettingsComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
@ -90,7 +104,7 @@ import {
TimeseriesTableKeySettingsComponent, TimeseriesTableKeySettingsComponent,
TimeseriesTableLatestKeySettingsComponent, TimeseriesTableLatestKeySettingsComponent,
MarkdownWidgetSettingsComponent, MarkdownWidgetSettingsComponent,
LabelWidgetFontComponent, WidgetFontComponent,
LabelWidgetLabelComponent, LabelWidgetLabelComponent,
LabelWidgetSettingsComponent, LabelWidgetSettingsComponent,
SimpleCardWidgetSettingsComponent, SimpleCardWidgetSettingsComponent,
@ -100,7 +114,11 @@ import {
EntitiesTableWidgetSettingsComponent, EntitiesTableWidgetSettingsComponent,
EntitiesTableKeySettingsComponent, EntitiesTableKeySettingsComponent,
AlarmsTableWidgetSettingsComponent, AlarmsTableWidgetSettingsComponent,
AlarmsTableKeySettingsComponent AlarmsTableKeySettingsComponent,
GaugeHighlightComponent,
AnalogueRadialGaugeWidgetSettingsComponent,
AnalogueLinearGaugeWidgetSettingsComponent,
AnalogueCompassWidgetSettingsComponent
] ]
}) })
export class WidgetSettingsModule { export class WidgetSettingsModule {
@ -120,5 +138,8 @@ export const widgetSettingsComponentsMap: {[key: string]: Type<IWidgetSettingsCo
'tb-entities-table-widget-settings': EntitiesTableWidgetSettingsComponent, 'tb-entities-table-widget-settings': EntitiesTableWidgetSettingsComponent,
'tb-entities-table-key-settings': EntitiesTableKeySettingsComponent, 'tb-entities-table-key-settings': EntitiesTableKeySettingsComponent,
'tb-alarms-table-widget-settings': AlarmsTableWidgetSettingsComponent, 'tb-alarms-table-widget-settings': AlarmsTableWidgetSettingsComponent,
'tb-alarms-table-key-settings': AlarmsTableKeySettingsComponent 'tb-alarms-table-key-settings': AlarmsTableKeySettingsComponent,
'tb-analogue-radial-gauge-widget-settings': AnalogueRadialGaugeWidgetSettingsComponent,
'tb-analogue-linear-gauge-widget-settings': AnalogueLinearGaugeWidgetSettingsComponent,
'tb-analogue-compass-widget-settings': AnalogueCompassWidgetSettingsComponent
}; };

19
ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.scss

@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
@import '../../../../../../../scss/constants';
:host { :host {
.tb-widget-settings { .tb-widget-settings {
.fields-group { .fields-group {
@ -27,6 +30,7 @@
} }
legend + * { legend + * {
display: block;
margin-top: 16px; margin-top: 16px;
} }
@ -43,6 +47,20 @@
} }
} }
} }
.tb-control-list {
overflow-y: auto;
&.mat-padding {
padding: 8px;
@media #{$mat-gt-sm} {
padding: 16px;
}
}
}
.tb-prompt{
margin: 30px 0;
}
} }
} }
@ -109,5 +127,6 @@
.mat-slide-toggle-content { .mat-slide-toggle-content {
white-space: normal; white-space: normal;
} }
} }
} }

20
ui-ngx/src/app/modules/home/components/widget/widget-config.component.html

@ -110,23 +110,21 @@
</div> </div>
</div> </div>
<div style="overflow: auto; padding-bottom: 15px;"> <div style="overflow: auto; padding-bottom: 15px;">
<mat-list dndDropzone dndEffectAllowed="move" <mat-list class="tb-drop-list"
(dndDrop)="onDatasourceDrop($event)" cdkDropList
[dndDisableIf]="disabled" formArrayName="datasources"> cdkDropListOrientation="vertical"
<mat-list-item dndPlaceholderRef (cdkDropListDropped)="onDatasourceDrop($event)"
class="dndPlaceholder"> [cdkDropListDisabled]="disabled"
</mat-list-item> formArrayName="datasources">
<mat-list-item *ngFor="let datasourceControl of datasourcesFormArray().controls; let $index = index;" <mat-list-item *ngFor="let datasourceControl of datasourcesFormArray().controls; let $index = index;"
[dndDraggable]="datasourceControl.value" class="tb-datasource-list-item tb-draggable" cdkDrag
(dndMoved)="dndDatasourceMoved($index)" [cdkDragDisabled]="disabled">
[dndDisableIf]="disabled"
dndEffectAllowed="move">
<div fxFlex fxLayout="row" fxLayoutAlign="start center"> <div fxFlex fxLayout="row" fxLayoutAlign="start center">
<div style="width: 60px;"> <div style="width: 60px;">
<button *ngIf="!disabled" mat-icon-button color="primary" <button *ngIf="!disabled" mat-icon-button color="primary"
class="handle" class="handle"
style="min-width: 40px; margin: 0" style="min-width: 40px; margin: 0"
dndHandle cdkDragHandle
matTooltip="{{ 'action.drag' | translate }}" matTooltip="{{ 'action.drag' | translate }}"
matTooltipPosition="above"> matTooltipPosition="above">
<mat-icon>drag_handle</mat-icon> <mat-icon>drag_handle</mat-icon>

13
ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss

@ -15,6 +15,12 @@
*/ */
@import '../../../../../scss/constants'; @import '../../../../../scss/constants';
.tb-datasource-list-item.tb-draggable {
&.cdk-drag-preview {
background: #fff;
}
}
:host { :host {
.tb-widget-config { .tb-widget-config {
.tb-advanced-widget-config { .tb-advanced-widget-config {
@ -35,13 +41,6 @@
height: auto; height: auto;
min-height: 68px; min-height: 68px;
display: block; display: block;
&.dndDraggingSource {
display: none;
}
&.dndPlaceholder {
display: block;
background-color: #ddd;
}
} }
} }
.tb-datasource-type { .tb-datasource-type {

19
ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts

@ -73,7 +73,7 @@ import { Filter, Filters } from '@shared/models/query/query.models';
import { FilterDialogComponent, FilterDialogData } from '@home/components/filter/filter-dialog.component'; import { FilterDialogComponent, FilterDialogData } from '@home/components/filter/filter-dialog.component';
import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes';
import { MatChipInputEvent } from '@angular/material/chips'; import { MatChipInputEvent } from '@angular/material/chips';
import { DndDropEvent } from 'ngx-drag-drop'; import { CdkDragDrop } from '@angular/cdk/drag-drop';
const emptySettingsSchema: JsonSchema = { const emptySettingsSchema: JsonSchema = {
type: 'object', type: 'object',
@ -730,18 +730,11 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont
!!this.modelValue.settingsDirective && !!this.modelValue.settingsDirective.length); !!this.modelValue.settingsDirective && !!this.modelValue.settingsDirective.length);
} }
public dndDatasourceMoved(index: number) { public onDatasourceDrop(event: CdkDragDrop<string[]>) {
this.datasourcesFormArray().removeAt(index); const datasourcesFormArray = this.datasourcesFormArray();
} const datasourceForm = datasourcesFormArray.at(event.previousIndex);
datasourcesFormArray.removeAt(event.previousIndex);
public onDatasourceDrop(event: DndDropEvent) { datasourcesFormArray.insert(event.currentIndex, datasourceForm);
let index = event.index;
if (isUndefined(index)) {
index = this.datasourcesFormArray().length;
}
this.datasourcesFormArray().insert(index,
this.buildDatasourceForm(event.data)
);
} }
public removeDatasource(index: number) { public removeDatasource(index: number) {

6
ui-ngx/src/app/shared/shared.module.ts

@ -136,7 +136,6 @@ import { TbJsonToStringDirective } from '@shared/components/directives/tb-json-t
import { JsonObjectEditDialogComponent } from '@shared/components/dialog/json-object-edit-dialog.component'; import { JsonObjectEditDialogComponent } from '@shared/components/dialog/json-object-edit-dialog.component';
import { HistorySelectorComponent } from '@shared/components/time/history-selector/history-selector.component'; import { HistorySelectorComponent } from '@shared/components/time/history-selector/history-selector.component';
import { EntityGatewaySelectComponent } from '@shared/components/entity/entity-gateway-select.component'; import { EntityGatewaySelectComponent } from '@shared/components/entity/entity-gateway-select.component';
import { DndModule } from 'ngx-drag-drop';
import { QueueTypeListComponent } from '@shared/components/queue/queue-type-list.component'; import { QueueTypeListComponent } from '@shared/components/queue/queue-type-list.component';
import { ContactComponent } from '@shared/components/contact.component'; import { ContactComponent } from '@shared/components/contact.component';
import { TimezoneSelectComponent } from '@shared/components/time/timezone-select.component'; import { TimezoneSelectComponent } from '@shared/components/time/timezone-select.component';
@ -161,6 +160,7 @@ import { ProtobufContentComponent } from '@shared/components/protobuf-content.co
import { CssComponent } from '@shared/components/css.component'; import { CssComponent } from '@shared/components/css.component';
import { HtmlComponent } from '@shared/components/html.component'; import { HtmlComponent } from '@shared/components/html.component';
import { SafePipe } from '@shared/pipe/safe.pipe'; import { SafePipe } from '@shared/pipe/safe.pipe';
import { DragDropModule } from '@angular/cdk/drag-drop';
export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) {
return markedOptionsService; return markedOptionsService;
@ -319,6 +319,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
MatAutocompleteModule, MatAutocompleteModule,
MatChipsModule, MatChipsModule,
MatListModule, MatListModule,
DragDropModule,
GridsterModule, GridsterModule,
ClipboardModule, ClipboardModule,
FlexLayoutModule.withConfig({addFlexToParent: false}), FlexLayoutModule.withConfig({addFlexToParent: false}),
@ -329,7 +330,6 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
HotkeyModule, HotkeyModule,
ColorPickerModule, ColorPickerModule,
NgxHmCarouselModule, NgxHmCarouselModule,
DndModule,
NgxFlowModule, NgxFlowModule,
NgxFlowchartModule, NgxFlowchartModule,
// ngx-markdown // ngx-markdown
@ -429,6 +429,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
MatAutocompleteModule, MatAutocompleteModule,
MatChipsModule, MatChipsModule,
MatListModule, MatListModule,
DragDropModule,
GridsterModule, GridsterModule,
ClipboardModule, ClipboardModule,
FlexLayoutModule, FlexLayoutModule,
@ -439,7 +440,6 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
HotkeyModule, HotkeyModule,
ColorPickerModule, ColorPickerModule,
NgxHmCarouselModule, NgxHmCarouselModule,
DndModule,
NgxFlowchartModule, NgxFlowchartModule,
MarkdownModule, MarkdownModule,
ConfirmDialogComponent, ConfirmDialogComponent,

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

@ -3260,6 +3260,82 @@
"sort-settings": "Sort settings", "sort-settings": "Sort settings",
"nodes-sort-function": "Nodes sort function" "nodes-sort-function": "Nodes sort function"
}, },
"gauge": {
"default-color": "Default color",
"radial-gauge-settings": "Radial gauge settings",
"ticks-settings": "Ticks settings",
"min-value": "Minimum value",
"max-value": "Maximum value",
"start-ticks-angle": "Start ticks angle",
"ticks-angle": "Ticks angle",
"major-ticks-count": "Major ticks count",
"major-ticks-color": "Major ticks color",
"minor-ticks-count": "Minor ticks count",
"minor-ticks-color": "Minor ticks color",
"tick-numbers-font": "Tick numbers font",
"unit-title-settings": "Unit title settings",
"show-unit-title": "Show unit title",
"unit-title": "Unit title",
"title-font": "Title text font",
"units-settings": "Units settings",
"units-font": "Units text font",
"value-box-settings": "Value box settings",
"show-value-box": "Show value box",
"value-int": "Digits count for integer part of value",
"value-font": "Value text font",
"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",
"plate-color": "Plate color",
"needle-settings": "Needle settings",
"needle-circle-size": "Needle circle size",
"needle-color": "Needle color",
"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",
"highlights-settings": "Highlights settings",
"highlights-width": "Highlights width",
"highlights": "Highlights",
"highlight-from": "From",
"highlight-to": "To",
"highlight-color": "Color",
"no-highlights": "No highlights configured",
"add-highlight": "Add highlight",
"animation-settings": "Animation settings",
"enable-animation": "Enable animation",
"animation-duration": "Animation duration",
"animation-rule": "Animation rule",
"animation-linear": "Linear",
"animation-quad": "Quad",
"animation-quint": "Quint",
"animation-cycle": "Cycle",
"animation-bounce": "Bounce",
"animation-elastic": "Elastic",
"animation-dequad": "Dequad",
"animation-dequint": "Dequint",
"animation-decycle": "Decycle",
"animation-debounce": "Debounce",
"animation-delastic": "Delastic",
"linear-gauge-settings": "Linear gauge settings",
"bar-stroke-width": "Bar stroke width",
"bar-stroke-color": "Bar stroke color",
"bar-background-color": "Bar background color",
"bar-background-color-end": "Bar background color - end gradient",
"progress-bar-color": "Progress bar color",
"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-color": "Needle circle color",
"animation-target": "Animation target",
"animation-target-needle": "Needle",
"animation-target-plate": "Plate"
},
"html-card": { "html-card": {
"html": "HTML", "html": "HTML",
"css": "CSS" "css": "CSS"
@ -3318,18 +3394,6 @@
"qr-code-text-function": "QR code text function" "qr-code-text-function": "QR code text function"
}, },
"label-widget": { "label-widget": {
"font-family": "Font family",
"relative-font-size": "Relative font size (percents)",
"font-style": "Style",
"font-style-normal": "Normal",
"font-style-italic": "Italic",
"font-style-oblique": "Oblique",
"font-weight": "Weight",
"font-weight-normal": "Normal",
"font-weight-bold": "Bold",
"font-weight-bolder": "Bolder",
"font-weight-lighter": "Lighter",
"color": "Color",
"label-pattern": "Pattern", "label-pattern": "Pattern",
"label-pattern-hint": "Hint: for ex. 'Text <code><span style=\"color: #000;\">$&#123;</span>keyName<span style=\"color: #000;\">&#125;</span></code> units.' or <code><span style=\"color: #000;\">$&#123;</span>#&lt;key index&gt;<span style=\"color: #000;\">&#125;</span></code> units'", "label-pattern-hint": "Hint: for ex. 'Text <code><span style=\"color: #000;\">$&#123;</span>keyName<span style=\"color: #000;\">&#125;</span></code> units.' or <code><span style=\"color: #000;\">$&#123;</span>#&lt;key index&gt;<span style=\"color: #000;\">&#125;</span></code> units'",
"label-pattern-required": "Pattern is required", "label-pattern-required": "Pattern is required",
@ -3479,6 +3543,22 @@
"display-alarm-details": "Display alarm details", "display-alarm-details": "Display alarm details",
"allow-alarms-ack": "Allow alarms acknowledgment", "allow-alarms-ack": "Allow alarms acknowledgment",
"allow-alarms-clear": "Allow alarms clear" "allow-alarms-clear": "Allow alarms clear"
},
"widget-font": {
"font-family": "Font family",
"size": "Size",
"relative-font-size": "Relative font size (percents)",
"font-style": "Style",
"font-style-normal": "Normal",
"font-style-italic": "Italic",
"font-style-oblique": "Oblique",
"font-weight": "Weight",
"font-weight-normal": "Normal",
"font-weight-bold": "Bold",
"font-weight-bolder": "Bolder",
"font-weight-lighter": "Lighter",
"color": "Color",
"shadow-color": "Shadow color"
} }
}, },
"icon": { "icon": {

14
ui-ngx/src/styles.scss

@ -1439,4 +1439,18 @@ mat-label {
.tb-toast-panel { .tb-toast-panel {
pointer-events: none !important; pointer-events: none !important;
} }
.tb-draggable {
&.cdk-drag-animating {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
}
.tb-drop-list {
&.cdk-drop-list-dragging {
.tb-draggable {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
}
}
} }

7
ui-ngx/yarn.lock

@ -6630,13 +6630,6 @@ ngx-daterangepicker-material@^5.0.1:
dayjs "^1.10.4" dayjs "^1.10.4"
tslib "^2.0.0" tslib "^2.0.0"
ngx-drag-drop@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ngx-drag-drop/-/ngx-drag-drop-2.0.0.tgz#65d970229964803726fb7b9af4aec24005c810c7"
integrity sha512-t+4/eiC8zaXKqU1ruNfFEfGs1GpMNwpffD0baopvZFKjQHCb5rhNqFilJ54wO4T0OwGp4/RnsVhlcxe1mX6UJg==
dependencies:
tslib "^1.9.0"
"ngx-flowchart@https://github.com/thingsboard/ngx-flowchart.git#release/1.0.0": "ngx-flowchart@https://github.com/thingsboard/ngx-flowchart.git#release/1.0.0":
version "0.0.1" version "0.0.1"
resolved "https://github.com/thingsboard/ngx-flowchart.git#aac96f7e0490a386d58864d7819873e7c63cbb48" resolved "https://github.com/thingsboard/ngx-flowchart.git#aac96f7e0490a386d58864d7819873e7c63cbb48"

Loading…
Cancel
Save