svelteplot 0.1.3-next.9 → 0.2.1
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 +18 -2
- package/dist/Plot.svelte +45 -29
- package/dist/helpers/index.d.ts +2 -1
- package/dist/helpers/index.js +1 -0
- package/dist/helpers/resolve.js +7 -6
- package/dist/helpers/scales.d.ts +2 -2
- package/dist/helpers/scales.js +8 -5
- package/dist/helpers/typeChecks.js +14 -10
- 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/ColorLegend.svelte +6 -10
- package/dist/marks/Dot.svelte +11 -20
- package/dist/marks/Dot.svelte.d.ts +8 -8
- package/dist/marks/Frame.svelte +10 -5
- package/dist/marks/Frame.svelte.d.ts +6 -1
- package/dist/marks/Geo.svelte +50 -41
- package/dist/marks/Geo.svelte.d.ts +3 -1
- package/dist/marks/GridX.svelte +17 -8
- package/dist/marks/GridY.svelte +17 -8
- package/dist/marks/Pointer.svelte +4 -3
- 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 +2 -2
- package/dist/marks/Text.svelte.d.ts +2 -2
- package/dist/marks/helpers/CanvasLayer.svelte +10 -16
- package/dist/marks/helpers/CanvasLayer.svelte.d.ts +2 -6
- package/dist/marks/helpers/DotCanvas.svelte +82 -159
- package/dist/marks/helpers/DotCanvas.svelte.d.ts +2 -4
- package/dist/marks/helpers/GeoCanvas.svelte +95 -145
- package/dist/marks/helpers/GeoCanvas.svelte.d.ts +3 -5
- 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 +2 -0
- package/dist/transforms/recordize.js +20 -10
- package/dist/transforms/stack.js +10 -7
- package/dist/transforms/window.d.ts +2 -0
- package/dist/types.d.ts +34 -13
- package/package.json +23 -20
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
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
ScaledDataRecord,
|
|
19
19
|
ScaleType
|
|
20
20
|
} from './types.js';
|
|
21
|
+
import { isEqual } from 'es-toolkit';
|
|
21
22
|
import { getUsedScales, projectXY, projectX, projectY } from './helpers/scales.js';
|
|
22
23
|
import { testFilter, isValid } from './helpers/index.js';
|
|
23
24
|
import { resolveChannel, resolveProp } from './helpers/resolve.js';
|
|
@@ -105,6 +106,13 @@
|
|
|
105
106
|
|
|
106
107
|
let added = false;
|
|
107
108
|
|
|
109
|
+
$effect(() => {
|
|
110
|
+
const prevOptions = untrack(() => mark.options);
|
|
111
|
+
if (!isEqual(prevOptions, optionsWithAutoFacet)) {
|
|
112
|
+
mark.options = optionsWithAutoFacet;
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
108
116
|
$effect(() => {
|
|
109
117
|
if (added) return;
|
|
110
118
|
// without using untrack() here we end up with inexplicable
|
|
@@ -118,6 +126,7 @@
|
|
|
118
126
|
);
|
|
119
127
|
mark.data = untrack(() => data);
|
|
120
128
|
mark.options = untrack(() => optionsWithAutoFacet);
|
|
129
|
+
|
|
121
130
|
addMark(mark);
|
|
122
131
|
added = true;
|
|
123
132
|
});
|
|
@@ -225,9 +234,15 @@
|
|
|
225
234
|
usedScales.y,
|
|
226
235
|
suffix
|
|
227
236
|
);
|
|
237
|
+
|
|
228
238
|
out[`x${suffix}`] = x;
|
|
229
239
|
out[`y${suffix}`] = y;
|
|
230
|
-
out.valid =
|
|
240
|
+
out.valid =
|
|
241
|
+
out.valid &&
|
|
242
|
+
isValid(row.x) &&
|
|
243
|
+
isValid(row.y) &&
|
|
244
|
+
isValid(x) &&
|
|
245
|
+
isValid(y);
|
|
231
246
|
}
|
|
232
247
|
}
|
|
233
248
|
}
|
|
@@ -238,7 +253,7 @@
|
|
|
238
253
|
ScaleName
|
|
239
254
|
][]) {
|
|
240
255
|
// check if the mark has defined an accessor for this channel
|
|
241
|
-
if (options?.[channel]
|
|
256
|
+
if (options?.[channel] != null && out[channel] === undefined) {
|
|
242
257
|
// resolve value
|
|
243
258
|
const value = row[channel];
|
|
244
259
|
|
|
@@ -251,6 +266,7 @@
|
|
|
251
266
|
: value;
|
|
252
267
|
|
|
253
268
|
out.valid = out.valid && isValid(value);
|
|
269
|
+
|
|
254
270
|
// apply dx/dy transform
|
|
255
271
|
out[channel] =
|
|
256
272
|
scale === 'x' && Number.isFinite(scaled) ? (scaled as number) + dx : scaled;
|
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/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;
|
|
@@ -16,3 +16,4 @@ export declare const POSITION_CHANNELS: Set<ChannelName>;
|
|
|
16
16
|
export declare function parseInset(inset: number | string, width: number): number;
|
|
17
17
|
export declare function omit<T extends {}, K extends keyof T>(obj: T, ...keys: K[]): Omit<T, K>;
|
|
18
18
|
export declare function identity<T>(x: T): T;
|
|
19
|
+
export declare const GEOJSON_PREFER_STROKE: Set<string>;
|
package/dist/helpers/index.js
CHANGED
package/dist/helpers/resolve.js
CHANGED
|
@@ -4,16 +4,17 @@ import isRawValue from './isRawValue.js';
|
|
|
4
4
|
import { isValid } from './isValid.js';
|
|
5
5
|
import { pick } from 'es-toolkit';
|
|
6
6
|
import { getBaseStylesObject } from './getBaseStyles.js';
|
|
7
|
+
import { RAW_VALUE } from '../transforms/recordize.js';
|
|
7
8
|
export function resolveProp(accessor, datum, _defaultValue = null) {
|
|
8
9
|
if (typeof accessor === 'function') {
|
|
9
|
-
// datum
|
|
10
|
+
// datum[RAW_VALUE] exists if an array of raw values was used as dataset and got
|
|
10
11
|
// "recordized" by the recordize transform. We want to hide this wrapping to the user
|
|
11
12
|
// so we're passing the original value to accessor functions instead of our wrapped record
|
|
12
13
|
return datum == null
|
|
13
14
|
? accessor()
|
|
14
|
-
: accessor(datum
|
|
15
|
+
: accessor(datum[RAW_VALUE] != null ? datum[RAW_VALUE] : datum);
|
|
15
16
|
}
|
|
16
|
-
else if (typeof accessor === 'string' && datum && datum[accessor] !== undefined) {
|
|
17
|
+
else if ((typeof accessor === 'string' || typeof accessor === 'symbol') && datum && datum[accessor] !== undefined) {
|
|
17
18
|
return datum[accessor];
|
|
18
19
|
}
|
|
19
20
|
return isRawValue(accessor) ? accessor : _defaultValue;
|
|
@@ -46,12 +47,12 @@ function resolve(datum, accessor, channel, scale) {
|
|
|
46
47
|
if (isDataRecord(datum)) {
|
|
47
48
|
// use accessor function
|
|
48
49
|
if (typeof accessor === 'function')
|
|
49
|
-
// datum
|
|
50
|
+
// datum[RAW_VALUE] exists if an array of raw values was used as dataset and got
|
|
50
51
|
// "recordized" by the recordize transform. We want to hide this wrapping to the user
|
|
51
52
|
// so we're passing the original value to accessor functions instead of our wrapped record
|
|
52
|
-
return accessor(datum
|
|
53
|
+
return accessor(datum[RAW_VALUE] != null ? datum[RAW_VALUE] : datum);
|
|
53
54
|
// use accessor string
|
|
54
|
-
if (typeof accessor === 'string' && datum[accessor] !== undefined)
|
|
55
|
+
if ((typeof accessor === 'string' || typeof accessor === 'symbol') && datum[accessor] !== undefined)
|
|
55
56
|
return datum[accessor];
|
|
56
57
|
// fallback to channel name as accessor
|
|
57
58
|
if (accessor === null && datum[channel] !== undefined)
|
package/dist/helpers/scales.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChannelAccessor, GenericMarkOptions, Mark, MarkType, PlotDefaults, PlotOptions, PlotScales, PlotState, RawValue, ScaleName, ScaleOptions, ScaleType, ScaledChannelName } from '../types.js';
|
|
1
|
+
import type { ChannelAccessor, GenericMarkOptions, Mark, MarkType, PlotDefaults, PlotOptions, PlotScales, PlotState, RawValue, ScaleName, ScaleOptions, ScaleType, ScaledChannelName, UsedScales } from '../types.js';
|
|
2
2
|
/**
|
|
3
3
|
* compute the plot scales
|
|
4
4
|
*/
|
|
@@ -35,7 +35,7 @@ export declare function inferScaleType(name: ScaleName, dataValues: RawValue[],
|
|
|
35
35
|
* scales, we need to check if the the scale is supposed to be used
|
|
36
36
|
* not. That's what this function is used for.
|
|
37
37
|
*/
|
|
38
|
-
export declare function getUsedScales(plot: PlotState, options: GenericMarkOptions, mark: Mark<GenericMarkOptions>):
|
|
38
|
+
export declare function getUsedScales(plot: PlotState, options: GenericMarkOptions, mark: Mark<GenericMarkOptions>): UsedScales;
|
|
39
39
|
export declare function looksLikeANumber(input: string | number): boolean;
|
|
40
40
|
export declare function projectXY(scales: PlotScales, x: RawValue, y: RawValue, useXScale?: boolean, useYScale?: boolean): [number, number];
|
|
41
41
|
export declare function projectX(channel: 'x' | 'x1' | 'x2', scales: PlotScales, value: RawValue): number;
|
package/dist/helpers/scales.js
CHANGED
|
@@ -113,7 +113,7 @@ export function createScale(name, scaleOptions, marks, plotOptions, plotWidth, p
|
|
|
113
113
|
for (const datum of mark.data) {
|
|
114
114
|
const value = resolveProp(channelOptions.value, datum);
|
|
115
115
|
dataValues.add(value);
|
|
116
|
-
if (name === 'color' && scaleOptions.type === 'quantile') {
|
|
116
|
+
if (name === 'color' && scaleOptions.type === 'quantile' || scaleOptions.type === 'quantile-cont') {
|
|
117
117
|
allDataValues.push(value);
|
|
118
118
|
}
|
|
119
119
|
}
|
|
@@ -146,8 +146,11 @@ export function createScale(name, scaleOptions, marks, plotOptions, plotWidth, p
|
|
|
146
146
|
if (isOrdinal && sortOrdinalDomain) {
|
|
147
147
|
valueArr.sort(ascending);
|
|
148
148
|
}
|
|
149
|
+
const valueArray = type === 'quantile' || type === 'quantile-cont' ? allDataValues.toSorted() : valueArr;
|
|
149
150
|
const domain = scaleOptions.domain
|
|
150
|
-
?
|
|
151
|
+
? isOrdinal
|
|
152
|
+
? scaleOptions.domain
|
|
153
|
+
: extent(scaleOptions.zero ? [0, ...scaleOptions.domain] : scaleOptions.domain)
|
|
151
154
|
: type === 'band' ||
|
|
152
155
|
type === 'point' ||
|
|
153
156
|
type === 'ordinal' ||
|
|
@@ -155,9 +158,9 @@ export function createScale(name, scaleOptions, marks, plotOptions, plotWidth, p
|
|
|
155
158
|
type === 'quantile' ||
|
|
156
159
|
type === 'quantile-cont'
|
|
157
160
|
? name === 'y'
|
|
158
|
-
?
|
|
159
|
-
:
|
|
160
|
-
: extent(scaleOptions.zero ? [0, ...
|
|
161
|
+
? valueArray.toReversed()
|
|
162
|
+
: valueArray
|
|
163
|
+
: extent(scaleOptions.zero ? [0, ...valueArray] : valueArray);
|
|
161
164
|
if (!scaleOptions.scale) {
|
|
162
165
|
throw new Error(`No scale function defined for ${name}`);
|
|
163
166
|
}
|
|
@@ -26,16 +26,20 @@ export function isSymbolOrNull(v) {
|
|
|
26
26
|
return v == null || ((typeof v === 'string' || typeof v === 'object') && isSymbol(v));
|
|
27
27
|
}
|
|
28
28
|
export function isColorOrNull(v) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
if (v == null)
|
|
30
|
+
return true;
|
|
31
|
+
if (typeof v === 'string') {
|
|
32
|
+
v = `${v}`.toLowerCase();
|
|
33
|
+
return (v === 'currentcolor' ||
|
|
34
|
+
CSS_VAR.test(v) ||
|
|
35
|
+
CSS_COLOR.test(v) ||
|
|
36
|
+
CSS_COLOR_MIX.test(v) ||
|
|
37
|
+
CSS_COLOR_CONTRAST.test(v) ||
|
|
38
|
+
CSS_RGBA.test(v) ||
|
|
39
|
+
CSS_URL.test(v) ||
|
|
40
|
+
color(v) !== null);
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
39
43
|
}
|
|
40
44
|
export function isOpacityOrNull(v) {
|
|
41
45
|
return v == null || (typeof v === 'number' && Number.isFinite(v) && v >= 0 && v <= 1);
|
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;
|