svelteplot 0.8.1 → 0.9.0-pr-309.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.
Files changed (131) hide show
  1. package/README.md +4 -3
  2. package/dist/Mark.svelte +1 -1
  3. package/dist/Mark.svelte.d.ts +6 -4
  4. package/dist/constants.d.ts +3 -1
  5. package/dist/constants.js +11 -2
  6. package/dist/core/Plot.svelte +4 -4
  7. package/dist/helpers/autoScales.d.ts +1 -1
  8. package/dist/helpers/callWithProps.d.ts +1 -3
  9. package/dist/helpers/callWithProps.js +5 -3
  10. package/dist/helpers/colors.d.ts +9 -12
  11. package/dist/helpers/facets.d.ts +1 -1
  12. package/dist/helpers/getBaseStyles.d.ts +2 -4
  13. package/dist/helpers/index.d.ts +3 -3
  14. package/dist/helpers/projection.js +7 -2
  15. package/dist/helpers/reduce.d.ts +1 -1
  16. package/dist/helpers/scales.d.ts +7 -7
  17. package/dist/helpers/symbols.d.ts +2 -2
  18. package/dist/helpers/time.d.ts +3 -3
  19. package/dist/helpers/typeChecks.d.ts +8 -8
  20. package/dist/hooks/usePlot.svelte.d.ts +51 -0
  21. package/dist/hooks/usePlot.svelte.js +90 -0
  22. package/dist/index.d.ts +1 -0
  23. package/dist/index.js +1 -0
  24. package/dist/marks/Area.svelte +3 -5
  25. package/dist/marks/Area.svelte.d.ts +6 -4
  26. package/dist/marks/AreaX.svelte.d.ts +7 -5
  27. package/dist/marks/Arrow.svelte +3 -5
  28. package/dist/marks/Arrow.svelte.d.ts +6 -4
  29. package/dist/marks/AxisX.svelte +2 -3
  30. package/dist/marks/AxisX.svelte.d.ts +7 -5
  31. package/dist/marks/AxisY.svelte +3 -4
  32. package/dist/marks/AxisY.svelte.d.ts +7 -5
  33. package/dist/marks/BarX.svelte +2 -4
  34. package/dist/marks/BarX.svelte.d.ts +6 -4
  35. package/dist/marks/BarY.svelte +2 -4
  36. package/dist/marks/BarY.svelte.d.ts +6 -4
  37. package/dist/marks/BollingerX.svelte.d.ts +2 -76
  38. package/dist/marks/BollingerY.svelte.d.ts +2 -76
  39. package/dist/marks/BoxX.svelte +4 -138
  40. package/dist/marks/BoxY.svelte +20 -137
  41. package/dist/marks/BoxY.svelte.d.ts +6 -64
  42. package/dist/marks/Brush.svelte +3 -3
  43. package/dist/marks/Brush.svelte.d.ts +1 -63
  44. package/dist/marks/Cell.svelte +2 -4
  45. package/dist/marks/Cell.svelte.d.ts +6 -4
  46. package/dist/marks/ColorLegend.svelte +2 -4
  47. package/dist/marks/CustomMark.svelte.d.ts +2 -84
  48. package/dist/marks/CustomMarkHTML.svelte +5 -10
  49. package/dist/marks/DifferenceY.svelte +3 -5
  50. package/dist/marks/DifferenceY.svelte.d.ts +1 -63
  51. package/dist/marks/Dot.svelte +4 -5
  52. package/dist/marks/Dot.svelte.d.ts +6 -4
  53. package/dist/marks/DotX.svelte.d.ts +7 -5
  54. package/dist/marks/DotY.svelte.d.ts +7 -5
  55. package/dist/marks/Frame.svelte +3 -9
  56. package/dist/marks/Frame.svelte.d.ts +7 -5
  57. package/dist/marks/Geo.svelte +5 -5
  58. package/dist/marks/Geo.svelte.d.ts +7 -4
  59. package/dist/marks/GridX.svelte +3 -10
  60. package/dist/marks/GridX.svelte.d.ts +6 -4
  61. package/dist/marks/GridY.svelte +3 -4
  62. package/dist/marks/GridY.svelte.d.ts +6 -4
  63. package/dist/marks/HTMLTooltip.svelte +5 -5
  64. package/dist/marks/Image.svelte.d.ts +2 -75
  65. package/dist/marks/Line.svelte +7 -6
  66. package/dist/marks/Line.svelte.d.ts +6 -4
  67. package/dist/marks/LineX.svelte.d.ts +8 -6
  68. package/dist/marks/LineY.svelte.d.ts +8 -6
  69. package/dist/marks/Link.svelte +2 -4
  70. package/dist/marks/Link.svelte.d.ts +6 -4
  71. package/dist/marks/Pointer.svelte +4 -4
  72. package/dist/marks/Rect.svelte +2 -4
  73. package/dist/marks/Rect.svelte.d.ts +6 -4
  74. package/dist/marks/RectX.svelte +4 -4
  75. package/dist/marks/RectY.svelte +4 -4
  76. package/dist/marks/RuleX.svelte +2 -4
  77. package/dist/marks/RuleX.svelte.d.ts +6 -4
  78. package/dist/marks/RuleY.svelte +2 -4
  79. package/dist/marks/RuleY.svelte.d.ts +6 -4
  80. package/dist/marks/Spike.svelte.d.ts +7 -5
  81. package/dist/marks/SymbolLegend.svelte +2 -4
  82. package/dist/marks/SymbolLegend.svelte.d.ts +17 -2
  83. package/dist/marks/Text.svelte.d.ts +6 -4
  84. package/dist/marks/TickX.svelte +2 -3
  85. package/dist/marks/TickX.svelte.d.ts +6 -4
  86. package/dist/marks/TickY.svelte +2 -3
  87. package/dist/marks/TickY.svelte.d.ts +6 -4
  88. package/dist/marks/Trail.svelte +161 -0
  89. package/dist/marks/Trail.svelte.d.ts +44 -0
  90. package/dist/marks/Vector.svelte +3 -4
  91. package/dist/marks/Vector.svelte.d.ts +6 -4
  92. package/dist/marks/WaffleX.svelte +2 -3
  93. package/dist/marks/WaffleX.svelte.d.ts +2 -85
  94. package/dist/marks/WaffleY.svelte +2 -4
  95. package/dist/marks/WaffleY.svelte.d.ts +2 -83
  96. package/dist/marks/helpers/AreaCanvas.svelte +2 -4
  97. package/dist/marks/helpers/Box.svelte +271 -0
  98. package/dist/marks/helpers/Box.svelte.d.ts +55 -0
  99. package/dist/marks/helpers/CanvasLayer.svelte +2 -4
  100. package/dist/marks/helpers/DotCanvas.svelte +3 -5
  101. package/dist/marks/helpers/GeoCanvas.svelte +2 -4
  102. package/dist/marks/helpers/LineCanvas.svelte +2 -4
  103. package/dist/marks/helpers/LinearGradientX.svelte +3 -4
  104. package/dist/marks/helpers/LinearGradientY.svelte +3 -4
  105. package/dist/marks/helpers/MarkerPath.svelte +4 -5
  106. package/dist/marks/helpers/MarkerPath.svelte.d.ts +2 -102
  107. package/dist/marks/helpers/MultilineText.svelte +4 -4
  108. package/dist/marks/helpers/RectPath.svelte +5 -6
  109. package/dist/marks/helpers/Regression.svelte +4 -8
  110. package/dist/marks/helpers/TrailCanvas.svelte +138 -0
  111. package/dist/marks/helpers/TrailCanvas.svelte.d.ts +40 -0
  112. package/dist/marks/helpers/events.d.ts +2 -2
  113. package/dist/marks/helpers/events.js +4 -4
  114. package/dist/marks/helpers/trail.d.ts +23 -0
  115. package/dist/marks/helpers/trail.js +372 -0
  116. package/dist/marks/index.d.ts +1 -0
  117. package/dist/marks/index.js +1 -0
  118. package/dist/transforms/bollinger.d.ts +1 -69
  119. package/dist/transforms/centroid.d.ts +1 -4
  120. package/dist/transforms/group.d.ts +4 -12
  121. package/dist/transforms/interval.d.ts +2 -128
  122. package/dist/transforms/normalize.d.ts +23 -0
  123. package/dist/transforms/recordize.d.ts +4 -7
  124. package/dist/transforms/select.d.ts +7 -448
  125. package/dist/transforms/sort.d.ts +5 -253
  126. package/dist/transforms/stack.d.ts +3 -23
  127. package/dist/transforms/window.d.ts +2 -134
  128. package/dist/types/mark.d.ts +2 -1
  129. package/dist/types/plot.d.ts +6 -1
  130. package/dist/ui/Spiral.svelte +4 -0
  131. package/package.json +25 -23
@@ -8,17 +8,16 @@
8
8
  ChannelAccessor,
9
9
  BaseMarkProps,
10
10
  LinkableMarkProps,
11
- PlotContext,
12
11
  BorderRadius
13
12
  } from '../types';
14
13
  import { wafflePolygon, type WaffleOptions } from './helpers/waffle';
15
14
  import { getPlotDefaults } from '../hooks/plotDefaults';
16
- import { getContext } from 'svelte';
17
15
  import { intervalY, recordizeY, sort, stackY } from '../transforms';
18
16
  import Mark from '../Mark.svelte';
19
17
  import { resolveProp, resolveStyles } from '../helpers/resolve';
20
18
  import { roundedRect } from '../helpers/roundedRect';
21
19
  import GroupMultiple from './helpers/GroupMultiple.svelte';
20
+ import { usePlot } from '../hooks/usePlot.svelte.js';
22
21
 
23
22
  interface WaffleYMarkProps
24
23
  extends BaseMarkProps<Datum>, LinkableMarkProps<Datum>, WaffleOptions<Datum> {
@@ -56,8 +55,7 @@
56
55
  ...options
57
56
  }: WaffleYMarkProps = $derived({ ...DEFAULTS, ...markProps });
58
57
 
59
- const { getPlotState } = getContext<PlotContext>('svelteplot');
60
- const plot = $derived(getPlotState());
58
+ const plot = usePlot();
61
59
 
