@mstone6969/graph 0.1.0 → 0.2.0

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.
Files changed (238) hide show
  1. package/README.md +111 -14
  2. package/dist/ExcelWriter-3ZSYUH4T.cjs +154 -0
  3. package/dist/GraphType.js +24 -38
  4. package/dist/PdfWriter-6HJFYMCO.cjs +205 -0
  5. package/dist/catalog-YWX6FHRM.cjs +8 -0
  6. package/dist/catalog.js +5 -1
  7. package/dist/charts/bars/index.js +2 -12
  8. package/dist/charts/comparison/EffectForestPlot.js +1 -1
  9. package/dist/charts/comparison/index.js +1 -8
  10. package/dist/charts/demography/Nomogram.js +3 -3
  11. package/dist/charts/density/HexbinChart.js +6 -4
  12. package/dist/charts/diagrams/ArchitectureCanvas.js +68 -0
  13. package/dist/charts/diagrams/ArchitectureDiagram.js +331 -0
  14. package/dist/charts/diagrams/ArchitectureLayout.js +106 -0
  15. package/dist/charts/diagrams/ArchitectureLinkLabels.js +78 -0
  16. package/dist/charts/diagrams/ArchitectureModel.js +108 -0
  17. package/dist/charts/diagrams/ArchitectureRouter.js +348 -0
  18. package/dist/charts/diagrams/ArchitectureSamples.js +312 -0
  19. package/dist/charts/diagrams/ArchitectureShapes.js +130 -0
  20. package/dist/charts/diagrams/ArchitectureText.js +25 -0
  21. package/dist/charts/diagrams/DiagramText.js +38 -0
  22. package/dist/charts/diagrams/EntityRelationshipDiagram.js +465 -0
  23. package/dist/charts/diagrams/ErCrowsFoot.js +33 -0
  24. package/dist/charts/diagrams/ErSamples.js +205 -0
  25. package/dist/charts/diagrams/ErSchema.js +122 -0
  26. package/dist/charts/diagrams/LogicCircuit.js +154 -0
  27. package/dist/charts/diagrams/LogicCircuitLayout.js +600 -0
  28. package/dist/charts/diagrams/LogicCircuitSamples.js +66 -0
  29. package/dist/charts/diagrams/LogicGateDiagram.js +216 -0
  30. package/dist/charts/diagrams/LogicGateSymbol.js +113 -0
  31. package/dist/charts/diagrams/NetworkTopologyDiagram.js +247 -0
  32. package/dist/charts/diagrams/SequenceDiagram.js +351 -0
  33. package/dist/charts/diagrams/SequenceLayout.js +422 -0
  34. package/dist/charts/diagrams/SequenceModel.js +221 -0
  35. package/dist/charts/diagrams/TopologyLayout.js +143 -0
  36. package/dist/charts/diagrams/architectureEnums.js +50 -0
  37. package/dist/charts/diagrams/index.js +26 -0
  38. package/dist/charts/diagrams/logicEnums.js +42 -0
  39. package/dist/charts/diagrams/sequenceEnums.js +40 -0
  40. package/dist/charts/distribution/HistogramChart.js +25 -3
  41. package/dist/charts/distribution/index.js +1 -3
  42. package/dist/charts/earthscience/HovmollerDiagram.js +477 -0
  43. package/dist/charts/earthscience/HovmollerEnums.js +42 -0
  44. package/dist/charts/earthscience/HovmollerField.js +180 -0
  45. package/dist/charts/earthscience/HovmollerSample.js +40 -0
  46. package/dist/charts/earthscience/HovmollerSpeed.js +71 -0
  47. package/dist/charts/earthscience/index.js +10 -2
  48. package/dist/charts/engineering/ConstellationDiagram.js +26 -6
  49. package/dist/charts/engineering/EyeDiagram.js +2 -1
  50. package/dist/charts/engineering/PoleZeroPlot.js +32 -8
  51. package/dist/charts/financial/RelativeStrengthRotation.js +434 -0
  52. package/dist/charts/financial/RelativeStrengthRotationMath.js +71 -0
  53. package/dist/charts/financial/RelativeStrengthRotationSamples.js +27 -0
  54. package/dist/charts/financial/index.js +5 -3
  55. package/dist/charts/flow/index.js +1 -5
  56. package/dist/charts/frameworks/AnsoffMatrix.js +523 -0
  57. package/dist/charts/frameworks/FrameworkText.js +98 -0
  58. package/dist/charts/frameworks/NpsGauge.js +279 -0
  59. package/dist/charts/frameworks/NpsSurvey.js +58 -0
  60. package/dist/charts/frameworks/PerceptualMap.js +419 -0
  61. package/dist/charts/frameworks/PerceptualProjection.js +142 -0
  62. package/dist/charts/frameworks/PositioningSamples.js +191 -0
  63. package/dist/charts/frameworks/RaciMatrix.js +458 -0
  64. package/dist/charts/frameworks/RaciPlan.js +81 -0
  65. package/dist/charts/frameworks/RaciSamples.js +76 -0
  66. package/dist/charts/frameworks/SwotMatrix.js +358 -0
  67. package/dist/charts/frameworks/SwotSamples.js +85 -0
  68. package/dist/charts/frameworks/VanWestendorpChart.js +187 -0
  69. package/dist/charts/frameworks/VanWestendorpSurvey.js +197 -0
  70. package/dist/charts/frameworks/index.js +26 -0
  71. package/dist/charts/frameworks/raciEnums.js +30 -0
  72. package/dist/charts/frameworks/swotEnums.js +34 -0
  73. package/dist/charts/genomics/CircosPlot.js +1 -1
  74. package/dist/charts/geoflows/GeoFlowChart.js +2 -2
  75. package/dist/charts/geoflows/GeoFlowSample.js +2 -1
  76. package/dist/charts/geomaps/FloorPlanMap.js +324 -0
  77. package/dist/charts/geomaps/FloorPlanModel.js +179 -0
  78. package/dist/charts/geomaps/FloorPlanSamples.js +416 -0
  79. package/dist/charts/geomaps/GeoLand.js +2 -2
  80. package/dist/charts/geomaps/GeoSamples.js +2 -1
  81. package/dist/charts/geomaps/GraticuleMap.js +2 -2
  82. package/dist/charts/geomaps/RoomLabelFit.js +200 -0
  83. package/dist/charts/geomaps/TissotMap.js +2 -2
  84. package/dist/charts/geomaps/index.js +8 -4
  85. package/dist/charts/hierarchy/SunburstChart.js +17 -10
  86. package/dist/charts/hierarchy/index.js +2 -11
  87. package/dist/charts/indicators/BulletChart.js +8 -2
  88. package/dist/charts/indicators/SpeedometerChart.js +1 -1
  89. package/dist/charts/indicators/ThermometerChart.js +1 -1
  90. package/dist/charts/lifescience/LoessFit.js +113 -0
  91. package/dist/charts/lifescience/MaPlot.js +337 -0
  92. package/dist/charts/lifescience/MaPlotSamples.js +35 -0
  93. package/dist/charts/lifescience/OncoGlyph.js +137 -0
  94. package/dist/charts/lifescience/OncoPrint.js +373 -0
  95. package/dist/charts/lifescience/OncoPrintMatrix.js +107 -0
  96. package/dist/charts/lifescience/OncoPrintSamples.js +142 -0
  97. package/dist/charts/lifescience/PedigreeChart.js +306 -0
  98. package/dist/charts/lifescience/PedigreeLayout.js +261 -0
  99. package/dist/charts/lifescience/PedigreeRows.js +70 -0
  100. package/dist/charts/lifescience/PedigreeSamples.js +161 -0
  101. package/dist/charts/lifescience/PedigreeSymbol.js +47 -0
  102. package/dist/charts/lifescience/RamachandranPlot.js +364 -0
  103. package/dist/charts/lifescience/RamachandranRegions.js +2712 -0
  104. package/dist/charts/lifescience/RamachandranSamples.js +235 -0
  105. package/dist/charts/lifescience/index.js +25 -0
  106. package/dist/charts/lifescience/pedigreeEnums.js +21 -0
  107. package/dist/charts/lifescience/ramachandranEnums.js +34 -0
  108. package/dist/charts/linesareas/DualAxisChart.js +1 -1
  109. package/dist/charts/linesareas/LineEnums.js +1 -15
  110. package/dist/charts/linesareas/MultiLineChart.js +1 -1
  111. package/dist/charts/linesareas/TrendChart.js +15 -5
  112. package/dist/charts/linesareas/index.js +2 -6
  113. package/dist/charts/massive/MassiveChart.js +3 -2
  114. package/dist/charts/mathematical/FourierSeriesChart.js +7 -1
  115. package/dist/charts/mathematical/index.js +2 -6
  116. package/dist/charts/matrix/GridPlot.js +27 -2
  117. package/dist/charts/matrix/TilegramChart.js +2 -2
  118. package/dist/charts/mlcharts/AttentionGrid.js +79 -0
  119. package/dist/charts/mlcharts/AttentionHeatmap.js +329 -0
  120. package/dist/charts/mlcharts/AttentionModel.js +132 -0
  121. package/dist/charts/mlcharts/AttentionSamples.js +82 -0
  122. package/dist/charts/mlcharts/CellNumber.js +8 -0
  123. package/dist/charts/mlcharts/CurveDiagnosticSamples.js +95 -0
  124. package/dist/charts/mlcharts/CurvePickMark.js +31 -0
  125. package/dist/charts/mlcharts/DecisionBoundaryChart.js +316 -0
  126. package/dist/charts/mlcharts/DecisionSamples.js +60 -0
  127. package/dist/charts/mlcharts/DecisionSurface.js +130 -0
  128. package/dist/charts/mlcharts/DistinctTicks.js +13 -0
  129. package/dist/charts/mlcharts/ElbowMath.js +153 -0
  130. package/dist/charts/mlcharts/ElbowPlot.js +273 -0
  131. package/dist/charts/mlcharts/ExplainabilitySamples.js +70 -0
  132. package/dist/charts/mlcharts/FeatureImportanceChart.js +150 -0
  133. package/dist/charts/mlcharts/ImportanceRanking.js +98 -0
  134. package/dist/charts/mlcharts/LearningCurveChart.js +276 -0
  135. package/dist/charts/mlcharts/LearningCurveMath.js +92 -0
  136. package/dist/charts/mlcharts/PartialDependence.js +92 -0
  137. package/dist/charts/mlcharts/PartialDependencePlot.js +225 -0
  138. package/dist/charts/mlcharts/WideLabel.js +28 -0
  139. package/dist/charts/mlcharts/curveDiagnosticEnums.js +37 -0
  140. package/dist/charts/mlcharts/index.js +32 -0
  141. package/dist/charts/proportion/index.js +5 -9
  142. package/dist/charts/scatter/CategoryScatterBase.js +1 -4
  143. package/dist/charts/scatter/ConnectedScatter.js +7 -4
  144. package/dist/charts/scatter/MarginalScatter.js +13 -8
  145. package/dist/charts/scatter/index.js +4 -17
  146. package/dist/charts/scientific/SpectrogramChart.js +9 -3
  147. package/dist/charts/scientific/index.js +2 -2
  148. package/dist/charts/signals/index.js +3 -13
  149. package/dist/charts/statistics/LorenzCurve.js +7 -4
  150. package/dist/charts/threebars/Candlestick3DChart.js +18 -2
  151. package/dist/charts/threeglobe/GlobeChart.js +2 -2
  152. package/dist/charts/threeglobe/GlobeSamples.js +2 -1
  153. package/dist/charts/threeglobe/RingGlobe.js +1 -1
  154. package/dist/charts/threenetwork/ConeTreeChart.js +2 -1
  155. package/dist/charts/threenetwork/Gantt3DChart.js +3 -2
  156. package/dist/charts/threesurfaces/Ridgeline3DChart.js +22 -4
  157. package/dist/charts/threevolume/LorenzAttractor.js +19 -0
  158. package/dist/charts/threevolume/VolumeRaycastChart.js +4 -3
  159. package/dist/charts/threevolume/volumeEnums.js +1 -0
  160. package/dist/charts/timeline/index.js +2 -10
  161. package/dist/chunk-753UBLV2.cjs +33 -0
  162. package/dist/chunk-VX54A7KA.cjs +17 -0
  163. package/dist/{chunk-W5GAAAZY.cjs → chunk-WAODDPYX.cjs} +24874 -17620
  164. package/dist/chunk-Z3JPIJSC.cjs +338 -0
  165. package/dist/core/CartesianChart.js +87 -11
  166. package/dist/core/Chart.js +63 -15
  167. package/dist/core/Chart2D.js +54 -17
  168. package/dist/core/Chart3D.js +56 -20
  169. package/dist/core/ChartExportError.js +2 -0
  170. package/dist/core/ChartExporter.js +50 -8
  171. package/dist/core/ColumnCheck.js +53 -0
  172. package/dist/core/Context2D.js +29 -15
  173. package/dist/core/Context3D.js +7 -2
  174. package/dist/core/ExcelWriter.js +152 -0
  175. package/dist/core/ExportText.js +28 -0
  176. package/dist/core/MarkOrigin.js +88 -0
  177. package/dist/core/MarkStyle.js +294 -0
  178. package/dist/core/Palette.js +27 -7
  179. package/dist/core/PdfPage.js +13 -0
  180. package/dist/core/PdfWriter.js +245 -0
  181. package/dist/core/Scales.js +52 -2
  182. package/dist/core/SceneOverlay.js +4 -4
  183. package/dist/core/TextFit.js +37 -0
  184. package/dist/core/Theme.js +28 -1
  185. package/dist/core/enums.js +33 -1
  186. package/dist/core/pathMorph.js +15 -0
  187. package/dist/data/SampleData.js +1 -17
  188. package/dist/data/WorldSample.js +23 -0
  189. package/dist/index.cjs +810 -691
  190. package/dist/index.d.cts +8390 -2925
  191. package/dist/index.d.ts +8392 -2927
  192. package/dist/index.js +106 -56
  193. package/dist/react/ChartView.js +18 -8
  194. package/dist/react/GraphHandle.js +2 -0
  195. package/dist/react/components.js +74 -116
  196. package/package.json +13 -3
  197. package/dist/catalog-4UP2YFNR.cjs +0 -7
  198. package/dist/charts/bars/BulletBar.js +0 -184
  199. package/dist/charts/bars/ErrorBarColumn.js +0 -147
  200. package/dist/charts/bars/HistogramBar.js +0 -217
  201. package/dist/charts/bars/MarimekkoBar.js +0 -191
  202. package/dist/charts/bars/ParetoBar.js +0 -143
  203. package/dist/charts/comparison/PanelChart.js +0 -70
  204. package/dist/charts/comparison/SmallMultipleBars.js +0 -134
  205. package/dist/charts/comparison/SpanChart.js +0 -118
  206. package/dist/charts/comparison/TrellisChart.js +0 -158
  207. package/dist/charts/distribution/RidgeSlabs3DChart.js +0 -169
  208. package/dist/charts/financial/Candlestick3D.js +0 -157
  209. package/dist/charts/flow/BumpFlow.js +0 -212
  210. package/dist/charts/flow/StreamFlow.js +0 -174
  211. package/dist/charts/geomaps/ThiessenMap.js +0 -106
  212. package/dist/charts/hierarchy/ConeTree3D.js +0 -135
  213. package/dist/charts/hierarchy/Hierarchy3DChart.js +0 -27
  214. package/dist/charts/hierarchy/SpherePack3D.js +0 -81
  215. package/dist/charts/hierarchy/SunburstTower3D.js +0 -93
  216. package/dist/charts/hierarchy/TreemapSkyline3D.js +0 -98
  217. package/dist/charts/linesareas/ConnectedScatterTime.js +0 -206
  218. package/dist/charts/linesareas/SmallMultipleLines.js +0 -153
  219. package/dist/charts/mathematical/ParametricSurface3D.js +0 -234
  220. package/dist/charts/mathematical/StrangeAttractor3D.js +0 -251
  221. package/dist/charts/proportion/ConeFunnel.js +0 -126
  222. package/dist/charts/proportion/ExtrudedPieChart.js +0 -123
  223. package/dist/charts/scatter/BeeswarmScatter.js +0 -151
  224. package/dist/charts/scatter/BinnedScatterBase.js +0 -51
  225. package/dist/charts/scatter/ContourScatter.js +0 -116
  226. package/dist/charts/scatter/GridBinScatter.js +0 -98
  227. package/dist/charts/scatter/HexbinScatter.js +0 -74
  228. package/dist/charts/scatter/StripScatter.js +0 -107
  229. package/dist/charts/scatter/SunflowerScatter.js +0 -109
  230. package/dist/charts/signals/ConstellationChart.js +0 -153
  231. package/dist/charts/signals/CorrelogramChart.js +0 -171
  232. package/dist/charts/signals/EyeDiagramChart.js +0 -155
  233. package/dist/charts/signals/PoleZeroChart.js +0 -164
  234. package/dist/charts/signals/SpectrogramChart.js +0 -79
  235. package/dist/charts/timeline/CalendarSkylineChart.js +0 -128
  236. package/dist/charts/timeline/ScheduleBlocksChart.js +0 -119
  237. package/dist/charts/timeline/SpiralTimeline.js +0 -154
  238. package/dist/charts/timeline/StreamTimeline.js +0 -141
