@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.js
CHANGED
|
@@ -1694,35 +1694,10 @@ var ThemeToggle = ({
|
|
|
1694
1694
|
};
|
|
1695
1695
|
|
|
1696
1696
|
// src/components/PIDCanvas/PIDCanvas.tsx
|
|
1697
|
-
import { useCallback as useCallback7, useState as
|
|
1697
|
+
import { useCallback as useCallback7, useState as useState12, useEffect as useEffect10, useRef as useRef5 } from "react";
|
|
1698
1698
|
|
|
1699
1699
|
// src/diagram/symbols/mockSymbolLibrary.ts
|
|
1700
1700
|
var mockSymbolLibrary = {
|
|
1701
|
-
"valve-ball": {
|
|
1702
|
-
id: "valve-ball",
|
|
1703
|
-
name: "Ball Valve",
|
|
1704
|
-
category: "valve",
|
|
1705
|
-
viewBox: { x: 0, y: 0, width: 50, height: 50 },
|
|
1706
|
-
ports: [
|
|
1707
|
-
{ id: "inlet", x: 0, y: 25, type: "inlet", direction: "in" },
|
|
1708
|
-
{ id: "outlet", x: 50, y: 25, type: "outlet", direction: "out" }
|
|
1709
|
-
],
|
|
1710
|
-
svgContent: `
|
|
1711
|
-
<g>
|
|
1712
|
-
<!-- Valve body -->
|
|
1713
|
-
<rect x="15" y="10" width="20" height="30" fill="#546e7a" stroke="#263238" stroke-width="2" rx="2"/>
|
|
1714
|
-
<!-- Ball indicator -->
|
|
1715
|
-
<circle cx="25" cy="25" r="6" fill="#ffa726" stroke="#e65100" stroke-width="1.5"/>
|
|
1716
|
-
<!-- Inlet/outlet lines -->
|
|
1717
|
-
<line x1="0" y1="25" x2="15" y2="25" stroke="#263238" stroke-width="3" stroke-linecap="round"/>
|
|
1718
|
-
<line x1="35" y1="25" x2="50" y2="25" stroke="#263238" stroke-width="3" stroke-linecap="round"/>
|
|
1719
|
-
</g>
|
|
1720
|
-
`,
|
|
1721
|
-
metadata: {
|
|
1722
|
-
description: "Ball valve for flow control",
|
|
1723
|
-
tags: ["valve", "control", "shutoff"]
|
|
1724
|
-
}
|
|
1725
|
-
},
|
|
1726
1701
|
"valve-gate": {
|
|
1727
1702
|
id: "valve-gate",
|
|
1728
1703
|
name: "Gate Valve (Powered)",
|
|
@@ -1735,11 +1710,11 @@ var mockSymbolLibrary = {
|
|
|
1735
1710
|
svgContent: `
|
|
1736
1711
|
<g>
|
|
1737
1712
|
<!-- Actuator box -->
|
|
1738
|
-
<rect x="16.74" y="0" width="18.02" height="18.02" fill="#edeeef" stroke="#666666" pointer-events="all"/>
|
|
1713
|
+
<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"/>
|
|
1739
1714
|
<!-- Actuator stem -->
|
|
1740
|
-
<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"/>
|
|
1715
|
+
<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"/>
|
|
1741
1716
|
<!-- Valve body (two triangles forming diamond) -->
|
|
1742
|
-
<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"/>
|
|
1717
|
+
<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"/>
|
|
1743
1718
|
</g>
|
|
1744
1719
|
`,
|
|
1745
1720
|
metadata: {
|
|
@@ -1747,84 +1722,1143 @@ var mockSymbolLibrary = {
|
|
|
1747
1722
|
tags: ["valve", "gate", "powered", "actuator"]
|
|
1748
1723
|
}
|
|
1749
1724
|
},
|
|
1750
|
-
"pump-
|
|
1751
|
-
id: "pump-
|
|
1752
|
-
name: "
|
|
1725
|
+
"pump-positive-displacement": {
|
|
1726
|
+
id: "pump-positive-displacement",
|
|
1727
|
+
name: "Positive Displacement Pump",
|
|
1753
1728
|
category: "pump",
|
|
1754
|
-
viewBox: { x: 0, y: 0, width:
|
|
1729
|
+
viewBox: { x: 0, y: 0, width: 56.25, height: 56.25 },
|
|
1755
1730
|
ports: [
|
|
1756
|
-
{ id: "inlet", x:
|
|
1757
|
-
{ id: "outlet", x:
|
|
1731
|
+
{ id: "inlet", x: 0, y: 28.125, type: "inlet", direction: "in" },
|
|
1732
|
+
{ id: "outlet", x: 56.25, y: 28.125, type: "outlet", direction: "out" }
|
|
1733
|
+
],
|
|
1734
|
+
svgContent: `
|
|
1735
|
+
<g transform="scale(0.5625)">
|
|
1736
|
+
<!-- Outer circle -->
|
|
1737
|
+
<ellipse
|
|
1738
|
+
cx="50"
|
|
1739
|
+
cy="50"
|
|
1740
|
+
rx="50"
|
|
1741
|
+
ry="50"
|
|
1742
|
+
fill="var(--symbol-fill, #edeeef)"
|
|
1743
|
+
stroke="var(--symbol-stroke, rgb(0, 0, 0))"
|
|
1744
|
+
stroke-width="1"
|
|
1745
|
+
/>
|
|
1746
|
+
|
|
1747
|
+
<!-- Diagonal line from top to bottom-right -->
|
|
1748
|
+
<path
|
|
1749
|
+
d="M 50 0 L 100 50 L 50 100"
|
|
1750
|
+
fill="none"
|
|
1751
|
+
stroke="var(--symbol-stroke, rgb(0, 0, 0))"
|
|
1752
|
+
stroke-width="1"
|
|
1753
|
+
stroke-miterlimit="10"
|
|
1754
|
+
/>
|
|
1755
|
+
|
|
1756
|
+
<!-- Center square -->
|
|
1757
|
+
<rect
|
|
1758
|
+
x="35"
|
|
1759
|
+
y="35"
|
|
1760
|
+
width="30"
|
|
1761
|
+
height="30"
|
|
1762
|
+
fill="none"
|
|
1763
|
+
stroke="var(--symbol-stroke, rgb(0, 0, 0))"
|
|
1764
|
+
stroke-width="1"
|
|
1765
|
+
/>
|
|
1766
|
+
</g>
|
|
1767
|
+
`,
|
|
1768
|
+
metadata: {
|
|
1769
|
+
description: "Positive displacement pump (ISO standard)",
|
|
1770
|
+
tags: ["pump", "positive-displacement", "iso"]
|
|
1771
|
+
}
|
|
1772
|
+
},
|
|
1773
|
+
"vannefold-bottom": {
|
|
1774
|
+
id: "vannefold-bottom",
|
|
1775
|
+
name: "Vannefold Block (Bottom)",
|
|
1776
|
+
category: "valve",
|
|
1777
|
+
viewBox: { x: -0.5, y: -0.5, width: 88, height: 67.785156 },
|
|
1778
|
+
ports: [
|
|
1779
|
+
{ id: "bottom-inlet", x: 0, y: 25, type: "control", direction: "in" },
|
|
1780
|
+
{ id: "top-outlet", x: 48, y: 65, type: "control", direction: "out" }
|
|
1758
1781
|
],
|
|
1759
1782
|
svgContent: `
|
|
1760
1783
|
<g>
|
|
1761
|
-
<!--
|
|
1762
|
-
<
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1784
|
+
<!-- Bottom inlet pipe -->
|
|
1785
|
+
<path
|
|
1786
|
+
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"
|
|
1787
|
+
fill="none"
|
|
1788
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1789
|
+
stroke-miterlimit="10"
|
|
1790
|
+
/>
|
|
1791
|
+
|
|
1792
|
+
<!-- Top outlet pipe -->
|
|
1793
|
+
<path
|
|
1794
|
+
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"
|
|
1795
|
+
fill="none"
|
|
1796
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1797
|
+
stroke-miterlimit="10"
|
|
1798
|
+
/>
|
|
1799
|
+
|
|
1800
|
+
<!-- Main block outer -->
|
|
1801
|
+
<rect
|
|
1802
|
+
x="7"
|
|
1803
|
+
y="0"
|
|
1804
|
+
width="80"
|
|
1805
|
+
height="59.785156"
|
|
1806
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
1807
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1808
|
+
/>
|
|
1809
|
+
|
|
1810
|
+
<!-- Main block inner -->
|
|
1811
|
+
<rect
|
|
1812
|
+
x="9"
|
|
1813
|
+
y="2"
|
|
1814
|
+
width="76"
|
|
1815
|
+
height="55.785156"
|
|
1816
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
1817
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1818
|
+
/>
|
|
1819
|
+
|
|
1820
|
+
<!-- Bolt holes -->
|
|
1821
|
+
<ellipse cx="15" cy="7" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1822
|
+
<ellipse cx="15" cy="7" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1823
|
+
<ellipse cx="79" cy="7" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1824
|
+
<ellipse cx="79" cy="7" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1825
|
+
<ellipse cx="15" cy="51.785156" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1826
|
+
<ellipse cx="15" cy="51.785156" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1827
|
+
<ellipse cx="79" cy="51.785156" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1828
|
+
<ellipse cx="79" cy="51.785156" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1829
|
+
|
|
1772
1830
|
</g>
|
|
1773
1831
|
`,
|
|
1774
1832
|
metadata: {
|
|
1775
|
-
description: "
|
|
1776
|
-
tags: ["
|
|
1833
|
+
description: "Vannefold heat exchanger block with bottom inlet configuration",
|
|
1834
|
+
tags: ["heat-exchanger", "vannefold", "fold", "bottom"]
|
|
1777
1835
|
}
|
|
1778
1836
|
},
|
|
1779
|
-
"
|
|
1780
|
-
id: "
|
|
1781
|
-
name: "
|
|
1782
|
-
category: "
|
|
1783
|
-
viewBox: { x: 0, y: 0, width:
|
|
1837
|
+
"vannefold-middle": {
|
|
1838
|
+
id: "vannefold-middle",
|
|
1839
|
+
name: "Vannefold Block (Middle)",
|
|
1840
|
+
category: "valve",
|
|
1841
|
+
viewBox: { x: -0.5, y: -0.5, width: 95, height: 53.097656 },
|
|
1784
1842
|
ports: [
|
|
1785
|
-
{ id: "inlet", x:
|
|
1786
|
-
{ id: "outlet", x:
|
|
1843
|
+
{ id: "left-inlet", x: 0, y: 27.3125, type: "control", direction: "in" },
|
|
1844
|
+
{ id: "right-outlet", x: 95, y: 27.3125, type: "control", direction: "out" }
|
|
1787
1845
|
],
|
|
1788
1846
|
svgContent: `
|
|
1789
1847
|
<g>
|
|
1790
|
-
<!--
|
|
1791
|
-
<
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
<!--
|
|
1799
|
-
<
|
|
1848
|
+
<!-- Left inlet pipe -->
|
|
1849
|
+
<path
|
|
1850
|
+
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"
|
|
1851
|
+
fill="none"
|
|
1852
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1853
|
+
stroke-miterlimit="10"
|
|
1854
|
+
/>
|
|
1855
|
+
|
|
1856
|
+
<!-- Main block outer -->
|
|
1857
|
+
<rect
|
|
1858
|
+
x="7"
|
|
1859
|
+
y="0"
|
|
1860
|
+
width="80"
|
|
1861
|
+
height="52.097656"
|
|
1862
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
1863
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1864
|
+
/>
|
|
1865
|
+
|
|
1866
|
+
<!-- Main block inner -->
|
|
1867
|
+
<rect
|
|
1868
|
+
x="9"
|
|
1869
|
+
y="0"
|
|
1870
|
+
width="76"
|
|
1871
|
+
height="52.097656"
|
|
1872
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
1873
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1874
|
+
/>
|
|
1875
|
+
|
|
1876
|
+
<!-- Bolt holes -->
|
|
1877
|
+
<ellipse cx="15" cy="5.3125" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1878
|
+
<ellipse cx="15" cy="5.3125" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1879
|
+
<ellipse cx="79" cy="5.3125" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1880
|
+
<ellipse cx="79" cy="5.3125" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1881
|
+
<ellipse cx="15" cy="47.3125" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1882
|
+
<ellipse cx="15" cy="47.3125" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1883
|
+
<ellipse cx="79" cy="47.3125" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1884
|
+
<ellipse cx="79" cy="47.3125" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1800
1885
|
</g>
|
|
1801
1886
|
`,
|
|
1802
1887
|
metadata: {
|
|
1803
|
-
description: "
|
|
1804
|
-
tags: ["
|
|
1888
|
+
description: "Vannefold heat exchanger block with side inlet configuration",
|
|
1889
|
+
tags: ["heat-exchanger", "vannefold", "fold", "middle"]
|
|
1805
1890
|
}
|
|
1806
1891
|
},
|
|
1807
|
-
"
|
|
1808
|
-
id: "
|
|
1809
|
-
name: "
|
|
1810
|
-
category: "
|
|
1811
|
-
viewBox: { x: 0, y: 0, width:
|
|
1892
|
+
"vannefold-top": {
|
|
1893
|
+
id: "vannefold-top",
|
|
1894
|
+
name: "Vannefold Block (Top)",
|
|
1895
|
+
category: "valve",
|
|
1896
|
+
viewBox: { x: -0.5, y: -0.5, width: 95, height: 60.785156 },
|
|
1812
1897
|
ports: [
|
|
1813
|
-
{ id: "
|
|
1898
|
+
{ id: "bottom-inlet", x: 0, y: 35, type: "control", direction: "in" },
|
|
1899
|
+
{ id: "top-outlet", x: 48, y: 0, type: "control", direction: "out" }
|
|
1814
1900
|
],
|
|
1815
1901
|
svgContent: `
|
|
1816
1902
|
<g>
|
|
1817
|
-
<!--
|
|
1818
|
-
<
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1903
|
+
<!-- Bottom inlet pipe -->
|
|
1904
|
+
<path
|
|
1905
|
+
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"
|
|
1906
|
+
fill="none"
|
|
1907
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1908
|
+
stroke-miterlimit="10"
|
|
1909
|
+
/>
|
|
1910
|
+
|
|
1911
|
+
<!-- Main block outer -->
|
|
1912
|
+
<rect
|
|
1913
|
+
x="7"
|
|
1914
|
+
y="0"
|
|
1915
|
+
width="80"
|
|
1916
|
+
height="59.785156"
|
|
1917
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
1918
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1919
|
+
/>
|
|
1920
|
+
|
|
1921
|
+
<!-- Main block inner -->
|
|
1922
|
+
<rect
|
|
1923
|
+
x="9"
|
|
1924
|
+
y="2"
|
|
1925
|
+
width="76"
|
|
1926
|
+
height="57.785156"
|
|
1927
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
1928
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1929
|
+
/>
|
|
1930
|
+
|
|
1931
|
+
<!-- Bolt holes -->
|
|
1932
|
+
<ellipse cx="15" cy="8" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1933
|
+
<ellipse cx="15" cy="8" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1934
|
+
<ellipse cx="79" cy="8" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1935
|
+
<ellipse cx="79" cy="8" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1936
|
+
<ellipse cx="15" cy="55" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1937
|
+
<ellipse cx="15" cy="55" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1938
|
+
<ellipse cx="79" cy="55" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1939
|
+
<ellipse cx="79" cy="55" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1940
|
+
|
|
1823
1941
|
</g>
|
|
1824
1942
|
`,
|
|
1825
1943
|
metadata: {
|
|
1826
|
-
description: "
|
|
1827
|
-
tags: ["
|
|
1944
|
+
description: "Vannefold heat exchanger block with bottom inlet and top outlet configuration",
|
|
1945
|
+
tags: ["heat-exchanger", "vannefold", "fold", "top"]
|
|
1946
|
+
}
|
|
1947
|
+
},
|
|
1948
|
+
"vannefold-top-top-inlet": {
|
|
1949
|
+
id: "vannefold-top-top-inlet",
|
|
1950
|
+
name: "Vannefold Block (Top, Top Inlet)",
|
|
1951
|
+
category: "valve",
|
|
1952
|
+
viewBox: { x: 0, y: 0, width: 88, height: 67.576004 },
|
|
1953
|
+
ports: [
|
|
1954
|
+
{ id: "top-inlet", x: 47, y: 0, type: "control", direction: "in" },
|
|
1955
|
+
{ id: "bottom-outlet", x: 0, y: 42, type: "control", direction: "out" }
|
|
1956
|
+
],
|
|
1957
|
+
svgContent: `
|
|
1958
|
+
<g>
|
|
1959
|
+
<!-- Top inlet pipe flange -->
|
|
1960
|
+
<path
|
|
1961
|
+
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"
|
|
1962
|
+
fill="none"
|
|
1963
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1964
|
+
stroke-miterlimit="10"
|
|
1965
|
+
/>
|
|
1966
|
+
|
|
1967
|
+
<!-- Bottom outlet pipe flange -->
|
|
1968
|
+
<path
|
|
1969
|
+
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"
|
|
1970
|
+
fill="none"
|
|
1971
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1972
|
+
stroke-miterlimit="10"
|
|
1973
|
+
/>
|
|
1974
|
+
|
|
1975
|
+
<!-- Main block outer -->
|
|
1976
|
+
<rect
|
|
1977
|
+
x="7"
|
|
1978
|
+
y="6.7908498"
|
|
1979
|
+
width="80"
|
|
1980
|
+
height="59.785156"
|
|
1981
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
1982
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1983
|
+
/>
|
|
1984
|
+
|
|
1985
|
+
<!-- Main block inner -->
|
|
1986
|
+
<rect
|
|
1987
|
+
x="9"
|
|
1988
|
+
y="8.7908498"
|
|
1989
|
+
width="76"
|
|
1990
|
+
height="57.785156"
|
|
1991
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
1992
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
1993
|
+
/>
|
|
1994
|
+
|
|
1995
|
+
<!-- Bolt holes -->
|
|
1996
|
+
<ellipse cx="15" cy="14.79085" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1997
|
+
<ellipse cx="15" cy="14.79085" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
1998
|
+
<ellipse cx="15" cy="61.79085" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
1999
|
+
<ellipse cx="15" cy="61.79085" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2000
|
+
<ellipse cx="79" cy="14.79085" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2001
|
+
<ellipse cx="79" cy="14.79085" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2002
|
+
<ellipse cx="79" cy="61.79085" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2003
|
+
<ellipse cx="79" cy="61.79085" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2004
|
+
|
|
2005
|
+
</g>
|
|
2006
|
+
`,
|
|
2007
|
+
metadata: {
|
|
2008
|
+
description: "Vannefold heat exchanger block with top inlet and bottom outlet configuration",
|
|
2009
|
+
tags: ["heat-exchanger", "vannefold", "fold", "top", "top-inlet"]
|
|
2010
|
+
}
|
|
2011
|
+
},
|
|
2012
|
+
"vannefold-left": {
|
|
2013
|
+
id: "vannefold-left",
|
|
2014
|
+
name: "Vannefold Block (Left)",
|
|
2015
|
+
category: "valve",
|
|
2016
|
+
viewBox: { x: 0, y: 0, width: 67.785156, height: 88.5 },
|
|
2017
|
+
ports: [
|
|
2018
|
+
{ id: "left-inlet", x: 0, y: 41.5, type: "control", direction: "in" },
|
|
2019
|
+
{ id: "right-outlet", x: 42, y: 87, type: "control", direction: "out" }
|
|
2020
|
+
],
|
|
2021
|
+
svgContent: `
|
|
2022
|
+
<g>
|
|
2023
|
+
<!-- Left inlet pipe flange -->
|
|
2024
|
+
<path
|
|
2025
|
+
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"
|
|
2026
|
+
fill="none"
|
|
2027
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2028
|
+
stroke-miterlimit="10"
|
|
2029
|
+
/>
|
|
2030
|
+
|
|
2031
|
+
<!-- Right outlet pipe flange -->
|
|
2032
|
+
<path
|
|
2033
|
+
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"
|
|
2034
|
+
fill="none"
|
|
2035
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2036
|
+
stroke-miterlimit="10"
|
|
2037
|
+
/>
|
|
2038
|
+
|
|
2039
|
+
<!-- Main block outer -->
|
|
2040
|
+
<rect
|
|
2041
|
+
x="7"
|
|
2042
|
+
y="0.5"
|
|
2043
|
+
width="59.785156"
|
|
2044
|
+
height="80"
|
|
2045
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2046
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2047
|
+
/>
|
|
2048
|
+
|
|
2049
|
+
<!-- Main block inner -->
|
|
2050
|
+
<rect
|
|
2051
|
+
x="9"
|
|
2052
|
+
y="2.5"
|
|
2053
|
+
width="57.785156"
|
|
2054
|
+
height="76"
|
|
2055
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2056
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2057
|
+
/>
|
|
2058
|
+
|
|
2059
|
+
<!-- Bolt holes -->
|
|
2060
|
+
<ellipse cx="15" cy="8.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2061
|
+
<ellipse cx="15" cy="8.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2062
|
+
<ellipse cx="62" cy="8.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2063
|
+
<ellipse cx="62" cy="8.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2064
|
+
<ellipse cx="15" cy="72.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2065
|
+
<ellipse cx="15" cy="72.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2066
|
+
<ellipse cx="62" cy="72.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2067
|
+
<ellipse cx="62" cy="72.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2068
|
+
|
|
2069
|
+
`,
|
|
2070
|
+
metadata: {
|
|
2071
|
+
description: "Vannefold heat exchanger block with left inlet and right outlet, vertical orientation",
|
|
2072
|
+
tags: ["heat-exchanger", "vannefold", "fold", "left", "vertical"]
|
|
2073
|
+
}
|
|
2074
|
+
},
|
|
2075
|
+
"vannefold-right": {
|
|
2076
|
+
id: "vannefold-right",
|
|
2077
|
+
name: "Vannefold Block (Right)",
|
|
2078
|
+
category: "valve",
|
|
2079
|
+
viewBox: { x: 0, y: 0, width: 67.785156, height: 88.5 },
|
|
2080
|
+
ports: [
|
|
2081
|
+
{ id: "right-inlet", x: 67.785156, y: 41.5, type: "control", direction: "in" },
|
|
2082
|
+
{ id: "left-outlet", x: 24.785156, y: 87.5, type: "control", direction: "out" }
|
|
2083
|
+
],
|
|
2084
|
+
svgContent: `
|
|
2085
|
+
<g>
|
|
2086
|
+
<!-- Right inlet pipe flange -->
|
|
2087
|
+
<path
|
|
2088
|
+
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"
|
|
2089
|
+
fill="none"
|
|
2090
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2091
|
+
stroke-miterlimit="10"
|
|
2092
|
+
/>
|
|
2093
|
+
|
|
2094
|
+
<!-- Left outlet pipe flange -->
|
|
2095
|
+
<path
|
|
2096
|
+
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"
|
|
2097
|
+
fill="none"
|
|
2098
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2099
|
+
stroke-miterlimit="10"
|
|
2100
|
+
/>
|
|
2101
|
+
|
|
2102
|
+
<!-- Main block outer -->
|
|
2103
|
+
<rect
|
|
2104
|
+
x="0"
|
|
2105
|
+
y="0.5"
|
|
2106
|
+
width="59.785156"
|
|
2107
|
+
height="80"
|
|
2108
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2109
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2110
|
+
/>
|
|
2111
|
+
|
|
2112
|
+
<!-- Main block inner -->
|
|
2113
|
+
<rect
|
|
2114
|
+
x="0"
|
|
2115
|
+
y="2.5"
|
|
2116
|
+
width="57.785156"
|
|
2117
|
+
height="76"
|
|
2118
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2119
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2120
|
+
/>
|
|
2121
|
+
|
|
2122
|
+
<!-- Bolt holes -->
|
|
2123
|
+
<ellipse cx="51.785156" cy="8.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2124
|
+
<ellipse cx="51.785156" cy="8.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2125
|
+
<ellipse cx="4.785156" cy="8.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2126
|
+
<ellipse cx="4.785156" cy="8.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2127
|
+
<ellipse cx="51.785156" cy="72.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2128
|
+
<ellipse cx="51.785156" cy="72.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2129
|
+
<ellipse cx="4.785156" cy="72.5" rx="5" ry="5" fill="#ffffff" stroke="var(--symbol-stroke, #000000)" />
|
|
2130
|
+
<ellipse cx="4.785156" cy="72.5" rx="3" ry="3" fill="none" stroke="var(--symbol-stroke, #000000)" />
|
|
2131
|
+
|
|
2132
|
+
`,
|
|
2133
|
+
metadata: {
|
|
2134
|
+
description: "Vannefold heat exchanger block with right inlet and left outlet, vertical orientation",
|
|
2135
|
+
tags: ["heat-exchanger", "vannefold", "fold", "right", "vertical"]
|
|
2136
|
+
}
|
|
2137
|
+
},
|
|
2138
|
+
"pixer": {
|
|
2139
|
+
id: "pixer",
|
|
2140
|
+
name: "Pixer",
|
|
2141
|
+
category: "pump",
|
|
2142
|
+
viewBox: { x: 0, y: 0, width: 50.625, height: 46.6875 },
|
|
2143
|
+
ports: [
|
|
2144
|
+
{ id: "right-outlet", x: 50.625, y: 30.9375, type: "control", direction: "out" },
|
|
2145
|
+
{ id: "left-outlet", x: 0, y: 30.9375, type: "control", direction: "out" },
|
|
2146
|
+
{ id: "left-inlet", x: 50.625, y: 19.6875, type: "control", direction: "in" },
|
|
2147
|
+
{ id: "right-inlet", x: 0, y: 19.6875, type: "control", direction: "in" },
|
|
2148
|
+
{ id: "top-inlet", x: 25.3125, y: 0, type: "control", direction: "in" }
|
|
2149
|
+
],
|
|
2150
|
+
svgContent: `
|
|
2151
|
+
<g transform="scale(0.196875) translate(-195, -186)">
|
|
2152
|
+
<!-- Top mounting flange -->
|
|
2153
|
+
<rect
|
|
2154
|
+
width="141.313"
|
|
2155
|
+
height="9.872"
|
|
2156
|
+
transform="translate(252.392 185.89)"
|
|
2157
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2158
|
+
stroke-miterlimit="10"
|
|
2159
|
+
stroke-width="1"
|
|
2160
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2161
|
+
/>
|
|
2162
|
+
|
|
2163
|
+
<!-- Motor housing top -->
|
|
2164
|
+
<rect
|
|
2165
|
+
width="106.614"
|
|
2166
|
+
height="2.468"
|
|
2167
|
+
transform="translate(269.742 199.918)"
|
|
2168
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2169
|
+
stroke-miterlimit="10"
|
|
2170
|
+
stroke-width="1"
|
|
2171
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2172
|
+
/>
|
|
2173
|
+
<rect
|
|
2174
|
+
width="106.614"
|
|
2175
|
+
height="5.835"
|
|
2176
|
+
transform="translate(269.742 202.384)"
|
|
2177
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2178
|
+
stroke-miterlimit="10"
|
|
2179
|
+
stroke-width="1"
|
|
2180
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2181
|
+
/>
|
|
2182
|
+
<rect
|
|
2183
|
+
width="106.614"
|
|
2184
|
+
height="2.468"
|
|
2185
|
+
transform="translate(269.742 208.222)"
|
|
2186
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2187
|
+
stroke-miterlimit="10"
|
|
2188
|
+
stroke-width="1"
|
|
2189
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2190
|
+
/>
|
|
2191
|
+
|
|
2192
|
+
<!-- Bottom mounting flange -->
|
|
2193
|
+
<rect
|
|
2194
|
+
width="221.702"
|
|
2195
|
+
height="2.401"
|
|
2196
|
+
transform="translate(212.199 395.587)"
|
|
2197
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2198
|
+
stroke-miterlimit="10"
|
|
2199
|
+
stroke-width="1"
|
|
2200
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2201
|
+
/>
|
|
2202
|
+
<rect
|
|
2203
|
+
width="221.702"
|
|
2204
|
+
height="6.269"
|
|
2205
|
+
transform="translate(212.199 397.988)"
|
|
2206
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2207
|
+
stroke-miterlimit="10"
|
|
2208
|
+
stroke-width="1"
|
|
2209
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2210
|
+
/>
|
|
2211
|
+
<rect
|
|
2212
|
+
width="221.702"
|
|
2213
|
+
height="2.65"
|
|
2214
|
+
transform="translate(212.199 404.257)"
|
|
2215
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2216
|
+
stroke-miterlimit="10"
|
|
2217
|
+
stroke-width="1"
|
|
2218
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2219
|
+
/>
|
|
2220
|
+
|
|
2221
|
+
<!-- Motor housing transition -->
|
|
2222
|
+
<path
|
|
2223
|
+
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"
|
|
2224
|
+
transform="translate(-192.059 -32.959)"
|
|
2225
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2226
|
+
stroke-miterlimit="10"
|
|
2227
|
+
stroke-width="1"
|
|
2228
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2229
|
+
/>
|
|
2230
|
+
|
|
2231
|
+
<!-- Bottom flange -->
|
|
2232
|
+
<rect
|
|
2233
|
+
width="256"
|
|
2234
|
+
height="9.872"
|
|
2235
|
+
transform="translate(195.05 411.066)"
|
|
2236
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2237
|
+
stroke-miterlimit="10"
|
|
2238
|
+
stroke-width="1"
|
|
2239
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2240
|
+
/>
|
|
2241
|
+
<path
|
|
2242
|
+
d="M195.05,1148.286l17.149-4.156H433.9l17.149,4.156Z"
|
|
2243
|
+
transform="translate(0 -737.221)"
|
|
2244
|
+
fill="var(--symbol-fill, #e2e2e2)"
|
|
2245
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2246
|
+
stroke-miterlimit="10"
|
|
2247
|
+
stroke-width="1"
|
|
2248
|
+
/>
|
|
2249
|
+
|
|
2250
|
+
<!-- Vessel top cone -->
|
|
2251
|
+
<path
|
|
2252
|
+
d="M451.05,328.356h-256l74.692-34.946H376.358Z"
|
|
2253
|
+
transform="translate(0 -82.72)"
|
|
2254
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2255
|
+
stroke-miterlimit="10"
|
|
2256
|
+
stroke-width="1"
|
|
2257
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2258
|
+
/>
|
|
2259
|
+
|
|
2260
|
+
<!-- Main vessel body -->
|
|
2261
|
+
<rect
|
|
2262
|
+
width="256"
|
|
2263
|
+
height="59.803"
|
|
2264
|
+
transform="translate(195.05 245.636)"
|
|
2265
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2266
|
+
stroke-miterlimit="10"
|
|
2267
|
+
stroke-width="1"
|
|
2268
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2269
|
+
/>
|
|
2270
|
+
<rect
|
|
2271
|
+
width="256"
|
|
2272
|
+
height="76.892"
|
|
2273
|
+
transform="translate(195.05 308.417)"
|
|
2274
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2275
|
+
stroke-miterlimit="10"
|
|
2276
|
+
stroke-width="1"
|
|
2277
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2278
|
+
/>
|
|
2279
|
+
|
|
2280
|
+
<!-- Vessel bottom transitions -->
|
|
2281
|
+
<path
|
|
2282
|
+
d="M449.265,705.7H196.773l-1.654-1.465a.014.014,0,0,1,0-.023H451.078Z"
|
|
2283
|
+
transform="translate(-0.049 -398.769)"
|
|
2284
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2285
|
+
stroke-miterlimit="10"
|
|
2286
|
+
stroke-width="1"
|
|
2287
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2288
|
+
/>
|
|
2289
|
+
<path
|
|
2290
|
+
d="M449.278,710.66H196.793l-1.663,1.462v.016H451.086s.012,0,0-.016Z"
|
|
2291
|
+
transform="translate(-0.062 -403.731)"
|
|
2292
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2293
|
+
stroke-miterlimit="10"
|
|
2294
|
+
stroke-width="1"
|
|
2295
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2296
|
+
/>
|
|
2297
|
+
<path
|
|
2298
|
+
d="M433.9,1060.758H212.2L195.05,1050.48h256Z"
|
|
2299
|
+
transform="translate(0 -665.171)"
|
|
2300
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2301
|
+
stroke-miterlimit="10"
|
|
2302
|
+
stroke-width="1"
|
|
2303
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2304
|
+
/>
|
|
2305
|
+
|
|
2306
|
+
<!-- Agitator blades/impellers (simplified without gradients) -->
|
|
2307
|
+
<ellipse
|
|
2308
|
+
cx="15.454"
|
|
2309
|
+
cy="6.096"
|
|
2310
|
+
rx="15.454"
|
|
2311
|
+
ry="6.096"
|
|
2312
|
+
transform="translate(307.486 228.161)"
|
|
2313
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2314
|
+
stroke-miterlimit="10"
|
|
2315
|
+
stroke-width="1"
|
|
2316
|
+
fill="var(--symbol-fill, #c0c0c0)"
|
|
2317
|
+
/>
|
|
2318
|
+
<ellipse
|
|
2319
|
+
cx="15.454"
|
|
2320
|
+
cy="5.3"
|
|
2321
|
+
rx="15.454"
|
|
2322
|
+
ry="5.3"
|
|
2323
|
+
transform="translate(307.486 229.753)"
|
|
2324
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2325
|
+
stroke-miterlimit="10"
|
|
2326
|
+
stroke-width="1"
|
|
2327
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2328
|
+
/>
|
|
2329
|
+
<ellipse
|
|
2330
|
+
cx="5.174"
|
|
2331
|
+
cy="15.117"
|
|
2332
|
+
rx="5.174"
|
|
2333
|
+
ry="15.117"
|
|
2334
|
+
transform="translate(367.144 236.079) rotate(-77.61)"
|
|
2335
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2336
|
+
stroke-miterlimit="10"
|
|
2337
|
+
stroke-width="1"
|
|
2338
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2339
|
+
/>
|
|
2340
|
+
<path
|
|
2341
|
+
d="M947,380.271s1.631-2.83,8.084-2.235c5.427.5,16.927,2.855,20.574,8.26"
|
|
2342
|
+
transform="translate(-578.512 -147.764)"
|
|
2343
|
+
fill="none"
|
|
2344
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2345
|
+
stroke-miterlimit="10"
|
|
2346
|
+
stroke-width="1"
|
|
2347
|
+
/>
|
|
2348
|
+
<ellipse
|
|
2349
|
+
cx="15.117"
|
|
2350
|
+
cy="5.174"
|
|
2351
|
+
rx="15.117"
|
|
2352
|
+
ry="5.174"
|
|
2353
|
+
transform="translate(247 232.438) rotate(-12.39)"
|
|
2354
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2355
|
+
stroke-miterlimit="10"
|
|
2356
|
+
stroke-width="1"
|
|
2357
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2358
|
+
/>
|
|
2359
|
+
<path
|
|
2360
|
+
d="M456.439,380.271s-1.631-2.83-8.073-2.235c-5.43.5-16.93,2.855-20.576,8.26"
|
|
2361
|
+
transform="translate(-179.058 -147.764)"
|
|
2362
|
+
fill="none"
|
|
2363
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2364
|
+
stroke-miterlimit="10"
|
|
2365
|
+
stroke-width="1"
|
|
2366
|
+
/>
|
|
2367
|
+
<ellipse
|
|
2368
|
+
cx="1.651"
|
|
2369
|
+
cy="15.082"
|
|
2370
|
+
rx="1.651"
|
|
2371
|
+
ry="15.082"
|
|
2372
|
+
transform="translate(406.71 230.174) rotate(-68.13)"
|
|
2373
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2374
|
+
stroke-miterlimit="10"
|
|
2375
|
+
stroke-width="1"
|
|
2376
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2377
|
+
/>
|
|
2378
|
+
<path
|
|
2379
|
+
d="M1119,375.62a119.876,119.876,0,0,1,26.193,10.419"
|
|
2380
|
+
transform="translate(-710.84 -145.969)"
|
|
2381
|
+
fill="none"
|
|
2382
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2383
|
+
stroke-miterlimit="10"
|
|
2384
|
+
stroke-width="1"
|
|
2385
|
+
/>
|
|
2386
|
+
<ellipse
|
|
2387
|
+
cx="15.082"
|
|
2388
|
+
cy="1.651"
|
|
2389
|
+
rx="15.082"
|
|
2390
|
+
ry="1.651"
|
|
2391
|
+
transform="translate(210.225 238.342) rotate(-21.87)"
|
|
2392
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2393
|
+
stroke-miterlimit="10"
|
|
2394
|
+
stroke-width="1"
|
|
2395
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2396
|
+
/>
|
|
2397
|
+
<path
|
|
2398
|
+
d="M293.943,375.62a119.829,119.829,0,0,0-26.193,10.419"
|
|
2399
|
+
transform="translate(-55.932 -145.969)"
|
|
2400
|
+
fill="none"
|
|
2401
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2402
|
+
stroke-miterlimit="10"
|
|
2403
|
+
stroke-width="1"
|
|
2404
|
+
/>
|
|
2405
|
+
</g>
|
|
2406
|
+
`,
|
|
2407
|
+
metadata: {
|
|
2408
|
+
description: "Pixer mixer/agitator vessel with top-mounted drive",
|
|
2409
|
+
tags: ["vessel", "mixer", "agitator", "pixer", "tank"]
|
|
2410
|
+
}
|
|
2411
|
+
},
|
|
2412
|
+
"pixer-barb": {
|
|
2413
|
+
id: "pixer-barb",
|
|
2414
|
+
name: "Pixer (Hose Barb)",
|
|
2415
|
+
category: "pump",
|
|
2416
|
+
viewBox: { x: 0, y: 0, width: 50.625, height: 46.6875 },
|
|
2417
|
+
ports: [
|
|
2418
|
+
{ id: "right-outlet", x: 50.625, y: 30.9375, type: "control", direction: "out" },
|
|
2419
|
+
{ id: "left-outlet", x: 0, y: 30.9375, type: "control", direction: "out" },
|
|
2420
|
+
{ id: "left-inlet", x: 50.625, y: 19.6875, type: "control", direction: "in" },
|
|
2421
|
+
{ id: "right-inlet", x: 0, y: 19.6875, type: "control", direction: "in" },
|
|
2422
|
+
{ id: "top-inlet", x: 25.3125, y: 0, type: "control", direction: "in" }
|
|
2423
|
+
],
|
|
2424
|
+
svgContent: `
|
|
2425
|
+
<g transform="scale(0.196875) translate(-195, -186)">
|
|
2426
|
+
<!-- Hose barb ridges at top -->
|
|
2427
|
+
<rect
|
|
2428
|
+
width="20"
|
|
2429
|
+
height="2"
|
|
2430
|
+
transform="translate(313 173)"
|
|
2431
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2432
|
+
stroke-miterlimit="10"
|
|
2433
|
+
stroke-width="0.5"
|
|
2434
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2435
|
+
/>
|
|
2436
|
+
<rect
|
|
2437
|
+
width="20"
|
|
2438
|
+
height="2"
|
|
2439
|
+
transform="translate(313 177)"
|
|
2440
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2441
|
+
stroke-miterlimit="10"
|
|
2442
|
+
stroke-width="0.5"
|
|
2443
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2444
|
+
/>
|
|
2445
|
+
<rect
|
|
2446
|
+
width="20"
|
|
2447
|
+
height="2"
|
|
2448
|
+
transform="translate(313 181)"
|
|
2449
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2450
|
+
stroke-miterlimit="10"
|
|
2451
|
+
stroke-width="0.5"
|
|
2452
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2453
|
+
/>
|
|
2454
|
+
|
|
2455
|
+
<!-- Taper from barb to motor housing -->
|
|
2456
|
+
<path
|
|
2457
|
+
d="M 313,183 L 269.742,199.918 L 376.356,199.918 L 333,183 Z"
|
|
2458
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2459
|
+
stroke-miterlimit="10"
|
|
2460
|
+
stroke-width="1"
|
|
2461
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2462
|
+
/>
|
|
2463
|
+
|
|
2464
|
+
<!-- Motor housing top -->
|
|
2465
|
+
<rect
|
|
2466
|
+
width="106.614"
|
|
2467
|
+
height="2.468"
|
|
2468
|
+
transform="translate(269.742 199.918)"
|
|
2469
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2470
|
+
stroke-miterlimit="10"
|
|
2471
|
+
stroke-width="1"
|
|
2472
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2473
|
+
/>
|
|
2474
|
+
<rect
|
|
2475
|
+
width="106.614"
|
|
2476
|
+
height="5.835"
|
|
2477
|
+
transform="translate(269.742 202.384)"
|
|
2478
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2479
|
+
stroke-miterlimit="10"
|
|
2480
|
+
stroke-width="1"
|
|
2481
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2482
|
+
/>
|
|
2483
|
+
<rect
|
|
2484
|
+
width="106.614"
|
|
2485
|
+
height="2.468"
|
|
2486
|
+
transform="translate(269.742 208.222)"
|
|
2487
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2488
|
+
stroke-miterlimit="10"
|
|
2489
|
+
stroke-width="1"
|
|
2490
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2491
|
+
/>
|
|
2492
|
+
|
|
2493
|
+
<!-- Bottom mounting flange -->
|
|
2494
|
+
<rect
|
|
2495
|
+
width="221.702"
|
|
2496
|
+
height="2.401"
|
|
2497
|
+
transform="translate(212.199 395.587)"
|
|
2498
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2499
|
+
stroke-miterlimit="10"
|
|
2500
|
+
stroke-width="1"
|
|
2501
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2502
|
+
/>
|
|
2503
|
+
<rect
|
|
2504
|
+
width="221.702"
|
|
2505
|
+
height="6.269"
|
|
2506
|
+
transform="translate(212.199 397.988)"
|
|
2507
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2508
|
+
stroke-miterlimit="10"
|
|
2509
|
+
stroke-width="1"
|
|
2510
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2511
|
+
/>
|
|
2512
|
+
<rect
|
|
2513
|
+
width="221.702"
|
|
2514
|
+
height="2.65"
|
|
2515
|
+
transform="translate(212.199 404.257)"
|
|
2516
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2517
|
+
stroke-miterlimit="10"
|
|
2518
|
+
stroke-width="1"
|
|
2519
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2520
|
+
/>
|
|
2521
|
+
|
|
2522
|
+
<!-- Bottom flange -->
|
|
2523
|
+
<rect
|
|
2524
|
+
width="256"
|
|
2525
|
+
height="9.872"
|
|
2526
|
+
transform="translate(195.05 411.066)"
|
|
2527
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2528
|
+
stroke-miterlimit="10"
|
|
2529
|
+
stroke-width="1"
|
|
2530
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2531
|
+
/>
|
|
2532
|
+
<path
|
|
2533
|
+
d="M195.05,1148.286l17.149-4.156H433.9l17.149,4.156Z"
|
|
2534
|
+
transform="translate(0 -737.221)"
|
|
2535
|
+
fill="var(--symbol-fill, #e2e2e2)"
|
|
2536
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2537
|
+
stroke-miterlimit="10"
|
|
2538
|
+
stroke-width="1"
|
|
2539
|
+
/>
|
|
2540
|
+
|
|
2541
|
+
<!-- Vessel top cone -->
|
|
2542
|
+
<path
|
|
2543
|
+
d="M451.05,328.356h-256l74.692-34.946H376.358Z"
|
|
2544
|
+
transform="translate(0 -82.72)"
|
|
2545
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2546
|
+
stroke-miterlimit="10"
|
|
2547
|
+
stroke-width="1"
|
|
2548
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2549
|
+
/>
|
|
2550
|
+
|
|
2551
|
+
<!-- Main vessel body -->
|
|
2552
|
+
<rect
|
|
2553
|
+
width="256"
|
|
2554
|
+
height="59.803"
|
|
2555
|
+
transform="translate(195.05 245.636)"
|
|
2556
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2557
|
+
stroke-miterlimit="10"
|
|
2558
|
+
stroke-width="1"
|
|
2559
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2560
|
+
/>
|
|
2561
|
+
<rect
|
|
2562
|
+
width="256"
|
|
2563
|
+
height="76.892"
|
|
2564
|
+
transform="translate(195.05 308.417)"
|
|
2565
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2566
|
+
stroke-miterlimit="10"
|
|
2567
|
+
stroke-width="1"
|
|
2568
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2569
|
+
/>
|
|
2570
|
+
|
|
2571
|
+
<!-- Vessel bottom transitions -->
|
|
2572
|
+
<path
|
|
2573
|
+
d="M449.265,705.7H196.773l-1.654-1.465a.014.014,0,0,1,0-.023H451.078Z"
|
|
2574
|
+
transform="translate(-0.049 -398.769)"
|
|
2575
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2576
|
+
stroke-miterlimit="10"
|
|
2577
|
+
stroke-width="1"
|
|
2578
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2579
|
+
/>
|
|
2580
|
+
<path
|
|
2581
|
+
d="M449.278,710.66H196.793l-1.663,1.462v.016H451.086s.012,0,0-.016Z"
|
|
2582
|
+
transform="translate(-0.062 -403.731)"
|
|
2583
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2584
|
+
stroke-miterlimit="10"
|
|
2585
|
+
stroke-width="1"
|
|
2586
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2587
|
+
/>
|
|
2588
|
+
<path
|
|
2589
|
+
d="M433.9,1060.758H212.2L195.05,1050.48h256Z"
|
|
2590
|
+
transform="translate(0 -665.171)"
|
|
2591
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2592
|
+
stroke-miterlimit="10"
|
|
2593
|
+
stroke-width="1"
|
|
2594
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2595
|
+
/>
|
|
2596
|
+
|
|
2597
|
+
<!-- Agitator blades/impellers (simplified without gradients) -->
|
|
2598
|
+
<ellipse
|
|
2599
|
+
cx="15.454"
|
|
2600
|
+
cy="6.096"
|
|
2601
|
+
rx="15.454"
|
|
2602
|
+
ry="6.096"
|
|
2603
|
+
transform="translate(307.486 228.161)"
|
|
2604
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2605
|
+
stroke-miterlimit="10"
|
|
2606
|
+
stroke-width="1"
|
|
2607
|
+
fill="var(--symbol-fill, #c0c0c0)"
|
|
2608
|
+
/>
|
|
2609
|
+
<ellipse
|
|
2610
|
+
cx="15.454"
|
|
2611
|
+
cy="5.3"
|
|
2612
|
+
rx="15.454"
|
|
2613
|
+
ry="5.3"
|
|
2614
|
+
transform="translate(307.486 229.753)"
|
|
2615
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2616
|
+
stroke-miterlimit="10"
|
|
2617
|
+
stroke-width="1"
|
|
2618
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2619
|
+
/>
|
|
2620
|
+
<ellipse
|
|
2621
|
+
cx="5.174"
|
|
2622
|
+
cy="15.117"
|
|
2623
|
+
rx="5.174"
|
|
2624
|
+
ry="15.117"
|
|
2625
|
+
transform="translate(367.144 236.079) rotate(-77.61)"
|
|
2626
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2627
|
+
stroke-miterlimit="10"
|
|
2628
|
+
stroke-width="1"
|
|
2629
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2630
|
+
/>
|
|
2631
|
+
<path
|
|
2632
|
+
d="M947,380.271s1.631-2.83,8.084-2.235c5.427.5,16.927,2.855,20.574,8.26"
|
|
2633
|
+
transform="translate(-578.512 -147.764)"
|
|
2634
|
+
fill="none"
|
|
2635
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2636
|
+
stroke-miterlimit="10"
|
|
2637
|
+
stroke-width="1"
|
|
2638
|
+
/>
|
|
2639
|
+
<ellipse
|
|
2640
|
+
cx="15.117"
|
|
2641
|
+
cy="5.174"
|
|
2642
|
+
rx="15.117"
|
|
2643
|
+
ry="5.174"
|
|
2644
|
+
transform="translate(247 232.438) rotate(-12.39)"
|
|
2645
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2646
|
+
stroke-miterlimit="10"
|
|
2647
|
+
stroke-width="1"
|
|
2648
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2649
|
+
/>
|
|
2650
|
+
<path
|
|
2651
|
+
d="M456.439,380.271s-1.631-2.83-8.073-2.235c-5.43.5-16.93,2.855-20.576,8.26"
|
|
2652
|
+
transform="translate(-179.058 -147.764)"
|
|
2653
|
+
fill="none"
|
|
2654
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2655
|
+
stroke-miterlimit="10"
|
|
2656
|
+
stroke-width="1"
|
|
2657
|
+
/>
|
|
2658
|
+
<ellipse
|
|
2659
|
+
cx="1.651"
|
|
2660
|
+
cy="15.082"
|
|
2661
|
+
rx="1.651"
|
|
2662
|
+
ry="15.082"
|
|
2663
|
+
transform="translate(406.71 230.174) rotate(-68.13)"
|
|
2664
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2665
|
+
stroke-miterlimit="10"
|
|
2666
|
+
stroke-width="1"
|
|
2667
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2668
|
+
/>
|
|
2669
|
+
<path
|
|
2670
|
+
d="M1119,375.62a119.876,119.876,0,0,1,26.193,10.419"
|
|
2671
|
+
transform="translate(-710.84 -145.969)"
|
|
2672
|
+
fill="none"
|
|
2673
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2674
|
+
stroke-miterlimit="10"
|
|
2675
|
+
stroke-width="1"
|
|
2676
|
+
/>
|
|
2677
|
+
<ellipse
|
|
2678
|
+
cx="15.082"
|
|
2679
|
+
cy="1.651"
|
|
2680
|
+
rx="15.082"
|
|
2681
|
+
ry="1.651"
|
|
2682
|
+
transform="translate(210.225 238.342) rotate(-21.87)"
|
|
2683
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2684
|
+
stroke-miterlimit="10"
|
|
2685
|
+
stroke-width="1"
|
|
2686
|
+
fill="var(--symbol-fill, #d0d0d0)"
|
|
2687
|
+
/>
|
|
2688
|
+
<path
|
|
2689
|
+
d="M293.943,375.62a119.829,119.829,0,0,0-26.193,10.419"
|
|
2690
|
+
transform="translate(-55.932 -145.969)"
|
|
2691
|
+
fill="none"
|
|
2692
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2693
|
+
stroke-miterlimit="10"
|
|
2694
|
+
stroke-width="1"
|
|
2695
|
+
/>
|
|
2696
|
+
</g>
|
|
2697
|
+
`,
|
|
2698
|
+
metadata: {
|
|
2699
|
+
description: "Pixer mixer/agitator vessel with tapered hose barb connection at top",
|
|
2700
|
+
tags: ["vessel", "mixer", "agitator", "pixer", "tank", "hose-barb"]
|
|
2701
|
+
}
|
|
2702
|
+
},
|
|
2703
|
+
"vessel-balloon": {
|
|
2704
|
+
id: "vessel-balloon",
|
|
2705
|
+
name: "Vessel",
|
|
2706
|
+
category: "vessel",
|
|
2707
|
+
viewBox: { x: 0, y: 0, width: 50.625, height: 91 },
|
|
2708
|
+
ports: [
|
|
2709
|
+
{ id: "top", type: "inlet", x: 25.3125, y: 0 },
|
|
2710
|
+
{ id: "left", type: "inlet", x: 5, y: 39 },
|
|
2711
|
+
{ id: "right", type: "outlet", x: 45.625, y: 39 },
|
|
2712
|
+
{ id: "bottom", type: "outlet", x: 25.3125, y: 91 }
|
|
2713
|
+
],
|
|
2714
|
+
svgContent: `
|
|
2715
|
+
<g transform="scale(0.196875) translate(-195, -100)">
|
|
2716
|
+
<!-- Top opening nozzle -->
|
|
2717
|
+
<rect
|
|
2718
|
+
width="65"
|
|
2719
|
+
height="19.5"
|
|
2720
|
+
transform="translate(290.5, 100)"
|
|
2721
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2722
|
+
stroke-miterlimit="10"
|
|
2723
|
+
stroke-width="1"
|
|
2724
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2725
|
+
/>
|
|
2726
|
+
|
|
2727
|
+
<!-- Transition from nozzle to dome -->
|
|
2728
|
+
<path
|
|
2729
|
+
d="M 290.5,119.5 L 238,152 L 408,152 L 355.5,119.5 Z"
|
|
2730
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2731
|
+
stroke-miterlimit="10"
|
|
2732
|
+
stroke-width="1"
|
|
2733
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2734
|
+
/>
|
|
2735
|
+
|
|
2736
|
+
<!-- Upper balloon dome - rounded bulge -->
|
|
2737
|
+
<path
|
|
2738
|
+
d="M 238,152 C 185,210 150,320 180,395 L 466,395 C 496,320 461,210 408,152 Z"
|
|
2739
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2740
|
+
stroke-miterlimit="10"
|
|
2741
|
+
stroke-width="1"
|
|
2742
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2743
|
+
/>
|
|
2744
|
+
|
|
2745
|
+
<!-- Tapered vessel body -->
|
|
2746
|
+
<path
|
|
2747
|
+
d="M 180,395 L 269.742,530 L 376.356,530 L 466,395 Z"
|
|
2748
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2749
|
+
stroke-miterlimit="10"
|
|
2750
|
+
stroke-width="1"
|
|
2751
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2752
|
+
/>
|
|
2753
|
+
|
|
2754
|
+
<!-- Bottom cone -->
|
|
2755
|
+
<path
|
|
2756
|
+
d="M 269.742,530 L 280,555 L 366,555 L 376.356,530 Z"
|
|
2757
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2758
|
+
stroke-miterlimit="10"
|
|
2759
|
+
stroke-width="1"
|
|
2760
|
+
fill="var(--symbol-fill, #e0e0e0)"
|
|
2761
|
+
/>
|
|
2762
|
+
|
|
2763
|
+
<!-- Bottom flange matching pixer top dimensions -->
|
|
2764
|
+
<rect
|
|
2765
|
+
width="141.313"
|
|
2766
|
+
height="9.872"
|
|
2767
|
+
transform="translate(252.392, 555)"
|
|
2768
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2769
|
+
stroke-miterlimit="10"
|
|
2770
|
+
stroke-width="1"
|
|
2771
|
+
fill="var(--symbol-fill, #eaeaea)"
|
|
2772
|
+
/>
|
|
2773
|
+
</g>
|
|
2774
|
+
`,
|
|
2775
|
+
metadata: {
|
|
2776
|
+
description: "Balloon-shaped vessel with rounded top and tapered bottom, designed to fit on standard pixer",
|
|
2777
|
+
tags: ["vessel", "storage", "tank", "balloon"]
|
|
2778
|
+
}
|
|
2779
|
+
},
|
|
2780
|
+
"psr-f": {
|
|
2781
|
+
id: "psr-f",
|
|
2782
|
+
name: "PSR F",
|
|
2783
|
+
category: "instrument",
|
|
2784
|
+
viewBox: { x: 0, y: 0, width: 57, height: 57 },
|
|
2785
|
+
ports: [
|
|
2786
|
+
{ id: "top", type: "signal", x: 28.5, y: 14.25 },
|
|
2787
|
+
{ id: "right", type: "signal", x: 42.75, y: 28.5 },
|
|
2788
|
+
{ id: "bottom", type: "signal", x: 28.5, y: 42.75 },
|
|
2789
|
+
{ id: "left", type: "signal", x: 14.25, y: 28.5 }
|
|
2790
|
+
],
|
|
2791
|
+
svgContent: `
|
|
2792
|
+
<g transform="scale(0.5) translate(28.5, 28.5)">
|
|
2793
|
+
<!-- Circle background -->
|
|
2794
|
+
<ellipse
|
|
2795
|
+
cx="28.5"
|
|
2796
|
+
cy="28.5"
|
|
2797
|
+
rx="28.5"
|
|
2798
|
+
ry="28.5"
|
|
2799
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2800
|
+
stroke-width="1"
|
|
2801
|
+
fill="var(--symbol-fill, #ffffff)"
|
|
2802
|
+
/>
|
|
2803
|
+
|
|
2804
|
+
<!-- Letter F -->
|
|
2805
|
+
<text
|
|
2806
|
+
x="28.5"
|
|
2807
|
+
y="38"
|
|
2808
|
+
text-anchor="middle"
|
|
2809
|
+
font-family="'Times New Roman', Georgia, serif"
|
|
2810
|
+
font-size="34"
|
|
2811
|
+
font-weight="normal"
|
|
2812
|
+
font-style="italic"
|
|
2813
|
+
fill="var(--symbol-stroke, #000000)"
|
|
2814
|
+
>F</text>
|
|
2815
|
+
</g>
|
|
2816
|
+
`,
|
|
2817
|
+
metadata: {
|
|
2818
|
+
description: "PSR F instrument symbol - Flow indicator",
|
|
2819
|
+
tags: ["instrument", "psr", "flow", "indicator"]
|
|
2820
|
+
}
|
|
2821
|
+
},
|
|
2822
|
+
"psr-p": {
|
|
2823
|
+
id: "psr-p",
|
|
2824
|
+
name: "PSR P",
|
|
2825
|
+
category: "instrument",
|
|
2826
|
+
viewBox: { x: 0, y: 0, width: 57, height: 57 },
|
|
2827
|
+
ports: [
|
|
2828
|
+
{ id: "top", type: "signal", x: 28.5, y: 14.25 },
|
|
2829
|
+
{ id: "right", type: "signal", x: 42.75, y: 28.5 },
|
|
2830
|
+
{ id: "bottom", type: "signal", x: 28.5, y: 42.75 },
|
|
2831
|
+
{ id: "left", type: "signal", x: 14.25, y: 28.5 }
|
|
2832
|
+
],
|
|
2833
|
+
svgContent: `
|
|
2834
|
+
<g transform="scale(0.5) translate(28.5, 28.5)">
|
|
2835
|
+
<!-- Circle background -->
|
|
2836
|
+
<ellipse
|
|
2837
|
+
cx="28.5"
|
|
2838
|
+
cy="28.5"
|
|
2839
|
+
rx="28.5"
|
|
2840
|
+
ry="28.5"
|
|
2841
|
+
stroke="var(--symbol-stroke, #000000)"
|
|
2842
|
+
stroke-width="1"
|
|
2843
|
+
fill="var(--symbol-fill, #ffffff)"
|
|
2844
|
+
/>
|
|
2845
|
+
|
|
2846
|
+
<!-- Letter P -->
|
|
2847
|
+
<text
|
|
2848
|
+
x="28.5"
|
|
2849
|
+
y="38"
|
|
2850
|
+
text-anchor="middle"
|
|
2851
|
+
font-family="'Times New Roman', Georgia, serif"
|
|
2852
|
+
font-size="34"
|
|
2853
|
+
font-weight="normal"
|
|
2854
|
+
font-style="italic"
|
|
2855
|
+
fill="var(--symbol-stroke, #000000)"
|
|
2856
|
+
>P</text>
|
|
2857
|
+
</g>
|
|
2858
|
+
`,
|
|
2859
|
+
metadata: {
|
|
2860
|
+
description: "PSR P instrument symbol - Pressure indicator",
|
|
2861
|
+
tags: ["instrument", "psr", "pressure", "indicator"]
|
|
1828
2862
|
}
|
|
1829
2863
|
}
|
|
1830
2864
|
};
|
|
@@ -1904,6 +2938,24 @@ function NodeRenderer({
|
|
|
1904
2938
|
`translate(${centerX}, ${centerY}) scale(${scaleX}, ${scaleY}) translate(${-centerX}, ${-centerY})`
|
|
1905
2939
|
);
|
|
1906
2940
|
}
|
|
2941
|
+
const getStatusColor = (status) => {
|
|
2942
|
+
switch (status) {
|
|
2943
|
+
case "running":
|
|
2944
|
+
return "#22c55e";
|
|
2945
|
+
// Green
|
|
2946
|
+
case "alarm":
|
|
2947
|
+
return "#ef4444";
|
|
2948
|
+
// Red
|
|
2949
|
+
case "warning":
|
|
2950
|
+
return "#f59e0b";
|
|
2951
|
+
// Orange
|
|
2952
|
+
case "stopped":
|
|
2953
|
+
default:
|
|
2954
|
+
return "#edeeef";
|
|
2955
|
+
}
|
|
2956
|
+
};
|
|
2957
|
+
const fillColor = node.customColors?.fill ?? getStatusColor(node.status);
|
|
2958
|
+
const strokeColor = node.customColors?.stroke ?? "rgb(0, 0, 0)";
|
|
1907
2959
|
return /* @__PURE__ */ jsxs9(
|
|
1908
2960
|
"g",
|
|
1909
2961
|
{
|
|
@@ -1912,6 +2964,11 @@ function NodeRenderer({
|
|
|
1912
2964
|
"data-selected": isSelected,
|
|
1913
2965
|
"data-dragging": isDragging,
|
|
1914
2966
|
transform: transforms.join(" "),
|
|
2967
|
+
style: {
|
|
2968
|
+
"--symbol-fill": fillColor,
|
|
2969
|
+
"--symbol-stroke": strokeColor,
|
|
2970
|
+
cursor: enableDrag ? isDragging ? "grabbing" : "grab" : onNodeClick ? "pointer" : "default"
|
|
2971
|
+
},
|
|
1915
2972
|
onClick: (e) => {
|
|
1916
2973
|
e.stopPropagation();
|
|
1917
2974
|
onNodeClick?.(node.id, e);
|
|
@@ -1931,9 +2988,6 @@ function NodeRenderer({
|
|
|
1931
2988
|
onNodeDragStart?.(node.id, e);
|
|
1932
2989
|
}
|
|
1933
2990
|
},
|
|
1934
|
-
style: {
|
|
1935
|
-
cursor: enableDrag ? isDragging ? "grabbing" : "grab" : onNodeClick ? "pointer" : "default"
|
|
1936
|
-
},
|
|
1937
2991
|
children: [
|
|
1938
2992
|
isSelected && /* @__PURE__ */ jsx13(
|
|
1939
2993
|
"rect",
|
|
@@ -1986,6 +3040,9 @@ function PipeRenderer({
|
|
|
1986
3040
|
onPipeClick,
|
|
1987
3041
|
enableWaypointEditing = false,
|
|
1988
3042
|
onWaypointDragStart,
|
|
3043
|
+
onWaypointClick,
|
|
3044
|
+
selectedWaypointPipeId,
|
|
3045
|
+
selectedWaypointIndex,
|
|
1989
3046
|
editingPipeId,
|
|
1990
3047
|
draggingWaypointIndex,
|
|
1991
3048
|
waypointDragOffset,
|
|
@@ -2006,7 +3063,7 @@ function PipeRenderer({
|
|
|
2006
3063
|
});
|
|
2007
3064
|
const pointsString = displayPoints.map((point) => `${point.x},${point.y}`).join(" ");
|
|
2008
3065
|
const pipeStyle = pipe.style || {};
|
|
2009
|
-
const stroke = isSelected ? "#3b82f6" : pipeStyle.stroke || "#
|
|
3066
|
+
const stroke = isSelected ? "#3b82f6" : pipeStyle.stroke || "#94a1b8";
|
|
2010
3067
|
const strokeWidth = isSelected ? (pipeStyle.strokeWidth || 3) + 2 : pipeStyle.strokeWidth || 3;
|
|
2011
3068
|
const strokeDasharray = pipeStyle.strokeDasharray;
|
|
2012
3069
|
const opacity = pipeStyle.opacity !== void 0 ? pipeStyle.opacity : 1;
|
|
@@ -2055,10 +3112,11 @@ function PipeRenderer({
|
|
|
2055
3112
|
] }),
|
|
2056
3113
|
displayPoints.map((point, idx) => {
|
|
2057
3114
|
const isEndpoint = idx === 0 || idx === displayPoints.length - 1;
|
|
3115
|
+
const isSelectedWaypoint = selectedWaypointPipeId === pipe.id && selectedWaypointIndex === idx;
|
|
2058
3116
|
const isDragging = isEditing && draggingWaypointIndex === idx;
|
|
2059
|
-
const waypointSize = isDragging ? 8 : showEditingControls ? 6 : isSelected ? 3 : 2;
|
|
2060
|
-
const waypointOpacity = isDragging ? 1 : showEditingControls ? 0.9 : isSelected ? 0.8 : 0.5;
|
|
2061
|
-
const waypointColor = isEndpoint && showEditingControls ? "#f59e0b" : isDragging ? "#10b981" : stroke;
|
|
3117
|
+
const waypointSize = isSelectedWaypoint ? 8 : isDragging ? 8 : showEditingControls ? 6 : isSelected ? 3 : 2;
|
|
3118
|
+
const waypointOpacity = isSelectedWaypoint ? 1 : isDragging ? 1 : showEditingControls ? 0.9 : isSelected ? 0.8 : 0.5;
|
|
3119
|
+
const waypointColor = isSelectedWaypoint ? "#3b82f6" : isEndpoint && showEditingControls ? "#f59e0b" : isDragging ? "#10b981" : stroke;
|
|
2062
3120
|
return /* @__PURE__ */ jsx14(
|
|
2063
3121
|
"circle",
|
|
2064
3122
|
{
|
|
@@ -2074,6 +3132,12 @@ function PipeRenderer({
|
|
|
2074
3132
|
cursor: showEditingControls ? isDragging ? "grabbing" : "grab" : "default"
|
|
2075
3133
|
},
|
|
2076
3134
|
pointerEvents: showEditingControls ? "all" : "none",
|
|
3135
|
+
onClick: (e) => {
|
|
3136
|
+
if (showEditingControls) {
|
|
3137
|
+
e.stopPropagation();
|
|
3138
|
+
onWaypointClick?.(pipe.id, idx);
|
|
3139
|
+
}
|
|
3140
|
+
},
|
|
2077
3141
|
onMouseDown: (e) => {
|
|
2078
3142
|
if (showEditingControls) {
|
|
2079
3143
|
e.stopPropagation();
|
|
@@ -2150,7 +3214,13 @@ function PipeRenderer({
|
|
|
2150
3214
|
|
|
2151
3215
|
// src/components/PIDCanvas/DataOverlay.tsx
|
|
2152
3216
|
import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2153
|
-
function DataOverlay({
|
|
3217
|
+
function DataOverlay({
|
|
3218
|
+
nodeId,
|
|
3219
|
+
x,
|
|
3220
|
+
y,
|
|
3221
|
+
telemetry,
|
|
3222
|
+
scale = 1
|
|
3223
|
+
}) {
|
|
2154
3224
|
const { value, display, history } = telemetry;
|
|
2155
3225
|
const showValue = display?.showValue ?? true;
|
|
2156
3226
|
const showStatus = display?.showStatus ?? true;
|
|
@@ -2190,9 +3260,9 @@ function DataOverlay({ nodeId, x, y, telemetry }) {
|
|
|
2190
3260
|
const displayText = value.unit ? `${formattedValue} ${value.unit}` : formattedValue;
|
|
2191
3261
|
const sparklinePath = (() => {
|
|
2192
3262
|
if (!showSparkline || !history || history.length < 2) return "";
|
|
2193
|
-
const width = 70;
|
|
2194
|
-
const height = 20;
|
|
2195
|
-
const padding = 5;
|
|
3263
|
+
const width = 70 * scale;
|
|
3264
|
+
const height = 20 * scale;
|
|
3265
|
+
const padding = 5 * scale;
|
|
2196
3266
|
const effectiveWidth = width - padding * 2;
|
|
2197
3267
|
const effectiveHeight = height - padding * 2;
|
|
2198
3268
|
const min = Math.min(...history);
|
|
@@ -2206,21 +3276,22 @@ function DataOverlay({ nodeId, x, y, telemetry }) {
|
|
|
2206
3276
|
return `M ${points.join(" L ")}`;
|
|
2207
3277
|
})();
|
|
2208
3278
|
const hasSparkline = showSparkline && sparklinePath;
|
|
2209
|
-
const overlayHeight = label ? hasSparkline ? 55 : 30 : hasSparkline ? 47 : 22;
|
|
3279
|
+
const overlayHeight = (label ? hasSparkline ? 55 : 30 : hasSparkline ? 47 : 22) * scale;
|
|
3280
|
+
const overlayWidth = 80 * scale;
|
|
2210
3281
|
const displayX = x + offsetX;
|
|
2211
3282
|
const displayY = y + offsetY;
|
|
2212
3283
|
return /* @__PURE__ */ jsxs11("g", { "data-overlay-node": nodeId, "data-status": value.status, children: [
|
|
2213
3284
|
/* @__PURE__ */ jsx15(
|
|
2214
3285
|
"rect",
|
|
2215
3286
|
{
|
|
2216
|
-
x: displayX -
|
|
2217
|
-
y: displayY - 25,
|
|
2218
|
-
width:
|
|
3287
|
+
x: displayX - overlayWidth / 2,
|
|
3288
|
+
y: displayY - 25 * scale,
|
|
3289
|
+
width: overlayWidth,
|
|
2219
3290
|
height: overlayHeight,
|
|
2220
|
-
rx:
|
|
3291
|
+
rx: 4 * scale,
|
|
2221
3292
|
fill: colors.bg,
|
|
2222
3293
|
stroke: colors.border,
|
|
2223
|
-
strokeWidth:
|
|
3294
|
+
strokeWidth: 1 * scale,
|
|
2224
3295
|
opacity: "0.95",
|
|
2225
3296
|
filter: "drop-shadow(0 2px 4px rgba(0,0,0,0.2))"
|
|
2226
3297
|
}
|
|
@@ -2229,9 +3300,9 @@ function DataOverlay({ nodeId, x, y, telemetry }) {
|
|
|
2229
3300
|
"text",
|
|
2230
3301
|
{
|
|
2231
3302
|
x: displayX,
|
|
2232
|
-
y: displayY - 15,
|
|
3303
|
+
y: displayY - 15 * scale,
|
|
2233
3304
|
textAnchor: "middle",
|
|
2234
|
-
fontSize:
|
|
3305
|
+
fontSize: 8 * scale,
|
|
2235
3306
|
fontWeight: "600",
|
|
2236
3307
|
fill: finalTextColor,
|
|
2237
3308
|
opacity: "0.9",
|
|
@@ -2242,31 +3313,41 @@ function DataOverlay({ nodeId, x, y, telemetry }) {
|
|
|
2242
3313
|
"text",
|
|
2243
3314
|
{
|
|
2244
3315
|
x: displayX,
|
|
2245
|
-
y: label ? displayY - 3 : displayY - 9,
|
|
3316
|
+
y: label ? displayY - 3 * scale : displayY - 9 * scale,
|
|
2246
3317
|
textAnchor: "middle",
|
|
2247
|
-
fontSize:
|
|
3318
|
+
fontSize: 11 * scale,
|
|
2248
3319
|
fontWeight: "700",
|
|
2249
3320
|
fill: finalTextColor,
|
|
2250
3321
|
letterSpacing: "0.02em",
|
|
2251
3322
|
children: displayText
|
|
2252
3323
|
}
|
|
2253
3324
|
),
|
|
2254
|
-
showStatus && value.status !== "normal" && /* @__PURE__ */ jsx15(
|
|
2255
|
-
"
|
|
3325
|
+
showStatus && value.status !== "normal" && /* @__PURE__ */ jsx15(
|
|
3326
|
+
"circle",
|
|
2256
3327
|
{
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
3328
|
+
cx: displayX + 35 * scale,
|
|
3329
|
+
cy: displayY - 18 * scale,
|
|
3330
|
+
r: 3 * scale,
|
|
3331
|
+
fill: finalTextColor,
|
|
3332
|
+
opacity: "0.9",
|
|
3333
|
+
children: /* @__PURE__ */ jsx15(
|
|
3334
|
+
"animate",
|
|
3335
|
+
{
|
|
3336
|
+
attributeName: "opacity",
|
|
3337
|
+
values: "0.9;0.3;0.9",
|
|
3338
|
+
dur: "1.5s",
|
|
3339
|
+
repeatCount: "indefinite"
|
|
3340
|
+
}
|
|
3341
|
+
)
|
|
2261
3342
|
}
|
|
2262
|
-
)
|
|
3343
|
+
),
|
|
2263
3344
|
value.quality !== void 0 && value.quality < 100 && /* @__PURE__ */ jsxs11(
|
|
2264
3345
|
"text",
|
|
2265
3346
|
{
|
|
2266
3347
|
x: displayX,
|
|
2267
|
-
y: displayY + 5,
|
|
3348
|
+
y: displayY + 5 * scale,
|
|
2268
3349
|
textAnchor: "middle",
|
|
2269
|
-
fontSize:
|
|
3350
|
+
fontSize: 7 * scale,
|
|
2270
3351
|
fontWeight: "500",
|
|
2271
3352
|
fill: finalTextColor,
|
|
2272
3353
|
opacity: "0.7",
|
|
@@ -2277,13 +3358,13 @@ function DataOverlay({ nodeId, x, y, telemetry }) {
|
|
|
2277
3358
|
]
|
|
2278
3359
|
}
|
|
2279
3360
|
),
|
|
2280
|
-
hasSparkline && /* @__PURE__ */ jsx15("g", { transform: `translate(${displayX - 35}, ${displayY + (label ? 5 : 0)})`, children: /* @__PURE__ */ jsx15(
|
|
3361
|
+
hasSparkline && /* @__PURE__ */ jsx15("g", { transform: `translate(${displayX - 35 * scale}, ${displayY + (label ? 5 : 0) * scale})`, children: /* @__PURE__ */ jsx15(
|
|
2281
3362
|
"path",
|
|
2282
3363
|
{
|
|
2283
3364
|
d: sparklinePath,
|
|
2284
3365
|
fill: "none",
|
|
2285
3366
|
stroke: sparklineColor || finalTextColor,
|
|
2286
|
-
strokeWidth:
|
|
3367
|
+
strokeWidth: 1.5 * scale,
|
|
2287
3368
|
strokeLinecap: "round",
|
|
2288
3369
|
strokeLinejoin: "round",
|
|
2289
3370
|
opacity: "0.9"
|
|
@@ -2292,8 +3373,145 @@ function DataOverlay({ nodeId, x, y, telemetry }) {
|
|
|
2292
3373
|
] });
|
|
2293
3374
|
}
|
|
2294
3375
|
|
|
3376
|
+
// src/components/PIDCanvas/PositionPanel.tsx
|
|
3377
|
+
import { useState as useState7, useEffect as useEffect4 } from "react";
|
|
3378
|
+
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3379
|
+
function PositionPanel({
|
|
3380
|
+
selectedNode,
|
|
3381
|
+
selectedWaypoint,
|
|
3382
|
+
onPositionChange,
|
|
3383
|
+
onWaypointPositionChange,
|
|
3384
|
+
position = "top-right"
|
|
3385
|
+
}) {
|
|
3386
|
+
const [x, setX] = useState7("");
|
|
3387
|
+
const [y, setY] = useState7("");
|
|
3388
|
+
useEffect4(() => {
|
|
3389
|
+
if (selectedNode) {
|
|
3390
|
+
setX(selectedNode.transform.x.toFixed(2));
|
|
3391
|
+
setY(selectedNode.transform.y.toFixed(2));
|
|
3392
|
+
} else if (selectedWaypoint) {
|
|
3393
|
+
setX(selectedWaypoint.position.x.toFixed(2));
|
|
3394
|
+
setY(selectedWaypoint.position.y.toFixed(2));
|
|
3395
|
+
}
|
|
3396
|
+
}, [selectedNode, selectedWaypoint]);
|
|
3397
|
+
if (!selectedNode && !selectedWaypoint) {
|
|
3398
|
+
return null;
|
|
3399
|
+
}
|
|
3400
|
+
const handleXChange = (value) => {
|
|
3401
|
+
setX(value);
|
|
3402
|
+
const numValue = parseFloat(value);
|
|
3403
|
+
if (!isNaN(numValue)) {
|
|
3404
|
+
if (selectedNode && onPositionChange) {
|
|
3405
|
+
onPositionChange(selectedNode.id, numValue, selectedNode.transform.y);
|
|
3406
|
+
} else if (selectedWaypoint && onWaypointPositionChange) {
|
|
3407
|
+
onWaypointPositionChange(
|
|
3408
|
+
selectedWaypoint.pipeId,
|
|
3409
|
+
selectedWaypoint.pointIndex,
|
|
3410
|
+
numValue,
|
|
3411
|
+
selectedWaypoint.position.y
|
|
3412
|
+
);
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3415
|
+
};
|
|
3416
|
+
const handleYChange = (value) => {
|
|
3417
|
+
setY(value);
|
|
3418
|
+
const numValue = parseFloat(value);
|
|
3419
|
+
if (!isNaN(numValue)) {
|
|
3420
|
+
if (selectedNode && onPositionChange) {
|
|
3421
|
+
onPositionChange(selectedNode.id, selectedNode.transform.x, numValue);
|
|
3422
|
+
} else if (selectedWaypoint && onWaypointPositionChange) {
|
|
3423
|
+
onWaypointPositionChange(
|
|
3424
|
+
selectedWaypoint.pipeId,
|
|
3425
|
+
selectedWaypoint.pointIndex,
|
|
3426
|
+
selectedWaypoint.position.x,
|
|
3427
|
+
numValue
|
|
3428
|
+
);
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3431
|
+
};
|
|
3432
|
+
const handleBlur = () => {
|
|
3433
|
+
if (selectedNode) {
|
|
3434
|
+
setX(selectedNode.transform.x.toFixed(2));
|
|
3435
|
+
setY(selectedNode.transform.y.toFixed(2));
|
|
3436
|
+
} else if (selectedWaypoint) {
|
|
3437
|
+
setX(selectedWaypoint.position.x.toFixed(2));
|
|
3438
|
+
setY(selectedWaypoint.position.y.toFixed(2));
|
|
3439
|
+
}
|
|
3440
|
+
};
|
|
3441
|
+
const positionStyles = {
|
|
3442
|
+
"top-left": { top: 10, left: 10 },
|
|
3443
|
+
"top-right": { top: 10, right: 10 },
|
|
3444
|
+
"bottom-left": { bottom: 10, left: 10 },
|
|
3445
|
+
"bottom-right": { bottom: 10, right: 10 }
|
|
3446
|
+
};
|
|
3447
|
+
return /* @__PURE__ */ jsxs12(
|
|
3448
|
+
"div",
|
|
3449
|
+
{
|
|
3450
|
+
style: {
|
|
3451
|
+
position: "absolute",
|
|
3452
|
+
...positionStyles[position],
|
|
3453
|
+
backgroundColor: "white",
|
|
3454
|
+
border: "1px solid #ccc",
|
|
3455
|
+
borderRadius: "4px",
|
|
3456
|
+
padding: "12px",
|
|
3457
|
+
boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
|
|
3458
|
+
zIndex: 1e3,
|
|
3459
|
+
minWidth: "180px",
|
|
3460
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
3461
|
+
fontSize: "13px"
|
|
3462
|
+
},
|
|
3463
|
+
children: [
|
|
3464
|
+
/* @__PURE__ */ jsx16("div", { style: { marginBottom: "8px", fontWeight: 600, color: "#333" }, children: "Position" }),
|
|
3465
|
+
/* @__PURE__ */ jsxs12("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
|
|
3466
|
+
/* @__PURE__ */ jsxs12("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
3467
|
+
/* @__PURE__ */ jsx16("label", { style: { width: "16px", color: "#666" }, children: "X:" }),
|
|
3468
|
+
/* @__PURE__ */ jsx16(
|
|
3469
|
+
"input",
|
|
3470
|
+
{
|
|
3471
|
+
type: "number",
|
|
3472
|
+
value: x,
|
|
3473
|
+
onChange: (e) => handleXChange(e.target.value),
|
|
3474
|
+
onBlur: handleBlur,
|
|
3475
|
+
style: {
|
|
3476
|
+
flex: 1,
|
|
3477
|
+
padding: "4px 8px",
|
|
3478
|
+
border: "1px solid #ddd",
|
|
3479
|
+
borderRadius: "3px",
|
|
3480
|
+
fontSize: "13px"
|
|
3481
|
+
},
|
|
3482
|
+
step: "1"
|
|
3483
|
+
}
|
|
3484
|
+
)
|
|
3485
|
+
] }),
|
|
3486
|
+
/* @__PURE__ */ jsxs12("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
3487
|
+
/* @__PURE__ */ jsx16("label", { style: { width: "16px", color: "#666" }, children: "Y:" }),
|
|
3488
|
+
/* @__PURE__ */ jsx16(
|
|
3489
|
+
"input",
|
|
3490
|
+
{
|
|
3491
|
+
type: "number",
|
|
3492
|
+
value: y,
|
|
3493
|
+
onChange: (e) => handleYChange(e.target.value),
|
|
3494
|
+
onBlur: handleBlur,
|
|
3495
|
+
style: {
|
|
3496
|
+
flex: 1,
|
|
3497
|
+
padding: "4px 8px",
|
|
3498
|
+
border: "1px solid #ddd",
|
|
3499
|
+
borderRadius: "3px",
|
|
3500
|
+
fontSize: "13px"
|
|
3501
|
+
},
|
|
3502
|
+
step: "1"
|
|
3503
|
+
}
|
|
3504
|
+
)
|
|
3505
|
+
] })
|
|
3506
|
+
] }),
|
|
3507
|
+
/* @__PURE__ */ jsx16("div", { style: { marginTop: "8px", fontSize: "11px", color: "#888" }, children: "Use arrow keys to nudge (\xB11px)" })
|
|
3508
|
+
]
|
|
3509
|
+
}
|
|
3510
|
+
);
|
|
3511
|
+
}
|
|
3512
|
+
|
|
2295
3513
|
// src/diagram/hooks/useViewBox.ts
|
|
2296
|
-
import { useState as
|
|
3514
|
+
import { useState as useState8, useCallback as useCallback3, useRef as useRef2, useEffect as useEffect5 } from "react";
|
|
2297
3515
|
function useViewBox(options) {
|
|
2298
3516
|
const {
|
|
2299
3517
|
initialViewBox,
|
|
@@ -2304,7 +3522,7 @@ function useViewBox(options) {
|
|
|
2304
3522
|
zoomSensitivity = 1e-3,
|
|
2305
3523
|
allowLeftClickPan = true
|
|
2306
3524
|
} = options;
|
|
2307
|
-
const [viewBox, setViewBox] =
|
|
3525
|
+
const [viewBox, setViewBox] = useState8(initialViewBox);
|
|
2308
3526
|
const svgRef = useRef2(null);
|
|
2309
3527
|
const isPanningRef = useRef2(false);
|
|
2310
3528
|
const lastMousePosRef = useRef2({ x: 0, y: 0 });
|
|
@@ -2347,7 +3565,35 @@ function useViewBox(options) {
|
|
|
2347
3565
|
};
|
|
2348
3566
|
});
|
|
2349
3567
|
}, [initialViewBox, maxZoom]);
|
|
2350
|
-
|
|
3568
|
+
const fitToContent = useCallback3((bounds, padding = 50) => {
|
|
3569
|
+
const contentWidth = bounds.maxX - bounds.minX;
|
|
3570
|
+
const contentHeight = bounds.maxY - bounds.minY;
|
|
3571
|
+
if (contentWidth === 0 || contentHeight === 0) {
|
|
3572
|
+
return;
|
|
3573
|
+
}
|
|
3574
|
+
const paddedWidth = contentWidth + padding * 2;
|
|
3575
|
+
const paddedHeight = contentHeight + padding * 2;
|
|
3576
|
+
const aspectRatio = initialViewBox.width / initialViewBox.height;
|
|
3577
|
+
const contentAspectRatio = paddedWidth / paddedHeight;
|
|
3578
|
+
let newWidth;
|
|
3579
|
+
let newHeight;
|
|
3580
|
+
if (contentAspectRatio > aspectRatio) {
|
|
3581
|
+
newWidth = paddedWidth;
|
|
3582
|
+
newHeight = paddedWidth / aspectRatio;
|
|
3583
|
+
} else {
|
|
3584
|
+
newHeight = paddedHeight;
|
|
3585
|
+
newWidth = paddedHeight * aspectRatio;
|
|
3586
|
+
}
|
|
3587
|
+
const centerX = bounds.minX + contentWidth / 2;
|
|
3588
|
+
const centerY = bounds.minY + contentHeight / 2;
|
|
3589
|
+
setViewBox({
|
|
3590
|
+
x: centerX - newWidth / 2,
|
|
3591
|
+
y: centerY - newHeight / 2,
|
|
3592
|
+
width: newWidth,
|
|
3593
|
+
height: newHeight
|
|
3594
|
+
});
|
|
3595
|
+
}, [initialViewBox]);
|
|
3596
|
+
useEffect5(() => {
|
|
2351
3597
|
if (!enableZoom || !svgRef.current) return;
|
|
2352
3598
|
const svg = svgRef.current;
|
|
2353
3599
|
const handleWheel = (e) => {
|
|
@@ -2380,7 +3626,7 @@ function useViewBox(options) {
|
|
|
2380
3626
|
svg.addEventListener("wheel", handleWheel, { passive: false });
|
|
2381
3627
|
return () => svg.removeEventListener("wheel", handleWheel);
|
|
2382
3628
|
}, [enableZoom, zoomSensitivity, minZoom, initialViewBox]);
|
|
2383
|
-
|
|
3629
|
+
useEffect5(() => {
|
|
2384
3630
|
if (!enablePan || !svgRef.current) return;
|
|
2385
3631
|
const svg = svgRef.current;
|
|
2386
3632
|
const handleMouseDown = (e) => {
|
|
@@ -2456,7 +3702,7 @@ function useViewBox(options) {
|
|
|
2456
3702
|
window.removeEventListener("keyup", handleKeyUp);
|
|
2457
3703
|
};
|
|
2458
3704
|
}, [enablePan, allowLeftClickPan]);
|
|
2459
|
-
|
|
3705
|
+
useEffect5(() => {
|
|
2460
3706
|
if (!svgRef.current) return;
|
|
2461
3707
|
if (!enablePan && !enableZoom) return;
|
|
2462
3708
|
const svg = svgRef.current;
|
|
@@ -2578,20 +3824,22 @@ function useViewBox(options) {
|
|
|
2578
3824
|
resetViewBox,
|
|
2579
3825
|
zoomIn,
|
|
2580
3826
|
zoomOut,
|
|
3827
|
+
fitToContent,
|
|
3828
|
+
setViewBox,
|
|
2581
3829
|
screenToWorld,
|
|
2582
3830
|
svgRef
|
|
2583
3831
|
};
|
|
2584
3832
|
}
|
|
2585
3833
|
|
|
2586
3834
|
// src/diagram/hooks/useSelection.ts
|
|
2587
|
-
import { useState as
|
|
3835
|
+
import { useState as useState9, useCallback as useCallback4 } from "react";
|
|
2588
3836
|
function useSelection(options = {}) {
|
|
2589
3837
|
const {
|
|
2590
3838
|
multiSelect = true,
|
|
2591
3839
|
initialSelection = { selectedNodeIds: /* @__PURE__ */ new Set(), selectedPipeIds: /* @__PURE__ */ new Set() },
|
|
2592
3840
|
onSelectionChange
|
|
2593
3841
|
} = options;
|
|
2594
|
-
const [selection, setSelection] =
|
|
3842
|
+
const [selection, setSelection] = useState9(initialSelection);
|
|
2595
3843
|
const notifyChange = useCallback4(
|
|
2596
3844
|
(newSelection) => {
|
|
2597
3845
|
if (onSelectionChange) {
|
|
@@ -2689,14 +3937,14 @@ function useSelection(options = {}) {
|
|
|
2689
3937
|
}
|
|
2690
3938
|
|
|
2691
3939
|
// src/diagram/hooks/useTelemetry.ts
|
|
2692
|
-
import { useState as
|
|
3940
|
+
import { useState as useState10, useCallback as useCallback5, useEffect as useEffect6, useRef as useRef3 } from "react";
|
|
2693
3941
|
function useTelemetry(options = {}) {
|
|
2694
3942
|
const {
|
|
2695
3943
|
initialBindings = [],
|
|
2696
3944
|
onTelemetryChange,
|
|
2697
3945
|
refreshInterval = 0
|
|
2698
3946
|
} = options;
|
|
2699
|
-
const [telemetry, setTelemetry] =
|
|
3947
|
+
const [telemetry, setTelemetry] = useState10(() => {
|
|
2700
3948
|
const map = /* @__PURE__ */ new Map();
|
|
2701
3949
|
initialBindings.forEach((binding) => {
|
|
2702
3950
|
map.set(binding.nodeId, binding);
|
|
@@ -2817,7 +4065,7 @@ function useTelemetry(options = {}) {
|
|
|
2817
4065
|
},
|
|
2818
4066
|
[notifyChange]
|
|
2819
4067
|
);
|
|
2820
|
-
|
|
4068
|
+
useEffect6(() => {
|
|
2821
4069
|
if (refreshInterval <= 0) return;
|
|
2822
4070
|
const intervalId = setInterval(() => {
|
|
2823
4071
|
notifyChange(telemetryRef.current);
|
|
@@ -2834,8 +4082,50 @@ function useTelemetry(options = {}) {
|
|
|
2834
4082
|
};
|
|
2835
4083
|
}
|
|
2836
4084
|
|
|
4085
|
+
// src/diagram/hooks/useTelemetryStatus.ts
|
|
4086
|
+
import { useEffect as useEffect7 } from "react";
|
|
4087
|
+
function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
|
|
4088
|
+
const { enabled = true, mapStatus } = options;
|
|
4089
|
+
useEffect7(() => {
|
|
4090
|
+
if (!enabled) return;
|
|
4091
|
+
const defaultMapStatus = (telemetryStatus) => {
|
|
4092
|
+
switch (telemetryStatus) {
|
|
4093
|
+
case "normal":
|
|
4094
|
+
return "running";
|
|
4095
|
+
case "warning":
|
|
4096
|
+
return "warning";
|
|
4097
|
+
case "alarm":
|
|
4098
|
+
case "fault":
|
|
4099
|
+
return "alarm";
|
|
4100
|
+
case "off":
|
|
4101
|
+
return "stopped";
|
|
4102
|
+
default:
|
|
4103
|
+
return "stopped";
|
|
4104
|
+
}
|
|
4105
|
+
};
|
|
4106
|
+
const statusMapper = mapStatus || defaultMapStatus;
|
|
4107
|
+
let needsUpdate = false;
|
|
4108
|
+
const updatedNodes = diagram.nodes.map((node) => {
|
|
4109
|
+
const binding = telemetry.get(node.id);
|
|
4110
|
+
if (!binding) return node;
|
|
4111
|
+
const newStatus = statusMapper(binding.value.status);
|
|
4112
|
+
if (node.status !== newStatus) {
|
|
4113
|
+
needsUpdate = true;
|
|
4114
|
+
return { ...node, status: newStatus };
|
|
4115
|
+
}
|
|
4116
|
+
return node;
|
|
4117
|
+
});
|
|
4118
|
+
if (needsUpdate) {
|
|
4119
|
+
setDiagram({
|
|
4120
|
+
...diagram,
|
|
4121
|
+
nodes: updatedNodes
|
|
4122
|
+
});
|
|
4123
|
+
}
|
|
4124
|
+
}, [telemetry, diagram, setDiagram, enabled, mapStatus]);
|
|
4125
|
+
}
|
|
4126
|
+
|
|
2837
4127
|
// src/diagram/hooks/useDrag.ts
|
|
2838
|
-
import { useState as
|
|
4128
|
+
import { useState as useState11, useCallback as useCallback6, useRef as useRef4, useEffect as useEffect8 } from "react";
|
|
2839
4129
|
function useDrag(options = {}) {
|
|
2840
4130
|
const {
|
|
2841
4131
|
onDragStart,
|
|
@@ -2845,13 +4135,13 @@ function useDrag(options = {}) {
|
|
|
2845
4135
|
dragThreshold = 3,
|
|
2846
4136
|
screenToWorld = (x, y) => ({ x, y })
|
|
2847
4137
|
} = options;
|
|
2848
|
-
const [dragState, setDragState] =
|
|
4138
|
+
const [dragState, setDragState] = useState11({
|
|
2849
4139
|
isDragging: false,
|
|
2850
4140
|
startPosition: null,
|
|
2851
4141
|
offset: { x: 0, y: 0 },
|
|
2852
4142
|
draggedId: null
|
|
2853
4143
|
});
|
|
2854
|
-
const [isListening, setIsListening] =
|
|
4144
|
+
const [isListening, setIsListening] = useState11(false);
|
|
2855
4145
|
const dragStartRef = useRef4(null);
|
|
2856
4146
|
const hasMovedRef = useRef4(false);
|
|
2857
4147
|
const applySnap = useCallback6(
|
|
@@ -3020,7 +4310,7 @@ function useDrag(options = {}) {
|
|
|
3020
4310
|
},
|
|
3021
4311
|
[screenToWorld, applySnap, onDragEnd]
|
|
3022
4312
|
);
|
|
3023
|
-
|
|
4313
|
+
useEffect8(() => {
|
|
3024
4314
|
if (!isListening) return;
|
|
3025
4315
|
document.addEventListener("mousemove", handleMouseMove);
|
|
3026
4316
|
document.addEventListener("mouseup", handleMouseUp);
|
|
@@ -3089,7 +4379,7 @@ function useDrag(options = {}) {
|
|
|
3089
4379
|
}
|
|
3090
4380
|
|
|
3091
4381
|
// src/diagram/hooks/useKeyboardShortcuts.ts
|
|
3092
|
-
import { useEffect as
|
|
4382
|
+
import { useEffect as useEffect9 } from "react";
|
|
3093
4383
|
function useKeyboardShortcuts(options) {
|
|
3094
4384
|
const {
|
|
3095
4385
|
onDelete,
|
|
@@ -3100,7 +4390,7 @@ function useKeyboardShortcuts(options) {
|
|
|
3100
4390
|
onSelectAll,
|
|
3101
4391
|
enabled = true
|
|
3102
4392
|
} = options;
|
|
3103
|
-
|
|
4393
|
+
useEffect9(() => {
|
|
3104
4394
|
if (!enabled) return;
|
|
3105
4395
|
const handleKeyDown = (event) => {
|
|
3106
4396
|
const target = event.target;
|
|
@@ -3209,7 +4499,7 @@ function nodeHasPort(node, portId) {
|
|
|
3209
4499
|
}
|
|
3210
4500
|
|
|
3211
4501
|
// src/components/PIDCanvas/PIDCanvas.tsx
|
|
3212
|
-
import { Fragment as Fragment5, jsx as
|
|
4502
|
+
import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3213
4503
|
function PIDCanvas({
|
|
3214
4504
|
diagram,
|
|
3215
4505
|
className = "",
|
|
@@ -3232,35 +4522,290 @@ function PIDCanvas({
|
|
|
3232
4522
|
onPaste,
|
|
3233
4523
|
onSymbolDrop,
|
|
3234
4524
|
onPipeCreated,
|
|
4525
|
+
onMounted,
|
|
3235
4526
|
telemetry,
|
|
3236
4527
|
...props
|
|
3237
4528
|
}) {
|
|
3238
|
-
const [localDiagram, setLocalDiagram] =
|
|
3239
|
-
const [dragOverPosition, setDragOverPosition] =
|
|
3240
|
-
const [isConnecting, setIsConnecting] =
|
|
3241
|
-
const [connectionSource, setConnectionSource] =
|
|
3242
|
-
const [connectionSourcePort, setConnectionSourcePort] =
|
|
3243
|
-
const [connectionCursor, setConnectionCursor] =
|
|
3244
|
-
const [hoveredNode, setHoveredNode] =
|
|
3245
|
-
const [hoveredPort, setHoveredPort] =
|
|
3246
|
-
|
|
3247
|
-
|
|
4529
|
+
const [localDiagram, setLocalDiagram] = useState12(diagram);
|
|
4530
|
+
const [dragOverPosition, setDragOverPosition] = useState12(null);
|
|
4531
|
+
const [isConnecting, setIsConnecting] = useState12(false);
|
|
4532
|
+
const [connectionSource, setConnectionSource] = useState12(null);
|
|
4533
|
+
const [connectionSourcePort, setConnectionSourcePort] = useState12(null);
|
|
4534
|
+
const [connectionCursor, setConnectionCursor] = useState12(null);
|
|
4535
|
+
const [hoveredNode, setHoveredNode] = useState12(null);
|
|
4536
|
+
const [hoveredPort, setHoveredPort] = useState12(null);
|
|
4537
|
+
const [selectedWaypoint, setSelectedWaypoint] = useState12(null);
|
|
4538
|
+
const historyStack = useRef5([]);
|
|
4539
|
+
const redoStack = useRef5([]);
|
|
4540
|
+
const isUndoRedoAction = useRef5(false);
|
|
4541
|
+
const isInternalChange = useRef5(false);
|
|
4542
|
+
const lastInternalDiagram = useRef5(null);
|
|
4543
|
+
useEffect10(() => {
|
|
4544
|
+
const isExternal = !isInternalChange.current && diagram !== lastInternalDiagram.current;
|
|
4545
|
+
if (isExternal) {
|
|
4546
|
+
setLocalDiagram(diagram);
|
|
4547
|
+
if (!isUndoRedoAction.current) {
|
|
4548
|
+
historyStack.current = [];
|
|
4549
|
+
redoStack.current = [];
|
|
4550
|
+
}
|
|
4551
|
+
}
|
|
4552
|
+
isInternalChange.current = false;
|
|
3248
4553
|
}, [diagram]);
|
|
3249
4554
|
const {
|
|
3250
4555
|
viewBox: controlledViewBox,
|
|
3251
4556
|
svgRef,
|
|
3252
|
-
screenToWorld
|
|
4557
|
+
screenToWorld,
|
|
4558
|
+
fitToContent: fitToContentViewBox,
|
|
4559
|
+
setViewBox
|
|
3253
4560
|
} = useViewBox({
|
|
3254
4561
|
initialViewBox: diagram.viewBox,
|
|
3255
4562
|
enablePan: features.pan ?? true,
|
|
3256
4563
|
enableZoom: features.zoom ?? true
|
|
3257
4564
|
});
|
|
4565
|
+
const calculateContentBounds = useCallback7(() => {
|
|
4566
|
+
const nodes2 = localDiagram.nodes.filter((n) => n.visible !== false);
|
|
4567
|
+
if (nodes2.length === 0) {
|
|
4568
|
+
return null;
|
|
4569
|
+
}
|
|
4570
|
+
let minX = Infinity;
|
|
4571
|
+
let minY = Infinity;
|
|
4572
|
+
let maxX = -Infinity;
|
|
4573
|
+
let maxY = -Infinity;
|
|
4574
|
+
nodes2.forEach((node) => {
|
|
4575
|
+
const symbol = getSymbolDefinition(node.symbolId);
|
|
4576
|
+
if (!symbol) return;
|
|
4577
|
+
const nodeMinX = node.transform.x;
|
|
4578
|
+
const nodeMinY = node.transform.y;
|
|
4579
|
+
const nodeMaxX = node.transform.x + symbol.viewBox.width;
|
|
4580
|
+
const nodeMaxY = node.transform.y + symbol.viewBox.height;
|
|
4581
|
+
minX = Math.min(minX, nodeMinX);
|
|
4582
|
+
minY = Math.min(minY, nodeMinY);
|
|
4583
|
+
maxX = Math.max(maxX, nodeMaxX);
|
|
4584
|
+
maxY = Math.max(maxY, nodeMaxY);
|
|
4585
|
+
});
|
|
4586
|
+
return { minX, minY, maxX, maxY };
|
|
4587
|
+
}, [localDiagram.nodes]);
|
|
4588
|
+
useEffect10(() => {
|
|
4589
|
+
if (onMounted) {
|
|
4590
|
+
const controls = {
|
|
4591
|
+
fitToContent: (padding = 50) => {
|
|
4592
|
+
const bounds = calculateContentBounds();
|
|
4593
|
+
if (bounds) {
|
|
4594
|
+
fitToContentViewBox(bounds, padding);
|
|
4595
|
+
}
|
|
4596
|
+
},
|
|
4597
|
+
setZoom: (zoomLevel) => {
|
|
4598
|
+
const centerX = controlledViewBox.x + controlledViewBox.width / 2;
|
|
4599
|
+
const centerY = controlledViewBox.y + controlledViewBox.height / 2;
|
|
4600
|
+
const newWidth = diagram.viewBox.width / zoomLevel;
|
|
4601
|
+
const newHeight = diagram.viewBox.height / zoomLevel;
|
|
4602
|
+
setViewBox({
|
|
4603
|
+
x: centerX - newWidth / 2,
|
|
4604
|
+
y: centerY - newHeight / 2,
|
|
4605
|
+
width: newWidth,
|
|
4606
|
+
height: newHeight
|
|
4607
|
+
});
|
|
4608
|
+
},
|
|
4609
|
+
getZoom: () => {
|
|
4610
|
+
return diagram.viewBox.width / controlledViewBox.width;
|
|
4611
|
+
}
|
|
4612
|
+
};
|
|
4613
|
+
onMounted(controls);
|
|
4614
|
+
}
|
|
4615
|
+
}, [
|
|
4616
|
+
onMounted,
|
|
4617
|
+
calculateContentBounds,
|
|
4618
|
+
fitToContentViewBox,
|
|
4619
|
+
setViewBox,
|
|
4620
|
+
controlledViewBox,
|
|
4621
|
+
diagram.viewBox
|
|
4622
|
+
]);
|
|
3258
4623
|
const { selection, selectNode, selectPipe, clearSelection } = useSelection({
|
|
3259
4624
|
multiSelect: features.multiSelect ?? true,
|
|
3260
4625
|
onSelectionChange
|
|
3261
4626
|
});
|
|
3262
4627
|
const dragEnabled = features.dragNodes ?? false;
|
|
3263
4628
|
const selectionEnabled = features.selection ?? false;
|
|
4629
|
+
const containerRef = useRef5(null);
|
|
4630
|
+
const pushToHistory = useCallback7((currentDiagram) => {
|
|
4631
|
+
if (isUndoRedoAction.current) return;
|
|
4632
|
+
const snapshot = JSON.parse(JSON.stringify(currentDiagram));
|
|
4633
|
+
historyStack.current.push(snapshot);
|
|
4634
|
+
if (historyStack.current.length > 15) {
|
|
4635
|
+
historyStack.current.shift();
|
|
4636
|
+
}
|
|
4637
|
+
redoStack.current = [];
|
|
4638
|
+
}, []);
|
|
4639
|
+
const undo = useCallback7(() => {
|
|
4640
|
+
if (historyStack.current.length === 0) return;
|
|
4641
|
+
isUndoRedoAction.current = true;
|
|
4642
|
+
const currentSnapshot = JSON.parse(JSON.stringify(localDiagram));
|
|
4643
|
+
redoStack.current.push(currentSnapshot);
|
|
4644
|
+
const previousState = historyStack.current.pop();
|
|
4645
|
+
isInternalChange.current = true;
|
|
4646
|
+
lastInternalDiagram.current = previousState;
|
|
4647
|
+
setLocalDiagram(previousState);
|
|
4648
|
+
onDiagramChange?.(previousState);
|
|
4649
|
+
setTimeout(() => {
|
|
4650
|
+
isUndoRedoAction.current = false;
|
|
4651
|
+
}, 0);
|
|
4652
|
+
}, [localDiagram, onDiagramChange]);
|
|
4653
|
+
const redo = useCallback7(() => {
|
|
4654
|
+
if (redoStack.current.length === 0) return;
|
|
4655
|
+
isUndoRedoAction.current = true;
|
|
4656
|
+
const currentSnapshot = JSON.parse(JSON.stringify(localDiagram));
|
|
4657
|
+
historyStack.current.push(currentSnapshot);
|
|
4658
|
+
const nextState = redoStack.current.pop();
|
|
4659
|
+
isInternalChange.current = true;
|
|
4660
|
+
lastInternalDiagram.current = nextState;
|
|
4661
|
+
setLocalDiagram(nextState);
|
|
4662
|
+
onDiagramChange?.(nextState);
|
|
4663
|
+
setTimeout(() => {
|
|
4664
|
+
isUndoRedoAction.current = false;
|
|
4665
|
+
}, 0);
|
|
4666
|
+
}, [localDiagram, onDiagramChange]);
|
|
4667
|
+
useEffect10(() => {
|
|
4668
|
+
const handleKeyDown = (e) => {
|
|
4669
|
+
const isCtrlOrCmd = e.ctrlKey || e.metaKey;
|
|
4670
|
+
if (isCtrlOrCmd && e.key === "z" && !e.shiftKey) {
|
|
4671
|
+
e.preventDefault();
|
|
4672
|
+
undo();
|
|
4673
|
+
} else if (isCtrlOrCmd && e.key === "z" && e.shiftKey) {
|
|
4674
|
+
e.preventDefault();
|
|
4675
|
+
redo();
|
|
4676
|
+
} else if (isCtrlOrCmd && e.key === "y") {
|
|
4677
|
+
e.preventDefault();
|
|
4678
|
+
redo();
|
|
4679
|
+
}
|
|
4680
|
+
};
|
|
4681
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
4682
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
4683
|
+
}, [undo, redo]);
|
|
4684
|
+
useEffect10(() => {
|
|
4685
|
+
if (!features.dragNodes) return;
|
|
4686
|
+
const handleKeyDown = (e) => {
|
|
4687
|
+
if (selection.selectedNodeIds.size === 0 && !selectedWaypoint) return;
|
|
4688
|
+
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) {
|
|
4689
|
+
return;
|
|
4690
|
+
}
|
|
4691
|
+
const nudgeAmount = e.shiftKey ? 10 : 1;
|
|
4692
|
+
let dx = 0;
|
|
4693
|
+
let dy = 0;
|
|
4694
|
+
switch (e.key) {
|
|
4695
|
+
case "ArrowLeft":
|
|
4696
|
+
dx = -nudgeAmount;
|
|
4697
|
+
e.preventDefault();
|
|
4698
|
+
break;
|
|
4699
|
+
case "ArrowRight":
|
|
4700
|
+
dx = nudgeAmount;
|
|
4701
|
+
e.preventDefault();
|
|
4702
|
+
break;
|
|
4703
|
+
case "ArrowUp":
|
|
4704
|
+
dy = -nudgeAmount;
|
|
4705
|
+
e.preventDefault();
|
|
4706
|
+
break;
|
|
4707
|
+
case "ArrowDown":
|
|
4708
|
+
dy = nudgeAmount;
|
|
4709
|
+
e.preventDefault();
|
|
4710
|
+
break;
|
|
4711
|
+
default:
|
|
4712
|
+
return;
|
|
4713
|
+
}
|
|
4714
|
+
if (selectedWaypoint) {
|
|
4715
|
+
pushToHistory(localDiagram);
|
|
4716
|
+
const updatedPipes = localDiagram.pipes.map((pipe) => {
|
|
4717
|
+
if (pipe.id === selectedWaypoint.pipeId) {
|
|
4718
|
+
const updatedRoutePoints = pipe.routePoints.map(
|
|
4719
|
+
(point, idx) => idx === selectedWaypoint.pointIndex ? { x: point.x + dx, y: point.y + dy } : point
|
|
4720
|
+
);
|
|
4721
|
+
return { ...pipe, routePoints: updatedRoutePoints };
|
|
4722
|
+
}
|
|
4723
|
+
return pipe;
|
|
4724
|
+
});
|
|
4725
|
+
const updatedDiagram = { ...localDiagram, pipes: updatedPipes };
|
|
4726
|
+
isInternalChange.current = true;
|
|
4727
|
+
lastInternalDiagram.current = updatedDiagram;
|
|
4728
|
+
setLocalDiagram(updatedDiagram);
|
|
4729
|
+
onDiagramChange?.(updatedDiagram);
|
|
4730
|
+
return;
|
|
4731
|
+
}
|
|
4732
|
+
if (selectionEnabled && selection.selectedNodeIds.size > 0) {
|
|
4733
|
+
pushToHistory(localDiagram);
|
|
4734
|
+
const updatedNodes = localDiagram.nodes.map(
|
|
4735
|
+
(node) => selection.selectedNodeIds.has(node.id) ? {
|
|
4736
|
+
...node,
|
|
4737
|
+
transform: {
|
|
4738
|
+
...node.transform,
|
|
4739
|
+
x: node.transform.x + dx,
|
|
4740
|
+
y: node.transform.y + dy
|
|
4741
|
+
}
|
|
4742
|
+
} : node
|
|
4743
|
+
);
|
|
4744
|
+
const updatedDiagram = { ...localDiagram, nodes: updatedNodes };
|
|
4745
|
+
isInternalChange.current = true;
|
|
4746
|
+
lastInternalDiagram.current = updatedDiagram;
|
|
4747
|
+
setLocalDiagram(updatedDiagram);
|
|
4748
|
+
onDiagramChange?.(updatedDiagram);
|
|
4749
|
+
selection.selectedNodeIds.forEach((nodeId) => {
|
|
4750
|
+
const node = updatedNodes.find((n) => n.id === nodeId);
|
|
4751
|
+
if (node) {
|
|
4752
|
+
onNodeMove?.(nodeId, node.transform.x, node.transform.y);
|
|
4753
|
+
}
|
|
4754
|
+
});
|
|
4755
|
+
}
|
|
4756
|
+
};
|
|
4757
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
4758
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
4759
|
+
}, [
|
|
4760
|
+
selectionEnabled,
|
|
4761
|
+
features.dragNodes,
|
|
4762
|
+
selection.selectedNodeIds,
|
|
4763
|
+
selectedWaypoint,
|
|
4764
|
+
localDiagram,
|
|
4765
|
+
onDiagramChange,
|
|
4766
|
+
onNodeMove,
|
|
4767
|
+
pushToHistory
|
|
4768
|
+
]);
|
|
4769
|
+
const handlePositionChange = useCallback7(
|
|
4770
|
+
(nodeId, x, y) => {
|
|
4771
|
+
pushToHistory(localDiagram);
|
|
4772
|
+
const updatedNodes = localDiagram.nodes.map(
|
|
4773
|
+
(node) => node.id === nodeId ? {
|
|
4774
|
+
...node,
|
|
4775
|
+
transform: {
|
|
4776
|
+
...node.transform,
|
|
4777
|
+
x,
|
|
4778
|
+
y
|
|
4779
|
+
}
|
|
4780
|
+
} : node
|
|
4781
|
+
);
|
|
4782
|
+
const updatedDiagram = { ...localDiagram, nodes: updatedNodes };
|
|
4783
|
+
isInternalChange.current = true;
|
|
4784
|
+
lastInternalDiagram.current = updatedDiagram;
|
|
4785
|
+
setLocalDiagram(updatedDiagram);
|
|
4786
|
+
onDiagramChange?.(updatedDiagram);
|
|
4787
|
+
onNodeMove?.(nodeId, x, y);
|
|
4788
|
+
},
|
|
4789
|
+
[localDiagram, onDiagramChange, onNodeMove, pushToHistory]
|
|
4790
|
+
);
|
|
4791
|
+
const handleWaypointPositionChange = useCallback7(
|
|
4792
|
+
(pipeId, pointIndex, x, y) => {
|
|
4793
|
+
pushToHistory(localDiagram);
|
|
4794
|
+
const updatedPipes = localDiagram.pipes.map((pipe) => {
|
|
4795
|
+
if (pipe.id === pipeId) {
|
|
4796
|
+
const updatedRoutePoints = pipe.routePoints.map(
|
|
4797
|
+
(point, idx) => idx === pointIndex ? { x, y } : point
|
|
4798
|
+
);
|
|
4799
|
+
return { ...pipe, routePoints: updatedRoutePoints };
|
|
4800
|
+
}
|
|
4801
|
+
return pipe;
|
|
4802
|
+
});
|
|
4803
|
+
const updatedDiagram = { ...localDiagram, pipes: updatedPipes };
|
|
4804
|
+
setLocalDiagram(updatedDiagram);
|
|
4805
|
+
onDiagramChange?.(updatedDiagram);
|
|
4806
|
+
},
|
|
4807
|
+
[localDiagram, onDiagramChange, pushToHistory]
|
|
4808
|
+
);
|
|
3264
4809
|
const handleDragEnd = useCallback7(
|
|
3265
4810
|
(nodeId, offset, finalPosition) => {
|
|
3266
4811
|
const dragDistance = Math.sqrt(offset.x ** 2 + offset.y ** 2);
|
|
@@ -3270,6 +4815,7 @@ function PIDCanvas({
|
|
|
3270
4815
|
}
|
|
3271
4816
|
return;
|
|
3272
4817
|
}
|
|
4818
|
+
pushToHistory(localDiagram);
|
|
3273
4819
|
const updatedNodes = localDiagram.nodes.map(
|
|
3274
4820
|
(node) => node.id === nodeId ? {
|
|
3275
4821
|
...node,
|
|
@@ -3307,11 +4853,13 @@ function PIDCanvas({
|
|
|
3307
4853
|
nodes: updatedNodes,
|
|
3308
4854
|
pipes: updatedPipes
|
|
3309
4855
|
};
|
|
4856
|
+
isInternalChange.current = true;
|
|
4857
|
+
lastInternalDiagram.current = updatedDiagram;
|
|
3310
4858
|
setLocalDiagram(updatedDiagram);
|
|
3311
4859
|
onDiagramChange?.(updatedDiagram);
|
|
3312
4860
|
onNodeMove?.(nodeId, finalPosition.x, finalPosition.y);
|
|
3313
4861
|
},
|
|
3314
|
-
[localDiagram, onDiagramChange, onNodeMove, selectionEnabled, selectNode]
|
|
4862
|
+
[localDiagram, onDiagramChange, onNodeMove, selectionEnabled, selectNode, pushToHistory]
|
|
3315
4863
|
);
|
|
3316
4864
|
const { dragState, startDrag } = useDrag({
|
|
3317
4865
|
snapToGrid: features.snapToGrid ?? 0,
|
|
@@ -3322,6 +4870,7 @@ function PIDCanvas({
|
|
|
3322
4870
|
snapToGrid: features.snapToGrid ?? 0,
|
|
3323
4871
|
screenToWorld,
|
|
3324
4872
|
onDragEnd: (pipeId, _offset, finalPosition) => {
|
|
4873
|
+
pushToHistory(localDiagram);
|
|
3325
4874
|
const [actualPipeId, pointIndex] = pipeId.split(":");
|
|
3326
4875
|
const idx = parseInt(pointIndex, 10);
|
|
3327
4876
|
const updatedPipes = localDiagram.pipes.map((pipe) => {
|
|
@@ -3332,6 +4881,8 @@ function PIDCanvas({
|
|
|
3332
4881
|
return { ...pipe, routePoints: updatedRoutePoints };
|
|
3333
4882
|
});
|
|
3334
4883
|
const updatedDiagram = { ...localDiagram, pipes: updatedPipes };
|
|
4884
|
+
isInternalChange.current = true;
|
|
4885
|
+
lastInternalDiagram.current = updatedDiagram;
|
|
3335
4886
|
setLocalDiagram(updatedDiagram);
|
|
3336
4887
|
onDiagramChange?.(updatedDiagram);
|
|
3337
4888
|
}
|
|
@@ -3344,6 +4895,15 @@ function PIDCanvas({
|
|
|
3344
4895
|
},
|
|
3345
4896
|
[localDiagram.nodes, startDrag]
|
|
3346
4897
|
);
|
|
4898
|
+
const handleWaypointClick = useCallback7(
|
|
4899
|
+
(pipeId, pointIndex) => {
|
|
4900
|
+
setSelectedWaypoint({ pipeId, pointIndex });
|
|
4901
|
+
if (selectionEnabled) {
|
|
4902
|
+
clearSelection();
|
|
4903
|
+
}
|
|
4904
|
+
},
|
|
4905
|
+
[selectionEnabled, clearSelection]
|
|
4906
|
+
);
|
|
3347
4907
|
const handleWaypointDragStart = useCallback7(
|
|
3348
4908
|
(pipeId, pointIndex, event) => {
|
|
3349
4909
|
const pipe = localDiagram.pipes.find((p) => p.id === pipeId);
|
|
@@ -3355,6 +4915,7 @@ function PIDCanvas({
|
|
|
3355
4915
|
);
|
|
3356
4916
|
const handlePipeSegmentClick = useCallback7(
|
|
3357
4917
|
(pipeId, position, segmentIndex) => {
|
|
4918
|
+
pushToHistory(localDiagram);
|
|
3358
4919
|
const updatedPipes = localDiagram.pipes.map((pipe) => {
|
|
3359
4920
|
if (pipe.id !== pipeId) return pipe;
|
|
3360
4921
|
const updatedRoutePoints = [
|
|
@@ -3368,13 +4929,14 @@ function PIDCanvas({
|
|
|
3368
4929
|
setLocalDiagram(updatedDiagram);
|
|
3369
4930
|
onDiagramChange?.(updatedDiagram);
|
|
3370
4931
|
},
|
|
3371
|
-
[localDiagram, onDiagramChange]
|
|
4932
|
+
[localDiagram, onDiagramChange, pushToHistory]
|
|
3372
4933
|
);
|
|
3373
4934
|
const telemetryEnabled = features.telemetry ?? false;
|
|
3374
4935
|
const handleDelete = useCallback7(() => {
|
|
3375
4936
|
if (!selectionEnabled) return;
|
|
3376
4937
|
const { selectedNodeIds, selectedPipeIds } = selection;
|
|
3377
4938
|
if (selectedNodeIds.size === 0 && selectedPipeIds.size === 0) return;
|
|
4939
|
+
pushToHistory(localDiagram);
|
|
3378
4940
|
const updatedNodes = localDiagram.nodes.filter((node) => !selectedNodeIds.has(node.id));
|
|
3379
4941
|
const updatedPipes = localDiagram.pipes.filter(
|
|
3380
4942
|
(pipe) => !selectedPipeIds.has(pipe.id) && !selectedNodeIds.has(pipe.fromNodeId) && !selectedNodeIds.has(pipe.toNodeId)
|
|
@@ -3384,11 +4946,21 @@ function PIDCanvas({
|
|
|
3384
4946
|
nodes: updatedNodes,
|
|
3385
4947
|
pipes: updatedPipes
|
|
3386
4948
|
};
|
|
4949
|
+
isInternalChange.current = true;
|
|
4950
|
+
lastInternalDiagram.current = updatedDiagram;
|
|
3387
4951
|
setLocalDiagram(updatedDiagram);
|
|
3388
4952
|
clearSelection();
|
|
3389
4953
|
onDiagramChange?.(updatedDiagram);
|
|
3390
4954
|
onDelete?.(Array.from(selectedNodeIds), Array.from(selectedPipeIds));
|
|
3391
|
-
}, [
|
|
4955
|
+
}, [
|
|
4956
|
+
selection,
|
|
4957
|
+
localDiagram,
|
|
4958
|
+
selectionEnabled,
|
|
4959
|
+
clearSelection,
|
|
4960
|
+
onDiagramChange,
|
|
4961
|
+
onDelete,
|
|
4962
|
+
pushToHistory
|
|
4963
|
+
]);
|
|
3392
4964
|
const handleCopy = useCallback7(() => {
|
|
3393
4965
|
if (!selectionEnabled) return;
|
|
3394
4966
|
const { selectedNodeIds, selectedPipeIds } = selection;
|
|
@@ -3445,10 +5017,15 @@ function PIDCanvas({
|
|
|
3445
5017
|
}
|
|
3446
5018
|
onPipeClick?.(pipeId);
|
|
3447
5019
|
};
|
|
3448
|
-
const handleCanvasClick = () => {
|
|
5020
|
+
const handleCanvasClick = (e) => {
|
|
5021
|
+
const target = e.target;
|
|
5022
|
+
if (target.closest(".pipe-route-point")) {
|
|
5023
|
+
return;
|
|
5024
|
+
}
|
|
3449
5025
|
if (selectionEnabled) {
|
|
3450
5026
|
clearSelection();
|
|
3451
5027
|
}
|
|
5028
|
+
setSelectedWaypoint(null);
|
|
3452
5029
|
};
|
|
3453
5030
|
const handleDragOver = useCallback7(
|
|
3454
5031
|
(event) => {
|
|
@@ -3459,7 +5036,7 @@ function PIDCanvas({
|
|
|
3459
5036
|
const worldPos = screenToWorld(event.clientX, event.clientY);
|
|
3460
5037
|
setDragOverPosition(worldPos);
|
|
3461
5038
|
},
|
|
3462
|
-
[features.allowSymbolDrop, screenToWorld]
|
|
5039
|
+
[features.allowSymbolDrop, screenToWorld, svgRef]
|
|
3463
5040
|
);
|
|
3464
5041
|
const handleDrop = useCallback7(
|
|
3465
5042
|
(event) => {
|
|
@@ -3472,7 +5049,7 @@ function PIDCanvas({
|
|
|
3472
5049
|
const worldPos = screenToWorld(event.clientX, event.clientY);
|
|
3473
5050
|
onSymbolDrop?.(symbolId, worldPos);
|
|
3474
5051
|
},
|
|
3475
|
-
[features.allowSymbolDrop, screenToWorld, onSymbolDrop]
|
|
5052
|
+
[features.allowSymbolDrop, screenToWorld, onSymbolDrop, svgRef]
|
|
3476
5053
|
);
|
|
3477
5054
|
const handleDragLeave = useCallback7(() => {
|
|
3478
5055
|
setDragOverPosition(null);
|
|
@@ -3496,7 +5073,7 @@ function PIDCanvas({
|
|
|
3496
5073
|
const distance = Math.sqrt(
|
|
3497
5074
|
(worldPos.x - portPos.x) ** 2 + (worldPos.y - portPos.y) ** 2
|
|
3498
5075
|
);
|
|
3499
|
-
if (distance <
|
|
5076
|
+
if (distance < 15) {
|
|
3500
5077
|
foundPort = port.id;
|
|
3501
5078
|
foundNode = node.id;
|
|
3502
5079
|
break;
|
|
@@ -3513,9 +5090,11 @@ function PIDCanvas({
|
|
|
3513
5090
|
const { name } = diagram;
|
|
3514
5091
|
const viewBox = controlledViewBox;
|
|
3515
5092
|
const displayDiagram = localDiagram;
|
|
3516
|
-
|
|
5093
|
+
const selectedNode = selectionEnabled && selection.selectedNodeIds.size === 1 ? localDiagram.nodes.find((n) => selection.selectedNodeIds.has(n.id)) || null : null;
|
|
5094
|
+
return /* @__PURE__ */ jsxs13(
|
|
3517
5095
|
"div",
|
|
3518
5096
|
{
|
|
5097
|
+
ref: containerRef,
|
|
3519
5098
|
className: `pid-canvas ${className}`.trim(),
|
|
3520
5099
|
style: {
|
|
3521
5100
|
width: "100%",
|
|
@@ -3526,223 +5105,287 @@ function PIDCanvas({
|
|
|
3526
5105
|
...style
|
|
3527
5106
|
},
|
|
3528
5107
|
...props,
|
|
3529
|
-
children:
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
/* @__PURE__ */
|
|
3550
|
-
/* @__PURE__ */
|
|
3551
|
-
|
|
3552
|
-
/* @__PURE__ */
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
5108
|
+
children: [
|
|
5109
|
+
/* @__PURE__ */ jsxs13(
|
|
5110
|
+
"svg",
|
|
5111
|
+
{
|
|
5112
|
+
ref: svgRef,
|
|
5113
|
+
width: "100%",
|
|
5114
|
+
height: "100%",
|
|
5115
|
+
viewBox: `${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`,
|
|
5116
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
5117
|
+
style: {
|
|
5118
|
+
display: "block"
|
|
5119
|
+
},
|
|
5120
|
+
"aria-label": `P&ID diagram: ${name}`,
|
|
5121
|
+
role: "img",
|
|
5122
|
+
onClick: handleCanvasClick,
|
|
5123
|
+
onMouseMove: handleMouseMove,
|
|
5124
|
+
onDragOver: handleDragOver,
|
|
5125
|
+
onDrop: handleDrop,
|
|
5126
|
+
onDragLeave: handleDragLeave,
|
|
5127
|
+
children: [
|
|
5128
|
+
features.showGrid !== false ? /* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
5129
|
+
/* @__PURE__ */ jsxs13("defs", { children: [
|
|
5130
|
+
/* @__PURE__ */ jsx17("pattern", { id: "grid-minor", width: "5", height: "5", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx17("path", { d: "M 5 0 L 0 0 0 5", fill: "none", stroke: "#e5e7eb", strokeWidth: "0.5" }) }),
|
|
5131
|
+
/* @__PURE__ */ jsxs13("pattern", { id: "grid-major", width: "25", height: "25", patternUnits: "userSpaceOnUse", children: [
|
|
5132
|
+
/* @__PURE__ */ jsx17("rect", { width: "25", height: "25", fill: "url(#grid-minor)" }),
|
|
5133
|
+
/* @__PURE__ */ jsx17("path", { d: "M 25 0 L 0 0 0 25", fill: "none", stroke: "#d1d5db", strokeWidth: "1" })
|
|
5134
|
+
] })
|
|
5135
|
+
] }),
|
|
5136
|
+
/* @__PURE__ */ jsx17(
|
|
5137
|
+
"rect",
|
|
5138
|
+
{
|
|
5139
|
+
x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
|
|
5140
|
+
y: Math.floor(viewBox.y / 25) * 25 - viewBox.height,
|
|
5141
|
+
width: Math.ceil(viewBox.width * 3 / 25) * 25,
|
|
5142
|
+
height: Math.ceil(viewBox.height * 3 / 25) * 25,
|
|
5143
|
+
fill: "url(#grid-major)"
|
|
5144
|
+
}
|
|
5145
|
+
)
|
|
5146
|
+
] }) : /* @__PURE__ */ jsx17(
|
|
3557
5147
|
"rect",
|
|
3558
5148
|
{
|
|
3559
5149
|
x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
|
|
3560
5150
|
y: Math.floor(viewBox.y / 25) * 25 - viewBox.height,
|
|
3561
5151
|
width: Math.ceil(viewBox.width * 3 / 25) * 25,
|
|
3562
5152
|
height: Math.ceil(viewBox.height * 3 / 25) * 25,
|
|
3563
|
-
fill: "
|
|
5153
|
+
fill: features.backgroundColor ?? "#ffffff"
|
|
3564
5154
|
}
|
|
3565
|
-
)
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
{
|
|
3569
|
-
x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
|
|
3570
|
-
y: Math.floor(viewBox.y / 25) * 25 - viewBox.height,
|
|
3571
|
-
width: Math.ceil(viewBox.width * 3 / 25) * 25,
|
|
3572
|
-
height: Math.ceil(viewBox.height * 3 / 25) * 25,
|
|
3573
|
-
fill: features.backgroundColor ?? "#ffffff"
|
|
3574
|
-
}
|
|
3575
|
-
),
|
|
3576
|
-
/* @__PURE__ */ jsx16(
|
|
3577
|
-
PipeRenderer,
|
|
3578
|
-
{
|
|
3579
|
-
pipes: displayDiagram.pipes,
|
|
3580
|
-
selectedPipeIds: selectionEnabled ? selection.selectedPipeIds : void 0,
|
|
3581
|
-
onPipeClick: selectionEnabled ? handlePipeClick : void 0,
|
|
3582
|
-
enableWaypointEditing: false,
|
|
3583
|
-
onWaypointDragStart: void 0,
|
|
3584
|
-
editingPipeId: null,
|
|
3585
|
-
draggingWaypointIndex: null,
|
|
3586
|
-
waypointDragOffset: void 0,
|
|
3587
|
-
onPipeSegmentClick: void 0
|
|
3588
|
-
}
|
|
3589
|
-
),
|
|
3590
|
-
/* @__PURE__ */ jsx16(
|
|
3591
|
-
NodeRenderer,
|
|
3592
|
-
{
|
|
3593
|
-
nodes: displayDiagram.nodes,
|
|
3594
|
-
selectedNodeIds: selectionEnabled ? selection.selectedNodeIds : void 0,
|
|
3595
|
-
onNodeClick: selectionEnabled || features.connectionMode ? handleNodeClick : void 0,
|
|
3596
|
-
onNodeDoubleClick: selectionEnabled ? handleNodeDoubleClick : void 0,
|
|
3597
|
-
enableDrag: dragEnabled && !isConnecting,
|
|
3598
|
-
onNodeDragStart: dragEnabled && !isConnecting ? handleNodeDragStart : void 0,
|
|
3599
|
-
draggingNodeId: dragState.draggedId,
|
|
3600
|
-
dragOffset: dragState.offset
|
|
3601
|
-
}
|
|
3602
|
-
),
|
|
3603
|
-
(features.editPipeRoutes ?? false) && /* @__PURE__ */ jsx16(
|
|
3604
|
-
PipeRenderer,
|
|
3605
|
-
{
|
|
3606
|
-
pipes: displayDiagram.pipes,
|
|
3607
|
-
selectedPipeIds: selectionEnabled ? selection.selectedPipeIds : void 0,
|
|
3608
|
-
onPipeClick: void 0,
|
|
3609
|
-
enableWaypointEditing: true,
|
|
3610
|
-
onWaypointDragStart: handleWaypointDragStart,
|
|
3611
|
-
editingPipeId: waypointDragState.draggedId?.split(":")[0] || null,
|
|
3612
|
-
draggingWaypointIndex: waypointDragState.draggedId ? parseInt(waypointDragState.draggedId.split(":")[1], 10) : null,
|
|
3613
|
-
waypointDragOffset: waypointDragState.offset,
|
|
3614
|
-
onPipeSegmentClick: handlePipeSegmentClick
|
|
3615
|
-
}
|
|
3616
|
-
),
|
|
3617
|
-
telemetryEnabled && telemetry && /* @__PURE__ */ jsx16("g", { id: "layer-telemetry", children: displayDiagram.nodes.map((node) => {
|
|
3618
|
-
const binding = telemetry.get(node.id);
|
|
3619
|
-
if (!binding) return null;
|
|
3620
|
-
const symbol = getSymbolDefinition(node.symbolId);
|
|
3621
|
-
if (!symbol) return null;
|
|
3622
|
-
const overlayY = node.transform.y - symbol.viewBox.height / 2 - 10;
|
|
3623
|
-
return /* @__PURE__ */ jsx16(
|
|
3624
|
-
DataOverlay,
|
|
5155
|
+
),
|
|
5156
|
+
/* @__PURE__ */ jsx17(
|
|
5157
|
+
PipeRenderer,
|
|
3625
5158
|
{
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
"circle",
|
|
3636
|
-
{
|
|
3637
|
-
cx: dragOverPosition.x,
|
|
3638
|
-
cy: dragOverPosition.y,
|
|
3639
|
-
r: 20,
|
|
3640
|
-
fill: "#3b82f6",
|
|
3641
|
-
opacity: 0.3,
|
|
3642
|
-
stroke: "#3b82f6",
|
|
3643
|
-
strokeWidth: 2,
|
|
3644
|
-
pointerEvents: "none"
|
|
3645
|
-
}
|
|
3646
|
-
),
|
|
3647
|
-
isConnecting && connectionSource && connectionCursor && /* @__PURE__ */ jsx16("g", { id: "connection-preview", pointerEvents: "none", children: (() => {
|
|
3648
|
-
const sourceNode = displayDiagram.nodes.find((n) => n.id === connectionSource);
|
|
3649
|
-
if (!sourceNode) return null;
|
|
3650
|
-
const symbol = getSymbolDefinition(sourceNode.symbolId);
|
|
3651
|
-
let lineStartX = sourceNode.transform.x;
|
|
3652
|
-
let lineStartY = sourceNode.transform.y;
|
|
3653
|
-
if (connectionSourcePort && symbol?.ports) {
|
|
3654
|
-
const port = symbol.ports.find((p) => p.id === connectionSourcePort);
|
|
3655
|
-
if (port) {
|
|
3656
|
-
const portPos = getPortWorldPosition(sourceNode, connectionSourcePort);
|
|
3657
|
-
if (portPos) {
|
|
3658
|
-
lineStartX = portPos.x;
|
|
3659
|
-
lineStartY = portPos.y;
|
|
3660
|
-
}
|
|
5159
|
+
pipes: displayDiagram.pipes,
|
|
5160
|
+
selectedPipeIds: selectionEnabled ? selection.selectedPipeIds : void 0,
|
|
5161
|
+
onPipeClick: selectionEnabled ? handlePipeClick : void 0,
|
|
5162
|
+
enableWaypointEditing: false,
|
|
5163
|
+
onWaypointDragStart: void 0,
|
|
5164
|
+
editingPipeId: null,
|
|
5165
|
+
draggingWaypointIndex: null,
|
|
5166
|
+
waypointDragOffset: void 0,
|
|
5167
|
+
onPipeSegmentClick: void 0
|
|
3661
5168
|
}
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
const symbol = getSymbolDefinition(node.symbolId);
|
|
3703
|
-
if (!symbol?.ports) return null;
|
|
3704
|
-
return symbol.ports.map((port) => {
|
|
3705
|
-
const portPos = getPortWorldPosition(node, port.id);
|
|
3706
|
-
if (!portPos) return null;
|
|
3707
|
-
const isHovered = hoveredPort === port.id && hoveredNode === node.id;
|
|
3708
|
-
const isSourcePort = node.id === connectionSource && port.id === connectionSourcePort;
|
|
3709
|
-
return /* @__PURE__ */ jsx16(
|
|
3710
|
-
"circle",
|
|
5169
|
+
),
|
|
5170
|
+
/* @__PURE__ */ jsx17(
|
|
5171
|
+
NodeRenderer,
|
|
5172
|
+
{
|
|
5173
|
+
nodes: displayDiagram.nodes,
|
|
5174
|
+
selectedNodeIds: selectionEnabled ? selection.selectedNodeIds : void 0,
|
|
5175
|
+
onNodeClick: selectionEnabled || features.connectionMode ? handleNodeClick : void 0,
|
|
5176
|
+
onNodeDoubleClick: selectionEnabled ? handleNodeDoubleClick : void 0,
|
|
5177
|
+
enableDrag: dragEnabled && !isConnecting,
|
|
5178
|
+
onNodeDragStart: dragEnabled && !isConnecting ? handleNodeDragStart : void 0,
|
|
5179
|
+
draggingNodeId: dragState.draggedId,
|
|
5180
|
+
dragOffset: dragState.offset
|
|
5181
|
+
}
|
|
5182
|
+
),
|
|
5183
|
+
(features.editPipeRoutes ?? false) && /* @__PURE__ */ jsx17(
|
|
5184
|
+
PipeRenderer,
|
|
5185
|
+
{
|
|
5186
|
+
pipes: displayDiagram.pipes,
|
|
5187
|
+
selectedPipeIds: selectionEnabled ? selection.selectedPipeIds : void 0,
|
|
5188
|
+
onPipeClick: void 0,
|
|
5189
|
+
enableWaypointEditing: true,
|
|
5190
|
+
onWaypointClick: handleWaypointClick,
|
|
5191
|
+
onWaypointDragStart: handleWaypointDragStart,
|
|
5192
|
+
selectedWaypointPipeId: selectedWaypoint?.pipeId || null,
|
|
5193
|
+
selectedWaypointIndex: selectedWaypoint?.pointIndex ?? null,
|
|
5194
|
+
editingPipeId: waypointDragState.draggedId?.split(":")[0] || null,
|
|
5195
|
+
draggingWaypointIndex: waypointDragState.draggedId ? parseInt(waypointDragState.draggedId.split(":")[1], 10) : null,
|
|
5196
|
+
waypointDragOffset: waypointDragState.offset,
|
|
5197
|
+
onPipeSegmentClick: handlePipeSegmentClick
|
|
5198
|
+
}
|
|
5199
|
+
),
|
|
5200
|
+
telemetryEnabled && telemetry && /* @__PURE__ */ jsx17("g", { id: "layer-telemetry", children: displayDiagram.nodes.map((node) => {
|
|
5201
|
+
const binding = telemetry.get(node.id);
|
|
5202
|
+
if (!binding) return null;
|
|
5203
|
+
const symbol = getSymbolDefinition(node.symbolId);
|
|
5204
|
+
if (!symbol) return null;
|
|
5205
|
+
const overlayX = node.transform.x + symbol.viewBox.width / 2;
|
|
5206
|
+
const overlayY = node.transform.y + symbol.viewBox.height + 50;
|
|
5207
|
+
return /* @__PURE__ */ jsx17(
|
|
5208
|
+
DataOverlay,
|
|
3711
5209
|
{
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
strokeWidth: isHovered || isSourcePort ? 2 : 1,
|
|
3718
|
-
opacity: isHovered || isSourcePort ? 1 : 0.6
|
|
5210
|
+
nodeId: node.id,
|
|
5211
|
+
x: overlayX,
|
|
5212
|
+
y: overlayY,
|
|
5213
|
+
telemetry: binding,
|
|
5214
|
+
scale: features.telemetryScale ?? 1
|
|
3719
5215
|
},
|
|
3720
|
-
|
|
5216
|
+
`telemetry-${node.id}`
|
|
3721
5217
|
);
|
|
3722
|
-
})
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
5218
|
+
}) }),
|
|
5219
|
+
dragOverPosition && /* @__PURE__ */ jsx17(
|
|
5220
|
+
"circle",
|
|
5221
|
+
{
|
|
5222
|
+
cx: dragOverPosition.x,
|
|
5223
|
+
cy: dragOverPosition.y,
|
|
5224
|
+
r: 20,
|
|
5225
|
+
fill: "#3b82f6",
|
|
5226
|
+
opacity: 0.3,
|
|
5227
|
+
stroke: "#3b82f6",
|
|
5228
|
+
strokeWidth: 2,
|
|
5229
|
+
pointerEvents: "none"
|
|
5230
|
+
}
|
|
5231
|
+
),
|
|
5232
|
+
isConnecting && connectionSource && connectionCursor && /* @__PURE__ */ jsx17("g", { id: "connection-preview", pointerEvents: "none", children: (() => {
|
|
5233
|
+
const sourceNode = displayDiagram.nodes.find((n) => n.id === connectionSource);
|
|
5234
|
+
if (!sourceNode) return null;
|
|
5235
|
+
const symbol = getSymbolDefinition(sourceNode.symbolId);
|
|
5236
|
+
let lineStartX = sourceNode.transform.x;
|
|
5237
|
+
let lineStartY = sourceNode.transform.y;
|
|
5238
|
+
if (connectionSourcePort && symbol?.ports) {
|
|
5239
|
+
const port = symbol.ports.find((p) => p.id === connectionSourcePort);
|
|
5240
|
+
if (port) {
|
|
5241
|
+
const portPos = getPortWorldPosition(sourceNode, connectionSourcePort);
|
|
5242
|
+
if (portPos) {
|
|
5243
|
+
lineStartX = portPos.x;
|
|
5244
|
+
lineStartY = portPos.y;
|
|
5245
|
+
}
|
|
5246
|
+
}
|
|
5247
|
+
}
|
|
5248
|
+
return /* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
5249
|
+
/* @__PURE__ */ jsx17(
|
|
5250
|
+
"circle",
|
|
5251
|
+
{
|
|
5252
|
+
cx: lineStartX,
|
|
5253
|
+
cy: lineStartY,
|
|
5254
|
+
r: 30,
|
|
5255
|
+
fill: "none",
|
|
5256
|
+
stroke: "#10b981",
|
|
5257
|
+
strokeWidth: 3,
|
|
5258
|
+
opacity: 0.6
|
|
5259
|
+
}
|
|
5260
|
+
),
|
|
5261
|
+
/* @__PURE__ */ jsx17(
|
|
5262
|
+
"line",
|
|
5263
|
+
{
|
|
5264
|
+
x1: lineStartX,
|
|
5265
|
+
y1: lineStartY,
|
|
5266
|
+
x2: connectionCursor.x,
|
|
5267
|
+
y2: connectionCursor.y,
|
|
5268
|
+
stroke: "#10b981",
|
|
5269
|
+
strokeWidth: 2,
|
|
5270
|
+
strokeDasharray: "5,5",
|
|
5271
|
+
opacity: 0.8
|
|
5272
|
+
}
|
|
5273
|
+
),
|
|
5274
|
+
/* @__PURE__ */ jsx17(
|
|
5275
|
+
"circle",
|
|
5276
|
+
{
|
|
5277
|
+
cx: connectionCursor.x,
|
|
5278
|
+
cy: connectionCursor.y,
|
|
5279
|
+
r: 8,
|
|
5280
|
+
fill: "#10b981",
|
|
5281
|
+
opacity: 0.6
|
|
5282
|
+
}
|
|
5283
|
+
)
|
|
5284
|
+
] });
|
|
5285
|
+
})() }),
|
|
5286
|
+
features.connectionMode && /* @__PURE__ */ jsx17("g", { id: "port-indicators", children: displayDiagram.nodes.map((node) => {
|
|
5287
|
+
const symbol = getSymbolDefinition(node.symbolId);
|
|
5288
|
+
if (!symbol?.ports) return null;
|
|
5289
|
+
return symbol.ports.map((port) => {
|
|
5290
|
+
const portPos = getPortWorldPosition(node, port.id);
|
|
5291
|
+
if (!portPos) return null;
|
|
5292
|
+
const isHovered = hoveredPort === port.id && hoveredNode === node.id;
|
|
5293
|
+
const isSourcePort = node.id === connectionSource && port.id === connectionSourcePort;
|
|
5294
|
+
return /* @__PURE__ */ jsxs13("g", { children: [
|
|
5295
|
+
/* @__PURE__ */ jsx17(
|
|
5296
|
+
"circle",
|
|
5297
|
+
{
|
|
5298
|
+
cx: portPos.x,
|
|
5299
|
+
cy: portPos.y,
|
|
5300
|
+
r: 15,
|
|
5301
|
+
fill: "transparent",
|
|
5302
|
+
style: { cursor: "pointer" },
|
|
5303
|
+
pointerEvents: "auto",
|
|
5304
|
+
onClick: (e) => {
|
|
5305
|
+
e.stopPropagation();
|
|
5306
|
+
if (isConnecting && connectionSource) {
|
|
5307
|
+
if (connectionSource !== node.id) {
|
|
5308
|
+
onPipeCreated?.(
|
|
5309
|
+
connectionSource,
|
|
5310
|
+
node.id,
|
|
5311
|
+
connectionSourcePort || void 0,
|
|
5312
|
+
port.id
|
|
5313
|
+
);
|
|
5314
|
+
setIsConnecting(false);
|
|
5315
|
+
setConnectionSource(null);
|
|
5316
|
+
setConnectionSourcePort(null);
|
|
5317
|
+
setConnectionCursor(null);
|
|
5318
|
+
setHoveredPort(null);
|
|
5319
|
+
}
|
|
5320
|
+
} else {
|
|
5321
|
+
setIsConnecting(true);
|
|
5322
|
+
setConnectionSource(node.id);
|
|
5323
|
+
setConnectionSourcePort(port.id);
|
|
5324
|
+
}
|
|
5325
|
+
}
|
|
5326
|
+
}
|
|
5327
|
+
),
|
|
5328
|
+
/* @__PURE__ */ jsx17(
|
|
5329
|
+
"circle",
|
|
5330
|
+
{
|
|
5331
|
+
cx: portPos.x,
|
|
5332
|
+
cy: portPos.y,
|
|
5333
|
+
r: isHovered ? 8 : 5,
|
|
5334
|
+
fill: isSourcePort ? "#10b981" : isHovered ? "#3b82f6" : "#94a3b8",
|
|
5335
|
+
stroke: isSourcePort ? "#059669" : isHovered ? "#2563eb" : "#64748b",
|
|
5336
|
+
strokeWidth: isHovered || isSourcePort ? 2 : 1,
|
|
5337
|
+
opacity: isHovered || isSourcePort ? 1 : 0.6,
|
|
5338
|
+
pointerEvents: "none"
|
|
5339
|
+
}
|
|
5340
|
+
)
|
|
5341
|
+
] }, `${node.id}-${port.id}`);
|
|
5342
|
+
});
|
|
5343
|
+
}) })
|
|
5344
|
+
]
|
|
5345
|
+
}
|
|
5346
|
+
),
|
|
5347
|
+
features.dragNodes && /* @__PURE__ */ jsx17(
|
|
5348
|
+
PositionPanel,
|
|
5349
|
+
{
|
|
5350
|
+
selectedNode,
|
|
5351
|
+
selectedWaypoint: selectedWaypoint ? {
|
|
5352
|
+
pipeId: selectedWaypoint.pipeId,
|
|
5353
|
+
pointIndex: selectedWaypoint.pointIndex,
|
|
5354
|
+
position: localDiagram.pipes.find((p) => p.id === selectedWaypoint.pipeId)?.routePoints[selectedWaypoint.pointIndex] || { x: 0, y: 0 }
|
|
5355
|
+
} : null,
|
|
5356
|
+
onPositionChange: handlePositionChange,
|
|
5357
|
+
onWaypointPositionChange: handleWaypointPositionChange,
|
|
5358
|
+
position: "top-right"
|
|
5359
|
+
}
|
|
5360
|
+
)
|
|
5361
|
+
]
|
|
3727
5362
|
}
|
|
3728
5363
|
);
|
|
3729
5364
|
}
|
|
3730
5365
|
|
|
3731
5366
|
// src/components/SymbolLibrary/SymbolLibrary.tsx
|
|
3732
|
-
import { useState as
|
|
3733
|
-
import { jsx as
|
|
5367
|
+
import { useState as useState13 } from "react";
|
|
5368
|
+
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3734
5369
|
function SymbolLibrary({
|
|
3735
5370
|
className = "",
|
|
3736
5371
|
onSymbolDragStart,
|
|
3737
5372
|
showCategories = true,
|
|
3738
5373
|
categories = ["Valves", "Pumps", "Tanks", "Instruments", "Displays"]
|
|
3739
5374
|
}) {
|
|
3740
|
-
const [selectedCategory, setSelectedCategory] =
|
|
3741
|
-
const [searchQuery, setSearchQuery] =
|
|
5375
|
+
const [selectedCategory, setSelectedCategory] = useState13("all");
|
|
5376
|
+
const [searchQuery, setSearchQuery] = useState13("");
|
|
3742
5377
|
const symbolIds = getAvailableSymbols();
|
|
3743
5378
|
const allSymbols = symbolIds.map((id) => getSymbolDefinition(id)).filter((symbol) => symbol !== void 0);
|
|
5379
|
+
const categoryMap = {
|
|
5380
|
+
Valves: "valve",
|
|
5381
|
+
Pumps: "pump",
|
|
5382
|
+
Tanks: "vessel",
|
|
5383
|
+
Instruments: "instrument",
|
|
5384
|
+
Displays: "display"
|
|
5385
|
+
};
|
|
3744
5386
|
const filteredSymbols = allSymbols.filter((symbol) => {
|
|
3745
|
-
const
|
|
5387
|
+
const actualCategory = categoryMap[selectedCategory] || selectedCategory;
|
|
5388
|
+
const matchesCategory = selectedCategory === "all" || symbol.category === actualCategory;
|
|
3746
5389
|
const matchesSearch = searchQuery === "" || symbol.name.toLowerCase().includes(searchQuery.toLowerCase()) || symbol.id.toLowerCase().includes(searchQuery.toLowerCase());
|
|
3747
5390
|
return matchesCategory && matchesSearch;
|
|
3748
5391
|
});
|
|
@@ -3751,9 +5394,9 @@ function SymbolLibrary({
|
|
|
3751
5394
|
event.dataTransfer.effectAllowed = "copy";
|
|
3752
5395
|
onSymbolDragStart?.(symbol.id, event);
|
|
3753
5396
|
};
|
|
3754
|
-
return /* @__PURE__ */
|
|
3755
|
-
/* @__PURE__ */
|
|
3756
|
-
/* @__PURE__ */
|
|
5397
|
+
return /* @__PURE__ */ jsxs14("div", { className: `symbol-library ${className}`.trim(), style: styles.container, children: [
|
|
5398
|
+
/* @__PURE__ */ jsx18("div", { style: styles.header, children: /* @__PURE__ */ jsx18("h3", { style: styles.title, children: "Symbol Library" }) }),
|
|
5399
|
+
/* @__PURE__ */ jsx18("div", { style: styles.searchContainer, children: /* @__PURE__ */ jsx18(
|
|
3757
5400
|
"input",
|
|
3758
5401
|
{
|
|
3759
5402
|
type: "text",
|
|
@@ -3763,8 +5406,8 @@ function SymbolLibrary({
|
|
|
3763
5406
|
style: styles.searchInput
|
|
3764
5407
|
}
|
|
3765
5408
|
) }),
|
|
3766
|
-
showCategories && /* @__PURE__ */
|
|
3767
|
-
/* @__PURE__ */
|
|
5409
|
+
showCategories && /* @__PURE__ */ jsxs14("div", { style: styles.categories, children: [
|
|
5410
|
+
/* @__PURE__ */ jsx18(
|
|
3768
5411
|
"button",
|
|
3769
5412
|
{
|
|
3770
5413
|
onClick: () => setSelectedCategory("all"),
|
|
@@ -3775,7 +5418,7 @@ function SymbolLibrary({
|
|
|
3775
5418
|
children: "All"
|
|
3776
5419
|
}
|
|
3777
5420
|
),
|
|
3778
|
-
categories.map((category) => /* @__PURE__ */
|
|
5421
|
+
categories.map((category) => /* @__PURE__ */ jsx18(
|
|
3779
5422
|
"button",
|
|
3780
5423
|
{
|
|
3781
5424
|
onClick: () => setSelectedCategory(category),
|
|
@@ -3788,7 +5431,7 @@ function SymbolLibrary({
|
|
|
3788
5431
|
category
|
|
3789
5432
|
))
|
|
3790
5433
|
] }),
|
|
3791
|
-
/* @__PURE__ */
|
|
5434
|
+
/* @__PURE__ */ jsx18("div", { style: styles.symbolGrid, children: filteredSymbols.length === 0 ? /* @__PURE__ */ jsx18("div", { style: styles.emptyState, children: "No symbols found" }) : filteredSymbols.map((symbol) => /* @__PURE__ */ jsxs14(
|
|
3792
5435
|
"div",
|
|
3793
5436
|
{
|
|
3794
5437
|
draggable: true,
|
|
@@ -3796,15 +5439,15 @@ function SymbolLibrary({
|
|
|
3796
5439
|
style: styles.symbolCard,
|
|
3797
5440
|
title: symbol.metadata?.description || symbol.name,
|
|
3798
5441
|
children: [
|
|
3799
|
-
/* @__PURE__ */
|
|
5442
|
+
/* @__PURE__ */ jsx18("div", { style: styles.symbolPreview, children: /* @__PURE__ */ jsx18(
|
|
3800
5443
|
"svg",
|
|
3801
5444
|
{
|
|
3802
5445
|
viewBox: `${symbol.viewBox.x} ${symbol.viewBox.y} ${symbol.viewBox.width} ${symbol.viewBox.height}`,
|
|
3803
5446
|
style: styles.symbolSvg,
|
|
3804
|
-
children: /* @__PURE__ */
|
|
5447
|
+
children: /* @__PURE__ */ jsx18("g", { dangerouslySetInnerHTML: { __html: symbol.svgContent } })
|
|
3805
5448
|
}
|
|
3806
5449
|
) }),
|
|
3807
|
-
/* @__PURE__ */
|
|
5450
|
+
/* @__PURE__ */ jsx18("div", { style: styles.symbolName, children: symbol.name })
|
|
3808
5451
|
]
|
|
3809
5452
|
},
|
|
3810
5453
|
symbol.id
|
|
@@ -3913,7 +5556,7 @@ var styles = {
|
|
|
3913
5556
|
};
|
|
3914
5557
|
|
|
3915
5558
|
// src/components/NodeConfigPanel/NodeConfigPanel.tsx
|
|
3916
|
-
import { Fragment as Fragment6, jsx as
|
|
5559
|
+
import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3917
5560
|
function NodeConfigPanel({
|
|
3918
5561
|
node,
|
|
3919
5562
|
binding,
|
|
@@ -3932,15 +5575,15 @@ function NodeConfigPanel({
|
|
|
3932
5575
|
padding: "20px",
|
|
3933
5576
|
...style
|
|
3934
5577
|
};
|
|
3935
|
-
return /* @__PURE__ */
|
|
3936
|
-
/* @__PURE__ */
|
|
5578
|
+
return /* @__PURE__ */ jsxs15("div", { className, style: defaultStyle, children: [
|
|
5579
|
+
/* @__PURE__ */ jsxs15("h2", { style: { margin: "0 0 16px 0", fontSize: "1rem", fontWeight: 600 }, children: [
|
|
3937
5580
|
"Configure: ",
|
|
3938
5581
|
node.id
|
|
3939
5582
|
] }),
|
|
3940
|
-
/* @__PURE__ */
|
|
3941
|
-
/* @__PURE__ */
|
|
3942
|
-
/* @__PURE__ */
|
|
3943
|
-
/* @__PURE__ */
|
|
5583
|
+
/* @__PURE__ */ jsxs15("div", { style: { marginBottom: "20px" }, children: [
|
|
5584
|
+
/* @__PURE__ */ jsx19("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Node Settings" }),
|
|
5585
|
+
/* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label:" }),
|
|
5586
|
+
/* @__PURE__ */ jsx19(
|
|
3944
5587
|
"input",
|
|
3945
5588
|
{
|
|
3946
5589
|
type: "text",
|
|
@@ -3956,10 +5599,10 @@ function NodeConfigPanel({
|
|
|
3956
5599
|
}
|
|
3957
5600
|
}
|
|
3958
5601
|
),
|
|
3959
|
-
/* @__PURE__ */
|
|
3960
|
-
/* @__PURE__ */
|
|
3961
|
-
/* @__PURE__ */
|
|
3962
|
-
/* @__PURE__ */
|
|
5602
|
+
/* @__PURE__ */ jsxs15("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
|
|
5603
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
5604
|
+
/* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset X:" }),
|
|
5605
|
+
/* @__PURE__ */ jsx19(
|
|
3963
5606
|
"input",
|
|
3964
5607
|
{
|
|
3965
5608
|
type: "number",
|
|
@@ -3980,9 +5623,9 @@ function NodeConfigPanel({
|
|
|
3980
5623
|
}
|
|
3981
5624
|
)
|
|
3982
5625
|
] }),
|
|
3983
|
-
/* @__PURE__ */
|
|
3984
|
-
/* @__PURE__ */
|
|
3985
|
-
/* @__PURE__ */
|
|
5626
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
5627
|
+
/* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset Y:" }),
|
|
5628
|
+
/* @__PURE__ */ jsx19(
|
|
3986
5629
|
"input",
|
|
3987
5630
|
{
|
|
3988
5631
|
type: "number",
|
|
@@ -4004,9 +5647,9 @@ function NodeConfigPanel({
|
|
|
4004
5647
|
)
|
|
4005
5648
|
] })
|
|
4006
5649
|
] }),
|
|
4007
|
-
/* @__PURE__ */
|
|
4008
|
-
/* @__PURE__ */
|
|
4009
|
-
/* @__PURE__ */
|
|
5650
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
5651
|
+
/* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Font Size:" }),
|
|
5652
|
+
/* @__PURE__ */ jsx19(
|
|
4010
5653
|
"input",
|
|
4011
5654
|
{
|
|
4012
5655
|
type: "number",
|
|
@@ -4026,9 +5669,9 @@ function NodeConfigPanel({
|
|
|
4026
5669
|
}
|
|
4027
5670
|
)
|
|
4028
5671
|
] }),
|
|
4029
|
-
/* @__PURE__ */
|
|
4030
|
-
/* @__PURE__ */
|
|
4031
|
-
/* @__PURE__ */
|
|
5672
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
5673
|
+
/* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Rotation (degrees):" }),
|
|
5674
|
+
/* @__PURE__ */ jsx19(
|
|
4032
5675
|
"input",
|
|
4033
5676
|
{
|
|
4034
5677
|
type: "number",
|
|
@@ -4053,9 +5696,9 @@ function NodeConfigPanel({
|
|
|
4053
5696
|
)
|
|
4054
5697
|
] })
|
|
4055
5698
|
] }),
|
|
4056
|
-
/* @__PURE__ */
|
|
4057
|
-
/* @__PURE__ */
|
|
4058
|
-
!binding ? /* @__PURE__ */
|
|
5699
|
+
/* @__PURE__ */ jsxs15("div", { style: { marginBottom: "20px" }, children: [
|
|
5700
|
+
/* @__PURE__ */ jsx19("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Telemetry Data" }),
|
|
5701
|
+
!binding ? /* @__PURE__ */ jsx19(
|
|
4059
5702
|
"button",
|
|
4060
5703
|
{
|
|
4061
5704
|
onClick: () => {
|
|
@@ -4098,9 +5741,9 @@ function NodeConfigPanel({
|
|
|
4098
5741
|
},
|
|
4099
5742
|
children: "+ Add Telemetry"
|
|
4100
5743
|
}
|
|
4101
|
-
) : /* @__PURE__ */
|
|
4102
|
-
/* @__PURE__ */
|
|
4103
|
-
/* @__PURE__ */
|
|
5744
|
+
) : /* @__PURE__ */ jsxs15(Fragment6, { children: [
|
|
5745
|
+
/* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Initial Value:" }),
|
|
5746
|
+
/* @__PURE__ */ jsx19(
|
|
4104
5747
|
"input",
|
|
4105
5748
|
{
|
|
4106
5749
|
type: "number",
|
|
@@ -4122,8 +5765,8 @@ function NodeConfigPanel({
|
|
|
4122
5765
|
}
|
|
4123
5766
|
}
|
|
4124
5767
|
),
|
|
4125
|
-
/* @__PURE__ */
|
|
4126
|
-
/* @__PURE__ */
|
|
5768
|
+
/* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Unit:" }),
|
|
5769
|
+
/* @__PURE__ */ jsx19(
|
|
4127
5770
|
"input",
|
|
4128
5771
|
{
|
|
4129
5772
|
type: "text",
|
|
@@ -4145,8 +5788,8 @@ function NodeConfigPanel({
|
|
|
4145
5788
|
}
|
|
4146
5789
|
}
|
|
4147
5790
|
),
|
|
4148
|
-
/* @__PURE__ */
|
|
4149
|
-
/* @__PURE__ */
|
|
5791
|
+
/* @__PURE__ */ jsxs15("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
|
|
5792
|
+
/* @__PURE__ */ jsx19(
|
|
4150
5793
|
"input",
|
|
4151
5794
|
{
|
|
4152
5795
|
type: "checkbox",
|
|
@@ -4168,8 +5811,8 @@ function NodeConfigPanel({
|
|
|
4168
5811
|
),
|
|
4169
5812
|
"Show Sparkline"
|
|
4170
5813
|
] }),
|
|
4171
|
-
/* @__PURE__ */
|
|
4172
|
-
/* @__PURE__ */
|
|
5814
|
+
/* @__PURE__ */ jsxs15("div", { style: { marginTop: "12px" }, children: [
|
|
5815
|
+
/* @__PURE__ */ jsx19(
|
|
4173
5816
|
"label",
|
|
4174
5817
|
{
|
|
4175
5818
|
style: {
|
|
@@ -4181,10 +5824,10 @@ function NodeConfigPanel({
|
|
|
4181
5824
|
children: "Telemetry Position Offset:"
|
|
4182
5825
|
}
|
|
4183
5826
|
),
|
|
4184
|
-
/* @__PURE__ */
|
|
4185
|
-
/* @__PURE__ */
|
|
4186
|
-
/* @__PURE__ */
|
|
4187
|
-
/* @__PURE__ */
|
|
5827
|
+
/* @__PURE__ */ jsxs15("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
|
|
5828
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
5829
|
+
/* @__PURE__ */ jsx19("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "X Offset:" }),
|
|
5830
|
+
/* @__PURE__ */ jsx19(
|
|
4188
5831
|
"input",
|
|
4189
5832
|
{
|
|
4190
5833
|
type: "number",
|
|
@@ -4211,9 +5854,9 @@ function NodeConfigPanel({
|
|
|
4211
5854
|
}
|
|
4212
5855
|
)
|
|
4213
5856
|
] }),
|
|
4214
|
-
/* @__PURE__ */
|
|
4215
|
-
/* @__PURE__ */
|
|
4216
|
-
/* @__PURE__ */
|
|
5857
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
5858
|
+
/* @__PURE__ */ jsx19("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Y Offset:" }),
|
|
5859
|
+
/* @__PURE__ */ jsx19(
|
|
4217
5860
|
"input",
|
|
4218
5861
|
{
|
|
4219
5862
|
type: "number",
|
|
@@ -4241,8 +5884,8 @@ function NodeConfigPanel({
|
|
|
4241
5884
|
)
|
|
4242
5885
|
] })
|
|
4243
5886
|
] }),
|
|
4244
|
-
/* @__PURE__ */
|
|
4245
|
-
/* @__PURE__ */
|
|
5887
|
+
/* @__PURE__ */ jsxs15("div", { style: { marginTop: "16px" }, children: [
|
|
5888
|
+
/* @__PURE__ */ jsx19(
|
|
4246
5889
|
"label",
|
|
4247
5890
|
{
|
|
4248
5891
|
style: {
|
|
@@ -4254,10 +5897,10 @@ function NodeConfigPanel({
|
|
|
4254
5897
|
children: "Display Colors:"
|
|
4255
5898
|
}
|
|
4256
5899
|
),
|
|
4257
|
-
/* @__PURE__ */
|
|
4258
|
-
/* @__PURE__ */
|
|
4259
|
-
/* @__PURE__ */
|
|
4260
|
-
/* @__PURE__ */
|
|
5900
|
+
/* @__PURE__ */ jsxs15("div", { style: { marginBottom: "8px" }, children: [
|
|
5901
|
+
/* @__PURE__ */ jsx19("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Text Color:" }),
|
|
5902
|
+
/* @__PURE__ */ jsxs15("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
|
|
5903
|
+
/* @__PURE__ */ jsx19(
|
|
4261
5904
|
"input",
|
|
4262
5905
|
{
|
|
4263
5906
|
type: "color",
|
|
@@ -4283,7 +5926,7 @@ function NodeConfigPanel({
|
|
|
4283
5926
|
}
|
|
4284
5927
|
}
|
|
4285
5928
|
),
|
|
4286
|
-
/* @__PURE__ */
|
|
5929
|
+
/* @__PURE__ */ jsx19(
|
|
4287
5930
|
"input",
|
|
4288
5931
|
{
|
|
4289
5932
|
type: "text",
|
|
@@ -4313,10 +5956,10 @@ function NodeConfigPanel({
|
|
|
4313
5956
|
)
|
|
4314
5957
|
] })
|
|
4315
5958
|
] }),
|
|
4316
|
-
binding.display?.showSparkline && /* @__PURE__ */
|
|
4317
|
-
/* @__PURE__ */
|
|
4318
|
-
/* @__PURE__ */
|
|
4319
|
-
/* @__PURE__ */
|
|
5959
|
+
binding.display?.showSparkline && /* @__PURE__ */ jsxs15("div", { style: { marginBottom: "8px" }, children: [
|
|
5960
|
+
/* @__PURE__ */ jsx19("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Sparkline Color:" }),
|
|
5961
|
+
/* @__PURE__ */ jsxs15("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
|
|
5962
|
+
/* @__PURE__ */ jsx19(
|
|
4320
5963
|
"input",
|
|
4321
5964
|
{
|
|
4322
5965
|
type: "color",
|
|
@@ -4342,7 +5985,7 @@ function NodeConfigPanel({
|
|
|
4342
5985
|
}
|
|
4343
5986
|
}
|
|
4344
5987
|
),
|
|
4345
|
-
/* @__PURE__ */
|
|
5988
|
+
/* @__PURE__ */ jsx19(
|
|
4346
5989
|
"input",
|
|
4347
5990
|
{
|
|
4348
5991
|
type: "text",
|
|
@@ -4372,9 +6015,9 @@ function NodeConfigPanel({
|
|
|
4372
6015
|
)
|
|
4373
6016
|
] })
|
|
4374
6017
|
] }),
|
|
4375
|
-
/* @__PURE__ */
|
|
4376
|
-
/* @__PURE__ */
|
|
4377
|
-
/* @__PURE__ */
|
|
6018
|
+
/* @__PURE__ */ jsxs15("div", { style: { marginBottom: "8px" }, children: [
|
|
6019
|
+
/* @__PURE__ */ jsx19("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Background:" }),
|
|
6020
|
+
/* @__PURE__ */ jsx19(
|
|
4378
6021
|
"input",
|
|
4379
6022
|
{
|
|
4380
6023
|
type: "text",
|
|
@@ -4402,20 +6045,20 @@ function NodeConfigPanel({
|
|
|
4402
6045
|
}
|
|
4403
6046
|
}
|
|
4404
6047
|
),
|
|
4405
|
-
/* @__PURE__ */
|
|
6048
|
+
/* @__PURE__ */ jsx19("div", { style: { fontSize: "0.65rem", color: "#6b7280", marginTop: "2px" }, children: "Use 'status' for status-based color or hex code" })
|
|
4406
6049
|
] })
|
|
4407
6050
|
] }),
|
|
4408
6051
|
" "
|
|
4409
6052
|
] })
|
|
4410
6053
|
] })
|
|
4411
6054
|
] }),
|
|
4412
|
-
binding && /* @__PURE__ */
|
|
4413
|
-
/* @__PURE__ */
|
|
6055
|
+
binding && /* @__PURE__ */ jsxs15("div", { style: { marginBottom: "20px" }, children: [
|
|
6056
|
+
/* @__PURE__ */ jsx19("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Thresholds" }),
|
|
4414
6057
|
["highHigh", "high", "low", "lowLow"].map((key) => {
|
|
4415
6058
|
const label = key === "highHigh" ? "High-High (\u2265)" : key === "high" ? "High (\u2265)" : key === "low" ? "Low (\u2264)" : "Low-Low (\u2264)";
|
|
4416
|
-
return /* @__PURE__ */
|
|
4417
|
-
/* @__PURE__ */
|
|
4418
|
-
/* @__PURE__ */
|
|
6059
|
+
return /* @__PURE__ */ jsxs15("div", { style: { marginBottom: "8px" }, children: [
|
|
6060
|
+
/* @__PURE__ */ jsx19("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: label }),
|
|
6061
|
+
/* @__PURE__ */ jsx19(
|
|
4419
6062
|
"input",
|
|
4420
6063
|
{
|
|
4421
6064
|
type: "number",
|
|
@@ -4439,8 +6082,8 @@ function NodeConfigPanel({
|
|
|
4439
6082
|
] }, key);
|
|
4440
6083
|
})
|
|
4441
6084
|
] }),
|
|
4442
|
-
binding && /* @__PURE__ */
|
|
4443
|
-
/* @__PURE__ */
|
|
6085
|
+
binding && /* @__PURE__ */ jsxs15("div", { style: { marginBottom: "20px" }, children: [
|
|
6086
|
+
/* @__PURE__ */ jsx19("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Status Colors" }),
|
|
4444
6087
|
["normal", "warning", "alarm", "fault", "off"].map((status) => {
|
|
4445
6088
|
const defaultColors = {
|
|
4446
6089
|
normal: "#10b981",
|
|
@@ -4450,13 +6093,13 @@ function NodeConfigPanel({
|
|
|
4450
6093
|
off: "#6b7280"
|
|
4451
6094
|
};
|
|
4452
6095
|
const label = status === "normal" ? "Normal" : status === "warning" ? "Warning" : status === "alarm" ? "Alarm" : status === "fault" ? "Fault" : "Off";
|
|
4453
|
-
return /* @__PURE__ */
|
|
4454
|
-
/* @__PURE__ */
|
|
6096
|
+
return /* @__PURE__ */ jsxs15("div", { style: { marginBottom: "8px" }, children: [
|
|
6097
|
+
/* @__PURE__ */ jsxs15("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
|
|
4455
6098
|
label,
|
|
4456
6099
|
":"
|
|
4457
6100
|
] }),
|
|
4458
|
-
/* @__PURE__ */
|
|
4459
|
-
/* @__PURE__ */
|
|
6101
|
+
/* @__PURE__ */ jsxs15("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
|
|
6102
|
+
/* @__PURE__ */ jsx19(
|
|
4460
6103
|
"input",
|
|
4461
6104
|
{
|
|
4462
6105
|
type: "color",
|
|
@@ -4477,7 +6120,7 @@ function NodeConfigPanel({
|
|
|
4477
6120
|
}
|
|
4478
6121
|
}
|
|
4479
6122
|
),
|
|
4480
|
-
/* @__PURE__ */
|
|
6123
|
+
/* @__PURE__ */ jsx19(
|
|
4481
6124
|
"input",
|
|
4482
6125
|
{
|
|
4483
6126
|
type: "text",
|
|
@@ -4504,7 +6147,7 @@ function NodeConfigPanel({
|
|
|
4504
6147
|
] }, status);
|
|
4505
6148
|
})
|
|
4506
6149
|
] }),
|
|
4507
|
-
/* @__PURE__ */
|
|
6150
|
+
/* @__PURE__ */ jsx19("div", { style: { marginTop: "20px", paddingTop: "20px", borderTop: "1px solid #cbd5e1" }, children: /* @__PURE__ */ jsx19(
|
|
4508
6151
|
"button",
|
|
4509
6152
|
{
|
|
4510
6153
|
onClick: onRemove,
|
|
@@ -4744,7 +6387,7 @@ var DEFAULT_THRESHOLDS = {
|
|
|
4744
6387
|
};
|
|
4745
6388
|
|
|
4746
6389
|
// src/diagram/hooks/useSimulation.ts
|
|
4747
|
-
import { useEffect as
|
|
6390
|
+
import { useEffect as useEffect11 } from "react";
|
|
4748
6391
|
function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
4749
6392
|
const {
|
|
4750
6393
|
interval = 2e3,
|
|
@@ -4755,7 +6398,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
|
4755
6398
|
historyLength = 10,
|
|
4756
6399
|
generateValue
|
|
4757
6400
|
} = options;
|
|
4758
|
-
|
|
6401
|
+
useEffect11(() => {
|
|
4759
6402
|
if (!enabled) return;
|
|
4760
6403
|
const intervalId = setInterval(() => {
|
|
4761
6404
|
const updates = [];
|
|
@@ -4857,6 +6500,7 @@ export {
|
|
|
4857
6500
|
useSelection,
|
|
4858
6501
|
useSimulation,
|
|
4859
6502
|
useTelemetry,
|
|
6503
|
+
useTelemetryStatus,
|
|
4860
6504
|
useTheme,
|
|
4861
6505
|
useViewBox,
|
|
4862
6506
|
validateDiagram
|