Browse Source

Fixed Range and Bar chart limits setup

pull/14964/head
Maksym Tsymbarov 4 months ago
parent
commit
d3628bb9d8
  1. 2
      application/src/main/data/json/system/widget_types/bar_chart_with_labels.json
  2. 2
      application/src/main/data/json/system/widget_types/range_chart.json
  3. 12
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/bar-chart-with-labels-basic-config.component.ts
  4. 7
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.ts
  5. 6
      ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.component.ts
  6. 6
      ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.component.ts
  7. 100
      ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts
  8. 23
      ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts
  9. 6
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.ts
  10. 7
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts
  11. 37
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/axis-scale-row.component.ts
  12. 6
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.ts
  13. 108
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axes-panel.component.ts
  14. 29
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts

2
application/src/main/data/json/system/widget_types/bar_chart_with_labels.json

@ -11,7 +11,7 @@
"resources": [], "resources": [],
"templateHtml": "<tb-bar-chart-with-labels-widget \n [ctx]=\"ctx\">\n</tb-bar-chart-with-labels-widget>", "templateHtml": "<tb-bar-chart-with-labels-widget \n [ctx]=\"ctx\">\n</tb-bar-chart-with-labels-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": ".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",
"controllerScript": "self.onInit = function() {\n self.ctx.$scope.barChartWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.barChartWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n previewWidth: '80%',\n embedTitlePanel: true,\n embedActionsPanel: true,\n supportsUnitConversion: true,\n hasAdditionalLatestDataKeys: false,\n defaultDataKeysFunction: function() {\n return [{ name: 'humidity', label: 'Humidity', type: 'timeseries' }];\n }\n };\n}\n", "controllerScript": "self.onInit = function() {\n self.ctx.$scope.barChartWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.barChartWidget.onDataUpdated();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.barChartWidget.onLatestDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n previewWidth: '80%',\n embedTitlePanel: true,\n embedActionsPanel: true,\n supportsUnitConversion: true,\n hasAdditionalLatestDataKeys: false,\n defaultDataKeysFunction: function() {\n return [{ name: 'humidity', label: 'Humidity', type: 'timeseries' }];\n }\n };\n}\n",
"settingsForm": [], "settingsForm": [],
"dataKeySettingsForm": [], "dataKeySettingsForm": [],
"latestDataKeySettingsForm": [], "latestDataKeySettingsForm": [],

2
application/src/main/data/json/system/widget_types/range_chart.json

@ -11,7 +11,7 @@
"resources": [], "resources": [],
"templateHtml": "<tb-range-chart-widget \n [ctx]=\"ctx\">\n</tb-range-chart-widget>", "templateHtml": "<tb-range-chart-widget \n [ctx]=\"ctx\">\n</tb-range-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": ".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",
"controllerScript": "self.onInit = function() {\n self.ctx.$scope.rangeChartWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.rangeChartWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '80%',\n embedTitlePanel: true,\n embedActionsPanel: true,\n supportsUnitConversion: true,\n hasAdditionalLatestDataKeys: false,\n defaultDataKeysFunction: function() {\n return [{ name: 'temperature', label: 'Temperature', type: 'timeseries' }];\n }\n };\n}\n", "controllerScript": "self.onInit = function() {\n self.ctx.$scope.rangeChartWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.rangeChartWidget.onDataUpdated();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.rangeChartWidget.onLatestDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '80%',\n embedTitlePanel: true,\n embedActionsPanel: true,\n supportsUnitConversion: true,\n hasAdditionalLatestDataKeys: false,\n defaultDataKeysFunction: function() {\n return [{ name: 'temperature', label: 'Temperature', type: 'timeseries' }];\n }\n };\n}\n",
"settingsForm": [], "settingsForm": [],
"dataKeySettingsForm": [], "dataKeySettingsForm": [],
"latestDataKeySettingsForm": [], "latestDataKeySettingsForm": [],

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

