svelteplot 0.1.3-next.8 → 0.2.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.
- package/README.md +4 -2
- package/dist/Mark.svelte +25 -21
- package/dist/Plot.svelte +45 -29
- package/dist/core/Plot.svelte +4 -2
- package/dist/helpers/index.d.ts +1 -1
- package/dist/helpers/resolve.js +1 -1
- package/dist/helpers/scales.js +3 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/marks/BarX.svelte +15 -5
- package/dist/marks/BarY.svelte +20 -12
- package/dist/marks/BarY.svelte.d.ts +22 -1
- package/dist/marks/Brush.svelte +364 -0
- package/dist/marks/Brush.svelte.d.ts +32 -0
- package/dist/marks/BrushX.svelte +7 -0
- package/dist/marks/BrushX.svelte.d.ts +4 -0
- package/dist/marks/BrushY.svelte +7 -0
- package/dist/marks/BrushY.svelte.d.ts +4 -0
- package/dist/marks/Cell.svelte +0 -7
- package/dist/marks/Dot.svelte +9 -18
- package/dist/marks/Dot.svelte.d.ts +8 -8
- package/dist/marks/Frame.svelte +24 -12
- package/dist/marks/Frame.svelte.d.ts +6 -1
- package/dist/marks/GridX.svelte +15 -6
- package/dist/marks/GridY.svelte +15 -6
- package/dist/marks/Link.svelte +1 -1
- package/dist/marks/Pointer.svelte +2 -2
- package/dist/marks/Pointer.svelte.d.ts +2 -2
- package/dist/marks/Rect.svelte +12 -19
- package/dist/marks/Sphere.svelte.d.ts +14 -4
- package/dist/marks/Text.svelte +14 -6
- package/dist/marks/Text.svelte.d.ts +2 -2
- package/dist/marks/helpers/events.d.ts +13 -0
- package/dist/marks/helpers/events.js +32 -3
- package/dist/transforms/bin.d.ts +7 -7
- package/dist/transforms/recordize.d.ts +1 -0
- package/dist/transforms/recordize.js +4 -5
- package/dist/transforms/window.d.ts +2 -0
- package/dist/types.d.ts +29 -9
- package/package.json +9 -7
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# SveltePlot
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+

