@sentropic/design-system-svelte 0.18.0 → 0.20.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/BoxPlotChart.svelte +302 -0
- package/dist/BoxPlotChart.svelte.d.ts +40 -0
- package/dist/BoxPlotChart.svelte.d.ts.map +1 -0
- package/dist/BulletChart.svelte +479 -0
- package/dist/BulletChart.svelte.d.ts +32 -0
- package/dist/BulletChart.svelte.d.ts.map +1 -0
- package/dist/BumpChart.svelte +387 -0
- package/dist/BumpChart.svelte.d.ts +35 -0
- package/dist/BumpChart.svelte.d.ts.map +1 -0
- package/dist/CalendarHeatmapChart.svelte +345 -0
- package/dist/CalendarHeatmapChart.svelte.d.ts +28 -0
- package/dist/CalendarHeatmapChart.svelte.d.ts.map +1 -0
- package/dist/CandlestickChart.svelte +333 -0
- package/dist/CandlestickChart.svelte.d.ts +31 -0
- package/dist/CandlestickChart.svelte.d.ts.map +1 -0
- package/dist/HeatmapChart.svelte +337 -0
- package/dist/HeatmapChart.svelte.d.ts +35 -0
- package/dist/HeatmapChart.svelte.d.ts.map +1 -0
- package/dist/HistogramChart.svelte +294 -0
- package/dist/HistogramChart.svelte.d.ts +38 -0
- package/dist/HistogramChart.svelte.d.ts.map +1 -0
- package/dist/MarimekkoChart.svelte +319 -0
- package/dist/MarimekkoChart.svelte.d.ts +35 -0
- package/dist/MarimekkoChart.svelte.d.ts.map +1 -0
- package/dist/ParallelCoordinatesChart.svelte +315 -0
- package/dist/ParallelCoordinatesChart.svelte.d.ts +35 -0
- package/dist/ParallelCoordinatesChart.svelte.d.ts.map +1 -0
- package/dist/RadarChart.svelte +340 -0
- package/dist/RadarChart.svelte.d.ts +43 -0
- package/dist/RadarChart.svelte.d.ts.map +1 -0
- package/dist/SankeyChart.svelte +364 -0
- package/dist/SankeyChart.svelte.d.ts +45 -0
- package/dist/SankeyChart.svelte.d.ts.map +1 -0
- package/dist/SunburstChart.svelte +388 -0
- package/dist/SunburstChart.svelte.d.ts +39 -0
- package/dist/SunburstChart.svelte.d.ts.map +1 -0
- package/dist/chartContrast.d.ts +0 -4
- package/dist/chartContrast.d.ts.map +1 -1
- package/dist/chartContrast.js +4 -56
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/package.json +1 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RadarChart - API canonique (référence Svelte, React/Vue doivent s'aligner)
|
|
3
|
+
*
|
|
4
|
+
* Props obligatoires :
|
|
5
|
+
* axes string[] - libellés des axes (N axes = polygone à N côtés)
|
|
6
|
+
* series RadarChartSeries[] - séries {label, values: number[], tone?}
|
|
7
|
+
* label string - aria-label du graphique
|
|
8
|
+
*
|
|
9
|
+
* Props optionnelles :
|
|
10
|
+
* maxValue number (défaut : max des valeurs, min 1) - valeur plafond du
|
|
11
|
+
* domaine. PAS de plancher arbitraire à 100 - l'échelle
|
|
12
|
+
* s'adapte aux données. React/Vue doivent supprimer leur
|
|
13
|
+
* `Math.max(100, …)` pour s'aligner sur ce comportement.
|
|
14
|
+
* levels number (défaut 4) - nombre de cercles / anneaux de grille
|
|
15
|
+
* legend boolean (défaut false) - affiche la légende des séries
|
|
16
|
+
* width number (défaut 360) - largeur du viewBox en px
|
|
17
|
+
* height number (défaut 320) - hauteur du viewBox en px
|
|
18
|
+
* class string - classe CSS supplémentaire
|
|
19
|
+
*
|
|
20
|
+
* NaN/vide : les valeurs non-finies sont exclues du calcul du domaine
|
|
21
|
+
* (filter Number.isFinite). Séries vides → polygone nul sans crash.
|
|
22
|
+
*/
|
|
23
|
+
export type RadarChartTone = "category1" | "category2" | "category3" | "category4" | "category5" | "category6" | "category7" | "category8";
|
|
24
|
+
export type RadarChartSeries = {
|
|
25
|
+
label: string;
|
|
26
|
+
values: number[];
|
|
27
|
+
tone?: RadarChartTone;
|
|
28
|
+
};
|
|
29
|
+
type RadarChartProps = {
|
|
30
|
+
axes: string[];
|
|
31
|
+
series: RadarChartSeries[];
|
|
32
|
+
label: string;
|
|
33
|
+
legend?: boolean;
|
|
34
|
+
maxValue?: number;
|
|
35
|
+
levels?: number;
|
|
36
|
+
width?: number;
|
|
37
|
+
height?: number;
|
|
38
|
+
class?: string;
|
|
39
|
+
};
|
|
40
|
+
declare const RadarChart: import("svelte").Component<RadarChartProps, {}, "">;
|
|
41
|
+
type RadarChart = ReturnType<typeof RadarChart>;
|
|
42
|
+
export default RadarChart;
|
|
43
|
+
//# sourceMappingURL=RadarChart.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RadarChart.svelte.d.ts","sourceRoot":"","sources":["../src/lib/RadarChart.svelte.ts"],"names":[],"mappings":"AAGE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,cAAc,GACtB,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,CAAC;AAEhB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB,CAAC;AAMF,KAAK,eAAe,GAAG;IACrB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAqJJ,QAAA,MAAM,UAAU,qDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
/**
|
|
3
|
+
* SankeyChart - API canonique (référence Svelte, React/Vue doivent s'aligner)
|
|
4
|
+
*
|
|
5
|
+
* Props obligatoires :
|
|
6
|
+
* nodes SankeyChartNode[] - liste des nœuds {id, label, tone?}
|
|
7
|
+
* links SankeyChartLink[] - liste des liens {source, target, value, tone?}
|
|
8
|
+
* source/target = id d'un nœud existant ;
|
|
9
|
+
* les liens orphelins (nœud absent) sont rendus
|
|
10
|
+
* avec un fallback (pas de drop silencieux)
|
|
11
|
+
* label string - aria-label du graphique
|
|
12
|
+
*
|
|
13
|
+
* Props optionnelles :
|
|
14
|
+
* width number (défaut 560) - largeur du viewBox en px
|
|
15
|
+
* height number (défaut 280) - hauteur du viewBox en px
|
|
16
|
+
* class string - classe CSS supplémentaire
|
|
17
|
+
*
|
|
18
|
+
* Layout :
|
|
19
|
+
* Hauteur d'un nœud = max(valeurs entrantes sommées, valeurs sortantes sommées)
|
|
20
|
+
* - conservation de flux : un nœud agrégateur occupe autant que la somme
|
|
21
|
+
* de ses flux, pas juste le max d'un lien individuel.
|
|
22
|
+
*/
|
|
23
|
+
export type SankeyChartTone =
|
|
24
|
+
| "category1"
|
|
25
|
+
| "category2"
|
|
26
|
+
| "category3"
|
|
27
|
+
| "category4"
|
|
28
|
+
| "category5"
|
|
29
|
+
| "category6"
|
|
30
|
+
| "category7"
|
|
31
|
+
| "category8";
|
|
32
|
+
|
|
33
|
+
export type SankeyChartNode = {
|
|
34
|
+
id: string;
|
|
35
|
+
label: string;
|
|
36
|
+
tone?: SankeyChartTone;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type SankeyChartLink = {
|
|
40
|
+
source: string;
|
|
41
|
+
target: string;
|
|
42
|
+
value: number;
|
|
43
|
+
tone?: SankeyChartTone;
|
|
44
|
+
};
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<script lang="ts">
|
|
48
|
+
import ChartDataList from "./ChartDataList.svelte";
|
|
49
|
+
|
|
50
|
+
type SankeyChartProps = {
|
|
51
|
+
nodes: SankeyChartNode[];
|
|
52
|
+
links: SankeyChartLink[];
|
|
53
|
+
label: string;
|
|
54
|
+
width?: number;
|
|
55
|
+
height?: number;
|
|
56
|
+
class?: string;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
let {
|
|
60
|
+
nodes,
|
|
61
|
+
links,
|
|
62
|
+
label,
|
|
63
|
+
width = 560,
|
|
64
|
+
height = 280,
|
|
65
|
+
class: className
|
|
66
|
+
}: SankeyChartProps = $props();
|
|
67
|
+
|
|
68
|
+
const MARGIN = { top: 18, right: 26, bottom: 18, left: 26 };
|
|
69
|
+
const NODE_WIDTH = 14;
|
|
70
|
+
const TONES = [
|
|
71
|
+
"category1",
|
|
72
|
+
"category2",
|
|
73
|
+
"category3",
|
|
74
|
+
"category4",
|
|
75
|
+
"category5",
|
|
76
|
+
"category6",
|
|
77
|
+
"category7",
|
|
78
|
+
"category8"
|
|
79
|
+
] as const;
|
|
80
|
+
|
|
81
|
+
function magnitude(value: number): number {
|
|
82
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function nodeDepths(): Map<string, number> {
|
|
86
|
+
const depths = new Map(nodes.map((node) => [node.id, 0]));
|
|
87
|
+
for (let pass = 0; pass < nodes.length; pass += 1) {
|
|
88
|
+
let changed = false;
|
|
89
|
+
for (const link of links) {
|
|
90
|
+
const sourceDepth = depths.get(link.source) ?? 0;
|
|
91
|
+
const targetDepth = depths.get(link.target) ?? 0;
|
|
92
|
+
if (sourceDepth + 1 > targetDepth) {
|
|
93
|
+
depths.set(link.target, sourceDepth + 1);
|
|
94
|
+
changed = true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (!changed) break;
|
|
98
|
+
}
|
|
99
|
+
return depths;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let hoveredLinkIndex: number | null = $state(null);
|
|
103
|
+
|
|
104
|
+
const nodeById = $derived(new Map(nodes.map((node) => [node.id, node])));
|
|
105
|
+
|
|
106
|
+
// Conservation de flux : hauteur nœud = max(Σ flux sortants, Σ flux entrants)
|
|
107
|
+
const nodeValues = $derived.by(() => {
|
|
108
|
+
const valueOut = new Map<string, number>();
|
|
109
|
+
const valueIn = new Map<string, number>();
|
|
110
|
+
for (const node of nodes) {
|
|
111
|
+
valueOut.set(node.id, 0);
|
|
112
|
+
valueIn.set(node.id, 0);
|
|
113
|
+
}
|
|
114
|
+
for (const link of links) {
|
|
115
|
+
const value = magnitude(link.value);
|
|
116
|
+
valueOut.set(link.source, (valueOut.get(link.source) ?? 0) + value);
|
|
117
|
+
valueIn.set(link.target, (valueIn.get(link.target) ?? 0) + value);
|
|
118
|
+
}
|
|
119
|
+
const values = new Map<string, number>();
|
|
120
|
+
for (const node of nodes) {
|
|
121
|
+
values.set(node.id, Math.max(valueOut.get(node.id) ?? 0, valueIn.get(node.id) ?? 0));
|
|
122
|
+
}
|
|
123
|
+
return values;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const layout = $derived.by(() => {
|
|
127
|
+
const depths = nodeDepths();
|
|
128
|
+
const maxDepth = Math.max(0, ...Array.from(depths.values()));
|
|
129
|
+
const plotWidth = Math.max(width - MARGIN.left - MARGIN.right - NODE_WIDTH, 1);
|
|
130
|
+
const plotHeight = Math.max(height - MARGIN.top - MARGIN.bottom, 1);
|
|
131
|
+
const maxNodeValue = Math.max(1, ...Array.from(nodeValues.values()));
|
|
132
|
+
const byDepth = new Map<number, SankeyChartNode[]>();
|
|
133
|
+
|
|
134
|
+
nodes.forEach((node) => {
|
|
135
|
+
const depth = depths.get(node.id) ?? 0;
|
|
136
|
+
const bucket = byDepth.get(depth) ?? [];
|
|
137
|
+
bucket.push(node);
|
|
138
|
+
byDepth.set(depth, bucket);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const positionedNodes = nodes.map((node, index) => {
|
|
142
|
+
const depth = depths.get(node.id) ?? 0;
|
|
143
|
+
const bucket = byDepth.get(depth) ?? [node];
|
|
144
|
+
const row = Math.max(0, bucket.findIndex((entry) => entry.id === node.id));
|
|
145
|
+
const slot = plotHeight / Math.max(bucket.length, 1);
|
|
146
|
+
const nodeHeight = Math.max(24, Math.min(slot * 0.72, 18 + ((nodeValues.get(node.id) ?? 0) / maxNodeValue) * 54));
|
|
147
|
+
const x = MARGIN.left + (maxDepth === 0 ? plotWidth / 2 : (plotWidth * depth) / maxDepth);
|
|
148
|
+
const y = MARGIN.top + slot * row + (slot - nodeHeight) / 2;
|
|
149
|
+
const tone = node.tone ?? TONES[index % TONES.length];
|
|
150
|
+
return {
|
|
151
|
+
node,
|
|
152
|
+
tone,
|
|
153
|
+
x,
|
|
154
|
+
y,
|
|
155
|
+
width: NODE_WIDTH,
|
|
156
|
+
height: nodeHeight,
|
|
157
|
+
centerY: y + nodeHeight / 2
|
|
158
|
+
};
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const positionedById = new Map(positionedNodes.map((node) => [node.node.id, node]));
|
|
162
|
+
const maxLinkValue = Math.max(1, ...links.map((link) => magnitude(link.value)));
|
|
163
|
+
|
|
164
|
+
const positionedLinks = links.map((link, index) => {
|
|
165
|
+
const source = positionedById.get(link.source);
|
|
166
|
+
const target = positionedById.get(link.target);
|
|
167
|
+
const fallbackY = MARGIN.top + plotHeight / 2;
|
|
168
|
+
const x1 = (source?.x ?? MARGIN.left) + NODE_WIDTH;
|
|
169
|
+
const y1 = source?.centerY ?? fallbackY;
|
|
170
|
+
const x2 = target?.x ?? width - MARGIN.right;
|
|
171
|
+
const y2 = target?.centerY ?? fallbackY;
|
|
172
|
+
const c = Math.max(32, Math.abs(x2 - x1) * 0.5);
|
|
173
|
+
return {
|
|
174
|
+
link,
|
|
175
|
+
source,
|
|
176
|
+
target,
|
|
177
|
+
tone: link.tone ?? source?.tone ?? TONES[index % TONES.length],
|
|
178
|
+
width: Math.max(2, (magnitude(link.value) / maxLinkValue) * 18),
|
|
179
|
+
path: `M ${x1} ${y1} C ${x1 + c} ${y1}, ${x2 - c} ${y2}, ${x2} ${y2}`,
|
|
180
|
+
midX: (x1 + x2) / 2,
|
|
181
|
+
midY: (y1 + y2) / 2
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return { nodes: positionedNodes, links: positionedLinks };
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const dataValueItems = $derived(
|
|
189
|
+
links.map((link) => {
|
|
190
|
+
const source = nodeById.get(link.source)?.label ?? link.source;
|
|
191
|
+
const target = nodeById.get(link.target)?.label ?? link.target;
|
|
192
|
+
return `${source} -> ${target}: ${link.value}`;
|
|
193
|
+
})
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
function handleVisualPointerMove(event: PointerEvent) {
|
|
197
|
+
const target = event.target;
|
|
198
|
+
if (!(target instanceof Element)) {
|
|
199
|
+
hoveredLinkIndex = null;
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const index = Number(target.getAttribute("data-link-index"));
|
|
203
|
+
hoveredLinkIndex = Number.isInteger(index) ? index : null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const classes = () => ["st-sankeyChart", className].filter(Boolean).join(" ");
|
|
207
|
+
</script>
|
|
208
|
+
|
|
209
|
+
<div class={classes()}>
|
|
210
|
+
<div
|
|
211
|
+
class="st-sankeyChart__visual"
|
|
212
|
+
role="img"
|
|
213
|
+
aria-label={label}
|
|
214
|
+
onpointermove={handleVisualPointerMove}
|
|
215
|
+
onpointerleave={() => (hoveredLinkIndex = null)}
|
|
216
|
+
>
|
|
217
|
+
<svg
|
|
218
|
+
viewBox="0 0 {width} {height}"
|
|
219
|
+
preserveAspectRatio="xMidYMid meet"
|
|
220
|
+
width="100%"
|
|
221
|
+
height="100%"
|
|
222
|
+
focusable="false"
|
|
223
|
+
aria-hidden="true"
|
|
224
|
+
>
|
|
225
|
+
<g class="st-sankeyChart__links">
|
|
226
|
+
{#each layout.links as flow, i (`${flow.link.source}-${flow.link.target}-${i}`)}
|
|
227
|
+
<path
|
|
228
|
+
class="st-sankeyChart__link st-sankeyChart__link--{flow.tone}"
|
|
229
|
+
class:st-sankeyChart__link--dim={hoveredLinkIndex !== null && hoveredLinkIndex !== i}
|
|
230
|
+
d={flow.path}
|
|
231
|
+
stroke-width={flow.width}
|
|
232
|
+
data-link-index={i}
|
|
233
|
+
/>
|
|
234
|
+
{/each}
|
|
235
|
+
</g>
|
|
236
|
+
|
|
237
|
+
<g class="st-sankeyChart__nodes">
|
|
238
|
+
{#each layout.nodes as entry (entry.node.id)}
|
|
239
|
+
<rect
|
|
240
|
+
class="st-sankeyChart__node st-sankeyChart__node--{entry.tone}"
|
|
241
|
+
x={entry.x}
|
|
242
|
+
y={entry.y}
|
|
243
|
+
width={entry.width}
|
|
244
|
+
height={entry.height}
|
|
245
|
+
rx="2"
|
|
246
|
+
/>
|
|
247
|
+
<text
|
|
248
|
+
class="st-sankeyChart__nodeLabel"
|
|
249
|
+
x={entry.x + entry.width + 6}
|
|
250
|
+
y={entry.centerY}
|
|
251
|
+
dominant-baseline="middle"
|
|
252
|
+
>
|
|
253
|
+
{entry.node.label}
|
|
254
|
+
</text>
|
|
255
|
+
{/each}
|
|
256
|
+
</g>
|
|
257
|
+
</svg>
|
|
258
|
+
</div>
|
|
259
|
+
|
|
260
|
+
<ChartDataList {label} items={dataValueItems} />
|
|
261
|
+
|
|
262
|
+
{#if hoveredLinkIndex !== null && layout.links[hoveredLinkIndex]}
|
|
263
|
+
{@const flow = layout.links[hoveredLinkIndex]}
|
|
264
|
+
<div
|
|
265
|
+
class="st-sankeyChart__tooltip"
|
|
266
|
+
role="presentation"
|
|
267
|
+
style="left: {(flow.midX / width) * 100}%; top: {(flow.midY / height) * 100}%"
|
|
268
|
+
>
|
|
269
|
+
<span class="st-sankeyChart__tooltipLabel">{flow.source?.node.label ?? flow.link.source} -> {flow.target?.node.label ?? flow.link.target}</span>
|
|
270
|
+
<span class="st-sankeyChart__tooltipValue">{flow.link.value}</span>
|
|
271
|
+
</div>
|
|
272
|
+
{/if}
|
|
273
|
+
</div>
|
|
274
|
+
|
|
275
|
+
<style>
|
|
276
|
+
.st-sankeyChart {
|
|
277
|
+
color: var(--st-semantic-text-secondary);
|
|
278
|
+
display: block;
|
|
279
|
+
font-family: inherit;
|
|
280
|
+
max-width: 100%;
|
|
281
|
+
position: relative;
|
|
282
|
+
width: 100%;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.st-sankeyChart svg,
|
|
286
|
+
.st-sankeyChart__visual {
|
|
287
|
+
display: block;
|
|
288
|
+
overflow: visible;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.st-sankeyChart__link {
|
|
292
|
+
cursor: pointer;
|
|
293
|
+
fill: none;
|
|
294
|
+
opacity: 0.38;
|
|
295
|
+
stroke-linecap: round;
|
|
296
|
+
transition: opacity 120ms ease;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.st-sankeyChart__link:hover {
|
|
300
|
+
opacity: 0.62;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.st-sankeyChart__link--dim {
|
|
304
|
+
opacity: 0.16;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
@media (prefers-reduced-motion: reduce) {
|
|
308
|
+
.st-sankeyChart__link {
|
|
309
|
+
transition: none;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.st-sankeyChart__node {
|
|
314
|
+
stroke: var(--st-semantic-surface-default, Canvas);
|
|
315
|
+
stroke-width: 1;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.st-sankeyChart__link--category1,
|
|
319
|
+
.st-sankeyChart__node--category1 { stroke: var(--st-semantic-data-category1); fill: var(--st-semantic-data-category1); }
|
|
320
|
+
.st-sankeyChart__link--category2,
|
|
321
|
+
.st-sankeyChart__node--category2 { stroke: var(--st-semantic-data-category2); fill: var(--st-semantic-data-category2); }
|
|
322
|
+
.st-sankeyChart__link--category3,
|
|
323
|
+
.st-sankeyChart__node--category3 { stroke: var(--st-semantic-data-category3); fill: var(--st-semantic-data-category3); }
|
|
324
|
+
.st-sankeyChart__link--category4,
|
|
325
|
+
.st-sankeyChart__node--category4 { stroke: var(--st-semantic-data-category4); fill: var(--st-semantic-data-category4); }
|
|
326
|
+
.st-sankeyChart__link--category5,
|
|
327
|
+
.st-sankeyChart__node--category5 { stroke: var(--st-semantic-data-category5); fill: var(--st-semantic-data-category5); }
|
|
328
|
+
.st-sankeyChart__link--category6,
|
|
329
|
+
.st-sankeyChart__node--category6 { stroke: var(--st-semantic-data-category6); fill: var(--st-semantic-data-category6); }
|
|
330
|
+
.st-sankeyChart__link--category7,
|
|
331
|
+
.st-sankeyChart__node--category7 { stroke: var(--st-semantic-data-category7); fill: var(--st-semantic-data-category7); }
|
|
332
|
+
.st-sankeyChart__link--category8,
|
|
333
|
+
.st-sankeyChart__node--category8 { stroke: var(--st-semantic-data-category8); fill: var(--st-semantic-data-category8); }
|
|
334
|
+
|
|
335
|
+
.st-sankeyChart__nodeLabel {
|
|
336
|
+
fill: var(--st-semantic-text-secondary);
|
|
337
|
+
font-size: 0.75rem;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.st-sankeyChart__tooltip {
|
|
341
|
+
background: var(--st-semantic-surface-inverse);
|
|
342
|
+
border-radius: var(--st-radius-sm, 0.25rem);
|
|
343
|
+
color: var(--st-semantic-text-inverse);
|
|
344
|
+
display: inline-flex;
|
|
345
|
+
flex-direction: column;
|
|
346
|
+
font-size: 0.75rem;
|
|
347
|
+
gap: 0.125rem;
|
|
348
|
+
line-height: 1.2;
|
|
349
|
+
padding: 0.375rem 0.5rem;
|
|
350
|
+
pointer-events: none;
|
|
351
|
+
position: absolute;
|
|
352
|
+
transform: translate(-50%, -115%);
|
|
353
|
+
white-space: nowrap;
|
|
354
|
+
z-index: 1;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.st-sankeyChart__tooltipLabel {
|
|
358
|
+
font-weight: 600;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.st-sankeyChart__tooltipValue {
|
|
362
|
+
opacity: 0.85;
|
|
363
|
+
}
|
|
364
|
+
</style>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SankeyChart - API canonique (référence Svelte, React/Vue doivent s'aligner)
|
|
3
|
+
*
|
|
4
|
+
* Props obligatoires :
|
|
5
|
+
* nodes SankeyChartNode[] - liste des nœuds {id, label, tone?}
|
|
6
|
+
* links SankeyChartLink[] - liste des liens {source, target, value, tone?}
|
|
7
|
+
* source/target = id d'un nœud existant ;
|
|
8
|
+
* les liens orphelins (nœud absent) sont rendus
|
|
9
|
+
* avec un fallback (pas de drop silencieux)
|
|
10
|
+
* label string - aria-label du graphique
|
|
11
|
+
*
|
|
12
|
+
* Props optionnelles :
|
|
13
|
+
* width number (défaut 560) - largeur du viewBox en px
|
|
14
|
+
* height number (défaut 280) - hauteur du viewBox en px
|
|
15
|
+
* class string - classe CSS supplémentaire
|
|
16
|
+
*
|
|
17
|
+
* Layout :
|
|
18
|
+
* Hauteur d'un nœud = max(valeurs entrantes sommées, valeurs sortantes sommées)
|
|
19
|
+
* - conservation de flux : un nœud agrégateur occupe autant que la somme
|
|
20
|
+
* de ses flux, pas juste le max d'un lien individuel.
|
|
21
|
+
*/
|
|
22
|
+
export type SankeyChartTone = "category1" | "category2" | "category3" | "category4" | "category5" | "category6" | "category7" | "category8";
|
|
23
|
+
export type SankeyChartNode = {
|
|
24
|
+
id: string;
|
|
25
|
+
label: string;
|
|
26
|
+
tone?: SankeyChartTone;
|
|
27
|
+
};
|
|
28
|
+
export type SankeyChartLink = {
|
|
29
|
+
source: string;
|
|
30
|
+
target: string;
|
|
31
|
+
value: number;
|
|
32
|
+
tone?: SankeyChartTone;
|
|
33
|
+
};
|
|
34
|
+
type SankeyChartProps = {
|
|
35
|
+
nodes: SankeyChartNode[];
|
|
36
|
+
links: SankeyChartLink[];
|
|
37
|
+
label: string;
|
|
38
|
+
width?: number;
|
|
39
|
+
height?: number;
|
|
40
|
+
class?: string;
|
|
41
|
+
};
|
|
42
|
+
declare const SankeyChart: import("svelte").Component<SankeyChartProps, {}, "">;
|
|
43
|
+
type SankeyChart = ReturnType<typeof SankeyChart>;
|
|
44
|
+
export default SankeyChart;
|
|
45
|
+
//# sourceMappingURL=SankeyChart.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SankeyChart.svelte.d.ts","sourceRoot":"","sources":["../src/lib/SankeyChart.svelte.ts"],"names":[],"mappings":"AAGE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,eAAe,GACvB,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,GACX,WAAW,CAAC;AAEhB,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB,CAAC;AAMF,KAAK,gBAAgB,GAAG;IACtB,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAgMJ,QAAA,MAAM,WAAW,sDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|