@ -45,7 +45,10 @@ import {
barChartWithLabelsDefaultSettings, barChartWithLabelsDefaultSettings,
BarChartWithLabelsWidgetSettings BarChartWithLabelsWidgetSettings
} from '@home/components/widget/lib/chart/bar-chart-with-labels-widget.models'; } from '@home/components/widget/lib/chart/bar-chart-with-labels-widget.models';
import { TimeSeriesChartType } from '@home/components/widget/lib/chart/time-series-chart.models'; import {
TimeSeriesChartType,
updateLatestDataKeys
} from '@home/components/widget/lib/chart/time-series-chart.models';
import { getSourceTbUnitSymbol } from '@shared/models/unit.models'; import { getSourceTbUnitSymbol } from '@shared/models/unit.models';
@Component({ @Component({
@ -75,7 +78,7 @@ export class BarChartWithLabelsBasicConfigComponent extends BasicWidgetConfigCom
tooltipDatePreviewFn = this._tooltipDatePreviewFn.bind(this); tooltipDatePreviewFn = this._tooltipDatePreviewFn.bind(this);
predefinedValues = widgetTitleAutocompleteValues; predefinedValues = widgetTitleAutocompleteValues;
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent, protected widgetConfigComponent: WidgetConfigComponent,
private $injector: Injector, private $injector: Injector,
@ -166,6 +169,11 @@ export class BarChartWithLabelsBasicConfigComponent extends BasicWidgetConfigCom
}); });
} }
protected onConfigChanged(widgetConfig: WidgetConfigComponentData) {
updateLatestDataKeys([widgetConfig.config.settings.yAxis], this.datasource, this.callbacks);
super.onConfigChanged(widgetConfig);
}
protected prepareOutputConfig(config: any): WidgetConfigComponentData { protected prepareOutputConfig(config: any): WidgetConfigComponentData {
setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig);
this.widgetConfig.config.datasources = config.datasources; this.widgetConfig.config.datasources = config.datasources;

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

@ -47,7 +47,7 @@ import {
} from '@home/components/widget/lib/chart/range-chart-widget.models'; } from '@home/components/widget/lib/chart/range-chart-widget.models';
import { import {
lineSeriesStepTypes, lineSeriesStepTypes,
lineSeriesStepTypeTranslations lineSeriesStepTypeTranslations, updateLatestDataKeys
} from '@home/components/widget/lib/chart/time-series-chart.models'; } from '@home/components/widget/lib/chart/time-series-chart.models';
import { import {
chartLabelPositions, chartLabelPositions,
@ -288,6 +288,11 @@ export class RangeChartBasicConfigComponent extends BasicWidgetConfigComponent {
return this.widgetConfig; return this.widgetConfig;
} }
protected onConfigChanged(widgetConfig: WidgetConfigComponentData) {
updateLatestDataKeys([widgetConfig.config.settings.yAxis], this.datasource, this.callbacks);
super.onConfigChanged(widgetConfig);
}
protected validatorTriggers(): string[] { protected validatorTriggers(): string[] {
return ['showTitle', 'showIcon', 'showRangeThresholds', 'fillArea', 'showLine', return ['showTitle', 'showIcon', 'showRangeThresholds', 'fillArea', 'showLine',
'step', 'showPointLabel', 'enablePointLabelBackground', 'showLegend', 'showTooltip', 'tooltipShowDate']; 'step', 'showPointLabel', 'enablePointLabelBackground', 'showLegend', 'showTooltip', 'tooltipShowDate'];

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

@ -133,6 +133,12 @@ export class BarChartWithLabelsWidgetComponent implements OnInit, OnDestroy, Aft
} }
} }
public onLatestDataUpdated() {
if (this.timeSeriesChart) {
this.timeSeriesChart.latestUpdated();
}
}
public onLegendKeyEnter(key: DataKey) { public onLegendKeyEnter(key: DataKey) {
this.timeSeriesChart.keyEnter(key); this.timeSeriesChart.keyEnter(key);
} }

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

