From 28a36815b42925ea3c11ff2febb10bccff2bb084 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 27 Jun 2024 18:49:22 +0300 Subject: [PATCH] UI: SCADA symbol editor - show/hide hidden elements. Improve horizontal pipe symbol. --- .../scada_symbols/horizontal-connector.svg | 51 ---- .../system/scada_symbols/horizontal-pipe.svg | 287 ++++++++++++++++++ .../scada_water_system_symbols.json | 2 +- .../widget/lib/scada/scada-symbol.models.ts | 15 +- .../scada-symbol-metadata.component.scss | 3 + .../scada-symbol-editor.component.html | 40 ++- .../scada-symbol-editor.component.scss | 23 +- .../scada-symbol-editor.component.ts | 37 ++- .../scada-symbol-editor.models.ts | 132 +++++--- .../scada-symbol/scada-symbol.component.html | 1 + .../scada-symbol/scada-symbol.component.ts | 2 + .../assets/locale/locale.constant-en_US.json | 2 + 12 files changed, 479 insertions(+), 116 deletions(-) delete mode 100644 application/src/main/data/json/system/scada_symbols/horizontal-connector.svg create mode 100644 application/src/main/data/json/system/scada_symbols/horizontal-pipe.svg diff --git a/application/src/main/data/json/system/scada_symbols/horizontal-connector.svg b/application/src/main/data/json/system/scada_symbols/horizontal-connector.svg deleted file mode 100644 index 267ab0d155..0000000000 --- a/application/src/main/data/json/system/scada_symbols/horizontal-connector.svg +++ /dev/null @@ -1,51 +0,0 @@ - -{ - "title": "Horizontal connector", - "widgetSizeX": 1, - "widgetSizeY": 1, - "tags": [ - { - "tag": "fluid", - "stateRenderFunction": "var flow = ctx.values.flow;\nvar flowDirection = ctx.values.flowDirection;\nvar elementFlow = element.remember('flow');\nvar elementFlowDirection = element.remember('flowDirection');\nif (flow !== elementFlow) {\n element.remember('flow', flow);\n if (flow) {\n element.remember('flowDirection', flowDirection);\n element.show();\n animateFlow(flowDirection);\n } else {\n ctx.api.resetAnimation(element);\n element.hide();\n }\n} else if (flow && elementFlowDirection !== flowDirection) {\n element.remember('flowDirection', flowDirection);\n animateFlow(flowDirection);\n}\n\nfunction animateFlow(forwardElseReverse) {\n ctx.api.resetAnimation(element);\n var deltaX = forwardElseReverse ? 172 : -172;\n element.animate(1000).ease('-').relative(deltaX, 0).loop();\n}", - "actions": null - } - ], - "behavior": [ - { - "id": "flow", - "name": "Flow", - "hint": null, - "type": "value", - "valueType": "BOOLEAN", - "defaultValue": false, - "trueLabel": null, - "falseLabel": null, - "stateLabel": null, - "valueToDataType": "CONSTANT", - "constantValue": false, - "valueToDataFunction": "" - }, - { - "id": "flowDirection", - "name": "Flow direction", - "hint": null, - "type": "value", - "valueType": "BOOLEAN", - "defaultValue": true, - "trueLabel": "Forward", - "falseLabel": "Reverse", - "stateLabel": "Forward", - "valueToDataType": "CONSTANT", - "constantValue": false, - "valueToDataFunction": "" - } - ], - "properties": [] -} - - - - - - - \ No newline at end of file diff --git a/application/src/main/data/json/system/scada_symbols/horizontal-pipe.svg b/application/src/main/data/json/system/scada_symbols/horizontal-pipe.svg new file mode 100644 index 0000000000..6dc82ca4ef --- /dev/null +++ b/application/src/main/data/json/system/scada_symbols/horizontal-pipe.svg @@ -0,0 +1,287 @@ + +{ + "title": "Horizontal pipe", + "widgetSizeX": 1, + "widgetSizeY": 1, + "tags": [ + { + "tag": "fluid", + "stateRenderFunction": "var fluid = ctx.values.fluid && !ctx.values.leak;\nvar flow = ctx.values.flow;\nvar flowDirection = ctx.values.flowDirection;\n\nvar elementFluid = element.remember('fluid');\nvar elementFlow = null;\nvar elementFlowDirection = null;\n\nif (fluid !== elementFluid) {\n element.remember('fluid', fluid);\n elementFlow = null;\n elementFlowDirection = null;\n} else {\n elementFlow = element.remember('flow');\n elementFlowDirection = element.remember('flowDirection');\n}\n\nvar liquidPattern = ctx.svg.defs().findOne('pattern#liquid');\nif (liquidPattern) {\n liquidPattern.id(ctx.api.generateElementId());\n element.fill(liquidPattern);\n} else {\n liquidPattern = element.reference('fill');\n}\n\nif (fluid) {\n element.show();\n if (flow !== elementFlow) {\n element.remember('flow', flow);\n if (flow) {\n element.remember('flowDirection', flowDirection);\n animateFlow(liquidPattern, flowDirection);\n } else {\n if (liquidPattern) {\n ctx.api.resetAnimation(liquidPattern);\n }\n }\n } else if (flow && elementFlowDirection !== flowDirection) {\n element.remember('flowDirection', flowDirection);\n animateFlow(liquidPattern, flowDirection);\n }\n if (flow && liquidPattern) {\n liquidPattern.timeline().speed(ctx.values.flowAnimationSpeed);\n }\n} else {\n if (liquidPattern) {\n ctx.api.resetAnimation(liquidPattern);\n }\n element.hide();\n}\n\nfunction animateFlow(liquidPattern, forwardElseReverse) {\n if (liquidPattern) {\n ctx.api.resetAnimation(liquidPattern);\n var deltaX = forwardElseReverse ? 172 : -172;\n liquidPattern.animate(1000).ease('-').relative(deltaX, 0).loop();\n }\n}", + "actions": null + }, + { + "tag": "fluid-background", + "stateRenderFunction": "var fluid = ctx.values.fluid && !ctx.values.leak;\nif (fluid) {\n var color = ctx.properties.fluidColor;\n element.attr({fill: color});\n element.show();\n} else {\n element.hide();\n}", + "actions": null + }, + { + "tag": "leak", + "stateRenderFunction": "var leak = ctx.values.leak;\nif (leak) {\n element.show();\n} else {\n element.hide();\n}", + "actions": null + } + ], + "behavior": [ + { + "id": "fluid", + "name": "Fluid presence", + "hint": null, + "type": "value", + "valueType": "BOOLEAN", + "defaultValue": false, + "trueLabel": null, + "falseLabel": null, + "stateLabel": null, + "valueToDataType": "CONSTANT", + "constantValue": false, + "valueToDataFunction": "" + }, + { + "id": "flow", + "name": "Flow presence", + "hint": null, + "type": "value", + "valueType": "BOOLEAN", + "defaultValue": false, + "trueLabel": null, + "falseLabel": null, + "stateLabel": null, + "valueToDataType": "CONSTANT", + "constantValue": false, + "valueToDataFunction": "" + }, + { + "id": "flowDirection", + "name": "Flow direction", + "hint": null, + "type": "value", + "valueType": "BOOLEAN", + "defaultValue": true, + "trueLabel": "Forward", + "falseLabel": "Reverse", + "stateLabel": "Forward", + "valueToDataType": "CONSTANT", + "constantValue": false, + "valueToDataFunction": "" + }, + { + "id": "flowAnimationSpeed", + "name": "Flow rate animation speed", + "hint": null, + "type": "value", + "valueType": "DOUBLE", + "defaultValue": 1, + "trueLabel": null, + "falseLabel": null, + "stateLabel": null, + "valueToDataType": "CONSTANT", + "constantValue": false, + "valueToDataFunction": "" + }, + { + "id": "leak", + "name": "Leak", + "hint": null, + "type": "value", + "valueType": "BOOLEAN", + "defaultValue": false, + "trueLabel": null, + "falseLabel": null, + "stateLabel": null, + "valueToDataType": "CONSTANT", + "constantValue": false, + "valueToDataFunction": "" + } + ], + "properties": [ + { + "id": "fluidColor", + "name": "Fluid color", + "type": "color", + "default": "#1EC1F4", + "required": null, + "subLabel": null, + "divider": null, + "fieldSuffix": null, + "disableOnProperty": null, + "rowClass": "", + "fieldClass": "", + "min": null, + "max": null, + "step": null + } + ] +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json b/application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json index 153afd0335..49e42f3f03 100644 --- a/application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json +++ b/application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json @@ -23,7 +23,7 @@ "top_black_counter", "right_bottom_angle_connector", "vertical_connector", - "horizontal_connector", + "horizontal_pipe", "pump_left", "pump" ] diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts index bfc1187f8f..47de450351 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts @@ -28,6 +28,7 @@ import { import { createLabelFromSubscriptionEntityInfo, formatValue, + guid, isDefinedAndNotNull, isUndefinedOrNull, mergeDeep, @@ -44,6 +45,7 @@ import { ResizeObserver } from '@juggle/resize-observer'; import { takeUntil } from 'rxjs/operators'; export interface ScadaSymbolApi { + generateElementId: () => string; formatValue: (value: any, dec?: number, units?: string, showZeroDecimals?: boolean) => string | undefined; text: (element: Element | Element[], text: string) => void; font: (element: Element | Element[], font: Font, color: string) => void; @@ -61,6 +63,7 @@ export interface ScadaSymbolContext { tags: {[id: string]: Element[]}; values: {[id: string]: any}; properties: {[id: string]: any}; + svg: Svg; } export type ScadaSymbolStateRenderFunction = (ctx: ScadaSymbolContext, svg: Svg) => void; @@ -502,6 +505,15 @@ export class ScadaSymbolObject { private init() { this.context = { api: { + generateElementId: () => { + const id = guid(); + const firstChar = id.charAt(0); + if (firstChar >= '0' && firstChar <= '9') { + return 'a' + id; + } else { + return id; + } + }, formatValue, text: this.setElementText.bind(this), font: this.setElementFont.bind(this), @@ -515,7 +527,8 @@ export class ScadaSymbolObject { }, tags: {}, properties: {}, - values: {} + values: {}, + svg: this.svgShape }; const taggedElements = this.svgShape.find(`[tb\\:tag]`); for (const element of taggedElements) { diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.scss b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.scss index c553338969..370984230b 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.scss +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.scss @@ -92,6 +92,9 @@ &-api, &-api-method { color: #7214D0; } + &-svg, &-svg-method { + color: #c24c1a; + } &-properties, &-values, &-tags, &-api { // font-style: italic; // font-weight: bold; diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.html b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.html index 20cc6fb40e..4eaaf6d718 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.html +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.html @@ -20,21 +20,31 @@
-
- - +
+
+ + +
+
+ +
diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.scss b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.scss index 05909caf90..c400a32fef 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.scss +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.scss @@ -35,6 +35,21 @@ justify-content: space-between; align-items: flex-start; + .tb-primary-fill { + background: #fff; + border-radius: 50%; + &:before { + opacity: 0.1; + } + } + + .tb-scada-symbol-editor-view-buttons { + display: flex; + flex-direction: column; + gap: 8px; + z-index: 101; + } + .tb-scada-symbol-editor-zoom-buttons { display: flex; flex-direction: column; @@ -42,6 +57,7 @@ background: #fff; border-radius: 24px; &.tb-primary-fill { + border-radius: 24px; &:before { opacity: 0.1; } @@ -53,13 +69,6 @@ flex-direction: row; gap: 8px; z-index: 101; - .tb-primary-fill { - background: #fff; - border-radius: 50%; - &:before { - opacity: 0.1; - } - } } } diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.ts index 653aa8a9cb..9228c3e561 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.ts @@ -15,19 +15,24 @@ /// import { - AfterViewInit, ChangeDetectorRef, + AfterViewInit, + ChangeDetectorRef, Component, - ElementRef, EventEmitter, + ElementRef, + EventEmitter, Input, OnChanges, OnDestroy, - OnInit, Output, + OnInit, + Output, SimpleChanges, ViewChild, - ViewContainerRef, ViewEncapsulation } from '@angular/core'; -import { ScadaSymbolEditObject, ScadaSymbolEditObjectCallbacks } from '@home/pages/scada-symbol/scada-symbol-editor.models'; +import { + ScadaSymbolEditObject, + ScadaSymbolEditObjectCallbacks +} from '@home/pages/scada-symbol/scada-symbol-editor.models'; import { TbAnchorComponent } from '@shared/components/tb-anchor.component'; export interface ScadaSymbolEditorData { @@ -71,6 +76,14 @@ export class ScadaSymbolEditorComponent implements OnInit, OnDestroy, AfterViewI zoomInDisabled = false; zoomOutDisabled = false; + @Input() + showHiddenElements = false; + + @Output() + showHiddenElementsChange = new EventEmitter(); + + displayShowHidden = false; + constructor(private cd: ChangeDetectorRef) { } @@ -81,6 +94,13 @@ export class ScadaSymbolEditorComponent implements OnInit, OnDestroy, AfterViewI this.editObjectCallbacks.onZoom = () => { this.updateZoomButtonsState(); }; + this.editObjectCallbacks.hasHiddenElements = (hasHidden) => { + this.displayShowHidden = hasHidden; + if (hasHidden) { + this.scadaSymbolEditObject.showHiddenElements(this.showHiddenElements); + } + this.cd.markForCheck(); + }; this.scadaSymbolEditObject = new ScadaSymbolEditObject(this.scadaSymbolShape.nativeElement, this.tooltipsContainer.nativeElement, this.tooltipsContainerComponent.viewContainerRef, this.editObjectCallbacks, this.readonly); @@ -122,7 +142,14 @@ export class ScadaSymbolEditorComponent implements OnInit, OnDestroy, AfterViewI this.scadaSymbolEditObject.zoomOut(); } + toggleShowHidden() { + this.showHiddenElements = !this.showHiddenElements; + this.showHiddenElementsChange.emit(this.showHiddenElements); + this.scadaSymbolEditObject.showHiddenElements(this.showHiddenElements); + } + private updateContent(content: string) { + this.displayShowHidden = false; this.scadaSymbolEditObject.setContent(content); setTimeout(() => { this.updateZoomButtonsState(); diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.models.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.models.ts index 70ecacf43d..5ddec8b1a9 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.models.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.models.ts @@ -52,6 +52,7 @@ export interface ScadaSymbolEditObjectCallbacks { editTagStateRenderFunction: (tag: string) => void; editTagClickAction: (tag: string) => void; tagsUpdated: (tags: string[]) => void; + hasHiddenElements?: (hasHidden: boolean) => void; onSymbolEditObjectDirty: (dirty: boolean) => void; onZoom?: () => void; } @@ -68,6 +69,7 @@ export class ScadaSymbolEditObject { private readonly shapeResize$: ResizeObserver; private performSetup = false; private hoverFilterStyle: Style; + private showHidden = false; public scale = 1; public tags: string[] = []; @@ -95,6 +97,7 @@ export class ScadaSymbolEditObject { this.svgShape.remove(); } this.scale = 1; + this.showHidden = false; const contentData = scadaSymbolContentData(svgContent); this.svgRootNodePart = contentData.svgRootNode; this.svgShape = SVG().svg(contentData.innerSvg); @@ -121,6 +124,7 @@ export class ScadaSymbolEditObject { public getContent(): string { if (this.svgShape) { + this.elements.forEach(e => e.restoreOrigVisibility()); const svgContent = this.svgShape.svg((e: Element) => { if (e.node.hasAttribute('tb:inner')) { return false; @@ -132,6 +136,7 @@ export class ScadaSymbolEditObject { e.attr('svgjs:data', null); } }, false); + this.showHiddenElements(this.showHidden); return `${this.svgRootNodePart}\n${svgContent}\n`; } else { return null; @@ -152,6 +157,11 @@ export class ScadaSymbolEditObject { this.zoomAnimate(level); } + public showHiddenElements(show: boolean) { + this.showHidden = show; + this.elements.forEach(e => show ? e.showInvisible() : e.hideInvisible()); + } + private zoomAnimate(level: number, animationMs = 200) { if (level !== this.svgShape.zoom()) { this.hideTooltips(); @@ -294,15 +304,20 @@ export class ScadaSymbolEditObject { el.init(); } this.updateTags(); + const hasHidden = this.elements.some(e => e.invisible); + if (this.callbacks.hasHiddenElements) { + this.callbacks.hasHiddenElements(hasHidden); + } } - private addElement(e: Element) { + private addElement(e: Element, parentInvisible = false) { if (hasBBox(e)) { - const scadaSymbolElement = new ScadaSymbolElement(this, e); + const invisible = parentInvisible || !e.visible(); + const scadaSymbolElement = new ScadaSymbolElement(this, e, invisible); this.elements.push(scadaSymbolElement); e.children().forEach(child => { if (!(child.type === 'tspan' && e.type === 'text')) { - this.addElement(child); + this.addElement(child, invisible); } }, true); } @@ -444,8 +459,6 @@ export class ScadaSymbolElement { private highlightRect: Rect; private highlightRectTimeline: Timeline; - private elementPlaceholder: Rect; - public tooltip: ITooltipsterInstance; public tag: string; @@ -459,46 +472,38 @@ export class ScadaSymbolElement { private highlighted = false; - public invisible = false; - private tooltipMouseX: number; private tooltipMouseY: number; + private origVisibility = true; + get readonly(): boolean { return this.editObject.readonly; } - get activeElement(): Element { - return this.invisible ? this.elementPlaceholder : this.element; - } - constructor(private editObject: ScadaSymbolEditObject, - public element: Element) { + public element: Element, + public invisible = false) { this.tag = element.attr('tb:tag'); - if (element.visible()) { + this.origVisibility = element.visible(); + if (this.invisible) { + element.show(); + } + this.box = element.rbox(this.editObject.svgShape); +/* if (element.visible()) { this.box = element.rbox(this.editObject.svgShape); + if (parentGroup && parentGroup.invisible) { + this.invisible = true; + } } else { element.show(); this.box = element.rbox(this.editObject.svgShape); element.hide(); this.invisible = true; - } + }*/ } public init() { - if (this.invisible) { - this.elementPlaceholder = this.editObject.svgShape - .rect(this.box.width, this.box.height) - .x(this.box.x) - .y(this.box.y) - .attr({ - 'tb:inner': true, - fill: 'none', - stroke: 'rgba(0, 0, 0, 0.58)', - 'stroke-width': this.unscaled(4), - opacity: 1}); - this.element.after(this.elementPlaceholder); - } if (this.isGroup()) { this.highlightRect = this.editObject.svgShape @@ -517,14 +522,21 @@ export class ScadaSymbolElement { this.highlightRect.timeline(this.highlightRectTimeline); this.highlightRect.hide(); } else { - this.activeElement.addClass('tb-element'); + this.element.addClass('tb-element'); } - this.activeElement.on('mouseenter', (_event) => { + this.element.on('mouseenter', (_event) => { this.highlight(); }); - this.activeElement.on('mouseleave', (_event) => { + this.element.on('mouseleave', (_event) => { this.unhighlight(); }); + if (!this.invisible) { + this.setupTooltips(); + } + this.hideInvisible(); + } + + private setupTooltips() { if (this.hasTag()) { this.createTagTooltip(); } else if (!this.readonly) { @@ -532,6 +544,33 @@ export class ScadaSymbolElement { } } + public showInvisible() { + if (this.invisible) { + this.element.show(); + if (!this.tooltip) { + this.setupTooltips(); + } + } + } + + public hideInvisible() { + if (this.invisible) { + this.element.hide(); + if (this.tooltip) { + this.tooltip.destroy(); + this.tooltip = null; + } + } + } + + public restoreOrigVisibility() { + if (this.origVisibility) { + this.element.show(); + } else { + this.element.hide(); + } + } + public overlappingCenters(otherElement: ScadaSymbolElement): boolean { if (this.isGroup() || otherElement.isGroup()) { return false; @@ -553,7 +592,7 @@ export class ScadaSymbolElement { this.highlightRect.show(); this.highlightRect.animate(300).attr({opacity: 1}); } else { - this.activeElement.addClass('hovered'); + this.element.addClass('hovered'); } if (this.hasTag()) { this.tooltip.reposition(); @@ -571,7 +610,7 @@ export class ScadaSymbolElement { this.highlightRect.hide(); }); } else { - this.activeElement.removeClass('hovered'); + this.element.removeClass('hovered'); } if (this.hasTag() && !this.editing) { $(this.tooltip.elementTooltip()).removeClass('tb-active'); @@ -697,7 +736,7 @@ export class ScadaSymbolElement { } private createTagTooltip() { - const el = $(this.activeElement.node); + const el = $(this.element.node); el.tooltipster( { parent: this.tooltipContainer, @@ -716,7 +755,6 @@ export class ScadaSymbolElement { this.innerTagTooltipPosition(instance, helper, position), functionReady: (_instance, helper) => { const tooltipEl = $(helper.tooltip); - // tooltipEl.detach().appendTo($(this.editObject.tooltipsContainer)); tooltipEl.on('mouseenter', () => { this.highlight(); }); @@ -735,7 +773,7 @@ export class ScadaSymbolElement { } private createAddTagTooltip() { - const el = $(this.activeElement.node); + const el = $(this.element.node); el.tooltipster( { parent: this.tooltipContainer, @@ -919,6 +957,10 @@ const scadaSymbolCtxPropertyHighlightRules: TbHighlightRule[] = [ class: 'scada-symbol-ctx-api', regex: /(?<=ctx\.)(api)\b/ }, + { + class: 'scada-symbol-ctx-svg', + regex: /(?<=ctx\.)(svg)\b/ + }, { class: 'scada-symbol-ctx-property', regex: /(?<=ctx\.properties\.)([a-zA-Z$_\u00a1-\uffff][a-zA-Z\d$_\u00a1-\uffff]*)\b/ @@ -934,6 +976,10 @@ const scadaSymbolCtxPropertyHighlightRules: TbHighlightRule[] = [ { class: 'scada-symbol-ctx-api-method', regex: /(?<=ctx\.api\.)([a-zA-Z$_\u00a1-\uffff][a-zA-Z\d$_\u00a1-\uffff]*)\b/ + }, + { + class: 'scada-symbol-ctx-svg-method', + regex: /(?<=ctx\.svg\.)([a-zA-Z$_\u00a1-\uffff][a-zA-Z\d$_\u00a1-\uffff]*)\b/ } ]; @@ -1074,6 +1120,15 @@ export const scadaSymbolContextCompletion = (metadata: ScadaSymbolMetadata, tags }, ] }, + generateElementId: { + meta: 'function', + description: 'Generates new unique element id.', + args: [], + return: { + type: 'string', + description: 'Newly generated element id.' + } + }, formatValue: { meta: 'function', description: 'Formats numeric value according to specified decimals and units', @@ -1148,7 +1203,12 @@ export const scadaSymbolContextCompletion = (metadata: ScadaSymbolMetadata, tags }, properties, values, - tags: tagsCompletions + tags: tagsCompletions, + svg: { + meta: 'argument', + type: 'SVG.Svg', + description: 'A root svg node. Instance of SVG.Svg.' + } } }; }; diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.html b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.html index 72792c835c..3c613ed7ff 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.html +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.html @@ -120,6 +120,7 @@