svelteplot 0.0.1-alpha.9 → 0.1.3-next.3
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/LICENSE.md +5 -0
- package/README.md +3 -36
- package/dist/Mark.svelte +292 -0
- package/dist/Mark.svelte.d.ts +22 -0
- package/dist/Plot.svelte +148 -156
- package/dist/Plot.svelte.d.ts +15 -15
- package/dist/constants.d.ts +14 -0
- package/dist/constants.js +109 -0
- package/dist/core/Facet.svelte +59 -0
- package/dist/core/Facet.svelte.d.ts +18 -0
- package/dist/core/FacetAxes.svelte +66 -0
- package/dist/core/FacetAxes.svelte.d.ts +4 -0
- package/dist/core/FacetGrid.svelte +86 -0
- package/dist/core/FacetGrid.svelte.d.ts +13 -0
- package/dist/core/Plot.svelte +567 -0
- package/dist/core/Plot.svelte.d.ts +14 -0
- package/dist/helpers/arrowPath.d.ts +14 -0
- package/dist/helpers/arrowPath.js +129 -0
- package/dist/helpers/autoProjection.d.ts +19 -0
- package/dist/helpers/autoProjection.js +87 -0
- package/dist/helpers/autoScales.d.ts +23 -0
- package/dist/helpers/autoScales.js +203 -0
- package/dist/helpers/autoTicks.d.ts +3 -0
- package/dist/helpers/autoTicks.js +40 -0
- package/dist/helpers/autoTimeFormat.d.ts +2 -2
- package/dist/helpers/autoTimeFormat.js +34 -5
- package/dist/helpers/callWithProps.d.ts +8 -0
- package/dist/helpers/callWithProps.js +13 -0
- package/dist/helpers/colors.js +17 -2
- package/dist/helpers/curves.d.ts +3 -0
- package/dist/helpers/curves.js +42 -0
- package/dist/helpers/data.d.ts +9 -0
- package/dist/helpers/data.js +16 -0
- package/dist/helpers/facets.d.ts +12 -0
- package/dist/helpers/facets.js +49 -0
- package/dist/helpers/formats.d.ts +3 -0
- package/dist/helpers/formats.js +3 -0
- package/dist/helpers/getBaseStyles.d.ts +7 -2
- package/dist/helpers/getBaseStyles.js +34 -10
- package/dist/helpers/getLogTicks.js +5 -5
- package/dist/helpers/group.d.ts +6 -0
- package/dist/helpers/group.js +53 -0
- package/dist/helpers/index.d.ts +18 -0
- package/dist/helpers/index.js +53 -0
- package/dist/helpers/isRawValue.d.ts +2 -0
- package/dist/helpers/isRawValue.js +5 -0
- package/dist/helpers/isValid.d.ts +6 -0
- package/dist/helpers/isValid.js +6 -0
- package/dist/helpers/math.d.ts +19 -0
- package/dist/helpers/math.js +116 -0
- package/dist/helpers/mergeDeep.d.ts +1 -1
- package/dist/helpers/noise.d.ts +1 -0
- package/dist/helpers/noise.js +72 -0
- package/dist/helpers/projection.d.ts +33 -0
- package/dist/helpers/projection.js +100 -0
- package/dist/helpers/reduce.d.ts +10 -0
- package/dist/helpers/reduce.js +85 -0
- package/dist/helpers/regressionLoess.d.ts +12 -0
- package/dist/helpers/regressionLoess.js +47 -0
- package/dist/helpers/removeIdenticalLines.d.ts +8 -1
- package/dist/helpers/removeIdenticalLines.js +14 -7
- package/dist/helpers/resolve.d.ts +17 -0
- package/dist/helpers/resolve.js +152 -0
- package/dist/helpers/roundedRect.d.ts +9 -0
- package/dist/helpers/roundedRect.js +31 -0
- package/dist/helpers/scales.d.ts +42 -0
- package/dist/helpers/scales.js +309 -0
- package/dist/helpers/time.d.ts +6 -0
- package/dist/helpers/time.js +282 -0
- package/dist/helpers/typeChecks.d.ts +8 -5
- package/dist/helpers/typeChecks.js +27 -6
- package/dist/index.d.ts +49 -1
- package/dist/index.js +53 -2
- package/dist/marks/Area.svelte +146 -0
- package/dist/marks/Area.svelte.d.ts +30 -0
- package/dist/marks/AreaX.svelte +27 -0
- package/dist/marks/AreaX.svelte.d.ts +12 -0
- package/dist/marks/AreaY.svelte +38 -0
- package/dist/marks/AreaY.svelte.d.ts +19 -0
- package/dist/marks/Arrow.svelte +139 -0
- package/dist/marks/Arrow.svelte.d.ts +44 -0
- package/dist/marks/AxisX.svelte +198 -93
- package/dist/marks/AxisX.svelte.d.ts +17 -16
- package/dist/marks/AxisY.svelte +176 -62
- package/dist/marks/AxisY.svelte.d.ts +17 -14
- package/dist/marks/BarX.svelte +81 -0
- package/dist/marks/BarX.svelte.d.ts +4 -0
- package/dist/marks/BarY.svelte +95 -0
- package/dist/marks/BarY.svelte.d.ts +4 -0
- package/dist/marks/BollingerX.svelte +44 -0
- package/dist/marks/BollingerX.svelte.d.ts +18 -0
- package/dist/marks/BollingerY.svelte +39 -0
- package/dist/marks/BollingerY.svelte.d.ts +18 -0
- package/dist/marks/BoxX.svelte +89 -0
- package/dist/marks/BoxX.svelte.d.ts +4 -0
- package/dist/marks/BoxY.svelte +110 -0
- package/dist/marks/BoxY.svelte.d.ts +29 -0
- package/dist/marks/Cell.svelte +110 -0
- package/dist/marks/Cell.svelte.d.ts +16 -0
- package/dist/marks/CellX.svelte +24 -0
- package/dist/marks/CellX.svelte.d.ts +3 -0
- package/dist/marks/CellY.svelte +24 -0
- package/dist/marks/CellY.svelte.d.ts +3 -0
- package/dist/marks/ColorLegend.svelte +148 -27
- package/dist/marks/ColorLegend.svelte.d.ts +12 -13
- package/dist/marks/CustomMark.svelte +43 -0
- package/dist/marks/CustomMark.svelte.d.ts +16 -0
- package/dist/marks/CustomMarkHTML.svelte +103 -0
- package/dist/marks/CustomMarkHTML.svelte.d.ts +17 -0
- package/dist/marks/DifferenceY.svelte +144 -0
- package/dist/marks/DifferenceY.svelte.d.ts +30 -0
- package/dist/marks/Dot.svelte +128 -73
- package/dist/marks/Dot.svelte.d.ts +24 -14
- package/dist/marks/DotX.svelte +15 -3
- package/dist/marks/DotX.svelte.d.ts +8 -16
- package/dist/marks/DotY.svelte +8 -3
- package/dist/marks/DotY.svelte.d.ts +5 -17
- package/dist/marks/Frame.svelte +32 -31
- package/dist/marks/Frame.svelte.d.ts +7 -14
- package/dist/marks/Geo.svelte +102 -0
- package/dist/marks/Geo.svelte.d.ts +10 -0
- package/dist/marks/Graticule.svelte +28 -0
- package/dist/marks/Graticule.svelte.d.ts +9 -0
- package/dist/marks/GridX.svelte +67 -36
- package/dist/marks/GridX.svelte.d.ts +7 -18
- package/dist/marks/GridY.svelte +64 -25
- package/dist/marks/GridY.svelte.d.ts +7 -14
- package/dist/marks/HTMLTooltip.svelte +91 -0
- package/dist/marks/HTMLTooltip.svelte.d.ts +11 -0
- package/dist/marks/Line.svelte +219 -58
- package/dist/marks/Line.svelte.d.ts +30 -14
- package/dist/marks/LineX.svelte +8 -8
- package/dist/marks/LineX.svelte.d.ts +4 -17
- package/dist/marks/LineY.svelte +7 -8
- package/dist/marks/LineY.svelte.d.ts +4 -17
- package/dist/marks/Link.svelte +173 -0
- package/dist/marks/Link.svelte.d.ts +21 -0
- package/dist/marks/Pointer.svelte +126 -0
- package/dist/marks/Pointer.svelte.d.ts +23 -0
- package/dist/marks/Rect.svelte +103 -0
- package/dist/marks/Rect.svelte.d.ts +15 -0
- package/dist/marks/RectX.svelte +33 -0
- package/dist/marks/RectX.svelte.d.ts +15 -0
- package/dist/marks/RectY.svelte +33 -0
- package/dist/marks/RectY.svelte.d.ts +15 -0
- package/dist/marks/RegressionX.svelte +26 -0
- package/dist/marks/RegressionX.svelte.d.ts +4 -0
- package/dist/marks/RegressionY.svelte +26 -0
- package/dist/marks/RegressionY.svelte.d.ts +4 -0
- package/dist/marks/RuleX.svelte +52 -28
- package/dist/marks/RuleX.svelte.d.ts +14 -14
- package/dist/marks/RuleY.svelte +52 -28
- package/dist/marks/RuleY.svelte.d.ts +14 -14
- package/dist/marks/Sphere.svelte +8 -0
- package/dist/marks/Sphere.svelte.d.ts +51 -0
- package/dist/marks/Spike.svelte +15 -0
- package/dist/marks/Spike.svelte.d.ts +4 -0
- package/dist/marks/SymbolLegend.svelte +27 -12
- package/dist/marks/SymbolLegend.svelte.d.ts +8 -14
- package/dist/marks/Text.svelte +185 -0
- package/dist/marks/Text.svelte.d.ts +26 -0
- package/dist/marks/TickX.svelte +89 -0
- package/dist/marks/TickX.svelte.d.ts +22 -0
- package/dist/marks/TickY.svelte +90 -0
- package/dist/marks/TickY.svelte.d.ts +22 -0
- package/dist/marks/Vector.svelte +213 -0
- package/dist/marks/Vector.svelte.d.ts +31 -0
- package/dist/marks/helpers/BaseAxisX.svelte +210 -0
- package/dist/marks/helpers/BaseAxisX.svelte.d.ts +24 -0
- package/dist/marks/helpers/BaseAxisY.svelte +187 -0
- package/dist/marks/helpers/BaseAxisY.svelte.d.ts +23 -0
- package/dist/marks/helpers/CanvasLayer.svelte +38 -0
- package/dist/marks/helpers/CanvasLayer.svelte.d.ts +13 -0
- package/dist/marks/helpers/DotCanvas.svelte +184 -0
- package/dist/marks/helpers/DotCanvas.svelte.d.ts +11 -0
- package/dist/marks/helpers/GeoCanvas.svelte +165 -0
- package/dist/marks/helpers/GeoCanvas.svelte.d.ts +13 -0
- package/dist/marks/helpers/GroupMultiple.svelte +17 -0
- package/dist/marks/helpers/GroupMultiple.svelte.d.ts +9 -0
- package/dist/marks/helpers/Marker.svelte +93 -0
- package/dist/marks/helpers/Marker.svelte.d.ts +10 -0
- package/dist/marks/helpers/MarkerPath.svelte +164 -0
- package/dist/marks/helpers/MarkerPath.svelte.d.ts +44 -0
- package/dist/marks/helpers/Regression.svelte +174 -0
- package/dist/marks/helpers/Regression.svelte.d.ts +26 -0
- package/dist/marks/helpers/events.d.ts +8 -0
- package/dist/marks/helpers/events.js +64 -0
- package/dist/transforms/bin.d.ts +51 -0
- package/dist/transforms/bin.js +171 -0
- package/dist/transforms/bollinger.d.ts +21 -0
- package/dist/transforms/bollinger.js +53 -0
- package/dist/transforms/centroid.d.ts +9 -0
- package/dist/transforms/centroid.js +13 -0
- package/dist/transforms/facet.d.ts +1 -0
- package/dist/transforms/facet.js +1 -0
- package/dist/transforms/filter.d.ts +2 -0
- package/dist/transforms/filter.js +8 -0
- package/dist/transforms/group.d.ts +66 -0
- package/dist/transforms/group.js +109 -0
- package/dist/transforms/interval.d.ts +11 -0
- package/dist/transforms/interval.js +34 -0
- package/dist/transforms/jitter.d.ts +0 -0
- package/dist/transforms/jitter.js +1 -0
- package/dist/transforms/map.d.ts +10 -0
- package/dist/transforms/map.js +89 -0
- package/dist/transforms/normalize.d.ts +9 -0
- package/dist/transforms/normalize.js +86 -0
- package/dist/transforms/recordize.d.ts +13 -0
- package/dist/transforms/recordize.js +75 -0
- package/dist/transforms/rename.d.ts +14 -0
- package/dist/transforms/rename.js +42 -0
- package/dist/transforms/select.d.ts +35 -0
- package/dist/transforms/select.js +55 -0
- package/dist/transforms/shift.d.ts +13 -0
- package/dist/transforms/shift.js +45 -0
- package/dist/transforms/sort.d.ts +28 -0
- package/dist/transforms/sort.js +61 -0
- package/dist/transforms/stack.d.ts +10 -0
- package/dist/transforms/stack.js +110 -0
- package/dist/transforms/window.d.ts +22 -0
- package/dist/transforms/window.js +73 -0
- package/dist/types.d.ts +625 -188
- package/dist/ui/Checkbox.svelte +6 -0
- package/dist/ui/Checkbox.svelte.d.ts +13 -0
- package/dist/ui/RadioInput.svelte +27 -0
- package/dist/ui/RadioInput.svelte.d.ts +9 -0
- package/dist/ui/Select.svelte +27 -0
- package/dist/ui/Select.svelte.d.ts +9 -0
- package/dist/ui/Slider.svelte +47 -0
- package/dist/ui/Slider.svelte.d.ts +11 -0
- package/dist/ui/Spiral.svelte +46 -0
- package/dist/ui/Spiral.svelte.d.ts +15 -0
- package/dist/ui/index.d.ts +4 -0
- package/dist/ui/index.js +4 -0
- package/package.json +79 -40
- package/LICENSE +0 -11
- package/dist/classes/Channel.svelte.js +0 -74
- package/dist/classes/Mark.svelte.js +0 -17
- package/dist/classes/Plot.svelte.js +0 -98
- package/dist/contants.d.ts +0 -3
- package/dist/contants.js +0 -40
- package/dist/helpers/GroupMultiple.svelte +0 -8
- package/dist/helpers/GroupMultiple.svelte.d.ts +0 -19
- package/dist/helpers/createScale.d.ts +0 -5
- package/dist/helpers/createScale.js +0 -57
- package/dist/helpers/resolveChannel.d.ts +0 -2
- package/dist/helpers/resolveChannel.js +0 -28
- package/dist/helpers/wrapArray.d.ts +0 -2
- package/dist/helpers/wrapArray.js +0 -4
- package/dist/marks/BaseMark.svelte +0 -22
- package/dist/marks/BaseMark.svelte.d.ts +0 -19
package/LICENSE.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Copyright 2024, Gregor Aisch
|
|
2
|
+
|
|
3
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
|
4
|
+
|
|
5
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,38 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# SveltePlot
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
SveltePlot is a new reactive 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.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
If you're seeing this, you've probably already done this step. Congrats!
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
# create a new project in the current directory
|
|
11
|
-
npm create svelte@latest
|
|
12
|
-
|
|
13
|
-
# create a new project in my-app
|
|
14
|
-
npm create svelte@latest my-app
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Developing
|
|
18
|
-
|
|
19
|
-
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npm run dev
|
|
23
|
-
|
|
24
|
-
# or start the server and open the app in a new browser tab
|
|
25
|
-
npm run dev -- --open
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Building
|
|
29
|
-
|
|
30
|
-
To create a production version of your app:
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
npm run build
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
You can preview the production build with `npm run preview`.
|
|
37
|
-
|
|
38
|
-
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
|
|
5
|
+
<img src="static/logo.png" alt="logo" width="400" />
|
package/dist/Mark.svelte
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getContext, untrack, type Snippet } from 'svelte';
|
|
3
|
+
|
|
4
|
+
import { CHANNEL_SCALE } from './constants.js';
|
|
5
|
+
import type {
|
|
6
|
+
ScaledChannelName,
|
|
7
|
+
MarkType,
|
|
8
|
+
DataRecord,
|
|
9
|
+
PlotContext,
|
|
10
|
+
ChannelName,
|
|
11
|
+
GenericMarkOptions,
|
|
12
|
+
ChannelAccessor,
|
|
13
|
+
BaseMarkProps,
|
|
14
|
+
FacetContext,
|
|
15
|
+
ScaleName,
|
|
16
|
+
RawValue,
|
|
17
|
+
ResolvedDataRecord,
|
|
18
|
+
ScaledDataRecord,
|
|
19
|
+
ScaleType
|
|
20
|
+
} from './types.js';
|
|
21
|
+
import { getUsedScales, projectXY, projectX, projectY } from './helpers/scales.js';
|
|
22
|
+
import { testFilter, isValid } from './helpers/index.js';
|
|
23
|
+
import { resolveChannel, resolveProp } from './helpers/resolve.js';
|
|
24
|
+
|
|
25
|
+
type MarkProps = {
|
|
26
|
+
data?: DataRecord[];
|
|
27
|
+
automatic?: boolean;
|
|
28
|
+
type: MarkType;
|
|
29
|
+
channels?: ScaledChannelName[];
|
|
30
|
+
required?: ScaledChannelName[];
|
|
31
|
+
requiredScales?: Partial<Record<ScaleName, ScaleType[]>>;
|
|
32
|
+
children?: Snippet<
|
|
33
|
+
[
|
|
34
|
+
{
|
|
35
|
+
mark: Mark<GenericMarkOptions>;
|
|
36
|
+
usedScales: ReturnType<typeof getUsedScales>;
|
|
37
|
+
scaledData: ScaledDataRecord[];
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
>;
|
|
41
|
+
defaults?: Partial<Record<ScaledChannelName, RawValue>>;
|
|
42
|
+
} & Partial<Record<ChannelName, ChannelAccessor>> &
|
|
43
|
+
Partial<BaseMarkProps>;
|
|
44
|
+
|
|
45
|
+
let {
|
|
46
|
+
data = [],
|
|
47
|
+
children,
|
|
48
|
+
type,
|
|
49
|
+
channels = [],
|
|
50
|
+
required = [],
|
|
51
|
+
requiredScales = {},
|
|
52
|
+
defaults = {},
|
|
53
|
+
...options
|
|
54
|
+
}: MarkProps = $props();
|
|
55
|
+
|
|
56
|
+
const channelsWithFacets: ScaledChannelName[] = $derived([...channels, 'fx', 'fy']);
|
|
57
|
+
|
|
58
|
+
const { addMark, updateMark, updatePlotState, removeMark, getTopLevelFacet, getPlotState } =
|
|
59
|
+
getContext<PlotContext>('svelteplot');
|
|
60
|
+
|
|
61
|
+
const plot = $derived(getPlotState());
|
|
62
|
+
const facet = $derived(getTopLevelFacet());
|
|
63
|
+
|
|
64
|
+
const { getFacetState } = getContext<FacetContext>('svelteplot/facet');
|
|
65
|
+
const { left, top } = $derived(getFacetState());
|
|
66
|
+
|
|
67
|
+
class Mark {
|
|
68
|
+
id;
|
|
69
|
+
type;
|
|
70
|
+
channels: ScaledChannelName[] = $state.raw([]);
|
|
71
|
+
scales: Set<ScaleName> = $state.raw(new Set());
|
|
72
|
+
data: DataRecord[] = $state.raw([]);
|
|
73
|
+
options: GenericMarkOptions = $state.raw({});
|
|
74
|
+
|
|
75
|
+
constructor(type: MarkType) {
|
|
76
|
+
this.id = Symbol();
|
|
77
|
+
this.type = type;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const mark = new Mark(type);
|
|
82
|
+
|
|
83
|
+
$effect(() => {
|
|
84
|
+
return () => {
|
|
85
|
+
removeMark(mark);
|
|
86
|
+
added = false;
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// let mark2 = $state(mark);
|
|
91
|
+
const facetMode = $derived(options.facet || 'auto');
|
|
92
|
+
|
|
93
|
+
const optionsWithAutoFacet = $derived({
|
|
94
|
+
...options,
|
|
95
|
+
__firstFacet: left && top,
|
|
96
|
+
...(facet &&
|
|
97
|
+
facet.data &&
|
|
98
|
+
((facetMode === 'auto' && facet.data === data) || facetMode === 'include')
|
|
99
|
+
? {
|
|
100
|
+
fx: facet.x,
|
|
101
|
+
fy: facet.y
|
|
102
|
+
}
|
|
103
|
+
: {})
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
let added = false;
|
|
107
|
+
|
|
108
|
+
$effect(() => {
|
|
109
|
+
if (added) return;
|
|
110
|
+
// without using untrack() here we end up with inexplicable
|
|
111
|
+
// circular dependency updates resulting in a stack overflow
|
|
112
|
+
const channels = untrack(() => channelsWithFacets);
|
|
113
|
+
mark.channels = channels;
|
|
114
|
+
mark.scales = new Set(
|
|
115
|
+
channels
|
|
116
|
+
.filter((channel) => options[channel] !== 0)
|
|
117
|
+
.map((channel) => CHANNEL_SCALE[channel])
|
|
118
|
+
);
|
|
119
|
+
mark.data = untrack(() => data);
|
|
120
|
+
mark.options = untrack(() => optionsWithAutoFacet);
|
|
121
|
+
addMark(mark);
|
|
122
|
+
added = true;
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const { getTestFacet } = getContext<FacetContext>('svelteplot/facet');
|
|
126
|
+
const testFacet = $derived(getTestFacet());
|
|
127
|
+
|
|
128
|
+
const resolvedData: ResolvedDataRecord[] = $derived(
|
|
129
|
+
data.flatMap((row) => {
|
|
130
|
+
const channels = options as Record<ChannelName, ChannelAccessor>;
|
|
131
|
+
if (!testFacet(row, channels) || !testFilter(row, channels)) return [];
|
|
132
|
+
const out: ResolvedDataRecord = {
|
|
133
|
+
datum: row
|
|
134
|
+
};
|
|
135
|
+
for (const [channel] of Object.entries(CHANNEL_SCALE) as [
|
|
136
|
+
ScaledChannelName,
|
|
137
|
+
ScaleName
|
|
138
|
+
][]) {
|
|
139
|
+
// check if the mark has defined an accessor for this channel
|
|
140
|
+
if (options?.[channel] !== undefined && out[channel] === undefined) {
|
|
141
|
+
// resolve value
|
|
142
|
+
out[channel] = resolveChannel(channel, row, options);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return [out];
|
|
146
|
+
})
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
let prevResolvedData: ResolvedDataRecord[] = [];
|
|
150
|
+
|
|
151
|
+
$effect(() => {
|
|
152
|
+
if (isDifferent(resolvedData, prevResolvedData)) {
|
|
153
|
+
prevResolvedData = resolvedData;
|
|
154
|
+
// data has changed
|
|
155
|
+
mark.data = data;
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
function isDifferent(array1: ResolvedDataRecord[], array2: ResolvedDataRecord[]) {
|
|
160
|
+
if (array1.length !== array2.length) return true;
|
|
161
|
+
for (let i = 0; i < array1.length; i++) {
|
|
162
|
+
for (const [channel] of Object.entries(CHANNEL_SCALE) as [
|
|
163
|
+
ScaledChannelName,
|
|
164
|
+
ScaleName
|
|
165
|
+
][]) {
|
|
166
|
+
if (array1[i][channel] !== array2[i][channel]) return true;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const errors = $derived([
|
|
173
|
+
...required
|
|
174
|
+
.filter((name) => options[name] == null)
|
|
175
|
+
.map((name) => `missing channel value for ${mark.type} mark: ${name}`),
|
|
176
|
+
...Object.entries(requiredScales)
|
|
177
|
+
.filter(([scale, types]) => {
|
|
178
|
+
return !types.includes(plot.scales[scale].type);
|
|
179
|
+
})
|
|
180
|
+
.map(
|
|
181
|
+
([scale, types]) => `scale type mismatch for ${scale} (needs ${types.join(' or ')})`
|
|
182
|
+
)
|
|
183
|
+
]);
|
|
184
|
+
|
|
185
|
+
$effect(() => {
|
|
186
|
+
for (const name of required) {
|
|
187
|
+
if (options[name] == null) throw new Error(`missing channel value: ${name}`);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const usedScales = $derived(getUsedScales(plot, optionsWithAutoFacet, mark));
|
|
192
|
+
/**
|
|
193
|
+
* based on the data and the global scales we can now map the data
|
|
194
|
+
* elements to the scales
|
|
195
|
+
*/
|
|
196
|
+
const scaledData = $derived(
|
|
197
|
+
resolvedData.flatMap((row) => {
|
|
198
|
+
const out: ScaledDataRecord = {
|
|
199
|
+
datum: row.datum,
|
|
200
|
+
valid: true
|
|
201
|
+
};
|
|
202
|
+
// compute dx/dy
|
|
203
|
+
const dx = Number(resolveProp<number>(options.dx, out.datum, 0));
|
|
204
|
+
const dy = Number(resolveProp<number>(options.dy, out.datum, 0));
|
|
205
|
+
|
|
206
|
+
// special handling if there's a projection
|
|
207
|
+
if (plot.scales.projection && mark.type !== 'geo') {
|
|
208
|
+
for (const suffix of ['', '1', '2']) {
|
|
209
|
+
if (
|
|
210
|
+
options?.[`x${suffix}`] !== undefined &&
|
|
211
|
+
options?.[`y${suffix}`] !== undefined
|
|
212
|
+
) {
|
|
213
|
+
// we have two-dimensional accessors
|
|
214
|
+
// for the x and y channels
|
|
215
|
+
const rx = resolveChannel(`x${suffix}`, row, options);
|
|
216
|
+
const ry = resolveChannel(`y${suffix}`, row, options);
|
|
217
|
+
const [x, y] =
|
|
218
|
+
mark.type === 'line'
|
|
219
|
+
? [rx, ry] // line paths are projected later
|
|
220
|
+
: projectXY(
|
|
221
|
+
plot.scales,
|
|
222
|
+
rx,
|
|
223
|
+
ry,
|
|
224
|
+
usedScales.x,
|
|
225
|
+
usedScales.y,
|
|
226
|
+
suffix
|
|
227
|
+
);
|
|
228
|
+
out[`x${suffix}`] = x;
|
|
229
|
+
out[`y${suffix}`] = y;
|
|
230
|
+
out.valid = out.valid && isValid(rx) && isValid(ry);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// iterate over all scaled channels
|
|
236
|
+
for (const [channel, scale] of Object.entries(CHANNEL_SCALE) as [
|
|
237
|
+
ScaledChannelName,
|
|
238
|
+
ScaleName
|
|
239
|
+
][]) {
|
|
240
|
+
// check if the mark has defined an accessor for this channel
|
|
241
|
+
if (options?.[channel] !== undefined && out[channel] === undefined) {
|
|
242
|
+
// resolve value
|
|
243
|
+
const value = row[channel];
|
|
244
|
+
|
|
245
|
+
const scaled = usedScales[channel]
|
|
246
|
+
? scale === 'x'
|
|
247
|
+
? projectX(channel as 'x' | 'x1' | 'x2', plot.scales, value)
|
|
248
|
+
: scale === 'y'
|
|
249
|
+
? projectY(channel as 'y' | 'y1' | 'y1', plot.scales, value)
|
|
250
|
+
: plot.scales[scale].fn(value)
|
|
251
|
+
: value;
|
|
252
|
+
|
|
253
|
+
out.valid = out.valid && isValid(value);
|
|
254
|
+
// apply dx/dy transform
|
|
255
|
+
out[channel] =
|
|
256
|
+
scale === 'x' && Number.isFinite(scaled) ? (scaled as number) + dx : scaled;
|
|
257
|
+
out[channel] =
|
|
258
|
+
scale === 'y' && Number.isFinite(scaled) ? (scaled as number) + dy : scaled;
|
|
259
|
+
} else if (defaults[channel]) {
|
|
260
|
+
out[channel] = defaults[channel];
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return [out];
|
|
265
|
+
})
|
|
266
|
+
);
|
|
267
|
+
</script>
|
|
268
|
+
|
|
269
|
+
{#if errors.length}
|
|
270
|
+
<text transform="translate(10,10)">
|
|
271
|
+
{#each errors as error, i}
|
|
272
|
+
<tspan x="0" dy={i ? 14 : 0}>{error}</tspan>
|
|
273
|
+
{/each}
|
|
274
|
+
</text>
|
|
275
|
+
{:else if children}
|
|
276
|
+
{@render children({
|
|
277
|
+
mark,
|
|
278
|
+
usedScales,
|
|
279
|
+
scaledData
|
|
280
|
+
})}
|
|
281
|
+
{/if}
|
|
282
|
+
|
|
283
|
+
<style>
|
|
284
|
+
text {
|
|
285
|
+
stroke: var(--plot-bg);
|
|
286
|
+
fill: crimson;
|
|
287
|
+
font-size: 11px;
|
|
288
|
+
stroke-width: 3px;
|
|
289
|
+
font-weight: bold;
|
|
290
|
+
paint-order: stroke fill;
|
|
291
|
+
}
|
|
292
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type Snippet } from 'svelte';
|
|
2
|
+
import type { ScaledChannelName, MarkType, DataRecord, ChannelName, GenericMarkOptions, ChannelAccessor, BaseMarkProps, ScaleName, RawValue, ScaledDataRecord, ScaleType } from './types.js';
|
|
3
|
+
import { getUsedScales } from './helpers/scales.js';
|
|
4
|
+
type MarkProps = {
|
|
5
|
+
data?: DataRecord[];
|
|
6
|
+
automatic?: boolean;
|
|
7
|
+
type: MarkType;
|
|
8
|
+
channels?: ScaledChannelName[];
|
|
9
|
+
required?: ScaledChannelName[];
|
|
10
|
+
requiredScales?: Partial<Record<ScaleName, ScaleType[]>>;
|
|
11
|
+
children?: Snippet<[
|
|
12
|
+
{
|
|
13
|
+
mark: Mark<GenericMarkOptions>;
|
|
14
|
+
usedScales: ReturnType<typeof getUsedScales>;
|
|
15
|
+
scaledData: ScaledDataRecord[];
|
|
16
|
+
}
|
|
17
|
+
]>;
|
|
18
|
+
defaults?: Partial<Record<ScaledChannelName, RawValue>>;
|
|
19
|
+
} & Partial<Record<ChannelName, ChannelAccessor>> & Partial<BaseMarkProps>;
|
|
20
|
+
declare const Mark: import("svelte").Component<MarkProps, {}, "">;
|
|
21
|
+
type Mark = ReturnType<typeof Mark>;
|
|
22
|
+
export default Mark;
|