@ -161,6 +161,12 @@ export class RangeChartWidgetComponent implements OnInit, OnDestroy, AfterViewIn
} }
} }
public onLatestDataUpdated() {
if (this.timeSeriesChart) {
this.timeSeriesChart.latestUpdated();
}
}
public toggleRangeItem(item: RangeItem) { public toggleRangeItem(item: RangeItem) {
item.enabled = !item.enabled; item.enabled = !item.enabled;
this.timeSeriesChart.toggleVisualMapRange(item.index); this.timeSeriesChart.toggleVisualMapRange(item.index);

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

@ -99,6 +99,8 @@ import {
TimeSeriesChartTooltipWidgetSettings TimeSeriesChartTooltipWidgetSettings
} from '@home/components/widget/lib/chart/time-series-chart-tooltip.models'; } from '@home/components/widget/lib/chart/time-series-chart-tooltip.models';
import { TbUnit, TbUnitConverter } from '@shared/models/unit.models'; import { TbUnit, TbUnitConverter } from '@shared/models/unit.models';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { DataKeysCallbacks } from '@home/components/widget/lib/settings/common/key/data-keys.component.models';
type TimeSeriesChartDataEntry = [number, any, number, number]; type TimeSeriesChartDataEntry = [number, any, number, number];
@ -1495,3 +1497,101 @@ const createSeriesLabelOption = (item: TimeSeriesChartDataItem, show: boolean,
} }
return labelOption; return labelOption;
}; };
export const checkLatestDataKeys = (yAxes: TimeSeriesChartYAxes, datasource: Datasource): TimeSeriesChartYAxes => {
const latestKeys = datasource?.latestDataKeys || [];
const result: TimeSeriesChartYAxes = {};
for (const [id, axis] of Object.entries(yAxes)) {
axis.min = normalizeAxisLimit(axis.min);
axis.max = normalizeAxisLimit(axis.max);
const minCfg = axis.min;
const maxCfg = axis.max;
const minValid = !!minCfg && (
minCfg.type !== ValueSourceType.latestKey ||
latestKeys.some(k => isYAxisKey(k, minCfg))
);
const maxValid = !!maxCfg && (
maxCfg.type !== ValueSourceType.latestKey ||
latestKeys.some(k => isYAxisKey(k, maxCfg))
);
if (minValid && maxValid) {
result[id] = axis;
}
}
return result;
}
export const updateLatestDataKeys = (yAxes: TimeSeriesChartYAxisSettings[], datasource: Datasource, dataKeyCallbacks: DataKeysCallbacks)=> {
if (datasource) {
let latestKeys = datasource.latestDataKeys;
if (!latestKeys) {
latestKeys = [];
datasource.latestDataKeys = latestKeys;
}
const existingYAxisKeys = latestKeys.filter(k => k.settings?.__yAxisMinKey === true || k.settings?.__yAxisMaxKey === true);
const foundYAxisKeys: DataKey[] = [];
for(const yAxis of yAxes) {
const min = yAxis.min as ValueSourceConfig;
const max = yAxis.max as ValueSourceConfig;
if (min && min.type === ValueSourceType.latestKey) {
const found = existingYAxisKeys.find(k => isYAxisKey(k, min));
if (!found) {
const newKey = dataKeyCallbacks.generateDataKey(min.latestKey, min.latestKeyType,
null, true, null);
newKey.settings.__yAxisMinKey = true;
latestKeys.push(newKey);
} else if (foundYAxisKeys.indexOf(found) === -1) {
foundYAxisKeys.push(found);
}
}
if (max && max.type === ValueSourceType.latestKey) {
const found = existingYAxisKeys.find(k => isYAxisKey(k, max));
if (!found) {
const newKey = dataKeyCallbacks.generateDataKey(max.latestKey, max.latestKeyType,
null, true, null);
newKey.settings.__yAxisMaxKey = true;
latestKeys.push(newKey);
} else if (foundYAxisKeys.indexOf(found) === -1) {
foundYAxisKeys.push(found);
}
}
}
const toRemove = existingYAxisKeys.filter(k => foundYAxisKeys.indexOf(k) === -1);
for (const key of toRemove) {
const index = latestKeys.indexOf(key);
if (index > -1) {
latestKeys.splice(index, 1);
}
}
}
}
export const isYAxisKey = (d: DataKey, limit: ValueSourceConfig): boolean => {
return (d.type === DataKeyType.function && d.label === limit.latestKey) ||
(d.type !== DataKeyType.function && d.name === limit.latestKey &&
d.type === limit.latestKeyType);
}
export const normalizeAxisLimit = (limit: string | number | ValueSourceConfig): ValueSourceConfig => {
if (!limit) {
return {
type: ValueSourceType.constant,
value: null,
entityAlias: null
};
} else if (typeof limit === 'number' || typeof limit === 'string') {
return {
type: ValueSourceType.constant,
value: Number(limit),
entityAlias: null
};
}
return limit;
}

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

