@sentropic/design-system-svelte 0.34.36 → 0.34.38
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/DecompositionTreeChart.svelte +399 -0
- package/dist/DecompositionTreeChart.svelte.d.ts +48 -0
- package/dist/DecompositionTreeChart.svelte.d.ts.map +1 -0
- package/dist/Density2DChart.svelte +438 -0
- package/dist/Density2DChart.svelte.d.ts +39 -0
- package/dist/Density2DChart.svelte.d.ts.map +1 -0
- package/dist/FlamegraphChart.svelte +291 -0
- package/dist/FlamegraphChart.svelte.d.ts +39 -0
- package/dist/FlamegraphChart.svelte.d.ts.map +1 -0
- package/dist/TraceWaterfallChart.svelte +432 -0
- package/dist/TraceWaterfallChart.svelte.d.ts +44 -0
- package/dist/TraceWaterfallChart.svelte.d.ts.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/package.json +1 -1
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
/**
|
|
3
|
+
* Density2DChart - densité 2D NON-géographique sur axes numériques (heatmap
|
|
4
|
+
* binned, façon Tableau/Dataiku density). On agrège des points (x,y) en cellules
|
|
5
|
+
* d'une grille régulière `bins×bins` sur l'étendue [minX,maxX]×[minY,maxY] ; la
|
|
6
|
+
* couleur d'une cellule encode la DENSITÉ (somme des poids) normalisée sur
|
|
7
|
+
* l'échelle catégorielle continue category1..8 (reprise de HeatmapChart /
|
|
8
|
+
* AnomalySwimLane). Axes X/Y gradués (niceTicks) + légende rampe Low→High.
|
|
9
|
+
* API canonique (référence Svelte, React/Vue doivent s'aligner).
|
|
10
|
+
*
|
|
11
|
+
* Props obligatoires :
|
|
12
|
+
* data Density2DPoint[] - tableau { x, y, weight? }
|
|
13
|
+
*
|
|
14
|
+
* Props optionnelles :
|
|
15
|
+
* bins number (nb de bins par axe, défaut 12)
|
|
16
|
+
* label string
|
|
17
|
+
* width number (défaut 640)
|
|
18
|
+
* height number (défaut 320)
|
|
19
|
+
* size number (alias de width)
|
|
20
|
+
* class string
|
|
21
|
+
*/
|
|
22
|
+
export type Density2DTone =
|
|
23
|
+
| "category1" | "category2" | "category3" | "category4"
|
|
24
|
+
| "category5" | "category6" | "category7" | "category8";
|
|
25
|
+
|
|
26
|
+
export type Density2DPoint = {
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
weight?: number;
|
|
30
|
+
};
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<script lang="ts">
|
|
34
|
+
import ChartDataList from "./ChartDataList.svelte";
|
|
35
|
+
|
|
36
|
+
type Density2DChartProps = {
|
|
37
|
+
data: Density2DPoint[];
|
|
38
|
+
bins?: number;
|
|
39
|
+
label?: string;
|
|
40
|
+
width?: number;
|
|
41
|
+
height?: number;
|
|
42
|
+
size?: number;
|
|
43
|
+
class?: string;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
let {
|
|
47
|
+
data = [],
|
|
48
|
+
bins = 12,
|
|
49
|
+
label,
|
|
50
|
+
width,
|
|
51
|
+
height = 320,
|
|
52
|
+
size,
|
|
53
|
+
class: className
|
|
54
|
+
}: Density2DChartProps = $props();
|
|
55
|
+
|
|
56
|
+
const resolvedWidth = $derived(width ?? size ?? 640);
|
|
57
|
+
|
|
58
|
+
const MARGIN = { top: 16, right: 18, bottom: 36, left: 48 };
|
|
59
|
+
const TONES = [
|
|
60
|
+
"category1","category2","category3","category4","category5","category6","category7","category8"
|
|
61
|
+
] as const;
|
|
62
|
+
|
|
63
|
+
// Échelle continue : densité normalisée 0..max → category1..8 (reprise de
|
|
64
|
+
// HeatmapChart). max ≤ 0 ou densité non finie → category1 (intensité plancher).
|
|
65
|
+
function toneForDensity(density: number, densityMax: number): Density2DTone {
|
|
66
|
+
if (!Number.isFinite(density) || densityMax <= 0) return "category1";
|
|
67
|
+
const ratio = Math.max(0, Math.min(1, density / densityMax));
|
|
68
|
+
const index = Math.max(0, Math.min(TONES.length - 1, Math.floor(ratio * TONES.length)));
|
|
69
|
+
return TONES[index];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function niceTicks(min: number, max: number, target = 5): number[] {
|
|
73
|
+
if (!Number.isFinite(min) || !Number.isFinite(max) || min === max) {
|
|
74
|
+
return [Number.isFinite(max) ? max : 0];
|
|
75
|
+
}
|
|
76
|
+
const range = max - min;
|
|
77
|
+
const rough = range / Math.max(target - 1, 1);
|
|
78
|
+
const pow = Math.pow(10, Math.floor(Math.log10(rough)));
|
|
79
|
+
const norm = rough / pow;
|
|
80
|
+
let step: number;
|
|
81
|
+
if (norm < 1.5) step = pow;
|
|
82
|
+
else if (norm < 3) step = 2 * pow;
|
|
83
|
+
else if (norm < 7) step = 5 * pow;
|
|
84
|
+
else step = 10 * pow;
|
|
85
|
+
const start = Math.floor(min / step) * step;
|
|
86
|
+
const end = Math.ceil(max / step) * step;
|
|
87
|
+
const ticks: number[] = [];
|
|
88
|
+
for (let v = start; v <= end + step / 2; v += step) ticks.push(Number(v.toFixed(10)));
|
|
89
|
+
return ticks;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function scaleLinear(v: number, d0: number, d1: number, r0: number, r1: number) {
|
|
93
|
+
if (d1 === d0) return r0;
|
|
94
|
+
return r0 + ((v - d0) * (r1 - r0)) / (d1 - d0);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function formatTick(v: number): string {
|
|
98
|
+
if (Math.abs(v) >= 1000) return `${(v / 1000).toFixed(v % 1000 === 0 ? 0 : 1)}k`;
|
|
99
|
+
return Number.isInteger(v) ? String(v) : v.toFixed(1);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let hoveredKey: string | null = $state(null);
|
|
103
|
+
|
|
104
|
+
const plotWidth = $derived(Math.max(resolvedWidth - MARGIN.left - MARGIN.right, 1));
|
|
105
|
+
const plotHeight = $derived(Math.max(height - MARGIN.top - MARGIN.bottom, 1));
|
|
106
|
+
|
|
107
|
+
// Nombre de bins effectif : entier ≥ 1, plafonné pour rester lisible.
|
|
108
|
+
const binCount = $derived(
|
|
109
|
+
Math.max(1, Math.min(40, Math.floor(Number.isFinite(bins) ? bins : 12)))
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
// Normalise : ne garde que les points aux coordonnées finies.
|
|
113
|
+
const validData = $derived(
|
|
114
|
+
data.filter((d) => d && Number.isFinite(d.x) && Number.isFinite(d.y))
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
// Étendue [minX,maxX]×[minY,maxY] + ticks « nice » pour les axes.
|
|
118
|
+
const scales = $derived.by(() => {
|
|
119
|
+
const xs = validData.map((d) => d.x);
|
|
120
|
+
const ys = validData.map((d) => d.y);
|
|
121
|
+
const xTicks = niceTicks(xs.length ? Math.min(...xs) : 0, xs.length ? Math.max(...xs) : 1);
|
|
122
|
+
const yTicks = niceTicks(ys.length ? Math.min(...ys) : 0, ys.length ? Math.max(...ys) : 1);
|
|
123
|
+
return {
|
|
124
|
+
xTicks,
|
|
125
|
+
yTicks,
|
|
126
|
+
xMin: xTicks[0],
|
|
127
|
+
xMax: xTicks[xTicks.length - 1],
|
|
128
|
+
yMin: yTicks[0],
|
|
129
|
+
yMax: yTicks[yTicks.length - 1]
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
type Bin = {
|
|
134
|
+
key: string;
|
|
135
|
+
ix: number;
|
|
136
|
+
iy: number;
|
|
137
|
+
density: number;
|
|
138
|
+
x: number;
|
|
139
|
+
y: number;
|
|
140
|
+
width: number;
|
|
141
|
+
height: number;
|
|
142
|
+
cx: number;
|
|
143
|
+
cy: number;
|
|
144
|
+
x0: number;
|
|
145
|
+
x1: number;
|
|
146
|
+
y0: number;
|
|
147
|
+
y1: number;
|
|
148
|
+
tone: Density2DTone;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// Binning régulier : grille binCount×binCount sur l'étendue ; chaque point
|
|
152
|
+
// tombe dans une cellule, sa densité = somme des poids (défaut 1).
|
|
153
|
+
const layout = $derived.by(() => {
|
|
154
|
+
const { xMin, xMax, yMin, yMax } = scales;
|
|
155
|
+
if (validData.length === 0 || xMax === xMin || yMax === yMin) {
|
|
156
|
+
return { bins: [] as Bin[], densityMax: 0 };
|
|
157
|
+
}
|
|
158
|
+
const counts = new Float64Array(binCount * binCount);
|
|
159
|
+
const idx = (ix: number, iy: number) => iy * binCount + ix;
|
|
160
|
+
for (const d of validData) {
|
|
161
|
+
const fx = (d.x - xMin) / (xMax - xMin);
|
|
162
|
+
const fy = (d.y - yMin) / (yMax - yMin);
|
|
163
|
+
const ix = Math.max(0, Math.min(binCount - 1, Math.floor(fx * binCount)));
|
|
164
|
+
const iy = Math.max(0, Math.min(binCount - 1, Math.floor(fy * binCount)));
|
|
165
|
+
const w = typeof d.weight === "number" && Number.isFinite(d.weight) ? d.weight : 1;
|
|
166
|
+
counts[idx(ix, iy)] += w;
|
|
167
|
+
}
|
|
168
|
+
let densityMax = 0;
|
|
169
|
+
for (let i = 0; i < counts.length; i++) densityMax = Math.max(densityMax, counts[i]);
|
|
170
|
+
|
|
171
|
+
const cellW = plotWidth / binCount;
|
|
172
|
+
const cellH = plotHeight / binCount;
|
|
173
|
+
const out: Bin[] = [];
|
|
174
|
+
for (let iy = 0; iy < binCount; iy++) {
|
|
175
|
+
for (let ix = 0; ix < binCount; ix++) {
|
|
176
|
+
const density = counts[idx(ix, iy)];
|
|
177
|
+
if (density <= 0) continue;
|
|
178
|
+
// iy=0 en bas (y croissant vers le haut) → inverse l'axe écran.
|
|
179
|
+
const x = MARGIN.left + ix * cellW;
|
|
180
|
+
const y = MARGIN.top + (binCount - 1 - iy) * cellH;
|
|
181
|
+
const x0 = xMin + (ix / binCount) * (xMax - xMin);
|
|
182
|
+
const x1 = xMin + ((ix + 1) / binCount) * (xMax - xMin);
|
|
183
|
+
const y0 = yMin + (iy / binCount) * (yMax - yMin);
|
|
184
|
+
const y1 = yMin + ((iy + 1) / binCount) * (yMax - yMin);
|
|
185
|
+
out.push({
|
|
186
|
+
key: `${ix}-${iy}`,
|
|
187
|
+
ix,
|
|
188
|
+
iy,
|
|
189
|
+
density,
|
|
190
|
+
x,
|
|
191
|
+
y,
|
|
192
|
+
width: Math.max(cellW - 1, 1),
|
|
193
|
+
height: Math.max(cellH - 1, 1),
|
|
194
|
+
cx: x + cellW / 2,
|
|
195
|
+
cy: y + cellH / 2,
|
|
196
|
+
x0,
|
|
197
|
+
x1,
|
|
198
|
+
y0,
|
|
199
|
+
y1,
|
|
200
|
+
tone: toneForDensity(density, densityMax)
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return { bins: out, densityMax };
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
const binCells = $derived(layout.bins);
|
|
208
|
+
|
|
209
|
+
const xAxisTicks = $derived.by(() => {
|
|
210
|
+
const { xTicks, xMin, xMax } = scales;
|
|
211
|
+
return xTicks.map((t) => ({
|
|
212
|
+
value: t,
|
|
213
|
+
x: MARGIN.left + scaleLinear(t, xMin, xMax, 0, plotWidth)
|
|
214
|
+
}));
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
const yAxisTicks = $derived.by(() => {
|
|
218
|
+
const { yTicks, yMin, yMax } = scales;
|
|
219
|
+
return yTicks.map((t) => ({
|
|
220
|
+
value: t,
|
|
221
|
+
y: MARGIN.top + scaleLinear(t, yMin, yMax, plotHeight, 0)
|
|
222
|
+
}));
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
const dataValueItems = $derived(
|
|
226
|
+
binCells.map(
|
|
227
|
+
(b) => `[${formatTick(b.x0)}–${formatTick(b.x1)}] × [${formatTick(b.y0)}–${formatTick(b.y1)}]: ${b.density}`
|
|
228
|
+
)
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
const legendItems = $derived(TONES.map((tone) => ({ tone })));
|
|
232
|
+
const hasLegend = $derived(binCells.length > 0);
|
|
233
|
+
|
|
234
|
+
function handlePointerMove(event: PointerEvent) {
|
|
235
|
+
const target = event.target;
|
|
236
|
+
if (!(target instanceof Element)) {
|
|
237
|
+
hoveredKey = null;
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const key = target.getAttribute("data-chart-key");
|
|
241
|
+
hoveredKey = key ?? null;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const hoveredCell = $derived.by(() => {
|
|
245
|
+
if (hoveredKey === null) return null;
|
|
246
|
+
return binCells.find((b) => b.key === hoveredKey) ?? null;
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
const classes = () => ["st-density2DChart", className].filter(Boolean).join(" ");
|
|
250
|
+
</script>
|
|
251
|
+
|
|
252
|
+
<div class={classes()}>
|
|
253
|
+
<div
|
|
254
|
+
class="st-density2DChart__visual"
|
|
255
|
+
role="img"
|
|
256
|
+
aria-label={label}
|
|
257
|
+
onpointermove={handlePointerMove}
|
|
258
|
+
onpointerleave={() => (hoveredKey = null)}
|
|
259
|
+
>
|
|
260
|
+
<svg
|
|
261
|
+
viewBox="0 0 {resolvedWidth} {height}"
|
|
262
|
+
preserveAspectRatio="xMidYMid meet"
|
|
263
|
+
width="100%"
|
|
264
|
+
height="100%"
|
|
265
|
+
focusable="false"
|
|
266
|
+
aria-hidden="true"
|
|
267
|
+
>
|
|
268
|
+
<!-- tick labels (axe Y) -->
|
|
269
|
+
{#each yAxisTicks as tick (tick.value)}
|
|
270
|
+
<text class="st-density2DChart__tickLabel" x={MARGIN.left - 8} y={tick.y} text-anchor="end" dominant-baseline="middle">
|
|
271
|
+
{formatTick(tick.value)}
|
|
272
|
+
</text>
|
|
273
|
+
{/each}
|
|
274
|
+
|
|
275
|
+
<!-- tick labels (axe X) -->
|
|
276
|
+
{#each xAxisTicks as tick (tick.value)}
|
|
277
|
+
<text class="st-density2DChart__tickLabel" x={tick.x} y={height - MARGIN.bottom + 16} text-anchor="middle">
|
|
278
|
+
{formatTick(tick.value)}
|
|
279
|
+
</text>
|
|
280
|
+
{/each}
|
|
281
|
+
|
|
282
|
+
<!-- axes -->
|
|
283
|
+
<line class="st-density2DChart__axis" x1={MARGIN.left} x2={MARGIN.left} y1={MARGIN.top} y2={height - MARGIN.bottom} />
|
|
284
|
+
<line class="st-density2DChart__axis" x1={MARGIN.left} x2={resolvedWidth - MARGIN.right} y1={height - MARGIN.bottom} y2={height - MARGIN.bottom} />
|
|
285
|
+
|
|
286
|
+
<!-- cellules de densité (grille bins×bins, couleur ∝ densité) -->
|
|
287
|
+
{#each binCells as cell (cell.key)}
|
|
288
|
+
<rect
|
|
289
|
+
class="st-density2DChart__cell st-density2DChart__cell--{cell.tone}"
|
|
290
|
+
class:st-density2DChart__cell--dim={hoveredKey !== null && hoveredKey !== cell.key}
|
|
291
|
+
x={cell.x}
|
|
292
|
+
y={cell.y}
|
|
293
|
+
width={cell.width}
|
|
294
|
+
height={cell.height}
|
|
295
|
+
rx="1"
|
|
296
|
+
data-chart-key={cell.key}
|
|
297
|
+
/>
|
|
298
|
+
{/each}
|
|
299
|
+
</svg>
|
|
300
|
+
</div>
|
|
301
|
+
|
|
302
|
+
{#if hasLegend}
|
|
303
|
+
<div class="st-density2DChart__legend" aria-hidden="true">
|
|
304
|
+
<span class="st-density2DChart__legendText">Low</span>
|
|
305
|
+
<span class="st-density2DChart__legendRamp">
|
|
306
|
+
{#each legendItems as item (item.tone)}
|
|
307
|
+
<span class="st-density2DChart__legendSwatch st-density2DChart__legendSwatch--{item.tone}"></span>
|
|
308
|
+
{/each}
|
|
309
|
+
</span>
|
|
310
|
+
<span class="st-density2DChart__legendText">High</span>
|
|
311
|
+
</div>
|
|
312
|
+
{/if}
|
|
313
|
+
|
|
314
|
+
<ChartDataList label={label ?? "density 2d"} items={dataValueItems} />
|
|
315
|
+
|
|
316
|
+
{#if hoveredCell}
|
|
317
|
+
{@const cell = hoveredCell}
|
|
318
|
+
<div
|
|
319
|
+
class="st-density2DChart__tooltip"
|
|
320
|
+
role="presentation"
|
|
321
|
+
style="left: {(cell.cx / resolvedWidth) * 100}%; top: {(cell.cy / height) * 100}%"
|
|
322
|
+
>
|
|
323
|
+
<span class="st-density2DChart__tooltipLabel">[{formatTick(cell.x0)}–{formatTick(cell.x1)}] × [{formatTick(cell.y0)}–{formatTick(cell.y1)}]</span>
|
|
324
|
+
<span class="st-density2DChart__tooltipValue">{cell.density}</span>
|
|
325
|
+
</div>
|
|
326
|
+
{/if}
|
|
327
|
+
</div>
|
|
328
|
+
|
|
329
|
+
<style>
|
|
330
|
+
.st-density2DChart {
|
|
331
|
+
color: var(--st-semantic-text-secondary);
|
|
332
|
+
display: block;
|
|
333
|
+
font-family: inherit;
|
|
334
|
+
position: relative;
|
|
335
|
+
width: 100%;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.st-density2DChart svg {
|
|
339
|
+
display: block;
|
|
340
|
+
overflow: visible;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.st-density2DChart__visual {
|
|
344
|
+
display: block;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.st-density2DChart__axis {
|
|
348
|
+
stroke: var(--st-semantic-border-subtle);
|
|
349
|
+
stroke-width: 1;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.st-density2DChart__tickLabel {
|
|
353
|
+
fill: var(--st-semantic-text-secondary);
|
|
354
|
+
font-size: 0.6875rem;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.st-density2DChart__cell {
|
|
358
|
+
cursor: pointer;
|
|
359
|
+
stroke: var(--st-semantic-surface-default, Canvas);
|
|
360
|
+
stroke-width: 0.5;
|
|
361
|
+
transition: opacity 120ms ease;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.st-density2DChart__cell--dim {
|
|
365
|
+
opacity: 0.4;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.st-density2DChart__cell--category1,
|
|
369
|
+
.st-density2DChart__legendSwatch--category1 { fill: var(--st-semantic-data-category1); background: var(--st-semantic-data-category1); }
|
|
370
|
+
.st-density2DChart__cell--category2,
|
|
371
|
+
.st-density2DChart__legendSwatch--category2 { fill: var(--st-semantic-data-category2); background: var(--st-semantic-data-category2); }
|
|
372
|
+
.st-density2DChart__cell--category3,
|
|
373
|
+
.st-density2DChart__legendSwatch--category3 { fill: var(--st-semantic-data-category3); background: var(--st-semantic-data-category3); }
|
|
374
|
+
.st-density2DChart__cell--category4,
|
|
375
|
+
.st-density2DChart__legendSwatch--category4 { fill: var(--st-semantic-data-category4); background: var(--st-semantic-data-category4); }
|
|
376
|
+
.st-density2DChart__cell--category5,
|
|
377
|
+
.st-density2DChart__legendSwatch--category5 { fill: var(--st-semantic-data-category5); background: var(--st-semantic-data-category5); }
|
|
378
|
+
.st-density2DChart__cell--category6,
|
|
379
|
+
.st-density2DChart__legendSwatch--category6 { fill: var(--st-semantic-data-category6); background: var(--st-semantic-data-category6); }
|
|
380
|
+
.st-density2DChart__cell--category7,
|
|
381
|
+
.st-density2DChart__legendSwatch--category7 { fill: var(--st-semantic-data-category7); background: var(--st-semantic-data-category7); }
|
|
382
|
+
.st-density2DChart__cell--category8,
|
|
383
|
+
.st-density2DChart__legendSwatch--category8 { fill: var(--st-semantic-data-category8); background: var(--st-semantic-data-category8); }
|
|
384
|
+
|
|
385
|
+
.st-density2DChart__legend {
|
|
386
|
+
align-items: center;
|
|
387
|
+
display: flex;
|
|
388
|
+
gap: var(--st-spacing-2, 0.5rem);
|
|
389
|
+
margin-top: var(--st-spacing-2, 0.5rem);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.st-density2DChart__legendRamp {
|
|
393
|
+
display: inline-grid;
|
|
394
|
+
grid-template-columns: repeat(8, minmax(0.75rem, 1fr));
|
|
395
|
+
min-width: 8rem;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.st-density2DChart__legendSwatch {
|
|
399
|
+
display: block;
|
|
400
|
+
height: 0.5rem;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.st-density2DChart__legendText {
|
|
404
|
+
color: var(--st-semantic-text-secondary);
|
|
405
|
+
font-size: 0.75rem;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.st-density2DChart__tooltip {
|
|
409
|
+
background: var(--st-semantic-surface-inverse);
|
|
410
|
+
border-radius: var(--st-radius-sm, 0.25rem);
|
|
411
|
+
color: var(--st-semantic-text-inverse);
|
|
412
|
+
display: inline-flex;
|
|
413
|
+
flex-direction: column;
|
|
414
|
+
font-size: 0.75rem;
|
|
415
|
+
gap: 0.125rem;
|
|
416
|
+
line-height: 1.2;
|
|
417
|
+
padding: 0.375rem 0.5rem;
|
|
418
|
+
pointer-events: none;
|
|
419
|
+
position: absolute;
|
|
420
|
+
transform: translate(-50%, calc(-100% - 8px));
|
|
421
|
+
white-space: nowrap;
|
|
422
|
+
z-index: 1;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.st-density2DChart__tooltipLabel {
|
|
426
|
+
font-weight: 600;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.st-density2DChart__tooltipValue {
|
|
430
|
+
opacity: 0.85;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
@media (prefers-reduced-motion: reduce) {
|
|
434
|
+
.st-density2DChart__cell {
|
|
435
|
+
transition: none;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
</style>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Density2DChart - densité 2D NON-géographique sur axes numériques (heatmap
|
|
3
|
+
* binned, façon Tableau/Dataiku density). On agrège des points (x,y) en cellules
|
|
4
|
+
* d'une grille régulière `bins×bins` sur l'étendue [minX,maxX]×[minY,maxY] ; la
|
|
5
|
+
* couleur d'une cellule encode la DENSITÉ (somme des poids) normalisée sur
|
|
6
|
+
* l'échelle catégorielle continue category1..8 (reprise de HeatmapChart /
|
|
7
|
+
* AnomalySwimLane). Axes X/Y gradués (niceTicks) + légende rampe Low→High.
|
|
8
|
+
* API canonique (référence Svelte, React/Vue doivent s'aligner).
|
|
9
|
+
*
|
|
10
|
+
* Props obligatoires :
|
|
11
|
+
* data Density2DPoint[] - tableau { x, y, weight? }
|
|
12
|
+
*
|
|
13
|
+
* Props optionnelles :
|
|
14
|
+
* bins number (nb de bins par axe, défaut 12)
|
|
15
|
+
* label string
|
|
16
|
+
* width number (défaut 640)
|
|
17
|
+
* height number (défaut 320)
|
|
18
|
+
* size number (alias de width)
|
|
19
|
+
* class string
|
|
20
|
+
*/
|
|
21
|
+
export type Density2DTone = "category1" | "category2" | "category3" | "category4" | "category5" | "category6" | "category7" | "category8";
|
|
22
|
+
export type Density2DPoint = {
|
|
23
|
+
x: number;
|
|
24
|
+
y: number;
|
|
25
|
+
weight?: number;
|
|
26
|
+
};
|
|
27
|
+
type Density2DChartProps = {
|
|
28
|
+
data: Density2DPoint[];
|
|
29
|
+
bins?: number;
|
|
30
|
+
label?: string;
|
|
31
|
+
width?: number;
|
|
32
|
+
height?: number;
|
|
33
|
+
size?: number;
|
|
34
|
+
class?: string;
|
|
35
|
+
};
|
|
36
|
+
declare const Density2DChart: import("svelte").Component<Density2DChartProps, {}, "">;
|
|
37
|
+
type Density2DChart = ReturnType<typeof Density2DChart>;
|
|
38
|
+
export default Density2DChart;
|
|
39
|
+
//# sourceMappingURL=Density2DChart.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Density2DChart.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Density2DChart.svelte.ts"],"names":[],"mappings":"AAGE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,aAAa,GACrB,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,GACrD,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;AAE1D,MAAM,MAAM,cAAc,GAAG;IAC3B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAMF,KAAK,mBAAmB,GAAG;IACzB,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AA6QJ,QAAA,MAAM,cAAc,yDAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
|