62
60
  const args = $derived(
63
61
  stackY(
@@ -1,87 +1,6 @@
1
- import type { DataRecord, ChannelAccessor, LinkableMarkProps } from '../types';
2
- import { type WaffleOptions } from './helpers/waffle';
1
+ import type { DataRecord } from '../types';
3
2
  declare function $$render<Datum extends DataRecord>(): {
4
- props: Partial<{
5
- filter: import("../types").ConstantAccessor<boolean, Datum>;
6
- facet: "auto" | "include" | "exclude";
7
- fx: ChannelAccessor<Datum>;
8
- fy: ChannelAccessor<Datum>;
9
- dx: import("../types").ConstantAccessor<number, Datum>;
10
- dy: import("../types").ConstantAccessor<number, Datum>;
11
- dodgeX: import("../transforms/dodge").DodgeXOptions;
12
- dodgeY: import("../transforms/dodge").DodgeYOptions;
13
- fill: ChannelAccessor<Datum>;
14
- fillOpacity: import("../types").ConstantAccessor<number, Datum>;
15
- sort: ((a: import("../types").RawValue, b: import("../types").RawValue) => number) | {
16
- channel: string;
17
- order?: "ascending" | "descending";
18
- } | import("../types").ConstantAccessor<import("../types").RawValue, Datum>;
19
- stroke: ChannelAccessor<Datum>;
20
- strokeWidth: import("../types").ConstantAccessor<number, Datum>;
21
- strokeOpacity: import("../types").ConstantAccessor<number, Datum>;
22
- strokeLinejoin: import("../types").ConstantAccessor<import("csstype").Property.StrokeLinejoin, Datum>;
23
- strokeLinecap: import("../types").ConstantAccessor<import("csstype").Property.StrokeLinecap, Datum>;
24
- strokeMiterlimit: import("../types").ConstantAccessor<number, Datum>;
25
- opacity: ChannelAccessor<Datum>;
26
- strokeDasharray: import("../types").ConstantAccessor<string, Datum>;
27
- strokeDashoffset: import("../types").ConstantAccessor<number, Datum>;
28
- mixBlendMode: import("../types").ConstantAccessor<import("csstype").Property.MixBlendMode, Datum>;
29
- clipPath: string;
30
- imageFilter: import("../types").ConstantAccessor<string, Datum>;
31
- shapeRendering: import("../types").ConstantAccessor<import("csstype").Property.ShapeRendering, Datum>;
32
- paintOrder: import("../types").ConstantAccessor<string, Datum>;
33
- onclick: import("svelte/elements").MouseEventHandler<SVGPathElement>;
34
- ondblclick: import("svelte/elements").MouseEventHandler<SVGPathElement>;
35
- onmouseup: import("svelte/elements").MouseEventHandler<SVGPathElement>;
36
- onmousedown: import("svelte/elements").MouseEventHandler<SVGPathElement>;
37
- onmouseenter: import("svelte/elements").MouseEventHandler<SVGPathElement>;
38
- onmousemove: import("svelte/elements").MouseEventHandler<SVGPathElement>;
39
- onmouseleave: import("svelte/elements").MouseEventHandler<SVGPathElement>;
40
- onmouseout: import("svelte/elements").MouseEventHandler<SVGPathElement>;
41
- onmouseover: import("svelte/elements").MouseEventHandler<SVGPathElement>;
42
- onpointercancel: import("svelte/elements").MouseEventHandler<SVGPathElement>;
43
- onpointerdown: import("svelte/elements").MouseEventHandler<SVGPathElement>;
44
- onpointerup: import("svelte/elements").MouseEventHandler<SVGPathElement>;
45
- onpointerenter: import("svelte/elements").MouseEventHandler<SVGPathElement>;
46
- onpointerleave: import("svelte/elements").MouseEventHandler<SVGPathElement>;
47
- onpointermove: import("svelte/elements").MouseEventHandler<SVGPathElement>;
48
- onpointerover: import("svelte/elements").MouseEventHandler<SVGPathElement>;
49
- onpointerout: import("svelte/elements").MouseEventHandler<SVGPathElement>;
50
- ondrag: import("svelte/elements").MouseEventHandler<SVGPathElement>;
51
- ondrop: import("svelte/elements").MouseEventHandler<SVGPathElement>;
52
- ondragstart: import("svelte/elements").MouseEventHandler<SVGPathElement>;
53
- ondragenter: import("svelte/elements").MouseEventHandler<SVGPathElement>;
54
- ondragleave: import("svelte/elements").MouseEventHandler<SVGPathElement>;
55
- ondragover: import("svelte/elements").MouseEventHandler<SVGPathElement>;
56
- ondragend: import("svelte/elements").MouseEventHandler<SVGPathElement>;
57
- ontouchstart: import("svelte/elements").MouseEventHandler<SVGPathElement>;
58
- ontouchmove: import("svelte/elements").MouseEventHandler<SVGPathElement>;
59
- ontouchend: import("svelte/elements").MouseEventHandler<SVGPathElement>;
60
- ontouchcancel: import("svelte/elements").MouseEventHandler<SVGPathElement>;
61
- oncontextmenu: import("svelte/elements").MouseEventHandler<SVGPathElement>;
62
- onwheel: import("svelte/elements").MouseEventHandler<SVGPathElement>;
63
- class: string;
64
- style: string;
65
- cursor: import("../types").ConstantAccessor<import("csstype").Property.Cursor, Datum>;
66
- }> & LinkableMarkProps<Datum> & WaffleOptions<Datum> & {
67
- data?: Datum[];
68
- /**
69
- * bound to a babd scale
70
- */
71
- x?: ChannelAccessor<Datum>;
72
- /**
73
- * bound to a quantitative scale
74
- */
75
- y?: ChannelAccessor<Datum>;
76
- /**
77
- * bound to a quantitative scale
78
- */
79
- y1?: ChannelAccessor<Datum>;
80
- /**
81
- * bound to a quantitative scale
82
- */
83
- y2?: ChannelAccessor<Datum>;
84
- };
3
+ props: any;
85
4
  exports: {};
86
5
  bindings: "";
87
6
  slots: {};
@@ -2,17 +2,16 @@
2
2
  import type {
3
3
  Mark,
4
4
  BaseMarkProps,
5
- PlotContext,
6
5
  ScaledDataRecord,
7
6
  UsedScales
8
7
  } from '../../types/index.js';
9
8
  import { resolveProp, resolveScaledStyleProps } from '../../helpers/resolve.js';
10
- import { getContext } from 'svelte';
11
9
  import { type Area } from 'd3-shape';
12
10
  import CanvasLayer from './CanvasLayer.svelte';
13
11
  import type { Attachment } from 'svelte/attachments';
14
12
  import { devicePixelRatio } from 'svelte/reactivity/window';
15
13
  import { resolveColor } from './canvas.js';
14
+ import { usePlot } from '../../hooks/usePlot.svelte.js';
16
15
 
17
16
  let {
18
17
  mark,
@@ -26,8 +25,7 @@
26
25
  areaPath: Area<ScaledDataRecord>;
27
26
  } = $props();
28
27
 
29
- const { getPlotState } = getContext<PlotContext>('svelteplot');
30
- const plot = $derived(getPlotState());
28
+ const plot = usePlot();
31
29
 
32
30
  function maybeOpacity(value: unknown) {
33
31
  return value == null ? 1 : +value;
@@ -0,0 +1,271 @@
1
+ <!-- @component
2
+ Internal shared box plot implementation for BoxX and BoxY
3
+ -->
4
+ <script lang="ts" generics="Datum extends DataRecord">
5
+ type Orientation = 'x' | 'y';
6
+
7
+ interface BoxMarkProps extends Pick<
8
+ BaseMarkProps<Datum>,
9
+ 'class' | 'fill' | 'stroke' | 'fx' | 'fy'
10
+ > {
11
+ data: Datum[];
12
+ x: ChannelAccessor;
13
+ y: ChannelAccessor;
14
+ /**
15
+ * Custom sort order for grouped box plot data
16
+ */
17
+ sort?: 'min' | 'max' | 'median' | 'p25' | 'p75' | ((d: Datum) => RawValue);
18
+ /**
19
+ * Options for the rule marks that represent the min/max range
20
+ */
21
+ rule: Record<string, ChannelAccessor<Datum>>;
22
+ /**
23
+ * Options for the bar marks that represent the IQR range
24
+ */
25
+ bar: Record<string, ChannelAccessor<Datum>>;
26
+ /**
27
+ * Options for the tick marks that represent the median
28
+ */
29
+ tickMedian: Record<string, ChannelAccessor<Datum>> | boolean;
30
+ /**
31
+ * Options for the tick marks that represent the min/max range
32
+ */
33
+ tickMinMax: Record<string, ChannelAccessor<Datum>> | boolean;
34
+ /**
35
+ * Options for the dot marks that represent the outliers
36
+ */
37
+ dot: Record<string, ChannelAccessor<Datum>>;
38
+ orientation: Orientation;
39
+ }
40
+
41
+ import GroupMultiple from './GroupMultiple.svelte';
42
+ import { groupX, groupY, BarY, TickY, RuleX, BarX, TickX, RuleY, Dot } from '../../index.js';
43
+ import { resolveChannel } from '../../helpers/resolve.js';
44
+ import type { BaseMarkProps, ChannelAccessor, DataRecord, RawValue } from '../../types';
45
+ import { IS_SORTED } from '../../transforms/sort';
46
+
47
+ let markProps: BoxMarkProps = $props();
48
+
49
+ const {
50
+ data = [{}],
51
+ bar,
52
+ rule,
53
+ tickMedian,
54
+ tickMinMax,
55
+ dot,
56
+ x,
57
+ y,
58
+ sort,
59
+ fx,
60
+ fy,
61
+ fill,
62
+ stroke,
63
+ orientation,
64
+ class: className = ''
65
+ }: BoxMarkProps = $derived(markProps);
66
+
67
+ const groupFn = $derived(orientation === 'y' ? groupX : groupY);
68
+ const BarMark = $derived(orientation === 'y' ? BarY : BarX);
69
+ const RuleMark = $derived(orientation === 'y' ? RuleX : RuleY);
70
+ const TickMark = $derived(orientation === 'y' ? TickY : TickX);
71
+
72
+ // the channels as if this would be a BoxX
73
+ const xChannel = $derived(orientation === 'y' ? y : x);
74
+ const yChannel = $derived(orientation === 'y' ? x : y);
75
+ const xProp = $derived(orientation === 'x' ? 'x' : 'y');
76
+ const x1Prop = $derived(`${xProp}1`);
77
+ const x2Prop = $derived(`${xProp}2`);
78
+ const yProp = $derived(orientation === 'x' ? 'y' : 'x');
79
+
80
+ const { data: grouped, ...groupChannels } = $derived(
81
+ groupFn(
82
+ {
83
+ data: data.filter((d) => resolveChannel(xProp, d, { x, y }) != null),
84
+ x,
85
+ y,
86
+ [x1Prop]: xChannel,
87
+ [x2Prop]: xChannel,
88
+ fx,
89
+ fy
90
+ },
91
+ { [xProp]: 'median', [x1Prop]: 'p25', [x2Prop]: 'p75', fill: (rows) => rows }
92
+ )
93
+ );
94
+
95
+ const X = Symbol('x'),
96
+ Y = Symbol('y'),
97
+ FX = Symbol('fx'),
98
+ FY = Symbol('fy'),
99
+ P25 = Symbol('p25'),
100
+ P75 = Symbol('p75'),
101
+ MEDIAN = Symbol('median'),
102
+ MIN = Symbol('min'),
103
+ MAX = Symbol('max'),
104
+ OUTLIERS = Symbol('outliers'),
105
+ SORT_REF = Symbol('sortRef');
106
+
107
+ const facets = $derived({
108
+ ...(fx != null && { fx: FX }),
109
+ ...(fy != null && { fy: FY })
110
+ });
111
+
112
+ const sortProps = { [IS_SORTED]: true };
113
+
114
+ const compareValues = (a: RawValue, b: RawValue) =>
115
+ (typeof a === 'string' && typeof b === 'string'
116
+ ? a.localeCompare(b)
117
+ : a > b
118
+ ? 1
119
+ : a < b
120
+ ? -1
121
+ : 0) || 0;
122
+
123
+ const boxData = $derived.by(() => {
124
+ const boxes = grouped
125
+ .map((row) => {
126
+ const medianKey = groupChannels[xProp];
127
+ const p25Key = groupChannels[x1Prop];
128
+ const p75Key = groupChannels[x2Prop];
129
+ const groupKey = groupChannels[yProp];
130
+
131
+ const iqr = row[p75Key] - row[p25Key];
132
+ const whisker = iqr * 1.5;
133
+ const lower = row[p25Key] - whisker;
134
+ const upper = row[p75Key] + whisker;
135
+ const data = row[groupChannels.fill].map((d) => ({
136
+ ...d,
137
+ [orientation === 'y' ? Y : X]: resolveChannel(xProp, d, {
138
+ x,
139
+ y
140
+ })
141
+ }));
142
+ const valueSym = orientation === 'y' ? Y : X;
143
+ const groupSym = orientation === 'y' ? X : Y;
144
+ const outliers = data.filter((d) => d[valueSym] < lower || d[valueSym] > upper);
145
+ const inside = data
146
+ .filter((d) => d[valueSym] >= lower && d[valueSym] <= upper)
147
+ .sort((a, b) => a[valueSym] - b[valueSym]);
148
+
149
+ return {
150
+ ...data[0],
151
+ [SORT_REF]: row[groupChannels.fill]?.[0],
152
+ [groupSym]: row[groupKey],
153
+ [P25]: row[p25Key],
154
+ [MEDIAN]: row[medianKey],
155
+ [P75]: row[p75Key],
156
+ [MIN]: inside.length ? inside[0][valueSym] : null,
157
+ [MAX]: inside.length ? inside.at(-1)[valueSym] : null,
158
+ [FX]: resolveChannel('fx', data[0], { fx }, null),
159
+ [FY]: resolveChannel('fy', data[0], { fy }, null),
160
+ [OUTLIERS]: outliers
161
+ };
162
+ })
163
+ .filter(Boolean);
164
+
165
+ const stripSortRef = ({ [SORT_REF]: _, ...rest }) => rest;
166
+
167
+ if (!sort) return boxes.map(stripSortRef);
168
+
169
+ const [sort_, direction] = maybeSort(sort);
170
+
171
+ const sortAccessor =
172
+ typeof sort === 'function'
173
+ ? (d) => sort(d[SORT_REF])
174
+ : (d) => {
175
+ switch (sort_) {
176
+ case 'min':
177
+ return d[MIN];
178
+ case 'max':
179
+ return d[MAX];
180
+ case 'p25':
181
+ return d[P25];
182
+ case 'p75':
183
+ return d[P75];
184
+ case 'median':
185
+ default:
186
+ return d[MEDIAN];
187
+ }
188
+ };
189
+
190
+ return boxes
191
+ .toSorted(
192
+ (a, b) =>
193
+ compareValues(sortAccessor(a), sortAccessor(b)) *
194
+ direction *
195
+ (orientation === 'x' ? -1 : 1)
196
+ )
197
+ .map(stripSortRef);
198
+ });
199
+
200
+ function maybeSort(
201
+ sort: string | ((d: Datum) => RawValue) | undefined
202
+ ): [string | ((d: Datum) => RawValue), 1 | -1] {
203
+ if (typeof sort !== 'string') return [sort, 1];
204
+ if (sort.startsWith('-')) {
205
+ return [sort.slice(1), -1];
206
+ }
207
+ return [sort, 1];
208
+ }
209
+
210
+ const valueSymbol = $derived(orientation === 'y' ? Y : X);
211
+ const groupSymbol = $derived(orientation === 'y' ? X : Y);
212
+ const length = $derived(className ? 2 : grouped.length);
213
+ const baseClass = $derived(`box-${orientation} ${className || ''}`);
214
+ </script>
215
+
216
+ <GroupMultiple class={baseClass} {length}>
217
+ <RuleMark
218
+ data={boxData}
219
+ {...{ [yProp]: groupSymbol, [x1Prop]: MIN, [x2Prop]: P25 }}
220
+ {stroke}
221
+ {...rule || {}}
222
+ {...facets}
223
+ {...sortProps} />
224
+ <RuleMark
225
+ data={boxData}
226
+ {...{ [yProp]: groupSymbol, [x1Prop]: P75, [x2Prop]: MAX }}
227
+ {stroke}
228
+ {...rule || {}}
229
+ {...facets} />
230
+ <BarMark
231
+ data={boxData}
232
+ {...{ [yProp]: groupSymbol, [x1Prop]: P25, [x2Prop]: P75 }}
233
+ {fill}
234
+ {stroke}
235
+ {...facets}
236
+ {...bar || {}} />
237
+ {#if tickMedian}
238
+ <TickMark
239
+ data={boxData}
240
+ {...{ [yProp]: groupSymbol, [xProp]: MEDIAN }}
241
+ {...facets}
242
+ {stroke}
243
+ strokeWidth={2}
244
+ {...typeof tickMedian === 'object' ? tickMedian : {}} />
245
+ {/if}
246
+ {#if tickMinMax}
247
+ <TickMark
248
+ data={boxData}
249
+ {...{ [yProp]: groupSymbol, [xProp]: MIN }}
250
+ {stroke}
251
+ {...facets}
252
+ inset="20%"
253
+ {...typeof tickMinMax === 'object' ? tickMinMax : {}} />
254
+ <TickMark
255
+ data={boxData}
256
+ {...{ [yProp]: groupSymbol, [xProp]: MAX }}
257
+ {stroke}
258
+ {...facets}
259
+ inset="20%"
260
+ {...typeof tickMinMax === 'object' ? tickMinMax : {}} />
261
+ {/if}
262
+ <Dot
263
+ data={boxData.map((d) => d[OUTLIERS]).flat()}
264
+ {x}
265
+ {y}
266
+ {fx}
267
+ {fy}
268
+ {fill}
269
+ {stroke}
270
+ {...dot || {}} />
271
+ </GroupMultiple>
@@ -0,0 +1,55 @@
1
+ import type { ChannelAccessor, DataRecord, RawValue } from '../../types';
2
+ declare function $$render<Datum extends DataRecord>(): {
3
+ props: Pick<BaseMarkProps<Datum>, "fill" | "stroke" | "fx" | "fy" | "class"> & {
4
+ data: Datum[];
5
+ x: ChannelAccessor;
6
+ y: ChannelAccessor;
7
+ /**
8
+ * Custom sort order for grouped box plot data
9
+ */
10
+ sort?: "min" | "max" | "median" | "p25" | "p75" | ((d: Datum) => RawValue);
11
+ /**
12
+ * Options for the rule marks that represent the min/max range
13
+ */
14
+ rule: Record<string, ChannelAccessor<Datum>>;
15
+ /**
16
+ * Options for the bar marks that represent the IQR range
17
+ */
18
+ bar: Record<string, ChannelAccessor<Datum>>;
19
+ /**
20
+ * Options for the tick marks that represent the median
21
+ */
22
+ tickMedian: Record<string, ChannelAccessor<Datum>> | boolean;
23
+ /**
24
+ * Options for the tick marks that represent the min/max range
25
+ */
26
+ tickMinMax: Record<string, ChannelAccessor<Datum>> | boolean;
27
+ /**
28
+ * Options for the dot marks that represent the outliers
29
+ */
30
+ dot: Record<string, ChannelAccessor<Datum>>;
31
+ orientation: "x" | "y";
32
+ };
33
+ exports: {};
34
+ bindings: "";
35
+ slots: {};
36
+ events: {};
37
+ };
38
+ declare class __sveltets_Render<Datum extends DataRecord> {
39
+ props(): ReturnType<typeof $$render<Datum>>['props'];
40
+ events(): ReturnType<typeof $$render<Datum>>['events'];
41
+ slots(): ReturnType<typeof $$render<Datum>>['slots'];
42
+ bindings(): "";
43
+ exports(): {};
44
+ }
45
+ interface $$IsomorphicComponent {
46
+ new <Datum extends DataRecord>(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']>> & {
47
+ $$bindings?: ReturnType<__sveltets_Render<Datum>['bindings']>;
48
+ } & ReturnType<__sveltets_Render<Datum>['exports']>;
49
+ <Datum extends DataRecord>(internal: unknown, props: ReturnType<__sveltets_Render<Datum>['props']> & {}): ReturnType<__sveltets_Render<Datum>['exports']>;
50
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
51
+ }
52
+ /** Internal shared box plot implementation for BoxX and BoxY */
53
+ declare const Box: $$IsomorphicComponent;
54
+ type Box<Datum extends DataRecord> = InstanceType<typeof Box<Datum>>;
55
+ export default Box;
@@ -1,9 +1,8 @@
1
1
  <script lang="ts">
2
- import { getContext } from 'svelte';
3
- import type { PlotContext } from '../../types/plot';
4
2
  import { devicePixelRatio } from 'svelte/reactivity/window';
5
3
  import { MediaQuery } from 'svelte/reactivity';
6
4
  import type { Attachment } from 'svelte/attachments';
5
+ import { usePlot } from '../../hooks/usePlot.svelte.js';
7
6
 
8
7
  const darkMode = new MediaQuery('prefers-color-scheme: dark');
9
8
  let colorScheme = $state();
@@ -26,8 +25,7 @@
26
25
 
27
26
  let restProps: {} = $props();
28
27
 
29
- const { getPlotState } = getContext<PlotContext>('svelteplot');
30
- const plot = $derived(getPlotState());
28
+ const plot = usePlot();
31
29
  </script>
32
30
 
33
31
  <!--
@@ -3,20 +3,18 @@
3
3
  PlotState,
4
4
  Mark,
5
5
  BaseMarkProps,
6
- ScaledDataRecord,
7
- PlotContext
6
+ ScaledDataRecord
8
7
  } from '../../types/index.js';
9
8
  import { resolveProp } from '../../helpers/resolve.js';
10
9
  import { maybeSymbol } from '../../helpers/symbols.js';
11
10
  import { symbol as d3Symbol } from 'd3-shape';
12
11
  import type { Attachment } from 'svelte/attachments';
13
12
  import CanvasLayer from './CanvasLayer.svelte';
14
- import { getContext } from 'svelte';
15
13
  import { devicePixelRatio } from 'svelte/reactivity/window';
16
14
  import { resolveColor } from './canvas.js';
15
+ import { usePlot } from '../../hooks/usePlot.svelte.js';
17
16
 
18
- const { getPlotState } = getContext<PlotContext>('svelteplot');
19
- const plot = $derived(getPlotState());
17
+ const plot = usePlot();
20
18
 
21
19
  let {
22
20
  mark,
@@ -2,18 +2,17 @@
2
2
  import type {
3
3
  Mark,
4
4
  BaseMarkProps,
5
- PlotContext,
6
5
  ScaledDataRecord,
7
6
  UsedScales
8
7
  } from '../../types/index.js';
9
8
  import { CSS_VAR } from '../../constants.js';
10
9
  import { resolveProp, resolveScaledStyleProps } from '../../helpers/resolve.js';
11
- import { getContext } from 'svelte';
12
10
  import { type GeoPath } from 'd3-geo';
13
11
  import CanvasLayer from './CanvasLayer.svelte';
14
12
  import type { Attachment } from 'svelte/attachments';
15
13
  import { devicePixelRatio } from 'svelte/reactivity/window';
16
14
  import { GEOJSON_PREFER_STROKE } from '../../helpers/index.js';
15
+ import { usePlot } from '../../hooks/usePlot.svelte.js';
17
16
 
18
17
  let {
19
18
  mark,
@@ -27,8 +26,7 @@
27
26
  usedScales: UsedScales;
28
27
  } = $props();
29
28
 
30
- const { getPlotState } = getContext<PlotContext>('svelteplot');
31
- const plot = $derived(getPlotState());
29
+ const plot = usePlot();
32
30
 
33
31
  function maybeOpacity(value) {
34
32
  return value == null ? 1 : +value;
@@ -2,17 +2,16 @@
2
2
  import type {
3
3
  Mark,
4
4
  BaseMarkProps,
5
- PlotContext,
6
5
  ScaledDataRecord,
7
6
  UsedScales
8
7
  } from '../../types/index.js';
9
8
  import { resolveProp, resolveScaledStyleProps } from '../../helpers/resolve.js';
10
- import { getContext } from 'svelte';
11
9
  import { type Line } from 'd3-shape';
12
10
  import CanvasLayer from './CanvasLayer.svelte';
13
11
  import type { Attachment } from 'svelte/attachments';
14
12
  import { devicePixelRatio } from 'svelte/reactivity/window';
15
13
  import { resolveColor } from './canvas.js';
14
+ import { usePlot } from '../../hooks/usePlot.svelte.js';
16
15
 
17
16
  let {
18
17
  mark,
@@ -27,8 +26,7 @@
27
26
  groupByKey?: unknown;
28
27
  } = $props();
29
28
 
30
- const { getPlotState } = getContext<PlotContext>('svelteplot');
31
- const plot = $derived(getPlotState());
29
+ const plot = usePlot();
32
30
 
33
31
  function maybeOpacity(value: unknown) {
34
32
  return value == null ? 1 : +value;
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
- import { getContext } from 'svelte';
3
- import type { PlotContext, RawValue } from '../../index.js';
2
+ import type { RawValue } from '../../index.js';
3
+ import { usePlot } from '../../hooks/usePlot.svelte.js';
4
4
 
5
5
  let {
6
6
  id,
@@ -10,8 +10,7 @@
10
10
  stops: { x: RawValue; color: string }[];
11
11
  } = $props();
12
12
 
13
- const { getPlotState } = getContext<PlotContext>('svelteplot');
14
- const plot = $derived(getPlotState());
13
+ const plot = usePlot();
15
14
 
16
15
  const projectedStops = $derived(
17
16
  stops
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
- import { getContext } from 'svelte';
3
- import type { PlotContext, RawValue } from '../../index.js';
2
+ import type { RawValue } from '../../index.js';
3
+ import { usePlot } from '../../hooks/usePlot.svelte.js';
4
4
 
5
5
  let {
6
6
  id,
@@ -10,8 +10,7 @@
10
10
  stops: { y: RawValue; color: string }[];
11
11
  } = $props();
12
12
 
13
- const { getPlotState } = getContext<PlotContext>('svelteplot');
14
- const plot = $derived(getPlotState());
13
+ const plot = usePlot();
15
14
 
16
15
  const projectedStops = $derived(
17
16
  stops
@@ -11,11 +11,10 @@
11
11
  ConstantAccessor,
12
12
  DataRecord,
13
13
  Mark,
14
- PlotContext,
15
14
  PlotScales
16
15
  } from '../../types/index.js';
17
16
  import { addEventHandlers } from './events.js';
18
- import { getContext } from 'svelte';
17
+ import { usePlot } from '../../hooks/usePlot.svelte.js';
19
18
 
20
19
  type MarkerPathProps = BaseMarkProps<Datum> & {
21
20
  /**
@@ -78,7 +77,7 @@
78
77
 
79
78
  const id = randomId();
80
79
 
81
- const { getPlotState } = getContext<PlotContext>('svelteplot');
80
+ const plot = usePlot();
82
81
 
83
82
  const points = $derived(text && d != null ? d.split(/[LMC]/).slice(1) : []);
84
83
  const hasPath = $derived(points.length > 0);
@@ -96,7 +95,7 @@
96
95
  class={className}
97
96
  stroke-width={strokeWidth_}
98
97
  {@attach addEventHandlers({
99
- getPlotState,
98
+ plot,
100
99
  options: mark.options,
101
100
  datum: datum
102
101
  })}>
@@ -127,7 +126,7 @@
127
126
  {d}
128
127
  {style}
129
128
  {@attach addEventHandlers({
130
- getPlotState,
129
+ plot,
131
130
  options: mark.options,
132
131
  datum: datum
133
132
  })} />