@ -23,7 +23,7 @@ import {
createTimeSeriesYAxis, createTimeSeriesYAxis,
defaultTimeSeriesChartYAxisSettings, defaultTimeSeriesChartYAxisSettings,
generateChartData, generateChartData,
LineSeriesStepType, LineSeriesStepType, normalizeAxisLimit,
parseThresholdData, parseThresholdData,
TimeSeriesChartAxis, TimeSeriesChartAxis,
TimeSeriesChartDataItem, TimeSeriesChartDataItem,
@ -581,8 +581,8 @@ export class TbTimeSeriesChart {
yAxisSettingsList.sort((a1, a2) => a1.order - a2.order); yAxisSettingsList.sort((a1, a2) => a1.order - a2.order);
const axisLimitDatasources: Datasource[] = []; const axisLimitDatasources: Datasource[] = [];
for (const yAxisSettings of yAxisSettingsList) { for (const yAxisSettings of yAxisSettingsList) {
yAxisSettings.min = this.normalizeAxisLimit(yAxisSettings.min); yAxisSettings.min = normalizeAxisLimit(yAxisSettings.min);
yAxisSettings.max = this.normalizeAxisLimit(yAxisSettings.max); yAxisSettings.max = normalizeAxisLimit(yAxisSettings.max);
const axisSettings = mergeDeep<TimeSeriesChartYAxisSettings>({} as TimeSeriesChartYAxisSettings, const axisSettings = mergeDeep<TimeSeriesChartYAxisSettings>({} as TimeSeriesChartYAxisSettings,
defaultTimeSeriesChartYAxisSettings, yAxisSettings); defaultTimeSeriesChartYAxisSettings, yAxisSettings);
const units = isNotEmptyTbUnits(axisSettings.units) ? axisSettings.units : this.ctx.units; const units = isNotEmptyTbUnits(axisSettings.units) ? axisSettings.units : this.ctx.units;
@ -1080,21 +1080,4 @@ export class TbTimeSeriesChart {
this.timeSeriesChart.setOption(this.timeSeriesChartOptions); this.timeSeriesChart.setOption(this.timeSeriesChartOptions);
} }
} }
private normalizeAxisLimit(limit: string | number | ValueSourceConfig): string | number | ValueSourceConfig {
if (!limit) {
return {
type: ValueSourceType.constant,
value: null,
entityAlias: null
};
} else if (typeof limit === 'number' || typeof limit === 'string') {
return {
type: ValueSourceType.constant,
value: Number(limit),
entityAlias: null
};
}
return limit;
}
} }

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

@ -31,6 +31,7 @@ import {
barChartWithLabelsDefaultSettings barChartWithLabelsDefaultSettings
} from '@home/components/widget/lib/chart/bar-chart-with-labels-widget.models'; } from '@home/components/widget/lib/chart/bar-chart-with-labels-widget.models';
import { getSourceTbUnitSymbol } from '@shared/models/unit.models'; import { getSourceTbUnitSymbol } from '@shared/models/unit.models';
import { updateLatestDataKeys } from '@home/components/widget/lib/chart/time-series-chart.models';
@Component({ @Component({
selector: 'tb-bar-chart-with-labels-widget-settings', selector: 'tb-bar-chart-with-labels-widget-settings',
@ -122,6 +123,11 @@ export class BarChartWithLabelsWidgetSettingsComponent extends WidgetSettingsCom
}); });
} }
protected onSettingsChanged(updated: WidgetSettings) {
updateLatestDataKeys([updated.yAxis], this.datasource, this.dataKeyCallbacks);
super.onSettingsChanged(updated);
}
protected validatorTriggers(): string[] { protected validatorTriggers(): string[] {
return ['showBarLabel', 'showBarValue', 'showBarBorder', 'showLegend', 'showTooltip', 'tooltipShowDate']; return ['showBarLabel', 'showBarValue', 'showBarBorder', 'showLegend', 'showTooltip', 'tooltipShowDate'];
} }

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

