Browse Source

UI: Implement line / bar / point charts.

pull/10315/head
Igor Kulikov 2 years ago
parent
commit
cd206c0f80
  1. 5
      application/src/main/data/json/system/widget_bundles/charts.json
  2. 32
      application/src/main/data/json/system/widget_types/bar_chart.json
  3. 32
      application/src/main/data/json/system/widget_types/line_chart.json
  4. 32
      application/src/main/data/json/system/widget_types/point_chart.json
  5. 8
      application/src/main/data/json/system/widget_types/time_series_chart.json
  6. 5
      application/src/main/data/json/system/widget_types/timeseries_bar_chart.json
  7. 5
      application/src/main/data/json/system/widget_types/timeseries_line_chart.json
  8. 17
      ui-ngx/src/app/core/api/data-aggregator.ts
  9. 7
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/bar-chart-with-labels-basic-config.component.html
  10. 6
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/bar-chart-with-labels-basic-config.component.ts
  11. 7
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.html
  12. 6
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.ts
  13. 2
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/time-series-chart-basic-config.component.html
  14. 18
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/time-series-chart-basic-config.component.ts
  15. 8
      ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.scss
  16. 1
      ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts
  17. 2
      ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html
  18. 107
      ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.scss
  19. 1
      ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html
  20. 12
      ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts
  21. 9
      ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-bar.models.ts
  22. 15
      ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts
  23. 21
      ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts
  24. 7
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.html
  25. 7
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.ts
  26. 7
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.html
  27. 5
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts
  28. 6
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-key-settings.component.html
  29. 14
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-key-settings.component.ts
  30. 89
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.html
  31. 7
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts
  32. 159
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-widget-settings.component.html
  33. 174
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-widget-settings.component.ts
  34. 3
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.html
  35. 41
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.scss
  36. 6
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.ts
  37. 68
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.html
  38. 2
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.scss
  39. 9
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.ts
  40. 3
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-thresholds-panel.component.html
  41. 31
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-thresholds-panel.component.scss
  42. 12
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/data-key-input.component.html
  43. 3
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/data-key-input.component.ts
  44. 12
      ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts
  45. 1
      ui-ngx/src/app/modules/home/components/widget/widget-config.component.html
  46. 9
      ui-ngx/src/app/shared/models/time/time.models.ts
  47. 9
      ui-ngx/src/app/shared/models/widget.models.ts
  48. 6
      ui-ngx/src/assets/locale/locale.constant-en_US.json

5
application/src/main/data/json/system/widget_bundles/charts.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/bar_chart.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/line_chart.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/point_chart.json

File diff suppressed because one or more lines are too long

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

@ -10,12 +10,12 @@
"sizeY": 5,
"resources": [],
"templateHtml": "<tb-time-series-chart-widget \n [ctx]=\"ctx\"\n [widgetTitlePanel]=\"widgetTitlePanel\">\n</tb-time-series-chart-widget>",
"templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.$scope.timeSeriesChartWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.timeSeriesChartWidget.onDataUpdated();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.timeSeriesChartWidget.onLatestDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n previewWidth: '80%',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n dataKeySettingsFunction: TbTimeSeriesChart.dataKeySettings(),\n defaultDataKeysFunction: function() {\n return [{ name: 'temperature', label: 'Temperature', type: 'timeseries', units: '°C', decimals: 0 }];\n }\n };\n}\n",
"settingsSchema": "{}",
"dataKeySettingsSchema": "{}",
"latestDataKeySettingsSchema": "{}",
"settingsDirective": "",
"settingsDirective": "tb-time-series-chart-widget-settings",
"dataKeySettingsDirective": "tb-time-series-chart-key-settings",
"latestDataKeySettingsDirective": "",
"hasBasicMode": true,
@ -29,6 +29,8 @@
"line",
"line chart",
"bar",
"bar chart"
"bar chart",
"point",
"point chart"
]
}

5
application/src/main/data/json/system/widget_types/timeseries_bar_chart.json

@ -1,8 +1,8 @@
{
"fqn": "charts.timeseries_bars_flot",
"name": "Timeseries Bar Chart",
"deprecated": false,
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAABOFBMVEUAAAA3oPR3d3d6enp8fHyBgYGDg4OGhoaNjY2RkZGSkpKTk5OUlJSVlZWWlpaXl5eYmJiZmZmampqcnJydnZ2enp6goKChoaGioqKjo6OkpKSlpaWmpqanp6eoqKipqamqqqqrq6usrKytra2urq6wsLCxsbGysrK0tLS1tbW2tra3t7e4uLi5ubm6urq8vLy9vb2+vr6/v7/AwMDBwcHDw8PExMTHx8fIyMjJycnLy8vNzc3Ozs7Pz8/S0tLT09PU1NTV1dXW1tbX19fZ2dna2trb29vc3Nzd3d3e3t7f39/h4eHi4uLj4+Pk5OTl5eXm5ubn5+fo6Ojq6urr6+vs7Ozt7e3u7u7v7+/w8PDx8fH09PT19fX29vb39/f4+Pj5+fn6+vr7+/v8/Pz9/f3+/v7/xx////8KXFhiAAAAAWJLR0RnW9PpswAAAvtJREFUeNrt3GtXElEUBuDpZlAqylVHCyMwyi4SpkaWAl4qk8wwUhJlmOn9//+gLzbKbc6AAm5991p82WvPOedZZw6zYM3aGupCQ4tYkZDSsKDrocNVvz8jHQKYY1ZiT/6OAJllRPSpsnzIqIG9SjYmHpKfAzI4CIuHjJeBtyHfZwCatiI1/m+BYV2Dw35NniOEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQUp/6Wx+DgbRbxOAhEb/fXJ98akiH1AIAHtSWlqRDSvdDGcOHnYR0SPV7zVsaQyHeO0jTJapEV5C9bUz9fIjsvHRIefhRxHqpjxzA3ftajXOudHGJOtHV+1rV04/wHenDc2QQkFbLJISQwUDaP90IIYQQQgghpAvIxRO9gFxG4lZ9XBFIx6sihJD+QVRjEEIIIYQQcoMgahkhhBDSe0iLX3ydQdSLIKR9ghCJkIYEIYQQIhPS8d+AhPQboppFw9HMxBrs/lqCIbObpgezP67YjnQ8iwagHDzrryUZUgsUz/prCYZY05vn+msJhiwM6XrR7q/V9OJU4xQuEpcxRsezNPbXEn3Yzz9Hulg3IYT0C3LxxI2CNCQIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQlpA7P5a0iF2fy3hkLP+WsIhVbu/lvRby+6vJR1i99eSG6ffu1XHxlRNcfWq3I0iIK4tJK2nXVyV0lOqEmvjGWAtvnCu+jMzkQWMiOlYdRSd3MAH/UnVPWR/ApFfSkcpiOBvRc3XtAeYW1ZUJbZMD5C8azhWLX4xvZVR692Se0huHm9ySogxkhs3lFVewPM4WlFUlUMoJEYUox1+jAFIbLuHrKaQWlMu8TicDp+4gdw7/qS4t2qBohk4UUF2nieBfLyDM/ItgXhBucT113i14QbixW7M+SRNb6EQ0u8kHavyZQxj2/kgNUCsYDRoqXfEF/Mdu4G8D43uOtakh3R9H1DsyKZvOmneDjt+D/0DTzolrPMHmggAAAAASUVORK5CYII=",
"deprecated": true,
"image": "tb-image:dGltZXNlcmllc19iYXJfY2hhcnRfc3lzdGVtX3dpZGdldF9pbWFnZS5wbmc=:IlRpbWVzZXJpZXMgQmFyIENoYXJ0IiBzeXN0ZW0gd2lkZ2V0IGltYWdl;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAABOFBMVEUAAAA3oPR3d3d6enp8fHyBgYGDg4OGhoaNjY2RkZGSkpKTk5OUlJSVlZWWlpaXl5eYmJiZmZmampqcnJydnZ2enp6goKChoaGioqKjo6OkpKSlpaWmpqanp6eoqKipqamqqqqrq6usrKytra2urq6wsLCxsbGysrK0tLS1tbW2tra3t7e4uLi5ubm6urq8vLy9vb2+vr6/v7/AwMDBwcHDw8PExMTHx8fIyMjJycnLy8vNzc3Ozs7Pz8/S0tLT09PU1NTV1dXW1tbX19fZ2dna2trb29vc3Nzd3d3e3t7f39/h4eHi4uLj4+Pk5OTl5eXm5ubn5+fo6Ojq6urr6+vs7Ozt7e3u7u7v7+/w8PDx8fH09PT19fX29vb39/f4+Pj5+fn6+vr7+/v8/Pz9/f3+/v7/xx////8KXFhiAAAAAWJLR0RnW9PpswAAAvtJREFUeNrt3GtXElEUBuDpZlAqylVHCyMwyi4SpkaWAl4qk8wwUhJlmOn9//+gLzbKbc6AAm5991p82WvPOedZZw6zYM3aGupCQ4tYkZDSsKDrocNVvz8jHQKYY1ZiT/6OAJllRPSpsnzIqIG9SjYmHpKfAzI4CIuHjJeBtyHfZwCatiI1/m+BYV2Dw35NniOEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQUp/6Wx+DgbRbxOAhEb/fXJ98akiH1AIAHtSWlqRDSvdDGcOHnYR0SPV7zVsaQyHeO0jTJapEV5C9bUz9fIjsvHRIefhRxHqpjxzA3ftajXOudHGJOtHV+1rV04/wHenDc2QQkFbLJISQwUDaP90IIYQQQgghpAvIxRO9gFxG4lZ9XBFIx6sihJD+QVRjEEIIIYQQcoMgahkhhBDSe0iLX3ydQdSLIKR9ghCJkIYEIYQQIhPS8d+AhPQboppFw9HMxBrs/lqCIbObpgezP67YjnQ8iwagHDzrryUZUgsUz/prCYZY05vn+msJhiwM6XrR7q/V9OJU4xQuEpcxRsezNPbXEn3Yzz9Hulg3IYT0C3LxxI2CNCQIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQlpA7P5a0iF2fy3hkLP+WsIhVbu/lvRby+6vJR1i99eSG6ffu1XHxlRNcfWq3I0iIK4tJK2nXVyV0lOqEmvjGWAtvnCu+jMzkQWMiOlYdRSd3MAH/UnVPWR/ApFfSkcpiOBvRc3XtAeYW1ZUJbZMD5C8azhWLX4xvZVR692Se0huHm9ySogxkhs3lFVewPM4WlFUlUMoJEYUox1+jAFIbLuHrKaQWlMu8TicDp+4gdw7/qS4t2qBohk4UUF2nieBfLyDM/ItgXhBucT113i14QbixW7M+SRNb6EQ0u8kHavyZQxj2/kgNUCsYDRoqXfEF/Mdu4G8D43uOtakh3R9H1DsyKZvOmneDjt+D/0DTzolrPMHmggAAAAASUVORK5CYII=",
"description": "Displays changes to time-series data over time—for example, daily water consumption for the last month.",
"descriptor": {
"type": "timeseries",
@ -21,6 +21,5 @@
"basicModeDirective": "tb-flot-basic-config",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000},\"aggregation\":{\"limit\":200,\"type\":\"AVG\"}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":true,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"defaultBarWidth\":600,\"barAlignment\":\"left\",\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false},\"title\":\"Timeseries Bar Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"configMode\":\"basic\",\"showTitleIcon\":false,\"titleIcon\":\"thermostat\",\"iconColor\":\"#1F6BDD\"}"
},
"externalId": null,
"tags": null
}

