graphein 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/dist/animation/animate.d.ts +6 -1
  2. package/dist/animation/animate.d.ts.map +1 -1
  3. package/dist/animation/animate.js +2 -2
  4. package/dist/animation/animate.js.map +2 -2
  5. package/dist/animation/env.d.ts +5 -0
  6. package/dist/animation/env.d.ts.map +1 -1
  7. package/dist/animation/env.js +4 -0
  8. package/dist/animation/env.js.map +2 -2
  9. package/dist/animation/index.d.ts +1 -0
  10. package/dist/animation/index.d.ts.map +1 -1
  11. package/dist/animation/index.js +1 -0
  12. package/dist/animation/index.js.map +2 -2
  13. package/dist/animation/stagger.d.ts +13 -0
  14. package/dist/animation/stagger.d.ts.map +1 -0
  15. package/dist/animation/stagger.js +13 -0
  16. package/dist/animation/stagger.js.map +7 -0
  17. package/dist/axes/draw.d.ts +5 -1
  18. package/dist/axes/draw.d.ts.map +1 -1
  19. package/dist/axes/draw.js +13 -1
  20. package/dist/axes/draw.js.map +2 -2
  21. package/dist/axes/morph.d.ts +111 -0
  22. package/dist/axes/morph.d.ts.map +1 -0
  23. package/dist/axes/morph.js +207 -0
  24. package/dist/axes/morph.js.map +7 -0
  25. package/dist/axes/overlay.d.ts.map +1 -1
  26. package/dist/axes/overlay.js +88 -25
  27. package/dist/axes/overlay.js.map +2 -2
  28. package/dist/axes/text.d.ts +2 -0
  29. package/dist/axes/text.d.ts.map +1 -1
  30. package/dist/axes/text.js +1 -0
  31. package/dist/axes/text.js.map +2 -2
  32. package/dist/axes/tickLabels.d.ts +2 -0
  33. package/dist/axes/tickLabels.d.ts.map +1 -1
  34. package/dist/axes/tickLabels.js +2 -2
  35. package/dist/axes/tickLabels.js.map +2 -2
  36. package/dist/charts/annotations.d.ts +9 -3
  37. package/dist/charts/annotations.d.ts.map +1 -1
  38. package/dist/charts/annotations.js +82 -27
  39. package/dist/charts/annotations.js.map +2 -2
  40. package/dist/charts/area.d.ts +37 -1
  41. package/dist/charts/area.d.ts.map +1 -1
  42. package/dist/charts/area.js +35 -17
  43. package/dist/charts/area.js.map +2 -2
  44. package/dist/charts/bar.d.ts +53 -0
  45. package/dist/charts/bar.d.ts.map +1 -1
  46. package/dist/charts/bar.js +117 -83
  47. package/dist/charts/bar.js.map +2 -2
  48. package/dist/charts/box.d.ts +31 -0
  49. package/dist/charts/box.d.ts.map +1 -1
  50. package/dist/charts/box.js +93 -70
  51. package/dist/charts/box.js.map +2 -2
  52. package/dist/charts/bubbleMap.d.ts +20 -0
  53. package/dist/charts/bubbleMap.d.ts.map +1 -0
  54. package/dist/charts/bubbleMap.js +951 -0
  55. package/dist/charts/bubbleMap.js.map +7 -0
  56. package/dist/charts/bullet.d.ts.map +1 -1
  57. package/dist/charts/bullet.js +69 -51
  58. package/dist/charts/bullet.js.map +2 -2
  59. package/dist/charts/calendarHeatmap.d.ts.map +1 -1
  60. package/dist/charts/calendarHeatmap.js +56 -19
  61. package/dist/charts/calendarHeatmap.js.map +2 -2
  62. package/dist/charts/candlestick.d.ts +40 -0
  63. package/dist/charts/candlestick.d.ts.map +1 -0
  64. package/dist/charts/candlestick.js +325 -0
  65. package/dist/charts/candlestick.js.map +7 -0
  66. package/dist/charts/choropleth.d.ts.map +1 -1
  67. package/dist/charts/choropleth.js +46 -67
  68. package/dist/charts/choropleth.js.map +2 -2
  69. package/dist/charts/combo.d.ts.map +1 -1
  70. package/dist/charts/combo.js +127 -27
  71. package/dist/charts/combo.js.map +3 -3
  72. package/dist/charts/dumbbell.d.ts.map +1 -1
  73. package/dist/charts/dumbbell.js +100 -31
  74. package/dist/charts/dumbbell.js.map +2 -2
  75. package/dist/charts/funnel.d.ts.map +1 -1
  76. package/dist/charts/funnel.js +93 -28
  77. package/dist/charts/funnel.js.map +3 -3
  78. package/dist/charts/gantt.d.ts +22 -0
  79. package/dist/charts/gantt.d.ts.map +1 -0
  80. package/dist/charts/gantt.js +564 -0
  81. package/dist/charts/gantt.js.map +7 -0
  82. package/dist/charts/gauge.d.ts.map +1 -1
  83. package/dist/charts/gauge.js +30 -4
  84. package/dist/charts/gauge.js.map +2 -2
  85. package/dist/charts/geo.d.ts +87 -0
  86. package/dist/charts/geo.d.ts.map +1 -0
  87. package/dist/charts/geo.js +140 -0
  88. package/dist/charts/geo.js.map +7 -0
  89. package/dist/charts/geometry.d.ts +20 -0
  90. package/dist/charts/geometry.d.ts.map +1 -0
  91. package/dist/charts/geometry.js +25 -0
  92. package/dist/charts/geometry.js.map +7 -0
  93. package/dist/charts/heatmap.d.ts.map +1 -1
  94. package/dist/charts/heatmap.js +58 -49
  95. package/dist/charts/heatmap.js.map +2 -2
  96. package/dist/charts/histogram.d.ts +1 -1
  97. package/dist/charts/histogram.d.ts.map +1 -1
  98. package/dist/charts/histogram.js +49 -31
  99. package/dist/charts/histogram.js.map +2 -2
  100. package/dist/charts/index.d.ts +35 -1
  101. package/dist/charts/index.d.ts.map +1 -1
  102. package/dist/charts/index.js +12 -0
  103. package/dist/charts/index.js.map +2 -2
  104. package/dist/charts/legibility.d.ts +38 -0
  105. package/dist/charts/legibility.d.ts.map +1 -0
  106. package/dist/charts/legibility.js +72 -0
  107. package/dist/charts/legibility.js.map +7 -0
  108. package/dist/charts/line.d.ts +39 -1
  109. package/dist/charts/line.d.ts.map +1 -1
  110. package/dist/charts/line.js +48 -16
  111. package/dist/charts/line.js.map +2 -2
  112. package/dist/charts/matrix.d.ts +2 -1
  113. package/dist/charts/matrix.d.ts.map +1 -1
  114. package/dist/charts/matrix.js +481 -319
  115. package/dist/charts/matrix.js.map +3 -3
  116. package/dist/charts/morphFrame.d.ts +83 -0
  117. package/dist/charts/morphFrame.d.ts.map +1 -0
  118. package/dist/charts/morphFrame.js +128 -0
  119. package/dist/charts/morphFrame.js.map +7 -0
  120. package/dist/charts/pie.d.ts.map +1 -1
  121. package/dist/charts/pie.js +89 -26
  122. package/dist/charts/pie.js.map +2 -2
  123. package/dist/charts/pieState.d.ts +27 -0
  124. package/dist/charts/pieState.d.ts.map +1 -0
  125. package/dist/charts/pieState.js +55 -0
  126. package/dist/charts/pieState.js.map +7 -0
  127. package/dist/charts/radar.d.ts +62 -0
  128. package/dist/charts/radar.d.ts.map +1 -0
  129. package/dist/charts/radar.js +912 -0
  130. package/dist/charts/radar.js.map +7 -0
  131. package/dist/charts/radialBar.d.ts +60 -0
  132. package/dist/charts/radialBar.d.ts.map +1 -0
  133. package/dist/charts/radialBar.js +708 -0
  134. package/dist/charts/radialBar.js.map +7 -0
  135. package/dist/charts/sankey.d.ts.map +1 -1
  136. package/dist/charts/sankey.js +223 -57
  137. package/dist/charts/sankey.js.map +3 -3
  138. package/dist/charts/scatter.d.ts +31 -0
  139. package/dist/charts/scatter.d.ts.map +1 -1
  140. package/dist/charts/scatter.js +48 -12
  141. package/dist/charts/scatter.js.map +2 -2
  142. package/dist/charts/slope.d.ts.map +1 -1
  143. package/dist/charts/slope.js +55 -3
  144. package/dist/charts/slope.js.map +2 -2
  145. package/dist/charts/sunburst.d.ts +14 -0
  146. package/dist/charts/sunburst.d.ts.map +1 -0
  147. package/dist/charts/sunburst.js +885 -0
  148. package/dist/charts/sunburst.js.map +7 -0
  149. package/dist/charts/table.d.ts +2 -1
  150. package/dist/charts/table.d.ts.map +1 -1
  151. package/dist/charts/table.js +214 -224
  152. package/dist/charts/table.js.map +3 -3
  153. package/dist/charts/tableView/canvas.d.ts +16 -1
  154. package/dist/charts/tableView/canvas.d.ts.map +1 -1
  155. package/dist/charts/tableView/canvas.js +361 -252
  156. package/dist/charts/tableView/canvas.js.map +3 -3
  157. package/dist/charts/tableView/conditional.d.ts +66 -40
  158. package/dist/charts/tableView/conditional.d.ts.map +1 -1
  159. package/dist/charts/tableView/conditional.js +163 -256
  160. package/dist/charts/tableView/conditional.js.map +3 -3
  161. package/dist/charts/tableView/dom.d.ts +26 -2
  162. package/dist/charts/tableView/dom.d.ts.map +1 -1
  163. package/dist/charts/tableView/dom.js +609 -269
  164. package/dist/charts/tableView/dom.js.map +3 -3
  165. package/dist/charts/tableView/layout.d.ts +22 -0
  166. package/dist/charts/tableView/layout.d.ts.map +1 -0
  167. package/dist/charts/tableView/layout.js +246 -0
  168. package/dist/charts/tableView/layout.js.map +7 -0
  169. package/dist/charts/tableView/sketch.d.ts +3 -2
  170. package/dist/charts/tableView/sketch.d.ts.map +1 -1
  171. package/dist/charts/tableView/sketch.js +2 -2
  172. package/dist/charts/tableView/sketch.js.map +2 -2
  173. package/dist/charts/tableView/sketchBar.d.ts +7 -0
  174. package/dist/charts/tableView/sketchBar.d.ts.map +1 -0
  175. package/dist/charts/tableView/sketchBar.js +32 -0
  176. package/dist/charts/tableView/sketchBar.js.map +7 -0
  177. package/dist/charts/tableView/sort.d.ts +9 -0
  178. package/dist/charts/tableView/sort.d.ts.map +1 -0
  179. package/dist/charts/tableView/sort.js +70 -0
  180. package/dist/charts/tableView/sort.js.map +7 -0
  181. package/dist/charts/tableView/sparkline.d.ts +30 -0
  182. package/dist/charts/tableView/sparkline.d.ts.map +1 -0
  183. package/dist/charts/tableView/sparkline.js +63 -0
  184. package/dist/charts/tableView/sparkline.js.map +7 -0
  185. package/dist/charts/tableView/style.d.ts +67 -0
  186. package/dist/charts/tableView/style.d.ts.map +1 -0
  187. package/dist/charts/tableView/style.js +131 -0
  188. package/dist/charts/tableView/style.js.map +7 -0
  189. package/dist/charts/tableView/types.d.ts +69 -46
  190. package/dist/charts/tableView/types.d.ts.map +1 -1
  191. package/dist/charts/tableView/types.js +22 -87
  192. package/dist/charts/tableView/types.js.map +2 -2
  193. package/dist/charts/tableView.d.ts +10 -5
  194. package/dist/charts/tableView.d.ts.map +1 -1
  195. package/dist/charts/tableView.js +12 -8
  196. package/dist/charts/tableView.js.map +2 -2
  197. package/dist/charts/treemap.d.ts.map +1 -1
  198. package/dist/charts/treemap.js +177 -68
  199. package/dist/charts/treemap.js.map +3 -3
  200. package/dist/charts/trendline.d.ts +13 -5
  201. package/dist/charts/trendline.d.ts.map +1 -1
  202. package/dist/charts/trendline.js +205 -56
  203. package/dist/charts/trendline.js.map +2 -2
  204. package/dist/charts/waterfall.d.ts.map +1 -1
  205. package/dist/charts/waterfall.js +76 -5
  206. package/dist/charts/waterfall.js.map +2 -2
  207. package/dist/index.d.ts +1 -1
  208. package/dist/index.js +1 -1
  209. package/dist/index.js.map +1 -1
  210. package/dist/interaction/cartesian.d.ts +4 -1
  211. package/dist/interaction/cartesian.d.ts.map +1 -1
  212. package/dist/interaction/cartesian.js +104 -34
  213. package/dist/interaction/cartesian.js.map +2 -2
  214. package/dist/interaction/controller.d.ts +29 -1
  215. package/dist/interaction/controller.d.ts.map +1 -1
  216. package/dist/interaction/controller.js +131 -8
  217. package/dist/interaction/controller.js.map +2 -2
  218. package/dist/interaction/focus.d.ts +23 -0
  219. package/dist/interaction/focus.d.ts.map +1 -0
  220. package/dist/interaction/focus.js +65 -0
  221. package/dist/interaction/focus.js.map +7 -0
  222. package/dist/interaction/tooltip.d.ts +6 -0
  223. package/dist/interaction/tooltip.d.ts.map +1 -1
  224. package/dist/interaction/tooltip.js +41 -16
  225. package/dist/interaction/tooltip.js.map +2 -2
  226. package/dist/interaction/types.d.ts +19 -0
  227. package/dist/interaction/types.d.ts.map +1 -1
  228. package/dist/interaction/veil.d.ts +25 -0
  229. package/dist/interaction/veil.d.ts.map +1 -0
  230. package/dist/interaction/veil.js +35 -0
  231. package/dist/interaction/veil.js.map +7 -0
  232. package/dist/pivot/pivot.d.ts +18 -0
  233. package/dist/pivot/pivot.d.ts.map +1 -1
  234. package/dist/pivot/pivot.js +46 -34
  235. package/dist/pivot/pivot.js.map +2 -2
  236. package/dist/render/chromeMotion.d.ts +65 -0
  237. package/dist/render/chromeMotion.d.ts.map +1 -0
  238. package/dist/render/chromeMotion.js +79 -0
  239. package/dist/render/chromeMotion.js.map +7 -0
  240. package/dist/render/pathSample.d.ts +24 -0
  241. package/dist/render/pathSample.d.ts.map +1 -0
  242. package/dist/render/pathSample.js +76 -0
  243. package/dist/render/pathSample.js.map +7 -0
  244. package/dist/render/transient.d.ts +18 -0
  245. package/dist/render/transient.d.ts.map +1 -0
  246. package/dist/render/transient.js +19 -0
  247. package/dist/render/transient.js.map +7 -0
  248. package/dist/runtime/candlestick.d.ts +112 -0
  249. package/dist/runtime/candlestick.d.ts.map +1 -0
  250. package/dist/runtime/candlestick.js +531 -0
  251. package/dist/runtime/candlestick.js.map +7 -0
  252. package/dist/runtime/cartesian.d.ts +14 -3
  253. package/dist/runtime/cartesian.d.ts.map +1 -1
  254. package/dist/runtime/cartesian.js.map +2 -2
  255. package/dist/runtime/chartAnimation.d.ts +54 -7
  256. package/dist/runtime/chartAnimation.d.ts.map +1 -1
  257. package/dist/runtime/chartAnimation.js +146 -28
  258. package/dist/runtime/chartAnimation.js.map +2 -2
  259. package/dist/runtime/chartRuntime.d.ts +42 -0
  260. package/dist/runtime/chartRuntime.d.ts.map +1 -1
  261. package/dist/runtime/chartRuntime.js +196 -30
  262. package/dist/runtime/chartRuntime.js.map +2 -2
  263. package/dist/runtime/dashboardDom.d.ts.map +1 -1
  264. package/dist/runtime/dashboardDom.js +45 -0
  265. package/dist/runtime/dashboardDom.js.map +2 -2
  266. package/dist/runtime/facet.d.ts +1 -1
  267. package/dist/runtime/facet.d.ts.map +1 -1
  268. package/dist/runtime/gantt.d.ts +137 -0
  269. package/dist/runtime/gantt.d.ts.map +1 -0
  270. package/dist/runtime/gantt.js +647 -0
  271. package/dist/runtime/gantt.js.map +7 -0
  272. package/dist/runtime/morph.d.ts +33 -0
  273. package/dist/runtime/morph.d.ts.map +1 -0
  274. package/dist/runtime/morph.js +332 -0
  275. package/dist/runtime/morph.js.map +7 -0
  276. package/dist/runtime/radar.d.ts +75 -0
  277. package/dist/runtime/radar.d.ts.map +1 -0
  278. package/dist/runtime/radar.js +201 -0
  279. package/dist/runtime/radar.js.map +7 -0
  280. package/dist/runtime/radialBar.d.ts +81 -0
  281. package/dist/runtime/radialBar.d.ts.map +1 -0
  282. package/dist/runtime/radialBar.js +125 -0
  283. package/dist/runtime/radialBar.js.map +7 -0
  284. package/dist/runtime/report/constants.d.ts +2 -2
  285. package/dist/runtime/report/constants.d.ts.map +1 -1
  286. package/dist/runtime/runtimeShared.d.ts +3 -3
  287. package/dist/runtime/runtimeShared.d.ts.map +1 -1
  288. package/dist/runtime/sunburst.d.ts +74 -0
  289. package/dist/runtime/sunburst.d.ts.map +1 -0
  290. package/dist/runtime/sunburst.js +150 -0
  291. package/dist/runtime/sunburst.js.map +7 -0
  292. package/dist/runtime/wire.d.ts.map +1 -1
  293. package/dist/runtime/wire.js +3 -1
  294. package/dist/runtime/wire.js.map +2 -2
  295. package/dist/shape/arc.d.ts +15 -2
  296. package/dist/shape/arc.d.ts.map +1 -1
  297. package/dist/shape/arc.js +204 -32
  298. package/dist/shape/arc.js.map +2 -2
  299. package/dist/spec/chartDefinitions.d.ts +6 -0
  300. package/dist/spec/chartDefinitions.d.ts.map +1 -1
  301. package/dist/spec/chartDefinitions.js +7 -1
  302. package/dist/spec/chartDefinitions.js.map +2 -2
  303. package/dist/spec/templates.d.ts.map +1 -1
  304. package/dist/spec/templates.js +177 -2
  305. package/dist/spec/templates.js.map +2 -2
  306. package/dist/spec/types.d.ts +258 -6
  307. package/dist/spec/types.d.ts.map +1 -1
  308. package/dist/spec/types.js +6 -0
  309. package/dist/spec/types.js.map +2 -2
  310. package/dist/spec/validate/charts.js +147 -15
  311. package/dist/spec/validate/charts.js.map +2 -2
  312. package/dist/spec/validate/common.d.ts +6 -0
  313. package/dist/spec/validate/common.d.ts.map +1 -1
  314. package/dist/spec/validate/overlays.js +2 -2
  315. package/dist/spec/validate/overlays.js.map +2 -2
  316. package/dist/spec/validate.data.d.ts.map +1 -1
  317. package/dist/spec/validate.data.js +8 -3
  318. package/dist/spec/validate.data.js.map +2 -2
  319. package/package.json +1 -1
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/runtime/gantt.ts"],
4
+ "sourcesContent": ["/**\n * Gantt model builder.\n *\n * A `gantt` reads tidy rows of `{ task, start, end, group?, progress? }` and lays\n * one bar per row along a shared time (or numeric) axis, in one lane per distinct\n * task. Rows whose start/end are missing, invalid or reversed are skipped and\n * counted \u2014 never reordered or invented \u2014 and a row whose end equals its start\n * is a milestone. Like the waterfall / histogram builders it resolves a synthetic\n * vertical `base` {@link CartesianModel}: x is the time axis and y the task lanes,\n * so the shared chrome (`drawAxesUnderlay` / `drawOverlay`, annotations) renders\n * time gridlines, tick labels, task names in the left gutter, titles and the\n * group legend unchanged. `drawGantt` paints the lanes, bars and milestones.\n */\n\nimport type { Datum, Rect } from '../types';\nimport type { ThemeTokens } from '../theme';\nimport type { Annotation, BarSpec, GanttSpec, LegendConfig, LegendPosition } from '../spec/types';\nimport { accessor, inferType, toDate, toKey, toNumber } from '../util/data';\nimport { ticks as numericTicks, timeTicks } from '../ticks';\nimport { linearScale, timeScale, type ContinuousScale } from '../scales';\nimport { formatDate, formatNumber, formatValue, prettyDate } from '../format';\nimport { computeFrame, NO_PADDING, type Frame, type LegendItem } from '../layout';\nimport { fontString, measureText } from '../render/text';\nimport { resolveSketch, type ResolvedSketch } from '../spec/sketch';\nimport { ordinalColorScale, rgbaToCss } from '../color';\nimport { resolvePalette } from './categories';\nimport type { BuildOptions, CartesianModel, ResolvedSeries, Tick, XModel, YModel } from './cartesian';\n\n/** Whether the shared axis measures dates (epoch ms) or abstract numeric units. */\nexport type GanttScaleKind = 'time' | 'linear';\n\nexport interface GanttGroup {\n key: string;\n label: string;\n raw: unknown;\n color: string;\n}\n\n/** One drawable row: a bar from `start` to `end`, or a milestone when they are equal. */\nexport interface GanttTask {\n /** Lane identity (the canonical task key). */\n key: string;\n /** Raw task value, published by click selections. */\n raw: unknown;\n label: string;\n /** Epoch milliseconds on a time axis, numeric units on a linear one. */\n start: number;\n end: number;\n milestone: boolean;\n groupKey?: string;\n groupLabel?: string;\n groupRaw?: unknown;\n color: string;\n /** Completed fraction, clamped to 0..1; absent when not encoded or unusable. */\n progress?: number;\n sourceIndex: number;\n row: Datum;\n /** Lane index after sorting (top to bottom). */\n lane: number;\n /** Bar rect, or the milestone diamond's bounding box, in pixels. */\n rect: Rect;\n}\n\nexport interface GanttLane {\n key: string;\n raw: unknown;\n label: string;\n index: number;\n top: number;\n height: number;\n center: number;\n tasks: GanttTask[];\n}\n\nexport interface GanttModel {\n spec: GanttSpec;\n tokens: ThemeTokens;\n frame: Frame;\n plot: Rect;\n kind: GanttScaleKind;\n /** Drawable rows in data order. */\n tasks: GanttTask[];\n lanes: GanttLane[];\n /** Groups present among drawable rows, in color-domain order. */\n groups: GanttGroup[];\n grouped: boolean;\n /** Axis domain (the data extent, snapped out to nearby ticks). */\n domain: [number, number];\n /** The drawable rows' own extent (plus annotated instants). */\n extent: [number, number];\n xScale: ContinuousScale;\n laneHeight: number;\n barHeight: number;\n milestoneRadius: number;\n cornerRadius: number;\n showLabels: boolean;\n /** Task names are drawn in the left gutter (so bar labels show details instead). */\n laneAxis: boolean;\n /** Input rows that could not be drawn (missing / invalid / reversed bounds). */\n skipped: number;\n base: CartesianModel;\n sketch: ResolvedSketch | null;\n}\n\nexport interface GanttBuildOptions extends BuildOptions {\n /** Unfiltered rows, so group colors stay stable while a cross-filter subsets the data. */\n colorSource?: readonly Datum[];\n}\n\nconst MINUTE = 60_000;\nconst HOUR = 60 * MINUTE;\nconst DAY = 24 * HOUR;\nconst YEAR = 365 * DAY;\n/** Very short tasks still draw a visible sliver. */\nconst MIN_BAR_WIDTH = 3;\nconst MAX_BAR_HEIGHT = 26;\nconst MAX_MILESTONE_RADIUS = 11;\n\nfunction isFiniteNumber(value: number): boolean {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nfunction labelFor(value: unknown): string {\n if (value == null || value === '') return '(blank)';\n if (value instanceof Date) return Number.isFinite(value.getTime()) ? formatDate(value, '%b %e, %Y') : String(value);\n return String(value);\n}\n\nfunction titleInput(spec: GanttSpec): { text?: string; subtitle?: string; align?: 'left' | 'center' | 'right' } | undefined {\n if (typeof spec.title === 'string') return { text: spec.title };\n if (spec.title) return { text: spec.title.text, subtitle: spec.title.subtitle, align: spec.title.align };\n return undefined;\n}\n\n/**\n * A quantitative start/end (declared, or inferred from numeric values) selects a\n * linear axis of abstract units; everything else is a time axis.\n */\nexport function ganttScaleKind(spec: GanttSpec, data: readonly Datum[]): GanttScaleKind {\n const { start, end } = spec.encoding;\n const declared = start.type ?? end.type;\n if (declared === 'quantitative') return 'linear';\n if (declared === 'temporal') return 'time';\n const inferred = inferType(data, start.field);\n if (inferred === 'quantitative') return 'linear';\n if (inferred === 'temporal') return 'time';\n return inferType(data, end.field) === 'quantitative' ? 'linear' : 'time';\n}\n\n/** Parse a start/end/annotation value onto the axis (NaN when unusable). */\nexport function ganttValue(kind: GanttScaleKind, value: unknown): number {\n if (kind === 'linear') return toNumber(value);\n const date = toDate(value);\n return date ? date.getTime() : NaN;\n}\n\ninterface ParsedRows {\n tasks: GanttTask[];\n skipped: number;\n}\n\nfunction parseRows(spec: GanttSpec, data: readonly Datum[], kind: GanttScaleKind): ParsedRows {\n const enc = spec.encoding;\n const readTask = accessor(enc.task.field);\n const readStart = accessor(enc.start.field);\n const readEnd = accessor(enc.end.field);\n const readGroup = enc.group ? accessor(enc.group.field) : null;\n const readProgress = enc.progress ? accessor(enc.progress.field) : null;\n const tasks: GanttTask[] = [];\n let skipped = 0;\n data.forEach((row, sourceIndex) => {\n const start = ganttValue(kind, readStart(row));\n const end = ganttValue(kind, readEnd(row));\n // Missing or reversed bounds are an unresolved data decision: the row is\n // disclosed as unrepresented, never swapped, clipped or given a duration.\n if (!isFiniteNumber(start) || !isFiniteNumber(end) || end < start) {\n skipped++;\n return;\n }\n const raw = readTask(row);\n const groupRaw = readGroup ? readGroup(row) : undefined;\n const progressValue = readProgress ? toNumber(readProgress(row)) : NaN;\n tasks.push({\n key: toKey(raw),\n raw,\n label: labelFor(raw),\n start,\n end,\n milestone: end === start,\n groupKey: readGroup ? toKey(groupRaw) : undefined,\n groupLabel: readGroup ? labelFor(groupRaw) : undefined,\n groupRaw,\n color: '',\n progress: isFiniteNumber(progressValue) ? clamp(progressValue, 0, 1) : undefined,\n sourceIndex,\n row,\n lane: 0,\n rect: { x: 0, y: 0, width: 0, height: 0 },\n });\n });\n return { tasks, skipped };\n}\n\ninterface LaneOrder {\n key: string;\n raw: unknown;\n label: string;\n first: number;\n minStart: number;\n minEnd: number;\n total: number;\n tasks: GanttTask[];\n}\n\n/** One lane per distinct task, ordered by `sort` (ties keep first-seen order). */\nfunction orderLanes(tasks: readonly GanttTask[], sort: GanttSpec['sort']): LaneOrder[] {\n const byKey = new Map<string, LaneOrder>();\n const lanes: LaneOrder[] = [];\n tasks.forEach((task, index) => {\n let lane = byKey.get(task.key);\n if (!lane) {\n lane = { key: task.key, raw: task.raw, label: task.label, first: index, minStart: task.start, minEnd: task.end, total: 0, tasks: [] };\n byKey.set(task.key, lane);\n lanes.push(lane);\n }\n lane.minStart = Math.min(lane.minStart, task.start);\n lane.minEnd = Math.min(lane.minEnd, task.end);\n lane.total += task.end - task.start;\n lane.tasks.push(task);\n });\n const metric: Record<string, ((lane: LaneOrder) => number) | undefined> = {\n start: (lane) => lane.minStart,\n end: (lane) => lane.minEnd,\n duration: (lane) => -lane.total,\n };\n const by = sort ? metric[sort] : undefined;\n return by ? lanes.slice().sort((a, b) => by(a) - by(b) || a.first - b.first) : lanes;\n}\n\ninterface GroupResolution {\n groups: GanttGroup[];\n colorOf: (key: string) => string;\n grouped: boolean;\n /** Bars without a group: an explicit palette's first color, else the theme accent. */\n plain: string;\n /** Ungrouped milestones read as key dates in the theme's ink. */\n plainMilestone: string;\n}\n\nfunction resolveGroups(spec: GanttSpec, tokens: ThemeTokens, tasks: readonly GanttTask[], colorSource: readonly Datum[]): GroupResolution {\n const palette = resolvePalette(spec.palette, tokens);\n const plain = spec.palette !== undefined && palette.length > 0 ? palette[0] : tokens.color.accent;\n const groupDef = spec.encoding.group;\n if (!groupDef) return { groups: [], colorOf: () => plain, grouped: false, plain, plainMilestone: tokens.color.text };\n // Colors follow an explicit domain, then the unfiltered rows' first-seen order,\n // so a group keeps its color while cross-filters subset the plan.\n const explicit = groupDef.scale?.domain;\n const order = new Map<string, number>();\n const note = (key: string) => {\n if (!order.has(key)) order.set(key, order.size);\n };\n if (Array.isArray(explicit)) for (const value of explicit) note(toKey(value));\n const read = accessor(groupDef.field);\n for (const row of colorSource) note(toKey(read(row)));\n for (const task of tasks) note(task.groupKey!);\n const scale = ordinalColorScale({ domain: [...order.keys()], palette });\n const cache = new Map<string, string>();\n const colorOf = (key: string): string => {\n let color = cache.get(key);\n if (!color) cache.set(key, (color = rgbaToCss(scale.map(key))));\n return color;\n };\n const present = new Map<string, GanttGroup>();\n for (const task of tasks) {\n const key = task.groupKey!;\n if (!present.has(key)) present.set(key, { key, label: task.groupLabel!, raw: task.groupRaw, color: colorOf(key) });\n }\n const groups = [...present.values()].sort((a, b) => (order.get(a.key) ?? 0) - (order.get(b.key) ?? 0));\n return { groups, colorOf, grouped: true, plain, plainMilestone: tokens.color.text };\n}\n\nfunction legendShown(spec: GanttSpec, count: number): boolean {\n const cfg = spec.legend;\n if (cfg === false) return false;\n if (typeof cfg === 'object' && cfg.show === false) return false;\n return count > 1;\n}\n\n/** Values the annotations place on the time axis, so a deadline past the plan stays in view. */\nfunction annotationValues(spec: GanttSpec, kind: GanttScaleKind): number[] {\n const list = Array.isArray(spec.annotations) ? spec.annotations : [];\n const out: number[] = [];\n const add = (value: unknown) => {\n const n = ganttValue(kind, value);\n if (isFiniteNumber(n)) out.push(n);\n };\n for (const ann of list as Annotation[]) {\n if (!ann || typeof ann !== 'object') continue;\n if (ann.type === 'point') add(ann.x);\n else if (ann.axis === 'x') {\n if (ann.value !== undefined) add(ann.value);\n if (ann.from !== undefined) add(ann.from);\n if (ann.to !== undefined) add(ann.to);\n }\n }\n return out;\n}\n\nfunction explicitDomain(spec: GanttSpec, kind: GanttScaleKind): [number, number] | null {\n const domain = spec.encoding.start.scale?.domain ?? spec.encoding.end.scale?.domain;\n if (!Array.isArray(domain) || domain.length !== 2) return null;\n const lo = ganttValue(kind, domain[0]);\n const hi = ganttValue(kind, domain[1]);\n return isFiniteNumber(lo) && isFiniteNumber(hi) && hi > lo ? [lo, hi] : null;\n}\n\n/** The data extent (plus annotated instants), widened when it is a single instant. */\nfunction dataExtent(spec: GanttSpec, kind: GanttScaleKind, tasks: readonly GanttTask[]): [number, number] {\n let lo = Infinity;\n let hi = -Infinity;\n for (const task of tasks) {\n lo = Math.min(lo, task.start);\n hi = Math.max(hi, task.end);\n }\n if (tasks.length > 0) {\n for (const value of annotationValues(spec, kind)) {\n lo = Math.min(lo, value);\n hi = Math.max(hi, value);\n }\n }\n if (!isFiniteNumber(lo) || !isFiniteNumber(hi)) return kind === 'time' ? [0, DAY] : [0, 1];\n if (!isFiniteNumber(hi - lo)) return [lo, hi];\n if (hi === lo) {\n const pad = kind === 'time' ? DAY : Math.abs(lo) > 0 ? Math.abs(lo) * 0.1 : 1;\n return [lo - pad, hi + pad];\n }\n return [lo, hi];\n}\n\nfunction rawTicks(kind: GanttScaleKind, lo: number, hi: number, count: number): number[] {\n return kind === 'time' ? timeTicks(lo, hi, count) : numericTicks(lo, hi, count);\n}\n\ninterface AxisTicks {\n domain: [number, number];\n values: number[];\n}\n\n/**\n * Ticks for the extent and the domain they imply: the extent snaps out to the\n * neighbouring ticks when that adds little empty time, so the axis usually\n * starts and ends on a labelled boundary. The domain and the ticks come from one\n * interval choice, so a snapped edge never shifts the tick step.\n */\nfunction axisTicks(spec: GanttSpec, kind: GanttScaleKind, extent: [number, number], explicit: [number, number] | null, count: number): AxisTicks {\n const [lo, hi] = explicit ?? extent;\n const values = rawTicks(kind, lo, hi, count).filter(isFiniteNumber);\n const userTicks = spec.axes?.x?.tickValues;\n // Explicit ticks parse like the data (ISO strings or Dates on a time axis); if none are usable, keep the automatic ones.\n const parsed = Array.isArray(userTicks)\n ? userTicks.map((v) => ganttValue(kind, v)).filter(isFiniteNumber).sort((a, b) => a - b)\n : [];\n const ticks = parsed.length > 0 ? parsed : values;\n if (explicit) return { domain: explicit, values: ticks };\n const span = hi - lo;\n if (!(span > 0) || !isFiniteNumber(span) || values.length < 2) return { domain: [lo, hi], values: ticks };\n const first = values[0];\n const last = values[values.length - 1];\n return {\n domain: [\n first <= lo && lo - first <= span * 0.08 ? first : lo,\n last >= hi && last - hi <= span * 0.08 ? last : hi,\n ],\n values: ticks,\n };\n}\n\nfunction tickCountFor(spec: GanttSpec, width: number): number {\n const explicit = spec.axes?.x?.ticks;\n if (typeof explicit === 'number' && Number.isFinite(explicit) && explicit >= 1) return Math.round(explicit);\n return clamp(Math.round(width / 80), 2, 10);\n}\n\n/**\n * Room for labelled time-axis rules and bands: their labels sit in a strip at\n * the top (or bottom) of the plot, so lanes start below it and the label never\n * covers a bar or its text.\n */\nfunction annotationStrips(spec: GanttSpec, tokens: ThemeTokens, height: number): { top: number; bottom: number } {\n const list = Array.isArray(spec.annotations) ? spec.annotations : [];\n const strip = Math.ceil(tokens.font.size.small * 1.2 + 6);\n let top = 0;\n let bottom = 0;\n for (const ann of list as Annotation[]) {\n if (!ann || typeof ann !== 'object' || !ann.label || ann.type === 'point' || ann.axis !== 'x') continue;\n const position = ann.labelPosition ?? 'end';\n if (position === 'end') top = strip;\n else if (position === 'start') bottom = strip;\n }\n return height >= (top + bottom) * 3 ? { top, bottom } : { top: 0, bottom: 0 };\n}\n\n/**\n * Multi-scale time tick labels: years for yearly steps, month names with the\n * year where it changes, day dates for daily/weekly steps, and clock times with\n * the date at midnight for intraday steps.\n */\nexport function ganttTimeTickLabels(values: readonly number[], format?: string): string[] {\n if (format) return values.map((value) => formatValue(value, format));\n let step = Infinity;\n for (let i = 1; i < values.length; i++) step = Math.min(step, Math.abs(values[i] - values[i - 1]));\n if (!Number.isFinite(step)) step = DAY;\n return values.map((value, i) => {\n const date = new Date(value);\n if (step >= YEAR * 0.9) return formatDate(date, '%Y');\n if (step >= 27 * DAY) return i === 0 || date.getMonth() === 0 ? formatDate(date, '%b %Y') : formatDate(date, '%b');\n if (step >= DAY * 0.9) return formatDate(date, '%b %e');\n const midnight = date.getHours() === 0 && date.getMinutes() === 0;\n if (midnight) return formatDate(date, '%b %e');\n return i === 0 ? formatDate(date, '%b %e %H:%M') : formatDate(date, '%H:%M');\n });\n}\n\nfunction linearTickLabels(values: readonly number[], format?: string): string[] {\n return values.map((value) => (format ? formatValue(value, format) : formatNumber(value, ',')));\n}\n\nfunction axisFormat(spec: GanttSpec): string | undefined {\n return spec.axes?.x?.format ?? spec.encoding.start.format;\n}\n\nfunction tickLabels(spec: GanttSpec, kind: GanttScaleKind, values: readonly number[]): string[] {\n return kind === 'time' ? ganttTimeTickLabels(values, axisFormat(spec)) : linearTickLabels(values, axisFormat(spec));\n}\n\ninterface FrameInputs {\n laneLabels: string[];\n legendItems: LegendItem[];\n legendPosition: LegendPosition | null;\n}\n\nfunction ganttFrame(spec: GanttSpec, tokens: ThemeTokens, opts: BuildOptions, xLabels: string[], inputs: FrameInputs, position?: LegendPosition): Frame {\n const axes = spec.axes;\n const legendAt = position ?? inputs.legendPosition;\n return computeFrame({\n width: Math.max(0, opts.width),\n height: Math.max(0, opts.height),\n originX: opts.originX,\n originY: opts.originY,\n titleGap: opts.titleGap,\n minimumPlotSize: opts.minimumPlotSize,\n padding: { ...NO_PADDING, ...spec.padding },\n font: tokens.font,\n title: titleInput(spec),\n legend: legendAt && inputs.legendItems.length > 0 ? { items: inputs.legendItems, position: legendAt } : undefined,\n xAxis: {\n show: axes?.x?.show !== false,\n labels: axes?.x?.labels === false ? [] : xLabels,\n title: axes?.x?.title,\n edgeAnchored: true,\n },\n yAxis: {\n show: axes?.y?.show !== false,\n labels: axes?.y?.labels === false ? [] : inputs.laneLabels,\n title: axes?.y?.title ?? spec.encoding.task.title,\n },\n });\n}\n\n/**\n * Pick the legend side. An explicit position wins; otherwise a short legend\n * prefers the top band (keeping the time axis wide) and a long one the right\n * gutter, falling back to whichever side shows every group.\n */\nfunction chooseLegendFrame(spec: GanttSpec, tokens: ThemeTokens, opts: BuildOptions, xLabels: string[], inputs: FrameInputs): Frame {\n if (!inputs.legendPosition || inputs.legendItems.length === 0) return ganttFrame(spec, tokens, opts, xLabels, inputs);\n const explicit = typeof spec.legend === 'object' ? (spec.legend as LegendConfig).position : undefined;\n if (explicit) return ganttFrame(spec, tokens, opts, xLabels, inputs, explicit);\n const order: LegendPosition[] = inputs.legendItems.length > 8 ? ['right', 'top'] : ['top', 'right'];\n let best: Frame | null = null;\n for (const position of order) {\n const frame = ganttFrame(spec, tokens, opts, xLabels, inputs, position);\n const complete = frame.legendOverflow === 0 && !frame.dropped.includes('legend');\n if (complete) return frame;\n if (!best || hiddenGroups(frame, inputs) < hiddenGroups(best, inputs)) best = frame;\n }\n return best!;\n}\n\nfunction hiddenGroups(frame: Frame, inputs: FrameInputs): number {\n return frame.dropped.includes('legend') ? inputs.legendItems.length : frame.legendOverflow;\n}\n\nfunction placeTasks(tasks: GanttTask[], lanes: GanttLane[], xScale: ContinuousScale, plot: Rect, barHeight: number, radius: number): void {\n const right = plot.x + plot.width;\n for (const task of tasks) {\n const lane = lanes[task.lane];\n const x0 = xScale.map(task.start);\n if (task.milestone) {\n task.rect = { x: x0 - radius, y: lane.center - radius, width: radius * 2, height: radius * 2 };\n continue;\n }\n const x1 = xScale.map(task.end);\n let width = x1 - x0;\n let x = x0;\n if (width < MIN_BAR_WIDTH) {\n width = MIN_BAR_WIDTH;\n // Keep a widened sliver inside the plot rather than letting it hang off the edge.\n if (x + width > right && x <= right) x = Math.max(plot.x, right - width);\n }\n task.rect = { x, y: lane.center - barHeight / 2, width, height: barHeight };\n }\n}\n\nfunction finiteRect(rect: Rect): boolean {\n return isFiniteNumber(rect.x) && isFiniteNumber(rect.y) && isFiniteNumber(rect.width) && isFiniteNumber(rect.height) &&\n isFiniteNumber(rect.x + rect.width) && isFiniteNumber(rect.y + rect.height);\n}\n\n/** Font size of a mark's label: small type once lanes (milestones) or bars are roomy. */\nexport function ganttLabelSize(tokens: ThemeTokens, extent: number): number {\n return extent >= 18 ? tokens.font.size.small : tokens.font.size.tiny;\n}\n\n/** First index whose value is \u2265 `value` in ascending `values`. */\nexport function lowerBound(values: readonly number[], value: number): number {\n let lo = 0;\n let hi = values.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (values[mid] < value) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\n/** Spans up to this many pixels wide are found by a binary search; the few wider ones are scanned. */\nconst NARROW_SPAN = 128;\n\n/** One lane's marks as pixel spans, indexed by left edge for \"is anything in (lo, hi)?\" queries. */\nclass LaneSpans {\n private readonly lefts: number[] = [];\n private readonly rights: number[] = [];\n private readonly owners: GanttTask[] = [];\n private reach = 0;\n private readonly wide: Array<{ left: number; right: number; task: GanttTask }> = [];\n\n constructor(tasks: readonly GanttTask[], xScale: ContinuousScale, radius: number) {\n const narrow: Array<{ left: number; right: number; task: GanttTask }> = [];\n for (const task of tasks) {\n const pad = task.milestone ? radius : 0;\n const left = xScale.map(task.start) - pad;\n const right = xScale.map(task.end) + pad;\n // A span without finite edges can never block a label.\n if (!isFiniteNumber(left) || !isFiniteNumber(right)) continue;\n (right - left <= NARROW_SPAN ? narrow : this.wide).push({ left, right, task });\n }\n narrow.sort((a, b) => a.left - b.left);\n for (const span of narrow) {\n this.lefts.push(span.left);\n this.rights.push(span.right);\n this.owners.push(span.task);\n this.reach = Math.max(this.reach, span.right - span.left);\n }\n }\n\n /** Whether a mark other than `self` overlaps the open interval (lo, hi). */\n hits(lo: number, hi: number, self: GanttTask): boolean {\n if (this.wide.some((span) => span.task !== self && span.left < hi && span.right > lo)) return true;\n for (let i = lowerBound(this.lefts, lo - this.reach); i < this.lefts.length && this.lefts[i] < hi; i++) {\n if (this.rights[i] > lo && this.owners[i] !== self) return true;\n }\n return false;\n }\n}\n\n/**\n * Extra right inset so a milestone near the end of the plan keeps its label\n * beside it: needed only when the label would run off the plot on the right and\n * cannot sit on the left either (the plot edge, or another mark of its lane).\n */\nfunction milestoneLabelRoom(\n tasks: readonly GanttTask[],\n xScale: ContinuousScale,\n plot: Rect,\n radius: number,\n laneHeight: number,\n tokens: ThemeTokens,\n textOf: (task: GanttTask) => string,\n): number {\n const size = ganttLabelSize(tokens, laneHeight);\n if (laneHeight < size * 1.2 + 1) return 0;\n const font = fontString(size, tokens.font.family, tokens.font.weight.medium);\n const right = plot.x + plot.width;\n const members = new Map<string, GanttTask[]>();\n for (const task of tasks) {\n const lane = members.get(task.key);\n if (lane) lane.push(task);\n else members.set(task.key, [task]);\n }\n // Indexed lazily: only lanes with a milestone that would overflow are ever queried.\n const lanes = new Map<string, LaneSpans>();\n const spansOf = (key: string): LaneSpans => {\n let spans = lanes.get(key);\n if (!spans) lanes.set(key, (spans = new LaneSpans(members.get(key) ?? [], xScale, radius)));\n return spans;\n };\n let need = 0;\n for (const task of tasks) {\n if (!task.milestone) continue;\n const x = xScale.map(task.start);\n const text = textOf(task);\n if (!isFiniteNumber(x) || !text) continue;\n const width = measureText(text, font).width;\n const overflow = x + radius + 4 + width + 2 - right;\n if (overflow <= need) continue;\n const leftEdge = x - radius - 4 - width;\n const leftFree = leftEdge >= plot.x + 1 && !spansOf(task.key).hits(leftEdge - 1, x - radius - 3, task);\n if (!leftFree) need = overflow;\n }\n return need;\n}\n\nfunction buildXModel(spec: GanttSpec, kind: GanttScaleKind, xScale: ContinuousScale): XModel {\n return {\n kind,\n field: spec.encoding.start.field,\n type: kind === 'time' ? 'temporal' : 'quantitative',\n continuous: xScale,\n bandwidth: 0,\n pixel: (value) => {\n const n = ganttValue(kind, value);\n if (!isFiniteNumber(n)) return undefined;\n const px = xScale.map(n);\n return isFiniteNumber(px) ? px : undefined;\n },\n };\n}\n\nfunction buildYModel(spec: GanttSpec, lanes: readonly GanttLane[], area: { y: number; height: number }, plot: Rect): YModel {\n const centers = new Map(lanes.map((lane) => [lane.key, lane.center]));\n const scale = linearScale({ domain: [0, Math.max(1, lanes.length)], range: [area.y, area.y + area.height] });\n return {\n field: spec.encoding.task.field,\n scale,\n baseline: plot.y + plot.height,\n // Lanes are keyed by task: a task (string, number or date) lands on its lane center.\n pixel: (value) => centers.get(toKey(value)) ?? NaN,\n };\n}\n\nfunction baseSpec(spec: GanttSpec, data: Datum[]): BarSpec {\n const axes = spec.axes;\n return {\n type: 'bar',\n data,\n encoding: {\n x: { field: spec.encoding.start.field },\n y: { field: spec.encoding.task.field, title: spec.encoding.task.title },\n },\n // Lanes carry their own separators; horizontal gridlines at lane centers would strike through bars.\n axes: { ...axes, x: { ...axes?.x }, y: { ...axes?.y, grid: false } },\n title: spec.title,\n padding: spec.padding,\n legend: spec.legend,\n tooltip: spec.tooltip,\n background: spec.background,\n annotations: spec.annotations,\n };\n}\n\n/**\n * Build a {@link GanttModel} from a {@link GanttSpec}. Pure: depends only on the\n * spec, theme tokens and target size (plus the optional unfiltered color source).\n */\nexport function buildGanttModel(spec: GanttSpec, tokens: ThemeTokens, opts: GanttBuildOptions): GanttModel {\n const data = (Array.isArray(spec.data) ? spec.data : []) as Datum[];\n const sketch = resolveSketch(spec);\n const kind = ganttScaleKind(spec, data);\n const { tasks: parsed, skipped: invalid } = parseRows(spec, data, kind);\n const laneOrder = orderLanes(parsed, spec.sort);\n const groupInfo = resolveGroups(spec, tokens, parsed, opts.colorSource ?? data);\n for (const task of parsed) {\n task.color = groupInfo.grouped ? groupInfo.colorOf(task.groupKey!) : task.milestone ? groupInfo.plainMilestone : groupInfo.plain;\n }\n\n const explicit = explicitDomain(spec, kind);\n const extent = explicit ?? dataExtent(spec, kind, parsed);\n const legendItems: LegendItem[] = legendShown(spec, groupInfo.groups.length)\n ? groupInfo.groups.map((group) => ({ label: group.label, color: group.color, symbol: 'square' }))\n : [];\n const inputs: FrameInputs = {\n laneLabels: laneOrder.map((lane) => lane.label),\n legendItems,\n legendPosition: legendItems.length > 0 ? 'top' : null,\n };\n\n // Two passes: estimate the tick density from the container, then refine it\n // from the plot width the frame actually leaves for the time axis.\n let count = tickCountFor(spec, Math.max(0, opts.width) * 0.75);\n let axis = axisTicks(spec, kind, extent, explicit, count);\n let frame = chooseLegendFrame(spec, tokens, opts, tickLabels(spec, kind, axis.values), inputs);\n const refined = tickCountFor(spec, frame.plot.width);\n if (refined !== count) {\n count = refined;\n axis = axisTicks(spec, kind, extent, explicit, count);\n frame = chooseLegendFrame(spec, tokens, opts, tickLabels(spec, kind, axis.values), inputs);\n }\n const { domain } = axis;\n const plot = frame.plot;\n\n const laneCount = Math.max(1, laneOrder.length);\n const strips = annotationStrips(spec, tokens, plot.height);\n const laneArea = { y: plot.y + strips.top, height: Math.max(0, plot.height - strips.top - strips.bottom) };\n const laneHeight = laneArea.height / laneCount;\n const barHeight = laneHeight >= 6 ? Math.min(laneHeight * 0.62, MAX_BAR_HEIGHT) : laneHeight * 0.8;\n const milestoneRadius = Math.max(2, Math.min(barHeight * 0.62, laneHeight * 0.46, MAX_MILESTONE_RADIUS));\n const lanes: GanttLane[] = laneOrder.map((lane, index) => {\n const top = laneArea.y + index * laneHeight;\n return { key: lane.key, raw: lane.raw, label: lane.label, index, top, height: laneHeight, center: top + laneHeight / 2, tasks: lane.tasks };\n });\n for (const lane of lanes) for (const task of lane.tasks) task.lane = lane.index;\n\n const laneAxis = spec.axes?.y?.show !== false && spec.axes?.y?.labels !== false;\n const showLabels = spec.labels !== false;\n // Inset the range so milestone diamonds and bar ends at the extremes stay inside\n // the plot, and widen the right inset when a late milestone's label needs room.\n const inset = Math.min(milestoneRadius + 3, plot.width * 0.08);\n const scaleWith = (right: number): ContinuousScale => {\n const range: [number, number] = [plot.x + inset, plot.x + plot.width - right];\n return kind === 'time' ? timeScale({ domain, range }) : linearScale({ domain, range });\n };\n let xScale = scaleWith(inset);\n if (showLabels) {\n const room = milestoneLabelRoom(parsed, xScale, plot, milestoneRadius, laneHeight, tokens,\n (task) => ganttLabelText({ laneAxis, kind, spec, extent }, task));\n if (room > 0) xScale = scaleWith(Math.min(inset + room, Math.max(inset, plot.width * 0.3)));\n }\n placeTasks(parsed, lanes, xScale, plot, barHeight, milestoneRadius);\n const tasks = parsed.filter((task) => finiteRect(task.rect));\n const skipped = invalid + (parsed.length - tasks.length);\n\n const labels = tickLabels(spec, kind, axis.values);\n const xTicks: Tick[] = [];\n axis.values.forEach((value, i) => {\n const pos = xScale.map(value);\n if (isFiniteNumber(pos) && pos >= plot.x - 0.5 && pos <= plot.x + plot.width + 0.5) xTicks.push({ value, pos, label: labels[i] });\n });\n const yTicks: Tick[] = lanes.map((lane) => ({ value: lane.key, pos: lane.center, label: lane.label }));\n const shownGroups = frame.legendItems ? groupInfo.groups.slice(0, frame.legendItems.length) : [];\n const groupRows = new Map<string, Datum[]>();\n for (const task of tasks) {\n if (task.groupKey === undefined) continue;\n const list = groupRows.get(task.groupKey);\n if (list) list.push(task.row);\n else groupRows.set(task.groupKey, [task.row]);\n }\n const series: ResolvedSeries[] = shownGroups.map((group) => ({\n key: group.key,\n label: group.label,\n color: group.color,\n value: group.raw,\n rows: groupRows.get(group.key) ?? [],\n }));\n\n const base: CartesianModel = {\n spec: baseSpec(spec, data),\n tokens,\n frame,\n plot,\n x: buildXModel(spec, kind, xScale),\n y: buildYModel(spec, lanes, laneArea, plot),\n series,\n seriesField: spec.encoding.group?.field,\n stacked: false,\n orientation: 'vertical',\n project: (c, v) => ({ x: c, y: v }),\n xTicks,\n yTicks,\n colorOf: (key) => groupInfo.colorOf(key),\n colorDomain: groupInfo.groups.map((group) => group.key),\n sketch,\n };\n\n return {\n spec,\n tokens,\n frame,\n plot,\n kind,\n tasks,\n lanes,\n groups: groupInfo.groups,\n grouped: groupInfo.grouped,\n domain,\n extent,\n xScale,\n laneHeight,\n barHeight,\n milestoneRadius,\n cornerRadius: Math.max(0, spec.cornerRadius ?? 3),\n showLabels,\n laneAxis,\n skipped,\n base,\n sketch,\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Formatting shared by labels and tooltips */\n/* ------------------------------------------------------------------ */\n\nfunction round1(value: number): number {\n return Math.round(value * 10) / 10;\n}\n\nfunction plural(value: number, unit: string): string {\n return `${formatNumber(value, ',')} ${unit}${value === 1 ? '' : 's'}`;\n}\n\n/** Whether `end` falls at the same local wall-clock time on the calendar day after `start`. */\nfunction isNextCalendarDay(start: number, end: number): boolean {\n const a = new Date(start);\n const b = new Date(end);\n if (a.getHours() !== b.getHours() || a.getMinutes() !== b.getMinutes() || a.getSeconds() !== b.getSeconds() || a.getMilliseconds() !== b.getMilliseconds()) return false;\n const next = new Date(a.getFullYear(), a.getMonth(), a.getDate() + 1);\n return b.getFullYear() === next.getFullYear() && b.getMonth() === next.getMonth() && b.getDate() === next.getDate();\n}\n\n/** A task's length: `{ short: '18d', long: '18 days' }` on a time axis, units otherwise. */\nexport function ganttDuration(model: Pick<GanttModel, 'kind' | 'spec'>, task: Pick<GanttTask, 'start' | 'end'>): { short: string; long: string } {\n const span = task.end - task.start;\n if (model.kind === 'linear') {\n const text = formatValue(span, model.spec.encoding.end.format ?? model.spec.encoding.start.format ?? ',');\n return { short: text, long: text };\n }\n if (span < HOUR) {\n const minutes = round1(span / MINUTE);\n return { short: `${formatNumber(minutes, ',')}m`, long: `${formatNumber(minutes, ',')} min` };\n }\n if (span < DAY) {\n // A calendar day that loses an hour to daylight saving is still one day.\n if (isNextCalendarDay(task.start, task.end)) return { short: '1d', long: plural(1, 'day') };\n const hours = round1(span / HOUR);\n return { short: `${formatNumber(hours, ',')}h`, long: plural(hours, 'hour') };\n }\n if (span < YEAR) {\n const exact = span / DAY;\n // Whole calendar days stay whole across a daylight-saving shift.\n const days = Math.abs(exact - Math.round(exact)) < 0.05 ? Math.round(exact) : round1(exact);\n return { short: `${formatNumber(days, ',')}d`, long: plural(days, 'day') };\n }\n const years = round1(span / (365.25 * DAY));\n return { short: `${formatNumber(years, ',')}y`, long: plural(years, 'year') };\n}\n\n/** A full instant for tooltips (`Jan 2, 2024`, or a formatted number on a linear axis). */\nexport function ganttInstant(model: Pick<GanttModel, 'kind' | 'spec'>, value: number, which: 'start' | 'end'): string {\n const def = which === 'start' ? model.spec.encoding.start : model.spec.encoding.end;\n const format = def.format ?? (which === 'end' ? model.spec.encoding.start.format : undefined);\n if (model.kind === 'linear') return format ? formatValue(value, format) : formatNumber(value, ',');\n return format ? formatValue(value, format) : prettyDate(value);\n}\n\n/**\n * A compact instant for milestone labels: `Mar 20` (with the year only when a\n * long plan crosses one), plus the clock time when it is not midnight \u2014 or just\n * the time within a plan of a day or two.\n */\nexport function ganttShortInstant(model: Pick<GanttModel, 'kind' | 'spec' | 'extent'>, value: number): string {\n const format = model.spec.encoding.start.format;\n if (model.kind === 'linear') return format ? formatValue(value, format) : formatNumber(value, ',');\n if (format) return formatValue(value, format);\n const date = new Date(value);\n const [lo, hi] = model.extent;\n const span = hi - lo;\n const midnight = date.getHours() === 0 && date.getMinutes() === 0;\n if (!midnight && span <= 2 * DAY) return formatDate(date, '%H:%M');\n const crossesYears = span > 31 * DAY && new Date(lo).getFullYear() !== new Date(hi).getFullYear();\n const day = crossesYears ? '%b %e, %Y' : '%b %e';\n return midnight ? formatDate(date, day) : formatDate(date, `${day} %H:%M`);\n}\n\n/**\n * The text a mark carries. Beside a task axis the gutter already names the lane,\n * so a bar shows its completed share (or its duration) and a milestone its date;\n * without one, every lane is named on its bars.\n */\nexport function ganttLabelText(\n model: Pick<GanttModel, 'laneAxis' | 'kind' | 'spec' | 'extent'>,\n task: Pick<GanttTask, 'label' | 'milestone' | 'start' | 'end' | 'progress'>,\n): string {\n if (!model.laneAxis) return task.label;\n if (task.milestone) return ganttShortInstant(model, task.start);\n if (task.progress !== undefined) return `${Math.round(task.progress * 100)}%`;\n return ganttDuration(model, task).short;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Geometry morphs — the update transition for cartesian charts.
3
+ *
4
+ * When a chart's data changes (`update()`, a cross-filter, a legend toggle) the
5
+ * runtime pairs the outgoing frame's mark geometry with the incoming one and
6
+ * tweens between them, so bars grow and slide, lines reshape vertex by vertex,
7
+ * stacks collapse and reopen around entering/exiting series, and points glide
8
+ * to their new positions. Everything here is pure pixel-space interpolation of
9
+ * the geometry the renderers already resolve, keyed by stable identities
10
+ * (series + category, series + x, or the source datum), so the morph never has
11
+ * to re-derive scales and the final frame is exactly the static draw.
12
+ */
13
+ import type { CartesianGeometry } from '../charts/geometry.js';
14
+ /** A planned transition between two geometries of the same kind. */
15
+ export interface GeometryMorph {
16
+ /** Geometry at eased progress `t` (0 = outgoing, 1 = the incoming geometry). */
17
+ at(t: number): CartesianGeometry;
18
+ /** Duration multiplier for transitions that make more than one move. */
19
+ durationScale?: number;
20
+ }
21
+ /** Bounds that keep per-frame interpolation well inside a frame budget. */
22
+ export declare const MORPH_LIMITS: Readonly<{
23
+ bars: 4000;
24
+ vertices: 20000;
25
+ points: 5000;
26
+ }>;
27
+ /**
28
+ * Plan a morph from `from` to `to`, or null when the pair can't be morphed
29
+ * meaningfully (different mark kinds, orientation/stacking flips that change
30
+ * what a mark means, or data too large to tween per frame).
31
+ */
32
+ export declare function planGeometryMorph(from: CartesianGeometry, to: CartesianGeometry): GeometryMorph | null;
33
+ //# sourceMappingURL=morph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"morph.d.ts","sourceRoot":"","sources":["../../src/runtime/morph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAU5D,oEAAoE;AACpE,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC;IACjC,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,2EAA2E;AAC3E,eAAO,MAAM,YAAY;;;;EAA+D,CAAC;AAmBzF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,EAAE,EAAE,EAAE,iBAAiB,GAAG,aAAa,GAAG,IAAI,CAOtG"}
@@ -0,0 +1,332 @@
1
+ import { lineMarkers } from "../charts/line.js";
2
+ import { areaMarkers } from "../charts/area.js";
3
+ import { parseColor, rgbaToCss } from "../color/index.js";
4
+ import { toKey } from "../util/data.js";
5
+ const MORPH_LIMITS = Object.freeze({ bars: 4e3, vertices: 2e4, points: 5e3 });
6
+ const lerp = (a, b, t) => a + (b - a) * t;
7
+ function finite(point) {
8
+ return Number.isFinite(point.x) && Number.isFinite(point.y ?? point.y1 ?? NaN);
9
+ }
10
+ function colorTrack(from, to) {
11
+ if (from === to) return () => to;
12
+ const a = parseColor(from);
13
+ const b = parseColor(to);
14
+ if (!a || !b) return (t) => t < 0.5 ? from : to;
15
+ return (t) => t >= 1 ? to : rgbaToCss({ r: lerp(a.r, b.r, t), g: lerp(a.g, b.g, t), b: lerp(a.b, b.b, t), a: lerp(a.a, b.a, t) });
16
+ }
17
+ function planGeometryMorph(from, to) {
18
+ if (from.kind === "bar" && to.kind === "bar") return planBars(from, to);
19
+ if (from.kind === "line" && to.kind === "line") return planLine(from, to);
20
+ if (from.kind === "area" && to.kind === "area") return planArea(from, to);
21
+ if (from.kind === "scatter" && to.kind === "scatter") return planScatter(from, to);
22
+ if (from.kind === "box" && to.kind === "box") return planBoxes(from, to);
23
+ return null;
24
+ }
25
+ function stacksOf(marks) {
26
+ const stacks = /* @__PURE__ */ new Map();
27
+ for (const mark of marks) {
28
+ if (mark.stack == null) continue;
29
+ const list = stacks.get(mark.stack);
30
+ if (list) list.push(mark);
31
+ else stacks.set(mark.stack, [mark]);
32
+ }
33
+ return stacks;
34
+ }
35
+ function lowerNeighbor(mark, stacks, keep) {
36
+ let best;
37
+ for (const other of stacks.get(mark.stack ?? "") ?? []) {
38
+ if ((other.level ?? 0) >= (mark.level ?? 0) || !keep(other)) continue;
39
+ if (!best || (other.level ?? 0) > (best.level ?? 0)) best = other;
40
+ }
41
+ return best;
42
+ }
43
+ function stackPeer(mark, stacks, keep) {
44
+ return (stacks.get(mark.stack ?? "") ?? []).find((other) => other !== mark && keep(other));
45
+ }
46
+ function collapsed(mark, stacks, counterpart, baseline) {
47
+ if (mark.stack == null) return { ...mark, end: mark.base, alpha: 0 };
48
+ const persists = (m) => counterpart.has(m.key);
49
+ const below = lowerNeighbor(mark, stacks, persists);
50
+ const peer = below ?? stackPeer(mark, stacks, persists);
51
+ const geometry = peer ? counterpart.get(peer.key) : mark;
52
+ const anchor = below ? counterpart.get(below.key).end : baseline;
53
+ return { ...mark, catStart: geometry.catStart, catThick: geometry.catThick, base: anchor, end: anchor, alpha: 0 };
54
+ }
55
+ function barTrack(a, b, stage = "together") {
56
+ const color = colorTrack(a.color, b.color);
57
+ return (t) => {
58
+ const tv = stage === "value-first" ? phase(t, 0, 0.6) : stage === "category-first" ? phase(t, 0.4, 1) : t;
59
+ const tc = stage === "value-first" ? phase(t, 0.4, 1) : stage === "category-first" ? phase(t, 0, 0.6) : t;
60
+ return {
61
+ ...b,
62
+ catStart: lerp(a.catStart, b.catStart, tc),
63
+ catThick: lerp(a.catThick, b.catThick, tc),
64
+ base: lerp(a.base, b.base, tv),
65
+ end: lerp(a.end, b.end, tv),
66
+ color: color(t),
67
+ alpha: lerp(a.alpha, b.alpha, t)
68
+ };
69
+ };
70
+ }
71
+ function phase(t, start, end) {
72
+ const u = Math.min(1, Math.max(0, (t - start) / (end - start)));
73
+ return u * u * (3 - 2 * u);
74
+ }
75
+ function stageOf(from, to) {
76
+ const stacked = (g) => g.marks.some((mark) => mark.stack != null);
77
+ const was = stacked(from);
78
+ const is = stacked(to);
79
+ if (!was && is) return "value-first";
80
+ if (was && !is) return "category-first";
81
+ return "together";
82
+ }
83
+ function planBars(from, to) {
84
+ if (from.horizontal !== to.horizontal) return null;
85
+ if (from.marks.length > MORPH_LIMITS.bars || to.marks.length > MORPH_LIMITS.bars) return null;
86
+ const fromByKey = new Map(from.marks.map((mark) => [mark.key, mark]));
87
+ const toByKey = new Map(to.marks.map((mark) => [mark.key, mark]));
88
+ const fromStacks = stacksOf(from.marks);
89
+ const toStacks = stacksOf(to.marks);
90
+ const stage = stageOf(from, to);
91
+ const tracks = [];
92
+ for (const mark of from.marks) {
93
+ if (!toByKey.has(mark.key)) tracks.push(barTrack(mark, collapsed(mark, fromStacks, toByKey, to.baseline)));
94
+ }
95
+ for (const mark of to.marks) {
96
+ const source = fromByKey.get(mark.key);
97
+ tracks.push(source ? barTrack(source, mark, stage) : barTrack(collapsed(mark, toStacks, fromByKey, from.baseline), mark));
98
+ }
99
+ return {
100
+ at: (t) => t >= 1 ? to : { ...to, marks: tracks.map((track) => track(t)) },
101
+ ...stage === "together" ? {} : { durationScale: 1.7 }
102
+ };
103
+ }
104
+ function pairSeries(from, to) {
105
+ const fromByKey = new Map(from.map((s) => [s.series.key, s]));
106
+ const toKeys = new Set(to.map((s) => s.series.key));
107
+ const pairs = [];
108
+ for (const s of from) if (!toKeys.has(s.series.key)) pairs.push({ a: s });
109
+ for (const s of to) pairs.push({ a: fromByKey.get(s.series.key), b: s });
110
+ return pairs;
111
+ }
112
+ function bracket(points, x) {
113
+ let lo = 0;
114
+ let hi = points.length - 1;
115
+ let found = -1;
116
+ while (lo <= hi) {
117
+ const mid = lo + hi >> 1;
118
+ if (points[mid].x <= x) {
119
+ found = mid;
120
+ lo = mid + 1;
121
+ } else hi = mid - 1;
122
+ }
123
+ return found;
124
+ }
125
+ function sampleAt(points, x, read) {
126
+ const i = bracket(points, x);
127
+ if (i < 0) return read(points[0]);
128
+ if (i >= points.length - 1) return read(points[points.length - 1]);
129
+ const p = points[i];
130
+ const q = points[i + 1];
131
+ const span = q.x - p.x;
132
+ return span > 0 ? lerp(read(p), read(q), (x - p.x) / span) : read(q);
133
+ }
134
+ function vertexTotal(series) {
135
+ let n = 0;
136
+ for (const s of series) n += s.points.length;
137
+ return n;
138
+ }
139
+ function vertexTracks(fromPoints, toPoints, project) {
140
+ const fromFinite = fromPoints.filter(finite);
141
+ const toFinite = toPoints.filter(finite);
142
+ const fromByKey = /* @__PURE__ */ new Map();
143
+ for (const p of fromFinite) if (p.key != null) fromByKey.set(p.key, p);
144
+ const starts = toPoints.map((p) => {
145
+ if (!finite(p)) return p;
146
+ return (p.key != null ? fromByKey.get(p.key) : void 0) ?? (fromFinite.length ? project(fromFinite, p.x, p) : p);
147
+ });
148
+ const gapFree = fromFinite.length === fromPoints.length && toFinite.length === toPoints.length;
149
+ const toKeys = new Set(toFinite.map((p) => p.key));
150
+ const exits = gapFree && toFinite.length ? fromFinite.filter((p) => p.key == null || !toKeys.has(p.key)).map((a) => ({ a, b: project(toFinite, a.x, a) })) : [];
151
+ return { starts, exits };
152
+ }
153
+ function projectLine(onto, x) {
154
+ return { x, y: sampleAt(onto, x, (p) => p.y) };
155
+ }
156
+ function lineSeriesTrack(a, b, geometry) {
157
+ const { starts, exits } = vertexTracks(a.points, b.points, (onto, x) => projectLine(onto, x));
158
+ return (t) => {
159
+ let points = b.points.map(
160
+ (p, i) => finite(p) ? { x: lerp(starts[i].x, p.x, t), y: lerp(starts[i].y, p.y, t), key: p.key } : p
161
+ );
162
+ if (exits.length) {
163
+ points = points.concat(exits.map(({ a: p, b: q }) => ({ x: lerp(p.x, q.x, t), y: lerp(p.y, q.y, t) }))).sort((p, q) => p.x - q.x);
164
+ }
165
+ return { ...b, points, markers: lineMarkers(geometry.markerMode, points), alpha: lerp(a.alpha, b.alpha, t) };
166
+ };
167
+ }
168
+ function fadeTrack(s, from, to) {
169
+ return (t) => ({ ...s, alpha: lerp(from, to, t) });
170
+ }
171
+ function drawable(series) {
172
+ return series.filter((s) => s.points.some(finite));
173
+ }
174
+ function planLine(from, to) {
175
+ if (vertexTotal(from.series) > MORPH_LIMITS.vertices || vertexTotal(to.series) > MORPH_LIMITS.vertices) return null;
176
+ const tracks = pairSeries(drawable(from.series), drawable(to.series)).map(({ a, b }) => {
177
+ if (a && b) return lineSeriesTrack(a, b, to);
178
+ if (b) return fadeTrack(b, 0, b.alpha);
179
+ return fadeTrack(a, a.alpha, 0);
180
+ });
181
+ return { at: (t) => t >= 1 ? to : { ...to, series: tracks.map((track) => track(t)) } };
182
+ }
183
+ function projectBand(onto, x) {
184
+ return { x, y0: sampleAt(onto, x, (p) => p.y0), y1: sampleAt(onto, x, (p) => p.y1) };
185
+ }
186
+ function bandTrack(a, b) {
187
+ const { starts, exits } = vertexTracks(a.points, b.points, (onto, x) => projectBand(onto, x));
188
+ return (t) => {
189
+ let points = b.points.map(
190
+ (p, i) => finite(p) ? { x: lerp(starts[i].x, p.x, t), y0: lerp(starts[i].y0, p.y0, t), y1: lerp(starts[i].y1, p.y1, t), key: p.key } : p
191
+ );
192
+ if (exits.length) {
193
+ points = points.concat(exits.map(({ a: p, b: q }) => ({ x: lerp(p.x, q.x, t), y0: lerp(p.y0, q.y0, t), y1: lerp(p.y1, q.y1, t) }))).sort((p, q) => p.x - q.x);
194
+ }
195
+ return { ...b, points, markers: areaMarkers(points), alpha: lerp(a.alpha, b.alpha, t) };
196
+ };
197
+ }
198
+ function collapsedBand(band, order, counterpart, baseline) {
199
+ const index = order.indexOf(band);
200
+ let below;
201
+ for (let i = index - 1; i >= 0 && !below; i--) below = counterpart.get(order[i].series.key);
202
+ const anchor = below?.points.filter(finite) ?? [];
203
+ const points = band.points.map((p) => {
204
+ if (!finite(p)) return p;
205
+ const y = anchor.length ? sampleAt(anchor, p.x, (q) => q.y1) : baseline;
206
+ return { x: p.x, y0: y, y1: y, key: p.key };
207
+ });
208
+ return { ...band, points };
209
+ }
210
+ function planArea(from, to) {
211
+ if (from.stacked !== to.stacked) return null;
212
+ if (vertexTotal(from.bands) > MORPH_LIMITS.vertices || vertexTotal(to.bands) > MORPH_LIMITS.vertices) return null;
213
+ const fromBands = drawable(from.bands);
214
+ const toBands = drawable(to.bands);
215
+ const fromByKey = new Map(fromBands.map((band) => [band.series.key, band]));
216
+ const toByKey = new Map(toBands.map((band) => [band.series.key, band]));
217
+ const tracks = pairSeries(fromBands, toBands).map(({ a, b }) => {
218
+ if (a && b) return bandTrack(a, b);
219
+ if (!to.stacked) return b ? fadeTrack(b, 0, b.alpha) : fadeTrack(a, a.alpha, 0);
220
+ if (b) return bandTrack(collapsedBand(b, toBands, fromByKey, from.baseline), b);
221
+ return bandTrack(a, collapsedBand(a, fromBands, toByKey, to.baseline));
222
+ });
223
+ return { at: (t) => t >= 1 ? to : { ...to, bands: tracks.map((track) => track(t)) } };
224
+ }
225
+ function signature(row, positional) {
226
+ if (!row || typeof row !== "object") return "";
227
+ const parts = [];
228
+ for (const key of Object.keys(row).sort()) {
229
+ if (positional.has(key)) continue;
230
+ const value = row[key];
231
+ if (value !== null && typeof value === "object" && !(value instanceof Date)) continue;
232
+ parts.push(`${key}=${toKey(value)}`);
233
+ }
234
+ return parts.join("");
235
+ }
236
+ function pairPoints(from, to) {
237
+ const byRow = /* @__PURE__ */ new Map();
238
+ for (const p of from.points) if (p.row) byRow.set(p.row, p);
239
+ const matched = /* @__PURE__ */ new Set();
240
+ const pairs = [];
241
+ const unmatched = [];
242
+ for (const b of to.points) {
243
+ const a = b.row ? byRow.get(b.row) : void 0;
244
+ if (a && !matched.has(a) && a.seriesKey === b.seriesKey) {
245
+ matched.add(a);
246
+ pairs.push({ a, b });
247
+ } else unmatched.push(b);
248
+ }
249
+ const positional = /* @__PURE__ */ new Set([to.fields.x, to.fields.y, ...to.fields.size ? [to.fields.size] : []]);
250
+ const pool = /* @__PURE__ */ new Map();
251
+ for (const a of from.points) {
252
+ if (matched.has(a)) continue;
253
+ const key = `${a.seriesKey}${signature(a.row, positional)}`;
254
+ const list = pool.get(key);
255
+ if (list) list.push(a);
256
+ else pool.set(key, [a]);
257
+ }
258
+ for (const b of unmatched) {
259
+ const a = pool.get(`${b.seriesKey}${signature(b.row, positional)}`)?.shift();
260
+ if (a) matched.add(a);
261
+ pairs.push({ a, b });
262
+ }
263
+ const exits = from.points.filter((a) => !matched.has(a)).map((a) => ({ a }));
264
+ return [...exits, ...pairs];
265
+ }
266
+ function pointTrack(a, b) {
267
+ if (a && b) {
268
+ const color = colorTrack(a.color, b.color);
269
+ return (t) => ({
270
+ ...b,
271
+ x: lerp(a.x, b.x, t),
272
+ y: lerp(a.y, b.y, t),
273
+ r: lerp(a.r, b.r, t),
274
+ color: color(t),
275
+ alpha: lerp(a.alpha, b.alpha, t)
276
+ });
277
+ }
278
+ if (b) return (t) => ({ ...b, r: b.r * t, alpha: b.alpha * t });
279
+ return (t) => ({ ...a, r: a.r * (1 - t), alpha: a.alpha * (1 - t) });
280
+ }
281
+ function planScatter(from, to) {
282
+ if (from.points.length > MORPH_LIMITS.points || to.points.length > MORPH_LIMITS.points) return null;
283
+ const tracks = pairPoints(from, to).map(({ a, b }) => pointTrack(a, b));
284
+ return { at: (t) => t >= 1 ? to : { ...to, points: tracks.map((track) => track(t)) } };
285
+ }
286
+ function flatBox(mark) {
287
+ const y = mark.yMed;
288
+ return { ...mark, yQ1: y, yQ3: y, yLo: y, yHi: y, outliers: mark.outliers.map(() => y), alpha: 0 };
289
+ }
290
+ function whiskerEnd(mark, y) {
291
+ return Math.abs(y - mark.yHi) <= Math.abs(y - mark.yLo) ? mark.yHi : mark.yLo;
292
+ }
293
+ function boxTrack(a, b) {
294
+ const color = colorTrack(a.color, b.color);
295
+ const count = Math.max(a.outliers.length, b.outliers.length);
296
+ const from = [];
297
+ const to = [];
298
+ for (let i = 0; i < count; i++) {
299
+ const ya = a.outliers[i];
300
+ const yb = b.outliers[i];
301
+ from.push(ya ?? whiskerEnd(a, yb));
302
+ to.push(yb ?? whiskerEnd(b, ya));
303
+ }
304
+ return (t) => ({
305
+ ...b,
306
+ color: color(t),
307
+ cx: lerp(a.cx, b.cx, t),
308
+ boxW: lerp(a.boxW, b.boxW, t),
309
+ yQ1: lerp(a.yQ1, b.yQ1, t),
310
+ yQ3: lerp(a.yQ3, b.yQ3, t),
311
+ yMed: lerp(a.yMed, b.yMed, t),
312
+ yLo: lerp(a.yLo, b.yLo, t),
313
+ yHi: lerp(a.yHi, b.yHi, t),
314
+ outliers: from.map((y, i) => lerp(y, to[i], t)),
315
+ alpha: lerp(a.alpha, b.alpha, t)
316
+ });
317
+ }
318
+ function planBoxes(from, to) {
319
+ if (from.marks.length > MORPH_LIMITS.bars || to.marks.length > MORPH_LIMITS.bars) return null;
320
+ const before = new Map(from.marks.map((mark) => [mark.key, mark]));
321
+ const kept = new Set(to.marks.map((mark) => mark.key));
322
+ const tracks = [
323
+ ...from.marks.filter((mark) => !kept.has(mark.key)).map((mark) => boxTrack(mark, flatBox(mark))),
324
+ ...to.marks.map((mark) => boxTrack(before.get(mark.key) ?? flatBox(mark), mark))
325
+ ];
326
+ return { at: (t) => t >= 1 ? to : { ...to, marks: tracks.map((track) => track(t)) } };
327
+ }
328
+ export {
329
+ MORPH_LIMITS,
330
+ planGeometryMorph
331
+ };
332
+ //# sourceMappingURL=morph.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/runtime/morph.ts"],
4
+ "sourcesContent": ["/**\n * Geometry morphs \u2014 the update transition for cartesian charts.\n *\n * When a chart's data changes (`update()`, a cross-filter, a legend toggle) the\n * runtime pairs the outgoing frame's mark geometry with the incoming one and\n * tweens between them, so bars grow and slide, lines reshape vertex by vertex,\n * stacks collapse and reopen around entering/exiting series, and points glide\n * to their new positions. Everything here is pure pixel-space interpolation of\n * the geometry the renderers already resolve, keyed by stable identities\n * (series + category, series + x, or the source datum), so the morph never has\n * to re-derive scales and the final frame is exactly the static draw.\n */\n\nimport type { CartesianGeometry } from '../charts/geometry';\nimport type { BarGeometry, BarMark } from '../charts/bar';\nimport { lineMarkers, type KeyedPoint, type LineGeometry, type SeriesPoints } from '../charts/line';\nimport { areaMarkers, type AreaGeometry, type BandPoints, type KeyedAreaPoint } from '../charts/area';\nimport type { ScatterGeometry, ScatterPoint } from '../charts/scatter';\nimport type { BoxGeometry, BoxMark } from '../charts/box';\nimport { parseColor, rgbaToCss } from '../color';\nimport type { Datum } from '../types';\nimport { toKey } from '../util/data';\n\n/** A planned transition between two geometries of the same kind. */\nexport interface GeometryMorph {\n /** Geometry at eased progress `t` (0 = outgoing, 1 = the incoming geometry). */\n at(t: number): CartesianGeometry;\n /** Duration multiplier for transitions that make more than one move. */\n durationScale?: number;\n}\n\n/** Bounds that keep per-frame interpolation well inside a frame budget. */\nexport const MORPH_LIMITS = Object.freeze({ bars: 4000, vertices: 20000, points: 5000 });\n\ntype Track<T> = (t: number) => T;\n\nconst lerp = (a: number, b: number, t: number): number => a + (b - a) * t;\n\nfunction finite(point: { x: number; y?: number; y1?: number }): boolean {\n return Number.isFinite(point.x) && Number.isFinite(point.y ?? point.y1 ?? NaN);\n}\n\nfunction colorTrack(from: string, to: string): Track<string> {\n if (from === to) return () => to;\n const a = parseColor(from);\n const b = parseColor(to);\n if (!a || !b) return (t) => (t < 0.5 ? from : to);\n return (t) =>\n t >= 1 ? to : rgbaToCss({ r: lerp(a.r, b.r, t), g: lerp(a.g, b.g, t), b: lerp(a.b, b.b, t), a: lerp(a.a, b.a, t) });\n}\n\n/**\n * Plan a morph from `from` to `to`, or null when the pair can't be morphed\n * meaningfully (different mark kinds, orientation/stacking flips that change\n * what a mark means, or data too large to tween per frame).\n */\nexport function planGeometryMorph(from: CartesianGeometry, to: CartesianGeometry): GeometryMorph | null {\n if (from.kind === 'bar' && to.kind === 'bar') return planBars(from, to);\n if (from.kind === 'line' && to.kind === 'line') return planLine(from, to);\n if (from.kind === 'area' && to.kind === 'area') return planArea(from, to);\n if (from.kind === 'scatter' && to.kind === 'scatter') return planScatter(from, to);\n if (from.kind === 'box' && to.kind === 'box') return planBoxes(from, to);\n return null;\n}\n\n/* ------------------------------------------------------------------ */\n/* Bars */\n/* ------------------------------------------------------------------ */\n\nfunction stacksOf(marks: readonly BarMark[]): Map<string, BarMark[]> {\n const stacks = new Map<string, BarMark[]>();\n for (const mark of marks) {\n if (mark.stack == null) continue;\n const list = stacks.get(mark.stack);\n if (list) list.push(mark);\n else stacks.set(mark.stack, [mark]);\n }\n return stacks;\n}\n\n/** The highest segment below `mark` in its stack that satisfies `keep`. */\nfunction lowerNeighbor(mark: BarMark, stacks: Map<string, BarMark[]>, keep: (m: BarMark) => boolean): BarMark | undefined {\n let best: BarMark | undefined;\n for (const other of stacks.get(mark.stack ?? '') ?? []) {\n if ((other.level ?? 0) >= (mark.level ?? 0) || !keep(other)) continue;\n if (!best || (other.level ?? 0) > (best.level ?? 0)) best = other;\n }\n return best;\n}\n\n/** Any other segment in `mark`'s stack that satisfies `keep` (to borrow its category geometry). */\nfunction stackPeer(mark: BarMark, stacks: Map<string, BarMark[]>, keep: (m: BarMark) => boolean): BarMark | undefined {\n return (stacks.get(mark.stack ?? '') ?? []).find((other) => other !== mark && keep(other));\n}\n\n/**\n * Where an entering bar starts / an exiting bar ends: a zero-length, fully\n * transparent bar. A grouped bar collapses onto its own base; a stacked segment\n * collapses onto the outer edge of the nearest segment beneath it that exists\n * on the other side of the transition (or the baseline), so stacks close and\n * reopen without gaps.\n */\nfunction collapsed(\n mark: BarMark,\n stacks: Map<string, BarMark[]>,\n counterpart: Map<string, BarMark>,\n baseline: number,\n): BarMark {\n if (mark.stack == null) return { ...mark, end: mark.base, alpha: 0 };\n const persists = (m: BarMark): boolean => counterpart.has(m.key);\n const below = lowerNeighbor(mark, stacks, persists);\n const peer = below ?? stackPeer(mark, stacks, persists);\n const geometry = peer ? counterpart.get(peer.key)! : mark;\n const anchor = below ? counterpart.get(below.key)!.end : baseline;\n return { ...mark, catStart: geometry.catStart, catThick: geometry.catThick, base: anchor, end: anchor, alpha: 0 };\n}\n\nfunction barTrack(a: BarMark, b: BarMark, stage: BarStage = 'together'): Track<BarMark> {\n const color = colorTrack(a.color, b.color);\n return (t) => {\n const tv = stage === 'value-first' ? phase(t, 0, 0.6) : stage === 'category-first' ? phase(t, 0.4, 1) : t;\n const tc = stage === 'value-first' ? phase(t, 0.4, 1) : stage === 'category-first' ? phase(t, 0, 0.6) : t;\n return {\n ...b,\n catStart: lerp(a.catStart, b.catStart, tc),\n catThick: lerp(a.catThick, b.catThick, tc),\n base: lerp(a.base, b.base, tv),\n end: lerp(a.end, b.end, tv),\n color: color(t),\n alpha: lerp(a.alpha, b.alpha, t),\n };\n };\n}\n\n/**\n * How a bar morph sequences its two axes. Switching between grouped and stacked\n * layouts reads best as two moves (like d3's classic stacked-to-grouped\n * transition): stacking first lifts each bar to its stack slot and then widens\n * it; grouping first narrows bars into their slots and then drops them to the\n * baseline. Ordinary data changes move both axes together.\n */\ntype BarStage = 'together' | 'value-first' | 'category-first';\n\n/** Smoothstepped sub-progress of `t` over [start, end]. */\nfunction phase(t: number, start: number, end: number): number {\n const u = Math.min(1, Math.max(0, (t - start) / (end - start)));\n return u * u * (3 - 2 * u);\n}\n\nfunction stageOf(from: BarGeometry, to: BarGeometry): BarStage {\n const stacked = (g: BarGeometry): boolean => g.marks.some((mark) => mark.stack != null);\n const was = stacked(from);\n const is = stacked(to);\n if (!was && is) return 'value-first';\n if (was && !is) return 'category-first';\n return 'together';\n}\n\nfunction planBars(from: BarGeometry, to: BarGeometry): GeometryMorph | null {\n if (from.horizontal !== to.horizontal) return null;\n if (from.marks.length > MORPH_LIMITS.bars || to.marks.length > MORPH_LIMITS.bars) return null;\n const fromByKey = new Map(from.marks.map((mark) => [mark.key, mark]));\n const toByKey = new Map(to.marks.map((mark) => [mark.key, mark]));\n const fromStacks = stacksOf(from.marks);\n const toStacks = stacksOf(to.marks);\n const stage = stageOf(from, to);\n const tracks: Track<BarMark>[] = [];\n // Exiting bars paint first so persisting marks slide over them.\n for (const mark of from.marks) {\n if (!toByKey.has(mark.key)) tracks.push(barTrack(mark, collapsed(mark, fromStacks, toByKey, to.baseline)));\n }\n for (const mark of to.marks) {\n const source = fromByKey.get(mark.key);\n tracks.push(source ? barTrack(source, mark, stage) : barTrack(collapsed(mark, toStacks, fromByKey, from.baseline), mark));\n }\n return {\n at: (t) => (t >= 1 ? to : { ...to, marks: tracks.map((track) => track(t)) }),\n ...(stage === 'together' ? {} : { durationScale: 1.7 }),\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Lines & areas */\n/* ------------------------------------------------------------------ */\n\n/** Pair series across frames by key: exiting series first, then the target's paint order. */\nfunction pairSeries<S extends { series: { key: string } }>(from: readonly S[], to: readonly S[]): Array<{ a?: S; b?: S }> {\n const fromByKey = new Map(from.map((s) => [s.series.key, s]));\n const toKeys = new Set(to.map((s) => s.series.key));\n const pairs: Array<{ a?: S; b?: S }> = [];\n for (const s of from) if (!toKeys.has(s.series.key)) pairs.push({ a: s });\n for (const s of to) pairs.push({ a: fromByKey.get(s.series.key), b: s });\n return pairs;\n}\n\n/** Index of the last vertex with x \u2264 `x` in an x-sorted run (\u22121 when before the first). */\nfunction bracket<T extends { x: number }>(points: readonly T[], x: number): number {\n let lo = 0;\n let hi = points.length - 1;\n let found = -1;\n while (lo <= hi) {\n const mid = (lo + hi) >> 1;\n if (points[mid].x <= x) {\n found = mid;\n lo = mid + 1;\n } else hi = mid - 1;\n }\n return found;\n}\n\n/** Linearly sample an x-sorted polyline at `x`, holding the end values outside it. */\nfunction sampleAt<T extends { x: number }>(points: readonly T[], x: number, read: (p: T) => number): number {\n const i = bracket(points, x);\n if (i < 0) return read(points[0]);\n if (i >= points.length - 1) return read(points[points.length - 1]);\n const p = points[i];\n const q = points[i + 1];\n const span = q.x - p.x;\n return span > 0 ? lerp(read(p), read(q), (x - p.x) / span) : read(q);\n}\n\nfunction vertexTotal(series: ReadonlyArray<{ points: readonly unknown[] }>): number {\n let n = 0;\n for (const s of series) n += s.points.length;\n return n;\n}\n\n/**\n * Vertex pairing for one persisting series. Matching vertices (same x key) move\n * between their positions; a new vertex starts on the outgoing polyline at its\n * own x, and a dropped vertex flattens onto the incoming polyline before it\n * disappears \u2014 so the path reshapes continuously rather than snapping.\n */\nfunction vertexTracks<P extends { x: number; key?: string }>(\n fromPoints: readonly P[],\n toPoints: readonly P[],\n project: (onto: readonly P[], x: number, like: P) => P,\n): { starts: P[]; exits: Array<{ a: P; b: P }> } {\n const fromFinite = fromPoints.filter(finite);\n const toFinite = toPoints.filter(finite);\n const fromByKey = new Map<string, P>();\n for (const p of fromFinite) if (p.key != null) fromByKey.set(p.key, p);\n const starts = toPoints.map((p) => {\n if (!finite(p)) return p;\n return (p.key != null ? fromByKey.get(p.key) : undefined) ?? (fromFinite.length ? project(fromFinite, p.x, p) : p);\n });\n // Exiting vertices only make sense on gap-free paths; with gaps they'd bridge breaks.\n const gapFree = fromFinite.length === fromPoints.length && toFinite.length === toPoints.length;\n const toKeys = new Set(toFinite.map((p) => p.key));\n const exits =\n gapFree && toFinite.length\n ? fromFinite.filter((p) => p.key == null || !toKeys.has(p.key)).map((a) => ({ a, b: project(toFinite, a.x, a) }))\n : [];\n return { starts, exits };\n}\n\nfunction projectLine(onto: readonly KeyedPoint[], x: number): KeyedPoint {\n return { x, y: sampleAt(onto, x, (p) => p.y) };\n}\n\nfunction lineSeriesTrack(a: SeriesPoints, b: SeriesPoints, geometry: LineGeometry): Track<SeriesPoints> {\n const { starts, exits } = vertexTracks(a.points, b.points, (onto, x) => projectLine(onto, x));\n return (t) => {\n let points: KeyedPoint[] = b.points.map((p, i) =>\n finite(p) ? { x: lerp(starts[i].x, p.x, t), y: lerp(starts[i].y, p.y, t), key: p.key } : p,\n );\n if (exits.length) {\n points = points\n .concat(exits.map(({ a: p, b: q }) => ({ x: lerp(p.x, q.x, t), y: lerp(p.y, q.y, t) })))\n .sort((p, q) => p.x - q.x);\n }\n return { ...b, points, markers: lineMarkers(geometry.markerMode, points), alpha: lerp(a.alpha, b.alpha, t) };\n };\n}\n\nfunction fadeTrack<S extends { alpha: number }>(s: S, from: number, to: number): Track<S> {\n return (t) => ({ ...s, alpha: lerp(from, to, t) });\n}\n\n/**\n * Series with at least one drawable vertex. A series that draws nothing (empty\n * or all-missing data) on one side of a transition takes part as entering or\n * leaving, so it fades or collapses in rather than snapping to its final shape.\n */\nfunction drawable<S extends { points: ReadonlyArray<{ x: number; y?: number; y1?: number }> }>(series: readonly S[]): S[] {\n return series.filter((s) => s.points.some(finite));\n}\n\nfunction planLine(from: LineGeometry, to: LineGeometry): GeometryMorph | null {\n if (vertexTotal(from.series) > MORPH_LIMITS.vertices || vertexTotal(to.series) > MORPH_LIMITS.vertices) return null;\n const tracks = pairSeries(drawable(from.series), drawable(to.series)).map(({ a, b }): Track<SeriesPoints> => {\n if (a && b) return lineSeriesTrack(a, b, to);\n if (b) return fadeTrack(b, 0, b.alpha);\n return fadeTrack(a!, a!.alpha, 0);\n });\n return { at: (t) => (t >= 1 ? to : { ...to, series: tracks.map((track) => track(t)) }) };\n}\n\nfunction projectBand(onto: readonly KeyedAreaPoint[], x: number): KeyedAreaPoint {\n return { x, y0: sampleAt(onto, x, (p) => p.y0), y1: sampleAt(onto, x, (p) => p.y1) };\n}\n\nfunction bandTrack(a: BandPoints, b: BandPoints): Track<BandPoints> {\n const { starts, exits } = vertexTracks(a.points, b.points, (onto, x) => projectBand(onto, x));\n return (t) => {\n let points: KeyedAreaPoint[] = b.points.map((p, i) =>\n finite(p)\n ? { x: lerp(starts[i].x, p.x, t), y0: lerp(starts[i].y0, p.y0, t), y1: lerp(starts[i].y1, p.y1, t), key: p.key }\n : p,\n );\n if (exits.length) {\n points = points\n .concat(exits.map(({ a: p, b: q }) => ({ x: lerp(p.x, q.x, t), y0: lerp(p.y0, q.y0, t), y1: lerp(p.y1, q.y1, t) })))\n .sort((p, q) => p.x - q.x);\n }\n return { ...b, points, markers: areaMarkers(points), alpha: lerp(a.alpha, b.alpha, t) };\n };\n}\n\n/**\n * A stacked band entering or leaving collapses to zero thickness on the top\n * edge of the nearest band beneath it that exists on the other side of the\n * transition (or the baseline), so the stack opens and closes without gaps.\n */\nfunction collapsedBand(\n band: BandPoints,\n order: readonly BandPoints[],\n counterpart: Map<string, BandPoints>,\n baseline: number,\n): BandPoints {\n const index = order.indexOf(band);\n let below: BandPoints | undefined;\n for (let i = index - 1; i >= 0 && !below; i--) below = counterpart.get(order[i].series.key);\n const anchor = below?.points.filter(finite) ?? [];\n const points = band.points.map((p): KeyedAreaPoint => {\n if (!finite(p)) return p;\n const y = anchor.length ? sampleAt(anchor, p.x, (q) => q.y1) : baseline;\n return { x: p.x, y0: y, y1: y, key: p.key };\n });\n return { ...band, points };\n}\n\nfunction planArea(from: AreaGeometry, to: AreaGeometry): GeometryMorph | null {\n if (from.stacked !== to.stacked) return null;\n if (vertexTotal(from.bands) > MORPH_LIMITS.vertices || vertexTotal(to.bands) > MORPH_LIMITS.vertices) return null;\n const fromBands = drawable(from.bands);\n const toBands = drawable(to.bands);\n const fromByKey = new Map(fromBands.map((band) => [band.series.key, band]));\n const toByKey = new Map(toBands.map((band) => [band.series.key, band]));\n const tracks = pairSeries(fromBands, toBands).map(({ a, b }): Track<BandPoints> => {\n if (a && b) return bandTrack(a, b);\n if (!to.stacked) return b ? fadeTrack(b, 0, b.alpha) : fadeTrack(a!, a!.alpha, 0);\n if (b) return bandTrack(collapsedBand(b, toBands, fromByKey, from.baseline), b);\n return bandTrack(a!, collapsedBand(a!, fromBands, toByKey, to.baseline));\n });\n return { at: (t) => (t >= 1 ? to : { ...to, bands: tracks.map((track) => track(t)) }) };\n}\n\n/* ------------------------------------------------------------------ */\n/* Scatter */\n/* ------------------------------------------------------------------ */\n\n/** Identity for a datum from its non-positional columns (used when row objects differ). */\nfunction signature(row: Datum | undefined, positional: ReadonlySet<string>): string {\n if (!row || typeof row !== 'object') return '';\n const parts: string[] = [];\n for (const key of Object.keys(row).sort()) {\n if (positional.has(key)) continue;\n const value = row[key];\n if (value !== null && typeof value === 'object' && !(value instanceof Date)) continue;\n parts.push(`${key}=${toKey(value)}`);\n }\n return parts.join('\\u0002');\n}\n\nfunction pairPoints(from: ScatterGeometry, to: ScatterGeometry): Array<{ a?: ScatterPoint; b?: ScatterPoint }> {\n const byRow = new Map<Datum, ScatterPoint>();\n for (const p of from.points) if (p.row) byRow.set(p.row, p);\n const matched = new Set<ScatterPoint>();\n const pairs: Array<{ a?: ScatterPoint; b?: ScatterPoint }> = [];\n const unmatched: ScatterPoint[] = [];\n for (const b of to.points) {\n const a = b.row ? byRow.get(b.row) : undefined;\n if (a && !matched.has(a) && a.seriesKey === b.seriesKey) {\n matched.add(a);\n pairs.push({ a, b });\n } else unmatched.push(b);\n }\n // New row objects (a fresh update) still pair by series + non-positional\n // columns, falling back to order of appearance within the series.\n const positional = new Set([to.fields.x, to.fields.y, ...(to.fields.size ? [to.fields.size] : [])]);\n const pool = new Map<string, ScatterPoint[]>();\n for (const a of from.points) {\n if (matched.has(a)) continue;\n const key = `${a.seriesKey}\\u0001${signature(a.row, positional)}`;\n const list = pool.get(key);\n if (list) list.push(a);\n else pool.set(key, [a]);\n }\n for (const b of unmatched) {\n const a = pool.get(`${b.seriesKey}\\u0001${signature(b.row, positional)}`)?.shift();\n if (a) matched.add(a);\n pairs.push({ a, b });\n }\n const exits = from.points.filter((a) => !matched.has(a)).map((a) => ({ a }));\n return [...exits, ...pairs];\n}\n\nfunction pointTrack(a: ScatterPoint | undefined, b: ScatterPoint | undefined): Track<ScatterPoint> {\n if (a && b) {\n const color = colorTrack(a.color, b.color);\n return (t) => ({\n ...b,\n x: lerp(a.x, b.x, t),\n y: lerp(a.y, b.y, t),\n r: lerp(a.r, b.r, t),\n color: color(t),\n alpha: lerp(a.alpha, b.alpha, t),\n });\n }\n // Entering points grow out of their position; exiting points shrink away.\n if (b) return (t) => ({ ...b, r: b.r * t, alpha: b.alpha * t });\n return (t) => ({ ...a!, r: a!.r * (1 - t), alpha: a!.alpha * (1 - t) });\n}\n\nfunction planScatter(from: ScatterGeometry, to: ScatterGeometry): GeometryMorph | null {\n if (from.points.length > MORPH_LIMITS.points || to.points.length > MORPH_LIMITS.points) return null;\n const tracks = pairPoints(from, to).map(({ a, b }) => pointTrack(a, b));\n return { at: (t) => (t >= 1 ? to : { ...to, points: tracks.map((track) => track(t)) }) };\n}\n\n/* ------------------------------------------------------------------ */\n/* Boxes */\n/* ------------------------------------------------------------------ */\n\n/** A box folded flat onto its median line, invisible \u2014 where boxes enter from and exit to. */\nfunction flatBox(mark: BoxMark): BoxMark {\n const y = mark.yMed;\n return { ...mark, yQ1: y, yQ3: y, yLo: y, yHi: y, outliers: mark.outliers.map(() => y), alpha: 0 };\n}\n\n/** The whisker end nearer to `y` \u2014 where an outlier with no counterpart emerges or retracts. */\nfunction whiskerEnd(mark: BoxMark, y: number): number {\n return Math.abs(y - mark.yHi) <= Math.abs(y - mark.yLo) ? mark.yHi : mark.yLo;\n}\n\nfunction boxTrack(a: BoxMark, b: BoxMark): Track<BoxMark> {\n const color = colorTrack(a.color, b.color);\n const count = Math.max(a.outliers.length, b.outliers.length);\n const from: number[] = [];\n const to: number[] = [];\n for (let i = 0; i < count; i++) {\n const ya = a.outliers[i];\n const yb = b.outliers[i];\n from.push(ya ?? whiskerEnd(a, yb));\n to.push(yb ?? whiskerEnd(b, ya));\n }\n return (t) => ({\n ...b,\n color: color(t),\n cx: lerp(a.cx, b.cx, t),\n boxW: lerp(a.boxW, b.boxW, t),\n yQ1: lerp(a.yQ1, b.yQ1, t),\n yQ3: lerp(a.yQ3, b.yQ3, t),\n yMed: lerp(a.yMed, b.yMed, t),\n yLo: lerp(a.yLo, b.yLo, t),\n yHi: lerp(a.yHi, b.yHi, t),\n outliers: from.map((y, i) => lerp(y, to[i], t)),\n alpha: lerp(a.alpha, b.alpha, t),\n });\n}\n\n/**\n * Boxes keyed by category (and series) glide and reshape \u2014 quartiles, whiskers\n * and median travel to their new levels, outliers slide along (extra ones\n * emerge from / retract into the nearer whisker), new boxes unfold from their\n * median and removed ones fold flat.\n */\nfunction planBoxes(from: BoxGeometry, to: BoxGeometry): GeometryMorph | null {\n if (from.marks.length > MORPH_LIMITS.bars || to.marks.length > MORPH_LIMITS.bars) return null;\n const before = new Map(from.marks.map((mark) => [mark.key, mark]));\n const kept = new Set(to.marks.map((mark) => mark.key));\n const tracks = [\n ...from.marks.filter((mark) => !kept.has(mark.key)).map((mark) => boxTrack(mark, flatBox(mark))),\n ...to.marks.map((mark) => boxTrack(before.get(mark.key) ?? flatBox(mark), mark)),\n ];\n return { at: (t) => (t >= 1 ? to : { ...to, marks: tracks.map((track) => track(t)) }) };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }