svelteplot 0.0.1-alpha.9 → 0.1.3-next.12

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 (251) hide show
  1. package/LICENSE.md +5 -0
  2. package/README.md +3 -35
  3. package/dist/Mark.svelte +292 -0
  4. package/dist/Mark.svelte.d.ts +22 -0
  5. package/dist/Plot.svelte +148 -156
  6. package/dist/Plot.svelte.d.ts +15 -15
  7. package/dist/constants.d.ts +15 -0
  8. package/dist/constants.js +110 -0
  9. package/dist/core/Facet.svelte +59 -0
  10. package/dist/core/Facet.svelte.d.ts +18 -0
  11. package/dist/core/FacetAxes.svelte +66 -0
  12. package/dist/core/FacetAxes.svelte.d.ts +4 -0
  13. package/dist/core/FacetGrid.svelte +86 -0
  14. package/dist/core/FacetGrid.svelte.d.ts +13 -0
  15. package/dist/core/Plot.svelte +568 -0
  16. package/dist/core/Plot.svelte.d.ts +14 -0
  17. package/dist/helpers/arrowPath.d.ts +14 -0
  18. package/dist/helpers/arrowPath.js +129 -0
  19. package/dist/helpers/autoProjection.d.ts +19 -0
  20. package/dist/helpers/autoProjection.js +87 -0
  21. package/dist/helpers/autoScales.d.ts +23 -0
  22. package/dist/helpers/autoScales.js +203 -0
  23. package/dist/helpers/autoTicks.d.ts +3 -0
  24. package/dist/helpers/autoTicks.js +40 -0
  25. package/dist/helpers/autoTimeFormat.d.ts +2 -2
  26. package/dist/helpers/autoTimeFormat.js +34 -5
  27. package/dist/helpers/callWithProps.d.ts +8 -0
  28. package/dist/helpers/callWithProps.js +13 -0
  29. package/dist/helpers/colors.js +17 -2
  30. package/dist/helpers/curves.d.ts +3 -0
  31. package/dist/helpers/curves.js +42 -0
  32. package/dist/helpers/data.d.ts +9 -0
  33. package/dist/helpers/data.js +16 -0
  34. package/dist/helpers/facets.d.ts +12 -0
  35. package/dist/helpers/facets.js +49 -0
  36. package/dist/helpers/formats.d.ts +3 -0
  37. package/dist/helpers/formats.js +3 -0
  38. package/dist/helpers/getBaseStyles.d.ts +7 -2
  39. package/dist/helpers/getBaseStyles.js +34 -10
  40. package/dist/helpers/getLogTicks.js +5 -5
  41. package/dist/helpers/group.d.ts +6 -0
  42. package/dist/helpers/group.js +53 -0
  43. package/dist/helpers/index.d.ts +18 -0
  44. package/dist/helpers/index.js +55 -0
  45. package/dist/helpers/isRawValue.d.ts +2 -0
  46. package/dist/helpers/isRawValue.js +5 -0
  47. package/dist/helpers/isValid.d.ts +6 -0
  48. package/dist/helpers/isValid.js +6 -0
  49. package/dist/helpers/math.d.ts +19 -0
  50. package/dist/helpers/math.js +116 -0
  51. package/dist/helpers/mergeDeep.d.ts +1 -1
  52. package/dist/helpers/noise.d.ts +1 -0
  53. package/dist/helpers/noise.js +72 -0
  54. package/dist/helpers/projection.d.ts +33 -0
  55. package/dist/helpers/projection.js +100 -0
  56. package/dist/helpers/reduce.d.ts +10 -0
  57. package/dist/helpers/reduce.js +85 -0
  58. package/dist/helpers/regressionLoess.d.ts +12 -0
  59. package/dist/helpers/regressionLoess.js +47 -0
  60. package/dist/helpers/removeIdenticalLines.d.ts +8 -1
  61. package/dist/helpers/removeIdenticalLines.js +14 -7
  62. package/dist/helpers/resolve.d.ts +21 -0
  63. package/dist/helpers/resolve.js +156 -0
  64. package/dist/helpers/roundedRect.d.ts +9 -0
  65. package/dist/helpers/roundedRect.js +31 -0
  66. package/dist/helpers/scales.d.ts +42 -0
  67. package/dist/helpers/scales.js +311 -0
  68. package/dist/helpers/time.d.ts +6 -0
  69. package/dist/helpers/time.js +282 -0
  70. package/dist/helpers/typeChecks.d.ts +8 -5
  71. package/dist/helpers/typeChecks.js +27 -6
  72. package/dist/index.d.ts +49 -1
  73. package/dist/index.js +53 -2
  74. package/dist/marks/Area.svelte +146 -0
  75. package/dist/marks/Area.svelte.d.ts +30 -0
  76. package/dist/marks/AreaX.svelte +27 -0
  77. package/dist/marks/AreaX.svelte.d.ts +12 -0
  78. package/dist/marks/AreaY.svelte +38 -0
  79. package/dist/marks/AreaY.svelte.d.ts +19 -0
  80. package/dist/marks/Arrow.svelte +139 -0
  81. package/dist/marks/Arrow.svelte.d.ts +44 -0
  82. package/dist/marks/AxisX.svelte +198 -93
  83. package/dist/marks/AxisX.svelte.d.ts +17 -16
  84. package/dist/marks/AxisY.svelte +176 -62
  85. package/dist/marks/AxisY.svelte.d.ts +17 -14
  86. package/dist/marks/BarX.svelte +93 -0
  87. package/dist/marks/BarX.svelte.d.ts +4 -0
  88. package/dist/marks/BarY.svelte +103 -0
  89. package/dist/marks/BarY.svelte.d.ts +25 -0
  90. package/dist/marks/BollingerX.svelte +44 -0
  91. package/dist/marks/BollingerX.svelte.d.ts +18 -0
  92. package/dist/marks/BollingerY.svelte +39 -0
  93. package/dist/marks/BollingerY.svelte.d.ts +18 -0
  94. package/dist/marks/BoxX.svelte +89 -0
  95. package/dist/marks/BoxX.svelte.d.ts +4 -0
  96. package/dist/marks/BoxY.svelte +110 -0
  97. package/dist/marks/BoxY.svelte.d.ts +29 -0
  98. package/dist/marks/Cell.svelte +110 -0
  99. package/dist/marks/Cell.svelte.d.ts +16 -0
  100. package/dist/marks/CellX.svelte +24 -0
  101. package/dist/marks/CellX.svelte.d.ts +3 -0
  102. package/dist/marks/CellY.svelte +24 -0
  103. package/dist/marks/CellY.svelte.d.ts +3 -0
  104. package/dist/marks/ColorLegend.svelte +148 -27
  105. package/dist/marks/ColorLegend.svelte.d.ts +12 -13
  106. package/dist/marks/CustomMark.svelte +43 -0
  107. package/dist/marks/CustomMark.svelte.d.ts +16 -0
  108. package/dist/marks/CustomMarkHTML.svelte +103 -0
  109. package/dist/marks/CustomMarkHTML.svelte.d.ts +17 -0
  110. package/dist/marks/DifferenceY.svelte +144 -0
  111. package/dist/marks/DifferenceY.svelte.d.ts +30 -0
  112. package/dist/marks/Dot.svelte +128 -73
  113. package/dist/marks/Dot.svelte.d.ts +24 -14
  114. package/dist/marks/DotX.svelte +15 -3
  115. package/dist/marks/DotX.svelte.d.ts +8 -16
  116. package/dist/marks/DotY.svelte +8 -3
  117. package/dist/marks/DotY.svelte.d.ts +5 -17
  118. package/dist/marks/Frame.svelte +39 -31
  119. package/dist/marks/Frame.svelte.d.ts +7 -14
  120. package/dist/marks/Geo.svelte +102 -0
  121. package/dist/marks/Geo.svelte.d.ts +10 -0
  122. package/dist/marks/Graticule.svelte +28 -0
  123. package/dist/marks/Graticule.svelte.d.ts +9 -0
  124. package/dist/marks/GridX.svelte +67 -36
  125. package/dist/marks/GridX.svelte.d.ts +7 -18
  126. package/dist/marks/GridY.svelte +64 -25
  127. package/dist/marks/GridY.svelte.d.ts +7 -14
  128. package/dist/marks/HTMLTooltip.svelte +91 -0
  129. package/dist/marks/HTMLTooltip.svelte.d.ts +11 -0
  130. package/dist/marks/Line.svelte +219 -58
  131. package/dist/marks/Line.svelte.d.ts +30 -14
  132. package/dist/marks/LineX.svelte +8 -8
  133. package/dist/marks/LineX.svelte.d.ts +4 -17
  134. package/dist/marks/LineY.svelte +7 -8
  135. package/dist/marks/LineY.svelte.d.ts +4 -17
  136. package/dist/marks/Link.svelte +180 -0
  137. package/dist/marks/Link.svelte.d.ts +21 -0
  138. package/dist/marks/Pointer.svelte +126 -0
  139. package/dist/marks/Pointer.svelte.d.ts +23 -0
  140. package/dist/marks/Rect.svelte +103 -0
  141. package/dist/marks/Rect.svelte.d.ts +15 -0
  142. package/dist/marks/RectX.svelte +33 -0
  143. package/dist/marks/RectX.svelte.d.ts +15 -0
  144. package/dist/marks/RectY.svelte +33 -0
  145. package/dist/marks/RectY.svelte.d.ts +15 -0
  146. package/dist/marks/RegressionX.svelte +26 -0
  147. package/dist/marks/RegressionX.svelte.d.ts +4 -0
  148. package/dist/marks/RegressionY.svelte +26 -0
  149. package/dist/marks/RegressionY.svelte.d.ts +4 -0
  150. package/dist/marks/RuleX.svelte +52 -28
  151. package/dist/marks/RuleX.svelte.d.ts +14 -14
  152. package/dist/marks/RuleY.svelte +52 -28
  153. package/dist/marks/RuleY.svelte.d.ts +14 -14
  154. package/dist/marks/Sphere.svelte +8 -0
  155. package/dist/marks/Sphere.svelte.d.ts +51 -0
  156. package/dist/marks/Spike.svelte +15 -0
  157. package/dist/marks/Spike.svelte.d.ts +4 -0
  158. package/dist/marks/SymbolLegend.svelte +27 -12
  159. package/dist/marks/SymbolLegend.svelte.d.ts +8 -14
  160. package/dist/marks/Text.svelte +189 -0
  161. package/dist/marks/Text.svelte.d.ts +26 -0
  162. package/dist/marks/TickX.svelte +89 -0
  163. package/dist/marks/TickX.svelte.d.ts +22 -0
  164. package/dist/marks/TickY.svelte +90 -0
  165. package/dist/marks/TickY.svelte.d.ts +22 -0
  166. package/dist/marks/Vector.svelte +219 -0
  167. package/dist/marks/Vector.svelte.d.ts +31 -0
  168. package/dist/marks/helpers/BaseAxisX.svelte +210 -0
  169. package/dist/marks/helpers/BaseAxisX.svelte.d.ts +24 -0
  170. package/dist/marks/helpers/BaseAxisY.svelte +187 -0
  171. package/dist/marks/helpers/BaseAxisY.svelte.d.ts +23 -0
  172. package/dist/marks/helpers/CanvasLayer.svelte +38 -0
  173. package/dist/marks/helpers/CanvasLayer.svelte.d.ts +13 -0
  174. package/dist/marks/helpers/DotCanvas.svelte +184 -0
  175. package/dist/marks/helpers/DotCanvas.svelte.d.ts +11 -0
  176. package/dist/marks/helpers/GeoCanvas.svelte +165 -0
  177. package/dist/marks/helpers/GeoCanvas.svelte.d.ts +13 -0
  178. package/dist/marks/helpers/GroupMultiple.svelte +17 -0
  179. package/dist/marks/helpers/GroupMultiple.svelte.d.ts +9 -0
  180. package/dist/marks/helpers/Marker.svelte +93 -0
  181. package/dist/marks/helpers/Marker.svelte.d.ts +10 -0
  182. package/dist/marks/helpers/MarkerPath.svelte +141 -0
  183. package/dist/marks/helpers/MarkerPath.svelte.d.ts +44 -0
  184. package/dist/marks/helpers/Regression.svelte +174 -0
  185. package/dist/marks/helpers/Regression.svelte.d.ts +26 -0
  186. package/dist/marks/helpers/events.d.ts +8 -0
  187. package/dist/marks/helpers/events.js +74 -0
  188. package/dist/transforms/bin.d.ts +51 -0
  189. package/dist/transforms/bin.js +171 -0
  190. package/dist/transforms/bollinger.d.ts +21 -0
  191. package/dist/transforms/bollinger.js +53 -0
  192. package/dist/transforms/centroid.d.ts +9 -0
  193. package/dist/transforms/centroid.js +13 -0
  194. package/dist/transforms/facet.d.ts +1 -0
  195. package/dist/transforms/facet.js +1 -0
  196. package/dist/transforms/filter.d.ts +2 -0
  197. package/dist/transforms/filter.js +8 -0
  198. package/dist/transforms/group.d.ts +66 -0
  199. package/dist/transforms/group.js +109 -0
  200. package/dist/transforms/interval.d.ts +11 -0
  201. package/dist/transforms/interval.js +34 -0
  202. package/dist/transforms/jitter.d.ts +1 -0
  203. package/dist/transforms/jitter.js +1 -0
  204. package/dist/transforms/map.d.ts +10 -0
  205. package/dist/transforms/map.js +89 -0
  206. package/dist/transforms/normalize.d.ts +9 -0
  207. package/dist/transforms/normalize.js +86 -0
  208. package/dist/transforms/recordize.d.ts +15 -0
  209. package/dist/transforms/recordize.js +78 -0
  210. package/dist/transforms/rename.d.ts +14 -0
  211. package/dist/transforms/rename.js +42 -0
  212. package/dist/transforms/select.d.ts +35 -0
  213. package/dist/transforms/select.js +55 -0
  214. package/dist/transforms/shift.d.ts +13 -0
  215. package/dist/transforms/shift.js +45 -0
  216. package/dist/transforms/sort.d.ts +28 -0
  217. package/dist/transforms/sort.js +66 -0
  218. package/dist/transforms/stack.d.ts +10 -0
  219. package/dist/transforms/stack.js +110 -0
  220. package/dist/transforms/window.d.ts +24 -0
  221. package/dist/transforms/window.js +73 -0
  222. package/dist/types.d.ts +625 -188
  223. package/dist/ui/Checkbox.svelte +6 -0
  224. package/dist/ui/Checkbox.svelte.d.ts +13 -0
  225. package/dist/ui/RadioInput.svelte +27 -0
  226. package/dist/ui/RadioInput.svelte.d.ts +9 -0
  227. package/dist/ui/Select.svelte +27 -0
  228. package/dist/ui/Select.svelte.d.ts +9 -0
  229. package/dist/ui/Slider.svelte +47 -0
  230. package/dist/ui/Slider.svelte.d.ts +11 -0
  231. package/dist/ui/Spiral.svelte +46 -0
  232. package/dist/ui/Spiral.svelte.d.ts +15 -0
  233. package/dist/ui/index.d.ts +4 -0
  234. package/dist/ui/index.js +4 -0
  235. package/package.json +81 -42
  236. package/LICENSE +0 -11
  237. package/dist/classes/Channel.svelte.js +0 -74
  238. package/dist/classes/Mark.svelte.js +0 -17
  239. package/dist/classes/Plot.svelte.js +0 -98
  240. package/dist/contants.d.ts +0 -3
  241. package/dist/contants.js +0 -40
  242. package/dist/helpers/GroupMultiple.svelte +0 -8
  243. package/dist/helpers/GroupMultiple.svelte.d.ts +0 -19
  244. package/dist/helpers/createScale.d.ts +0 -5
  245. package/dist/helpers/createScale.js +0 -57
  246. package/dist/helpers/resolveChannel.d.ts +0 -2
  247. package/dist/helpers/resolveChannel.js +0 -28
  248. package/dist/helpers/wrapArray.d.ts +0 -2
  249. package/dist/helpers/wrapArray.js +0 -4
  250. package/dist/marks/BaseMark.svelte +0 -22
  251. package/dist/marks/BaseMark.svelte.d.ts +0 -19
