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/charts/radialBar.ts"],
4
+ "sourcesContent": ["/**\n * Radial bar renderer.\n *\n * Two layouts share one keyed mark model:\n * - `radial` (default): one concentric track per category, the first category\n * outermost. Each arc sweeps clockwise from 12 o'clock with a length\n * proportional to `value / max` over at most `sweep` degrees (progress rings).\n * - `polar`: equal-angle wedges starting at 12 o'clock whose AREA is\n * proportional to `value / max` \u2014 the radius grows with the square root \u2014 a\n * polar-area (\"nightingale rose\") chart.\n *\n * Values above `max` fill their track and carry a small chevron so overflow is\n * never silently hidden; the tooltip shows the true value and its share of max.\n * Labels name each arc at its start (radial) or around the rim (polar); when\n * they cannot fit, a legend takes over. Arcs sweep in on entrance, and an update\n * carries every arc to its new length (new categories grow in, removed ones\n * shrink away) instead of cross-fading.\n */\n\nimport { contrastRatio, parseColor, rgbaToCss } from '../color';\nimport { formatValue } from '../format';\nimport type { Hover, HoverPaintState, InteractionModel, TooltipRow } from '../interaction/types';\nimport { FOCUS_VEIL, hoverFocusEnabled, paintCutoutVeil } from '../interaction/veil';\nimport type { MarkBoundary } from '../render/evidence';\nimport { boxesOverlap, fitLabel } from '../render/labelLedger';\nimport type { Surface } from '../render/surface';\nimport { fontString, measureText } from '../render/text';\nimport { RoughPen } from '../rough';\nimport {\n buildRadialBarModel,\n minArcSpan,\n polarRadius,\n radialBarPalette,\n radialTracks,\n sectorBounds,\n sectorExtents,\n TAU,\n valueAngle,\n type RadialBarModel,\n type TrackLayout,\n} from '../runtime/radialBar';\nimport { arc, type PathSink } from '../shape';\nimport { resolveSketch } from '../spec/sketch';\nimport type { ChartSpec, RadialBarSpec } from '../spec/types';\nimport type { ThemeTokens } from '../theme';\nimport type { Insets, Rect, RGBA, Size } from '../types';\nimport { addOverlayText, drawCategoricalLegend, drawTitleBlock, type LegendEntry } from './chrome';\nimport { rowAlpha } from './emphasis';\nimport type { RenderContext } from './index';\nimport { compositeOver, contrastTarget, inkOn, knownBackdrop, toneForContrast } from './legibility';\nimport { lerp, lerpValue, mixColor, morphInput, morphKeyed, stashMorphFrame, switchAt, type MorphPlan } from './morphFrame';\nimport { drawNoData } from './noData';\n\ntype Layout = 'radial' | 'polar';\n\n/** Gap between a radial label's right edge and the 12 o'clock line. */\nconst LABEL_GAP = 8;\n/** Gap between a label's category name and its value. */\nconst NAME_GAP = 5;\n/** Distance from the rose's rim to its outside labels. */\nconst POLAR_LABEL_OFFSET = 8;\n/** Thinnest wedge (px) a positive value draws in the polar layout. */\nconst MIN_POLAR_THICKNESS = 2;\n/** Fills fainter than this against the backdrop get a tone-on-tone hairline (the report's mark floor is 1.5). */\nconst PALE_CONTRAST = 1.6;\nconst EPSILON = 1e-6;\n\n/** An annular sector: radii, clockwise angles from 12 o'clock, rounding and gaps. */\ninterface Sector {\n inner: number;\n outer: number;\n start: number;\n end: number;\n corner: number;\n pad: number;\n /** Radius the pad gap is measured at, so gaps stay parallel-sided. */\n padRadius: number;\n}\n\n/** An arc or wedge as drawn, keyed by category so an update carries it to its new value. */\nexport interface RadialBarMark {\n key: string;\n layout: Layout;\n label: string;\n /** Displayed value; counts between datasets mid-morph. */\n value: number;\n color: string;\n cx: number;\n cy: number;\n /** The value arc (radial) or wedge (polar). */\n arc: Sector;\n /** Its background track (radial) or full-radius slot (polar). */\n track: Sector;\n /** Overflow-indicator strength: 1 when the value exceeds `max`. */\n over: number;\n /** Highlight alpha, carried so emphasis changes fade instead of snapping. */\n emph: number;\n /** Fade for categories arriving or leaving mid-morph. */\n alpha: number;\n}\n\ninterface LabelStyle {\n size: number;\n lineH: number;\n nameFont: string;\n valueFont: string;\n}\n\n/** The resolved layout of one draw. */\ninterface Frame {\n layout: Layout;\n /** Drawing area after title, padding and legend. */\n area: Rect;\n cx: number;\n cy: number;\n radius: number;\n hole: number;\n /** Largest arc sweep (radial); a full turn for polar. */\n sweep: number;\n /** Radial track thickness, pitch and radii (outermost first). */\n tracks: TrackLayout;\n /** Polar wedge span and pad angle. */\n span: number;\n pad: number;\n /** Label style when labels are drawn, else null. */\n labels: LabelStyle | null;\n legend: boolean;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\nfunction finiteOr(value: unknown, fallback: number): number {\n return typeof value === 'number' && Number.isFinite(value) ? value : fallback;\n}\n\nfunction valueFormat(spec: RadialBarSpec): string | undefined {\n const format = spec.format ?? spec.encoding?.value?.format;\n return typeof format === 'string' ? format : undefined;\n}\n\nfunction insetRect(rect: Rect, padding: Partial<Insets> | undefined): Rect {\n const pad = (side: unknown): number => (typeof side === 'number' && Number.isFinite(side) ? Math.max(0, side) : 0);\n const p = padding && typeof padding === 'object' ? padding : {};\n const left = pad(p.left);\n const top = pad(p.top);\n return {\n x: rect.x + left,\n y: rect.y + top,\n width: Math.max(0, rect.width - left - pad(p.right)),\n height: Math.max(0, rect.height - top - pad(p.bottom)),\n };\n}\n\nfunction tooltipEnabled(spec: RadialBarSpec): boolean {\n const tooltip = spec.tooltip;\n return tooltip !== false && !(tooltip && typeof tooltip === 'object' && tooltip.show === false);\n}\n\n// ---------------------------------------------------------------------------\n// Geometry\n// ---------------------------------------------------------------------------\n\nfunction traceSector(sink: PathSink, cx: number, cy: number, s: Sector): void {\n if (s.end - s.start >= TAU - 1e-9) {\n traceRing(sink, cx, cy, s.inner, s.outer, s.start);\n return;\n }\n arc({\n innerRadius: s.inner,\n outerRadius: s.outer,\n startAngle: s.start,\n endAngle: s.end,\n cornerRadius: s.corner,\n padAngle: s.pad,\n padRadius: s.pad > 0 ? s.padRadius : undefined,\n })(sink, cx, cy);\n}\n\n/**\n * A full ring (or disk) as half-turn arcs, the outer circle clockwise and the\n * inner one counter-clockwise so the hole stays empty. Some canvas backends\n * (Skia in `@napi-rs/canvas`) drop a single arc that sweeps exactly 2\u03C0.\n */\nfunction traceRing(sink: PathSink, cx: number, cy: number, inner: number, outer: number, start: number): void {\n const a0 = start - Math.PI / 2;\n sink.moveTo(cx + outer * Math.cos(a0), cy + outer * Math.sin(a0));\n sink.arc(cx, cy, outer, a0, a0 + Math.PI, false);\n sink.arc(cx, cy, outer, a0 + Math.PI, a0 + TAU, false);\n sink.closePath();\n if (!(inner > EPSILON)) return;\n sink.moveTo(cx + inner * Math.cos(a0), cy + inner * Math.sin(a0));\n sink.arc(cx, cy, inner, a0, a0 - Math.PI, true);\n sink.arc(cx, cy, inner, a0 - Math.PI, a0 - TAU, true);\n sink.closePath();\n}\n\nfunction drawable(s: Sector): boolean {\n return s.end - s.start > EPSILON && s.outer - s.inner > EPSILON;\n}\n\nfunction lerpSector(a: Sector, b: Sector, t: number): Sector {\n return {\n inner: lerp(a.inner, b.inner, t),\n outer: lerp(a.outer, b.outer, t),\n start: lerp(a.start, b.start, t),\n end: lerp(a.end, b.end, t),\n corner: lerp(a.corner, b.corner, t),\n pad: lerp(a.pad, b.pad, t),\n padRadius: lerp(a.padRadius, b.padRadius, t),\n };\n}\n\nconst NO_TRACKS: TrackLayout = { width: 0, pitch: 0, radii: [] };\n\n/**\n * Fit concentric tracks spanning `sweep` into `area`. Labels sit left of the\n * 12 o'clock line, so when they need more room than the empty quarter offers\n * the rings may shrink (down to `minScale` of their full size) and shift right.\n */\nfunction fitRadial(area: Rect, n: number, sweep: number, holeFrac: number, column: number, lineH: number, minScale = 0.75) {\n const ext = sectorExtents(holeFrac, 1, 0, sweep);\n const spanX = Math.max(EPSILON, ext.maxX - ext.minX);\n const spanY = Math.max(EPSILON, ext.maxY - ext.minY);\n // The outermost label is centered on the outer track and may poke above it.\n const top = lineH / 2;\n const availH = Math.max(0, area.height - top);\n const full = Math.max(0, Math.min(availH / spanY, area.width / spanX));\n const labelsLeft = column > 0 && sweep <= 1.5 * Math.PI + EPSILON ? column + LABEL_GAP : 0;\n const leftOf = (r: number): number => Math.max(-ext.minX * r, labelsLeft);\n let radius = full;\n if (leftOf(radius) + ext.maxX * radius > area.width && ext.maxX > 0) {\n radius = Math.max(full * minScale, Math.min(full, (area.width - labelsLeft) / ext.maxX));\n }\n const right = ext.maxX * radius;\n const left = Math.min(leftOf(radius), Math.max(0, area.width - right));\n const cx = area.x + Math.max(0, area.width - left - right) / 2 + left;\n const cy = area.y + top + Math.max(0, availH - spanY * radius) / 2 - ext.minY * radius;\n const hole = holeFrac * radius;\n return { cx, cy, radius, hole, tracks: radialTracks(radius, hole, n), span: 0, pad: 0 };\n}\n\n/** Fit the rose into `area`, leaving a ring of room for outside labels. */\nfunction fitPolar(area: Rect, n: number, holeFrac: number, column: number, lineH: number) {\n const bare = Math.max(0, Math.min(area.width, area.height) / 2 - 1);\n let radius = bare;\n if (column > 0) {\n const byHeight = (area.height - 2 * (lineH + POLAR_LABEL_OFFSET)) / 2;\n const wanted = Math.min((area.width - 2 * (column + POLAR_LABEL_OFFSET)) / 2, byHeight);\n // Long names ellipsize rather than starve the rose.\n radius = Math.max(Math.min(bare * 0.6, byHeight), wanted);\n }\n radius = Math.max(0, radius);\n const span = TAU / Math.max(1, n);\n const pad = n > 1 && radius > 0 ? Math.min(2 / radius, span * 0.25) : 0;\n return {\n cx: area.x + area.width / 2,\n cy: area.y + area.height / 2,\n radius,\n hole: holeFrac * radius,\n tracks: NO_TRACKS,\n span,\n pad,\n };\n}\n\n/**\n * How wide the radial label of the track at `radius` may be. Up to a 270\u00B0\n * sweep the quarter left of 12 o'clock is empty; beyond it, the label stops\n * short of any track the sweep draws across its row.\n */\nfunction radialLabelBudget(area: Rect, cx: number, sweep: number, radius: number, rings: readonly number[], width: number, lineH: number): number {\n let budget = cx - LABEL_GAP - area.x;\n if (sweep <= 1.5 * Math.PI + EPSILON) return Math.max(0, budget);\n const slope = Math.tan(TAU - sweep);\n const half = width / 2;\n for (const ring of rings) {\n for (const dy of [radius - lineH / 2, radius, radius + lineH / 2]) {\n if (dy <= 0) continue;\n const outer = ring + half;\n const inner = ring - half;\n if (outer <= dy) continue;\n // Where this ring's drawn part begins along the label row (distance left of 12 o'clock).\n const from = Math.max(inner > dy ? Math.sqrt(inner * inner - dy * dy) : 0, dy * slope);\n if (from > Math.sqrt(outer * outer - dy * dy)) continue;\n budget = Math.min(budget, from - LABEL_GAP - 2);\n }\n }\n return Math.max(0, budget);\n}\n\nfunction labelStyle(tokens: ThemeTokens, size: number): LabelStyle {\n return {\n size,\n lineH: size * 1.2,\n nameFont: fontString(size, tokens.font.family, tokens.font.weight.normal),\n valueFont: fontString(size, tokens.font.family, tokens.font.weight.bold),\n };\n}\n\ninterface LegendChoice {\n mode: 'auto' | 'on' | 'off';\n position: 'top' | 'right' | 'bottom' | 'left';\n}\n\n/** A label style that fits, and how far the rings may shrink to make room for it. */\ninterface Labelling {\n style: LabelStyle;\n minScale: number;\n}\n\nfunction legendChoice(spec: RadialBarSpec, area: Rect): LegendChoice {\n const legend = spec.legend;\n const auto = area.width >= area.height * 1.15 ? 'right' : 'bottom';\n if (legend === false || (legend && typeof legend === 'object' && legend.show === false)) return { mode: 'off', position: auto };\n if (legend && typeof legend === 'object') return { mode: 'on', position: legend.position ?? auto };\n return { mode: legend === true ? 'on' : 'auto', position: auto };\n}\n\n/**\n * Resolve the layout: labels when (most) arcs can carry one; otherwise \u2014 or\n * when asked \u2014 a legend names the arcs and the rings fit the space left over.\n */\nfunction planFrame(surface: Surface, spec: RadialBarSpec, tokens: ThemeTokens, content: Rect, model: RadialBarModel): Frame {\n const layout: Layout = spec.layout === 'polar' ? 'polar' : 'radial';\n const n = model.items.length;\n const sweep = layout === 'polar' ? TAU : (clamp(finiteOr(spec.sweep, 270), 30, 360) * Math.PI) / 180;\n const holeFrac = clamp(finiteOr(spec.innerRadius, 0.25), 0, 0.9);\n const format = valueFormat(spec);\n const texts = model.items.map((item) => ({ name: item.label, value: formatValue(item.value, format) }));\n // Widest label column per font size: names alone (polar) or name + value (radial).\n const columns = new Map<number, number>();\n const columnFor = (style: LabelStyle): number => {\n let width = columns.get(style.size);\n if (width === undefined) {\n width = texts.reduce((w, t) => Math.max(w, measureText(t.name, style.nameFont).width +\n (layout === 'radial' ? NAME_GAP + measureText(t.value, style.valueFont).width : 0)), 0);\n columns.set(style.size, width);\n }\n return width;\n };\n const fit = (area: Rect, labels: Labelling | null) => {\n const style = labels?.style;\n if (layout === 'polar') {\n const column = style ? Math.min(columnFor(style), Math.max(40, area.width * 0.22)) : 0;\n return fitPolar(area, n, holeFrac, column, style?.lineH ?? 0);\n }\n return fitRadial(area, n, sweep, holeFrac, style ? columnFor(style) : 0, style?.lineH ?? 0, labels?.minScale);\n };\n const readable = (area: Rect): Labelling | null => {\n if (spec.labels === false || area.width <= 0 || area.height <= 0) return null;\n for (const size of [tokens.font.size.small, tokens.font.size.tiny]) {\n const style = labelStyle(tokens, size);\n if (layout === 'polar') {\n const g = fit(area, { style, minScale: 1 });\n if (g.radius >= 24 && (g.radius + POLAR_LABEL_OFFSET) * g.span >= style.lineH * 0.9) return { style, minScale: 1 };\n continue;\n }\n // Shrinking the rings to make room for long names must not make the tracks too thin to label;\n // full-size rings with shortened names beat a legend.\n for (const minScale of [0.75, 1]) {\n const g = fit(area, { style, minScale });\n if (!(g.radius > 0) || g.tracks.pitch < style.lineH - 1.5) continue;\n // Most tracks need room for at least a short name beside their value.\n const roomy = g.tracks.radii.filter((r, i) =>\n radialLabelBudget(area, g.cx, sweep, r, g.tracks.radii, g.tracks.width, style.lineH) >=\n Math.min(48, measureText(texts[i].value, style.valueFont).width + NAME_GAP + 24)).length;\n if (roomy * 2 >= n) return { style, minScale };\n }\n }\n return null;\n };\n\n const legend = legendChoice(spec, content);\n let labels = readable(content);\n const showLegend = legend.mode === 'on' || (legend.mode === 'auto' && labels === null);\n let area = content;\n if (showLegend) {\n const entries: LegendEntry[] = model.items.map((item) => ({ label: item.label, color: item.color, symbol: 'circle' }));\n area = drawCategoricalLegend(surface, tokens, content, entries, legend.position);\n if (labels) labels = readable(area);\n }\n if (labels === null && spec.labels !== false) {\n surface.labels?.omit({ role: 'data-label', reason: 'space', required: !showLegend, count: n, path: '/labels' });\n }\n return { layout, area, sweep, labels: labels?.style ?? null, legend: showLegend, ...fit(area, labels) };\n}\n\n// ---------------------------------------------------------------------------\n// Marks\n// ---------------------------------------------------------------------------\n\n/** Final marks for the frame, swept to `sweepProgress` on entrance (outer rings lead). */\nfunction buildMarks(frame: Frame, model: RadialBarModel, spec: RadialBarSpec, context: RenderContext | undefined): RadialBarMark[] {\n const progress = clamp(finiteOr(context?.sweepProgress, 1), 0, 1);\n const n = model.items.length;\n const stagger = n > 1 ? Math.min(0.08, 0.35 / (n - 1)) : 0;\n const categoryField = spec.encoding.category.field;\n const emphasis = context?.emphasis ?? null;\n const corner = (thickness: number): number => Math.max(0, Math.min(4, thickness * 0.22));\n return model.items.map((item, i): RadialBarMark => {\n const local = progress >= 1 ? 1 : clamp((progress - i * stagger) / (1 - (n - 1) * stagger), 0, 1);\n const shows = item.value > 0 && local > 0;\n const base = {\n key: item.key,\n layout: frame.layout,\n label: item.label,\n value: item.value,\n color: item.color,\n cx: frame.cx,\n cy: frame.cy,\n over: item.value > model.max && local >= 1 ? 1 : 0,\n emph: rowAlpha(emphasis, { [categoryField]: item.category }),\n alpha: 1,\n };\n if (frame.layout === 'radial') {\n const r = frame.tracks.radii[i];\n const w = frame.tracks.width;\n const track: Sector = { inner: r - w / 2, outer: r + w / 2, start: 0, end: frame.sweep, corner: w / 2, pad: 0, padRadius: 0 };\n const swept = valueAngle(item.value, model.max, frame.sweep) * local;\n // A positive value always shows at least a round dot.\n const end = shows ? Math.min(frame.sweep, Math.max(swept, minArcSpan(r, w))) : 0;\n return { ...base, track, arc: { ...track, end } };\n }\n const start = i * frame.span;\n const room = Math.max(0, frame.radius - frame.hole);\n const track: Sector = {\n inner: frame.hole, outer: frame.radius, start, end: start + frame.span,\n corner: corner(room), pad: frame.pad, padRadius: frame.radius,\n };\n const reach = polarRadius(item.value, model.max, frame.hole, frame.radius) - frame.hole;\n const thickness = shows ? Math.min(room, Math.max(reach * local, MIN_POLAR_THICKNESS)) : 0;\n return { ...base, track, arc: { ...track, outer: frame.hole + thickness, corner: corner(thickness) } };\n });\n}\n\n/**\n * `mark` grown to fraction `k`. Its slot opens (or closes) as neighbours\n * re-space \u2014 a ring thickens about its radius, a wedge widens about its\n * mid-angle \u2014 while the arc sweeps out of 12 o'clock or the wedge out of the hole.\n */\nfunction grown(mark: RadialBarMark, k: number, alpha: number): RadialBarMark {\n const scale = (s: Sector): Sector => {\n if (mark.layout === 'radial') {\n const mid = (s.inner + s.outer) / 2;\n const half = ((s.outer - s.inner) / 2) * k;\n return { ...s, inner: mid - half, outer: mid + half, corner: s.corner * k };\n }\n const mid = (s.start + s.end) / 2;\n const half = ((s.end - s.start) / 2) * k;\n return { ...s, start: mid - half, end: mid + half };\n };\n const track = scale(mark.track);\n const arc = scale(mark.arc);\n if (mark.layout === 'radial') arc.end = lerp(arc.start, arc.end, k);\n else arc.outer = lerp(arc.inner, arc.outer, k);\n // An arc in transit isn't full, so it carries no overflow chevron.\n return { ...mark, arc, track, over: k >= 1 ? mark.over : 0, alpha };\n}\n\nconst RADIAL_BAR_MORPH: MorphPlan<RadialBarMark> = {\n lerp: (a, b, t) => ({\n key: b.key,\n layout: switchAt(a.layout, b.layout, t),\n label: b.label,\n value: lerpValue(a.value, b.value, t),\n color: mixColor(a.color, b.color, t),\n cx: lerp(a.cx, b.cx, t),\n cy: lerp(a.cy, b.cy, t),\n arc: lerpSector(a.arc, b.arc, t),\n track: lerpSector(a.track, b.track, t),\n over: lerp(a.over, b.over, t),\n emph: lerp(a.emph, b.emph, t),\n alpha: lerp(a.alpha, b.alpha, t),\n }),\n enter: (b, t) => grown(b, t, t),\n exit: (a, t) => grown(a, 1 - t, a.alpha * (1 - t)),\n};\n\n// ---------------------------------------------------------------------------\n// Painting\n// ---------------------------------------------------------------------------\n\ninterface PaintStyle {\n tokens: ThemeTokens;\n pen: RoughPen | null;\n /** Track color, or null when tracks are off. */\n track: string | null;\n backdrop: RGBA | null;\n}\n\nfunction trackColor(tokens: ThemeTokens): string {\n if (!tokens.dark) return tokens.color.grid;\n const muted = parseColor(tokens.color.textMuted);\n return muted ? rgbaToCss({ ...muted, a: 0.16 }) : tokens.color.grid;\n}\n\n/** The color actually under a mark's ink: its fill, composited when faded. */\nfunction underColor(mark: RadialBarMark, style: PaintStyle): RGBA | null {\n const fill = parseColor(mark.color);\n if (!fill) return null;\n const alpha = mark.emph * mark.alpha;\n return style.backdrop && (alpha < 1 || fill.a < 1) ? compositeOver(fill, alpha, style.backdrop) : { ...fill, a: 1 };\n}\n\n/** A pale fill's identifying hairline: its own hue, deepened just enough to read. */\nfunction paleBoundary(mark: RadialBarMark, style: PaintStyle, opacity: number): MarkBoundary | undefined {\n const fill = parseColor(mark.color);\n const { backdrop } = style;\n if (!fill || !backdrop || contrastRatio(compositeOver(fill, 1, backdrop), backdrop) >= PALE_CONTRAST) return undefined;\n const color = toneForContrast(mark.color, contrastTarget(backdrop, style.tokens), backdrop, PALE_CONTRAST);\n return { color, opacity, width: 1 };\n}\n\nfunction paintTrack(ctx: CanvasRenderingContext2D, mark: RadialBarMark, style: PaintStyle, color: string): void {\n const s = mark.track;\n if (!drawable(s) || !(mark.alpha > 0)) return;\n if (mark.alpha !== 1) ctx.globalAlpha = mark.alpha;\n if (style.pen) {\n style.pen.wedge(mark.cx, mark.cy, s.inner, s.outer, s.start, s.end, { fill: color, fillStyle: 'solid' });\n } else {\n ctx.beginPath();\n traceSector(ctx, mark.cx, mark.cy, s);\n ctx.fillStyle = color;\n ctx.fill();\n }\n if (mark.alpha !== 1) ctx.globalAlpha = 1;\n}\n\nfunction paintArc(surface: Surface, ctx: CanvasRenderingContext2D, mark: RadialBarMark, style: PaintStyle): void {\n const s = mark.arc;\n const alpha = mark.emph * mark.alpha;\n if (!drawable(s) || !(alpha > 0)) return;\n const boundary = style.pen ? undefined : paleBoundary(mark, style, alpha);\n if (alpha !== 1) ctx.globalAlpha = alpha;\n if (style.pen) {\n style.pen.wedge(mark.cx, mark.cy, s.inner, s.outer, s.start, s.end, { fill: mark.color, stroke: mark.color, strokeWidth: 1 });\n } else {\n ctx.beginPath();\n traceSector(ctx, mark.cx, mark.cy, s);\n ctx.fillStyle = mark.color;\n ctx.fill();\n if (boundary) {\n ctx.strokeStyle = boundary.color;\n ctx.lineWidth = boundary.width;\n ctx.stroke();\n }\n }\n if (alpha !== 1) ctx.globalAlpha = 1;\n const b = sectorBounds(mark.cx, mark.cy, s.inner, s.outer, s.start, s.end);\n surface.evidence?.mark(mark.layout === 'radial' ? 'bar' : 'slice', b.x, b.y, b.width, b.height, mark.color, alpha,\n undefined, 1, undefined, alpha < 1, boundary);\n}\n\n/**\n * A \"\u00BB\" inside the end of an arc that exceeds `max` \u2014 pointing along the sweep\n * (radial) or out of the rim (polar) \u2014 so a clamped value never reads as\n * exactly full. Thin marks get a single chevron; hairlines rely on the label\n * and tooltip.\n */\nfunction paintOverflow(ctx: CanvasRenderingContext2D, mark: RadialBarMark, style: PaintStyle): void {\n const s = mark.arc;\n const alpha = mark.over * mark.emph * mark.alpha;\n if (!drawable(s) || !(alpha > 0)) return;\n const thickness = s.outer - s.inner;\n let size: number;\n let a: number;\n let r: number;\n let tangential: boolean;\n if (mark.layout === 'radial') {\n r = (s.inner + s.outer) / 2;\n size = Math.min(thickness * 0.5, 12);\n // Centered on the round end cap.\n a = s.end - minArcSpan(r, thickness) / 2;\n if (thickness < 7 || a <= s.start) return;\n tangential = true;\n } else {\n size = Math.min(thickness * 0.3, 12);\n r = s.outer - size * 1.1;\n a = (s.start + s.end) / 2;\n const room = 2 * r * Math.sin(Math.min(Math.PI / 2, (s.end - s.start - s.pad) / 2));\n if (size < 5 || room < size + 6 || r - size <= s.inner) return;\n tangential = false;\n }\n const radial = { x: Math.sin(a), y: -Math.cos(a) };\n const along = { x: Math.cos(a), y: Math.sin(a) };\n // Point along the sweep (radial) or out of the rim (polar).\n const dir = tangential ? along : radial;\n const side = tangential ? radial : along;\n const back = size / 4;\n const offsets = thickness >= 12 ? [-size * 0.3, size * 0.3] : [0];\n const under = underColor(mark, style);\n const ink = under ? inkOn(under, style.tokens, 3) : style.tokens.color.background;\n const width = Math.max(1.4, size * 0.17);\n ctx.globalAlpha = alpha * 0.9;\n for (const offset of offsets) {\n const cx = mark.cx + r * radial.x + dir.x * offset;\n const cy = mark.cy + r * radial.y + dir.y * offset;\n const pts = [\n { x: cx - dir.x * back + (side.x * size) / 2, y: cy - dir.y * back + (side.y * size) / 2 },\n { x: cx + dir.x * back, y: cy + dir.y * back },\n { x: cx - dir.x * back - (side.x * size) / 2, y: cy - dir.y * back - (side.y * size) / 2 },\n ];\n if (style.pen) {\n style.pen.polyline(pts, { stroke: ink, strokeWidth: width });\n continue;\n }\n ctx.beginPath();\n ctx.moveTo(pts[0].x, pts[0].y);\n ctx.lineTo(pts[1].x, pts[1].y);\n ctx.lineTo(pts[2].x, pts[2].y);\n ctx.strokeStyle = ink;\n ctx.lineWidth = width;\n ctx.lineCap = 'round';\n ctx.lineJoin = 'round';\n ctx.stroke();\n }\n ctx.globalAlpha = 1;\n}\n\n/** Tracks beneath every arc, then the arcs, then overflow chevrons on top. */\nfunction paintMarks(surface: Surface, marks: readonly RadialBarMark[], style: PaintStyle): void {\n if (marks.length === 0) return;\n const ctx = surface.marks.ctx;\n ctx.save();\n if (style.track) for (const mark of marks) paintTrack(ctx, mark, style, style.track);\n for (const mark of marks) paintArc(surface, ctx, mark, style);\n for (const mark of marks) if (mark.over > 0) paintOverflow(ctx, mark, style);\n ctx.restore();\n}\n\n// ---------------------------------------------------------------------------\n// Labels\n// ---------------------------------------------------------------------------\n\ninterface LabelContext {\n surface: Surface;\n tokens: ThemeTokens;\n spec: RadialBarSpec;\n frame: Frame;\n style: LabelStyle;\n paint: PaintStyle;\n /** Hit boxes of drawn labels, by mark key. */\n boxes: Map<string, Rect>;\n}\n\nfunction omitLabel(ctx: LabelContext, reason: 'space' | 'collision' | 'unreadable', example: string): void {\n ctx.surface.labels?.omit({ role: 'data-label', reason, required: !ctx.frame.legend, example, path: '/labels' });\n}\n\n/** Opacity for a faded label, and the backdrop its contrast is judged on (intentionally dimmed text isn't). */\nfunction labelPaint(ctx: LabelContext, mark: RadialBarMark): { opacity?: number; background?: string } {\n const alpha = mark.emph * mark.alpha;\n return alpha < 1 ? { opacity: alpha } : { background: ctx.surface.evidence?.background };\n}\n\n/** Name + value right-aligned against the 12 o'clock line, at the start of each track. */\nfunction drawRadialLabels(ctx: LabelContext, marks: readonly RadialBarMark[]): void {\n const { surface, tokens, frame, style } = ctx;\n const format = valueFormat(ctx.spec);\n const rings = marks.map((m) => (m.track.inner + m.track.outer) / 2);\n for (const mark of marks) {\n const r = (mark.track.inner + mark.track.outer) / 2;\n const y = mark.cy - r;\n const right = mark.cx - LABEL_GAP;\n const valueText = formatValue(mark.value, format);\n const budget = radialLabelBudget(frame.area, mark.cx, frame.sweep, r, rings, mark.track.outer - mark.track.inner, style.lineH);\n const valueW = measureText(valueText, style.valueFont).width;\n const nameBudget = budget - valueW - NAME_GAP;\n // Rows stay inside the area and above the 9 o'clock line, where the arcs return.\n const fitsRow = y - style.lineH / 2 >= frame.area.y - 1 && y + style.lineH / 2 <= mark.cy - 1;\n if (!fitsRow || nameBudget < 12) {\n omitLabel(ctx, 'space', mark.label);\n continue;\n }\n const fitted = fitLabel(mark.label, nameBudget, style.nameFont);\n if (fitted.truncated && (fitted.text.length < 4 || fitted.text === '\u2026')) {\n omitLabel(ctx, 'unreadable', mark.label);\n continue;\n }\n const paint = labelPaint(ctx, mark);\n addOverlayText(surface, tokens, {\n left: right, top: y, text: valueText, color: tokens.color.text, size: style.size,\n weight: tokens.font.weight.bold, transform: 'translate(-100%,-50%)', path: '/labels', ...paint,\n });\n const nameRight = right - valueW - NAME_GAP;\n addOverlayText(surface, tokens, {\n left: nameRight, top: y, text: mark.label, color: tokens.color.textMuted, size: style.size,\n transform: 'translate(-100%,-50%)', maxWidth: nameBudget, path: '/labels', ...paint,\n });\n const nameW = measureText(fitted.text, style.nameFont).width;\n ctx.boxes.set(mark.key, { x: nameRight - nameW, y: y - style.lineH / 2, width: right - nameRight + nameW, height: style.lineH });\n }\n}\n\n/** Category names around the rim at each wedge's mid-angle; values inside wedges that fit them. */\nfunction drawPolarLabels(ctx: LabelContext, marks: readonly RadialBarMark[]): void {\n const { surface, tokens, frame, style } = ctx;\n const { area } = frame;\n const format = valueFormat(ctx.spec);\n const placed: Rect[] = [];\n const cap = Math.max(40, area.width * 0.22);\n for (const mark of marks) {\n const a = (mark.track.start + mark.track.end) / 2;\n const sin = Math.sin(a);\n const cos = Math.cos(a);\n const rim = mark.track.outer + POLAR_LABEL_OFFSET;\n const px = mark.cx + rim * sin;\n const py = mark.cy - rim * cos;\n const align = sin > 0.3 ? 'left' : sin < -0.3 ? 'right' : 'center';\n const midY = py - (cos * style.lineH) / 2;\n const room = align === 'left' ? area.x + area.width - px : align === 'right' ? px - area.x\n : 2 * Math.min(px - area.x, area.x + area.width - px);\n const budget = Math.min(room, align === 'center' ? cap * 1.6 : cap);\n const fitted = fitLabel(mark.label, budget, style.nameFont);\n if (budget < 16 || (fitted.truncated && (fitted.text.length < 4 || fitted.text === '\u2026'))) {\n omitLabel(ctx, 'unreadable', mark.label);\n continue;\n }\n const w = measureText(fitted.text, style.nameFont).width;\n const box = { x: align === 'left' ? px : align === 'right' ? px - w : px - w / 2, y: midY - style.lineH / 2, width: w, height: style.lineH };\n if (box.y < area.y - 1 || box.y + box.height > area.y + area.height + 1) omitLabel(ctx, 'space', mark.label);\n else if (placed.some((p) => boxesOverlap(p, box, 2))) omitLabel(ctx, 'collision', mark.label);\n else {\n placed.push(box);\n addOverlayText(surface, tokens, {\n left: px, top: midY, text: mark.label, color: tokens.color.text, size: style.size,\n transform: align === 'left' ? 'translateY(-50%)' : align === 'right' ? 'translate(-100%,-50%)' : 'translate(-50%,-50%)',\n maxWidth: budget, path: '/labels', ...labelPaint(ctx, mark),\n });\n ctx.boxes.set(mark.key, box);\n }\n }\n drawPolarValues(ctx, marks, format);\n}\n\n/**\n * Each wedge's value, centered inside it in contrast-aware ink. Values show\n * where they fit as long as most wedges can carry theirs; otherwise none do,\n * so the rose never reads as randomly annotated.\n */\nfunction drawPolarValues(ctx: LabelContext, marks: readonly RadialBarMark[], format: string | undefined): void {\n const { surface, tokens } = ctx;\n const size = tokens.font.size.tiny;\n const font = fontString(size, tokens.font.family, tokens.font.weight.bold);\n const lineH = size * 1.2;\n const plans = marks.filter((mark) => drawable(mark.arc)).map((mark) => {\n const s = mark.arc;\n const text = formatValue(mark.value, format);\n const thickness = s.outer - s.inner;\n const r = s.inner + thickness * 0.55;\n const half = Math.min(Math.PI / 2, (s.end - s.start - s.pad) / 2);\n const chord = 2 * Math.max(0, r - lineH / 2) * Math.sin(Math.max(0, half));\n const fits = thickness >= lineH + 6 && chord >= measureText(text, font).width + 6;\n return { mark, text, r, fits };\n });\n const fitting = plans.filter((plan) => plan.fits);\n const shown = fitting.length * 3 >= plans.length * 2 ? fitting : [];\n surface.labels?.omit({\n role: 'data-label', reason: 'space', required: false, count: plans.length - shown.length,\n example: plans.find((plan) => !shown.includes(plan))?.text, path: '/labels',\n });\n for (const { mark, text, r } of shown) {\n const s = mark.arc;\n const a = (s.start + s.end) / 2;\n // Ink is chosen against the (possibly dimmed) fill actually beneath it.\n const under = underColor(mark, ctx.paint);\n addOverlayText(surface, tokens, {\n left: mark.cx + r * Math.sin(a), top: mark.cy - r * Math.cos(a), text, size,\n color: under ? inkOn(under, tokens) : tokens.color.text, weight: tokens.font.weight.bold,\n transform: 'translate(-50%,-50%)', opacity: mark.alpha < 1 ? mark.alpha : undefined,\n background: under && mark.alpha >= 1 ? rgbaToCss(under) : undefined, path: '/labels',\n });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Interaction\n// ---------------------------------------------------------------------------\n\n/** The slot each hover focuses, so a moving hover can glide between slots. */\nconst HOVER_SLOTS = new WeakMap<Hover, { key: string; cx: number; cy: number; slot: Sector }>();\n\nfunction buildInteraction(\n spec: RadialBarSpec,\n tokens: ThemeTokens,\n frame: Frame,\n model: RadialBarModel,\n marks: readonly RadialBarMark[],\n labelBoxes: ReadonlyMap<string, Rect>,\n): InteractionModel {\n const categoryField = spec.encoding.category.field;\n const format = valueFormat(spec);\n const measureLabel = spec.encoding.value.title ?? spec.encoding.value.field;\n const tooltips = tooltipEnabled(spec);\n const focusOn = hoverFocusEnabled(spec);\n const veil = spec.background ?? tokens.color.background;\n const region = frame.area;\n const n = model.items.length;\n\n const indexAt = (px: number, py: number): number => {\n for (let i = 0; i < n; i++) {\n const box = labelBoxes.get(marks[i].key);\n if (box && px >= box.x - 2 && px <= box.x + box.width + 2 && py >= box.y && py <= box.y + box.height) return i;\n }\n const dx = px - frame.cx;\n const dy = py - frame.cy;\n const r = Math.hypot(dx, dy);\n let theta = Math.atan2(dx, -dy);\n if (theta < 0) theta += TAU;\n if (frame.layout === 'polar') {\n if (r > frame.radius + 2 || r < frame.hole - 2 || !(frame.span > 0)) return -1;\n return Math.min(n - 1, Math.floor(theta / frame.span));\n }\n if (theta > frame.sweep + EPSILON && frame.sweep < TAU - EPSILON) return -1;\n // The whole track band (its gap included) answers, so thin arcs are easy to hover.\n const half = Math.max(frame.tracks.pitch, frame.tracks.width) / 2;\n for (let i = 0; i < n; i++) if (Math.abs(r - frame.tracks.radii[i]) <= half) return i;\n return -1;\n };\n\n const paintHover = (ictx: CanvasRenderingContext2D, index: number, state: HoverPaintState): void => {\n const mark = marks[index];\n const prev = state.from ? HOVER_SLOTS.get(state.from) : undefined;\n const glide = prev && prev.key !== mark.key && state.glide < 1 ? state.glide : 1;\n const from = glide < 1 ? prev : undefined;\n const cx = from ? lerp(from.cx, mark.cx, glide) : mark.cx;\n const cy = from ? lerp(from.cy, mark.cy, glide) : mark.cy;\n const slot = from ? lerpSector(from.slot, mark.track, glide) : mark.track;\n if (focusOn) {\n // Everything recedes but the hovered category's track (or wedge slot) and its arc.\n paintCutoutVeil(ictx, region, veil, FOCUS_VEIL * state.focus, (c) => traceSector(c, cx, cy, slot));\n return;\n }\n // Hand-drawn charts (and `tooltip.focus: false`) outline the hovered slot instead.\n ictx.save();\n ictx.globalAlpha = state.focus;\n ictx.beginPath();\n traceSector(ictx, cx, cy, slot);\n ictx.lineWidth = 1.5;\n ictx.strokeStyle = tokens.color.text;\n ictx.stroke();\n ictx.restore();\n };\n\n return {\n region: { ...region },\n hitTest: (px, py) => {\n if (!tooltips) return null;\n const i = indexAt(px, py);\n if (i < 0) return null;\n const item = model.items[i];\n const ratio = item.value / model.max;\n const rows: TooltipRow[] = [\n { swatch: item.color, label: measureLabel, value: formatValue(item.value, format) },\n { label: '% of max', value: formatValue(ratio, ratio >= 10 ? ',.0%' : '.1%'), muted: true },\n ];\n const hover: Hover = {\n key: item.key,\n anchorX: px,\n anchorY: py,\n content: { title: item.label, rows },\n paint: (ictx, state) => paintHover(ictx, i, state),\n draw: (ictx) => paintHover(ictx, i, { focus: 1, glide: 1 }),\n };\n HOVER_SLOTS.set(hover, { key: item.key, cx: marks[i].cx, cy: marks[i].cy, slot: marks[i].track });\n return hover;\n },\n pick: (px, py) => {\n const i = indexAt(px, py);\n if (i < 0) return null;\n return { kind: 'point', fields: [categoryField], tuples: [[model.items[i].category]] };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Entry point\n// ---------------------------------------------------------------------------\n\nexport function drawRadialBar(\n surface: Surface,\n spec: ChartSpec,\n tokens: ThemeTokens,\n size: Size,\n context?: RenderContext,\n): InteractionModel | void {\n surface.evidence?.begin('aggregate');\n surface.evidence?.data(0, 'aggregate');\n const rb = spec as RadialBarSpec;\n const content = insetRect(drawTitleBlock(surface, tokens, size, rb.title), rb.padding);\n const model = buildRadialBarModel(rb, radialBarPalette(rb, tokens));\n const sketch = resolveSketch(rb);\n const paint: PaintStyle = {\n tokens,\n pen: sketch ? new RoughPen(surface.marks.ctx, sketch) : null,\n track: rb.track === false ? null : trackColor(tokens),\n backdrop: knownBackdrop(surface, tokens),\n };\n const morph = morphInput<RadialBarMark[]>(context);\n\n if (model.items.length === 0 || content.width < 2 || content.height < 2) {\n // Arcs on screen shrink away; a later update grows its arcs back in.\n const leaving = morph ? morphKeyed(morph.from, [], morph.t, RADIAL_BAR_MORPH).exits : [];\n paintMarks(surface, leaving, paint);\n stashMorphFrame(surface, 'radialBar', leaving);\n drawNoData(surface, tokens, content, (rb.data?.length ?? 0) > 0 ? 'No usable values' : 'No data', 'aggregate');\n return;\n }\n\n const frame = planFrame(surface, rb, tokens, content, model);\n const finals = buildMarks(frame, model, rb, context);\n // Update morph: arcs travel from the ones on screen (tracks re-space, values\n // count, colors and highlights blend); new categories grow in, removed ones\n // shrink away beneath the rest.\n const moved = morph ? morphKeyed(morph.from, finals, morph.t, RADIAL_BAR_MORPH) : null;\n const shown = moved ? [...moved.exits, ...moved.items] : finals;\n paintMarks(surface, shown, paint);\n stashMorphFrame(surface, 'radialBar', shown);\n surface.evidence?.data(model.represented, 'aggregate');\n\n const labelBoxes = new Map<string, Rect>();\n // Labels arrive with the final entrance frame; mid-morph, a category keeps\n // its label while at least half shown.\n if (frame.labels && finiteOr(context?.sweepProgress, 1) >= 1) {\n const labelled = moved ? shown.filter((mark) => mark.alpha >= 0.5) : finals;\n const ctx: LabelContext = { surface, tokens, spec: rb, frame, style: frame.labels, paint, boxes: labelBoxes };\n if (frame.layout === 'radial') drawRadialLabels(ctx, labelled);\n else drawPolarLabels(ctx, labelled);\n }\n\n return buildInteraction(rb, tokens, frame, model, finals, labelBoxes);\n}"],
5
+ "mappings": "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",
6
+ "names": ["area", "labels", "track", "mid", "half", "arc"]
7
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"sankey.d.ts","sourceRoot":"","sources":["../../src/charts/sankey.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAKjD,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAS,IAAI,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAElD,OAAO,KAAK,EAAE,gBAAgB,EAAc,MAAM,sBAAsB,CAAC;AAIzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,KAAK,EAAE,CAAC;IACrB,WAAW,EAAE,KAAK,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,KAAK,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB;AAgMD,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,EAAE,IAAI,EACV,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACzD,KAAK,CAIP;AA6gBD,wBAAgB,UAAU,CACxB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE,aAAa,GACtB,gBAAgB,GAAG,IAAI,CAsBzB"}
1
+ {"version":3,"file":"sankey.d.ts","sourceRoot":"","sources":["../../src/charts/sankey.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAKjD,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAS,IAAI,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAElD,OAAO,KAAK,EAAmB,gBAAgB,EAAc,MAAM,sBAAsB,CAAC;AAI1F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAO7C,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,KAAK,EAAE,CAAC;IACrB,WAAW,EAAE,KAAK,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,KAAK,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB;AAgVD,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,EAAE,IAAI,EACV,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACzD,KAAK,CAIP;AAkpBD,wBAAgB,UAAU,CACxB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE,aAAa,GACtB,gBAAgB,GAAG,IAAI,CAgCzB"}
@@ -1,16 +1,94 @@
1
- import { ordinalColorScale, rgbaToCss, withAlpha } from "../color/index.js";
1
+ import { interpolateOklab, ordinalColorScale, parseColor, rgbaToCss } from "../color/index.js";
2
2
  import { formatValue } from "../format/index.js";
3
3
  import { fontString, measureText } from "../render/text.js";
4
4
  import { roundedRect } from "../shape/index.js";
5
5
  import { RoughPen } from "../rough/index.js";
6
6
  import { resolveSketch } from "../spec/sketch.js";
7
7
  import { accessor, toKey, toNumber } from "../util/data.js";
8
+ import { FOCUS_VEIL, hoverFocusEnabled, paintFocusVeil } from "../interaction/veil.js";
8
9
  import { boxesOverlap, fitLabel } from "../render/labelLedger.js";
9
10
  import { addOverlayText, drawTitleBlock } from "./chrome.js";
10
11
  import { rowAlpha } from "./emphasis.js";
12
+ import { alphaForContrast, knownBackdrop } from "./legibility.js";
11
13
  import { drawNoData } from "./noData.js";
12
14
  import { spreadCenters } from "./labelLayout.js";
15
+ import { lerp, lerpValue, mixColor, morphInput, morphKeyed, stashMorphFrame } from "./morphFrame.js";
13
16
  const center = (n) => (n.y0 + n.y1) / 2;
17
+ const LINK_ALPHA_LIGHT = 0.45;
18
+ const LINK_ALPHA_DARK = 0.58;
19
+ const LINK_CONTRAST_MIN = 1.6;
20
+ const LINK_HOVER_ALPHA = 0.75;
21
+ const LINK_GRADIENT_STOPS = [0, 0.25, 0.5, 0.75, 1];
22
+ const nodeRadius = (width, height) => Math.max(0, Math.min(2, width / 2, height / 2));
23
+ function heldNode(node, k, alpha) {
24
+ const mid = (node.y0 + node.y1) / 2;
25
+ return { ...node, y0: lerp(mid, node.y0, k), y1: lerp(mid, node.y1, k), alpha };
26
+ }
27
+ const NODE_MORPH = {
28
+ lerp: (a, b, t) => ({
29
+ key: b.key,
30
+ layer: b.layer,
31
+ x0: lerp(a.x0, b.x0, t),
32
+ y0: lerp(a.y0, b.y0, t),
33
+ y1: lerp(a.y1, b.y1, t),
34
+ width: lerp(a.width, b.width, t),
35
+ color: mixColor(a.color, b.color, t),
36
+ value: lerpValue(a.value, b.value, t),
37
+ emph: lerp(a.emph, b.emph, t),
38
+ alpha: lerp(a.alpha, b.alpha, t)
39
+ }),
40
+ enter: (b, t) => heldNode(b, t, t),
41
+ exit: (a, t) => heldNode(a, 1 - t, a.alpha * (1 - t))
42
+ };
43
+ const lerpLink = (a, b, t) => ({
44
+ key: b.key,
45
+ source: { key: b.source.key, x1: lerp(a.source.x1, b.source.x1, t), color: mixColor(a.source.color, b.source.color, t) },
46
+ target: { key: b.target.key, x0: lerp(a.target.x0, b.target.x0, t), color: mixColor(a.target.color, b.target.color, t) },
47
+ sy: lerp(a.sy, b.sy, t),
48
+ ty: lerp(a.ty, b.ty, t),
49
+ width: lerp(a.width, b.width, t),
50
+ sourceAlpha: lerp(a.sourceAlpha, b.sourceAlpha, t),
51
+ targetAlpha: lerp(a.targetAlpha, b.targetAlpha, t),
52
+ emph: lerp(a.emph, b.emph, t),
53
+ alpha: lerp(a.alpha, b.alpha, t)
54
+ });
55
+ const byNodeKey = (nodes) => new Map(nodes.map((node) => [node.key, node]));
56
+ function seatLink(link, laid, now) {
57
+ const along = (y, was, is) => {
58
+ if (!was || !is) return y;
59
+ const span = was.y1 - was.y0;
60
+ return is.y0 + (span > 0 ? (y - was.y0) / span : 0.5) * (is.y1 - is.y0);
61
+ };
62
+ const source = now.get(link.source.key);
63
+ const target = now.get(link.target.key);
64
+ return {
65
+ ...link,
66
+ source: { ...link.source, x1: source ? source.x0 + source.width : link.source.x1 },
67
+ target: { ...link.target, x0: target ? target.x0 : link.target.x0 },
68
+ sy: along(link.sy, laid.get(link.source.key), source),
69
+ ty: along(link.ty, laid.get(link.target.key), target)
70
+ };
71
+ }
72
+ function linkPlan(before, after, now) {
73
+ return {
74
+ lerp: lerpLink,
75
+ enter: (b, t) => seatLink({ ...b, width: b.width * t, alpha: t }, after, now),
76
+ exit: (a, t) => seatLink({ ...a, width: a.width * (1 - t), alpha: a.alpha * (1 - t) }, before, now)
77
+ };
78
+ }
79
+ function sankeyMorph(context, finals) {
80
+ const morph = morphInput(context);
81
+ if (!morph) return { shown: finals, moved: null };
82
+ const nodes = morphKeyed(morph.from.nodes, finals.nodes, morph.t, NODE_MORPH);
83
+ const shownNodes = [...nodes.exits, ...nodes.items];
84
+ const plan = linkPlan(byNodeKey(morph.from.nodes), byNodeKey(finals.nodes), byNodeKey(shownNodes));
85
+ const links = morphKeyed(morph.from.links, finals.links, morph.t, plan);
86
+ return {
87
+ // Widest underneath by the widths on screen, so the stacking hands over as flows resize.
88
+ shown: { links: [...links.exits, ...links.items].sort((a, b) => b.width - a.width), nodes: shownNodes },
89
+ moved: nodes
90
+ };
91
+ }
14
92
  function clamp(value, min, max) {
15
93
  return Math.min(max, Math.max(min, value));
16
94
  }
@@ -251,18 +329,35 @@ function computeLinkBreadths(graph) {
251
329
  }
252
330
  }
