svelteplot 0.11.1 → 0.12.0

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.
@@ -0,0 +1,421 @@
1
+ <!-- @component
2
+ Renders a raster image in one of three modes:
3
+
4
+ **Dense grid mode** (`data` is an array, `width` and `height` are set, no
5
+ `x`/`y` channels): the data is treated as a row-major grid of fill values.
6
+ `fill` defaults to the identity function (each datum is its own value).
7
+
8
+ **Function sampling mode** (`data` is omitted/null, `fill` and/or
9
+ `fillOpacity` are `(x, y) => value` functions): the mark evaluates the
10
+ function on a pixel grid, converting pixel coords to data coords via scale
11
+ inversion, then maps results through the color scale.
12
+
13
+ **Scatter interpolation mode** (`data` is an array with `x`/`y` channels):
14
+ each datum contributes a position and fill value; the mark spatially
15
+ interpolates over the grid using the chosen `interpolate` method.
16
+ -->
17
+ <script lang="ts" generics="Datum extends DataRow">
18
+ interface RasterMarkProps {
19
+ /**
20
+ * Input data. For **dense grid** mode supply a flat row-major array and
21
+ * set `width`/`height`. Omit (or set null) for **function-sampling**
22
+ * mode. For **scatter interpolation** supply an array of records with
23
+ * `x`/`y` channels.
24
+ */
25
+ data?: Datum[] | null;
26
+ /** x position channel (scatter interpolation mode) */
27
+ x?: ChannelAccessor<Datum>;
28
+ /** y position channel (scatter interpolation mode) */
29
+ y?: ChannelAccessor<Datum>;
30
+ /**
31
+ * fill color channel, identity function for dense grid, or an
32
+ * `(x, y) => value` function for function-sampling mode
33
+ */
34
+ fill?: ChannelAccessor<Datum> | ((x: number, y: number) => any);
35
+ /**
36
+ * fill opacity channel or an `(x, y) => number` function for
37
+ * function-sampling mode
38
+ */
39
+ fillOpacity?: ChannelAccessor<Datum> | ((x: number, y: number) => number);
40
+ /** left bound of the raster in data coordinates */
41
+ x1?: number;
42
+ /** top bound of the raster in data coordinates */
43
+ y1?: number;
44
+ /** right bound of the raster in data coordinates */
45
+ x2?: number;
46
+ /** bottom bound of the raster in data coordinates */
47
+ y2?: number;
48
+ /**
49
+ * explicit pixel-grid width; required for dense grid mode, also used
50
+ * to set the canvas resolution in other modes (overrides `pixelSize`)
51
+ */
52
+ width?: number;
53
+ /**
54
+ * explicit pixel-grid height; required for dense grid mode, also used
55
+ * to set the canvas resolution in other modes (overrides `pixelSize`)
56
+ */
57
+ height?: number;
58
+ /** pixel size in screen pixels (default 1); ignored when `width`/`height` are set */
59
+ pixelSize?: number;
60
+ /** Gaussian blur radius in grid pixels (default 0) */
61
+ blur?: number;
62
+ /**
63
+ * spatial interpolation for scatter mode:
64
+ * `"none"` | `"nearest"` | `"barycentric"` | `"random-walk"` or a
65
+ * custom `(index, w, h, X, Y, V) => W` function
66
+ */
67
+ interpolate?: 'none' | 'nearest' | 'barycentric' | 'random-walk' | InterpolateFunction;
68
+ /** CSS image-rendering property (default `"auto"`) */
69
+ imageRendering?: string;
70
+ clipPath?: string;
71
+ }
72
+
73
+ import type {
74
+ DataRow,
75
+ DataRecord,
76
+ ChannelAccessor,
77
+ ScaledDataRecord,
78
+ MarkType
79
+ } from '../types/index.js';
80
+ import { blurImage, extent } from 'd3-array';
81
+ import { rgb } from 'd3-color';
82
+ import Mark from '../Mark.svelte';
83
+ import { usePlot } from '../hooks/usePlot.svelte.js';
84
+ import {
85
+ interpolateNone,
86
+ interpolateNearest,
87
+ interpolatorBarycentric,
88
+ interpolatorRandomWalk,
89
+ type InterpolateFunction
90
+ } from '../helpers/rasterInterpolate.js';
91
+ import { X, Y, RAW_VALUE } from '../transforms/recordize.js';
92
+ import { scaleLinear } from 'd3-scale';
93
+
94
+ let markProps: RasterMarkProps = $props();
95
+
96
+ const {
97
+ data,
98
+ fill,
99
+ fillOpacity,
100
+ x1: x1Prop,
101
+ y1: y1Prop,
102
+ x2: x2Prop,
103
+ y2: y2Prop,
104
+ width: widthProp,
105
+ height: heightProp,
106
+ pixelSize = 1,
107
+ blur = 0,
108
+ interpolate,
109
+ imageRendering = 'auto',
110
+ ...options
111
+ }: RasterMarkProps = $derived({ ...markProps });
112
+
113
+ const plot = usePlot();
114
+
115
+ /** No data: fill/fillOpacity are (x,y) functions */
116
+ const isSamplerMode = $derived(data == null);
117
+
118
+ /**
119
+ * Dense grid: data is a flat array, width+height are given, no x/y
120
+ * channels. Each datum is its own fill value (unless fill is specified).
121
+ */
122
+ const isDenseGridMode = $derived(
123
+ data != null &&
124
+ widthProp != null &&
125
+ heightProp != null &&
126
+ (options as any).x == null &&
127
+ (options as any).y == null
128
+ );
129
+
130
+ const interpolateFn = $derived(resolveInterpolate(interpolate));
131
+
132
+ function resolveInterpolate(interp: RasterMarkProps['interpolate']): InterpolateFunction {
133
+ if (typeof interp === 'function') return interp;
134
+ if (interp == null) return interpolateNone;
135
+ switch (String(interp).toLowerCase()) {
136
+ case 'none':
137
+ return interpolateNone;
138
+ case 'nearest':
139
+ return interpolateNearest;
140
+ case 'barycentric':
141
+ return interpolatorBarycentric();
142
+ case 'random-walk':
143
+ return interpolatorRandomWalk();
144
+ }
145
+ throw new Error(`invalid interpolate: ${interp}`);
146
+ }
147
+
148
+ /** Pixel-space bounds of the raster image. */
149
+ function getBounds() {
150
+ const facetWidth = plot.facetWidth ?? 100;
151
+ const facetHeight = plot.facetHeight ?? 100;
152
+ const marginLeft = plot.options.marginLeft ?? 0;
153
+ const marginTop = plot.options.marginTop ?? 0;
154
+ return {
155
+ bx1: marginLeft,
156
+ by1: marginTop,
157
+ bx2: marginLeft + facetWidth,
158
+ by2: marginTop + facetHeight
159
+ };
160
+ }
161
+
162
+ /** Build the off-screen canvas and return it together with its bounds. */
163
+ function computeCanvas(scaledData: ScaledDataRecord[]): {
164
+ canvas: HTMLCanvasElement;
165
+ bx1: number;
166
+ by1: number;
167
+ dx: number;
168
+ dy: number;
169
+ } | null {
170
+ if (typeof document === 'undefined') return null;
171
+
172
+ const { bx1, by1, bx2, by2 } = getBounds();
173
+ const dx = bx2 - bx1;
174
+ const dy = by2 - by1;
175
+ // Canvas pixel dimensions
176
+ const w = widthProp ?? Math.round(Math.abs(dx) / pixelSize);
177
+ const h = heightProp ?? Math.round(Math.abs(dy) / pixelSize);
178
+ if (w <= 0 || h <= 0) return null;
179
+ const n = w * h;
180
+
181
+ // --- Populate fill value array F (and optional opacity array FO) ---
182
+ let F: any[] | null = null;
183
+ let FO: number[] | null = null;
184
+
185
+ if (isDenseGridMode) {
186
+ // Build the value array in data order, then flip rows so that
187
+ // data row 0 (y=0) renders at the bottom of the canvas, matching
188
+ // the standard y-up chart convention.
189
+ let Fraw: any[];
190
+ if (typeof fill === 'function') {
191
+ Fraw = (data as any[]).map(fill as (d: any) => any);
192
+ } else if (fill != null && typeof fill !== 'string') {
193
+ Fraw = (data as any[]).map((d) =>
194
+ typeof fill === 'string' ? d[fill] : (fill as (d: any) => any)(d)
195
+ );
196
+ } else {
197
+ Fraw = data as any[];
198
+ }
199
+ // Flip vertically: canvas row 0 (top) = data row h-1 (highest y).
200
+ F = new Array(n);
201
+ for (let row = 0; row < h; ++row) {
202
+ const srcRow = h - 1 - row;
203
+ for (let col = 0; col < w; ++col) {
204
+ F[row * w + col] = Fraw[srcRow * w + col];
205
+ }
206
+ }
207
+ } else if (isSamplerMode) {
208
+ // Evaluate f(x,y) for every grid pixel
209
+ const xScale = scaleLinear().range([x1Prop!, x2Prop!]).domain([bx1, bx2]);
210
+ const yScale = scaleLinear().range([y1Prop!, y2Prop!]).domain([by1, by2]);
211
+ const kx = dx / w;
212
+ const ky = dy / h;
213
+ if (typeof fill === 'function') {
214
+ F = new Array(n);
215
+ let i = 0;
216
+ for (let yi = 0.5; yi < h; ++yi) {
217
+ for (let xi = 0.5; xi < w; ++xi, ++i) {
218
+ const xData = xScale(bx1 + xi * kx);
219
+ const yData = yScale(by1 + yi * ky);
220
+ F[i] = (fill as (x: any, y: any) => any)(xData, yData);
221
+ }
222
+ }
223
+ }
224
+ if (typeof fillOpacity === 'function') {
225
+ FO = new Array(n);
226
+ let i = 0;
227
+ for (let yi = 0.5; yi < h; ++yi) {
228
+ for (let xi = 0.5; xi < w; ++xi, ++i) {
229
+ const xData = xScale(bx1 + xi * kx);
230
+ const yData = yScale(by1 + yi * ky);
231
+ FO[i] = (fillOpacity as (x: any, y: any) => number)(xData, yData);
232
+ }
233
+ }
234
+ }
235
+ } else if (scaledData.length > 0) {
236
+ // Scatter interpolation: map data points onto grid
237
+ const validData = scaledData.filter((d) => d.valid && d.x != null && d.y != null);
238
+
239
+ if (validData.length > 0) {
240
+ const kx = w / dx;
241
+ const ky = h / dy;
242
+ const index = validData.map((_, i) => i);
243
+ const IX = new Float64Array(validData.map((d) => ((d.x as number) - bx1) * kx));
244
+ const IY = new Float64Array(validData.map((d) => ((d.y as number) - by1) * ky));
245
+ // Use raw pre-color-scale fill values so we can interpolate
246
+ // numerically, then apply the color scale after interpolation.
247
+ const rawFill = validData.map((d) => d.resolved?.fill);
248
+ if (rawFill.some((v) => v != null)) {
249
+ F = Array.from(interpolateFn(index, w, h, IX, IY, rawFill));
250
+ }
251
+ if (fillOpacity !== undefined) {
252
+ const rawFO = validData.map((d) => d.resolved?.fillOpacity);
253
+ if (rawFO.some((v) => v != null)) {
254
+ FO = Array.from(interpolateFn(index, w, h, IX, IY, rawFO)) as number[];
255
+ }
256
+ }
257
+ }
258
+ }
259
+
260
+ // --- Rasterize: map value array to RGBA pixel data ---
261
+ const canvas = document.createElement('canvas');
262
+ canvas.width = w;
263
+ canvas.height = h;
264
+ const ctx = canvas.getContext('2d')!;
265
+ const imageData = ctx.createImageData(w, h);
266
+ const imgData = imageData.data;
267
+
268
+ // For sampler mode the fill function values are not registered with the
269
+ // Plot's mark data (to avoid reactive cycles), so the color scale may
270
+ // not have a domain set. In that case we compute the F extent here and
271
+ // rescale through the plot color scale using a normalised [0,1] input.
272
+ let colorFn: (v: any) => any = plot.scales.color?.fn ?? ((x: any) => x);
273
+ if (isSamplerMode && F && plot.scales.color?.fn) {
274
+ const [fMin, fMax] = extent(F.filter((v) => v != null) as number[]);
275
+ const colorDomain = plot.scales.color.fn.domain?.() ?? [];
276
+ const domainIsEmpty =
277
+ colorDomain.length === 0 || colorDomain[0] === colorDomain[colorDomain.length - 1];
278
+ if (domainIsEmpty && fMin != null && fMax != null && fMin !== fMax) {
279
+ // Remap raw F values into the color scale's current domain range
280
+ const [dMin, dMax] =
281
+ colorDomain.length >= 2
282
+ ? [colorDomain[0] as number, colorDomain[colorDomain.length - 1] as number]
283
+ : [0, 1];
284
+ const span = fMax - fMin;
285
+ colorFn = (v: any) =>
286
+ plot.scales.color!.fn(dMin + ((v - fMin) / span) * (dMax - dMin));
287
+ }
288
+ }
289
+
290
+ const defColor = typeof fill === 'string' ? rgb(fill) : null;
291
+ const defR = defColor?.r ?? 0;
292
+ const defG = defColor?.g ?? 0;
293
+ const defB = defColor?.b ?? 0;
294
+ const defA = typeof fillOpacity === 'number' ? fillOpacity * 255 : F ? 255 : 0;
295
+
296
+ for (let i = 0; i < n; ++i) {
297
+ const j = i << 2;
298
+ let r = defR,
299
+ g = defG,
300
+ b = defB,
301
+ a = defA;
302
+
303
+ if (F) {
304
+ const colorVal = colorFn(F[i]);
305
+ if (colorVal == null) {
306
+ imgData[j + 3] = 0;
307
+ continue;
308
+ }
309
+ const c = rgb(String(colorVal));
310
+ if (c) ({ r, g, b } = c);
311
+ a = 255;
312
+ }
313
+
314
+ if (FO != null) a = (FO[i] ?? 0) * 255;
315
+
316
+ imgData[j + 0] = r;
317
+ imgData[j + 1] = g;
318
+ imgData[j + 2] = b;
319
+ imgData[j + 3] = a;
320
+ }
321
+
322
+ if (blur > 0) blurImage(imageData, blur);
323
+ ctx.putImageData(imageData, 0, 0);
324
+
325
+ return { canvas, bx1, by1, dx, dy };
326
+ }
327
+
328
+ /**
329
+ * Resolves the fill value for a single datum in dense grid mode.
330
+ * The datum may be a raw primitive or a record; `fill` may be a
331
+ * field name, accessor, or omitted (identity).
332
+ */
333
+ function resolveFillValue(datum: any): any {
334
+ if (fill == null) return datum; // identity: datum IS the value
335
+ if (typeof fill === 'string') return datum[fill];
336
+ if (typeof fill === 'function') return (fill as (d: any) => any)(datum);
337
+ return datum;
338
+ }
339
+
340
+ /**
341
+ * For dense grid mode, fold the flat array into records keyed by Symbols
342
+ * (like recordizeXY). Symbol keys survive `{ ...d, [INDEX]: i }` spreading
343
+ * in Mark.svelte, so scale domains are computed from the actual values.
344
+ * The grid column/row indices become x/y channels so the x and y scale
345
+ * domains are also registered (0..width-1 and 0..height-1).
346
+ */
347
+ const denseMarkData = $derived(
348
+ isDenseGridMode
349
+ ? (data as any[]).map((d, i) => ({
350
+ [X]: i % widthProp!,
351
+ [Y]: Math.floor(i / widthProp!),
352
+ [RAW_VALUE]: resolveFillValue(d)
353
+ }))
354
+ : null
355
+ );
356
+
357
+ /**
358
+ * For sampler mode, pass two corner records so the Plot can register the
359
+ * x/y scale domains from x1/y1/x2/y2. We intentionally do NOT pre-evaluate
360
+ * the fill function here — doing so inside a $derived creates a reactive
361
+ * cycle because the resulting array (new reference each evaluation) feeds
362
+ * back through Mark → plot.scales → scaledData → effect → mark.data.
363
+ * The color scale domain is handled directly inside computeCanvas instead.
364
+ */
365
+ const samplerMarkData = $derived.by(() => {
366
+ if (!isSamplerMode) return null;
367
+ const x1 = x1Prop,
368
+ x2 = x2Prop,
369
+ y1 = y1Prop,
370
+ y2 = y2Prop;
371
+ if (x1 == null || x2 == null || y1 == null || y2 == null) return null;
372
+ return [
373
+ { [X]: x1, [Y]: y1 },
374
+ { [X]: x2, [Y]: y2 }
375
+ ] as unknown as DataRecord[];
376
+ });
377
+
378
+ const markChannels = $derived(
379
+ isDenseGridMode
380
+ ? (['x', 'y', 'fill'] as const)
381
+ : isSamplerMode
382
+ ? (['x', 'y'] as const)
383
+ : (['x', 'y', 'fill', 'fillOpacity'] as const)
384
+ );
385
+
386
+ const markFill = $derived(
387
+ isDenseGridMode ? (RAW_VALUE as any) : !isSamplerMode ? (fill as any) : undefined
388
+ );
389
+
390
+ const markX = $derived(isDenseGridMode || isSamplerMode ? (X as any) : undefined);
391
+ const markY = $derived(isDenseGridMode || isSamplerMode ? (Y as any) : undefined);
392
+ </script>
393
+
394
+ <Mark
395
+ type={'raster' as MarkType}
396
+ data={isDenseGridMode
397
+ ? (denseMarkData as DataRecord[])
398
+ : isSamplerMode
399
+ ? ((samplerMarkData ?? []) as DataRecord[])
400
+ : ((data ?? []) as DataRecord[])}
401
+ channels={markChannels as any}
402
+ x={markX}
403
+ y={markY}
404
+ fill={markFill}
405
+ fillOpacity={!isSamplerMode && !isDenseGridMode ? (fillOpacity as any) : undefined}
406
+ {...options}>
407
+ {#snippet children({ scaledData })}
408
+ {@const result = computeCanvas(scaledData)}
409
+ {#if result}
410
+ <image
411
+ transform="translate({plot.options.marginLeft},{plot.options
412
+ .marginTop}) scale({Math.sign(result.dx)},{Math.sign(result.dy)})"
413
+ width={Math.abs(result.dx)}
414
+ height={Math.abs(result.dy)}
415
+ preserveAspectRatio="none"
416
+ clip-path={options.clipPath}
417
+ image-rendering={imageRendering}
418
+ href={result.canvas.toDataURL()} />
419
+ {/if}
420
+ {/snippet}
421
+ </Mark>
@@ -0,0 +1,95 @@
1
+ import type { DataRow, ChannelAccessor } from '../types/index.js';
2
+ import { type InterpolateFunction } from '../helpers/rasterInterpolate.js';
3
+ declare function $$render<Datum extends DataRow>(): {
4
+ props: {
5
+ /**
6
+ * Input data. For **dense grid** mode supply a flat row-major array and
7
+ * set `width`/`height`. Omit (or set null) for **function-sampling**
8
+ * mode. For **scatter interpolation** supply an array of records with
9
+ * `x`/`y` channels.
10
+ */
11
+ data?: Datum[] | null;
12
+ /** x position channel (scatter interpolation mode) */
13
+ x?: ChannelAccessor<Datum>;
14
+ /** y position channel (scatter interpolation mode) */
15
+ y?: ChannelAccessor<Datum>;
16
+ /**
17
+ * fill color channel, identity function for dense grid, or an
18
+ * `(x, y) => value` function for function-sampling mode
19
+ */
20
+ fill?: ChannelAccessor<Datum> | ((x: number, y: number) => any);
21
+ /**
22
+ * fill opacity channel or an `(x, y) => number` function for
23
+ * function-sampling mode
24
+ */
25
+ fillOpacity?: ChannelAccessor<Datum> | ((x: number, y: number) => number);
26
+ /** left bound of the raster in data coordinates */
27
+ x1?: number;
28
+ /** top bound of the raster in data coordinates */
29
+ y1?: number;
30
+ /** right bound of the raster in data coordinates */
31
+ x2?: number;
32
+ /** bottom bound of the raster in data coordinates */
33
+ y2?: number;
34
+ /**
35
+ * explicit pixel-grid width; required for dense grid mode, also used
36
+ * to set the canvas resolution in other modes (overrides `pixelSize`)
37
+ */
38
+ width?: number;
39
+ /**
40
+ * explicit pixel-grid height; required for dense grid mode, also used
41
+ * to set the canvas resolution in other modes (overrides `pixelSize`)
42
+ */
43
+ height?: number;
44
+ /** pixel size in screen pixels (default 1); ignored when `width`/`height` are set */
45
+ pixelSize?: number;
46
+ /** Gaussian blur radius in grid pixels (default 0) */
47
+ blur?: number;
48
+ /**
49
+ * spatial interpolation for scatter mode:
50
+ * `"none"` | `"nearest"` | `"barycentric"` | `"random-walk"` or a
51
+ * custom `(index, w, h, X, Y, V) => W` function
52
+ */
53
+ interpolate?: "none" | "nearest" | "barycentric" | "random-walk" | InterpolateFunction;
54
+ /** CSS image-rendering property (default `"auto"`) */
55
+ imageRendering?: string;
56
+ clipPath?: string;
57
+ };
58
+ exports: {};
59
+ bindings: "";
60
+ slots: {};
61
+ events: {};
62
+ };
63
+ declare class __sveltets_Render<Datum extends DataRow> {
64
+ props(): ReturnType<typeof $$render<Datum>>['props'];
65
+ events(): ReturnType<typeof $$render<Datum>>['events'];
66
+ slots(): ReturnType<typeof $$render<Datum>>['slots'];
67
+ bindings(): "";
68
+ exports(): {};
69
+ }
70
+ interface $$IsomorphicComponent {
71
+ new <Datum extends DataRow>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<Datum>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<Datum>['props']>, ReturnType<__sveltets_Render<Datum>['events']>, ReturnType<__sveltets_Render<Datum>['slots']>> & {
72
+ $$bindings?: ReturnType<__sveltets_Render<Datum>['bindings']>;
73
+ } & ReturnType<__sveltets_Render<Datum>['exports']>;
74
+ <Datum extends DataRow>(internal: unknown, props: ReturnType<__sveltets_Render<Datum>['props']> & {}): ReturnType<__sveltets_Render<Datum>['exports']>;
75
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
76
+ }
77
+ /**
78
+ * Renders a raster image in one of three modes:
79
+ *
80
+ * **Dense grid mode** (`data` is an array, `width` and `height` are set, no
81
+ * `x`/`y` channels): the data is treated as a row-major grid of fill values.
82
+ * `fill` defaults to the identity function (each datum is its own value).
83
+ *
84
+ * **Function sampling mode** (`data` is omitted/null, `fill` and/or
85
+ * `fillOpacity` are `(x, y) => value` functions): the mark evaluates the
86
+ * function on a pixel grid, converting pixel coords to data coords via scale
87
+ * inversion, then maps results through the color scale.
88
+ *
89
+ * **Scatter interpolation mode** (`data` is an array with `x`/`y` channels):
90
+ * each datum contributes a position and fill value; the mark spatially
91
+ * interpolates over the grid using the chosen `interpolate` method.
92
+ */
93
+ declare const Raster: $$IsomorphicComponent;
94
+ type Raster<Datum extends DataRow> = InstanceType<typeof Raster<Datum>>;
95
+ export default Raster;
@@ -109,7 +109,7 @@
109
109
 
