diff --git a/application/src/main/data/json/system/scada_symbols/bottom-right-elbow-connector-hp.svg b/application/src/main/data/json/system/scada_symbols/bottom-right-elbow-connector-hp.svg index fa273dc8ec..b76f7399cc 100644 --- a/application/src/main/data/json/system/scada_symbols/bottom-right-elbow-connector-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/bottom-right-elbow-connector-hp.svg @@ -3,7 +3,7 @@ "description": "Bottom right elbow connector", "widgetSizeX": 1, "widgetSizeY": 1, - "stateRenderFunction": "const {\n flowAnimation,\n animationDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst animation = ctx.tags.animationGroup[0];\nconst offset = Date.now() % 1000;\nconst duration = 1 / flowAnimationSpeed;\n\nconst prevFlowAnimation = animation.remember('flowAnimation');\nconst prevFlowDirection = animation.remember('flowDirection');\nconst prevFlowDuration = animation.remember('flowDuration');\n\nif (flowAnimation && flowAnimation !== prevFlowAnimation) {\n animation.remember('flowAnimation', flowAnimation);\n animation.remember('flowDuration', duration);\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && flowDirection !== prevFlowDirection) {\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && duration !== prevFlowDuration) {\n animation.remember('flowDuration', duration);\n animation.findOne('animate').attr('dur', `${duration}s`) ;\n} else if (!flowAnimation && prevFlowAnimation) {\n animation.remember('flowAnimation', null);\n animation.clear();\n}\n\nfunction animateFlow(offset, flowDirection) {\n animation.clear();\n const dashArray = `${dashWidth}${dashGap ? ` ${dashGap}` : ''}`;\n const value = flowDirection ? `-${dashWidth + (dashGap || dashWidth)}` : `${dashWidth + (dashGap || dashWidth)}`;\n\n animation.add(``);\n}\n", + "stateRenderFunction": "const {\n flowAnimation,\n animationDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst lineReversed = 'M 200,100 L 125,100 Q 100,100 100,125 L 100, 200';\nconst animation = ctx.tags.animationGroup[0];\nconst duration = 1 / flowAnimationSpeed;\n\nlet animateFlow = ctx.api.connectorAnimation(animation);\n\nif (flowAnimation) {\n if (!animateFlow) {\n animateFlow = ctx.api.connectorAnimate(animation, line, lineReversed).flowAppearance(lineWidth, lineColor, dashCap, dashWidth, dashGap).duration(duration).direction(flowDirection).play();\n } else {\n animateFlow.duration(duration).direction(flowDirection).play();\n }\n} else {\n if (animateFlow) {\n animateFlow.finish();\n }\n}\n", "tags": [ { "tag": "line", @@ -140,13 +140,14 @@ }, { "id": "mainLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 6, "required": true, "subLabel": "Main", "divider": true, "fieldSuffix": "px", + "condition": "return model.mainLine;", "min": 0, "max": 99, "step": 1, @@ -155,21 +156,23 @@ }, { "id": "secondaryLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 2, "required": true, "subLabel": "Secondary", + "divider": true, "fieldSuffix": "px", + "condition": "return !model.mainLine;", "min": 0, "max": 99, "step": 1, "disabled": false, - "visible": true + "visible": false }, { "id": "lineColor", - "name": "{i18n:scada.symbol.line-color}", + "name": "{i18n:scada.symbol.main-line}", "type": "color", "default": "#1A1A1A", "disabled": false, @@ -182,6 +185,7 @@ "type": "number", "default": 4, "subLabel": "Width", + "divider": true, "fieldSuffix": "px", "min": 1, "step": 1, @@ -200,6 +204,7 @@ { "id": "flowStyleDash", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -215,6 +220,7 @@ { "id": "flowStyleGap", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -250,5 +256,5 @@ } ] }]]> - + \ No newline at end of file diff --git a/application/src/main/data/json/system/scada_symbols/bottom-tee-connector-hp.svg b/application/src/main/data/json/system/scada_symbols/bottom-tee-connector-hp.svg index 2feb95e9ff..28e0788d35 100644 --- a/application/src/main/data/json/system/scada_symbols/bottom-tee-connector-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/bottom-tee-connector-hp.svg @@ -3,7 +3,7 @@ "description": "Bottom tee connector", "widgetSizeX": 1, "widgetSizeY": 1, - "stateRenderFunction": "const {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\n\nconst leftLine = \"M0 100H100\";\nconst rightLine = \"M100 100H200\";\nconst bottomLine = \"M 100,200 V 103\";\n\nprepareFlowAnimation('left', leftLine);\nprepareFlowAnimation('right', rightLine);\nprepareFlowAnimation('bottom', bottomLine);\n\nfunction prepareFlowAnimation(prefix, line) {\n const flowAnimation = ctx.values[prefix + 'Flow'];\n const flowDirection = ctx.values[prefix + 'FlowDirection'];\n const flowAnimationSpeed = ctx.values[prefix + 'FlowAnimationSpeed'];\n\n const animation = ctx.tags[prefix + 'Line'][0];\n const offset = Date.now() % 1000;\n const duration = 1 / flowAnimationSpeed;\n \n const prevFlowAnimation = animation.remember('flowAnimation');\n const prevFlowDirection = animation.remember('flowDirection');\n const prevFlowDuration = animation.remember('flowDuration');\n \n if (flowAnimation && flowAnimation !== prevFlowAnimation) {\n animation.remember('flowAnimation', flowAnimation);\n animation.remember('flowDuration', duration);\n animation.remember('flowDirection', flowDirection);\n animateFlow(animation, offset, flowDirection, duration, line);\n } else if (flowAnimation && flowDirection !== prevFlowDirection) {\n animation.remember('flowDirection', flowDirection);\n animateFlow(animation, offset, flowDirection, duration, line);\n } else if (flowAnimation && duration !== prevFlowDuration) {\n animation.remember('flowDuration', duration);\n animation.findOne('animate').attr('dur', `${duration}s`) ;\n } else if (!flowAnimation && prevFlowAnimation) {\n animation.remember('flowAnimation', null);\n animation.clear();\n }\n}\n\nfunction animateFlow(group, offset, flowDirection, duration, line) {\n group.clear();\n const dashArray = `${dashWidth}${dashGap ? ` ${dashGap}` : ''}`;\n const value = flowDirection ? `${dashWidth + (dashGap || dashWidth)}` : `-${dashWidth + (dashGap || dashWidth)}`;\n\n group.add(``);\n}", + "stateRenderFunction": "const {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\n\nconst leftLine = \"M0 100H100\";\nconst leftLineReversed = \"M 100,100 H 0\";\nconst rightLine = \"M100 100H200\";\nconst rightLineReversed = \"M 200,100 H 100\";\nconst bottomLine = \"M 100,200 V 103\";\nconst bottomLineReversed = \"M 100,103 V 200\";\n\nprepareFlowAnimation('left', leftLine, leftLineReversed);\nprepareFlowAnimation('right', rightLine, rightLineReversed);\nprepareFlowAnimation('bottom', bottomLine, bottomLineReversed);\n\nfunction prepareFlowAnimation(prefix, line, reversedLine) {\n const flowAnimation = ctx.values[prefix + 'Flow'];\n const flowDirection = ctx.values[prefix + 'FlowDirection'];\n const flowAnimationSpeed = ctx.values[prefix + 'FlowAnimationSpeed'];\n\n const animation = ctx.tags[prefix + 'Line'][0];\n const duration = 1 / flowAnimationSpeed;\n \n let animateFlow = ctx.api.connectorAnimation(animation);\n \n if (flowAnimation) {\n if (!animateFlow) {\n animateFlow = ctx.api.connectorAnimate(animation, line, reversedLine).flowAppearance(lineWidth, lineColor, dashCap, dashWidth, dashGap).duration(duration).direction(flowDirection).play();\n } else {\n animateFlow.duration(duration).direction(flowDirection).play();\n }\n } else {\n if (animateFlow) {\n animateFlow.finish();\n }\n }\n}\n", "tags": [ { "tag": "line", @@ -377,13 +377,14 @@ }, { "id": "mainLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 6, "required": true, "subLabel": "Main", "divider": true, "fieldSuffix": "px", + "condition": "return model.mainLine;", "min": 0, "max": 99, "step": 1, @@ -392,21 +393,23 @@ }, { "id": "secondaryLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 2, "required": true, "subLabel": "Secondary", + "divider": true, "fieldSuffix": "px", + "condition": "return !model.mainLine;", "min": 0, "max": 99, "step": 1, "disabled": false, - "visible": true + "visible": false }, { "id": "lineColor", - "name": "{i18n:scada.symbol.line-color}", + "name": "{i18n:scada.symbol.main-line}", "type": "color", "default": "#1A1A1A", "disabled": false, @@ -419,6 +422,7 @@ "type": "number", "default": 4, "subLabel": "Width", + "divider": true, "fieldSuffix": "px", "min": 1, "step": 1, @@ -437,6 +441,7 @@ { "id": "flowStyleDash", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -452,6 +457,7 @@ { "id": "flowStyleGap", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, diff --git a/application/src/main/data/json/system/scada_symbols/cross-connector-hp.svg b/application/src/main/data/json/system/scada_symbols/cross-connector-hp.svg index ab6798b48b..480666a589 100644 --- a/application/src/main/data/json/system/scada_symbols/cross-connector-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/cross-connector-hp.svg @@ -3,7 +3,7 @@ "description": "Cross connector", "widgetSizeX": 1, "widgetSizeY": 1, - "stateRenderFunction": "const {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\n\nconst leftLine = \"M0 100H100\";\nconst topLine = \"M100 97L100 0\";\nconst rightLine = \"M100 100H200\";\nconst bottomLine = \"M 100,200 V 103\";\n\nprepareFlowAnimation('left', leftLine);\nprepareFlowAnimation('top', topLine);\nprepareFlowAnimation('right', rightLine);\nprepareFlowAnimation('bottom', bottomLine);\n\nfunction prepareFlowAnimation(prefix, line) {\n const flowAnimation = ctx.values[prefix + 'Flow'];\n const flowDirection = ctx.values[prefix + 'FlowDirection'];\n const flowAnimationSpeed = ctx.values[prefix + 'FlowAnimationSpeed'];\n\n const animation = ctx.tags[prefix + 'Line'][0];\n const offset = Date.now() % 1000;\n const duration = 1 / flowAnimationSpeed;\n \n const prevFlowAnimation = animation.remember('flowAnimation');\n const prevFlowDirection = animation.remember('flowDirection');\n const prevFlowDuration = animation.remember('flowDuration');\n \n if (flowAnimation && flowAnimation !== prevFlowAnimation) {\n animation.remember('flowAnimation', flowAnimation);\n animation.remember('flowDuration', duration);\n animation.remember('flowDirection', flowDirection);\n animateFlow(animation, offset, flowDirection, duration, line);\n } else if (flowAnimation && flowDirection !== prevFlowDirection) {\n animation.remember('flowDirection', flowDirection);\n animateFlow(animation, offset, flowDirection, duration, line);\n } else if (flowAnimation && duration !== prevFlowDuration) {\n animation.remember('flowDuration', duration);\n animation.findOne('animate').attr('dur', `${duration}s`) ;\n } else if (!flowAnimation && prevFlowAnimation) {\n animation.remember('flowAnimation', null);\n animation.clear();\n }\n}\n\nfunction animateFlow(group, offset, flowDirection, duration, line) {\n group.clear();\n const dashArray = `${dashWidth}${dashGap ? ` ${dashGap}` : ''}`;\n const value = flowDirection ? `${dashWidth + (dashGap || dashWidth)}` : `-${dashWidth + (dashGap || dashWidth)}`;\n\n group.add(``);\n}", + "stateRenderFunction": "const {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\n\nconst leftLine = \"M0 100H100\";\nconst leftLineReversed = \"M 100,100 H 0\";\nconst topLine = \"M100 97L100 0\";\nconst topLineReversed = \"M 100,0 V 97\";\nconst rightLine = \"M100 100H200\";\nconst rightLineReversed = \"M 200,100 H 100\";\nconst bottomLine = \"M 100,200 V 103\";\nconst bottomLineReversed = \"M 100,103 V 200\";\n\nprepareFlowAnimation('left', leftLine, leftLineReversed);\nprepareFlowAnimation('top', topLine, topLineReversed);\nprepareFlowAnimation('right', rightLine, rightLineReversed);\nprepareFlowAnimation('bottom', bottomLine, bottomLineReversed);\n\nfunction prepareFlowAnimation(prefix, line, reversedLine) {\n const flowAnimation = ctx.values[prefix + 'Flow'];\n const flowDirection = ctx.values[prefix + 'FlowDirection'];\n const flowAnimationSpeed = ctx.values[prefix + 'FlowAnimationSpeed'];\n\n const animation = ctx.tags[prefix + 'Line'][0];\n const duration = 1 / flowAnimationSpeed;\n \n let animateFlow = ctx.api.connectorAnimation(animation);\n \n if (flowAnimation) {\n if (!animateFlow) {\n animateFlow = ctx.api.connectorAnimate(animation, line, reversedLine).flowAppearance(lineWidth, lineColor, dashCap, dashWidth, dashGap).duration(duration).direction(flowDirection).play();\n } else {\n animateFlow.duration(duration).direction(flowDirection).play();\n }\n } else {\n if (animateFlow) {\n animateFlow.finish();\n }\n }\n}", "tags": [ { "tag": "line", @@ -493,13 +493,14 @@ }, { "id": "mainLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 6, "required": true, "subLabel": "Main", "divider": true, "fieldSuffix": "px", + "condition": "return model.mainLine;", "min": 0, "max": 99, "step": 1, @@ -508,21 +509,23 @@ }, { "id": "secondaryLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 2, "required": true, "subLabel": "Secondary", + "divider": true, "fieldSuffix": "px", + "condition": "return !model.mainLine;", "min": 0, "max": 99, "step": 1, "disabled": false, - "visible": true + "visible": false }, { "id": "lineColor", - "name": "{i18n:scada.symbol.line-color}", + "name": "{i18n:scada.symbol.main-line}", "type": "color", "default": "#1A1A1A", "disabled": false, @@ -535,6 +538,7 @@ "type": "number", "default": 4, "subLabel": "Width", + "divider": true, "fieldSuffix": "px", "min": 1, "step": 1, @@ -553,6 +557,7 @@ { "id": "flowStyleDash", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -568,6 +573,7 @@ { "id": "flowStyleGap", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, diff --git a/application/src/main/data/json/system/scada_symbols/horizontal-connector-hp.svg b/application/src/main/data/json/system/scada_symbols/horizontal-connector-hp.svg index 74d048e884..230c7b68a5 100644 --- a/application/src/main/data/json/system/scada_symbols/horizontal-connector-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/horizontal-connector-hp.svg @@ -3,7 +3,7 @@ "description": "Horizontal connector with an optional directional arrow to visually indicate flow.", "widgetSizeX": 1, "widgetSizeY": 1, - "stateRenderFunction": "const {\n flowAnimation,\n arrowDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst animation = ctx.tags.animationGroup[0];\nconst offset = Date.now() % 1000;\nconst duration = 1 / flowAnimationSpeed;\n\nconst prevFlowAnimation = animation.remember('flowAnimation');\nconst prevFlowDirection = animation.remember('flowDirection');\nconst prevFlowDuration = animation.remember('flowDuration');\n\nif (flowAnimation && flowAnimation !== prevFlowAnimation) {\n animation.remember('flowAnimation', flowAnimation);\n animation.remember('flowDuration', duration);\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && flowDirection !== prevFlowDirection) {\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && duration !== prevFlowDuration) {\n animation.remember('flowDuration', duration);\n animation.findOne('animate').attr('dur', `${duration}s`) ;\n} else if (!flowAnimation && prevFlowAnimation) {\n animation.remember('flowAnimation', null);\n animation.clear();\n}\n\nfunction animateFlow(offset, flowDirection) {\n animation.clear();\n const dashArray = `${dashWidth}${dashGap ? ` ${dashGap}` : ''}`;\n const value = flowDirection ? `${dashWidth + (dashGap || dashWidth)}` : `-${dashWidth + (dashGap || dashWidth)}`;\n\n animation.add(``);\n}\n", + "stateRenderFunction": "const {\n flowAnimation,\n arrowDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst lineReversed = 'M 200,100 H 0';\nconst animation = ctx.tags.animationGroup[0];\nconst duration = 1 / flowAnimationSpeed;\n\nlet animateFlow = ctx.api.connectorAnimation(animation);\n\nif (flowAnimation) {\n if (!animateFlow) {\n animateFlow = ctx.api.connectorAnimate(animation, line, lineReversed).flowAppearance(lineWidth, lineColor, dashCap, dashWidth, dashGap).duration(duration).direction(flowDirection).play();\n } else {\n animateFlow.duration(duration).direction(flowDirection).play();\n }\n} else {\n if (animateFlow) {\n animateFlow.finish();\n }\n}\n\n", "tags": [ { "tag": "arrow", @@ -176,13 +176,14 @@ }, { "id": "mainLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 6, "required": true, "subLabel": "Main", "divider": true, "fieldSuffix": "px", + "condition": "return model.mainLine;", "min": 0, "max": 99, "step": 1, @@ -191,21 +192,23 @@ }, { "id": "secondaryLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 2, "required": true, "subLabel": "Secondary", + "divider": true, "fieldSuffix": "px", + "condition": "return !model.mainLine;", "min": 0, "max": 99, "step": 1, "disabled": false, - "visible": true + "visible": false }, { "id": "lineColor", - "name": "{i18n:scada.symbol.line-color}", + "name": "{i18n:scada.symbol.main-line}", "type": "color", "default": "#1A1A1A", "disabled": false, @@ -229,11 +232,14 @@ "name": "{i18n:scada.symbol.flow}", "group": "{i18n:scada.symbol.animation}", "type": "color", - "default": "#C8DFF7" + "default": "#C8DFF7", + "disabled": false, + "visible": true }, { "id": "flowStyleDash", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -249,6 +255,7 @@ { "id": "flowStyleGap", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, diff --git a/application/src/main/data/json/system/scada_symbols/left-bottom-elbow-connector-hp.svg b/application/src/main/data/json/system/scada_symbols/left-bottom-elbow-connector-hp.svg index fd14834d12..1dbeec5f92 100644 --- a/application/src/main/data/json/system/scada_symbols/left-bottom-elbow-connector-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/left-bottom-elbow-connector-hp.svg @@ -3,7 +3,7 @@ "description": "Left bottom elbow connector", "widgetSizeX": 1, "widgetSizeY": 1, - "stateRenderFunction": "const {\n flowAnimation,\n animationDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst animation = ctx.tags.animationGroup[0];\nconst offset = Date.now() % 1000;\nconst duration = 1 / flowAnimationSpeed;\n\nconst prevFlowAnimation = animation.remember('flowAnimation');\nconst prevFlowDirection = animation.remember('flowDirection');\nconst prevFlowDuration = animation.remember('flowDuration');\n\nif (flowAnimation && flowAnimation !== prevFlowAnimation) {\n animation.remember('flowAnimation', flowAnimation);\n animation.remember('flowDuration', duration);\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && flowDirection !== prevFlowDirection) {\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && duration !== prevFlowDuration) {\n animation.remember('flowDuration', duration);\n animation.findOne('animate').attr('dur', `${duration}s`) ;\n} else if (!flowAnimation && prevFlowAnimation) {\n animation.remember('flowAnimation', null);\n animation.clear();\n}\n\nfunction animateFlow(offset, flowDirection) {\n animation.clear();\n const dashArray = `${dashWidth}${dashGap ? ` ${dashGap}` : ''}`;\n const value = flowDirection ? `${dashWidth + (dashGap || dashWidth)}` : `-${dashWidth + (dashGap || dashWidth)}`;\n\n animation.add(``);\n}\n", + "stateRenderFunction": "const {\n flowAnimation,\n animationDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst lineReversed = 'M 100,200 L 100,125 Q 100,100 75,100 L 0, 100';\nconst animation = ctx.tags.animationGroup[0];\nconst duration = 1 / flowAnimationSpeed;\n\nlet animateFlow = ctx.api.connectorAnimation(animation);\n\nif (flowAnimation) {\n if (!animateFlow) {\n animateFlow = ctx.api.connectorAnimate(animation, line, lineReversed).flowAppearance(lineWidth, lineColor, dashCap, dashWidth, dashGap).duration(duration).direction(flowDirection).play();\n } else {\n animateFlow.duration(duration).direction(flowDirection).play();\n }\n} else {\n if (animateFlow) {\n animateFlow.finish();\n }\n}\n", "tags": [ { "tag": "line", @@ -140,13 +140,14 @@ }, { "id": "mainLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 6, "required": true, "subLabel": "Main", "divider": true, "fieldSuffix": "px", + "condition": "return model.mainLine;", "min": 0, "max": 99, "step": 1, @@ -155,21 +156,24 @@ }, { "id": "secondaryLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 2, "required": true, "subLabel": "Secondary", + "divider": true, "fieldSuffix": "px", + "disableOnProperty": "mainLine", + "condition": "return !model.mainLine;", "min": 0, "max": 99, "step": 1, "disabled": false, - "visible": true + "visible": false }, { "id": "lineColor", - "name": "{i18n:scada.symbol.line-color}", + "name": "{i18n:scada.symbol.main-line}", "type": "color", "default": "#1A1A1A", "disabled": false, @@ -182,6 +186,7 @@ "type": "number", "default": 4, "subLabel": "Width", + "divider": true, "fieldSuffix": "px", "min": 1, "step": 1, @@ -193,11 +198,14 @@ "name": "{i18n:scada.symbol.flow}", "group": "{i18n:scada.symbol.animation}", "type": "color", - "default": "#C8DFF7" + "default": "#C8DFF7", + "disabled": false, + "visible": true }, { "id": "flowStyleDash", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -213,6 +221,7 @@ { "id": "flowStyleGap", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -248,5 +257,5 @@ } ] }]]> - + \ No newline at end of file diff --git a/application/src/main/data/json/system/scada_symbols/left-tee-connector-hp.svg b/application/src/main/data/json/system/scada_symbols/left-tee-connector-hp.svg index af83a4abb3..82b8babcf7 100644 --- a/application/src/main/data/json/system/scada_symbols/left-tee-connector-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/left-tee-connector-hp.svg @@ -3,7 +3,7 @@ "description": "Left tee connector", "widgetSizeX": 1, "widgetSizeY": 1, - "stateRenderFunction": "const {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\n\nconst leftLine = \"M0 100H97\";\nconst topLine = \"M100 100L100 0\";\nconst bottomLine = \"M 100,200 V 100\";\n\nprepareFlowAnimation('left', leftLine);\nprepareFlowAnimation('top', topLine);\nprepareFlowAnimation('bottom', bottomLine);\n\nfunction prepareFlowAnimation(prefix, line) {\n const flowAnimation = ctx.values[prefix + 'Flow'];\n const flowDirection = ctx.values[prefix + 'FlowDirection'];\n const flowAnimationSpeed = ctx.values[prefix + 'FlowAnimationSpeed'];\n\n const animation = ctx.tags[prefix + 'Line'][0];\n const offset = Date.now() % 1000;\n const duration = 1 / flowAnimationSpeed;\n \n const prevFlowAnimation = animation.remember('flowAnimation');\n const prevFlowDirection = animation.remember('flowDirection');\n const prevFlowDuration = animation.remember('flowDuration');\n \n if (flowAnimation && flowAnimation !== prevFlowAnimation) {\n animation.remember('flowAnimation', flowAnimation);\n animation.remember('flowDuration', duration);\n animation.remember('flowDirection', flowDirection);\n animateFlow(animation, offset, flowDirection, duration, line);\n } else if (flowAnimation && flowDirection !== prevFlowDirection) {\n animation.remember('flowDirection', flowDirection);\n animateFlow(animation, offset, flowDirection, duration, line);\n } else if (flowAnimation && duration !== prevFlowDuration) {\n animation.remember('flowDuration', duration);\n animation.findOne('animate').attr('dur', `${duration}s`) ;\n } else if (!flowAnimation && prevFlowAnimation) {\n animation.remember('flowAnimation', null);\n animation.clear();\n }\n}\n\nfunction animateFlow(group, offset, flowDirection, duration, line) {\n group.clear();\n const dashArray = `${dashWidth}${dashGap ? ` ${dashGap}` : ''}`;\n const value = flowDirection ? `${dashWidth + (dashGap || dashWidth)}` : `-${dashWidth + (dashGap || dashWidth)}`;\n\n group.add(``);\n}", + "stateRenderFunction": "const {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\n\nconst leftLine = \"M0 100H97\";\nconst leftLineReversed = \"M 97,100 H 0\";\nconst topLine = \"M100 100L100 0\";\nconst topLineReversed = \"M 100,0 V 100\";\nconst bottomLine = \"M 100,200 V 100\";\nconst bottomLineReversed = \"M 100,100 V 200\";\n\nprepareFlowAnimation('left', leftLine, leftLineReversed);\nprepareFlowAnimation('top', topLine, topLineReversed);\nprepareFlowAnimation('bottom', bottomLine, bottomLineReversed);\n\nfunction prepareFlowAnimation(prefix, line, reversedLine) {\n const flowAnimation = ctx.values[prefix + 'Flow'];\n const flowDirection = ctx.values[prefix + 'FlowDirection'];\n const flowAnimationSpeed = ctx.values[prefix + 'FlowAnimationSpeed'];\n\n const animation = ctx.tags[prefix + 'Line'][0];\n const duration = 1 / flowAnimationSpeed;\n \n let animateFlow = ctx.api.connectorAnimation(animation);\n \n if (flowAnimation) {\n if (!animateFlow) {\n animateFlow = ctx.api.connectorAnimate(animation, line, reversedLine).flowAppearance(lineWidth, lineColor, dashCap, dashWidth, dashGap).duration(duration).direction(flowDirection).play();\n } else {\n animateFlow.duration(duration).direction(flowDirection).play();\n }\n } else {\n if (animateFlow) {\n animateFlow.finish();\n }\n }\n}", "tags": [ { "tag": "line", @@ -377,13 +377,14 @@ }, { "id": "mainLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 6, "required": true, "subLabel": "Main", "divider": true, "fieldSuffix": "px", + "condition": "return model.mainLine;", "min": 0, "max": 99, "step": 1, @@ -392,21 +393,23 @@ }, { "id": "secondaryLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 2, "required": true, "subLabel": "Secondary", + "divider": true, "fieldSuffix": "px", + "condition": "return !model.mainLine;", "min": 0, "max": 99, "step": 1, "disabled": false, - "visible": true + "visible": false }, { "id": "lineColor", - "name": "{i18n:scada.symbol.line-color}", + "name": "{i18n:scada.symbol.main-line}", "type": "color", "default": "#1A1A1A", "disabled": false, @@ -419,6 +422,7 @@ "type": "number", "default": 4, "subLabel": "Width", + "divider": true, "fieldSuffix": "px", "min": 1, "step": 1, @@ -437,6 +441,7 @@ { "id": "flowStyleDash", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -452,6 +457,7 @@ { "id": "flowStyleGap", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -487,5 +493,5 @@ } ] }]]> - + \ No newline at end of file diff --git a/application/src/main/data/json/system/scada_symbols/left-top-elbow-connector-hp.svg b/application/src/main/data/json/system/scada_symbols/left-top-elbow-connector-hp.svg index 5b6d30ab65..3c811a2372 100644 --- a/application/src/main/data/json/system/scada_symbols/left-top-elbow-connector-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/left-top-elbow-connector-hp.svg @@ -3,7 +3,7 @@ "description": "Left top elbow connector", "widgetSizeX": 1, "widgetSizeY": 1, - "stateRenderFunction": "const {\n flowAnimation,\n animationDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst animation = ctx.tags.animationGroup[0];\nconst offset = Date.now() % 1000;\nconst duration = 1 / flowAnimationSpeed;\n\nconst prevFlowAnimation = animation.remember('flowAnimation');\nconst prevFlowDirection = animation.remember('flowDirection');\nconst prevFlowDuration = animation.remember('flowDuration');\n\nif (flowAnimation && flowAnimation !== prevFlowAnimation) {\n animation.remember('flowAnimation', flowAnimation);\n animation.remember('flowDuration', duration);\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && flowDirection !== prevFlowDirection) {\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && duration !== prevFlowDuration) {\n animation.remember('flowDuration', duration);\n animation.findOne('animate').attr('dur', `${duration}s`) ;\n} else if (!flowAnimation && prevFlowAnimation) {\n animation.remember('flowAnimation', null);\n animation.clear();\n}\n\nfunction animateFlow(offset, flowDirection) {\n animation.clear();\n const dashArray = `${dashWidth}${dashGap ? ` ${dashGap}` : ''}`;\n const value = flowDirection ? `${dashWidth + (dashGap || dashWidth)}` : `-${dashWidth + (dashGap || dashWidth)}`;\n\n animation.add(``);\n}\n", + "stateRenderFunction": "const {\n flowAnimation,\n animationDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst lineReversed = 'M 100,0 L 100,75 Q 100,100 75,100 L 0, 100';\nconst animation = ctx.tags.animationGroup[0];\nconst duration = 1 / flowAnimationSpeed;\n\nlet animateFlow = ctx.api.connectorAnimation(animation);\n\nif (flowAnimation) {\n if (!animateFlow) {\n animateFlow = ctx.api.connectorAnimate(animation, line, lineReversed).flowAppearance(lineWidth, lineColor, dashCap, dashWidth, dashGap).duration(duration).direction(flowDirection).play();\n } else {\n animateFlow.duration(duration).direction(flowDirection).play();\n }\n} else {\n if (animateFlow) {\n animateFlow.finish();\n }\n}\n", "tags": [ { "tag": "line", @@ -140,13 +140,14 @@ }, { "id": "mainLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 6, "required": true, "subLabel": "Main", "divider": true, "fieldSuffix": "px", + "condition": "return model.mainLine;", "min": 0, "max": 99, "step": 1, @@ -155,21 +156,23 @@ }, { "id": "secondaryLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 2, "required": true, "subLabel": "Secondary", + "divider": true, "fieldSuffix": "px", + "condition": "return !model.mainLine;", "min": 0, "max": 99, "step": 1, "disabled": false, - "visible": true + "visible": false }, { "id": "lineColor", - "name": "{i18n:scada.symbol.line-color}", + "name": "{i18n:scada.symbol.main-line}", "type": "color", "default": "#1A1A1A", "disabled": false, @@ -182,6 +185,7 @@ "type": "number", "default": 4, "subLabel": "Width", + "divider": true, "fieldSuffix": "px", "min": 1, "step": 1, @@ -200,6 +204,7 @@ { "id": "flowStyleDash", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -215,6 +220,7 @@ { "id": "flowStyleGap", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -250,5 +256,5 @@ } ] }]]> - + \ No newline at end of file diff --git a/application/src/main/data/json/system/scada_symbols/long-horizontal-connector-hp.svg b/application/src/main/data/json/system/scada_symbols/long-horizontal-connector-hp.svg index 3e65bd6b04..3a3296544d 100644 --- a/application/src/main/data/json/system/scada_symbols/long-horizontal-connector-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/long-horizontal-connector-hp.svg @@ -1,10 +1,9 @@ - - { +<svg xmlns="http://www.w3.org/2000/svg" xmlns:tb="https://thingsboard.io/svg" width="400" height="200" fill="none" version="1.1" viewBox="0 0 400 200"><tb:metadata xmlns=""><![CDATA[{ "title": "HP Long horizontal connector", "description": "Long horizontal connector with an optional directional arrow to visually indicate flow.", "widgetSizeX": 2, "widgetSizeY": 1, - "stateRenderFunction": "const {\n flowAnimation,\n arrowDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst animation = ctx.tags.animationGroup[0];\nconst offset = Date.now() % 1000;\nconst duration = 1 / flowAnimationSpeed;\n\nconst prevFlowAnimation = animation.remember('flowAnimation');\nconst prevFlowDirection = animation.remember('flowDirection');\nconst prevFlowDuration = animation.remember('flowDuration');\n\nif (flowAnimation && flowAnimation !== prevFlowAnimation) {\n animation.remember('flowAnimation', flowAnimation);\n animation.remember('flowDuration', duration);\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && flowDirection !== prevFlowDirection) {\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && duration !== prevFlowDuration) {\n animation.remember('flowDuration', duration);\n animation.findOne('animate').attr('dur', `${duration}s`) ;\n} else if (!flowAnimation && prevFlowAnimation) {\n animation.remember('flowAnimation', null);\n animation.clear();\n}\n\nfunction animateFlow(offset, flowDirection) {\n animation.clear();\n const dashArray = `${dashWidth}${dashGap ? ` ${dashGap}` : ''}`;\n const value = flowDirection ? `${dashWidth + (dashGap || dashWidth)}` : `-${dashWidth + (dashGap || dashWidth)}`;\n\n animation.add(`<path style=\"stroke-dasharray: ${dashArray}; stroke-linecap: ${dashCap}; stroke-dashoffset: 0;\" d=\"${line}\" stroke-miterlimit=\"10\" fill=\"none\" stroke=\"${lineColor}\" stroke-width=\"${lineWidth}\"><animate attributeName=\"stroke-dashoffset\" values=\"${value};0\" dur=\"${duration}s\" begin=\"-${offset}ms\" calcMode=\"linear\" repeatCount=\"indefinite\" /></path>`);\n}\n", + "stateRenderFunction": "const {\n flowAnimation,\n arrowDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst lineReversed = 'M 400,100 H 0';\nconst animation = ctx.tags.animationGroup[0];\nconst duration = 1 / flowAnimationSpeed;\n\nlet animateFlow = ctx.api.connectorAnimation(animation);\n\nif (flowAnimation) {\n if (!animateFlow) {\n animateFlow = ctx.api.connectorAnimate(animation, line, lineReversed).flowAppearance(lineWidth, lineColor, dashCap, dashWidth, dashGap).duration(duration).direction(flowDirection).play();\n } else {\n animateFlow.duration(duration).direction(flowDirection).play();\n }\n} else {\n if (animateFlow) {\n animateFlow.finish();\n }\n}\n", "tags": [ { "tag": "arrow", @@ -177,27 +176,30 @@ }, { "id": "mainLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 6, "required": true, "subLabel": "Main", "divider": true, "fieldSuffix": "px", + "condition": "return model.mainLine;", "min": 0, "max": 99, "step": 1, "disabled": false, - "visible": true + "visible": false }, { "id": "secondaryLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 2, "required": true, "subLabel": "Secondary", + "divider": true, "fieldSuffix": "px", + "condition": "return !model.mainLine;", "min": 0, "max": 99, "step": 1, @@ -206,7 +208,7 @@ }, { "id": "lineColor", - "name": "{i18n:scada.symbol.line-color}", + "name": "{i18n:scada.symbol.main-line}", "type": "color", "default": "#1A1A1A", "disabled": false, @@ -219,6 +221,7 @@ "type": "number", "default": 4, "subLabel": "Width", + "divider": true, "fieldSuffix": "px", "min": 1, "step": 1, @@ -230,11 +233,14 @@ "name": "{i18n:scada.symbol.flow}", "group": "{i18n:scada.symbol.animation}", "type": "color", - "default": "#C8DFF7" + "default": "#C8DFF7", + "disabled": false, + "visible": true }, { "id": "flowStyleDash", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -250,6 +256,7 @@ { "id": "flowStyleGap", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -285,5 +292,5 @@ } ] } - + \ No newline at end of file diff --git a/application/src/main/data/json/system/scada_symbols/long-vertical-connector-hp.svg b/application/src/main/data/json/system/scada_symbols/long-vertical-connector-hp.svg index b5c9730842..e66fd62c2e 100644 --- a/application/src/main/data/json/system/scada_symbols/long-vertical-connector-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/long-vertical-connector-hp.svg @@ -3,7 +3,7 @@ "description": "Long vertical connector with an optional directional arrow to visually indicate flow.", "widgetSizeX": 1, "widgetSizeY": 2, - "stateRenderFunction": "const {\n flowAnimation,\n arrowDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst animation = ctx.tags.animationGroup[0];\nconst offset = Date.now() % 1000;\nconst duration = 1 / flowAnimationSpeed;\n\nconst prevFlowAnimation = animation.remember('flowAnimation');\nconst prevFlowDirection = animation.remember('flowDirection');\nconst prevFlowDuration = animation.remember('flowDuration');\n\nif (flowAnimation && flowAnimation !== prevFlowAnimation) {\n animation.remember('flowAnimation', flowAnimation);\n animation.remember('flowDuration', duration);\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && flowDirection !== prevFlowDirection) {\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && duration !== prevFlowDuration) {\n animation.remember('flowDuration', duration);\n animation.findOne('animate').attr('dur', `${duration}s`) ;\n} else if (!flowAnimation && prevFlowAnimation) {\n animation.remember('flowAnimation', null);\n animation.clear();\n}\n\nfunction animateFlow(offset, flowDirection) {\n animation.clear();\n const dashArray = `${dashWidth}${dashGap ? ` ${dashGap}` : ''}`;\n const value = flowDirection ? `${dashWidth + (dashGap || dashWidth)}` : `-${dashWidth + (dashGap || dashWidth)}`;\n\n animation.add(``);\n}\n", + "stateRenderFunction": "const {\n flowAnimation,\n arrowDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst lineReversed = 'M 100,0 V 400';\nconst animation = ctx.tags.animationGroup[0];\nconst duration = 1 / flowAnimationSpeed;\n\nlet animateFlow = ctx.api.connectorAnimation(animation);\n\nif (flowAnimation) {\n if (!animateFlow) {\n animateFlow = ctx.api.connectorAnimate(animation, line, lineReversed).flowAppearance(lineWidth, lineColor, dashCap, dashWidth, dashGap).duration(duration).direction(flowDirection).play();\n } else {\n animateFlow.duration(duration).direction(flowDirection).play();\n }\n} else {\n if (animateFlow) {\n animateFlow.finish();\n }\n}\n\n", "tags": [ { "tag": "arrow", @@ -176,13 +176,14 @@ }, { "id": "mainLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 6, "required": true, "subLabel": "Main", "divider": true, "fieldSuffix": "px", + "condition": "return model.mainLine;", "min": 0, "max": 99, "step": 1, @@ -191,21 +192,23 @@ }, { "id": "secondaryLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 2, "required": true, "subLabel": "Secondary", + "divider": true, "fieldSuffix": "px", + "condition": "return !model.mainLine;", "min": 0, "max": 99, "step": 1, "disabled": false, - "visible": true + "visible": false }, { "id": "lineColor", - "name": "{i18n:scada.symbol.line-color}", + "name": "{i18n:scada.symbol.main-line}", "type": "color", "default": "#1A1A1A", "disabled": false, @@ -218,6 +221,7 @@ "type": "number", "default": 4, "subLabel": "Width", + "divider": true, "fieldSuffix": "px", "min": 1, "step": 1, @@ -229,11 +233,14 @@ "name": "{i18n:scada.symbol.flow}", "group": "{i18n:scada.symbol.animation}", "type": "color", - "default": "#C8DFF7" + "default": "#C8DFF7", + "disabled": false, + "visible": true }, { "id": "flowStyleDash", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -249,6 +256,7 @@ { "id": "flowStyleGap", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -284,5 +292,5 @@ } ] }]]> - + \ No newline at end of file diff --git a/application/src/main/data/json/system/scada_symbols/right-tee-connector-hp.svg b/application/src/main/data/json/system/scada_symbols/right-tee-connector-hp.svg index 62aecb065d..e40936c152 100644 --- a/application/src/main/data/json/system/scada_symbols/right-tee-connector-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/right-tee-connector-hp.svg @@ -3,7 +3,7 @@ "description": "Right tee connector", "widgetSizeX": 1, "widgetSizeY": 1, - "stateRenderFunction": "const {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\n\nconst topLine = \"M100 100L100 0\";\nconst rightLine = \"M103 100H200\";\nconst bottomLine = \"M 100,200 V 100\";\n\nprepareFlowAnimation('top', topLine);\nprepareFlowAnimation('right', rightLine);\nprepareFlowAnimation('bottom', bottomLine);\n\nfunction prepareFlowAnimation(prefix, line) {\n const flowAnimation = ctx.values[prefix + 'Flow'];\n const flowDirection = ctx.values[prefix + 'FlowDirection'];\n const flowAnimationSpeed = ctx.values[prefix + 'FlowAnimationSpeed'];\n\n const animation = ctx.tags[prefix + 'Line'][0];\n const offset = Date.now() % 1000;\n const duration = 1 / flowAnimationSpeed;\n \n const prevFlowAnimation = animation.remember('flowAnimation');\n const prevFlowDirection = animation.remember('flowDirection');\n const prevFlowDuration = animation.remember('flowDuration');\n \n if (flowAnimation && flowAnimation !== prevFlowAnimation) {\n animation.remember('flowAnimation', flowAnimation);\n animation.remember('flowDuration', duration);\n animation.remember('flowDirection', flowDirection);\n animateFlow(animation, offset, flowDirection, duration, line);\n } else if (flowAnimation && flowDirection !== prevFlowDirection) {\n animation.remember('flowDirection', flowDirection);\n animateFlow(animation, offset, flowDirection, duration, line);\n } else if (flowAnimation && duration !== prevFlowDuration) {\n animation.remember('flowDuration', duration);\n animation.findOne('animate').attr('dur', `${duration}s`) ;\n } else if (!flowAnimation && prevFlowAnimation) {\n animation.remember('flowAnimation', null);\n animation.clear();\n }\n}\n\nfunction animateFlow(group, offset, flowDirection, duration, line) {\n group.clear();\n const dashArray = `${dashWidth}${dashGap ? ` ${dashGap}` : ''}`;\n const value = flowDirection ? `${dashWidth + (dashGap || dashWidth)}` : `-${dashWidth + (dashGap || dashWidth)}`;\n\n group.add(``);\n}", + "stateRenderFunction": "const {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\n\nconst topLine = \"M100 100L100 0\";\nconst topLineReversed = \"M 100,0 V 100\";\nconst rightLine = \"M103 100H200\";\nconst rightLineReversed = \"M 200,100 H 103\";\nconst bottomLine = \"M 100,200 V 100\";\nconst bottomLineReversed = \"M 100,100 V 200\";\n\nprepareFlowAnimation('top', topLine, topLineReversed);\nprepareFlowAnimation('right', rightLine, rightLineReversed);\nprepareFlowAnimation('bottom', bottomLine, bottomLineReversed);\n\nfunction prepareFlowAnimation(prefix, line, reversedLine) {\n const flowAnimation = ctx.values[prefix + 'Flow'];\n const flowDirection = ctx.values[prefix + 'FlowDirection'];\n const flowAnimationSpeed = ctx.values[prefix + 'FlowAnimationSpeed'];\n\n const animation = ctx.tags[prefix + 'Line'][0];\n const duration = 1 / flowAnimationSpeed;\n \n let animateFlow = ctx.api.connectorAnimation(animation);\n \n if (flowAnimation) {\n if (!animateFlow) {\n animateFlow = ctx.api.connectorAnimate(animation, line, reversedLine).flowAppearance(lineWidth, lineColor, dashCap, dashWidth, dashGap).duration(duration).direction(flowDirection).play();\n } else {\n animateFlow.duration(duration).direction(flowDirection).play();\n }\n } else {\n if (animateFlow) {\n animateFlow.finish();\n }\n }\n}", "tags": [ { "tag": "line", @@ -377,13 +377,14 @@ }, { "id": "mainLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 6, "required": true, "subLabel": "Main", "divider": true, "fieldSuffix": "px", + "condition": "return model.mainLine;", "min": 0, "max": 99, "step": 1, @@ -392,21 +393,23 @@ }, { "id": "secondaryLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 2, "required": true, "subLabel": "Secondary", + "divider": true, "fieldSuffix": "px", + "condition": "return !model.mainLine;", "min": 0, "max": 99, "step": 1, "disabled": false, - "visible": true + "visible": false }, { "id": "lineColor", - "name": "{i18n:scada.symbol.line-color}", + "name": "{i18n:scada.symbol.main-line}", "type": "color", "default": "#1A1A1A", "disabled": false, @@ -419,6 +422,7 @@ "type": "number", "default": 4, "subLabel": "Width", + "divider": true, "fieldSuffix": "px", "min": 1, "step": 1, @@ -437,6 +441,7 @@ { "id": "flowStyleDash", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -452,6 +457,7 @@ { "id": "flowStyleGap", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, diff --git a/application/src/main/data/json/system/scada_symbols/top-right-elbow-connector-hp.svg b/application/src/main/data/json/system/scada_symbols/top-right-elbow-connector-hp.svg index 8ec4e3cc65..8c5224c9f8 100644 --- a/application/src/main/data/json/system/scada_symbols/top-right-elbow-connector-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/top-right-elbow-connector-hp.svg @@ -3,7 +3,7 @@ "description": "Top right elbow connector", "widgetSizeX": 1, "widgetSizeY": 1, - "stateRenderFunction": "const {\n flowAnimation,\n animationDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst animation = ctx.tags.animationGroup[0];\nconst offset = Date.now() % 1000;\nconst duration = 1 / flowAnimationSpeed;\n\nconst prevFlowAnimation = animation.remember('flowAnimation');\nconst prevFlowDirection = animation.remember('flowDirection');\nconst prevFlowDuration = animation.remember('flowDuration');\n\nif (flowAnimation && flowAnimation !== prevFlowAnimation) {\n animation.remember('flowAnimation', flowAnimation);\n animation.remember('flowDuration', duration);\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && flowDirection !== prevFlowDirection) {\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && duration !== prevFlowDuration) {\n animation.remember('flowDuration', duration);\n animation.findOne('animate').attr('dur', `${duration}s`) ;\n} else if (!flowAnimation && prevFlowAnimation) {\n animation.remember('flowAnimation', null);\n animation.clear();\n}\n\nfunction animateFlow(offset, flowDirection) {\n animation.clear();\n const dashArray = `${dashWidth}${dashGap ? ` ${dashGap}` : ''}`;\n const value = flowDirection ? `-${dashWidth + (dashGap || dashWidth)}` : `${dashWidth + (dashGap || dashWidth)}`;\n\n animation.add(``);\n}\n", + "stateRenderFunction": "const {\n flowAnimation,\n animationDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst lineReversed = 'M 200,100 L 125,100 Q 100,100 100,75 L 100, 0';\nconst animation = ctx.tags.animationGroup[0];\nconst duration = 1 / flowAnimationSpeed;\n\nlet animateFlow = ctx.api.connectorAnimation(animation);\n\nif (flowAnimation) {\n if (!animateFlow) {\n animateFlow = ctx.api.connectorAnimate(animation, line, lineReversed).flowAppearance(lineWidth, lineColor, dashCap, dashWidth, dashGap).duration(duration).direction(flowDirection).play();\n } else {\n animateFlow.duration(duration).direction(flowDirection).play();\n }\n} else {\n if (animateFlow) {\n animateFlow.finish();\n }\n}\n", "tags": [ { "tag": "line", @@ -140,13 +140,14 @@ }, { "id": "mainLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 6, "required": true, "subLabel": "Main", "divider": true, "fieldSuffix": "px", + "condition": "return model.mainLine;", "min": 0, "max": 99, "step": 1, @@ -155,21 +156,23 @@ }, { "id": "secondaryLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 2, "required": true, "subLabel": "Secondary", + "divider": true, "fieldSuffix": "px", + "condition": "return !model.mainLine;", "min": 0, "max": 99, "step": 1, "disabled": false, - "visible": true + "visible": false }, { "id": "lineColor", - "name": "{i18n:scada.symbol.line-color}", + "name": "{i18n:scada.symbol.main-line}", "type": "color", "default": "#1A1A1A", "disabled": false, @@ -182,6 +185,7 @@ "type": "number", "default": 4, "subLabel": "Width", + "divider": true, "fieldSuffix": "px", "min": 1, "step": 1, @@ -200,6 +204,7 @@ { "id": "flowStyleDash", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -215,6 +220,7 @@ { "id": "flowStyleGap", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -250,5 +256,5 @@ } ] }]]> - + \ No newline at end of file diff --git a/application/src/main/data/json/system/scada_symbols/top-tee-connector-hp.svg b/application/src/main/data/json/system/scada_symbols/top-tee-connector-hp.svg index e4561a8347..101799fd4b 100644 --- a/application/src/main/data/json/system/scada_symbols/top-tee-connector-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/top-tee-connector-hp.svg @@ -3,7 +3,7 @@ "description": "Top tee connector", "widgetSizeX": 1, "widgetSizeY": 1, - "stateRenderFunction": "const {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\n\nconst leftLine = \"M0 100H100\";\nconst topLine = \"M100 97L100 0\";\nconst rightLine = \"M100 100H200\";\n\nprepareFlowAnimation('left', leftLine);\nprepareFlowAnimation('top', topLine);\nprepareFlowAnimation('right', rightLine);\n\nfunction prepareFlowAnimation(prefix, line) {\n const flowAnimation = ctx.values[prefix + 'Flow'];\n const flowDirection = ctx.values[prefix + 'FlowDirection'];\n const flowAnimationSpeed = ctx.values[prefix + 'FlowAnimationSpeed'];\n\n const animation = ctx.tags[prefix + 'Line'][0];\n const offset = Date.now() % 1000;\n const duration = 1 / flowAnimationSpeed;\n \n const prevFlowAnimation = animation.remember('flowAnimation');\n const prevFlowDirection = animation.remember('flowDirection');\n const prevFlowDuration = animation.remember('flowDuration');\n \n if (flowAnimation && flowAnimation !== prevFlowAnimation) {\n animation.remember('flowAnimation', flowAnimation);\n animation.remember('flowDuration', duration);\n animation.remember('flowDirection', flowDirection);\n animateFlow(animation, offset, flowDirection, duration, line);\n } else if (flowAnimation && flowDirection !== prevFlowDirection) {\n animation.remember('flowDirection', flowDirection);\n animateFlow(animation, offset, flowDirection, duration, line);\n } else if (flowAnimation && duration !== prevFlowDuration) {\n animation.remember('flowDuration', duration);\n animation.findOne('animate').attr('dur', `${duration}s`) ;\n } else if (!flowAnimation && prevFlowAnimation) {\n animation.remember('flowAnimation', null);\n animation.clear();\n }\n}\n\nfunction animateFlow(group, offset, flowDirection, duration, line) {\n group.clear();\n const dashArray = `${dashWidth}${dashGap ? ` ${dashGap}` : ''}`;\n const value = flowDirection ? `${dashWidth + (dashGap || dashWidth)}` : `-${dashWidth + (dashGap || dashWidth)}`;\n\n group.add(``);\n}", + "stateRenderFunction": "const {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\n\nconst leftLine = \"M0 100H100\";\nconst leftLineReversed = \"M 100,100 H 0\";\nconst topLine = \"M100 97L100 0\";\nconst topLineReversed = \"M 100,0 V 97\";\nconst rightLine = \"M100 100H200\";\nconst rightLineReversed = \"M 200,100 H 100\";\n\nprepareFlowAnimation('left', leftLine, leftLineReversed);\nprepareFlowAnimation('top', topLine, topLineReversed);\nprepareFlowAnimation('right', rightLine, rightLineReversed);\n\nfunction prepareFlowAnimation(prefix, line, reversedLine) {\n const flowAnimation = ctx.values[prefix + 'Flow'];\n const flowDirection = ctx.values[prefix + 'FlowDirection'];\n const flowAnimationSpeed = ctx.values[prefix + 'FlowAnimationSpeed'];\n\n const animation = ctx.tags[prefix + 'Line'][0];\n const duration = 1 / flowAnimationSpeed;\n \n let animateFlow = ctx.api.connectorAnimation(animation);\n \n if (flowAnimation) {\n if (!animateFlow) {\n animateFlow = ctx.api.connectorAnimate(animation, line, reversedLine).flowAppearance(lineWidth, lineColor, dashCap, dashWidth, dashGap).duration(duration).direction(flowDirection).play();\n } else {\n animateFlow.duration(duration).direction(flowDirection).play();\n }\n } else {\n if (animateFlow) {\n animateFlow.finish();\n }\n }\n}", "tags": [ { "tag": "line", @@ -377,13 +377,14 @@ }, { "id": "mainLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 6, "required": true, "subLabel": "Main", "divider": true, "fieldSuffix": "px", + "condition": "return model.mainLine;", "min": 0, "max": 99, "step": 1, @@ -392,21 +393,23 @@ }, { "id": "secondaryLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 2, "required": true, "subLabel": "Secondary", + "divider": true, "fieldSuffix": "px", + "condition": "return !model.mainLine;", "min": 0, "max": 99, "step": 1, "disabled": false, - "visible": true + "visible": false }, { "id": "lineColor", - "name": "{i18n:scada.symbol.line-color}", + "name": "{i18n:scada.symbol.main-line}", "type": "color", "default": "#1A1A1A", "disabled": false, @@ -419,6 +422,7 @@ "type": "number", "default": 4, "subLabel": "Width", + "divider": true, "fieldSuffix": "px", "min": 1, "step": 1, @@ -437,6 +441,7 @@ { "id": "flowStyleDash", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -452,6 +457,7 @@ { "id": "flowStyleGap", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, diff --git a/application/src/main/data/json/system/scada_symbols/vertical-connector-hp.svg b/application/src/main/data/json/system/scada_symbols/vertical-connector-hp.svg index cfaf6793ea..698a910f8d 100644 --- a/application/src/main/data/json/system/scada_symbols/vertical-connector-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/vertical-connector-hp.svg @@ -3,7 +3,7 @@ "description": "Vertical connector with an optional directional arrow to visually indicate flow.", "widgetSizeX": 1, "widgetSizeY": 1, - "stateRenderFunction": "const {\n flowAnimation,\n arrowDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst animation = ctx.tags.animationGroup[0];\nconst offset = Date.now() % 1000;\nconst duration = 1 / flowAnimationSpeed;\n\nconst prevFlowAnimation = animation.remember('flowAnimation');\nconst prevFlowDirection = animation.remember('flowDirection');\nconst prevFlowDuration = animation.remember('flowDuration');\n\nif (flowAnimation && flowAnimation !== prevFlowAnimation) {\n animation.remember('flowAnimation', flowAnimation);\n animation.remember('flowDuration', duration);\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && flowDirection !== prevFlowDirection) {\n animation.remember('flowDirection', flowDirection);\n animateFlow(offset, flowDirection);\n} else if (flowAnimation && duration !== prevFlowDuration) {\n animation.remember('flowDuration', duration);\n animation.findOne('animate').attr('dur', `${duration}s`) ;\n} else if (!flowAnimation && prevFlowAnimation) {\n animation.remember('flowAnimation', null);\n animation.clear();\n}\n\nfunction animateFlow(offset, flowDirection) {\n animation.clear();\n const dashArray = `${dashWidth}${dashGap ? ` ${dashGap}` : ''}`;\n const value = flowDirection ? `${dashWidth + (dashGap || dashWidth)}` : `-${dashWidth + (dashGap || dashWidth)}`;\n\n animation.add(``);\n}\n", + "stateRenderFunction": "const {\n flowAnimation,\n arrowDirection: flowDirection,\n flowAnimationSpeed\n} = ctx.values;\nconst {\n flowAnimationWidth: lineWidth,\n flowAnimationColor: lineColor,\n flowStyleDash: dashWidth,\n flowStyleGap: dashGap,\n flowDashCap: dashCap\n} = ctx.properties;\nconst line = ctx.tags.line[0].attr('d');\nconst lineReversed = 'M 100,0 V 200';\nconst animation = ctx.tags.animationGroup[0];\nconst duration = 1 / flowAnimationSpeed;\n\nlet animateFlow = ctx.api.connectorAnimation(animation);\n\nif (flowAnimation) {\n if (!animateFlow) {\n animateFlow = ctx.api.connectorAnimate(animation, line, lineReversed).flowAppearance(lineWidth, lineColor, dashCap, dashWidth, dashGap).duration(duration).direction(flowDirection).play();\n } else {\n animateFlow.duration(duration).direction(flowDirection).play();\n }\n} else {\n if (animateFlow) {\n animateFlow.finish();\n }\n}\n", "tags": [ { "tag": "arrow", @@ -176,13 +176,14 @@ }, { "id": "mainLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 6, "required": true, "subLabel": "Main", "divider": true, "fieldSuffix": "px", + "condition": "return model.mainLine;", "min": 0, "max": 99, "step": 1, @@ -191,21 +192,23 @@ }, { "id": "secondaryLineSize", - "name": "{i18n:scada.symbol.line}", + "name": "{i18n:scada.symbol.main-line}", "type": "number", "default": 2, "required": true, "subLabel": "Secondary", + "divider": true, "fieldSuffix": "px", + "condition": "return !model.mainLine;", "min": 0, "max": 99, "step": 1, "disabled": false, - "visible": true + "visible": false }, { "id": "lineColor", - "name": "{i18n:scada.symbol.line-color}", + "name": "{i18n:scada.symbol.main-line}", "type": "color", "default": "#1A1A1A", "disabled": false, @@ -218,6 +221,7 @@ "type": "number", "default": 4, "subLabel": "Width", + "divider": true, "fieldSuffix": "px", "min": 1, "step": 1, @@ -229,11 +233,14 @@ "name": "{i18n:scada.symbol.flow}", "group": "{i18n:scada.symbol.animation}", "type": "color", - "default": "#C8DFF7" + "default": "#C8DFF7", + "disabled": false, + "visible": true }, { "id": "flowStyleDash", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -249,6 +256,7 @@ { "id": "flowStyleGap", "name": "{i18n:scada.symbol.flow-style}", + "hint": "{i18n:scada.symbol.flow-style-hint}", "group": "{i18n:scada.symbol.animation}", "type": "number", "default": 10, @@ -284,5 +292,5 @@ } ] }]]> - + \ No newline at end of file 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 abe570fa3c..ee63dc59a6 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 @@ -83,6 +83,10 @@ export interface ScadaSymbolApi { cssAnimation: (element: Element) => ScadaSymbolAnimation | undefined; resetCssAnimation: (element: Element) => void; finishCssAnimation: (element: Element) => void; + connectorAnimation:(element: Element) => ConnectorScadaSymbolAnimation | undefined; + connectorAnimate:(element: Element) => ConnectorScadaSymbolAnimation; + resetConnectorAnimation: (element: Element) => void; + finishConnectorAnimation: (element: Element) => void; disable: (element: Element | Element[]) => void; enable: (element: Element | Element[]) => void; callAction: (event: Event, behaviorId: string, value?: any, observer?: Partial>) => void; @@ -186,6 +190,8 @@ const tbNamespaceRegex = //gm const tbTagRegex = /tb:tag="([^"]*)"/gms; +let syncTime = Date.now(); + const generateElementId = () => { const id = guid(); const firstChar = id.charAt(0); @@ -485,6 +491,7 @@ export class ScadaSymbolObject { private settings: ScadaSymbolObjectSettings; private context: ScadaSymbolContext; private cssAnimations: CssScadaSymbolAnimations; + private connectorAnimations: ScadaSymbolFlowConnectorAnimations; private svgShape: Svg; private box: Box; @@ -604,6 +611,7 @@ export class ScadaSymbolObject { private init() { this.cssAnimations = new CssScadaSymbolAnimations(this.svgShape, this.raf); + this.connectorAnimations = new ScadaSymbolFlowConnectorAnimations(); this.context = { api: { generateElementId: () => generateElementId(), @@ -615,6 +623,10 @@ export class ScadaSymbolObject { cssAnimation: this.cssAnimation.bind(this), resetCssAnimation: this.resetCssAnimation.bind(this), finishCssAnimation: this.finishCssAnimation.bind(this), + connectorAnimation: this.connectorAnimation.bind(this), + connectorAnimate: this.connectorAnimate.bind(this), + resetConnectorAnimation: this.resetConnectorAnimation.bind(this), + finishConnectorAnimation: this.finishConnectorAnimation.bind(this), disable: this.disableElement.bind(this), enable: this.enableElement.bind(this), callAction: this.callAction.bind(this), @@ -959,6 +971,22 @@ export class ScadaSymbolObject { this.cssAnimations.finishAnimation(element); } + private connectorAnimate(element: Element, path: string, reversedPath: string): ConnectorScadaSymbolAnimation { + return this.connectorAnimations.animate(element, path, reversedPath); + } + + private connectorAnimation(element: Element): ConnectorScadaSymbolAnimation | undefined { + return this.connectorAnimations.animation(element); + } + + private resetConnectorAnimation(element: Element) { + this.connectorAnimations.resetAnimation(element); + } + + private finishConnectorAnimation(element: Element) { + this.connectorAnimations.finishAnimation(element); + } + private disableElement(e: Element | Element[]) { this.elements(e).forEach(element => { element.attr({'pointer-events': 'none'}); @@ -1108,6 +1136,20 @@ interface ScadaSymbolAnimation { } +const scadaSymbolConnectorFlowAnimationId = 'scadaSymbolConnectorFlowAnimation'; + +type StrokeLineCap = 'butt' | 'round '| 'square'; + +interface ConnectorScadaSymbolAnimation { + play(): void; + stop(): void; + finish(): void; + + flowAppearance(width: number, color: string, lineCap: StrokeLineCap, dashWidth: number, dashGap: number): ConnectorScadaSymbolAnimation; + duration(speed: number): ConnectorScadaSymbolAnimation; + direction(direction: boolean): ConnectorScadaSymbolAnimation; +} + class CssScadaSymbolAnimations { constructor(private svgShape: Svg, private raf: RafService) {} @@ -1159,6 +1201,135 @@ class CssScadaSymbolAnimations { } } +class ScadaSymbolFlowConnectorAnimations { + constructor() {} + + public animate(element: Element, path = '', reversedPath = ''): ConnectorScadaSymbolAnimation { + this.checkOldAnimation(element); + return this.setupAnimation(element, this.createAnimation(element, path, reversedPath)); + } + + public animation(element: Element): ConnectorScadaSymbolAnimation | undefined { + return element.remember(scadaSymbolConnectorFlowAnimationId); + } + + public resetAnimation(element: Element) { + const animation: ConnectorScadaSymbolAnimation = element.remember(scadaSymbolConnectorFlowAnimationId); + if (animation) { + animation.stop(); + element.remember(scadaSymbolConnectorFlowAnimationId, null); + } + } + + public finishAnimation(element: Element) { + const animation: ConnectorScadaSymbolAnimation = element.remember(scadaSymbolConnectorFlowAnimationId); + if (animation) { + animation.finish(); + element.remember(scadaSymbolConnectorFlowAnimationId, null); + } + } + + private setupAnimation(element: Element, animation: ConnectorScadaSymbolAnimation): ConnectorScadaSymbolAnimation { + element.remember(scadaSymbolConnectorFlowAnimationId, animation); + return animation; + } + + private checkOldAnimation(element: Element) { + const previousAnimation: ConnectorScadaSymbolAnimation = element.remember(scadaSymbolConnectorFlowAnimationId); + if (previousAnimation) { + previousAnimation.finish(); + } + } + + private createAnimation(element: Element, path: string, reversedPath: string): ConnectorScadaSymbolAnimation { + return new FlowConnectorAnimation(element, path, reversedPath); + } +} + +class FlowConnectorAnimation implements ConnectorScadaSymbolAnimation { + + private readonly _path: string; + private readonly _reversedPath: string; + private readonly _animation: Element; + + private _duration: number = 1; + private _lineColor: string = '#C8DFF7'; + private _lineWidth: number = 4; + private _strokeLineCap: StrokeLineCap = 'butt'; + private _dashWidth: number = 10; + private _dashGap: number = 10; + private _direction: boolean = true; + + constructor(private element: Element, + path: string, + pathReversed: string) { + this._path = path; + this._reversedPath = pathReversed; + + const dashArray = `${this._dashWidth} ${this._dashGap}`; + const values = `${this._dashWidth + this._dashGap};0`; + + this._animation = SVG( + `` + + `` + ); + } + + public play() { + if (!this.element.node.childElementCount) { + this.element.add(this._animation); + } + if (!syncTime) { + syncTime = Date.now(); + } + const animateElement = this.element.node.getElementsByTagName('animate')[0]; + const offset = ((Date.now() - syncTime) % 1000) * -1; + (animateElement as SVGAnimationElement).beginElementAt(offset); + } + + public stop() { + const animateElement = this.element.node.getElementsByTagName('animate')[0]; + (animateElement as SVGAnimationElement)?.endElement(); + } + + public finish() { + this.element.findOne('path')?.remove(); + } + + public flowAppearance(width: number, color: string, linecap: StrokeLineCap, dashWidth: number, dashGap: number): this { + const totalLength = (this._animation.node as SVGPathElement).getTotalLength(); + let offset = 0; + if ((totalLength % 100) !== 0) { + const clientWidth = totalLength < 100 ? 100 : this.element.node.ownerSVGElement.clientWidth; + const clientWidthDash = clientWidth / (dashWidth + dashGap); + const totalLengthDash = totalLength / clientWidthDash; + offset = ((dashWidth + dashGap) - totalLengthDash) / 2; + } + this._lineColor = color; + this._lineWidth = width; + this._strokeLineCap = linecap; + this._dashWidth = dashWidth - offset; + this._dashGap = dashGap - offset; + const dashArray = `${this._dashWidth}${this._dashGap ? ` ${this._dashGap}` : ''}`; + const values = `${this._dashWidth + (this._dashGap || this._dashWidth)};0`; + this._animation.stroke({width, color, linecap, dasharray: dashArray}); + this._animation.findOne('animate').attr('values', values); + return this; + } + + public duration(speed: number): this { + this._duration = speed; + this._animation.findOne('animate').attr('dur', `${speed}s`); + return this; + } + + public direction(direction: boolean): this { + this._direction = direction; + this._animation.attr('d', direction ? this._path : this._reversedPath); + return this; + } +} + interface ScadaSymbolAnimationKeyframe { stop: string; style: any; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-panel.component.html index b32c7b5ab1..af59457abe 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-panel.component.html @@ -30,6 +30,12 @@ +
+
scada.behavior.hint
+ + + +
dynamic-form.property.group-title
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-panel.component.ts index 2df62e1259..00a614636d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-panel.component.ts @@ -104,6 +104,7 @@ export class DynamicFormPropertyPanelComponent implements OnInit { { id: [this.property.id, [Validators.required]], name: [this.property.name, [Validators.required]], + hint: [this.property.hint, []], group: [this.property.group, []], type: [this.property.type, [Validators.required]], arrayItemType: [this.property.arrayItemType, [Validators.required]], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form.component.html index a64c178eb6..449af2b240 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form.component.html @@ -91,9 +91,15 @@
- {{ propertyRow.label | customTranslate }} +
+ {{ propertyRow.label | customTranslate }} +
-
{{ propertyRow.label | customTranslate }}
+
+
+ {{ propertyRow.label | customTranslate }} +
+
diff --git a/ui-ngx/src/app/shared/models/dynamic-form.models.ts b/ui-ngx/src/app/shared/models/dynamic-form.models.ts index 4132eeff94..b1cc83dbd7 100644 --- a/ui-ngx/src/app/shared/models/dynamic-form.models.ts +++ b/ui-ngx/src/app/shared/models/dynamic-form.models.ts @@ -87,6 +87,7 @@ export type PropertyConditionFunction = (property: FormProperty, model: any) => export interface FormPropertyBase { id: string; name: string; + hint?: string; group?: string; type: FormPropertyType; default: any; @@ -237,6 +238,7 @@ export interface FormPropertyContainerBase { } export interface FormPropertyRow extends FormPropertyContainerBase { + hint?: string; properties?: FormProperty[]; switch?: FormProperty; rowClass?: string; @@ -362,6 +364,7 @@ const toPropertyContainers = (properties: FormProperty[], if (!propertyRow) { propertyRow = { label: property.name, + hint: property.hint, type: FormPropertyContainerType.row, properties: [], rowClass: property.rowClass, diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 72afcfc0b9..a3ba654258 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3446,6 +3446,7 @@ "flow-animation-hint": "Indicates whether animation is present in connector.", "flow": "Flow", "flow-style": "Flow style", + "flow-style-hint": "Set the Dash and Gap values so that their sum is divisible by 100 without a remainder for perfect animation synchronization.", "flow-dash-cap": "Flow dash cap", "dash-cap-butt": "Butt", "dash-cap-round": "Round",