layerchart 2.0.0-next.62 → 2.0.0-next.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/canvas.d.ts +4 -0
- package/dist/canvas.js +4 -0
- package/dist/components/Arc/Arc.shared.svelte.d.ts +2 -0
- package/dist/components/ArcLabel/ArcLabel.shared.svelte.d.ts +1 -0
- package/dist/components/Circle/Circle.shared.svelte.js +24 -5
- package/dist/components/Circle/Circle.svelte.test.js +70 -0
- package/dist/components/Dodge/Dodge.shared.svelte.d.ts +132 -0
- package/dist/components/Dodge/Dodge.shared.svelte.js +240 -0
- package/dist/components/Dodge/Dodge.svelte +88 -0
- package/dist/components/Dodge/Dodge.svelte.d.ts +27 -0
- package/dist/components/Dodge/Dodge.test.d.ts +1 -0
- package/dist/components/Dodge/Dodge.test.js +128 -0
- package/dist/components/Image/Image.html.svelte +0 -8
- package/dist/components/Image/Image.svg.svelte +1 -9
- package/dist/components/Pattern/Pattern.canvas.svelte +4 -1
- package/dist/components/Pattern/Pattern.shared.svelte.d.ts +31 -2
- package/dist/components/Pattern/Pattern.shared.svelte.js +20 -1
- package/dist/components/Pattern/Pattern.svg.svelte +17 -1
- package/dist/components/Raster/Raster.base.svelte +2 -8
- package/dist/components/Rect/Rect.canvas.svelte +2 -4
- package/dist/components/Rect/Rect.canvas.svelte.d.ts +1 -1
- package/dist/components/Rect/Rect.html.svelte +3 -9
- package/dist/components/Rect/Rect.html.svelte.d.ts +1 -1
- package/dist/components/Rect/Rect.shared.svelte.d.ts +5 -2
- package/dist/components/Rect/Rect.shared.svelte.js +26 -13
- package/dist/components/Rect/Rect.svelte.test.js +45 -0
- package/dist/components/Rect/Rect.svg.svelte +36 -21
- package/dist/components/Rect/Rect.svg.svelte.d.ts +1 -1
- package/dist/components/Spline/Spline.base.svelte +3 -2
- package/dist/components/Text/Text.canvas.svelte +9 -0
- package/dist/components/Text/Text.html.svelte +6 -0
- package/dist/components/Text/Text.shared.svelte.d.ts +25 -2
- package/dist/components/Text/Text.shared.svelte.js +36 -5
- package/dist/components/Text/Text.svelte.test.js +40 -0
- package/dist/components/Text/Text.svg.svelte +7 -1
- package/dist/components/Waffle/Waffle.shared.svelte.d.ts +182 -0
- package/dist/components/Waffle/Waffle.shared.svelte.js +300 -0
- package/dist/components/Waffle/Waffle.svelte +148 -0
- package/dist/components/Waffle/Waffle.svelte.d.ts +5 -0
- package/dist/components/charts/ArcChart/ArcChart.base.svelte +1 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +4 -0
- package/dist/html.d.ts +4 -0
- package/dist/html.js +4 -0
- package/dist/states/chart.svelte.js +8 -4
- package/dist/states/chart.svelte.test.js +53 -0
- package/dist/svg.d.ts +4 -0
- package/dist/svg.js +4 -0
- package/dist/utils/canvas.js +54 -13
- package/dist/utils/canvas.svelte.test.js +44 -0
- package/dist/utils/download.d.ts +5 -3
- package/dist/utils/download.js +36 -16
- package/dist/utils/stack.js +10 -2
- package/package.json +1 -1
|
@@ -50,6 +50,14 @@
|
|
|
50
50
|
strokeWidth: itemStrokeWidth ?? c.staticStrokeWidth,
|
|
51
51
|
opacity: itemOpacity ?? c.staticOpacity,
|
|
52
52
|
paintOrder: 'stroke',
|
|
53
|
+
...(rest.fontSize != null
|
|
54
|
+
? {
|
|
55
|
+
fontSize:
|
|
56
|
+
typeof rest.fontSize === 'number'
|
|
57
|
+
? `${rest.fontSize}px`
|
|
58
|
+
: rest.fontSize,
|
|
59
|
+
}
|
|
60
|
+
: {}),
|
|
53
61
|
...((rest.textAnchor ?? 'start') !== 'start'
|
|
54
62
|
? { textAnchor: rest.textAnchor }
|
|
55
63
|
: {}),
|
|
@@ -195,6 +203,7 @@
|
|
|
195
203
|
rest.class,
|
|
196
204
|
c.truncateConfig,
|
|
197
205
|
rest.rotate,
|
|
206
|
+
rest.fontSize,
|
|
198
207
|
rest.lineHeight,
|
|
199
208
|
rest.textAnchor,
|
|
200
209
|
rest.verticalAnchor,
|
|
@@ -46,6 +46,9 @@
|
|
|
46
46
|
{textAnchor === 'middle' ? 'center' : textAnchor === 'end' ? 'right' : 'left'}"
|
|
47
47
|
style:white-space="pre-wrap"
|
|
48
48
|
style:line-height={rest.lineHeight ?? '1em'}
|
|
49
|
+
style:font-size={typeof rest.fontSize === 'number'
|
|
50
|
+
? `${rest.fontSize}px`
|
|
51
|
+
: rest.fontSize}
|
|
49
52
|
style:color={resolvedFill}
|
|
50
53
|
style:opacity={resolvedOpacity ?? resolvedFillOpacity}
|
|
51
54
|
class={['lc-text', resolvedClass]}
|
|
@@ -74,6 +77,9 @@
|
|
|
74
77
|
{textAnchor === 'middle' ? 'center' : textAnchor === 'end' ? 'right' : 'left'}"
|
|
75
78
|
style:white-space="pre-wrap"
|
|
76
79
|
style:line-height={rest.lineHeight ?? '1em'}
|
|
80
|
+
style:font-size={typeof rest.fontSize === 'number'
|
|
81
|
+
? `${rest.fontSize}px`
|
|
82
|
+
: rest.fontSize}
|
|
77
83
|
style:color={c.staticFill}
|
|
78
84
|
style:opacity={c.staticOpacity ?? c.staticFillOpacity}
|
|
79
85
|
class={['lc-text', c.staticClassName]}
|
|
@@ -88,8 +88,20 @@ export type TextPropsWithoutHTML = {
|
|
|
88
88
|
*/
|
|
89
89
|
lineHeight?: string;
|
|
90
90
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
91
|
+
* Font size of the text. A number is treated as pixels; a string passes
|
|
92
|
+
* through (e.g. `'12px'`, `'1.25em'`). When set, vertical centering math
|
|
93
|
+
* derives `capHeight` from this value automatically (as `fontSize * 0.71`),
|
|
94
|
+
* so per-item scaled labels with `verticalAnchor="middle"` align correctly
|
|
95
|
+
* without an explicit `capHeight` override.
|
|
96
|
+
*/
|
|
97
|
+
fontSize?: number | string;
|
|
98
|
+
/**
|
|
99
|
+
* Cap height of the text — used by vertical anchor math to align the text
|
|
100
|
+
* to its visual center (as opposed to the font box). Defaults to `0.71em`,
|
|
101
|
+
* but if `fontSize` is set, defaults to `fontSize * 0.71` so centering
|
|
102
|
+
* stays correct as text scales.
|
|
103
|
+
*
|
|
104
|
+
* @default '0.71em' (or `fontSize * 0.71` when `fontSize` is set)
|
|
93
105
|
*/
|
|
94
106
|
capHeight?: string;
|
|
95
107
|
/**
|
|
@@ -182,6 +194,17 @@ export declare function getPathLength(pathRef: SVGPathElement | undefined): numb
|
|
|
182
194
|
* Convert css value to pixel value (ex. 0.71em => 11.36)
|
|
183
195
|
*/
|
|
184
196
|
export declare function getPixelValue(cssValue: number | string): number;
|
|
197
|
+
/**
|
|
198
|
+
* Resolve the cap-height used by vertical-anchor math.
|
|
199
|
+
*
|
|
200
|
+
* Priority:
|
|
201
|
+
* 1. Explicit `capHeight` prop
|
|
202
|
+
* 2. `fontSize * 0.71` when `fontSize` is set (keeps centering correct as
|
|
203
|
+
* labels scale per-item)
|
|
204
|
+
* 3. `'0.71em'` (legacy default — only correct for ~16px text since
|
|
205
|
+
* `getPixelValue` resolves `em` against 16, not the actual font-size)
|
|
206
|
+
*/
|
|
207
|
+
export declare function resolveCapHeight(capHeight: string | undefined, fontSize: number | string | undefined): number | string;
|
|
185
208
|
export declare function isValidXOrY(xOrY: string | number | undefined): boolean;
|
|
186
209
|
/** Build the standard `markInfo` payload used by every Text variant. */
|
|
187
210
|
export declare function textMarkInfo(props: TextProps, dataMode: boolean): {
|
|
@@ -58,6 +58,23 @@ export function getPixelValue(cssValue) {
|
|
|
58
58
|
return 0;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Resolve the cap-height used by vertical-anchor math.
|
|
63
|
+
*
|
|
64
|
+
* Priority:
|
|
65
|
+
* 1. Explicit `capHeight` prop
|
|
66
|
+
* 2. `fontSize * 0.71` when `fontSize` is set (keeps centering correct as
|
|
67
|
+
* labels scale per-item)
|
|
68
|
+
* 3. `'0.71em'` (legacy default — only correct for ~16px text since
|
|
69
|
+
* `getPixelValue` resolves `em` against 16, not the actual font-size)
|
|
70
|
+
*/
|
|
71
|
+
export function resolveCapHeight(capHeight, fontSize) {
|
|
72
|
+
if (capHeight != null)
|
|
73
|
+
return capHeight;
|
|
74
|
+
if (fontSize != null)
|
|
75
|
+
return getPixelValue(fontSize) * 0.71;
|
|
76
|
+
return '0.71em';
|
|
77
|
+
}
|
|
61
78
|
export function isValidXOrY(xOrY) {
|
|
62
79
|
return ((typeof xOrY === 'number' && Number.isFinite(xOrY)) ||
|
|
63
80
|
typeof xOrY === 'string');
|
|
@@ -89,7 +106,9 @@ export class TextState {
|
|
|
89
106
|
// Path measurement (only meaningful for SVG layer where the textPath element exists)
|
|
90
107
|
pathRef = $state();
|
|
91
108
|
// Data mode detection
|
|
92
|
-
dataMode = $derived(
|
|
109
|
+
dataMode = $derived(this.#getProps().data != null ||
|
|
110
|
+
isTextDataProp(this.#getProps().x) ||
|
|
111
|
+
isTextDataProp(this.#getProps().y));
|
|
93
112
|
// Data resolution
|
|
94
113
|
#resolvedData = $derived(this.dataMode ? (this.#getProps().data ?? chartDataArray(this.chartCtx.data)) : []);
|
|
95
114
|
resolvedItems = $derived.by(() => {
|
|
@@ -115,9 +134,21 @@ export class TextState {
|
|
|
115
134
|
const [projX, projY] = resolveGeoDataPair(props.x, props.y, d, this.geo.projection);
|
|
116
135
|
return { x: projX, y: projY };
|
|
117
136
|
}
|
|
137
|
+
// When x/y are omitted, fall back to the chart's accessors (xGet/yGet) —
|
|
138
|
+
// mirroring the Circle / Points / Dodge pattern.
|
|
139
|
+
const xDefault = typeof props.x === 'number'
|
|
140
|
+
? props.x
|
|
141
|
+
: props.x == null && this.chartCtx.config.x != null
|
|
142
|
+
? Number(this.chartCtx.xGet(d)) || 0
|
|
143
|
+
: 0;
|
|
144
|
+
const yDefault = typeof props.y === 'number'
|
|
145
|
+
? props.y
|
|
146
|
+
: props.y == null && this.chartCtx.config.y != null
|
|
147
|
+
? Number(this.chartCtx.yGet(d)) || 0
|
|
148
|
+
: 0;
|
|
118
149
|
return {
|
|
119
|
-
x: resolveDataProp(props.x, d, this.chartCtx.xScale,
|
|
120
|
-
y: resolveDataProp(props.y, d, this.chartCtx.yScale,
|
|
150
|
+
x: resolveDataProp(props.x, d, this.chartCtx.xScale, xDefault),
|
|
151
|
+
y: resolveDataProp(props.y, d, this.chartCtx.yScale, yDefault),
|
|
121
152
|
};
|
|
122
153
|
}
|
|
123
154
|
resolveTextValue(d) {
|
|
@@ -220,7 +251,7 @@ export class TextState {
|
|
|
220
251
|
const props = this.#getProps();
|
|
221
252
|
const verticalAnchor = props.verticalAnchor ?? 'end';
|
|
222
253
|
const lineHeight = props.lineHeight ?? '1em';
|
|
223
|
-
const capHeight = props.capHeight
|
|
254
|
+
const capHeight = resolveCapHeight(props.capHeight, props.fontSize);
|
|
224
255
|
if (verticalAnchor === 'start') {
|
|
225
256
|
return getPixelValue(lineHeight);
|
|
226
257
|
}
|
|
@@ -233,7 +264,7 @@ export class TextState {
|
|
|
233
264
|
const props = this.#getProps();
|
|
234
265
|
const verticalAnchor = props.verticalAnchor ?? 'end';
|
|
235
266
|
const lineHeight = props.lineHeight ?? '1em';
|
|
236
|
-
const capHeight = props.capHeight
|
|
267
|
+
const capHeight = resolveCapHeight(props.capHeight, props.fontSize);
|
|
237
268
|
if (verticalAnchor === 'start')
|
|
238
269
|
return getPixelValue(lineHeight);
|
|
239
270
|
if (verticalAnchor === 'middle')
|
|
@@ -148,5 +148,45 @@ describe('Text', () => {
|
|
|
148
148
|
const texts = page.getByTestId(componentTestId).elements();
|
|
149
149
|
await expect.poll(() => texts.length).toBe(1);
|
|
150
150
|
});
|
|
151
|
+
it('should enter data mode when only `data` prop is set, using chart accessors', async () => {
|
|
152
|
+
render(TestHarness, {
|
|
153
|
+
component: Text,
|
|
154
|
+
chartProps: {
|
|
155
|
+
data,
|
|
156
|
+
x: 'date',
|
|
157
|
+
y: 'value',
|
|
158
|
+
yDomain: [0, 100],
|
|
159
|
+
},
|
|
160
|
+
componentProps: {
|
|
161
|
+
data,
|
|
162
|
+
value: 'label',
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
const texts = page.getByTestId(componentTestId).elements();
|
|
166
|
+
await expect.poll(() => texts.length).toBe(3);
|
|
167
|
+
const ys = texts.map((t) => Number(t.getAttribute('y')));
|
|
168
|
+
expect(ys[0]).toBeGreaterThan(ys[1]);
|
|
169
|
+
expect(ys[1]).toBeGreaterThan(ys[2]);
|
|
170
|
+
});
|
|
171
|
+
it('should fall back to chart x accessor when only y is omitted', async () => {
|
|
172
|
+
render(TestHarness, {
|
|
173
|
+
component: Text,
|
|
174
|
+
chartProps: {
|
|
175
|
+
data,
|
|
176
|
+
x: 'date',
|
|
177
|
+
y: 'value',
|
|
178
|
+
yDomain: [0, 100],
|
|
179
|
+
},
|
|
180
|
+
componentProps: {
|
|
181
|
+
data,
|
|
182
|
+
x: 'date',
|
|
183
|
+
value: 'label',
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
const texts = page.getByTestId(componentTestId).elements();
|
|
187
|
+
await expect.poll(() => texts.length).toBe(3);
|
|
188
|
+
const ys = texts.map((t) => Number(t.getAttribute('y')));
|
|
189
|
+
expect(ys[0]).toBeGreaterThan(ys[2]);
|
|
190
|
+
});
|
|
151
191
|
});
|
|
152
192
|
});
|
|
@@ -30,10 +30,13 @@
|
|
|
30
30
|
rotate,
|
|
31
31
|
dx,
|
|
32
32
|
dy,
|
|
33
|
+
// `fontSize` is a typed prop (drives `capHeight` defaults), but on the
|
|
34
|
+
// DOM it must be rendered as the kebab-case `font-size` attribute.
|
|
35
|
+
fontSize,
|
|
33
36
|
...rest
|
|
34
37
|
}: TextProps = $props();
|
|
35
38
|
|
|
36
|
-
const c = new TextState(() => ({ rotate, dx, dy, ...rest } as TextProps));
|
|
39
|
+
const c = new TextState(() => ({ rotate, dx, dy, fontSize, ...rest } as TextProps));
|
|
37
40
|
|
|
38
41
|
let ref = $state<SVGTextElement>();
|
|
39
42
|
let svgRef = $state<SVGElement>();
|
|
@@ -78,6 +81,7 @@
|
|
|
78
81
|
transform={(rest.transform as string | undefined) ?? dataRotateTransform}
|
|
79
82
|
text-anchor={rest.textAnchor ?? 'start'}
|
|
80
83
|
dominant-baseline={rest.dominantBaseline ?? 'auto'}
|
|
84
|
+
font-size={fontSize}
|
|
81
85
|
fill={resolvedFill}
|
|
82
86
|
fill-opacity={resolvedFillOpacity}
|
|
83
87
|
stroke={resolvedStroke}
|
|
@@ -109,6 +113,7 @@
|
|
|
109
113
|
{...rest as any}
|
|
110
114
|
bind:this={ref}
|
|
111
115
|
dy={dy ?? 0}
|
|
116
|
+
font-size={fontSize}
|
|
112
117
|
fill={c.staticFill}
|
|
113
118
|
fill-opacity={c.staticFillOpacity}
|
|
114
119
|
stroke={c.staticStroke}
|
|
@@ -140,6 +145,7 @@
|
|
|
140
145
|
transform={c.transform}
|
|
141
146
|
text-anchor={rest.textAnchor ?? 'start'}
|
|
142
147
|
dominant-baseline={rest.dominantBaseline ?? 'auto'}
|
|
148
|
+
font-size={fontSize}
|
|
143
149
|
fill={c.staticFill}
|
|
144
150
|
fill-opacity={c.staticFillOpacity}
|
|
145
151
|
stroke={c.staticStroke}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { SVGAttributes } from 'svelte/elements';
|
|
3
|
+
import type { ChartState } from '../../states/chart.svelte.js';
|
|
4
|
+
import { type Accessor } from '../../utils/common.js';
|
|
5
|
+
import { type Insets } from '../../utils/rect.svelte.js';
|
|
6
|
+
import type { CommonStyleProps, Without } from '../../utils/types.js';
|
|
7
|
+
export type WaffleRound = boolean | ((n: number) => number);
|
|
8
|
+
export type WafflePropsWithoutHTML = {
|
|
9
|
+
/** Override chart context data. */
|
|
10
|
+
data?: any[];
|
|
11
|
+
/** Override `x` from context. @default ctx.x */
|
|
12
|
+
x?: Accessor;
|
|
13
|
+
/** Override `y` from context. @default ctx.y */
|
|
14
|
+
y?: Accessor;
|
|
15
|
+
/** Override `x1` from context. @default ctx.x1 */
|
|
16
|
+
x1?: Accessor;
|
|
17
|
+
/** Override `y1` from context. @default ctx.y1 */
|
|
18
|
+
y1?: Accessor;
|
|
19
|
+
/**
|
|
20
|
+
* Axis the waffle extends along (the value axis).
|
|
21
|
+
*
|
|
22
|
+
* - `'y'` (default): vertical waffle, like Plot's `waffleY`. Cells stack
|
|
23
|
+
* upward from the value=0 baseline.
|
|
24
|
+
* - `'x'`: horizontal waffle, like Plot's `waffleX`. Cells extend rightward.
|
|
25
|
+
*
|
|
26
|
+
* Falls back to the chart's `valueAxis`.
|
|
27
|
+
*/
|
|
28
|
+
axis?: 'x' | 'y';
|
|
29
|
+
/**
|
|
30
|
+
* The quantity each cell represents. Larger units produce fewer cells.
|
|
31
|
+
* @default 1
|
|
32
|
+
*/
|
|
33
|
+
unit?: number;
|
|
34
|
+
/**
|
|
35
|
+
* The number of cells per row (along the anchor axis). When omitted,
|
|
36
|
+
* computed automatically from the bar width and unit so cells stay
|
|
37
|
+
* approximately square.
|
|
38
|
+
*/
|
|
39
|
+
multiple?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Pixel separation between adjacent cells.
|
|
42
|
+
* @default 1
|
|
43
|
+
*/
|
|
44
|
+
gap?: number;
|
|
45
|
+
/**
|
|
46
|
+
* How to handle non-integer cell counts.
|
|
47
|
+
*
|
|
48
|
+
* - `false` (default) — keep the partial cell as a fractional cut-off
|
|
49
|
+
* - `true` — `Math.round`
|
|
50
|
+
* - function — custom rounding (e.g. `Math.floor`, `Math.ceil`)
|
|
51
|
+
*/
|
|
52
|
+
round?: WaffleRound;
|
|
53
|
+
/** Cell horizontal corner radius (number of pixels, or "100%" for circles). */
|
|
54
|
+
rx?: number | string;
|
|
55
|
+
/** Cell vertical corner radius (number of pixels, or "100%" for circles). */
|
|
56
|
+
ry?: number | string;
|
|
57
|
+
/** Series key for stacked-waffle support. */
|
|
58
|
+
seriesKey?: string;
|
|
59
|
+
/** Insets to shrink each waffle's bounding band. */
|
|
60
|
+
insets?: Insets;
|
|
61
|
+
/** Fixed band-axis size in pixels. Override the band width / height. */
|
|
62
|
+
width?: number;
|
|
63
|
+
/** Fixed band-axis size in pixels. Override the band width / height. */
|
|
64
|
+
height?: number;
|
|
65
|
+
/** Default `(d, i) => i` */
|
|
66
|
+
key?: (d: any, index: number) => any;
|
|
67
|
+
/** Setup pointer events to show tooltip for the hovered datum. */
|
|
68
|
+
tooltip?: boolean;
|
|
69
|
+
/** Click handler invoked with `(event, { data })` for the hovered waffle. */
|
|
70
|
+
onWaffleClick?: (e: MouseEvent, detail: {
|
|
71
|
+
data: any;
|
|
72
|
+
}) => void;
|
|
73
|
+
/**
|
|
74
|
+
* Render a custom symbol per cell instead of the default rect. The snippet
|
|
75
|
+
* receives the cell's `width`/`height` and the resolved `color` for the
|
|
76
|
+
* cell. The CSS `color` is applied to the wrapping element, so any nested
|
|
77
|
+
* SVG using `fill="currentColor"` (or stroke) inherits it automatically.
|
|
78
|
+
*
|
|
79
|
+
* SVG layer only — canvas falls back to the default rect.
|
|
80
|
+
*/
|
|
81
|
+
symbol?: Snippet<[
|
|
82
|
+
{
|
|
83
|
+
width: number;
|
|
84
|
+
height: number;
|
|
85
|
+
datum: any;
|
|
86
|
+
color: string;
|
|
87
|
+
}
|
|
88
|
+
]>;
|
|
89
|
+
} & CommonStyleProps;
|
|
90
|
+
export type WaffleProps = WafflePropsWithoutHTML & Without<Omit<SVGAttributes<SVGElement>, 'width' | 'height' | 'x' | 'y'>, WafflePropsWithoutHTML>;
|
|
91
|
+
/** Per-datum, fully-resolved waffle layout — pixel coords ready to render. */
|
|
92
|
+
export type WaffleItem = {
|
|
93
|
+
data: any;
|
|
94
|
+
index: number;
|
|
95
|
+
/** SVG path data for the waffle outline (relative to translate). */
|
|
96
|
+
pathData: string;
|
|
97
|
+
/** Pixel translate origin — apply to the path/pattern as `translate(tx, ty)`. */
|
|
98
|
+
tx: number;
|
|
99
|
+
ty: number;
|
|
100
|
+
/** Cell box width in pixels (pattern tile width). */
|
|
101
|
+
cx: number;
|
|
102
|
+
/** Cell box height in pixels (pattern tile height). */
|
|
103
|
+
cy: number;
|
|
104
|
+
/** Cell centroid in pixel coords (translated). */
|
|
105
|
+
centroid: {
|
|
106
|
+
x: number;
|
|
107
|
+
y: number;
|
|
108
|
+
};
|
|
109
|
+
/** Resolved fill color. */
|
|
110
|
+
fill: string | null;
|
|
111
|
+
};
|
|
112
|
+
export type WaffleLayoutOptions = {
|
|
113
|
+
axis: 'x' | 'y';
|
|
114
|
+
unit: number;
|
|
115
|
+
multiple?: number;
|
|
116
|
+
round: (n: number) => number;
|
|
117
|
+
/** Anchor-axis size in pixels (the bar's other-axis extent). */
|
|
118
|
+
barSize: number;
|
|
119
|
+
/** Anchor-axis pixel position (the bar's other-axis start). */
|
|
120
|
+
barStart: number;
|
|
121
|
+
/** Pixels per data unit on the value axis (signed; negative = inverted). */
|
|
122
|
+
pixelsPerUnit: number;
|
|
123
|
+
/** Pixel position of the value=0 baseline along the value axis. */
|
|
124
|
+
valueZero: number;
|
|
125
|
+
/** Value range in data units. */
|
|
126
|
+
v1: number;
|
|
127
|
+
v2: number;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Shared reactive state for Waffle. Resolves accessors, computes per-datum
|
|
131
|
+
* dimensions and waffle layouts (pattern tile size, polygon path, centroid),
|
|
132
|
+
* and exposes them via `items`.
|
|
133
|
+
*/
|
|
134
|
+
export declare class WaffleState {
|
|
135
|
+
#private;
|
|
136
|
+
ctx: ChartState;
|
|
137
|
+
constructor(getProps: () => WaffleProps);
|
|
138
|
+
axis: "x" | "y";
|
|
139
|
+
unit: number;
|
|
140
|
+
gap: number;
|
|
141
|
+
round: (n: number) => number;
|
|
142
|
+
multipleProp: number | undefined;
|
|
143
|
+
series: import("../index.js").SeriesData<any, any> | undefined;
|
|
144
|
+
/** Opacity multiplier — fades to 0.1 when another series is highlighted. */
|
|
145
|
+
seriesOpacity: number;
|
|
146
|
+
seriesAccessor: string | number | ((d: any) => any) | Accessor<any>[] | undefined;
|
|
147
|
+
stackAccessors: {
|
|
148
|
+
y0: (d: any) => number;
|
|
149
|
+
y1: (d: any) => number;
|
|
150
|
+
value: (d: any) => [number, number] | null;
|
|
151
|
+
} | null;
|
|
152
|
+
data: any[];
|
|
153
|
+
x: Accessor;
|
|
154
|
+
y: Accessor;
|
|
155
|
+
getDimensions: (item: any) => {
|
|
156
|
+
x: any;
|
|
157
|
+
y: any;
|
|
158
|
+
width: number;
|
|
159
|
+
height: number;
|
|
160
|
+
} | undefined;
|
|
161
|
+
/** Pixel slope of the value-axis scale (signed). */
|
|
162
|
+
pixelsPerUnit: number;
|
|
163
|
+
/** Pixel position of value=0 along the value axis. */
|
|
164
|
+
valueZero: number;
|
|
165
|
+
items: WaffleItem[];
|
|
166
|
+
/** Resolved gap. */
|
|
167
|
+
resolvedGap: number;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Generate the polygon outline of a waffle covering the cell interval
|
|
171
|
+
* `[i1, i2)` on a grid of `columns` columns. The shape is approximately
|
|
172
|
+
* rectangular but may have one or two corner cuts when the start or end
|
|
173
|
+
* value is not aligned to a row boundary, plus extra cuts for fractional
|
|
174
|
+
* intervals. The last point is the centroid (popped by callers for tooltips
|
|
175
|
+
* and tip placement).
|
|
176
|
+
*
|
|
177
|
+
* Coordinate space is `(column, row)` in cell units — callers transform to
|
|
178
|
+
* pixel space (and may negate the row axis for screen y).
|
|
179
|
+
*
|
|
180
|
+
* @see https://github.com/observablehq/plot/blob/main/src/marks/waffle.js
|
|
181
|
+
*/
|
|
182
|
+
export declare function wafflePoints(i1: number, i2: number, columns: number): [number, number][];
|