@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
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Shared aesthetic resolution for all geoms. Done ONCE here so every geom's build
|
|
2
|
+
// function inherits the same ggplot-aligned fill/color and alpha rules.
|
|
3
|
+
// See docs/backlog/2026-08-17-chart-aesthetics-unification.md §2, §3, §11.
|
|
4
|
+
|
|
5
|
+
const GRAY = { fill: '#888', stroke: '#888' }
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Resolve a mark's interior (fill) and outline (stroke) from the `fill` and `color`
|
|
9
|
+
* channels through the shared categorical `colors` palette (Map<value, {fill, stroke}>).
|
|
10
|
+
*
|
|
11
|
+
* ggplot fallback:
|
|
12
|
+
* - color-only → fill AND stroke from the color value's entry (backward compatible)
|
|
13
|
+
* - fill-only → fill AND stroke from the fill value's entry
|
|
14
|
+
* - both → interior from the fill value, outline from the color value
|
|
15
|
+
* - neither → the first palette entry (single-series)
|
|
16
|
+
*
|
|
17
|
+
* @param {Record<string, unknown>} row
|
|
18
|
+
* @param {{ fill?: string, color?: string }} channels
|
|
19
|
+
* @param {Map<unknown, { fill: string, stroke: string }>} colors
|
|
20
|
+
* @returns {{ fill: string, stroke: string }}
|
|
21
|
+
*/
|
|
22
|
+
export function resolveFillStroke(row, channels, colors) {
|
|
23
|
+
const { fill, color } = channels ?? {}
|
|
24
|
+
const first = colors?.values?.().next?.().value ?? GRAY
|
|
25
|
+
const fillEntry = fill ? (colors?.get(row?.[fill]) ?? first) : null
|
|
26
|
+
const colorEntry = color ? (colors?.get(row?.[color]) ?? first) : null
|
|
27
|
+
const base = fillEntry ?? colorEntry ?? first
|
|
28
|
+
return {
|
|
29
|
+
fill: (fillEntry ?? base).fill,
|
|
30
|
+
stroke: (colorEntry ?? base).stroke
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Resolve a geom's mark opacity: an explicit fixed `alpha`, else the per-geom preset
|
|
36
|
+
* default, else fully opaque.
|
|
37
|
+
* @param {number|undefined} alpha
|
|
38
|
+
* @param {string} type - geom type key into preset.opacity
|
|
39
|
+
* @param {{ opacity?: Record<string, number> }} [preset]
|
|
40
|
+
* @returns {number}
|
|
41
|
+
*/
|
|
42
|
+
export function resolveAlpha(alpha, type, preset) {
|
|
43
|
+
if (typeof alpha === 'number') return alpha
|
|
44
|
+
return preset?.opacity?.[type] ?? 1
|
|
45
|
+
}
|
|
@@ -49,7 +49,7 @@ export function buildStackedAreas(data: Object[], channels: {
|
|
|
49
49
|
}>, curve?: "linear" | "smooth" | "step", patterns?: Map<unknown, string>, place?: (x: any, y: any) => {
|
|
50
50
|
x: any;
|
|
51
51
|
y: any;
|
|
52
|
-
}): {
|
|
52
|
+
}, normalize?: boolean): {
|
|
53
53
|
d: string;
|
|
54
54
|
fill: string;
|
|
55
55
|
stroke: string;
|
package/dist/geoms/lib/areas.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { area, stack, curveCatmullRom, curveStep } from 'd3-shape'
|
|
1
|
+
import { area, stack, stackOffsetExpand, curveCatmullRom, curveStep } from 'd3-shape'
|
|
2
2
|
import { toPatternId } from '../../lib/brewing/patterns.js'
|
|
3
|
+
import { literalColor, markEntry } from '../../lib/brewing/colors.js'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Builds area path geometry for multi-series area charts.
|
|
@@ -15,16 +16,25 @@ import { toPatternId } from '../../lib/brewing/patterns.js'
|
|
|
15
16
|
* @returns {{ d: string, fill: string, stroke: string, key: unknown, patternId: string|null }[]}
|
|
16
17
|
*/
|
|
17
18
|
export function buildAreas(data, channels, xScale, yScale, colors, curve, patterns, place = (x, y) => ({ x, y })) {
|
|
18
|
-
const { x: xf, y: yf,
|
|
19
|
+
const { x: xf, y: yf, pattern: pf } = channels
|
|
20
|
+
// A literal color (var()/oklch()/hex/currentColor) isn't a data field — it's the exact
|
|
21
|
+
// fill the caller wants for THIS area. Don't group on it, and don't fall back to the
|
|
22
|
+
// shared color scale (one value across all geoms); use it directly.
|
|
23
|
+
const lit = literalColor(channels.color)
|
|
24
|
+
const cf = lit ? undefined : channels.color
|
|
19
25
|
const baseline = yScale.range()[0] // bottom of the chart (y pixel max)
|
|
20
26
|
|
|
21
27
|
const xPos = (d) =>
|
|
22
28
|
typeof xScale.bandwidth === 'function' ? xScale(d[xf]) + xScale.bandwidth() / 2 : xScale(d[xf])
|
|
23
29
|
|
|
24
30
|
// Each area edge (baseline + top) is placed so the area transposes under orientation.
|
|
25
|
-
|
|
31
|
+
// `v` carries the raw y-value so the generator can break the area at a gap (null).
|
|
32
|
+
const toEdge = (d) => ({ base: place(xPos(d), baseline), top: place(xPos(d), yScale(d[yf])), v: d[yf] })
|
|
26
33
|
const makeGen = () => {
|
|
27
34
|
const gen = area()
|
|
35
|
+
// A null y-value is a GAP (a missing period): break the area there instead of
|
|
36
|
+
// dropping it onto the 0 baseline. A genuine 0 stays defined and fills.
|
|
37
|
+
.defined((p) => Number.isFinite(p.top.y) && (yf === undefined || yf === null || (p.v !== undefined && p.v !== null)))
|
|
28
38
|
.x0((p) => p.base.x)
|
|
29
39
|
.y0((p) => p.base.y)
|
|
30
40
|
.x1((p) => p.top.x)
|
|
@@ -45,7 +55,8 @@ export function buildAreas(data, channels, xScale, yScale, colors, curve, patter
|
|
|
45
55
|
}
|
|
46
56
|
|
|
47
57
|
if (!cf) {
|
|
48
|
-
|
|
58
|
+
// A literal color IS the fill; a single-series field uses the shared shade.
|
|
59
|
+
const entry = markEntry(lit, undefined, colors, colors?.values().next().value ?? { fill: '#888', stroke: '#888' })
|
|
49
60
|
const patternKey = pf ? data[0]?.[pf] : null
|
|
50
61
|
const patternId =
|
|
51
62
|
patternKey !== null && patternKey !== undefined && patterns?.has(patternKey)
|
|
@@ -92,7 +103,7 @@ export function buildAreas(data, channels, xScale, yScale, colors, curve, patter
|
|
|
92
103
|
* @param {Map<unknown, string>} [patterns]
|
|
93
104
|
* @returns {{ d: string, fill: string, stroke: string, key: unknown, patternId: string|null }[]}
|
|
94
105
|
*/
|
|
95
|
-
export function buildStackedAreas(data, channels, xScale, yScale, colors, curve, patterns, place = (x, y) => ({ x, y })) {
|
|
106
|
+
export function buildStackedAreas(data, channels, xScale, yScale, colors, curve, patterns, place = (x, y) => ({ x, y }), normalize = false) {
|
|
96
107
|
const { x: xf, y: yf, color: cf, pattern: pf } = channels
|
|
97
108
|
if (!cf) return buildAreas(data, channels, xScale, yScale, colors, curve, patterns)
|
|
98
109
|
|
|
@@ -132,6 +143,8 @@ export function buildStackedAreas(data, channels, xScale, yScale, colors, curve,
|
|
|
132
143
|
}
|
|
133
144
|
|
|
134
145
|
const stackGen = stack().keys(colorCategories)
|
|
146
|
+
// position='fill' → normalize each x column to [0,1] (100% stacked area).
|
|
147
|
+
if (normalize) stackGen.offset(stackOffsetExpand)
|
|
135
148
|
const layers = stackGen(wide)
|
|
136
149
|
|
|
137
150
|
const orderedPatternKeys = pf && pf !== cf ? [...(patterns?.keys() ?? [])] : null
|
package/dist/geoms/lib/bars.d.ts
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
export function buildBars(data: any, channels: any, xScale: any, yScale: any, colors: any, innerHeight: any, patterns: any, place?: (x: any, y: any) => {
|
|
12
12
|
x: any;
|
|
13
13
|
y: any;
|
|
14
|
-
}, continuousCategory?: boolean): any;
|
|
14
|
+
}, continuousCategory?: boolean, dodge?: boolean): any;
|
|
15
15
|
export function buildStackedBars(data: any, channels: any, xScale: any, yScale: any, colors: any, innerHeight: any, patterns: any, place?: (x: any, y: any) => {
|
|
16
16
|
x: any;
|
|
17
17
|
y: any;
|
|
18
|
-
}): any;
|
|
18
|
+
}, normalize?: boolean): any;
|
package/dist/geoms/lib/bars.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { scaleBand } from 'd3-scale'
|
|
2
|
-
import { stack } from 'd3-shape'
|
|
2
|
+
import { stack, stackOffsetExpand } from 'd3-shape'
|
|
3
3
|
import { toPatternId } from '../../lib/brewing/patterns.js'
|
|
4
|
-
import { isLiteralColor } from '../../lib/brewing/colors.js'
|
|
4
|
+
import { isLiteralColor, literalColor, markEntry } from '../../lib/brewing/colors.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Returns a band scale suitable for bar x-positioning.
|
|
@@ -17,14 +17,15 @@ function ensureBandX(xScale, data, xField) {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* Returns the sub-band fields: distinct non-x fields among [color, pattern].
|
|
21
|
-
* These are the fields that cause multiple bars within a single x-band.
|
|
20
|
+
* Returns the sub-band fields: distinct non-x fields among [group, color, pattern].
|
|
21
|
+
* These are the fields that cause multiple bars within a single x-band (dodge/grouping).
|
|
22
|
+
* `group` (the explicit grouping channel) takes precedence as the first sub-band.
|
|
22
23
|
*/
|
|
23
24
|
function subBandFields(channels) {
|
|
24
|
-
const { x: xf, color: cf, pattern: pf } = channels
|
|
25
|
+
const { x: xf, group: gf, color: cf, pattern: pf } = channels
|
|
25
26
|
const seen = new Set()
|
|
26
27
|
const out = []
|
|
27
|
-
for (const f of [cf, pf]) {
|
|
28
|
+
for (const f of [gf, cf, pf]) {
|
|
28
29
|
if (f && f !== xf && !seen.has(f) && !isLiteralColor(f)) {
|
|
29
30
|
seen.add(f)
|
|
30
31
|
out.push(f)
|
|
@@ -52,11 +53,16 @@ export function buildBars(
|
|
|
52
53
|
innerHeight,
|
|
53
54
|
patterns,
|
|
54
55
|
place = (x, y) => ({ x, y }),
|
|
55
|
-
continuousCategory = false
|
|
56
|
+
continuousCategory = false,
|
|
57
|
+
dodge = true
|
|
56
58
|
) {
|
|
57
59
|
const { x: xf, y: yf, color: cf, pattern: pf } = channels
|
|
60
|
+
// A literal color is the exact fill for every bar; a field indexes the shared color scale.
|
|
61
|
+
const lit = literalColor(cf)
|
|
62
|
+
const field = lit ? undefined : cf
|
|
58
63
|
|
|
59
|
-
|
|
64
|
+
// No sub-banding for a continuous (race) axis or position='identity' (dodge=false → overlap).
|
|
65
|
+
const subFields = continuousCategory || !dodge ? [] : subBandFields(channels)
|
|
60
66
|
const getSubKey = (d) => subFields.map((f) => String(d[f])).join('::')
|
|
61
67
|
|
|
62
68
|
let positionOf
|
|
@@ -93,12 +99,16 @@ export function buildBars(
|
|
|
93
99
|
|
|
94
100
|
return data.map((d, i) => {
|
|
95
101
|
const xVal = d[xf]
|
|
96
|
-
const colorKey =
|
|
102
|
+
const colorKey = field ? d[field] : null
|
|
97
103
|
const patternKey = pf ? d[pf] : null
|
|
98
104
|
const subKey = getSubKey(d)
|
|
99
105
|
|
|
100
|
-
const colorEntry =
|
|
106
|
+
const colorEntry = markEntry(
|
|
107
|
+
lit,
|
|
108
|
+
colorKey,
|
|
109
|
+
colors,
|
|
101
110
|
colors?.values().next().value ?? { fill: '#888', stroke: '#888' }
|
|
111
|
+
)
|
|
102
112
|
const patternId =
|
|
103
113
|
patternKey !== null && patternKey !== undefined && patterns?.has(patternKey)
|
|
104
114
|
? toPatternId(String(patternKey))
|
|
@@ -131,8 +141,10 @@ export function buildBars(
|
|
|
131
141
|
})
|
|
132
142
|
}
|
|
133
143
|
|
|
134
|
-
export function buildStackedBars(data, channels, xScale, yScale, colors, innerHeight, patterns, place = (x, y) => ({ x, y })) {
|
|
144
|
+
export function buildStackedBars(data, channels, xScale, yScale, colors, innerHeight, patterns, place = (x, y) => ({ x, y }), normalize = false) {
|
|
135
145
|
const { x: xf, y: yf, color: cf, pattern: pf } = channels
|
|
146
|
+
const lit = literalColor(cf)
|
|
147
|
+
const field = lit ? undefined : cf
|
|
136
148
|
|
|
137
149
|
const bandScale = ensureBandX(xScale, data, xf)
|
|
138
150
|
|
|
@@ -159,6 +171,8 @@ export function buildStackedBars(data, channels, xScale, yScale, colors, innerHe
|
|
|
159
171
|
})
|
|
160
172
|
|
|
161
173
|
const stackGen = stack().keys(stackCategories)
|
|
174
|
+
// position='fill' → normalize each x column to [0,1] (100% stacked).
|
|
175
|
+
if (normalize) stackGen.offset(stackOffsetExpand)
|
|
162
176
|
const layers = stackGen(wide)
|
|
163
177
|
|
|
164
178
|
const bars = []
|
|
@@ -170,8 +184,8 @@ export function buildStackedBars(data, channels, xScale, yScale, colors, innerHe
|
|
|
170
184
|
const xVal = point.data[xf]
|
|
171
185
|
|
|
172
186
|
// Color lookup: cf may equal xf (= xVal) or stackField (= stackKey)
|
|
173
|
-
const colorKey =
|
|
174
|
-
const colorEntry =
|
|
187
|
+
const colorKey = field ? (field === xf ? xVal : field === stackField ? stackKey : null) : null
|
|
188
|
+
const colorEntry = markEntry(lit, colorKey, colors, { fill: '#888', stroke: '#888' })
|
|
175
189
|
|
|
176
190
|
// Pattern lookup: pf may equal xf (= xVal) or stackField (= stackKey)
|
|
177
191
|
const patternKey = pf ? (pf === xf ? xVal : pf === stackField ? stackKey : null) : null
|
|
@@ -180,13 +194,19 @@ export function buildStackedBars(data, channels, xScale, yScale, colors, innerHe
|
|
|
180
194
|
? toPatternId(String(patternKey))
|
|
181
195
|
: null
|
|
182
196
|
|
|
197
|
+
// Two opposite corners in (band, value) space, mapped through place() so the
|
|
198
|
+
// stack transposes under orientation='horizontal' (identity default → unchanged).
|
|
199
|
+
// Without this a grouped stack/fill ignored place() and always drew vertically.
|
|
200
|
+
const band = bandScale(xVal) ?? 0
|
|
201
|
+
const c1 = place(band, yScale(y0))
|
|
202
|
+
const c2 = place(band + bandScale.bandwidth(), yScale(y1))
|
|
183
203
|
bars.push({
|
|
184
204
|
data: point.data,
|
|
185
205
|
key: `${String(xVal)}::${String(stackKey)}`,
|
|
186
|
-
x:
|
|
187
|
-
y:
|
|
188
|
-
width:
|
|
189
|
-
height:
|
|
206
|
+
x: Math.min(c1.x, c2.x),
|
|
207
|
+
y: Math.min(c1.y, c2.y),
|
|
208
|
+
width: Math.abs(c2.x - c1.x),
|
|
209
|
+
height: Math.abs(c2.y - c1.y),
|
|
190
210
|
fill: colorEntry.fill,
|
|
191
211
|
stroke: colorEntry.stroke,
|
|
192
212
|
patternId
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build renderable pie/donut arcs. Slice interior + border come from `fill ?? color`
|
|
3
|
+
* through the shared palette (buildArcs already yields fill + a darker stroke). Adds the
|
|
4
|
+
* geom's fixed `alpha`.
|
|
5
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
6
|
+
*/
|
|
7
|
+
export function buildArcMarks({ 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
|
+
key: unknown;
|
|
20
|
+
patternId: string | null;
|
|
21
|
+
pct: number;
|
|
22
|
+
centroid: [number, number];
|
|
23
|
+
data: Record<string, unknown>;
|
|
24
|
+
}[];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { buildArcs } from '../../../lib/brewing/marks/arcs.js'
|
|
2
|
+
import { resolveAlpha } from '../aesthetics.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build renderable pie/donut arcs. Slice interior + border come from `fill ?? color`
|
|
6
|
+
* through the shared palette (buildArcs already yields fill + a darker stroke). Adds the
|
|
7
|
+
* geom's fixed `alpha`.
|
|
8
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
9
|
+
*/
|
|
10
|
+
export function buildArcMarks({ data, plot, channels, options = {}, alpha, type = 'arc' }) {
|
|
11
|
+
if (!data?.length) return []
|
|
12
|
+
const interiorField = channels.fill ?? channels.color
|
|
13
|
+
// Guard: skip until data catches up after a fill-field change — otherwise a stale row set
|
|
14
|
+
// (missing the new field) produces all-undefined keys and duplicate-key errors.
|
|
15
|
+
if (interiorField && data[0] && !(interiorField in data[0])) return []
|
|
16
|
+
|
|
17
|
+
const arcs = buildArcs(
|
|
18
|
+
data,
|
|
19
|
+
{ color: interiorField, y: channels.y, pattern: channels.pattern },
|
|
20
|
+
plot.colors,
|
|
21
|
+
plot.innerWidth,
|
|
22
|
+
plot.innerHeight,
|
|
23
|
+
{ innerRadius: options.innerRadius ?? 0 },
|
|
24
|
+
plot.patterns
|
|
25
|
+
)
|
|
26
|
+
const a = resolveAlpha(alpha, type, plot.chartPreset)
|
|
27
|
+
return arcs.map((arc) => ({ ...arc, alpha: a }))
|
|
28
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build renderable area segments. Interior is grouped/filled by `fill ?? color`
|
|
3
|
+
* (ggplot geom_area's fill). A border stroke is drawn only when BOTH `fill` and `color`
|
|
4
|
+
* are set — so an old `color`-only area stays border-less (backward compatible); the
|
|
5
|
+
* border uses the interior group's darker stroke shade. Per-field border coloring
|
|
6
|
+
* (fill ≠ color, two legends) is the deferred dual-scale follow-up.
|
|
7
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
8
|
+
*/
|
|
9
|
+
export function buildAreaMarks({ data, plot, channels, options, alpha, type }: {
|
|
10
|
+
data: any[];
|
|
11
|
+
plot: any;
|
|
12
|
+
channels: any;
|
|
13
|
+
options?: any;
|
|
14
|
+
alpha?: number;
|
|
15
|
+
type?: string;
|
|
16
|
+
}): {
|
|
17
|
+
stroke: any;
|
|
18
|
+
alpha: number;
|
|
19
|
+
d: string;
|
|
20
|
+
fill: string;
|
|
21
|
+
key: unknown;
|
|
22
|
+
patternId: string | null;
|
|
23
|
+
}[];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { buildAreas, buildStackedAreas } from '../areas.js'
|
|
2
|
+
import { resolveAlpha } from '../aesthetics.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build renderable area segments. Interior is grouped/filled by `fill ?? color`
|
|
6
|
+
* (ggplot geom_area's fill). A border stroke is drawn only when BOTH `fill` and `color`
|
|
7
|
+
* are set — so an old `color`-only area stays border-less (backward compatible); the
|
|
8
|
+
* border uses the interior group's darker stroke shade. Per-field border coloring
|
|
9
|
+
* (fill ≠ color, two legends) is the deferred dual-scale follow-up.
|
|
10
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
11
|
+
*/
|
|
12
|
+
export function buildAreaMarks({ data, plot, channels, options = {}, alpha, type = 'area' }) {
|
|
13
|
+
const { xScale, yScale, colors, patterns } = plot
|
|
14
|
+
if (!data?.length || !xScale || !yScale || !channels.x || !channels.y) return []
|
|
15
|
+
|
|
16
|
+
const interiorField = channels.fill ?? channels.color
|
|
17
|
+
const hasBorder = Boolean(channels.fill && channels.color)
|
|
18
|
+
const place = plot.place.bind(plot)
|
|
19
|
+
const areaChannels = {
|
|
20
|
+
x: channels.x,
|
|
21
|
+
y: channels.y,
|
|
22
|
+
color: interiorField,
|
|
23
|
+
pattern: channels.pattern
|
|
24
|
+
}
|
|
25
|
+
// Areas don't dodge; position selects stack | fill (100%) | identity (overlap, default).
|
|
26
|
+
const position = options.position ?? (options.stack ? 'stack' : 'identity')
|
|
27
|
+
const stacked = position === 'stack' || position === 'fill'
|
|
28
|
+
const raw = stacked
|
|
29
|
+
? buildStackedAreas(data, areaChannels, xScale, yScale, colors, options.curve, patterns, place, position === 'fill')
|
|
30
|
+
: buildAreas(data, areaChannels, xScale, yScale, colors, options.curve, patterns, place)
|
|
31
|
+
|
|
32
|
+
const a = resolveAlpha(alpha, type, plot.chartPreset)
|
|
33
|
+
return raw.map((seg) => ({
|
|
34
|
+
...seg,
|
|
35
|
+
stroke: hasBorder ? (colors.get(seg.key)?.stroke ?? 'none') : 'none',
|
|
36
|
+
alpha: a
|
|
37
|
+
}))
|
|
38
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build renderable bar marks. Interior is grouped/filled by `fill ?? color`; the `group`
|
|
3
|
+
* channel (default `fill ?? color`) drives the sub-series partitioned by `position`:
|
|
4
|
+
* - stack: cumulative segments - dodge: side-by-side sub-bands (default)
|
|
5
|
+
* - fill: 100% (normalized) stack - identity: overlapping full-width bars
|
|
6
|
+
* `options.stack: true` maps to position 'stack' (back-compat). Adds the geom's fixed `alpha`.
|
|
7
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
8
|
+
*/
|
|
9
|
+
export function buildBarMarks({ data, plot, channels, options, alpha, type }: {
|
|
10
|
+
data: any[];
|
|
11
|
+
plot: any;
|
|
12
|
+
channels: any;
|
|
13
|
+
options?: any;
|
|
14
|
+
alpha?: number;
|
|
15
|
+
type?: string;
|
|
16
|
+
}): any;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { buildBars, buildStackedBars } from '../bars.js'
|
|
2
|
+
import { resolveAlpha } from '../aesthetics.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build renderable bar marks. Interior is grouped/filled by `fill ?? color`; the `group`
|
|
6
|
+
* channel (default `fill ?? color`) drives the sub-series partitioned by `position`:
|
|
7
|
+
* - stack: cumulative segments - dodge: side-by-side sub-bands (default)
|
|
8
|
+
* - fill: 100% (normalized) stack - identity: overlapping full-width bars
|
|
9
|
+
* `options.stack: true` maps to position 'stack' (back-compat). Adds the geom's fixed `alpha`.
|
|
10
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
11
|
+
*/
|
|
12
|
+
export function buildBarMarks({ data, plot, channels, options = {}, alpha, type = 'bar' }) {
|
|
13
|
+
const { xScale, yScale, colors, patterns } = plot
|
|
14
|
+
if (!data?.length || !xScale || !yScale) return []
|
|
15
|
+
|
|
16
|
+
const interiorField = channels.fill ?? channels.color
|
|
17
|
+
const groupField = channels.group ?? channels.fill ?? channels.color
|
|
18
|
+
const barChannels = {
|
|
19
|
+
x: channels.x,
|
|
20
|
+
y: channels.y,
|
|
21
|
+
color: interiorField,
|
|
22
|
+
pattern: channels.pattern,
|
|
23
|
+
group: groupField
|
|
24
|
+
}
|
|
25
|
+
const place = plot.place.bind(plot)
|
|
26
|
+
const ih = plot.innerHeight
|
|
27
|
+
const position = options.position ?? (options.stack ? 'stack' : 'dodge')
|
|
28
|
+
|
|
29
|
+
let raw
|
|
30
|
+
if (position === 'stack') {
|
|
31
|
+
raw = buildStackedBars(data, barChannels, xScale, yScale, colors, ih, patterns, place, false)
|
|
32
|
+
} else if (position === 'fill') {
|
|
33
|
+
raw = buildStackedBars(data, barChannels, xScale, yScale, colors, ih, patterns, place, true)
|
|
34
|
+
} else if (position === 'identity') {
|
|
35
|
+
raw = buildBars(data, barChannels, xScale, yScale, colors, ih, patterns, place, plot.continuousCategory, false)
|
|
36
|
+
} else {
|
|
37
|
+
// dodge (default): side-by-side sub-bands
|
|
38
|
+
raw = buildBars(data, barChannels, xScale, yScale, colors, ih, patterns, place, plot.continuousCategory, true)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const a = resolveAlpha(alpha, type, plot.chartPreset)
|
|
42
|
+
return raw.map((bar) => ({ ...bar, alpha: a }))
|
|
43
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build renderable box marks. Body fill + outline (whiskers/median/caps) come from the
|
|
3
|
+
* `fill` channel (defaulting to `x`); an explicit `color` channel overrides the outline
|
|
4
|
+
* stroke (interior stays from `fill`). Adds the geom's fixed `alpha`.
|
|
5
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
6
|
+
*/
|
|
7
|
+
export function buildBoxMarks({ 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
|
+
}): any[];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { buildBoxes } from '../../../lib/brewing/marks/boxes.js'
|
|
2
|
+
import { resolveAlpha } from '../aesthetics.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build renderable box marks. Body fill + outline (whiskers/median/caps) come from the
|
|
6
|
+
* `fill` channel (defaulting to `x`); an explicit `color` channel overrides the outline
|
|
7
|
+
* stroke (interior stays from `fill`). Adds the geom's fixed `alpha`.
|
|
8
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
9
|
+
*/
|
|
10
|
+
export function buildBoxMarks({ data, plot, channels, options = {}, alpha, type = 'box' }) {
|
|
11
|
+
const { xScale, yScale, colors } = plot
|
|
12
|
+
if (!data?.length || !xScale || !yScale) return []
|
|
13
|
+
|
|
14
|
+
const fillField = channels.fill ?? channels.x
|
|
15
|
+
const boxes = buildBoxes(
|
|
16
|
+
data,
|
|
17
|
+
{ x: channels.x, fill: fillField, pattern: channels.pattern },
|
|
18
|
+
xScale,
|
|
19
|
+
yScale,
|
|
20
|
+
colors,
|
|
21
|
+
{ side: options.side, width: options.width, patterns: plot.patterns }
|
|
22
|
+
)
|
|
23
|
+
const a = resolveAlpha(alpha, type, plot.chartPreset)
|
|
24
|
+
const colorField = channels.color
|
|
25
|
+
return boxes.map((box) => ({
|
|
26
|
+
...box,
|
|
27
|
+
stroke: colorField ? (colors.get(box.data[colorField])?.stroke ?? box.stroke) : box.stroke,
|
|
28
|
+
alpha: a
|
|
29
|
+
}))
|
|
30
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build renderable candlesticks. Body + wick color is semantic (up/down from options), not
|
|
3
|
+
* the shared palette. Adds fixed `alpha`. Places (band, value) corners through place() so the
|
|
4
|
+
* candle transposes under orientation flip.
|
|
5
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
6
|
+
*/
|
|
7
|
+
export function buildCandleMarks({ 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
|
+
key: string;
|
|
16
|
+
bodyX: number;
|
|
17
|
+
bodyY: number;
|
|
18
|
+
bodyWidth: number;
|
|
19
|
+
bodyHeight: number;
|
|
20
|
+
fill: any;
|
|
21
|
+
alpha: number;
|
|
22
|
+
wickX1: any;
|
|
23
|
+
wickY1: any;
|
|
24
|
+
wickX2: any;
|
|
25
|
+
wickY2: any;
|
|
26
|
+
data: any;
|
|
27
|
+
}[];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { resolveAlpha } from '../aesthetics.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Build renderable candlesticks. Body + wick color is semantic (up/down from options), not
|
|
5
|
+
* the shared palette. Adds fixed `alpha`. Places (band, value) corners through place() so the
|
|
6
|
+
* candle transposes under orientation flip.
|
|
7
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
8
|
+
*/
|
|
9
|
+
export function buildCandleMarks({ data, plot, channels, options = {}, alpha, type = 'candlestick' }) {
|
|
10
|
+
const { xScale, yScale } = plot
|
|
11
|
+
if (!data?.length || !xScale || !yScale) return []
|
|
12
|
+
|
|
13
|
+
const open = options.open ?? 'open'
|
|
14
|
+
const high = options.high ?? 'high'
|
|
15
|
+
const low = options.low ?? 'low'
|
|
16
|
+
const close = options.close ?? 'close'
|
|
17
|
+
const upColor = options.upColor ?? '#22c55e'
|
|
18
|
+
const downColor = options.downColor ?? '#ef4444'
|
|
19
|
+
const a = resolveAlpha(alpha, type, plot.chartPreset)
|
|
20
|
+
|
|
21
|
+
const bw = typeof xScale.bandwidth === 'function' ? xScale.bandwidth() : 10
|
|
22
|
+
const bodyWidth = bw * 0.6
|
|
23
|
+
const bodyOffset = (bw - bodyWidth) / 2
|
|
24
|
+
|
|
25
|
+
return data.map((d, i) => {
|
|
26
|
+
const xPos = (xScale(d[channels.x ?? '']) ?? 0) + bodyOffset
|
|
27
|
+
const openVal = Number(d[open])
|
|
28
|
+
const closeVal = Number(d[close])
|
|
29
|
+
const isUp = closeVal >= openVal
|
|
30
|
+
const bodyTop = yScale(isUp ? closeVal : openVal)
|
|
31
|
+
const bodyBottom = yScale(isUp ? openVal : closeVal)
|
|
32
|
+
|
|
33
|
+
const b1 = plot.place(xPos, bodyTop)
|
|
34
|
+
const b2 = plot.place(xPos + bodyWidth, bodyBottom)
|
|
35
|
+
const wa = plot.place(xPos + bodyWidth / 2, yScale(Number(d[high])))
|
|
36
|
+
const wb = plot.place(xPos + bodyWidth / 2, yScale(Number(d[low])))
|
|
37
|
+
return {
|
|
38
|
+
key: `${d[channels.x ?? '']}-${i}`,
|
|
39
|
+
bodyX: Math.min(b1.x, b2.x),
|
|
40
|
+
bodyY: Math.min(b1.y, b2.y),
|
|
41
|
+
bodyWidth: Math.abs(b2.x - b1.x),
|
|
42
|
+
bodyHeight: Math.max(1, Math.abs(b2.y - b1.y)),
|
|
43
|
+
fill: isUp ? upColor : downColor,
|
|
44
|
+
alpha: a,
|
|
45
|
+
wickX1: wa.x,
|
|
46
|
+
wickY1: wa.y,
|
|
47
|
+
wickX2: wb.x,
|
|
48
|
+
wickY2: wb.y,
|
|
49
|
+
data: d
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build renderable heatmap cells. Cell fill is the continuous color scale (numeric color
|
|
3
|
+
* field) or the categorical palette entry, from `fill ?? color`. Adds fixed `alpha`.
|
|
4
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
5
|
+
*/
|
|
6
|
+
export function buildHeatmapMarks({ data, plot, channels, 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: any;
|
|
16
|
+
y: any;
|
|
17
|
+
width: any;
|
|
18
|
+
height: any;
|
|
19
|
+
fill: string;
|
|
20
|
+
alpha: number;
|
|
21
|
+
value: any;
|
|
22
|
+
display: string;
|
|
23
|
+
data: any;
|
|
24
|
+
}[];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { resolveAlpha } from '../aesthetics.js'
|
|
2
|
+
import { literalColor } from '../../../lib/brewing/colors.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build renderable heatmap cells. Cell fill is the continuous color scale (numeric color
|
|
6
|
+
* field) or the categorical palette entry, from `fill ?? color`. Adds fixed `alpha`.
|
|
7
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
8
|
+
*/
|
|
9
|
+
export function buildHeatmapMarks({ data, plot, channels, alpha, type = 'heatmap' }) {
|
|
10
|
+
const { xScale, yScale, colors } = plot
|
|
11
|
+
if (!data?.length || !xScale || !yScale) return []
|
|
12
|
+
|
|
13
|
+
const colorField = channels.fill ?? channels.color
|
|
14
|
+
// A literal fill/color paints every cell directly, skipping the value/palette scale.
|
|
15
|
+
const lit = literalColor(colorField)
|
|
16
|
+
const field = lit ? undefined : colorField
|
|
17
|
+
const continuous = plot.continuousColorScale
|
|
18
|
+
const bwX = typeof xScale.bandwidth === 'function' ? xScale.bandwidth() : 0
|
|
19
|
+
const bwY = typeof yScale.bandwidth === 'function' ? yScale.bandwidth() : 0
|
|
20
|
+
const a = resolveAlpha(alpha, type, plot.chartPreset)
|
|
21
|
+
|
|
22
|
+
return data.map((d, i) => {
|
|
23
|
+
const xVal = d[channels.x ?? '']
|
|
24
|
+
const yVal = d[channels.y ?? '']
|
|
25
|
+
const colorVal = field ? d[field] : null
|
|
26
|
+
let fill = lit ?? '#ccc'
|
|
27
|
+
if (!lit) {
|
|
28
|
+
if (continuous) fill = continuous.scale(Number(colorVal))
|
|
29
|
+
else {
|
|
30
|
+
const entry = colors?.get(colorVal)
|
|
31
|
+
if (entry) fill = entry.fill
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
key: `${xVal}-${yVal}-${i}`,
|
|
36
|
+
x: xScale(xVal) ?? 0,
|
|
37
|
+
y: yScale(yVal) ?? 0,
|
|
38
|
+
width: bwX,
|
|
39
|
+
height: bwY,
|
|
40
|
+
fill,
|
|
41
|
+
alpha: a,
|
|
42
|
+
value: colorVal,
|
|
43
|
+
display: String(colorVal ?? ''),
|
|
44
|
+
data: d
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** SVG path for a pointy-top hexagon of radius r, centered at the origin. */
|
|
2
|
+
export function hexPath(r: any): string;
|
|
3
|
+
/**
|
|
4
|
+
* Build renderable hex bins. Fill is the continuous color scale (by count) or a density-ramp
|
|
5
|
+
* rgba fallback. `alpha` is a flat multiplier on top (default 1 → unchanged).
|
|
6
|
+
* @param {{ data: any[], plot: any, channels: any, options?: any, alpha?: number, type?: string }} ctx
|
|
7
|
+
*/
|
|
8
|
+
export function buildHexbinMarks({ data, plot, channels, options, alpha, type }: {
|
|
9
|
+
data: any[];
|
|
10
|
+
plot: any;
|
|
11
|
+
channels: any;
|
|
12
|
+
options?: any;
|
|
13
|
+
alpha?: number;
|
|
14
|
+
type?: string;
|
|
15
|
+
}): {
|
|
16
|
+
key: string;
|
|
17
|
+
cx: any;
|
|
18
|
+
cy: any;
|
|
19
|
+
count: any;
|
|
20
|
+
fill: any;
|
|
21
|
+
alpha: number;
|
|
22
|
+
value: any;
|
|
23
|
+
display: string;
|
|
24
|
+
data: {
|
|
25
|
+
count: any;
|
|
26
|
+
x: any;
|
|
27
|
+
y: any;
|
|
28
|
+
};
|
|
29
|
+
}[];
|