svelteplot 0.0.1-alpha.8 → 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.
Files changed (251) hide show
  1. package/LICENSE.md +5 -0
  2. package/README.md +3 -36
  3. package/dist/Mark.svelte +292 -0
  4. package/dist/Mark.svelte.d.ts +22 -0
  5. package/dist/Plot.svelte +148 -153
  6. package/dist/Plot.svelte.d.ts +15 -15
  7. package/dist/constants.d.ts +14 -0
  8. package/dist/constants.js +109 -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 +567 -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 +53 -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 +17 -0
  63. package/dist/helpers/resolve.js +152 -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 +309 -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 +81 -0
  87. package/dist/marks/BarX.svelte.d.ts +4 -0
  88. package/dist/marks/BarY.svelte +95 -0
  89. package/dist/marks/BarY.svelte.d.ts +4 -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 +32 -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 +173 -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 +185 -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 +213 -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 +164 -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 +64 -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 +0 -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 +13 -0
  209. package/dist/transforms/recordize.js +75 -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 +61 -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 +22 -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 +79 -40
  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,567 @@
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
+ ...initialOpts
45
+ }: Partial<PlotOptions> = $props();
46
+
47
+ // automatic margins can be applied by the marks, registered
48
+ // with their respective unique identifier as keys
49
+ let autoMarginLeft = writable(new SvelteMap<string, number>());
50
+ let autoMarginRight = writable(new SvelteMap<string, number>());
51
+ let autoMarginBottom = writable(new SvelteMap<string, number>());
52
+ let autoMarginTop = writable(new SvelteMap<string, number>());
53
+
54
+ // autoMargin stores are shared via context
55
+ setContext('svelteplot/autoMargins', {
56
+ autoMarginLeft,
57
+ autoMarginRight,
58
+ autoMarginBottom,
59
+ autoMarginTop
60
+ });
61
+
62
+ // compute maximum margins to either side of the plot from the
63
+ // automatic margins defined by marks
64
+ const maxMarginLeft = $derived(Math.max(...$autoMarginLeft.values()));
65
+ const maxMarginRight = $derived(Math.max(...$autoMarginRight.values()));
66
+ const maxMarginBottom = $derived(Math.max(...$autoMarginBottom.values()));
67
+ const maxMarginTop = $derived(Math.max(...$autoMarginTop.values()));
68
+
69
+ // default settings in the plot and marks can be overwritten by
70
+ // defining the svelteplot/defaults context outside of Plot
71
+ const DEFAULTS: PlotDefaults = {
72
+ axisXAnchor: 'bottom',
73
+ axisYAnchor: 'left',
74
+ xTickSpacing: 80,
75
+ yTickSpacing: 50,
76
+ height: 350,
77
+ initialWidth: 500,
78
+ inset: 0,
79
+ colorScheme: 'turbo',
80
+ dotRadius: 3,
81
+ frame: false,
82
+ axes: true,
83
+ grid: false,
84
+ categoricalColorScheme: 'observable10',
85
+ pointScaleHeight: 18,
86
+ bandScaleHeight: 30,
87
+ locale: 'en-US',
88
+ numberFormat: {
89
+ style: 'decimal',
90
+ notation: 'compact',
91
+ compactDisplay: 'short'
92
+ },
93
+ markerDotRadius: 3,
94
+ ...getContext<Partial<PlotDefaults>>('svelteplot/defaults')
95
+ };
96
+
97
+ let width = $state(DEFAULTS.initialWidth);
98
+
99
+ setContext('svelteplot/_defaults', DEFAULTS);
100
+
101
+ // information that influences the default plot options
102
+ type PlotOptionsParameters = {
103
+ explicitScales: Set<ScaleName>;
104
+ explicitDomains: Set<ScaleName>;
105
+ hasProjection: boolean;
106
+ margins?: number;
107
+ inset?: number;
108
+ };
109
+
110
+ let scaleCounter = $state(0);
111
+
112
+ /**
113
+ * the marks used in the plot
114
+ */
115
+ let marks = $state.raw<Mark<GenericMarkOptions>[]>([]);
116
+
117
+ /**
118
+ *
119
+ */
120
+ const explicitMarks = $derived(marks.filter((m) => !m.options.automatic));
121
+
122
+ // knowing if the plot includes explicit grids and marks is useful for
123
+ // including the automatic/implicit axes/grids
124
+ const hasExplicitAxisX = $derived(!!explicitMarks.find((m) => m.type === 'axisX'));
125
+ const hasExplicitAxisY = $derived(!!explicitMarks.find((m) => m.type === 'axisY'));
126
+ const hasExplicitGridX = $derived(!!explicitMarks.find((m) => m.type === 'gridX'));
127
+ const hasExplicitGridY = $derived(!!explicitMarks.find((m) => m.type === 'gridY'));
128
+
129
+ const explicitScales = $derived(
130
+ new Set(
131
+ explicitMarks
132
+ .map((m) =>
133
+ [...m.scales.values()].filter((scale) => {
134
+ // remove the scales where no input channels are defined for this mark
135
+ const channels = Object.entries(CHANNEL_SCALE)
136
+ .filter(([, scaleName]) => scale === scaleName)
137
+ .map(([channel]) => channel);
138
+ return channels.find((channel) => m.options[channel] != null);
139
+ })
140
+ )
141
+ .flat(1)
142
+ )
143
+ );
144
+
145
+ const explicitDomains = $derived(
146
+ new Set(SCALES.filter((scale) => !!initialOpts[scale]?.domain))
147
+ );
148
+
149
+ // one-dimensional plots have different automatic margins and heights
150
+ const isOneDimensional = $derived(explicitScales.has('x') !== explicitScales.has('y'));
151
+
152
+ // construct the plot options from the user-defined options (top-level props) as well
153
+ // as extending them from smart context-aware defaults
154
+ const plotOptions = $derived(
155
+ extendPlotOptions(initialOpts, {
156
+ explicitScales,
157
+ explicitDomains,
158
+ hasProjection: !!initialOpts.projection,
159
+ margins: initialOpts.margins,
160
+ inset: initialOpts.inset
161
+ })
162
+ );
163
+
164
+ // if the plot is showing filled dot marks we're using different defaults
165
+ // for the symbol axis range, so we're passing on this info to the createScales
166
+ // function below
167
+ const hasFilledDotMarks = $derived(
168
+ !!explicitMarks.find((d) => d.type === 'dot' && d.options.fill)
169
+ );
170
+
171
+ // compute preliminary scales with a fixed height, since we don't have
172
+ // height defined at this point, but still need some of the scales
173
+ const preScales: PlotScales = $derived(
174
+ computeScales(plotOptions, width, 400, hasFilledDotMarks, marks, DEFAULTS)
175
+ );
176
+
177
+ const hasProjection = $derived(!!preScales.projection);
178
+
179
+ const plotWidth = $derived(width - plotOptions.marginLeft - plotOptions.marginRight);
180
+
181
+ // the facet and y domain counts are used for computing the automatic height
182
+ const xFacetCount = $derived(Math.max(1, preScales.fx.domain.length));
183
+ const yFacetCount = $derived(Math.max(1, preScales.fy.domain.length));
184
+ const yDomainCount = $derived(
185
+ isOneDimensional && explicitScales.has('x') ? 1 : preScales.y.domain.length
186
+ );
187
+ // compute the (automatic) height based on various factors:
188
+ // - if the plot used a projection and the projection requires an aspect ratio,
189
+ // we use it, but adjust for the facet counts
190
+ // - if the user defined a domain-aspect ratio, we use the heightFromAspect
191
+ // method to compute the height based on the preliminary x and y scales
192
+ // - for one-dimensional scales using the x scale we set a fixed height
193
+ // - for y band-scales we use the number of items in the y domain
194
+ const height = $derived(
195
+ plotOptions.height === 'auto'
196
+ ? Math.round(
197
+ preScales.projection && preScales.projection.aspectRatio
198
+ ? ((plotWidth * preScales.projection.aspectRatio) / xFacetCount) *
199
+ yFacetCount +
200
+ plotOptions.marginTop +
201
+ plotOptions.marginBottom
202
+ : plotOptions.aspectRatio
203
+ ? heightFromAspect(
204
+ preScales.x,
205
+ preScales.y,
206
+ plotOptions.aspectRatio,
207
+ plotWidth,
208
+ plotOptions.marginTop,
209
+ plotOptions.marginBottom
210
+ )
211
+ : ((isOneDimensional && explicitScales.has('x')) || !explicitMarks.length
212
+ ? yFacetCount * DEFAULTS.bandScaleHeight
213
+ : preScales.y.type === 'band'
214
+ ? yFacetCount * yDomainCount * DEFAULTS.bandScaleHeight
215
+ : preScales.y.type === 'point'
216
+ ? yFacetCount * yDomainCount * DEFAULTS.pointScaleHeight
217
+ : DEFAULTS.height) +
218
+ plotOptions.marginTop +
219
+ plotOptions.marginBottom
220
+ )
221
+ : typeof plotOptions.height === 'function'
222
+ ? plotOptions.height(plotWidth)
223
+ : plotOptions.height
224
+ );
225
+
226
+ const plotHeight = $derived(height - plotOptions.marginTop - plotOptions.marginBottom);
227
+
228
+ // TODO: check if there's still a reason to store and expose the plot body element
229
+ let plotBody: HTMLDivElement | null = $state(null);
230
+
231
+ let facetWidth: number | null = $state(null);
232
+ let facetHeight: number | null = $state(null);
233
+
234
+ let plotState: PlotState = $state(computePlotState());
235
+
236
+ $effect(() => {
237
+ plotState = computePlotState();
238
+ });
239
+
240
+ function computePlotState() {
241
+ // now that we know the actual height and facet dimensions, we can compute
242
+ // the scales used in all the marks
243
+ const scales = computeScales(
244
+ plotOptions,
245
+ facetWidth || width,
246
+ facetHeight || height,
247
+ hasFilledDotMarks,
248
+ marks,
249
+ DEFAULTS
250
+ );
251
+ const colorSymbolRedundant =
252
+ scales.color.uniqueScaleProps?.size === 1 &&
253
+ scales.symbol.uniqueScaleProps?.size === 1 &&
254
+ [...scales.color.uniqueScaleProps?.values()][0] ===
255
+ [...scales.symbol.uniqueScaleProps?.values()][0];
256
+ return {
257
+ options: plotOptions,
258
+ width,
259
+ height,
260
+ facetWidth,
261
+ facetHeight,
262
+ plotHeight,
263
+ plotWidth,
264
+ scales,
265
+ colorSymbolRedundant,
266
+ hasFilledDotMarks,
267
+ body: plotBody,
268
+ css
269
+ };
270
+ }
271
+
272
+ setContext('svelteplot', {
273
+ /**
274
+ * used by the Mark component to register new marks to the plot
275
+ */
276
+ addMark(mark: Mark<GenericMarkOptions>) {
277
+ if (marks.find((m) => m.id === mark.id)) {
278
+ return;
279
+ }
280
+
281
+ marks = [...marks, mark];
282
+ },
283
+ /**
284
+ * used by the Mark component to update marks when its props change
285
+ */
286
+ updateMark(mark: Mark<GenericMarkOptions>) {
287
+ // marks = marks.map((m) => (m.id === mark.id ? mark : m));
288
+ },
289
+ /**
290
+ * used by the Mark component to unregister marks when their
291
+ * respective components get removed from the plot
292
+ */
293
+ removeMark(mark: Mark<GenericMarkOptions>) {
294
+ marks = marks.filter((m) => m.id !== mark.id);
295
+ },
296
+ getPlotState() {
297
+ return plotState;
298
+ },
299
+ getTopLevelFacet() {
300
+ // we need to expose the facet options to allow marks to
301
+ // react to state changes by updating the fx and fy channels
302
+ return facet;
303
+ },
304
+ updateDimensions(w: number, h: number) {
305
+ if (facetWidth !== w) facetWidth = w;
306
+ if (facetHeight !== h) facetHeight = h;
307
+ },
308
+ updatePlotState() {
309
+ plotState = computePlotState();
310
+ }
311
+ });
312
+
313
+ // TODO: perhaps we don't need this anymore
314
+ export function getWidth() {
315
+ return width;
316
+ }
317
+
318
+ function heightFromAspect(
319
+ x: PlotScale,
320
+ y: PlotScale,
321
+ aspectRatio: number,
322
+ plotWidth: number,
323
+ marginTop: number,
324
+ marginBottom: number
325
+ ) {
326
+ const xDomainExtent =
327
+ x.type === 'band' || x.type === 'point'
328
+ ? x.domain.length
329
+ : Math.abs(x.domain[1] - x.domain[0]);
330
+ const yDomainExtent =
331
+ y.type === 'band' || y.type === 'point'
332
+ ? y.domain.length
333
+ : Math.abs(y.domain[1] - y.domain[0]);
334
+ return (
335
+ ((plotWidth / xDomainExtent) * yDomainExtent) / aspectRatio + marginTop + marginBottom
336
+ );
337
+ }
338
+
339
+ function extendPlotOptions(
340
+ initialOpts: Partial<PlotOptions>,
341
+ opts: PlotOptionsParameters
342
+ ): PlotOptions {
343
+ return mergeDeep<PlotOptions>({}, smartDefaultPlotOptions(opts), initialOpts);
344
+ }
345
+
346
+ /**
347
+ * compute smart default options for the plot based on the scales and marks
348
+ */
349
+ function smartDefaultPlotOptions({
350
+ explicitScales,
351
+ explicitDomains,
352
+ hasProjection,
353
+ margins
354
+ }: PlotOptionsParameters): PlotOptions {
355
+ const autoXAxis = explicitScales.has('x') || explicitDomains.has('x');
356
+ const autoYAxis = explicitScales.has('y') || explicitDomains.has('y');
357
+ const isOneDimensional = autoXAxis !== autoYAxis;
358
+ const oneDimX = autoXAxis && !autoYAxis;
359
+ const oneDimY = autoYAxis && !autoXAxis;
360
+ return {
361
+ title: '',
362
+ subtitle: '',
363
+ caption: '',
364
+ height: 'auto',
365
+ // maxWidth: oneDimY ? `${60 * e}px` : undefined,
366
+ marginLeft: hasProjection
367
+ ? 0
368
+ : margins != null
369
+ ? margins
370
+ : Math.max(maxMarginLeft + 1, 1),
371
+ marginRight: hasProjection
372
+ ? 0
373
+ : margins != null
374
+ ? margins
375
+ : oneDimY
376
+ ? 0
377
+ : Math.max(maxMarginRight + 1, 4),
378
+ marginTop: hasProjection
379
+ ? 0
380
+ : margins != null
381
+ ? margins
382
+ : oneDimX
383
+ ? 0
384
+ : Math.max(5, maxMarginTop),
385
+ marginBottom: hasProjection
386
+ ? 0
387
+ : margins != null
388
+ ? margins
389
+ : Math.max(5, maxMarginBottom),
390
+ inset: isOneDimensional ? 10 : DEFAULTS.inset,
391
+ grid: DEFAULTS.grid,
392
+ axes: DEFAULTS.axes,
393
+ frame: DEFAULTS.frame,
394
+ projection: null,
395
+ aspectRatio: null,
396
+ facet: {},
397
+ padding: 0.1,
398
+ x: {
399
+ type: 'auto',
400
+ axis: autoXAxis ? DEFAULTS.axisXAnchor : false,
401
+ labelAnchor: 'auto',
402
+ reverse: false,
403
+ clamp: false,
404
+ nice: false,
405
+ zero: false,
406
+ round: false,
407
+ percent: false,
408
+ align: 0.5,
409
+ tickSpacing: DEFAULTS.xTickSpacing,
410
+ tickFormat: 'auto',
411
+ grid: false
412
+ },
413
+ y: {
414
+ type: 'auto',
415
+ axis: autoYAxis ? DEFAULTS.axisYAnchor : false,
416
+ labelAnchor: 'auto',
417
+ reverse: false,
418
+ clamp: false,
419
+ nice: false,
420
+ zero: false,
421
+ round: false,
422
+ percent: false,
423
+ align: 0.5,
424
+ tickSpacing: DEFAULTS.yTickSpacing,
425
+ tickFormat: 'auto',
426
+ grid: false
427
+ },
428
+ opacity: {
429
+ type: 'linear',
430
+ reverse: false,
431
+ clamp: false,
432
+ nice: false,
433
+ zero: false,
434
+ round: false,
435
+ tickSpacing: 0,
436
+ percent: false,
437
+ padding: 0.1,
438
+ align: 0.5
439
+ },
440
+ r: {
441
+ type: 'sqrt',
442
+ reverse: false,
443
+ clamp: false,
444
+ nice: false,
445
+ zero: true,
446
+ percent: false,
447
+ round: false,
448
+ padding: 0,
449
+ align: 0
450
+ },
451
+ color: { type: 'auto' },
452
+ length: { type: 'linear' },
453
+ symbol: { type: 'ordinal' },
454
+ fx: { type: 'band', axis: 'top' },
455
+ fy: { type: 'band', axis: 'right' },
456
+ locale: DEFAULTS.locale
457
+ };
458
+ }
459
+
460
+ const mapXY = $derived((x: RawValue, y: RawValue) => {
461
+ const [px, py] = projectXY(plotState.scales, x, y);
462
+ return { x: px, y: py };
463
+ });
464
+ </script>
465
+
466
+ <figure
467
+ class="svelteplot {className}"
468
+ bind:clientWidth={width}
469
+ style:max-width={plotOptions.maxWidth}
470
+ data-testid={testid}>
471
+ {#if header}
472
+ <div class="plot-header">
473
+ {#if header}{@render header()}{/if}
474
+ </div>
475
+ {/if}
476
+ <div class="plot-body" bind:this={plotBody}>
477
+ {#if underlay}<div class="plot-underlay">{@render underlay(plotOptions)}</div>{/if}
478
+ <svg
479
+ {width}
480
+ {height}
481
+ fill="currentColor"
482
+ viewBox="0 0 {width} {height}"
483
+ font-family="system-ui, sans-serif">
484
+ {@render facetAxes?.()}
485
+ <FacetGrid marks={explicitMarks}>
486
+ {#if children}
487
+ {@render children({
488
+ width,
489
+ height,
490
+ options: plotOptions,
491
+ scales: plotState.scales,
492
+ mapXY,
493
+ hasProjection,
494
+ hasExplicitAxisX,
495
+ hasExplicitAxisY,
496
+ hasExplicitGridX,
497
+ hasExplicitGridY
498
+ })}
499
+ {/if}
500
+ </FacetGrid>
501
+ </svg>
502
+ {#if overlay}<div class="plot-overlay">{@render overlay()}</div>{/if}
503
+ </div>
504
+ {#if footer}
505
+ <figcaption class="plot-footer">
506
+ {#if footer}{@render footer()}{/if}
507
+ </figcaption>
508
+ {/if}
509
+ </figure>
510
+
511
+ <style>
512
+ :root {
513
+ --plot-bg: white;
514
+ --plot-fg: currentColor;
515
+ }
516
+
517
+ figure {
518
+ margin: 0;
519
+ padding: 0;
520
+ }
521
+
522
+ .plot-body {
523
+ position: relative;
524
+ }
525
+
526
+ .plot-overlay,
527
+ .plot-underlay {
528
+ position: absolute;
529
+ top: 0;
530
+ left: 0;
531
+ right: 0;
532
+ bottom: 0;
533
+ pointer-events: none;
534
+ }
535
+
536
+ .plot-underlay {
537
+ z-index: -1;
538
+ }
539
+
540
+ .plot-header {
541
+ margin-top: 1rem;
542
+ display: flex;
543
+ flex-direction: column;
544
+ row-gap: 0.35rem;
545
+ }
546
+
547
+ .plot-header :global(h2),
548
+ .plot-header :global(h3) {
549
+ margin: 0 !important;
550
+ padding: 0 !important;
551
+ border: 0 !important;
552
+ }
553
+
554
+ .plot-header :global(h3) {
555
+ font-weight: 500;
556
+ }
557
+
558
+ .plot-footer {
559
+ margin-bottom: 2rem;
560
+ }
561
+
562
+ .plot-footer :global(> div) {
563
+ font-size: 12px;
564
+ font-style: italic;
565
+ opacity: 0.7;
566
+ }
567
+ </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;