5
application/src/main/data/json/system/widget_types/timeseries_line_chart.json

File diff suppressed because one or more lines are too long

17
ui-ngx/src/app/core/api/data-aggregator.ts

@ -14,24 +14,23 @@
/// limitations under the License.
///
import { AggKey, IndexedSubscriptionData, } from '@app/shared/models/telemetry/telemetry.models';
import {
AggKey,
IndexedSubscriptionData,
} from '@app/shared/models/telemetry/telemetry.models';
import {
AggregationType, calculateAggIntervalWithSubscriptionTimeWindow,
AggregationType,
calculateAggIntervalWithSubscriptionTimeWindow,
calculateIntervalComparisonEndTime,
calculateIntervalEndTime,
calculateIntervalStartEndTime,
getCurrentTime,
getTime, IntervalMath,
getTime,
IntervalMath,
SubscriptionTimewindow
} from '@shared/models/time/time.models';
import { UtilsService } from '@core/services/utils.service';
import { deepClone, isDefinedAndNotNull, isNumber, isNumeric } from '@core/utils';
import Timeout = NodeJS.Timeout;
import { DataEntry, DataSet, IndexedData } from '@shared/models/widget.models';
import BTree from 'sorted-btree';
import Timeout = NodeJS.Timeout;
export declare type onAggregatedData = (data: IndexedData, detectChanges: boolean) => void;
@ -318,7 +317,9 @@ export class DataAggregator {
this.startTs += tickTs;
this.endTs += tickTs;
}
this.updateLastInterval();
if (this.subsTw.aggregation.type !== AggregationType.NONE) {
this.updateLastInterval();
}
this.data = this.updateData();
this.elapsed = this.elapsed - delta * this.aggregationTimeout;
}

7
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/bar-chart-with-labels-basic-config.component.html

@ -205,6 +205,13 @@
</tb-color-input>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="tooltipDateInterval">
<div tb-hint-tooltip-icon="{{'tooltip.show-date-time-interval-hint' | translate}}">
{{ 'tooltip.show-date-time-interval' | translate }}
</div>
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput

6
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/bar-chart-with-labels-basic-config.component.ts

@ -127,6 +127,8 @@ export class BarChartWithLabelsBasicConfigComponent extends BasicWidgetConfigCom
tooltipDateFormat: [settings.tooltipDateFormat, []],
tooltipDateFont: [settings.tooltipDateFont, []],
tooltipDateColor: [settings.tooltipDateColor, []],
tooltipDateInterval: [settings.tooltipDateInterval, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
@ -178,6 +180,7 @@ export class BarChartWithLabelsBasicConfigComponent extends BasicWidgetConfigCom
this.widgetConfig.config.settings.tooltipDateFormat = config.tooltipDateFormat;
this.widgetConfig.config.settings.tooltipDateFont = config.tooltipDateFont;
this.widgetConfig.config.settings.tooltipDateColor = config.tooltipDateColor;
this.widgetConfig.config.settings.tooltipDateInterval = config.tooltipDateInterval;
this.widgetConfig.config.settings.tooltipBackgroundColor = config.tooltipBackgroundColor;
this.widgetConfig.config.settings.tooltipBackgroundBlur = config.tooltipBackgroundBlur;
@ -266,10 +269,12 @@ export class BarChartWithLabelsBasicConfigComponent extends BasicWidgetConfigCom
this.barChartWidgetConfigForm.get('tooltipDateFormat').enable();
this.barChartWidgetConfigForm.get('tooltipDateFont').enable();
this.barChartWidgetConfigForm.get('tooltipDateColor').enable();
this.barChartWidgetConfigForm.get('tooltipDateInterval').enable();
} else {
this.barChartWidgetConfigForm.get('tooltipDateFormat').disable();
this.barChartWidgetConfigForm.get('tooltipDateFont').disable();
this.barChartWidgetConfigForm.get('tooltipDateColor').disable();
this.barChartWidgetConfigForm.get('tooltipDateInterval').disable();
}
} else {
this.barChartWidgetConfigForm.get('tooltipValueFont').disable();
@ -278,6 +283,7 @@ export class BarChartWithLabelsBasicConfigComponent extends BasicWidgetConfigCom
this.barChartWidgetConfigForm.get('tooltipDateFormat').disable();
this.barChartWidgetConfigForm.get('tooltipDateFont').disable();
this.barChartWidgetConfigForm.get('tooltipDateColor').disable();
this.barChartWidgetConfigForm.get('tooltipDateInterval').disable();
this.barChartWidgetConfigForm.get('tooltipBackgroundColor').disable();
this.barChartWidgetConfigForm.get('tooltipBackgroundBlur').disable();
}

7
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.html

@ -179,6 +179,13 @@
</tb-color-input>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="tooltipDateInterval">
<div tb-hint-tooltip-icon="{{'tooltip.show-date-time-interval-hint' | translate}}">
{{ 'tooltip.show-date-time-interval' | translate }}
</div>
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput

6
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.ts

