@fundar/data-chart-telling 0.0.25 → 0.0.27

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 (198) hide show
  1. package/dist/charts/BaseChart.svelte +18 -10
  2. package/dist/charts/BaseChart.svelte.d.ts +4 -2
  3. package/dist/charts/bar/Chart.svelte +2 -0
  4. package/dist/charts/heatmap/Chart.svelte +5 -3
  5. package/dist/charts/heatmap/Chart.svelte.d.ts +1 -2
  6. package/dist/charts/line/Chart.svelte +2 -0
  7. package/dist/charts/pyramid/Chart.svelte +5 -3
  8. package/dist/charts/pyramid/Chart.svelte.d.ts +1 -2
  9. package/dist/charts/scatter/Chart.svelte +95 -0
  10. package/dist/charts/scatter/Chart.svelte.d.ts +28 -0
  11. package/dist/configuration/config.svelte.js +28 -0
  12. package/dist/configuration/themes/dark.js +4 -0
  13. package/dist/configuration/themes/index.d.ts +112 -0
  14. package/dist/index.d.ts +26 -16
  15. package/dist/index.js +11 -3
  16. package/dist/layout/coordinates/CoordinatesLayout.svelte +93 -0
  17. package/dist/layout/{plot/RuleLayout.svelte.d.ts → coordinates/CoordinatesLayout.svelte.d.ts} +13 -16
  18. package/dist/layout/coordinates/margins.d.ts +16 -0
  19. package/dist/layout/coordinates/margins.js +11 -0
  20. package/dist/{plots/geo → layout/coordinates}/projections/argentina.d.ts +1 -1
  21. package/dist/layout/{geo → coordinates}/resolveProjection.d.ts +1 -1
  22. package/dist/layout/coordinates/resolveProjection.js +24 -0
  23. package/dist/{plots/geo → layout/coordinates}/zoom.svelte.d.ts +1 -1
  24. package/dist/layout/facet/FacetIndicator.svelte +31 -0
  25. package/dist/layout/facet/FacetIndicator.svelte.d.ts +8 -0
  26. package/dist/layout/facet/FacetLayout.svelte +249 -24
  27. package/dist/layout/facet/FacetLayout.svelte.d.ts +7 -1
  28. package/dist/layout/geometry/GeometryLayout.svelte +231 -0
  29. package/dist/layout/geometry/GeometryLayout.svelte.d.ts +62 -0
  30. package/dist/layout/legend/ContinuousSection.svelte +1 -1
  31. package/dist/layout/legend/ContinuousSection.svelte.d.ts +1 -1
  32. package/dist/layout/legend/DiscreteSection.svelte +1 -1
  33. package/dist/layout/legend/DiscreteSection.svelte.d.ts +1 -1
  34. package/dist/layout/legend/LegendLayout.svelte +1 -1
  35. package/dist/layout/legend/LegendLayout.svelte.d.ts +1 -1
  36. package/dist/layout/legend/interaction.svelte.d.ts +9 -1
  37. package/dist/layout/legend/interaction.svelte.js +9 -1
  38. package/dist/layout/plot/BasePlotLayout.svelte +142 -155
  39. package/dist/layout/plot/BasePlotLayout.svelte.d.ts +61 -51
  40. package/dist/layout/plot/margins.d.ts +0 -16
  41. package/dist/layout/plot/margins.js +0 -11
  42. package/dist/layout/{plot/AxisLayout.svelte → scales/ScalesLayout.svelte} +23 -16
  43. package/dist/layout/{plot/AxisLayout.svelte.d.ts → scales/ScalesLayout.svelte.d.ts} +4 -5
  44. package/dist/layout/scales/buildScale.d.ts +8 -0
  45. package/dist/layout/scales/buildScale.js +43 -0
  46. package/dist/layout/styles/StylesLayout.svelte +75 -0
  47. package/dist/layout/styles/StylesLayout.svelte.d.ts +15 -0
  48. package/dist/{plots/geo → layout/styles}/TileLayer.svelte +2 -2
  49. package/dist/{plots/geo → layout/styles}/TileLayer.svelte.d.ts +1 -1
  50. package/dist/layout/timeline/Timeline.svelte +1 -1
  51. package/dist/layout/timeline/Timeline.svelte.d.ts +1 -1
  52. package/dist/layout/timeline/TimelineLayout.svelte +1 -1
  53. package/dist/layout/timeline/TimelineLayout.svelte.d.ts +1 -1
  54. package/dist/layout/tooltip/Tooltip.svelte +16 -20
  55. package/dist/layout/tooltip/Tooltip.svelte.d.ts +5 -0
  56. package/dist/layout/tooltip/TooltipLayout.svelte +7 -1
  57. package/dist/layout/tooltip/TooltipLayout.svelte.d.ts +4 -0
  58. package/dist/layout/tooltip/controller.svelte.d.ts +4 -5
  59. package/dist/layout/tooltip/controller.svelte.js +42 -16
  60. package/dist/layout/tooltip/resolveTooltipPlacement.d.ts +24 -0
  61. package/dist/layout/tooltip/resolveTooltipPlacement.js +49 -0
  62. package/dist/layout/tooltip/utils.d.ts +27 -19
  63. package/dist/layout/tooltip/utils.js +16 -15
  64. package/dist/markers/BarMarker.svelte +92 -0
  65. package/dist/markers/BarMarker.svelte.d.ts +7 -0
  66. package/dist/markers/CellMarker.svelte +21 -0
  67. package/dist/markers/CellMarker.svelte.d.ts +7 -0
  68. package/dist/markers/ContourMarker.svelte +28 -0
  69. package/dist/markers/ContourMarker.svelte.d.ts +7 -0
  70. package/dist/markers/DeltaMarker.svelte +32 -39
  71. package/dist/markers/DeltaMarker.svelte.d.ts +4 -5
  72. package/dist/markers/DotMarker.svelte +35 -6
  73. package/dist/markers/DotMarker.svelte.d.ts +11 -2
  74. package/dist/markers/GeoFeaturesMarker.svelte +19 -0
  75. package/dist/markers/GeoFeaturesMarker.svelte.d.ts +7 -0
  76. package/dist/markers/GeoHoverMarker.svelte +25 -0
  77. package/dist/markers/GeoHoverMarker.svelte.d.ts +9 -0
  78. package/dist/markers/GraticuleMarker.svelte +18 -0
  79. package/dist/markers/GraticuleMarker.svelte.d.ts +7 -0
  80. package/dist/markers/HoverMarker.svelte +34 -35
  81. package/dist/markers/HoverMarker.svelte.d.ts +15 -9
  82. package/dist/markers/LineMarker.svelte +19 -0
  83. package/dist/markers/LineMarker.svelte.d.ts +7 -0
  84. package/dist/markers/LinkMarker.svelte +42 -0
  85. package/dist/markers/LinkMarker.svelte.d.ts +7 -0
  86. package/dist/markers/RuleMarker.svelte +24 -0
  87. package/dist/markers/RuleMarker.svelte.d.ts +10 -0
  88. package/dist/markers/SphereMarker.svelte +15 -0
  89. package/dist/markers/SphereMarker.svelte.d.ts +7 -0
  90. package/dist/markers/TextMarker.svelte +1 -1
  91. package/dist/markers/TextMarker.svelte.d.ts +1 -1
  92. package/dist/markers/VectorMarker.svelte +20 -0
  93. package/dist/markers/VectorMarker.svelte.d.ts +7 -0
  94. package/dist/markers/inset/InsetMarker.svelte +38 -45
  95. package/dist/markers/inset/InsetMarker.svelte.d.ts +6 -2
  96. package/dist/plots/bar/Plot.svelte +96 -87
  97. package/dist/plots/bar/Plot.svelte.d.ts +4 -5
  98. package/dist/plots/bar/ValueLabels.svelte +70 -24
  99. package/dist/plots/bar/ValueLabels.svelte.d.ts +11 -2
  100. package/dist/plots/bar/buildBarMarkers.d.ts +30 -0
  101. package/dist/plots/bar/buildBarMarkers.js +100 -0
  102. package/dist/plots/bar/layout.svelte.d.ts +1 -2
  103. package/dist/plots/bar/layout.svelte.js +1 -1
  104. package/dist/plots/geo/Plot.svelte +113 -387
  105. package/dist/plots/geo/Plot.svelte.d.ts +5 -4
  106. package/dist/plots/geo/buildGeoMarkers.d.ts +33 -0
  107. package/dist/plots/geo/buildGeoMarkers.js +47 -0
  108. package/dist/plots/heatmap/Plot.svelte +27 -52
  109. package/dist/plots/heatmap/Plot.svelte.d.ts +4 -5
  110. package/dist/plots/heatmap/ValueLabels.svelte +5 -5
  111. package/dist/plots/heatmap/ValueLabels.svelte.d.ts +3 -3
  112. package/dist/plots/heatmap/buildCellMarkers.d.ts +21 -0
  113. package/dist/plots/heatmap/buildCellMarkers.js +25 -0
  114. package/dist/plots/line/Plot.svelte +73 -141
  115. package/dist/plots/line/Plot.svelte.d.ts +4 -4
  116. package/dist/plots/line/ValueLabels.svelte +84 -85
  117. package/dist/plots/line/ValueLabels.svelte.d.ts +10 -1
  118. package/dist/plots/line/buildLineMarkers.d.ts +15 -0
  119. package/dist/plots/line/buildLineMarkers.js +57 -0
  120. package/dist/plots/pyramid/Plot.svelte +80 -121
  121. package/dist/plots/pyramid/Plot.svelte.d.ts +4 -5
  122. package/dist/plots/pyramid/ValueLabels.svelte +71 -25
  123. package/dist/plots/pyramid/ValueLabels.svelte.d.ts +11 -2
  124. package/dist/plots/pyramid/buildPyramidBarMarkers.d.ts +19 -0
  125. package/dist/plots/pyramid/buildPyramidBarMarkers.js +32 -0
  126. package/dist/plots/scatter/Plot.svelte +242 -0
  127. package/dist/{layout/plot/GridLayout.svelte.d.ts → plots/scatter/Plot.svelte.d.ts} +9 -7
  128. package/dist/plots/scatter/ValueLabels.svelte +149 -0
  129. package/dist/plots/{bar/BarSegments.svelte.d.ts → scatter/ValueLabels.svelte.d.ts} +17 -15
  130. package/dist/plots/scatter/buildScatterMarkers.d.ts +11 -0
  131. package/dist/plots/scatter/buildScatterMarkers.js +37 -0
  132. package/dist/plots/scatter/resolveRadiusPaddedDomain.d.ts +10 -0
  133. package/dist/plots/scatter/resolveRadiusPaddedDomain.js +23 -0
  134. package/dist/plots/utils/declutter.d.ts +55 -37
  135. package/dist/plots/utils/declutter.js +79 -64
  136. package/dist/plots/utils/geoAccessors.d.ts +1 -1
  137. package/dist/plots/utils/geoAccessors.js +1 -1
  138. package/dist/plots/utils/labelOverflow.svelte.d.ts +51 -0
  139. package/dist/plots/utils/labelOverflow.svelte.js +116 -0
  140. package/dist/plots/utils/legendDisabled.d.ts +1 -1
  141. package/dist/plots/utils/segments.d.ts +17 -10
  142. package/dist/plots/utils/segments.js +26 -16
  143. package/dist/types/charts/common.d.ts +3 -50
  144. package/dist/types/charts/props.d.ts +8 -8
  145. package/dist/types/configuration/styling.d.ts +26 -2
  146. package/dist/types/{plots/scales/geo.d.ts → layout/coordinates.d.ts} +33 -1
  147. package/dist/types/layout/facet.d.ts +41 -0
  148. package/dist/types/layout/geometry.d.ts +17 -0
  149. package/dist/types/layout/legend.d.ts +65 -1
  150. package/dist/types/{plots/axis.d.ts → layout/scales.d.ts} +11 -0
  151. package/dist/types/layout/styles.d.ts +115 -0
  152. package/dist/types/layout/timeline.d.ts +32 -0
  153. package/dist/types/layout/tooltip.d.ts +20 -1
  154. package/dist/types/markers/all.d.ts +11 -0
  155. package/dist/types/markers/all.js +1 -0
  156. package/dist/types/markers/base.d.ts +45 -0
  157. package/dist/types/markers/base.js +1 -0
  158. package/dist/types/markers/common.d.ts +64 -16
  159. package/dist/types/markers/geo.d.ts +75 -100
  160. package/dist/types/markers/line.d.ts +34 -0
  161. package/dist/types/markers/line.js +1 -0
  162. package/dist/types/markers/props.d.ts +1 -1
  163. package/dist/types/plots/data/common.d.ts +1 -1
  164. package/dist/types/plots/data/scatter.d.ts +13 -0
  165. package/dist/types/plots/data/scatter.js +1 -0
  166. package/dist/types/plots/props.d.ts +46 -74
  167. package/dist/types/plots/segments/common.d.ts +6 -12
  168. package/dist/types/plots/segments/config.d.ts +1 -1
  169. package/dist/types/plots/styling.d.ts +10 -0
  170. package/dist/{plots/utils → utils}/delta.d.ts +2 -2
  171. package/dist/{plots/utils → utils}/delta.js +1 -1
  172. package/dist/utils/edgeAwareAnchor.d.ts +37 -0
  173. package/dist/utils/edgeAwareAnchor.js +65 -0
  174. package/dist/utils/grouping.d.ts +1 -1
  175. package/dist/utils/interpolate.d.ts +2 -2
  176. package/package.json +3 -1
  177. package/dist/layout/geo/GeoLayout.svelte +0 -51
  178. package/dist/layout/geo/GeoLayout.svelte.d.ts +0 -24
  179. package/dist/layout/geo/resolveProjection.js +0 -48
  180. package/dist/layout/plot/GridLayout.svelte +0 -30
  181. package/dist/layout/plot/RuleLayout.svelte +0 -111
  182. package/dist/plots/bar/BarSegments.svelte +0 -69
  183. package/dist/types/charts/legend.d.ts +0 -60
  184. package/dist/types/plots/delta.d.ts +0 -19
  185. package/dist/types/plots/styles/common.d.ts +0 -52
  186. package/dist/types/plots/styles/geo.d.ts +0 -42
  187. /package/dist/{plots/geo → layout/coordinates}/projections/argentina.js +0 -0
  188. /package/dist/{plots/geo → layout/coordinates}/projections/fit.d.ts +0 -0
  189. /package/dist/{plots/geo → layout/coordinates}/projections/fit.js +0 -0
  190. /package/dist/{plots/geo → layout/coordinates}/rotate.svelte.d.ts +0 -0
  191. /package/dist/{plots/geo → layout/coordinates}/rotate.svelte.js +0 -0
  192. /package/dist/{plots/geo → layout/coordinates}/zoom.svelte.js +0 -0
  193. /package/dist/types/{charts/legend.js → layout/coordinates.js} +0 -0
  194. /package/dist/types/{plots/axis.js → layout/facet.js} +0 -0
  195. /package/dist/types/{plots/delta.js → layout/geometry.js} +0 -0
  196. /package/dist/types/{plots/scales/geo.js → layout/scales.js} +0 -0
  197. /package/dist/types/{plots/styles/common.js → layout/styles.js} +0 -0
  198. /package/dist/types/{plots/styles/geo.js → layout/timeline.js} +0 -0
