@fundar/data-chart-telling 0.0.63 → 0.0.64
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 +4 -1
- package/dist/configuration/config.svelte.js +3 -0
- package/dist/configuration/themes/index.d.ts +12 -0
- package/dist/layout/legend/ContinuousSection.svelte +32 -14
- package/dist/layout/legend/DiscreteSection.svelte +7 -0
- package/dist/types/configuration/styling.d.ts +6 -0
- package/dist/types/layout/legend.d.ts +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -482,10 +482,13 @@ Each is a `TextStyle` — `{ font, size, weight, color, leading, spacing }` —
|
|
|
482
482
|
| `legend.navButton.fontSize` | `string` | `'1rem'` | `--dct-legend-nav-font-size` |
|
|
483
483
|
| `legend.navButton.disabledOpacity` | `number` | `0.3` | `--dct-legend-nav-disabled-opacity` |
|
|
484
484
|
|
|
485
|
-
`legend.continuous` — the gradient bar
|
|
485
|
+
`legend.continuous` — the gradient bar itself, its draggable handles, ticks, and labels:
|
|
486
486
|
|
|
487
487
|
| Field | Type | Default | CSS variable |
|
|
488
488
|
| ----- | ---- | ------- | ------------- |
|
|
489
|
+
| `legend.continuous.height` | `number` (px) | `20` | — |
|
|
490
|
+
| `legend.continuous.barHeight` | `number` (px) | `12` | — |
|
|
491
|
+
| `legend.continuous.barRadius` | `number` (px) | `2` | — |
|
|
489
492
|
| `legend.continuous.handle.width` | `string` | `'6px'` | `--dct-continuous-handle-width` |
|
|
490
493
|
| `legend.continuous.handle.height` | `string` | `'20px'` | `--dct-continuous-handle-height` |
|
|
491
494
|
| `legend.continuous.handle.radius` | `string` | `'3px'` | `--dct-continuous-handle-radius` |
|
|
@@ -58,6 +58,9 @@ export declare const THEMES: {
|
|
|
58
58
|
disabledOpacity?: number | undefined;
|
|
59
59
|
} | undefined;
|
|
60
60
|
continuous?: {
|
|
61
|
+
height?: number | undefined;
|
|
62
|
+
barHeight?: number | undefined;
|
|
63
|
+
barRadius?: number | undefined;
|
|
61
64
|
handle?: {
|
|
62
65
|
width?: string | undefined;
|
|
63
66
|
height?: string | undefined;
|
|
@@ -296,6 +299,9 @@ export declare const THEMES: {
|
|
|
296
299
|
disabledOpacity?: number | undefined;
|
|
297
300
|
} | undefined;
|
|
298
301
|
continuous?: {
|
|
302
|
+
height?: number | undefined;
|
|
303
|
+
barHeight?: number | undefined;
|
|
304
|
+
barRadius?: number | undefined;
|
|
299
305
|
handle?: {
|
|
300
306
|
width?: string | undefined;
|
|
301
307
|
height?: string | undefined;
|
|
@@ -534,6 +540,9 @@ export declare const THEMES: {
|
|
|
534
540
|
disabledOpacity?: number | undefined;
|
|
535
541
|
} | undefined;
|
|
536
542
|
continuous?: {
|
|
543
|
+
height?: number | undefined;
|
|
544
|
+
barHeight?: number | undefined;
|
|
545
|
+
barRadius?: number | undefined;
|
|
537
546
|
handle?: {
|
|
538
547
|
width?: string | undefined;
|
|
539
548
|
height?: string | undefined;
|
|
@@ -772,6 +781,9 @@ export declare const THEMES: {
|
|
|
772
781
|
disabledOpacity?: number | undefined;
|
|
773
782
|
} | undefined;
|
|
774
783
|
continuous?: {
|
|
784
|
+
height?: number | undefined;
|
|
785
|
+
barHeight?: number | undefined;
|
|
786
|
+
barRadius?: number | undefined;
|
|
775
787
|
handle?: {
|
|
776
788
|
width?: string | undefined;
|
|
777
789
|
height?: string | undefined;
|
|
@@ -14,6 +14,23 @@
|
|
|
14
14
|
const fmt = $derived(section.format ?? ((v: number) => String(v)));
|
|
15
15
|
const isInteractive = $derived(section.interactive?.enabled ?? false);
|
|
16
16
|
|
|
17
|
+
// How far the default handle bleeds past its 0/1 track position, so the
|
|
18
|
+
// track can be inset from `barWidth`'s edges by that much.
|
|
19
|
+
let loHandleEl = $state<SVGRectElement>();
|
|
20
|
+
const handleBleed = $derived(
|
|
21
|
+
isInteractive && !section.interactive?.handle && loHandleEl
|
|
22
|
+
? Math.ceil(loHandleEl.getBoundingClientRect().width / 2)
|
|
23
|
+
: 0,
|
|
24
|
+
);
|
|
25
|
+
const trackWidth = $derived(Math.max(0, barWidth - handleBleed * 2));
|
|
26
|
+
function trackX(t: number): number {
|
|
27
|
+
return handleBleed + t * trackWidth;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const svgHeight = $derived(cfg.legend.continuous.height);
|
|
31
|
+
const barHeight = $derived(cfg.legend.continuous.barHeight);
|
|
32
|
+
const barRadius = $derived(cfg.legend.continuous.barRadius);
|
|
33
|
+
|
|
17
34
|
// Fill/opacity for the excluded-margin rects.
|
|
18
35
|
const excludedStyle = $derived.by((): { fill: string; opacity: number } => {
|
|
19
36
|
const d = section.interactive?.disabledStyle;
|
|
@@ -133,7 +150,7 @@
|
|
|
133
150
|
target.setPointerCapture(event.pointerId);
|
|
134
151
|
const startX = event.clientX;
|
|
135
152
|
const startValue = which === 'lo' ? lo : hi;
|
|
136
|
-
const valuePerPixel = (section.max - section.min) /
|
|
153
|
+
const valuePerPixel = (section.max - section.min) / trackWidth;
|
|
137
154
|
|
|
138
155
|
function onMove(e: PointerEvent): void {
|
|
139
156
|
const next = startValue + (e.clientX - startX) * valuePerPixel;
|
|
@@ -173,12 +190,12 @@
|
|
|
173
190
|
const labelsOverlap = $derived(
|
|
174
191
|
isInteractive &&
|
|
175
192
|
cfg.legend.continuous.label.overlap.enabled &&
|
|
176
|
-
(hiT - loT) *
|
|
193
|
+
(hiT - loT) * trackWidth - loLabelWidth - hiLabelWidth < cfg.legend.continuous.label.overlap.margin,
|
|
177
194
|
);
|
|
178
195
|
</script>
|
|
179
196
|
|
|
180
197
|
<div class="dct-continuous" style:width="{barWidth}px">
|
|
181
|
-
<svg width={barWidth} height=
|
|
198
|
+
<svg width={barWidth} height={svgHeight} style="overflow: visible">
|
|
182
199
|
<defs>
|
|
183
200
|
<linearGradient id={gradientId} x1="0" x2="1" y1="0" y2="0">
|
|
184
201
|
{#each stops as s (s.offset)}
|
|
@@ -186,17 +203,17 @@
|
|
|
186
203
|
{/each}
|
|
187
204
|
</linearGradient>
|
|
188
205
|
</defs>
|
|
189
|
-
<rect width={
|
|
206
|
+
<rect x={handleBleed} width={trackWidth} height={barHeight} rx={barRadius} fill="url(#{gradientId})" />
|
|
190
207
|
{#each tickPositions as tick (tick.v)}
|
|
191
|
-
<rect class="dct-continuous__tick-mark" x={tick.t
|
|
208
|
+
<rect class="dct-continuous__tick-mark" x={trackX(tick.t)} y={barHeight} />
|
|
192
209
|
{/each}
|
|
193
210
|
|
|
194
211
|
{#if isInteractive}
|
|
195
212
|
{#if loT > 0}
|
|
196
|
-
<rect x=
|
|
213
|
+
<rect x={handleBleed} y="0" width={loT * trackWidth} height={barHeight} rx={barRadius} fill={excludedStyle.fill} fill-opacity={excludedStyle.opacity} />
|
|
197
214
|
{/if}
|
|
198
215
|
{#if hiT < 1}
|
|
199
|
-
<rect x={hiT
|
|
216
|
+
<rect x={trackX(hiT)} y="0" width={trackWidth - hiT * trackWidth} height={barHeight} rx={barRadius} fill={excludedStyle.fill} fill-opacity={excludedStyle.opacity} />
|
|
200
217
|
{/if}
|
|
201
218
|
{#if section.interactive?.handle}
|
|
202
219
|
{@render section.interactive.handle({
|
|
@@ -216,8 +233,9 @@
|
|
|
216
233
|
{:else}
|
|
217
234
|
<rect
|
|
218
235
|
class="dct-continuous__handle"
|
|
219
|
-
|
|
220
|
-
|
|
236
|
+
bind:this={loHandleEl}
|
|
237
|
+
x={trackX(loT)}
|
|
238
|
+
y={barHeight / 2}
|
|
221
239
|
onpointerdown={startDrag('lo')}
|
|
222
240
|
ondblclick={resetHandle('lo')}
|
|
223
241
|
role="slider"
|
|
@@ -229,8 +247,8 @@
|
|
|
229
247
|
/>
|
|
230
248
|
<rect
|
|
231
249
|
class="dct-continuous__handle"
|
|
232
|
-
x={hiT
|
|
233
|
-
y=
|
|
250
|
+
x={trackX(hiT)}
|
|
251
|
+
y={barHeight / 2}
|
|
234
252
|
onpointerdown={startDrag('hi')}
|
|
235
253
|
ondblclick={resetHandle('hi')}
|
|
236
254
|
role="slider"
|
|
@@ -251,17 +269,17 @@
|
|
|
251
269
|
<span
|
|
252
270
|
class="dct-continuous__tick dct-continuous__tick--handle-lo"
|
|
253
271
|
class:dct-continuous__tick--vertical={labelsOverlap}
|
|
254
|
-
style:left="{loT
|
|
272
|
+
style:left="{trackX(loT)}px"
|
|
255
273
|
>{fmt(lo)}</span>
|
|
256
274
|
<span
|
|
257
275
|
class="dct-continuous__tick dct-continuous__tick--handle-hi"
|
|
258
276
|
class:dct-continuous__tick--vertical={labelsOverlap}
|
|
259
|
-
style:left="{hiT
|
|
277
|
+
style:left="{trackX(hiT)}px"
|
|
260
278
|
>{fmt(hi)}</span>
|
|
261
279
|
{:else}
|
|
262
280
|
<span class="dct-continuous__edge dct-continuous__edge--start">{fmt(section.min)}</span>
|
|
263
281
|
{#each tickPositions as tick (tick.v)}
|
|
264
|
-
<span class="dct-continuous__tick" style:left="{tick.t
|
|
282
|
+
<span class="dct-continuous__tick" style:left="{trackX(tick.t)}px">{tick.label}</span>
|
|
265
283
|
{/each}
|
|
266
284
|
<span class="dct-continuous__edge dct-continuous__edge--end">{fmt(section.max)}</span>
|
|
267
285
|
{/if}
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
const cfg = $derived(getConfiguration());
|
|
27
27
|
const layout = $derived(section.layout ?? defaultItemsLayout);
|
|
28
28
|
const isHorizontal = $derived(layout.type === 'horizontal');
|
|
29
|
+
const isFlex = $derived(layout.type === 'flex');
|
|
29
30
|
const maxRows = $derived(layout.type === 'horizontal' ? Math.max(1, layout.maxRows ?? 1) : 1);
|
|
30
31
|
const columns = $derived(section.columns ?? 1);
|
|
31
32
|
const isInteractive = $derived(section.interactive?.enabled ?? false);
|
|
@@ -238,6 +239,12 @@
|
|
|
238
239
|
)}
|
|
239
240
|
{/if}
|
|
240
241
|
</div>
|
|
242
|
+
{:else if isFlex}
|
|
243
|
+
<div class="dct-discrete dct-discrete--horizontal">
|
|
244
|
+
{#each section.items as item, i (item.name)}
|
|
245
|
+
{@render discreteItem(item, i)}
|
|
246
|
+
{/each}
|
|
247
|
+
</div>
|
|
241
248
|
{:else}
|
|
242
249
|
<div class="dct-discrete" style:grid-template-columns="repeat({columns}, max-content)">
|
|
243
250
|
{#each section.items as item, i (item.name)}
|
|
@@ -50,6 +50,12 @@ export type ChartConfig = {
|
|
|
50
50
|
};
|
|
51
51
|
/** Continuous section styling: the draggable lo/hi handles and the tick/edge labels. */
|
|
52
52
|
continuous: {
|
|
53
|
+
/** Total height (px) of the bar's drawing area. */
|
|
54
|
+
height: number;
|
|
55
|
+
/** Height (px) of the gradient bar itself, centered within `height`. */
|
|
56
|
+
barHeight: number;
|
|
57
|
+
/** Corner radius (px) of the gradient bar and excluded-range overlays. */
|
|
58
|
+
barRadius: number;
|
|
53
59
|
/** The draggable lo/hi handle. */
|
|
54
60
|
handle: {
|
|
55
61
|
width: string;
|
|
@@ -37,13 +37,16 @@ export type LegendItem = {
|
|
|
37
37
|
/**
|
|
38
38
|
* How a discrete section's items flow. `'vertical'` stacks them in a
|
|
39
39
|
* `columns`-wide grid; `'horizontal'` flows them left to right, paginating
|
|
40
|
-
* past `maxRows` (default 1) with prev/next arrows
|
|
40
|
+
* past `maxRows` (default 1) with prev/next arrows; `'flex'` also flows them
|
|
41
|
+
* left to right, but wraps onto as many rows as it takes instead of paginating.
|
|
41
42
|
*/
|
|
42
43
|
export type LegendItemsLayout = {
|
|
43
44
|
type: 'vertical';
|
|
44
45
|
} | {
|
|
45
46
|
type: 'horizontal';
|
|
46
47
|
maxRows?: number;
|
|
48
|
+
} | {
|
|
49
|
+
type: 'flex';
|
|
47
50
|
};
|
|
48
51
|
export type LegendNavDirection = 'prev' | 'next';
|
|
49
52
|
export type LegendNavContext = {
|