@ -108,6 +108,8 @@ export class RangeChartBasicConfigComponent extends BasicWidgetConfigComponent {
tooltipDateFormat: [settings.tooltipDateFormat, []],
tooltipDateFont: [settings.tooltipDateFont, []],
tooltipDateColor: [settings.tooltipDateColor, []],
tooltipDateInterval: [settings.tooltipDateInterval, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
@ -155,6 +157,7 @@ export class RangeChartBasicConfigComponent extends BasicWidgetConfigComponent {
this.widgetConfig.config.settings.tooltipDateFormat = config.tooltipDateFormat;
this.widgetConfig.config.settings.tooltipDateFont = config.tooltipDateFont;
this.widgetConfig.config.settings.tooltipDateColor = config.tooltipDateColor;
this.widgetConfig.config.settings.tooltipDateInterval = config.tooltipDateInterval;
this.widgetConfig.config.settings.tooltipBackgroundColor = config.tooltipBackgroundColor;
this.widgetConfig.config.settings.tooltipBackgroundBlur = config.tooltipBackgroundBlur;
@ -225,10 +228,12 @@ export class RangeChartBasicConfigComponent extends BasicWidgetConfigComponent {
this.rangeChartWidgetConfigForm.get('tooltipDateFormat').enable();
this.rangeChartWidgetConfigForm.get('tooltipDateFont').enable();
this.rangeChartWidgetConfigForm.get('tooltipDateColor').enable();
this.rangeChartWidgetConfigForm.get('tooltipDateInterval').enable();
} else {
this.rangeChartWidgetConfigForm.get('tooltipDateFormat').disable();
this.rangeChartWidgetConfigForm.get('tooltipDateFont').disable();
this.rangeChartWidgetConfigForm.get('tooltipDateColor').disable();
this.rangeChartWidgetConfigForm.get('tooltipDateInterval').disable();
}
} else {
this.rangeChartWidgetConfigForm.get('tooltipValueFont').disable();
@ -237,6 +242,7 @@ export class RangeChartBasicConfigComponent extends BasicWidgetConfigComponent {
this.rangeChartWidgetConfigForm.get('tooltipDateFormat').disable();
this.rangeChartWidgetConfigForm.get('tooltipDateFont').disable();
this.rangeChartWidgetConfigForm.get('tooltipDateColor').disable();
this.rangeChartWidgetConfigForm.get('tooltipDateInterval').disable();
this.rangeChartWidgetConfigForm.get('tooltipBackgroundColor').disable();
this.rangeChartWidgetConfigForm.get('tooltipBackgroundBlur').disable();
}

2
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/time-series-chart-basic-config.component.html

@ -32,7 +32,7 @@
removeKeyTitle="{{ 'widgets.chart.remove-series' | translate }}"
noKeysText="{{ 'widgets.chart.no-series' | translate }}"
requiredKeysText="{{ 'widgets.chart.no-series-error' | translate }}"
showTimeSeriesType
[showTimeSeriesType]="chartType === TimeSeriesChartType.default"
hideSourceSelection
[datasourceType]="datasource?.type"
[deviceId]="datasource?.deviceId"

18
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/time-series-chart-basic-config.component.ts

@ -33,7 +33,7 @@ import {
getTimewindowConfig,
setTimewindowConfig
} from '@home/components/widget/config/timewindow-config-panel.component';
import { formatValue, isUndefined, mergeDeep } from '@core/utils';
import { formatValue, isDefinedAndNotNull, isUndefined, mergeDeep } from '@core/utils';
import {
cssSizeToStrSize,
DateFormatProcessor,
@ -44,8 +44,8 @@ import {
timeSeriesChartWidgetDefaultSettings,
TimeSeriesChartWidgetSettings
} from '@home/components/widget/lib/chart/time-series-chart-widget.models';
import { ValueType } from '@shared/models/constants';
import { EChartsTooltipTrigger } from '@home/components/widget/lib/chart/echarts-widget.models';
import { TimeSeriesChartType } from '@home/components/widget/lib/chart/time-series-chart.models';
@Component({
selector: 'tb-time-series-chart-basic-config',
@ -63,6 +63,8 @@ export class TimeSeriesChartBasicConfigComponent extends BasicWidgetConfigCompon
}
}
TimeSeriesChartType = TimeSeriesChartType;
EChartsTooltipTrigger = EChartsTooltipTrigger;
legendPositions = legendPositions;
@ -75,6 +77,8 @@ export class TimeSeriesChartBasicConfigComponent extends BasicWidgetConfigCompon
tooltipDatePreviewFn = this._tooltipDatePreviewFn.bind(this);
chartType = TimeSeriesChartType.default;
constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent,
private $injector: Injector,
@ -86,6 +90,14 @@ export class TimeSeriesChartBasicConfigComponent extends BasicWidgetConfigCompon
return this.timeSeriesChartWidgetConfigForm;
}
protected setupConfig(widgetConfig: WidgetConfigComponentData) {
const params = widgetConfig.typeParameters as any;
if (isDefinedAndNotNull(params.chartType)) {
this.chartType = params.chartType;
}
super.setupConfig(widgetConfig);
}
protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] {
return [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries, units: '°C', decimals: 0 }];
}
@ -309,6 +321,4 @@ export class TimeSeriesChartBasicConfigComponent extends BasicWidgetConfigCompon
processor.update(Date.now());
return processor.formatted;
}
protected readonly ValueType = ValueType;
}

8
ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.scss

@ -68,7 +68,13 @@
.tb-label-field, .tb-units-field, .tb-color-field, .tb-decimals-field {
display: none;
@media #{$mat-gt-sm} {
display: block;
display: flex;
}
}
.tb-time-series-type-field {
@media #{$mat-md} {
display: none;
}
}

1
ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts

@ -322,6 +322,7 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit {
if (this.showTimeSeriesType) {
this.keyRowFormGroup.get('timeSeriesType').patchValue(this.modelValue.settings?.type, {emitEvent: false});
}
this.keyFormControl.patchValue(deepClone(this.modelValue), {emitEvent: false});
this.updateModel();
this.cd.markForCheck();
}

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

@ -15,7 +15,7 @@
limitations under the License.
-->
<div class="tb-form-panel">
<div class="tb-form-panel tb-data-keys-panel">
<div class="tb-form-panel-title">{{ panelTitle }}</div>
<div class="tb-form-table">
<div class="tb-form-table-header no-padding-right">

107
ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.scss

