@rokkit/chart 1.3.7 → 1.3.9
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/AnimatedPlot.svelte +26 -8
- package/dist/AnimatedPlot.svelte.d.ts +5 -0
- package/dist/Chart.svelte +51 -65
- package/dist/FacetPlot.svelte +1 -1
- package/dist/Plot/Axis.svelte +19 -10
- package/dist/Plot/Root.svelte +67 -46
- package/dist/Plot/Root.svelte.d.ts +29 -2
- package/dist/Plot/Timeline.svelte +39 -13
- package/dist/Plot/index.d.ts +5 -5
- package/dist/Plot/index.js +5 -5
- package/dist/Plot.svelte +95 -178
- package/dist/Plot.svelte.d.ts +4 -0
- package/dist/PlotState.svelte.d.ts +29 -1
- package/dist/PlotState.svelte.js +163 -19
- package/dist/PlotSurface.svelte +162 -0
- package/dist/PlotSurface.svelte.d.ts +25 -0
- package/dist/charts/AreaChart.svelte +12 -2
- package/dist/charts/AreaChart.svelte.d.ts +6 -0
- package/dist/charts/BarChart.svelte +40 -4
- package/dist/charts/BarChart.svelte.d.ts +15 -1
- package/dist/charts/BoxPlot.svelte +7 -3
- package/dist/charts/BoxPlot.svelte.d.ts +2 -0
- package/dist/charts/BubbleChart.svelte +37 -4
- package/dist/charts/BubbleChart.svelte.d.ts +12 -1
- package/dist/charts/LineChart.svelte +4 -2
- package/dist/charts/LineChart.svelte.d.ts +1 -0
- package/dist/charts/PieChart.svelte +5 -3
- package/dist/charts/PieChart.svelte.d.ts +1 -0
- package/dist/charts/ScatterPlot.svelte +35 -4
- package/dist/charts/ScatterPlot.svelte.d.ts +11 -1
- package/dist/charts/ViolinPlot.svelte +7 -3
- package/dist/charts/ViolinPlot.svelte.d.ts +2 -0
- package/dist/examples/BarChartExample.svelte +1 -1
- package/dist/geoms/Arc.svelte +21 -54
- 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 -45
- package/dist/geoms/Bar.svelte.d.ts +9 -0
- package/dist/geoms/Box.svelte +103 -61
- package/dist/geoms/Box.svelte.d.ts +12 -3
- package/dist/geoms/Candlestick.svelte +26 -75
- 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 +67 -0
- package/dist/geoms/Jitter.svelte.d.ts +17 -0
- package/dist/geoms/Line.svelte +27 -31
- package/dist/geoms/Line.svelte.d.ts +5 -0
- package/dist/geoms/Point.svelte +31 -60
- 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 +117 -0
- package/dist/geoms/Rule.svelte.d.ts +19 -0
- package/dist/geoms/Violin.svelte +36 -31
- package/dist/geoms/Violin.svelte.d.ts +10 -3
- package/dist/geoms/Waterfall.svelte +25 -79
- 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 +6 -2
- package/dist/geoms/lib/areas.js +20 -12
- package/dist/geoms/lib/bars.d.ts +18 -3
- package/dist/geoms/lib/bars.js +80 -101
- 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 +41 -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 +31 -0
- package/dist/geoms/lib/marks/ribbon.js +77 -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 +25 -12
- package/dist/index.js +26 -13
- package/dist/lib/brewing/marks/arcs.js +7 -1
- package/dist/lib/brewing/marks/boxes.d.ts +11 -2
- package/dist/lib/brewing/marks/boxes.js +32 -11
- package/dist/lib/brewing/marks/lines.d.ts +4 -1
- package/dist/lib/brewing/marks/lines.js +18 -15
- package/dist/lib/brewing/marks/swarm.d.ts +32 -0
- package/dist/lib/brewing/marks/swarm.js +125 -0
- package/dist/lib/brewing/marks/violins.d.ts +4 -20
- package/dist/lib/brewing/marks/violins.js +41 -25
- package/dist/lib/brewing/stats.d.ts +3 -1
- package/dist/lib/brewing/stats.js +28 -11
- package/dist/lib/plot/scales.js +12 -7
- package/dist/lib/plot/types.d.ts +9 -1
- package/dist/lib/plot/types.js +3 -1
- 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/Plot/Area.svelte +0 -54
- package/dist/Plot/Area.svelte.d.ts +0 -14
- package/dist/Plot/Bar.svelte +0 -69
- package/dist/Plot/Bar.svelte.d.ts +0 -11
- package/dist/Plot/Line.svelte +0 -54
- package/dist/Plot/Line.svelte.d.ts +0 -13
- package/dist/Plot/Point.svelte +0 -58
- package/dist/Plot/Point.svelte.d.ts +0 -13
- 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
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { resolveAlpha } from '../aesthetics.js'
|
|
2
|
+
|
|
3
|
+
/** SVG path for a pointy-top hexagon of radius r, centered at the origin. */
|
|
4
|
+
export function hexPath(r) {
|
|
5
|
+
const angles = [0, 1, 2, 3, 4, 5].map((i) => ((i * 60 - 30) * Math.PI) / 180)
|
|
6
|
+
return `${angles.map((a, i) => `${i === 0 ? 'M' : 'L'}${r * Math.cos(a)},${r * Math.sin(a)}`).join('')}Z`
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Group points into hexagonal bins and count per bin. */
|
|
10
|
+
function hexBin(rows, xField, yField, xScale, yScale, r) {
|
|
11
|
+
const dx = r * 2 * Math.sin(Math.PI / 3)
|
|
12
|
+
const dy = r * 1.5
|
|
13
|
+
const bins = new Map()
|
|
14
|
+
for (const d of rows) {
|
|
15
|
+
const px = xScale(d[xField ?? ''])
|
|
16
|
+
const py = yScale(d[yField ?? ''])
|
|
17
|
+
if (px === null || px === undefined || py === null || py === undefined) continue
|
|
18
|
+
const col = Math.round(px / dx)
|
|
19
|
+
const row = Math.round(py / dy)
|
|
20
|
+
const cx = col * dx + (row % 2 ? dx / 2 : 0)
|
|
21
|
+
const cy = row * dy
|
|
22
|
+
const key = `${col},${row}`
|
|
23
|
+
let bin = bins.get(key)
|
|
24
|
+
if (!bin) {
|
|
25
|
+
bin = { cx, cy, count: 0, points: [] }
|
|
26
|
+
bins.set(key, bin)
|
|
27
|
+
}
|
|
28
|
+
bin.count++
|
|
29
|
+
bin.points.push(d)
|
|
30
|
+
}
|
|
31
|
+
return [...bins.values()]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Build renderable hex bins. Fill is the continuous color scale (by count) or a density-ramp
|
|
36
|
+
* rgba fallback. `alpha` is a flat multiplier on top (default 1 → unchanged).
|
|
37
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
38
|
+
*/
|
|
39
|
+
export function buildHexbinMarks({ data, plot, channels, options = {}, alpha, type = 'hexbin' }) {
|
|
40
|
+
const { xScale, yScale } = plot
|
|
41
|
+
if (!data?.length || !xScale || !yScale) return []
|
|
42
|
+
|
|
43
|
+
const radius = options.radius ?? 20
|
|
44
|
+
const bins = hexBin(data, channels.x, channels.y, xScale, yScale, radius)
|
|
45
|
+
const maxCount = Math.max(1, ...bins.map((b) => b.count))
|
|
46
|
+
const colorScale = plot.continuousColorScale?.scale
|
|
47
|
+
const a = resolveAlpha(alpha, type, plot.chartPreset)
|
|
48
|
+
|
|
49
|
+
return bins.map((bin, i) => ({
|
|
50
|
+
key: `hex-${i}`,
|
|
51
|
+
cx: bin.cx,
|
|
52
|
+
cy: bin.cy,
|
|
53
|
+
count: bin.count,
|
|
54
|
+
fill: colorScale
|
|
55
|
+
? colorScale(bin.count)
|
|
56
|
+
: `rgba(66, 133, 244, ${0.1 + 0.9 * (bin.count / maxCount)})`,
|
|
57
|
+
alpha: a,
|
|
58
|
+
value: bin.count,
|
|
59
|
+
display: `${bin.count}`,
|
|
60
|
+
data: { count: bin.count, x: bin.cx, y: bin.cy }
|
|
61
|
+
}))
|
|
62
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build renderable jitter/swarm points. Fill + outline come from `fill` (defaulting to
|
|
3
|
+
* `x`); an explicit `color` channel overrides the outline stroke. Adds fixed `alpha`.
|
|
4
|
+
* Horizontal orientation swaps each point's screen coords via place().
|
|
5
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
6
|
+
*/
|
|
7
|
+
export function buildJitterMarks({ data, plot, channels, options, alpha, type }: {
|
|
8
|
+
data: any[];
|
|
9
|
+
plot: any;
|
|
10
|
+
channels: any;
|
|
11
|
+
options?: any;
|
|
12
|
+
alpha?: number;
|
|
13
|
+
type?: string;
|
|
14
|
+
}): {
|
|
15
|
+
cx: any;
|
|
16
|
+
cy: any;
|
|
17
|
+
stroke: any;
|
|
18
|
+
alpha: number;
|
|
19
|
+
fill: string;
|
|
20
|
+
data: Record<string, unknown>;
|
|
21
|
+
}[];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { buildSwarm } from '../../../lib/brewing/marks/swarm.js'
|
|
2
|
+
import { resolveAlpha } from '../aesthetics.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build renderable jitter/swarm points. Fill + outline come from `fill` (defaulting to
|
|
6
|
+
* `x`); an explicit `color` channel overrides the outline stroke. Adds fixed `alpha`.
|
|
7
|
+
* Horizontal orientation swaps each point's screen coords via place().
|
|
8
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
9
|
+
*/
|
|
10
|
+
export function buildJitterMarks({ data, plot, channels, options = {}, alpha, type = 'jitter' }) {
|
|
11
|
+
const { xScale, yScale, colors } = plot
|
|
12
|
+
if (!data?.length || !xScale || !yScale) return []
|
|
13
|
+
|
|
14
|
+
const fillField = channels.fill ?? channels.x
|
|
15
|
+
const raw = buildSwarm(
|
|
16
|
+
data,
|
|
17
|
+
{ x: channels.x, y: channels.y, fill: fillField },
|
|
18
|
+
xScale,
|
|
19
|
+
yScale,
|
|
20
|
+
colors,
|
|
21
|
+
{ method: options.method, r: options.r, side: options.side }
|
|
22
|
+
)
|
|
23
|
+
const a = resolveAlpha(alpha, type, plot.chartPreset)
|
|
24
|
+
const colorField = channels.color
|
|
25
|
+
const flip = plot.isFlipped
|
|
26
|
+
return raw.map((p) => {
|
|
27
|
+
const s = flip ? plot.place(p.cx, p.cy) : { x: p.cx, y: p.cy }
|
|
28
|
+
return {
|
|
29
|
+
...p,
|
|
30
|
+
cx: s.x,
|
|
31
|
+
cy: s.y,
|
|
32
|
+
stroke: colorField ? (colors.get(p.data[colorField])?.stroke ?? p.stroke) : p.stroke,
|
|
33
|
+
alpha: a
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build renderable line segments. A line has no interior, so its single aesthetic is
|
|
3
|
+
* the stroke — driven by `color`, with `fill` accepted as an alias (ggplot geom_line
|
|
4
|
+
* uses `colour`). Each segment gets the geom's fixed `alpha`.
|
|
5
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
6
|
+
*/
|
|
7
|
+
export function buildLineMarks({ data, plot, channels, options, alpha, type }: {
|
|
8
|
+
data: any[];
|
|
9
|
+
plot: any;
|
|
10
|
+
channels: any;
|
|
11
|
+
options?: any;
|
|
12
|
+
alpha?: number;
|
|
13
|
+
type?: string;
|
|
14
|
+
}): {
|
|
15
|
+
alpha: number;
|
|
16
|
+
d: string | null;
|
|
17
|
+
fill: string;
|
|
18
|
+
stroke: string;
|
|
19
|
+
points: {
|
|
20
|
+
x: number;
|
|
21
|
+
y: number;
|
|
22
|
+
data: Record<string, unknown>;
|
|
23
|
+
i: number;
|
|
24
|
+
}[];
|
|
25
|
+
key?: unknown;
|
|
26
|
+
}[];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { buildLines } from '../../../lib/brewing/marks/lines.js'
|
|
2
|
+
import { resolveAlpha } from '../aesthetics.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build renderable line segments. A line has no interior, so its single aesthetic is
|
|
6
|
+
* the stroke — driven by `color`, with `fill` accepted as an alias (ggplot geom_line
|
|
7
|
+
* uses `colour`). Each segment gets the geom's fixed `alpha`.
|
|
8
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
9
|
+
*/
|
|
10
|
+
export function buildLineMarks({ data, plot, channels, options = {}, alpha, type = 'line' }) {
|
|
11
|
+
const { xScale, yScale, colors } = plot
|
|
12
|
+
if (!data?.length || !xScale || !yScale) return []
|
|
13
|
+
const lineColor = channels.color ?? channels.fill
|
|
14
|
+
const segs = buildLines(
|
|
15
|
+
data,
|
|
16
|
+
{ x: channels.x, y: channels.y, color: lineColor },
|
|
17
|
+
xScale,
|
|
18
|
+
yScale,
|
|
19
|
+
colors,
|
|
20
|
+
options.curve,
|
|
21
|
+
plot.place.bind(plot)
|
|
22
|
+
)
|
|
23
|
+
const a = resolveAlpha(alpha, type, plot.chartPreset)
|
|
24
|
+
return segs.map((seg) => ({ ...seg, alpha: a }))
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build renderable point marks: geometry (from buildPoints) + shared aesthetics
|
|
3
|
+
* (fill/color split + alpha) + value/display. The geom template just renders these.
|
|
4
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
5
|
+
*/
|
|
6
|
+
export function buildPointMarks({ data, plot, channels, options, alpha, type }: {
|
|
7
|
+
data: any[];
|
|
8
|
+
plot: any;
|
|
9
|
+
channels: any;
|
|
10
|
+
options?: any;
|
|
11
|
+
alpha?: number;
|
|
12
|
+
type?: string;
|
|
13
|
+
}): {
|
|
14
|
+
cx: any;
|
|
15
|
+
cy: any;
|
|
16
|
+
fill: string;
|
|
17
|
+
stroke: string;
|
|
18
|
+
alpha: number;
|
|
19
|
+
value: unknown;
|
|
20
|
+
display: string;
|
|
21
|
+
key: string;
|
|
22
|
+
data: Record<string, unknown>;
|
|
23
|
+
r: number;
|
|
24
|
+
symbolPath: string | null;
|
|
25
|
+
}[];
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { scaleSqrt } from 'd3-scale'
|
|
2
|
+
import { buildPoints } from '../../../lib/brewing/marks/points.js'
|
|
3
|
+
import { resolveFillStroke, resolveAlpha } from '../aesthetics.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Size scale for a bubble/size channel — sqrt so area (not radius) is proportional.
|
|
7
|
+
* @returns {import('d3-scale').ScalePower<number, number> | null}
|
|
8
|
+
*/
|
|
9
|
+
function buildSizeScale(data, sizeField, options) {
|
|
10
|
+
if (!sizeField || !data?.length) return null
|
|
11
|
+
const vals = data.map((d) => Number(d[sizeField])).filter((v) => !isNaN(v))
|
|
12
|
+
if (!vals.length) return null
|
|
13
|
+
return scaleSqrt()
|
|
14
|
+
.domain([Math.min(...vals), Math.max(...vals)])
|
|
15
|
+
.range([options?.minRadius ?? 3, options?.maxRadius ?? 20])
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Build renderable point marks: geometry (from buildPoints) + shared aesthetics
|
|
20
|
+
* (fill/color split + alpha) + value/display. The geom template just renders these.
|
|
21
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
22
|
+
*/
|
|
23
|
+
export function buildPointMarks({ data, plot, channels, options = {}, alpha, type = 'point' }) {
|
|
24
|
+
const { xScale, yScale, colors } = plot
|
|
25
|
+
if (!data?.length || !xScale || !yScale) return []
|
|
26
|
+
|
|
27
|
+
const sizeScale = buildSizeScale(data, channels.size, options)
|
|
28
|
+
const raw = buildPoints(
|
|
29
|
+
data,
|
|
30
|
+
channels,
|
|
31
|
+
xScale,
|
|
32
|
+
yScale,
|
|
33
|
+
colors,
|
|
34
|
+
sizeScale,
|
|
35
|
+
plot.symbols,
|
|
36
|
+
options.radius ?? 4,
|
|
37
|
+
options.jitter ?? null
|
|
38
|
+
)
|
|
39
|
+
const a = resolveAlpha(alpha, type, plot.chartPreset)
|
|
40
|
+
const yf = channels.y
|
|
41
|
+
|
|
42
|
+
return raw.map((p, i) => {
|
|
43
|
+
const { fill, stroke } = resolveFillStroke(p.data, channels, colors)
|
|
44
|
+
// Horizontal orientation: swap each point's screen coords via place().
|
|
45
|
+
const s = plot.isFlipped ? plot.place(p.cx, p.cy) : { x: p.cx, y: p.cy }
|
|
46
|
+
return {
|
|
47
|
+
...p,
|
|
48
|
+
cx: s.x,
|
|
49
|
+
cy: s.y,
|
|
50
|
+
fill,
|
|
51
|
+
stroke,
|
|
52
|
+
alpha: a,
|
|
53
|
+
value: yf ? p.data[yf] : undefined,
|
|
54
|
+
display: yf ? String(p.data[yf] ?? '') : '',
|
|
55
|
+
key: `${i}::${p.data[channels.x ?? '']}::${p.data[yf ?? '']}`
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a Sankey-style ribbon layout: links (flows) + source/target node boxes. Link fill
|
|
3
|
+
* comes from the source (then target) palette entry; `alpha` is fixed (default 0.5). Returns
|
|
4
|
+
* an object rather than a flat array, so the geom template renders links + node labels.
|
|
5
|
+
* @param {{ data: any[], plot: any, options?: any, alpha?: number, type?: string }} ctx
|
|
6
|
+
*/
|
|
7
|
+
export function buildRibbonMarks({ data, plot, options, alpha, type }: {
|
|
8
|
+
data: any[];
|
|
9
|
+
plot: any;
|
|
10
|
+
options?: any;
|
|
11
|
+
alpha?: number;
|
|
12
|
+
type?: string;
|
|
13
|
+
}): {
|
|
14
|
+
links: {
|
|
15
|
+
key: string;
|
|
16
|
+
d: string;
|
|
17
|
+
fill: any;
|
|
18
|
+
alpha: number;
|
|
19
|
+
data: any;
|
|
20
|
+
}[];
|
|
21
|
+
sourceNodes: {
|
|
22
|
+
name: any;
|
|
23
|
+
y: number;
|
|
24
|
+
height: number;
|
|
25
|
+
}[];
|
|
26
|
+
targetNodes: {
|
|
27
|
+
name: any;
|
|
28
|
+
y: number;
|
|
29
|
+
height: number;
|
|
30
|
+
}[];
|
|
31
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { resolveAlpha } from '../aesthetics.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Build a Sankey-style ribbon layout: links (flows) + source/target node boxes. Link fill
|
|
5
|
+
* comes from the source (then target) palette entry; `alpha` is fixed (default 0.5). Returns
|
|
6
|
+
* an object rather than a flat array, so the geom template renders links + node labels.
|
|
7
|
+
* @param {{ data: any[], plot: any, options?: any, alpha?: number, type?: string }} ctx
|
|
8
|
+
*/
|
|
9
|
+
export function buildRibbonMarks({ data, plot, options = {}, alpha, type = 'ribbon' }) {
|
|
10
|
+
const empty = { links: [], sourceNodes: [], targetNodes: [] }
|
|
11
|
+
if (!data?.length) return empty
|
|
12
|
+
|
|
13
|
+
const { colors, innerHeight, innerWidth } = plot
|
|
14
|
+
const sourceField = options.source ?? 'source'
|
|
15
|
+
const targetField = options.target ?? 'target'
|
|
16
|
+
const valueField = options.value ?? 'value'
|
|
17
|
+
const a = resolveAlpha(alpha, type, plot.chartPreset)
|
|
18
|
+
|
|
19
|
+
const flows = data.map((d) => ({
|
|
20
|
+
source: String(d[sourceField]),
|
|
21
|
+
target: String(d[targetField]),
|
|
22
|
+
value: Number(d[valueField]) || 0,
|
|
23
|
+
data: d
|
|
24
|
+
}))
|
|
25
|
+
|
|
26
|
+
const sourceMap = new Map()
|
|
27
|
+
const targetMap = new Map()
|
|
28
|
+
for (const f of flows) {
|
|
29
|
+
sourceMap.set(f.source, (sourceMap.get(f.source) ?? 0) + f.value)
|
|
30
|
+
targetMap.set(f.target, (targetMap.get(f.target) ?? 0) + f.value)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const totalSource = Math.max(1, [...sourceMap.values()].reduce((s, v) => s + v, 0))
|
|
34
|
+
const totalTarget = Math.max(1, [...targetMap.values()].reduce((s, v) => s + v, 0))
|
|
35
|
+
const padding = 4
|
|
36
|
+
const availHeight = innerHeight - padding * (Math.max(sourceMap.size, targetMap.size) - 1)
|
|
37
|
+
|
|
38
|
+
let sourceY = 0
|
|
39
|
+
const sourceNodes = []
|
|
40
|
+
for (const [name, value] of sourceMap) {
|
|
41
|
+
const h = (value / totalSource) * availHeight
|
|
42
|
+
sourceNodes.push({ name, y: sourceY, height: h })
|
|
43
|
+
sourceY += h + padding
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let targetY = 0
|
|
47
|
+
const targetNodes = []
|
|
48
|
+
for (const [name, value] of targetMap) {
|
|
49
|
+
const h = (value / totalTarget) * availHeight
|
|
50
|
+
targetNodes.push({ name, y: targetY, height: h })
|
|
51
|
+
targetY += h + padding
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const sourceOffsets = new Map(sourceNodes.map((n) => [n.name, n.y]))
|
|
55
|
+
const targetOffsets = new Map(targetNodes.map((n) => [n.name, n.y]))
|
|
56
|
+
const x0 = 0
|
|
57
|
+
const x1 = innerWidth
|
|
58
|
+
|
|
59
|
+
const links = flows.map((f, i) => {
|
|
60
|
+
const sy0 = sourceOffsets.get(f.source) ?? 0
|
|
61
|
+
const ty0 = targetOffsets.get(f.target) ?? 0
|
|
62
|
+
const sourceTotal = sourceMap.get(f.source) ?? 1
|
|
63
|
+
const targetTotal = targetMap.get(f.target) ?? 1
|
|
64
|
+
const sh = (f.value / sourceTotal) * (sourceNodes.find((n) => n.name === f.source)?.height ?? 0)
|
|
65
|
+
const th = (f.value / targetTotal) * (targetNodes.find((n) => n.name === f.target)?.height ?? 0)
|
|
66
|
+
|
|
67
|
+
const path = `M${x0},${sy0} C${innerWidth * 0.4},${sy0} ${innerWidth * 0.6},${ty0} ${x1},${ty0} L${x1},${ty0 + th} C${innerWidth * 0.6},${ty0 + th} ${innerWidth * 0.4},${sy0 + sh} ${x0},${sy0 + sh} Z`
|
|
68
|
+
|
|
69
|
+
sourceOffsets.set(f.source, sy0 + sh)
|
|
70
|
+
targetOffsets.set(f.target, ty0 + th)
|
|
71
|
+
|
|
72
|
+
const fill = colors?.get(f.source)?.fill ?? colors?.get(f.target)?.fill ?? '#888'
|
|
73
|
+
return { key: `ribbon-${i}`, d: path, fill, alpha: a, data: f.data }
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
return { links, sourceNodes, targetNodes }
|
|
77
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build renderable violin silhouettes. Interior + outline come from `fill` (defaulting to
|
|
3
|
+
* `x`); an explicit `color` channel overrides the outline stroke. Adds fixed `alpha`.
|
|
4
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
5
|
+
*/
|
|
6
|
+
export function buildViolinMarks({ data, plot, channels, options, alpha, type }: {
|
|
7
|
+
data: any[];
|
|
8
|
+
plot: any;
|
|
9
|
+
channels: any;
|
|
10
|
+
options?: any;
|
|
11
|
+
alpha?: number;
|
|
12
|
+
type?: string;
|
|
13
|
+
}): any;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { buildViolins } from '../../../lib/brewing/marks/violins.js'
|
|
2
|
+
import { resolveAlpha } from '../aesthetics.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build renderable violin silhouettes. Interior + outline come from `fill` (defaulting to
|
|
6
|
+
* `x`); an explicit `color` channel overrides the outline stroke. Adds fixed `alpha`.
|
|
7
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
8
|
+
*/
|
|
9
|
+
export function buildViolinMarks({ data, plot, channels, options = {}, alpha, type = 'violin' }) {
|
|
10
|
+
const { xScale, yScale, colors } = plot
|
|
11
|
+
if (!data?.length || !xScale || !yScale) return []
|
|
12
|
+
|
|
13
|
+
const fillField = channels.fill ?? channels.x
|
|
14
|
+
const violins = buildViolins(
|
|
15
|
+
data,
|
|
16
|
+
{ x: channels.x, fill: fillField, pattern: channels.pattern },
|
|
17
|
+
xScale,
|
|
18
|
+
yScale,
|
|
19
|
+
colors,
|
|
20
|
+
plot.place.bind(plot),
|
|
21
|
+
options.side,
|
|
22
|
+
plot.patterns
|
|
23
|
+
)
|
|
24
|
+
const a = resolveAlpha(alpha, type, plot.chartPreset)
|
|
25
|
+
const colorField = channels.color
|
|
26
|
+
return violins.map((v) => ({
|
|
27
|
+
...v,
|
|
28
|
+
stroke: colorField ? (colors.get(v.data[colorField])?.stroke ?? v.stroke) : v.stroke,
|
|
29
|
+
alpha: a
|
|
30
|
+
}))
|
|
31
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build renderable waterfall bars. Bar color is semantic (positive/negative/total from
|
|
3
|
+
* options), not the shared palette. Adds fixed `alpha` and carries connector anchors.
|
|
4
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
5
|
+
*/
|
|
6
|
+
export function buildWaterfallMarks({ data, plot, channels, options, alpha, type }: {
|
|
7
|
+
data: any[];
|
|
8
|
+
plot: any;
|
|
9
|
+
channels: any;
|
|
10
|
+
options?: any;
|
|
11
|
+
alpha?: number;
|
|
12
|
+
type?: string;
|
|
13
|
+
}): {
|
|
14
|
+
key: string;
|
|
15
|
+
x: number;
|
|
16
|
+
y: number;
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
fill: any;
|
|
20
|
+
alpha: number;
|
|
21
|
+
bandStart: any;
|
|
22
|
+
bandEnd: any;
|
|
23
|
+
cumY: any;
|
|
24
|
+
data: any;
|
|
25
|
+
}[];
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { resolveAlpha } from '../aesthetics.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Build renderable waterfall bars. Bar color is semantic (positive/negative/total from
|
|
5
|
+
* options), not the shared palette. Adds fixed `alpha` and carries connector anchors.
|
|
6
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
7
|
+
*/
|
|
8
|
+
export function buildWaterfallMarks({ data, plot, channels, options = {}, alpha, type = 'waterfall' }) {
|
|
9
|
+
const { xScale, yScale } = plot
|
|
10
|
+
if (!data?.length || !xScale || !yScale) return []
|
|
11
|
+
|
|
12
|
+
const positiveColor = options.positiveColor ?? '#22c55e'
|
|
13
|
+
const negativeColor = options.negativeColor ?? '#ef4444'
|
|
14
|
+
const totalColor = options.totalColor ?? '#3b82f6'
|
|
15
|
+
const totalField = options.totalField ?? undefined
|
|
16
|
+
const a = resolveAlpha(alpha, type, plot.chartPreset)
|
|
17
|
+
|
|
18
|
+
const bw = typeof xScale.bandwidth === 'function' ? xScale.bandwidth() : 10
|
|
19
|
+
let cumulative = 0
|
|
20
|
+
|
|
21
|
+
return data.map((d, i) => {
|
|
22
|
+
const xVal = d[channels.x ?? '']
|
|
23
|
+
const yVal = Number(d[channels.y ?? ''])
|
|
24
|
+
const isTotal = totalField ? Boolean(d[totalField]) : false
|
|
25
|
+
const xPos = xScale(xVal) ?? 0
|
|
26
|
+
let barTop
|
|
27
|
+
let barBottom
|
|
28
|
+
let fill
|
|
29
|
+
|
|
30
|
+
if (isTotal) {
|
|
31
|
+
barTop = yScale(Math.max(0, cumulative)) ?? 0
|
|
32
|
+
barBottom = yScale(0) ?? 0
|
|
33
|
+
fill = totalColor
|
|
34
|
+
} else {
|
|
35
|
+
const start = cumulative
|
|
36
|
+
cumulative += yVal
|
|
37
|
+
barTop = yScale(Math.max(start, cumulative)) ?? 0
|
|
38
|
+
barBottom = yScale(Math.min(start, cumulative)) ?? 0
|
|
39
|
+
fill = yVal >= 0 ? positiveColor : negativeColor
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const c1 = plot.place(xPos, barTop)
|
|
43
|
+
const c2 = plot.place(xPos + bw, barBottom)
|
|
44
|
+
return {
|
|
45
|
+
key: `${xVal}-${i}`,
|
|
46
|
+
x: Math.min(c1.x, c2.x),
|
|
47
|
+
y: Math.min(c1.y, c2.y),
|
|
48
|
+
width: Math.abs(c2.x - c1.x),
|
|
49
|
+
height: Math.max(1, Math.abs(c2.y - c1.y)),
|
|
50
|
+
fill,
|
|
51
|
+
alpha: a,
|
|
52
|
+
bandStart: xPos,
|
|
53
|
+
bandEnd: xPos + bw,
|
|
54
|
+
cumY: yScale(cumulative) ?? 0,
|
|
55
|
+
data: d
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,15 @@ export namespace Plot {
|
|
|
10
10
|
export { Arc };
|
|
11
11
|
export { Highlight };
|
|
12
12
|
export { Trend };
|
|
13
|
+
export { Box };
|
|
14
|
+
export { Violin };
|
|
15
|
+
export { Jitter };
|
|
16
|
+
export { Candlestick };
|
|
17
|
+
export { Heatmap };
|
|
18
|
+
export { Hexbin };
|
|
19
|
+
export { Ribbon };
|
|
20
|
+
export { Waterfall };
|
|
21
|
+
export { Rule };
|
|
13
22
|
}
|
|
14
23
|
export namespace PlotLayers { }
|
|
15
24
|
export { default as PlotChart } from "./Plot.svelte";
|
|
@@ -32,6 +41,8 @@ export { default as GeomHexbin } from "./geoms/Hexbin.svelte";
|
|
|
32
41
|
export { default as GeomRibbon } from "./geoms/Ribbon.svelte";
|
|
33
42
|
export { default as GeomHighlight } from "./geoms/Highlight.svelte";
|
|
34
43
|
export { default as GeomTrend } from "./geoms/Trend.svelte";
|
|
44
|
+
export { default as GeomJitter } from "./geoms/Jitter.svelte";
|
|
45
|
+
export { default as GeomRule } from "./geoms/Rule.svelte";
|
|
35
46
|
export { default as Chart } from "./Chart.svelte";
|
|
36
47
|
export { default as Sparkline } from "./Sparkline.svelte";
|
|
37
48
|
export { default as BarChart } from "./charts/BarChart.svelte";
|
|
@@ -43,13 +54,6 @@ export { default as BoxPlot } from "./charts/BoxPlot.svelte";
|
|
|
43
54
|
export { default as ViolinPlot } from "./charts/ViolinPlot.svelte";
|
|
44
55
|
export { default as BubbleChart } from "./charts/BubbleChart.svelte";
|
|
45
56
|
export { PlotState } from "./PlotState.svelte.js";
|
|
46
|
-
export { ChartBrewer } from "./lib/brewing/index.svelte.js";
|
|
47
|
-
export * from "./lib/brewing/index.svelte.js";
|
|
48
|
-
export { CartesianBrewer } from "./lib/brewing/CartesianBrewer.svelte.js";
|
|
49
|
-
export { PieBrewer } from "./lib/brewing/PieBrewer.svelte.js";
|
|
50
|
-
export { QuartileBrewer } from "./lib/brewing/QuartileBrewer.svelte.js";
|
|
51
|
-
export { BoxBrewer } from "./lib/brewing/BoxBrewer.svelte.js";
|
|
52
|
-
export { ViolinBrewer } from "./lib/brewing/ViolinBrewer.svelte.js";
|
|
53
57
|
export { createCrossFilter } from "./crossfilter/createCrossFilter.svelte.js";
|
|
54
58
|
export { default as CrossFilter } from "./crossfilter/CrossFilter.svelte";
|
|
55
59
|
export { default as FilterBar } from "./crossfilter/FilterBar.svelte";
|
|
@@ -57,14 +61,23 @@ export { default as FilterSlider } from "./crossfilter/FilterSlider.svelte";
|
|
|
57
61
|
export { default as FilterHistogram } from "./crossfilter/FilterHistogram.svelte";
|
|
58
62
|
import Root from './Plot/Root.svelte';
|
|
59
63
|
import Axis from './Plot/Axis.svelte';
|
|
60
|
-
import Bar from './
|
|
64
|
+
import Bar from './geoms/Bar.svelte';
|
|
61
65
|
import Grid from './Plot/Grid.svelte';
|
|
62
66
|
import Legend from './Plot/Legend.svelte';
|
|
63
|
-
import Line from './
|
|
64
|
-
import Area from './
|
|
65
|
-
import Point from './
|
|
66
|
-
import Arc from './
|
|
67
|
+
import Line from './geoms/Line.svelte';
|
|
68
|
+
import Area from './geoms/Area.svelte';
|
|
69
|
+
import Point from './geoms/Point.svelte';
|
|
70
|
+
import Arc from './geoms/Arc.svelte';
|
|
67
71
|
import Highlight from './geoms/Highlight.svelte';
|
|
68
72
|
import Trend from './geoms/Trend.svelte';
|
|
73
|
+
import Box from './geoms/Box.svelte';
|
|
74
|
+
import Violin from './geoms/Violin.svelte';
|
|
75
|
+
import Jitter from './geoms/Jitter.svelte';
|
|
76
|
+
import Candlestick from './geoms/Candlestick.svelte';
|
|
77
|
+
import Heatmap from './geoms/Heatmap.svelte';
|
|
78
|
+
import Hexbin from './geoms/Hexbin.svelte';
|
|
79
|
+
import Ribbon from './geoms/Ribbon.svelte';
|
|
80
|
+
import Waterfall from './geoms/Waterfall.svelte';
|
|
81
|
+
import Rule from './geoms/Rule.svelte';
|
|
69
82
|
export { createChartPreset, defaultPreset } from "./lib/preset.js";
|
|
70
83
|
export { buildSequentialScale, buildDivergingScale } from "./lib/brewing/colors.js";
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import Root from './Plot/Root.svelte'
|
|
2
2
|
import Axis from './Plot/Axis.svelte'
|
|
3
|
-
import Bar from './
|
|
3
|
+
import Bar from './geoms/Bar.svelte'
|
|
4
4
|
import Grid from './Plot/Grid.svelte'
|
|
5
5
|
import Legend from './Plot/Legend.svelte'
|
|
6
|
-
import Line from './
|
|
7
|
-
import Area from './
|
|
8
|
-
import Point from './
|
|
9
|
-
import Arc from './
|
|
6
|
+
import Line from './geoms/Line.svelte'
|
|
7
|
+
import Area from './geoms/Area.svelte'
|
|
8
|
+
import Point from './geoms/Point.svelte'
|
|
9
|
+
import Arc from './geoms/Arc.svelte'
|
|
10
10
|
import Highlight from './geoms/Highlight.svelte'
|
|
11
11
|
import Trend from './geoms/Trend.svelte'
|
|
12
|
+
import Box from './geoms/Box.svelte'
|
|
13
|
+
import Violin from './geoms/Violin.svelte'
|
|
14
|
+
import Jitter from './geoms/Jitter.svelte'
|
|
15
|
+
import Candlestick from './geoms/Candlestick.svelte'
|
|
16
|
+
import Heatmap from './geoms/Heatmap.svelte'
|
|
17
|
+
import Hexbin from './geoms/Hexbin.svelte'
|
|
18
|
+
import Ribbon from './geoms/Ribbon.svelte'
|
|
19
|
+
import Waterfall from './geoms/Waterfall.svelte'
|
|
20
|
+
import Rule from './geoms/Rule.svelte'
|
|
12
21
|
|
|
13
22
|
// Composable Plot primitives — use as <Plot.Root>, <Plot.Axis>, <Plot.Bar>, etc.
|
|
14
23
|
export const Plot = {
|
|
@@ -22,7 +31,16 @@ export const Plot = {
|
|
|
22
31
|
Point,
|
|
23
32
|
Arc,
|
|
24
33
|
Highlight,
|
|
25
|
-
Trend
|
|
34
|
+
Trend,
|
|
35
|
+
Box,
|
|
36
|
+
Violin,
|
|
37
|
+
Jitter,
|
|
38
|
+
Candlestick,
|
|
39
|
+
Heatmap,
|
|
40
|
+
Hexbin,
|
|
41
|
+
Ribbon,
|
|
42
|
+
Waterfall,
|
|
43
|
+
Rule
|
|
26
44
|
}
|
|
27
45
|
|
|
28
46
|
/** @deprecated Use Plot instead */
|
|
@@ -54,6 +72,8 @@ export { default as GeomHexbin } from './geoms/Hexbin.svelte'
|
|
|
54
72
|
export { default as GeomRibbon } from './geoms/Ribbon.svelte'
|
|
55
73
|
export { default as GeomHighlight } from './geoms/Highlight.svelte'
|
|
56
74
|
export { default as GeomTrend } from './geoms/Trend.svelte'
|
|
75
|
+
export { default as GeomJitter } from './geoms/Jitter.svelte'
|
|
76
|
+
export { default as GeomRule } from './geoms/Rule.svelte'
|
|
57
77
|
|
|
58
78
|
// Export standalone components
|
|
59
79
|
export { default as Chart } from './Chart.svelte'
|
|
@@ -71,14 +91,7 @@ export { default as BubbleChart } from './charts/BubbleChart.svelte'
|
|
|
71
91
|
export { PlotState } from './PlotState.svelte.js'
|
|
72
92
|
|
|
73
93
|
// Export utilities
|
|
74
|
-
export { ChartBrewer } from './lib/brewing/index.svelte.js'
|
|
75
|
-
export * from './lib/brewing/index.svelte.js'
|
|
76
94
|
export { buildSequentialScale, buildDivergingScale } from './lib/brewing/colors.js'
|
|
77
|
-
export { CartesianBrewer } from './lib/brewing/CartesianBrewer.svelte.js'
|
|
78
|
-
export { PieBrewer } from './lib/brewing/PieBrewer.svelte.js'
|
|
79
|
-
export { QuartileBrewer } from './lib/brewing/QuartileBrewer.svelte.js'
|
|
80
|
-
export { BoxBrewer } from './lib/brewing/BoxBrewer.svelte.js'
|
|
81
|
-
export { ViolinBrewer } from './lib/brewing/ViolinBrewer.svelte.js'
|
|
82
95
|
|
|
83
96
|
// CrossFilter system
|
|
84
97
|
export { createCrossFilter } from './crossfilter/createCrossFilter.svelte.js'
|
|
@@ -15,7 +15,13 @@ import { toPatternId } from '../../brewing/patterns.js'
|
|
|
15
15
|
export function buildArcs(data, channels, colors, width, height, opts = {}, patterns) {
|
|
16
16
|
const { color: lf, y: yf } = channels
|
|
17
17
|
const radius = Math.min(width, height) / 2
|
|
18
|
-
|
|
18
|
+
// innerRadius: a value <= 1 is a fraction of the radius (responsive donut);
|
|
19
|
+
// a value > 1 is absolute pixels. Clamp below the outer radius so a bad value
|
|
20
|
+
// (e.g. a fraction/pixel mixup) can never invert the arc into a giant ring
|
|
21
|
+
// rendered outside the circle.
|
|
22
|
+
const rawInner = opts.innerRadius ?? 0
|
|
23
|
+
const innerPx = rawInner <= 1 ? rawInner * radius : rawInner
|
|
24
|
+
const innerRadius = Math.max(0, Math.min(innerPx, radius * 0.98))
|
|
19
25
|
const pieGen = pie().value((d) => Number(d[yf]))
|
|
20
26
|
const arcGen = arc().innerRadius(innerRadius).outerRadius(radius)
|
|
21
27
|
const slices = pieGen(data)
|