|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
SveltePlot is a visualization framework based on the [layered grammar of graphics](https://vita.had.co.nz/papers/layered-grammar.html) ideas. It's API is heavily inspired by [Observable Plot](https://github.com/observablehq/plot). Created by Gregor Aisch.
|
|
6
|
+
|
|
7
|
+
<img src="static/logo.png" alt="SveltePlot logo" width="401" />
|
package/dist/Mark.svelte
CHANGED
|
@@ -78,8 +78,6 @@
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
81
|
const mark = new Mark(type);
|
|
84
82
|
|
|
85
83
|
$effect(() => {
|
|
@@ -128,24 +126,26 @@
|
|
|
128
126
|
const testFacet = $derived(getTestFacet());
|
|
129
127
|
|
|
130
128
|
const resolvedData: ResolvedDataRecord[] = $derived(
|
|
131
|
-
data
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
//
|
|
144
|
-
|
|
129
|
+
data
|
|
130
|
+
.map((d, i) => ({ ...d, [INDEX]: i }))
|
|
131
|
+
.flatMap((row) => {
|
|
132
|
+
const channels = options as Record<ChannelName, ChannelAccessor>;
|
|
133
|
+
if (!testFacet(row, channels) || !testFilter(row, channels)) return [];
|
|
134
|
+
const out: ResolvedDataRecord = {
|
|
135
|
+
datum: row
|
|
136
|
+
};
|
|
137
|
+
for (const [channel] of Object.entries(CHANNEL_SCALE) as [
|
|
138
|
+
ScaledChannelName,
|
|
139
|
+
ScaleName
|
|
140
|
+
][]) {
|
|
141
|
+
// check if the mark has defined an accessor for this channel
|
|
142
|
+
if (options?.[channel] !== undefined && out[channel] === undefined) {
|
|
143
|
+
// resolve value
|
|
144
|
+
out[channel] = resolveChannel(channel, row, options);
|
|
145
|
+
}
|
|
145
146
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
})
|
|
147
|
+
return [out];
|
|
148
|
+
})
|
|
149
149
|
);
|
|
150
150
|
|
|
151
151
|
let prevResolvedData: ResolvedDataRecord[] = [];
|
|
@@ -158,7 +158,6 @@
|
|
|
158
158
|
}
|
|
159
159
|
});
|
|
160
160
|
|
|
161
|
-
|
|
162
161
|
function isDifferent(array1: ResolvedDataRecord[], array2: ResolvedDataRecord[]) {
|
|
163
162
|
if (array1.length !== array2.length) return true;
|
|
164
163
|
for (let i = 0; i < array1.length; i++) {
|
|
@@ -228,7 +227,12 @@
|
|
|
228
227
|
);
|
|
229
228
|
out[`x${suffix}`] = x;
|
|
230
229
|
out[`y${suffix}`] = y;
|
|
231
|
-
out.valid =
|
|
230
|
+
out.valid =
|
|
231
|
+
out.valid &&
|
|
232
|
+
isValid(row.x) &&
|
|
233
|
+
isValid(row.y) &&
|
|
234
|
+
isValid(x) &&
|
|
235
|
+
isValid(y);
|
|
232
236
|
}
|
|
233
237
|
}
|
|
234
238
|
}
|
package/dist/Plot.svelte
CHANGED
|
@@ -116,39 +116,47 @@
|
|
|
116
116
|
scales,
|
|
117
117
|
...restProps
|
|
118
118
|
})}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
{#if
|
|
122
|
-
|
|
119
|
+
<svelte:boundary onerror={(err) => console.warn(err)}>
|
|
120
|
+
<!-- implicit axes -->
|
|
121
|
+
{#if !hasProjection && !hasExplicitAxisX}
|
|
122
|
+
{#if options.axes && (options.x.axis === 'top' || options.x.axis === 'both')}
|
|
123
|
+
<AxisX anchor="top" automatic />
|
|
124
|
+
{/if}
|
|
125
|
+
{#if options.axes && (options.x.axis === 'bottom' || options.x.axis === 'both')}
|
|
126
|
+
<AxisX anchor="bottom" automatic />
|
|
127
|
+
{/if}
|
|
123
128
|
{/if}
|
|
124
|
-
{#if
|
|
125
|
-
|
|
129
|
+
{#if !hasProjection && !hasExplicitAxisY}
|
|
130
|
+
{#if options.axes && (options.y.axis === 'left' || options.y.axis === 'both')}
|
|
131
|
+
<AxisY anchor="left" automatic />
|
|
132
|
+
{/if}
|
|
133
|
+
{#if options.axes && (options.y.axis === 'right' || options.y.axis === 'both')}
|
|
134
|
+
<AxisY anchor="right" automatic />
|
|
135
|
+
{/if}
|
|
126
136
|
{/if}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
<AxisY anchor="left" automatic />
|
|
137
|
+
<!-- implicit grids -->
|
|
138
|
+
{#if !hasExplicitGridX && (options.grid || options.x.grid)}
|
|
139
|
+
<GridX automatic />
|
|
131
140
|
{/if}
|
|
132
|
-
{#if
|
|
133
|
-
<
|
|
141
|
+
{#if !hasExplicitGridY && (options.grid || options.y.grid)}
|
|
142
|
+
<GridY automatic />
|
|
134
143
|
{/if}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
})}
|
|
144
|
+
<!-- implicit frame -->
|
|
145
|
+
{#if options.frame}
|
|
146
|
+
<Frame automatic />
|
|
147
|
+
{/if}
|
|
148
|
+
{@render parentChildren?.({
|
|
149
|
+
options,
|
|
150
|
+
scales,
|
|
151
|
+
...restProps
|
|
152
|
+
})}
|
|
153
|
+
{#snippet failed(error, reset)}
|
|
154
|
+
<text class="error" transform="translate(10,10)">
|
|
155
|
+
{#each error.message.split('\n') as line, i}
|
|
156
|
+
<tspan x="0" dy={i ? 14 : 0}>{line}</tspan>
|
|
157
|
+
{/each}
|
|
158
|
+
</text>{/snippet}
|
|
159
|
+
</svelte:boundary>
|
|
152
160
|
{/snippet}
|
|
153
161
|
{#snippet facetAxes()}
|
|
154
162
|
<FacetAxes />
|
|
@@ -160,4 +168,12 @@
|
|
|
160
168
|
--plot-bg: white;
|
|
161
169
|
--plot-fg: currentColor;
|
|
162
170
|
}
|
|
171
|
+
text.error {
|
|
172
|
+
stroke: var(--plot-bg);
|
|
173
|
+
fill: crimson;
|
|
174
|
+
font-size: 11px;
|
|
175
|
+
stroke-width: 3px;
|
|
176
|
+
font-weight: bold;
|
|
177
|
+
paint-order: stroke fill;
|
|
178
|
+
}
|
|
163
179
|
</style>
|
package/dist/core/Plot.svelte
CHANGED
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
explicitDomains,
|
|
157
157
|
hasProjection: !!initialOpts.projection,
|
|
158
158
|
margins: initialOpts.margins,
|
|
159
|
-
inset: initialOpts.inset
|
|
159
|
+
inset: initialOpts.inset
|
|
160
160
|
})
|
|
161
161
|
);
|
|
162
162
|
|
|
@@ -175,7 +175,9 @@
|
|
|
175
175
|
|
|
176
176
|
const hasProjection = $derived(!!preScales.projection);
|
|
177
177
|
|
|
178
|
-
const plotWidth = $derived(
|
|
178
|
+
const plotWidth = $derived(
|
|
179
|
+
(fixedWidth || width) - plotOptions.marginLeft - plotOptions.marginRight
|
|
180
|
+
);
|
|
179
181
|
|
|
180
182
|
// the facet and y domain counts are used for computing the automatic height
|
|
181
183
|
const xFacetCount = $derived(Math.max(1, preScales.fx.domain.length));
|
package/dist/helpers/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { Snippet } from 'svelte';
|
|
|
4
4
|
* Returns first argument that is not null or undefined
|
|
5
5
|
*/
|
|
6
6
|
export declare function coalesce(...args: (RawValue | undefined | null)[]): RawValue | null;
|
|
7
|
-
export declare function testFilter(datum: DataRecord, options: Record<ChannelName, ChannelAccessor>): string | number | boolean | Date | null;
|
|
7
|
+
export declare function testFilter(datum: DataRecord, options: Record<ChannelName, ChannelAccessor>): string | number | boolean | symbol | Date | null;
|
|
8
8
|
export declare function randomId(): string;
|
|
9
9
|
export declare function isSnippet(value: unknown): value is Snippet;
|
|
10
10
|
export declare function isValid(value: RawValue | undefined): value is number | Date | string;
|
package/dist/helpers/resolve.js
CHANGED
|
@@ -51,7 +51,7 @@ function resolve(datum, accessor, channel, scale) {
|
|
|
51
51
|
// so we're passing the original value to accessor functions instead of our wrapped record
|
|
52
52
|
return accessor(datum.___orig___ != null ? datum.___orig___ : datum);
|
|
53
53
|
// use accessor string
|
|
54
|
-
if (typeof accessor === 'string' && datum[accessor] !== undefined)
|
|
54
|
+
if ((typeof accessor === 'string' || typeof accessor === 'symbol') && datum[accessor] !== undefined)
|
|
55
55
|
return datum[accessor];
|
|
56
56
|
// fallback to channel name as accessor
|
|
57
57
|
if (accessor === null && datum[channel] !== undefined)
|
package/dist/helpers/scales.js
CHANGED
|
@@ -147,7 +147,9 @@ export function createScale(name, scaleOptions, marks, plotOptions, plotWidth, p
|
|
|
147
147
|
valueArr.sort(ascending);
|
|
148
148
|
}
|
|
149
149
|
const domain = scaleOptions.domain
|
|
150
|
-
?
|
|
150
|
+
? isOrdinal
|
|
151
|
+
? scaleOptions.domain
|
|
152
|
+
: extent(scaleOptions.zero ? [0, ...scaleOptions.domain] : scaleOptions.domain)
|
|
151
153
|
: type === 'band' ||
|
|
152
154
|
type === 'point' ||
|
|
153
155
|
type === 'ordinal' ||
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,9 @@ export { default as BollingerX } from './marks/BollingerX.svelte';
|
|
|
10
10
|
export { default as BollingerY } from './marks/BollingerY.svelte';
|
|
11
11
|
export { default as BoxX } from './marks/BoxX.svelte';
|
|
12
12
|
export { default as BoxY } from './marks/BoxY.svelte';
|
|
13
|
+
export { default as Brush } from './marks/Brush.svelte';
|
|
14
|
+
export { default as BrushX } from './marks/BrushX.svelte';
|
|
15
|
+
export { default as BrushY } from './marks/BrushY.svelte';
|
|
13
16
|
export { default as Cell } from './marks/Cell.svelte';
|
|
14
17
|
export { default as CellX } from './marks/CellX.svelte';
|
|
15
18
|
export { default as CellY } from './marks/CellY.svelte';
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,9 @@ export { default as BollingerX } from './marks/BollingerX.svelte';
|
|
|
11
11
|
export { default as BollingerY } from './marks/BollingerY.svelte';
|
|
12
12
|
export { default as BoxX } from './marks/BoxX.svelte';
|
|
13
13
|
export { default as BoxY } from './marks/BoxY.svelte';
|
|
14
|
+
export { default as Brush } from './marks/Brush.svelte';
|
|
15
|
+
export { default as BrushX } from './marks/BrushX.svelte';
|
|
16
|
+
export { default as BrushY } from './marks/BrushY.svelte';
|
|
14
17
|
export { default as Cell } from './marks/Cell.svelte';
|
|
15
18
|
export { default as CellX } from './marks/CellX.svelte';
|
|
16
19
|
export { default as CellY } from './marks/CellY.svelte';
|
package/dist/marks/BarX.svelte
CHANGED
|
@@ -46,8 +46,6 @@
|
|
|
46
46
|
stack
|
|
47
47
|
)
|
|
48
48
|
);
|
|
49
|
-
|
|
50
|
-
$inspect({args})
|
|
51
49
|
</script>
|
|
52
50
|
|
|
53
51
|
<Mark
|
|
@@ -61,16 +59,28 @@
|
|
|
61
59
|
{@const bw = plot.scales.y.fn.bandwidth()}
|
|
62
60
|
{@const minx = Math.min(d.x1, d.x2)}
|
|
63
61
|
{@const maxx = Math.max(d.x1, d.x2)}
|
|
64
|
-
{@const
|
|
62
|
+
{@const insetLeft = resolveProp(args.insetLeft, d.datum, 0)}
|
|
63
|
+
{@const insetRight = resolveProp(args.insetRight, d.datum, 0)}
|
|
64
|
+
{@const insetTop = resolveProp(args.insetTop || args.inset, d.datum, 0)}
|
|
65
|
+
{@const insetBottom = resolveProp(args.insetBottom || args.inset, d.datum, 0)}
|
|
65
66
|
{@const dx = resolveProp(args.dx, d.datum, 0)}
|
|
66
67
|
{@const dy = resolveProp(args.dy, d.datum, 0)}
|
|
67
68
|
{#if d.valid}
|
|
68
69
|
{@const [style, styleClass] = resolveStyles(plot, d, args, 'fill', usedScales)}
|
|
69
70
|
<path
|
|
70
|
-
d={roundedRect(
|
|
71
|
+
d={roundedRect(
|
|
72
|
+
0,
|
|
73
|
+
0,
|
|
74
|
+
maxx - minx - insetLeft - insetRight,
|
|
75
|
+
bw - insetTop - insetBottom,
|
|
76
|
+
options.borderRadius
|
|
77
|
+
)}
|
|
71
78
|
class={[styleClass, className]}
|
|
72
79
|
{style}
|
|
73
|
-
transform="translate({[
|
|
80
|
+
transform="translate({[
|
|
81
|
+
minx + dx + insetLeft,
|
|
82
|
+
d.y + insetTop + dy - bw * 0.5
|
|
83
|
+
]})"
|
|
74
84
|
use:addEventHandlers={{
|
|
75
85
|
getPlotState,
|
|
76
86
|
options: args,
|
package/dist/marks/BarY.svelte
CHANGED
|
@@ -11,10 +11,8 @@
|
|
|
11
11
|
import {
|
|
12
12
|
type PlotContext,
|
|
13
13
|
type BaseMarkProps,
|
|
14
|
-
type RectMarkProps,
|
|
15
14
|
type ChannelAccessor,
|
|
16
|
-
type DataRow
|
|
17
|
-
type FacetContext
|
|
15
|
+
type DataRow
|
|
18
16
|
} from '../types.js';
|
|
19
17
|
import type { StackOptions } from '../transforms/stack.js';
|
|
20
18
|
import { maybeData } from '../helpers/index.js';
|
|
@@ -41,25 +39,23 @@
|
|
|
41
39
|
bottomRight?: number;
|
|
42
40
|
bottomLeft?: number;
|
|
43
41
|
};
|
|
44
|
-
}
|
|
42
|
+
};
|
|
45
43
|
|
|
46
44
|
let { data = [{}], class: className = null, stack, ...options }: BarYProps = $props();
|
|
47
45
|
|
|
48
46
|
const { getPlotState } = getContext<PlotContext>('svelteplot');
|
|
49
|
-
|
|
47
|
+
const plot = $derived(getPlotState());
|
|
50
48
|
|
|
51
|
-
|
|
49
|
+
const args = $derived(
|
|
52
50
|
stackY(
|
|
53
51
|
intervalY(
|
|
54
52
|
// by default, sort by x channel (the ordinal labels)
|
|
55
|
-
sort(recordizeY({ data
|
|
53
|
+
sort(recordizeY({ data, sort: { channel: 'x' }, ...options })),
|
|
56
54
|
{ plot }
|
|
57
55
|
),
|
|
58
56
|
stack
|
|
59
57
|
)
|
|
60
58
|
);
|
|
61
|
-
|
|
62
|
-
const { getTestFacet } = getContext<FacetContext>('svelteplot/facet');
|
|
63
59
|
</script>
|
|
64
60
|
|
|
65
61
|
<Mark
|
|
@@ -73,16 +69,28 @@
|
|
|
73
69
|
{@const bw = plot.scales.x.fn.bandwidth()}
|
|
74
70
|
{@const miny = Math.min(d.y1, d.y2)}
|
|
75
71
|
{@const maxy = Math.max(d.y1, d.y2)}
|
|
76
|
-
{@const
|
|
72
|
+
{@const insetLeft = resolveProp(args.insetLeft || args.inset, d.datum, 0)}
|
|
73
|
+
{@const insetRight = resolveProp(args.insetRight || args.inset, d.datum, 0)}
|
|
74
|
+
{@const insetTop = resolveProp(args.insetTop, d.datum, 0)}
|
|
75
|
+
{@const insetBottom = resolveProp(args.insetBottom, d.datum, 0)}
|
|
77
76
|
{@const dx = resolveProp(args.dx, d.datum, 0)}
|
|
78
77
|
{@const dy = resolveProp(args.dy, d.datum, 0)}
|
|
79
78
|
{#if d.valid}
|
|
80
79
|
{@const [style, styleClass] = resolveStyles(plot, d, args, 'fill', usedScales)}
|
|
81
80
|
<path
|
|
82
|
-
d={roundedRect(
|
|
81
|
+
d={roundedRect(
|
|
82
|
+
0,
|
|
83
|
+
0,
|
|
84
|
+
bw - insetLeft - insetRight,
|
|
85
|
+
maxy - miny - insetTop - insetBottom,
|
|
86
|
+
options.borderRadius
|
|
87
|
+
)}
|
|
83
88
|
class={[styleClass, className]}
|
|
84
89
|
{style}
|
|
85
|
-
transform="translate({[
|
|
90
|
+
transform="translate({[
|
|
91
|
+
d.x + insetLeft + dx - bw * 0.5,
|
|
92
|
+
miny + dy + insetTop
|
|
93
|
+
]})"
|
|
86
94
|
use:addEventHandlers={{
|
|
87
95
|
getPlotState,
|
|
88
96
|
options: args,
|
|
@@ -1,4 +1,25 @@
|
|
|
1
|
+
import { type BaseMarkProps, type ChannelAccessor, type DataRow } from '../types.js';
|
|
2
|
+
import type { StackOptions } from '../transforms/stack.js';
|
|
3
|
+
type BarYProps = BaseMarkProps & {
|
|
4
|
+
data: DataRow[];
|
|
5
|
+
x?: ChannelAccessor;
|
|
6
|
+
y?: ChannelAccessor;
|
|
7
|
+
y1?: ChannelAccessor;
|
|
8
|
+
y2?: ChannelAccessor;
|
|
9
|
+
stack?: StackOptions;
|
|
10
|
+
/**
|
|
11
|
+
* Converts y into y1/y2 ranges based on the provided interval. Disables the
|
|
12
|
+
* implicit stacking
|
|
13
|
+
*/
|
|
14
|
+
interval?: number | string;
|
|
15
|
+
borderRadius?: number | {
|
|
16
|
+
topLeft?: number;
|
|
17
|
+
topRight?: number;
|
|
18
|
+
bottomRight?: number;
|
|
19
|
+
bottomLeft?: number;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
1
22
|
/** For vertical column charts using a band scale as x axis */
|
|
2
|
-
declare const BarY: import("svelte").Component<
|
|
23
|
+
declare const BarY: import("svelte").Component<BarYProps, {}, "">;
|
|
3
24
|
type BarY = ReturnType<typeof BarY>;
|
|
4
25
|
export default BarY;
|