110
110
  import MultilineText from './helpers/MultilineText.svelte';
111
111
  import TextCanvas from './helpers/TextCanvas.svelte';
112
- import { indexData } from '../transforms/recordize.js';
112
+ import { indexData, recordize } from '../transforms/recordize.js';
113
113
  import { getPlotDefaults } from '../hooks/plotDefaults.js';
114
114
 
115
115
  const DEFAULTS = {
@@ -137,11 +137,13 @@
137
137
  } = $derived(mergedProps);
138
138
 
139
139
  const args = $derived(
140
- sort({
141
- data: indexData(data as object[]) as any,
142
- ...options
143
- })
144
- ) as TextMarkProps;
140
+ sort(
141
+ recordize({
142
+ data,
143
+ ...options
144
+ } as any)
145
+ )
146
+ ) as unknown as TextMarkProps;
145
147
  </script>
146
148
 
147
149
  <Mark
@@ -5,7 +5,12 @@
5
5
  children,
6
6
  class: className = null,
7
7
  ...groupProps
8
- }: { children: Snippet; length?: number; class?: string | null } = $props();
8
+ }: {
9
+ children: Snippet;
10
+ length?: number;
11
+ class?: string | null;
12
+ [key: string]: unknown;
13
+ } = $props();
9
14
  </script>