@ -15,56 +15,71 @@
*/
@import '../../../../../../../../scss/constants';
.tb-form-table-header-cell {
&.tb-source-header {
width: 108px;
min-width: 108px;
}
&.tb-key-header {
flex: 1;
min-width: 150px;
@media #{$mat-gt-sm} {
flex: 1 1 60%;
.tb-data-keys-panel {
.tb-form-table-header-cell {
&.tb-source-header {
width: 108px;
min-width: 108px;
}
}
&.tb-label-header {
flex: 1 1 40%;
min-width: 100px;
}
&.tb-units-header {
width: 80px;
min-width: 80px;
}
&.tb-color-header {
width: 40px;
min-width: 40px;
}
&.tb-decimals-header {
width: 60px;
min-width: 60px;
}
&.tb-time-series-type-header {
width: 60px;
min-width: 60px;
}
&.tb-actions-header {
width: 40px;
min-width: 40px;
@media #{$mat-gt-md} {
width: 120px;
min-width: 120px;
&.tb-key-header {
flex: 1;
min-width: 150px;
@media #{$mat-gt-sm} {
flex: 1 1 60%;
}
}
}
&.tb-label-header, &.tb-units-header, &.tb-color-header, &.tb-decimals-header {
display: none;
@media #{$mat-gt-sm} {
display: block;
&.tb-label-header {
flex: 1 1 40%;
min-width: 100px;
}
&.tb-units-header {
width: 80px;
min-width: 80px;
}
&.tb-color-header {
width: 40px;
min-width: 40px;
}
&.tb-decimals-header {
width: 60px;
min-width: 60px;
}
&.tb-time-series-type-header {
width: 60px;
min-width: 60px;
}
&.tb-actions-header {
width: 40px;
min-width: 40px;
@media #{$mat-gt-md} {
width: 120px;
min-width: 120px;
}
}
&.tb-label-header, &.tb-units-header, &.tb-color-header, &.tb-decimals-header {
display: none;
@media #{$mat-gt-sm} {
display: block;
}
}
&.tb-time-series-type-header {
@media #{$mat-md} {
display: none;
}
}
}
}
.tb-form-table-body {
tb-data-key-row {
overflow: hidden;
.tb-form-table-body {
tb-data-key-row {
overflow: hidden;
}
}
}

1
ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html

@ -196,6 +196,7 @@
<tb-widget-settings
[dashboard]="dashboard"
[aliasController]="aliasController"
[dataKeyCallbacks]="callbacks"
[widget]="widget"
[widgetConfig]="widgetConfig"
formControlName="settings">

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

@ -49,6 +49,7 @@ import { Dashboard } from '@shared/models/dashboard.models';
import { WidgetService } from '@core/http/widget.service';
import { IAliasController } from '@core/api/widget-api.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import { DataKeysCallbacks } from '@home/components/widget/config/data-keys.component.models';
@Component({
selector: 'tb-widget-settings',
@ -77,6 +78,9 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, On
@Input()
aliasController: IAliasController;
@Input()
dataKeyCallbacks: DataKeysCallbacks;
@Input()
dashboard: Dashboard;
@ -98,7 +102,7 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, On
private definedSettingsComponent: IWidgetSettingsComponent;
private widgetSettingsFormData: JsonFormComponentData;
private propagateChange = (v: any) => { };
private propagateChange = (_v: any) => { };
constructor(private translate: TranslateService,
private cfr: ComponentFactoryResolver,
@ -138,6 +142,11 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, On
this.definedSettingsComponent.aliasController = this.aliasController;
}
}
if (propName === 'dataKeyCallbacks') {
if (this.definedSettingsComponent) {
this.definedSettingsComponent.dataKeyCallbacks = this.dataKeyCallbacks;
}
}
if (propName === 'widgetConfig') {
if (this.definedSettingsComponent) {
this.definedSettingsComponent.widgetConfig = this.widgetConfig;
@ -225,6 +234,7 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, On
this.definedSettingsComponentRef = this.definedSettingsContainer.createComponent(factory);
this.definedSettingsComponent = this.definedSettingsComponentRef.instance;
this.definedSettingsComponent.aliasController = this.aliasController;
this.definedSettingsComponent.dataKeyCallbacks = this.dataKeyCallbacks;
this.definedSettingsComponent.dashboard = this.dashboard;
this.definedSettingsComponent.widget = this.widget;
this.definedSettingsComponent.widgetConfig = this.widgetConfig;

9
ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-bar.models.ts

@ -119,10 +119,17 @@ export const renderTimeSeriesBar = (params: CustomSeriesRenderItemParams, api: C
style.rich = renderCtx.labelOption.rich;
}
let borderRadius: number[];
if (value < 0) {
borderRadius = [0, 0, renderCtx.visualSettings.borderRadius, renderCtx.visualSettings.borderRadius];
} else {
borderRadius = [renderCtx.visualSettings.borderRadius, renderCtx.visualSettings.borderRadius, 0, 0];
}
return rectShape && {
type: 'rect',
id: time + '',
shape: {...rectShape, r: renderCtx.visualSettings.borderRadius},
shape: {...rectShape, r: borderRadius},
style,
focus: 'series',
transition: 'all',

15
ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts

@ -43,6 +43,21 @@ import { TbColorScheme } from '@shared/models/color.models';
import { AbstractControl, ValidationErrors } from '@angular/forms';
import { MarkLine2DDataItemOption } from 'echarts/types/src/component/marker/MarkLineModel';
export enum TimeSeriesChartType {
default = 'default',
line = 'line',
bar = 'bar',
point = 'point'
}
export const timeSeriesChartTypeTranslations = new Map<TimeSeriesChartType, string>(
[
[TimeSeriesChartType.line, 'widgets.time-series-chart.type-line'],
[TimeSeriesChartType.bar, 'widgets.time-series-chart.type-bar'],
[TimeSeriesChartType.point, 'widgets.time-series-chart.type-point']
]
);
const timeSeriesChartColorScheme: TbColorScheme = {
'threshold.line': {
light: 'rgba(0, 0, 0, 0.76)',

21
ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts

@ -21,15 +21,18 @@ import {
createTimeSeriesXAxisOption,
createTimeSeriesYAxis,
generateChartData,
parseThresholdData, SeriesLabelPosition,
parseThresholdData,
SeriesLabelPosition,
TimeSeriesChartDataItem,
timeSeriesChartDefaultSettings,
timeSeriesChartKeyDefaultSettings,
TimeSeriesChartKeySettings,
TimeSeriesChartSeriesType,
TimeSeriesChartSettings,
TimeSeriesChartShape,
TimeSeriesChartThresholdItem,
TimeSeriesChartThresholdType,
TimeSeriesChartType,
TimeSeriesChartYAxis,
updateDarkMode
} from '@home/components/widget/lib/chart/time-series-chart.models';
@ -63,11 +66,23 @@ import { DataKeySettingsFunction } from '@home/components/widget/config/data-key
export class TbTimeSeriesChart {
public static dataKeySettings(): DataKeySettingsFunction {
public static dataKeySettings(type = TimeSeriesChartType.default): DataKeySettingsFunction {
return (key, isLatestDataKey) => {
if (!isLatestDataKey) {
return mergeDeep<TimeSeriesChartKeySettings>({} as TimeSeriesChartKeySettings,
const settings = mergeDeep<TimeSeriesChartKeySettings>({} as TimeSeriesChartKeySettings,
timeSeriesChartKeyDefaultSettings);
if (type === TimeSeriesChartType.line) {
settings.type = TimeSeriesChartSeriesType.line;
} else if (type === TimeSeriesChartType.bar) {
settings.type = TimeSeriesChartSeriesType.bar;
} else if (type === TimeSeriesChartType.point) {
settings.type = TimeSeriesChartSeriesType.line;
settings.lineSettings.showLine = false;
settings.lineSettings.showPoints = true;
settings.lineSettings.pointShape = TimeSeriesChartShape.circle;
settings.lineSettings.pointSize = 8;
}
return settings;
}
return null;
};

7
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.html

@ -124,6 +124,13 @@
</tb-color-input>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="tooltipDateInterval">
<div tb-hint-tooltip-icon="{{'tooltip.show-date-time-interval-hint' | translate}}">
{{ 'tooltip.show-date-time-interval' | translate }}
</div>
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput

7
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.ts

@ -33,7 +33,7 @@ import {
@Component({
selector: 'tb-bar-chart-with-labels-widget-settings',
templateUrl: './bar-chart-with-labels-widget-settings.component.html',
styleUrls: []
styleUrls: ['./../widget-settings.scss']
})
export class BarChartWithLabelsWidgetSettingsComponent extends WidgetSettingsComponent {
@ -83,6 +83,8 @@ export class BarChartWithLabelsWidgetSettingsComponent extends WidgetSettingsCom
tooltipDateFormat: [settings.tooltipDateFormat, []],
tooltipDateFont: [settings.tooltipDateFont, []],
tooltipDateColor: [settings.tooltipDateColor, []],
tooltipDateInterval: [settings.tooltipDateInterval, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
@ -137,10 +139,12 @@ export class BarChartWithLabelsWidgetSettingsComponent extends WidgetSettingsCom
this.barChartWidgetSettingsForm.get('tooltipDateFormat').enable();
this.barChartWidgetSettingsForm.get('tooltipDateFont').enable();
this.barChartWidgetSettingsForm.get('tooltipDateColor').enable();
this.barChartWidgetSettingsForm.get('tooltipDateInterval').enable();
} else {
this.barChartWidgetSettingsForm.get('tooltipDateFormat').disable();
this.barChartWidgetSettingsForm.get('tooltipDateFont').disable();
this.barChartWidgetSettingsForm.get('tooltipDateColor').disable();
this.barChartWidgetSettingsForm.get('tooltipDateInterval').disable();
}
} else {
this.barChartWidgetSettingsForm.get('tooltipValueFont').disable();
@ -149,6 +153,7 @@ export class BarChartWithLabelsWidgetSettingsComponent extends WidgetSettingsCom
this.barChartWidgetSettingsForm.get('tooltipDateFormat').disable();
this.barChartWidgetSettingsForm.get('tooltipDateFont').disable();
this.barChartWidgetSettingsForm.get('tooltipDateColor').disable();
this.barChartWidgetSettingsForm.get('tooltipDateInterval').disable();
this.barChartWidgetSettingsForm.get('tooltipBackgroundColor').disable();
this.barChartWidgetSettingsForm.get('tooltipBackgroundBlur').disable();
}

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

@ -114,6 +114,13 @@
</tb-color-input>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="tooltipDateInterval">
<div tb-hint-tooltip-icon="{{'tooltip.show-date-time-interval-hint' | translate}}">
{{ 'tooltip.show-date-time-interval' | translate }}
</div>
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput

5
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts

@ -78,6 +78,8 @@ export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent {
tooltipDateFormat: [settings.tooltipDateFormat, []],
tooltipDateFont: [settings.tooltipDateFont, []],
tooltipDateColor: [settings.tooltipDateColor, []],
tooltipDateInterval: [settings.tooltipDateInterval, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
@ -114,10 +116,12 @@ export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent {
this.rangeChartWidgetSettingsForm.get('tooltipDateFormat').enable();
this.rangeChartWidgetSettingsForm.get('tooltipDateFont').enable();
this.rangeChartWidgetSettingsForm.get('tooltipDateColor').enable();
this.rangeChartWidgetSettingsForm.get('tooltipDateInterval').enable();
} else {
this.rangeChartWidgetSettingsForm.get('tooltipDateFormat').disable();
this.rangeChartWidgetSettingsForm.get('tooltipDateFont').disable();
this.rangeChartWidgetSettingsForm.get('tooltipDateColor').disable();
this.rangeChartWidgetSettingsForm.get('tooltipDateInterval').disable();
}
} else {
this.rangeChartWidgetSettingsForm.get('tooltipValueFont').disable();
@ -126,6 +130,7 @@ export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent {
this.rangeChartWidgetSettingsForm.get('tooltipDateFormat').disable();
this.rangeChartWidgetSettingsForm.get('tooltipDateFont').disable();
this.rangeChartWidgetSettingsForm.get('tooltipDateColor').disable();
this.rangeChartWidgetSettingsForm.get('tooltipDateInterval').disable();
this.rangeChartWidgetSettingsForm.get('tooltipBackgroundColor').disable();
this.rangeChartWidgetSettingsForm.get('tooltipBackgroundBlur').disable();
}

6
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-key-settings.component.html

@ -30,13 +30,14 @@
</mat-slide-toggle>
</div>
<div class="tb-form-panel">
<div fxLayout="row" fxLayoutAlign="space-between center">
<div *ngIf="chartType === TimeSeriesChartType.default; else chartTypeTitle" fxLayout="row" fxLayoutAlign="space-between center">
<div class="tb-form-panel-title" translate>widgets.time-series-chart.series.series-type</div>
<tb-toggle-select formControlName="type">
<tb-toggle-option *ngFor="let type of timeSeriesChartSeriesTypes" [value]="type">{{ timeSeriesChartSeriesTypeTranslations.get(type) | translate }}</tb-toggle-option>
</tb-toggle-select>
</div>
<tb-time-series-chart-line-settings [fxShow]="timeSeriesChartKeySettingsForm.get('type').value === TimeSeriesChartSeriesType.line"
[chartType]="chartType"
formControlName="lineSettings">
</tb-time-series-chart-line-settings>
<tb-time-series-chart-bar-settings [fxShow]="timeSeriesChartKeySettingsForm.get('type').value === TimeSeriesChartSeriesType.bar"
@ -44,3 +45,6 @@
</tb-time-series-chart-bar-settings>
</div>
</ng-container>
<ng-template #chartTypeTitle>
<div class="tb-form-panel-title">{{ timeSeriesChartTypeTranslations.get(chartType) | translate }}</div>
</ng-template>

14
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-key-settings.component.ts

@ -19,13 +19,13 @@ import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.m
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { mergeDeep } from '@core/utils';
import { isDefinedAndNotNull, mergeDeep } from '@core/utils';
import {
timeSeriesChartKeyDefaultSettings,
TimeSeriesChartKeySettings,
TimeSeriesChartSeriesType,
timeSeriesChartSeriesTypes,
timeSeriesChartSeriesTypeTranslations
timeSeriesChartSeriesTypeTranslations, TimeSeriesChartType, timeSeriesChartTypeTranslations
} from '@home/components/widget/lib/chart/time-series-chart.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
@ -36,6 +36,10 @@ import { WidgetConfigComponentData } from '@home/models/widget-component.models'
})
export class TimeSeriesChartKeySettingsComponent extends WidgetSettingsComponent {
TimeSeriesChartType = TimeSeriesChartType;
timeSeriesChartTypeTranslations = timeSeriesChartTypeTranslations;
TimeSeriesChartSeriesType = TimeSeriesChartSeriesType;
timeSeriesChartSeriesTypes = timeSeriesChartSeriesTypes;
@ -44,6 +48,8 @@ export class TimeSeriesChartKeySettingsComponent extends WidgetSettingsComponent
timeSeriesChartKeySettingsForm: UntypedFormGroup;
chartType = TimeSeriesChartType.default;
constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder) {
super(store);
@ -55,7 +61,9 @@ export class TimeSeriesChartKeySettingsComponent extends WidgetSettingsComponent
protected onWidgetConfigSet(widgetConfig: WidgetConfigComponentData) {
const params = widgetConfig.typeParameters as any;
// const timeSeriesChartType = params.timeSeriesChartType;
if (isDefinedAndNotNull(params.chartType)) {
this.chartType = params.chartType;
}
}
protected defaultSettings(): WidgetSettings {

89
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.html

@ -16,7 +16,7 @@
-->
<ng-container [formGroup]="lineSettingsFormGroup">
<div class="tb-form-panel stroked">
<div *ngIf="chartType !== TimeSeriesChartType.point" class="tb-form-panel stroked">
<div class="tb-form-panel-title" translate>widgets.time-series-chart.series.line.line</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="showLine">
@ -57,57 +57,60 @@
</mat-form-field>
</div>
</div>
<div class="tb-form-panel stroked">
<div *ngIf="chartType !== TimeSeriesChartType.point; else pointSettings" class="tb-form-panel stroked">
<div class="tb-form-panel-title" translate>widgets.time-series-chart.series.point.points</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="showPoints">
{{ 'widgets.time-series-chart.series.point.show-points' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between column-lt-md">
<mat-slide-toggle class="mat-slide" formControlName="showPointLabel">
<div tb-hint-tooltip-icon="{{'widgets.time-series-chart.series.point.point-label-hint' | translate}}">
{{ 'widgets.time-series-chart.series.point.point-label' | translate }}
</div>
</mat-slide-toggle>
<div fxLayout="row" fxFlex.lt-md fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" fxFlex.lt-md appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="pointLabelPosition">
<mat-option *ngFor="let position of seriesLabelPositions" [value]="position">
{{ seriesLabelPositionTranslations.get(position) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-font-settings formControlName="pointLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
[previewText]="pointLabelPreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="pointLabelColor">
</tb-color-input>
<ng-container *ngTemplateOutlet="pointSettings"></ng-container>
</div>
<tb-time-series-chart-fill-settings
formControlName="fillAreaSettings">
</tb-time-series-chart-fill-settings>
</ng-container>
<ng-template #pointSettings [formGroup]="lineSettingsFormGroup">
<div class="tb-form-row space-between column-lt-md">
<mat-slide-toggle class="mat-slide" formControlName="showPointLabel">
<div tb-hint-tooltip-icon="{{'widgets.time-series-chart.series.point.point-label-hint' | translate}}">
{{ 'widgets.time-series-chart.series.point.point-label' | translate }}
</div>
</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.time-series-chart.series.point.point-shape</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="pointShape">
<mat-option *ngFor="let shape of timeSeriesChartShapes" [value]="shape">
{{ timeSeriesChartShapeTranslations.get(shape) | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxFlex.lt-md fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" fxFlex.lt-md appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="pointLabelPosition">
<mat-option *ngFor="let position of seriesLabelPositions" [value]="position">
{{ seriesLabelPositionTranslations.get(position) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.time-series-chart.series.point.point-size</div>
<mat-form-field class="medium-width number" appearance="outline" subscriptSizing="dynamic">
<input matInput type="number" formControlName="pointSize" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}"/>
</mat-form-field>
<tb-font-settings formControlName="pointLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
[previewText]="pointLabelPreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="pointLabelColor">
</tb-color-input>
</div>
</div>
<tb-time-series-chart-fill-settings
formControlName="fillAreaSettings">
</tb-time-series-chart-fill-settings>
</ng-container>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.time-series-chart.series.point.point-shape</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="pointShape">
<mat-option *ngFor="let shape of timeSeriesChartShapes" [value]="shape">
{{ timeSeriesChartShapeTranslations.get(shape) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.time-series-chart.series.point.point-size</div>
<mat-form-field class="medium-width number" appearance="outline" subscriptSizing="dynamic">
<input matInput type="number" formControlName="pointSize" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}"/>
</mat-form-field>
</div>
</ng-template>

7
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts

@ -29,7 +29,7 @@ import {
seriesLabelPositions,
seriesLabelPositionTranslations,
timeSeriesChartShapes,
timeSeriesChartShapeTranslations,
timeSeriesChartShapeTranslations, TimeSeriesChartType,
timeSeriesLineTypes,
timeSeriesLineTypeTranslations
} from '@home/components/widget/lib/chart/time-series-chart.models';
@ -53,6 +53,8 @@ import { DataKeyConfigComponent } from '@home/components/widget/config/data-key-
})
export class TimeSeriesChartLineSettingsComponent implements OnInit, ControlValueAccessor {
TimeSeriesChartType = TimeSeriesChartType;
lineSeriesStepTypes = lineSeriesStepTypes;
lineSeriesStepTypeTranslations = lineSeriesStepTypeTranslations;
@ -74,6 +76,9 @@ export class TimeSeriesChartLineSettingsComponent implements OnInit, ControlValu
@Input()
disabled: boolean;
@Input()
chartType: TimeSeriesChartType;
private modelValue: LineSeriesSettings;
private propagateChange = null;

159
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-widget-settings.component.html

@ -0,0 +1,159 @@
<!--
Copyright © 2016-2024 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<ng-container [formGroup]="timeSeriesChartWidgetSettingsForm">
<tb-time-series-chart-thresholds-panel
formControlName="thresholds"
[aliasController]="aliasController"
[dataKeyCallbacks]="dataKeyCallbacks"
[datasource]="datasource"
[widgetConfig]="widgetConfig?.config">
</tb-time-series-chart-thresholds-panel>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.time-series-chart.chart-style</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="dataZoom">
{{ 'widgets.time-series-chart.data-zoom' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="stack">
<div tb-hint-tooltip-icon="{{'widgets.time-series-chart.stack-mode-hint' | translate}}">
{{ 'widgets.time-series-chart.stack-mode' | translate }}
</div>
</mat-slide-toggle>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.time-series-chart.axis.axes</div>
<tb-time-series-chart-axis-settings
formControlName="yAxis"
axisType="yAxis">
</tb-time-series-chart-axis-settings>
<tb-time-series-chart-axis-settings
formControlName="xAxis"
axisType="xAxis">
</tb-time-series-chart-axis-settings>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="timeSeriesChartWidgetSettingsForm.get('showLegend').value"
[disabled]="!timeSeriesChartWidgetSettingsForm.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between">
<div>{{ 'legend.label' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendLabelFont"
previewText="Temperature">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendLabelColor">
</tb-color-input>
</div>
</div>
<tb-legend-config hideDirection
formControlName="legendConfig">
</tb-legend-config>
</ng-template>
</mat-expansion-panel>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="timeSeriesChartWidgetSettingsForm.get('showTooltip').value"
[disabled]="!timeSeriesChartWidgetSettingsForm.get('showTooltip').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showTooltip" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.tooltip' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.trigger' | translate }}</div>
<mat-chip-listbox class="center-stretch" formControlName="tooltipTrigger">
<mat-chip-option [selectable]="timeSeriesChartWidgetSettingsForm.get('tooltipTrigger').value !== EChartsTooltipTrigger.point"
[value]="EChartsTooltipTrigger.point">{{ 'tooltip.trigger-point' | translate }}</mat-chip-option>
<mat-chip-option [selectable]="timeSeriesChartWidgetSettingsForm.get('tooltipTrigger').value !== EChartsTooltipTrigger.axis"
[value]="EChartsTooltipTrigger.axis">{{ 'tooltip.trigger-axis' | translate }}</mat-chip-option>
</mat-chip-listbox>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="tooltipValueFont"
[previewText]="tooltipValuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipValueColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="tooltipShowDate">
{{ 'tooltip.date' | translate }}
</mat-slide-toggle>
<div fxFlex.gt-xs fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-date-format-select fxFlex excludeLastUpdateAgo formControlName="tooltipDateFormat"></tb-date-format-select>
<tb-font-settings formControlName="tooltipDateFont"
[previewText]="tooltipDatePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipDateColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="tooltipDateInterval">
<div tb-hint-tooltip-icon="{{'tooltip.show-date-time-interval-hint' | translate}}">
{{ 'tooltip.show-date-time-interval' | translate }}
</div>
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipBackgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-blur' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipBackgroundBlur" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-background-settings formControlName="background">
</tb-background-settings>
</div>
</div>
</ng-container>

174
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-widget-settings.component.ts

@ -0,0 +1,174 @@
///
/// Copyright © 2016-2024 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component, Injector } from '@angular/core';
import {
Datasource,
legendPositions,
legendPositionTranslationMap,
WidgetSettings,
WidgetSettingsComponent
} from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { formatValue, mergeDeep } from '@core/utils';
import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-settings.models';
import {
barChartWithLabelsDefaultSettings
} from '@home/components/widget/lib/chart/bar-chart-with-labels-widget.models';
import { EChartsTooltipTrigger } from '../../chart/echarts-widget.models';
import {
timeSeriesChartWidgetDefaultSettings, TimeSeriesChartWidgetSettings
} from '@home/components/widget/lib/chart/time-series-chart-widget.models';
@Component({
selector: 'tb-time-series-chart-widget-settings',
templateUrl: './time-series-chart-widget-settings.component.html',
styleUrls: ['./../widget-settings.scss']
})
export class TimeSeriesChartWidgetSettingsComponent extends WidgetSettingsComponent {
public get datasource(): Datasource {
const datasources: Datasource[] = this.widgetConfig.config.datasources;
if (datasources && datasources.length) {
return datasources[0];
} else {
return null;
}
}
EChartsTooltipTrigger = EChartsTooltipTrigger;
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
timeSeriesChartWidgetSettingsForm: UntypedFormGroup;
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
tooltipDatePreviewFn = this._tooltipDatePreviewFn.bind(this);
constructor(protected store: Store<AppState>,
private $injector: Injector,
private fb: UntypedFormBuilder) {
super(store);
}
protected settingsForm(): UntypedFormGroup {
return this.timeSeriesChartWidgetSettingsForm;
}
protected defaultSettings(): WidgetSettings {
return mergeDeep({} as TimeSeriesChartWidgetSettings, timeSeriesChartWidgetDefaultSettings);
}
protected onSettingsSet(settings: WidgetSettings) {
this.timeSeriesChartWidgetSettingsForm = this.fb.group({
thresholds: [settings.thresholds, []],
dataZoom: [settings.dataZoom, []],
stack: [settings.stack, []],
yAxis: [settings.yAxis, []],
xAxis: [settings.xAxis, []],
showLegend: [settings.showLegend, []],
legendLabelFont: [settings.legendLabelFont, []],
legendLabelColor: [settings.legendLabelColor, []],
legendConfig: [settings.legendConfig, []],
showTooltip: [settings.showTooltip, []],
tooltipTrigger: [settings.tooltipTrigger, []],
tooltipValueFont: [settings.tooltipValueFont, []],
tooltipValueColor: [settings.tooltipValueColor, []],
tooltipShowDate: [settings.tooltipShowDate, []],
tooltipDateFormat: [settings.tooltipDateFormat, []],
tooltipDateFont: [settings.tooltipDateFont, []],
tooltipDateColor: [settings.tooltipDateColor, []],
tooltipDateInterval: [settings.tooltipDateInterval, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
background: [settings.background, []]
});
}
protected validatorTriggers(): string[] {
return ['showLegend', 'showTooltip', 'tooltipShowDate'];
}
protected updateValidators(emitEvent: boolean) {
const showLegend: boolean = this.timeSeriesChartWidgetSettingsForm.get('showLegend').value;
const showTooltip: boolean = this.timeSeriesChartWidgetSettingsForm.get('showTooltip').value;
const tooltipShowDate: boolean = this.timeSeriesChartWidgetSettingsForm.get('tooltipShowDate').value;
if (showLegend) {
this.timeSeriesChartWidgetSettingsForm.get('legendLabelFont').enable();
this.timeSeriesChartWidgetSettingsForm.get('legendLabelColor').enable();
this.timeSeriesChartWidgetSettingsForm.get('legendConfig').enable();
} else {
this.timeSeriesChartWidgetSettingsForm.get('legendLabelFont').disable();
this.timeSeriesChartWidgetSettingsForm.get('legendLabelColor').disable();
this.timeSeriesChartWidgetSettingsForm.get('legendConfig').disable();
}
if (showTooltip) {
this.timeSeriesChartWidgetSettingsForm.get('tooltipTrigger').enable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipValueFont').enable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipValueColor').enable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipShowDate').enable({emitEvent: false});
this.timeSeriesChartWidgetSettingsForm.get('tooltipBackgroundColor').enable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipBackgroundBlur').enable();
if (tooltipShowDate) {
this.timeSeriesChartWidgetSettingsForm.get('tooltipDateFormat').enable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipDateFont').enable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipDateColor').enable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipDateInterval').enable();
} else {
this.timeSeriesChartWidgetSettingsForm.get('tooltipDateFormat').disable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipDateFont').disable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipDateColor').disable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipDateInterval').disable();
}
} else {
this.timeSeriesChartWidgetSettingsForm.get('tooltipValueFont').disable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipValueColor').disable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipShowDate').disable({emitEvent: false});
this.timeSeriesChartWidgetSettingsForm.get('tooltipDateFormat').disable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipDateFont').disable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipDateColor').disable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipDateInterval').disable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipBackgroundColor').disable();
this.timeSeriesChartWidgetSettingsForm.get('tooltipBackgroundBlur').disable();
}
}
private _tooltipValuePreviewFn(): string {
return formatValue(22, 0, '°C', false);
}
private _tooltipDatePreviewFn(): string {
const dateFormat: DateFormatSettings = this.timeSeriesChartWidgetSettingsForm.get('tooltipDateFormat').value;
const processor = DateFormatProcessor.fromSettings(this.$injector, dateFormat);
processor.update(Date.now());
return processor.formatted;
}
}

3
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.html

@ -49,10 +49,12 @@
<tb-data-key-input
*ngIf="thresholdFormGroup.get('type').value === TimeSeriesChartThresholdType.latestKey"
required
requiredText="widgets.time-series-chart.threshold.key-required"
[datasourceType]="datasource?.type"
[entityAliasId]="datasource?.entityAliasId"
[deviceId]="datasource?.deviceId"
[aliasController]="aliasController"
[dataKeyType]="datasource?.type === DatasourceType.function ? DataKeyType.function : null"
[dataKeyTypes]="[DataKeyType.attribute, DataKeyType.timeseries]"
[callbacks]="dataKeyCallbacks"
[editable]="false"
@ -61,6 +63,7 @@
<tb-data-key-input
*ngIf="thresholdFormGroup.get('type').value === TimeSeriesChartThresholdType.entity"
required
requiredText="widgets.time-series-chart.threshold.entity-key-required"
[datasourceType]="DatasourceType.entity"
[aliasController]="aliasController"
[entityAlias]="thresholdFormGroup.get('entityAlias').value"

41
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.scss

@ -13,14 +13,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.tb-time-series-threshold-row {
@import '../../../../../../../../../scss/constants';
.tb-form-table-row.tb-time-series-threshold-row {
@media #{$mat-lt-md} {
align-items: flex-start;
}
.tb-threshold-source-field {
flex: 1;
min-width: 200px;
min-width: 100px;
display: flex;
align-items: center;
flex-direction: row;
gap: 12px;
flex-direction: column;
gap: 8px;
@media #{$mat-gt-sm} {
flex-direction: row;
align-items: center;
gap: 12px;
}
@media #{$mat-gt-md} {
min-width: 200px;
}
}
.tb-threshold-type-field {
@ -33,13 +46,16 @@
.tb-threshold-key-value-field {
flex: 1;
min-width: 150px;
.tb-inline-field, .tb-data-key-input {
flex: 1;
min-width: 100px;
.tb-inline-field {
width: 100%;
}
@media #{$mat-gt-md} {
min-width: 150px;
}
}
.tb-threshold-key-value-field, .tb-color-field, .tb-units-field, .tb-decimals-field {
.tb-color-field, .tb-units-field, .tb-decimals-field {
display: flex;
flex-direction: row;
place-content: center;
@ -61,4 +77,11 @@
min-width: 60px;
}
.tb-units-field, .tb-color-field, .tb-decimals-field {
display: none;
@media #{$mat-gt-md} {
display: flex;
}
}
}

6
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.ts

@ -212,7 +212,11 @@ export class TimeSeriesChartThresholdRowComponent implements ControlValueAccesso
thresholdSettingsPanelPopover.hide();
this.modelValue = {...this.modelValue, ...thresholdSettings};
this.thresholdFormGroup.patchValue(
{lineColor: this.modelValue.lineColor},
{
units: this.modelValue.units,
decimals: this.modelValue.decimals,
lineColor: this.modelValue.lineColor
},
{emitEvent: false});
this.propagateChange(this.modelValue);
});

68
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.html

@ -18,6 +18,42 @@
<div class="tb-threshold-settings-panel" [formGroup]="thresholdSettingsFormGroup">
<div class="tb-threshold-settings-title">{{ 'widgets.time-series-chart.threshold.threshold-settings' | translate }}</div>
<div class="tb-threshold-settings-panel-content">
<div class="tb-form-row space-between">
<div translate>widget-config.units-short</div>
<tb-unit-input
formControlName="units">
</tb-unit-input>
</div>
<div class="tb-form-row space-between">
<div translate>widget-config.decimals-short</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="decimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
<div class="tb-form-row space-between column-lt-md">
<mat-slide-toggle class="mat-slide" formControlName="showLabel">
{{ 'widgets.time-series-chart.threshold.label' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxFlex.lt-md fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" fxFlex.lt-md appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="labelPosition">
<mat-option *ngFor="let position of timeSeriesThresholdLabelPositions" [value]="position">
{{ timeSeriesThresholdLabelPositionTranslations.get(position) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-font-settings formControlName="labelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
[previewText]="labelPreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="labelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.time-series-chart.threshold.line-appearance</div>
<div class="tb-form-row space-between">
@ -46,7 +82,7 @@
<div class="tb-form-row space-between column-xs">
<div translate>widgets.time-series-chart.threshold.start-symbol</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="startSymbol">
<mat-option *ngFor="let shape of timeSeriesChartShapes" [value]="shape">
{{ timeSeriesChartShapeTranslations.get(shape) | translate }}
@ -54,7 +90,7 @@
</mat-select>
</mat-form-field>
<div class="tb-small-label" translate>widgets.time-series-chart.threshold.symbol-size</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<mat-form-field appearance="outline" class="number flex" subscriptSizing="dynamic">
<input matInput formControlName="startSymbolSize"
type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
@ -63,7 +99,7 @@
<div class="tb-form-row space-between column-xs">
<div translate>widgets.time-series-chart.threshold.end-symbol</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="endSymbol">
<mat-option *ngFor="let shape of timeSeriesChartShapes" [value]="shape">
{{ timeSeriesChartShapeTranslations.get(shape) | translate }}
@ -71,36 +107,12 @@
</mat-select>
</mat-form-field>
<div class="tb-small-label" translate>widgets.time-series-chart.threshold.symbol-size</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<mat-form-field appearance="outline" class="number flex" subscriptSizing="dynamic">
<input matInput formControlName="endSymbolSize"
type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-row space-between column-lt-md">
<mat-slide-toggle class="mat-slide" formControlName="showLabel">
{{ 'widgets.time-series-chart.threshold.label' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxFlex.lt-md fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" fxFlex.lt-md appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="labelPosition">
<mat-option *ngFor="let position of timeSeriesThresholdLabelPositions" [value]="position">
{{ timeSeriesThresholdLabelPositionTranslations.get(position) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-font-settings formControlName="labelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
[previewText]="labelPreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="labelColor">
</tb-color-input>
</div>
</div>
</div>
</div>
<div class="tb-threshold-settings-panel-buttons">

2
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.scss

@ -28,6 +28,8 @@
flex-direction: column;
gap: 16px;
overflow: auto;
margin: -10px;
padding: 10px;
}
.tb-threshold-settings-title {
font-size: 16px;

9
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.ts

@ -74,6 +74,8 @@ export class TimeSeriesChartThresholdSettingsPanelComponent implements OnInit {
ngOnInit(): void {
this.thresholdSettingsFormGroup = this.fb.group(
{
units: [this.thresholdSettings.units, []],
decimals: [this.thresholdSettings.decimals, [Validators.min(0)]],
lineColor: [this.thresholdSettings.lineColor, []],
lineType: [this.thresholdSettings.lineType, []],
lineWidth: [this.thresholdSettings.lineWidth, [Validators.min(0)]],
@ -130,9 +132,10 @@ export class TimeSeriesChartThresholdSettingsPanelComponent implements OnInit {
}
private _labelPreviewFn(): string {
const units = this.thresholdSettings.units && this.thresholdSettings.units.length ?
this.thresholdSettings.units : this.widgetConfig.units;
const decimals = isDefinedAndNotNull(this.thresholdSettings.decimals) ? this.thresholdSettings.decimals :
let units: string = this.thresholdSettingsFormGroup.get('units').value;
units = units && units.length ? units : this.widgetConfig.units;
let decimals: number = this.thresholdSettingsFormGroup.get('decimals').value;
decimals = isDefinedAndNotNull(decimals) ? decimals :
(isDefinedAndNotNull(this.widgetConfig.decimals) ? this.widgetConfig.decimals : 2);
return formatValue(22, decimals, units, false);
}

3
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-thresholds-panel.component.html

@ -27,11 +27,12 @@
<div class="tb-form-table-header-cell tb-actions-header"></div>
</div>
<div *ngIf="thresholdsFormArray().controls.length; else noThresholds" class="tb-form-table-body">
<div *ngFor="let thresholdControl of thresholdsFormArray().controls; trackBy: trackByThreshold; let $index = index;">
<div *ngFor="let thresholdControl of thresholdsFormArray().controls; trackBy: trackByThreshold; let $index = index; let $last = last">
<tb-time-series-chart-threshold-row fxFlex
[formControl]="thresholdControl"
(thresholdRemoved)="removeThreshold($index)">
</tb-time-series-chart-threshold-row>
<mat-divider *ngIf="!$last"></mat-divider>
</div>
</div>
</div>

31
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-thresholds-panel.component.scss

@ -13,15 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@import '../../../../../../../../../scss/constants';
.tb-time-series-thresholds-panel {
.tb-form-table-header-cell {
&.tb-threshold-source-header {
flex: 1;
min-width: 200px;
min-width: 100px;
@media #{$mat-gt-md} {
min-width: 200px;
}
}
&.tb-threshold-key-value-header {
flex: 1;
min-width: 150px;
min-width: 100px;
@media #{$mat-gt-md} {
min-width: 150px;
}
}
&.tb-units-header {
@ -43,5 +52,23 @@
width: 80px;
min-width: 80px;
}
&.tb-units-header, &.tb-color-header, &.tb-decimals-header {
display: none;
@media #{$mat-gt-md} {
display: block;
}
}
}
.tb-form-table-body {
.tb-time-series-threshold-row {
overflow: hidden;
}
.mat-divider {
margin-top: 8px;
@media #{$mat-gt-sm} {
display: none;
}
}
}
}

12
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/data-key-input.component.html

@ -15,7 +15,8 @@
limitations under the License.
-->
<mat-form-field class="tb-inline-field tb-key-field" subscriptSizing="dynamic">
<mat-form-field class="tb-inline-field tb-key-field" subscriptSizing="dynamic"
[class.tb-suffix-absolute]="!keysFormControl.value?.length">
<mat-chip-grid #chipList [formControl]="keysFormControl">
<mat-chip-row class="tb-datakey-chip" *ngIf="modelValue?.type"
(removed)="removeKey()">
@ -74,6 +75,15 @@
(matChipInputTokenEnd)="addKey($event)"
/>
</mat-chip-grid>
<mat-icon matSuffix
matTooltipPosition="above"
matTooltipClass="tb-error-tooltip"
[matTooltip]="requiredText | translate"
*ngIf="requiredText && keysFormControl.hasError('required')
&& keysFormControl.touched"
class="tb-error">
warning
</mat-icon>
<mat-autocomplete #keyAutocomplete="matAutocomplete"
class="tb-autocomplete"
panelWidth="fit-content"

3
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/data-key-input.component.ts

@ -87,6 +87,9 @@ export class DataKeyInputComponent implements ControlValueAccessor, OnInit, OnCh
@coerceBoolean()
required = false;
@Input()
requiredText: string;
@Input()
@coerceBoolean()
isLatestDataKeys = false;

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

@ -342,6 +342,9 @@ import {
import {
TimeSeriesChartBarSettingsComponent
} from '@home/components/widget/lib/settings/chart/time-series-chart-bar-settings.component';
import {
TimeSeriesChartWidgetSettingsComponent
} from '@home/components/widget/lib/settings/chart/time-series-chart-widget-settings.component';
@NgModule({
declarations: [
@ -464,7 +467,8 @@ import {
TimeSeriesChartKeySettingsComponent,
TimeSeriesChartLineSettingsComponent,
TimeSeriesChartBarSettingsComponent,
TimeSeriesChartFillSettingsComponent
TimeSeriesChartFillSettingsComponent,
TimeSeriesChartWidgetSettingsComponent
],
imports: [
CommonModule,
@ -592,7 +596,8 @@ import {
TimeSeriesChartKeySettingsComponent,
TimeSeriesChartLineSettingsComponent,
TimeSeriesChartBarSettingsComponent,
TimeSeriesChartFillSettingsComponent
TimeSeriesChartFillSettingsComponent,
TimeSeriesChartWidgetSettingsComponent
]
})
export class WidgetSettingsModule {
@ -684,5 +689,6 @@ export const widgetSettingsComponentsMap: {[key: string]: Type<IWidgetSettingsCo
'tb-power-button-widget-settings': PowerButtonWidgetSettingsComponent,
'tb-slider-widget-settings': SliderWidgetSettingsComponent,
'tb-toggle-button-widget-settings': ToggleButtonWidgetSettingsComponent,
'tb-time-series-chart-key-settings': TimeSeriesChartKeySettingsComponent
'tb-time-series-chart-key-settings': TimeSeriesChartKeySettingsComponent,
'tb-time-series-chart-widget-settings': TimeSeriesChartWidgetSettingsComponent
};

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

@ -288,6 +288,7 @@
<div *ngIf="displayAdvancedAppearance" style="height: 100%;" [formGroup]="advancedSettings">
<tb-widget-settings
[aliasController]="aliasController"
[dataKeyCallbacks]="widgetConfigCallbacks"
[dashboard]="dashboard"
[widget]="widget"
[widgetConfig]="modelValue"

9
ui-ngx/src/app/shared/models/time/time.models.ts

@ -1116,8 +1116,13 @@ export const endIntervalDate = (current: moment_.Moment, interval: IntervalType)
};
export const calculateAggIntervalWithSubscriptionTimeWindow
= (subsTw: SubscriptionTimewindow, endTs: number, timestamp: number): [number, number] =>
calculateInterval(subsTw.startTs, endTs, subsTw.aggregation.interval, subsTw.tsOffset, subsTw.timezone, timestamp);
= (subsTw: SubscriptionTimewindow, endTs: number, timestamp: number): [number, number] => {
if (subsTw.aggregation.type === AggregationType.NONE) {
return [timestamp, timestamp];
} else {
return calculateInterval(subsTw.startTs, endTs, subsTw.aggregation.interval, subsTw.tsOffset, subsTw.timezone, timestamp);
}
};
export const calculateAggIntervalWithWidgetTimeWindow
= (widgetTimeWindow: WidgetTimewindow, timestamp: number): [number, number] =>

9
ui-ngx/src/app/shared/models/widget.models.ts

@ -38,12 +38,12 @@ import { AbstractControl, UntypedFormGroup } from '@angular/forms';
import { Observable } from 'rxjs';
import { Dashboard } from '@shared/models/dashboard.models';
import { IAliasController } from '@core/api/widget-api.models';
import { isNotEmptyStr } from '@core/utils';
import { isNotEmptyStr, mergeDeep } from '@core/utils';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import { ComponentStyle, Font, TimewindowStyle } from '@shared/models/widget-settings.models';
import { NULL_UUID } from '@shared/models/id/has-uuid';
import { HasTenantId } from '@shared/models/entity.models';
import { DataKeySettingsFunction } from '@home/components/widget/config/data-keys.component.models';
import { DataKeysCallbacks, DataKeySettingsFunction } from '@home/components/widget/config/data-keys.component.models';
export enum widgetType {
timeseries = 'timeseries',
@ -815,6 +815,7 @@ export interface WidgetSize {
export interface IWidgetSettingsComponent {
aliasController: IAliasController;
dataKeyCallbacks: DataKeysCallbacks;
dashboard: Dashboard;
widget: Widget;
widgetConfig: WidgetConfigComponentData;
@ -832,6 +833,8 @@ export abstract class WidgetSettingsComponent extends PageComponent implements
aliasController: IAliasController;
dataKeyCallbacks: DataKeysCallbacks;
dashboard: Dashboard;
widget: Widget;
@ -857,7 +860,7 @@ export abstract class WidgetSettingsComponent extends PageComponent implements
if (!value) {
this.settingsValue = this.defaultSettings();
} else {
this.settingsValue = {...this.defaultSettings(), ...value};
this.settingsValue = mergeDeep(this.defaultSettings(), value);
}
if (!this.settingsSet) {
this.settingsSet = true;

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

@ -6597,6 +6597,7 @@
},
"time-series-chart": {
"chart": "Chart",
"chart-style": "Chart style",
"data-zoom": "Data zoom",
"stack-mode": "Stack mode",
"stack-mode-hint": "Stacks series on the chart. The series with the same unit would be put on top of each other.",
@ -6615,6 +6616,9 @@
"shape-pin": "Pin",
"shape-arrow": "Arrow",
"shape-none": "None",
"type-line": "Line",
"type-bar": "Bar",
"type-point": "Point",
"threshold": {
"thresholds": "Thresholds",
"source": "Source",
@ -6627,6 +6631,8 @@
"threshold-settings": "Threshold settings",
"remove-threshold": "Remove threshold",
"threshold-value-required": "Threshold value is required.",
"key-required": "Key is required.",
"entity-key-required": "Entity key is required.",
"line-appearance": "Line appearance",
"line-color": "Line color",
"start-symbol": "Start symbol",

Loading…
Cancel
Save