@@ -0,0 +1,86 @@
1
+ <!--
2
+ @component
3
+ The FacetGrid component repeats the
4
+ marks for each facet domain value
5
+ -->
6
+ <script lang="ts">
7
+ import { getContext, setContext, type Snippet } from 'svelte';
8
+ import type { PlotContext, GenericMarkOptions, Mark } from '../types.js';
9
+ import { scaleBand } from 'd3-scale';
10
+ import Facet from './Facet.svelte';
11
+ import { getEmptyFacets } from '../helpers/facets.js';
12
+
13
+ const { getPlotState, updateDimensions } = getContext<PlotContext>('svelteplot');
14
+ // we need the plot context for the overall width & height
15
+ const plot = $derived(getPlotState());
16
+
17
+ let {
18
+ children,
19
+ marks
20
+ }: {
21
+ children: Snippet;
22
+ marks: Mark<GenericMarkOptions>[];
23
+ } = $props();
24
+
25
+ const useFacetX = $derived(plot.scales.fx.domain.length > 0);
26
+ const useFacetY = $derived(plot.scales.fy.domain.length > 0);
27
+
28
+ const fxValues = $derived(useFacetX ? plot.scales.fx.domain : [true]);
29
+ const fyValues = $derived(useFacetY ? plot.scales.fy.domain : [true]);
30
+
31
+ // we need to track which facets are "empty", meaning that they don't contain
32
+ // any "faceted" data points. this can happen when fx and fy are combined and
33
+ // certain combinations don't yield results
34
+ const emptyFacets = $derived(getEmptyFacets(marks, fxValues, fyValues));
35
+
36
+ // create band scales for fx and fy
37
+ const facetXScale = $derived(
38
+ scaleBand()
39
+ .paddingInner(fxValues.length > 1 ? 0.1 : 0)
40
+ .domain(fxValues)
41
+ .rangeRound([0, plot.plotWidth])
42
+ );
43
+ const facetYScale = $derived(
44
+ scaleBand()
45
+ .paddingInner(fyValues.length > 1 ? 0.1 : 0)
46
+ .domain(fyValues)
47
+ .rangeRound([0, plot.plotHeight])
48
+ );
49
+
50
+ const facetWidth = $derived(useFacetX ? facetXScale.bandwidth() : plot.plotWidth);
51
+ const facetHeight = $derived(useFacetY ? facetYScale.bandwidth() : plot.plotHeight);
52
+
53
+ $effect.pre(() => {
54
+ updateDimensions(facetWidth, facetHeight);
55
+ });
56
+ </script>
57
+
58
+ {#each fxValues as facetX, i}
59
+ {#each fyValues as facetY, j}
60
+ <g
61
+ class="facet"
62
+ fill="currentColor"
63
+ style:display={emptyFacets.get(facetX)?.get(facetY) ? 'none' : 'block'}
64
+ transform="translate({useFacetX ? facetXScale(facetX) : 0}, {useFacetY
65
+ ? facetYScale(facetY)
66
+ : 0})">
67
+ <Facet
68
+ fx={facetX}
69
+ fy={facetY}
70
+ left={i === 0}
71
+ right={i === fxValues.length - 1}
72
+ top={j === 0}
73
+ bottom={j === fyValues.length - 1}
74
+ leftEmpty={!!(i === 0 || emptyFacets.get(fxValues[i - 1])?.get(facetY))}
75
+ topEmpty={!!(j === 0 || emptyFacets.get(facetX)?.get(fyValues[j - 1]))}
76
+ rightEmpty={!!(
77
+ i === fxValues.length - 1 || emptyFacets.get(fxValues[i + 1])?.get(facetY)
78
+ )}
79
+ bottomEmpty={!!(
80
+ j === fyValues.length - 1 || emptyFacets.get(facetX)?.get(fyValues[j + 1])
81
+ )}>
82
+ {@render children()}
83
+ </Facet>
84
+ </g>
85
+ {/each}
86
+ {/each}
@@ -0,0 +1,13 @@
1
+ import { type Snippet } from 'svelte';
2
+ import type { GenericMarkOptions, Mark } from '../types.js';
3
+ type $$ComponentProps = {
4
+ children: Snippet;
5
+ marks: Mark<GenericMarkOptions>[];
6
+ };
7
+ /**
8
+ * The FacetGrid component repeats the
9
+ * marks for each facet domain value
10
+ */
11
+ declare const FacetGrid: import("svelte").Component<$$ComponentProps, {}, "">;
12
+ type FacetGrid = ReturnType<typeof FacetGrid>;
13
+ export default FacetGrid;
@@ -0,0 +1,568 @@
1
+ <!--
2
+ @component
3
+ The core Plot component handles the main layout of the plot but it does not
4
+ include smart automatic scales and marks. It is to be used in cases where
5
+ you want to reduce the footprint of the plot to the bare minimum.
6
+
7
+ Keep in mind that you will have to create your own scales if you're using
8
+ this component.
9
+ -->
10
+ <script lang="ts">
11
+ import { getContext, setContext } from 'svelte';
12
+ import { SvelteMap } from 'svelte/reactivity';
13
+ import { writable } from 'svelte/store';
14
+
15
+ import type {
16
+ PlotOptions,
17
+ GenericMarkOptions,
18
+ Mark,
19
+ PlotScales,
20
+ ScaleName,
21
+ PlotScale,
22
+ PlotDefaults,
23
+ PlotState,
24
+ RawValue
25
+ } from '../types.js';
26
+ import FacetGrid from './FacetGrid.svelte';
27
+
28
+ import mergeDeep from '../helpers/mergeDeep.js';
29
+ import { computeScales, projectXY } from '../helpers/scales.js';
30
+ import { CHANNEL_SCALE, SCALES } from '../constants.js';
31
+ import { scale } from 'svelte/transition';
32
+
33
+ let {
34
+ header,
35
+ footer,
36
+ overlay,
37
+ underlay,
38
+ children,
39
+ facetAxes,
40
+ testid,
41
+ facet,
42
+ class: className = '',
43
+ css,
44
+ width: fixedWidth,
45
+ ...initialOpts
46
+ }: Partial<PlotOptions> = $props();
47
+
48
+ // automatic margins can be applied by the marks, registered
49
+ // with their respective unique identifier as keys
50
+ let autoMarginLeft = writable(new SvelteMap<string, number>());
51
+ let autoMarginRight = writable(new SvelteMap<string, number>());
52
+ let autoMarginBottom = writable(new SvelteMap<string, number>());
53
+ let autoMarginTop = writable(new SvelteMap<string, number>());
54
+
55
+ // autoMargin stores are shared via context
56
+ setContext('svelteplot/autoMargins', {
57
+ autoMarginLeft,
58
+ autoMarginRight,
59
+ autoMarginBottom,
60
+ autoMarginTop
61
+ });
62
+
63
+ // compute maximum margins to either side of the plot from the
64
+ // automatic margins defined by marks
65
+ const maxMarginLeft = $derived(Math.max(...$autoMarginLeft.values()));
66
+ const maxMarginRight = $derived(Math.max(...$autoMarginRight.values()));
67
+ const maxMarginBottom = $derived(Math.max(...$autoMarginBottom.values()));
68
+ const maxMarginTop = $derived(Math.max(...$autoMarginTop.values()));
69
+
70
+ // default settings in the plot and marks can be overwritten by
71
+ // defining the svelteplot/defaults context outside of Plot
72
+ const DEFAULTS: PlotDefaults = {
73
+ axisXAnchor: 'bottom',
74
+ axisYAnchor: 'left',
75
+ xTickSpacing: 80,
76
+ yTickSpacing: 50,
77
+ height: 350,
78
+ initialWidth: 500,
79
+ inset: 0,
80
+ colorScheme: 'turbo',
81
+ dotRadius: 3,
82
+ frame: false,
83
+ axes: true,
84
+ grid: false,
85
+ categoricalColorScheme: 'observable10',
86
+ pointScaleHeight: 18,
87
+ bandScaleHeight: 30,
88
+ locale: 'en-US',
89
+ numberFormat: {
90
+ style: 'decimal',
91
+ notation: 'compact',
92
+ compactDisplay: 'short'
93
+ },
94
+ markerDotRadius: 3,
95
+ ...getContext<Partial<PlotDefaults>>('svelteplot/defaults')
96
+ };
97
+
98
+ let width = $state(DEFAULTS.initialWidth);
99
+
100
+ setContext('svelteplot/_defaults', DEFAULTS);
101
+
102
+ // information that influences the default plot options
103
+ type PlotOptionsParameters = {
104
+ explicitScales: Set<ScaleName>;
105
+ explicitDomains: Set<ScaleName>;
106
+ hasProjection: boolean;
107
+ margins?: number;
108
+ inset?: number;
109
+ };
110
+
111
+ /**
112
+ * the marks used in the plot
113
+ */
114
+ let marks = $state.raw<Mark<GenericMarkOptions>[]>([]);
115
+
116
+ /**
117
+ *
118
+ */
119
+ const explicitMarks = $derived(marks.filter((m) => !m.options.automatic));
120
+
121
+ // knowing if the plot includes explicit grids and marks is useful for
122
+ // including the automatic/implicit axes/grids
123
+ const hasExplicitAxisX = $derived(!!explicitMarks.find((m) => m.type === 'axisX'));
124
+ const hasExplicitAxisY = $derived(!!explicitMarks.find((m) => m.type === 'axisY'));
125
+ const hasExplicitGridX = $derived(!!explicitMarks.find((m) => m.type === 'gridX'));
126
+ const hasExplicitGridY = $derived(!!explicitMarks.find((m) => m.type === 'gridY'));
127
+
128
+ const explicitScales = $derived(
129
+ new Set(
130
+ explicitMarks
131
+ .map((m) =>
132
+ [...m.scales.values()].filter((scale) => {
133
+ // remove the scales where no input channels are defined for this mark
134
+ const channels = Object.entries(CHANNEL_SCALE)
135
+ .filter(([, scaleName]) => scale === scaleName)
136
+ .map(([channel]) => channel);
137
+ return channels.find((channel) => m.options[channel] != null);
138
+ })
139
+ )
140
+ .flat(1)
141
+ )
142
+ );
143
+
144
+ const explicitDomains = $derived(
145
+ new Set(SCALES.filter((scale) => !!initialOpts[scale]?.domain))
146
+ );
147
+
148
+ // one-dimensional plots have different automatic margins and heights
149
+ const isOneDimensional = $derived(explicitScales.has('x') !== explicitScales.has('y'));
150
+
151
+ // construct the plot options from the user-defined options (top-level props) as well
152
+ // as extending them from smart context-aware defaults
153
+ const plotOptions = $derived(
154
+ extendPlotOptions(initialOpts, {
155
+ explicitScales,
156
+ explicitDomains,
157
+ hasProjection: !!initialOpts.projection,
158
+ margins: initialOpts.margins,
159
+ inset: initialOpts.inset
160
+ })
161
+ );
162
+
163
+ // if the plot is showing filled dot marks we're using different defaults
164
+ // for the symbol axis range, so we're passing on this info to the createScales
165
+ // function below
166
+ const hasFilledDotMarks = $derived(
167
+ !!explicitMarks.find((d) => d.type === 'dot' && d.options.fill)
168
+ );
169
+
170
+ // compute preliminary scales with a fixed height, since we don't have
171
+ // height defined at this point, but still need some of the scales
172
+ const preScales: PlotScales = $derived(
173
+ computeScales(plotOptions, width, 400, hasFilledDotMarks, marks, DEFAULTS)
174
+ );
175
+
176
+ const hasProjection = $derived(!!preScales.projection);
177
+
178
+ const plotWidth = $derived(
179
+ (fixedWidth || width) - plotOptions.marginLeft - plotOptions.marginRight
180
+ );
181
+
182
+ // the facet and y domain counts are used for computing the automatic height
183
+ const xFacetCount = $derived(Math.max(1, preScales.fx.domain.length));
184
+ const yFacetCount = $derived(Math.max(1, preScales.fy.domain.length));
185
+ const yDomainCount = $derived(
186
+ isOneDimensional && explicitScales.has('x') ? 1 : preScales.y.domain.length
187
+ );
188
+ // compute the (automatic) height based on various factors:
189
+ // - if the plot used a projection and the projection requires an aspect ratio,
190
+ // we use it, but adjust for the facet counts
191
+ // - if the user defined a domain-aspect ratio, we use the heightFromAspect
192
+ // method to compute the height based on the preliminary x and y scales
193
+ // - for one-dimensional scales using the x scale we set a fixed height
194
+ // - for y band-scales we use the number of items in the y domain
195
+ const height = $derived(
196
+ plotOptions.height === 'auto'
197
+ ? Math.round(
198
+ preScales.projection && preScales.projection.aspectRatio
199
+ ? ((plotWidth * preScales.projection.aspectRatio) / xFacetCount) *
200
+ yFacetCount +
201
+ plotOptions.marginTop +
202
+ plotOptions.marginBottom
203
+ : plotOptions.aspectRatio
204
+ ? heightFromAspect(
205
+ preScales.x,
206
+ preScales.y,
207
+ plotOptions.aspectRatio,
208
+ plotWidth,
209
+ plotOptions.marginTop,
210
+ plotOptions.marginBottom
211
+ )
212
+ : ((isOneDimensional && explicitScales.has('x')) || !explicitMarks.length
213
+ ? yFacetCount * DEFAULTS.bandScaleHeight
214
+ : preScales.y.type === 'band'
215
+ ? yFacetCount * yDomainCount * DEFAULTS.bandScaleHeight
216
+ : preScales.y.type === 'point'
217
+ ? yFacetCount * yDomainCount * DEFAULTS.pointScaleHeight
218
+ : DEFAULTS.height) +
219
+ plotOptions.marginTop +
220
+ plotOptions.marginBottom
221
+ )
222
+ : typeof plotOptions.height === 'function'
223
+ ? plotOptions.height(plotWidth)
224
+ : plotOptions.height
225
+ );
226
+
227
+ const plotHeight = $derived(height - plotOptions.marginTop - plotOptions.marginBottom);
228
+
229
+ // TODO: check if there's still a reason to store and expose the plot body element
230
+ let plotBody: HTMLDivElement | null = $state(null);
231
+
232
+ let facetWidth: number | null = $state(null);
233
+ let facetHeight: number | null = $state(null);
234
+
235
+ let plotState: PlotState = $state(computePlotState());
236
+
237
+ $effect(() => {
238
+ plotState = computePlotState();
239
+ });
240
+
241
+ function computePlotState() {
242
+ // now that we know the actual height and facet dimensions, we can compute
243
+ // the scales used in all the marks
244
+ const scales = computeScales(
245
+ plotOptions,
246
+ facetWidth || width,
247
+ facetHeight || height,
248
+ hasFilledDotMarks,
249
+ marks,
250
+ DEFAULTS
251
+ );
252
+ const colorSymbolRedundant =
253
+ scales.color.uniqueScaleProps?.size === 1 &&
254
+ scales.symbol.uniqueScaleProps?.size === 1 &&
255
+ [...scales.color.uniqueScaleProps?.values()][0] ===
256
+ [...scales.symbol.uniqueScaleProps?.values()][0];
257
+ return {
258
+ options: plotOptions,
259
+ width,
260
+ height,
261
+ facetWidth,
262
+ facetHeight,
263
+ plotHeight,
264
+ plotWidth,
265
+ scales,
266
+ colorSymbolRedundant,
267
+ hasFilledDotMarks,
268
+ body: plotBody,
269
+ css
270
+ };
271
+ }
272
+
273
+ setContext('svelteplot', {
274
+ /**
275
+ * used by the Mark component to register new marks to the plot
276
+ */
277
+ addMark(mark: Mark<GenericMarkOptions>) {
278
+ if (marks.find((m) => m.id === mark.id)) {
279
+ return;
280
+ }
281
+
282
+ marks = [...marks, mark];
283
+ },
284
+ /**
285
+ * used by the Mark component to update marks when its props change
286
+ */
287
+ updateMark(mark: Mark<GenericMarkOptions>) {
288
+ // marks = marks.map((m) => (m.id === mark.id ? mark : m));
289
+ },
290
+ /**
291
+ * used by the Mark component to unregister marks when their
292
+ * respective components get removed from the plot
293
+ */
294
+ removeMark(mark: Mark<GenericMarkOptions>) {
295
+ marks = marks.filter((m) => m.id !== mark.id);
296
+ },
297
+ getPlotState() {
298
+ return plotState;
299
+ },
300
+ getTopLevelFacet() {
301
+ // we need to expose the facet options to allow marks to
302
+ // react to state changes by updating the fx and fy channels
303
+ return facet;
304
+ },
305
+ updateDimensions(w: number, h: number) {
306
+ if (facetWidth !== w) facetWidth = w;
307
+ if (facetHeight !== h) facetHeight = h;
308
+ },
309
+ updatePlotState() {
310
+ plotState = computePlotState();
311
+ }
312
+ });
313
+
314
+ // TODO: perhaps we don't need this anymore
315
+ export function getWidth() {
316
+ return width;
317
+ }
318
+
319
+ function heightFromAspect(
320
+ x: PlotScale,
321
+ y: PlotScale,
322
+ aspectRatio: number,
323
+ plotWidth: number,
324
+ marginTop: number,
325
+ marginBottom: number
326
+ ) {
327
+ const xDomainExtent =
328
+ x.type === 'band' || x.type === 'point'
329
+ ? x.domain.length
330
+ : Math.abs(x.domain[1] - x.domain[0]);
331
+ const yDomainExtent =
332
+ y.type === 'band' || y.type === 'point'
333
+ ? y.domain.length
334
+ : Math.abs(y.domain[1] - y.domain[0]);
335
+ return (
336
+ ((plotWidth / xDomainExtent) * yDomainExtent) / aspectRatio + marginTop + marginBottom
337
+ );
338
+ }
339
+
340
+ function extendPlotOptions(
341
+ initialOpts: Partial<PlotOptions>,
342
+ opts: PlotOptionsParameters
343
+ ): PlotOptions {
344
+ return mergeDeep<PlotOptions>({}, smartDefaultPlotOptions(opts), initialOpts);
345
+ }
346
+
347
+ /**
348
+ * compute smart default options for the plot based on the scales and marks
349
+ */
350
+ function smartDefaultPlotOptions({
351
+ explicitScales,
352
+ explicitDomains,
353
+ hasProjection,
354
+ margins
355
+ }: PlotOptionsParameters): PlotOptions {
356
+ const autoXAxis = explicitScales.has('x') || explicitDomains.has('x');
357
+ const autoYAxis = explicitScales.has('y') || explicitDomains.has('y');
358
+ const isOneDimensional = autoXAxis !== autoYAxis;
359
+ const oneDimX = autoXAxis && !autoYAxis;
360
+ const oneDimY = autoYAxis && !autoXAxis;
361
+ return {
362
+ title: '',
363
+ subtitle: '',
364
+ caption: '',
365
+ height: 'auto',
366
+ // maxWidth: oneDimY ? `${60 * e}px` : undefined,
367
+ marginLeft: hasProjection
368
+ ? 0
369
+ : margins != null
370
+ ? margins
371
+ : Math.max(maxMarginLeft + 1, 1),
372
+ marginRight: hasProjection
373
+ ? 0
374
+ : margins != null
375
+ ? margins
376
+ : oneDimY
377
+ ? 0
378
+ : Math.max(maxMarginRight + 1, 4),
379
+ marginTop: hasProjection
380
+ ? 0
381
+ : margins != null
382
+ ? margins
383
+ : oneDimX
384
+ ? 0
385
+ : Math.max(5, maxMarginTop),
386
+ marginBottom: hasProjection
387
+ ? 0
388
+ : margins != null
389
+ ? margins
390
+ : Math.max(5, maxMarginBottom),
391
+ inset: isOneDimensional ? 10 : DEFAULTS.inset,
392
+ grid: DEFAULTS.grid,
393
+ axes: DEFAULTS.axes,
394
+ frame: DEFAULTS.frame,
395
+ projection: null,
396
+ aspectRatio: null,
397
+ facet: {},
398
+ padding: 0.1,
399
+ x: {
400
+ type: 'auto',
401
+ axis: autoXAxis ? DEFAULTS.axisXAnchor : false,
402
+ labelAnchor: 'auto',
403
+ reverse: false,
404
+ clamp: false,
405
+ nice: false,
406
+ zero: false,
407
+ round: false,
408
+ percent: false,
409
+ align: 0.5,
410
+ tickSpacing: DEFAULTS.xTickSpacing,
411
+ tickFormat: 'auto',
412
+ grid: false
413
+ },
414
+ y: {
415
+ type: 'auto',
416
+ axis: autoYAxis ? DEFAULTS.axisYAnchor : false,
417
+ labelAnchor: 'auto',
418
+ reverse: false,
419
+ clamp: false,
420
+ nice: false,
421
+ zero: false,
422
+ round: false,
423
+ percent: false,
424
+ align: 0.5,
425
+ tickSpacing: DEFAULTS.yTickSpacing,
426
+ tickFormat: 'auto',
427
+ grid: false
428
+ },
429
+ opacity: {
430
+ type: 'linear',
431
+ reverse: false,
432
+ clamp: false,
433
+ nice: false,
434
+ zero: false,
435
+ round: false,
436
+ tickSpacing: 0,
437
+ percent: false,
438
+ padding: 0.1,
439
+ align: 0.5
440
+ },
441
+ r: {
442
+ type: 'sqrt',
443
+ reverse: false,
444
+ clamp: false,
445
+ nice: false,
446
+ zero: true,
447
+ percent: false,
448
+ round: false,
449
+ padding: 0,
450
+ align: 0
451
+ },
452
+ color: { type: 'auto' },
453
+ length: { type: 'linear' },
454
+ symbol: { type: 'ordinal' },
455
+ fx: { type: 'band', axis: 'top' },
456
+ fy: { type: 'band', axis: 'right' },
457
+ locale: DEFAULTS.locale
458
+ };
459
+ }
460
+
461
+ const mapXY = $derived((x: RawValue, y: RawValue) => {
462
+ const [px, py] = projectXY(plotState.scales, x, y);
463
+ return { x: px, y: py };
464
+ });
465
+ </script>
466
+
467
+ <figure
468
+ class="svelteplot {className}"
469
+ bind:clientWidth={width}
470
+ style:max-width={plotOptions.maxWidth}
471
+ data-testid={testid}>
472
+ {#if header}
473
+ <div class="plot-header">
474
+ {#if header}{@render header()}{/if}
475
+ </div>
476
+ {/if}
477
+ <div class="plot-body" bind:this={plotBody}>
478
+ {#if underlay}<div class="plot-underlay">{@render underlay(plotOptions)}</div>{/if}
479
+ <svg
480
+ width={fixedWidth || width}
481
+ {height}
482
+ fill="currentColor"
483
+ viewBox="0 0 {width} {height}"
484
+ font-family="system-ui, sans-serif">
485
+ {@render facetAxes?.()}
486
+ <FacetGrid marks={explicitMarks}>
487
+ {#if children}
488
+ {@render children({
489
+ width,
490
+ height,
491
+ options: plotOptions,
492
+ scales: plotState.scales,
493
+ mapXY,
494
+ hasProjection,
495
+ hasExplicitAxisX,
496
+ hasExplicitAxisY,
497
+ hasExplicitGridX,
498
+ hasExplicitGridY
499
+ })}
500
+ {/if}
501
+ </FacetGrid>
502
+ </svg>
503
+ {#if overlay}<div class="plot-overlay">{@render overlay()}</div>{/if}
504
+ </div>
505
+ {#if footer}
506
+ <figcaption class="plot-footer">
507
+ {#if footer}{@render footer()}{/if}
508
+ </figcaption>
509
+ {/if}
510
+ </figure>
511
+
512
+ <style>
513
+ :root {
514
+ --plot-bg: white;
515
+ --plot-fg: currentColor;
516
+ }
517
+
518
+ figure {
519
+ margin: 0;
520
+ padding: 0;
521
+ }
522
+
523
+ .plot-body {
524
+ position: relative;
525
+ }
526
+
527
+ .plot-overlay,
528
+ .plot-underlay {
529
+ position: absolute;
530
+ top: 0;
531
+ left: 0;
532
+ right: 0;
533
+ bottom: 0;
534
+ pointer-events: none;
535
+ }
536
+
537
+ .plot-underlay {
538
+ z-index: -1;
539
+ }
540
+
541
+ .plot-header {
542
+ margin-top: 1rem;
543
+ display: flex;
544
+ flex-direction: column;
545
+ row-gap: 0.35rem;
546
+ }
547
+
548
+ .plot-header :global(h2),
549
+ .plot-header :global(h3) {
550
+ margin: 0 !important;
551
+ padding: 0 !important;
552
+ border: 0 !important;
553
+ }
554
+
555
+ .plot-header :global(h3) {
556
+ font-weight: 500;
557
+ }
558
+
559
+ .plot-footer {
560
+ margin-bottom: 2rem;
561
+ }
562
+
563
+ .plot-footer :global(> div) {
564
+ font-size: 12px;
565
+ font-style: italic;
566
+ opacity: 0.7;
567
+ }
568
+ </style>
@@ -0,0 +1,14 @@
1
+ import type { PlotOptions } from '../types.js';
2
+ /**
3
+ * The core Plot component handles the main layout of the plot but it does not
4
+ * include smart automatic scales and marks. It is to be used in cases where
5
+ * you want to reduce the footprint of the plot to the bare minimum.
6
+ *
7
+ * Keep in mind that you will have to create your own scales if you're using
8
+ * this component.
9
+ */
10
+ declare const Plot: import("svelte").Component<Partial<PlotOptions>, {
11
+ getWidth: () => number;
12
+ }, "">;
13
+ type Plot = ReturnType<typeof Plot>;
14
+ export default Plot;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2020-2023 Observable, Inc.
4
+ *
5
+ * Permission to use, copy, modify, and/or distribute this software for any purpose
6
+ * with or without fee is hereby granted, provided that the above copyright notice
7
+ * and this permission notice appear in all copies.
8
+ */
9
+ export declare function arrowPath(x1: number, y1: number, x2: number, y2: number, insetStart: number, insetEnd: number, headAngle: number, headLength: number, bend: number, strokeWidth: number, sweep: SweepFunc): string | null;
10
+ export declare function constant<T>(x: T): () => T;
11
+ export type SweepFunc = (x1: number, y1: number, x2: number, y2: number) => number;
12
+ export declare function keyword(input: string, name: string, allowed: string[]): string;
13
+ export type SweepOption = 1 | 0 | -1 | '+x' | '-x' | '+y' | '-y' | SweepFunc;
14
+ export declare function maybeSweep(sweep?: SweepOption): SweepFunc | undefined;