@rokkit/chart 1.3.8 → 1.3.10
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/Chart.svelte +50 -64
- package/dist/Plot/Root.svelte +4 -1
- package/dist/Plot/Root.svelte.d.ts +2 -0
- package/dist/Plot/index.d.ts +1 -1
- package/dist/Plot/index.js +1 -1
- package/dist/Plot.svelte +4 -1
- package/dist/Plot.svelte.d.ts +2 -0
- package/dist/PlotState.svelte.d.ts +14 -2
- package/dist/PlotState.svelte.js +81 -5
- package/dist/charts/AreaChart.svelte +8 -1
- package/dist/charts/AreaChart.svelte.d.ts +5 -0
- package/dist/charts/BarChart.svelte +8 -1
- package/dist/charts/BarChart.svelte.d.ts +5 -0
- package/dist/charts/BoxPlot.svelte +3 -1
- package/dist/charts/BoxPlot.svelte.d.ts +1 -0
- package/dist/charts/BubbleChart.svelte +3 -1
- package/dist/charts/BubbleChart.svelte.d.ts +1 -0
- package/dist/charts/LineChart.svelte +3 -1
- package/dist/charts/LineChart.svelte.d.ts +1 -0
- package/dist/charts/PieChart.svelte +4 -2
- package/dist/charts/PieChart.svelte.d.ts +1 -0
- package/dist/charts/ScatterPlot.svelte +3 -1
- package/dist/charts/ScatterPlot.svelte.d.ts +1 -0
- package/dist/charts/ViolinPlot.svelte +3 -1
- package/dist/charts/ViolinPlot.svelte.d.ts +1 -0
- package/dist/geoms/Arc.svelte +21 -55
- package/dist/geoms/Arc.svelte.d.ts +4 -4
- package/dist/geoms/Area.svelte +45 -44
- package/dist/geoms/Area.svelte.d.ts +8 -1
- package/dist/geoms/Bar.svelte +33 -56
- package/dist/geoms/Bar.svelte.d.ts +9 -0
- package/dist/geoms/Box.svelte +118 -131
- package/dist/geoms/Box.svelte.d.ts +5 -3
- package/dist/geoms/Candlestick.svelte +22 -77
- package/dist/geoms/Candlestick.svelte.d.ts +2 -0
- package/dist/geoms/Heatmap.svelte +21 -66
- package/dist/geoms/Heatmap.svelte.d.ts +2 -0
- package/dist/geoms/Hexbin.svelte +20 -100
- package/dist/geoms/Hexbin.svelte.d.ts +2 -0
- package/dist/geoms/Jitter.svelte +21 -36
- package/dist/geoms/Jitter.svelte.d.ts +5 -3
- package/dist/geoms/Line.svelte +27 -31
- package/dist/geoms/Line.svelte.d.ts +5 -0
- package/dist/geoms/Point.svelte +31 -66
- package/dist/geoms/Point.svelte.d.ts +5 -1
- package/dist/geoms/Ribbon.svelte +30 -124
- package/dist/geoms/Ribbon.svelte.d.ts +2 -0
- package/dist/geoms/Rule.svelte +5 -1
- package/dist/geoms/Rule.svelte.d.ts +3 -0
- package/dist/geoms/Violin.svelte +21 -40
- package/dist/geoms/Violin.svelte.d.ts +5 -3
- package/dist/geoms/Waterfall.svelte +19 -80
- package/dist/geoms/Waterfall.svelte.d.ts +2 -0
- package/dist/geoms/lib/GeomState.svelte.d.ts +51 -0
- package/dist/geoms/lib/GeomState.svelte.js +79 -0
- package/dist/geoms/lib/aesthetics.d.ts +36 -0
- package/dist/geoms/lib/aesthetics.js +45 -0
- package/dist/geoms/lib/areas.d.ts +1 -1
- package/dist/geoms/lib/areas.js +18 -5
- package/dist/geoms/lib/bars.d.ts +2 -2
- package/dist/geoms/lib/bars.js +37 -17
- package/dist/geoms/lib/marks/arc.d.ts +24 -0
- package/dist/geoms/lib/marks/arc.js +28 -0
- package/dist/geoms/lib/marks/area.d.ts +23 -0
- package/dist/geoms/lib/marks/area.js +38 -0
- package/dist/geoms/lib/marks/bar.d.ts +16 -0
- package/dist/geoms/lib/marks/bar.js +43 -0
- package/dist/geoms/lib/marks/box.d.ts +14 -0
- package/dist/geoms/lib/marks/box.js +30 -0
- package/dist/geoms/lib/marks/candlestick.d.ts +27 -0
- package/dist/geoms/lib/marks/candlestick.js +52 -0
- package/dist/geoms/lib/marks/heatmap.d.ts +24 -0
- package/dist/geoms/lib/marks/heatmap.js +47 -0
- package/dist/geoms/lib/marks/hexbin.d.ts +29 -0
- package/dist/geoms/lib/marks/hexbin.js +62 -0
- package/dist/geoms/lib/marks/jitter.d.ts +21 -0
- package/dist/geoms/lib/marks/jitter.js +36 -0
- package/dist/geoms/lib/marks/line.d.ts +26 -0
- package/dist/geoms/lib/marks/line.js +25 -0
- package/dist/geoms/lib/marks/point.d.ts +25 -0
- package/dist/geoms/lib/marks/point.js +58 -0
- package/dist/geoms/lib/marks/ribbon.d.ts +32 -0
- package/dist/geoms/lib/marks/ribbon.js +80 -0
- package/dist/geoms/lib/marks/violin.d.ts +13 -0
- package/dist/geoms/lib/marks/violin.js +31 -0
- package/dist/geoms/lib/marks/waterfall.d.ts +25 -0
- package/dist/geoms/lib/marks/waterfall.js +58 -0
- package/dist/index.d.ts +1 -8
- package/dist/index.js +1 -8
- package/dist/lib/brewing/colors.d.ts +31 -1
- package/dist/lib/brewing/colors.js +34 -1
- package/dist/lib/brewing/marks/arcs.js +9 -4
- package/dist/lib/brewing/marks/boxes.js +8 -4
- package/dist/lib/brewing/marks/lines.js +13 -2
- package/dist/lib/brewing/marks/points.js +7 -2
- package/dist/lib/brewing/marks/swarm.js +6 -2
- package/dist/lib/brewing/marks/violins.js +8 -4
- package/dist/lib/preset.d.ts +11 -1
- package/dist/lib/preset.js +16 -4
- package/package.json +1 -1
- package/dist/Plot/Arc.svelte +0 -30
- package/dist/Plot/Arc.svelte.d.ts +0 -18
- package/dist/lib/brewer.d.ts +0 -9
- package/dist/lib/brewer.js +0 -25
- package/dist/lib/brewing/BoxBrewer.svelte.d.ts +0 -8
- package/dist/lib/brewing/BoxBrewer.svelte.js +0 -14
- package/dist/lib/brewing/CartesianBrewer.svelte.d.ts +0 -8
- package/dist/lib/brewing/CartesianBrewer.svelte.js +0 -21
- package/dist/lib/brewing/PieBrewer.svelte.d.ts +0 -8
- package/dist/lib/brewing/PieBrewer.svelte.js +0 -14
- package/dist/lib/brewing/QuartileBrewer.svelte.d.ts +0 -9
- package/dist/lib/brewing/QuartileBrewer.svelte.js +0 -51
- package/dist/lib/brewing/ViolinBrewer.svelte.d.ts +0 -8
- package/dist/lib/brewing/ViolinBrewer.svelte.js +0 -14
- package/dist/lib/brewing/axes.svelte.d.ts +0 -66
- package/dist/lib/brewing/axes.svelte.js +0 -270
- package/dist/lib/brewing/bars.svelte.d.ts +0 -56
- package/dist/lib/brewing/bars.svelte.js +0 -201
- package/dist/lib/brewing/brewer.svelte.d.ts +0 -124
- package/dist/lib/brewing/brewer.svelte.js +0 -277
- package/dist/lib/brewing/dimensions.svelte.d.ts +0 -35
- package/dist/lib/brewing/dimensions.svelte.js +0 -56
- package/dist/lib/brewing/index.svelte.d.ts +0 -118
- package/dist/lib/brewing/index.svelte.js +0 -205
- package/dist/lib/brewing/legends.svelte.d.ts +0 -48
- package/dist/lib/brewing/legends.svelte.js +0 -137
- package/dist/lib/brewing/marks/areas.d.ts +0 -31
- package/dist/lib/brewing/marks/areas.js +0 -72
- package/dist/lib/brewing/marks/bars.d.ts +0 -1
- package/dist/lib/brewing/marks/bars.js +0 -49
- package/dist/lib/brewing/scales.svelte.d.ts +0 -24
- package/dist/lib/brewing/scales.svelte.js +0 -82
- package/dist/lib/context.d.ts +0 -13
- package/dist/lib/context.js +0 -131
- package/dist/lib/plot/chartProps.d.ts +0 -177
- package/dist/lib/plot/chartProps.js +0 -76
- package/dist/lib/scales.svelte.d.ts +0 -35
- package/dist/lib/scales.svelte.js +0 -151
- package/dist/lib/ticks.d.ts +0 -36
- package/dist/lib/ticks.js +0 -46
package/dist/geoms/Arc.svelte
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getContext, onMount, onDestroy } from 'svelte'
|
|
3
3
|
import type { PlotState } from '../PlotState.svelte.js'
|
|
4
|
-
import {
|
|
4
|
+
import { GeomState } from './lib/GeomState.svelte.js'
|
|
5
|
+
import { buildArcMarks } from './lib/marks/arc.js'
|
|
5
6
|
|
|
6
7
|
type Row = Record<string, unknown>
|
|
7
8
|
|
|
8
|
-
/**
|
|
9
|
-
* `fill` is the primary prop name; `color` is accepted as an alias for
|
|
10
|
-
* spec-driven usage (Plot.svelte passes `color` to all geoms generically).
|
|
11
|
-
*/
|
|
12
9
|
type Props = {
|
|
13
10
|
theta?: string
|
|
11
|
+
/** Slice interior aesthetic (field). */
|
|
14
12
|
fill?: string
|
|
13
|
+
/** Accepted as an alias for `fill`. */
|
|
15
14
|
color?: string
|
|
16
15
|
pattern?: string
|
|
16
|
+
/** Fixed slice opacity 0–1; defaults to the per-geom preset (arc = 1). */
|
|
17
|
+
alpha?: number
|
|
17
18
|
stat?: string
|
|
18
19
|
labelFn?: (data: Row) => string
|
|
19
20
|
options?: { innerRadius?: number }
|
|
@@ -25,58 +26,30 @@
|
|
|
25
26
|
fill,
|
|
26
27
|
color,
|
|
27
28
|
pattern,
|
|
29
|
+
alpha,
|
|
28
30
|
labelFn = undefined,
|
|
29
31
|
stat = 'identity',
|
|
30
32
|
options = {},
|
|
31
33
|
onselect = undefined
|
|
32
34
|
}: Props = $props()
|
|
33
35
|
|
|
34
|
-
const fillField = $derived(fill ?? color)
|
|
35
|
-
|
|
36
36
|
const plotState = getContext<PlotState>('plot-state')
|
|
37
|
-
let id = $state<string | null>(null)
|
|
38
|
-
|
|
39
|
-
onMount(() => {
|
|
40
|
-
id = plotState.registerGeom({
|
|
41
|
-
type: 'arc',
|
|
42
|
-
channels: { color: fillField, y: theta, pattern },
|
|
43
|
-
stat,
|
|
44
|
-
options
|
|
45
|
-
})
|
|
46
|
-
})
|
|
47
|
-
onDestroy(() => {
|
|
48
|
-
if (id) plotState.unregisterGeom(id)
|
|
49
|
-
})
|
|
50
37
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
38
|
+
const geom = new GeomState(plotState, () => ({
|
|
39
|
+
type: 'arc',
|
|
40
|
+
channels: { y: theta, color, fill, pattern },
|
|
41
|
+
stat,
|
|
42
|
+
options: { innerRadius: options.innerRadius ?? 0 },
|
|
43
|
+
alpha,
|
|
44
|
+
build: buildArcMarks
|
|
45
|
+
}))
|
|
46
|
+
onMount(geom.register)
|
|
47
|
+
onDestroy(geom.destroy)
|
|
48
|
+
$effect(geom.sync)
|
|
54
49
|
|
|
55
|
-
const
|
|
56
|
-
const colors = $derived(plotState.colors)
|
|
57
|
-
const patterns = $derived(plotState.patterns)
|
|
50
|
+
const arcs = $derived(geom.marks)
|
|
58
51
|
const w = $derived(plotState.innerWidth)
|
|
59
52
|
const h = $derived(plotState.innerHeight)
|
|
60
|
-
|
|
61
|
-
const arcs = $derived.by(() => {
|
|
62
|
-
if (!data?.length) return []
|
|
63
|
-
// Guard: skip until data catches up after a fill-field change.
|
|
64
|
-
// When fillField changes, the $effect updates the geom asynchronously, but
|
|
65
|
-
// this derived runs first with stale data whose rows don't have the new
|
|
66
|
-
// field — causing all keys to be undefined (duplicate key error).
|
|
67
|
-
if (fillField && !(fillField in data[0])) return []
|
|
68
|
-
// innerRadius passed through raw — buildArcs interprets it (a fraction of the
|
|
69
|
-
// radius when <= 1, absolute pixels when > 1) and clamps it below the outer radius.
|
|
70
|
-
return buildArcs(
|
|
71
|
-
data,
|
|
72
|
-
{ color: fillField, y: theta, pattern },
|
|
73
|
-
colors,
|
|
74
|
-
w,
|
|
75
|
-
h,
|
|
76
|
-
{ innerRadius: options.innerRadius ?? 0 },
|
|
77
|
-
patterns
|
|
78
|
-
)
|
|
79
|
-
})
|
|
80
53
|
</script>
|
|
81
54
|
|
|
82
55
|
{#if arcs.length > 0}
|
|
@@ -86,6 +59,7 @@
|
|
|
86
59
|
<path
|
|
87
60
|
d={arc.d}
|
|
88
61
|
fill={arc.fill}
|
|
62
|
+
fill-opacity={arc.alpha}
|
|
89
63
|
stroke={arc.stroke}
|
|
90
64
|
stroke-width="1"
|
|
91
65
|
role={onselect ? 'button' : 'presentation'}
|
|
@@ -116,15 +90,7 @@
|
|
|
116
90
|
pointer-events="none"
|
|
117
91
|
data-plot-element="arc-label"
|
|
118
92
|
>
|
|
119
|
-
<rect
|
|
120
|
-
x={-lw / 2}
|
|
121
|
-
y="-9"
|
|
122
|
-
width={lw}
|
|
123
|
-
height="18"
|
|
124
|
-
rx="4"
|
|
125
|
-
fill="white"
|
|
126
|
-
fill-opacity="0.82"
|
|
127
|
-
/>
|
|
93
|
+
<rect x={-lw / 2} y="-9" width={lw} height="18" rx="4" fill="white" fill-opacity="0.82" />
|
|
128
94
|
<text
|
|
129
95
|
text-anchor="middle"
|
|
130
96
|
dominant-baseline="central"
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
type Row = Record<string, unknown>;
|
|
2
|
-
/**
|
|
3
|
-
* `fill` is the primary prop name; `color` is accepted as an alias for
|
|
4
|
-
* spec-driven usage (Plot.svelte passes `color` to all geoms generically).
|
|
5
|
-
*/
|
|
6
2
|
type Props = {
|
|
7
3
|
theta?: string;
|
|
4
|
+
/** Slice interior aesthetic (field). */
|
|
8
5
|
fill?: string;
|
|
6
|
+
/** Accepted as an alias for `fill`. */
|
|
9
7
|
color?: string;
|
|
10
8
|
pattern?: string;
|
|
9
|
+
/** Fixed slice opacity 0–1; defaults to the per-geom preset (arc = 1). */
|
|
10
|
+
alpha?: number;
|
|
11
11
|
stat?: string;
|
|
12
12
|
labelFn?: (data: Row) => string;
|
|
13
13
|
options?: {
|
package/dist/geoms/Area.svelte
CHANGED
|
@@ -1,73 +1,74 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getContext, onMount, onDestroy } from 'svelte'
|
|
3
3
|
import type { PlotState } from '../PlotState.svelte.js'
|
|
4
|
-
import {
|
|
4
|
+
import { GeomState } from './lib/GeomState.svelte.js'
|
|
5
|
+
import { buildAreaMarks } from './lib/marks/area.js'
|
|
5
6
|
import { buildSelectDetail } from '../lib/select.js'
|
|
6
7
|
|
|
7
8
|
type Row = Record<string, unknown>
|
|
8
|
-
|
|
9
9
|
type Options = {
|
|
10
|
+
/** @deprecated use `position="stack"` — kept as an alias. */
|
|
10
11
|
stack?: boolean
|
|
11
12
|
curve?: 'linear' | 'smooth' | 'step'
|
|
12
|
-
opacity?: number
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
type Props = {
|
|
16
16
|
x?: string
|
|
17
17
|
y?: string
|
|
18
|
+
/** Border aesthetic (field); a border is drawn only when both fill and color are set. */
|
|
18
19
|
color?: string
|
|
20
|
+
/** Interior aesthetic (field); falls back to `color`. */
|
|
21
|
+
fill?: string
|
|
19
22
|
pattern?: string
|
|
23
|
+
/** Multi-series arrangement: 'stack' | 'fill' (100%) | 'identity' (overlap, default). */
|
|
24
|
+
position?: 'stack' | 'fill' | 'identity'
|
|
25
|
+
/** Fixed area opacity 0–1; defaults to the per-geom preset (area = 0.6). */
|
|
26
|
+
alpha?: number
|
|
20
27
|
stat?: string
|
|
21
28
|
options?: Options
|
|
22
29
|
}
|
|
23
30
|
|
|
24
|
-
let { x, y, color, pattern, stat = 'identity', options = {} }: Props =
|
|
31
|
+
let { x, y, color, fill, pattern, position, alpha, stat = 'identity', options = {} }: Props =
|
|
32
|
+
$props()
|
|
33
|
+
|
|
34
|
+
// `options.stack: true` is the back-compat alias for position='stack'.
|
|
35
|
+
const resolvedPosition = $derived(position ?? (options?.stack ? 'stack' : 'identity'))
|
|
25
36
|
|
|
26
37
|
const plotState = getContext<PlotState>('plot-state')
|
|
27
|
-
|
|
38
|
+
|
|
39
|
+
const geom = new GeomState(plotState, () => ({
|
|
40
|
+
type: 'area',
|
|
41
|
+
channels: { x, y, color, fill, pattern },
|
|
42
|
+
stat,
|
|
43
|
+
options: { stack: options?.stack ?? false, position: resolvedPosition, curve: options?.curve },
|
|
44
|
+
alpha,
|
|
45
|
+
build: buildAreaMarks
|
|
46
|
+
}))
|
|
47
|
+
onMount(geom.register)
|
|
48
|
+
onDestroy(geom.destroy)
|
|
49
|
+
$effect(geom.sync)
|
|
50
|
+
|
|
51
|
+
const areas = $derived(geom.marks)
|
|
52
|
+
// Per-row tooltip hit-circles are rendered from the geom's rows + shared scales.
|
|
53
|
+
const rows = $derived(geom.data)
|
|
54
|
+
const xScale = $derived(plotState.xScale)
|
|
55
|
+
const yScale = $derived(plotState.yScale)
|
|
56
|
+
|
|
57
|
+
const seriesField = $derived(fill ?? color)
|
|
28
58
|
|
|
29
59
|
function selectPoint(d: Row, event: MouseEvent | KeyboardEvent) {
|
|
30
60
|
if (plotState.interactive)
|
|
31
61
|
plotState.handleSelect(
|
|
32
|
-
buildSelectDetail(
|
|
62
|
+
buildSelectDetail(
|
|
63
|
+
d,
|
|
64
|
+
plotState.data.indexOf(d),
|
|
65
|
+
{ x, y },
|
|
66
|
+
'area',
|
|
67
|
+
seriesField ? d[seriesField] : undefined,
|
|
68
|
+
event
|
|
69
|
+
)
|
|
33
70
|
)
|
|
34
71
|
}
|
|
35
|
-
|
|
36
|
-
onMount(() => {
|
|
37
|
-
id = plotState.registerGeom({
|
|
38
|
-
type: 'area',
|
|
39
|
-
channels: { x, y, color, pattern },
|
|
40
|
-
stat,
|
|
41
|
-
options: { stack: options?.stack ?? false }
|
|
42
|
-
})
|
|
43
|
-
})
|
|
44
|
-
onDestroy(() => {
|
|
45
|
-
if (id) plotState.unregisterGeom(id)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
$effect(() => {
|
|
49
|
-
if (id)
|
|
50
|
-
plotState.updateGeom(id, {
|
|
51
|
-
channels: { x, y, color, pattern },
|
|
52
|
-
stat,
|
|
53
|
-
options: { stack: options?.stack ?? false }
|
|
54
|
-
})
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
const data = $derived(id ? plotState.geomData(id) : [])
|
|
58
|
-
const xScale = $derived(plotState.xScale)
|
|
59
|
-
const yScale = $derived(plotState.yScale)
|
|
60
|
-
const colors = $derived(plotState.colors)
|
|
61
|
-
const patterns = $derived(plotState.patterns)
|
|
62
|
-
|
|
63
|
-
const areas = $derived.by(() => {
|
|
64
|
-
if (!data?.length || !xScale || !yScale || !x || !y) return []
|
|
65
|
-
const channels = { x, y, color, pattern }
|
|
66
|
-
if (options.stack) {
|
|
67
|
-
return buildStackedAreas(data, channels, xScale, yScale, colors, options.curve, patterns, plotState.place.bind(plotState))
|
|
68
|
-
}
|
|
69
|
-
return buildAreas(data, channels, xScale, yScale, colors, options.curve, patterns, plotState.place.bind(plotState))
|
|
70
|
-
})
|
|
71
72
|
</script>
|
|
72
73
|
|
|
73
74
|
{#if areas.length > 0}
|
|
@@ -76,7 +77,7 @@
|
|
|
76
77
|
<path
|
|
77
78
|
d={seg.d}
|
|
78
79
|
fill={seg.fill}
|
|
79
|
-
fill-opacity={seg.patternId ? 1 :
|
|
80
|
+
fill-opacity={seg.patternId ? 1 : seg.alpha}
|
|
80
81
|
stroke={seg.stroke ?? 'none'}
|
|
81
82
|
data-plot-element="area"
|
|
82
83
|
/>
|
|
@@ -86,7 +87,7 @@
|
|
|
86
87
|
{/each}
|
|
87
88
|
<!-- Invisible hit circles for tooltip: one per data point -->
|
|
88
89
|
{#if x && y}
|
|
89
|
-
{#each
|
|
90
|
+
{#each rows as d, i (`hover::${i}`)}
|
|
90
91
|
{@const px = typeof xScale?.bandwidth === 'function' ? (xScale(d[x]) ?? 0) + xScale.bandwidth() / 2 : (xScale?.(d[x]) ?? 0)}
|
|
91
92
|
{@const py = yScale?.(d[y]) ?? 0}
|
|
92
93
|
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
type Options = {
|
|
2
|
+
/** @deprecated use `position="stack"` — kept as an alias. */
|
|
2
3
|
stack?: boolean;
|
|
3
4
|
curve?: 'linear' | 'smooth' | 'step';
|
|
4
|
-
opacity?: number;
|
|
5
5
|
};
|
|
6
6
|
type Props = {
|
|
7
7
|
x?: string;
|
|
8
8
|
y?: string;
|
|
9
|
+
/** Border aesthetic (field); a border is drawn only when both fill and color are set. */
|
|
9
10
|
color?: string;
|
|
11
|
+
/** Interior aesthetic (field); falls back to `color`. */
|
|
12
|
+
fill?: string;
|
|
10
13
|
pattern?: string;
|
|
14
|
+
/** Multi-series arrangement: 'stack' | 'fill' (100%) | 'identity' (overlap, default). */
|
|
15
|
+
position?: 'stack' | 'fill' | 'identity';
|
|
16
|
+
/** Fixed area opacity 0–1; defaults to the per-geom preset (area = 0.6). */
|
|
17
|
+
alpha?: number;
|
|
11
18
|
stat?: string;
|
|
12
19
|
options?: Options;
|
|
13
20
|
};
|
package/dist/geoms/Bar.svelte
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import { getContext, onMount, onDestroy } from 'svelte'
|
|
3
3
|
import type { PlotState } from '../PlotState.svelte.js'
|
|
4
4
|
import type { createCrossFilter } from '../crossfilter/createCrossFilter.svelte.js'
|
|
5
|
-
import {
|
|
5
|
+
import { GeomState } from './lib/GeomState.svelte.js'
|
|
6
|
+
import { buildBarMarks } from './lib/marks/bar.js'
|
|
6
7
|
import { keyboardNav } from '../lib/keyboard-nav.js'
|
|
7
8
|
import { buildSelectDetail } from '../lib/select.js'
|
|
8
9
|
import LabelPill from './LabelPill.svelte'
|
|
@@ -10,6 +11,7 @@
|
|
|
10
11
|
type Row = Record<string, unknown>
|
|
11
12
|
type CrossFilter = ReturnType<typeof createCrossFilter>
|
|
12
13
|
type Options = {
|
|
14
|
+
/** @deprecated use `position="stack"` — kept as an alias. */
|
|
13
15
|
stack?: boolean
|
|
14
16
|
orientation?: 'horizontal' | 'vertical'
|
|
15
17
|
labelInside?: boolean
|
|
@@ -19,9 +21,17 @@
|
|
|
19
21
|
type Props = {
|
|
20
22
|
x?: string
|
|
21
23
|
y?: string
|
|
24
|
+
/** Border/outline aesthetic (field). */
|
|
22
25
|
color?: string
|
|
26
|
+
/** Interior aesthetic (field); falls back to `color`. */
|
|
23
27
|
fill?: string
|
|
24
28
|
pattern?: string
|
|
29
|
+
/** Multi-series arrangement: 'stack' | 'dodge' (default) | 'fill' (100%) | 'identity' (overlap). */
|
|
30
|
+
position?: 'stack' | 'dodge' | 'fill' | 'identity'
|
|
31
|
+
/** Sub-series field for stack/dodge; defaults to `fill ?? color`. */
|
|
32
|
+
group?: string
|
|
33
|
+
/** Fixed bar opacity 0–1; defaults to the per-geom preset (bar = 1). */
|
|
34
|
+
alpha?: number
|
|
25
35
|
label?: boolean | string | ((data: Row) => unknown)
|
|
26
36
|
stat?: string
|
|
27
37
|
options?: Options
|
|
@@ -34,8 +44,11 @@
|
|
|
34
44
|
x,
|
|
35
45
|
y,
|
|
36
46
|
color,
|
|
37
|
-
fill
|
|
47
|
+
fill,
|
|
38
48
|
pattern,
|
|
49
|
+
position,
|
|
50
|
+
group,
|
|
51
|
+
alpha,
|
|
39
52
|
label = false,
|
|
40
53
|
stat = 'identity',
|
|
41
54
|
options = {},
|
|
@@ -44,8 +57,8 @@
|
|
|
44
57
|
keyboard = false
|
|
45
58
|
}: Props = $props()
|
|
46
59
|
|
|
47
|
-
// `
|
|
48
|
-
const
|
|
60
|
+
// `options.stack: true` is the back-compat alias for position='stack'.
|
|
61
|
+
const resolvedPosition = $derived(position ?? (options?.stack ? 'stack' : 'dodge'))
|
|
49
62
|
|
|
50
63
|
function resolveLabel(data: Row, defaultField: string | undefined): string | null {
|
|
51
64
|
if (!label) return null
|
|
@@ -68,59 +81,22 @@
|
|
|
68
81
|
|
|
69
82
|
const plotState = getContext<PlotState>('plot-state')
|
|
70
83
|
const cf = getContext<CrossFilter | undefined>('crossfilter')
|
|
71
|
-
let id = $state<string | null>(null)
|
|
72
84
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
$
|
|
86
|
-
if (id)
|
|
87
|
-
plotState.updateGeom(id, {
|
|
88
|
-
channels: { x, y, color: colorChannel, pattern },
|
|
89
|
-
stat,
|
|
90
|
-
options: { stack: options?.stack ?? false }
|
|
91
|
-
})
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
const data = $derived(id ? plotState.geomData(id) : [])
|
|
95
|
-
const xScale = $derived(plotState.xScale)
|
|
96
|
-
const yScale = $derived(plotState.yScale)
|
|
97
|
-
const colors = $derived(plotState.colors)
|
|
98
|
-
const patterns = $derived(plotState.patterns)
|
|
85
|
+
const geom = new GeomState(plotState, () => ({
|
|
86
|
+
type: 'bar',
|
|
87
|
+
channels: { x, y, color, fill, pattern, group },
|
|
88
|
+
stat,
|
|
89
|
+
options: { stack: options?.stack ?? false, position: resolvedPosition },
|
|
90
|
+
alpha,
|
|
91
|
+
build: buildBarMarks
|
|
92
|
+
}))
|
|
93
|
+
onMount(geom.register)
|
|
94
|
+
onDestroy(geom.destroy)
|
|
95
|
+
$effect(geom.sync)
|
|
96
|
+
|
|
97
|
+
const bars = $derived(geom.marks)
|
|
99
98
|
const effectiveOrientation = $derived(options.orientation ?? plotState.orientation)
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
const bars = $derived.by(() => {
|
|
103
|
-
if (!data?.length || !xScale || !yScale) return []
|
|
104
|
-
const channels = { x, y, color: colorChannel, pattern }
|
|
105
|
-
// One builder, one path: express bars in (category, value) space and map to screen via
|
|
106
|
-
// place() (identity vertical, swap when flipped). `continuousCategory` keeps a linear
|
|
107
|
-
// category axis (the bar-chart race's tweened rank) so it positions/tweens smoothly.
|
|
108
|
-
const place = plotState.place.bind(plotState)
|
|
109
|
-
if (options.stack) {
|
|
110
|
-
return buildStackedBars(data, channels, xScale, yScale, colors, innerHeight, patterns, place)
|
|
111
|
-
}
|
|
112
|
-
return buildBars(
|
|
113
|
-
data,
|
|
114
|
-
channels,
|
|
115
|
-
xScale,
|
|
116
|
-
yScale,
|
|
117
|
-
colors,
|
|
118
|
-
innerHeight,
|
|
119
|
-
patterns,
|
|
120
|
-
place,
|
|
121
|
-
plotState.continuousCategory
|
|
122
|
-
)
|
|
123
|
-
})
|
|
99
|
+
const seriesField = $derived(fill ?? color)
|
|
124
100
|
|
|
125
101
|
let dimmedByKey = $state<Record<string, boolean>>({})
|
|
126
102
|
|
|
@@ -155,7 +131,7 @@
|
|
|
155
131
|
plotState.data.indexOf(bar.data),
|
|
156
132
|
{ x, y },
|
|
157
133
|
'bar',
|
|
158
|
-
|
|
134
|
+
seriesField ? bar.data[seriesField] : undefined,
|
|
159
135
|
event
|
|
160
136
|
)
|
|
161
137
|
)
|
|
@@ -188,6 +164,7 @@
|
|
|
188
164
|
width={Math.max(0, bar.width)}
|
|
189
165
|
height={Math.max(0, bar.height)}
|
|
190
166
|
fill={bar.fill}
|
|
167
|
+
fill-opacity={bar.alpha}
|
|
191
168
|
stroke={bar.stroke ?? 'none'}
|
|
192
169
|
stroke-width={bar.stroke ? 0.5 : 0}
|
|
193
170
|
data-plot-element="bar"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
type Row = Record<string, unknown>;
|
|
2
2
|
type Options = {
|
|
3
|
+
/** @deprecated use `position="stack"` — kept as an alias. */
|
|
3
4
|
stack?: boolean;
|
|
4
5
|
orientation?: 'horizontal' | 'vertical';
|
|
5
6
|
labelInside?: boolean;
|
|
@@ -8,9 +9,17 @@ type Options = {
|
|
|
8
9
|
type Props = {
|
|
9
10
|
x?: string;
|
|
10
11
|
y?: string;
|
|
12
|
+
/** Border/outline aesthetic (field). */
|
|
11
13
|
color?: string;
|
|
14
|
+
/** Interior aesthetic (field); falls back to `color`. */
|
|
12
15
|
fill?: string;
|
|
13
16
|
pattern?: string;
|
|
17
|
+
/** Multi-series arrangement: 'stack' | 'dodge' (default) | 'fill' (100%) | 'identity' (overlap). */
|
|
18
|
+
position?: 'stack' | 'dodge' | 'fill' | 'identity';
|
|
19
|
+
/** Sub-series field for stack/dodge; defaults to `fill ?? color`. */
|
|
20
|
+
group?: string;
|
|
21
|
+
/** Fixed bar opacity 0–1; defaults to the per-geom preset (bar = 1). */
|
|
22
|
+
alpha?: number;
|
|
14
23
|
label?: boolean | string | ((data: Row) => unknown);
|
|
15
24
|
stat?: string;
|
|
16
25
|
options?: Options;
|