UI: Hint for dynamic settings and refactoring flow animation
@ -3,7 +3,7 @@
|
|||||||
"description": "Bottom right elbow connector",
|
"description": "Bottom right elbow connector",
|
||||||
"widgetSizeX": 1,
|
"widgetSizeX": 1,
|
||||||
"widgetSizeY": 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(`<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 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": [
|
"tags": [
|
||||||
{
|
{
|
||||||
"tag": "line",
|
"tag": "line",
|
||||||
@ -140,13 +140,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mainLineSize",
|
"id": "mainLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 6,
|
"default": 6,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Main",
|
"subLabel": "Main",
|
||||||
"divider": true,
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -155,21 +156,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "secondaryLineSize",
|
"id": "secondaryLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 2,
|
"default": 2,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Secondary",
|
"subLabel": "Secondary",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return !model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"visible": true
|
"visible": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "lineColor",
|
"id": "lineColor",
|
||||||
"name": "{i18n:scada.symbol.line-color}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#1A1A1A",
|
"default": "#1A1A1A",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
@ -182,6 +185,7 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 4,
|
"default": 4,
|
||||||
"subLabel": "Width",
|
"subLabel": "Width",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -200,6 +204,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleDash",
|
"id": "flowStyleDash",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -215,6 +220,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleGap",
|
"id": "flowStyleGap",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -250,5 +256,5 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}]]></tb:metadata>
|
}]]></tb:metadata>
|
||||||
<path d="M200 100H132C115 100 100 115 100 132V200" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><g tb:tag="animationGroup"/>
|
<path d="M 100,200 L 100,125 Q 100,100 125,100 L 200, 100" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><g tb:tag="animationGroup"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 8.2 KiB |
@ -3,7 +3,7 @@
|
|||||||
"description": "Bottom tee connector",
|
"description": "Bottom tee connector",
|
||||||
"widgetSizeX": 1,
|
"widgetSizeX": 1,
|
||||||
"widgetSizeY": 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(`<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}",
|
"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": [
|
"tags": [
|
||||||
{
|
{
|
||||||
"tag": "line",
|
"tag": "line",
|
||||||
@ -377,13 +377,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mainLineSize",
|
"id": "mainLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 6,
|
"default": 6,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Main",
|
"subLabel": "Main",
|
||||||
"divider": true,
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -392,21 +393,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "secondaryLineSize",
|
"id": "secondaryLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 2,
|
"default": 2,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Secondary",
|
"subLabel": "Secondary",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return !model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"visible": true
|
"visible": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "lineColor",
|
"id": "lineColor",
|
||||||
"name": "{i18n:scada.symbol.line-color}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#1A1A1A",
|
"default": "#1A1A1A",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
@ -419,6 +422,7 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 4,
|
"default": 4,
|
||||||
"subLabel": "Width",
|
"subLabel": "Width",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -437,6 +441,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleDash",
|
"id": "flowStyleDash",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -452,6 +457,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleGap",
|
"id": "flowStyleGap",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
@ -3,7 +3,7 @@
|
|||||||
"description": "Cross connector",
|
"description": "Cross connector",
|
||||||
"widgetSizeX": 1,
|
"widgetSizeX": 1,
|
||||||
"widgetSizeY": 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(`<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}",
|
"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": [
|
"tags": [
|
||||||
{
|
{
|
||||||
"tag": "line",
|
"tag": "line",
|
||||||
@ -493,13 +493,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mainLineSize",
|
"id": "mainLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 6,
|
"default": 6,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Main",
|
"subLabel": "Main",
|
||||||
"divider": true,
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -508,21 +509,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "secondaryLineSize",
|
"id": "secondaryLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 2,
|
"default": 2,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Secondary",
|
"subLabel": "Secondary",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return !model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"visible": true
|
"visible": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "lineColor",
|
"id": "lineColor",
|
||||||
"name": "{i18n:scada.symbol.line-color}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#1A1A1A",
|
"default": "#1A1A1A",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
@ -535,6 +538,7 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 4,
|
"default": 4,
|
||||||
"subLabel": "Width",
|
"subLabel": "Width",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -553,6 +557,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleDash",
|
"id": "flowStyleDash",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -568,6 +573,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleGap",
|
"id": "flowStyleGap",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 20 KiB |
@ -3,7 +3,7 @@
|
|||||||
"description": "Horizontal connector with an optional directional arrow to visually indicate flow.",
|
"description": "Horizontal connector with an optional directional arrow to visually indicate flow.",
|
||||||
"widgetSizeX": 1,
|
"widgetSizeX": 1,
|
||||||
"widgetSizeY": 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(`<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 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": [
|
"tags": [
|
||||||
{
|
{
|
||||||
"tag": "arrow",
|
"tag": "arrow",
|
||||||
@ -176,13 +176,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mainLineSize",
|
"id": "mainLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 6,
|
"default": 6,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Main",
|
"subLabel": "Main",
|
||||||
"divider": true,
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -191,21 +192,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "secondaryLineSize",
|
"id": "secondaryLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 2,
|
"default": 2,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Secondary",
|
"subLabel": "Secondary",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return !model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"visible": true
|
"visible": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "lineColor",
|
"id": "lineColor",
|
||||||
"name": "{i18n:scada.symbol.line-color}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#1A1A1A",
|
"default": "#1A1A1A",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
@ -229,11 +232,14 @@
|
|||||||
"name": "{i18n:scada.symbol.flow}",
|
"name": "{i18n:scada.symbol.flow}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#C8DFF7"
|
"default": "#C8DFF7",
|
||||||
|
"disabled": false,
|
||||||
|
"visible": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "flowStyleDash",
|
"id": "flowStyleDash",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -249,6 +255,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleGap",
|
"id": "flowStyleGap",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.7 KiB |
@ -3,7 +3,7 @@
|
|||||||
"description": "Left bottom elbow connector",
|
"description": "Left bottom elbow connector",
|
||||||
"widgetSizeX": 1,
|
"widgetSizeX": 1,
|
||||||
"widgetSizeY": 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(`<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 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": [
|
"tags": [
|
||||||
{
|
{
|
||||||
"tag": "line",
|
"tag": "line",
|
||||||
@ -140,13 +140,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mainLineSize",
|
"id": "mainLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 6,
|
"default": 6,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Main",
|
"subLabel": "Main",
|
||||||
"divider": true,
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -155,21 +156,24 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "secondaryLineSize",
|
"id": "secondaryLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 2,
|
"default": 2,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Secondary",
|
"subLabel": "Secondary",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"disableOnProperty": "mainLine",
|
||||||
|
"condition": "return !model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"visible": true
|
"visible": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "lineColor",
|
"id": "lineColor",
|
||||||
"name": "{i18n:scada.symbol.line-color}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#1A1A1A",
|
"default": "#1A1A1A",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
@ -182,6 +186,7 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 4,
|
"default": 4,
|
||||||
"subLabel": "Width",
|
"subLabel": "Width",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -193,11 +198,14 @@
|
|||||||
"name": "{i18n:scada.symbol.flow}",
|
"name": "{i18n:scada.symbol.flow}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#C8DFF7"
|
"default": "#C8DFF7",
|
||||||
|
"disabled": false,
|
||||||
|
"visible": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "flowStyleDash",
|
"id": "flowStyleDash",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -213,6 +221,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleGap",
|
"id": "flowStyleGap",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -248,5 +257,5 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}]]></tb:metadata>
|
}]]></tb:metadata>
|
||||||
<path d="M100 200L100 131C100 113.879 86.1208 100 69 100L0 100" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><g tb:tag="animationGroup"/>
|
<path d="M 0,100 L 75,100 Q 100,100 100,125 L 100, 200" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><g tb:tag="animationGroup"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 8.2 KiB |
@ -3,7 +3,7 @@
|
|||||||
"description": "Left tee connector",
|
"description": "Left tee connector",
|
||||||
"widgetSizeX": 1,
|
"widgetSizeX": 1,
|
||||||
"widgetSizeY": 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(`<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}",
|
"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": [
|
"tags": [
|
||||||
{
|
{
|
||||||
"tag": "line",
|
"tag": "line",
|
||||||
@ -377,13 +377,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mainLineSize",
|
"id": "mainLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 6,
|
"default": 6,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Main",
|
"subLabel": "Main",
|
||||||
"divider": true,
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -392,21 +393,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "secondaryLineSize",
|
"id": "secondaryLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 2,
|
"default": 2,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Secondary",
|
"subLabel": "Secondary",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return !model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"visible": true
|
"visible": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "lineColor",
|
"id": "lineColor",
|
||||||
"name": "{i18n:scada.symbol.line-color}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#1A1A1A",
|
"default": "#1A1A1A",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
@ -419,6 +422,7 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 4,
|
"default": 4,
|
||||||
"subLabel": "Width",
|
"subLabel": "Width",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -437,6 +441,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleDash",
|
"id": "flowStyleDash",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -452,6 +457,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleGap",
|
"id": "flowStyleGap",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -487,5 +493,5 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}]]></tb:metadata>
|
}]]></tb:metadata>
|
||||||
<path d="M100 0V200" stroke="#1A1A1A" stroke-width="6" id="path6" tb:tag="line"/><path d="M100 113V87C100 87 100 100 86 100C100 100 100 113 100 113Z" fill="#1A1A1A" stroke="#1A1A1A" stroke-width="2" id="path8" tb:tag="line-color"/><path d="M0 100H85C93.2843 100 100 93.2843 100 85V0" stroke="#1A1A1A" stroke-width="6" id="path4" tb:tag="line"/><path d="M0 100H85C93.2843 100 100 106.716 100 115V200" stroke="#1A1A1A" stroke-width="6" id="path2" tb:tag="line"/><g tb:tag="animationGroup"><g tb:tag="leftLine"/><g tb:tag="topLine"/><g tb:tag="bottomLine"/></g>
|
<path d="M100 0V200" stroke="#1A1A1A" stroke-width="6" id="path6" tb:tag="line"/><path d="M100 113V87C100 87 100 100 86 100C100 100 100 113 100 113Z" fill="#1A1A1A" stroke="#1A1A1A" stroke-width="2" id="path8" tb:tag="line-color"/><path d="M0 100H85C93.2843 100 100 93.2843 100 85V0" stroke="#1A1A1A" stroke-width="6" id="path4" tb:tag="line"/><path d="M0 100H85C93.2843 100 100 106.716 100 115V200" stroke="#1A1A1A" stroke-width="6" id="path2" tb:tag="line"/><g tb:tag="animationGroup"><g tb:tag="leftLine"/><g tb:tag="topLine"> </g><g tb:tag="bottomLine"> </g></g>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
@ -3,7 +3,7 @@
|
|||||||
"description": "Left top elbow connector",
|
"description": "Left top elbow connector",
|
||||||
"widgetSizeX": 1,
|
"widgetSizeX": 1,
|
||||||
"widgetSizeY": 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(`<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 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": [
|
"tags": [
|
||||||
{
|
{
|
||||||
"tag": "line",
|
"tag": "line",
|
||||||
@ -140,13 +140,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mainLineSize",
|
"id": "mainLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 6,
|
"default": 6,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Main",
|
"subLabel": "Main",
|
||||||
"divider": true,
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -155,21 +156,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "secondaryLineSize",
|
"id": "secondaryLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 2,
|
"default": 2,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Secondary",
|
"subLabel": "Secondary",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return !model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"visible": true
|
"visible": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "lineColor",
|
"id": "lineColor",
|
||||||
"name": "{i18n:scada.symbol.line-color}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#1A1A1A",
|
"default": "#1A1A1A",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
@ -182,6 +185,7 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 4,
|
"default": 4,
|
||||||
"subLabel": "Width",
|
"subLabel": "Width",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -200,6 +204,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleDash",
|
"id": "flowStyleDash",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -215,6 +220,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleGap",
|
"id": "flowStyleGap",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -250,5 +256,5 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}]]></tb:metadata>
|
}]]></tb:metadata>
|
||||||
<path d="M0 100H69C86.1208 100 100 86.1208 100 69V0" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><g tb:tag="animationGroup"/>
|
<path d="M 0,100 L 75,100 Q 100,100 100,75 L 100, 0" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><g tb:tag="animationGroup"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 8.2 KiB |
@ -1,10 +1,9 @@
|
|||||||
<svg width="400" height="200" fill="none" version="1.1" viewBox="0 0 400 200" xmlns="http://www.w3.org/2000/svg" xmlns:tb="https://thingsboard.io/svg">
|
<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[{
|
||||||
<tb:metadata><![CDATA[{
|
|
||||||
"title": "HP Long horizontal connector",
|
"title": "HP Long horizontal connector",
|
||||||
"description": "Long horizontal connector with an optional directional arrow to visually indicate flow.",
|
"description": "Long horizontal connector with an optional directional arrow to visually indicate flow.",
|
||||||
"widgetSizeX": 2,
|
"widgetSizeX": 2,
|
||||||
"widgetSizeY": 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(`<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": [
|
"tags": [
|
||||||
{
|
{
|
||||||
"tag": "arrow",
|
"tag": "arrow",
|
||||||
@ -177,27 +176,30 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mainLineSize",
|
"id": "mainLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 6,
|
"default": 6,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Main",
|
"subLabel": "Main",
|
||||||
"divider": true,
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"visible": true
|
"visible": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "secondaryLineSize",
|
"id": "secondaryLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 2,
|
"default": 2,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Secondary",
|
"subLabel": "Secondary",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return !model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -206,7 +208,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "lineColor",
|
"id": "lineColor",
|
||||||
"name": "{i18n:scada.symbol.line-color}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#1A1A1A",
|
"default": "#1A1A1A",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
@ -219,6 +221,7 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 4,
|
"default": 4,
|
||||||
"subLabel": "Width",
|
"subLabel": "Width",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -230,11 +233,14 @@
|
|||||||
"name": "{i18n:scada.symbol.flow}",
|
"name": "{i18n:scada.symbol.flow}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#C8DFF7"
|
"default": "#C8DFF7",
|
||||||
|
"disabled": false,
|
||||||
|
"visible": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "flowStyleDash",
|
"id": "flowStyleDash",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -250,6 +256,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleGap",
|
"id": "flowStyleGap",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -285,5 +292,5 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}]]></tb:metadata>
|
}]]></tb:metadata>
|
||||||
<path d="m0 100h400" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><path d="m229 100-58 29v-58z" fill="#1a1a1a" tb:tag="arrow"/><g tb:tag="animationGroup"/>
|
<path d="M0 100H400" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><path d="m229 100-58 29v-58z" fill="#1a1a1a" tb:tag="arrow"/><g tb:tag="animationGroup"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.7 KiB |
@ -3,7 +3,7 @@
|
|||||||
"description": "Long vertical connector with an optional directional arrow to visually indicate flow.",
|
"description": "Long vertical connector with an optional directional arrow to visually indicate flow.",
|
||||||
"widgetSizeX": 1,
|
"widgetSizeX": 1,
|
||||||
"widgetSizeY": 2,
|
"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(`<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 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": [
|
"tags": [
|
||||||
{
|
{
|
||||||
"tag": "arrow",
|
"tag": "arrow",
|
||||||
@ -176,13 +176,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mainLineSize",
|
"id": "mainLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 6,
|
"default": 6,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Main",
|
"subLabel": "Main",
|
||||||
"divider": true,
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -191,21 +192,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "secondaryLineSize",
|
"id": "secondaryLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 2,
|
"default": 2,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Secondary",
|
"subLabel": "Secondary",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return !model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"visible": true
|
"visible": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "lineColor",
|
"id": "lineColor",
|
||||||
"name": "{i18n:scada.symbol.line-color}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#1A1A1A",
|
"default": "#1A1A1A",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
@ -218,6 +221,7 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 4,
|
"default": 4,
|
||||||
"subLabel": "Width",
|
"subLabel": "Width",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -229,11 +233,14 @@
|
|||||||
"name": "{i18n:scada.symbol.flow}",
|
"name": "{i18n:scada.symbol.flow}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#C8DFF7"
|
"default": "#C8DFF7",
|
||||||
|
"disabled": false,
|
||||||
|
"visible": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "flowStyleDash",
|
"id": "flowStyleDash",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -249,6 +256,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleGap",
|
"id": "flowStyleGap",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -284,5 +292,5 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}]]></tb:metadata>
|
}]]></tb:metadata>
|
||||||
<path d="m100 400v-400" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><path d="m100 171 29 58h-58l29-58z" fill="#1A1A1A" tb:tag="arrow"/><g tb:tag="animationGroup"/>
|
<path d="M 100,400 V 0" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><path d="m100 171 29 58h-58l29-58z" fill="#1A1A1A" tb:tag="arrow"/><g tb:tag="animationGroup"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.7 KiB |
@ -3,7 +3,7 @@
|
|||||||
"description": "Right tee connector",
|
"description": "Right tee connector",
|
||||||
"widgetSizeX": 1,
|
"widgetSizeX": 1,
|
||||||
"widgetSizeY": 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(`<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}",
|
"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": [
|
"tags": [
|
||||||
{
|
{
|
||||||
"tag": "line",
|
"tag": "line",
|
||||||
@ -377,13 +377,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mainLineSize",
|
"id": "mainLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 6,
|
"default": 6,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Main",
|
"subLabel": "Main",
|
||||||
"divider": true,
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -392,21 +393,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "secondaryLineSize",
|
"id": "secondaryLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 2,
|
"default": 2,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Secondary",
|
"subLabel": "Secondary",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return !model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"visible": true
|
"visible": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "lineColor",
|
"id": "lineColor",
|
||||||
"name": "{i18n:scada.symbol.line-color}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#1A1A1A",
|
"default": "#1A1A1A",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
@ -419,6 +422,7 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 4,
|
"default": 4,
|
||||||
"subLabel": "Width",
|
"subLabel": "Width",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -437,6 +441,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleDash",
|
"id": "flowStyleDash",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -452,6 +457,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleGap",
|
"id": "flowStyleGap",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
@ -3,7 +3,7 @@
|
|||||||
"description": "Top right elbow connector",
|
"description": "Top right elbow connector",
|
||||||
"widgetSizeX": 1,
|
"widgetSizeX": 1,
|
||||||
"widgetSizeY": 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(`<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 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": [
|
"tags": [
|
||||||
{
|
{
|
||||||
"tag": "line",
|
"tag": "line",
|
||||||
@ -140,13 +140,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mainLineSize",
|
"id": "mainLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 6,
|
"default": 6,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Main",
|
"subLabel": "Main",
|
||||||
"divider": true,
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -155,21 +156,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "secondaryLineSize",
|
"id": "secondaryLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 2,
|
"default": 2,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Secondary",
|
"subLabel": "Secondary",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return !model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"visible": true
|
"visible": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "lineColor",
|
"id": "lineColor",
|
||||||
"name": "{i18n:scada.symbol.line-color}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#1A1A1A",
|
"default": "#1A1A1A",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
@ -182,6 +185,7 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 4,
|
"default": 4,
|
||||||
"subLabel": "Width",
|
"subLabel": "Width",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -200,6 +204,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleDash",
|
"id": "flowStyleDash",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -215,6 +220,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleGap",
|
"id": "flowStyleGap",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -250,5 +256,5 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}]]></tb:metadata>
|
}]]></tb:metadata>
|
||||||
<path d="M100 0V69C100 86.1208 113.879 100 131 100H200" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><g tb:tag="animationGroup"/>
|
<path d="M 100,0 L 100,75 Q 100,100 125,100 L 200, 100" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><g tb:tag="animationGroup"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 8.2 KiB |
@ -3,7 +3,7 @@
|
|||||||
"description": "Top tee connector",
|
"description": "Top tee connector",
|
||||||
"widgetSizeX": 1,
|
"widgetSizeX": 1,
|
||||||
"widgetSizeY": 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(`<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}",
|
"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": [
|
"tags": [
|
||||||
{
|
{
|
||||||
"tag": "line",
|
"tag": "line",
|
||||||
@ -377,13 +377,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mainLineSize",
|
"id": "mainLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 6,
|
"default": 6,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Main",
|
"subLabel": "Main",
|
||||||
"divider": true,
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -392,21 +393,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "secondaryLineSize",
|
"id": "secondaryLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 2,
|
"default": 2,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Secondary",
|
"subLabel": "Secondary",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return !model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"visible": true
|
"visible": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "lineColor",
|
"id": "lineColor",
|
||||||
"name": "{i18n:scada.symbol.line-color}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#1A1A1A",
|
"default": "#1A1A1A",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
@ -419,6 +422,7 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 4,
|
"default": 4,
|
||||||
"subLabel": "Width",
|
"subLabel": "Width",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -437,6 +441,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleDash",
|
"id": "flowStyleDash",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -452,6 +457,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleGap",
|
"id": "flowStyleGap",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
@ -3,7 +3,7 @@
|
|||||||
"description": "Vertical connector with an optional directional arrow to visually indicate flow.",
|
"description": "Vertical connector with an optional directional arrow to visually indicate flow.",
|
||||||
"widgetSizeX": 1,
|
"widgetSizeX": 1,
|
||||||
"widgetSizeY": 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(`<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 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": [
|
"tags": [
|
||||||
{
|
{
|
||||||
"tag": "arrow",
|
"tag": "arrow",
|
||||||
@ -176,13 +176,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mainLineSize",
|
"id": "mainLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 6,
|
"default": 6,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Main",
|
"subLabel": "Main",
|
||||||
"divider": true,
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -191,21 +192,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "secondaryLineSize",
|
"id": "secondaryLineSize",
|
||||||
"name": "{i18n:scada.symbol.line}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 2,
|
"default": 2,
|
||||||
"required": true,
|
"required": true,
|
||||||
"subLabel": "Secondary",
|
"subLabel": "Secondary",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
|
"condition": "return !model.mainLine;",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 99,
|
"max": 99,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"visible": true
|
"visible": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "lineColor",
|
"id": "lineColor",
|
||||||
"name": "{i18n:scada.symbol.line-color}",
|
"name": "{i18n:scada.symbol.main-line}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#1A1A1A",
|
"default": "#1A1A1A",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
@ -218,6 +221,7 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 4,
|
"default": 4,
|
||||||
"subLabel": "Width",
|
"subLabel": "Width",
|
||||||
|
"divider": true,
|
||||||
"fieldSuffix": "px",
|
"fieldSuffix": "px",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"step": 1,
|
"step": 1,
|
||||||
@ -229,11 +233,14 @@
|
|||||||
"name": "{i18n:scada.symbol.flow}",
|
"name": "{i18n:scada.symbol.flow}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "color",
|
"type": "color",
|
||||||
"default": "#C8DFF7"
|
"default": "#C8DFF7",
|
||||||
|
"disabled": false,
|
||||||
|
"visible": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "flowStyleDash",
|
"id": "flowStyleDash",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -249,6 +256,7 @@
|
|||||||
{
|
{
|
||||||
"id": "flowStyleGap",
|
"id": "flowStyleGap",
|
||||||
"name": "{i18n:scada.symbol.flow-style}",
|
"name": "{i18n:scada.symbol.flow-style}",
|
||||||
|
"hint": "{i18n:scada.symbol.flow-style-hint}",
|
||||||
"group": "{i18n:scada.symbol.animation}",
|
"group": "{i18n:scada.symbol.animation}",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
@ -284,5 +292,5 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}]]></tb:metadata>
|
}]]></tb:metadata>
|
||||||
<path d="M100 200L100 0" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><path d="M100 71L129 129H71L100 71Z" fill="#1A1A1A" tb:tag="arrow"/><g tb:tag="animationGroup"/>
|
<path d="M 100,200 V 0" stroke="#1A1A1A" stroke-width="6" tb:tag="line"/><path d="M100 71L129 129H71L100 71Z" fill="#1A1A1A" tb:tag="arrow"/><g tb:tag="animationGroup"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.7 KiB |
@ -83,6 +83,10 @@ export interface ScadaSymbolApi {
|
|||||||
cssAnimation: (element: Element) => ScadaSymbolAnimation | undefined;
|
cssAnimation: (element: Element) => ScadaSymbolAnimation | undefined;
|
||||||
resetCssAnimation: (element: Element) => void;
|
resetCssAnimation: (element: Element) => void;
|
||||||
finishCssAnimation: (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;
|
disable: (element: Element | Element[]) => void;
|
||||||
enable: (element: Element | Element[]) => void;
|
enable: (element: Element | Element[]) => void;
|
||||||
callAction: (event: Event, behaviorId: string, value?: any, observer?: Partial<Observer<void>>) => void;
|
callAction: (event: Event, behaviorId: string, value?: any, observer?: Partial<Observer<void>>) => void;
|
||||||
@ -186,6 +190,8 @@ const tbNamespaceRegex = /<svg.*(xmlns:tb="https:\/\/thingsboard.io\/svg").*>/gm
|
|||||||
|
|
||||||
const tbTagRegex = /tb:tag="([^"]*)"/gms;
|
const tbTagRegex = /tb:tag="([^"]*)"/gms;
|
||||||
|
|
||||||
|
let syncTime = Date.now();
|
||||||
|
|
||||||
const generateElementId = () => {
|
const generateElementId = () => {
|
||||||
const id = guid();
|
const id = guid();
|
||||||
const firstChar = id.charAt(0);
|
const firstChar = id.charAt(0);
|
||||||
@ -485,6 +491,7 @@ export class ScadaSymbolObject {
|
|||||||
private settings: ScadaSymbolObjectSettings;
|
private settings: ScadaSymbolObjectSettings;
|
||||||
private context: ScadaSymbolContext;
|
private context: ScadaSymbolContext;
|
||||||
private cssAnimations: CssScadaSymbolAnimations;
|
private cssAnimations: CssScadaSymbolAnimations;
|
||||||
|
private connectorAnimations: ScadaSymbolFlowConnectorAnimations;
|
||||||
|
|
||||||
private svgShape: Svg;
|
private svgShape: Svg;
|
||||||
private box: Box;
|
private box: Box;
|
||||||
@ -604,6 +611,7 @@ export class ScadaSymbolObject {
|
|||||||
|
|
||||||
private init() {
|
private init() {
|
||||||
this.cssAnimations = new CssScadaSymbolAnimations(this.svgShape, this.raf);
|
this.cssAnimations = new CssScadaSymbolAnimations(this.svgShape, this.raf);
|
||||||
|
this.connectorAnimations = new ScadaSymbolFlowConnectorAnimations();
|
||||||
this.context = {
|
this.context = {
|
||||||
api: {
|
api: {
|
||||||
generateElementId: () => generateElementId(),
|
generateElementId: () => generateElementId(),
|
||||||
@ -615,6 +623,10 @@ export class ScadaSymbolObject {
|
|||||||
cssAnimation: this.cssAnimation.bind(this),
|
cssAnimation: this.cssAnimation.bind(this),
|
||||||
resetCssAnimation: this.resetCssAnimation.bind(this),
|
resetCssAnimation: this.resetCssAnimation.bind(this),
|
||||||
finishCssAnimation: this.finishCssAnimation.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),
|
disable: this.disableElement.bind(this),
|
||||||
enable: this.enableElement.bind(this),
|
enable: this.enableElement.bind(this),
|
||||||
callAction: this.callAction.bind(this),
|
callAction: this.callAction.bind(this),
|
||||||
@ -959,6 +971,22 @@ export class ScadaSymbolObject {
|
|||||||
this.cssAnimations.finishAnimation(element);
|
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[]) {
|
private disableElement(e: Element | Element[]) {
|
||||||
this.elements(e).forEach(element => {
|
this.elements(e).forEach(element => {
|
||||||
element.attr({'pointer-events': 'none'});
|
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 {
|
class CssScadaSymbolAnimations {
|
||||||
constructor(private svgShape: Svg,
|
constructor(private svgShape: Svg,
|
||||||
private raf: RafService) {}
|
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(
|
||||||
|
`<path d="${this._path}" stroke-dasharray="${dashArray}" stroke-linecap="${this._strokeLineCap}" fill="none" stroke="${this._lineColor}" stroke-width="${this._lineWidth}">` +
|
||||||
|
`<animate attributeName="stroke-dashoffset" values="${values}" dur="${this._duration}s" begin="indefinite" calcMode="linear" repeatCount="indefinite"></animate></path>`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
interface ScadaSymbolAnimationKeyframe {
|
||||||
stop: string;
|
stop: string;
|
||||||
style: any;
|
style: any;
|
||||||
|
|||||||
@ -30,6 +30,12 @@
|
|||||||
<input required matInput formControlName="name" placeholder="{{ 'widget-config.set' | translate }}">
|
<input required matInput formControlName="name" placeholder="{{ 'widget-config.set' | translate }}">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tb-form-row">
|
||||||
|
<div class="fixed-title-width" translate>scada.behavior.hint</div>
|
||||||
|
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
|
||||||
|
<input matInput formControlName="hint" placeholder="{{ 'widget-config.set' | translate }}">
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
<div class="tb-form-row">
|
<div class="tb-form-row">
|
||||||
<div class="fixed-title-width" translate>dynamic-form.property.group-title</div>
|
<div class="fixed-title-width" translate>dynamic-form.property.group-title</div>
|
||||||
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
|
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
|
||||||
|
|||||||
@ -104,6 +104,7 @@ export class DynamicFormPropertyPanelComponent implements OnInit {
|
|||||||
{
|
{
|
||||||
id: [this.property.id, [Validators.required]],
|
id: [this.property.id, [Validators.required]],
|
||||||
name: [this.property.name, [Validators.required]],
|
name: [this.property.name, [Validators.required]],
|
||||||
|
hint: [this.property.hint, []],
|
||||||
group: [this.property.group, []],
|
group: [this.property.group, []],
|
||||||
type: [this.property.type, [Validators.required]],
|
type: [this.property.type, [Validators.required]],
|
||||||
arrayItemType: [this.property.arrayItemType, [Validators.required]],
|
arrayItemType: [this.property.arrayItemType, [Validators.required]],
|
||||||
|
|||||||
@ -91,9 +91,15 @@
|
|||||||
<div [formGroup]="propertiesFormGroup" class="tb-form-row space-between overflow-auto" [class]="propertyRow.rowClass">
|
<div [formGroup]="propertiesFormGroup" class="tb-form-row space-between overflow-auto" [class]="propertyRow.rowClass">
|
||||||
<mat-slide-toggle *ngIf="propertyRow.switch && propertyRow.switch.visible"
|
<mat-slide-toggle *ngIf="propertyRow.switch && propertyRow.switch.visible"
|
||||||
class="mat-slide fixed-title-width margin" formControlName="{{ propertyRow.switch.id }}">
|
class="mat-slide fixed-title-width margin" formControlName="{{ propertyRow.switch.id }}">
|
||||||
{{ propertyRow.label | customTranslate }}
|
<div tb-hint-tooltip-icon="{{ propertyRow.hint | customTranslate }}">
|
||||||
|
{{ propertyRow.label | customTranslate }}
|
||||||
|
</div>
|
||||||
</mat-slide-toggle>
|
</mat-slide-toggle>
|
||||||
<div *ngIf="!propertyRow.switch" class="fixed-title-width fixed-title-height">{{ propertyRow.label | customTranslate }}</div>
|
<div *ngIf="!propertyRow.switch" class="fixed-title-width fixed-title-height">
|
||||||
|
<div tb-hint-tooltip-icon="{{ propertyRow.hint | customTranslate }}">
|
||||||
|
{{ propertyRow.label | customTranslate }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div *ngIf="propertyRow.properties.length" class="tb-flex" [class]="propertyRow.propertiesRowClass">
|
<div *ngIf="propertyRow.properties.length" class="tb-flex" [class]="propertyRow.propertiesRowClass">
|
||||||
<ng-container *ngFor="let property of propertyRow.properties">
|
<ng-container *ngFor="let property of propertyRow.properties">
|
||||||
<ng-container *ngIf="property.visible">
|
<ng-container *ngIf="property.visible">
|
||||||
|
|||||||
@ -87,6 +87,7 @@ export type PropertyConditionFunction = (property: FormProperty, model: any) =>
|
|||||||
export interface FormPropertyBase {
|
export interface FormPropertyBase {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
hint?: string;
|
||||||
group?: string;
|
group?: string;
|
||||||
type: FormPropertyType;
|
type: FormPropertyType;
|
||||||
default: any;
|
default: any;
|
||||||
@ -237,6 +238,7 @@ export interface FormPropertyContainerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface FormPropertyRow extends FormPropertyContainerBase {
|
export interface FormPropertyRow extends FormPropertyContainerBase {
|
||||||
|
hint?: string;
|
||||||
properties?: FormProperty[];
|
properties?: FormProperty[];
|
||||||
switch?: FormProperty;
|
switch?: FormProperty;
|
||||||
rowClass?: string;
|
rowClass?: string;
|
||||||
@ -362,6 +364,7 @@ const toPropertyContainers = (properties: FormProperty[],
|
|||||||
if (!propertyRow) {
|
if (!propertyRow) {
|
||||||
propertyRow = {
|
propertyRow = {
|
||||||
label: property.name,
|
label: property.name,
|
||||||
|
hint: property.hint,
|
||||||
type: FormPropertyContainerType.row,
|
type: FormPropertyContainerType.row,
|
||||||
properties: [],
|
properties: [],
|
||||||
rowClass: property.rowClass,
|
rowClass: property.rowClass,
|
||||||
|
|||||||
@ -3446,6 +3446,7 @@
|
|||||||
"flow-animation-hint": "Indicates whether animation is present in connector.",
|
"flow-animation-hint": "Indicates whether animation is present in connector.",
|
||||||
"flow": "Flow",
|
"flow": "Flow",
|
||||||
"flow-style": "Flow style",
|
"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",
|
"flow-dash-cap": "Flow dash cap",
|
||||||
"dash-cap-butt": "Butt",
|
"dash-cap-butt": "Butt",
|
||||||
"dash-cap-round": "Round",
|
"dash-cap-round": "Round",
|
||||||
|
|||||||