@ -30,7 +30,7 @@ import { rangeChartDefaultSettings } from '@home/components/widget/lib/chart/ran
import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-settings.models'; import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-settings.models';
import { import {
lineSeriesStepTypes, lineSeriesStepTypes,
lineSeriesStepTypeTranslations lineSeriesStepTypeTranslations, updateLatestDataKeys
} from '@home/components/widget/lib/chart/time-series-chart.models'; } from '@home/components/widget/lib/chart/time-series-chart.models';
import { import {
chartLabelPositions, chartLabelPositions,
@ -268,6 +268,11 @@ export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent {
} }
} }
protected onSettingsChanged(updated: WidgetSettings) {
updateLatestDataKeys([updated.yAxis], this.datasource, this.dataKeyCallbacks);
super.onSettingsChanged(updated);
}
private _pointLabelPreviewFn(): string { private _pointLabelPreviewFn(): string {
const units = getSourceTbUnitSymbol(this.widgetConfig.config.units); const units = getSourceTbUnitSymbol(this.widgetConfig.config.units);
const decimals: number = this.widgetConfig.config.decimals; const decimals: number = this.widgetConfig.config.decimals;

37
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/axis-scale-row.component.ts

@ -96,7 +96,7 @@ export class AxisScaleRowComponent implements ControlValueAccessor, OnInit, Vali
this.limitForm = this.fb.group({ this.limitForm = this.fb.group({
type: [ValueSourceType.constant], type: [ValueSourceType.constant],
value: [null], value: [null],
entityAlias: [null] entityAlias: [null, [Validators.required]]
}); });
this.latestKeyFormControl = this.fb.control(null, [Validators.required]); this.latestKeyFormControl = this.fb.control(null, [Validators.required]);
this.entityKeyFormControl = this.fb.control(null, [Validators.required]); this.entityKeyFormControl = this.fb.control(null, [Validators.required]);
@ -168,23 +168,24 @@ export class AxisScaleRowComponent implements ControlValueAccessor, OnInit, Vali
} }
private updateValidators() { private updateValidators() {
const axisTypeControl = this.limitForm.get('type'); const type = this.limitForm.get('type')?.value;
if (axisTypeControl && this.entityKeyFormControl && this.latestKeyFormControl) { const entityAliasCtr = this.limitForm.get('entityAlias');
const type = axisTypeControl.value;
if (type === ValueSourceType.latestKey) { const isLatestKey = type === ValueSourceType.latestKey;
this.latestKeyFormControl.setValidators([Validators.required]); const isEntity = type === ValueSourceType.entity;
this.entityKeyFormControl.clearValidators();
} else if (type === ValueSourceType.entity) { isLatestKey ? this.latestKeyFormControl.enable({ emitEvent: false })
this.latestKeyFormControl.clearValidators(); : this.latestKeyFormControl.disable({ emitEvent: false });
this.limitForm.get('entityAlias').setValidators([Validators.required]);
this.entityKeyFormControl.setValidators([Validators.required]); isEntity ? this.entityKeyFormControl.enable({ emitEvent: false })
} else { : this.entityKeyFormControl.disable({ emitEvent: false });
this.latestKeyFormControl.clearValidators();
this.entityKeyFormControl.clearValidators(); isEntity ? entityAliasCtr.enable({ emitEvent: false })
} : entityAliasCtr.disable({ emitEvent: false });
this.latestKeyFormControl.updateValueAndValidity({ emitEvent: false });
this.entityKeyFormControl.updateValueAndValidity({ emitEvent: false }); this.latestKeyFormControl.updateValueAndValidity({ emitEvent: false });
} this.entityKeyFormControl.updateValueAndValidity({ emitEvent: false });
entityAliasCtr.updateValueAndValidity({ emitEvent: false });
} }
private updateModel() { private updateModel() {

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

@ -25,7 +25,7 @@ import {
Validators Validators
} from '@angular/forms'; } from '@angular/forms';
import { import {
AxisPosition, defaultXAxisTicksFormat, AxisPosition, defaultXAxisTicksFormat, normalizeAxisLimit,
timeSeriesAxisPositionTranslations, timeSeriesAxisPositionTranslations,
TimeSeriesChartAxisSettings, TimeSeriesChartXAxisSettings, TimeSeriesChartAxisSettings, TimeSeriesChartXAxisSettings,
TimeSeriesChartYAxisSettings TimeSeriesChartYAxisSettings
@ -137,8 +137,8 @@ export class TimeSeriesChartAxisSettingsComponent implements OnInit, ControlValu
this.axisSettingsFormGroup.addControl('ticksGenerator', this.fb.control(null, [])); this.axisSettingsFormGroup.addControl('ticksGenerator', this.fb.control(null, []));
this.axisSettingsFormGroup.addControl('interval', this.fb.control(null, [Validators.min(0)])); this.axisSettingsFormGroup.addControl('interval', this.fb.control(null, [Validators.min(0)]));
this.axisSettingsFormGroup.addControl('splitNumber', this.fb.control(null, [Validators.min(1)])); this.axisSettingsFormGroup.addControl('splitNumber', this.fb.control(null, [Validators.min(1)]));
this.axisSettingsFormGroup.addControl('min', this.fb.control(null, [])); this.axisSettingsFormGroup.addControl('min', this.fb.control(normalizeAxisLimit(null), []));
this.axisSettingsFormGroup.addControl('max', this.fb.control(null, [])); this.axisSettingsFormGroup.addControl('max', this.fb.control(normalizeAxisLimit(null), []));
} else if (this.axisType === 'xAxis') { } else if (this.axisType === 'xAxis') {
this.axisSettingsFormGroup.addControl('ticksFormat', this.fb.control(null, [])); this.axisSettingsFormGroup.addControl('ticksFormat', this.fb.control(null, []));
} }

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

@ -36,13 +36,15 @@ import {
Validator Validator
} from '@angular/forms'; } from '@angular/forms';
import { import {
checkLatestDataKeys,
defaultTimeSeriesChartYAxisSettings, defaultTimeSeriesChartYAxisSettings,
getNextTimeSeriesYAxisId, getNextTimeSeriesYAxisId,
TimeSeriesChartYAxes, TimeSeriesChartYAxes,
TimeSeriesChartYAxisId, TimeSeriesChartYAxisId,
TimeSeriesChartYAxisSettings, TimeSeriesChartYAxisSettings,
timeSeriesChartYAxisValid, timeSeriesChartYAxisValid,
timeSeriesChartYAxisValidator timeSeriesChartYAxisValidator,
updateLatestDataKeys
} from '@home/components/widget/lib/chart/time-series-chart.models'; } from '@home/components/widget/lib/chart/time-series-chart.models';
import { mergeDeep } from '@core/utils'; import { mergeDeep } from '@core/utils';
import { CdkDragDrop } from '@angular/cdk/drag-drop'; import { CdkDragDrop } from '@angular/cdk/drag-drop';
@ -50,7 +52,7 @@ import { coerceBoolean } from '@shared/decorators/coercion';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { IAliasController } from '@app/core/public-api'; import { IAliasController } from '@app/core/public-api';
import { DataKeysCallbacks } from '@home/components/widget/lib/settings/common/key/data-keys.component.models'; import { DataKeysCallbacks } from '@home/components/widget/lib/settings/common/key/data-keys.component.models';
import { DataKey, DataKeyType, Datasource, ValueSourceConfig, ValueSourceType } from '@app/shared/public-api'; import { Datasource } from '@app/shared/public-api';
@Component({ @Component({
selector: 'tb-time-series-chart-y-axes-panel', selector: 'tb-time-series-chart-y-axes-panel',
@ -126,7 +128,7 @@ export class TimeSeriesChartYAxesPanelComponent implements ControlValueAccessor,
for (const axis of axes) { for (const axis of axes) {
yAxes[axis.id] = axis; yAxes[axis.id] = axis;
} }
this.updateLatestDataKeys(Object.values(yAxes)); updateLatestDataKeys(Object.values(yAxes), this.datasource, this.dataKeyCallbacks);
this.propagateChange(yAxes); this.propagateChange(yAxes);
} }
); );
@ -149,7 +151,7 @@ export class TimeSeriesChartYAxesPanelComponent implements ControlValueAccessor,
} }
writeValue(value: TimeSeriesChartYAxes | undefined): void { writeValue(value: TimeSeriesChartYAxes | undefined): void {
const yAxes: TimeSeriesChartYAxes = this.checkLatestDataKeys(value || {}); const yAxes: TimeSeriesChartYAxes = checkLatestDataKeys(value || {}, this.datasource);
if (!yAxes.default) { if (!yAxes.default) {
yAxes.default = mergeDeep({} as TimeSeriesChartYAxisSettings, defaultTimeSeriesChartYAxisSettings, yAxes.default = mergeDeep({} as TimeSeriesChartYAxisSettings, defaultTimeSeriesChartYAxisSettings,
{id: 'default', order: 0} as TimeSeriesChartYAxisSettings); {id: 'default', order: 0} as TimeSeriesChartYAxisSettings);
@ -196,8 +198,6 @@ export class TimeSeriesChartYAxesPanelComponent implements ControlValueAccessor,
const axes: TimeSeriesChartYAxisSettings[] = this.yAxesFormGroup.get('axes').value; const axes: TimeSeriesChartYAxisSettings[] = this.yAxesFormGroup.get('axes').value;
axis.id = getNextTimeSeriesYAxisId(axes); axis.id = getNextTimeSeriesYAxisId(axes);
axis.order = axes.length; axis.order = axes.length;
axis.min = this.normalizeAxisLimit(axis.min);
axis.max = this.normalizeAxisLimit(axis.max);
const axesArray = this.yAxesFormGroup.get('axes') as UntypedFormArray; const axesArray = this.yAxesFormGroup.get('axes') as UntypedFormArray;
const axisControl = this.fb.control(axis, [timeSeriesChartYAxisValidator]); const axisControl = this.fb.control(axis, [timeSeriesChartYAxisValidator]);
axesArray.push(axisControl); axesArray.push(axisControl);
@ -211,100 +211,4 @@ export class TimeSeriesChartYAxesPanelComponent implements ControlValueAccessor,
return this.fb.array(axesControls); return this.fb.array(axesControls);
} }
private checkLatestDataKeys(yAxes: TimeSeriesChartYAxes): TimeSeriesChartYAxes {
const latestKeys = this.datasource?.latestDataKeys || [];
const result: TimeSeriesChartYAxes = {};
for (const [id, axis] of Object.entries(yAxes)) {
axis.min = this.normalizeAxisLimit(axis.min);
axis.max = this.normalizeAxisLimit(axis.max);
const minCfg = axis.min;
const maxCfg = axis.max;
const minValid = !!minCfg && (
minCfg.type !== ValueSourceType.latestKey ||
latestKeys.some(k => this.isYAxisKey(k, minCfg))
);
const maxValid = !!maxCfg && (
maxCfg.type !== ValueSourceType.latestKey ||
latestKeys.some(k => this.isYAxisKey(k, maxCfg))
);
if (minValid && maxValid) {
result[id] = axis;
}
}
return result;
}
private updateLatestDataKeys(yAxes: TimeSeriesChartYAxisSettings[]) {
if (this.datasource) {
let latestKeys = this.datasource.latestDataKeys;
if (!latestKeys) {
latestKeys = [];
this.datasource.latestDataKeys = latestKeys;
}
const existingYAxisKeys = latestKeys.filter(k => k.settings?.__yAxisMinKey === true || k.settings?.__yAxisMaxKey === true);
const foundYAxisKeys: DataKey[] = [];
for(const yAxis of yAxes) {
const min = yAxis.min as ValueSourceConfig;
const max = yAxis.max as ValueSourceConfig;
if (min.type === ValueSourceType.latestKey) {
const found = existingYAxisKeys.find(k => this.isYAxisKey(k, min));
if (!found) {
const newKey = this.dataKeyCallbacks.generateDataKey(min.latestKey, min.latestKeyType,
null, true, null);
newKey.settings.__yAxisMinKey = true;
latestKeys.push(newKey);
} else if (foundYAxisKeys.indexOf(found) === -1) {
foundYAxisKeys.push(found);
}
}
if (max.type === ValueSourceType.latestKey) {
const found = existingYAxisKeys.find(k => this.isYAxisKey(k, max));
if (!found) {
const newKey = this.dataKeyCallbacks.generateDataKey(max.latestKey, max.latestKeyType,
null, true, null);
newKey.settings.__yAxisMaxKey = true;
latestKeys.push(newKey);
} else if (foundYAxisKeys.indexOf(found) === -1) {
foundYAxisKeys.push(found);
}
}
}
const toRemove = existingYAxisKeys.filter(k => foundYAxisKeys.indexOf(k) === -1);
for (const key of toRemove) {
const index = latestKeys.indexOf(key);
if (index > -1) {
latestKeys.splice(index, 1);
}
}
}
}
private isYAxisKey(d: DataKey, limit: ValueSourceConfig): boolean {
return (d.type === DataKeyType.function && d.label === limit.latestKey) ||
(d.type !== DataKeyType.function && d.name === limit.latestKey &&
d.type === limit.latestKeyType);
}
private normalizeAxisLimit(limit: string | number | ValueSourceConfig): ValueSourceConfig {
if (!limit) {
return {
type: ValueSourceType.constant,
value: null,
entityAlias: null
};
} else if (typeof limit === 'number' || typeof limit === 'string') {
return {
type: ValueSourceType.constant,
value: Number(limit),
entityAlias: null
};
}
return limit;
}
} }

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