@@ -43,3 +43,13 @@ export type DotStyle = {
43
43
  dotStrokeOpacity?: number;
44
44
  dotStrokeDasharray?: string | LineStyle;
45
45
  };
46
+ /** Styling for a 2D area mark — a bar segment, a heatmap cell, a geo feature highlight. */
47
+ export type AreaStyle = {
48
+ fill?: string;
49
+ fillOpacity?: number;
50
+ stroke?: string;
51
+ strokeWidth?: number;
52
+ strokeOpacity?: number;
53
+ strokeDasharray?: string | LineStyle;
54
+ borderRadius?: number;
55
+ };
@@ -1,5 +1,5 @@
1
- import type { Series } from '../../types/plots/data/common';
2
- import type { DeltaConfig } from '../../types/plots/delta';
1
+ import type { Series } from '../types/plots/data/common';
2
+ import type { DeltaConfig } from '../types/markers/line';
3
3
  export type ResolvedDelta = {
4
4
  cfg: DeltaConfig;
5
5
  at: number;
@@ -1,4 +1,4 @@
1
- import { resolveAccessor } from './accessors';
1
+ import { resolveAccessor } from '../plots/utils/accessors';
2
2
  /**
3
3
  * Sorts `data` by `sortBy`, then finds the first adjacent pair where `scanBy`
4
4
  * brackets `target` and linearly interpolates `measureBy` at that crossing.
@@ -0,0 +1,37 @@
1
+ export type HorizontalAnchor = 'start' | 'middle' | 'end';
2
+ export type VerticalAnchor = 'top' | 'middle' | 'bottom';
3
+ /** Rough estimate of rendered text width in pixels — character count × font size, not a real DOM measurement. Shared so a pre-render space reservation (e.g. domain padding) and this file's own overflow check agree on the same number. */
4
+ export declare function estimateTextWidth(text: string, fontSize: number): number;
5
+ export type AnchorPlacement = {
6
+ textAnchor: HorizontalAnchor;
7
+ lineAnchor: VerticalAnchor;
8
+ dx: number;
9
+ dy: number;
10
+ };
11
+ /**
12
+ * Flips (or nudges) a label's anchor/offset when its default placement
13
+ * would push it past a pixel box — e.g. the plot's own inner content box.
14
+ * `extent` estimates the rendered label size (character count × font size,
15
+ * not a real DOM measurement) deliberately: measuring via `getBBox()` and
16
+ * feeding the result back into anything reactive to the plot's own layout
17
+ * (like svelteplot's shared margin-auto-sizing context) risks a feedback
18
+ * loop between this component's own effect and svelteplot's — this stays
19
+ * self-contained and read-only against the live scale instead.
20
+ */
21
+ export declare function resolveEdgeAwareAnchor(args: {
22
+ /** Pixel position of the anchored point. */
23
+ px: number;
24
+ py: number;
25
+ /** Size of the box the label must stay within — typically the plot's own inner content box. */
26
+ width: number;
27
+ height: number;
28
+ textAnchor: HorizontalAnchor;
29
+ lineAnchor: VerticalAnchor;
30
+ /** Desired distance from the point, in pixels — sign is resolved from the (possibly flipped) anchor. */
31
+ gapX: number;
32
+ gapY: number;
33
+ extent: {
34
+ width: number;
35
+ height: number;
36
+ };
37
+ }): AnchorPlacement;
@@ -0,0 +1,65 @@
1
+ /** Rough estimate of rendered text width in pixels — character count × font size, not a real DOM measurement. Shared so a pre-render space reservation (e.g. domain padding) and this file's own overflow check agree on the same number. */
2
+ export function estimateTextWidth(text, fontSize) {
3
+ return text.length * fontSize * 0.62;
4
+ }
5
+ /**
6
+ * Flips (or nudges) a label's anchor/offset when its default placement
7
+ * would push it past a pixel box — e.g. the plot's own inner content box.
8
+ * `extent` estimates the rendered label size (character count × font size,
9
+ * not a real DOM measurement) deliberately: measuring via `getBBox()` and
10
+ * feeding the result back into anything reactive to the plot's own layout
11
+ * (like svelteplot's shared margin-auto-sizing context) risks a feedback
12
+ * loop between this component's own effect and svelteplot's — this stays
13
+ * self-contained and read-only against the live scale instead.
14
+ */
15
+ export function resolveEdgeAwareAnchor(args) {
16
+ const { px, py, width, height, gapX, gapY, extent } = args;
17
+ let { textAnchor, lineAnchor } = args;
18
+ let dx;
19
+ let dy;
20
+ if (textAnchor === 'start') {
21
+ dx = gapX;
22
+ if (px + dx + extent.width > width) {
23
+ textAnchor = 'end';
24
+ dx = -gapX;
25
+ }
26
+ }
27
+ else if (textAnchor === 'end') {
28
+ dx = -gapX;
29
+ if (px + dx - extent.width < 0) {
30
+ textAnchor = 'start';
31
+ dx = gapX;
32
+ }
33
+ }
34
+ else {
35
+ const half = extent.width / 2;
36
+ dx = 0;
37
+ if (px - half < 0)
38
+ dx = half - px;
39
+ else if (px + half > width)
40
+ dx = width - (px + half);
41
+ }
42
+ if (lineAnchor === 'top') {
43
+ dy = gapY;
44
+ if (py + dy + extent.height > height) {
45
+ lineAnchor = 'bottom';
46
+ dy = -gapY;
47
+ }
48
+ }
49
+ else if (lineAnchor === 'bottom') {
50
+ dy = -gapY;
51
+ if (py + dy - extent.height < 0) {
52
+ lineAnchor = 'top';
53
+ dy = gapY;
54
+ }
55
+ }
56
+ else {
57
+ const half = extent.height / 2;
58
+ dy = 0;
59
+ if (py - half < 0)
60
+ dy = half - py;
61
+ else if (py + half > height)
62
+ dy = height - (py + half);
63
+ }
64
+ return { textAnchor, lineAnchor, dx, dy };
65
+ }
@@ -1,4 +1,4 @@
1
- import type { AxisValue } from '../types/plots/axis';
1
+ import type { AxisValue } from '../types/layout/scales';
2
2
  import type { Series, Accessor } from '../types/plots/data/common';
3
3
  /**
4
4
  * Splits rows into ordered groups keyed by the stringified accessor value.
@@ -1,6 +1,6 @@
1
1
  import type { EasingName, EasingFn } from '../types/charts/interpolate';
2
- import type { TimeValue, TimelineInterpolation } from '../types/charts/common';
3
- import type { AxisValue } from '../types/plots/axis';
2
+ import type { TimeValue, TimelineInterpolation } from '../types/layout/timeline';
3
+ import type { AxisValue } from '../types/layout/scales';
4
4
  import type { Accessor } from '../types/plots/data/common';
5
5
  export declare function resolveEasing(easing?: EasingName | EasingFn): EasingFn;
6
6
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fundar/data-chart-telling",
3
- "version": "0.0.25",
3
+ "version": "0.0.27",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"
@@ -58,6 +58,7 @@
58
58
  "eslint-plugin-storybook": "^10.4.1",
59
59
  "eslint-plugin-svelte": "^3.17.0",
60
60
  "globals": "^17.4.0",
61
+ "knip": "^6.32.1",
61
62
  "playwright": "^1.60.0",
62
63
  "prettier": "^3.8.1",
63
64
  "prettier-plugin-svelte": "^3.5.1",
@@ -80,6 +81,7 @@
80
81
  "build": "svelte-package",
81
82
  "check": "svelte-check --tsconfig ./tsconfig.json",
82
83
  "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
84
+ "check:unused-types": "knip --include types",
83
85
  "lint": "prettier --check . && eslint .",
84
86
  "format": "prettier --write .",
85
87
  "test": "vitest run --project=unit --project=browser",
@@ -1,51 +0,0 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte';
3
- import TileLayer from '../../plots/geo/TileLayer.svelte';
4
- import type { GeoTileLayerConfig } from '../../types/plots/styles/geo';
5
-
6
- /**
7
- * Geo-only chrome nested inside `BasePlotLayout` (the `GeoPlot` analog of
8
- * `AxisLayout`/`GridLayout`/`RuleLayout`) — just the pan/zoom transform
9
- * group and the raster tile layer underneath the map's own marks.
10
- * Everything else GeoPlot used to duplicate from `BasePlotLayout` (the hover
11
- * state machine, `<Plot>` itself, `<Pointer>`, the tooltip) now lives
12
- * exclusively in `BasePlotLayout`; the zoom/rotate *gesture* state itself lives
13
- * in `GeoPlot`'s own `Plot.svelte` (it also feeds the projection's
14
- * `rotate`, which has to reach `BasePlotLayout`'s `<Plot projection>` prop —
15
- * something a component nested *inside* that same `<Plot>` has no way to
16
- * reach back out to), and is only handed down here as an already-resolved
17
- * `zoomTransform` to apply.
18
- */
19
- let {
20
- width,
21
- height,
22
- numericMargins,
23
- zoomTransform,
24
- tileLayer,
25
- dataLonLatBounds,
26
- children,
27
- }: {
28
- width: number;
29
- height: number;
30
- numericMargins: { top: number; right: number; bottom: number; left: number };
31
- zoomTransform: { x: number; y: number; k: number };
32
- tileLayer?: GeoTileLayerConfig;
33
- /** Forwarded to `TileLayer` — see `Plot.svelte`'s `dataLonLatBounds`. */
34
- dataLonLatBounds?: [number, number, number, number] | null;
35
- children: Snippet;
36
- } = $props();
37
- </script>
38
-
39
- <g transform="translate({zoomTransform.x}, {zoomTransform.y}) scale({zoomTransform.k})">
40
- {#if tileLayer}
41
- <TileLayer
42
- config={tileLayer}
43
- left={numericMargins.left}
44
- top={numericMargins.top}
45
- width={Math.max(0, width - numericMargins.left - numericMargins.right)}
46
- height={Math.max(0, height - numericMargins.top - numericMargins.bottom)}
47
- {dataLonLatBounds}
48
- />
49
- {/if}
50
- {@render children()}
51
- </g>
@@ -1,24 +0,0 @@
1
- import type { Snippet } from 'svelte';
2
- import type { GeoTileLayerConfig } from '../../types/plots/styles/geo';
3
- type $$ComponentProps = {
4
- width: number;
5
- height: number;
6
- numericMargins: {
7
- top: number;
8
- right: number;
9
- bottom: number;
10
- left: number;
11
- };
12
- zoomTransform: {
13
- x: number;
14
- y: number;
15
- k: number;
16
- };
17
- tileLayer?: GeoTileLayerConfig;
18
- /** Forwarded to `TileLayer` — see `Plot.svelte`'s `dataLonLatBounds`. */
19
- dataLonLatBounds?: [number, number, number, number] | null;
20
- children: Snippet;
21
- };
22
- declare const GeoLayout: import("svelte").Component<$$ComponentProps, {}, "">;
23
- type GeoLayout = ReturnType<typeof GeoLayout>;
24
- export default GeoLayout;
@@ -1,48 +0,0 @@
1
- /**
2
- * `data` (see `resolveProjection`) is one row per disjoint geometry *part*
3
- * (see `Plot.svelte`'s `hoverCandidates` — needed so hover-matching finds
4
- * every part of a multi-part feature, not just whichever one its combined
5
- * centroid happens to land near), not one row per feature. Several rows
6
- * therefore share the exact same `geometry` object by reference — spread
7
- * from the same tagged feature, only `__cx`/`__cy` differ. Deduping by that
8
- * reference before handing rows to d3-geo's bounds/fit computation matters:
9
- * a feature with many parts (e.g. a province whose `MultiPolygon` has
10
- * hundreds of small islands) would otherwise have its *entire* geometry
11
- * re-traversed once per part it contributed, an accidental O(parts²) cost
12
- * that got severe enough to be visible (multi-second) on real IGN data.
13
- */
14
- function dedupeByGeometry(data) {
15
- const seen = new Set();
16
- const result = [];
17
- for (const row of data) {
18
- if (seen.has(row.geometry))
19
- continue;
20
- seen.add(row.geometry);
21
- result.push(row);
22
- }
23
- return result;
24
- }
25
- /**
26
- * Resolves a `GeoScalesConfig['projection']` into what svelteplot's own
27
- * `<Plot projection>` expects — kept separate from `GeoPlot`'s own
28
- * `Plot.svelte` so adding more projection-level behavior (like the
29
- * `domain: 'data'` sentinel below) doesn't grow that component itself.
30
- */
31
- export function resolveProjection(projection, data) {
32
- if (!projection)
33
- return 'equal-earth';
34
- if (typeof projection === 'string')
35
- return projection;
36
- const domain = projection.domain === 'data'
37
- ? { type: 'FeatureCollection', features: dedupeByGeometry(data) }
38
- : projection.domain;
39
- return {
40
- type: projection.type,
41
- rotate: projection.rotate,
42
- center: projection.center,
43
- parallels: projection.parallels,
44
- inset: projection.inset,
45
- clip: projection.clip,
46
- domain,
47
- };
48
- }
@@ -1,30 +0,0 @@
1
- <script lang="ts" generics="TData extends Record<string, unknown>">
2
- import { GridX, GridY } from 'svelteplot';
3
- import type { AxisBasedScalesConfig } from '../../types/plots/props';
4
-
5
- /**
6
- * Grid lines for the plot kinds that have an x/y axis pair — opt-in via
7
- * `scales.x.grid`/`scales.y.grid` (svelteplot's own implicit grid is a
8
- * fixed, unstyled default, so this is drawn instead of that, not on top of
9
- * it — see `BasePlotLayout`'s `finalizeScale`, which strips `grid` from what
10
- * actually reaches `<Plot x y>`).
11
- */
12
- let { scales }: { scales?: AxisBasedScalesConfig<TData> } = $props();
13
- </script>
14
-
15
- {#if scales?.x?.grid}
16
- <GridX
17
- stroke={typeof scales.x.grid === 'object' ? scales.x.grid.stroke : undefined}
18
- strokeWidth={typeof scales.x.grid === 'object' ? scales.x.grid.strokeWidth : undefined}
19
- strokeOpacity={typeof scales.x.grid === 'object' ? scales.x.grid.strokeOpacity : undefined}
20
- strokeDasharray={typeof scales.x.grid === 'object' ? scales.x.grid.strokeDasharray : undefined}
21
- />
22
- {/if}
23
- {#if scales?.y?.grid}
24
- <GridY
25
- stroke={typeof scales.y.grid === 'object' ? scales.y.grid.stroke : undefined}
26
- strokeWidth={typeof scales.y.grid === 'object' ? scales.y.grid.strokeWidth : undefined}
27
- strokeOpacity={typeof scales.y.grid === 'object' ? scales.y.grid.strokeOpacity : undefined}
28
- strokeDasharray={typeof scales.y.grid === 'object' ? scales.y.grid.strokeDasharray : undefined}
29
- />
30
- {/if}
@@ -1,111 +0,0 @@
1
- <script lang="ts" generics="TData extends Record<string, unknown>">
2
- import type { Snippet } from 'svelte';
3
- import { RuleX, RuleY } from 'svelteplot';
4
- import HoverMarker from '../../markers/HoverMarker.svelte';
5
- import type { AxisValue } from '../../types/plots/axis';
6
- import type { Series } from '../../types/plots/data/common';
7
- import type { Marker } from '../../types/markers/common';
8
- import type { HoverPoint } from '../../types/layout/tooltip';
9
-
10
- /**
11
- * Standalone rule markers (`ruleX`/`ruleY`/un-scoped `component`) plus the
12
- * unscoped hover crosshair+dot+label — the plot kinds with an x/y axis pair
13
- * only (line/bar/heatmap/pyramid); `GeoPlot` has no rule/crosshair concept
14
- * of its own. Wraps `children` (the plot kind's actual marks) so both draw
15
- * in the same order as before this was split out of `BasePlotLayout`: marks
16
- * first, then rules/hover marker on top of them.
17
- */
18
- let {
19
- markers = [],
20
- seriesData = [],
21
- matchedPoints,
22
- ruleX,
23
- ruleY,
24
- impliesRuleX,
25
- impliesRuleY,
26
- showHoverLabels = true,
27
- children,
28
- }: {
29
- markers?: Marker[];
30
- /** All resolved series, forwarded to unscoped component markers (e.g. DeltaMarker). */
31
- seriesData?: Series<TData>[];
32
- matchedPoints: HoverPoint<TData>[];
33
- ruleX: AxisValue | null;
34
- ruleY: AxisValue | null;
35
- impliesRuleX: boolean;
36
- impliesRuleY: boolean;
37
- showHoverLabels?: boolean;
38
- children: Snippet;
39
- } = $props();
40
-
41
- const topLevelMarkers = $derived(
42
- markers.filter(
43
- (marker) =>
44
- marker.type === 'ruleX' ||
45
- marker.type === 'ruleY' ||
46
- (marker.type === 'component' && !marker.series),
47
- ),
48
- );
49
-
50
- /** The unscoped (no `series`) hover marker, if any. */
51
- const unscopedHoverMarker = $derived(
52
- markers.find((m) => m.type === 'hover' && !m.series) as
53
- | Extract<Marker, { type: 'hover' }>
54
- | undefined,
55
- );
56
-
57
- /**
58
- * Gate ruleX display: shows when the strategy implies it (default) or the
59
- * marker explicitly requests it (`ruleX: true`), and is never suppressed
60
- * unless the marker explicitly disables it (`ruleX: false`).
61
- */
62
- const showRuleX = $derived(
63
- unscopedHoverMarker != null &&
64
- unscopedHoverMarker.ruleX !== false &&
65
- (impliesRuleX || unscopedHoverMarker.ruleX === true),
66
- );
67
- const showRuleY = $derived(
68
- unscopedHoverMarker != null &&
69
- unscopedHoverMarker.ruleY !== false &&
70
- (impliesRuleY || unscopedHoverMarker.ruleY === true),
71
- );
72
- </script>
73
-
74
- {@render children()}
75
-
76
- {#each topLevelMarkers as marker, i (marker.type === 'ruleX' ? `${marker.type}-${marker.x}` : marker.type === 'ruleY' ? `${marker.type}-${marker.y}` : `${marker.type}-${i}`)}
77
- {#if marker.type === 'ruleX'}
78
- <RuleX
79
- data={[{ xValue: marker.x }]}
80
- x={(d) => d.xValue}
81
- stroke={marker.style?.stroke ?? 'currentColor'}
82
- strokeWidth={marker.style?.strokeWidth ?? 1}
83
- strokeOpacity={marker.style?.strokeOpacity ?? 1}
84
- strokeDasharray={marker.style?.strokeDasharray}
85
- />
86
- {:else if marker.type === 'ruleY'}
87
- <RuleY
88
- data={[{ yValue: marker.y }]}
89
- y={(d) => d.yValue}
90
- stroke={marker.style?.stroke ?? 'currentColor'}
91
- strokeWidth={marker.style?.strokeWidth ?? 1}
92
- strokeOpacity={marker.style?.strokeOpacity ?? 1}
93
- strokeDasharray={marker.style?.strokeDasharray}
94
- />
95
- {:else if marker.type === 'component'}
96
- <marker.component {...marker.props} data={marker.data ?? seriesData} />
97
- {/if}
98
- {/each}
99
-
100
- {#if unscopedHoverMarker}
101
- <HoverMarker
102
- data={matchedPoints}
103
- ruleX={showRuleX ? ruleX : null}
104
- ruleY={showRuleY ? ruleY : null}
105
- showLabels={unscopedHoverMarker.showLabels ?? showHoverLabels}
106
- format={unscopedHoverMarker.format}
107
- ruleStyle={unscopedHoverMarker.ruleStyle}
108
- dotStyle={unscopedHoverMarker.dotStyle}
109
- fontStyle={unscopedHoverMarker.fontStyle}
110
- />
111
- {/if}
@@ -1,69 +0,0 @@
1
- <script lang="ts" generics="TData extends Record<string, unknown>">
2
- import { BarX, BarY } from 'svelteplot';
3
- import { resolveAccessor } from '../utils/accessors';
4
- import type { Series } from '../../types/plots/data/common';
5
- import type { BarSegmentStyle } from '../../types/plots/segments/common';
6
- import type { VisualGroup } from '../../types/plots/segments/config';
7
- import type { BarLayout } from './layout.svelte';
8
-
9
- /**
10
- * Renders one series' bars — the `'stacked'` branch (cumulative baseline
11
- * from {@link BarLayout.stackedBaseline}) or the `'grouped'`/`'overlap'`
12
- * branch (per-segment insets from {@link BarLayout.seriesStep}/`seriesGap`).
13
- */
14
- let {
15
- group,
16
- seriesIndex,
17
- barLayout,
18
- isHorizontal,
19
- BarMark,
20
- defaultColor,
21
- disabledFill,
22
- }: {
23
- group: VisualGroup<Series<TData>, BarSegmentStyle>;
24
- seriesIndex: number;
25
- barLayout: BarLayout<TData>;
26
- isHorizontal: boolean;
27
- BarMark: typeof BarX | typeof BarY;
28
- defaultColor: string;
29
- disabledFill?: { fill?: string; fillOpacity?: number };
30
- } = $props();
31
-
32
- const xFn = $derived(resolveAccessor(group.series.x));
33
- const yFn = $derived(resolveAccessor(group.series.y));
34
- </script>
35
-
36
- {#if barLayout.layout === 'stacked'}
37
- {@const stackedBaselineFn = (d: TData) => barLayout.stackedBaseline(xFn(d), seriesIndex)}
38
- {@const stackedTopFn = (d: TData) => barLayout.stackedBaseline(xFn(d), seriesIndex) + Number(yFn(d))}
39
- <BarMark
40
- data={group.series.data}
41
- {...isHorizontal
42
- ? { y: xFn, x1: stackedBaselineFn, x2: stackedTopFn }
43
- : { x: xFn, y1: stackedBaselineFn, y2: stackedTopFn }}
44
- fill={disabledFill?.fill ?? defaultColor}
45
- fillOpacity={disabledFill?.fillOpacity ?? 1}
46
- />
47
- {:else}
48
- {#each group.visualSegments as seg, i (`${group.series.name}-${i}`)}
49
- <BarMark
50
- data={seg.data}
51
- {...isHorizontal
52
- ? { y: xFn, x1: barLayout.valueBaseline, x2: yFn }
53
- : { x: xFn, y1: barLayout.valueBaseline, y2: yFn }}
54
- fill={disabledFill?.fill ?? seg.style.fill ?? defaultColor}
55
- fillOpacity={disabledFill?.fillOpacity ?? seg.style.fillOpacity ?? 1}
56
- {...barLayout.layout === 'grouped'
57
- ? isHorizontal
58
- ? {
59
- insetTop: seriesIndex * barLayout.seriesStep + barLayout.seriesGap / 2,
60
- insetBottom: (barLayout.seriesCount - 1 - seriesIndex) * barLayout.seriesStep + barLayout.seriesGap / 2,
61
- }
62
- : {
63
- insetLeft: seriesIndex * barLayout.seriesStep + barLayout.seriesGap / 2,
64
- insetRight: (barLayout.seriesCount - 1 - seriesIndex) * barLayout.seriesStep + barLayout.seriesGap / 2,
65
- }
66
- : {}}
67
- />
68
- {/each}
69
- {/if}
@@ -1,60 +0,0 @@
1
- import type { SymbolType, LineStyle } from '../plots/constants';
2
- import type { StrokeStyle, DotStyle } from '../plots/styling';
3
- export type LegendSectionType = 'discrete' | 'continuous';
4
- /**
5
- * Style applied to whatever a legend interaction has turned "off" — a
6
- * toggled-off discrete series, or a datapoint/cell/feature outside an active
7
- * continuous range filter. `opacity` is a blanket convenience: any
8
- * `*Opacity` field a consumer doesn't set falls back to it, so
9
- * `{ opacity: 0.1 }` alone is enough to read as "disabled" everywhere.
10
- */
11
- export type LegendDisabledStyle = {
12
- opacity?: number;
13
- stroke?: StrokeStyle;
14
- dots?: DotStyle;
15
- fill?: string;
16
- fillOpacity?: number;
17
- };
18
- export type LegendItem = {
19
- name: string;
20
- label?: string;
21
- color?: string;
22
- symbol?: SymbolType;
23
- opacity?: number;
24
- lineStyle?: LineStyle;
25
- /** Initial toggled-off state (uncontrolled — the user can still click it back on). */
26
- disabled?: boolean;
27
- };
28
- export type DiscreteLegendSection = {
29
- type: 'discrete';
30
- title?: string;
31
- items: LegendItem[];
32
- columns?: number;
33
- /** Enables click-to-toggle on each item. */
34
- interactive?: boolean;
35
- /** Style applied to a toggled-off item's series. Falls back to `cfg.legend.disabledOpacity`. */
36
- disabledStyle?: LegendDisabledStyle;
37
- };
38
- export type ContinuousLegendSection = {
39
- type: 'continuous';
40
- title?: string;
41
- columns?: number;
42
- min: number;
43
- max: number;
44
- colorMin?: string;
45
- colorMax?: string;
46
- ticks?: number[];
47
- width?: number;
48
- format?: (v: number) => string;
49
- /** Enables drag handles on the bar's edges to narrow the visible range. */
50
- interactive?: boolean;
51
- /**
52
- * How the color ramp responds to a narrowed range: `'rescale'` reprojects
53
- * it onto the new bounds, `'filter'` keeps the original domain and only
54
- * excludes out-of-range values. Defaults to `'filter'`.
55
- */
56
- mode?: 'rescale' | 'filter';
57
- /** Style applied to values outside the active range. Falls back to `cfg.legend.disabledOpacity`. */
58
- disabledStyle?: LegendDisabledStyle;
59
- };
60
- export type LegendSection = DiscreteLegendSection | ContinuousLegendSection;
@@ -1,19 +0,0 @@
1
- import type { AxisValue } from './axis';
2
- import type { StrokeStyle, FontStyle, DotStyle } from './styling';
3
- export type DeltaTarget = {
4
- type: 'series';
5
- series: string;
6
- } | {
7
- type: 'axis';
8
- value?: number;
9
- };
10
- export type DeltaConfig = {
11
- axis: 'x' | 'y';
12
- at: AxisValue;
13
- from: DeltaTarget;
14
- to?: DeltaTarget;
15
- formatDiff?: (diff: number) => string;
16
- strokeStyle?: StrokeStyle;
17
- fontStyle?: FontStyle;
18
- dotStyle?: DotStyle;
19
- };
@@ -1,52 +0,0 @@
1
- import type { ValueAnchor } from '../constants';
2
- import type { FontStyle, StrokeStyle } from '../styling';
3
- /**
4
- * Controls if and how value labels are rendered on a plot. The high-level
5
- * `anchor` sets sensible defaults for placement; `fontStyle` (`dx`, `dy`,
6
- * `textAnchor`, `lineAnchor`, `lineHeight`, `rotate`, `class`, `textClass`,
7
- * `fill`, …) overrides those defaults field-by-field when provided — mirrors
8
- * {@link DeltaConfig}'s `fontStyle`/`strokeStyle` split, so label text and
9
- * connector-line styling never mix into one flat bag of props.
10
- */
11
- export type ValuesStyle = {
12
- show?: boolean;
13
- anchor?: ValueAnchor;
14
- /** Called with the numeric value and the series name. Return a string to render. */
15
- format?: (value: number, seriesName: string) => string;
16
- /** Text styling for the label itself. */
17
- fontStyle?: FontStyle;
18
- /**
19
- * Style for the leader line drawn from a label displaced to clear an
20
- * overlap with another series' label, back to its real data point.
21
- * Labels only ever move when they'd otherwise collide — this is a no-op
22
- * style until that happens. Falls back to a neutral grey, thin, solid
23
- * stroke — deliberately not the series' own colour or stroke width, since
24
- * matching the data line reads as more data rather than as a leader,
25
- * right where several lines are already converging. Unset fields keep
26
- * that fallback.
27
- */
28
- strokeStyle?: StrokeStyle;
29
- };
30
- /**
31
- * Color overrides for plots that derive their palette from data.
32
- * Each plot uses only the fields relevant to its kind; unused fields are
33
- * silently ignored.
34
- *
35
- * - `min` / `max` — sequential colour ramp endpoints (heatmap).
36
- * - `left` / `right` — diverging bar sides (pyramid).
37
- */
38
- export type ColorsStyle = {
39
- min?: string;
40
- max?: string;
41
- left?: string;
42
- right?: string;
43
- };
44
- /**
45
- * Top-level rendering style overrides shared by the non-geo plot kinds.
46
- * Passed as the `styles` prop. Each plot reads only the fields it cares
47
- * about.
48
- */
49
- export type BasePlotStyles = {
50
- values?: ValuesStyle;
51
- colors?: ColorsStyle;
52
- };