@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.
- package/README.md +111 -14
- package/dist/ExcelWriter-3ZSYUH4T.cjs +154 -0
- package/dist/GraphType.js +24 -38
- package/dist/PdfWriter-6HJFYMCO.cjs +205 -0
- package/dist/catalog-YWX6FHRM.cjs +8 -0
- package/dist/catalog.js +5 -1
- package/dist/charts/bars/index.js +2 -12
- package/dist/charts/comparison/EffectForestPlot.js +1 -1
- package/dist/charts/comparison/index.js +1 -8
- package/dist/charts/demography/Nomogram.js +3 -3
- package/dist/charts/density/HexbinChart.js +6 -4
- package/dist/charts/diagrams/ArchitectureCanvas.js +68 -0
- package/dist/charts/diagrams/ArchitectureDiagram.js +331 -0
- package/dist/charts/diagrams/ArchitectureLayout.js +106 -0
- package/dist/charts/diagrams/ArchitectureLinkLabels.js +78 -0
- package/dist/charts/diagrams/ArchitectureModel.js +108 -0
- package/dist/charts/diagrams/ArchitectureRouter.js +348 -0
- package/dist/charts/diagrams/ArchitectureSamples.js +312 -0
- package/dist/charts/diagrams/ArchitectureShapes.js +130 -0
- package/dist/charts/diagrams/ArchitectureText.js +25 -0
- package/dist/charts/diagrams/DiagramText.js +38 -0
- package/dist/charts/diagrams/EntityRelationshipDiagram.js +465 -0
- package/dist/charts/diagrams/ErCrowsFoot.js +33 -0
- package/dist/charts/diagrams/ErSamples.js +205 -0
- package/dist/charts/diagrams/ErSchema.js +122 -0
- package/dist/charts/diagrams/LogicCircuit.js +154 -0
- package/dist/charts/diagrams/LogicCircuitLayout.js +600 -0
- package/dist/charts/diagrams/LogicCircuitSamples.js +66 -0
- package/dist/charts/diagrams/LogicGateDiagram.js +216 -0
- package/dist/charts/diagrams/LogicGateSymbol.js +113 -0
- package/dist/charts/diagrams/NetworkTopologyDiagram.js +247 -0
- package/dist/charts/diagrams/SequenceDiagram.js +351 -0
- package/dist/charts/diagrams/SequenceLayout.js +422 -0
- package/dist/charts/diagrams/SequenceModel.js +221 -0
- package/dist/charts/diagrams/TopologyLayout.js +143 -0
- package/dist/charts/diagrams/architectureEnums.js +50 -0
- package/dist/charts/diagrams/index.js +26 -0
- package/dist/charts/diagrams/logicEnums.js +42 -0
- package/dist/charts/diagrams/sequenceEnums.js +40 -0
- package/dist/charts/distribution/HistogramChart.js +25 -3
- package/dist/charts/distribution/index.js +1 -3
- package/dist/charts/earthscience/HovmollerDiagram.js +477 -0
- package/dist/charts/earthscience/HovmollerEnums.js +42 -0
- package/dist/charts/earthscience/HovmollerField.js +180 -0
- package/dist/charts/earthscience/HovmollerSample.js +40 -0
- package/dist/charts/earthscience/HovmollerSpeed.js +71 -0
- package/dist/charts/earthscience/index.js +10 -2
- package/dist/charts/engineering/ConstellationDiagram.js +26 -6
- package/dist/charts/engineering/EyeDiagram.js +2 -1
- package/dist/charts/engineering/PoleZeroPlot.js +32 -8
- package/dist/charts/financial/RelativeStrengthRotation.js +434 -0
- package/dist/charts/financial/RelativeStrengthRotationMath.js +71 -0
- package/dist/charts/financial/RelativeStrengthRotationSamples.js +27 -0
- package/dist/charts/financial/index.js +5 -3
- package/dist/charts/flow/index.js +1 -5
- package/dist/charts/frameworks/AnsoffMatrix.js +523 -0
- package/dist/charts/frameworks/FrameworkText.js +98 -0
- package/dist/charts/frameworks/NpsGauge.js +279 -0
- package/dist/charts/frameworks/NpsSurvey.js +58 -0
- package/dist/charts/frameworks/PerceptualMap.js +419 -0
- package/dist/charts/frameworks/PerceptualProjection.js +142 -0
- package/dist/charts/frameworks/PositioningSamples.js +191 -0
- package/dist/charts/frameworks/RaciMatrix.js +458 -0
- package/dist/charts/frameworks/RaciPlan.js +81 -0
- package/dist/charts/frameworks/RaciSamples.js +76 -0
- package/dist/charts/frameworks/SwotMatrix.js +358 -0
- package/dist/charts/frameworks/SwotSamples.js +85 -0
- package/dist/charts/frameworks/VanWestendorpChart.js +187 -0
- package/dist/charts/frameworks/VanWestendorpSurvey.js +197 -0
- package/dist/charts/frameworks/index.js +26 -0
- package/dist/charts/frameworks/raciEnums.js +30 -0
- package/dist/charts/frameworks/swotEnums.js +34 -0
- package/dist/charts/genomics/CircosPlot.js +1 -1
- package/dist/charts/geoflows/GeoFlowChart.js +2 -2
- package/dist/charts/geoflows/GeoFlowSample.js +2 -1
- package/dist/charts/geomaps/FloorPlanMap.js +324 -0
- package/dist/charts/geomaps/FloorPlanModel.js +179 -0
- package/dist/charts/geomaps/FloorPlanSamples.js +416 -0
- package/dist/charts/geomaps/GeoLand.js +2 -2
- package/dist/charts/geomaps/GeoSamples.js +2 -1
- package/dist/charts/geomaps/GraticuleMap.js +2 -2
- package/dist/charts/geomaps/RoomLabelFit.js +200 -0
- package/dist/charts/geomaps/TissotMap.js +2 -2
- package/dist/charts/geomaps/index.js +8 -4
- package/dist/charts/hierarchy/SunburstChart.js +17 -10
- package/dist/charts/hierarchy/index.js +2 -11
- package/dist/charts/indicators/BulletChart.js +8 -2
- package/dist/charts/indicators/SpeedometerChart.js +1 -1
- package/dist/charts/indicators/ThermometerChart.js +1 -1
- package/dist/charts/lifescience/LoessFit.js +113 -0
- package/dist/charts/lifescience/MaPlot.js +337 -0
- package/dist/charts/lifescience/MaPlotSamples.js +35 -0
- package/dist/charts/lifescience/OncoGlyph.js +137 -0
- package/dist/charts/lifescience/OncoPrint.js +373 -0
- package/dist/charts/lifescience/OncoPrintMatrix.js +107 -0
- package/dist/charts/lifescience/OncoPrintSamples.js +142 -0
- package/dist/charts/lifescience/PedigreeChart.js +306 -0
- package/dist/charts/lifescience/PedigreeLayout.js +261 -0
- package/dist/charts/lifescience/PedigreeRows.js +70 -0
- package/dist/charts/lifescience/PedigreeSamples.js +161 -0
- package/dist/charts/lifescience/PedigreeSymbol.js +47 -0
- package/dist/charts/lifescience/RamachandranPlot.js +364 -0
- package/dist/charts/lifescience/RamachandranRegions.js +2712 -0
- package/dist/charts/lifescience/RamachandranSamples.js +235 -0
- package/dist/charts/lifescience/index.js +25 -0
- package/dist/charts/lifescience/pedigreeEnums.js +21 -0
- package/dist/charts/lifescience/ramachandranEnums.js +34 -0
- package/dist/charts/linesareas/DualAxisChart.js +1 -1
- package/dist/charts/linesareas/LineEnums.js +1 -15
- package/dist/charts/linesareas/MultiLineChart.js +1 -1
- package/dist/charts/linesareas/TrendChart.js +15 -5
- package/dist/charts/linesareas/index.js +2 -6
- package/dist/charts/massive/MassiveChart.js +3 -2
- package/dist/charts/mathematical/FourierSeriesChart.js +7 -1
- package/dist/charts/mathematical/index.js +2 -6
- package/dist/charts/matrix/GridPlot.js +27 -2
- package/dist/charts/matrix/TilegramChart.js +2 -2
- package/dist/charts/mlcharts/AttentionGrid.js +79 -0
- package/dist/charts/mlcharts/AttentionHeatmap.js +329 -0
- package/dist/charts/mlcharts/AttentionModel.js +132 -0
- package/dist/charts/mlcharts/AttentionSamples.js +82 -0
- package/dist/charts/mlcharts/CellNumber.js +8 -0
- package/dist/charts/mlcharts/CurveDiagnosticSamples.js +95 -0
- package/dist/charts/mlcharts/CurvePickMark.js +31 -0
- package/dist/charts/mlcharts/DecisionBoundaryChart.js +316 -0
- package/dist/charts/mlcharts/DecisionSamples.js +60 -0
- package/dist/charts/mlcharts/DecisionSurface.js +130 -0
- package/dist/charts/mlcharts/DistinctTicks.js +13 -0
- package/dist/charts/mlcharts/ElbowMath.js +153 -0
- package/dist/charts/mlcharts/ElbowPlot.js +273 -0
- package/dist/charts/mlcharts/ExplainabilitySamples.js +70 -0
- package/dist/charts/mlcharts/FeatureImportanceChart.js +150 -0
- package/dist/charts/mlcharts/ImportanceRanking.js +98 -0
- package/dist/charts/mlcharts/LearningCurveChart.js +276 -0
- package/dist/charts/mlcharts/LearningCurveMath.js +92 -0
- package/dist/charts/mlcharts/PartialDependence.js +92 -0
- package/dist/charts/mlcharts/PartialDependencePlot.js +225 -0
- package/dist/charts/mlcharts/WideLabel.js +28 -0
- package/dist/charts/mlcharts/curveDiagnosticEnums.js +37 -0
- package/dist/charts/mlcharts/index.js +32 -0
- package/dist/charts/proportion/index.js +5 -9
- package/dist/charts/scatter/CategoryScatterBase.js +1 -4
- package/dist/charts/scatter/ConnectedScatter.js +7 -4
- package/dist/charts/scatter/MarginalScatter.js +13 -8
- package/dist/charts/scatter/index.js +4 -17
- package/dist/charts/scientific/SpectrogramChart.js +9 -3
- package/dist/charts/scientific/index.js +2 -2
- package/dist/charts/signals/index.js +3 -13
- package/dist/charts/statistics/LorenzCurve.js +7 -4
- package/dist/charts/threebars/Candlestick3DChart.js +18 -2
- package/dist/charts/threeglobe/GlobeChart.js +2 -2
- package/dist/charts/threeglobe/GlobeSamples.js +2 -1
- package/dist/charts/threeglobe/RingGlobe.js +1 -1
- package/dist/charts/threenetwork/ConeTreeChart.js +2 -1
- package/dist/charts/threenetwork/Gantt3DChart.js +3 -2
- package/dist/charts/threesurfaces/Ridgeline3DChart.js +22 -4
- package/dist/charts/threevolume/LorenzAttractor.js +19 -0
- package/dist/charts/threevolume/VolumeRaycastChart.js +4 -3
- package/dist/charts/threevolume/volumeEnums.js +1 -0
- package/dist/charts/timeline/index.js +2 -10
- package/dist/chunk-753UBLV2.cjs +33 -0
- package/dist/chunk-VX54A7KA.cjs +17 -0
- package/dist/{chunk-W5GAAAZY.cjs → chunk-WAODDPYX.cjs} +24874 -17620
- package/dist/chunk-Z3JPIJSC.cjs +338 -0
- package/dist/core/CartesianChart.js +87 -11
- package/dist/core/Chart.js +63 -15
- package/dist/core/Chart2D.js +54 -17
- package/dist/core/Chart3D.js +56 -20
- package/dist/core/ChartExportError.js +2 -0
- package/dist/core/ChartExporter.js +50 -8
- package/dist/core/ColumnCheck.js +53 -0
- package/dist/core/Context2D.js +29 -15
- package/dist/core/Context3D.js +7 -2
- package/dist/core/ExcelWriter.js +152 -0
- package/dist/core/ExportText.js +28 -0
- package/dist/core/MarkOrigin.js +88 -0
- package/dist/core/MarkStyle.js +294 -0
- package/dist/core/Palette.js +27 -7
- package/dist/core/PdfPage.js +13 -0
- package/dist/core/PdfWriter.js +245 -0
- package/dist/core/Scales.js +52 -2
- package/dist/core/SceneOverlay.js +4 -4
- package/dist/core/TextFit.js +37 -0
- package/dist/core/Theme.js +28 -1
- package/dist/core/enums.js +33 -1
- package/dist/core/pathMorph.js +15 -0
- package/dist/data/SampleData.js +1 -17
- package/dist/data/WorldSample.js +23 -0
- package/dist/index.cjs +810 -691
- package/dist/index.d.cts +8390 -2925
- package/dist/index.d.ts +8392 -2927
- package/dist/index.js +106 -56
- package/dist/react/ChartView.js +18 -8
- package/dist/react/GraphHandle.js +2 -0
- package/dist/react/components.js +74 -116
- package/package.json +13 -3
- package/dist/catalog-4UP2YFNR.cjs +0 -7
- package/dist/charts/bars/BulletBar.js +0 -184
- package/dist/charts/bars/ErrorBarColumn.js +0 -147
- package/dist/charts/bars/HistogramBar.js +0 -217
- package/dist/charts/bars/MarimekkoBar.js +0 -191
- package/dist/charts/bars/ParetoBar.js +0 -143
- package/dist/charts/comparison/PanelChart.js +0 -70
- package/dist/charts/comparison/SmallMultipleBars.js +0 -134
- package/dist/charts/comparison/SpanChart.js +0 -118
- package/dist/charts/comparison/TrellisChart.js +0 -158
- package/dist/charts/distribution/RidgeSlabs3DChart.js +0 -169
- package/dist/charts/financial/Candlestick3D.js +0 -157
- package/dist/charts/flow/BumpFlow.js +0 -212
- package/dist/charts/flow/StreamFlow.js +0 -174
- package/dist/charts/geomaps/ThiessenMap.js +0 -106
- package/dist/charts/hierarchy/ConeTree3D.js +0 -135
- package/dist/charts/hierarchy/Hierarchy3DChart.js +0 -27
- package/dist/charts/hierarchy/SpherePack3D.js +0 -81
- package/dist/charts/hierarchy/SunburstTower3D.js +0 -93
- package/dist/charts/hierarchy/TreemapSkyline3D.js +0 -98
- package/dist/charts/linesareas/ConnectedScatterTime.js +0 -206
- package/dist/charts/linesareas/SmallMultipleLines.js +0 -153
- package/dist/charts/mathematical/ParametricSurface3D.js +0 -234
- package/dist/charts/mathematical/StrangeAttractor3D.js +0 -251
- package/dist/charts/proportion/ConeFunnel.js +0 -126
- package/dist/charts/proportion/ExtrudedPieChart.js +0 -123
- package/dist/charts/scatter/BeeswarmScatter.js +0 -151
- package/dist/charts/scatter/BinnedScatterBase.js +0 -51
- package/dist/charts/scatter/ContourScatter.js +0 -116
- package/dist/charts/scatter/GridBinScatter.js +0 -98
- package/dist/charts/scatter/HexbinScatter.js +0 -74
- package/dist/charts/scatter/StripScatter.js +0 -107
- package/dist/charts/scatter/SunflowerScatter.js +0 -109
- package/dist/charts/signals/ConstellationChart.js +0 -153
- package/dist/charts/signals/CorrelogramChart.js +0 -171
- package/dist/charts/signals/EyeDiagramChart.js +0 -155
- package/dist/charts/signals/PoleZeroChart.js +0 -164
- package/dist/charts/signals/SpectrogramChart.js +0 -79
- package/dist/charts/timeline/CalendarSkylineChart.js +0 -128
- package/dist/charts/timeline/ScheduleBlocksChart.js +0 -119
- package/dist/charts/timeline/SpiralTimeline.js +0 -154
- 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 };
|