@rokkit/chart 1.0.0-next.15 → 1.0.0-next.150

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 (223) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +150 -46
  3. package/dist/Plot/index.d.ts +9 -0
  4. package/dist/PlotState.svelte.d.ts +47 -0
  5. package/dist/crossfilter/createCrossFilter.svelte.d.ts +15 -0
  6. package/dist/elements/index.d.ts +6 -0
  7. package/dist/geoms/lib/areas.d.ts +52 -0
  8. package/dist/geoms/lib/bars.d.ts +3 -0
  9. package/dist/index.d.ts +51 -0
  10. package/dist/lib/brewer.d.ts +9 -0
  11. package/dist/lib/brewing/BoxBrewer.svelte.d.ts +10 -0
  12. package/dist/lib/brewing/CartesianBrewer.svelte.d.ts +8 -0
  13. package/dist/lib/brewing/PieBrewer.svelte.d.ts +8 -0
  14. package/dist/lib/brewing/ViolinBrewer.svelte.d.ts +9 -0
  15. package/dist/lib/brewing/axes.svelte.d.ts +66 -0
  16. package/dist/lib/brewing/bars.svelte.d.ts +56 -0
  17. package/dist/lib/brewing/brewer.svelte.d.ts +145 -0
  18. package/dist/lib/brewing/colors.d.ts +17 -0
  19. package/dist/lib/brewing/dimensions.svelte.d.ts +35 -0
  20. package/dist/lib/brewing/index.svelte.d.ts +118 -0
  21. package/dist/lib/brewing/legends.svelte.d.ts +48 -0
  22. package/dist/lib/brewing/marks/arcs.d.ts +17 -0
  23. package/dist/lib/brewing/marks/areas.d.ts +31 -0
  24. package/dist/lib/brewing/marks/bars.d.ts +1 -0
  25. package/dist/lib/brewing/marks/boxes.d.ts +24 -0
  26. package/dist/lib/brewing/marks/lines.d.ts +24 -0
  27. package/dist/lib/brewing/marks/points.d.ts +40 -0
  28. package/dist/lib/brewing/marks/violins.d.ts +20 -0
  29. package/dist/lib/brewing/patterns.d.ts +14 -0
  30. package/dist/lib/brewing/scales.d.ts +28 -0
  31. package/dist/lib/brewing/scales.svelte.d.ts +24 -0
  32. package/dist/lib/brewing/stats.d.ts +31 -0
  33. package/dist/lib/brewing/symbols.d.ts +7 -0
  34. package/dist/lib/brewing/types.d.ts +162 -0
  35. package/dist/lib/chart.d.ts +40 -0
  36. package/dist/lib/context.d.ts +13 -0
  37. package/dist/lib/grid.d.ts +72 -0
  38. package/dist/lib/plot/chartProps.d.ts +177 -0
  39. package/dist/lib/plot/crossfilter.d.ts +13 -0
  40. package/dist/lib/plot/facet.d.ts +24 -0
  41. package/dist/lib/plot/frames.d.ts +47 -0
  42. package/dist/lib/plot/helpers.d.ts +3 -0
  43. package/dist/lib/plot/preset.d.ts +29 -0
  44. package/dist/lib/plot/scales.d.ts +5 -0
  45. package/dist/lib/plot/stat.d.ts +32 -0
  46. package/dist/lib/plot/types.d.ts +89 -0
  47. package/dist/lib/scales.svelte.d.ts +35 -0
  48. package/dist/lib/swatch.d.ts +12 -0
  49. package/dist/lib/ticks.d.ts +36 -0
  50. package/dist/lib/utils.d.ts +61 -0
  51. package/dist/lib/xscale.d.ts +11 -0
  52. package/dist/patterns/index.d.ts +4 -0
  53. package/dist/patterns/patterns.d.ts +72 -0
  54. package/dist/patterns/scale.d.ts +30 -0
  55. package/dist/symbols/constants/index.d.ts +1 -0
  56. package/dist/symbols/index.d.ts +5 -0
  57. package/package.json +41 -45
  58. package/src/AnimatedPlot.svelte +214 -0
  59. package/src/Chart.svelte +101 -0
  60. package/src/FacetPlot/Panel.svelte +23 -0
  61. package/src/FacetPlot.svelte +90 -0
  62. package/src/Plot/Arc.svelte +29 -0
  63. package/src/Plot/Area.svelte +25 -0
  64. package/src/Plot/Axis.svelte +73 -0
  65. package/src/Plot/Bar.svelte +96 -0
  66. package/src/Plot/Grid.svelte +30 -0
  67. package/src/Plot/Legend.svelte +167 -0
  68. package/src/Plot/Line.svelte +27 -0
  69. package/src/Plot/Point.svelte +27 -0
  70. package/src/Plot/Root.svelte +107 -0
  71. package/src/Plot/Timeline.svelte +95 -0
  72. package/src/Plot/Tooltip.svelte +81 -0
  73. package/src/Plot/index.js +9 -0
  74. package/src/Plot.svelte +189 -0
  75. package/src/PlotState.svelte.js +278 -0
  76. package/src/Sparkline.svelte +69 -0
  77. package/src/Symbol.svelte +21 -0
  78. package/src/Texture.svelte +18 -0
  79. package/src/charts/AreaChart.svelte +25 -0
  80. package/src/charts/BarChart.svelte +26 -0
  81. package/src/charts/BoxPlot.svelte +21 -0
  82. package/src/charts/BubbleChart.svelte +23 -0
  83. package/src/charts/LineChart.svelte +26 -0
  84. package/src/charts/PieChart.svelte +25 -0
  85. package/src/charts/ScatterPlot.svelte +25 -0
  86. package/src/charts/ViolinPlot.svelte +21 -0
  87. package/src/crossfilter/CrossFilter.svelte +38 -0
  88. package/src/crossfilter/FilterBar.svelte +32 -0
  89. package/src/crossfilter/FilterSlider.svelte +79 -0
  90. package/src/crossfilter/createCrossFilter.svelte.js +113 -0
  91. package/src/elements/Bar.svelte +22 -24
  92. package/src/elements/ColorRamp.svelte +20 -22
  93. package/src/elements/ContinuousLegend.svelte +20 -17
  94. package/src/elements/DefinePatterns.svelte +24 -0
  95. package/src/elements/DiscreteLegend.svelte +15 -15
  96. package/src/elements/Label.svelte +4 -8
  97. package/src/elements/SymbolGrid.svelte +22 -0
  98. package/src/elements/index.js +6 -0
  99. package/src/examples/BarChartExample.svelte +81 -0
  100. package/src/geoms/Arc.svelte +81 -0
  101. package/src/geoms/Area.svelte +50 -0
  102. package/src/geoms/Bar.svelte +142 -0
  103. package/src/geoms/Box.svelte +101 -0
  104. package/src/geoms/LabelPill.svelte +17 -0
  105. package/src/geoms/Line.svelte +100 -0
  106. package/src/geoms/Point.svelte +100 -0
  107. package/src/geoms/Violin.svelte +44 -0
  108. package/src/geoms/lib/areas.js +131 -0
  109. package/src/geoms/lib/bars.js +172 -0
  110. package/src/index.js +67 -16
  111. package/src/lib/brewer.js +25 -0
  112. package/src/lib/brewing/BoxBrewer.svelte.js +56 -0
  113. package/src/lib/brewing/CartesianBrewer.svelte.js +16 -0
  114. package/src/lib/brewing/PieBrewer.svelte.js +14 -0
  115. package/src/lib/brewing/ViolinBrewer.svelte.js +55 -0
  116. package/src/lib/brewing/axes.svelte.js +270 -0
  117. package/src/lib/brewing/bars.svelte.js +201 -0
  118. package/src/lib/brewing/brewer.svelte.js +229 -0
  119. package/src/lib/brewing/colors.js +22 -0
  120. package/src/lib/brewing/dimensions.svelte.js +56 -0
  121. package/src/lib/brewing/index.svelte.js +205 -0
  122. package/src/lib/brewing/legends.svelte.js +137 -0
  123. package/src/lib/brewing/marks/arcs.js +43 -0
  124. package/src/lib/brewing/marks/areas.js +59 -0
  125. package/src/lib/brewing/marks/bars.js +49 -0
  126. package/src/lib/brewing/marks/boxes.js +75 -0
  127. package/src/lib/brewing/marks/lines.js +48 -0
  128. package/src/lib/brewing/marks/points.js +57 -0
  129. package/src/lib/brewing/marks/violins.js +90 -0
  130. package/src/lib/brewing/patterns.js +31 -0
  131. package/src/lib/brewing/scales.js +51 -0
  132. package/src/lib/brewing/scales.svelte.js +82 -0
  133. package/src/lib/brewing/stats.js +62 -0
  134. package/src/lib/brewing/symbols.js +10 -0
  135. package/src/lib/brewing/types.js +73 -0
  136. package/src/lib/chart.js +213 -0
  137. package/src/lib/context.js +131 -0
  138. package/src/lib/grid.js +85 -0
  139. package/src/lib/plot/chartProps.js +76 -0
  140. package/src/lib/plot/crossfilter.js +16 -0
  141. package/src/lib/plot/facet.js +58 -0
  142. package/src/lib/plot/frames.js +80 -0
  143. package/src/lib/plot/helpers.js +14 -0
  144. package/src/lib/plot/preset.js +53 -0
  145. package/src/lib/plot/scales.js +56 -0
  146. package/src/lib/plot/stat.js +92 -0
  147. package/src/lib/plot/types.js +65 -0
  148. package/src/lib/scales.svelte.js +151 -0
  149. package/src/lib/swatch.js +13 -0
  150. package/src/lib/ticks.js +46 -0
  151. package/src/lib/utils.js +111 -118
  152. package/src/lib/xscale.js +31 -0
  153. package/src/patterns/DefinePatterns.svelte +32 -0
  154. package/src/patterns/PatternDef.svelte +27 -0
  155. package/src/patterns/README.md +3 -0
  156. package/src/patterns/index.js +4 -0
  157. package/src/patterns/patterns.js +208 -0
  158. package/src/patterns/scale.js +87 -0
  159. package/src/spec/chart-spec.js +29 -0
  160. package/src/symbols/RoundedSquare.svelte +33 -0
  161. package/src/symbols/Shape.svelte +37 -0
  162. package/src/symbols/constants/index.js +4 -0
  163. package/src/symbols/index.js +9 -0
  164. package/src/symbols/outline.svelte +60 -0
  165. package/src/symbols/solid.svelte +60 -0
  166. package/src/chart/FacetGrid.svelte +0 -51
  167. package/src/chart/Grid.svelte +0 -34
  168. package/src/chart/Legend.svelte +0 -16
  169. package/src/chart/PatternDefs.svelte +0 -13
  170. package/src/chart/Swatch.svelte +0 -93
  171. package/src/chart/SwatchButton.svelte +0 -29
  172. package/src/chart/SwatchGrid.svelte +0 -55
  173. package/src/chart/Symbol.svelte +0 -37
  174. package/src/chart/Texture.svelte +0 -16
  175. package/src/chart/TexturedShape.svelte +0 -27
  176. package/src/chart/TimelapseChart.svelte +0 -97
  177. package/src/chart/Timer.svelte +0 -27
  178. package/src/chart.js +0 -9
  179. package/src/components/charts/Axis.svelte +0 -66
  180. package/src/components/charts/Chart.svelte +0 -35
  181. package/src/components/index.js +0 -23
  182. package/src/components/lib/axis.js +0 -0
  183. package/src/components/lib/chart.js +0 -187
  184. package/src/components/lib/color.js +0 -327
  185. package/src/components/lib/funnel.js +0 -204
  186. package/src/components/lib/index.js +0 -19
  187. package/src/components/lib/pattern.js +0 -190
  188. package/src/components/lib/rollup.js +0 -55
  189. package/src/components/lib/shape.js +0 -199
  190. package/src/components/lib/summary.js +0 -145
  191. package/src/components/lib/theme.js +0 -23
  192. package/src/components/lib/timer.js +0 -41
  193. package/src/components/lib/utils.js +0 -165
  194. package/src/components/plots/BarPlot.svelte +0 -36
  195. package/src/components/plots/BoxPlot.svelte +0 -54
  196. package/src/components/plots/ScatterPlot.svelte +0 -30
  197. package/src/components/store.js +0 -70
  198. package/src/constants.js +0 -66
  199. package/src/elements/PatternDefs.svelte +0 -13
  200. package/src/elements/PatternMask.svelte +0 -20
  201. package/src/elements/Symbol.svelte +0 -38
  202. package/src/elements/Tooltip.svelte +0 -23
  203. package/src/funnel.svelte +0 -35
  204. package/src/geom.js +0 -105
  205. package/src/lib/axis.js +0 -75
  206. package/src/lib/colors.js +0 -32
  207. package/src/lib/geom.js +0 -4
  208. package/src/lib/shapes.js +0 -144
  209. package/src/lib/timer.js +0 -44
  210. package/src/lookup.js +0 -29
  211. package/src/plots/BarPlot.svelte +0 -55
  212. package/src/plots/BoxPlot.svelte +0 -0
  213. package/src/plots/FunnelPlot.svelte +0 -33
  214. package/src/plots/HeatMap.svelte +0 -5
  215. package/src/plots/HeatMapCalendar.svelte +0 -129
  216. package/src/plots/LinePlot.svelte +0 -55
  217. package/src/plots/Plot.svelte +0 -25
  218. package/src/plots/RankBarPlot.svelte +0 -38
  219. package/src/plots/ScatterPlot.svelte +0 -20
  220. package/src/plots/ViolinPlot.svelte +0 -11
  221. package/src/plots/heatmap.js +0 -70
  222. package/src/plots/index.js +0 -10
  223. package/src/swatch.js +0 -11
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Unified pattern library.
3
+ *
4
+ * Each entry is an array of mark descriptors. All geometry is in normalized
5
+ * 0–1 coordinates; the renderer scales by `size` at paint time.
6
+ *
7
+ * Mark types
8
+ * ----------
9
+ * circle { cx, cy, r }
10
+ * line { x1, y1, x2, y2 } coordinates may exceed 0–1 for seamless tiling
11
+ * polygon { points: [x,y][] }
12
+ * rect { x, y, w, h }
13
+ * path { d: [cmd, ...args][] } SVG path commands as nested arrays (H/V take one arg)
14
+ *
15
+ * Appearance
16
+ * ----------
17
+ * fill: true → element uses fill color (stroke: none)
18
+ * fill: false → element uses stroke color (fill: none) ← default
19
+ * fillOpacity: n → applied as fill-opacity on filled marks
20
+ * opacity: n → applied as opacity on any mark
21
+ */
22
+
23
+ /** @typedef {{ type: 'circle', cx: number, cy: number, r: number, fill?: boolean, fillOpacity?: number, opacity?: number }} CircleMark */
24
+ /** @typedef {{ type: 'line', x1: number, y1: number, x2: number, y2: number, fill?: false, strokeWidth?: number }} LineMark */
25
+ /** @typedef {{ type: 'polygon', points: [number,number][], fill?: boolean, fillOpacity?: number, opacity?: number }} PolygonMark */
26
+ /** @typedef {{ type: 'rect', x: number, y: number, w: number, h: number, fill?: boolean, fillOpacity?: number, opacity?: number }} RectMark */
27
+ /** @typedef {{ type: 'path', d: (string|number)[][], fill?: boolean, fillOpacity?: number, opacity?: number }} PathMark */
28
+ /** @typedef {CircleMark | LineMark | PolygonMark | RectMark | PathMark} PatternMark */
29
+
30
+ /** @type {Record<string, PatternMark[]>} */
31
+ export const PATTERNS = {
32
+ // ── Line-based ──────────────────────────────────────────────────────────────
33
+
34
+ brick: [
35
+ { type: 'line', x1: 0, y1: 0.25, x2: 0.5, y2: 0.25 },
36
+ { type: 'line', x1: 0.5, y1: 0.75, x2: 1, y2: 0.75 },
37
+ { type: 'line', x1: 0, y1: 0, x2: 0, y2: 1 },
38
+ { type: 'line', x1: 1, y1: 0, x2: 1, y2: 1 },
39
+ { type: 'line', x1: 0.5, y1: 0, x2: 0.5, y2: 1 }
40
+ ],
41
+
42
+ hatch: [
43
+ { type: 'line', x1: 0, y1: 0.25, x2: 1, y2: 0.25 },
44
+ { type: 'line', x1: 0, y1: 0.5, x2: 1, y2: 0.5 },
45
+ { type: 'line', x1: 0, y1: 0.75, x2: 1, y2: 0.75 },
46
+ { type: 'line', x1: 0.25, y1: 0, x2: 0.25, y2: 1 },
47
+ { type: 'line', x1: 0.5, y1: 0, x2: 0.5, y2: 1 },
48
+ { type: 'line', x1: 0.75, y1: 0, x2: 0.75, y2: 1 }
49
+ ],
50
+
51
+ // Coordinates intentionally exceed 0–1 so lines tile seamlessly at tile edges
52
+ diagonal: [
53
+ { type: 'line', x1: -0.5, y1: 0.5, x2: 0.5, y2: -0.5 },
54
+ { type: 'line', x1: 0, y1: 1, x2: 1, y2: 0 },
55
+ { type: 'line', x1: 0.5, y1: 1.5, x2: 1.5, y2: 0.5 }
56
+ ],
57
+
58
+ // Two sets of diagonals crossing to form a diamond lattice
59
+ diamonds: [
60
+ { type: 'line', x1: 0, y1: 1, x2: 1, y2: 0 },
61
+ { type: 'line', x1: -0.5, y1: 0.5, x2: 0.5, y2: -0.5 },
62
+ { type: 'line', x1: 0.5, y1: 1.5, x2: 1.5, y2: 0.5 },
63
+ { type: 'line', x1: 0, y1: 0, x2: 1, y2: 1 },
64
+ { type: 'line', x1: -0.5, y1: 0.5, x2: 0.5, y2: 1.5 },
65
+ { type: 'line', x1: 0.5, y1: -0.5, x2: 1.5, y2: 0.5 }
66
+ ],
67
+
68
+ tile: [
69
+ { type: 'line', x1: 0, y1: 0.5, x2: 1, y2: 0.5 },
70
+ { type: 'line', x1: 0.5, y1: 0, x2: 0.5, y2: 1 }
71
+ ],
72
+
73
+ // ── Path-based ──────────────────────────────────────────────────────────────
74
+
75
+ swell: [
76
+ { type: 'path', d: [['M', 0, 0.3], ['A', 0.6, 0.5, 0, 0, 0, 1, 0.3]] }
77
+ ],
78
+
79
+ waves: [
80
+ { type: 'path', d: [['M', 0, 0.5], ['L', 0.25, 0], ['L', 0.75, 1], ['L', 1, 0.5]] }
81
+ ],
82
+
83
+ // ── Circle-based ────────────────────────────────────────────────────────────
84
+
85
+ // Small filled dots in an X pattern across the tile
86
+ dots: [
87
+ { type: 'circle', cx: 0.2, cy: 0.2, r: 0.08, fill: true },
88
+ { type: 'circle', cx: 0.4, cy: 0.4, r: 0.08, fill: true },
89
+ { type: 'circle', cx: 0.6, cy: 0.6, r: 0.08, fill: true },
90
+ { type: 'circle', cx: 0.8, cy: 0.8, r: 0.08, fill: true },
91
+ { type: 'circle', cx: 0.8, cy: 0.2, r: 0.08, fill: true },
92
+ { type: 'circle', cx: 0.6, cy: 0.4, r: 0.08, fill: true },
93
+ { type: 'circle', cx: 0.4, cy: 0.6, r: 0.08, fill: true },
94
+ { type: 'circle', cx: 0.2, cy: 0.8, r: 0.08, fill: true }
95
+ ],
96
+
97
+ // Outlined diamond (rotated square)
98
+ lattice: [
99
+ { type: 'polygon', points: [[0.5, 0.22], [0.78, 0.5], [0.5, 0.78], [0.22, 0.5]] }
100
+ ],
101
+
102
+ // Fish-scale geometry as stroke only — same circles as petals, no fill
103
+ scales: [
104
+ {
105
+ type: 'path',
106
+ d: [
107
+ ['M', -0.7071, 0], ['a', 0.7071, 0.7071, 0, 1, 0, 1.4142, 0], ['a', 0.7071, 0.7071, 0, 1, 0, -1.4142, 0],
108
+ ['M', 0.2929, 0], ['a', 0.7071, 0.7071, 0, 1, 0, 1.4142, 0], ['a', 0.7071, 0.7071, 0, 1, 0, -1.4142, 0],
109
+ ['M', -0.2071, 0.5], ['a', 0.7071, 0.7071, 0, 1, 0, 1.4142, 0], ['a', 0.7071, 0.7071, 0, 1, 0, -1.4142, 0],
110
+ ['M', -0.7071, 1], ['a', 0.7071, 0.7071, 0, 1, 0, 1.4142, 0], ['a', 0.7071, 0.7071, 0, 1, 0, -1.4142, 0],
111
+ ['M', 0.2929, 1], ['a', 0.7071, 0.7071, 0, 1, 0, 1.4142, 0], ['a', 0.7071, 0.7071, 0, 1, 0, -1.4142, 0],
112
+ ]
113
+ }
114
+ ],
115
+
116
+ // Filled circles at tile corners + center (5-point dice pattern)
117
+ circles: [
118
+ { type: 'circle', cx: 0.5, cy: 0.5, r: 0.2, fill: true },
119
+ { type: 'circle', cx: 0, cy: 0, r: 0.2, fill: true },
120
+ { type: 'circle', cx: 1, cy: 0, r: 0.2, fill: true },
121
+ { type: 'circle', cx: 0, cy: 1, r: 0.2, fill: true },
122
+ { type: 'circle', cx: 1, cy: 1, r: 0.2, fill: true }
123
+ ],
124
+
125
+ // Diagonal cross strokes with a filled circle at the center
126
+ pip: [
127
+ { type: 'line', x1: 0, y1: 0, x2: 1, y2: 1 },
128
+ { type: 'line', x1: 0, y1: 1, x2: 1, y2: 0 },
129
+ { type: 'circle', cx: 0.5, cy: 0.5, r: 0.22, fill: true }
130
+ ],
131
+
132
+ // Two outlined circles + two filled circles in a 2×2 grid
133
+ rings: [
134
+ { type: 'circle', cx: 0.25, cy: 0.25, r: 0.2 },
135
+ { type: 'circle', cx: 0.75, cy: 0.75, r: 0.2 },
136
+ { type: 'circle', cx: 0.25, cy: 0.75, r: 0.2, fill: true },
137
+ { type: 'circle', cx: 0.75, cy: 0.25, r: 0.2, fill: true }
138
+ ],
139
+
140
+ // Fish-scale: circles centered at corners + tile center, r = 0.5√2 so each
141
+ // circle passes through its adjacent neighbors' centers. Even-odd fill produces
142
+ // the scallop/petal pattern where overlapping regions alternate filled/clear.
143
+ petals: [
144
+ {
145
+ type: 'path', fill: true, fillRule: 'evenodd',
146
+ d: [
147
+ // center (0, 0) r=0.7071 leftmost = (-0.7071, 0)
148
+ ['M', -0.7071, 0], ['a', 0.7071, 0.7071, 0, 1, 0, 1.4142, 0], ['a', 0.7071, 0.7071, 0, 1, 0, -1.4142, 0],
149
+ // center (1, 0) leftmost = (0.2929, 0)
150
+ ['M', 0.2929, 0], ['a', 0.7071, 0.7071, 0, 1, 0, 1.4142, 0], ['a', 0.7071, 0.7071, 0, 1, 0, -1.4142, 0],
151
+ // center (0.5, 0.5) leftmost = (-0.2071, 0.5)
152
+ ['M', -0.2071, 0.5], ['a', 0.7071, 0.7071, 0, 1, 0, 1.4142, 0], ['a', 0.7071, 0.7071, 0, 1, 0, -1.4142, 0],
153
+ // center (0, 1) leftmost = (-0.7071, 1)
154
+ ['M', -0.7071, 1], ['a', 0.7071, 0.7071, 0, 1, 0, 1.4142, 0], ['a', 0.7071, 0.7071, 0, 1, 0, -1.4142, 0],
155
+ // center (1, 1) leftmost = (0.2929, 1)
156
+ ['M', 0.2929, 1], ['a', 0.7071, 0.7071, 0, 1, 0, 1.4142, 0], ['a', 0.7071, 0.7071, 0, 1, 0, -1.4142, 0],
157
+ ]
158
+ }
159
+ ],
160
+
161
+ // ── Polygon-based ───────────────────────────────────────────────────────────
162
+
163
+ // Three filled triangles tiling the corners + center of the tile
164
+ triangles: [
165
+ { type: 'polygon', points: [[0, 0.5], [0.5, 1], [0, 1]], fill: true },
166
+ { type: 'polygon', points: [[0.5, 0], [0, 0], [0, 0.5]], fill: true },
167
+ { type: 'polygon', points: [[1, 0], [0.5, 0.5], [1, 1]], fill: true }
168
+ ],
169
+
170
+ // Two filled triangles scattered at opposite corners
171
+ shards: [
172
+ { type: 'polygon', points: [[0.25, 0.017], [0, 0.417], [0.5, 0.417]], fill: true },
173
+ { type: 'polygon', points: [[0.5, 0.583], [1, 0.583], [0.75, 0.983]], fill: true }
174
+ ],
175
+
176
+ // Diagonal corner split — two-tone polygon division
177
+ wedge: [
178
+ { type: 'polygon', points: [[1, 1], [0.45, 1], [0, 0.55], [0, 0]], fill: true },
179
+ { type: 'polygon', points: [[1, 0], [0, 0], [1, 1]], fill: true, fillOpacity: 0.55 }
180
+ ],
181
+
182
+ // Two triangles pointing inward from top and bottom edges
183
+ argyle: [
184
+ { type: 'polygon', points: [[1, 0], [0.5, 0.5], [0, 0]], fill: true },
185
+ { type: 'polygon', points: [[1, 1], [0.5, 0.5], [0, 1]], fill: true }
186
+ ],
187
+
188
+ // triangles pattern rotated 90° clockwise: (x,y) → (1−y, x)
189
+ chevrons: [
190
+ { type: 'polygon', points: [[0, 0], [0.5, 0], [0, 0.5]], fill: true },
191
+ { type: 'polygon', points: [[0.5, 0], [1, 0], [1, 0.5]], fill: true },
192
+ { type: 'polygon', points: [[0, 1], [1, 1], [0.5, 0.5]], fill: true }
193
+ ],
194
+
195
+ // ── Rect-based ──────────────────────────────────────────────────────────────
196
+
197
+ checkerboard: [
198
+ { type: 'rect', x: 0, y: 0, w: 0.5, h: 0.5, fill: true },
199
+ { type: 'rect', x: 0.5, y: 0.5, w: 0.5, h: 0.5, fill: true }
200
+ ],
201
+
202
+ // Quarter-circle filled shape (bottom-left corner) with two accent dots
203
+ shell: [
204
+ { type: 'path', d: [['M', 0, 1], ['V', 0], ['H', 0.6], ['V', 0.4], ['A', 0.6, 0.6, 0, 0, 1, 0, 1]], fill: true },
205
+ { type: 'circle', cx: 0.798, cy: 0.298, r: 0.081, fill: true },
206
+ { type: 'circle', cx: 0.798, cy: 0.702, r: 0.081, fill: true }
207
+ ],
208
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Mark geometry scaling and attribute resolution utilities.
3
+ *
4
+ * All pattern coordinates are stored normalized 0–1. `scaleMark` multiplies
5
+ * every geometric value by `size`. `resolveMarkAttrs` then folds in the
6
+ * runtime fill/stroke colors and produces a plain object whose keys are
7
+ * valid SVG attribute names, ready for spread (`{...attrs}`).
8
+ *
9
+ * Path `A` (arc) commands: indices 2, 3, 4 are xRotation, largeArcFlag, and
10
+ * sweepFlag — NOT coordinates — and are never scaled.
11
+ *
12
+ * Source → SVG name mappings applied by scaleMark:
13
+ * rect w → width, h → height
14
+ * polygon points [[x,y]…] → SVG points string
15
+ * path d [[cmd,…]…] → SVG d string
16
+ */
17
+
18
+ /** @import { PatternMark } from './patterns.js' */
19
+
20
+ /**
21
+ * Scale a single SVG path command by `size`.
22
+ * @param {(string|number)[]} cmd
23
+ * @param {number} size
24
+ * @returns {(string|number)[]}
25
+ */
26
+ function scalePathCmd(cmd, size) {
27
+ const [op, ...args] = cmd
28
+ if (op === 'A' || op === 'a') {
29
+ return [op, args[0] * size, args[1] * size, args[2], args[3], args[4], args[5] * size, args[6] * size]
30
+ }
31
+ return [op, ...args.map((v) => (typeof v === 'number' ? v * size : v))]
32
+ }
33
+
34
+ /**
35
+ * Scale all geometric coordinates in a mark by `size`.
36
+ * Renames rect `w`/`h` to `width`/`height` and converts polygon/path to strings.
37
+ * @param {PatternMark} mark
38
+ * @param {number} size
39
+ * @returns {object}
40
+ */
41
+ export function scaleMark(mark, size) {
42
+ switch (mark.type) {
43
+ case 'line':
44
+ return { ...mark, x1: mark.x1 * size, y1: mark.y1 * size, x2: mark.x2 * size, y2: mark.y2 * size }
45
+ case 'circle':
46
+ return { ...mark, cx: mark.cx * size, cy: mark.cy * size, r: mark.r * size }
47
+ case 'rect': {
48
+ const { w, h, ...rest } = mark
49
+ return { ...rest, x: mark.x * size, y: mark.y * size, width: w * size, height: h * size }
50
+ }
51
+ case 'polygon':
52
+ return { ...mark, points: mark.points.map(([x, y]) => `${x * size},${y * size}`).join(' ') }
53
+ case 'path':
54
+ return { ...mark, d: mark.d.map((cmd) => scalePathCmd(cmd, size)).map((cmd) => cmd.join(' ')).join(' ') }
55
+ default:
56
+ return mark
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Resolve a scaled mark into SVG-ready `{ type, attrs }`.
62
+ * `attrs` can be spread directly onto the SVG element.
63
+ *
64
+ * Per-mark overrides respected:
65
+ * mark.strokeWidth → `stroke-width` (takes precedence over `thickness`)
66
+ * mark.fillOpacity → `fill-opacity`
67
+ * mark.opacity → `opacity`
68
+ *
69
+ * @param {object} scaledMark Output of scaleMark
70
+ * @param {{ fill: string, stroke: string, thickness: number }} appearance
71
+ * @returns {{ type: string, attrs: object }}
72
+ */
73
+ export function resolveMarkAttrs(scaledMark, { fill, stroke, thickness }) {
74
+ const { type, fill: isFill, strokeWidth, fillOpacity, opacity, fillRule, ...geometry } = scaledMark
75
+
76
+ const attrs = {
77
+ ...geometry,
78
+ fill: isFill ? fill : 'none',
79
+ stroke: isFill ? 'none' : stroke,
80
+ 'stroke-width': isFill ? 0 : (strokeWidth ?? thickness),
81
+ }
82
+ if (fillOpacity !== null && fillOpacity !== undefined) attrs['fill-opacity'] = fillOpacity
83
+ if (opacity !== null && opacity !== undefined) attrs.opacity = opacity
84
+ if (fillRule !== null && fillRule !== undefined) attrs['fill-rule'] = fillRule
85
+
86
+ return { type, attrs }
87
+ }
@@ -0,0 +1,29 @@
1
+ export class ChartSpec {
2
+ constructor(data) {
3
+ this.data = data ?? []
4
+ this.channels = {}
5
+ this.layers = []
6
+ this.options = {}
7
+ }
8
+
9
+ x(f) { this.channels.x = f; return this }
10
+ y(f) { this.channels.y = f; return this }
11
+ color(f) { this.channels.color = f; return this }
12
+ pattern(f){ this.channels.pattern = f; return this }
13
+ aes(ch) { Object.assign(this.channels, ch); return this }
14
+
15
+ bar(opts = {}) { this.layers.push({ type: 'bar', ...opts }); return this }
16
+ line(opts = {}) { this.layers.push({ type: 'line', ...opts }); return this }
17
+ area(opts = {}) { this.layers.push({ type: 'area', ...opts }); return this }
18
+ arc(opts = {}) { this.layers.push({ type: 'arc', ...opts }); return this }
19
+ point(opts = {}) { this.layers.push({ type: 'point', ...opts }); return this }
20
+
21
+ grid(opts = {}) { this.options.grid = opts; return this }
22
+ legend(opts = {}) { this.options.legend = opts; return this }
23
+ axis(type, opts = {}) { this.options[`axis_${type}`] = opts; return this }
24
+ size(w, h) { this.options.width = w; this.options.height = h; return this }
25
+ }
26
+
27
+ export function chart(data, channels = {}) {
28
+ return new ChartSpec(data).aes(channels)
29
+ }
@@ -0,0 +1,33 @@
1
+ <script>
2
+ let {
3
+ x = 0,
4
+ y = 0,
5
+ size = 1,
6
+ fill = 'currentColor',
7
+ stroke = 'currentColor',
8
+ onclick,
9
+ onmouseover,
10
+ onmouseleave,
11
+ onfocus,
12
+ ...restProps
13
+ } = $props()
14
+
15
+ let r = $derived(size * 3.534)
16
+ let props = $derived({ rx: r * 0.1, ry: r * 0.1, ...restProps })
17
+ </script>
18
+
19
+ <rect
20
+ x={x - r}
21
+ y={y - r}
22
+ width={r * 2}
23
+ height={r * 2}
24
+ {fill}
25
+ {stroke}
26
+ {...props}
27
+ role="button"
28
+ {onclick}
29
+ {onmouseover}
30
+ {onmouseleave}
31
+ {onfocus}
32
+ tabindex="0"
33
+ />
@@ -0,0 +1,37 @@
1
+ <script>
2
+ import { namedShapes } from './constants'
3
+
4
+ let {
5
+ x = 0,
6
+ y = 0,
7
+ size = 1,
8
+ fill = 'none',
9
+ stroke = 'currentColor',
10
+ thickness = 1,
11
+ name = 'circle',
12
+ onclick,
13
+ onmouseover,
14
+ onmouseleave,
15
+ onfocus,
16
+ onblur
17
+ } = $props()
18
+
19
+ let d = $derived(name in namedShapes ? namedShapes[name](size) : namedShapes['circle'](size))
20
+ </script>
21
+
22
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
23
+ <path
24
+ {d}
25
+ {fill}
26
+ {stroke}
27
+ transform="translate({x},{y})"
28
+ stroke-width={thickness}
29
+ fill-rule="nonzero"
30
+ role="button"
31
+ {onclick}
32
+ {onmouseover}
33
+ {onmouseleave}
34
+ {onfocus}
35
+ {onblur}
36
+ tabindex="0"
37
+ />
@@ -0,0 +1,4 @@
1
+ import { scaledPathCollection } from '../../lib/utils'
2
+ import paths from './shapes.json' with { type: 'json' }
3
+
4
+ export const namedShapes = scaledPathCollection(paths)
@@ -0,0 +1,9 @@
1
+ import { namedShapes } from './constants'
2
+ import { default as Shape } from './Shape.svelte'
3
+ import { default as RoundedSquare } from './RoundedSquare.svelte'
4
+
5
+ export const shapes = [...Object.keys(namedShapes), 'rounded-square']
6
+ export const components = {
7
+ default: Shape,
8
+ 'rounded-square': RoundedSquare
9
+ }
@@ -0,0 +1,60 @@
1
+ <svg
2
+ class="plot"
3
+ fill="currentColor"
4
+ font-family="system-ui, sans-serif"
5
+ font-size="10"
6
+ text-anchor="middle"
7
+ width="688"
8
+ height="60"
9
+ viewBox="0 0 688 60"
10
+ >
11
+ <style>
12
+ :where(.plot) {
13
+ --plot-background: white;
14
+ display: block;
15
+ height: auto;
16
+ height: intrinsic;
17
+ max-width: 100%;
18
+ }
19
+ :where(.plot text),
20
+ :where(.plot tspan) {
21
+ white-space: pre;
22
+ }
23
+ </style>
24
+ <g aria-label="x-axis tick" fill="none" stroke="currentColor"
25
+ ><path transform="translate(68,30)" d="M0,0L0,6"></path><path
26
+ transform="translate(160,30)"
27
+ d="M0,0L0,6"
28
+ ></path><path transform="translate(252,30)" d="M0,0L0,6"></path><path
29
+ transform="translate(344,30)"
30
+ d="M0,0L0,6"
31
+ ></path><path transform="translate(436,30)" d="M0,0L0,6"></path><path
32
+ transform="translate(528,30)"
33
+ d="M0,0L0,6"
34
+ ></path><path transform="translate(620,30)" d="M0,0L0,6"></path></g
35
+ ><g aria-label="x-axis tick label" transform="translate(0,9)"
36
+ ><text y="0.71em" transform="translate(68,30)">asterisk</text><text
37
+ y="0.71em"
38
+ transform="translate(160,30)">circle</text
39
+ ><text y="0.71em" transform="translate(252,30)">diamond2</text><text
40
+ y="0.71em"
41
+ transform="translate(344,30)">plus</text
42
+ ><text y="0.71em" transform="translate(436,30)">square2</text><text
43
+ y="0.71em"
44
+ transform="translate(528,30)">times</text
45
+ ><text y="0.71em" transform="translate(620,30)">triangle2</text></g
46
+ ><g aria-label="dot" fill="none" stroke="currentColor" stroke-width="1.5"
47
+ ><path transform="translate(160,15.25)" d="M4.5,0A4.5,4.5,0,1,1,-4.5,0A4.5,4.5,0,1,1,4.5,0"
48
+ ></path><path transform="translate(344,15.25)" d="M-6.873,0L6.873,0M0,6.873L0,-6.873"
49
+ ></path><path transform="translate(528,15.25)" d="M-4.87,-4.87L4.87,4.87M-4.87,4.87L4.87,-4.87"
50
+ ></path><path transform="translate(620,15.25)" d="M0,-5.443L4.714,2.721L-4.714,2.721Z"
51
+ ></path><path
52
+ transform="translate(68,15.25)"
53
+ d="M0,4.769L0,-4.769M-4.13,-2.384L4.13,2.384M-4.13,2.384L4.13,-2.384"
54
+ ></path><path
55
+ transform="translate(436,15.25)"
56
+ d="M3.534,3.534L3.534,-3.534L-3.534,-3.534L-3.534,3.534Z"
57
+ ></path><path transform="translate(252,15.25)" d="M0,-4.995L4.995,0L0,4.995L-4.995,0Z"
58
+ ></path></g
59
+ ></svg
60
+ >
@@ -0,0 +1,60 @@
1
+ <svg
2
+ class="plot"
3
+ fill="currentColor"
4
+ font-family="system-ui, sans-serif"
5
+ font-size="10"
6
+ text-anchor="middle"
7
+ width="688"
8
+ height="60"
9
+ viewBox="0 0 688 60"
10
+ ><style>
11
+ :where(.plot) {
12
+ --plot-background: white;
13
+ display: block;
14
+ height: auto;
15
+ height: intrinsic;
16
+ max-width: 100%;
17
+ }
18
+ :where(.plot text),
19
+ :where(.plot tspan) {
20
+ white-space: pre;
21
+ }
22
+ </style><g aria-label="x-axis tick" fill="none" stroke="currentColor"
23
+ ><path transform="translate(68,30)" d="M0,0L0,6"></path><path
24
+ transform="translate(160,30)"
25
+ d="M0,0L0,6"
26
+ ></path><path transform="translate(252,30)" d="M0,0L0,6"></path><path
27
+ transform="translate(344,30)"
28
+ d="M0,0L0,6"
29
+ ></path><path transform="translate(436,30)" d="M0,0L0,6"></path><path
30
+ transform="translate(528,30)"
31
+ d="M0,0L0,6"
32
+ ></path><path transform="translate(620,30)" d="M0,0L0,6"></path></g
33
+ ><g aria-label="x-axis tick label" transform="translate(0,9)"
34
+ ><text y="0.71em" transform="translate(68,30)">circle</text><text
35
+ y="0.71em"
36
+ transform="translate(160,30)">cross</text
37
+ ><text y="0.71em" transform="translate(252,30)">diamond</text><text
38
+ y="0.71em"
39
+ transform="translate(344,30)">square</text
40
+ ><text y="0.71em" transform="translate(436,30)">star</text><text
41
+ y="0.71em"
42
+ transform="translate(528,30)">triangle</text
43
+ ><text y="0.71em" transform="translate(620,30)">wye</text></g
44
+ ><g aria-label="dot"
45
+ ><path transform="translate(68,15.25)" d="M4.5,0A4.5,4.5,0,1,1,-4.5,0A4.5,4.5,0,1,1,4.5,0"
46
+ ></path><path
47
+ transform="translate(160,15.25)"
48
+ d="M-5.35,-1.783L-1.783,-1.783L-1.783,-5.35L1.783,-5.35L1.783,-1.783L5.35,-1.783L5.35,1.783L1.783,1.783L1.783,5.35L-1.783,5.35L-1.783,1.783L-5.35,1.783Z"
49
+ ></path><path transform="translate(252,15.25)" d="M0,-7.423L4.285,0L0,7.423L-4.285,0Z"
50
+ ></path><path transform="translate(344,15.25)" d="M-3.988,-3.988h7.976v7.976h-7.976Z"
51
+ ></path><path
52
+ transform="translate(436,15.25)"
53
+ d="M0,-7.528L1.69,-2.326L7.16,-2.326L2.735,0.889L4.425,6.09L0,2.875L-4.425,6.09L-2.735,0.889L-7.16,-2.326L-1.69,-2.326Z"
54
+ ></path><path transform="translate(528,15.25)" d="M0,-6.998L6.06,3.499L-6.06,3.499Z"
55
+ ></path><path
56
+ transform="translate(620,15.25)"
57
+ d="M2.152,1.243L2.152,5.547L-2.152,5.547L-2.152,1.243L-5.88,-0.91L-3.728,-4.638L0,-2.485L3.728,-4.638L5.88,-0.91Z"
58
+ ></path></g
59
+ ></svg
60
+ >
@@ -1,51 +0,0 @@
1
- <script>
2
- import Chart from './Chart.svelte'
3
- import AxisGrid from './AxisGrid.svelte'
4
- import Axis from './Axis.svelte'
5
- import AxisTicks from './AxisTicks.svelte'
6
- import AxisLabels from './AxisLabels.svelte'
7
-
8
- export let data
9
- export let row
10
- export let col
11
- export let plot
12
- export let x
13
- export let y
14
- export let labels = { x: true, y: true }
15
-
16
- $: rowValues = [...new Set(data.map((d) => d[row]))]
17
- $: colValues = [...new Set(data.map((d) => d[col]))]
18
- </script>
19
-
20
- <div class="flex flex-col">
21
- {#each rowValues as rowItem}
22
- {@const dataFilteredByRow = data.filter((d) => d[row] === rowItem)}
23
-
24
- <div class="flex flex-row">
25
- {#each colValues as colItem}
26
- {@const dataFilteredByCol = dataFilteredByRow.filter(
27
- (d) => d[col] === colItem
28
- )}
29
-
30
- <Chart data={dataFilteredByCol} {x} {y}>
31
- <Axis name="x" count={7} gap={10}>
32
- <AxisTicks side="bottom">
33
- {#if labels.x}
34
- <AxisLabels angle={-60} />
35
- {/if}
36
- </AxisTicks>
37
- </Axis>
38
- <Axis name="y" gap={10}>
39
- <AxisTicks side="left">
40
- {#if labels.y}
41
- <AxisLabels />
42
- {/if}
43
- </AxisTicks>
44
- <AxisGrid />
45
- </Axis>
46
- <svelte:component this={plot} />
47
- </Chart>
48
- {/each}
49
- </div>
50
- {/each}
51
- </div>
@@ -1,34 +0,0 @@
1
- <script>
2
- import { getContext } from 'svelte'
3
-
4
- export let opacity = 1
5
- export let hideVertical = false
6
- export let hideHorizontal = false
7
- let chart = getContext('chart')
8
-
9
- $: opacityV = hideVertical ? 0 : opacity
10
- $: opacityH = hideHorizontal ? 0 : opacity
11
- $: xRange = $chart.axis.x.scale.range()
12
- $: yRange = $chart.axis.y.scale.range()
13
- </script>
14
-
15
- <g class="grid">
16
- {#each $chart.axis.x.ticks as tick}
17
- <line
18
- x1={tick.position}
19
- x2={tick.position}
20
- y1={yRange[0]}
21
- y2={yRange[1]}
22
- opacity={opacityV}
23
- />
24
- {/each}
25
- {#each $chart.axis.y.ticks as tick}
26
- <line
27
- y1={tick.position}
28
- y2={tick.position}
29
- x1={xRange[0]}
30
- x2={xRange[1]}
31
- opacity={opacityH}
32
- />
33
- {/each}
34
- </g>
@@ -1,16 +0,0 @@
1
- <script>
2
- export let title
3
- export let items = []
4
- </script>
5
-
6
- <ul class="flex flex-col">
7
- <p>{title}</p>
8
- {#each items as item}
9
- <li class="flex flex-row gap-5">
10
- <svg width="42" height="42" viewBox="0 0 42 42">
11
- <rect width="42" height="42" fill={item.fillUrl || item.fill} />
12
- </svg>
13
- <p class="flex flex-grow">{item.label}</p>
14
- </li>
15
- {/each}
16
- </ul>
@@ -1,13 +0,0 @@
1
- <script>
2
- import Texture from './Texture.svelte'
3
- const size = 10
4
-
5
- export let thickness = 0.5
6
- export let patterns
7
- </script>
8
-
9
- <defs>
10
- {#each patterns as pattern}
11
- <Texture {...pattern} {thickness} {size} />
12
- {/each}
13
- </defs>