@@ -0,0 +1,348 @@
1
+ // src/charts/diagrams/ArchitectureRouter.ts
2
+ var ArchitectureFlow = /* @__PURE__ */ function(ArchitectureFlow) {
3
+ ArchitectureFlow["Down"] = "down";
4
+ ArchitectureFlow["Right"] = "right";
5
+ ArchitectureFlow["None"] = "none";
6
+ return ArchitectureFlow;
7
+ }({});
8
+ var CLEAR = 6;
9
+ var STUB = 12;
10
+ var LANE = 22;
11
+ var BEND = 14;
12
+ var OVERLAP = 70;
13
+ var CROSSING = 12;
14
+ var TAKEN = 60;
15
+ var OFF_FLOW = 26;
16
+ var AGAINST_FLOW = 70;
17
+ var EXPANSIONS = 15e4;
18
+ var SKIRT = 5;
19
+ var HUG = 70;
20
+ /** Past these sizes a search costs seconds, so what remains is drawn straight. Only a diagram too dense to read gets here. */
21
+ var MAX_GRID = 1e6;
22
+ var BUDGET = 2e8;
23
+ var STEPS = [
24
+ [1, 0],
25
+ [0, 1],
26
+ [-1, 0],
27
+ [0, -1]
28
+ ];
29
+ /** Which way a port leaves each face: right, bottom, left, top. */
30
+ var FACES = [
31
+ 0,
32
+ 1,
33
+ 2,
34
+ 3
35
+ ];
36
+ var SPREAD = 8;
37
+ var unique = (values) => [...new Set(values.map((value) => Math.round(value)))].sort((a, b) => a - b);
38
+ /**
39
+ * Orthogonal connector routing around rectangular obstacles (Wybrow, Marriott and Stuckey, 2009):
40
+ * A* over a grid drawn from the obstacles' edges, costing length, bends, overlaps and crossings.
41
+ */
42
+ var ArchitectureRouter = class ArchitectureRouter {
43
+ #xs;
44
+ #ys;
45
+ #across;
46
+ #along;
47
+ #hugAcross;
48
+ #hugAlong;
49
+ #spent = 0;
50
+ #taken = /* @__PURE__ */ new Map();
51
+ #options;
52
+ static route(requests, options) {
53
+ return new ArchitectureRouter(options).#all(requests);
54
+ }
55
+ constructor(options) {
56
+ this.#options = options;
57
+ const { rects, bounds } = options;
58
+ const lines = (start, size) => unique(rects.flatMap((rect) => {
59
+ const low = rect[start], high = low + rect[size];
60
+ return [
61
+ low - LANE,
62
+ low - STUB,
63
+ high + STUB,
64
+ high + LANE,
65
+ ...ArchitectureRouter.#stops(rect[size]).map((at) => low + at)
66
+ ];
67
+ })).filter((line) => !bounds || line >= bounds[start] && line <= bounds[start] + bounds[size]);
68
+ this.#xs = lines("x", "width");
69
+ this.#ys = lines("y", "height");
70
+ const nodes = this.#xs.length * this.#ys.length;
71
+ this.#spent = nodes > MAX_GRID ? BUDGET : 0;
72
+ const room = nodes > MAX_GRID ? 0 : nodes;
73
+ this.#across = new Uint8Array(room);
74
+ this.#along = new Uint8Array(room);
75
+ this.#hugAcross = new Uint8Array(room);
76
+ this.#hugAlong = new Uint8Array(room);
77
+ if (room) for (const rect of options.skirt ?? []) this.#mark(rect);
78
+ }
79
+ /** Flags grid runs that lie along an edge of `rect`. */
80
+ #mark(rect) {
81
+ const xs = this.#xs, ys = this.#ys, nx = xs.length;
82
+ const near = (value, a, b) => Math.abs(value - a) <= SKIRT || Math.abs(value - b) <= SKIRT;
83
+ const within = (value, low, size) => value >= low - SKIRT && value <= low + size + SKIRT;
84
+ ys.forEach((y, j) => xs.forEach((x, i) => {
85
+ if (near(x, rect.x, rect.x + rect.width) && within(y, rect.y, rect.height)) this.#hugAlong[j * nx + i] = 1;
86
+ if (near(y, rect.y, rect.y + rect.height) && within(x, rect.x, rect.width)) this.#hugAcross[j * nx + i] = 1;
87
+ }));
88
+ }
89
+ /** Ports along a face of `length`: always the middle, then outward as room allows. */
90
+ static #stops(length) {
91
+ const count = length >= 150 ? 5 : length >= 36 ? 3 : 1;
92
+ return Array.from({ length: count }, (_, i) => Math.round(length * (i + 1) / (count + 1)));
93
+ }
94
+ #all(requests) {
95
+ const out = new Array(requests.length);
96
+ const pairs = /* @__PURE__ */ new Map();
97
+ const pair = (request) => [ArchitectureRouter.#mid(request.from), ArchitectureRouter.#mid(request.to)].map((at) => `${at.x},${at.y}`).sort().join(">");
98
+ requests.forEach((request, i) => pairs.set(pair(request), [...pairs.get(pair(request)) ?? [], i]));
99
+ const pending = [];
100
+ requests.forEach((request, i) => {
101
+ const twins = pairs.get(pair(request)), shift = (twins.indexOf(i) - (twins.length - 1) / 2) * SPREAD;
102
+ const line = this.#options.direct ? ArchitectureRouter.#straight(request, shift) : null;
103
+ if (line && !request.blocks.some((rect) => rect !== request.from && rect !== request.to && ArchitectureRouter.#hits(line[0], line[1], rect))) out[i] = line;
104
+ else pending.push(i);
105
+ });
106
+ const span = (i) => {
107
+ const a = ArchitectureRouter.#mid(requests[i].from), b = ArchitectureRouter.#mid(requests[i].to);
108
+ return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
109
+ };
110
+ for (const i of pending.sort((a, b) => span(a) - span(b) || a - b)) out[i] = this.#search(requests[i]) ?? ArchitectureRouter.#straight(requests[i], 0);
111
+ return out;
112
+ }
113
+ static #mid(rect) {
114
+ return {
115
+ x: rect.x + rect.width / 2,
116
+ y: rect.y + rect.height / 2
117
+ };
118
+ }
119
+ /** Where the line from inside `rect` towards `toward` leaves it. */
120
+ static #edge(from, toward, rect) {
121
+ const dx = toward.x - from.x, dy = toward.y - from.y;
122
+ const t = Math.min(dx ? Math.max((rect.x - from.x) / dx, (rect.x + rect.width - from.x) / dx) : Infinity, dy ? Math.max((rect.y - from.y) / dy, (rect.y + rect.height - from.y) / dy) : Infinity);
123
+ return Number.isFinite(t) ? {
124
+ x: from.x + dx * t,
125
+ y: from.y + dy * t
126
+ } : from;
127
+ }
128
+ static #straight({ from, to }, shift) {
129
+ const a = ArchitectureRouter.#mid(from), b = ArchitectureRouter.#mid(to);
130
+ const length = Math.hypot(b.x - a.x, b.y - a.y) || 1;
131
+ const nudge = {
132
+ x: -(b.y - a.y) / length * shift,
133
+ y: (b.x - a.x) / length * shift
134
+ };
135
+ const start = {
136
+ x: a.x + nudge.x,
137
+ y: a.y + nudge.y
138
+ }, end = {
139
+ x: b.x + nudge.x,
140
+ y: b.y + nudge.y
141
+ };
142
+ return [ArchitectureRouter.#edge(start, end, from), ArchitectureRouter.#edge(end, start, to)];
143
+ }
144
+ /** Liang-Barsky clip of a segment against `rect` grown by the clearance. */
145
+ static #hits(a, b, rect) {
146
+ let low = 0, high = 1;
147
+ const dx = b.x - a.x, dy = b.y - a.y;
148
+ const sides = [
149
+ [-dx, a.x - rect.x + CLEAR],
150
+ [dx, rect.x + rect.width + CLEAR - a.x],
151
+ [-dy, a.y - rect.y + CLEAR],
152
+ [dy, rect.y + rect.height + CLEAR - a.y]
153
+ ];
154
+ for (const [p, q] of sides) {
155
+ if (p === 0) {
156
+ if (q < 0) return false;
157
+ continue;
158
+ }
159
+ const t = q / p;
160
+ if (p < 0) low = Math.max(low, t);
161
+ else high = Math.min(high, t);
162
+ if (low > high) return false;
163
+ }
164
+ return true;
165
+ }
166
+ #node(x, y) {
167
+ const i = this.#xs.indexOf(Math.round(x)), j = this.#ys.indexOf(Math.round(y));
168
+ return i < 0 || j < 0 ? -1 : j * this.#xs.length + i;
169
+ }
170
+ /** Each face offers its stops; the flow makes lines prefer to leave forward and arrive from behind. */
171
+ #ports(rect, leaving, flow) {
172
+ const forward = flow === "down" ? 1 : 0;
173
+ return FACES.flatMap((face) => {
174
+ const [dx, dy] = STEPS[face], along = dx !== 0;
175
+ const stops = ArchitectureRouter.#stops(along ? rect.height : rect.width);
176
+ const facing = flow === "none" ? 0 : face === (leaving ? forward : forward + 2) ? 0 : face === (leaving ? forward + 2 : forward) ? AGAINST_FLOW : OFF_FLOW;
177
+ return stops.flatMap((stop) => {
178
+ const x = Math.round(along ? dx > 0 ? rect.x + rect.width : rect.x : rect.x + stop);
179
+ const y = Math.round(along ? rect.y + stop : dy > 0 ? rect.y + rect.height : rect.y);
180
+ const node = this.#node(x + dx * STUB, y + dy * STUB);
181
+ if (node < 0) return [];
182
+ const centre = Math.abs(stop - (along ? rect.height : rect.width) / 2) * .15;
183
+ return [{
184
+ point: {
185
+ x,
186
+ y
187
+ },
188
+ node,
189
+ dir: leaving ? face : (face + 2) % 4,
190
+ cost: facing + centre + (this.#taken.get(`${x},${y}`) ?? 0) * TAKEN
191
+ }];
192
+ });
193
+ });
194
+ }
195
+ #blocked(rects) {
196
+ const xs = this.#xs, ys = this.#ys, blocked = new Uint8Array(xs.length * ys.length);
197
+ for (const rect of rects) for (let j = 0; j < ys.length; j++) {
198
+ if (ys[j] <= rect.y - CLEAR || ys[j] >= rect.y + rect.height + CLEAR) continue;
199
+ for (let i = 0; i < xs.length; i++) if (xs[i] > rect.x - CLEAR && xs[i] < rect.x + rect.width + CLEAR) blocked[j * xs.length + i] = 1;
200
+ }
201
+ return blocked;
202
+ }
203
+ #search(request) {
204
+ if (this.#spent >= BUDGET) return null;
205
+ const xs = this.#xs, ys = this.#ys, nx = xs.length, ny = ys.length, count = nx * ny;
206
+ this.#spent += count;
207
+ const blocked = this.#blocked([
208
+ ...request.blocks,
209
+ request.from,
210
+ request.to
211
+ ]), flow = request.flow ?? this.#options.flow;
212
+ const dist = new Float64Array(count * 4).fill(Infinity), prev = new Int32Array(count * 4).fill(-1);
213
+ const seeds = this.#ports(request.from, true, flow).filter((port) => !blocked[port.node]);
214
+ const goals = /* @__PURE__ */ new Map();
215
+ for (const port of this.#ports(request.to, false, flow)) if (!blocked[port.node]) goals.set(port.node, [...goals.get(port.node) ?? [], port]);
216
+ if (!seeds.length || !goals.size) return null;
217
+ const { to } = request;
218
+ const estimate = (node) => {
219
+ const x = xs[node % nx], y = ys[Math.floor(node / nx)];
220
+ return Math.max(to.x - x, 0, x - to.x - to.width) + Math.max(to.y - y, 0, y - to.y - to.height);
221
+ };
222
+ const heap = new MinHeap();
223
+ const starts = /* @__PURE__ */ new Map();
224
+ for (const port of seeds) {
225
+ const state = port.node * 4 + port.dir;
226
+ if (port.cost >= dist[state]) continue;
227
+ dist[state] = port.cost;
228
+ starts.set(state, port);
229
+ heap.push(port.cost + estimate(port.node), state);
230
+ }
231
+ let best = Infinity, end = -1, finish = null, steps = 0;
232
+ while (heap.size && steps++ < EXPANSIONS) {
233
+ const { key, value: state } = heap.pop();
234
+ if (key >= best) break;
235
+ const node = state >> 2, dir = state & 3, cost = dist[state];
236
+ if (key - estimate(node) > cost + 1e-6) continue;
237
+ for (const goal of goals.get(node) ?? []) {
238
+ const total = cost + goal.cost + (dir === goal.dir ? 0 : BEND);
239
+ if (total < best) {
240
+ best = total;
241
+ end = state;
242
+ finish = goal;
243
+ }
244
+ }
245
+ const i = node % nx, j = Math.floor(node / nx);
246
+ for (let turn = 0; turn < 4; turn++) {
247
+ if (turn === (dir + 2) % 4) continue;
248
+ const a = i + STEPS[turn][0], b = j + STEPS[turn][1];
249
+ if (a < 0 || b < 0 || a >= nx || b >= ny) continue;
250
+ const next = b * nx + a;
251
+ if (blocked[next]) continue;
252
+ const step = cost + Math.abs(xs[a] - xs[i]) + Math.abs(ys[b] - ys[j]) + (turn === dir ? 0 : BEND) + this.#penalty(node, next, a, b, turn);
253
+ const target = next * 4 + turn;
254
+ if (step >= dist[target]) continue;
255
+ dist[target] = step;
256
+ prev[target] = state;
257
+ heap.push(step + estimate(next), target);
258
+ }
259
+ }
260
+ if (end < 0) return null;
261
+ return this.#commit(end, prev, starts, finish);
262
+ }
263
+ #penalty(node, next, a, b, turn) {
264
+ const nx = this.#xs.length, flat = turn % 2 === 0;
265
+ const shared = (flat ? this.#across : this.#along)[Math.min(node, next)] ? OVERLAP : 0;
266
+ const crossing = flat ? this.#along[next] || b > 0 && this.#along[next - nx] : this.#across[next] || a > 0 && this.#across[next - 1];
267
+ const hug = flat ? this.#hugAcross : this.#hugAlong;
268
+ return shared + (crossing ? CROSSING : 0) + (hug[node] && hug[next] ? HUG : 0);
269
+ }
270
+ #commit(end, prev, starts, finish) {
271
+ const nx = this.#xs.length;
272
+ const nodes = [];
273
+ let state = end;
274
+ for (;;) {
275
+ nodes.unshift(state >> 2);
276
+ if (prev[state] === -1) break;
277
+ state = prev[state];
278
+ }
279
+ const start = starts.get(state);
280
+ nodes.forEach((node, i) => {
281
+ if (!i) return;
282
+ const low = Math.min(node, nodes[i - 1]);
283
+ (Math.abs(node - nodes[i - 1]) === 1 ? this.#across : this.#along)[low] = 1;
284
+ });
285
+ for (const { x, y } of [start.point, finish.point]) this.#taken.set(`${x},${y}`, (this.#taken.get(`${x},${y}`) ?? 0) + 1);
286
+ const points = [
287
+ start.point,
288
+ ...nodes.map((node) => ({
289
+ x: this.#xs[node % nx],
290
+ y: this.#ys[Math.floor(node / nx)]
291
+ })),
292
+ finish.point
293
+ ];
294
+ return points.filter((at, i) => {
295
+ const before = points[i - 1], after = points[i + 1];
296
+ if (!before || !after) return true;
297
+ return !(before.x === at.x && at.x === after.x || before.y === at.y && at.y === after.y);
298
+ });
299
+ }
300
+ };
301
+ /** Binary heap of number keys, for the search frontier. */
302
+ var MinHeap = class {
303
+ #keys = [];
304
+ #values = [];
305
+ get size() {
306
+ return this.#keys.length;
307
+ }
308
+ push(key, value) {
309
+ const keys = this.#keys, values = this.#values;
310
+ let i = keys.length;
311
+ keys.push(key);
312
+ values.push(value);
313
+ while (i > 0) {
314
+ const up = i - 1 >> 1;
315
+ if (keys[up] <= key) break;
316
+ keys[i] = keys[up];
317
+ values[i] = values[up];
318
+ i = up;
319
+ }
320
+ keys[i] = key;
321
+ values[i] = value;
322
+ }
323
+ pop() {
324
+ const keys = this.#keys, values = this.#values;
325
+ const top = {
326
+ key: keys[0],
327
+ value: values[0]
328
+ };
329
+ const key = keys.pop(), value = values.pop();
330
+ const n = keys.length;
331
+ if (n) {
332
+ let i = 0;
333
+ for (;;) {
334
+ let child = 2 * i + 1;
335
+ if (child >= n) break;
336
+ if (child + 1 < n && keys[child + 1] < keys[child]) child++;
337
+ if (keys[child] >= key) break;
338
+ keys[i] = keys[child];
339
+ values[i] = values[child];
340
+ i = child;
341
+ }
342
+ keys[i] = key;
343
+ values[i] = value;
344
+ }
345
+ return top;
346
+ }
347
+ };
348
+ export { ArchitectureFlow, ArchitectureRouter };
@@ -0,0 +1,312 @@
1
+ import { SampleData } from "../../data/SampleData.js";
2
+ import { ArchitectureKind, NetworkDeviceKind } from "./architectureEnums.js";
3
+ // src/charts/diagrams/ArchitectureSamples.ts
4
+ var optional = (seed) => +SampleData.categories(seed, 1, 1)[0].value % 2 === 0;
5
+ /** Synthetic examples for the diagrams: a fictional parcel carrier and a fictional office network. Nothing here describes a real system. */
6
+ var ArchitectureSamples = class {
7
+ static parcelTracking(seed) {
8
+ const nodes = [
9
+ {
10
+ id: "carrier",
11
+ name: "Parcel carrier",
12
+ kind: ArchitectureKind.Boundary
13
+ },
14
+ {
15
+ id: "customer",
16
+ name: "Customer",
17
+ kind: ArchitectureKind.Person,
18
+ description: "Follows a parcel from order to doorstep."
19
+ },
20
+ {
21
+ id: "support",
22
+ name: "Support agent",
23
+ kind: ArchitectureKind.Person,
24
+ description: "Answers questions about late parcels."
25
+ },
26
+ {
27
+ id: "tracking",
28
+ name: "Tracking system",
29
+ kind: ArchitectureKind.System,
30
+ parent: "carrier",
31
+ description: "Shows where every parcel is."
32
+ },
33
+ {
34
+ id: "billing",
35
+ name: "Billing system",
36
+ kind: ArchitectureKind.System,
37
+ parent: "carrier",
38
+ description: "Invoices business customers."
39
+ },
40
+ {
41
+ id: "web",
42
+ name: "Web app",
43
+ kind: ArchitectureKind.Container,
44
+ parent: "tracking",
45
+ technology: "React",
46
+ description: "Tracking pages and the support console."
47
+ },
48
+ {
49
+ id: "api",
50
+ name: "Tracking API",
51
+ kind: ArchitectureKind.Container,
52
+ parent: "tracking",
53
+ technology: "Go",
54
+ description: "Serves parcel status over HTTPS."
55
+ },
56
+ {
57
+ id: "store",
58
+ name: "Parcel store",
59
+ kind: ArchitectureKind.Database,
60
+ parent: "tracking",
61
+ technology: "PostgreSQL",
62
+ description: "Holds parcels and scan events."
63
+ },
64
+ {
65
+ id: "routes",
66
+ name: "Parcel routes",
67
+ kind: ArchitectureKind.Component,
68
+ parent: "api",
69
+ technology: "chi",
70
+ description: "Handles lookups by tracking number."
71
+ },
72
+ {
73
+ id: "scans",
74
+ name: "Scan ingest",
75
+ kind: ArchitectureKind.Component,
76
+ parent: "api",
77
+ technology: "Go",
78
+ description: "Validates scans sent by carriers."
79
+ },
80
+ {
81
+ id: "notify",
82
+ name: "Notifier",
83
+ kind: ArchitectureKind.Component,
84
+ parent: "api",
85
+ technology: "Go",
86
+ description: "Emails customers when status changes."
87
+ },
88
+ {
89
+ id: "mail",
90
+ name: "Email service",
91
+ kind: ArchitectureKind.System,
92
+ external: true,
93
+ description: "Delivers transactional email."
94
+ },
95
+ {
96
+ id: "partner",
97
+ name: "Partner depots",
98
+ kind: ArchitectureKind.System,
99
+ external: true,
100
+ description: "Send a scan at every handover."
101
+ }
102
+ ];
103
+ const links = [
104
+ {
105
+ source: "customer",
106
+ target: "web",
107
+ label: "Tracks parcels",
108
+ technology: "HTTPS"
109
+ },
110
+ {
111
+ source: "support",
112
+ target: "web",
113
+ label: "Looks up parcels",
114
+ technology: "HTTPS"
115
+ },
116
+ {
117
+ source: "web",
118
+ target: "routes",
119
+ label: "Requests status",
120
+ technology: "JSON/HTTPS"
121
+ },
122
+ {
123
+ source: "routes",
124
+ target: "store",
125
+ label: "Reads parcels",
126
+ technology: "SQL"
127
+ },
128
+ {
129
+ source: "partner",
130
+ target: "scans",
131
+ label: "Posts scans",
132
+ technology: "Webhook"
133
+ },
134
+ {
135
+ source: "scans",
136
+ target: "store",
137
+ label: "Writes events",
138
+ technology: "SQL"
139
+ },
140
+ {
141
+ source: "scans",
142
+ target: "notify",
143
+ label: "Signals a change"
144
+ },
145
+ {
146
+ source: "notify",
147
+ target: "mail",
148
+ label: "Sends email",
149
+ technology: "SMTP"
150
+ },
151
+ {
152
+ source: "customer",
153
+ target: "billing",
154
+ label: "Pays invoices",
155
+ technology: "HTTPS"
156
+ }
157
+ ];
158
+ if (optional(seed)) {
159
+ nodes.push({
160
+ id: "reports",
161
+ name: "Reporting job",
162
+ kind: ArchitectureKind.Container,
163
+ parent: "tracking",
164
+ technology: "Python",
165
+ description: "Builds nightly delivery reports."
166
+ });
167
+ links.push({
168
+ source: "reports",
169
+ target: "store",
170
+ label: "Reads events",
171
+ technology: "SQL"
172
+ });
173
+ }
174
+ return {
175
+ nodes,
176
+ links
177
+ };
178
+ }
179
+ static officeNetwork(seed) {
180
+ const nodes = [
181
+ {
182
+ id: "wan",
183
+ name: "Internet",
184
+ kind: NetworkDeviceKind.Cloud
185
+ },
186
+ {
187
+ id: "edge-a",
188
+ name: "edge-a",
189
+ kind: NetworkDeviceKind.Router,
190
+ address: "192.0.2.1"
191
+ },
192
+ {
193
+ id: "edge-b",
194
+ name: "edge-b",
195
+ kind: NetworkDeviceKind.Router,
196
+ address: "192.0.2.2"
197
+ },
198
+ {
199
+ id: "core-a",
200
+ name: "core-a",
201
+ kind: NetworkDeviceKind.Switch,
202
+ address: "10.0.0.2"
203
+ },
204
+ {
205
+ id: "core-b",
206
+ name: "core-b",
207
+ kind: NetworkDeviceKind.Switch,
208
+ address: "10.0.0.3"
209
+ },
210
+ {
211
+ id: "access",
212
+ name: "access-1",
213
+ kind: NetworkDeviceKind.Switch,
214
+ address: "10.0.1.2"
215
+ },
216
+ {
217
+ id: "web",
218
+ name: "web-1",
219
+ kind: NetworkDeviceKind.Server,
220
+ address: "10.0.10.11"
221
+ },
222
+ {
223
+ id: "app",
224
+ name: "app-1",
225
+ kind: NetworkDeviceKind.Server,
226
+ address: "10.0.10.21"
227
+ },
228
+ {
229
+ id: "files",
230
+ name: "files-1",
231
+ kind: NetworkDeviceKind.Server,
232
+ address: "10.0.20.5"
233
+ },
234
+ {
235
+ id: "db",
236
+ name: "db-1",
237
+ kind: NetworkDeviceKind.Database,
238
+ address: "10.0.30.5"
239
+ }
240
+ ];
241
+ const links = [
242
+ {
243
+ source: "wan",
244
+ target: "edge-a",
245
+ label: "1 Gbps"
246
+ },
247
+ {
248
+ source: "wan",
249
+ target: "edge-b",
250
+ label: "1 Gbps"
251
+ },
252
+ {
253
+ source: "edge-a",
254
+ target: "core-a",
255
+ label: "10 Gbps"
256
+ },
257
+ {
258
+ source: "edge-b",
259
+ target: "core-b",
260
+ label: "10 Gbps"
261
+ },
262
+ {
263
+ source: "core-a",
264
+ target: "core-b",
265
+ label: "LAG"
266
+ },
267
+ {
268
+ source: "core-a",
269
+ target: "web",
270
+ label: "VLAN 10"
271
+ },
272
+ {
273
+ source: "core-a",
274
+ target: "app",
275
+ label: "VLAN 10"
276
+ },
277
+ {
278
+ source: "core-b",
279
+ target: "access",
280
+ label: "10 Gbps"
281
+ },
282
+ {
283
+ source: "access",
284
+ target: "files",
285
+ label: "VLAN 20"
286
+ },
287
+ {
288
+ source: "access",
289
+ target: "db",
290
+ label: "VLAN 30"
291
+ }
292
+ ];
293
+ if (optional(seed)) {
294
+ nodes.push({
295
+ id: "backup",
296
+ name: "backup-1",
297
+ kind: NetworkDeviceKind.Server,
298
+ address: "10.0.20.9"
299
+ });
300
+ links.push({
301
+ source: "access",
302
+ target: "backup",
303
+ label: "VLAN 20"
304
+ });
305
+ }
306
+ return {
307
+ nodes,
308
+ links
309
+ };
310
+ }
311
+ };
312
+ export { ArchitectureSamples };