create-slide-deck 0.1.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/dist/index.js +119 -0
- package/package.json +36 -0
- package/template-full/README.md +99 -0
- package/template-full/package.json +47 -0
- package/template-full/src/reveal/components/auto-layout.ts +229 -0
- package/template-full/src/reveal/components/charts.tsx +213 -0
- package/template-full/src/reveal/core/blocks.ts +172 -0
- package/template-full/src/reveal/core/deck-init.ts +60 -0
- package/template-full/src/reveal/core/design.ts +46 -0
- package/template-full/src/reveal/core/layout.ts +187 -0
- package/template-full/src/reveal/core/mount-registry.ts +41 -0
- package/template-full/src/reveal/core/presets.ts +189 -0
- package/template-full/src/reveal/core/runtime.ts +141 -0
- package/template-full/src/reveal/core/types.ts +114 -0
- package/template-full/src/reveal/data/algorithms.ts +78 -0
- package/template-full/src/reveal/data/benchmark.ts +79 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-arc-progress.tsx +153 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-before-after.tsx +164 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-bigtext.tsx +70 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-card-flip.tsx +118 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-chat-bubbles.tsx +257 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-code.tsx +136 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-concept-map.tsx +336 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-counter.tsx +194 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-cover.tsx +188 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-dark-dashboard.tsx +166 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-eval-matrix.tsx +191 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-force-graph.tsx +169 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-fullbleed-bars.tsx +109 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-fullbleed-flow.tsx +177 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-heatmap.tsx +135 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-icon-wall.tsx +143 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-math.tsx +103 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-number-morph.tsx +126 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-path.tsx +185 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-radar.tsx +124 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-rough.tsx +169 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-sankey.tsx +144 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-screenshot-annotate.tsx +181 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-stacked-cards.tsx +159 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-tabs.tsx +206 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-timeline.tsx +162 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-treemap.tsx +161 -0
- package/template-full/src/reveal/decks/demo-showcase/components/demo-zoom-focus.tsx +223 -0
- package/template-full/src/reveal/decks/demo-showcase/components/registry.ts +63 -0
- package/template-full/src/reveal/decks/demo-showcase/demo.css +237 -0
- package/template-full/src/reveal/decks/demo-showcase/index.html +24 -0
- package/template-full/src/reveal/decks/demo-showcase/main.ts +7 -0
- package/template-full/src/reveal/decks/demo-showcase/slides.ts +271 -0
- package/template-full/src/reveal/decks/fse26-rca/components/aws-cascade.tsx +295 -0
- package/template-full/src/reveal/decks/fse26-rca/components/bench-compare.tsx +64 -0
- package/template-full/src/reveal/decks/fse26-rca/components/bench-deficiency.tsx +104 -0
- package/template-full/src/reveal/decks/fse26-rca/components/bench-loop.tsx +402 -0
- package/template-full/src/reveal/decks/fse26-rca/components/bench-needs.tsx +78 -0
- package/template-full/src/reveal/decks/fse26-rca/components/closing-takeaway.tsx +165 -0
- package/template-full/src/reveal/decks/fse26-rca/components/cloud-incidents.tsx +88 -0
- package/template-full/src/reveal/decks/fse26-rca/components/failure-modes.tsx +59 -0
- package/template-full/src/reveal/decks/fse26-rca/components/fault-heatmap.tsx +85 -0
- package/template-full/src/reveal/decks/fse26-rca/components/hierarchy-tree.tsx +93 -0
- package/template-full/src/reveal/decks/fse26-rca/components/incident-hard.tsx +72 -0
- package/template-full/src/reveal/decks/fse26-rca/components/rca-pipeline.tsx +193 -0
- package/template-full/src/reveal/decks/fse26-rca/components/registry.ts +37 -0
- package/template-full/src/reveal/decks/fse26-rca/components/simple-rca.tsx +216 -0
- package/template-full/src/reveal/decks/fse26-rca/components/sota-collapse.tsx +63 -0
- package/template-full/src/reveal/decks/fse26-rca/components/srca-results.tsx +115 -0
- package/template-full/src/reveal/decks/fse26-rca/images/aws-outage-2025-deployflow.png +0 -0
- package/template-full/src/reveal/decks/fse26-rca/images/aws-post-event-summary.png +0 -0
- package/template-full/src/reveal/decks/fse26-rca/images/bbc-crowdstrike.png +0 -0
- package/template-full/src/reveal/decks/fse26-rca/images/cnn-meta-outage-2021.png +0 -0
- package/template-full/src/reveal/decks/fse26-rca/images/cover.png +0 -0
- package/template-full/src/reveal/decks/fse26-rca/images/nyt-facebook-2021.png +0 -0
- package/template-full/src/reveal/decks/fse26-rca/images/qr-repo.png +0 -0
- package/template-full/src/reveal/decks/fse26-rca/images/verge-crowdstrike-2024.png +0 -0
- package/template-full/src/reveal/decks/fse26-rca/images/wiki-meta-outage-2021.png +0 -0
- package/template-full/src/reveal/decks/fse26-rca/index.html +30 -0
- package/template-full/src/reveal/decks/fse26-rca/main.ts +8 -0
- package/template-full/src/reveal/decks/fse26-rca/slides.ts +175 -0
- package/template-full/src/reveal/env.d.ts +38 -0
- package/template-full/src/reveal/theme.css +762 -0
- package/template-full/src/reveal/tools/dev.mjs +120 -0
- package/template-full/src/reveal/tools/export-pdf.mjs +86 -0
- package/template-full/src/reveal/tools/preview.mjs +132 -0
- package/template-full/tsconfig.json +19 -0
- package/template-full/vite.config.ts +95 -0
- package/template-minimal/package.json +42 -0
- package/template-minimal/src/reveal/components/auto-layout.ts +229 -0
- package/template-minimal/src/reveal/components/charts.tsx +213 -0
- package/template-minimal/src/reveal/core/blocks.ts +172 -0
- package/template-minimal/src/reveal/core/deck-init.ts +60 -0
- package/template-minimal/src/reveal/core/design.ts +46 -0
- package/template-minimal/src/reveal/core/layout.ts +187 -0
- package/template-minimal/src/reveal/core/mount-registry.ts +41 -0
- package/template-minimal/src/reveal/core/presets.ts +189 -0
- package/template-minimal/src/reveal/core/runtime.ts +141 -0
- package/template-minimal/src/reveal/core/types.ts +114 -0
- package/template-minimal/src/reveal/data/.gitkeep +0 -0
- package/template-minimal/src/reveal/decks/my-deck/components/example-component.tsx +28 -0
- package/template-minimal/src/reveal/decks/my-deck/components/registry.ts +9 -0
- package/template-minimal/src/reveal/decks/my-deck/index.html +14 -0
- package/template-minimal/src/reveal/decks/my-deck/main.ts +5 -0
- package/template-minimal/src/reveal/decks/my-deck/slides.ts +34 -0
- package/template-minimal/src/reveal/env.d.ts +38 -0
- package/template-minimal/src/reveal/theme.css +762 -0
- package/template-minimal/tsconfig.json +19 -0
- package/template-minimal/vite.config.ts +95 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { SlideComponentProps } from "../../../core/types.ts";
|
|
3
|
+
import { CANVAS, SlideCanvas, vis } from "../../../core/presets.ts";
|
|
4
|
+
import { FAULT_TYPES as TYPES } from "../../../data/benchmark.ts";
|
|
5
|
+
|
|
6
|
+
const COL_W = 320;
|
|
7
|
+
const COL_GAP = 40;
|
|
8
|
+
const PAD_X = 50;
|
|
9
|
+
const CHART_H = 130;
|
|
10
|
+
const CHART_W = 240;
|
|
11
|
+
const SVG_W = 3 * COL_W + 2 * COL_GAP + 2 * PAD_X;
|
|
12
|
+
const SVG_H = 520;
|
|
13
|
+
|
|
14
|
+
function colX(i: number) { return PAD_X + i * (COL_W + COL_GAP); }
|
|
15
|
+
|
|
16
|
+
function MiniChart({ type, x, y }: { type: number; x: number; y: number }) {
|
|
17
|
+
const barW = 36;
|
|
18
|
+
const gap = 12;
|
|
19
|
+
let heights: number[];
|
|
20
|
+
let colors: string[];
|
|
21
|
+
let labels: { i: number; text: string; color: string }[] = [];
|
|
22
|
+
|
|
23
|
+
if (type === 0) {
|
|
24
|
+
heights = [18, 110, 15, 20, 16];
|
|
25
|
+
colors = ["#ddd", "#C00000", "#ddd", "#ddd", "#ddd"];
|
|
26
|
+
labels = [{ i: 1, text: "injected", color: "#C00000" }];
|
|
27
|
+
} else if (type === 1) {
|
|
28
|
+
heights = [14, 16, 13, 15, 14];
|
|
29
|
+
colors = ["#ddd", "#ddd", "#ddd", "#ddd", "#ddd"];
|
|
30
|
+
labels = [{ i: 2, text: "no signal", color: "#767676" }];
|
|
31
|
+
} else {
|
|
32
|
+
heights = [16, 42, 20, 100, 18];
|
|
33
|
+
colors = ["#ddd", "#E8912D", "#ddd", "#76B82A", "#ddd"];
|
|
34
|
+
labels = [
|
|
35
|
+
{ i: 1, text: "root cause", color: "#E8912D" },
|
|
36
|
+
{ i: 3, text: "loudest", color: "#76B82A" },
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const totalW = 5 * barW + 4 * gap;
|
|
41
|
+
const startX = x + (CHART_W - totalW) / 2;
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<g>
|
|
45
|
+
<rect x={x - 10} y={y - 10} width={CHART_W + 20} height={CHART_H + 20} rx="10" fill="#F8F8F8" stroke="#eee" strokeWidth="1" />
|
|
46
|
+
{heights.map(function (h, i) {
|
|
47
|
+
const bx = startX + i * (barW + gap);
|
|
48
|
+
const by = y + CHART_H - h;
|
|
49
|
+
return <rect key={i} x={bx} y={by} width={barW} height={h} rx="4" fill={colors[i]} />;
|
|
50
|
+
})}
|
|
51
|
+
{labels.map(function (l) {
|
|
52
|
+
const bx = startX + l.i * (barW + gap) + barW / 2;
|
|
53
|
+
const lh = heights[l.i];
|
|
54
|
+
return <text key={l.i} x={bx} y={y + CHART_H - lh - 8} textAnchor="middle" fontSize="14" fontWeight="800" fill={l.color} fontFamily={CANVAS.fontFamily}>{l.text}</text>;
|
|
55
|
+
})}
|
|
56
|
+
</g>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default function BenchDeficiency({ Reveal }: SlideComponentProps) {
|
|
61
|
+
return (
|
|
62
|
+
<SlideCanvas Reveal={Reveal} W={SVG_W} H={SVG_H}>{(step, instant) => <>
|
|
63
|
+
|
|
64
|
+
{TYPES.map(function (t, i) {
|
|
65
|
+
const x = colX(i);
|
|
66
|
+
const chartX = x + (COL_W - CHART_W) / 2;
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<g key={i} style={vis(step, i, instant)}>
|
|
70
|
+
<MiniChart type={i} x={chartX} y={20} />
|
|
71
|
+
|
|
72
|
+
<text x={x + COL_W / 2} y={220} textAnchor="middle" fontSize="42" fontWeight="900" fill={t.color} fontFamily={CANVAS.fontFamily}>{t.pct}%</text>
|
|
73
|
+
|
|
74
|
+
<text x={x + COL_W / 2} y={250} textAnchor="middle" fontSize="14" fontWeight="800" fill={t.color} fontFamily={CANVAS.fontFamily}>{t.label}</text>
|
|
75
|
+
|
|
76
|
+
<text x={x + COL_W / 2} y={280} textAnchor="middle" fontSize="22" fontWeight="900" fill="#313131" fontFamily={CANVAS.fontFamily}>{t.title}</text>
|
|
77
|
+
|
|
78
|
+
<foreignObject x={x} y={294} width={COL_W} height={60}>
|
|
79
|
+
<div style={{ textAlign: "center", fontFamily: CANVAS.fontFamily }}>
|
|
80
|
+
<div style={{ fontSize: 16, fontWeight: 700, color: "#767676", lineHeight: 1.3 }}>{t.desc}</div>
|
|
81
|
+
<div style={{ fontSize: 14, fontWeight: 700, color: t.color, marginTop: 4 }}>{t.detail}</div>
|
|
82
|
+
</div>
|
|
83
|
+
</foreignObject>
|
|
84
|
+
</g>
|
|
85
|
+
);
|
|
86
|
+
})}
|
|
87
|
+
|
|
88
|
+
<g style={vis(step, 3, instant)}>
|
|
89
|
+
<text x={SVG_W / 2} y={SVG_H - 68} textAnchor="middle" fontSize="22" fontWeight="800" fill="#313131" fontFamily={CANVAS.fontFamily}>
|
|
90
|
+
<tspan fill="#C00000" fontWeight="900">68%</tspan>
|
|
91
|
+
<tspan fill="#767676"> trivially easy + </tspan>
|
|
92
|
+
<tspan fill="#767676" fontWeight="900">18%</tspan>
|
|
93
|
+
<tspan fill="#767676"> no signal = </tspan>
|
|
94
|
+
<tspan fill="#C00000" fontWeight="900" fontSize="28">86%</tspan>
|
|
95
|
+
<tspan> fail to test causal reasoning</tspan>
|
|
96
|
+
</text>
|
|
97
|
+
<text x={SVG_W / 2} y={SVG_H - 34} textAnchor="middle" fontSize="18" fontWeight="700" fill="#767676" fontFamily={CANVAS.fontFamily}>
|
|
98
|
+
<tspan fill="#C00000" fontWeight="900">99%</tspan>
|
|
99
|
+
<tspan> of cases lack complete observability data</tspan>
|
|
100
|
+
</text>
|
|
101
|
+
</g>
|
|
102
|
+
</>}</SlideCanvas>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { hierarchy, tree as d3tree } from "d3-hierarchy";
|
|
3
|
+
import type { SlideComponentProps } from "../../../core/types.ts";
|
|
4
|
+
import { findLargestSlot } from "../../../components/auto-layout.ts";
|
|
5
|
+
import { NODE, CANVAS, SlideCanvas, vis } from "../../../core/presets.ts";
|
|
6
|
+
|
|
7
|
+
const NODES = [
|
|
8
|
+
{ id: "system", label: "TrainTicket", color: "#1B556B", cx: 80, cy: 230 },
|
|
9
|
+
{ id: "load", label: "Dynamic load", color: "#76B82A", cx: 250, cy: 60 },
|
|
10
|
+
{ id: "fault", label: "Fault controller", color: "#C00000", cx: 430, cy: 60 },
|
|
11
|
+
{ id: "telemetry", label: "Telemetry", color: "#00A6D6", cx: 430, cy: 400 },
|
|
12
|
+
{ id: "validator", label: "SLI validator", color: "#76B82A", cx: 250, cy: 400 },
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const ICON_PATHS = {
|
|
16
|
+
system: "M2 20h20M4 20V4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v16M12 12h.01M8 12h.01M16 12h.01",
|
|
17
|
+
load: "M22 12h-4l-3 9L9 3l-3 9H2",
|
|
18
|
+
fault: "M13 2L3 14h9l-1 8 10-12h-9l1-8z",
|
|
19
|
+
telemetry: "M4 7V4a2 2 0 0 1 2-2h8.5L20 7.5V20a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-3M8 12h8M8 16h8M8 8h2",
|
|
20
|
+
validator: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10zM9 12l2 2 4-4",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const LINKS = [
|
|
24
|
+
{ from: 0, to: 1, nodeStep: 1 },
|
|
25
|
+
{ from: 1, to: 2, nodeStep: 2 },
|
|
26
|
+
{ from: 2, to: 3, nodeStep: 3 },
|
|
27
|
+
{ from: 3, to: 4, nodeStep: 4 },
|
|
28
|
+
{ from: 4, to: 0, nodeStep: 4 },
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const STEP_MAP = [
|
|
32
|
+
{ node: 0 }, { node: 1 }, { node: 1 }, { node: 1 },
|
|
33
|
+
{ node: 1 }, { node: 1 }, { node: 1 },
|
|
34
|
+
{ node: 2 }, { node: 3 }, { node: 4 },
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const TITLES = [
|
|
38
|
+
"50 services with realistic dependencies",
|
|
39
|
+
"Booking Request", "3 required parameters",
|
|
40
|
+
"Seat & Insurance options", "Passenger selection methods",
|
|
41
|
+
"Recursive sub-workflows", "36 API combinations per booking flow",
|
|
42
|
+
"31 fault types across 7 categories",
|
|
43
|
+
"Metrics, logs, traces from all services",
|
|
44
|
+
"84.4% filtered — only impacting cases kept",
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
const LOAD_W = 760, LOAD_H = 280;
|
|
48
|
+
|
|
49
|
+
const VBS = {
|
|
50
|
+
0: "0 0 360 200",
|
|
51
|
+
1: "0 0 " + LOAD_W + " " + LOAD_H,
|
|
52
|
+
2: "0 0 280 110",
|
|
53
|
+
3: "0 0 280 100",
|
|
54
|
+
4: "0 0 280 110",
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
function nodeForStep(step: number) {
|
|
58
|
+
if (step < 0 || step >= STEP_MAP.length) return -1;
|
|
59
|
+
return STEP_MAP[step].node;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function maxStepForNode(nodeIdx: number) {
|
|
63
|
+
let max = -1;
|
|
64
|
+
for (let i = 0; i < STEP_MAP.length; i++) {
|
|
65
|
+
if (STEP_MAP[i].node <= nodeIdx && i > max) max = i;
|
|
66
|
+
}
|
|
67
|
+
return max;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function anim(delay: number, instant: boolean) {
|
|
71
|
+
if (instant) return { opacity: 1 };
|
|
72
|
+
return { opacity: 0, animation: "blFadeIn 0.4s ease " + delay + "s forwards" };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function SystemIllust({ instant }: { instant: boolean }) {
|
|
76
|
+
const nodes: [number, number, string, string | null][] = [
|
|
77
|
+
[60,50,"#1B556B","order"],[150,35,"#00A6D6","travel"],[240,55,"#76B82A","seat"],
|
|
78
|
+
[300,110,"#1B556B","pay"],[210,125,"#E8912D","route"],[105,118,"#00A6D6","auth"],
|
|
79
|
+
[45,148,"#76B82A",null],[165,170,"#C00000",null],
|
|
80
|
+
];
|
|
81
|
+
const lines: [number, number, number, number][] = [
|
|
82
|
+
[60,50,150,35],[150,35,240,55],[240,55,300,110],[300,110,210,125],
|
|
83
|
+
[210,125,105,118],[105,118,60,50],[105,118,45,148],[210,125,165,170],
|
|
84
|
+
[150,35,210,125],[60,50,105,118],
|
|
85
|
+
];
|
|
86
|
+
return (
|
|
87
|
+
<g>
|
|
88
|
+
{lines.map(function(l,i) {
|
|
89
|
+
return <line key={"l"+i} x1={l[0]} y1={l[1]} x2={l[2]} y2={l[3]} stroke="#ddd" strokeWidth="1.5" style={anim(0.1+i*0.05, instant)} />;
|
|
90
|
+
})}
|
|
91
|
+
{nodes.map(function(n,i) {
|
|
92
|
+
return (
|
|
93
|
+
<g key={"n"+i} style={anim(0.3+i*0.1, instant)}>
|
|
94
|
+
<circle cx={n[0]} cy={n[1]} r={14} fill="white" stroke={n[2]} strokeWidth="2.5" />
|
|
95
|
+
{n[3] && <text x={n[0]} y={n[1]-20} textAnchor="middle" fontSize="14" fontWeight="700" fill="#999">{n[3]}</text>}
|
|
96
|
+
</g>
|
|
97
|
+
);
|
|
98
|
+
})}
|
|
99
|
+
</g>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const LOAD_TREE = {
|
|
104
|
+
n: "Booking Request", step: 0, color: "#76B82A", style: "root",
|
|
105
|
+
children: [
|
|
106
|
+
{ n: "Passenger", step: 1, color: "#00A6D6", style: "param", count: 6,
|
|
107
|
+
children: [
|
|
108
|
+
{ n: "Query", step: 3, style: "leaf", tag: "1" },
|
|
109
|
+
{ n: "Modify", step: 3, style: "leaf", tag: "1" },
|
|
110
|
+
{ n: "Create New", step: 3, color: "#C00000", style: "highlight",
|
|
111
|
+
children: [
|
|
112
|
+
{ n: "ID Number", step: 4, color: "#C00000", style: "sub",
|
|
113
|
+
children: [
|
|
114
|
+
{ n: "Generate", step: 4, style: "leaf" },
|
|
115
|
+
{ n: "Retrieve", step: 4, style: "leaf" },
|
|
116
|
+
]},
|
|
117
|
+
{ n: "Passenger Name", step: 4, color: "#C00000", style: "sub",
|
|
118
|
+
children: [
|
|
119
|
+
{ n: "Generate", step: 4, style: "leaf" },
|
|
120
|
+
{ n: "Retrieve", step: 4, style: "leaf" },
|
|
121
|
+
]},
|
|
122
|
+
]},
|
|
123
|
+
]},
|
|
124
|
+
{ n: "Seat Preference", step: 1, color: "#00A6D6", style: "param", count: 3,
|
|
125
|
+
children: [
|
|
126
|
+
{ n: "Window", step: 2, style: "leaf" },
|
|
127
|
+
{ n: "Aisle", step: 2, style: "leaf" },
|
|
128
|
+
{ n: "Random", step: 2, style: "leaf" },
|
|
129
|
+
]},
|
|
130
|
+
{ n: "Insurance", step: 1, color: "#00A6D6", style: "param", count: 2,
|
|
131
|
+
children: [
|
|
132
|
+
{ n: "Add", step: 2, style: "leaf" },
|
|
133
|
+
{ n: "Skip", step: 2, style: "leaf" },
|
|
134
|
+
]},
|
|
135
|
+
],
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const loadRoot = hierarchy(LOAD_TREE as any);
|
|
139
|
+
d3tree().size([LOAD_W - 120, LOAD_H - 70]).separation(function(a, b) {
|
|
140
|
+
return a.parent === b.parent ? 1.1 : 1.5;
|
|
141
|
+
})(loadRoot);
|
|
142
|
+
const loadNodes = loadRoot.descendants();
|
|
143
|
+
const loadLinks = loadRoot.links();
|
|
144
|
+
|
|
145
|
+
function LoadIllust({ subStep, instant }: { subStep: number; instant: boolean }) {
|
|
146
|
+
const gc = "#76B82A", rc = "#C00000";
|
|
147
|
+
const pad = 10;
|
|
148
|
+
return (
|
|
149
|
+
<g transform={"translate(" + (pad + 40) + "," + 14 + ")"}>
|
|
150
|
+
{loadLinks.map(function(link, i) {
|
|
151
|
+
const s = link.source.data, t = link.target.data;
|
|
152
|
+
const linkStep = t.step;
|
|
153
|
+
return (
|
|
154
|
+
<line key={"e" + i} x1={link.source.x} y1={link.source.y}
|
|
155
|
+
x2={link.target.x} y2={link.target.y}
|
|
156
|
+
stroke="#ccc" strokeWidth="1"
|
|
157
|
+
style={vis(subStep, linkStep, instant)} />
|
|
158
|
+
);
|
|
159
|
+
})}
|
|
160
|
+
|
|
161
|
+
{loadNodes.map(function(nd, i) {
|
|
162
|
+
const d = nd.data;
|
|
163
|
+
let w, h = 24, fs = 12, stroke = "#999", sw = 1, dash = "3 2", fw = 700, tc = "#666";
|
|
164
|
+
if (d.style === "root") { w = 140; h = 28; fs = 14; stroke = d.color; sw = 2; dash = "none"; fw = 800; tc = d.color; }
|
|
165
|
+
else if (d.style === "param") { w = 130; h = 26; fs = 13; stroke = d.color; sw = 1.5; dash = "none"; fw = 800; tc = d.color; }
|
|
166
|
+
else if (d.style === "highlight") { w = 92; h = 25; fs = 13; stroke = d.color; sw = 1.5; dash = "none"; fw = 800; tc = d.color; }
|
|
167
|
+
else if (d.style === "sub") { w = 104; stroke = d.color || "#999"; tc = d.color || "#666"; }
|
|
168
|
+
else { w = 74; }
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<g key={"n" + i} style={vis(subStep, d.step, instant)}>
|
|
172
|
+
<rect x={nd.x! - w/2} y={nd.y! - h/2} width={w} height={h} rx="4"
|
|
173
|
+
fill="white" stroke={stroke} strokeWidth={sw} strokeDasharray={dash} />
|
|
174
|
+
<text x={nd.x!} y={nd.y! + 5} textAnchor="middle" fontSize={fs}
|
|
175
|
+
fontWeight={fw} fill={tc} fontFamily={CANVAS.fontFamily}>{d.n}</text>
|
|
176
|
+
{d.tag && <text x={nd.x!} y={nd.y! + h/2 + 14} textAnchor="middle" fontSize="14" fontWeight="700" fill="#999">{d.tag}</text>}
|
|
177
|
+
{d.count && <text x={nd.x!} y={nd.y! + h/2 + 16} textAnchor="middle" fontSize="14" fontWeight="900" fill={gc}>{d.count}</text>}
|
|
178
|
+
</g>
|
|
179
|
+
);
|
|
180
|
+
})}
|
|
181
|
+
|
|
182
|
+
<g style={vis(subStep, 4, instant)}>
|
|
183
|
+
<text x={LOAD_W / 2} y={LOAD_H - 36} textAnchor="middle" fontSize="14" fontWeight="800" fill={rc} fontFamily={CANVAS.fontFamily}>Create New: 2 x 2 = 4 paths | Query: 1 | Modify: 1 | Total: 1 + 1 + 4 = 6</text>
|
|
184
|
+
</g>
|
|
185
|
+
|
|
186
|
+
<g style={vis(subStep, 5, instant)}>
|
|
187
|
+
<text x={LOAD_W / 2} y={LOAD_H - 10} textAnchor="middle" fontSize="14" fontWeight="900" fill="#313131" fontFamily={CANVAS.fontFamily}>6 x 3 x 2 = 36 combinations</text>
|
|
188
|
+
</g>
|
|
189
|
+
</g>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function FaultIllust({ instant }: { instant: boolean }) {
|
|
194
|
+
const cats: [number, number, string, string, number][] = [
|
|
195
|
+
[30,25,"CPU","#C00000",0.1],[90,25,"HTTP","#1B556B",0.25],[150,25,"DNS","#E8912D",0.4],
|
|
196
|
+
[30,65,"Network","#76B82A",0.55],[90,65,"Code","#7B61FF",0.7],[150,65,"Time","#00A6D6",0.85],
|
|
197
|
+
[210,45,"Disk","#999",1.0],
|
|
198
|
+
];
|
|
199
|
+
return (
|
|
200
|
+
<g>
|
|
201
|
+
{cats.map(function(c, i) {
|
|
202
|
+
return (
|
|
203
|
+
<g key={i} style={anim(c[4], instant)}>
|
|
204
|
+
<rect x={c[0]-24} y={c[1]-12} width="48" height="24" rx="6" fill={c[3]} fillOpacity="0.12" stroke={c[3]} strokeWidth="1.5" />
|
|
205
|
+
<text x={c[0]} y={c[1]+4} textAnchor="middle" fontSize="10" fontWeight="800" fill={c[3]}>{c[2]}</text>
|
|
206
|
+
</g>
|
|
207
|
+
);
|
|
208
|
+
})}
|
|
209
|
+
</g>
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function TelemetryIllust({ instant }: { instant: boolean }) {
|
|
214
|
+
return (
|
|
215
|
+
<g>
|
|
216
|
+
<g style={anim(0.1, instant)}>
|
|
217
|
+
<text x="38" y="8" textAnchor="middle" fontSize="10" fontWeight="700" fill="#00A6D6">metrics</text>
|
|
218
|
+
<line x1="6" y1="75" x2="70" y2="75" stroke="#ddd" strokeWidth="1" />
|
|
219
|
+
<line x1="6" y1="75" x2="6" y2="10" stroke="#ddd" strokeWidth="1" />
|
|
220
|
+
<polyline points="10,55 22,50 34,45 42,22 50,30 58,40 66,42" fill="none" stroke="#00A6D6" strokeWidth="2" />
|
|
221
|
+
</g>
|
|
222
|
+
<g style={anim(0.5, instant)}>
|
|
223
|
+
<text x="118" y="8" textAnchor="middle" fontSize="10" fontWeight="700" fill="#1B556B">logs</text>
|
|
224
|
+
<rect x="82" y="14" width="72" height="11" rx="2" fill="#F5F5F5" stroke="#ddd" strokeWidth="0.8" />
|
|
225
|
+
<text x="86" y="22" fontSize="8" fill="#999" fontWeight="600">INFO ok</text>
|
|
226
|
+
<rect x="82" y="28" width="72" height="11" rx="2" fill="#FFF3F3" stroke="#C00000" strokeWidth="1" />
|
|
227
|
+
<text x="86" y="36" fontSize="8" fill="#C00000" fontWeight="800">ERROR refused</text>
|
|
228
|
+
<rect x="82" y="42" width="72" height="11" rx="2" fill="#F5F5F5" stroke="#ddd" strokeWidth="0.8" />
|
|
229
|
+
<text x="86" y="50" fontSize="8" fill="#999" fontWeight="600">WARN slow</text>
|
|
230
|
+
</g>
|
|
231
|
+
<g style={anim(0.9, instant)}>
|
|
232
|
+
<text x="196" y="8" textAnchor="middle" fontSize="10" fontWeight="700" fill="#76B82A">traces</text>
|
|
233
|
+
<rect x="168" y="18" width="55" height="9" rx="2" fill="#00A6D6" fillOpacity="0.25" />
|
|
234
|
+
<rect x="178" y="32" width="40" height="9" rx="2" fill="#76B82A" fillOpacity="0.25" />
|
|
235
|
+
<rect x="188" y="46" width="30" height="9" rx="2" fill="#C00000" fillOpacity="0.25" />
|
|
236
|
+
</g>
|
|
237
|
+
</g>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function ValidatorIllust({ instant }: { instant: boolean }) {
|
|
242
|
+
return (
|
|
243
|
+
<g>
|
|
244
|
+
<g style={anim(0.1, instant)}>
|
|
245
|
+
<text x="30" y="14" fontSize="10" fontWeight="700" fill="#999">9,152 injections</text>
|
|
246
|
+
</g>
|
|
247
|
+
{[0,1,2,3,4,5,6,7,8,9].map(function(i) {
|
|
248
|
+
const x = 10 + (i % 5) * 22;
|
|
249
|
+
const y = 22 + Math.floor(i / 5) * 22;
|
|
250
|
+
const pass = i === 2 || i === 7;
|
|
251
|
+
return (
|
|
252
|
+
<g key={i} style={anim(0.3 + i * 0.08, instant)}>
|
|
253
|
+
<rect x={x} y={y} width="16" height="16" rx="3"
|
|
254
|
+
fill={pass ? "#76B82A" : "#eee"} fillOpacity={pass ? 0.3 : 1}
|
|
255
|
+
stroke={pass ? "#76B82A" : "#ddd"} strokeWidth={pass ? 2 : 1} />
|
|
256
|
+
{!pass && <line x1={x+3} y1={y+3} x2={x+13} y2={y+13} stroke="#ccc" strokeWidth="1.5" />}
|
|
257
|
+
{!pass && <line x1={x+13} y1={y+3} x2={x+3} y2={y+13} stroke="#ccc" strokeWidth="1.5" />}
|
|
258
|
+
</g>
|
|
259
|
+
);
|
|
260
|
+
})}
|
|
261
|
+
<g style={anim(1.2, instant)}>
|
|
262
|
+
<line x1="130" y1="20" x2="130" y2="60" stroke="#ddd" strokeWidth="1" />
|
|
263
|
+
<text x="140" y="30" fontSize="10" fontWeight="800" fill="#C00000">84.4% silent</text>
|
|
264
|
+
<text x="140" y="44" fontSize="10" fontWeight="700" fill="#999">no user impact</text>
|
|
265
|
+
</g>
|
|
266
|
+
<g style={anim(1.5, instant)}>
|
|
267
|
+
<line x1="130" y1="68" x2="180" y2="68" stroke="#76B82A" strokeWidth="1.5" />
|
|
268
|
+
<text x="140" y="82" fontSize="10" fontWeight="900" fill="#76B82A">1,430 cases</text>
|
|
269
|
+
<text x="140" y="94" fontSize="10" fontWeight="700" fill="#999">validated impact</text>
|
|
270
|
+
</g>
|
|
271
|
+
</g>
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const R = 30;
|
|
276
|
+
const ICON_SZ = 22;
|
|
277
|
+
const SVG_W = 1100;
|
|
278
|
+
const SVG_H = 480;
|
|
279
|
+
const MAX_D_W = 740;
|
|
280
|
+
const MAX_D_H = 470;
|
|
281
|
+
|
|
282
|
+
function curvedPath(x1: number, y1: number, x2: number, y2: number) {
|
|
283
|
+
const mx = (x1 + x2) / 2;
|
|
284
|
+
const my = (y1 + y2) / 2;
|
|
285
|
+
const dx = x2 - x1;
|
|
286
|
+
const dy = y2 - y1;
|
|
287
|
+
const len = Math.sqrt(dx * dx + dy * dy);
|
|
288
|
+
const nx = -dy / len * 30;
|
|
289
|
+
const ny = dx / len * 30;
|
|
290
|
+
return "M" + x1 + "," + y1 + " Q" + (mx + nx) + "," + (my + ny) + " " + x2 + "," + y2;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function edgePoints(n1: typeof NODES[number], n2: typeof NODES[number]) {
|
|
294
|
+
const dx = n2.cx - n1.cx;
|
|
295
|
+
const dy = n2.cy - n1.cy;
|
|
296
|
+
const len = Math.sqrt(dx * dx + dy * dy);
|
|
297
|
+
const ux = dx / len;
|
|
298
|
+
const uy = dy / len;
|
|
299
|
+
return {
|
|
300
|
+
x1: n1.cx + ux * (R + 6),
|
|
301
|
+
y1: n1.cy + uy * (R + 6),
|
|
302
|
+
x2: n2.cx - ux * (R + 6),
|
|
303
|
+
y2: n2.cy - uy * (R + 6),
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function LoopNode({ node, step, idx, instant }: { node: typeof NODES[number]; step: number; idx: number; instant: boolean }) {
|
|
308
|
+
const curNode = nodeForStep(step);
|
|
309
|
+
const isCurrent = curNode === idx;
|
|
310
|
+
const isVisible = step >= 0 && idx <= curNode;
|
|
311
|
+
const op = isVisible ? (isCurrent ? 1 : 0.5) : 0;
|
|
312
|
+
const tr = instant ? "none" : "opacity 0.4s ease";
|
|
313
|
+
const r = isCurrent ? R + 4 : R;
|
|
314
|
+
|
|
315
|
+
return (
|
|
316
|
+
<g style={{ opacity: op, transition: tr }}>
|
|
317
|
+
<circle cx={node.cx} cy={node.cy} r={r + 6} fill={node.color + "11"} />
|
|
318
|
+
<circle cx={node.cx} cy={node.cy} r={r} fill="white" stroke={node.color} strokeWidth={isCurrent ? 3.5 : 2.5} />
|
|
319
|
+
<g transform={"translate(" + (node.cx - ICON_SZ / 2) + "," + (node.cy - ICON_SZ / 2) + ")"}>
|
|
320
|
+
<svg width={ICON_SZ} height={ICON_SZ} viewBox="0 0 24 24" fill="none"
|
|
321
|
+
stroke={node.color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
322
|
+
<path d={(ICON_PATHS as Record<string, string>)[node.id]} />
|
|
323
|
+
</svg>
|
|
324
|
+
</g>
|
|
325
|
+
<text x={node.cx} y={node.cy + r + 18} textAnchor="middle" fontSize="16" fontWeight="900"
|
|
326
|
+
fill={NODE.labelColor} fontFamily={CANVAS.fontFamily}>{node.label}</text>
|
|
327
|
+
</g>
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function renderIllust(step: number, instant: boolean) {
|
|
332
|
+
const curNode = nodeForStep(step);
|
|
333
|
+
if (curNode === 0) return <SystemIllust instant={instant} />;
|
|
334
|
+
if (curNode === 1) { const sub = step - 1; return <LoadIllust subStep={sub} instant={instant} />; }
|
|
335
|
+
if (curNode === 2) return <FaultIllust instant={instant} />;
|
|
336
|
+
if (curNode === 3) return <TelemetryIllust instant={instant} />;
|
|
337
|
+
if (curNode === 4) return <ValidatorIllust instant={instant} />;
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export default function BenchLoop({ Reveal }: SlideComponentProps) {
|
|
342
|
+
return (
|
|
343
|
+
<SlideCanvas Reveal={Reveal} W={SVG_W} H={SVG_H}>{(step, instant) => {
|
|
344
|
+
const tr = instant ? "none" : "opacity 0.4s ease";
|
|
345
|
+
const curNode = nodeForStep(step);
|
|
346
|
+
const curVb = curNode >= 0 ? (VBS as Record<number, string>)[curNode] : "0 0 240 120";
|
|
347
|
+
|
|
348
|
+
const occ = [];
|
|
349
|
+
for (let ni = 0; ni <= Math.min(curNode, NODES.length - 1); ni++) {
|
|
350
|
+
const nd = NODES[ni];
|
|
351
|
+
occ.push({ x: nd.cx - R - 12, y: nd.cy - R - 20, w: 2 * (R + 12), h: 2 * R + 20 + 30 });
|
|
352
|
+
}
|
|
353
|
+
const slot = step >= 0 ? findLargestSlot({
|
|
354
|
+
canvasW: SVG_W, canvasH: SVG_H, occupied: occ,
|
|
355
|
+
maxW: MAX_D_W, maxH: MAX_D_H, margin: 14, step: 16,
|
|
356
|
+
}) : { x: 530, y: 30, w: 560, h: 420 };
|
|
357
|
+
|
|
358
|
+
return (<>
|
|
359
|
+
<defs>
|
|
360
|
+
<marker id="loop-arr" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
|
|
361
|
+
<path d="M 0 0 L 10 5 L 0 10 z" fill="#BFBFBF" />
|
|
362
|
+
</marker>
|
|
363
|
+
<style>{"\n@keyframes blFadeIn { from { opacity: 0; } to { opacity: 1; } }\n"}</style>
|
|
364
|
+
</defs>
|
|
365
|
+
|
|
366
|
+
{LINKS.map(function (link, i) {
|
|
367
|
+
const n1 = NODES[link.from], n2 = NODES[link.to];
|
|
368
|
+
const e = edgePoints(n1, n2);
|
|
369
|
+
const linkVisible = curNode >= link.nodeStep;
|
|
370
|
+
return <path key={i} d={curvedPath(e.x1, e.y1, e.x2, e.y2)}
|
|
371
|
+
fill="none" stroke="#BFBFBF" strokeWidth="2.5" strokeLinecap="round"
|
|
372
|
+
markerEnd="url(#loop-arr)" style={{ opacity: linkVisible ? 0.6 : 0, transition: tr }} />;
|
|
373
|
+
})}
|
|
374
|
+
|
|
375
|
+
{NODES.map(function (n, i) {
|
|
376
|
+
return <LoopNode key={n.id} node={n} step={step} idx={i} instant={instant} />;
|
|
377
|
+
})}
|
|
378
|
+
|
|
379
|
+
{step >= 0 && curNode >= 0 && (
|
|
380
|
+
<g key={"detail-" + curNode + "-" + step}>
|
|
381
|
+
<rect x={slot.x} y={slot.y} width={slot.w} height={slot.h} rx="12"
|
|
382
|
+
fill="white" fillOpacity="0.85" stroke="none" />
|
|
383
|
+
<foreignObject x={slot.x} y={slot.y} width={slot.w} height={slot.h}>
|
|
384
|
+
<div style={{
|
|
385
|
+
width: "100%", height: "100%", display: "flex", flexDirection: "column",
|
|
386
|
+
alignItems: "center", justifyContent: "center",
|
|
387
|
+
fontFamily: CANVAS.fontFamily, padding: "12px 20px", boxSizing: "border-box",
|
|
388
|
+
}}>
|
|
389
|
+
<svg style={{ flex: "1 1 auto", width: "100%", maxHeight: "82%" }} viewBox={curVb}>
|
|
390
|
+
{renderIllust(step, instant)}
|
|
391
|
+
</svg>
|
|
392
|
+
<div style={{ marginTop: 8, fontSize: 18, fontWeight: 800, color: "#313131", textAlign: "center", lineHeight: 1.3 }}>
|
|
393
|
+
{TITLES[step] || ""}
|
|
394
|
+
</div>
|
|
395
|
+
</div>
|
|
396
|
+
</foreignObject>
|
|
397
|
+
</g>
|
|
398
|
+
)}
|
|
399
|
+
</>);
|
|
400
|
+
}}</SlideCanvas>
|
|
401
|
+
);
|
|
402
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { SlideComponentProps } from "../../../core/types.ts";
|
|
3
|
+
import { CANVAS, MIN_FONT, SlideCanvas, vis } from "../../../core/presets.ts";
|
|
4
|
+
|
|
5
|
+
const W = 1200, H = 560;
|
|
6
|
+
const R = 46;
|
|
7
|
+
const CY = 280;
|
|
8
|
+
|
|
9
|
+
const C = { red: "#C00000", green: "#76B82A", label: "#313131", sub: "#767676" };
|
|
10
|
+
|
|
11
|
+
function IconNode({ cx, color, label, sub, children }: { cx: number; color: string; label: string; sub: string; children: React.ReactNode }) {
|
|
12
|
+
const iconScale = (R * 1.45) / 24;
|
|
13
|
+
const tx = cx - 12 * iconScale;
|
|
14
|
+
const ty = CY - 12 * iconScale;
|
|
15
|
+
return (
|
|
16
|
+
<g>
|
|
17
|
+
<circle cx={cx} cy={CY} r={R} fill={color} fillOpacity={0.08} stroke={color} strokeWidth={4} />
|
|
18
|
+
<g transform={"translate(" + tx + "," + ty + ") scale(" + iconScale + ")"} stroke={color} color={color}>
|
|
19
|
+
{children}
|
|
20
|
+
</g>
|
|
21
|
+
<text x={cx} y={CY + R + 38} textAnchor="middle" fontSize={24} fontWeight={900} fill={C.label} fontFamily={CANVAS.fontFamily}>
|
|
22
|
+
{label}
|
|
23
|
+
</text>
|
|
24
|
+
<text x={cx} y={CY + R + 64} textAnchor="middle" fontSize={MIN_FONT} fontWeight={600} fill={C.sub} fontFamily={CANVAS.fontFamily}>
|
|
25
|
+
{sub}
|
|
26
|
+
</text>
|
|
27
|
+
</g>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function Arrow({ fromX, toX, instant, step, req }: { fromX: number; toX: number; instant: boolean; step: number; req: number }) {
|
|
32
|
+
const gap = R + 14;
|
|
33
|
+
const x1 = fromX + gap;
|
|
34
|
+
const x2 = toX - gap;
|
|
35
|
+
return (
|
|
36
|
+
<g style={vis(step, req, instant)}>
|
|
37
|
+
<line x1={x1} y1={CY} x2={x2} y2={CY} stroke={C.green} strokeWidth={3} markerEnd="url(#bn-arrow-green)" />
|
|
38
|
+
</g>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default function BenchNeeds({ Reveal }: SlideComponentProps) {
|
|
43
|
+
const x0 = W * 0.2, x1 = W * 0.5, x2 = W * 0.8;
|
|
44
|
+
return (
|
|
45
|
+
<SlideCanvas Reveal={Reveal} W={W} H={H}>{(step, instant) => <>
|
|
46
|
+
<defs>
|
|
47
|
+
<marker id="bn-arrow-green" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
|
48
|
+
<path d="M0,0 L10,5 L0,10 z" fill={C.green} />
|
|
49
|
+
</marker>
|
|
50
|
+
</defs>
|
|
51
|
+
|
|
52
|
+
<Arrow fromX={x0} toX={x1} instant={instant} step={step} req={1} />
|
|
53
|
+
<Arrow fromX={x1} toX={x2} instant={instant} step={step} req={2} />
|
|
54
|
+
|
|
55
|
+
<g style={vis(step, 0, instant)}>
|
|
56
|
+
<IconNode cx={x0} color={C.red} label="Known source" sub="where fault starts">
|
|
57
|
+
<path d="M8 2l1.88 1.88M14.12 3.88 16 2M9 7.13v-1a3.003 3.003 0 1 1 6 0v1" fill="none" strokeWidth="2" strokeLinecap="round" />
|
|
58
|
+
<path d="M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6" fill="none" strokeWidth="2" />
|
|
59
|
+
<path d="M12 20v-9M6.53 9C4.6 8.8 3 7.1 3 5M6 13H2M3 21c0-2.1 1.7-3.9 3.8-4M20.97 5c0 2.1-1.6 3.8-3.5 4M22 13h-4M17.2 17c2.1.1 3.8 1.9 3.8 4" fill="none" strokeWidth="2" strokeLinecap="round" />
|
|
60
|
+
</IconNode>
|
|
61
|
+
</g>
|
|
62
|
+
|
|
63
|
+
<g style={vis(step, 1, instant)}>
|
|
64
|
+
<IconNode cx={x1} color={C.green} label="Propagation path" sub="path is preserved">
|
|
65
|
+
<circle cx="6" cy="19" r="2" fill="none" strokeWidth="2" />
|
|
66
|
+
<circle cx="18" cy="5" r="2" fill="none" strokeWidth="2" />
|
|
67
|
+
<path d="M6 17V7a5 5 0 0 1 5-5h1a5 5 0 0 1 5 5v10a5 5 0 0 0 5 5h1" fill="none" strokeWidth="2" strokeLinecap="round" />
|
|
68
|
+
</IconNode>
|
|
69
|
+
</g>
|
|
70
|
+
|
|
71
|
+
<g style={vis(step, 2, instant)}>
|
|
72
|
+
<IconNode cx={x2} color={C.green} label="User impact" sub="impact is validated">
|
|
73
|
+
<path d="m12 14 4-4M3.34 19a10 10 0 1 1 17.32 0" fill="none" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
|
74
|
+
</IconNode>
|
|
75
|
+
</g>
|
|
76
|
+
</>}</SlideCanvas>
|
|
77
|
+
);
|
|
78
|
+
}
|