@procaaso/alphinity-ui-components 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2110 -465
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -2
- package/dist/index.d.ts +63 -2
- package/dist/index.js +2064 -420
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -83,6 +83,7 @@ __export(index_exports, {
|
|
|
83
83
|
useSelection: () => useSelection,
|
|
84
84
|
useSimulation: () => useSimulation,
|
|
85
85
|
useTelemetry: () => useTelemetry,
|
|
86
|
+
useTelemetryStatus: () => useTelemetryStatus,
|
|
86
87
|
useTheme: () => useTheme,
|
|
87
88
|
useViewBox: () => useViewBox,
|
|
88
89
|
validateDiagram: () => validateDiagram
|
|
@@ -1785,35 +1786,10 @@ var ThemeToggle = ({
|
|
|
1785
1786
|
};
|
|
1786
1787
|
|
|
1787
1788
|
// src/components/PIDCanvas/PIDCanvas.tsx
|
|
1788
|
-
var
|
|
1789
|
+
var import_react15 = require("react");
|
|
1789
1790
|
|
|
1790
1791
|
// src/diagram/symbols/mockSymbolLibrary.ts
|
|
1791
1792
|
var mockSymbolLibrary = {
|
|
1792
|
-
"valve-ball": {
|
|
1793
|
-
id: "valve-ball",
|
|
1794
|
-
name: "Ball Valve",
|
|
1795
|
-
category: "valve",
|
|
1796
|
-
viewBox: { x: 0, y: 0, width: 50, height: 50 },
|
|
1797
|
-
ports: [
|
|
1798
|
-
{ id: "inlet", x: 0, y: 25, type: "inlet", direction: "in" },
|
|
1799
|
-
{ id: "outlet", x: 50, y: 25, type: "outlet", direction: "out" }
|
|
1800
|
-
],
|
|
1801
|
-
svgContent: `
|
|
1802
|
-
<g>
|
|
1803
|
-
<!-- Valve body -->
|
|
1804
|
-
<rect x="15" y="10" width="20" height="30" fill="#546e7a" stroke="#263238" stroke-width="2" rx="2"/>
|
|
1805
|
-
<!-- Ball indicator -->
|
|
1806
|
-
<circle cx="25" cy="25" r="6" fill="#ffa726" stroke="#e65100" stroke-width="1.5"/>
|
|
1807
|
-
<!-- Inlet/outlet lines -->
|
|
1808
|
-
<line x1="0" y1="25" x2="15" y2="25" stroke="#263238" stroke-width="3" stroke-linecap="round"/>
|
|
1809
|
-
<line x1="35" y1="25" x2="50" y2="25" stroke="#263238" stroke-width="3" stroke-linecap="round"/>
|
|
1810
|
-
</g>
|
|
1811
|
-
`,
|
|
1812
|
-
metadata: {
|
|
1813
|
-
description: "Ball valve for flow control",
|
|
1814
|
-
tags: ["valve", "control", "shutoff"]
|
|
1815
|
-
}
|
|
1816
|
-
},
|
|
1817
1793
|
"valve-gate": {
|
|
1818
1794
|
id: "valve-gate",
|
|
1819
1795
|
name: "Gate Valve (Powered)",
|
|
@@ -1826,11 +1802,11 @@ var mockSymbolLibrary = {
|
|
|
1826
1802
|
svgContent: `
|
|
1827
1803
|
<g>
|
|
1828
1804
|
<!-- Actuator box -->
|
|
1829
|
-
<rect x="16.74" y="0" width="18.02" height="18.02" fill="#edeeef" stroke="#666666" pointer-events="all"/>
|
|
1805
|
+
<rect x="16.74" y="0" width="18.02" height="18.02" fill="var(--symbol-fill, #edeeef)" stroke="var(--symbol-stroke, #666666)" pointer-events="all"/>
|
|
1830
1806
|
<!-- Actuator stem -->
|
|
1831
|
-
<path d="M 25.75 18.02 L 25.75 36.05" fill="none" stroke="#666666" stroke-linejoin="round" stroke-miterlimit="10" pointer-events="all"/>
|
|
1807
|
+
<path d="M 25.75 18.02 L 25.75 36.05" fill="none" stroke="var(--symbol-stroke, #666666)" stroke-linejoin="round" stroke-miterlimit="10" pointer-events="all"/>
|
|
1832
1808
|
<!-- Valve body (two triangles forming diamond) -->
|
|
1833
|
-
<path d="M 0 20.6 L 25.75 36.05 L 0 51.5 Z M 51.5 20.6 L 25.75 36.05 L 51.5 51.5 Z" fill="#edeeef" stroke="#666666" stroke-linejoin="round" stroke-miterlimit="10" pointer-events="all"/>
|
|
1809
|
+
<path d="M 0 20.6 L 25.75 36.05 L 0 51.5 Z M 51.5 20.6 L 25.75 36.05 L 51.5 51.5 Z" fill="var(--symbol-fill, #edeeef)" stroke="var(--symbol-stroke, #666666)" stroke-linejoin="round" stroke-miterlimit="10" pointer-events="all"/>
|
|
1834
1810
|
</g>
|
|
1835
1811
|
`,
|
|
1836
1812
|
metadata: {
|
|
@@ -1838,84 +1814,1143 @@ var mockSymbolLibrary = {
|
|
|
1838
1814
|
tags: ["valve", "gate", "powered", "actuator"]
|
|
1839
1815
|
}
|
|
1840
1816
|
},
|
|
1841
|
-
"pump-
|
|
1842
|
-
id: "pump-
|
|
1843
|
-
name: "
|
|
1817
|
+
"pump-positive-displacement": {
|
|
1818
|
+
id: "pump-positive-displacement",
|
|
1819
|
+
name: "Positive Displacement Pump",
|
|
1844
1820
|
category: "pump",
|
|
1845
|
-
viewBox: { x: 0, y: 0, width:
|
|
1821
|
+
viewBox: { x: 0, y: 0, width: 56.25, height: 56.25 },
|
|
1846
1822
|
ports: [
|
|
1847
|
-
{ id: "inlet", x:
|
|
1848
|
-
{ id: "outlet", x:
|
|
1823
|
+
{ id: "inlet", x: 0, y: 28.125, type: "inlet", direction: "in" },
|
|
1824
|
+
{ id: "outlet", x: 56.25, y: 28.125, type: "outlet", direction: "out" }
|
|
1825
|
+
],
|
|
1826
|
+
svgContent: `
|
|
1827
|
+
<g transform="scale(0.5625)">
|
|
1828
|
+
<!-- Outer circle -->
|
|
1829
|
+
<ellipse
|
|
1830
|
+
cx="50"
|
|
1831
|
+
cy="50"
|
|
1832
|
+
rx="50"
|
|
1833
|
+
ry="50"
|
|
1834
|
+
fill="var(--symbol-fill, #edeeef)"
|
|
1835
|
+
stroke="var(--symbol-stroke, rgb(0, 0, 0))"
|
|
1836
|
+
stroke-width="1"
|
|
1837
|
+
/>
|
|
1838
|
+
|
|
1839
|
+
<!-- Diagonal line from top to bottom-right -->
|
|
1840
|
+
<path
|
|
1841
|
+
d="M 50 0 L 100 50 L 50 100"
|
|
1842
|
+
fill="none"
|
|
1843
|
+
stroke="var(--symbol-stroke, rgb(0, 0, 0))"
|
|
1844
|
+
stroke-width="1"
|
|
1845
|
+
stroke-miterlimit="10"
|
|
1846
|
+
/>
|
|
1847
|
+
|
|
1848
|
+
<!-- Center square -->
|
|
1849
|
+
<rect
|
|
1850
|
+
x="35"
|
|
1851
|
+
y="35"
|
|
1852
|
+
width="30"
|
|
1853
|
+
height="30"
|
|
1854
|
+
fill="none"
|
|
1855
|
+
stroke="var(--symbol-stroke, rgb(0, 0, 0))"
|
|
1856
|
+
stroke-width="1"
|
|
1857
|
+
/>
|
|
1858
|
+
</g>
|
|
1859
|
+
`,
|
|
1860
|
+
metadata: {
|
|
1861
|
+
description: "Positive displacement pump (ISO standard)",
|
|
1862
|
+
tags: ["pump", "positive-displacement", "iso"]
|
|
1863
|
+
}
|
|
1864
|
+
},
|
|
1865
|
+
"vannefold-bottom": {
|
|
1866
|
+
id: "vannefold-bottom",
|
|
1867
|
+
name: "Vannefold Block (Bottom)",
|
|
1868
|
+
category: "valve",
|
|
1869
|
+
viewBox: { x: -0.5, y: -0.5, width: 88, height: 67.785156 },
|
|
1870
|
+
ports: [
|
|
1871
|
+
{ id: "bottom-inlet", x: 0, y: 25, type: "control", direction: "in" },
|
|
1872
|
+
{ id: "top-outlet", x: 48, y: 65, type: "control", direction: "out" }
|
|
1849
1873
|
],
|
|
1850
1874
|
svgContent: `
|
|
1851
1875
|
<g>
|
|
1852
|
-
<!--
|
|
1853
|
-
<
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1876
|
+
<!-- Bottom inlet pipe -->
|
|
1877
|
+
<path
|
|
1878
|
+
d="M 3,29.785156 H 0 v -10 h 3 m 14,10 h 3 v -10 h -3 m -15,8 h 16 m -16,-6 h 16"
|
|
1879
|
+
fill="none"
|
|
1880
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1881
|
+
stroke-miterlimit="10"
|
|
1882
|
+
/>
|
|
1883
|
+
|
|
1884
|
+
<!-- Top outlet pipe -->
|
|
1885
|
+
<path
|
|
1886
|
+
d="m 43,49.785156 v -3 h 10 v 3 m -10,14 v 3 h 10 v -3 m -8,-15 v 16 m 6,-16 v 16"
|
|
1887
|
+
fill="none"
|
|
1888
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1889
|
+
stroke-miterlimit="10"
|
|
1890
|
+
/>
|
|
1891
|
+
|
|
1892
|
+
<!-- Main block outer -->
|
|
1893
|
+
<rect
|
|
1894
|
+
x="7"
|
|
1895
|
+
y="0"
|
|
1896
|
+
width="80"
|
|
1897
|
+
height="59.785156"
|
|
1898
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
1899
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1900
|
+
/>
|
|
1901
|
+
|
|
1902
|
+
<!-- Main block inner -->
|
|
1903
|
+
<rect
|
|
1904
|
+
x="9"
|
|
1905
|
+
y="2"
|
|
1906
|
+
width="76"
|
|
1907
|
+
height="55.785156"
|
|
1908
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
1909
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1910
|
+
/>
|
|
1911
|
+
|
|
1912
|
+
<!-- Bolt holes -->
|
|
1913
|
+
<ellipse cx="15" cy="7" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1914
|
+
<ellipse cx="15" cy="7" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1915
|
+
<ellipse cx="79" cy="7" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1916
|
+
<ellipse cx="79" cy="7" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1917
|
+
<ellipse cx="15" cy="51.785156" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1918
|
+
<ellipse cx="15" cy="51.785156" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1919
|
+
<ellipse cx="79" cy="51.785156" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1920
|
+
<ellipse cx="79" cy="51.785156" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1921
|
+
|
|
1863
1922
|
</g>
|
|
1864
1923
|
`,
|
|
1865
1924
|
metadata: {
|
|
1866
|
-
description: "
|
|
1867
|
-
tags: ["
|
|
1925
|
+
description: "Vannefold heat exchanger block with bottom inlet configuration",
|
|
1926
|
+
tags: ["heat-exchanger", "vannefold", "fold", "bottom"]
|
|
1868
1927
|
}
|
|
1869
1928
|
},
|
|
1870
|
-
"
|
|
1871
|
-
id: "
|
|
1872
|
-
name: "
|
|
1873
|
-
category: "
|
|
1874
|
-
viewBox: { x: 0, y: 0, width:
|
|
1929
|
+
"vannefold-middle": {
|
|
1930
|
+
id: "vannefold-middle",
|
|
1931
|
+
name: "Vannefold Block (Middle)",
|
|
1932
|
+
category: "valve",
|
|
1933
|
+
viewBox: { x: -0.5, y: -0.5, width: 95, height: 53.097656 },
|
|
1875
1934
|
ports: [
|
|
1876
|
-
{ id: "inlet", x:
|
|
1877
|
-
{ id: "outlet", x:
|
|
1935
|
+
{ id: "left-inlet", x: 0, y: 27.3125, type: "control", direction: "in" },
|
|
1936
|
+
{ id: "right-outlet", x: 95, y: 27.3125, type: "control", direction: "out" }
|
|
1878
1937
|
],
|
|
1879
1938
|
svgContent: `
|
|
1880
1939
|
<g>
|
|
1881
|
-
<!--
|
|
1882
|
-
<
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
<!--
|
|
1890
|
-
<
|
|
1940
|
+
<!-- Left inlet pipe -->
|
|
1941
|
+
<path
|
|
1942
|
+
d="M 3,22.3125 H 0 v 10 H 3 m 14,-10 h 3 v 10 h -3 m -15,-8 h 16 m -16,6 h 16"
|
|
1943
|
+
fill="none"
|
|
1944
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1945
|
+
stroke-miterlimit="10"
|
|
1946
|
+
/>
|
|
1947
|
+
|
|
1948
|
+
<!-- Main block outer -->
|
|
1949
|
+
<rect
|
|
1950
|
+
x="7"
|
|
1951
|
+
y="0"
|
|
1952
|
+
width="80"
|
|
1953
|
+
height="52.097656"
|
|
1954
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
1955
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1956
|
+
/>
|
|
1957
|
+
|
|
1958
|
+
<!-- Main block inner -->
|
|
1959
|
+
<rect
|
|
1960
|
+
x="9"
|
|
1961
|
+
y="0"
|
|
1962
|
+
width="76"
|
|
1963
|
+
height="52.097656"
|
|
1964
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
1965
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1966
|
+
/>
|
|
1967
|
+
|
|
1968
|
+
<!-- Bolt holes -->
|
|
1969
|
+
<ellipse cx="15" cy="5.3125" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1970
|
+
<ellipse cx="15" cy="5.3125" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1971
|
+
<ellipse cx="79" cy="5.3125" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1972
|
+
<ellipse cx="79" cy="5.3125" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1973
|
+
<ellipse cx="15" cy="47.3125" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1974
|
+
<ellipse cx="15" cy="47.3125" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1975
|
+
<ellipse cx="79" cy="47.3125" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1976
|
+
<ellipse cx="79" cy="47.3125" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1891
1977
|
</g>
|
|
1892
1978
|
`,
|
|
1893
1979
|
metadata: {
|
|
1894
|
-
description: "
|
|
1895
|
-
tags: ["
|
|
1980
|
+
description: "Vannefold heat exchanger block with side inlet configuration",
|
|
1981
|
+
tags: ["heat-exchanger", "vannefold", "fold", "middle"]
|
|
1896
1982
|
}
|
|
1897
1983
|
},
|
|
1898
|
-
"
|
|
1899
|
-
id: "
|
|
1900
|
-
name: "
|
|
1901
|
-
category: "
|
|
1902
|
-
viewBox: { x: 0, y: 0, width:
|
|
1984
|
+
"vannefold-top": {
|
|
1985
|
+
id: "vannefold-top",
|
|
1986
|
+
name: "Vannefold Block (Top)",
|
|
1987
|
+
category: "valve",
|
|
1988
|
+
viewBox: { x: -0.5, y: -0.5, width: 95, height: 60.785156 },
|
|
1989
|
+
ports: [
|
|
1990
|
+
{ id: "bottom-inlet", x: 0, y: 35, type: "control", direction: "in" },
|
|
1991
|
+
{ id: "top-outlet", x: 48, y: 0, type: "control", direction: "out" }
|
|
1992
|
+
],
|
|
1993
|
+
svgContent: `
|
|
1994
|
+
<g>
|
|
1995
|
+
<!-- Bottom inlet pipe -->
|
|
1996
|
+
<path
|
|
1997
|
+
d="M 3,30 H 0 V 40 H 3 M 17,30 h 3 V 40 H 17 M 2,32 H 18 M 2,38 H 18"
|
|
1998
|
+
fill="none"
|
|
1999
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2000
|
+
stroke-miterlimit="10"
|
|
2001
|
+
/>
|
|
2002
|
+
|
|
2003
|
+
<!-- Main block outer -->
|
|
2004
|
+
<rect
|
|
2005
|
+
x="7"
|
|
2006
|
+
y="0"
|
|
2007
|
+
width="80"
|
|
2008
|
+
height="59.785156"
|
|
2009
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2010
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2011
|
+
/>
|
|
2012
|
+
|
|
2013
|
+
<!-- Main block inner -->
|
|
2014
|
+
<rect
|
|
2015
|
+
x="9"
|
|
2016
|
+
y="2"
|
|
2017
|
+
width="76"
|
|
2018
|
+
height="57.785156"
|
|
2019
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2020
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2021
|
+
/>
|
|
2022
|
+
|
|
2023
|
+
<!-- Bolt holes -->
|
|
2024
|
+
<ellipse cx="15" cy="8" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2025
|
+
<ellipse cx="15" cy="8" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2026
|
+
<ellipse cx="79" cy="8" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2027
|
+
<ellipse cx="79" cy="8" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2028
|
+
<ellipse cx="15" cy="55" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2029
|
+
<ellipse cx="15" cy="55" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2030
|
+
<ellipse cx="79" cy="55" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2031
|
+
<ellipse cx="79" cy="55" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2032
|
+
|
|
2033
|
+
</g>
|
|
2034
|
+
`,
|
|
2035
|
+
metadata: {
|
|
2036
|
+
description: "Vannefold heat exchanger block with bottom inlet and top outlet configuration",
|
|
2037
|
+
tags: ["heat-exchanger", "vannefold", "fold", "top"]
|
|
2038
|
+
}
|
|
2039
|
+
},
|
|
2040
|
+
"vannefold-top-top-inlet": {
|
|
2041
|
+
id: "vannefold-top-top-inlet",
|
|
2042
|
+
name: "Vannefold Block (Top, Top Inlet)",
|
|
2043
|
+
category: "valve",
|
|
2044
|
+
viewBox: { x: 0, y: 0, width: 88, height: 67.576004 },
|
|
2045
|
+
ports: [
|
|
2046
|
+
{ id: "top-inlet", x: 47, y: 0, type: "control", direction: "in" },
|
|
2047
|
+
{ id: "bottom-outlet", x: 0, y: 42, type: "control", direction: "out" }
|
|
2048
|
+
],
|
|
2049
|
+
svgContent: `
|
|
2050
|
+
<g>
|
|
2051
|
+
<!-- Top inlet pipe flange -->
|
|
2052
|
+
<path
|
|
2053
|
+
d="M 52,3 V 1.3598666e-8 H 42 V 3 m 10,14 v 3 H 42 V 17 M 50,2 V 18 M 44,2 v 16"
|
|
2054
|
+
fill="none"
|
|
2055
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2056
|
+
stroke-miterlimit="10"
|
|
2057
|
+
/>
|
|
2058
|
+
|
|
2059
|
+
<!-- Bottom outlet pipe flange -->
|
|
2060
|
+
<path
|
|
2061
|
+
d="M 3,36.79085 H 0 v 10 h 3 m 14,-10 h 3 v 10 h -3 m -15,-8 h 16 m -16,6 h 16"
|
|
2062
|
+
fill="none"
|
|
2063
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2064
|
+
stroke-miterlimit="10"
|
|
2065
|
+
/>
|
|
2066
|
+
|
|
2067
|
+
<!-- Main block outer -->
|
|
2068
|
+
<rect
|
|
2069
|
+
x="7"
|
|
2070
|
+
y="6.7908498"
|
|
2071
|
+
width="80"
|
|
2072
|
+
height="59.785156"
|
|
2073
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2074
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2075
|
+
/>
|
|
2076
|
+
|
|
2077
|
+
<!-- Main block inner -->
|
|
2078
|
+
<rect
|
|
2079
|
+
x="9"
|
|
2080
|
+
y="8.7908498"
|
|
2081
|
+
width="76"
|
|
2082
|
+
height="57.785156"
|
|
2083
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2084
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2085
|
+
/>
|
|
2086
|
+
|
|
2087
|
+
<!-- Bolt holes -->
|
|
2088
|
+
<ellipse cx="15" cy="14.79085" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2089
|
+
<ellipse cx="15" cy="14.79085" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2090
|
+
<ellipse cx="15" cy="61.79085" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2091
|
+
<ellipse cx="15" cy="61.79085" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2092
|
+
<ellipse cx="79" cy="14.79085" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2093
|
+
<ellipse cx="79" cy="14.79085" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2094
|
+
<ellipse cx="79" cy="61.79085" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2095
|
+
<ellipse cx="79" cy="61.79085" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2096
|
+
|
|
2097
|
+
</g>
|
|
2098
|
+
`,
|
|
2099
|
+
metadata: {
|
|
2100
|
+
description: "Vannefold heat exchanger block with top inlet and bottom outlet configuration",
|
|
2101
|
+
tags: ["heat-exchanger", "vannefold", "fold", "top", "top-inlet"]
|
|
2102
|
+
}
|
|
2103
|
+
},
|
|
2104
|
+
"vannefold-left": {
|
|
2105
|
+
id: "vannefold-left",
|
|
2106
|
+
name: "Vannefold Block (Left)",
|
|
2107
|
+
category: "valve",
|
|
2108
|
+
viewBox: { x: 0, y: 0, width: 67.785156, height: 88.5 },
|
|
2109
|
+
ports: [
|
|
2110
|
+
{ id: "left-inlet", x: 0, y: 41.5, type: "control", direction: "in" },
|
|
2111
|
+
{ id: "right-outlet", x: 42, y: 87, type: "control", direction: "out" }
|
|
2112
|
+
],
|
|
2113
|
+
svgContent: `
|
|
2114
|
+
<g>
|
|
2115
|
+
<!-- Left inlet pipe flange -->
|
|
2116
|
+
<path
|
|
2117
|
+
d="M 3,46.5 H 2.8789924e-8 v -10 H 3 m 14,10 h 3 v -10 h -3 m -15,8 h 16 m -16,-6 h 16"
|
|
2118
|
+
fill="none"
|
|
2119
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2120
|
+
stroke-miterlimit="10"
|
|
2121
|
+
/>
|
|
2122
|
+
|
|
2123
|
+
<!-- Right outlet pipe flange -->
|
|
2124
|
+
<path
|
|
2125
|
+
d="m 37,70.5 v -3 h 10 v 3 m -10,14 v 3 h 10 v -3 m -8,-15 v 16 m 6,-16 v 16"
|
|
2126
|
+
fill="none"
|
|
2127
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2128
|
+
stroke-miterlimit="10"
|
|
2129
|
+
/>
|
|
2130
|
+
|
|
2131
|
+
<!-- Main block outer -->
|
|
2132
|
+
<rect
|
|
2133
|
+
x="7"
|
|
2134
|
+
y="0.5"
|
|
2135
|
+
width="59.785156"
|
|
2136
|
+
height="80"
|
|
2137
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2138
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2139
|
+
/>
|
|
2140
|
+
|
|
2141
|
+
<!-- Main block inner -->
|
|
2142
|
+
<rect
|
|
2143
|
+
x="9"
|
|
2144
|
+
y="2.5"
|
|
2145
|
+
width="57.785156"
|
|
2146
|
+
height="76"
|
|
2147
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2148
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2149
|
+
/>
|
|
2150
|
+
|
|
2151
|
+
<!-- Bolt holes -->
|
|
2152
|
+
<ellipse cx="15" cy="8.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2153
|
+
<ellipse cx="15" cy="8.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2154
|
+
<ellipse cx="62" cy="8.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2155
|
+
<ellipse cx="62" cy="8.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2156
|
+
<ellipse cx="15" cy="72.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2157
|
+
<ellipse cx="15" cy="72.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2158
|
+
<ellipse cx="62" cy="72.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2159
|
+
<ellipse cx="62" cy="72.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2160
|
+
|
|
2161
|
+
`,
|
|
2162
|
+
metadata: {
|
|
2163
|
+
description: "Vannefold heat exchanger block with left inlet and right outlet, vertical orientation",
|
|
2164
|
+
tags: ["heat-exchanger", "vannefold", "fold", "left", "vertical"]
|
|
2165
|
+
}
|
|
2166
|
+
},
|
|
2167
|
+
"vannefold-right": {
|
|
2168
|
+
id: "vannefold-right",
|
|
2169
|
+
name: "Vannefold Block (Right)",
|
|
2170
|
+
category: "valve",
|
|
2171
|
+
viewBox: { x: 0, y: 0, width: 67.785156, height: 88.5 },
|
|
1903
2172
|
ports: [
|
|
1904
|
-
{ id: "
|
|
2173
|
+
{ id: "right-inlet", x: 67.785156, y: 41.5, type: "control", direction: "in" },
|
|
2174
|
+
{ id: "left-outlet", x: 24.785156, y: 87.5, type: "control", direction: "out" }
|
|
1905
2175
|
],
|
|
1906
2176
|
svgContent: `
|
|
1907
2177
|
<g>
|
|
1908
|
-
<!--
|
|
1909
|
-
<
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
2178
|
+
<!-- Right inlet pipe flange -->
|
|
2179
|
+
<path
|
|
2180
|
+
d="m 63.785156,46.5 h 3 v -10 h -3 m -14,10 h -3 v -10 h 3 m 15,8 h -16 m 16,-6 h -16"
|
|
2181
|
+
fill="none"
|
|
2182
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2183
|
+
stroke-miterlimit="10"
|
|
2184
|
+
/>
|
|
2185
|
+
|
|
2186
|
+
<!-- Left outlet pipe flange -->
|
|
2187
|
+
<path
|
|
2188
|
+
d="m 29.785156,70.5 v -3 h -10 v 3 m 10,14 v 3 h -10 v -3 m 8,-15 v 16 m -6,-16 v 16"
|
|
2189
|
+
fill="none"
|
|
2190
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2191
|
+
stroke-miterlimit="10"
|
|
2192
|
+
/>
|
|
2193
|
+
|
|
2194
|
+
<!-- Main block outer -->
|
|
2195
|
+
<rect
|
|
2196
|
+
x="0"
|
|
2197
|
+
y="0.5"
|
|
2198
|
+
width="59.785156"
|
|
2199
|
+
height="80"
|
|
2200
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2201
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2202
|
+
/>
|
|
2203
|
+
|
|
2204
|
+
<!-- Main block inner -->
|
|
2205
|
+
<rect
|
|
2206
|
+
x="0"
|
|
2207
|
+
y="2.5"
|
|
2208
|
+
width="57.785156"
|
|
2209
|
+
height="76"
|
|
2210
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2211
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2212
|
+
/>
|
|
2213
|
+
|
|
2214
|
+
<!-- Bolt holes -->
|
|
2215
|
+
<ellipse cx="51.785156" cy="8.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2216
|
+
<ellipse cx="51.785156" cy="8.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2217
|
+
<ellipse cx="4.785156" cy="8.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2218
|
+
<ellipse cx="4.785156" cy="8.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2219
|
+
<ellipse cx="51.785156" cy="72.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2220
|
+
<ellipse cx="51.785156" cy="72.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2221
|
+
<ellipse cx="4.785156" cy="72.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2222
|
+
<ellipse cx="4.785156" cy="72.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2223
|
+
|
|
2224
|
+
`,
|
|
2225
|
+
metadata: {
|
|
2226
|
+
description: "Vannefold heat exchanger block with right inlet and left outlet, vertical orientation",
|
|
2227
|
+
tags: ["heat-exchanger", "vannefold", "fold", "right", "vertical"]
|
|
2228
|
+
}
|
|
2229
|
+
},
|
|
2230
|
+
"pixer": {
|
|
2231
|
+
id: "pixer",
|
|
2232
|
+
name: "Pixer",
|
|
2233
|
+
category: "pump",
|
|
2234
|
+
viewBox: { x: 0, y: 0, width: 50.625, height: 46.6875 },
|
|
2235
|
+
ports: [
|
|
2236
|
+
{ id: "right-outlet", x: 50.625, y: 30.9375, type: "control", direction: "out" },
|
|
2237
|
+
{ id: "left-outlet", x: 0, y: 30.9375, type: "control", direction: "out" },
|
|
2238
|
+
{ id: "left-inlet", x: 50.625, y: 19.6875, type: "control", direction: "in" },
|
|
2239
|
+
{ id: "right-inlet", x: 0, y: 19.6875, type: "control", direction: "in" },
|
|
2240
|
+
{ id: "top-inlet", x: 25.3125, y: 0, type: "control", direction: "in" }
|
|
2241
|
+
],
|
|
2242
|
+
svgContent: `
|
|
2243
|
+
<g transform="scale(0.196875) translate(-195, -186)">
|
|
2244
|
+
<!-- Top mounting flange -->
|
|
2245
|
+
<rect
|
|
2246
|
+
width="141.313"
|
|
2247
|
+
height="9.872"
|
|
2248
|
+
transform="translate(252.392 185.89)"
|
|
2249
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2250
|
+
stroke-miterlimit="10"
|
|
2251
|
+
stroke-width="1"
|
|
2252
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2253
|
+
/>
|
|
2254
|
+
|
|
2255
|
+
<!-- Motor housing top -->
|
|
2256
|
+
<rect
|
|
2257
|
+
width="106.614"
|
|
2258
|
+
height="2.468"
|
|
2259
|
+
transform="translate(269.742 199.918)"
|
|
2260
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2261
|
+
stroke-miterlimit="10"
|
|
2262
|
+
stroke-width="1"
|
|
2263
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2264
|
+
/>
|
|
2265
|
+
<rect
|
|
2266
|
+
width="106.614"
|
|
2267
|
+
height="5.835"
|
|
2268
|
+
transform="translate(269.742 202.384)"
|
|
2269
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2270
|
+
stroke-miterlimit="10"
|
|
2271
|
+
stroke-width="1"
|
|
2272
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2273
|
+
/>
|
|
2274
|
+
<rect
|
|
2275
|
+
width="106.614"
|
|
2276
|
+
height="2.468"
|
|
2277
|
+
transform="translate(269.742 208.222)"
|
|
2278
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2279
|
+
stroke-miterlimit="10"
|
|
2280
|
+
stroke-width="1"
|
|
2281
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2282
|
+
/>
|
|
2283
|
+
|
|
2284
|
+
<!-- Bottom mounting flange -->
|
|
2285
|
+
<rect
|
|
2286
|
+
width="221.702"
|
|
2287
|
+
height="2.401"
|
|
2288
|
+
transform="translate(212.199 395.587)"
|
|
2289
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2290
|
+
stroke-miterlimit="10"
|
|
2291
|
+
stroke-width="1"
|
|
2292
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2293
|
+
/>
|
|
2294
|
+
<rect
|
|
2295
|
+
width="221.702"
|
|
2296
|
+
height="6.269"
|
|
2297
|
+
transform="translate(212.199 397.988)"
|
|
2298
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2299
|
+
stroke-miterlimit="10"
|
|
2300
|
+
stroke-width="1"
|
|
2301
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2302
|
+
/>
|
|
2303
|
+
<rect
|
|
2304
|
+
width="221.702"
|
|
2305
|
+
height="2.65"
|
|
2306
|
+
transform="translate(212.199 404.257)"
|
|
2307
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2308
|
+
stroke-miterlimit="10"
|
|
2309
|
+
stroke-width="1"
|
|
2310
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2311
|
+
/>
|
|
2312
|
+
|
|
2313
|
+
<!-- Motor housing transition -->
|
|
2314
|
+
<path
|
|
2315
|
+
d="M444.7,228.776l17.117,4.1H568.429l17.089-4.085a.032.032,0,0,0,0-.062H444.705a.028.028,0,0,0-.007.046Z"
|
|
2316
|
+
transform="translate(-192.059 -32.959)"
|
|
2317
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2318
|
+
stroke-miterlimit="10"
|
|
2319
|
+
stroke-width="1"
|
|
2320
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2321
|
+
/>
|
|
2322
|
+
|
|
2323
|
+
<!-- Bottom flange -->
|
|
2324
|
+
<rect
|
|
2325
|
+
width="256"
|
|
2326
|
+
height="9.872"
|
|
2327
|
+
transform="translate(195.05 411.066)"
|
|
2328
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2329
|
+
stroke-miterlimit="10"
|
|
2330
|
+
stroke-width="1"
|
|
2331
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2332
|
+
/>
|
|
2333
|
+
<path
|
|
2334
|
+
d="M195.05,1148.286l17.149-4.156H433.9l17.149,4.156Z"
|
|
2335
|
+
transform="translate(0 -737.221)"
|
|
2336
|
+
fill="var(--symbol-fill, #e2e2e2)"
|
|
2337
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2338
|
+
stroke-miterlimit="10"
|
|
2339
|
+
stroke-width="1"
|
|
2340
|
+
/>
|
|
2341
|
+
|
|
2342
|
+
<!-- Vessel top cone -->
|
|
2343
|
+
<path
|
|
2344
|
+
d="M451.05,328.356h-256l74.692-34.946H376.358Z"
|
|
2345
|
+
transform="translate(0 -82.72)"
|
|
2346
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2347
|
+
stroke-miterlimit="10"
|
|
2348
|
+
stroke-width="1"
|
|
2349
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2350
|
+
/>
|
|
2351
|
+
|
|
2352
|
+
<!-- Main vessel body -->
|
|
2353
|
+
<rect
|
|
2354
|
+
width="256"
|
|
2355
|
+
height="59.803"
|
|
2356
|
+
transform="translate(195.05 245.636)"
|
|
2357
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2358
|
+
stroke-miterlimit="10"
|
|
2359
|
+
stroke-width="1"
|
|
2360
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2361
|
+
/>
|
|
2362
|
+
<rect
|
|
2363
|
+
width="256"
|
|
2364
|
+
height="76.892"
|
|
2365
|
+
transform="translate(195.05 308.417)"
|
|
2366
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2367
|
+
stroke-miterlimit="10"
|
|
2368
|
+
stroke-width="1"
|
|
2369
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2370
|
+
/>
|
|
2371
|
+
|
|
2372
|
+
<!-- Vessel bottom transitions -->
|
|
2373
|
+
<path
|
|
2374
|
+
d="M449.265,705.7H196.773l-1.654-1.465a.014.014,0,0,1,0-.023H451.078Z"
|
|
2375
|
+
transform="translate(-0.049 -398.769)"
|
|
2376
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2377
|
+
stroke-miterlimit="10"
|
|
2378
|
+
stroke-width="1"
|
|
2379
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2380
|
+
/>
|
|
2381
|
+
<path
|
|
2382
|
+
d="M449.278,710.66H196.793l-1.663,1.462v.016H451.086s.012,0,0-.016Z"
|
|
2383
|
+
transform="translate(-0.062 -403.731)"
|
|
2384
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2385
|
+
stroke-miterlimit="10"
|
|
2386
|
+
stroke-width="1"
|
|
2387
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2388
|
+
/>
|
|
2389
|
+
<path
|
|
2390
|
+
d="M433.9,1060.758H212.2L195.05,1050.48h256Z"
|
|
2391
|
+
transform="translate(0 -665.171)"
|
|
2392
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2393
|
+
stroke-miterlimit="10"
|
|
2394
|
+
stroke-width="1"
|
|
2395
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2396
|
+
/>
|
|
2397
|
+
|
|
2398
|
+
<!-- Agitator blades/impellers (simplified without gradients) -->
|
|
2399
|
+
<ellipse
|
|
2400
|
+
cx="15.454"
|
|
2401
|
+
cy="6.096"
|
|
2402
|
+
rx="15.454"
|
|
2403
|
+
ry="6.096"
|
|
2404
|
+
transform="translate(307.486 228.161)"
|
|
2405
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2406
|
+
stroke-miterlimit="10"
|
|
2407
|
+
stroke-width="1"
|
|
2408
|
+
fill="var(--symbol-fill, #c0c0c0)"
|
|
2409
|
+
/>
|
|
2410
|
+
<ellipse
|
|
2411
|
+
cx="15.454"
|
|
2412
|
+
cy="5.3"
|
|
2413
|
+
rx="15.454"
|
|
2414
|
+
ry="5.3"
|
|
2415
|
+
transform="translate(307.486 229.753)"
|
|
2416
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2417
|
+
stroke-miterlimit="10"
|
|
2418
|
+
stroke-width="1"
|
|
2419
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2420
|
+
/>
|
|
2421
|
+
<ellipse
|
|
2422
|
+
cx="5.174"
|
|
2423
|
+
cy="15.117"
|
|
2424
|
+
rx="5.174"
|
|
2425
|
+
ry="15.117"
|
|
2426
|
+
transform="translate(367.144 236.079) rotate(-77.61)"
|
|
2427
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2428
|
+
stroke-miterlimit="10"
|
|
2429
|
+
stroke-width="1"
|
|
2430
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2431
|
+
/>
|
|
2432
|
+
<path
|
|
2433
|
+
d="M947,380.271s1.631-2.83,8.084-2.235c5.427.5,16.927,2.855,20.574,8.26"
|
|
2434
|
+
transform="translate(-578.512 -147.764)"
|
|
2435
|
+
fill="none"
|
|
2436
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2437
|
+
stroke-miterlimit="10"
|
|
2438
|
+
stroke-width="1"
|
|
2439
|
+
/>
|
|
2440
|
+
<ellipse
|
|
2441
|
+
cx="15.117"
|
|
2442
|
+
cy="5.174"
|
|
2443
|
+
rx="15.117"
|
|
2444
|
+
ry="5.174"
|
|
2445
|
+
transform="translate(247 232.438) rotate(-12.39)"
|
|
2446
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2447
|
+
stroke-miterlimit="10"
|
|
2448
|
+
stroke-width="1"
|
|
2449
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2450
|
+
/>
|
|
2451
|
+
<path
|
|
2452
|
+
d="M456.439,380.271s-1.631-2.83-8.073-2.235c-5.43.5-16.93,2.855-20.576,8.26"
|
|
2453
|
+
transform="translate(-179.058 -147.764)"
|
|
2454
|
+
fill="none"
|
|
2455
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2456
|
+
stroke-miterlimit="10"
|
|
2457
|
+
stroke-width="1"
|
|
2458
|
+
/>
|
|
2459
|
+
<ellipse
|
|
2460
|
+
cx="1.651"
|
|
2461
|
+
cy="15.082"
|
|
2462
|
+
rx="1.651"
|
|
2463
|
+
ry="15.082"
|
|
2464
|
+
transform="translate(406.71 230.174) rotate(-68.13)"
|
|
2465
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2466
|
+
stroke-miterlimit="10"
|
|
2467
|
+
stroke-width="1"
|
|
2468
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2469
|
+
/>
|
|
2470
|
+
<path
|
|
2471
|
+
d="M1119,375.62a119.876,119.876,0,0,1,26.193,10.419"
|
|
2472
|
+
transform="translate(-710.84 -145.969)"
|
|
2473
|
+
fill="none"
|
|
2474
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2475
|
+
stroke-miterlimit="10"
|
|
2476
|
+
stroke-width="1"
|
|
2477
|
+
/>
|
|
2478
|
+
<ellipse
|
|
2479
|
+
cx="15.082"
|
|
2480
|
+
cy="1.651"
|
|
2481
|
+
rx="15.082"
|
|
2482
|
+
ry="1.651"
|
|
2483
|
+
transform="translate(210.225 238.342) rotate(-21.87)"
|
|
2484
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2485
|
+
stroke-miterlimit="10"
|
|
2486
|
+
stroke-width="1"
|
|
2487
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2488
|
+
/>
|
|
2489
|
+
<path
|
|
2490
|
+
d="M293.943,375.62a119.829,119.829,0,0,0-26.193,10.419"
|
|
2491
|
+
transform="translate(-55.932 -145.969)"
|
|
2492
|
+
fill="none"
|
|
2493
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2494
|
+
stroke-miterlimit="10"
|
|
2495
|
+
stroke-width="1"
|
|
2496
|
+
/>
|
|
2497
|
+
</g>
|
|
2498
|
+
`,
|
|
2499
|
+
metadata: {
|
|
2500
|
+
description: "Pixer mixer/agitator vessel with top-mounted drive",
|
|
2501
|
+
tags: ["vessel", "mixer", "agitator", "pixer", "tank"]
|
|
2502
|
+
}
|
|
2503
|
+
},
|
|
2504
|
+
"pixer-barb": {
|
|
2505
|
+
id: "pixer-barb",
|
|
2506
|
+
name: "Pixer (Hose Barb)",
|
|
2507
|
+
category: "pump",
|
|
2508
|
+
viewBox: { x: 0, y: 0, width: 50.625, height: 46.6875 },
|
|
2509
|
+
ports: [
|
|
2510
|
+
{ id: "right-outlet", x: 50.625, y: 30.9375, type: "control", direction: "out" },
|
|
2511
|
+
{ id: "left-outlet", x: 0, y: 30.9375, type: "control", direction: "out" },
|
|
2512
|
+
{ id: "left-inlet", x: 50.625, y: 19.6875, type: "control", direction: "in" },
|
|
2513
|
+
{ id: "right-inlet", x: 0, y: 19.6875, type: "control", direction: "in" },
|
|
2514
|
+
{ id: "top-inlet", x: 25.3125, y: 0, type: "control", direction: "in" }
|
|
2515
|
+
],
|
|
2516
|
+
svgContent: `
|
|
2517
|
+
<g transform="scale(0.196875) translate(-195, -186)">
|
|
2518
|
+
<!-- Hose barb ridges at top -->
|
|
2519
|
+
<rect
|
|
2520
|
+
width="20"
|
|
2521
|
+
height="2"
|
|
2522
|
+
transform="translate(313 173)"
|
|
2523
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2524
|
+
stroke-miterlimit="10"
|
|
2525
|
+
stroke-width="0.5"
|
|
2526
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2527
|
+
/>
|
|
2528
|
+
<rect
|
|
2529
|
+
width="20"
|
|
2530
|
+
height="2"
|
|
2531
|
+
transform="translate(313 177)"
|
|
2532
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2533
|
+
stroke-miterlimit="10"
|
|
2534
|
+
stroke-width="0.5"
|
|
2535
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2536
|
+
/>
|
|
2537
|
+
<rect
|
|
2538
|
+
width="20"
|
|
2539
|
+
height="2"
|
|
2540
|
+
transform="translate(313 181)"
|
|
2541
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2542
|
+
stroke-miterlimit="10"
|
|
2543
|
+
stroke-width="0.5"
|
|
2544
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2545
|
+
/>
|
|
2546
|
+
|
|
2547
|
+
<!-- Taper from barb to motor housing -->
|
|
2548
|
+
<path
|
|
2549
|
+
d="M 313,183 L 269.742,199.918 L 376.356,199.918 L 333,183 Z"
|
|
2550
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2551
|
+
stroke-miterlimit="10"
|
|
2552
|
+
stroke-width="1"
|
|
2553
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2554
|
+
/>
|
|
2555
|
+
|
|
2556
|
+
<!-- Motor housing top -->
|
|
2557
|
+
<rect
|
|
2558
|
+
width="106.614"
|
|
2559
|
+
height="2.468"
|
|
2560
|
+
transform="translate(269.742 199.918)"
|
|
2561
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2562
|
+
stroke-miterlimit="10"
|
|
2563
|
+
stroke-width="1"
|
|
2564
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2565
|
+
/>
|
|
2566
|
+
<rect
|
|
2567
|
+
width="106.614"
|
|
2568
|
+
height="5.835"
|
|
2569
|
+
transform="translate(269.742 202.384)"
|
|
2570
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2571
|
+
stroke-miterlimit="10"
|
|
2572
|
+
stroke-width="1"
|
|
2573
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2574
|
+
/>
|
|
2575
|
+
<rect
|
|
2576
|
+
width="106.614"
|
|
2577
|
+
height="2.468"
|
|
2578
|
+
transform="translate(269.742 208.222)"
|
|
2579
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2580
|
+
stroke-miterlimit="10"
|
|
2581
|
+
stroke-width="1"
|
|
2582
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2583
|
+
/>
|
|
2584
|
+
|
|
2585
|
+
<!-- Bottom mounting flange -->
|
|
2586
|
+
<rect
|
|
2587
|
+
width="221.702"
|
|
2588
|
+
height="2.401"
|
|
2589
|
+
transform="translate(212.199 395.587)"
|
|
2590
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2591
|
+
stroke-miterlimit="10"
|
|
2592
|
+
stroke-width="1"
|
|
2593
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2594
|
+
/>
|
|
2595
|
+
<rect
|
|
2596
|
+
width="221.702"
|
|
2597
|
+
height="6.269"
|
|
2598
|
+
transform="translate(212.199 397.988)"
|
|
2599
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2600
|
+
stroke-miterlimit="10"
|
|
2601
|
+
stroke-width="1"
|
|
2602
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2603
|
+
/>
|
|
2604
|
+
<rect
|
|
2605
|
+
width="221.702"
|
|
2606
|
+
height="2.65"
|
|
2607
|
+
transform="translate(212.199 404.257)"
|
|
2608
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2609
|
+
stroke-miterlimit="10"
|
|
2610
|
+
stroke-width="1"
|
|
2611
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2612
|
+
/>
|
|
2613
|
+
|
|
2614
|
+
<!-- Bottom flange -->
|
|
2615
|
+
<rect
|
|
2616
|
+
width="256"
|
|
2617
|
+
height="9.872"
|
|
2618
|
+
transform="translate(195.05 411.066)"
|
|
2619
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2620
|
+
stroke-miterlimit="10"
|
|
2621
|
+
stroke-width="1"
|
|
2622
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2623
|
+
/>
|
|
2624
|
+
<path
|
|
2625
|
+
d="M195.05,1148.286l17.149-4.156H433.9l17.149,4.156Z"
|
|
2626
|
+
transform="translate(0 -737.221)"
|
|
2627
|
+
fill="var(--symbol-fill, #e2e2e2)"
|
|
2628
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2629
|
+
stroke-miterlimit="10"
|
|
2630
|
+
stroke-width="1"
|
|
2631
|
+
/>
|
|
2632
|
+
|
|
2633
|
+
<!-- Vessel top cone -->
|
|
2634
|
+
<path
|
|
2635
|
+
d="M451.05,328.356h-256l74.692-34.946H376.358Z"
|
|
2636
|
+
transform="translate(0 -82.72)"
|
|
2637
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2638
|
+
stroke-miterlimit="10"
|
|
2639
|
+
stroke-width="1"
|
|
2640
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2641
|
+
/>
|
|
2642
|
+
|
|
2643
|
+
<!-- Main vessel body -->
|
|
2644
|
+
<rect
|
|
2645
|
+
width="256"
|
|
2646
|
+
height="59.803"
|
|
2647
|
+
transform="translate(195.05 245.636)"
|
|
2648
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2649
|
+
stroke-miterlimit="10"
|
|
2650
|
+
stroke-width="1"
|
|
2651
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2652
|
+
/>
|
|
2653
|
+
<rect
|
|
2654
|
+
width="256"
|
|
2655
|
+
height="76.892"
|
|
2656
|
+
transform="translate(195.05 308.417)"
|
|
2657
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2658
|
+
stroke-miterlimit="10"
|
|
2659
|
+
stroke-width="1"
|
|
2660
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2661
|
+
/>
|
|
2662
|
+
|
|
2663
|
+
<!-- Vessel bottom transitions -->
|
|
2664
|
+
<path
|
|
2665
|
+
d="M449.265,705.7H196.773l-1.654-1.465a.014.014,0,0,1,0-.023H451.078Z"
|
|
2666
|
+
transform="translate(-0.049 -398.769)"
|
|
2667
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2668
|
+
stroke-miterlimit="10"
|
|
2669
|
+
stroke-width="1"
|
|
2670
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2671
|
+
/>
|
|
2672
|
+
<path
|
|
2673
|
+
d="M449.278,710.66H196.793l-1.663,1.462v.016H451.086s.012,0,0-.016Z"
|
|
2674
|
+
transform="translate(-0.062 -403.731)"
|
|
2675
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2676
|
+
stroke-miterlimit="10"
|
|
2677
|
+
stroke-width="1"
|
|
2678
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2679
|
+
/>
|
|
2680
|
+
<path
|
|
2681
|
+
d="M433.9,1060.758H212.2L195.05,1050.48h256Z"
|
|
2682
|
+
transform="translate(0 -665.171)"
|
|
2683
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2684
|
+
stroke-miterlimit="10"
|
|
2685
|
+
stroke-width="1"
|
|
2686
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2687
|
+
/>
|
|
2688
|
+
|
|
2689
|
+
<!-- Agitator blades/impellers (simplified without gradients) -->
|
|
2690
|
+
<ellipse
|
|
2691
|
+
cx="15.454"
|
|
2692
|
+
cy="6.096"
|
|
2693
|
+
rx="15.454"
|
|
2694
|
+
ry="6.096"
|
|
2695
|
+
transform="translate(307.486 228.161)"
|
|
2696
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2697
|
+
stroke-miterlimit="10"
|
|
2698
|
+
stroke-width="1"
|
|
2699
|
+
fill="var(--symbol-fill, #c0c0c0)"
|
|
2700
|
+
/>
|
|
2701
|
+
<ellipse
|
|
2702
|
+
cx="15.454"
|
|
2703
|
+
cy="5.3"
|
|
2704
|
+
rx="15.454"
|
|
2705
|
+
ry="5.3"
|
|
2706
|
+
transform="translate(307.486 229.753)"
|
|
2707
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2708
|
+
stroke-miterlimit="10"
|
|
2709
|
+
stroke-width="1"
|
|
2710
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2711
|
+
/>
|
|
2712
|
+
<ellipse
|
|
2713
|
+
cx="5.174"
|
|
2714
|
+
cy="15.117"
|
|
2715
|
+
rx="5.174"
|
|
2716
|
+
ry="15.117"
|
|
2717
|
+
transform="translate(367.144 236.079) rotate(-77.61)"
|
|
2718
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2719
|
+
stroke-miterlimit="10"
|
|
2720
|
+
stroke-width="1"
|
|
2721
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2722
|
+
/>
|
|
2723
|
+
<path
|
|
2724
|
+
d="M947,380.271s1.631-2.83,8.084-2.235c5.427.5,16.927,2.855,20.574,8.26"
|
|
2725
|
+
transform="translate(-578.512 -147.764)"
|
|
2726
|
+
fill="none"
|
|
2727
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2728
|
+
stroke-miterlimit="10"
|
|
2729
|
+
stroke-width="1"
|
|
2730
|
+
/>
|
|
2731
|
+
<ellipse
|
|
2732
|
+
cx="15.117"
|
|
2733
|
+
cy="5.174"
|
|
2734
|
+
rx="15.117"
|
|
2735
|
+
ry="5.174"
|
|
2736
|
+
transform="translate(247 232.438) rotate(-12.39)"
|
|
2737
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2738
|
+
stroke-miterlimit="10"
|
|
2739
|
+
stroke-width="1"
|
|
2740
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2741
|
+
/>
|
|
2742
|
+
<path
|
|
2743
|
+
d="M456.439,380.271s-1.631-2.83-8.073-2.235c-5.43.5-16.93,2.855-20.576,8.26"
|
|
2744
|
+
transform="translate(-179.058 -147.764)"
|
|
2745
|
+
fill="none"
|
|
2746
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2747
|
+
stroke-miterlimit="10"
|
|
2748
|
+
stroke-width="1"
|
|
2749
|
+
/>
|
|
2750
|
+
<ellipse
|
|
2751
|
+
cx="1.651"
|
|
2752
|
+
cy="15.082"
|
|
2753
|
+
rx="1.651"
|
|
2754
|
+
ry="15.082"
|
|
2755
|
+
transform="translate(406.71 230.174) rotate(-68.13)"
|
|
2756
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2757
|
+
stroke-miterlimit="10"
|
|
2758
|
+
stroke-width="1"
|
|
2759
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2760
|
+
/>
|
|
2761
|
+
<path
|
|
2762
|
+
d="M1119,375.62a119.876,119.876,0,0,1,26.193,10.419"
|
|
2763
|
+
transform="translate(-710.84 -145.969)"
|
|
2764
|
+
fill="none"
|
|
2765
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2766
|
+
stroke-miterlimit="10"
|
|
2767
|
+
stroke-width="1"
|
|
2768
|
+
/>
|
|
2769
|
+
<ellipse
|
|
2770
|
+
cx="15.082"
|
|
2771
|
+
cy="1.651"
|
|
2772
|
+
rx="15.082"
|
|
2773
|
+
ry="1.651"
|
|
2774
|
+
transform="translate(210.225 238.342) rotate(-21.87)"
|
|
2775
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2776
|
+
stroke-miterlimit="10"
|
|
2777
|
+
stroke-width="1"
|
|
2778
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2779
|
+
/>
|
|
2780
|
+
<path
|
|
2781
|
+
d="M293.943,375.62a119.829,119.829,0,0,0-26.193,10.419"
|
|
2782
|
+
transform="translate(-55.932 -145.969)"
|
|
2783
|
+
fill="none"
|
|
2784
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2785
|
+
stroke-miterlimit="10"
|
|
2786
|
+
stroke-width="1"
|
|
2787
|
+
/>
|
|
2788
|
+
</g>
|
|
2789
|
+
`,
|
|
2790
|
+
metadata: {
|
|
2791
|
+
description: "Pixer mixer/agitator vessel with tapered hose barb connection at top",
|
|
2792
|
+
tags: ["vessel", "mixer", "agitator", "pixer", "tank", "hose-barb"]
|
|
2793
|
+
}
|
|
2794
|
+
},
|
|
2795
|
+
"vessel-balloon": {
|
|
2796
|
+
id: "vessel-balloon",
|
|
2797
|
+
name: "Vessel",
|
|
2798
|
+
category: "vessel",
|
|
2799
|
+
viewBox: { x: 0, y: 0, width: 50.625, height: 91 },
|
|
2800
|
+
ports: [
|
|
2801
|
+
{ id: "top", type: "inlet", x: 25.3125, y: 0 },
|
|
2802
|
+
{ id: "left", type: "inlet", x: 5, y: 39 },
|
|
2803
|
+
{ id: "right", type: "outlet", x: 45.625, y: 39 },
|
|
2804
|
+
{ id: "bottom", type: "outlet", x: 25.3125, y: 91 }
|
|
2805
|
+
],
|
|
2806
|
+
svgContent: `
|
|
2807
|
+
<g transform="scale(0.196875) translate(-195, -100)">
|
|
2808
|
+
<!-- Top opening nozzle -->
|
|
2809
|
+
<rect
|
|
2810
|
+
width="65"
|
|
2811
|
+
height="19.5"
|
|
2812
|
+
transform="translate(290.5, 100)"
|
|
2813
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2814
|
+
stroke-miterlimit="10"
|
|
2815
|
+
stroke-width="1"
|
|
2816
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2817
|
+
/>
|
|
2818
|
+
|
|
2819
|
+
<!-- Transition from nozzle to dome -->
|
|
2820
|
+
<path
|
|
2821
|
+
d="M 290.5,119.5 L 238,152 L 408,152 L 355.5,119.5 Z"
|
|
2822
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2823
|
+
stroke-miterlimit="10"
|
|
2824
|
+
stroke-width="1"
|
|
2825
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2826
|
+
/>
|
|
2827
|
+
|
|
2828
|
+
<!-- Upper balloon dome - rounded bulge -->
|
|
2829
|
+
<path
|
|
2830
|
+
d="M 238,152 C 185,210 150,320 180,395 L 466,395 C 496,320 461,210 408,152 Z"
|
|
2831
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2832
|
+
stroke-miterlimit="10"
|
|
2833
|
+
stroke-width="1"
|
|
2834
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2835
|
+
/>
|
|
2836
|
+
|
|
2837
|
+
<!-- Tapered vessel body -->
|
|
2838
|
+
<path
|
|
2839
|
+
d="M 180,395 L 269.742,530 L 376.356,530 L 466,395 Z"
|
|
2840
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2841
|
+
stroke-miterlimit="10"
|
|
2842
|
+
stroke-width="1"
|
|
2843
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2844
|
+
/>
|
|
2845
|
+
|
|
2846
|
+
<!-- Bottom cone -->
|
|
2847
|
+
<path
|
|
2848
|
+
d="M 269.742,530 L 280,555 L 366,555 L 376.356,530 Z"
|
|
2849
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2850
|
+
stroke-miterlimit="10"
|
|
2851
|
+
stroke-width="1"
|
|
2852
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2853
|
+
/>
|
|
2854
|
+
|
|
2855
|
+
<!-- Bottom flange matching pixer top dimensions -->
|
|
2856
|
+
<rect
|
|
2857
|
+
width="141.313"
|
|
2858
|
+
height="9.872"
|
|
2859
|
+
transform="translate(252.392, 555)"
|
|
2860
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2861
|
+
stroke-miterlimit="10"
|
|
2862
|
+
stroke-width="1"
|
|
2863
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2864
|
+
/>
|
|
2865
|
+
</g>
|
|
2866
|
+
`,
|
|
2867
|
+
metadata: {
|
|
2868
|
+
description: "Balloon-shaped vessel with rounded top and tapered bottom, designed to fit on standard pixer",
|
|
2869
|
+
tags: ["vessel", "storage", "tank", "balloon"]
|
|
2870
|
+
}
|
|
2871
|
+
},
|
|
2872
|
+
"psr-f": {
|
|
2873
|
+
id: "psr-f",
|
|
2874
|
+
name: "PSR F",
|
|
2875
|
+
category: "instrument",
|
|
2876
|
+
viewBox: { x: 0, y: 0, width: 57, height: 57 },
|
|
2877
|
+
ports: [
|
|
2878
|
+
{ id: "top", type: "signal", x: 28.5, y: 14.25 },
|
|
2879
|
+
{ id: "right", type: "signal", x: 42.75, y: 28.5 },
|
|
2880
|
+
{ id: "bottom", type: "signal", x: 28.5, y: 42.75 },
|
|
2881
|
+
{ id: "left", type: "signal", x: 14.25, y: 28.5 }
|
|
2882
|
+
],
|
|
2883
|
+
svgContent: `
|
|
2884
|
+
<g transform="scale(0.5) translate(28.5, 28.5)">
|
|
2885
|
+
<!-- Circle background -->
|
|
2886
|
+
<ellipse
|
|
2887
|
+
cx="28.5"
|
|
2888
|
+
cy="28.5"
|
|
2889
|
+
rx="28.5"
|
|
2890
|
+
ry="28.5"
|
|
2891
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2892
|
+
stroke-width="1"
|
|
2893
|
+
fill="var(--symbol-fill, #ffffff)"
|
|
2894
|
+
/>
|
|
2895
|
+
|
|
2896
|
+
<!-- Letter F -->
|
|
2897
|
+
<text
|
|
2898
|
+
x="28.5"
|
|
2899
|
+
y="38"
|
|
2900
|
+
text-anchor="middle"
|
|
2901
|
+
font-family="'Times New Roman', Georgia, serif"
|
|
2902
|
+
font-size="34"
|
|
2903
|
+
font-weight="normal"
|
|
2904
|
+
font-style="italic"
|
|
2905
|
+
fill="var(--symbol-stroke, #000000)"
|
|
2906
|
+
>F</text>
|
|
1914
2907
|
</g>
|
|
1915
2908
|
`,
|
|
1916
2909
|
metadata: {
|
|
1917
|
-
description: "
|
|
1918
|
-
tags: ["instrument", "
|
|
2910
|
+
description: "PSR F instrument symbol - Flow indicator",
|
|
2911
|
+
tags: ["instrument", "psr", "flow", "indicator"]
|
|
2912
|
+
}
|
|
2913
|
+
},
|
|
2914
|
+
"psr-p": {
|
|
2915
|
+
id: "psr-p",
|
|
2916
|
+
name: "PSR P",
|
|
2917
|
+
category: "instrument",
|
|
2918
|
+
viewBox: { x: 0, y: 0, width: 57, height: 57 },
|
|
2919
|
+
ports: [
|
|
2920
|
+
{ id: "top", type: "signal", x: 28.5, y: 14.25 },
|
|
2921
|
+
{ id: "right", type: "signal", x: 42.75, y: 28.5 },
|
|
2922
|
+
{ id: "bottom", type: "signal", x: 28.5, y: 42.75 },
|
|
2923
|
+
{ id: "left", type: "signal", x: 14.25, y: 28.5 }
|
|
2924
|
+
],
|
|
2925
|
+
svgContent: `
|
|
2926
|
+
<g transform="scale(0.5) translate(28.5, 28.5)">
|
|
2927
|
+
<!-- Circle background -->
|
|
2928
|
+
<ellipse
|
|
2929
|
+
cx="28.5"
|
|
2930
|
+
cy="28.5"
|
|
2931
|
+
rx="28.5"
|
|
2932
|
+
ry="28.5"
|
|
2933
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2934
|
+
stroke-width="1"
|
|
2935
|
+
fill="var(--symbol-fill, #ffffff)"
|
|
2936
|
+
/>
|
|
2937
|
+
|
|
2938
|
+
<!-- Letter P -->
|
|
2939
|
+
<text
|
|
2940
|
+
x="28.5"
|
|
2941
|
+
y="38"
|
|
2942
|
+
text-anchor="middle"
|
|
2943
|
+
font-family="'Times New Roman', Georgia, serif"
|
|
2944
|
+
font-size="34"
|
|
2945
|
+
font-weight="normal"
|
|
2946
|
+
font-style="italic"
|
|
2947
|
+
fill="var(--symbol-stroke, #000000)"
|
|
2948
|
+
>P</text>
|
|
2949
|
+
</g>
|
|
2950
|
+
`,
|
|
2951
|
+
metadata: {
|
|
2952
|
+
description: "PSR P instrument symbol - Pressure indicator",
|
|
2953
|
+
tags: ["instrument", "psr", "pressure", "indicator"]
|
|
1919
2954
|
}
|
|
1920
2955
|
}
|
|
1921
2956
|
};
|
|
@@ -1995,6 +3030,24 @@ function NodeRenderer({
|
|
|
1995
3030
|
`translate(${centerX}, ${centerY}) scale(${scaleX}, ${scaleY}) translate(${-centerX}, ${-centerY})`
|
|
1996
3031
|
);
|
|
1997
3032
|
}
|
|
3033
|
+
const getStatusColor = (status) => {
|
|
3034
|
+
switch (status) {
|
|
3035
|
+
case "running":
|
|
3036
|
+
return "#22c55e";
|
|
3037
|
+
// Green
|
|
3038
|
+
case "alarm":
|
|
3039
|
+
return "#ef4444";
|
|
3040
|
+
// Red
|
|
3041
|
+
case "warning":
|
|
3042
|
+
return "#f59e0b";
|
|
3043
|
+
// Orange
|
|
3044
|
+
case "stopped":
|
|
3045
|
+
default:
|
|
3046
|
+
return "#edeeef";
|
|
3047
|
+
}
|
|
3048
|
+
};
|
|
3049
|
+
const fillColor = node.customColors?.fill ?? getStatusColor(node.status);
|
|
3050
|
+
const strokeColor = node.customColors?.stroke ?? "rgb(0, 0, 0)";
|
|
1998
3051
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1999
3052
|
"g",
|
|
2000
3053
|
{
|
|
@@ -2003,6 +3056,11 @@ function NodeRenderer({
|
|
|
2003
3056
|
"data-selected": isSelected,
|
|
2004
3057
|
"data-dragging": isDragging,
|
|
2005
3058
|
transform: transforms.join(" "),
|
|
3059
|
+
style: {
|
|
3060
|
+
"--symbol-fill": fillColor,
|
|
3061
|
+
"--symbol-stroke": strokeColor,
|
|
3062
|
+
cursor: enableDrag ? isDragging ? "grabbing" : "grab" : onNodeClick ? "pointer" : "default"
|
|
3063
|
+
},
|
|
2006
3064
|
onClick: (e) => {
|
|
2007
3065
|
e.stopPropagation();
|
|
2008
3066
|
onNodeClick?.(node.id, e);
|
|
@@ -2022,9 +3080,6 @@ function NodeRenderer({
|
|
|
2022
3080
|
onNodeDragStart?.(node.id, e);
|
|
2023
3081
|
}
|
|
2024
3082
|
},
|
|
2025
|
-
style: {
|
|
2026
|
-
cursor: enableDrag ? isDragging ? "grabbing" : "grab" : onNodeClick ? "pointer" : "default"
|
|
2027
|
-
},
|
|
2028
3083
|
children: [
|
|
2029
3084
|
isSelected && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2030
3085
|
"rect",
|
|
@@ -2077,6 +3132,9 @@ function PipeRenderer({
|
|
|
2077
3132
|
onPipeClick,
|
|
2078
3133
|
enableWaypointEditing = false,
|
|
2079
3134
|
onWaypointDragStart,
|
|
3135
|
+
onWaypointClick,
|
|
3136
|
+
selectedWaypointPipeId,
|
|
3137
|
+
selectedWaypointIndex,
|
|
2080
3138
|
editingPipeId,
|
|
2081
3139
|
draggingWaypointIndex,
|
|
2082
3140
|
waypointDragOffset,
|
|
@@ -2097,7 +3155,7 @@ function PipeRenderer({
|
|
|
2097
3155
|
});
|
|
2098
3156
|
const pointsString = displayPoints.map((point) => `${point.x},${point.y}`).join(" ");
|
|
2099
3157
|
const pipeStyle = pipe.style || {};
|
|
2100
|
-
const stroke = isSelected ? "#3b82f6" : pipeStyle.stroke || "#
|
|
3158
|
+
const stroke = isSelected ? "#3b82f6" : pipeStyle.stroke || "#94a1b8";
|
|
2101
3159
|
const strokeWidth = isSelected ? (pipeStyle.strokeWidth || 3) + 2 : pipeStyle.strokeWidth || 3;
|
|
2102
3160
|
const strokeDasharray = pipeStyle.strokeDasharray;
|
|
2103
3161
|
const opacity = pipeStyle.opacity !== void 0 ? pipeStyle.opacity : 1;
|
|
@@ -2146,10 +3204,11 @@ function PipeRenderer({
|
|
|
2146
3204
|
] }),
|
|
2147
3205
|
displayPoints.map((point, idx) => {
|
|
2148
3206
|
const isEndpoint = idx === 0 || idx === displayPoints.length - 1;
|
|
3207
|
+
const isSelectedWaypoint = selectedWaypointPipeId === pipe.id && selectedWaypointIndex === idx;
|
|
2149
3208
|
const isDragging = isEditing && draggingWaypointIndex === idx;
|
|
2150
|
-
const waypointSize = isDragging ? 8 : showEditingControls ? 6 : isSelected ? 3 : 2;
|
|
2151
|
-
const waypointOpacity = isDragging ? 1 : showEditingControls ? 0.9 : isSelected ? 0.8 : 0.5;
|
|
2152
|
-
const waypointColor = isEndpoint && showEditingControls ? "#f59e0b" : isDragging ? "#10b981" : stroke;
|
|
3209
|
+
const waypointSize = isSelectedWaypoint ? 8 : isDragging ? 8 : showEditingControls ? 6 : isSelected ? 3 : 2;
|
|
3210
|
+
const waypointOpacity = isSelectedWaypoint ? 1 : isDragging ? 1 : showEditingControls ? 0.9 : isSelected ? 0.8 : 0.5;
|
|
3211
|
+
const waypointColor = isSelectedWaypoint ? "#3b82f6" : isEndpoint && showEditingControls ? "#f59e0b" : isDragging ? "#10b981" : stroke;
|
|
2153
3212
|
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2154
3213
|
"circle",
|
|
2155
3214
|
{
|
|
@@ -2165,6 +3224,12 @@ function PipeRenderer({
|
|
|
2165
3224
|
cursor: showEditingControls ? isDragging ? "grabbing" : "grab" : "default"
|
|
2166
3225
|
},
|
|
2167
3226
|
pointerEvents: showEditingControls ? "all" : "none",
|
|
3227
|
+
onClick: (e) => {
|
|
3228
|
+
if (showEditingControls) {
|
|
3229
|
+
e.stopPropagation();
|
|
3230
|
+
onWaypointClick?.(pipe.id, idx);
|
|
3231
|
+
}
|
|
3232
|
+
},
|
|
2168
3233
|
onMouseDown: (e) => {
|
|
2169
3234
|
if (showEditingControls) {
|
|
2170
3235
|
e.stopPropagation();
|
|
@@ -2241,7 +3306,13 @@ function PipeRenderer({
|
|
|
2241
3306
|
|
|
2242
3307
|
// src/components/PIDCanvas/DataOverlay.tsx
|
|
2243
3308
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2244
|
-
function DataOverlay({
|
|
3309
|
+
function DataOverlay({
|
|
3310
|
+
nodeId,
|
|
3311
|
+
x,
|
|
3312
|
+
y,
|
|
3313
|
+
telemetry,
|
|
3314
|
+
scale = 1
|
|
3315
|
+
}) {
|
|
2245
3316
|
const { value, display, history } = telemetry;
|
|
2246
3317
|
const showValue = display?.showValue ?? true;
|
|
2247
3318
|
const showStatus = display?.showStatus ?? true;
|
|
@@ -2281,9 +3352,9 @@ function DataOverlay({ nodeId, x, y, telemetry }) {
|
|
|
2281
3352
|
const displayText = value.unit ? `${formattedValue} ${value.unit}` : formattedValue;
|
|
2282
3353
|
const sparklinePath = (() => {
|
|
2283
3354
|
if (!showSparkline || !history || history.length < 2) return "";
|
|
2284
|
-
const width = 70;
|
|
2285
|
-
const height = 20;
|
|
2286
|
-
const padding = 5;
|
|
3355
|
+
const width = 70 * scale;
|
|
3356
|
+
const height = 20 * scale;
|
|
3357
|
+
const padding = 5 * scale;
|
|
2287
3358
|
const effectiveWidth = width - padding * 2;
|
|
2288
3359
|
const effectiveHeight = height - padding * 2;
|
|
2289
3360
|
const min = Math.min(...history);
|
|
@@ -2297,21 +3368,22 @@ function DataOverlay({ nodeId, x, y, telemetry }) {
|
|
|
2297
3368
|
return `M ${points.join(" L ")}`;
|
|
2298
3369
|
})();
|
|
2299
3370
|
const hasSparkline = showSparkline && sparklinePath;
|
|
2300
|
-
const overlayHeight = label ? hasSparkline ? 55 : 30 : hasSparkline ? 47 : 22;
|
|
3371
|
+
const overlayHeight = (label ? hasSparkline ? 55 : 30 : hasSparkline ? 47 : 22) * scale;
|
|
3372
|
+
const overlayWidth = 80 * scale;
|
|
2301
3373
|
const displayX = x + offsetX;
|
|
2302
3374
|
const displayY = y + offsetY;
|
|
2303
3375
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("g", { "data-overlay-node": nodeId, "data-status": value.status, children: [
|
|
2304
3376
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2305
3377
|
"rect",
|
|
2306
3378
|
{
|
|
2307
|
-
x: displayX -
|
|
2308
|
-
y: displayY - 25,
|
|
2309
|
-
width:
|
|
3379
|
+
x: displayX - overlayWidth / 2,
|
|
3380
|
+
y: displayY - 25 * scale,
|
|
3381
|
+
width: overlayWidth,
|
|
2310
3382
|
height: overlayHeight,
|
|
2311
|
-
rx:
|
|
3383
|
+
rx: 4 * scale,
|
|
2312
3384
|
fill: colors.bg,
|
|
2313
3385
|
stroke: colors.border,
|
|
2314
|
-
strokeWidth:
|
|
3386
|
+
strokeWidth: 1 * scale,
|
|
2315
3387
|
opacity: "0.95",
|
|
2316
3388
|
filter: "drop-shadow(0 2px 4px rgba(0,0,0,0.2))"
|
|
2317
3389
|
}
|
|
@@ -2320,9 +3392,9 @@ function DataOverlay({ nodeId, x, y, telemetry }) {
|
|
|
2320
3392
|
"text",
|
|
2321
3393
|
{
|
|
2322
3394
|
x: displayX,
|
|
2323
|
-
y: displayY - 15,
|
|
3395
|
+
y: displayY - 15 * scale,
|
|
2324
3396
|
textAnchor: "middle",
|
|
2325
|
-
fontSize:
|
|
3397
|
+
fontSize: 8 * scale,
|
|
2326
3398
|
fontWeight: "600",
|
|
2327
3399
|
fill: finalTextColor,
|
|
2328
3400
|
opacity: "0.9",
|
|
@@ -2333,31 +3405,41 @@ function DataOverlay({ nodeId, x, y, telemetry }) {
|
|
|
2333
3405
|
"text",
|
|
2334
3406
|
{
|
|
2335
3407
|
x: displayX,
|
|
2336
|
-
y: label ? displayY - 3 : displayY - 9,
|
|
3408
|
+
y: label ? displayY - 3 * scale : displayY - 9 * scale,
|
|
2337
3409
|
textAnchor: "middle",
|
|
2338
|
-
fontSize:
|
|
3410
|
+
fontSize: 11 * scale,
|
|
2339
3411
|
fontWeight: "700",
|
|
2340
3412
|
fill: finalTextColor,
|
|
2341
3413
|
letterSpacing: "0.02em",
|
|
2342
3414
|
children: displayText
|
|
2343
3415
|
}
|
|
2344
3416
|
),
|
|
2345
|
-
showStatus && value.status !== "normal" && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2346
|
-
"
|
|
3417
|
+
showStatus && value.status !== "normal" && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3418
|
+
"circle",
|
|
2347
3419
|
{
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
3420
|
+
cx: displayX + 35 * scale,
|
|
3421
|
+
cy: displayY - 18 * scale,
|
|
3422
|
+
r: 3 * scale,
|
|
3423
|
+
fill: finalTextColor,
|
|
3424
|
+
opacity: "0.9",
|
|
3425
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3426
|
+
"animate",
|
|
3427
|
+
{
|
|
3428
|
+
attributeName: "opacity",
|
|
3429
|
+
values: "0.9;0.3;0.9",
|
|
3430
|
+
dur: "1.5s",
|
|
3431
|
+
repeatCount: "indefinite"
|
|
3432
|
+
}
|
|
3433
|
+
)
|
|
2352
3434
|
}
|
|
2353
|
-
)
|
|
3435
|
+
),
|
|
2354
3436
|
value.quality !== void 0 && value.quality < 100 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
2355
3437
|
"text",
|
|
2356
3438
|
{
|
|
2357
3439
|
x: displayX,
|
|
2358
|
-
y: displayY + 5,
|
|
3440
|
+
y: displayY + 5 * scale,
|
|
2359
3441
|
textAnchor: "middle",
|
|
2360
|
-
fontSize:
|
|
3442
|
+
fontSize: 7 * scale,
|
|
2361
3443
|
fontWeight: "500",
|
|
2362
3444
|
fill: finalTextColor,
|
|
2363
3445
|
opacity: "0.7",
|
|
@@ -2368,13 +3450,13 @@ function DataOverlay({ nodeId, x, y, telemetry }) {
|
|
|
2368
3450
|
]
|
|
2369
3451
|
}
|
|
2370
3452
|
),
|
|
2371
|
-
hasSparkline && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("g", { transform: `translate(${displayX - 35}, ${displayY + (label ? 5 : 0)})`, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3453
|
+
hasSparkline && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("g", { transform: `translate(${displayX - 35 * scale}, ${displayY + (label ? 5 : 0) * scale})`, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2372
3454
|
"path",
|
|
2373
3455
|
{
|
|
2374
3456
|
d: sparklinePath,
|
|
2375
3457
|
fill: "none",
|
|
2376
3458
|
stroke: sparklineColor || finalTextColor,
|
|
2377
|
-
strokeWidth:
|
|
3459
|
+
strokeWidth: 1.5 * scale,
|
|
2378
3460
|
strokeLinecap: "round",
|
|
2379
3461
|
strokeLinejoin: "round",
|
|
2380
3462
|
opacity: "0.9"
|
|
@@ -2383,8 +3465,145 @@ function DataOverlay({ nodeId, x, y, telemetry }) {
|
|
|
2383
3465
|
] });
|
|
2384
3466
|
}
|
|
2385
3467
|
|
|
2386
|
-
// src/
|
|
3468
|
+
// src/components/PIDCanvas/PositionPanel.tsx
|
|
2387
3469
|
var import_react8 = require("react");
|
|
3470
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
3471
|
+
function PositionPanel({
|
|
3472
|
+
selectedNode,
|
|
3473
|
+
selectedWaypoint,
|
|
3474
|
+
onPositionChange,
|
|
3475
|
+
onWaypointPositionChange,
|
|
3476
|
+
position = "top-right"
|
|
3477
|
+
}) {
|
|
3478
|
+
const [x, setX] = (0, import_react8.useState)("");
|
|
3479
|
+
const [y, setY] = (0, import_react8.useState)("");
|
|
3480
|
+
(0, import_react8.useEffect)(() => {
|
|
3481
|
+
if (selectedNode) {
|
|
3482
|
+
setX(selectedNode.transform.x.toFixed(2));
|
|
3483
|
+
setY(selectedNode.transform.y.toFixed(2));
|
|
3484
|
+
} else if (selectedWaypoint) {
|
|
3485
|
+
setX(selectedWaypoint.position.x.toFixed(2));
|
|
3486
|
+
setY(selectedWaypoint.position.y.toFixed(2));
|
|
3487
|
+
}
|
|
3488
|
+
}, [selectedNode, selectedWaypoint]);
|
|
3489
|
+
if (!selectedNode && !selectedWaypoint) {
|
|
3490
|
+
return null;
|
|
3491
|
+
}
|
|
3492
|
+
const handleXChange = (value) => {
|
|
3493
|
+
setX(value);
|
|
3494
|
+
const numValue = parseFloat(value);
|
|
3495
|
+
if (!isNaN(numValue)) {
|
|
3496
|
+
if (selectedNode && onPositionChange) {
|
|
3497
|
+
onPositionChange(selectedNode.id, numValue, selectedNode.transform.y);
|
|
3498
|
+
} else if (selectedWaypoint && onWaypointPositionChange) {
|
|
3499
|
+
onWaypointPositionChange(
|
|
3500
|
+
selectedWaypoint.pipeId,
|
|
3501
|
+
selectedWaypoint.pointIndex,
|
|
3502
|
+
numValue,
|
|
3503
|
+
selectedWaypoint.position.y
|
|
3504
|
+
);
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3507
|
+
};
|
|
3508
|
+
const handleYChange = (value) => {
|
|
3509
|
+
setY(value);
|
|
3510
|
+
const numValue = parseFloat(value);
|
|
3511
|
+
if (!isNaN(numValue)) {
|
|
3512
|
+
if (selectedNode && onPositionChange) {
|
|
3513
|
+
onPositionChange(selectedNode.id, selectedNode.transform.x, numValue);
|
|
3514
|
+
} else if (selectedWaypoint && onWaypointPositionChange) {
|
|
3515
|
+
onWaypointPositionChange(
|
|
3516
|
+
selectedWaypoint.pipeId,
|
|
3517
|
+
selectedWaypoint.pointIndex,
|
|
3518
|
+
selectedWaypoint.position.x,
|
|
3519
|
+
numValue
|
|
3520
|
+
);
|
|
3521
|
+
}
|
|
3522
|
+
}
|
|
3523
|
+
};
|
|
3524
|
+
const handleBlur = () => {
|
|
3525
|
+
if (selectedNode) {
|
|
3526
|
+
setX(selectedNode.transform.x.toFixed(2));
|
|
3527
|
+
setY(selectedNode.transform.y.toFixed(2));
|
|
3528
|
+
} else if (selectedWaypoint) {
|
|
3529
|
+
setX(selectedWaypoint.position.x.toFixed(2));
|
|
3530
|
+
setY(selectedWaypoint.position.y.toFixed(2));
|
|
3531
|
+
}
|
|
3532
|
+
};
|
|
3533
|
+
const positionStyles = {
|
|
3534
|
+
"top-left": { top: 10, left: 10 },
|
|
3535
|
+
"top-right": { top: 10, right: 10 },
|
|
3536
|
+
"bottom-left": { bottom: 10, left: 10 },
|
|
3537
|
+
"bottom-right": { bottom: 10, right: 10 }
|
|
3538
|
+
};
|
|
3539
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
3540
|
+
"div",
|
|
3541
|
+
{
|
|
3542
|
+
style: {
|
|
3543
|
+
position: "absolute",
|
|
3544
|
+
...positionStyles[position],
|
|
3545
|
+
backgroundColor: "white",
|
|
3546
|
+
border: "1px solid #ccc",
|
|
3547
|
+
borderRadius: "4px",
|
|
3548
|
+
padding: "12px",
|
|
3549
|
+
boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
|
|
3550
|
+
zIndex: 1e3,
|
|
3551
|
+
minWidth: "180px",
|
|
3552
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
3553
|
+
fontSize: "13px"
|
|
3554
|
+
},
|
|
3555
|
+
children: [
|
|
3556
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { marginBottom: "8px", fontWeight: 600, color: "#333" }, children: "Position" }),
|
|
3557
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
|
|
3558
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
3559
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("label", { style: { width: "16px", color: "#666" }, children: "X:" }),
|
|
3560
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3561
|
+
"input",
|
|
3562
|
+
{
|
|
3563
|
+
type: "number",
|
|
3564
|
+
value: x,
|
|
3565
|
+
onChange: (e) => handleXChange(e.target.value),
|
|
3566
|
+
onBlur: handleBlur,
|
|
3567
|
+
style: {
|
|
3568
|
+
flex: 1,
|
|
3569
|
+
padding: "4px 8px",
|
|
3570
|
+
border: "1px solid #ddd",
|
|
3571
|
+
borderRadius: "3px",
|
|
3572
|
+
fontSize: "13px"
|
|
3573
|
+
},
|
|
3574
|
+
step: "1"
|
|
3575
|
+
}
|
|
3576
|
+
)
|
|
3577
|
+
] }),
|
|
3578
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
3579
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("label", { style: { width: "16px", color: "#666" }, children: "Y:" }),
|
|
3580
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3581
|
+
"input",
|
|
3582
|
+
{
|
|
3583
|
+
type: "number",
|
|
3584
|
+
value: y,
|
|
3585
|
+
onChange: (e) => handleYChange(e.target.value),
|
|
3586
|
+
onBlur: handleBlur,
|
|
3587
|
+
style: {
|
|
3588
|
+
flex: 1,
|
|
3589
|
+
padding: "4px 8px",
|
|
3590
|
+
border: "1px solid #ddd",
|
|
3591
|
+
borderRadius: "3px",
|
|
3592
|
+
fontSize: "13px"
|
|
3593
|
+
},
|
|
3594
|
+
step: "1"
|
|
3595
|
+
}
|
|
3596
|
+
)
|
|
3597
|
+
] })
|
|
3598
|
+
] }),
|
|
3599
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { marginTop: "8px", fontSize: "11px", color: "#888" }, children: "Use arrow keys to nudge (\xB11px)" })
|
|
3600
|
+
]
|
|
3601
|
+
}
|
|
3602
|
+
);
|
|
3603
|
+
}
|
|
3604
|
+
|
|
3605
|
+
// src/diagram/hooks/useViewBox.ts
|
|
3606
|
+
var import_react9 = require("react");
|
|
2388
3607
|
function useViewBox(options) {
|
|
2389
3608
|
const {
|
|
2390
3609
|
initialViewBox,
|
|
@@ -2395,16 +3614,16 @@ function useViewBox(options) {
|
|
|
2395
3614
|
zoomSensitivity = 1e-3,
|
|
2396
3615
|
allowLeftClickPan = true
|
|
2397
3616
|
} = options;
|
|
2398
|
-
const [viewBox, setViewBox] = (0,
|
|
2399
|
-
const svgRef = (0,
|
|
2400
|
-
const isPanningRef = (0,
|
|
2401
|
-
const lastMousePosRef = (0,
|
|
2402
|
-
const spaceKeyDownRef = (0,
|
|
2403
|
-
const lastTouchDistanceRef = (0,
|
|
2404
|
-
const resetViewBox = (0,
|
|
3617
|
+
const [viewBox, setViewBox] = (0, import_react9.useState)(initialViewBox);
|
|
3618
|
+
const svgRef = (0, import_react9.useRef)(null);
|
|
3619
|
+
const isPanningRef = (0, import_react9.useRef)(false);
|
|
3620
|
+
const lastMousePosRef = (0, import_react9.useRef)({ x: 0, y: 0 });
|
|
3621
|
+
const spaceKeyDownRef = (0, import_react9.useRef)(false);
|
|
3622
|
+
const lastTouchDistanceRef = (0, import_react9.useRef)(null);
|
|
3623
|
+
const resetViewBox = (0, import_react9.useCallback)(() => {
|
|
2405
3624
|
setViewBox(initialViewBox);
|
|
2406
3625
|
}, [initialViewBox]);
|
|
2407
|
-
const zoomIn = (0,
|
|
3626
|
+
const zoomIn = (0, import_react9.useCallback)(() => {
|
|
2408
3627
|
setViewBox((prev) => {
|
|
2409
3628
|
const currentZoom = initialViewBox.width / prev.width;
|
|
2410
3629
|
const newZoom = Math.min(1 / minZoom, currentZoom * 1.25);
|
|
@@ -2421,7 +3640,7 @@ function useViewBox(options) {
|
|
|
2421
3640
|
};
|
|
2422
3641
|
});
|
|
2423
3642
|
}, [initialViewBox, minZoom]);
|
|
2424
|
-
const zoomOut = (0,
|
|
3643
|
+
const zoomOut = (0, import_react9.useCallback)(() => {
|
|
2425
3644
|
setViewBox((prev) => {
|
|
2426
3645
|
const currentZoom = initialViewBox.width / prev.width;
|
|
2427
3646
|
const newZoom = Math.max(1 / maxZoom, currentZoom * 0.8);
|
|
@@ -2438,7 +3657,35 @@ function useViewBox(options) {
|
|
|
2438
3657
|
};
|
|
2439
3658
|
});
|
|
2440
3659
|
}, [initialViewBox, maxZoom]);
|
|
2441
|
-
(0,
|
|
3660
|
+
const fitToContent = (0, import_react9.useCallback)((bounds, padding = 50) => {
|
|
3661
|
+
const contentWidth = bounds.maxX - bounds.minX;
|
|
3662
|
+
const contentHeight = bounds.maxY - bounds.minY;
|
|
3663
|
+
if (contentWidth === 0 || contentHeight === 0) {
|
|
3664
|
+
return;
|
|
3665
|
+
}
|
|
3666
|
+
const paddedWidth = contentWidth + padding * 2;
|
|
3667
|
+
const paddedHeight = contentHeight + padding * 2;
|
|
3668
|
+
const aspectRatio = initialViewBox.width / initialViewBox.height;
|
|
3669
|
+
const contentAspectRatio = paddedWidth / paddedHeight;
|
|
3670
|
+
let newWidth;
|
|
3671
|
+
let newHeight;
|
|
3672
|
+
if (contentAspectRatio > aspectRatio) {
|
|
3673
|
+
newWidth = paddedWidth;
|
|
3674
|
+
newHeight = paddedWidth / aspectRatio;
|
|
3675
|
+
} else {
|
|
3676
|
+
newHeight = paddedHeight;
|
|
3677
|
+
newWidth = paddedHeight * aspectRatio;
|
|
3678
|
+
}
|
|
3679
|
+
const centerX = bounds.minX + contentWidth / 2;
|
|
3680
|
+
const centerY = bounds.minY + contentHeight / 2;
|
|
3681
|
+
setViewBox({
|
|
3682
|
+
x: centerX - newWidth / 2,
|
|
3683
|
+
y: centerY - newHeight / 2,
|
|
3684
|
+
width: newWidth,
|
|
3685
|
+
height: newHeight
|
|
3686
|
+
});
|
|
3687
|
+
}, [initialViewBox]);
|
|
3688
|
+
(0, import_react9.useEffect)(() => {
|
|
2442
3689
|
if (!enableZoom || !svgRef.current) return;
|
|
2443
3690
|
const svg = svgRef.current;
|
|
2444
3691
|
const handleWheel = (e) => {
|
|
@@ -2471,7 +3718,7 @@ function useViewBox(options) {
|
|
|
2471
3718
|
svg.addEventListener("wheel", handleWheel, { passive: false });
|
|
2472
3719
|
return () => svg.removeEventListener("wheel", handleWheel);
|
|
2473
3720
|
}, [enableZoom, zoomSensitivity, minZoom, initialViewBox]);
|
|
2474
|
-
(0,
|
|
3721
|
+
(0, import_react9.useEffect)(() => {
|
|
2475
3722
|
if (!enablePan || !svgRef.current) return;
|
|
2476
3723
|
const svg = svgRef.current;
|
|
2477
3724
|
const handleMouseDown = (e) => {
|
|
@@ -2547,7 +3794,7 @@ function useViewBox(options) {
|
|
|
2547
3794
|
window.removeEventListener("keyup", handleKeyUp);
|
|
2548
3795
|
};
|
|
2549
3796
|
}, [enablePan, allowLeftClickPan]);
|
|
2550
|
-
(0,
|
|
3797
|
+
(0, import_react9.useEffect)(() => {
|
|
2551
3798
|
if (!svgRef.current) return;
|
|
2552
3799
|
if (!enablePan && !enableZoom) return;
|
|
2553
3800
|
const svg = svgRef.current;
|
|
@@ -2638,7 +3885,7 @@ function useViewBox(options) {
|
|
|
2638
3885
|
svg.removeEventListener("touchend", handleTouchEnd);
|
|
2639
3886
|
};
|
|
2640
3887
|
}, [enablePan, enableZoom, minZoom, initialViewBox]);
|
|
2641
|
-
const screenToWorld = (0,
|
|
3888
|
+
const screenToWorld = (0, import_react9.useCallback)(
|
|
2642
3889
|
(screenX, screenY) => {
|
|
2643
3890
|
const svg = svgRef.current;
|
|
2644
3891
|
if (!svg) return { x: screenX, y: screenY };
|
|
@@ -2669,21 +3916,23 @@ function useViewBox(options) {
|
|
|
2669
3916
|
resetViewBox,
|
|
2670
3917
|
zoomIn,
|
|
2671
3918
|
zoomOut,
|
|
3919
|
+
fitToContent,
|
|
3920
|
+
setViewBox,
|
|
2672
3921
|
screenToWorld,
|
|
2673
3922
|
svgRef
|
|
2674
3923
|
};
|
|
2675
3924
|
}
|
|
2676
3925
|
|
|
2677
3926
|
// src/diagram/hooks/useSelection.ts
|
|
2678
|
-
var
|
|
3927
|
+
var import_react10 = require("react");
|
|
2679
3928
|
function useSelection(options = {}) {
|
|
2680
3929
|
const {
|
|
2681
3930
|
multiSelect = true,
|
|
2682
3931
|
initialSelection = { selectedNodeIds: /* @__PURE__ */ new Set(), selectedPipeIds: /* @__PURE__ */ new Set() },
|
|
2683
3932
|
onSelectionChange
|
|
2684
3933
|
} = options;
|
|
2685
|
-
const [selection, setSelection] = (0,
|
|
2686
|
-
const notifyChange = (0,
|
|
3934
|
+
const [selection, setSelection] = (0, import_react10.useState)(initialSelection);
|
|
3935
|
+
const notifyChange = (0, import_react10.useCallback)(
|
|
2687
3936
|
(newSelection) => {
|
|
2688
3937
|
if (onSelectionChange) {
|
|
2689
3938
|
onSelectionChange(newSelection);
|
|
@@ -2691,15 +3940,15 @@ function useSelection(options = {}) {
|
|
|
2691
3940
|
},
|
|
2692
3941
|
[onSelectionChange]
|
|
2693
3942
|
);
|
|
2694
|
-
const isNodeSelected = (0,
|
|
3943
|
+
const isNodeSelected = (0, import_react10.useCallback)(
|
|
2695
3944
|
(nodeId) => selection.selectedNodeIds.has(nodeId),
|
|
2696
3945
|
[selection.selectedNodeIds]
|
|
2697
3946
|
);
|
|
2698
|
-
const isPipeSelected = (0,
|
|
3947
|
+
const isPipeSelected = (0, import_react10.useCallback)(
|
|
2699
3948
|
(pipeId) => selection.selectedPipeIds.has(pipeId),
|
|
2700
3949
|
[selection.selectedPipeIds]
|
|
2701
3950
|
);
|
|
2702
|
-
const selectNode = (0,
|
|
3951
|
+
const selectNode = (0, import_react10.useCallback)(
|
|
2703
3952
|
(nodeId, isMultiSelect = false) => {
|
|
2704
3953
|
setSelection((prev) => {
|
|
2705
3954
|
const newNodeIds = new Set(isMultiSelect && multiSelect ? prev.selectedNodeIds : []);
|
|
@@ -2718,7 +3967,7 @@ function useSelection(options = {}) {
|
|
|
2718
3967
|
},
|
|
2719
3968
|
[multiSelect, notifyChange]
|
|
2720
3969
|
);
|
|
2721
|
-
const selectPipe = (0,
|
|
3970
|
+
const selectPipe = (0, import_react10.useCallback)(
|
|
2722
3971
|
(pipeId, isMultiSelect = false) => {
|
|
2723
3972
|
setSelection((prev) => {
|
|
2724
3973
|
const newPipeIds = new Set(isMultiSelect && multiSelect ? prev.selectedPipeIds : []);
|
|
@@ -2737,7 +3986,7 @@ function useSelection(options = {}) {
|
|
|
2737
3986
|
},
|
|
2738
3987
|
[multiSelect, notifyChange]
|
|
2739
3988
|
);
|
|
2740
|
-
const clearSelection = (0,
|
|
3989
|
+
const clearSelection = (0, import_react10.useCallback)(() => {
|
|
2741
3990
|
const newSelection = {
|
|
2742
3991
|
selectedNodeIds: /* @__PURE__ */ new Set(),
|
|
2743
3992
|
selectedPipeIds: /* @__PURE__ */ new Set()
|
|
@@ -2745,7 +3994,7 @@ function useSelection(options = {}) {
|
|
|
2745
3994
|
setSelection(newSelection);
|
|
2746
3995
|
notifyChange(newSelection);
|
|
2747
3996
|
}, [notifyChange]);
|
|
2748
|
-
const selectNodes = (0,
|
|
3997
|
+
const selectNodes = (0, import_react10.useCallback)(
|
|
2749
3998
|
(nodeIds) => {
|
|
2750
3999
|
const newSelection = {
|
|
2751
4000
|
selectedNodeIds: new Set(nodeIds),
|
|
@@ -2756,7 +4005,7 @@ function useSelection(options = {}) {
|
|
|
2756
4005
|
},
|
|
2757
4006
|
[notifyChange]
|
|
2758
4007
|
);
|
|
2759
|
-
const selectPipes = (0,
|
|
4008
|
+
const selectPipes = (0, import_react10.useCallback)(
|
|
2760
4009
|
(pipeIds) => {
|
|
2761
4010
|
const newSelection = {
|
|
2762
4011
|
selectedNodeIds: /* @__PURE__ */ new Set(),
|
|
@@ -2780,23 +4029,23 @@ function useSelection(options = {}) {
|
|
|
2780
4029
|
}
|
|
2781
4030
|
|
|
2782
4031
|
// src/diagram/hooks/useTelemetry.ts
|
|
2783
|
-
var
|
|
4032
|
+
var import_react11 = require("react");
|
|
2784
4033
|
function useTelemetry(options = {}) {
|
|
2785
4034
|
const {
|
|
2786
4035
|
initialBindings = [],
|
|
2787
4036
|
onTelemetryChange,
|
|
2788
4037
|
refreshInterval = 0
|
|
2789
4038
|
} = options;
|
|
2790
|
-
const [telemetry, setTelemetry] = (0,
|
|
4039
|
+
const [telemetry, setTelemetry] = (0, import_react11.useState)(() => {
|
|
2791
4040
|
const map = /* @__PURE__ */ new Map();
|
|
2792
4041
|
initialBindings.forEach((binding) => {
|
|
2793
4042
|
map.set(binding.nodeId, binding);
|
|
2794
4043
|
});
|
|
2795
4044
|
return map;
|
|
2796
4045
|
});
|
|
2797
|
-
const telemetryRef = (0,
|
|
4046
|
+
const telemetryRef = (0, import_react11.useRef)(telemetry);
|
|
2798
4047
|
telemetryRef.current = telemetry;
|
|
2799
|
-
const notifyChange = (0,
|
|
4048
|
+
const notifyChange = (0, import_react11.useCallback)(
|
|
2800
4049
|
(newTelemetry) => {
|
|
2801
4050
|
if (onTelemetryChange) {
|
|
2802
4051
|
onTelemetryChange(newTelemetry);
|
|
@@ -2804,7 +4053,7 @@ function useTelemetry(options = {}) {
|
|
|
2804
4053
|
},
|
|
2805
4054
|
[onTelemetryChange]
|
|
2806
4055
|
);
|
|
2807
|
-
const updateTelemetry = (0,
|
|
4056
|
+
const updateTelemetry = (0, import_react11.useCallback)(
|
|
2808
4057
|
(nodeId, value) => {
|
|
2809
4058
|
setTelemetry((prev) => {
|
|
2810
4059
|
const newMap = new Map(prev);
|
|
@@ -2834,7 +4083,7 @@ function useTelemetry(options = {}) {
|
|
|
2834
4083
|
},
|
|
2835
4084
|
[notifyChange]
|
|
2836
4085
|
);
|
|
2837
|
-
const updateTelemetryBatch = (0,
|
|
4086
|
+
const updateTelemetryBatch = (0, import_react11.useCallback)(
|
|
2838
4087
|
(updates) => {
|
|
2839
4088
|
setTelemetry((prev) => {
|
|
2840
4089
|
const newMap = new Map(prev);
|
|
@@ -2888,16 +4137,16 @@ function useTelemetry(options = {}) {
|
|
|
2888
4137
|
},
|
|
2889
4138
|
[notifyChange]
|
|
2890
4139
|
);
|
|
2891
|
-
const getTelemetry = (0,
|
|
4140
|
+
const getTelemetry = (0, import_react11.useCallback)(
|
|
2892
4141
|
(nodeId) => telemetryRef.current.get(nodeId),
|
|
2893
4142
|
[]
|
|
2894
4143
|
);
|
|
2895
|
-
const clearTelemetry = (0,
|
|
4144
|
+
const clearTelemetry = (0, import_react11.useCallback)(() => {
|
|
2896
4145
|
const newMap = /* @__PURE__ */ new Map();
|
|
2897
4146
|
setTelemetry(newMap);
|
|
2898
4147
|
notifyChange(newMap);
|
|
2899
4148
|
}, [notifyChange]);
|
|
2900
|
-
const setBindings = (0,
|
|
4149
|
+
const setBindings = (0, import_react11.useCallback)(
|
|
2901
4150
|
(bindings) => {
|
|
2902
4151
|
const newMap = /* @__PURE__ */ new Map();
|
|
2903
4152
|
bindings.forEach((binding) => {
|
|
@@ -2908,7 +4157,7 @@ function useTelemetry(options = {}) {
|
|
|
2908
4157
|
},
|
|
2909
4158
|
[notifyChange]
|
|
2910
4159
|
);
|
|
2911
|
-
(0,
|
|
4160
|
+
(0, import_react11.useEffect)(() => {
|
|
2912
4161
|
if (refreshInterval <= 0) return;
|
|
2913
4162
|
const intervalId = setInterval(() => {
|
|
2914
4163
|
notifyChange(telemetryRef.current);
|
|
@@ -2925,8 +4174,50 @@ function useTelemetry(options = {}) {
|
|
|
2925
4174
|
};
|
|
2926
4175
|
}
|
|
2927
4176
|
|
|
4177
|
+
// src/diagram/hooks/useTelemetryStatus.ts
|
|
4178
|
+
var import_react12 = require("react");
|
|
4179
|
+
function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
|
|
4180
|
+
const { enabled = true, mapStatus } = options;
|
|
4181
|
+
(0, import_react12.useEffect)(() => {
|
|
4182
|
+
if (!enabled) return;
|
|
4183
|
+
const defaultMapStatus = (telemetryStatus) => {
|
|
4184
|
+
switch (telemetryStatus) {
|
|
4185
|
+
case "normal":
|
|
4186
|
+
return "running";
|
|
4187
|
+
case "warning":
|
|
4188
|
+
return "warning";
|
|
4189
|
+
case "alarm":
|
|
4190
|
+
case "fault":
|
|
4191
|
+
return "alarm";
|
|
4192
|
+
case "off":
|
|
4193
|
+
return "stopped";
|
|
4194
|
+
default:
|
|
4195
|
+
return "stopped";
|
|
4196
|
+
}
|
|
4197
|
+
};
|
|
4198
|
+
const statusMapper = mapStatus || defaultMapStatus;
|
|
4199
|
+
let needsUpdate = false;
|
|
4200
|
+
const updatedNodes = diagram.nodes.map((node) => {
|
|
4201
|
+
const binding = telemetry.get(node.id);
|
|
4202
|
+
if (!binding) return node;
|
|
4203
|
+
const newStatus = statusMapper(binding.value.status);
|
|
4204
|
+
if (node.status !== newStatus) {
|
|
4205
|
+
needsUpdate = true;
|
|
4206
|
+
return { ...node, status: newStatus };
|
|
4207
|
+
}
|
|
4208
|
+
return node;
|
|
4209
|
+
});
|
|
4210
|
+
if (needsUpdate) {
|
|
4211
|
+
setDiagram({
|
|
4212
|
+
...diagram,
|
|
4213
|
+
nodes: updatedNodes
|
|
4214
|
+
});
|
|
4215
|
+
}
|
|
4216
|
+
}, [telemetry, diagram, setDiagram, enabled, mapStatus]);
|
|
4217
|
+
}
|
|
4218
|
+
|
|
2928
4219
|
// src/diagram/hooks/useDrag.ts
|
|
2929
|
-
var
|
|
4220
|
+
var import_react13 = require("react");
|
|
2930
4221
|
function useDrag(options = {}) {
|
|
2931
4222
|
const {
|
|
2932
4223
|
onDragStart,
|
|
@@ -2936,23 +4227,23 @@ function useDrag(options = {}) {
|
|
|
2936
4227
|
dragThreshold = 3,
|
|
2937
4228
|
screenToWorld = (x, y) => ({ x, y })
|
|
2938
4229
|
} = options;
|
|
2939
|
-
const [dragState, setDragState] = (0,
|
|
4230
|
+
const [dragState, setDragState] = (0, import_react13.useState)({
|
|
2940
4231
|
isDragging: false,
|
|
2941
4232
|
startPosition: null,
|
|
2942
4233
|
offset: { x: 0, y: 0 },
|
|
2943
4234
|
draggedId: null
|
|
2944
4235
|
});
|
|
2945
|
-
const [isListening, setIsListening] = (0,
|
|
2946
|
-
const dragStartRef = (0,
|
|
2947
|
-
const hasMovedRef = (0,
|
|
2948
|
-
const applySnap = (0,
|
|
4236
|
+
const [isListening, setIsListening] = (0, import_react13.useState)(false);
|
|
4237
|
+
const dragStartRef = (0, import_react13.useRef)(null);
|
|
4238
|
+
const hasMovedRef = (0, import_react13.useRef)(false);
|
|
4239
|
+
const applySnap = (0, import_react13.useCallback)(
|
|
2949
4240
|
(value) => {
|
|
2950
4241
|
if (snapToGrid <= 0) return value;
|
|
2951
4242
|
return Math.round(value / snapToGrid) * snapToGrid;
|
|
2952
4243
|
},
|
|
2953
4244
|
[snapToGrid]
|
|
2954
4245
|
);
|
|
2955
|
-
const handleMouseMove = (0,
|
|
4246
|
+
const handleMouseMove = (0, import_react13.useCallback)(
|
|
2956
4247
|
(event) => {
|
|
2957
4248
|
if (!dragStartRef.current) return;
|
|
2958
4249
|
const { id, screenStart: _screenStart, itemPosition, clickOffset } = dragStartRef.current;
|
|
@@ -2993,7 +4284,7 @@ function useDrag(options = {}) {
|
|
|
2993
4284
|
},
|
|
2994
4285
|
[screenToWorld, dragThreshold, applySnap, onDragStart, onDragMove]
|
|
2995
4286
|
);
|
|
2996
|
-
const handleMouseUp = (0,
|
|
4287
|
+
const handleMouseUp = (0, import_react13.useCallback)(
|
|
2997
4288
|
(event) => {
|
|
2998
4289
|
if (!dragStartRef.current || !hasMovedRef.current) {
|
|
2999
4290
|
dragStartRef.current = null;
|
|
@@ -3030,7 +4321,7 @@ function useDrag(options = {}) {
|
|
|
3030
4321
|
},
|
|
3031
4322
|
[screenToWorld, applySnap, onDragEnd]
|
|
3032
4323
|
);
|
|
3033
|
-
const handleTouchMove = (0,
|
|
4324
|
+
const handleTouchMove = (0, import_react13.useCallback)(
|
|
3034
4325
|
(event) => {
|
|
3035
4326
|
if (!dragStartRef.current || event.touches.length !== 1) return;
|
|
3036
4327
|
const touch = event.touches[0];
|
|
@@ -3073,7 +4364,7 @@ function useDrag(options = {}) {
|
|
|
3073
4364
|
},
|
|
3074
4365
|
[screenToWorld, dragThreshold, applySnap, onDragStart, onDragMove]
|
|
3075
4366
|
);
|
|
3076
|
-
const handleTouchEnd = (0,
|
|
4367
|
+
const handleTouchEnd = (0, import_react13.useCallback)(
|
|
3077
4368
|
(event) => {
|
|
3078
4369
|
if (!dragStartRef.current || !hasMovedRef.current) {
|
|
3079
4370
|
dragStartRef.current = null;
|
|
@@ -3111,7 +4402,7 @@ function useDrag(options = {}) {
|
|
|
3111
4402
|
},
|
|
3112
4403
|
[screenToWorld, applySnap, onDragEnd]
|
|
3113
4404
|
);
|
|
3114
|
-
(0,
|
|
4405
|
+
(0, import_react13.useEffect)(() => {
|
|
3115
4406
|
if (!isListening) return;
|
|
3116
4407
|
document.addEventListener("mousemove", handleMouseMove);
|
|
3117
4408
|
document.addEventListener("mouseup", handleMouseUp);
|
|
@@ -3126,7 +4417,7 @@ function useDrag(options = {}) {
|
|
|
3126
4417
|
document.removeEventListener("touchcancel", handleTouchEnd);
|
|
3127
4418
|
};
|
|
3128
4419
|
}, [isListening, handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd]);
|
|
3129
|
-
const startDrag = (0,
|
|
4420
|
+
const startDrag = (0, import_react13.useCallback)(
|
|
3130
4421
|
(id, event, itemPosition) => {
|
|
3131
4422
|
event.stopPropagation();
|
|
3132
4423
|
let clientX;
|
|
@@ -3156,7 +4447,7 @@ function useDrag(options = {}) {
|
|
|
3156
4447
|
},
|
|
3157
4448
|
[screenToWorld]
|
|
3158
4449
|
);
|
|
3159
|
-
const cancelDrag = (0,
|
|
4450
|
+
const cancelDrag = (0, import_react13.useCallback)(() => {
|
|
3160
4451
|
dragStartRef.current = null;
|
|
3161
4452
|
hasMovedRef.current = false;
|
|
3162
4453
|
setIsListening(false);
|
|
@@ -3167,7 +4458,7 @@ function useDrag(options = {}) {
|
|
|
3167
4458
|
draggedId: null
|
|
3168
4459
|
});
|
|
3169
4460
|
}, []);
|
|
3170
|
-
const isDraggingItem = (0,
|
|
4461
|
+
const isDraggingItem = (0, import_react13.useCallback)(
|
|
3171
4462
|
(id) => dragState.isDragging && dragState.draggedId === id,
|
|
3172
4463
|
[dragState.isDragging, dragState.draggedId]
|
|
3173
4464
|
);
|
|
@@ -3180,7 +4471,7 @@ function useDrag(options = {}) {
|
|
|
3180
4471
|
}
|
|
3181
4472
|
|
|
3182
4473
|
// src/diagram/hooks/useKeyboardShortcuts.ts
|
|
3183
|
-
var
|
|
4474
|
+
var import_react14 = require("react");
|
|
3184
4475
|
function useKeyboardShortcuts(options) {
|
|
3185
4476
|
const {
|
|
3186
4477
|
onDelete,
|
|
@@ -3191,7 +4482,7 @@ function useKeyboardShortcuts(options) {
|
|
|
3191
4482
|
onSelectAll,
|
|
3192
4483
|
enabled = true
|
|
3193
4484
|
} = options;
|
|
3194
|
-
(0,
|
|
4485
|
+
(0, import_react14.useEffect)(() => {
|
|
3195
4486
|
if (!enabled) return;
|
|
3196
4487
|
const handleKeyDown = (event) => {
|
|
3197
4488
|
const target = event.target;
|
|
@@ -3300,7 +4591,7 @@ function nodeHasPort(node, portId) {
|
|
|
3300
4591
|
}
|
|
3301
4592
|
|
|
3302
4593
|
// src/components/PIDCanvas/PIDCanvas.tsx
|
|
3303
|
-
var
|
|
4594
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
3304
4595
|
function PIDCanvas({
|
|
3305
4596
|
diagram,
|
|
3306
4597
|
className = "",
|
|
@@ -3323,36 +4614,291 @@ function PIDCanvas({
|
|
|
3323
4614
|
onPaste,
|
|
3324
4615
|
onSymbolDrop,
|
|
3325
4616
|
onPipeCreated,
|
|
4617
|
+
onMounted,
|
|
3326
4618
|
telemetry,
|
|
3327
4619
|
...props
|
|
3328
4620
|
}) {
|
|
3329
|
-
const [localDiagram, setLocalDiagram] = (0,
|
|
3330
|
-
const [dragOverPosition, setDragOverPosition] = (0,
|
|
3331
|
-
const [isConnecting, setIsConnecting] = (0,
|
|
3332
|
-
const [connectionSource, setConnectionSource] = (0,
|
|
3333
|
-
const [connectionSourcePort, setConnectionSourcePort] = (0,
|
|
3334
|
-
const [connectionCursor, setConnectionCursor] = (0,
|
|
3335
|
-
const [hoveredNode, setHoveredNode] = (0,
|
|
3336
|
-
const [hoveredPort, setHoveredPort] = (0,
|
|
3337
|
-
(0,
|
|
3338
|
-
|
|
4621
|
+
const [localDiagram, setLocalDiagram] = (0, import_react15.useState)(diagram);
|
|
4622
|
+
const [dragOverPosition, setDragOverPosition] = (0, import_react15.useState)(null);
|
|
4623
|
+
const [isConnecting, setIsConnecting] = (0, import_react15.useState)(false);
|
|
4624
|
+
const [connectionSource, setConnectionSource] = (0, import_react15.useState)(null);
|
|
4625
|
+
const [connectionSourcePort, setConnectionSourcePort] = (0, import_react15.useState)(null);
|
|
4626
|
+
const [connectionCursor, setConnectionCursor] = (0, import_react15.useState)(null);
|
|
4627
|
+
const [hoveredNode, setHoveredNode] = (0, import_react15.useState)(null);
|
|
4628
|
+
const [hoveredPort, setHoveredPort] = (0, import_react15.useState)(null);
|
|
4629
|
+
const [selectedWaypoint, setSelectedWaypoint] = (0, import_react15.useState)(null);
|
|
4630
|
+
const historyStack = (0, import_react15.useRef)([]);
|
|
4631
|
+
const redoStack = (0, import_react15.useRef)([]);
|
|
4632
|
+
const isUndoRedoAction = (0, import_react15.useRef)(false);
|
|
4633
|
+
const isInternalChange = (0, import_react15.useRef)(false);
|
|
4634
|
+
const lastInternalDiagram = (0, import_react15.useRef)(null);
|
|
4635
|
+
(0, import_react15.useEffect)(() => {
|
|
4636
|
+
const isExternal = !isInternalChange.current && diagram !== lastInternalDiagram.current;
|
|
4637
|
+
if (isExternal) {
|
|
4638
|
+
setLocalDiagram(diagram);
|
|
4639
|
+
if (!isUndoRedoAction.current) {
|
|
4640
|
+
historyStack.current = [];
|
|
4641
|
+
redoStack.current = [];
|
|
4642
|
+
}
|
|
4643
|
+
}
|
|
4644
|
+
isInternalChange.current = false;
|
|
3339
4645
|
}, [diagram]);
|
|
3340
4646
|
const {
|
|
3341
4647
|
viewBox: controlledViewBox,
|
|
3342
4648
|
svgRef,
|
|
3343
|
-
screenToWorld
|
|
4649
|
+
screenToWorld,
|
|
4650
|
+
fitToContent: fitToContentViewBox,
|
|
4651
|
+
setViewBox
|
|
3344
4652
|
} = useViewBox({
|
|
3345
4653
|
initialViewBox: diagram.viewBox,
|
|
3346
4654
|
enablePan: features.pan ?? true,
|
|
3347
4655
|
enableZoom: features.zoom ?? true
|
|
3348
4656
|
});
|
|
4657
|
+
const calculateContentBounds = (0, import_react15.useCallback)(() => {
|
|
4658
|
+
const nodes2 = localDiagram.nodes.filter((n) => n.visible !== false);
|
|
4659
|
+
if (nodes2.length === 0) {
|
|
4660
|
+
return null;
|
|
4661
|
+
}
|
|
4662
|
+
let minX = Infinity;
|
|
4663
|
+
let minY = Infinity;
|
|
4664
|
+
let maxX = -Infinity;
|
|
4665
|
+
let maxY = -Infinity;
|
|
4666
|
+
nodes2.forEach((node) => {
|
|
4667
|
+
const symbol = getSymbolDefinition(node.symbolId);
|
|
4668
|
+
if (!symbol) return;
|
|
4669
|
+
const nodeMinX = node.transform.x;
|
|
4670
|
+
const nodeMinY = node.transform.y;
|
|
4671
|
+
const nodeMaxX = node.transform.x + symbol.viewBox.width;
|
|
4672
|
+
const nodeMaxY = node.transform.y + symbol.viewBox.height;
|
|
4673
|
+
minX = Math.min(minX, nodeMinX);
|
|
4674
|
+
minY = Math.min(minY, nodeMinY);
|
|
4675
|
+
maxX = Math.max(maxX, nodeMaxX);
|
|
4676
|
+
maxY = Math.max(maxY, nodeMaxY);
|
|
4677
|
+
});
|
|
4678
|
+
return { minX, minY, maxX, maxY };
|
|
4679
|
+
}, [localDiagram.nodes]);
|
|
4680
|
+
(0, import_react15.useEffect)(() => {
|
|
4681
|
+
if (onMounted) {
|
|
4682
|
+
const controls = {
|
|
4683
|
+
fitToContent: (padding = 50) => {
|
|
4684
|
+
const bounds = calculateContentBounds();
|
|
4685
|
+
if (bounds) {
|
|
4686
|
+
fitToContentViewBox(bounds, padding);
|
|
4687
|
+
}
|
|
4688
|
+
},
|
|
4689
|
+
setZoom: (zoomLevel) => {
|
|
4690
|
+
const centerX = controlledViewBox.x + controlledViewBox.width / 2;
|
|
4691
|
+
const centerY = controlledViewBox.y + controlledViewBox.height / 2;
|
|
4692
|
+
const newWidth = diagram.viewBox.width / zoomLevel;
|
|
4693
|
+
const newHeight = diagram.viewBox.height / zoomLevel;
|
|
4694
|
+
setViewBox({
|
|
4695
|
+
x: centerX - newWidth / 2,
|
|
4696
|
+
y: centerY - newHeight / 2,
|
|
4697
|
+
width: newWidth,
|
|
4698
|
+
height: newHeight
|
|
4699
|
+
});
|
|
4700
|
+
},
|
|
4701
|
+
getZoom: () => {
|
|
4702
|
+
return diagram.viewBox.width / controlledViewBox.width;
|
|
4703
|
+
}
|
|
4704
|
+
};
|
|
4705
|
+
onMounted(controls);
|
|
4706
|
+
}
|
|
4707
|
+
}, [
|
|
4708
|
+
onMounted,
|
|
4709
|
+
calculateContentBounds,
|
|
4710
|
+
fitToContentViewBox,
|
|
4711
|
+
setViewBox,
|
|
4712
|
+
controlledViewBox,
|
|
4713
|
+
diagram.viewBox
|
|
4714
|
+
]);
|
|
3349
4715
|
const { selection, selectNode, selectPipe, clearSelection } = useSelection({
|
|
3350
4716
|
multiSelect: features.multiSelect ?? true,
|
|
3351
4717
|
onSelectionChange
|
|
3352
4718
|
});
|
|
3353
4719
|
const dragEnabled = features.dragNodes ?? false;
|
|
3354
4720
|
const selectionEnabled = features.selection ?? false;
|
|
3355
|
-
const
|
|
4721
|
+
const containerRef = (0, import_react15.useRef)(null);
|
|
4722
|
+
const pushToHistory = (0, import_react15.useCallback)((currentDiagram) => {
|
|
4723
|
+
if (isUndoRedoAction.current) return;
|
|
4724
|
+
const snapshot = JSON.parse(JSON.stringify(currentDiagram));
|
|
4725
|
+
historyStack.current.push(snapshot);
|
|
4726
|
+
if (historyStack.current.length > 15) {
|
|
4727
|
+
historyStack.current.shift();
|
|
4728
|
+
}
|
|
4729
|
+
redoStack.current = [];
|
|
4730
|
+
}, []);
|
|
4731
|
+
const undo = (0, import_react15.useCallback)(() => {
|
|
4732
|
+
if (historyStack.current.length === 0) return;
|
|
4733
|
+
isUndoRedoAction.current = true;
|
|
4734
|
+
const currentSnapshot = JSON.parse(JSON.stringify(localDiagram));
|
|
4735
|
+
redoStack.current.push(currentSnapshot);
|
|
4736
|
+
const previousState = historyStack.current.pop();
|
|
4737
|
+
isInternalChange.current = true;
|
|
4738
|
+
lastInternalDiagram.current = previousState;
|
|
4739
|
+
setLocalDiagram(previousState);
|
|
4740
|
+
onDiagramChange?.(previousState);
|
|
4741
|
+
setTimeout(() => {
|
|
4742
|
+
isUndoRedoAction.current = false;
|
|
4743
|
+
}, 0);
|
|
4744
|
+
}, [localDiagram, onDiagramChange]);
|
|
4745
|
+
const redo = (0, import_react15.useCallback)(() => {
|
|
4746
|
+
if (redoStack.current.length === 0) return;
|
|
4747
|
+
isUndoRedoAction.current = true;
|
|
4748
|
+
const currentSnapshot = JSON.parse(JSON.stringify(localDiagram));
|
|
4749
|
+
historyStack.current.push(currentSnapshot);
|
|
4750
|
+
const nextState = redoStack.current.pop();
|
|
4751
|
+
isInternalChange.current = true;
|
|
4752
|
+
lastInternalDiagram.current = nextState;
|
|
4753
|
+
setLocalDiagram(nextState);
|
|
4754
|
+
onDiagramChange?.(nextState);
|
|
4755
|
+
setTimeout(() => {
|
|
4756
|
+
isUndoRedoAction.current = false;
|
|
4757
|
+
}, 0);
|
|
4758
|
+
}, [localDiagram, onDiagramChange]);
|
|
4759
|
+
(0, import_react15.useEffect)(() => {
|
|
4760
|
+
const handleKeyDown = (e) => {
|
|
4761
|
+
const isCtrlOrCmd = e.ctrlKey || e.metaKey;
|
|
4762
|
+
if (isCtrlOrCmd && e.key === "z" && !e.shiftKey) {
|
|
4763
|
+
e.preventDefault();
|
|
4764
|
+
undo();
|
|
4765
|
+
} else if (isCtrlOrCmd && e.key === "z" && e.shiftKey) {
|
|
4766
|
+
e.preventDefault();
|
|
4767
|
+
redo();
|
|
4768
|
+
} else if (isCtrlOrCmd && e.key === "y") {
|
|
4769
|
+
e.preventDefault();
|
|
4770
|
+
redo();
|
|
4771
|
+
}
|
|
4772
|
+
};
|
|
4773
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
4774
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
4775
|
+
}, [undo, redo]);
|
|
4776
|
+
(0, import_react15.useEffect)(() => {
|
|
4777
|
+
if (!features.dragNodes) return;
|
|
4778
|
+
const handleKeyDown = (e) => {
|
|
4779
|
+
if (selection.selectedNodeIds.size === 0 && !selectedWaypoint) return;
|
|
4780
|
+
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) {
|
|
4781
|
+
return;
|
|
4782
|
+
}
|
|
4783
|
+
const nudgeAmount = e.shiftKey ? 10 : 1;
|
|
4784
|
+
let dx = 0;
|
|
4785
|
+
let dy = 0;
|
|
4786
|
+
switch (e.key) {
|
|
4787
|
+
case "ArrowLeft":
|
|
4788
|
+
dx = -nudgeAmount;
|
|
4789
|
+
e.preventDefault();
|
|
4790
|
+
break;
|
|
4791
|
+
case "ArrowRight":
|
|
4792
|
+
dx = nudgeAmount;
|
|
4793
|
+
e.preventDefault();
|
|
4794
|
+
break;
|
|
4795
|
+
case "ArrowUp":
|
|
4796
|
+
dy = -nudgeAmount;
|
|
4797
|
+
e.preventDefault();
|
|
4798
|
+
break;
|
|
4799
|
+
case "ArrowDown":
|
|
4800
|
+
dy = nudgeAmount;
|
|
4801
|
+
e.preventDefault();
|
|
4802
|
+
break;
|
|
4803
|
+
default:
|
|
4804
|
+
return;
|
|
4805
|
+
}
|
|
4806
|
+
if (selectedWaypoint) {
|
|
4807
|
+
pushToHistory(localDiagram);
|
|
4808
|
+
const updatedPipes = localDiagram.pipes.map((pipe) => {
|
|
4809
|
+
if (pipe.id === selectedWaypoint.pipeId) {
|
|
4810
|
+
const updatedRoutePoints = pipe.routePoints.map(
|
|
4811
|
+
(point, idx) => idx === selectedWaypoint.pointIndex ? { x: point.x + dx, y: point.y + dy } : point
|
|
4812
|
+
);
|
|
4813
|
+
return { ...pipe, routePoints: updatedRoutePoints };
|
|
4814
|
+
}
|
|
4815
|
+
return pipe;
|
|
4816
|
+
});
|
|
4817
|
+
const updatedDiagram = { ...localDiagram, pipes: updatedPipes };
|
|
4818
|
+
isInternalChange.current = true;
|
|
4819
|
+
lastInternalDiagram.current = updatedDiagram;
|
|
4820
|
+
setLocalDiagram(updatedDiagram);
|
|
4821
|
+
onDiagramChange?.(updatedDiagram);
|
|
4822
|
+
return;
|
|
4823
|
+
}
|
|
4824
|
+
if (selectionEnabled && selection.selectedNodeIds.size > 0) {
|
|
4825
|
+
pushToHistory(localDiagram);
|
|
4826
|
+
const updatedNodes = localDiagram.nodes.map(
|
|
4827
|
+
(node) => selection.selectedNodeIds.has(node.id) ? {
|
|
4828
|
+
...node,
|
|
4829
|
+
transform: {
|
|
4830
|
+
...node.transform,
|
|
4831
|
+
x: node.transform.x + dx,
|
|
4832
|
+
y: node.transform.y + dy
|
|
4833
|
+
}
|
|
4834
|
+
} : node
|
|
4835
|
+
);
|
|
4836
|
+
const updatedDiagram = { ...localDiagram, nodes: updatedNodes };
|
|
4837
|
+
isInternalChange.current = true;
|
|
4838
|
+
lastInternalDiagram.current = updatedDiagram;
|
|
4839
|
+
setLocalDiagram(updatedDiagram);
|
|
4840
|
+
onDiagramChange?.(updatedDiagram);
|
|
4841
|
+
selection.selectedNodeIds.forEach((nodeId) => {
|
|
4842
|
+
const node = updatedNodes.find((n) => n.id === nodeId);
|
|
4843
|
+
if (node) {
|
|
4844
|
+
onNodeMove?.(nodeId, node.transform.x, node.transform.y);
|
|
4845
|
+
}
|
|
4846
|
+
});
|
|
4847
|
+
}
|
|
4848
|
+
};
|
|
4849
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
4850
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
4851
|
+
}, [
|
|
4852
|
+
selectionEnabled,
|
|
4853
|
+
features.dragNodes,
|
|
4854
|
+
selection.selectedNodeIds,
|
|
4855
|
+
selectedWaypoint,
|
|
4856
|
+
localDiagram,
|
|
4857
|
+
onDiagramChange,
|
|
4858
|
+
onNodeMove,
|
|
4859
|
+
pushToHistory
|
|
4860
|
+
]);
|
|
4861
|
+
const handlePositionChange = (0, import_react15.useCallback)(
|
|
4862
|
+
(nodeId, x, y) => {
|
|
4863
|
+
pushToHistory(localDiagram);
|
|
4864
|
+
const updatedNodes = localDiagram.nodes.map(
|
|
4865
|
+
(node) => node.id === nodeId ? {
|
|
4866
|
+
...node,
|
|
4867
|
+
transform: {
|
|
4868
|
+
...node.transform,
|
|
4869
|
+
x,
|
|
4870
|
+
y
|
|
4871
|
+
}
|
|
4872
|
+
} : node
|
|
4873
|
+
);
|
|
4874
|
+
const updatedDiagram = { ...localDiagram, nodes: updatedNodes };
|
|
4875
|
+
isInternalChange.current = true;
|
|
4876
|
+
lastInternalDiagram.current = updatedDiagram;
|
|
4877
|
+
setLocalDiagram(updatedDiagram);
|
|
4878
|
+
onDiagramChange?.(updatedDiagram);
|
|
4879
|
+
onNodeMove?.(nodeId, x, y);
|
|
4880
|
+
},
|
|
4881
|
+
[localDiagram, onDiagramChange, onNodeMove, pushToHistory]
|
|
4882
|
+
);
|
|
4883
|
+
const handleWaypointPositionChange = (0, import_react15.useCallback)(
|
|
4884
|
+
(pipeId, pointIndex, x, y) => {
|
|
4885
|
+
pushToHistory(localDiagram);
|
|
4886
|
+
const updatedPipes = localDiagram.pipes.map((pipe) => {
|
|
4887
|
+
if (pipe.id === pipeId) {
|
|
4888
|
+
const updatedRoutePoints = pipe.routePoints.map(
|
|
4889
|
+
(point, idx) => idx === pointIndex ? { x, y } : point
|
|
4890
|
+
);
|
|
4891
|
+
return { ...pipe, routePoints: updatedRoutePoints };
|
|
4892
|
+
}
|
|
4893
|
+
return pipe;
|
|
4894
|
+
});
|
|
4895
|
+
const updatedDiagram = { ...localDiagram, pipes: updatedPipes };
|
|
4896
|
+
setLocalDiagram(updatedDiagram);
|
|
4897
|
+
onDiagramChange?.(updatedDiagram);
|
|
4898
|
+
},
|
|
4899
|
+
[localDiagram, onDiagramChange, pushToHistory]
|
|
4900
|
+
);
|
|
4901
|
+
const handleDragEnd = (0, import_react15.useCallback)(
|
|
3356
4902
|
(nodeId, offset, finalPosition) => {
|
|
3357
4903
|
const dragDistance = Math.sqrt(offset.x ** 2 + offset.y ** 2);
|
|
3358
4904
|
if (dragDistance < 2) {
|
|
@@ -3361,6 +4907,7 @@ function PIDCanvas({
|
|
|
3361
4907
|
}
|
|
3362
4908
|
return;
|
|
3363
4909
|
}
|
|
4910
|
+
pushToHistory(localDiagram);
|
|
3364
4911
|
const updatedNodes = localDiagram.nodes.map(
|
|
3365
4912
|
(node) => node.id === nodeId ? {
|
|
3366
4913
|
...node,
|
|
@@ -3398,11 +4945,13 @@ function PIDCanvas({
|
|
|
3398
4945
|
nodes: updatedNodes,
|
|
3399
4946
|
pipes: updatedPipes
|
|
3400
4947
|
};
|
|
4948
|
+
isInternalChange.current = true;
|
|
4949
|
+
lastInternalDiagram.current = updatedDiagram;
|
|
3401
4950
|
setLocalDiagram(updatedDiagram);
|
|
3402
4951
|
onDiagramChange?.(updatedDiagram);
|
|
3403
4952
|
onNodeMove?.(nodeId, finalPosition.x, finalPosition.y);
|
|
3404
4953
|
},
|
|
3405
|
-
[localDiagram, onDiagramChange, onNodeMove, selectionEnabled, selectNode]
|
|
4954
|
+
[localDiagram, onDiagramChange, onNodeMove, selectionEnabled, selectNode, pushToHistory]
|
|
3406
4955
|
);
|
|
3407
4956
|
const { dragState, startDrag } = useDrag({
|
|
3408
4957
|
snapToGrid: features.snapToGrid ?? 0,
|
|
@@ -3413,6 +4962,7 @@ function PIDCanvas({
|
|
|
3413
4962
|
snapToGrid: features.snapToGrid ?? 0,
|
|
3414
4963
|
screenToWorld,
|
|
3415
4964
|
onDragEnd: (pipeId, _offset, finalPosition) => {
|
|
4965
|
+
pushToHistory(localDiagram);
|
|
3416
4966
|
const [actualPipeId, pointIndex] = pipeId.split(":");
|
|
3417
4967
|
const idx = parseInt(pointIndex, 10);
|
|
3418
4968
|
const updatedPipes = localDiagram.pipes.map((pipe) => {
|
|
@@ -3423,11 +4973,13 @@ function PIDCanvas({
|
|
|
3423
4973
|
return { ...pipe, routePoints: updatedRoutePoints };
|
|
3424
4974
|
});
|
|
3425
4975
|
const updatedDiagram = { ...localDiagram, pipes: updatedPipes };
|
|
4976
|
+
isInternalChange.current = true;
|
|
4977
|
+
lastInternalDiagram.current = updatedDiagram;
|
|
3426
4978
|
setLocalDiagram(updatedDiagram);
|
|
3427
4979
|
onDiagramChange?.(updatedDiagram);
|
|
3428
4980
|
}
|
|
3429
4981
|
});
|
|
3430
|
-
const handleNodeDragStart = (0,
|
|
4982
|
+
const handleNodeDragStart = (0, import_react15.useCallback)(
|
|
3431
4983
|
(nodeId, event) => {
|
|
3432
4984
|
const node = localDiagram.nodes.find((n) => n.id === nodeId);
|
|
3433
4985
|
if (!node) return;
|
|
@@ -3435,7 +4987,16 @@ function PIDCanvas({
|
|
|
3435
4987
|
},
|
|
3436
4988
|
[localDiagram.nodes, startDrag]
|
|
3437
4989
|
);
|
|
3438
|
-
const
|
|
4990
|
+
const handleWaypointClick = (0, import_react15.useCallback)(
|
|
4991
|
+
(pipeId, pointIndex) => {
|
|
4992
|
+
setSelectedWaypoint({ pipeId, pointIndex });
|
|
4993
|
+
if (selectionEnabled) {
|
|
4994
|
+
clearSelection();
|
|
4995
|
+
}
|
|
4996
|
+
},
|
|
4997
|
+
[selectionEnabled, clearSelection]
|
|
4998
|
+
);
|
|
4999
|
+
const handleWaypointDragStart = (0, import_react15.useCallback)(
|
|
3439
5000
|
(pipeId, pointIndex, event) => {
|
|
3440
5001
|
const pipe = localDiagram.pipes.find((p) => p.id === pipeId);
|
|
3441
5002
|
if (!pipe || pointIndex >= pipe.routePoints.length) return;
|
|
@@ -3444,8 +5005,9 @@ function PIDCanvas({
|
|
|
3444
5005
|
},
|
|
3445
5006
|
[localDiagram.pipes, startWaypointDrag]
|
|
3446
5007
|
);
|
|
3447
|
-
const handlePipeSegmentClick = (0,
|
|
5008
|
+
const handlePipeSegmentClick = (0, import_react15.useCallback)(
|
|
3448
5009
|
(pipeId, position, segmentIndex) => {
|
|
5010
|
+
pushToHistory(localDiagram);
|
|
3449
5011
|
const updatedPipes = localDiagram.pipes.map((pipe) => {
|
|
3450
5012
|
if (pipe.id !== pipeId) return pipe;
|
|
3451
5013
|
const updatedRoutePoints = [
|
|
@@ -3459,13 +5021,14 @@ function PIDCanvas({
|
|
|
3459
5021
|
setLocalDiagram(updatedDiagram);
|
|
3460
5022
|
onDiagramChange?.(updatedDiagram);
|
|
3461
5023
|
},
|
|
3462
|
-
[localDiagram, onDiagramChange]
|
|
5024
|
+
[localDiagram, onDiagramChange, pushToHistory]
|
|
3463
5025
|
);
|
|
3464
5026
|
const telemetryEnabled = features.telemetry ?? false;
|
|
3465
|
-
const handleDelete = (0,
|
|
5027
|
+
const handleDelete = (0, import_react15.useCallback)(() => {
|
|
3466
5028
|
if (!selectionEnabled) return;
|
|
3467
5029
|
const { selectedNodeIds, selectedPipeIds } = selection;
|
|
3468
5030
|
if (selectedNodeIds.size === 0 && selectedPipeIds.size === 0) return;
|
|
5031
|
+
pushToHistory(localDiagram);
|
|
3469
5032
|
const updatedNodes = localDiagram.nodes.filter((node) => !selectedNodeIds.has(node.id));
|
|
3470
5033
|
const updatedPipes = localDiagram.pipes.filter(
|
|
3471
5034
|
(pipe) => !selectedPipeIds.has(pipe.id) && !selectedNodeIds.has(pipe.fromNodeId) && !selectedNodeIds.has(pipe.toNodeId)
|
|
@@ -3475,18 +5038,28 @@ function PIDCanvas({
|
|
|
3475
5038
|
nodes: updatedNodes,
|
|
3476
5039
|
pipes: updatedPipes
|
|
3477
5040
|
};
|
|
5041
|
+
isInternalChange.current = true;
|
|
5042
|
+
lastInternalDiagram.current = updatedDiagram;
|
|
3478
5043
|
setLocalDiagram(updatedDiagram);
|
|
3479
5044
|
clearSelection();
|
|
3480
5045
|
onDiagramChange?.(updatedDiagram);
|
|
3481
5046
|
onDelete?.(Array.from(selectedNodeIds), Array.from(selectedPipeIds));
|
|
3482
|
-
}, [
|
|
3483
|
-
|
|
5047
|
+
}, [
|
|
5048
|
+
selection,
|
|
5049
|
+
localDiagram,
|
|
5050
|
+
selectionEnabled,
|
|
5051
|
+
clearSelection,
|
|
5052
|
+
onDiagramChange,
|
|
5053
|
+
onDelete,
|
|
5054
|
+
pushToHistory
|
|
5055
|
+
]);
|
|
5056
|
+
const handleCopy = (0, import_react15.useCallback)(() => {
|
|
3484
5057
|
if (!selectionEnabled) return;
|
|
3485
5058
|
const { selectedNodeIds, selectedPipeIds } = selection;
|
|
3486
5059
|
if (selectedNodeIds.size === 0 && selectedPipeIds.size === 0) return;
|
|
3487
5060
|
onItemsCopied?.(Array.from(selectedNodeIds), Array.from(selectedPipeIds));
|
|
3488
5061
|
}, [selection, selectionEnabled, onItemsCopied]);
|
|
3489
|
-
const handlePaste = (0,
|
|
5062
|
+
const handlePaste = (0, import_react15.useCallback)(() => {
|
|
3490
5063
|
if (!selectionEnabled) return;
|
|
3491
5064
|
onPaste?.();
|
|
3492
5065
|
}, [selectionEnabled, onPaste]);
|
|
@@ -3536,12 +5109,17 @@ function PIDCanvas({
|
|
|
3536
5109
|
}
|
|
3537
5110
|
onPipeClick?.(pipeId);
|
|
3538
5111
|
};
|
|
3539
|
-
const handleCanvasClick = () => {
|
|
5112
|
+
const handleCanvasClick = (e) => {
|
|
5113
|
+
const target = e.target;
|
|
5114
|
+
if (target.closest(".pipe-route-point")) {
|
|
5115
|
+
return;
|
|
5116
|
+
}
|
|
3540
5117
|
if (selectionEnabled) {
|
|
3541
5118
|
clearSelection();
|
|
3542
5119
|
}
|
|
5120
|
+
setSelectedWaypoint(null);
|
|
3543
5121
|
};
|
|
3544
|
-
const handleDragOver = (0,
|
|
5122
|
+
const handleDragOver = (0, import_react15.useCallback)(
|
|
3545
5123
|
(event) => {
|
|
3546
5124
|
if (!features.allowSymbolDrop) return;
|
|
3547
5125
|
event.preventDefault();
|
|
@@ -3550,9 +5128,9 @@ function PIDCanvas({
|
|
|
3550
5128
|
const worldPos = screenToWorld(event.clientX, event.clientY);
|
|
3551
5129
|
setDragOverPosition(worldPos);
|
|
3552
5130
|
},
|
|
3553
|
-
[features.allowSymbolDrop, screenToWorld]
|
|
5131
|
+
[features.allowSymbolDrop, screenToWorld, svgRef]
|
|
3554
5132
|
);
|
|
3555
|
-
const handleDrop = (0,
|
|
5133
|
+
const handleDrop = (0, import_react15.useCallback)(
|
|
3556
5134
|
(event) => {
|
|
3557
5135
|
if (!features.allowSymbolDrop) return;
|
|
3558
5136
|
event.preventDefault();
|
|
@@ -3563,12 +5141,12 @@ function PIDCanvas({
|
|
|
3563
5141
|
const worldPos = screenToWorld(event.clientX, event.clientY);
|
|
3564
5142
|
onSymbolDrop?.(symbolId, worldPos);
|
|
3565
5143
|
},
|
|
3566
|
-
[features.allowSymbolDrop, screenToWorld, onSymbolDrop]
|
|
5144
|
+
[features.allowSymbolDrop, screenToWorld, onSymbolDrop, svgRef]
|
|
3567
5145
|
);
|
|
3568
|
-
const handleDragLeave = (0,
|
|
5146
|
+
const handleDragLeave = (0, import_react15.useCallback)(() => {
|
|
3569
5147
|
setDragOverPosition(null);
|
|
3570
5148
|
}, []);
|
|
3571
|
-
const handleMouseMove = (0,
|
|
5149
|
+
const handleMouseMove = (0, import_react15.useCallback)(
|
|
3572
5150
|
(event) => {
|
|
3573
5151
|
const connectionModeEnabled = features.connectionMode ?? false;
|
|
3574
5152
|
if (connectionModeEnabled) {
|
|
@@ -3587,7 +5165,7 @@ function PIDCanvas({
|
|
|
3587
5165
|
const distance = Math.sqrt(
|
|
3588
5166
|
(worldPos.x - portPos.x) ** 2 + (worldPos.y - portPos.y) ** 2
|
|
3589
5167
|
);
|
|
3590
|
-
if (distance <
|
|
5168
|
+
if (distance < 15) {
|
|
3591
5169
|
foundPort = port.id;
|
|
3592
5170
|
foundNode = node.id;
|
|
3593
5171
|
break;
|
|
@@ -3604,9 +5182,11 @@ function PIDCanvas({
|
|
|
3604
5182
|
const { name } = diagram;
|
|
3605
5183
|
const viewBox = controlledViewBox;
|
|
3606
5184
|
const displayDiagram = localDiagram;
|
|
3607
|
-
|
|
5185
|
+
const selectedNode = selectionEnabled && selection.selectedNodeIds.size === 1 ? localDiagram.nodes.find((n) => selection.selectedNodeIds.has(n.id)) || null : null;
|
|
5186
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
3608
5187
|
"div",
|
|
3609
5188
|
{
|
|
5189
|
+
ref: containerRef,
|
|
3610
5190
|
className: `pid-canvas ${className}`.trim(),
|
|
3611
5191
|
style: {
|
|
3612
5192
|
width: "100%",
|
|
@@ -3617,223 +5197,287 @@ function PIDCanvas({
|
|
|
3617
5197
|
...style
|
|
3618
5198
|
},
|
|
3619
5199
|
...props,
|
|
3620
|
-
children:
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
/* @__PURE__ */ (0,
|
|
3641
|
-
/* @__PURE__ */ (0,
|
|
3642
|
-
|
|
3643
|
-
/* @__PURE__ */ (0,
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
5200
|
+
children: [
|
|
5201
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
5202
|
+
"svg",
|
|
5203
|
+
{
|
|
5204
|
+
ref: svgRef,
|
|
5205
|
+
width: "100%",
|
|
5206
|
+
height: "100%",
|
|
5207
|
+
viewBox: `${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`,
|
|
5208
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
5209
|
+
style: {
|
|
5210
|
+
display: "block"
|
|
5211
|
+
},
|
|
5212
|
+
"aria-label": `P&ID diagram: ${name}`,
|
|
5213
|
+
role: "img",
|
|
5214
|
+
onClick: handleCanvasClick,
|
|
5215
|
+
onMouseMove: handleMouseMove,
|
|
5216
|
+
onDragOver: handleDragOver,
|
|
5217
|
+
onDrop: handleDrop,
|
|
5218
|
+
onDragLeave: handleDragLeave,
|
|
5219
|
+
children: [
|
|
5220
|
+
features.showGrid !== false ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
5221
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("defs", { children: [
|
|
5222
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("pattern", { id: "grid-minor", width: "5", height: "5", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M 5 0 L 0 0 0 5", fill: "none", stroke: "#e5e7eb", strokeWidth: "0.5" }) }),
|
|
5223
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("pattern", { id: "grid-major", width: "25", height: "25", patternUnits: "userSpaceOnUse", children: [
|
|
5224
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("rect", { width: "25", height: "25", fill: "url(#grid-minor)" }),
|
|
5225
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M 25 0 L 0 0 0 25", fill: "none", stroke: "#d1d5db", strokeWidth: "1" })
|
|
5226
|
+
] })
|
|
5227
|
+
] }),
|
|
5228
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5229
|
+
"rect",
|
|
5230
|
+
{
|
|
5231
|
+
x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
|
|
5232
|
+
y: Math.floor(viewBox.y / 25) * 25 - viewBox.height,
|
|
5233
|
+
width: Math.ceil(viewBox.width * 3 / 25) * 25,
|
|
5234
|
+
height: Math.ceil(viewBox.height * 3 / 25) * 25,
|
|
5235
|
+
fill: "url(#grid-major)"
|
|
5236
|
+
}
|
|
5237
|
+
)
|
|
5238
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3648
5239
|
"rect",
|
|
3649
5240
|
{
|
|
3650
5241
|
x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
|
|
3651
5242
|
y: Math.floor(viewBox.y / 25) * 25 - viewBox.height,
|
|
3652
5243
|
width: Math.ceil(viewBox.width * 3 / 25) * 25,
|
|
3653
5244
|
height: Math.ceil(viewBox.height * 3 / 25) * 25,
|
|
3654
|
-
fill: "
|
|
5245
|
+
fill: features.backgroundColor ?? "#ffffff"
|
|
3655
5246
|
}
|
|
3656
|
-
)
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
{
|
|
3660
|
-
x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
|
|
3661
|
-
y: Math.floor(viewBox.y / 25) * 25 - viewBox.height,
|
|
3662
|
-
width: Math.ceil(viewBox.width * 3 / 25) * 25,
|
|
3663
|
-
height: Math.ceil(viewBox.height * 3 / 25) * 25,
|
|
3664
|
-
fill: features.backgroundColor ?? "#ffffff"
|
|
3665
|
-
}
|
|
3666
|
-
),
|
|
3667
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3668
|
-
PipeRenderer,
|
|
3669
|
-
{
|
|
3670
|
-
pipes: displayDiagram.pipes,
|
|
3671
|
-
selectedPipeIds: selectionEnabled ? selection.selectedPipeIds : void 0,
|
|
3672
|
-
onPipeClick: selectionEnabled ? handlePipeClick : void 0,
|
|
3673
|
-
enableWaypointEditing: false,
|
|
3674
|
-
onWaypointDragStart: void 0,
|
|
3675
|
-
editingPipeId: null,
|
|
3676
|
-
draggingWaypointIndex: null,
|
|
3677
|
-
waypointDragOffset: void 0,
|
|
3678
|
-
onPipeSegmentClick: void 0
|
|
3679
|
-
}
|
|
3680
|
-
),
|
|
3681
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3682
|
-
NodeRenderer,
|
|
3683
|
-
{
|
|
3684
|
-
nodes: displayDiagram.nodes,
|
|
3685
|
-
selectedNodeIds: selectionEnabled ? selection.selectedNodeIds : void 0,
|
|
3686
|
-
onNodeClick: selectionEnabled || features.connectionMode ? handleNodeClick : void 0,
|
|
3687
|
-
onNodeDoubleClick: selectionEnabled ? handleNodeDoubleClick : void 0,
|
|
3688
|
-
enableDrag: dragEnabled && !isConnecting,
|
|
3689
|
-
onNodeDragStart: dragEnabled && !isConnecting ? handleNodeDragStart : void 0,
|
|
3690
|
-
draggingNodeId: dragState.draggedId,
|
|
3691
|
-
dragOffset: dragState.offset
|
|
3692
|
-
}
|
|
3693
|
-
),
|
|
3694
|
-
(features.editPipeRoutes ?? false) && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3695
|
-
PipeRenderer,
|
|
3696
|
-
{
|
|
3697
|
-
pipes: displayDiagram.pipes,
|
|
3698
|
-
selectedPipeIds: selectionEnabled ? selection.selectedPipeIds : void 0,
|
|
3699
|
-
onPipeClick: void 0,
|
|
3700
|
-
enableWaypointEditing: true,
|
|
3701
|
-
onWaypointDragStart: handleWaypointDragStart,
|
|
3702
|
-
editingPipeId: waypointDragState.draggedId?.split(":")[0] || null,
|
|
3703
|
-
draggingWaypointIndex: waypointDragState.draggedId ? parseInt(waypointDragState.draggedId.split(":")[1], 10) : null,
|
|
3704
|
-
waypointDragOffset: waypointDragState.offset,
|
|
3705
|
-
onPipeSegmentClick: handlePipeSegmentClick
|
|
3706
|
-
}
|
|
3707
|
-
),
|
|
3708
|
-
telemetryEnabled && telemetry && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("g", { id: "layer-telemetry", children: displayDiagram.nodes.map((node) => {
|
|
3709
|
-
const binding = telemetry.get(node.id);
|
|
3710
|
-
if (!binding) return null;
|
|
3711
|
-
const symbol = getSymbolDefinition(node.symbolId);
|
|
3712
|
-
if (!symbol) return null;
|
|
3713
|
-
const overlayY = node.transform.y - symbol.viewBox.height / 2 - 10;
|
|
3714
|
-
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3715
|
-
DataOverlay,
|
|
5247
|
+
),
|
|
5248
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5249
|
+
PipeRenderer,
|
|
3716
5250
|
{
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
"circle",
|
|
3727
|
-
{
|
|
3728
|
-
cx: dragOverPosition.x,
|
|
3729
|
-
cy: dragOverPosition.y,
|
|
3730
|
-
r: 20,
|
|
3731
|
-
fill: "#3b82f6",
|
|
3732
|
-
opacity: 0.3,
|
|
3733
|
-
stroke: "#3b82f6",
|
|
3734
|
-
strokeWidth: 2,
|
|
3735
|
-
pointerEvents: "none"
|
|
3736
|
-
}
|
|
3737
|
-
),
|
|
3738
|
-
isConnecting && connectionSource && connectionCursor && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("g", { id: "connection-preview", pointerEvents: "none", children: (() => {
|
|
3739
|
-
const sourceNode = displayDiagram.nodes.find((n) => n.id === connectionSource);
|
|
3740
|
-
if (!sourceNode) return null;
|
|
3741
|
-
const symbol = getSymbolDefinition(sourceNode.symbolId);
|
|
3742
|
-
let lineStartX = sourceNode.transform.x;
|
|
3743
|
-
let lineStartY = sourceNode.transform.y;
|
|
3744
|
-
if (connectionSourcePort && symbol?.ports) {
|
|
3745
|
-
const port = symbol.ports.find((p) => p.id === connectionSourcePort);
|
|
3746
|
-
if (port) {
|
|
3747
|
-
const portPos = getPortWorldPosition(sourceNode, connectionSourcePort);
|
|
3748
|
-
if (portPos) {
|
|
3749
|
-
lineStartX = portPos.x;
|
|
3750
|
-
lineStartY = portPos.y;
|
|
3751
|
-
}
|
|
5251
|
+
pipes: displayDiagram.pipes,
|
|
5252
|
+
selectedPipeIds: selectionEnabled ? selection.selectedPipeIds : void 0,
|
|
5253
|
+
onPipeClick: selectionEnabled ? handlePipeClick : void 0,
|
|
5254
|
+
enableWaypointEditing: false,
|
|
5255
|
+
onWaypointDragStart: void 0,
|
|
5256
|
+
editingPipeId: null,
|
|
5257
|
+
draggingWaypointIndex: null,
|
|
5258
|
+
waypointDragOffset: void 0,
|
|
5259
|
+
onPipeSegmentClick: void 0
|
|
3752
5260
|
}
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
const symbol = getSymbolDefinition(node.symbolId);
|
|
3794
|
-
if (!symbol?.ports) return null;
|
|
3795
|
-
return symbol.ports.map((port) => {
|
|
3796
|
-
const portPos = getPortWorldPosition(node, port.id);
|
|
3797
|
-
if (!portPos) return null;
|
|
3798
|
-
const isHovered = hoveredPort === port.id && hoveredNode === node.id;
|
|
3799
|
-
const isSourcePort = node.id === connectionSource && port.id === connectionSourcePort;
|
|
3800
|
-
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3801
|
-
"circle",
|
|
5261
|
+
),
|
|
5262
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5263
|
+
NodeRenderer,
|
|
5264
|
+
{
|
|
5265
|
+
nodes: displayDiagram.nodes,
|
|
5266
|
+
selectedNodeIds: selectionEnabled ? selection.selectedNodeIds : void 0,
|
|
5267
|
+
onNodeClick: selectionEnabled || features.connectionMode ? handleNodeClick : void 0,
|
|
5268
|
+
onNodeDoubleClick: selectionEnabled ? handleNodeDoubleClick : void 0,
|
|
5269
|
+
enableDrag: dragEnabled && !isConnecting,
|
|
5270
|
+
onNodeDragStart: dragEnabled && !isConnecting ? handleNodeDragStart : void 0,
|
|
5271
|
+
draggingNodeId: dragState.draggedId,
|
|
5272
|
+
dragOffset: dragState.offset
|
|
5273
|
+
}
|
|
5274
|
+
),
|
|
5275
|
+
(features.editPipeRoutes ?? false) && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5276
|
+
PipeRenderer,
|
|
5277
|
+
{
|
|
5278
|
+
pipes: displayDiagram.pipes,
|
|
5279
|
+
selectedPipeIds: selectionEnabled ? selection.selectedPipeIds : void 0,
|
|
5280
|
+
onPipeClick: void 0,
|
|
5281
|
+
enableWaypointEditing: true,
|
|
5282
|
+
onWaypointClick: handleWaypointClick,
|
|
5283
|
+
onWaypointDragStart: handleWaypointDragStart,
|
|
5284
|
+
selectedWaypointPipeId: selectedWaypoint?.pipeId || null,
|
|
5285
|
+
selectedWaypointIndex: selectedWaypoint?.pointIndex ?? null,
|
|
5286
|
+
editingPipeId: waypointDragState.draggedId?.split(":")[0] || null,
|
|
5287
|
+
draggingWaypointIndex: waypointDragState.draggedId ? parseInt(waypointDragState.draggedId.split(":")[1], 10) : null,
|
|
5288
|
+
waypointDragOffset: waypointDragState.offset,
|
|
5289
|
+
onPipeSegmentClick: handlePipeSegmentClick
|
|
5290
|
+
}
|
|
5291
|
+
),
|
|
5292
|
+
telemetryEnabled && telemetry && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("g", { id: "layer-telemetry", children: displayDiagram.nodes.map((node) => {
|
|
5293
|
+
const binding = telemetry.get(node.id);
|
|
5294
|
+
if (!binding) return null;
|
|
5295
|
+
const symbol = getSymbolDefinition(node.symbolId);
|
|
5296
|
+
if (!symbol) return null;
|
|
5297
|
+
const overlayX = node.transform.x + symbol.viewBox.width / 2;
|
|
5298
|
+
const overlayY = node.transform.y + symbol.viewBox.height + 50;
|
|
5299
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5300
|
+
DataOverlay,
|
|
3802
5301
|
{
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
strokeWidth: isHovered || isSourcePort ? 2 : 1,
|
|
3809
|
-
opacity: isHovered || isSourcePort ? 1 : 0.6
|
|
5302
|
+
nodeId: node.id,
|
|
5303
|
+
x: overlayX,
|
|
5304
|
+
y: overlayY,
|
|
5305
|
+
telemetry: binding,
|
|
5306
|
+
scale: features.telemetryScale ?? 1
|
|
3810
5307
|
},
|
|
3811
|
-
|
|
5308
|
+
`telemetry-${node.id}`
|
|
3812
5309
|
);
|
|
3813
|
-
})
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
5310
|
+
}) }),
|
|
5311
|
+
dragOverPosition && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5312
|
+
"circle",
|
|
5313
|
+
{
|
|
5314
|
+
cx: dragOverPosition.x,
|
|
5315
|
+
cy: dragOverPosition.y,
|
|
5316
|
+
r: 20,
|
|
5317
|
+
fill: "#3b82f6",
|
|
5318
|
+
opacity: 0.3,
|
|
5319
|
+
stroke: "#3b82f6",
|
|
5320
|
+
strokeWidth: 2,
|
|
5321
|
+
pointerEvents: "none"
|
|
5322
|
+
}
|
|
5323
|
+
),
|
|
5324
|
+
isConnecting && connectionSource && connectionCursor && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("g", { id: "connection-preview", pointerEvents: "none", children: (() => {
|
|
5325
|
+
const sourceNode = displayDiagram.nodes.find((n) => n.id === connectionSource);
|
|
5326
|
+
if (!sourceNode) return null;
|
|
5327
|
+
const symbol = getSymbolDefinition(sourceNode.symbolId);
|
|
5328
|
+
let lineStartX = sourceNode.transform.x;
|
|
5329
|
+
let lineStartY = sourceNode.transform.y;
|
|
5330
|
+
if (connectionSourcePort && symbol?.ports) {
|
|
5331
|
+
const port = symbol.ports.find((p) => p.id === connectionSourcePort);
|
|
5332
|
+
if (port) {
|
|
5333
|
+
const portPos = getPortWorldPosition(sourceNode, connectionSourcePort);
|
|
5334
|
+
if (portPos) {
|
|
5335
|
+
lineStartX = portPos.x;
|
|
5336
|
+
lineStartY = portPos.y;
|
|
5337
|
+
}
|
|
5338
|
+
}
|
|
5339
|
+
}
|
|
5340
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
5341
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5342
|
+
"circle",
|
|
5343
|
+
{
|
|
5344
|
+
cx: lineStartX,
|
|
5345
|
+
cy: lineStartY,
|
|
5346
|
+
r: 30,
|
|
5347
|
+
fill: "none",
|
|
5348
|
+
stroke: "#10b981",
|
|
5349
|
+
strokeWidth: 3,
|
|
5350
|
+
opacity: 0.6
|
|
5351
|
+
}
|
|
5352
|
+
),
|
|
5353
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5354
|
+
"line",
|
|
5355
|
+
{
|
|
5356
|
+
x1: lineStartX,
|
|
5357
|
+
y1: lineStartY,
|
|
5358
|
+
x2: connectionCursor.x,
|
|
5359
|
+
y2: connectionCursor.y,
|
|
5360
|
+
stroke: "#10b981",
|
|
5361
|
+
strokeWidth: 2,
|
|
5362
|
+
strokeDasharray: "5,5",
|
|
5363
|
+
opacity: 0.8
|
|
5364
|
+
}
|
|
5365
|
+
),
|
|
5366
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5367
|
+
"circle",
|
|
5368
|
+
{
|
|
5369
|
+
cx: connectionCursor.x,
|
|
5370
|
+
cy: connectionCursor.y,
|
|
5371
|
+
r: 8,
|
|
5372
|
+
fill: "#10b981",
|
|
5373
|
+
opacity: 0.6
|
|
5374
|
+
}
|
|
5375
|
+
)
|
|
5376
|
+
] });
|
|
5377
|
+
})() }),
|
|
5378
|
+
features.connectionMode && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("g", { id: "port-indicators", children: displayDiagram.nodes.map((node) => {
|
|
5379
|
+
const symbol = getSymbolDefinition(node.symbolId);
|
|
5380
|
+
if (!symbol?.ports) return null;
|
|
5381
|
+
return symbol.ports.map((port) => {
|
|
5382
|
+
const portPos = getPortWorldPosition(node, port.id);
|
|
5383
|
+
if (!portPos) return null;
|
|
5384
|
+
const isHovered = hoveredPort === port.id && hoveredNode === node.id;
|
|
5385
|
+
const isSourcePort = node.id === connectionSource && port.id === connectionSourcePort;
|
|
5386
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("g", { children: [
|
|
5387
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5388
|
+
"circle",
|
|
5389
|
+
{
|
|
5390
|
+
cx: portPos.x,
|
|
5391
|
+
cy: portPos.y,
|
|
5392
|
+
r: 15,
|
|
5393
|
+
fill: "transparent",
|
|
5394
|
+
style: { cursor: "pointer" },
|
|
5395
|
+
pointerEvents: "auto",
|
|
5396
|
+
onClick: (e) => {
|
|
5397
|
+
e.stopPropagation();
|
|
5398
|
+
if (isConnecting && connectionSource) {
|
|
5399
|
+
if (connectionSource !== node.id) {
|
|
5400
|
+
onPipeCreated?.(
|
|
5401
|
+
connectionSource,
|
|
5402
|
+
node.id,
|
|
5403
|
+
connectionSourcePort || void 0,
|
|
5404
|
+
port.id
|
|
5405
|
+
);
|
|
5406
|
+
setIsConnecting(false);
|
|
5407
|
+
setConnectionSource(null);
|
|
5408
|
+
setConnectionSourcePort(null);
|
|
5409
|
+
setConnectionCursor(null);
|
|
5410
|
+
setHoveredPort(null);
|
|
5411
|
+
}
|
|
5412
|
+
} else {
|
|
5413
|
+
setIsConnecting(true);
|
|
5414
|
+
setConnectionSource(node.id);
|
|
5415
|
+
setConnectionSourcePort(port.id);
|
|
5416
|
+
}
|
|
5417
|
+
}
|
|
5418
|
+
}
|
|
5419
|
+
),
|
|
5420
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5421
|
+
"circle",
|
|
5422
|
+
{
|
|
5423
|
+
cx: portPos.x,
|
|
5424
|
+
cy: portPos.y,
|
|
5425
|
+
r: isHovered ? 8 : 5,
|
|
5426
|
+
fill: isSourcePort ? "#10b981" : isHovered ? "#3b82f6" : "#94a3b8",
|
|
5427
|
+
stroke: isSourcePort ? "#059669" : isHovered ? "#2563eb" : "#64748b",
|
|
5428
|
+
strokeWidth: isHovered || isSourcePort ? 2 : 1,
|
|
5429
|
+
opacity: isHovered || isSourcePort ? 1 : 0.6,
|
|
5430
|
+
pointerEvents: "none"
|
|
5431
|
+
}
|
|
5432
|
+
)
|
|
5433
|
+
] }, `${node.id}-${port.id}`);
|
|
5434
|
+
});
|
|
5435
|
+
}) })
|
|
5436
|
+
]
|
|
5437
|
+
}
|
|
5438
|
+
),
|
|
5439
|
+
features.dragNodes && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5440
|
+
PositionPanel,
|
|
5441
|
+
{
|
|
5442
|
+
selectedNode,
|
|
5443
|
+
selectedWaypoint: selectedWaypoint ? {
|
|
5444
|
+
pipeId: selectedWaypoint.pipeId,
|
|
5445
|
+
pointIndex: selectedWaypoint.pointIndex,
|
|
5446
|
+
position: localDiagram.pipes.find((p) => p.id === selectedWaypoint.pipeId)?.routePoints[selectedWaypoint.pointIndex] || { x: 0, y: 0 }
|
|
5447
|
+
} : null,
|
|
5448
|
+
onPositionChange: handlePositionChange,
|
|
5449
|
+
onWaypointPositionChange: handleWaypointPositionChange,
|
|
5450
|
+
position: "top-right"
|
|
5451
|
+
}
|
|
5452
|
+
)
|
|
5453
|
+
]
|
|
3818
5454
|
}
|
|
3819
5455
|
);
|
|
3820
5456
|
}
|
|
3821
5457
|
|
|
3822
5458
|
// src/components/SymbolLibrary/SymbolLibrary.tsx
|
|
3823
|
-
var
|
|
3824
|
-
var
|
|
5459
|
+
var import_react16 = require("react");
|
|
5460
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
3825
5461
|
function SymbolLibrary({
|
|
3826
5462
|
className = "",
|
|
3827
5463
|
onSymbolDragStart,
|
|
3828
5464
|
showCategories = true,
|
|
3829
5465
|
categories = ["Valves", "Pumps", "Tanks", "Instruments", "Displays"]
|
|
3830
5466
|
}) {
|
|
3831
|
-
const [selectedCategory, setSelectedCategory] = (0,
|
|
3832
|
-
const [searchQuery, setSearchQuery] = (0,
|
|
5467
|
+
const [selectedCategory, setSelectedCategory] = (0, import_react16.useState)("all");
|
|
5468
|
+
const [searchQuery, setSearchQuery] = (0, import_react16.useState)("");
|
|
3833
5469
|
const symbolIds = getAvailableSymbols();
|
|
3834
5470
|
const allSymbols = symbolIds.map((id) => getSymbolDefinition(id)).filter((symbol) => symbol !== void 0);
|
|
5471
|
+
const categoryMap = {
|
|
5472
|
+
Valves: "valve",
|
|
5473
|
+
Pumps: "pump",
|
|
5474
|
+
Tanks: "vessel",
|
|
5475
|
+
Instruments: "instrument",
|
|
5476
|
+
Displays: "display"
|
|
5477
|
+
};
|
|
3835
5478
|
const filteredSymbols = allSymbols.filter((symbol) => {
|
|
3836
|
-
const
|
|
5479
|
+
const actualCategory = categoryMap[selectedCategory] || selectedCategory;
|
|
5480
|
+
const matchesCategory = selectedCategory === "all" || symbol.category === actualCategory;
|
|
3837
5481
|
const matchesSearch = searchQuery === "" || symbol.name.toLowerCase().includes(searchQuery.toLowerCase()) || symbol.id.toLowerCase().includes(searchQuery.toLowerCase());
|
|
3838
5482
|
return matchesCategory && matchesSearch;
|
|
3839
5483
|
});
|
|
@@ -3842,9 +5486,9 @@ function SymbolLibrary({
|
|
|
3842
5486
|
event.dataTransfer.effectAllowed = "copy";
|
|
3843
5487
|
onSymbolDragStart?.(symbol.id, event);
|
|
3844
5488
|
};
|
|
3845
|
-
return /* @__PURE__ */ (0,
|
|
3846
|
-
/* @__PURE__ */ (0,
|
|
3847
|
-
/* @__PURE__ */ (0,
|
|
5489
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: `symbol-library ${className}`.trim(), style: styles.container, children: [
|
|
5490
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: styles.header, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h3", { style: styles.title, children: "Symbol Library" }) }),
|
|
5491
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: styles.searchContainer, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3848
5492
|
"input",
|
|
3849
5493
|
{
|
|
3850
5494
|
type: "text",
|
|
@@ -3854,8 +5498,8 @@ function SymbolLibrary({
|
|
|
3854
5498
|
style: styles.searchInput
|
|
3855
5499
|
}
|
|
3856
5500
|
) }),
|
|
3857
|
-
showCategories && /* @__PURE__ */ (0,
|
|
3858
|
-
/* @__PURE__ */ (0,
|
|
5501
|
+
showCategories && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: styles.categories, children: [
|
|
5502
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3859
5503
|
"button",
|
|
3860
5504
|
{
|
|
3861
5505
|
onClick: () => setSelectedCategory("all"),
|
|
@@ -3866,7 +5510,7 @@ function SymbolLibrary({
|
|
|
3866
5510
|
children: "All"
|
|
3867
5511
|
}
|
|
3868
5512
|
),
|
|
3869
|
-
categories.map((category) => /* @__PURE__ */ (0,
|
|
5513
|
+
categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3870
5514
|
"button",
|
|
3871
5515
|
{
|
|
3872
5516
|
onClick: () => setSelectedCategory(category),
|
|
@@ -3879,7 +5523,7 @@ function SymbolLibrary({
|
|
|
3879
5523
|
category
|
|
3880
5524
|
))
|
|
3881
5525
|
] }),
|
|
3882
|
-
/* @__PURE__ */ (0,
|
|
5526
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: styles.symbolGrid, children: filteredSymbols.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: styles.emptyState, children: "No symbols found" }) : filteredSymbols.map((symbol) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
3883
5527
|
"div",
|
|
3884
5528
|
{
|
|
3885
5529
|
draggable: true,
|
|
@@ -3887,15 +5531,15 @@ function SymbolLibrary({
|
|
|
3887
5531
|
style: styles.symbolCard,
|
|
3888
5532
|
title: symbol.metadata?.description || symbol.name,
|
|
3889
5533
|
children: [
|
|
3890
|
-
/* @__PURE__ */ (0,
|
|
5534
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: styles.symbolPreview, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3891
5535
|
"svg",
|
|
3892
5536
|
{
|
|
3893
5537
|
viewBox: `${symbol.viewBox.x} ${symbol.viewBox.y} ${symbol.viewBox.width} ${symbol.viewBox.height}`,
|
|
3894
5538
|
style: styles.symbolSvg,
|
|
3895
|
-
children: /* @__PURE__ */ (0,
|
|
5539
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("g", { dangerouslySetInnerHTML: { __html: symbol.svgContent } })
|
|
3896
5540
|
}
|
|
3897
5541
|
) }),
|
|
3898
|
-
/* @__PURE__ */ (0,
|
|
5542
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: styles.symbolName, children: symbol.name })
|
|
3899
5543
|
]
|
|
3900
5544
|
},
|
|
3901
5545
|
symbol.id
|
|
@@ -4004,7 +5648,7 @@ var styles = {
|
|
|
4004
5648
|
};
|
|
4005
5649
|
|
|
4006
5650
|
// src/components/NodeConfigPanel/NodeConfigPanel.tsx
|
|
4007
|
-
var
|
|
5651
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
4008
5652
|
function NodeConfigPanel({
|
|
4009
5653
|
node,
|
|
4010
5654
|
binding,
|
|
@@ -4023,15 +5667,15 @@ function NodeConfigPanel({
|
|
|
4023
5667
|
padding: "20px",
|
|
4024
5668
|
...style
|
|
4025
5669
|
};
|
|
4026
|
-
return /* @__PURE__ */ (0,
|
|
4027
|
-
/* @__PURE__ */ (0,
|
|
5670
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className, style: defaultStyle, children: [
|
|
5671
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("h2", { style: { margin: "0 0 16px 0", fontSize: "1rem", fontWeight: 600 }, children: [
|
|
4028
5672
|
"Configure: ",
|
|
4029
5673
|
node.id
|
|
4030
5674
|
] }),
|
|
4031
|
-
/* @__PURE__ */ (0,
|
|
4032
|
-
/* @__PURE__ */ (0,
|
|
4033
|
-
/* @__PURE__ */ (0,
|
|
4034
|
-
/* @__PURE__ */ (0,
|
|
5675
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginBottom: "20px" }, children: [
|
|
5676
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Node Settings" }),
|
|
5677
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label:" }),
|
|
5678
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4035
5679
|
"input",
|
|
4036
5680
|
{
|
|
4037
5681
|
type: "text",
|
|
@@ -4047,10 +5691,10 @@ function NodeConfigPanel({
|
|
|
4047
5691
|
}
|
|
4048
5692
|
}
|
|
4049
5693
|
),
|
|
4050
|
-
/* @__PURE__ */ (0,
|
|
4051
|
-
/* @__PURE__ */ (0,
|
|
4052
|
-
/* @__PURE__ */ (0,
|
|
4053
|
-
/* @__PURE__ */ (0,
|
|
5694
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
|
|
5695
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5696
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset X:" }),
|
|
5697
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4054
5698
|
"input",
|
|
4055
5699
|
{
|
|
4056
5700
|
type: "number",
|
|
@@ -4071,9 +5715,9 @@ function NodeConfigPanel({
|
|
|
4071
5715
|
}
|
|
4072
5716
|
)
|
|
4073
5717
|
] }),
|
|
4074
|
-
/* @__PURE__ */ (0,
|
|
4075
|
-
/* @__PURE__ */ (0,
|
|
4076
|
-
/* @__PURE__ */ (0,
|
|
5718
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5719
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset Y:" }),
|
|
5720
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4077
5721
|
"input",
|
|
4078
5722
|
{
|
|
4079
5723
|
type: "number",
|
|
@@ -4095,9 +5739,9 @@ function NodeConfigPanel({
|
|
|
4095
5739
|
)
|
|
4096
5740
|
] })
|
|
4097
5741
|
] }),
|
|
4098
|
-
/* @__PURE__ */ (0,
|
|
4099
|
-
/* @__PURE__ */ (0,
|
|
4100
|
-
/* @__PURE__ */ (0,
|
|
5742
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5743
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Font Size:" }),
|
|
5744
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4101
5745
|
"input",
|
|
4102
5746
|
{
|
|
4103
5747
|
type: "number",
|
|
@@ -4117,9 +5761,9 @@ function NodeConfigPanel({
|
|
|
4117
5761
|
}
|
|
4118
5762
|
)
|
|
4119
5763
|
] }),
|
|
4120
|
-
/* @__PURE__ */ (0,
|
|
4121
|
-
/* @__PURE__ */ (0,
|
|
4122
|
-
/* @__PURE__ */ (0,
|
|
5764
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5765
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Rotation (degrees):" }),
|
|
5766
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4123
5767
|
"input",
|
|
4124
5768
|
{
|
|
4125
5769
|
type: "number",
|
|
@@ -4144,9 +5788,9 @@ function NodeConfigPanel({
|
|
|
4144
5788
|
)
|
|
4145
5789
|
] })
|
|
4146
5790
|
] }),
|
|
4147
|
-
/* @__PURE__ */ (0,
|
|
4148
|
-
/* @__PURE__ */ (0,
|
|
4149
|
-
!binding ? /* @__PURE__ */ (0,
|
|
5791
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginBottom: "20px" }, children: [
|
|
5792
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Telemetry Data" }),
|
|
5793
|
+
!binding ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4150
5794
|
"button",
|
|
4151
5795
|
{
|
|
4152
5796
|
onClick: () => {
|
|
@@ -4189,9 +5833,9 @@ function NodeConfigPanel({
|
|
|
4189
5833
|
},
|
|
4190
5834
|
children: "+ Add Telemetry"
|
|
4191
5835
|
}
|
|
4192
|
-
) : /* @__PURE__ */ (0,
|
|
4193
|
-
/* @__PURE__ */ (0,
|
|
4194
|
-
/* @__PURE__ */ (0,
|
|
5836
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
5837
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Initial Value:" }),
|
|
5838
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4195
5839
|
"input",
|
|
4196
5840
|
{
|
|
4197
5841
|
type: "number",
|
|
@@ -4213,8 +5857,8 @@ function NodeConfigPanel({
|
|
|
4213
5857
|
}
|
|
4214
5858
|
}
|
|
4215
5859
|
),
|
|
4216
|
-
/* @__PURE__ */ (0,
|
|
4217
|
-
/* @__PURE__ */ (0,
|
|
5860
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Unit:" }),
|
|
5861
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4218
5862
|
"input",
|
|
4219
5863
|
{
|
|
4220
5864
|
type: "text",
|
|
@@ -4236,8 +5880,8 @@ function NodeConfigPanel({
|
|
|
4236
5880
|
}
|
|
4237
5881
|
}
|
|
4238
5882
|
),
|
|
4239
|
-
/* @__PURE__ */ (0,
|
|
4240
|
-
/* @__PURE__ */ (0,
|
|
5883
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
|
|
5884
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4241
5885
|
"input",
|
|
4242
5886
|
{
|
|
4243
5887
|
type: "checkbox",
|
|
@@ -4259,8 +5903,8 @@ function NodeConfigPanel({
|
|
|
4259
5903
|
),
|
|
4260
5904
|
"Show Sparkline"
|
|
4261
5905
|
] }),
|
|
4262
|
-
/* @__PURE__ */ (0,
|
|
4263
|
-
/* @__PURE__ */ (0,
|
|
5906
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginTop: "12px" }, children: [
|
|
5907
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4264
5908
|
"label",
|
|
4265
5909
|
{
|
|
4266
5910
|
style: {
|
|
@@ -4272,10 +5916,10 @@ function NodeConfigPanel({
|
|
|
4272
5916
|
children: "Telemetry Position Offset:"
|
|
4273
5917
|
}
|
|
4274
5918
|
),
|
|
4275
|
-
/* @__PURE__ */ (0,
|
|
4276
|
-
/* @__PURE__ */ (0,
|
|
4277
|
-
/* @__PURE__ */ (0,
|
|
4278
|
-
/* @__PURE__ */ (0,
|
|
5919
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
|
|
5920
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5921
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "X Offset:" }),
|
|
5922
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4279
5923
|
"input",
|
|
4280
5924
|
{
|
|
4281
5925
|
type: "number",
|
|
@@ -4302,9 +5946,9 @@ function NodeConfigPanel({
|
|
|
4302
5946
|
}
|
|
4303
5947
|
)
|
|
4304
5948
|
] }),
|
|
4305
|
-
/* @__PURE__ */ (0,
|
|
4306
|
-
/* @__PURE__ */ (0,
|
|
4307
|
-
/* @__PURE__ */ (0,
|
|
5949
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
|
|
5950
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Y Offset:" }),
|
|
5951
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4308
5952
|
"input",
|
|
4309
5953
|
{
|
|
4310
5954
|
type: "number",
|
|
@@ -4332,8 +5976,8 @@ function NodeConfigPanel({
|
|
|
4332
5976
|
)
|
|
4333
5977
|
] })
|
|
4334
5978
|
] }),
|
|
4335
|
-
/* @__PURE__ */ (0,
|
|
4336
|
-
/* @__PURE__ */ (0,
|
|
5979
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginTop: "16px" }, children: [
|
|
5980
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4337
5981
|
"label",
|
|
4338
5982
|
{
|
|
4339
5983
|
style: {
|
|
@@ -4345,10 +5989,10 @@ function NodeConfigPanel({
|
|
|
4345
5989
|
children: "Display Colors:"
|
|
4346
5990
|
}
|
|
4347
5991
|
),
|
|
4348
|
-
/* @__PURE__ */ (0,
|
|
4349
|
-
/* @__PURE__ */ (0,
|
|
4350
|
-
/* @__PURE__ */ (0,
|
|
4351
|
-
/* @__PURE__ */ (0,
|
|
5992
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginBottom: "8px" }, children: [
|
|
5993
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Text Color:" }),
|
|
5994
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
|
|
5995
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4352
5996
|
"input",
|
|
4353
5997
|
{
|
|
4354
5998
|
type: "color",
|
|
@@ -4374,7 +6018,7 @@ function NodeConfigPanel({
|
|
|
4374
6018
|
}
|
|
4375
6019
|
}
|
|
4376
6020
|
),
|
|
4377
|
-
/* @__PURE__ */ (0,
|
|
6021
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4378
6022
|
"input",
|
|
4379
6023
|
{
|
|
4380
6024
|
type: "text",
|
|
@@ -4404,10 +6048,10 @@ function NodeConfigPanel({
|
|
|
4404
6048
|
)
|
|
4405
6049
|
] })
|
|
4406
6050
|
] }),
|
|
4407
|
-
binding.display?.showSparkline && /* @__PURE__ */ (0,
|
|
4408
|
-
/* @__PURE__ */ (0,
|
|
4409
|
-
/* @__PURE__ */ (0,
|
|
4410
|
-
/* @__PURE__ */ (0,
|
|
6051
|
+
binding.display?.showSparkline && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginBottom: "8px" }, children: [
|
|
6052
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Sparkline Color:" }),
|
|
6053
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
|
|
6054
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4411
6055
|
"input",
|
|
4412
6056
|
{
|
|
4413
6057
|
type: "color",
|
|
@@ -4433,7 +6077,7 @@ function NodeConfigPanel({
|
|
|
4433
6077
|
}
|
|
4434
6078
|
}
|
|
4435
6079
|
),
|
|
4436
|
-
/* @__PURE__ */ (0,
|
|
6080
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4437
6081
|
"input",
|
|
4438
6082
|
{
|
|
4439
6083
|
type: "text",
|
|
@@ -4463,9 +6107,9 @@ function NodeConfigPanel({
|
|
|
4463
6107
|
)
|
|
4464
6108
|
] })
|
|
4465
6109
|
] }),
|
|
4466
|
-
/* @__PURE__ */ (0,
|
|
4467
|
-
/* @__PURE__ */ (0,
|
|
4468
|
-
/* @__PURE__ */ (0,
|
|
6110
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginBottom: "8px" }, children: [
|
|
6111
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Background:" }),
|
|
6112
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4469
6113
|
"input",
|
|
4470
6114
|
{
|
|
4471
6115
|
type: "text",
|
|
@@ -4493,20 +6137,20 @@ function NodeConfigPanel({
|
|
|
4493
6137
|
}
|
|
4494
6138
|
}
|
|
4495
6139
|
),
|
|
4496
|
-
/* @__PURE__ */ (0,
|
|
6140
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { fontSize: "0.65rem", color: "#6b7280", marginTop: "2px" }, children: "Use 'status' for status-based color or hex code" })
|
|
4497
6141
|
] })
|
|
4498
6142
|
] }),
|
|
4499
6143
|
" "
|
|
4500
6144
|
] })
|
|
4501
6145
|
] })
|
|
4502
6146
|
] }),
|
|
4503
|
-
binding && /* @__PURE__ */ (0,
|
|
4504
|
-
/* @__PURE__ */ (0,
|
|
6147
|
+
binding && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginBottom: "20px" }, children: [
|
|
6148
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Thresholds" }),
|
|
4505
6149
|
["highHigh", "high", "low", "lowLow"].map((key) => {
|
|
4506
6150
|
const label = key === "highHigh" ? "High-High (\u2265)" : key === "high" ? "High (\u2265)" : key === "low" ? "Low (\u2264)" : "Low-Low (\u2264)";
|
|
4507
|
-
return /* @__PURE__ */ (0,
|
|
4508
|
-
/* @__PURE__ */ (0,
|
|
4509
|
-
/* @__PURE__ */ (0,
|
|
6151
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginBottom: "8px" }, children: [
|
|
6152
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: label }),
|
|
6153
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4510
6154
|
"input",
|
|
4511
6155
|
{
|
|
4512
6156
|
type: "number",
|
|
@@ -4530,8 +6174,8 @@ function NodeConfigPanel({
|
|
|
4530
6174
|
] }, key);
|
|
4531
6175
|
})
|
|
4532
6176
|
] }),
|
|
4533
|
-
binding && /* @__PURE__ */ (0,
|
|
4534
|
-
/* @__PURE__ */ (0,
|
|
6177
|
+
binding && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginBottom: "20px" }, children: [
|
|
6178
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Status Colors" }),
|
|
4535
6179
|
["normal", "warning", "alarm", "fault", "off"].map((status) => {
|
|
4536
6180
|
const defaultColors = {
|
|
4537
6181
|
normal: "#10b981",
|
|
@@ -4541,13 +6185,13 @@ function NodeConfigPanel({
|
|
|
4541
6185
|
off: "#6b7280"
|
|
4542
6186
|
};
|
|
4543
6187
|
const label = status === "normal" ? "Normal" : status === "warning" ? "Warning" : status === "alarm" ? "Alarm" : status === "fault" ? "Fault" : "Off";
|
|
4544
|
-
return /* @__PURE__ */ (0,
|
|
4545
|
-
/* @__PURE__ */ (0,
|
|
6188
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginBottom: "8px" }, children: [
|
|
6189
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
|
|
4546
6190
|
label,
|
|
4547
6191
|
":"
|
|
4548
6192
|
] }),
|
|
4549
|
-
/* @__PURE__ */ (0,
|
|
4550
|
-
/* @__PURE__ */ (0,
|
|
6193
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
|
|
6194
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4551
6195
|
"input",
|
|
4552
6196
|
{
|
|
4553
6197
|
type: "color",
|
|
@@ -4568,7 +6212,7 @@ function NodeConfigPanel({
|
|
|
4568
6212
|
}
|
|
4569
6213
|
}
|
|
4570
6214
|
),
|
|
4571
|
-
/* @__PURE__ */ (0,
|
|
6215
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4572
6216
|
"input",
|
|
4573
6217
|
{
|
|
4574
6218
|
type: "text",
|
|
@@ -4595,7 +6239,7 @@ function NodeConfigPanel({
|
|
|
4595
6239
|
] }, status);
|
|
4596
6240
|
})
|
|
4597
6241
|
] }),
|
|
4598
|
-
/* @__PURE__ */ (0,
|
|
6242
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { marginTop: "20px", paddingTop: "20px", borderTop: "1px solid #cbd5e1" }, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
4599
6243
|
"button",
|
|
4600
6244
|
{
|
|
4601
6245
|
onClick: onRemove,
|
|
@@ -4835,7 +6479,7 @@ var DEFAULT_THRESHOLDS = {
|
|
|
4835
6479
|
};
|
|
4836
6480
|
|
|
4837
6481
|
// src/diagram/hooks/useSimulation.ts
|
|
4838
|
-
var
|
|
6482
|
+
var import_react17 = require("react");
|
|
4839
6483
|
function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
4840
6484
|
const {
|
|
4841
6485
|
interval = 2e3,
|
|
@@ -4846,7 +6490,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
|
4846
6490
|
historyLength = 10,
|
|
4847
6491
|
generateValue
|
|
4848
6492
|
} = options;
|
|
4849
|
-
(0,
|
|
6493
|
+
(0, import_react17.useEffect)(() => {
|
|
4850
6494
|
if (!enabled) return;
|
|
4851
6495
|
const intervalId = setInterval(() => {
|
|
4852
6496
|
const updates = [];
|
|
@@ -4949,6 +6593,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
|
4949
6593
|
useSelection,
|
|
4950
6594
|
useSimulation,
|
|
4951
6595
|
useTelemetry,
|
|
6596
|
+
useTelemetryStatus,
|
|
4952
6597
|
useTheme,
|
|
4953
6598
|
useViewBox,
|
|
4954
6599
|
validateDiagram
|