diff --git a/application/src/main/data/json/system/widget_types/photo_camera_input.json b/application/src/main/data/json/system/widget_types/photo_camera_input.json
index 69327395cc..fc676380ab 100644
--- a/application/src/main/data/json/system/widget_types/photo_camera_input.json
+++ b/application/src/main/data/json/system/widget_types/photo_camera_input.json
@@ -15,7 +15,7 @@
"settingsSchema": "",
"dataKeySettingsSchema": "{}\n",
"settingsDirective": "tb-photo-camera-input-widget-settings",
- "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Photo camera input\",\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"displayTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
+ "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"widgetTitle\":\"\",\"saveToGallery\":true,\"usePublicGalleryLink\":false,\"imageFormat\":\"image/png\",\"imageQuality\":0.92,\"maxWidth\":640,\"maxHeight\":480},\"title\":\"Photo camera input\",\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false,\"actions\":{}}"
},
"resources": [
{
diff --git a/application/src/main/data/json/system/widget_types/timeseries_table.json b/application/src/main/data/json/system/widget_types/timeseries_table.json
index 8343eb918c..15779eb902 100644
--- a/application/src/main/data/json/system/widget_types/timeseries_table.json
+++ b/application/src/main/data/json/system/widget_types/timeseries_table.json
@@ -17,7 +17,7 @@
"latestDataKeySettingsDirective": "tb-timeseries-table-latest-key-settings",
"hasBasicMode": true,
"basicModeDirective": "tb-timeseries-table-basic-config",
- "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}],\"latestDataKeys\":null}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true,\"displayPagination\":true,\"defaultPageSize\":10},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"displayTimewindow\":true,\"configMode\":\"basic\"}"
+ "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}],\"latestDataKeys\":null}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"enableSearch\":true,\"enableSelectColumnDisplay\":true,\"enableStickyHeader\":true,\"enableStickyAction\":true,\"showCellActionsMenu\":true,\"reserveSpaceForHiddenAction\":\"true\",\"showTimestamp\":true,\"dateFormat\":{\"format\":\"yyyy-MM-dd HH:mm:ss\"},\"displayPagination\":true,\"useEntityLabel\":false,\"defaultPageSize\":10,\"pageStepCount\":3,\"pageStepIncrement\":10,\"hideEmptyLines\":false,\"disableStickyHeader\":false,\"useRowStyleFunction\":false,\"rowStyleFunction\":\"\",\"tabSortKey\":\"timestamp\"},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"displayTimewindow\":true,\"configMode\":\"basic\"}"
},
"resources": [
{
@@ -32,4 +32,4 @@
"public": true
}
]
-}
\ No newline at end of file
+}
diff --git a/ui-ngx/patches/@iplab+ngx-color-picker+18.0.1.patch b/ui-ngx/patches/@iplab+ngx-color-picker+18.0.1.patch
new file mode 100644
index 0000000000..c8090076cc
--- /dev/null
+++ b/ui-ngx/patches/@iplab+ngx-color-picker+18.0.1.patch
@@ -0,0 +1,97 @@
+diff --git a/node_modules/@iplab/ngx-color-picker/esm2022/lib/components/parts/inputs/hex-input/hex-input.component.mjs b/node_modules/@iplab/ngx-color-picker/esm2022/lib/components/parts/inputs/hex-input/hex-input.component.mjs
+index bf5480b..02c8246 100644
+--- a/node_modules/@iplab/ngx-color-picker/esm2022/lib/components/parts/inputs/hex-input/hex-input.component.mjs
++++ b/node_modules/@iplab/ngx-color-picker/esm2022/lib/components/parts/inputs/hex-input/hex-input.component.mjs
+@@ -29,10 +29,10 @@ export class HexComponent {
+ }
+ }
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: HexComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
+- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.0", type: HexComponent, isStandalone: true, selector: "hex-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, prefixValue: { classPropertyName: "prefixValue", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "
\r\n \r\n @if (labelVisible()) {\r\n HEX\r\n }\r\n
", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
++ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.0", type: HexComponent, isStandalone: true, selector: "hex-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, prefixValue: { classPropertyName: "prefixValue", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "\r\n \r\n @if (labelVisible()) {\r\n HEX\r\n }\r\n
", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
+ }
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: HexComponent, decorators: [{
+ type: Component,
+- args: [{ selector: `hex-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "\r\n \r\n @if (labelVisible()) {\r\n HEX\r\n }\r\n
", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
++ args: [{ selector: `hex-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "\r\n \r\n @if (labelVisible()) {\r\n HEX\r\n }\r\n
", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
+ }] });
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGV4LWlucHV0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2lwbGFiL25neC1jb2xvci1waWNrZXIvc3JjL2xpYi9jb21wb25lbnRzL3BhcnRzL2lucHV0cy9oZXgtaW5wdXQvaGV4LWlucHV0LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2lwbGFiL25neC1jb2xvci1waWNrZXIvc3JjL2xpYi9jb21wb25lbnRzL3BhcnRzL2lucHV0cy9oZXgtaW5wdXQvaGV4LWlucHV0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsdUJBQXVCLEVBQUUsZ0JBQWdCLEVBQWUsS0FBSyxFQUFFLEtBQUssRUFBZSxNQUFNLGVBQWUsQ0FBQztBQUM3SCxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0saUNBQWlDLENBQUM7O0FBY3hELE1BQU0sT0FBTyxZQUFZO0lBWHpCO1FBYVcsVUFBSyxHQUF1QixLQUFLLENBQUMsUUFBUSxFQUFTLENBQUM7UUFFcEQsaUJBQVksR0FBeUIsS0FBSyxDQUFtQixLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxnQkFBZ0IsRUFBRSxDQUFDLENBQUM7UUFFckgsZ0JBQVcsR0FBd0IsS0FBSyxDQUFTLEVBQUUsRUFBRSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0tBMkJwRjtJQXpCRyxJQUFXLEtBQUs7UUFDWixPQUFPLElBQUksQ0FBQyxXQUFXLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ2xJLENBQUM7SUFFTSxhQUFhLENBQUMsS0FBb0IsRUFBRSxVQUFrQjtRQUN6RCxNQUFNLEtBQUssR0FBRyxVQUFVLENBQUMsV0FBVyxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUV4RCxJQUNBLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxLQUFLLEVBQUUsSUFBSSxLQUFLLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxLQUFLLE9BQU8sQ0FBQyxJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDO2VBQ2xGLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDMUMsTUFBTSxHQUFHLEdBQUcsUUFBUSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztZQUNoQyxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBRWhDOzs7OztlQUtHO1lBQ0gsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLEtBQUssS0FBSyxJQUFJLElBQUksQ0FBQyxLQUFLLEtBQUssS0FBSyxFQUFFLENBQUM7Z0JBQ3ZFLE1BQU0sUUFBUSxHQUFHLElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxFQUFFLENBQUMsQ0FBQztnQkFDeEMsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDN0IsQ0FBQztRQUNMLENBQUM7SUFDTCxDQUFDOzhHQWhDUSxZQUFZO2tHQUFaLFlBQVksZ2dCQ2Z6Qiw0TUFLTTs7MkZEVU8sWUFBWTtrQkFYeEIsU0FBUzsrQkFDSSxxQkFBcUIsbUJBT2QsdUJBQXVCLENBQUMsTUFBTSxjQUNuQyxJQUFJIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgYm9vbGVhbkF0dHJpYnV0ZSwgSW5wdXRTaWduYWwsIGlucHV0LCBtb2RlbCwgTW9kZWxTaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQ29sb3IgfSBmcm9tICcuLi8uLi8uLi8uLi9oZWxwZXJzL2NvbG9yLmNsYXNzJztcclxuXHJcblxyXG5AQ29tcG9uZW50KHtcclxuICAgIHNlbGVjdG9yOiBgaGV4LWlucHV0LWNvbXBvbmVudGAsXHJcbiAgICB0ZW1wbGF0ZVVybDogYC4vaGV4LWlucHV0LmNvbXBvbmVudC5odG1sYCxcclxuICAgIHN0eWxlVXJsczogW1xyXG4gICAgICAgIGAuLy4uLy4uL2Jhc2Uuc3R5bGUuc2Nzc2AsXHJcbiAgICAgICAgYC4vLi4vaW5wdXQuY29tcG9uZW50LnNjc3NgLFxyXG4gICAgICAgIGAuL2hleC1pbnB1dC5jb21wb25lbnQuc2Nzc2BcclxuICAgIF0sXHJcbiAgICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcclxuICAgIHN0YW5kYWxvbmU6IHRydWVcclxufSlcclxuZXhwb3J0IGNsYXNzIEhleENvbXBvbmVudCB7XHJcblxyXG4gICAgcHVibGljIGNvbG9yOiBNb2RlbFNpZ25hbDxDb2xvcj4gPSBtb2RlbC5yZXF1aXJlZDxDb2xvcj4oKTtcclxuXHJcbiAgICBwdWJsaWMgbGFiZWxWaXNpYmxlOiBJbnB1dFNpZ25hbDxib29sZWFuPiA9IGlucHV0PGJvb2xlYW4sIGJvb2xlYW4+KGZhbHNlLCB7IGFsaWFzOiAnbGFiZWwnLCB0cmFuc2Zvcm06IGJvb2xlYW5BdHRyaWJ1dGUgfSk7XHJcblxyXG4gICAgcHVibGljIHByZWZpeFZhbHVlOiBJbnB1dFNpZ25hbDxzdHJpbmc+ID0gaW5wdXQ8c3RyaW5nPignJywgeyBhbGlhczogJ3ByZWZpeCcgfSk7XHJcblxyXG4gICAgcHVibGljIGdldCB2YWx1ZSgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5wcmVmaXhWYWx1ZSgpICsgKHRoaXMuY29sb3IoKSA/IHRoaXMuY29sb3IoKS50b0hleFN0cmluZyh0aGlzLmNvbG9yKCkuZ2V0UmdiYSgpLmFscGhhIDwgMSkucmVwbGFjZSgnIycsICcnKSA6ICcnKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgb25JbnB1dENoYW5nZShldmVudDogS2V5Ym9hcmRFdmVudCwgaW5wdXRWYWx1ZTogc3RyaW5nKTogdm9pZCB7XHJcbiAgICAgICAgY29uc3QgdmFsdWUgPSBpbnB1dFZhbHVlLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgnIycsICcnKTtcclxuXHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICgoZXZlbnQua2V5Q29kZSA9PT0gMTMgfHwgZXZlbnQua2V5LnRvTG93ZXJDYXNlKCkgPT09ICdlbnRlcicpICYmIHZhbHVlLmxlbmd0aCA9PT0gMylcclxuICAgICAgICB8fCB2YWx1ZS5sZW5ndGggPT09IDYgfHwgdmFsdWUubGVuZ3RoID09PSA4KSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGhleCA9IHBhcnNlSW50KHZhbHVlLCAxNik7XHJcbiAgICAgICAgICAgIGNvbnN0IGhleFN0ciA9IGhleC50b1N0cmluZygxNik7XHJcblxyXG4gICAgICAgICAgICAvKipcclxuICAgICAgICAgICAgICogaWYgdmFsdWUgaXMgdmFsaWRcclxuICAgICAgICAgICAgICogY2hhbmdlIGNvbG9yIGVsc2UgZG8gbm90aGluZ1xyXG4gICAgICAgICAgICAgKiBhZnRlciBwYXJzaW5nIG51bWJlciBsZWFkaW5nIDAgaXMgcmVtb3ZlZCxcclxuICAgICAgICAgICAgICogY29tcGFyZSBsZW5ndGggYW5kIGFkZCBsZWFkaW5nIDAgYmVmb3JlIGNvbXBhcmluZyB0d28gdmFsdWVzXHJcbiAgICAgICAgICAgICAqL1xyXG4gICAgICAgICAgICBpZiAoaGV4U3RyLnBhZFN0YXJ0KHZhbHVlLmxlbmd0aCwgJzAnKSA9PT0gdmFsdWUgJiYgdGhpcy52YWx1ZSAhPT0gdmFsdWUpIHtcclxuICAgICAgICAgICAgICAgIGNvbnN0IG5ld0NvbG9yID0gbmV3IENvbG9yKGAjJHt2YWx1ZX1gKTtcclxuICAgICAgICAgICAgICAgIHRoaXMuY29sb3Iuc2V0KG5ld0NvbG9yKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG4iLCI8ZGl2IGNsYXNzPVwiY29sdW1uXCI+XHJcbiAgICA8aW5wdXQgI2VsUmVmIHR5cGU9XCJ0ZXh0XCIgW3ZhbHVlXT1cInZhbHVlXCIgKGtleXVwKT1cIm9uSW5wdXRDaGFuZ2UoJGV2ZW50LCBlbFJlZi52YWx1ZSlcIiAvPlxyXG4gICAgQGlmIChsYWJlbFZpc2libGUoKSkge1xyXG4gICAgICAgIDxzcGFuPkhFWDwvc3Bhbj5cclxuICAgIH1cclxuPC9kaXY+Il19
+diff --git a/node_modules/@iplab/ngx-color-picker/esm2022/lib/components/parts/inputs/hsla-input/hsla-input.component.mjs b/node_modules/@iplab/ngx-color-picker/esm2022/lib/components/parts/inputs/hsla-input/hsla-input.component.mjs
+index 2454b27..dd007ce 100644
+--- a/node_modules/@iplab/ngx-color-picker/esm2022/lib/components/parts/inputs/hsla-input/hsla-input.component.mjs
++++ b/node_modules/@iplab/ngx-color-picker/esm2022/lib/components/parts/inputs/hsla-input/hsla-input.component.mjs
+@@ -21,10 +21,10 @@ export class HslaComponent {
+ this.color.set(newColor);
+ }
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: HslaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
+- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.0", type: HslaComponent, isStandalone: true, selector: "hsla-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isAlphaVisible: { classPropertyName: "isAlphaVisible", publicName: "alpha", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "\r\n \r\n @if (labelVisible()) {\r\n H\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n S\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n L\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], dependencies: [{ kind: "directive", type: ColorPickerInputDirective, selector: "[inputChange]", inputs: ["min", "max"], outputs: ["inputChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
++ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.0", type: HslaComponent, isStandalone: true, selector: "hsla-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isAlphaVisible: { classPropertyName: "isAlphaVisible", publicName: "alpha", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "\r\n \r\n @if (labelVisible()) {\r\n H\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n S\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n L\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], dependencies: [{ kind: "directive", type: ColorPickerInputDirective, selector: "[inputChange]", inputs: ["min", "max"], outputs: ["inputChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
+ }
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: HslaComponent, decorators: [{
+ type: Component,
+- args: [{ selector: `hsla-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [ColorPickerInputDirective], template: "\r\n \r\n @if (labelVisible()) {\r\n H\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n S\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n L\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
++ args: [{ selector: `hsla-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [ColorPickerInputDirective], template: "\r\n \r\n @if (labelVisible()) {\r\n H\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n S\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n L\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
+ }] });
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHNsYS1pbnB1dC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9pcGxhYi9uZ3gtY29sb3ItcGlja2VyL3NyYy9saWIvY29tcG9uZW50cy9wYXJ0cy9pbnB1dHMvaHNsYS1pbnB1dC9oc2xhLWlucHV0LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2lwbGFiL25neC1jb2xvci1waWNrZXIvc3JjL2xpYi9jb21wb25lbnRzL3BhcnRzL2lucHV0cy9oc2xhLWlucHV0L2hzbGEtaW5wdXQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSx1QkFBdUIsRUFBRSxnQkFBZ0IsRUFBZSxLQUFLLEVBQUUsS0FBSyxFQUFlLE1BQU0sZUFBZSxDQUFDO0FBQzdILE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUMxRCxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxxREFBcUQsQ0FBQzs7QUFlaEcsTUFBTSxPQUFPLGFBQWE7SUFaMUI7UUFjVyxVQUFLLEdBQXVCLEtBQUssQ0FBQyxRQUFRLEVBQVMsQ0FBQztRQUVwRCxpQkFBWSxHQUF5QixLQUFLLENBQW1CLEtBQUssRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FBQztRQUVySCxtQkFBYyxHQUF5QixLQUFLLENBQW1CLElBQUksRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FBQztLQWdCaEk7SUFkRyxJQUFXLEtBQUs7UUFDWixPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsRUFBRSxPQUFPLEVBQUUsQ0FBQztJQUNuQyxDQUFDO0lBRU0sYUFBYSxDQUFDLFFBQWdCLEVBQUUsS0FBNEI7UUFDL0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQztRQUN6QixNQUFNLEdBQUcsR0FBRyxLQUFLLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUM7UUFDakQsTUFBTSxVQUFVLEdBQUcsS0FBSyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDO1FBQy9ELE1BQU0sU0FBUyxHQUFHLEtBQUssS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQztRQUM3RCxNQUFNLEtBQUssR0FBRyxLQUFLLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUM7UUFFckQsTUFBTSxRQUFRLEdBQUcsSUFBSSxLQUFLLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDeEUsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDN0IsQ0FBQzs4R0FyQlEsYUFBYTtrR0FBYixhQUFhLHNnQkNqQjFCLGlsQ0F5QkMseWVEVmEseUJBQXlCOzsyRkFFMUIsYUFBYTtrQkFaekIsU0FBUzsrQkFDSSxzQkFBc0IsbUJBT2YsdUJBQXVCLENBQUMsTUFBTSxjQUNuQyxJQUFJLFdBQ1AsQ0FBQyx5QkFBeUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIGJvb2xlYW5BdHRyaWJ1dGUsIElucHV0U2lnbmFsLCBpbnB1dCwgbW9kZWwsIE1vZGVsU2lnbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi8uLi8uLi8uLi8uLi9oZWxwZXJzL2NvbG9yLmNsYXNzJztcclxuaW1wb3J0IHsgQ29sb3JQaWNrZXJJbnB1dERpcmVjdGl2ZSB9IGZyb20gJy4uLy4uLy4uLy4uL2RpcmVjdGl2ZXMvY29sb3ItcGlja2VyLWlucHV0LmRpcmVjdGl2ZSc7XHJcblxyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgICBzZWxlY3RvcjogYGhzbGEtaW5wdXQtY29tcG9uZW50YCxcclxuICAgIHRlbXBsYXRlVXJsOiBgLi9oc2xhLWlucHV0LmNvbXBvbmVudC5odG1sYCxcclxuICAgIHN0eWxlVXJsczogW1xyXG4gICAgICAgIGAuLy4uLy4uL2Jhc2Uuc3R5bGUuc2Nzc2AsXHJcbiAgICAgICAgYC4vLi4vaW5wdXQuY29tcG9uZW50LnNjc3NgLFxyXG4gICAgICAgIGAuL2hzbGEtaW5wdXQuY29tcG9uZW50LnNjc3NgXHJcbiAgICBdLFxyXG4gICAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXHJcbiAgICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gICAgaW1wb3J0czogW0NvbG9yUGlja2VySW5wdXREaXJlY3RpdmVdXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBIc2xhQ29tcG9uZW50IHtcclxuXHJcbiAgICBwdWJsaWMgY29sb3I6IE1vZGVsU2lnbmFsPENvbG9yPiA9IG1vZGVsLnJlcXVpcmVkPENvbG9yPigpO1xyXG5cclxuICAgIHB1YmxpYyBsYWJlbFZpc2libGU6IElucHV0U2lnbmFsPGJvb2xlYW4+ID0gaW5wdXQ8Ym9vbGVhbiwgYm9vbGVhbj4oZmFsc2UsIHsgYWxpYXM6ICdsYWJlbCcsIHRyYW5zZm9ybTogYm9vbGVhbkF0dHJpYnV0ZSB9KTtcclxuXHJcbiAgICBwdWJsaWMgaXNBbHBoYVZpc2libGU6IElucHV0U2lnbmFsPGJvb2xlYW4+ID0gaW5wdXQ8Ym9vbGVhbiwgYm9vbGVhbj4odHJ1ZSwgeyBhbGlhczogJ2FscGhhJywgdHJhbnNmb3JtOiBib29sZWFuQXR0cmlidXRlIH0pO1xyXG5cclxuICAgIHB1YmxpYyBnZXQgdmFsdWUoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29sb3IoKT8uZ2V0SHNsYSgpO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBvbklucHV0Q2hhbmdlKG5ld1ZhbHVlOiBudW1iZXIsIGNvbG9yOiAnSCcgfCAnUycgfCAnTCcgfCAnQScpIHtcclxuICAgICAgICBjb25zdCB2YWx1ZSA9IHRoaXMudmFsdWU7XHJcbiAgICAgICAgY29uc3QgaHVlID0gY29sb3IgPT09ICdIJyA/IG5ld1ZhbHVlIDogdmFsdWUuaHVlO1xyXG4gICAgICAgIGNvbnN0IHNhdHVyYXRpb24gPSBjb2xvciA9PT0gJ1MnID8gbmV3VmFsdWUgOiB2YWx1ZS5zYXR1cmF0aW9uO1xyXG4gICAgICAgIGNvbnN0IGxpZ2h0bmVzcyA9IGNvbG9yID09PSAnTCcgPyBuZXdWYWx1ZSA6IHZhbHVlLmxpZ2h0bmVzcztcclxuICAgICAgICBjb25zdCBhbHBoYSA9IGNvbG9yID09PSAnQScgPyBuZXdWYWx1ZSA6IHZhbHVlLmFscGhhO1xyXG5cclxuICAgICAgICBjb25zdCBuZXdDb2xvciA9IG5ldyBDb2xvcigpLnNldEhzbGEoaHVlLCBzYXR1cmF0aW9uLCBsaWdodG5lc3MsIGFscGhhKTtcclxuICAgICAgICB0aGlzLmNvbG9yLnNldChuZXdDb2xvcik7XHJcbiAgICB9XHJcbn1cclxuIiwiPGRpdiBjbGFzcz1cImNvbHVtblwiPlxyXG4gICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgcGF0dGVybj1cIlswLTldKlwiIG1pbj1cIjBcIiBtYXg9XCIzNjBcIiBbdmFsdWVdPVwidmFsdWU/LmdldEh1ZSgpLnRvU3RyaW5nKClcIiAoaW5wdXRDaGFuZ2UpPVwib25JbnB1dENoYW5nZSgkZXZlbnQsICdIJylcIiAvPlxyXG4gICAgQGlmIChsYWJlbFZpc2libGUoKSkge1xyXG4gICAgICAgIDxzcGFuPkg8L3NwYW4+XHJcbiAgICB9XHJcbjwvZGl2PlxyXG48ZGl2IGNsYXNzPVwiY29sdW1uXCI+XHJcbiAgICA8aW5wdXQgdHlwZT1cInRleHRcIiBwYXR0ZXJuPVwiWzAtOV0qXCIgbWluPVwiMFwiIG1heD1cIjEwMFwiIFt2YWx1ZV09XCJ2YWx1ZT8uZ2V0U2F0dXJhdGlvbigpICsgJyUnXCIgKGlucHV0Q2hhbmdlKT1cIm9uSW5wdXRDaGFuZ2UoJGV2ZW50LCAnUycpXCIgLz5cclxuICAgIEBpZiAobGFiZWxWaXNpYmxlKCkpIHtcclxuICAgICAgICA8c3Bhbj5TPC9zcGFuPlxyXG4gICAgfVxyXG48L2Rpdj5cclxuPGRpdiBjbGFzcz1cImNvbHVtblwiPlxyXG4gICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgcGF0dGVybj1cIlswLTldKlwiIG1pbj1cIjBcIiBtYXg9XCIxMDBcIiBbdmFsdWVdPVwidmFsdWU/LmdldExpZ2h0bmVzcygpICsgJyUnXCIgKGlucHV0Q2hhbmdlKT1cIm9uSW5wdXRDaGFuZ2UoJGV2ZW50LCAnTCcpXCIgLz5cclxuICAgIEBpZiAobGFiZWxWaXNpYmxlKCkpIHtcclxuICAgICAgICA8c3Bhbj5MPC9zcGFuPlxyXG4gICAgfVxyXG48L2Rpdj5cclxuQGlmIChpc0FscGhhVmlzaWJsZSgpKSB7XHJcbiAgICA8ZGl2IGNsYXNzPVwiY29sdW1uXCI+XHJcbiAgICAgICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgcGF0dGVybj1cIlswLTldKyhbXFwuLF1bMC05XXsxLDJ9KT9cIiBtaW49XCIwXCIgbWF4PVwiMVwiIFt2YWx1ZV09XCJ2YWx1ZT8uZ2V0QWxwaGEoKS50b1N0cmluZygpXCIgKGlucHV0Q2hhbmdlKT1cIm9uSW5wdXRDaGFuZ2UoJGV2ZW50LCAnQScpXCIgLz5cclxuICAgICAgICBAaWYgKGxhYmVsVmlzaWJsZSgpKSB7XHJcbiAgICAgICAgICAgIDxzcGFuPkE8L3NwYW4+XHJcbiAgICAgICAgfVxyXG4gICAgPC9kaXY+XHJcbn0iXX0=
+diff --git a/node_modules/@iplab/ngx-color-picker/esm2022/lib/components/parts/inputs/rgba-input/rgba-input.component.mjs b/node_modules/@iplab/ngx-color-picker/esm2022/lib/components/parts/inputs/rgba-input/rgba-input.component.mjs
+index 6d976e8..8989aad 100644
+--- a/node_modules/@iplab/ngx-color-picker/esm2022/lib/components/parts/inputs/rgba-input/rgba-input.component.mjs
++++ b/node_modules/@iplab/ngx-color-picker/esm2022/lib/components/parts/inputs/rgba-input/rgba-input.component.mjs
+@@ -21,10 +21,10 @@ export class RgbaComponent {
+ this.color.set(newColor);
+ }
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: RgbaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
+- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.0", type: RgbaComponent, isStandalone: true, selector: "rgba-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isAlphaVisible: { classPropertyName: "isAlphaVisible", publicName: "alpha", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "\r\n \r\n @if (labelVisible()) {\r\n R\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n G\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n B\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], dependencies: [{ kind: "directive", type: ColorPickerInputDirective, selector: "[inputChange]", inputs: ["min", "max"], outputs: ["inputChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
++ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.0", type: RgbaComponent, isStandalone: true, selector: "rgba-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isAlphaVisible: { classPropertyName: "isAlphaVisible", publicName: "alpha", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "\r\n \r\n @if (labelVisible()) {\r\n R\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n G\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n B\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], dependencies: [{ kind: "directive", type: ColorPickerInputDirective, selector: "[inputChange]", inputs: ["min", "max"], outputs: ["inputChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
+ }
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: RgbaComponent, decorators: [{
+ type: Component,
+- args: [{ selector: `rgba-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [ColorPickerInputDirective], template: "\r\n \r\n @if (labelVisible()) {\r\n R\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n G\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n B\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
++ args: [{ selector: `rgba-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [ColorPickerInputDirective], template: "\r\n \r\n @if (labelVisible()) {\r\n R\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n G\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n B\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
+ }] });
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmdiYS1pbnB1dC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9pcGxhYi9uZ3gtY29sb3ItcGlja2VyL3NyYy9saWIvY29tcG9uZW50cy9wYXJ0cy9pbnB1dHMvcmdiYS1pbnB1dC9yZ2JhLWlucHV0LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2lwbGFiL25neC1jb2xvci1waWNrZXIvc3JjL2xpYi9jb21wb25lbnRzL3BhcnRzL2lucHV0cy9yZ2JhLWlucHV0L3JnYmEtaW5wdXQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSx1QkFBdUIsRUFBRSxnQkFBZ0IsRUFBZSxLQUFLLEVBQUUsS0FBSyxFQUFlLE1BQU0sZUFBZSxDQUFDO0FBQzdILE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUMxRCxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxxREFBcUQsQ0FBQzs7QUFlaEcsTUFBTSxPQUFPLGFBQWE7SUFaMUI7UUFjVyxVQUFLLEdBQXVCLEtBQUssQ0FBQyxRQUFRLEVBQVMsQ0FBQztRQUVwRCxpQkFBWSxHQUF5QixLQUFLLENBQW1CLEtBQUssRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FBQztRQUVySCxtQkFBYyxHQUF5QixLQUFLLENBQW1CLElBQUksRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FBQztLQWdCaEk7SUFkRyxJQUFXLEtBQUs7UUFDWixPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsRUFBRSxPQUFPLEVBQUUsQ0FBQztJQUNuQyxDQUFDO0lBRU0sYUFBYSxDQUFDLFFBQWdCLEVBQUUsS0FBNEI7UUFDL0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQztRQUN6QixNQUFNLEdBQUcsR0FBRyxLQUFLLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUM7UUFDakQsTUFBTSxLQUFLLEdBQUcsS0FBSyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDO1FBQ3JELE1BQU0sSUFBSSxHQUFHLEtBQUssS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztRQUNuRCxNQUFNLEtBQUssR0FBRyxLQUFLLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUM7UUFFckQsTUFBTSxRQUFRLEdBQUcsSUFBSSxLQUFLLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDOUQsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDN0IsQ0FBQzs4R0FyQlEsYUFBYTtrR0FBYixhQUFhLHNnQkNqQjFCLGlsQ0F5QkMseWVEVmEseUJBQXlCOzsyRkFFMUIsYUFBYTtrQkFaekIsU0FBUzsrQkFDSSxzQkFBc0IsbUJBT2YsdUJBQXVCLENBQUMsTUFBTSxjQUNuQyxJQUFJLFdBQ1AsQ0FBQyx5QkFBeUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIGJvb2xlYW5BdHRyaWJ1dGUsIElucHV0U2lnbmFsLCBpbnB1dCwgbW9kZWwsIE1vZGVsU2lnbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IENvbG9yIH0gZnJvbSAnLi8uLi8uLi8uLi8uLi9oZWxwZXJzL2NvbG9yLmNsYXNzJztcclxuaW1wb3J0IHsgQ29sb3JQaWNrZXJJbnB1dERpcmVjdGl2ZSB9IGZyb20gJy4uLy4uLy4uLy4uL2RpcmVjdGl2ZXMvY29sb3ItcGlja2VyLWlucHV0LmRpcmVjdGl2ZSc7XHJcblxyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgICBzZWxlY3RvcjogYHJnYmEtaW5wdXQtY29tcG9uZW50YCxcclxuICAgIHRlbXBsYXRlVXJsOiBgLi9yZ2JhLWlucHV0LmNvbXBvbmVudC5odG1sYCxcclxuICAgIHN0eWxlVXJsczogW1xyXG4gICAgICAgIGAuLy4uLy4uL2Jhc2Uuc3R5bGUuc2Nzc2AsXHJcbiAgICAgICAgYC4vLi4vaW5wdXQuY29tcG9uZW50LnNjc3NgLFxyXG4gICAgICAgIGAuL3JnYmEtaW5wdXQuY29tcG9uZW50LnNjc3NgXHJcbiAgICBdLFxyXG4gICAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXHJcbiAgICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gICAgaW1wb3J0czogW0NvbG9yUGlja2VySW5wdXREaXJlY3RpdmVdXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBSZ2JhQ29tcG9uZW50IHtcclxuXHJcbiAgICBwdWJsaWMgY29sb3I6IE1vZGVsU2lnbmFsPENvbG9yPiA9IG1vZGVsLnJlcXVpcmVkPENvbG9yPigpO1xyXG5cclxuICAgIHB1YmxpYyBsYWJlbFZpc2libGU6IElucHV0U2lnbmFsPGJvb2xlYW4+ID0gaW5wdXQ8Ym9vbGVhbiwgYm9vbGVhbj4oZmFsc2UsIHsgYWxpYXM6ICdsYWJlbCcsIHRyYW5zZm9ybTogYm9vbGVhbkF0dHJpYnV0ZSB9KTtcclxuXHJcbiAgICBwdWJsaWMgaXNBbHBoYVZpc2libGU6IElucHV0U2lnbmFsPGJvb2xlYW4+ID0gaW5wdXQ8Ym9vbGVhbiwgYm9vbGVhbj4odHJ1ZSwgeyBhbGlhczogJ2FscGhhJywgdHJhbnNmb3JtOiBib29sZWFuQXR0cmlidXRlIH0pO1xyXG5cclxuICAgIHB1YmxpYyBnZXQgdmFsdWUoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29sb3IoKT8uZ2V0UmdiYSgpO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBvbklucHV0Q2hhbmdlKG5ld1ZhbHVlOiBudW1iZXIsIGNvbG9yOiAnUicgfCAnRycgfCAnQicgfCAnQScpIHtcclxuICAgICAgICBjb25zdCB2YWx1ZSA9IHRoaXMudmFsdWU7XHJcbiAgICAgICAgY29uc3QgcmVkID0gY29sb3IgPT09ICdSJyA/IG5ld1ZhbHVlIDogdmFsdWUucmVkO1xyXG4gICAgICAgIGNvbnN0IGdyZWVuID0gY29sb3IgPT09ICdHJyA/IG5ld1ZhbHVlIDogdmFsdWUuZ3JlZW47XHJcbiAgICAgICAgY29uc3QgYmx1ZSA9IGNvbG9yID09PSAnQicgPyBuZXdWYWx1ZSA6IHZhbHVlLmJsdWU7XHJcbiAgICAgICAgY29uc3QgYWxwaGEgPSBjb2xvciA9PT0gJ0EnID8gbmV3VmFsdWUgOiB2YWx1ZS5hbHBoYTtcclxuXHJcbiAgICAgICAgY29uc3QgbmV3Q29sb3IgPSBuZXcgQ29sb3IoKS5zZXRSZ2JhKHJlZCwgZ3JlZW4sIGJsdWUsIGFscGhhKTtcclxuICAgICAgICB0aGlzLmNvbG9yLnNldChuZXdDb2xvcik7XHJcbiAgICB9XHJcbn1cclxuIiwiPGRpdiBjbGFzcz1cImNvbHVtblwiPlxyXG4gICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgcGF0dGVybj1cIlswLTldKlwiIG1pbj1cIjBcIiBtYXg9XCIyNTVcIiBbdmFsdWVdPVwidmFsdWU/LmdldFJlZCgpLnRvU3RyaW5nKClcIiAoaW5wdXRDaGFuZ2UpPVwib25JbnB1dENoYW5nZSgkZXZlbnQsICdSJylcIiAvPlxyXG4gICAgQGlmIChsYWJlbFZpc2libGUoKSkge1xyXG4gICAgICAgIDxzcGFuPlI8L3NwYW4+XHJcbiAgICB9XHJcbjwvZGl2PlxyXG48ZGl2IGNsYXNzPVwiY29sdW1uXCI+XHJcbiAgICA8aW5wdXQgdHlwZT1cInRleHRcIiBwYXR0ZXJuPVwiWzAtOV0qXCIgbWluPVwiMFwiIG1heD1cIjI1NVwiIFt2YWx1ZV09XCJ2YWx1ZT8uZ2V0R3JlZW4oKS50b1N0cmluZygpXCIgKGlucHV0Q2hhbmdlKT1cIm9uSW5wdXRDaGFuZ2UoJGV2ZW50LCAnRycpXCIgLz5cclxuICAgIEBpZiAobGFiZWxWaXNpYmxlKCkpIHtcclxuICAgICAgICA8c3Bhbj5HPC9zcGFuPlxyXG4gICAgfVxyXG48L2Rpdj5cclxuPGRpdiBjbGFzcz1cImNvbHVtblwiPlxyXG4gICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgcGF0dGVybj1cIlswLTldKlwiIG1pbj1cIjBcIiBtYXg9XCIyNTVcIiBbdmFsdWVdPVwidmFsdWU/LmdldEJsdWUoKS50b1N0cmluZygpXCIgKGlucHV0Q2hhbmdlKT1cIm9uSW5wdXRDaGFuZ2UoJGV2ZW50LCAnQicpXCIgLz5cclxuICAgIEBpZiAobGFiZWxWaXNpYmxlKCkpIHtcclxuICAgICAgICA8c3Bhbj5CPC9zcGFuPlxyXG4gICAgfVxyXG48L2Rpdj5cclxuQGlmIChpc0FscGhhVmlzaWJsZSgpKSB7XHJcbiAgICA8ZGl2IGNsYXNzPVwiY29sdW1uXCI+XHJcbiAgICAgICAgPGlucHV0IHR5cGU9XCJ0ZXh0XCIgcGF0dGVybj1cIlswLTldKyhbXFwuLF1bMC05XXsxLDJ9KT9cIiBtaW49XCIwXCIgbWF4PVwiMVwiIFt2YWx1ZV09XCJ2YWx1ZT8uZ2V0QWxwaGEoKS50b1N0cmluZygpXCIgKGlucHV0Q2hhbmdlKT1cIm9uSW5wdXRDaGFuZ2UoJGV2ZW50LCAnQScpXCIgLz5cclxuICAgICAgICBAaWYgKGxhYmVsVmlzaWJsZSgpKSB7XHJcbiAgICAgICAgICAgIDxzcGFuPkE8L3NwYW4+XHJcbiAgICAgICAgfVxyXG4gICAgPC9kaXY+XHJcbn0iXX0=
+diff --git a/node_modules/@iplab/ngx-color-picker/fesm2022/iplab-ngx-color-picker.mjs b/node_modules/@iplab/ngx-color-picker/fesm2022/iplab-ngx-color-picker.mjs
+index a3b270c..40bea7f 100644
+--- a/node_modules/@iplab/ngx-color-picker/fesm2022/iplab-ngx-color-picker.mjs
++++ b/node_modules/@iplab/ngx-color-picker/fesm2022/iplab-ngx-color-picker.mjs
+@@ -1123,11 +1123,11 @@ class RgbaComponent {
+ this.color.set(newColor);
+ }
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: RgbaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
+- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.0", type: RgbaComponent, isStandalone: true, selector: "rgba-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isAlphaVisible: { classPropertyName: "isAlphaVisible", publicName: "alpha", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "\r\n \r\n @if (labelVisible()) {\r\n R\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n G\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n B\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], dependencies: [{ kind: "directive", type: ColorPickerInputDirective, selector: "[inputChange]", inputs: ["min", "max"], outputs: ["inputChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
++ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.0", type: RgbaComponent, isStandalone: true, selector: "rgba-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isAlphaVisible: { classPropertyName: "isAlphaVisible", publicName: "alpha", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "\r\n \r\n @if (labelVisible()) {\r\n R\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n G\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n B\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], dependencies: [{ kind: "directive", type: ColorPickerInputDirective, selector: "[inputChange]", inputs: ["min", "max"], outputs: ["inputChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
+ }
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: RgbaComponent, decorators: [{
+ type: Component,
+- args: [{ selector: `rgba-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [ColorPickerInputDirective], template: "\r\n \r\n @if (labelVisible()) {\r\n R\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n G\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n B\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
++ args: [{ selector: `rgba-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [ColorPickerInputDirective], template: "\r\n \r\n @if (labelVisible()) {\r\n R\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n G\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n B\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
+ }] });
+
+ class HslaComponent {
+@@ -1149,11 +1149,11 @@ class HslaComponent {
+ this.color.set(newColor);
+ }
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: HslaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
+- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.0", type: HslaComponent, isStandalone: true, selector: "hsla-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isAlphaVisible: { classPropertyName: "isAlphaVisible", publicName: "alpha", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "\r\n \r\n @if (labelVisible()) {\r\n H\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n S\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n L\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], dependencies: [{ kind: "directive", type: ColorPickerInputDirective, selector: "[inputChange]", inputs: ["min", "max"], outputs: ["inputChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
++ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.0", type: HslaComponent, isStandalone: true, selector: "hsla-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, isAlphaVisible: { classPropertyName: "isAlphaVisible", publicName: "alpha", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "\r\n \r\n @if (labelVisible()) {\r\n H\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n S\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n L\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], dependencies: [{ kind: "directive", type: ColorPickerInputDirective, selector: "[inputChange]", inputs: ["min", "max"], outputs: ["inputChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
+ }
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: HslaComponent, decorators: [{
+ type: Component,
+- args: [{ selector: `hsla-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [ColorPickerInputDirective], template: "\r\n \r\n @if (labelVisible()) {\r\n H\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n S\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n L\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
++ args: [{ selector: `hsla-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [ColorPickerInputDirective], template: "\r\n \r\n @if (labelVisible()) {\r\n H\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n S\r\n }\r\n
\r\n\r\n \r\n @if (labelVisible()) {\r\n L\r\n }\r\n
\r\n@if (isAlphaVisible()) {\r\n \r\n \r\n @if (labelVisible()) {\r\n A\r\n }\r\n
\r\n}", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
+ }] });
+
+ class HexComponent {
+@@ -1184,11 +1184,11 @@ class HexComponent {
+ }
+ }
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: HexComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
+- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.0", type: HexComponent, isStandalone: true, selector: "hex-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, prefixValue: { classPropertyName: "prefixValue", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "\r\n \r\n @if (labelVisible()) {\r\n HEX\r\n }\r\n
", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
++ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.0", type: HexComponent, isStandalone: true, selector: "hex-input-component", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, labelVisible: { classPropertyName: "labelVisible", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, prefixValue: { classPropertyName: "prefixValue", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { color: "colorChange" }, ngImport: i0, template: "\r\n \r\n @if (labelVisible()) {\r\n HEX\r\n }\r\n
", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n", ""], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
+ }
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.0", ngImport: i0, type: HexComponent, decorators: [{
+ type: Component,
+- args: [{ selector: `hex-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "\r\n \r\n @if (labelVisible()) {\r\n HEX\r\n }\r\n
", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
++ args: [{ selector: `hex-input-component`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "\r\n \r\n @if (labelVisible()) {\r\n HEX\r\n }\r\n
", styles: [":host,:host ::ng-deep *{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}\n", ":host{display:table;width:100%;text-align:center;color:#b4b4b4;font-size:11px}.column{display:table-cell;padding:0 2px}input{width:100%;border:1px solid rgb(218,218,218);color:#272727;text-align:center;font-size:12px;-webkit-appearance:none;border-radius:0;margin:0 0 6px;height:26px;outline:none}\n"] }]
+ }] });
+
+ const OpacityAnimation = trigger('opacityAnimation', [
diff --git a/ui-ngx/src/app/core/guards/auth.guard.ts b/ui-ngx/src/app/core/guards/auth.guard.ts
index f8bbcc3241..5090af97ec 100644
--- a/ui-ngx/src/app/core/guards/auth.guard.ts
+++ b/ui-ngx/src/app/core/guards/auth.guard.ts
@@ -131,7 +131,7 @@ export class AuthGuard {
}
}
if (this.mobileService.isMobileApp() && !path.startsWith('dashboard.')) {
- this.mobileService.handleMobileNavigation(path, params);
+ this.mobileService.handleMobileNavigation(path, params, lastChild.queryParams);
return of(false);
}
if (authState.authUser.authority === Authority.PRE_VERIFICATION_TOKEN) {
diff --git a/ui-ngx/src/app/core/services/mobile.service.ts b/ui-ngx/src/app/core/services/mobile.service.ts
index 6fcb7c3602..aceb564ec2 100644
--- a/ui-ngx/src/app/core/services/mobile.service.ts
+++ b/ui-ngx/src/app/core/services/mobile.service.ts
@@ -106,9 +106,9 @@ export class MobileService {
}
}
- public handleMobileNavigation(path?: string, params?: Params) {
+ public handleMobileNavigation(path?: string, params?: Params, queryParams?: Params) {
if (this.mobileApp) {
- this.mobileChannel.callHandler(navigationHandler, path, params);
+ this.mobileChannel.callHandler(navigationHandler, path, params, queryParams);
}
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.component.scss
index 2eb0ceb940..1c97102fe0 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.component.scss
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.component.scss
@@ -51,7 +51,7 @@
flex-direction: row-reverse;
}
.tb-latest-chart-shape {
- flex: 1;
+ flex: 1 1 100%;
min-width: 10px;
min-height: 10px;
display: flex;
@@ -95,8 +95,14 @@
&.legend-right, &.legend-left {
gap: 24px;
.tb-latest-chart-legend {
+ flex: 0 1 auto;
+ overflow-y: auto;
+ max-height: 100%;
+ flex-wrap: nowrap;
+ min-width: fit-content;
+ max-width: 100%;
flex-direction: column;
- justify-content: center;
+ justify-content: stretch;
align-items: stretch;
.tb-latest-chart-legend-item {
flex-direction: row;
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.component.ts
index 85905dfd3e..1fa0437cea 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.component.ts
@@ -181,17 +181,13 @@ export class LatestChartComponent implements OnInit, OnDestroy, AfterViewInit {
private onResize() {
if (this.legendHorizontal) {
- this.renderer.setStyle(this.chartShape.nativeElement, 'max-width', null);
this.renderer.setStyle(this.chartShape.nativeElement, 'min-width', null);
- this.renderer.setStyle(this.chartLegend.nativeElement, 'flex', null);
}
const shapeWidth = this.chartShape.nativeElement.getBoundingClientRect().width;
const shapeHeight = this.chartShape.nativeElement.getBoundingClientRect().height;
const size = Math.min(shapeWidth, shapeHeight);
if (this.legendHorizontal) {
- this.renderer.setStyle(this.chartShape.nativeElement, 'max-width', `${size}px`);
this.renderer.setStyle(this.chartShape.nativeElement, 'min-width', `${size}px`);
- this.renderer.setStyle(this.chartLegend.nativeElement, 'flex', '1');
}
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/display-columns-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/display-columns-panel.component.html
index 65d647993f..d1142d08ed 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/display-columns-panel.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/display-columns-panel.component.html
@@ -17,8 +17,16 @@
-->
-
- {{ column.title }}
+
+ {{'entity.show-all-columns' | translate}}
+
+ @for (column of columns; track column.def) {
+
+ {{ column.title }}
+
+ }
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/display-columns-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/display-columns-panel.component.ts
index 8c5f13de69..4ef00bd575 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/display-columns-panel.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/display-columns-panel.component.ts
@@ -15,6 +15,8 @@
///
import { Component, Inject, InjectionToken } from '@angular/core';
+import { isDefinedAndNotNull } from '@core/utils';
+import { SelectableColumnsPipe } from '@shared/public-api';
import { DisplayColumn } from '@home/components/widget/lib/table-widget.models';
export const DISPLAY_COLUMNS_PANEL_DATA = new InjectionToken('DisplayColumnsPanelData');
@@ -33,8 +35,28 @@ export class DisplayColumnsPanelComponent {
columns: DisplayColumn[];
- constructor(@Inject(DISPLAY_COLUMNS_PANEL_DATA) public data: DisplayColumnsPanelData) {
- this.columns = this.data.columns;
+ constructor(@Inject(DISPLAY_COLUMNS_PANEL_DATA) public data: DisplayColumnsPanelData,
+ private selectableColumnsPipe: SelectableColumnsPipe ) {
+ this.columns = this.selectableColumnsPipe.transform(this.data.columns);
+ }
+
+ get allColumnsVisible(): boolean {
+ return isDefinedAndNotNull(this.columns) && this.columns.every(column => column.display);
+ }
+
+ get someColumnsVisible(): boolean {
+ const filtredColumns = this.columns.filter(item => item.display);
+ return filtredColumns.length !== 0 && this.columns.length !== filtredColumns.length;
+ }
+
+ public toggleAllColumns(event: any): void {
+ const isChecked = event.checked;
+
+ this.columns.forEach(column => {
+ column.display = isChecked;
+ });
+
+ this.update();
}
public update() {
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/polylines-data-layer.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/polylines-data-layer.ts
new file mode 100644
index 0000000000..1bb4b97b4c
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/polylines-data-layer.ts
@@ -0,0 +1,466 @@
+///
+/// Copyright © 2016-2025 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 {
+ defaultBasePolylinesDataLayerSettings,
+ isCutPolygon,
+ isJSON,
+ MapDataLayerType,
+ PolylinesDataLayerSettings,
+ TbMapDatasource,
+ TbPolylineCoordinates,
+ TbPolylineData,
+ TbPolylineRawCoordinates
+} from '@shared/models/widget/maps/map.models';
+import L from 'leaflet';
+import { DataKey, FormattedData } from '@shared/models/widget.models';
+import { ShapeStyleInfo, TbShapesDataLayer } from '@home/components/widget/lib/maps/data-layer/shapes-data-layer';
+import { TbMap } from '@home/components/widget/lib/maps/map';
+import { Observable } from 'rxjs';
+import { isNotEmptyStr, isString } from '@core/utils';
+import {
+ TbLatestDataLayerItem,
+ UnplacedMapDataItem
+} from '@home/components/widget/lib/maps/data-layer/latest-map-data-layer';
+import { map } from 'rxjs/operators';
+
+class TbPolylineDataLayerItem extends TbLatestDataLayerItem {
+
+ private polylineContainer: L.FeatureGroup;
+ private polyline: L.Polyline;
+ private polylineStyleInfo: ShapeStyleInfo;
+ private editing = false;
+
+ constructor(data: FormattedData,
+ dsData: FormattedData[],
+ protected settings: PolylinesDataLayerSettings,
+ protected dataLayer: TbPolylineDataLayer) {
+ super(data, dsData, settings, dataLayer);
+ }
+
+ public isEditing() {
+ return this.editing;
+ }
+
+ public updateBubblingMouseEvents() {
+ this.polyline.options.bubblingMouseEvents = !this.dataLayer.isEditMode();
+ }
+
+ public remove() {
+ super.remove();
+ if (this.polylineStyleInfo?.patternId) {
+ this.dataLayer.getMap().unUseShapePattern(this.polylineStyleInfo.patternId);
+ }
+ }
+
+ protected create(data: FormattedData, dsData: FormattedData[]): L.Layer {
+ const polyData = this.dataLayer.extractPolylineCoordinates(data);
+ const polyConstructor = L.polyline;
+ this.polyline = polyConstructor(polyData as (TbPolylineRawCoordinates & L.LatLngTuple[]), {
+ noClip: true,
+ snapIgnore: !this.dataLayer.isSnappable(),
+ bubblingMouseEvents: !this.dataLayer.isEditMode()
+ });
+
+ this.dataLayer.getStrokeStyle(data, dsData, this.polylineStyleInfo?.patternId).subscribe((styleInfo) => {
+ this.polylineStyleInfo = styleInfo;
+ if (this.polyline) {
+ this.polyline.setStyle(this.polylineStyleInfo.style);
+ }
+ });
+
+ this.polylineContainer = L.featureGroup();
+ this.polyline.addTo(this.polylineContainer);
+
+ this.updateLabel(data, dsData);
+ return this.polylineContainer;
+ }
+
+ protected unbindLabel() {
+ this.polylineContainer.unbindTooltip();
+ }
+
+ protected bindLabel(content: L.Content): void {
+ this.polylineContainer.bindTooltip(content, {className: 'tb-polyline-label', permanent: true, direction: 'center'})
+ .openTooltip(this.polylineContainer.getBounds().getCenter());
+ }
+
+ protected doUpdate(data: FormattedData, dsData: FormattedData[]): void {
+ this.dataLayer.getStrokeStyle(data, dsData, this.polylineStyleInfo?.patternId).subscribe((styleInfo) => {
+ this.polylineStyleInfo = styleInfo;
+ this.updatePolylineShape(data);
+ this.updateTooltip(data, dsData);
+ this.updateLabel(data, dsData);
+
+ if (!this.editing || !this.dataLayer.getMap().getMap().pm.globalCutModeEnabled()) {
+ this.polyline.setStyle(this.polylineStyleInfo.style);
+ }
+ });
+ }
+
+ protected doInvalidateCoordinates(data: FormattedData, _dsData: FormattedData[]): void {
+ this.updatePolylineShape(data);
+ }
+
+ protected addItemClass(clazz: string): void {
+ if ((this.polyline as any)._path) {
+ L.DomUtil.addClass((this.polyline as any)._path, clazz);
+ }
+ }
+
+ protected removeItemClass(clazz: string): void {
+ if ((this.polyline as any)._path) {
+ L.DomUtil.removeClass((this.polyline as any)._path, clazz);
+ }
+ }
+
+ protected enableDrag(): void {
+ this.polyline.pm.setOptions({
+ snappable: this.dataLayer.isSnappable()
+ });
+ this.polyline.pm.enableLayerDrag();
+ this.polyline.on('pm:dragstart', () => {
+ this.editing = true;
+ });
+ this.polyline.on('pm:drag', () => {
+ if (this.tooltip?.isOpen()) {
+ this.tooltip.setLatLng(this.polyline.getBounds().getCenter());
+ }
+ });
+ this.polyline.on('pm:dragend', () => {
+ this.savePolylineCoordinates();
+ this.editing = false;
+ });
+ }
+
+ protected disableDrag(): void {
+ this.polyline.pm.disableLayerDrag();
+ this.polyline.off('pm:dragstart');
+ this.polyline.off('pm:dragend');
+ }
+
+ protected onSelected(): L.TB.ToolbarButtonOptions[] {
+ const buttons: L.TB.ToolbarButtonOptions[] = [];
+ if (this.dataLayer.isEditEnabled()) {
+ this.enablePolylineEditMode();
+ buttons.push(
+ {
+ id: 'cut',
+ title: this.getDataLayer().getCtx().translate.instant('widgets.maps.data-layer.polygon.cut'),
+ iconClass: 'tb-cut',
+ click: (e, button) => {
+ const map = this.dataLayer.getMap().getMap();
+ if (!map.pm.globalCutModeEnabled()) {
+ this.disablePolylineRotateMode();
+ this.disablePolylineEditMode();
+ this.enablePolylineCutMode(button);
+ } else {
+ this.disablePolylineCutMode(button);
+ this.enablePolylineEditMode();
+ }
+ }
+ },
+ {
+ id: 'rotate',
+ title: this.getDataLayer().getCtx().translate.instant('widgets.maps.data-layer.polyline.rotate'),
+ iconClass: 'tb-rotate',
+ click: (e, button) => {
+ if (!this.polyline.pm.rotateEnabled()) {
+ this.disablePolylineCutMode();
+ this.disablePolylineEditMode();
+ this.enablePolylineRotateMode(button);
+ } else {
+ this.disablePolylineRotateMode(button);
+ this.enablePolylineEditMode();
+ }
+ }
+ }
+ );
+ }
+ return buttons;
+ }
+
+ protected onDeselected(): void {
+ if (this.dataLayer.isEditEnabled()) {
+ this.disablePolylineEditMode();
+ this.disablePolylineRotateMode();
+ }
+ }
+
+ protected canDeselect(cancel = false): boolean {
+ const map = this.dataLayer.getMap().getMap();
+ if (map.pm.globalCutModeEnabled()) {
+ if (cancel) {
+ this.disablePolylineCutMode();
+ }
+ return false;
+ } else if (this.polyline.pm.rotateEnabled()) {
+ if (cancel) {
+ this.disablePolylineRotateMode();
+ }
+ return false;
+ } else if (this.editing) {
+ return false;
+ }
+ return true;
+ }
+
+ protected removeDataItemTitle(): string {
+ return this.dataLayer.getCtx().translate.instant('widgets.maps.data-layer.polyline.remove-polyline-for', {entityName: this.data.entityName});
+ }
+
+ protected removeDataItem(): Observable {
+ return this.dataLayer.savePolylineCoordinates(this.data, null);
+ }
+
+ private enablePolylineEditMode() {
+ this.polyline.on('pm:markerdragstart', () => this.editing = true);
+ this.polyline.on('pm:markerdragend', () => setTimeout(() => {
+ this.editing = false;
+ }));
+ this.polyline.on('pm:edit', () => this.savePolylineCoordinates());
+ this.polyline.pm.enable();
+ const map = this.dataLayer.getMap();
+ map.getEditToolbar().getButton('remove')?.setDisabled(false);
+ }
+
+ private disablePolylineEditMode() {
+ this.polyline.pm.disable();
+ this.polyline.off('pm:markerdragstart');
+ this.polyline.off('pm:markerdragend');
+ this.polyline.off('pm:edit');
+ const map = this.dataLayer.getMap();
+ map.getEditToolbar().getButton('remove')?.setDisabled(true);
+ }
+
+ private enablePolylineCutMode(cutButton?: L.TB.ToolbarButton) {
+ this.polylineContainer.closePopup();
+ this.editing = true;
+ this.polyline.options.bubblingMouseEvents = true;
+ this.polyline.setStyle({
+ ...this.polylineStyleInfo.style, dashArray: '5 5', weight: 3,
+ color: '#3388ff', opacity: 1, fillColor: '#3388ff', fillOpacity: 0.2
+ });
+ this.addItemClass('tb-cut-mode');
+ this.polyline.once('pm:cut', (e) => {
+ if (e.layer instanceof L.Polyline) {
+ this.polyline = L.polyline(e.layer.getLatLngs() as L.LatLngExpression[] | L.LatLngExpression[][] , {
+ ...this.polylineStyleInfo.style,
+ snapIgnore: !this.dataLayer.isSnappable(),
+ bubblingMouseEvents: !this.dataLayer.isEditMode()
+ });
+ this.polyline.addTo(this.polylineContainer);
+ } else if (e.layer instanceof L.LayerGroup) {
+ const parts: L.LatLngExpression[][] = [];
+
+ if (e.layer && typeof e.layer.getLayers === 'function') {
+ const segments: L.Polyline[] = e.layer.getLayers() as L.Polyline[];
+ segments.forEach(segment => {
+ parts.push(segment.getLatLngs() as L.LatLngExpression[]);
+ });
+ } else if (e.layer instanceof L.Polyline) {
+ parts.push(e.layer.getLatLngs() as L.LatLngExpression[]);
+ }
+
+ if (parts.length > 0) {
+ this.polyline = L.polyline(parts, {
+ ...this.polylineStyleInfo.style,
+ snapIgnore: !this.dataLayer.isSnappable(),
+ bubblingMouseEvents: !this.dataLayer.isEditMode()
+ });
+ this.polyline.addTo(this.polylineContainer);
+ }
+ }
+ // @ts-ignore
+ e.layer._pmTempLayer = true;
+ e.layer.remove();
+ this.polylineContainer.removeLayer(this.polyline);
+ // @ts-ignore
+ this.polyline._pmTempLayer = false;
+ this.polyline.addTo(this.polylineContainer);
+ this.updateSelectedState();
+ cutButton?.setActive(false);
+ this.savePolylineCoordinates();
+ });
+ const map = this.dataLayer.getMap().getMap();
+ map.pm.setLang('en', {
+ tooltips: {
+ firstVertex: this.getDataLayer().getCtx().translate.instant('widgets.maps.data-layer.polyline.polyline-place-first-point-cut-hint'),
+ finishLine: this.getDataLayer().getCtx().translate.instant('widgets.maps.data-layer.polyline.finish-polyline-cut-hint')
+ }
+ }, 'en');
+ map.pm.enableGlobalCutMode({
+ // @ts-ignore
+ layersToCut: [this.polyline]
+ });
+ // @ts-ignore
+ L.DomUtil.addClass(map.pm.Draw.Cut._hintMarker.getTooltip()._container, 'tb-place-item-label');
+ cutButton?.setActive(true);
+ map.once('pm:globalcutmodetoggled', (e) => {
+ if (!e.enabled) {
+ this.disablePolylineCutMode(cutButton);
+ this.enablePolylineEditMode();
+ }
+ });
+ }
+
+ private disablePolylineCutMode(cutButton?: L.TB.ToolbarButton) {
+ this.editing = false;
+ this.polyline.options.bubblingMouseEvents = !this.dataLayer.isEditMode();
+ this.polyline.setStyle({...this.polylineStyleInfo.style, dashArray: null});
+ this.removeItemClass('tb-cut-mode');
+ this.polyline.off('pm:cut');
+ const map = this.dataLayer.getMap().getMap();
+ map.pm.disableGlobalCutMode();
+ cutButton?.setActive(false);
+ }
+
+ private enablePolylineRotateMode(rotateButton?: L.TB.ToolbarButton) {
+ this.polylineContainer.closePopup();
+ this.editing = true;
+ this.polyline.on('pm:rotateend', () => {
+ this.savePolylineCoordinates();
+ });
+ this.polyline.pm.enableRotate();
+ rotateButton?.setActive(true);
+ this.polyline.on('pm:rotatedisable', () => {
+ this.disablePolylineRotateMode(rotateButton);
+ this.enablePolylineEditMode();
+ });
+ }
+
+ private disablePolylineRotateMode(rotateButton?: L.TB.ToolbarButton) {
+ this.editing = false;
+ this.polyline.pm.disableRotate();
+ this.polyline.off('pm:rotateend');
+ this.polyline.off('pm:rotatedisable');
+ rotateButton?.setActive(false);
+ }
+
+ private savePolylineCoordinates() {
+ let coordinates: TbPolylineCoordinates = this.polyline.getLatLngs();
+ if (coordinates.length === 1) {
+ coordinates = coordinates[0] as TbPolylineCoordinates;
+ }
+ if (this.polyline instanceof L.Rectangle && !isCutPolygon(coordinates)) {
+ const bounds = this.polyline.getBounds();
+ const boundsArray = [bounds.getNorthWest(), bounds.getNorthEast(), bounds.getSouthWest(), bounds.getSouthEast()];
+ if (coordinates.every(point => boundsArray.find(boundPoint => boundPoint.equals(point as L.LatLng)) !== undefined)) {
+ coordinates = [bounds.getNorthWest(), bounds.getSouthEast()];
+ }
+ }
+ this.dataLayer.savePolylineCoordinates(this.data, coordinates).subscribe();
+ }
+
+ private updatePolylineShape(data: FormattedData) {
+ if (this.editing) {
+ return;
+ }
+
+ const polyData = this.dataLayer.extractPolylineCoordinates(data) as TbPolylineData;
+ if (this.polyline instanceof L.Polyline && !(this.polyline instanceof L.Rectangle)) {
+ this.polyline.setLatLngs(polyData as L.LatLngExpression[] | L.LatLngExpression[][]);
+ } else if (this.polyline instanceof L.Rectangle && polyData.length === 2) {
+ const bounds = new L.LatLngBounds(polyData as L.LatLngTuple[]);
+ this.polyline.setBounds(bounds);
+ } else {
+ this.polylineContainer.removeLayer(this.polyline);
+ if (polyData.length === 2 && isCutPolygon(polyData)) {
+ this.polyline = L.polyline(polyData as L.LatLngExpression[] | L.LatLngExpression[][], {
+ ...this.polylineStyleInfo.style,
+ snapIgnore: !this.dataLayer.isSnappable(),
+ bubblingMouseEvents: !this.dataLayer.isEditMode(),
+ noClip: true
+ });
+ }
+
+ this.polyline.addTo(this.polylineContainer);
+ this.editModeUpdated();
+ }
+ }
+}
+
+export class TbPolylineDataLayer extends TbShapesDataLayer {
+
+ constructor(protected map: TbMap,
+ inputSettings: PolylinesDataLayerSettings) {
+ super(map, inputSettings);
+ }
+
+ public dataLayerType(): MapDataLayerType {
+ return 'polylines';
+ }
+
+ public placeItem(item: UnplacedMapDataItem, layer: L.Layer): void {
+ if (layer instanceof L.Polyline) {
+ let coordinates: TbPolylineCoordinates;
+ coordinates = layer.getLatLngs();
+ if (coordinates.length === 1) {
+ coordinates = coordinates[0] as TbPolylineCoordinates;
+ }
+ this.savePolylineCoordinates(item.entity, coordinates).subscribe(
+ (converted) => {
+ item.entity[this.settings.polylineKey.label] = JSON.stringify(converted);
+ this.createItemFromUnplaced(item);
+ }
+ );
+ } else {
+ console.warn('Unable to place item, layer is not a polyline.');
+ }
+ }
+
+ public extractPolylineCoordinates(data: FormattedData): TbPolylineRawCoordinates {
+ let rawPolyData = data[this.settings.polylineKey.label];
+ if (isString(rawPolyData)) {
+ rawPolyData = JSON.parse(rawPolyData);
+ }
+ return this.map.polylineDataToCoordinates(rawPolyData);
+ }
+
+ public savePolylineCoordinates(data: FormattedData, coordinates: TbPolylineCoordinates): Observable {
+ const converted = coordinates ? this.map.coordinatesToPolylineData(coordinates) : null;
+ const polylineData = [
+ {
+ dataKey: this.settings.polylineKey,
+ value: converted
+ }
+ ];
+ return this.map.saveItemData(data.$datasource, polylineData, this.settings.edit?.attributeScope).pipe(
+ map(() => converted)
+ );
+ }
+
+ protected getDataKeys(): DataKey[] {
+ return [this.settings.polylineKey];
+ }
+
+ protected defaultBaseSettings(map: TbMap): Partial {
+ return defaultBasePolylinesDataLayerSettings(map.type());
+ }
+
+ protected doSetup(): Observable {
+ return super.doSetup();
+ }
+
+ protected isValidLayerData(layerData: FormattedData): boolean {
+ return layerData && ((isNotEmptyStr(layerData[this.settings.polylineKey.label]) && !isJSON(layerData[this.settings.polylineKey.label])
+ || Array.isArray(layerData[this.settings.polylineKey.label])));
+ }
+
+ protected createLayerItem(data: FormattedData, dsData: FormattedData[]): TbPolylineDataLayerItem {
+ return new TbPolylineDataLayerItem(data, dsData, this.settings, this);
+ }
+}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/shapes-data-layer.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/shapes-data-layer.ts
index 93502588b1..ef68f0a6b3 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/shapes-data-layer.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/shapes-data-layer.ts
@@ -37,10 +37,12 @@ import { isDefinedAndNotNull, objectHashCode, parseTbFunction, safeExecuteTbFunc
import { CompiledTbFunction } from '@shared/models/js-function.models';
import { ImagePipe } from '@shared/pipe/image.pipe';
-export type ShapePatternStorage = {[id: string]: {
- pattern: L.TB.Pattern;
- refCount: number;
-}};
+export type ShapePatternStorage = {
+ [id: string]: {
+ pattern: L.TB.Pattern;
+ refCount: number;
+ }
+};
interface ShapePatternInfo {
type: ShapeFillType;
@@ -311,6 +313,23 @@ export abstract class TbShapesDataLayer, dsData: FormattedData[], fillPatternId: string): Observable {
+ return this.shapePatternProcessor.processPattern(data, dsData, fillPatternId).pipe(
+ map((patternWithId) => {
+ const stroke = this.strokeColorProcessor.processColor(data, dsData);
+ const style: L.PathOptions = {
+ color: stroke,
+ weight: this.settings.strokeWeight,
+ opacity: 1
+ };
+ return {
+ patternId: patternWithId.patternId,
+ style
+ }
+ })
+ );
+ }
+
public getShapeStyle(data: FormattedData, dsData: FormattedData[], fillPatternId: string): Observable {
return this.shapePatternProcessor.processPattern(data, dsData, fillPatternId).pipe(
map((patternWithId) => {
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/trips-data-layer.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/trips-data-layer.ts
index ae2f62853e..bfb872c75a 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/trips-data-layer.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/trips-data-layer.ts
@@ -44,7 +44,7 @@ import { MarkerDataProcessor } from '@home/components/widget/lib/maps/data-layer
type TripRouteData = {[time: number]: FormattedData};
-interface PointItem {
+export interface PointItem {
point: L.CircleMarker;
tooltip?: L.Popup;
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/geo-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/geo-map.ts
index fd03990d26..6093b8ee8e 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/geo-map.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/geo-map.ts
@@ -24,7 +24,11 @@ import {
TbPolygonCoordinate,
TbPolygonCoordinates,
TbPolygonRawCoordinate,
- TbPolygonRawCoordinates
+ TbPolygonRawCoordinates,
+ TbPolylineCoordinate,
+ TbPolylineCoordinates,
+ TbPolylineRawCoordinate,
+ TbPolylineRawCoordinates
} from '@shared/models/widget/maps/map.models';
import { WidgetContext } from '@home/models/widget-component.models';
import { DeepPartial } from '@shared/models/common';
@@ -179,5 +183,29 @@ export class TbGeoMap extends TbMap {
return circleData;
}
+ public polylineDataToCoordinates(expression: TbPolylineRawCoordinates): TbPolylineRawCoordinates {
+ return (expression).map((el: TbPolylineRawCoordinate) => {
+ if (!Array.isArray(el[0]) && !Array.isArray(el[1]) && el.length === 2) {
+ return el;
+ } else if (Array.isArray(el) && el.length) {
+ return this.polylineDataToCoordinates(el as TbPolylineRawCoordinates) as TbPolylineRawCoordinate;
+ } else {
+ return null;
+ }
+ }).filter(el => !!el);
+ }
+ public coordinatesToPolylineData(coordinates: TbPolylineCoordinates): TbPolylineRawCoordinates {
+ if (coordinates.length) {
+ return coordinates.map((point: TbPolylineCoordinate) => {
+ if (Array.isArray(point)) {
+ return this.coordinatesToPolylineData(point) as TbPolylineRawCoordinate;
+ } else {
+ const convertPoint = latLngPointToBounds(point, this.southWest, this.northEast);
+ return [convertPoint.lat, convertPoint.lng];
+ }
+ });
+ }
+ return [];
+ }
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/image-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/image-map.ts
index 219f5d63ff..753528f006 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/image-map.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/image-map.ts
@@ -23,7 +23,12 @@ import {
ImageSourceType,
loadImageWithAspect,
MapZoomAction,
- TbCircleData, TbPolygonCoordinate, TbPolygonCoordinates, TbPolygonRawCoordinate, TbPolygonRawCoordinates
+ TbCircleData,
+ TbPolygonCoordinate,
+ TbPolygonCoordinates,
+ TbPolygonRawCoordinate,
+ TbPolygonRawCoordinates, TbPolylineCoordinate, TbPolylineCoordinates, TbPolylineRawCoordinate,
+ TbPolylineRawCoordinates
} from '@shared/models/widget/maps/map.models';
import { WidgetContext } from '@home/models/widget-component.models';
import { DeepPartial } from '@shared/models/common';
@@ -339,4 +344,36 @@ export class TbImageMap extends TbMap {
);
}
+ public polylineDataToCoordinates(expression: TbPolylineRawCoordinates): TbPolylineRawCoordinates{
+ return expression.map((el: TbPolylineRawCoordinate) => {
+ if (!Array.isArray(el[0]) && !Array.isArray(el[1]) && el.length === 2) {
+ const latLng = this.pointToLatLng(
+ el[0] * this.width,
+ el[1] * this.height
+ );
+ return [latLng.lat, latLng.lng] as TbPolylineRawCoordinate;
+ } else if (Array.isArray(el) && el.length) {
+ return this.polylineDataToCoordinates(el as TbPolylineRawCoordinates) as TbPolylineRawCoordinate;
+ }
+ else {
+ return null;
+ }
+ }).filter(el => !!el);
+ }
+
+ public coordinatesToPolylineData(coordinates: TbPolylineCoordinates): TbPolylineRawCoordinates{
+ if (coordinates.length) {
+ return coordinates.map((point: TbPolylineCoordinate) => {
+ if (Array.isArray(point)) {
+ return this.coordinatesToPolylineData(point) as TbPolylineRawCoordinate;
+ } else {
+ const pos = this.latLngToPoint(point);
+ return [calculateNewPointCoordinate(pos.x, this.width), calculateNewPointCoordinate(pos.y, this.height)];
+ }
+ });
+ } else {
+ return [];
+ }
+ }
+
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map.scss b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map.scss
index 985bdc17f5..5d00f9add6 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map.scss
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map.scss
@@ -169,6 +169,9 @@ div.tb-widget .tb-widget-content.tb-no-interaction {
&.tb-draw-circle {
mask-image: url('data:image/svg+xml,');
}
+ &.tb-draw-polyline {
+ mask-image: url('data:image/svg+xml,');
+ }
&.tb-close {
background: #D12730;
mask-image: url('data:image/svg+xml,');
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map.ts
index aa8dd67494..2c111110c9 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map.ts
@@ -27,7 +27,9 @@ import {
TbCircleData,
TbMapDatasource,
TbPolygonCoordinates,
- TbPolygonRawCoordinates
+ TbPolygonRawCoordinates,
+ TbPolylineCoordinates,
+ TbPolylineRawCoordinates
} from '@shared/models/widget/maps/map.models';
import { WidgetContext } from '@home/models/widget-component.models';
import {
@@ -80,11 +82,12 @@ import { TbTripsDataLayer } from '@home/components/widget/lib/maps/data-layer/tr
import { CompiledTbFunction } from '@shared/models/js-function.models';
import { TbMapDataLayer } from '@home/components/widget/lib/maps/data-layer/map-data-layer';
import { EntityType } from '@shared/models/entity-type.models';
+import { ShapePatternStorage } from '@home/components/widget/lib/maps/data-layer/shapes-data-layer';
+import { TbPolylineDataLayer } from '@home/components/widget/lib/maps/data-layer/polylines-data-layer';
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
import TooltipPositioningSide = JQueryTooltipster.TooltipPositioningSide;
-import { ShapePatternStorage } from '@home/components/widget/lib/maps/data-layer/shapes-data-layer';
-type TooltipInstancesData = {root: HTMLElement, instances: ITooltipsterInstance[]};
+type TooltipInstancesData = { root: HTMLElement, instances: ITooltipsterInstance[] };
export abstract class TbMap {
@@ -124,6 +127,7 @@ export abstract class TbMap {
protected addRectangleButton: L.TB.ToolbarButton;
protected addPolygonButton: L.TB.ToolbarButton;
protected addCircleButton: L.TB.ToolbarButton;
+ protected addPolylineButton: L.TB.ToolbarButton;
protected timeLineComponentRef: ComponentRef;
protected timeLineComponent: MapTimelinePanelComponent;
@@ -132,6 +136,7 @@ export abstract class TbMap {
protected addMarkerDataLayers: TbLatestMapDataLayer[];
protected addPolygonDataLayers: TbLatestMapDataLayer[];
protected addCircleDataLayers: TbLatestMapDataLayer[];
+ protected addPolylineDataLayers: TbLatestMapDataLayer[];
protected shapePatternStorage: ShapePatternStorage = {};
@@ -274,6 +279,11 @@ export abstract class TbMap {
this.dataLayers.push(...circlesDataLayers);
this.latestDataLayers.push(...circlesDataLayers);
}
+ if (this.settings.polylines) {
+ const polylinesDataLayers = this.settings.polylines.map(settings => new TbPolylineDataLayer(this, settings));
+ this.dataLayers.push(...polylinesDataLayers);
+ this.latestDataLayers.push(...polylinesDataLayers);
+ }
if (this.settings.trips) {
const tripsDataLayers = this.settings.trips.map(settings => new TbTripsDataLayer(this, settings));
this.dataLayers.push(...tripsDataLayers);
@@ -319,7 +329,7 @@ export abstract class TbMap {
let datasources: TbMapDatasource[];
for (const layerType of mapDataLayerTypes) {
const typeDatasources = this.latestDataLayers.filter(dl => dl.dataLayerType() === layerType)
- .map(dl => dl.getDataSources()).flat();
+ .map(dl => dl.getDataSources()).flat();
if (!datasources) {
datasources = typeDatasources;
} else {
@@ -419,88 +429,100 @@ export abstract class TbMap {
private setupEditMode() {
- this.editToolbar = L.TB.bottomToolbar({
- mapElement: $(this.mapElement),
- closeTitle: this.ctx.translate.instant('action.cancel'),
- onClose: () => {
- return this.deselectItem(true);
- }
- });
-
- this.map.on('click', () => {
- this.deselectItem();
- });
-
- if (this.latestDataLayers.some(dl => dl.isEditable())) {
- this.map.pm.setGlobalOptions({ snappable: false });
- this.map.pm.applyGlobalOptions();
- }
-
- const dragSupportedDataLayers = this.latestDataLayers.filter(dl => dl.isDragEnabled());
- const showDragModeButton = this.settings.dragModeButton && dragSupportedDataLayers.length;
- const addSupportedDataLayers = this.latestDataLayers.filter(dl => dl.isAddEnabled());
-
- if (showDragModeButton || addSupportedDataLayers.length) {
- const drawToolbar = L.TB.toolbar({
- position: this.settings.controlsPosition
- }).addTo(this.map);
- if (showDragModeButton) {
- this.dragModeButton = drawToolbar.toolbarButton({
- id: 'dragMode',
- title: this.ctx.translate.instant('widgets.maps.data-layer.drag-drop-mode'),
- iconClass: 'tb-drag-mode',
- click: (e, button) => {
- this.toggleDragMode(e, button);
- }
- });
- }
- this.addMarkerDataLayers = addSupportedDataLayers.filter(dl => dl.dataLayerType() === 'markers');
- if (this.addMarkerDataLayers.length) {
- this.addMarkerButton = drawToolbar.toolbarButton({
- id: 'addMarker',
- title: this.ctx.translate.instant('widgets.maps.data-layer.marker.place-marker'),
- iconClass: 'tb-place-marker',
- click: (e, button) => {
- this.placeMarker(e, button);
- }
- });
- this.addMarkerButton.setDisabled(true);
- this.setPlaceMarkerStyle();
- }
- this.addPolygonDataLayers = addSupportedDataLayers.filter(dl => dl.dataLayerType() === 'polygons');
- if (this.addPolygonDataLayers.length) {
- this.addRectangleButton = drawToolbar.toolbarButton({
- id: 'addRectangle',
- title: this.ctx.translate.instant('widgets.maps.data-layer.polygon.draw-rectangle'),
- iconClass: 'tb-draw-rectangle',
- click: (e, button) => {
- this.drawRectangle(e, button);
- }
- });
- this.addRectangleButton.setDisabled(true);
- this.addPolygonButton = drawToolbar.toolbarButton({
- id: 'addPolygon',
- title: this.ctx.translate.instant('widgets.maps.data-layer.polygon.draw-polygon'),
- iconClass: 'tb-draw-polygon',
- click: (e, button) => {
- this.drawPolygon(e, button);
- }
- });
- this.addPolygonButton.setDisabled(true);
- }
- this.addCircleDataLayers = addSupportedDataLayers.filter(dl => dl.dataLayerType() === 'circles');
- if (this.addCircleDataLayers.length) {
- this.addCircleButton = drawToolbar.toolbarButton({
- id: 'addCircle',
- title: this.ctx.translate.instant('widgets.maps.data-layer.circle.draw-circle'),
- iconClass: 'tb-draw-circle',
- click: (e, button) => {
- this.drawCircle(e, button);
- }
- });
- this.addCircleButton.setDisabled(true);
- }
- }
+ this.editToolbar = L.TB.bottomToolbar({
+ mapElement: $(this.mapElement),
+ closeTitle: this.ctx.translate.instant('action.cancel'),
+ onClose: () => {
+ return this.deselectItem(true);
+ }
+ });
+
+ this.map.on('click', () => {
+ this.deselectItem();
+ });
+
+ if (this.latestDataLayers.some(dl => dl.isEditable())) {
+ this.map.pm.setGlobalOptions({snappable: false});
+ this.map.pm.applyGlobalOptions();
+ }
+
+ const dragSupportedDataLayers = this.latestDataLayers.filter(dl => dl.isDragEnabled());
+ const showDragModeButton = this.settings.dragModeButton && dragSupportedDataLayers.length;
+ const addSupportedDataLayers = this.latestDataLayers.filter(dl => dl.isAddEnabled());
+
+ if (showDragModeButton || addSupportedDataLayers.length) {
+ const drawToolbar = L.TB.toolbar({
+ position: this.settings.controlsPosition
+ }).addTo(this.map);
+ if (showDragModeButton) {
+ this.dragModeButton = drawToolbar.toolbarButton({
+ id: 'dragMode',
+ title: this.ctx.translate.instant('widgets.maps.data-layer.drag-drop-mode'),
+ iconClass: 'tb-drag-mode',
+ click: (e, button) => {
+ this.toggleDragMode(e, button);
+ }
+ });
+ }
+ this.addMarkerDataLayers = addSupportedDataLayers.filter(dl => dl.dataLayerType() === 'markers');
+ if (this.addMarkerDataLayers.length) {
+ this.addMarkerButton = drawToolbar.toolbarButton({
+ id: 'addMarker',
+ title: this.ctx.translate.instant('widgets.maps.data-layer.marker.place-marker'),
+ iconClass: 'tb-place-marker',
+ click: (e, button) => {
+ this.placeMarker(e, button);
+ }
+ });
+ this.addMarkerButton.setDisabled(true);
+ this.setPlaceMarkerStyle();
+ }
+ this.addPolygonDataLayers = addSupportedDataLayers.filter(dl => dl.dataLayerType() === 'polygons');
+ if (this.addPolygonDataLayers.length) {
+ this.addRectangleButton = drawToolbar.toolbarButton({
+ id: 'addRectangle',
+ title: this.ctx.translate.instant('widgets.maps.data-layer.polygon.draw-rectangle'),
+ iconClass: 'tb-draw-rectangle',
+ click: (e, button) => {
+ this.drawRectangle(e, button);
+ }
+ });
+ this.addRectangleButton.setDisabled(true);
+ this.addPolygonButton = drawToolbar.toolbarButton({
+ id: 'addPolygon',
+ title: this.ctx.translate.instant('widgets.maps.data-layer.polygon.draw-polygon'),
+ iconClass: 'tb-draw-polygon',
+ click: (e, button) => {
+ this.drawPolygon(e, button);
+ }
+ });
+ this.addPolygonButton.setDisabled(true);
+ }
+ this.addCircleDataLayers = addSupportedDataLayers.filter(dl => dl.dataLayerType() === 'circles');
+ if (this.addCircleDataLayers.length) {
+ this.addCircleButton = drawToolbar.toolbarButton({
+ id: 'addCircle',
+ title: this.ctx.translate.instant('widgets.maps.data-layer.circle.draw-circle'),
+ iconClass: 'tb-draw-circle',
+ click: (e, button) => {
+ this.drawCircle(e, button);
+ }
+ });
+ this.addCircleButton.setDisabled(true);
+ }
+ this.addPolylineDataLayers = addSupportedDataLayers.filter(dl => dl.dataLayerType() === 'polylines');
+ if (this.addPolylineDataLayers.length) {
+ this.addPolylineButton = drawToolbar.toolbarButton({
+ id: 'addPolyline',
+ title: this.ctx.translate.instant('widgets.maps.data-layer.polyline.draw-polyline'),
+ iconClass: 'tb-draw-polyline',
+ click: (e, button) => {
+ this.drawPolyline(e, button);
+ }
+ });
+ this.addPolylineButton.setDisabled(true);
+ }
+ }
}
private toggleDragMode(_e: MouseEvent, button: L.TB.ToolbarButton): void {
@@ -557,6 +579,13 @@ export abstract class TbMap {
}));
}
+ private drawPolyline(e: MouseEvent, button: L.TB.ToolbarButton): void {
+ this.placeItem(e, button, this.addPolylineDataLayers, (entity) => this.prepareDrawMode('Line', {
+ startPolyline: this.ctx.translate.instant('widgets.maps.data-layer.polyline.polyline-place-first-point-hint-with-entity', {entityName: entity.entity.entityDisplayName}),
+ finishPolyline: this.ctx.translate.instant('widgets.maps.data-layer.polyline.finish-polyline-hint-with-entity', {entityName: entity.entity.entityDisplayName}),
+ }));
+ }
+
private placeItem(e: MouseEvent, button: L.TB.ToolbarButton, dataLayers: TbLatestMapDataLayer[],
prepareDrawMode: (entity: UnplacedMapDataItem) => void): void {
if (this.isPlacingItem) {
@@ -678,6 +707,9 @@ export abstract class TbMap {
case MapItemType.circle:
this.createCircle(actionData);
break;
+ case MapItemType.polyline:
+ this.createPolyline(actionData);
+ break;
}
}
@@ -725,6 +757,17 @@ export abstract class TbMap {
}));
}
+ private createPolyline(actionData: PlaceMapItemActionData): void {
+ this.createItem(actionData, () => this.prepareDrawMode('Line', {
+ startPolyline: actionData.action.mapItemTooltips.startPolyline
+ ? this.ctx.utilsService.customTranslation(actionData.action.mapItemTooltips.startPolyline)
+ : this.ctx.translate.instant(mapItemTooltipsTranslation.startPolyline),
+ finishPolyline: actionData.action.mapItemTooltips.finishPolyline
+ ? this.ctx.utilsService.customTranslation(actionData.action.mapItemTooltips.finishPolyline)
+ : this.ctx.translate.instant(mapItemTooltipsTranslation.finishPolyline),
+ }));
+ }
+
private createItem(actionData: PlaceMapItemActionData, prepareDrawMode: () => void) {
const actionId = 'id' in actionData.action ? actionData.action.id : 'map-button';
if (this.createMapItemActionId === actionId) {
@@ -765,7 +808,7 @@ export abstract class TbMap {
this.createMapItemActionId = actionId;
- const convertLayerToCoordinates = (type: MapItemType, layer: L.Layer): {x: number; y: number} | TbPolygonRawCoordinates | TbCircleData => {
+ const convertLayerToCoordinates = (type: MapItemType, layer: L.Layer): { x: number; y: number } | TbPolygonRawCoordinates | TbCircleData => {
switch (type) {
case MapItemType.marker:
if (layer instanceof L.Marker) {
@@ -792,6 +835,15 @@ export abstract class TbMap {
return this.coordinatesToCircleData(layer.getLatLng(), layer.getRadius());
}
return null;
+ case MapItemType.polyline:
+ if (layer instanceof L.Polyline) {
+ let coordinates: any = layer.getLatLngs();
+ if (coordinates.length === 1) {
+ coordinates = coordinates[0];
+ }
+ return this.coordinatesToPolylineData(coordinates);
+ }
+ return null;
}
}
}
@@ -813,8 +865,8 @@ export abstract class TbMap {
this.editToolbar.close();
}
- private prepareDrawMode(shape: 'Marker' | 'Rectangle' | 'Polygon' | 'Circle', tooltipsTranslation: Record) {
- this.map.pm.setLang('en', { tooltips: tooltipsTranslation }, 'en');
+ private prepareDrawMode(shape: 'Marker' | 'Rectangle' | 'Polygon' | 'Circle' | 'Line', tooltipsTranslation: Record) {
+ this.map.pm.setLang('en', {tooltips: tooltipsTranslation}, 'en');
this.map.pm.enableDraw(shape);
// @ts-ignore
L.DomUtil.addClass(this.map.pm.Draw[shape]._hintMarker.getTooltip()._container, 'tb-place-item-label');
@@ -848,46 +900,46 @@ export abstract class TbMap {
tooltipData.instances = [];
}
$(root)
- .find('a[role="button"]:not(.leaflet-pm-action)')
- .each((_index, element) => {
- let title: string;
- if (element.title) {
- title = element.title;
- $(element).removeAttr('title');
- } else if (element.parentElement.title) {
- title = element.parentElement.title;
- $(element).parent().removeAttr('title');
- }
- const tooltip = $(element).tooltipster(
- {
- content: title,
- theme: 'tooltipster-shadow',
- delay: 10,
- triggerClose: {
- click: true,
- tap: true,
- scroll: true,
- mouseleave: true
- },
- side,
- distance: 2,
- trackOrigin: true,
- functionBefore: (_instance, helper) => {
- if (helper.origin.ariaDisabled === 'true' || helper.origin.parentElement.classList.contains('active')) {
- return false;
- }
- },
- }
- );
- const instance = tooltip.tooltipster('instance');
- tooltipData.instances.push(instance);
- instance.on('destroyed', () => {
- const index = tooltipData.instances.indexOf(instance);
- if (index > -1) {
- tooltipData.instances.splice(index, 1);
+ .find('a[role="button"]:not(.leaflet-pm-action)')
+ .each((_index, element) => {
+ let title: string;
+ if (element.title) {
+ title = element.title;
+ $(element).removeAttr('title');
+ } else if (element.parentElement.title) {
+ title = element.parentElement.title;
+ $(element).parent().removeAttr('title');
}
+ const tooltip = $(element).tooltipster(
+ {
+ content: title,
+ theme: 'tooltipster-shadow',
+ delay: 10,
+ triggerClose: {
+ click: true,
+ tap: true,
+ scroll: true,
+ mouseleave: true
+ },
+ side,
+ distance: 2,
+ trackOrigin: true,
+ functionBefore: (_instance, helper) => {
+ if (helper.origin.ariaDisabled === 'true' || helper.origin.parentElement.classList.contains('active')) {
+ return false;
+ }
+ },
+ }
+ );
+ const instance = tooltip.tooltipster('instance');
+ tooltipData.instances.push(instance);
+ instance.on('destroyed', () => {
+ const index = tooltipData.instances.indexOf(instance);
+ if (index > -1) {
+ tooltipData.instances.splice(index, 1);
+ }
+ });
});
- });
});
}
@@ -899,6 +951,7 @@ export abstract class TbMap {
this.updateTripsAnchors();
this.updateBounds();
this.updateEditButtonsStates();
+
}
private updateTrips(subscription: IWidgetSubscription) {
@@ -943,6 +996,7 @@ export abstract class TbMap {
private updateTripsAppearance() {
this.tripDataLayers.forEach(dl => dl.updateAppearance());
}
+
private updateTripsTime() {
this.tripDataLayers.forEach(dl => dl.updateCurrentTime());
}
@@ -995,8 +1049,7 @@ export abstract class TbMap {
(!this.bounds || !this.bounds.isValid() || (!this.bounds.equals(bounds) || force) && this.settings.fitMapBounds)
&& !mapBounds.contains(bounds)
)
- )
- {
+ ) {
this.bounds = bounds;
if (!this.ignoreUpdateBounds && !this.isPlacingItem) {
this.fitBounds(bounds);
@@ -1023,6 +1076,9 @@ export abstract class TbMap {
if (this.addCircleButton && this.addCircleButton !== this.currentEditButton) {
this.addCircleButton.setDisabled(true);
}
+ if (this.addPolylineButton && this.addPolylineButton !== this.currentEditButton) {
+ this.addPolylineButton.setDisabled(true);
+ }
this.customActionsToolbar?.setDisabled(true);
} else {
if (this.dragModeButton) {
@@ -1040,6 +1096,9 @@ export abstract class TbMap {
if (this.addCircleButton) {
this.addCircleButton.setDisabled(!this.addCircleDataLayers.some(dl => dl.isEnabled() && dl.hasUnplacedItems()));
}
+ if (this.addPolylineButton) {
+ this.addPolylineButton.setDisabled(!this.addPolylineDataLayers.some(dl => dl.isEnabled() && dl.hasUnplacedItems()));
+ }
this.customActionsToolbar?.setDisabled(false);
}
}
@@ -1150,7 +1209,7 @@ export abstract class TbMap {
$event.preventDefault();
$event.stopPropagation();
}
- const { entityId, entityName, entityLabel, entityType } = data.$datasource;
+ const {entityId, entityName, entityLabel, entityType} = data.$datasource;
this.ctx.actionsApi.handleWidgetAction($event, action, {
entityType,
id: entityId
@@ -1219,7 +1278,7 @@ export abstract class TbMap {
}
}
- public saveLocation(data: FormattedData, values: {[key: string]: any}): Observable {
+ public saveLocation(data: FormattedData, values: { [key: string]: any }): Observable {
const datasource = data.$datasource;
let dataKeys = datasource.dataKeys;
if (datasource.latestDataKeys) {
@@ -1329,18 +1388,21 @@ export abstract class TbMap {
}
}
- public abstract locationDataToLatLng(position: {x: number; y: number}): L.LatLng;
+ public abstract locationDataToLatLng(position: { x: number; y: number }): L.LatLng;
- public abstract latLngToLocationData(position: L.LatLng): {x: number; y: number};
+ public abstract latLngToLocationData(position: L.LatLng): { x: number; y: number };
public abstract polygonDataToCoordinates(coordinates: TbPolygonRawCoordinates): TbPolygonRawCoordinates;
public abstract coordinatesToPolygonData(coordinates: TbPolygonCoordinates): TbPolygonRawCoordinates;
+ public abstract polylineDataToCoordinates(coordinates: TbPolylineRawCoordinates): TbPolylineRawCoordinates;
+
+ public abstract coordinatesToPolylineData(coordinates: TbPolylineCoordinates): TbPolylineRawCoordinates;
+
public abstract circleDataToCoordinates(circle: TbCircleData): TbCircleData;
public abstract coordinatesToCircleData(center: L.LatLng, radius: number): TbCircleData;
-
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.html
index bc3ad72e58..fe53ef9f66 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.html
@@ -20,7 +20,7 @@
widgets.input-widgets.no-image
-
![last photo]()
+
}
+ @case (MapItemType.polyline) {
+
+
+ }
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-js.raw b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-js.raw
index cb8c23faee..05e06542a5 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-js.raw
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-js.raw
@@ -79,7 +79,7 @@ function AddEntityDialogController(instance) {
const mapType = widgetContext.mapInstance.type();
attributes.push({key: mapType === 'image' ? 'xPos' : 'latitude', value: additionalParams.coordinates.x});
attributes.push({key: mapType === 'image' ? 'yPos' : 'longitude', value: additionalParams.coordinates.y});
- } else if (mapItemType === 'Rectangle' || mapItemType === 'Polygon') {
+ } else if (mapItemType === 'Rectangle' || mapItemType === 'Polygon' || mapItemType === 'Line' ) {
attributes.push({key: 'perimeter', value: additionalParams.coordinates});
} else if (mapItemType === 'Circle') {
attributes.push({key: 'circle', value: additionalParams.coordinates});
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.html
index 0ca912146c..178c948f43 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.html
@@ -163,6 +163,26 @@
(keyEdit)="editKey('circleKey')"
formControlName="circleKey">
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.ts
index 48854adc44..af653308da 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.ts
@@ -29,7 +29,7 @@ import {
MarkerType,
pathDecoratorSymbols,
pathDecoratorSymbolTranslationMap,
- PolygonsDataLayerSettings,
+ PolygonsDataLayerSettings, PolylinesDataLayerSettings,
ShapeDataLayerSettings, ShapeFillType,
TripsDataLayerSettings,
updateDataKeyToNewDsType
@@ -113,6 +113,8 @@ export class MapDataLayerDialogComponent extends DialogComponent
this.updateValidators()
@@ -291,6 +298,15 @@ export class MapDataLayerDialogComponent extends DialogComponent
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layers.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layers.component.ts
index 747ef21681..cb7e1c79f0 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layers.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layers.component.ts
@@ -104,6 +104,10 @@ export class MapDataLayersComponent implements ControlValueAccessor, OnInit, Val
this.addDataLayerText = 'widgets.maps.data-layer.circle.add-circle';
this.noDataLayersText = 'widgets.maps.data-layer.circle.no-circles';
break;
+ case 'polylines':
+ this.addDataLayerText = 'widgets.maps.data-layer.polyline.add-polylines';
+ this.noDataLayersText = 'widgets.maps.data-layer.polyline.no-polylines';
+ break;
}
this.dataLayersFormGroup = this.fb.group({
dataLayers: [this.fb.array([]), []]
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-settings.component.html
index fe2afa3b19..c32242cc32 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-settings.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-settings.component.html
@@ -45,6 +45,8 @@
{{ 'widgets.maps.overlays.markers' | translate }}
{{ 'widgets.maps.overlays.polygons' | translate }}
{{ 'widgets.maps.overlays.circles' | translate }}
+ //todo translation
+ Polylines
+