10
15
 
11
16
  {#if length > 1 || className}
@@ -3,6 +3,7 @@ type $$ComponentProps = {
3
3
  children: Snippet;
4
4
  length?: number;
5
5
  class?: string | null;
6
+ [key: string]: unknown;
6
7
  };
7
8
  declare const GroupMultiple: import("svelte").Component<$$ComponentProps, {}, "">;
8
9
  type GroupMultiple = ReturnType<typeof GroupMultiple>;
@@ -33,6 +33,7 @@ export { default as LineX } from './LineX.svelte';
33
33
  export { default as LineY } from './LineY.svelte';
34
34
  export { default as Link } from './Link.svelte';
35
35
  export { default as Pointer } from './Pointer.svelte';
36
+ export { default as Raster } from './Raster.svelte';
36
37
  export { default as Rect } from './Rect.svelte';
37
38
  export { default as RectX } from './RectX.svelte';
38
39
  export { default as RectY } from './RectY.svelte';
@@ -33,6 +33,7 @@ export { default as LineX } from './LineX.svelte';
33
33
  export { default as LineY } from './LineY.svelte';
34
34
  export { default as Link } from './Link.svelte';
35
35
  export { default as Pointer } from './Pointer.svelte';
36
+ export { default as Raster } from './Raster.svelte';
36
37
  export { default as Rect } from './Rect.svelte';
37
38
  export { default as RectX } from './RectX.svelte';
38
39
  export { default as RectY } from './RectY.svelte';
@@ -6,7 +6,7 @@ export type Mark<T> = {
6
6
  data: DataRecord<T>[];
7
7
  options: T;
8
8
  };
9
- export type MarkType = 'area' | 'arrow' | 'axisX' | 'axisY' | 'barX' | 'barY' | 'cell' | 'custom' | 'dot' | 'vector' | 'frame' | 'geo' | 'gridX' | 'gridY' | 'image' | 'link' | 'line' | 'rect' | 'regression' | 'ruleX' | 'ruleY' | 'swoopyArrow' | 'text' | 'tickX' | 'tickY' | 'trail' | 'waffleX' | 'waffleY';
9
+ export type MarkType = 'area' | 'arrow' | 'axisX' | 'axisY' | 'barX' | 'barY' | 'cell' | 'custom' | 'dot' | 'vector' | 'frame' | 'geo' | 'gridX' | 'gridY' | 'image' | 'link' | 'line' | 'raster' | 'rect' | 'regression' | 'ruleX' | 'ruleY' | 'swoopyArrow' | 'text' | 'tickX' | 'tickY' | 'trail' | 'waffleX' | 'waffleY';
10
10
  export type MarkStyleProps = 'strokeDasharray' | 'strokeLinejoin' | 'strokeLinecap' | 'opacity' | 'cursor' | 'pointerEvents' | 'blend' | 'fill' | 'fillOpacity' | 'fontFamily' | 'fontWeight' | 'fontVariant' | 'fontSize' | 'fontStyle' | 'letterSpacing' | 'wordSpacing' | 'stroke' | 'strokeWidth' | 'strokeOpacity' | 'x' | 'y' | 'clipPath' | 'mask' | 'filter' | 'angle' | 'radius' | 'symbol' | 'textAnchor' | 'textTransform' | 'textDecoration' | 'width';
11
11
  import type { ChannelAccessor, ConstantAccessor, DataRecord, RawValue } from './index.js';
12
12
  import type * as CSS from 'csstype';
@@ -84,7 +84,14 @@ export type PlotDefaults = {
84
84
  * default color scheme
85
85
  */
86
86
  colorScheme: ColorScheme;
87
- categoricalColorScheme: ColorScheme | string[] | Record<string, string>;
87
+ /**
88
+ * default color scheme for type 'categorical'
89
+ */
90
+ categoricalColorScheme: ColorScheme | string[] | ColorScheme | string[] | Record<string, string>;
91
+ /**
92
+ * default color scheme for tyoe 'diverging'
93
+ */
94
+ divergingColorScheme: ColorScheme | string[];
88
95
  /**
89
96
  * fallback color to be used for null/NA
90
97
  */
@@ -402,6 +409,8 @@ export type PlotOptions = {
402
409
  projection: string | null | {
403
410
  type?: string;
404
411
  rotate?: [number, number] | [number, number, number];
412
+ center?: [number, number] | [number, number, number];
413
+ parallels?: [number, number] | [number, number, number];
405
414
  domain?: object;
406
415
  inset?: number;
407
416
  clip?: Clip;