253
331
  }
254
- function strokeLink(ctx, l, color) {
332
+ function linkPaint(ctx, link, sourceAlpha, targetAlpha) {
333
+ const a = parseColor(link.source.color);
334
+ const b = parseColor(link.target.color);
335
+ if (!a) return link.source.color;
336
+ const from = rgbaToCss({ ...a, a: a.a * sourceAlpha });
337
+ const x0 = link.source.x1;
338
+ const x1 = link.target.x0;
339
+ if (!b || !Number.isFinite(x0) || !Number.isFinite(x1) || Math.abs(x1 - x0) < 1e-6) return from;
340
+ const gradient = ctx.createLinearGradient?.(x0, 0, x1, 0);
341
+ if (!gradient || typeof gradient.addColorStop !== "function") return from;
342
+ const mix = interpolateOklab(a, b);
343
+ for (const t of LINK_GRADIENT_STOPS) {
344
+ const c = mix(t);
345
+ gradient.addColorStop(t, rgbaToCss({ ...c, a: c.a * (sourceAlpha + (targetAlpha - sourceAlpha) * t) }));
346
+ }
347
+ return gradient;
348
+ }
349
+ function strokeLink(ctx, l, alpha) {
255
350
  const x0 = l.source.x1;
256
351
  const x1 = l.target.x0;
257
352
  const xm = (x0 + x1) / 2;
258
353
  ctx.lineWidth = l.width;
259
- ctx.strokeStyle = color;
354
+ ctx.strokeStyle = linkPaint(ctx, l, alpha, alpha);
260
355
  ctx.beginPath();
261
356
  ctx.moveTo(x0, l.sy);
262
357
  ctx.bezierCurveTo(xm, l.sy, xm, l.ty, x1, l.ty);
263
358
  ctx.stroke();
264
359
  }
265
- function paintLink(ctx, link, boundary, alpha = 1) {
360
+ function paintLink(ctx, link, sourceAlpha, targetAlpha, alpha = 1) {
266
361
  const x0 = link.source.x1;
267
362
  const x1 = link.target.x0;
268
363
  const middle = (x0 + x1) / 2;
@@ -274,13 +369,9 @@ function paintLink(ctx, link, boundary, alpha = 1) {
274
369
  ctx.lineTo(x1, link.ty + half);
275
370
  ctx.bezierCurveTo(middle, link.ty + half, middle, link.sy + half, x0, link.sy + half);
276
371
  ctx.closePath();
277
- ctx.fillStyle = link.source.color;
278
- ctx.globalAlpha = 0.4 * alpha;
372
+ ctx.fillStyle = linkPaint(ctx, link, sourceAlpha, targetAlpha);
373
+ ctx.globalAlpha = alpha;
279
374
  ctx.fill();
280
- ctx.strokeStyle = boundary.color;
281
- ctx.globalAlpha = boundary.opacity * alpha;
282
- ctx.lineWidth = boundary.width;
283
- ctx.stroke();
284
375
  ctx.restore();
285
376
  }
286
377
  function prepareSankeyFrame(surface, sankey, tokens, size, graph) {
@@ -324,51 +415,111 @@ function sankeyProbes(sankey) {
324
415
  link: (l) => ({ [sourceField]: l.sourceValue, [targetField]: l.targetValue })
325
416
  };
326
417
  }
327
- function drawSankeyMarks(surface, spec, tokens, graph, frame, alpha) {
418
+ function sankeyMarks(surface, tokens, graph, sorted, frame, alpha) {
419
+ const backdrop = knownBackdrop(surface, tokens);
420
+ const baseAlpha = tokens.dark ? LINK_ALPHA_DARK : LINK_ALPHA_LIGHT;
421
+ const linkAlphas = /* @__PURE__ */ new Map();
422
+ const linkAlpha = (color) => {
423
+ let a = linkAlphas.get(color);
424
+ if (a === void 0) {
425
+ a = alphaForContrast(color, baseAlpha, backdrop, LINK_CONTRAST_MIN);
426
+ linkAlphas.set(color, a);
427
+ }
428
+ return a;
429
+ };
430
+ return {
431
+ links: sorted.map((l) => ({
432
+ key: `${l.source.name}\0${l.target.name}`,
433
+ source: { key: l.source.name, x1: l.source.x1, color: l.source.color },
434
+ target: { key: l.target.name, x0: l.target.x0, color: l.target.color },
435
+ sy: l.sy,
436
+ ty: l.ty,
437
+ width: l.width,
438
+ sourceAlpha: linkAlpha(l.source.color),
439
+ targetAlpha: linkAlpha(l.target.color),
440
+ emph: alpha.link(l),
441
+ alpha: 1
442
+ })),
443
+ nodes: graph.nodes.map((n) => ({
444
+ key: n.name,
445
+ layer: n.layer,
446
+ x0: n.x0,
447
+ y0: n.y0,
448
+ y1: n.y1,
449
+ width: frame.nodeWidth,
450
+ color: n.color,
451
+ value: n.value,
452
+ emph: alpha.node(n),
453
+ alpha: 1
454
+ }))
455
+ };
456
+ }
457
+ function paintSankeyMarks(surface, spec, marks) {
328
458
  const ctx = surface.marks.ctx;
329
459
  ctx.save();
330
460
  ctx.lineCap = "butt";
331
- const sorted = [...graph.links].sort((a, b) => b.width - a.width);
332
- const boundary = { color: tokens.color.textMuted, opacity: 0.7, width: 1 };
333
- for (const l of sorted) {
334
- const a = alpha.link(l);
335
- paintLink(ctx, l, boundary, a);
461
+ for (const l of marks.links) {
462
+ const a = l.emph * l.alpha;
463
+ paintLink(ctx, l, l.sourceAlpha, l.targetAlpha, a);
336
464
  surface.evidence?.mark(
337
465
  "link",
338
- Math.min(l.source.x1, l.target.x0) - 0.5,
339
- Math.min(l.sy, l.ty) - l.width / 2 - 0.5,
340
- Math.abs(l.target.x0 - l.source.x1) + 1,
341
- Math.abs(l.ty - l.sy) + l.width + 1,
466
+ Math.min(l.source.x1, l.target.x0),
467
+ Math.min(l.sy, l.ty) - l.width / 2,
468
+ Math.abs(l.target.x0 - l.source.x1),
469
+ Math.abs(l.ty - l.sy) + l.width,
342
470
  l.source.color,
343
- 0.4 * a,
471
+ l.sourceAlpha * a,
344
472
  void 0,
345
473
  1,
346
474
  void 0,
347
- a < 1,
348
- boundary
475
+ a < 1
349
476
  );
350
477
  }
351
- const radius = Math.min(3, tokens.radius.sm);
352
478
  const sketch = resolveSketch(spec);
353
479
  const pen = sketch ? new RoughPen(ctx, sketch) : null;
354
- for (const n of graph.nodes) {
355
- const a = alpha.node(n);
480
+ for (const n of marks.nodes) {
481
+ const a = n.emph * n.alpha;
356
482
  const prev = ctx.globalAlpha;
357
483
  if (a !== 1) ctx.globalAlpha = a;
358
484
  const h = Math.max(1, n.y1 - n.y0);
359
485
  if (pen) {
360
- pen.rect(n.x0, n.y0, frame.nodeWidth, h, { fill: n.color, fillStyle: "solid" });
486
+ pen.rect(n.x0, n.y0, n.width, h, { fill: n.color, fillStyle: "solid" });
361
487
  } else {
362
488
  ctx.fillStyle = n.color;
363
489
  ctx.beginPath();
364
- roundedRect(ctx, n.x0, n.y0, frame.nodeWidth, h, Math.min(radius, h / 2));
490
+ roundedRect(ctx, n.x0, n.y0, n.width, h, nodeRadius(n.width, h));
365
491
  ctx.fill();
366
492
  }
367
- surface.evidence?.mark("node", n.x0, n.y0, frame.nodeWidth, h, n.color, a, void 0, 1, void 0, a < 1);
493
+ surface.evidence?.mark("node", n.x0, n.y0, n.width, h, n.color, a, void 0, 1, void 0, a < 1);
368
494
  if (a !== 1) ctx.globalAlpha = prev;
369
495
  }
370
496
  ctx.restore();
371
- return sorted;
497
+ }
498
+ function framedGraph(graph, moved) {
499
+ const shown = /* @__PURE__ */ new Map();
500
+ graph.nodes.forEach((n, i) => {
501
+ const m = moved.items[i];
502
+ shown.set(n, { ...n, x0: m.x0, x1: m.x0 + m.width, y0: m.y0, y1: m.y1, value: m.value });
503
+ });
504
+ const leaving = moved.exits.filter((m) => m.alpha >= 0.5).map((m, i) => ({
505
+ name: m.key,
506
+ index: graph.nodes.length + i,
507
+ layer: Math.min(m.layer, graph.maxLayer),
508
+ value: m.value,
509
+ x0: m.x0,
510
+ x1: m.x0 + m.width,
511
+ y0: m.y0,
512
+ y1: m.y1,
513
+ color: m.color,
514
+ sourceLinks: [],
515
+ targetLinks: []
516
+ }));
517
+ return {
518
+ ...graph,
519
+ nodes: [...graph.nodes.filter((_n, i) => moved.items[i].alpha >= 0.5).map((n) => shown.get(n)), ...leaving],
520
+ // Arriving nodes still bound their neighbours' labels.
521
+ columns: graph.columns.map((col) => col.map((n) => shown.get(n)))
522
+ };
372
523
  }
373
524
  function buildSankeyLabelRows(graph, frame) {
374
525
  const labelGap = 6;
@@ -556,19 +707,20 @@ function sankeyHitIndex(graph, content, sorted) {
556
707
  };
557
708
  return { nodeAt, linkAt };
558
709
  }
559
- function buildSankeyInteraction(sankey, graph, frame, sorted) {
710
+ function buildSankeyInteraction(sankey, graph, frame, sorted, tokens) {
560
711
  const tt = sankey.tooltip;
561
712
  if (tt === false || tt && typeof tt === "object" && tt.show === false) return;
562
713
  const sourceField = sankey.encoding.source.field;
563
714
  const targetField = sankey.encoding.target.field;
564
715
  const valueLabel = sankey.encoding.value.title ?? sankey.encoding.value.field;
565
716
  const { nodeAt, linkAt } = sankeyHitIndex(graph, frame.content, sorted);
717
+ const focus = hoverFocusEnabled(sankey) ? { area: frame.content, veil: sankey.background ?? tokens.color.background } : null;
566
718
  return {
567
719
  region: frame.content,
568
720
  hitTest: (px, py) => {
569
721
  const n = nodeAt(px, py);
570
- if (!n) return sankeyLinkTooltip(px, py, linkAt(px, py), valueLabel, sankey);
571
- return sankeyNodeTooltip(n, valueLabel, sankey);
722
+ if (!n) return sankeyLinkTooltip(px, py, linkAt(px, py), valueLabel, sankey, focus);
723
+ return sankeyNodeTooltip(n, valueLabel, sankey, focus);
572
724
  },
573
725
  pick: (px, py) => {
574
726
  const n = nodeAt(px, py);
@@ -582,8 +734,28 @@ function buildSankeyInteraction(sankey, graph, frame, sorted) {
582
734
  }
583
735
  };
584
736
  }
585
- function sankeyLinkTooltip(px, py, link, valueLabel, sankey) {
737
+ function paintSankeyNode(ictx, n) {
738
+ const h = Math.max(1, n.y1 - n.y0);
739
+ ictx.fillStyle = n.color;
740
+ ictx.beginPath();
741
+ roundedRect(ictx, n.x0, n.y0, n.x1 - n.x0, h, nodeRadius(n.x1 - n.x0, h));
742
+ ictx.fill();
743
+ }
744
+ function paintSankeyFlows(ictx, links, nodes, focus, strength) {
745
+ ictx.save();
746
+ if (focus) {
747
+ paintFocusVeil(ictx, focus.area, focus.veil, FOCUS_VEIL * strength);
748
+ for (const l of links) paintLink(ictx, l, LINK_HOVER_ALPHA, LINK_HOVER_ALPHA);
749
+ } else {
750
+ ictx.lineCap = "butt";
751
+ for (const l of links) strokeLink(ictx, l, LINK_HOVER_ALPHA);
752
+ }
753
+ for (const n of nodes) paintSankeyNode(ictx, n);
754
+ ictx.restore();
755
+ }
756
+ function sankeyLinkTooltip(px, py, link, valueLabel, sankey, focus) {
586
757
  if (!link) return null;
758
+ const nodes = focus ? [link.source, link.target] : [];
587
759
  return {
588
760
  key: `${link.source.name}\0${link.target.name}`,
589
761
  anchorX: px,
@@ -592,15 +764,11 @@ function sankeyLinkTooltip(px, py, link, valueLabel, sankey) {
592
764
  title: `${link.source.name} \u2192 ${link.target.name}`,
593
765
  rows: [{ swatch: link.source.color, label: valueLabel, value: formatValue(link.value, sankey.encoding.value.format) }]
594
766
  },
595
- draw: (ictx) => {
596
- ictx.save();
597
- ictx.lineCap = "butt";
598
- strokeLink(ictx, link, withAlpha(link.source.color, 0.72));
599
- ictx.restore();
600
- }
767
+ paint: (ictx, state) => paintSankeyFlows(ictx, [link], nodes, focus, state.focus),
768
+ draw: (ictx) => paintSankeyFlows(ictx, [link], nodes, focus, 1)
601
769
  };
602
770
  }
603
- function sankeyNodeTooltip(n, valueLabel, sankey) {
771
+ function sankeyNodeTooltip(n, valueLabel, sankey, focus) {
604
772
  const out = n.sourceLinks.reduce((s, l) => s + l.value, 0);
605
773
  const inc = n.targetLinks.reduce((s, l) => s + l.value, 0);
606
774
  const rows = [
@@ -608,24 +776,15 @@ function sankeyNodeTooltip(n, valueLabel, sankey) {
608
776
  ];
609
777
  if (inc > 0) rows.push({ label: "In", value: formatValue(inc, sankey.encoding.value.format), muted: true });
610
778
  if (out > 0) rows.push({ label: "Out", value: formatValue(out, sankey.encoding.value.format), muted: true });
779
+ const links = [...n.sourceLinks, ...n.targetLinks];
780
+ const nodes = focus ? [.../* @__PURE__ */ new Set([n, ...n.sourceLinks.map((l) => l.target), ...n.targetLinks.map((l) => l.source)])] : [n];
611
781
  return {
612
782
  key: n.name,
613
783
  anchorX: (n.x0 + n.x1) / 2,
614
784
  anchorY: center(n),
615
785
  content: { title: n.name, rows },
616
- draw: (ictx) => {
617
- ictx.save();
618
- ictx.lineCap = "butt";
619
- for (const l of [...n.sourceLinks, ...n.targetLinks]) {
620
- strokeLink(ictx, l, withAlpha(l.source.color, 0.72));
621
- }
622
- const h = Math.max(1, n.y1 - n.y0);
623
- ictx.fillStyle = n.color;
624
- ictx.beginPath();
625
- roundedRect(ictx, n.x0, n.y0, n.x1 - n.x0, h, Math.min(3, h / 2));
626
- ictx.fill();
627
- ictx.restore();
628
- }
786
+ paint: (ictx, state) => paintSankeyFlows(ictx, links, nodes, focus, state.focus),
787
+ draw: (ictx) => paintSankeyFlows(ictx, links, nodes, focus, 1)
629
788
  };
630
789
  }
631
790
  function drawSankey(surface, spec, tokens, size, context) {
@@ -638,6 +797,9 @@ function drawSankey(surface, spec, tokens, size, context) {
638
797
  const { content } = frame;
639
798
  if (graph.nodes.length === 0 || content.width <= 0 || content.height <= 0) {
640
799
  drawNoData(surface, tokens, content);
800
+ const { shown: shown2 } = sankeyMorph(context, { links: [], nodes: [] });
801
+ if (shown2.links.length + shown2.nodes.length > 0) paintSankeyMarks(surface, spec, shown2);
802
+ stashMorphFrame(surface, "sankey", shown2);
641
803
  return;
642
804
  }
643
805
  layout(graph, frame.area, frame.nodeWidth, frame.pad);
@@ -645,9 +807,13 @@ function drawSankey(surface, spec, tokens, size, context) {
645
807
  const probes = sankeyProbes(sankey);
646
808
  const nodeAlpha = (n) => rowAlpha(emphasis, probes.node(n));
647
809
  const linkAlpha = (l) => rowAlpha(emphasis, probes.link(l));
648
- const sorted = drawSankeyMarks(surface, spec, tokens, graph, frame, { node: nodeAlpha, link: linkAlpha });
649
- drawSankeyLabels(surface, tokens, sankey, graph, frame);
650
- return buildSankeyInteraction(sankey, graph, frame, sorted);
810
+ const sorted = [...graph.links].sort((a, b) => b.width - a.width);
811
+ const finals = sankeyMarks(surface, tokens, graph, sorted, frame, { node: nodeAlpha, link: linkAlpha });
812
+ const { shown, moved } = sankeyMorph(context, finals);
813
+ paintSankeyMarks(surface, spec, shown);
814
+ stashMorphFrame(surface, "sankey", shown);
815
+ drawSankeyLabels(surface, tokens, sankey, moved ? framedGraph(graph, moved) : graph, frame);
816
+ return buildSankeyInteraction(sankey, graph, frame, sorted, tokens);
651
817
  }
652
818
  export {
653
819
  buildSankeyLayout,