Browse Source

UI: Add analogue gauges widget settings forms

pull/6545/head
Igor Kulikov 4 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": [],
"templateHtml": "<canvas id=\"compass\"></canvas>",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.gauge = new TbAnalogueCompass(self.ctx, 'compass');\n}\n\nself.onDataUpdated = function() {\n self.ctx.gauge.update();\n}\n\nself.onResize = function() {\n self.ctx.gauge.resize();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.gauge.mobileModeChanged();\n}\n\nself.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": "{}",
"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\":{}}"
}
},
@ -36,9 +37,10 @@
"resources": [],
"templateHtml": "<canvas id=\"linearGauge\"></canvas>\n",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.gauge = new TbAnalogueLinearGauge(self.ctx, 'linearGauge'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.gauge.update();\n}\n\nself.onResize = function() {\n self.ctx.gauge.resize();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.gauge.mobileModeChanged();\n}\n\nself.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": "{}",
"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}}"
}
},
@ -54,9 +56,10 @@
"resources": [],
"templateHtml": "<canvas id=\"radialGauge\"></canvas>\n",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.gauge = new TbAnalogueRadialGauge(self.ctx, 'radialGauge'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.gauge.update();\n}\n\nself.onResize = function() {\n self.ctx.gauge.resize();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.gauge.mobileModeChanged();\n}\n\nself.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": "{}",
"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}}"
}
},
@ -72,9 +75,10 @@
"resources": [],
"templateHtml": "<canvas id=\"radialGauge\"></canvas>\n",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.gauge = new TbAnalogueRadialGauge(self.ctx, 'radialGauge'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.gauge.update();\n}\n\nself.onResize = function() {\n self.ctx.gauge.resize();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.gauge.mobileModeChanged();\n}\n\nself.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": "{}",
"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}}"
}
},
@ -90,9 +94,10 @@
"resources": [],
"templateHtml": "<canvas id=\"radialGauge\"></canvas>\n",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.gauge = new TbAnalogueRadialGauge(self.ctx, 'radialGauge'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.gauge.update();\n}\n\nself.onResize = function() {\n self.ctx.gauge.resize();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.gauge.mobileModeChanged();\n}\n\nself.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": "{}",
"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}}"
}
}

1
ui-ngx/package.json

@ -68,7 +68,6 @@
"ngx-clipboard": "^14.0.2",
"ngx-color-picker": "^11.0.0",
"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-hm-carousel": "^2.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-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"
[selectable]="!disabled"
[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
* limitations under the License.
*/
:host {
.mat-chip.mat-standard-chip {
overflow: hidden;
.tb-attribute-chip {
max-width: 100%;
color: rgb(66, 66, 66);
font-weight: normal;
font-size: 16px;
.mat-chip.mat-standard-chip.tb-datakey-chip {
overflow: hidden;
.tb-chip-drag-handle {
cursor: move;
.tb-attribute-chip {
max-width: 100%;
color: rgb(66, 66, 66);
font-weight: normal;
font-size: 16px;
mat-icon {
pointer-events: none;
}
}
.tb-chip-drag-handle {
cursor: move;
.tb-chip-labels {
display: flex;
flex-direction: row;
align-items: flex-end;
min-width: 0;
.tb-chip-label {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
mat-icon {
pointer-events: none;
}
}
.tb-chip-separator {
white-space: pre;
}
.tb-chip-labels {
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 {
width: 24px;
height: 24px;
font-size: 24px;
margin-left: 0;
color: inherit;
opacity: inherit;
.tb-chip-separator {
white-space: pre;
}
}
.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.
///
import { JsonSettingsSchema } from '@shared/models/widget.models';
import { FontSettings } from '@home/components/widget/lib/settings.models';
import { AnimationRule, AnimationTarget } from '@home/components/widget/lib/analogue-gauge.models';
@ -37,321 +36,3 @@ export interface AnalogueCompassSettings {
animationRule: AnimationRule;
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 * as CanvasGauges from 'canvas-gauges';
import {
AnalogueCompassSettings,
analogueCompassSettingsSchema
AnalogueCompassSettings
} from '@home/components/widget/lib/analogue-compass.models';
import { deepClone, isDefined } from '@core/utils';
import { JsonSettingsSchema } from '@shared/models/widget.models';
import { getFontFamily } from '@home/components/widget/lib/settings.models';
import { TbBaseGauge } from '@home/components/widget/lib/analogue-gauge.models';
import RadialGaugeOptions = CanvasGauges.RadialGaugeOptions;
import BaseGauge = CanvasGauges.BaseGauge;
import RadialGauge = CanvasGauges.RadialGauge;
const analogueCompassSettingsSchemaValue = analogueCompassSettingsSchema;
// @dynamic
export class TbAnalogueCompass extends TbBaseGauge<AnalogueCompassSettings, RadialGaugeOptions> {
static get settingsSchema(): JsonSettingsSchema {
return analogueCompassSettingsSchemaValue;
}
constructor(ctx: WidgetContext, canvasId: string) {
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 { 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 { isDefined } from '@core/utils';
import * as tinycolor_ from 'tinycolor2';
@ -67,776 +66,6 @@ export interface AnalogueGaugeSettings {
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> {
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.
///
import { JsonSettingsSchema } from '@shared/models/widget.models';
import { AnalogueGaugeSettings, analogueGaugeSettingsSchema } from '@home/components/widget/lib/analogue-gauge.models';
import { deepClone } from '@core/utils';
import { AnalogueGaugeSettings } from '@home/components/widget/lib/analogue-gauge.models';
export interface AnalogueLinearGaugeSettings extends AnalogueGaugeSettings {
barStrokeWidth: number;
@ -26,63 +24,3 @@ export interface AnalogueLinearGaugeSettings extends AnalogueGaugeSettings {
colorBarProgress: 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 { TbAnalogueGauge } from '@home/components/widget/lib/analogue-gauge.models';
import {
AnalogueLinearGaugeSettings,
getAnalogueLinearGaugeSettingsSchema
AnalogueLinearGaugeSettings
} from '@home/components/widget/lib/analogue-linear-gauge.models';
import { isDefined } from '@core/utils';
import * as tinycolor_ from 'tinycolor2';
@ -30,15 +29,9 @@ import BaseGauge = CanvasGauges.BaseGauge;
const tinycolor = tinycolor_;
const analogueLinearGaugeSettingsSchemaValue = getAnalogueLinearGaugeSettingsSchema();
// @dynamic
export class TbAnalogueLinearGauge extends TbAnalogueGauge<AnalogueLinearGaugeSettings, LinearGaugeOptions>{
static get settingsSchema(): JsonSettingsSchema {
return analogueLinearGaugeSettingsSchemaValue;
}
constructor(ctx: WidgetContext, canvasId: string) {
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.
///
import { JsonSettingsSchema } from '@shared/models/widget.models';
import { AnalogueGaugeSettings, analogueGaugeSettingsSchema } from '@home/components/widget/lib/analogue-gauge.models';
import { deepClone } from '@core/utils';
import { AnalogueGaugeSettings } from '@home/components/widget/lib/analogue-gauge.models';
export interface AnalogueRadialGaugeSettings extends AnalogueGaugeSettings {
startAngle: number;
ticksAngle: 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 {
AnalogueRadialGaugeSettings,
getAnalogueRadialGaugeSettingsSchema
AnalogueRadialGaugeSettings
} 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 { TbAnalogueGauge } from '@home/components/widget/lib/analogue-gauge.models';
import RadialGauge = CanvasGauges.RadialGauge;
import RadialGaugeOptions = CanvasGauges.RadialGaugeOptions;
import BaseGauge = CanvasGauges.BaseGauge;
const analogueRadialGaugeSettingsSchemaValue = getAnalogueRadialGaugeSettingsSchema();
// @dynamic
export class TbAnalogueRadialGauge extends TbAnalogueGauge<AnalogueRadialGaugeSettings, RadialGaugeOptions>{
static get settingsSchema(): JsonSettingsSchema {
return analogueRadialGaugeSettingsSchemaValue;
}
constructor(ctx: WidgetContext, canvasId: string) {
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">
<mat-form-field fxFlex>
<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 fxFlex>
<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>
</section>
</fieldset>
@ -64,7 +64,7 @@
</tb-color-input>
<fieldset class="fields-group">
<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>
</section>
</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 { AppState } from '@core/core.state';
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 {
pattern: string;
x: number;
y: number;
backgroundColor: string;
font: LabelWidgetFont;
font: WidgetFont;
}
@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">
<legend class="group-title" translate>widgets.label-widget.labels</legend>
<div fxLayout="column">
<div class="tb-label-widget-labels">
<div *ngFor="let labelControl of labelsFormArray().controls; trackBy: trackByLabel;
<div class="tb-control-list tb-drop-list" cdkDropList cdkDropListOrientation="vertical"
(cdkDropListDropped)="labelDrop($event)">
<div cdkDrag class="tb-draggable" *ngFor="let labelControl of labelsFormArray().controls; trackBy: trackByLabel;
let $index = index; last as isLast;"
fxLayout="column" [ngStyle]="!isLast ? {paddingBottom: '8px'} : {}">
<tb-label-widget-label [formControl]="labelControl"
[expanded]="$index === 0"
[expanded]="labelControl.new"
(removeLabel)="removeLabel($index)">
</tb-label-widget-label>
</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 { AppState } from '@core/core.state';
import { LabelWidgetLabel } from '@home/components/widget/lib/settings/cards/label-widget-label.component';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
@Component({
selector: 'tb-label-widget-settings',
templateUrl: './label-widget-settings.component.html',
styleUrls: ['./label-widget-settings.component.scss', './../widget-settings.scss']
styleUrls: ['./../widget-settings.scss']
})
export class LabelWidgetSettingsComponent extends WidgetSettingsComponent {
@ -63,8 +64,9 @@ export class LabelWidgetSettingsComponent extends WidgetSettingsComponent {
return this.labelWidgetSettingsForm.get('labels') as FormArray;
}
public trackByLabel(index: number, labelControl: AbstractControl): number {
return index;
public trackByLabel(index: number, labelControl: AbstractControl): any {
const label: LabelWidgetLabel = labelControl.value;
return label;
}
public removeLabel(index: number) {
@ -86,7 +88,16 @@ export class LabelWidgetSettingsComponent extends WidgetSettingsComponent {
}
};
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();
}
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.
-->
<section [formGroup]="labelWidgetFontFormGroup" fxLayout="column">
<section [formGroup]="widgetFontFormGroup" fxLayout="column">
<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">
</mat-form-field>
<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">
</mat-form-field>
<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-option [value]="'normal'">
{{ 'widgets.label-widget.font-style-normal' | translate }}
{{ 'widgets.widget-font.font-style-normal' | translate }}
</mat-option>
<mat-option [value]="'italic'">
{{ 'widgets.label-widget.font-style-italic' | translate }}
{{ 'widgets.widget-font.font-style-italic' | translate }}
</mat-option>
<mat-option [value]="'oblique'">
{{ 'widgets.label-widget.font-style-oblique' | translate }}
{{ 'widgets.widget-font.font-style-oblique' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<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-option [value]="'normal'">
{{ 'widgets.label-widget.font-weight-normal' | translate }}
{{ 'widgets.widget-font.font-weight-normal' | translate }}
</mat-option>
<mat-option [value]="'bold'">
{{ 'widgets.label-widget.font-weight-bold' | translate }}
{{ 'widgets.widget-font.font-weight-bold' | translate }}
</mat-option>
<mat-option [value]="'bolder'">
{{ 'widgets.label-widget.font-weight-bolder' | translate }}
{{ 'widgets.widget-font.font-weight-bolder' | translate }}
</mat-option>
<mat-option [value]="'lighter'">
{{ 'widgets.label-widget.font-weight-lighter' | translate }}
{{ 'widgets.widget-font.font-weight-lighter' | translate }}
</mat-option>
<mat-option [value]="'100'">100</mat-option>
<mat-option [value]="'200'">200</mat-option>
@ -66,6 +66,10 @@
</mat-form-field>
<tb-color-input
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>
</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 { TranslateService } from '@ngx-translate/core';
export interface LabelWidgetFont {
export interface WidgetFont {
family: string;
size: number;
style: 'normal' | 'italic' | 'oblique';
weight: 'normal' | 'bold' | 'bolder' | 'lighter' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900';
color: string;
shadowColor?: string;
}
@Component({
selector: 'tb-label-widget-font',
templateUrl: './label-widget-font.component.html',
selector: 'tb-widget-font',
templateUrl: './widget-font.component.html',
styleUrls: [],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => LabelWidgetFontComponent),
useExisting: forwardRef(() => WidgetFontComponent),
multi: true
}
]
})
export class LabelWidgetFontComponent extends PageComponent implements OnInit, ControlValueAccessor {
export class WidgetFontComponent extends PageComponent implements OnInit, ControlValueAccessor {
@HostBinding('style.display') display = 'block';
@Input()
disabled: boolean;
private modelValue: LabelWidgetFont;
@Input()
hasShadowColor = false;
@Input()
sizeTitle = 'widgets.widget-font.size';
private modelValue: WidgetFont;
private propagateChange = null;
public labelWidgetFontFormGroup: FormGroup;
public widgetFontFormGroup: FormGroup;
constructor(protected store: Store<AppState>,
private translate: TranslateService,
@ -61,14 +68,17 @@ export class LabelWidgetFontComponent extends PageComponent implements OnInit, C
}
ngOnInit(): void {
this.labelWidgetFontFormGroup = this.fb.group({
this.widgetFontFormGroup = this.fb.group({
family: [null, []],
size: [null, [Validators.min(1)]],
style: [null, []],
weight: [null, []],
color: [null, []]
});
this.labelWidgetFontFormGroup.valueChanges.subscribe(() => {
if (this.hasShadowColor) {
this.widgetFontFormGroup.addControl('shadowColor', this.fb.control(null, []));
}
this.widgetFontFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
}
@ -83,21 +93,21 @@ export class LabelWidgetFontComponent extends PageComponent implements OnInit, C
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (isDisabled) {
this.labelWidgetFontFormGroup.disable({emitEvent: false});
this.widgetFontFormGroup.disable({emitEvent: false});
} else {
this.labelWidgetFontFormGroup.enable({emitEvent: false});
this.widgetFontFormGroup.enable({emitEvent: false});
}
}
writeValue(value: LabelWidgetFont): void {
writeValue(value: WidgetFont): void {
this.modelValue = value;
this.labelWidgetFontFormGroup.patchValue(
this.widgetFontFormGroup.patchValue(
value, {emitEvent: false}
);
}
private updateModel() {
const value: LabelWidgetFont = this.labelWidgetFontFormGroup.value;
const value: WidgetFont = this.widgetFontFormGroup.value;
this.modelValue = value;
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
* limitations under the License.
*/
@import '../../../../../../../../scss/constants';
:host {
.tb-label-widget-labels {
overflow-y: auto;
&.mat-padding {
padding: 8px;
@media #{$mat-gt-sm} {
padding: 16px;
display: block;
.mat-expansion-panel {
box-shadow: none;
&.gauge-highlight {
border: 1px groove rgba(0, 0, 0, .25);
.mat-expansion-panel-header {
padding: 0 24px 0 8px;
&.mat-expanded {
height: 48px;
}
}
}
}
}
.tb-prompt{
margin: 30px 0;
:host ::ng-deep {
.mat-expansion-panel {
&.gauge-highlight {
.mat-expansion-panel-body {
padding: 0 8px 8px;
}
}
}
}

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

@ -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 {
MarkdownWidgetSettingsComponent
} 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 { LabelWidgetSettingsComponent } from '@home/components/widget/lib/settings/cards/label-widget-settings.component';
import {
@ -59,6 +59,16 @@ import {
import {
AlarmsTableKeySettingsComponent
} from '@home/components/widget/lib/settings/alarm/alarms-table-key-settings.component';
import { GaugeHighlightComponent } from '@home/components/widget/lib/settings/gauge/gauge-highlight.component';
import {
AnalogueRadialGaugeWidgetSettingsComponent
} from '@home/components/widget/lib/settings/gauge/analogue-radial-gauge-widget-settings.component';
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({
declarations: [
@ -67,7 +77,7 @@ import {
TimeseriesTableKeySettingsComponent,
TimeseriesTableLatestKeySettingsComponent,
MarkdownWidgetSettingsComponent,
LabelWidgetFontComponent,
WidgetFontComponent,
LabelWidgetLabelComponent,
LabelWidgetSettingsComponent,
SimpleCardWidgetSettingsComponent,
@ -77,7 +87,11 @@ import {
EntitiesTableWidgetSettingsComponent,
EntitiesTableKeySettingsComponent,
AlarmsTableWidgetSettingsComponent,
AlarmsTableKeySettingsComponent
AlarmsTableKeySettingsComponent,
GaugeHighlightComponent,
AnalogueRadialGaugeWidgetSettingsComponent,
AnalogueLinearGaugeWidgetSettingsComponent,
AnalogueCompassWidgetSettingsComponent
],
imports: [
CommonModule,
@ -90,7 +104,7 @@ import {
TimeseriesTableKeySettingsComponent,
TimeseriesTableLatestKeySettingsComponent,
MarkdownWidgetSettingsComponent,
LabelWidgetFontComponent,
WidgetFontComponent,
LabelWidgetLabelComponent,
LabelWidgetSettingsComponent,
SimpleCardWidgetSettingsComponent,
@ -100,7 +114,11 @@ import {
EntitiesTableWidgetSettingsComponent,
EntitiesTableKeySettingsComponent,
AlarmsTableWidgetSettingsComponent,
AlarmsTableKeySettingsComponent
AlarmsTableKeySettingsComponent,
GaugeHighlightComponent,
AnalogueRadialGaugeWidgetSettingsComponent,
AnalogueLinearGaugeWidgetSettingsComponent,
AnalogueCompassWidgetSettingsComponent
]
})
export class WidgetSettingsModule {
@ -120,5 +138,8 @@ export const widgetSettingsComponentsMap: {[key: string]: Type<IWidgetSettingsCo
'tb-entities-table-widget-settings': EntitiesTableWidgetSettingsComponent,
'tb-entities-table-key-settings': EntitiesTableKeySettingsComponent,
'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
* limitations under the License.
*/
@import '../../../../../../../scss/constants';
:host {
.tb-widget-settings {
.fields-group {
@ -27,6 +30,7 @@
}
legend + * {
display: block;
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 {
white-space: normal;
}
}
}

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

@ -110,23 +110,21 @@
</div>
</div>
<div style="overflow: auto; padding-bottom: 15px;">
<mat-list dndDropzone dndEffectAllowed="move"
(dndDrop)="onDatasourceDrop($event)"
[dndDisableIf]="disabled" formArrayName="datasources">
<mat-list-item dndPlaceholderRef
class="dndPlaceholder">
</mat-list-item>
<mat-list class="tb-drop-list"
cdkDropList
cdkDropListOrientation="vertical"
(cdkDropListDropped)="onDatasourceDrop($event)"
[cdkDropListDisabled]="disabled"
formArrayName="datasources">
<mat-list-item *ngFor="let datasourceControl of datasourcesFormArray().controls; let $index = index;"
[dndDraggable]="datasourceControl.value"
(dndMoved)="dndDatasourceMoved($index)"
[dndDisableIf]="disabled"
dndEffectAllowed="move">
class="tb-datasource-list-item tb-draggable" cdkDrag
[cdkDragDisabled]="disabled">
<div fxFlex fxLayout="row" fxLayoutAlign="start center">
<div style="width: 60px;">
<button *ngIf="!disabled" mat-icon-button color="primary"
class="handle"
style="min-width: 40px; margin: 0"
dndHandle
cdkDragHandle
matTooltip="{{ 'action.drag' | translate }}"
matTooltipPosition="above">
<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';
.tb-datasource-list-item.tb-draggable {
&.cdk-drag-preview {
background: #fff;
}
}
:host {
.tb-widget-config {
.tb-advanced-widget-config {
@ -35,13 +41,6 @@
height: auto;
min-height: 68px;
display: block;
&.dndDraggingSource {
display: none;
}
&.dndPlaceholder {
display: block;
background-color: #ddd;
}
}
}
.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 { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes';
import { MatChipInputEvent } from '@angular/material/chips';
import { DndDropEvent } from 'ngx-drag-drop';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
const emptySettingsSchema: JsonSchema = {
type: 'object',
@ -730,18 +730,11 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont
!!this.modelValue.settingsDirective && !!this.modelValue.settingsDirective.length);
}
public dndDatasourceMoved(index: number) {
this.datasourcesFormArray().removeAt(index);
}
public onDatasourceDrop(event: DndDropEvent) {
let index = event.index;
if (isUndefined(index)) {
index = this.datasourcesFormArray().length;
}
this.datasourcesFormArray().insert(index,
this.buildDatasourceForm(event.data)
);
public onDatasourceDrop(event: CdkDragDrop<string[]>) {
const datasourcesFormArray = this.datasourcesFormArray();
const datasourceForm = datasourcesFormArray.at(event.previousIndex);
datasourcesFormArray.removeAt(event.previousIndex);
datasourcesFormArray.insert(event.currentIndex, datasourceForm);
}
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 { HistorySelectorComponent } from '@shared/components/time/history-selector/history-selector.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 { ContactComponent } from '@shared/components/contact.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 { HtmlComponent } from '@shared/components/html.component';
import { SafePipe } from '@shared/pipe/safe.pipe';
import { DragDropModule } from '@angular/cdk/drag-drop';
export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) {
return markedOptionsService;
@ -319,6 +319,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
MatAutocompleteModule,
MatChipsModule,
MatListModule,
DragDropModule,
GridsterModule,
ClipboardModule,
FlexLayoutModule.withConfig({addFlexToParent: false}),
@ -329,7 +330,6 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
HotkeyModule,
ColorPickerModule,
NgxHmCarouselModule,
DndModule,
NgxFlowModule,
NgxFlowchartModule,
// ngx-markdown
@ -429,6 +429,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
MatAutocompleteModule,
MatChipsModule,
MatListModule,
DragDropModule,
GridsterModule,
ClipboardModule,
FlexLayoutModule,
@ -439,7 +440,6 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
HotkeyModule,
ColorPickerModule,
NgxHmCarouselModule,
DndModule,
NgxFlowchartModule,
MarkdownModule,
ConfirmDialogComponent,

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

@ -3260,6 +3260,82 @@
"sort-settings": "Sort settings",
"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": "HTML",
"css": "CSS"
@ -3318,18 +3394,6 @@
"qr-code-text-function": "QR code text function"
},
"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-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",
@ -3479,6 +3543,22 @@
"display-alarm-details": "Display alarm details",
"allow-alarms-ack": "Allow alarms acknowledgment",
"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": {

14
ui-ngx/src/styles.scss

@ -1439,4 +1439,18 @@ mat-label {
.tb-toast-panel {
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"
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":
version "0.0.1"
resolved "https://github.com/thingsboard/ngx-flowchart.git#aac96f7e0490a386d58864d7819873e7c63cbb48"

Loading…
Cancel
Save