@ -29,7 +29,7 @@ import {
} from '@angular/core'; } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { import {
AxisPosition, AxisPosition, normalizeAxisLimit,
timeSeriesAxisPositionTranslations, timeSeriesAxisPositionTranslations,
TimeSeriesChartYAxisSettings TimeSeriesChartYAxisSettings
} from '@home/components/widget/lib/chart/time-series-chart.models'; } from '@home/components/widget/lib/chart/time-series-chart.models';
@ -135,8 +135,8 @@ export class TimeSeriesChartYAxisRowComponent implements ControlValueAccessor, O
writeValue(value: TimeSeriesChartYAxisSettings): void { writeValue(value: TimeSeriesChartYAxisSettings): void {
this.modelValue = value; this.modelValue = value;
const min = this.normalizeLimit(value.min); const min = normalizeAxisLimit(value.min);
const max = this.normalizeLimit(value.max); const max = normalizeAxisLimit(value.max);
this.axisFormGroup.patchValue({ this.axisFormGroup.patchValue({
label: value.label, label: value.label,
@ -251,27 +251,4 @@ export class TimeSeriesChartYAxisRowComponent implements ControlValueAccessor, O
entityKeyType: [null, []] entityKeyType: [null, []]
}); });
} }
private normalizeLimit(limit: any) {
const base = {
type: ValueSourceType.constant,
value: null,
latestKey: null,
latestKeyType: null,
entityAlias: null,
entityKey: null,
entityKeyType: null
};
if (limit == null) return base;
if (typeof limit === 'number' || typeof limit === 'string') {
return { ...base, type: ValueSourceType.constant, value: Number(limit) };
}
return {
...base,
...limit,
};
}
} }

Loading…
Cancel
Save