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
@@ -1,10 +1,41 @@
1
1
  import { fontString } from "../render/text.js";
2
2
  import { overlayTextToCanvasCmd, paintCanvasText } from "../render/overlayText.js";
3
+ import { CHROME_VISIBLE, chromeEntrance, chromeMorph, revealAt, stashChrome, visibleItems } from "../render/chromeMotion.js";
4
+ import { morphedModel } from "../axes/morph.js";
3
5
  import { autoInsightAnnotations } from "../analyze/autoInsights.js";
4
6
  import { crisp } from "../util/math.js";
5
7
  const DEFAULT_DASH = [5, 4];
6
8
  const DEFAULT_FILL_OPACITY = 0.12;
7
9
  const DEFAULT_MARKER_RADIUS = 3.5;
10
+ const ANNOTATIONS = "annotations";
11
+ const ANNOTATION_LABELS = `${ANNOTATIONS}:labels`;
12
+ function drawnAnnotations(surface, list, name, revealOf) {
13
+ const current = list.map((ann) => ({ key: JSON.stringify(ann), ann, alpha: 1 }));
14
+ const morph = chromeMorph(surface, name);
15
+ if (!morph) {
16
+ const entering = chromeEntrance(surface) != null;
17
+ stashChrome(surface, name, entering ? current.map((d) => ({ ...d, alpha: revealOf(d.ann) })) : current);
18
+ return current;
19
+ }
20
+ const { from, t } = morph;
21
+ const before = new Map(from.map((d) => [d.key, d]));
22
+ const now = new Set(current.map((d) => d.key));
23
+ const drawn = visibleItems([
24
+ ...from.filter((d) => !now.has(d.key)).map((d) => ({ ...d, alpha: d.alpha * (1 - t) })),
25
+ ...current.map((d) => ({ ...d, alpha: before.has(d.key) ? before.get(d.key).alpha + (1 - before.get(d.key).alpha) * t : t }))
26
+ ]);
27
+ stashChrome(surface, name, drawn);
28
+ return drawn;
29
+ }
30
+ function annotationReveal(surface, kind) {
31
+ const t = chromeEntrance(surface);
32
+ if (t == null) return 1;
33
+ return kind === "point" ? revealAt(t, 0.6, 1) : revealAt(t, 0.35, 0.9);
34
+ }
35
+ function labelReveal(surface) {
36
+ const t = chromeEntrance(surface);
37
+ return t == null ? 1 : revealAt(t, 0.75, 1);
38
+ }
8
39
  function kindOf(ann) {
9
40
  if (ann.type === "point") return "point";
10
41
  if (ann.type === "line") return "line";
@@ -41,29 +72,34 @@ function annotationsOf(model) {
41
72
  return auto.length ? [...explicit, ...auto] : explicit;
42
73
  }
43
74
  function drawAnnotations(surface, model) {
44
- const list = annotationsOf(model);
45
- if (list.length === 0) return;
75
+ const drawn = drawnAnnotations(surface, annotationsOf(model), ANNOTATIONS, (ann) => annotationReveal(surface, kindOf(ann)));
76
+ if (drawn.length === 0) return;
77
+ const frame = morphedModel(surface, model);
46
78
  const ctx = surface.marks.ctx;
47
- const { plot, tokens } = model;
79
+ const { plot, tokens } = frame;
48
80
  const x1 = plot.x + plot.width;
49
81
  const y1 = plot.y + plot.height;
50
82
  ctx.save();
51
83
  ctx.beginPath();
52
84
  ctx.rect(plot.x, plot.y, plot.width, plot.height);
53
85
  ctx.clip();
54
- for (const ann of list) {
55
- if (kindOf(ann) === "point") {
56
- const pt = pointPixels(model, ann);
86
+ for (const { ann, alpha } of drawn) {
87
+ const kind = kindOf(ann);
88
+ const reveal = annotationReveal(surface, kind);
89
+ const k = alpha * reveal;
90
+ if (!(k > CHROME_VISIBLE)) continue;
91
+ if (kind === "point") {
92
+ const pt = pointPixels(frame, ann);
57
93
  if (!pt) continue;
58
- const r = ann.markerRadius ?? DEFAULT_MARKER_RADIUS;
94
+ const r = (ann.markerRadius ?? DEFAULT_MARKER_RADIUS) * (reveal < 1 ? reveal : 1);
59
95
  const dot = ann.color ?? tokens.color.text;
60
96
  ctx.save();
61
97
  ctx.fillStyle = tokens.color.background;
62
- ctx.globalAlpha = 0.9;
98
+ ctx.globalAlpha = 0.9 * k;
63
99
  ctx.beginPath();
64
100
  ctx.arc(pt.px, pt.py, r + 1.6, 0, Math.PI * 2);
65
101
  ctx.fill();
66
- ctx.globalAlpha = 1;
102
+ ctx.globalAlpha = k;
67
103
  ctx.fillStyle = dot;
68
104
  ctx.beginPath();
69
105
  ctx.arc(pt.px, pt.py, r, 0, Math.PI * 2);
@@ -73,11 +109,12 @@ function drawAnnotations(surface, model) {
73
109
  }
74
110
  const axis = ann.axis === "x" ? "x" : "y";
75
111
  const color = ann.color ?? tokens.color.textMuted;
76
- const ruleHorizontal = drawsHorizontalRule(model, axis);
77
- if (kindOf(ann) === "line") {
78
- const p = toPixel(model, axis, ann.value);
112
+ const ruleHorizontal = drawsHorizontalRule(frame, axis);
113
+ if (kind === "line") {
114
+ const p = toPixel(frame, axis, ann.value);
79
115
  if (p === void 0) continue;
80
116
  ctx.save();
117
+ if (k !== 1) ctx.globalAlpha = k;
81
118
  ctx.strokeStyle = color;
82
119
  ctx.lineWidth = ann.strokeWidth ?? 1.5;
83
120
  ctx.setLineDash(ann.strokeDash ?? DEFAULT_DASH);
@@ -85,7 +122,11 @@ function drawAnnotations(surface, model) {
85
122
  if (ruleHorizontal) {
86
123
  const y = crisp(p);
87
124
  ctx.moveTo(plot.x, y);
88
- ctx.lineTo(x1, y);
125
+ ctx.lineTo(reveal < 1 ? plot.x + plot.width * reveal : x1, y);
126
+ } else if (reveal < 1) {
127
+ const x = crisp(p);
128
+ ctx.moveTo(x, y1);
129
+ ctx.lineTo(x, y1 - plot.height * reveal);
89
130
  } else {
90
131
  const x = crisp(p);
91
132
  ctx.moveTo(x, plot.y);
@@ -95,20 +136,25 @@ function drawAnnotations(surface, model) {
95
136
  ctx.restore();
96
137
  continue;
97
138
  }
98
- const a = toPixel(model, axis, ann.from);
99
- const b = toPixel(model, axis, ann.to);
139
+ const a = toPixel(frame, axis, ann.from);
140
+ const b = toPixel(frame, axis, ann.to);
100
141
  if (a === void 0 || b === void 0) continue;
101
- const lo = Math.min(a, b);
102
- const hi = Math.max(a, b);
142
+ let lo = Math.min(a, b);
143
+ let hi = Math.max(a, b);
144
+ if (reveal < 1) {
145
+ const mid = (lo + hi) / 2;
146
+ lo = mid + (lo - mid) * reveal;
147
+ hi = mid + (hi - mid) * reveal;
148
+ }
103
149
  ctx.save();
104
- ctx.globalAlpha = ann.fillOpacity ?? DEFAULT_FILL_OPACITY;
150
+ ctx.globalAlpha = (ann.fillOpacity ?? DEFAULT_FILL_OPACITY) * k;
105
151
  ctx.fillStyle = color;
106
152
  if (ruleHorizontal) ctx.fillRect(plot.x, lo, plot.width, hi - lo);
107
153
  else ctx.fillRect(lo, plot.y, hi - lo, plot.height);
108
154
  ctx.restore();
109
155
  ctx.save();
110
156
  ctx.strokeStyle = color;
111
- ctx.globalAlpha = 0.55;
157
+ ctx.globalAlpha = 0.55 * k;
112
158
  ctx.lineWidth = 1;
113
159
  ctx.setLineDash(ann.strokeDash ?? [4, 4]);
114
160
  ctx.beginPath();
@@ -148,29 +194,34 @@ function labelBox(model, horizontalRule, pos, p) {
148
194
  return { left, top: plot.y + 2, align: "center", transform };
149
195
  }
150
196
  function drawAnnotationLabels(surface, model) {
151
- const list = annotationsOf(model);
152
- if (list.length === 0) return;
197
+ const drawn = drawnAnnotations(surface, annotationsOf(model), ANNOTATION_LABELS, () => labelReveal(surface));
198
+ if (drawn.length === 0) return [];
199
+ const frame = morphedModel(surface, model);
153
200
  const overlay = surface.overlay;
154
- const { tokens } = model;
201
+ const { tokens } = frame;
155
202
  const f = tokens.font;
156
203
  const font = fontString(f.size.small, f.family, f.weight.medium);
157
- for (const ann of list) {
204
+ const reveal = labelReveal(surface);
205
+ const elements = [];
206
+ for (const { ann, alpha } of drawn) {
158
207
  if (!ann.label) continue;
208
+ const opacity = alpha * reveal;
209
+ if (!surface.headless && !(opacity > CHROME_VISIBLE)) continue;
159
210
  let box;
160
211
  if (kindOf(ann) === "point") {
161
- const pt = pointPixels(model, ann);
212
+ const pt = pointPixels(frame, ann);
162
213
  if (!pt) continue;
163
214
  const r = ann.markerRadius ?? DEFAULT_MARKER_RADIUS;
164
215
  const gap = r + 4;
165
216
  const textH = f.size.small;
166
217
  const aboveTop = pt.py - gap - textH;
167
- const top = aboveTop < model.plot.y ? pt.py + gap : aboveTop;
218
+ const top = aboveTop < frame.plot.y ? pt.py + gap : aboveTop;
168
219
  box = { left: pt.px, top, align: "center", transform: "translateX(-50%)" };
169
220
  } else {
170
221
  const axis = ann.axis === "x" ? "x" : "y";
171
- const p = anchorPixel(model, ann, axis, kindOf(ann));
222
+ const p = anchorPixel(frame, ann, axis, kindOf(ann));
172
223
  if (p === void 0) continue;
173
- box = labelBox(model, drawsHorizontalRule(model, axis), ann.labelPosition ?? "end", p);
224
+ box = labelBox(frame, drawsHorizontalRule(frame, axis), ann.labelPosition ?? "end", p);
174
225
  }
175
226
  const color = ann.color ?? tokens.color.text;
176
227
  const pill = { background: withAlpha(tokens.color.background, 0.72), radius: 3, padX: 3, padY: 1 };
@@ -213,8 +264,11 @@ function drawAnnotationLabels(surface, model) {
213
264
  el.style.borderRadius = "3px";
214
265
  el.style.background = pill.background;
215
266
  el.style.pointerEvents = "none";
267
+ if (opacity < 1) el.style.opacity = String(Math.max(0, opacity));
216
268
  overlay.appendChild(el);
269
+ elements.push(el);
217
270
  }
271
+ return elements;
218
272
  }
219
273
  function withAlpha(color, alpha) {
220
274
  const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(color);
@@ -227,6 +281,7 @@ function withAlpha(color, alpha) {
227
281
  return `rgba(${r}, ${g}, ${b}, ${alpha})`;
228
282
  }
229
283
  export {
284
+ ANNOTATION_LABELS,
230
285
  drawAnnotationLabels,
231
286
  drawAnnotations
232
287
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/charts/annotations.ts"],
4
- "sourcesContent": ["/**\n * Reference annotations for cartesian charts \u2014 lines, bands, and threshold zones.\n *\n * A cross-cutting overlay primitive available to every cartesian chart via\n * `spec.annotations`. Marks (the rule strokes and band fills) are painted on the\n * marks canvas; labels live in the HTML overlay for crisp, selectable text,\n * mirroring how axes render. Geometry comes from the already-resolved\n * `CartesianModel` scales, so this module is pure presentation.\n */\n\nimport type { Surface } from '../render/surface';\nimport type { Annotation, ChartSpec } from '../spec/types';\nimport type { CartesianModel } from '../runtime/cartesian';\nimport { fontString } from '../render/text';\nimport { overlayTextToCanvasCmd, paintCanvasText } from '../render/overlayText';\nimport { autoInsightAnnotations } from '../analyze/autoInsights';\nimport { crisp } from '../util/math';\n\ntype Axis = 'x' | 'y';\ntype Kind = 'line' | 'band' | 'point';\n\nconst DEFAULT_DASH = [5, 4];\nconst DEFAULT_FILL_OPACITY = 0.12;\nconst DEFAULT_MARKER_RADIUS = 3.5;\n\n/** Resolve whether an annotation is a single line, a filled span, or a point. */\nfunction kindOf(ann: Annotation): Kind {\n if (ann.type === 'point') return 'point';\n if (ann.type === 'line') return 'line';\n if (ann.type === 'band' || ann.type === 'zone') return 'band';\n return ann.value !== undefined ? 'line' : 'band';\n}\n\n/** Project an annotation value to its pixel on the given axis (or undefined). */\nfunction toPixel(model: CartesianModel, axis: Axis, value: unknown): number | undefined {\n if (value === undefined || value === null) return undefined;\n const px = axis === 'x' ? model.x.pixel(value) : model.y.pixel(value);\n return px != null && Number.isFinite(px) ? px : undefined;\n}\n\n/** Resolve a `point` annotation's (x, y) data coords to plot pixels. */\nfunction pointPixels(model: CartesianModel, ann: Annotation): { px: number; py: number } | undefined {\n const cat = toPixel(model, 'x', ann.x);\n const val = toPixel(model, 'y', ann.y);\n if (cat === undefined || val === undefined) return undefined;\n const { x, y } = model.project(cat, val);\n return { px: x, py: y };\n}\n\n/**\n * Whether an annotation on the given data axis draws as a horizontal rule on\n * screen. In vertical charts the value (`y`) axis is horizontal; in horizontal\n * bar charts the axes swap, so the category (`x`) axis becomes the horizontal one.\n */\nfunction drawsHorizontalRule(model: CartesianModel, axis: Axis): boolean {\n return model.orientation === 'horizontal' ? axis === 'x' : axis === 'y';\n}\n\n/** Anchor pixel for an annotation's label (line value, or band midpoint). */\nfunction anchorPixel(model: CartesianModel, ann: Annotation, axis: Axis, kind: Kind): number | undefined {\n if (kind === 'line') return toPixel(model, axis, ann.value);\n const a = toPixel(model, axis, ann.from);\n const b = toPixel(model, axis, ann.to);\n if (a === undefined || b === undefined) return undefined;\n return (a + b) / 2;\n}\n\n/** Explicit `spec.annotations` plus any auto-insight callouts (`spec.insights`). */\nfunction annotationsOf(model: CartesianModel): Annotation[] {\n const spec = model.spec as { annotations?: Annotation[]; insights?: unknown };\n const explicit = Array.isArray(spec.annotations) ? spec.annotations : [];\n if (!spec.insights) return explicit;\n const auto = autoInsightAnnotations(model.spec as ChartSpec);\n return auto.length ? [...explicit, ...auto] : explicit;\n}\n\n/**\n * Paint reference lines and band/zone fills on the marks canvas, clipped to the\n * plot. Call after the chart's data marks so reference lines sit on top.\n */\nexport function drawAnnotations(surface: Surface, model: CartesianModel): void {\n const list = annotationsOf(model);\n if (list.length === 0) return;\n\n const ctx = surface.marks.ctx;\n const { plot, tokens } = model;\n const x1 = plot.x + plot.width;\n const y1 = plot.y + plot.height;\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(plot.x, plot.y, plot.width, plot.height);\n ctx.clip();\n\n for (const ann of list) {\n if (kindOf(ann) === 'point') {\n const pt = pointPixels(model, ann);\n if (!pt) continue;\n const r = ann.markerRadius ?? DEFAULT_MARKER_RADIUS;\n const dot = ann.color ?? tokens.color.text;\n ctx.save();\n // A background halo keeps the marker legible over data marks.\n ctx.fillStyle = tokens.color.background;\n ctx.globalAlpha = 0.9;\n ctx.beginPath();\n ctx.arc(pt.px, pt.py, r + 1.6, 0, Math.PI * 2);\n ctx.fill();\n ctx.globalAlpha = 1;\n ctx.fillStyle = dot;\n ctx.beginPath();\n ctx.arc(pt.px, pt.py, r, 0, Math.PI * 2);\n ctx.fill();\n ctx.restore();\n continue;\n }\n\n const axis: Axis = ann.axis === 'x' ? 'x' : 'y';\n const color = ann.color ?? tokens.color.textMuted;\n const ruleHorizontal = drawsHorizontalRule(model, axis);\n\n if (kindOf(ann) === 'line') {\n const p = toPixel(model, axis, ann.value);\n if (p === undefined) continue;\n ctx.save();\n ctx.strokeStyle = color;\n ctx.lineWidth = ann.strokeWidth ?? 1.5;\n ctx.setLineDash(ann.strokeDash ?? DEFAULT_DASH);\n ctx.beginPath();\n if (ruleHorizontal) {\n const y = crisp(p);\n ctx.moveTo(plot.x, y);\n ctx.lineTo(x1, y);\n } else {\n const x = crisp(p);\n ctx.moveTo(x, plot.y);\n ctx.lineTo(x, y1);\n }\n ctx.stroke();\n ctx.restore();\n continue;\n }\n\n // Band / zone: a filled span between `from` and `to`, with a faint border.\n const a = toPixel(model, axis, ann.from);\n const b = toPixel(model, axis, ann.to);\n if (a === undefined || b === undefined) continue;\n const lo = Math.min(a, b);\n const hi = Math.max(a, b);\n\n ctx.save();\n ctx.globalAlpha = ann.fillOpacity ?? DEFAULT_FILL_OPACITY;\n ctx.fillStyle = color;\n if (ruleHorizontal) ctx.fillRect(plot.x, lo, plot.width, hi - lo);\n else ctx.fillRect(lo, plot.y, hi - lo, plot.height);\n ctx.restore();\n\n ctx.save();\n ctx.strokeStyle = color;\n ctx.globalAlpha = 0.55;\n ctx.lineWidth = 1;\n ctx.setLineDash(ann.strokeDash ?? [4, 4]);\n ctx.beginPath();\n if (ruleHorizontal) {\n ctx.moveTo(plot.x, crisp(lo));\n ctx.lineTo(x1, crisp(lo));\n ctx.moveTo(plot.x, crisp(hi));\n ctx.lineTo(x1, crisp(hi));\n } else {\n ctx.moveTo(crisp(lo), plot.y);\n ctx.lineTo(crisp(lo), y1);\n ctx.moveTo(crisp(hi), plot.y);\n ctx.lineTo(crisp(hi), y1);\n }\n ctx.stroke();\n ctx.restore();\n }\n\n ctx.restore();\n}\n\ninterface LabelBox {\n left: number;\n top: number;\n width?: number;\n align: 'left' | 'center' | 'right';\n transform: string;\n}\n\n/** Resolve the overlay box for a label given whether its rule is horizontal on\n * screen, the anchor pixel, and the requested position. */\nfunction labelBox(\n model: CartesianModel,\n horizontalRule: boolean,\n pos: 'start' | 'middle' | 'end',\n p: number,\n): LabelBox {\n const { plot } = model;\n const inset = 6;\n if (horizontalRule) {\n // Horizontal line/band: label sits just above the rule, anchored horizontally.\n // Anchor (rather than span a full-width box) so the backing pill hugs the text\n // instead of drawing a band across the whole plot.\n const top = p - 3;\n if (pos === 'start') {\n return { left: plot.x + inset, top, align: 'left', transform: 'translateY(-100%)' };\n }\n if (pos === 'middle') {\n return { left: plot.x + plot.width / 2, top, align: 'center', transform: 'translateX(-50%) translateY(-100%)' };\n }\n return { left: plot.x + plot.width - inset, top, align: 'right', transform: 'translateX(-100%) translateY(-100%)' };\n }\n // Vertical line/band: label anchored at top (end), bottom (start), or middle.\n const left = p;\n const transform = 'translateX(-50%)';\n if (pos === 'start') return { left, top: plot.y + plot.height - 16, align: 'center', transform };\n if (pos === 'middle') return { left, top: plot.y + plot.height / 2, align: 'center', transform };\n return { left, top: plot.y + 2, align: 'center', transform };\n}\n\n/**\n * Append annotation labels to the HTML overlay. Call after `drawOverlay` so the\n * labels layer on top of axis text. No-op when there are no labeled annotations.\n */\nexport function drawAnnotationLabels(surface: Surface, model: CartesianModel): void {\n const list = annotationsOf(model);\n if (list.length === 0) return;\n\n const overlay = surface.overlay;\n const { tokens } = model;\n const f = tokens.font;\n const font = fontString(f.size.small, f.family, f.weight.medium);\n\n for (const ann of list) {\n if (!ann.label) continue;\n\n let box: LabelBox;\n if (kindOf(ann) === 'point') {\n const pt = pointPixels(model, ann);\n if (!pt) continue;\n const r = ann.markerRadius ?? DEFAULT_MARKER_RADIUS;\n const gap = r + 4;\n const textH = f.size.small;\n // Sit above the marker; flip below when that would clip the plot top.\n const aboveTop = pt.py - gap - textH;\n const top = aboveTop < model.plot.y ? pt.py + gap : aboveTop;\n box = { left: pt.px, top, align: 'center', transform: 'translateX(-50%)' };\n } else {\n const axis: Axis = ann.axis === 'x' ? 'x' : 'y';\n const p = anchorPixel(model, ann, axis, kindOf(ann));\n if (p === undefined) continue;\n box = labelBox(model, drawsHorizontalRule(model, axis), ann.labelPosition ?? 'end', p);\n }\n\n const color = ann.color ?? tokens.color.text;\n const pill = { background: withAlpha(tokens.color.background, 0.72), radius: 3, padX: 3, padY: 1 };\n\n if (surface.headless) {\n paintCanvasText(\n surface.marks.ctx,\n overlayTextToCanvasCmd(\n {\n left: box.left,\n top: box.top,\n width: box.width ?? undefined,\n text: ann.label,\n color,\n size: f.size.small,\n align: box.align,\n transform: box.transform,\n pill,\n },\n font,\n ),\n );\n continue;\n }\n\n const el = document.createElement('div');\n el.textContent = ann.label;\n el.style.position = 'absolute';\n el.style.font = font;\n el.style.fontSize = `${f.size.small}px`;\n el.style.fontWeight = String(f.weight.medium);\n el.style.color = color;\n el.style.whiteSpace = 'nowrap';\n el.style.left = `${box.left}px`;\n el.style.top = `${box.top}px`;\n if (box.width != null) {\n el.style.width = `${box.width}px`;\n el.style.textAlign = box.align;\n }\n el.style.transform = box.transform;\n // A faint backing pill keeps the label legible over data marks.\n el.style.padding = '0 3px';\n el.style.borderRadius = '3px';\n el.style.background = pill.background;\n el.style.pointerEvents = 'none';\n overlay.appendChild(el);\n }\n}\n\n/** Best-effort translucent background (handles #rgb/#rrggbb; falls back to the color). */\nfunction withAlpha(color: string, alpha: number): string {\n const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(color);\n if (!m) return color;\n let hex = m[1];\n if (hex.length === 3) hex = hex.split('').map((c) => c + c).join('');\n const r = parseInt(hex.slice(0, 2), 16);\n const g = parseInt(hex.slice(2, 4), 16);\n const b = parseInt(hex.slice(4, 6), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Reference annotations for cartesian charts \u2014 lines, bands, and threshold zones.\n *\n * A cross-cutting overlay primitive available to every cartesian chart via\n * `spec.annotations`. Marks (the rule strokes and band fills) are painted on the\n * marks canvas; labels live in the HTML overlay for crisp, selectable text,\n * mirroring how axes render. Geometry comes from the already-resolved\n * `CartesianModel` scales, so this module is pure presentation.\n */\n\nimport type { Surface } from '../render/surface';\nimport type { Annotation, ChartSpec } from '../spec/types';\nimport type { CartesianModel } from '../runtime/cartesian';\nimport { fontString } from '../render/text';\nimport { overlayTextToCanvasCmd, paintCanvasText } from '../render/overlayText';\nimport { CHROME_VISIBLE, chromeEntrance, chromeMorph, revealAt, stashChrome, visibleItems } from '../render/chromeMotion';\nimport { morphedModel } from '../axes/morph';\nimport { autoInsightAnnotations } from '../analyze/autoInsights';\nimport { crisp } from '../util/math';\n\ntype Axis = 'x' | 'y';\ntype Kind = 'line' | 'band' | 'point';\n\nconst DEFAULT_DASH = [5, 4];\nconst DEFAULT_FILL_OPACITY = 0.12;\nconst DEFAULT_MARKER_RADIUS = 3.5;\nconst ANNOTATIONS = 'annotations';\n/** Stash name of the annotation labels (an entrance fades them in place; see chromeMotion's fadeChrome). */\nexport const ANNOTATION_LABELS = `${ANNOTATIONS}:labels`;\n\n/** One annotation as drawn, and the opacity it was drawn at (for morphs). */\ninterface DrawnAnnotation {\n key: string;\n ann: Annotation;\n alpha: number;\n}\n\n/**\n * The annotations a frame draws. Outside a morph that is the spec's list at\n * full strength. While a morph is drawing, annotations present before and after\n * (same definition) stay solid and glide with the blended scales, new ones fade\n * in, and ones that are gone \u2014 including insight callouts that moved to a new\n * extreme \u2014 fade out where they were. Mid-entrance the stash records how far\n * each has revealed (`revealOf`), so an update that interrupts the entrance\n * fades them on from there instead of popping them in.\n */\nfunction drawnAnnotations(surface: Surface, list: readonly Annotation[], name: string, revealOf: (ann: Annotation) => number): DrawnAnnotation[] {\n const current = list.map((ann) => ({ key: JSON.stringify(ann), ann, alpha: 1 }));\n const morph = chromeMorph<DrawnAnnotation[]>(surface, name);\n if (!morph) {\n const entering = chromeEntrance(surface) != null;\n stashChrome(surface, name, entering ? current.map((d) => ({ ...d, alpha: revealOf(d.ann) })) : current);\n return current;\n }\n const { from, t } = morph;\n const before = new Map(from.map((d) => [d.key, d]));\n const now = new Set(current.map((d) => d.key));\n const drawn = visibleItems([\n ...from.filter((d) => !now.has(d.key)).map((d) => ({ ...d, alpha: d.alpha * (1 - t) })),\n ...current.map((d) => ({ ...d, alpha: before.has(d.key) ? before.get(d.key)!.alpha + (1 - before.get(d.key)!.alpha) * t : t })),\n ]);\n stashChrome(surface, name, drawn);\n return drawn;\n}\n\n/** Entrance timing: reference marks draw in once the data has mostly arrived. */\nfunction annotationReveal(surface: Surface, kind: Kind): number {\n const t = chromeEntrance(surface);\n if (t == null) return 1;\n return kind === 'point' ? revealAt(t, 0.6, 1) : revealAt(t, 0.35, 0.9);\n}\n\n/** Entrance timing for annotation labels: they arrive last. */\nfunction labelReveal(surface: Surface): number {\n const t = chromeEntrance(surface);\n return t == null ? 1 : revealAt(t, 0.75, 1);\n}\n\n/** Resolve whether an annotation is a single line, a filled span, or a point. */\nfunction kindOf(ann: Annotation): Kind {\n if (ann.type === 'point') return 'point';\n if (ann.type === 'line') return 'line';\n if (ann.type === 'band' || ann.type === 'zone') return 'band';\n return ann.value !== undefined ? 'line' : 'band';\n}\n\n/** Project an annotation value to its pixel on the given axis (or undefined). */\nfunction toPixel(model: CartesianModel, axis: Axis, value: unknown): number | undefined {\n if (value === undefined || value === null) return undefined;\n const px = axis === 'x' ? model.x.pixel(value) : model.y.pixel(value);\n return px != null && Number.isFinite(px) ? px : undefined;\n}\n\n/** Resolve a `point` annotation's (x, y) data coords to plot pixels. */\nfunction pointPixels(model: CartesianModel, ann: Annotation): { px: number; py: number } | undefined {\n const cat = toPixel(model, 'x', ann.x);\n const val = toPixel(model, 'y', ann.y);\n if (cat === undefined || val === undefined) return undefined;\n const { x, y } = model.project(cat, val);\n return { px: x, py: y };\n}\n\n/**\n * Whether an annotation on the given data axis draws as a horizontal rule on\n * screen. In vertical charts the value (`y`) axis is horizontal; in horizontal\n * bar charts the axes swap, so the category (`x`) axis becomes the horizontal one.\n */\nfunction drawsHorizontalRule(model: CartesianModel, axis: Axis): boolean {\n return model.orientation === 'horizontal' ? axis === 'x' : axis === 'y';\n}\n\n/** Anchor pixel for an annotation's label (line value, or band midpoint). */\nfunction anchorPixel(model: CartesianModel, ann: Annotation, axis: Axis, kind: Kind): number | undefined {\n if (kind === 'line') return toPixel(model, axis, ann.value);\n const a = toPixel(model, axis, ann.from);\n const b = toPixel(model, axis, ann.to);\n if (a === undefined || b === undefined) return undefined;\n return (a + b) / 2;\n}\n\n/** Explicit `spec.annotations` plus any auto-insight callouts (`spec.insights`). */\nfunction annotationsOf(model: CartesianModel): Annotation[] {\n const spec = model.spec as { annotations?: Annotation[]; insights?: unknown };\n const explicit = Array.isArray(spec.annotations) ? spec.annotations : [];\n if (!spec.insights) return explicit;\n const auto = autoInsightAnnotations(model.spec as ChartSpec);\n return auto.length ? [...explicit, ...auto] : explicit;\n}\n\n/**\n * Paint reference lines and band/zone fills on the marks canvas, clipped to the\n * plot. Call after the chart's data marks so reference lines sit on top. While a\n * morph is drawing they move with the axes (see axes/morph.ts); during an\n * entrance rules draw across, bands open out from their middle, and points pop\n * in once the marks have mostly arrived.\n */\nexport function drawAnnotations(surface: Surface, model: CartesianModel): void {\n const drawn = drawnAnnotations(surface, annotationsOf(model), ANNOTATIONS, (ann) => annotationReveal(surface, kindOf(ann)));\n if (drawn.length === 0) return;\n\n const frame = morphedModel(surface, model);\n const ctx = surface.marks.ctx;\n const { plot, tokens } = frame;\n const x1 = plot.x + plot.width;\n const y1 = plot.y + plot.height;\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(plot.x, plot.y, plot.width, plot.height);\n ctx.clip();\n\n for (const { ann, alpha } of drawn) {\n const kind = kindOf(ann);\n const reveal = annotationReveal(surface, kind);\n const k = alpha * reveal;\n if (!(k > CHROME_VISIBLE)) continue;\n if (kind === 'point') {\n const pt = pointPixels(frame, ann);\n if (!pt) continue;\n const r = (ann.markerRadius ?? DEFAULT_MARKER_RADIUS) * (reveal < 1 ? reveal : 1);\n const dot = ann.color ?? tokens.color.text;\n ctx.save();\n // A background halo keeps the marker legible over data marks.\n ctx.fillStyle = tokens.color.background;\n ctx.globalAlpha = 0.9 * k;\n ctx.beginPath();\n ctx.arc(pt.px, pt.py, r + 1.6, 0, Math.PI * 2);\n ctx.fill();\n ctx.globalAlpha = k;\n ctx.fillStyle = dot;\n ctx.beginPath();\n ctx.arc(pt.px, pt.py, r, 0, Math.PI * 2);\n ctx.fill();\n ctx.restore();\n continue;\n }\n\n const axis: Axis = ann.axis === 'x' ? 'x' : 'y';\n const color = ann.color ?? tokens.color.textMuted;\n const ruleHorizontal = drawsHorizontalRule(frame, axis);\n\n if (kind === 'line') {\n const p = toPixel(frame, axis, ann.value);\n if (p === undefined) continue;\n ctx.save();\n if (k !== 1) ctx.globalAlpha = k;\n ctx.strokeStyle = color;\n ctx.lineWidth = ann.strokeWidth ?? 1.5;\n ctx.setLineDash(ann.strokeDash ?? DEFAULT_DASH);\n ctx.beginPath();\n // Entering rules draw across: left to right, or bottom to top.\n if (ruleHorizontal) {\n const y = crisp(p);\n ctx.moveTo(plot.x, y);\n ctx.lineTo(reveal < 1 ? plot.x + plot.width * reveal : x1, y);\n } else if (reveal < 1) {\n const x = crisp(p);\n ctx.moveTo(x, y1);\n ctx.lineTo(x, y1 - plot.height * reveal);\n } else {\n const x = crisp(p);\n ctx.moveTo(x, plot.y);\n ctx.lineTo(x, y1);\n }\n ctx.stroke();\n ctx.restore();\n continue;\n }\n\n // Band / zone: a filled span between `from` and `to`, with a faint border.\n const a = toPixel(frame, axis, ann.from);\n const b = toPixel(frame, axis, ann.to);\n if (a === undefined || b === undefined) continue;\n let lo = Math.min(a, b);\n let hi = Math.max(a, b);\n if (reveal < 1) {\n // Entering bands open out from their middle.\n const mid = (lo + hi) / 2;\n lo = mid + (lo - mid) * reveal;\n hi = mid + (hi - mid) * reveal;\n }\n\n ctx.save();\n ctx.globalAlpha = (ann.fillOpacity ?? DEFAULT_FILL_OPACITY) * k;\n ctx.fillStyle = color;\n if (ruleHorizontal) ctx.fillRect(plot.x, lo, plot.width, hi - lo);\n else ctx.fillRect(lo, plot.y, hi - lo, plot.height);\n ctx.restore();\n\n ctx.save();\n ctx.strokeStyle = color;\n ctx.globalAlpha = 0.55 * k;\n ctx.lineWidth = 1;\n ctx.setLineDash(ann.strokeDash ?? [4, 4]);\n ctx.beginPath();\n if (ruleHorizontal) {\n ctx.moveTo(plot.x, crisp(lo));\n ctx.lineTo(x1, crisp(lo));\n ctx.moveTo(plot.x, crisp(hi));\n ctx.lineTo(x1, crisp(hi));\n } else {\n ctx.moveTo(crisp(lo), plot.y);\n ctx.lineTo(crisp(lo), y1);\n ctx.moveTo(crisp(hi), plot.y);\n ctx.lineTo(crisp(hi), y1);\n }\n ctx.stroke();\n ctx.restore();\n }\n\n ctx.restore();\n}\n\ninterface LabelBox {\n left: number;\n top: number;\n width?: number;\n align: 'left' | 'center' | 'right';\n transform: string;\n}\n\n/** Resolve the overlay box for a label given whether its rule is horizontal on\n * screen, the anchor pixel, and the requested position. */\nfunction labelBox(\n model: CartesianModel,\n horizontalRule: boolean,\n pos: 'start' | 'middle' | 'end',\n p: number,\n): LabelBox {\n const { plot } = model;\n const inset = 6;\n if (horizontalRule) {\n // Horizontal line/band: label sits just above the rule, anchored horizontally.\n // Anchor (rather than span a full-width box) so the backing pill hugs the text\n // instead of drawing a band across the whole plot.\n const top = p - 3;\n if (pos === 'start') {\n return { left: plot.x + inset, top, align: 'left', transform: 'translateY(-100%)' };\n }\n if (pos === 'middle') {\n return { left: plot.x + plot.width / 2, top, align: 'center', transform: 'translateX(-50%) translateY(-100%)' };\n }\n return { left: plot.x + plot.width - inset, top, align: 'right', transform: 'translateX(-100%) translateY(-100%)' };\n }\n // Vertical line/band: label anchored at top (end), bottom (start), or middle.\n const left = p;\n const transform = 'translateX(-50%)';\n if (pos === 'start') return { left, top: plot.y + plot.height - 16, align: 'center', transform };\n if (pos === 'middle') return { left, top: plot.y + plot.height / 2, align: 'center', transform };\n return { left, top: plot.y + 2, align: 'center', transform };\n}\n\n/**\n * Append annotation labels to the HTML overlay. Call after `drawOverlay` so the\n * labels layer on top of axis text. Returns the label elements (none when\n * headless) so an entrance can hold them back until their marks have drawn in.\n */\nexport function drawAnnotationLabels(surface: Surface, model: CartesianModel): HTMLElement[] {\n const drawn = drawnAnnotations(surface, annotationsOf(model), ANNOTATION_LABELS, () => labelReveal(surface));\n if (drawn.length === 0) return [];\n\n const frame = morphedModel(surface, model);\n const overlay = surface.overlay;\n const { tokens } = frame;\n const f = tokens.font;\n const font = fontString(f.size.small, f.family, f.weight.medium);\n const reveal = labelReveal(surface);\n const elements: HTMLElement[] = [];\n\n for (const { ann, alpha } of drawn) {\n if (!ann.label) continue;\n // Labels follow their marks: they fade with a morph, and arrive last on entrance.\n const opacity = alpha * reveal;\n if (!surface.headless && !(opacity > CHROME_VISIBLE)) continue;\n\n let box: LabelBox;\n if (kindOf(ann) === 'point') {\n const pt = pointPixels(frame, ann);\n if (!pt) continue;\n const r = ann.markerRadius ?? DEFAULT_MARKER_RADIUS;\n const gap = r + 4;\n const textH = f.size.small;\n // Sit above the marker; flip below when that would clip the plot top.\n const aboveTop = pt.py - gap - textH;\n const top = aboveTop < frame.plot.y ? pt.py + gap : aboveTop;\n box = { left: pt.px, top, align: 'center', transform: 'translateX(-50%)' };\n } else {\n const axis: Axis = ann.axis === 'x' ? 'x' : 'y';\n const p = anchorPixel(frame, ann, axis, kindOf(ann));\n if (p === undefined) continue;\n box = labelBox(frame, drawsHorizontalRule(frame, axis), ann.labelPosition ?? 'end', p);\n }\n\n const color = ann.color ?? tokens.color.text;\n const pill = { background: withAlpha(tokens.color.background, 0.72), radius: 3, padX: 3, padY: 1 };\n\n if (surface.headless) {\n paintCanvasText(\n surface.marks.ctx,\n overlayTextToCanvasCmd(\n {\n left: box.left,\n top: box.top,\n width: box.width ?? undefined,\n text: ann.label,\n color,\n size: f.size.small,\n align: box.align,\n transform: box.transform,\n pill,\n },\n font,\n ),\n );\n continue;\n }\n\n const el = document.createElement('div');\n el.textContent = ann.label;\n el.style.position = 'absolute';\n el.style.font = font;\n el.style.fontSize = `${f.size.small}px`;\n el.style.fontWeight = String(f.weight.medium);\n el.style.color = color;\n el.style.whiteSpace = 'nowrap';\n el.style.left = `${box.left}px`;\n el.style.top = `${box.top}px`;\n if (box.width != null) {\n el.style.width = `${box.width}px`;\n el.style.textAlign = box.align;\n }\n el.style.transform = box.transform;\n // A faint backing pill keeps the label legible over data marks.\n el.style.padding = '0 3px';\n el.style.borderRadius = '3px';\n el.style.background = pill.background;\n el.style.pointerEvents = 'none';\n if (opacity < 1) el.style.opacity = String(Math.max(0, opacity));\n overlay.appendChild(el);\n elements.push(el);\n }\n return elements;\n}\n\n/** Best-effort translucent background (handles #rgb/#rrggbb; falls back to the color). */\nfunction withAlpha(color: string, alpha: number): string {\n const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(color);\n if (!m) return color;\n let hex = m[1];\n if (hex.length === 3) hex = hex.split('').map((c) => c + c).join('');\n const r = parseInt(hex.slice(0, 2), 16);\n const g = parseInt(hex.slice(2, 4), 16);\n const b = parseInt(hex.slice(4, 6), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -9,6 +9,42 @@
9
9
  * Consumes the prebuilt `CartesianModel` (x/y scales, resolved series, baseline).
10
10
  */
11
11
  import type { Surface } from '../render/surface.js';
12
- import { type CartesianModel } from '../runtime/cartesian.js';
12
+ import { type AreaPoint } from '../shape/index.js';
13
+ import { type CartesianModel, type ResolvedSeries } from '../runtime/cartesian.js';
14
+ import type { Point } from '../types.js';
15
+ import { type SeriesEmphasisMode } from './emphasis.js';
16
+ /** A band vertex that remembers which datum (x key) it came from. */
17
+ export type KeyedAreaPoint = AreaPoint & {
18
+ key?: string;
19
+ };
20
+ export interface BandPoints {
21
+ series: ResolvedSeries;
22
+ points: KeyedAreaPoint[];
23
+ markers: AreaPoint[];
24
+ alpha: number;
25
+ mode: SeriesEmphasisMode;
26
+ matchPoints: Point[];
27
+ usableRows: number;
28
+ }
29
+ export interface AreaMetrics {
30
+ strokeWidth: number;
31
+ markerR: number;
32
+ markerSW: number;
33
+ }
34
+ /** Resolved pixel geometry for an area chart (one band per series, paint order). */
35
+ export interface AreaGeometry {
36
+ kind: 'area';
37
+ bands: BandPoints[];
38
+ metrics: AreaMetrics;
39
+ stacked: boolean;
40
+ /** Value-axis pixel of the zero baseline. */
41
+ baseline: number;
42
+ }
43
+ /** Vertices that get markers: only isolated ones (a lone vertex can't make a band). */
44
+ export declare function areaMarkers(points: readonly AreaPoint[]): AreaPoint[];
45
+ /** Resolve every band's pixel vertices and adaptive metrics without drawing. */
46
+ export declare function layoutArea(model: CartesianModel): AreaGeometry;
47
+ /** Paint resolved area geometry onto the marks layer, clipped to the plot. */
48
+ export declare function paintArea(surface: Surface, model: CartesianModel, geometry: AreaGeometry): void;
13
49
  export declare function drawArea(surface: Surface, model: CartesianModel): void;
14
50
  //# sourceMappingURL=area.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"area.d.ts","sourceRoot":"","sources":["../../src/charts/area.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAKjD,OAAO,EAAgB,KAAK,cAAc,EAAuB,MAAM,sBAAsB,CAAC;AAiT9F,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI,CAsCtE"}
1
+ {"version":3,"file":"area.d.ts","sourceRoot":"","sources":["../../src/charts/area.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAEtD,OAAO,EAAgB,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE9F,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEtC,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAgBzE,qEAAqE;AACrE,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,kBAAkB,CAAC;IACzB,WAAW,EAAE,KAAK,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,EAAE,CAKrE;AAgRD,gFAAgF;AAChF,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,YAAY,CAQ9D;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CA6B/F;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI,CAKtE"}
@@ -8,6 +8,7 @@ import { seriesEmphasisMode } from "./emphasis.js";
8
8
  import { isolatedPoints, lineStrokeWidth, markerRadius, markerStroke } from "../render/metrics.js";
9
9
  import { recordRuns } from "../render/evidence.js";
10
10
  import { drawMatchedPointMarkers, drawSeriesMarkers } from "./pointMarkers.js";
11
+ import { vertexKey } from "./line.js";
11
12
  function maxBandLength(bands) {
12
13
  let n = 0;
13
14
  for (const b of bands) {
@@ -16,6 +17,12 @@ function maxBandLength(bands) {
16
17
  }
17
18
  return n;
18
19
  }
20
+ function areaMarkers(points) {
21
+ return isolatedPoints(
22
+ points,
23
+ (point) => Number.isFinite(point.x) && Number.isFinite(point.y0) && Number.isFinite(point.y1)
24
+ );
25
+ }
19
26
  function buildBands(model, stacked) {
20
27
  const readX = accessor(model.x.field);
21
28
  const readY = accessor(model.y.field ?? "");
@@ -26,6 +33,7 @@ function buildBands(model, stacked) {
26
33
  const mode = seriesEmphasisMode(model.emphasis, series);
27
34
  const matchPoints = [];
28
35
  const points = [];
36
+ const seen = /* @__PURE__ */ new Map();
29
37
  let usableRows = 0;
30
38
  for (const row of series.rows) {
31
39
  const xv = readX(row);
@@ -33,6 +41,7 @@ function buildBands(model, stacked) {
33
41
  const raw = readY(row);
34
42
  const value = toNumber(raw);
35
43
  const missing = raw == null || raw === "" || Number.isNaN(value);
44
+ const vertex = vertexKey(seen, toKey(xv));
36
45
  if (stacked) {
37
46
  const key = toKey(xv);
38
47
  const totals = value >= 0 || missing ? positiveTotals : negativeTotals;
@@ -60,20 +69,18 @@ function buildBands(model, stacked) {
60
69
  matchPoints.push({ x: px, y: y1 });
61
70
  }
62
71
  const last = points[points.length - 1];
72
+ last.key = vertex;
63
73
  if (Number.isFinite(last.x) && Number.isFinite(last.y1) && Number.isFinite(last.y0))
64
74
  usableRows++;
65
75
  }
66
76
  points.sort((a, b) => a.sortKey - b.sortKey);
67
- const band = points.map(({ x, y0, y1 }) => ({ x, y0, y1 }));
77
+ const band = points.map(({ x, y0, y1, key }) => ({ x, y0, y1, key }));
68
78
  const reduced = Number.isFinite(threshold) ? decimate(band, threshold, {
69
79
  getX: (p) => p.x,
70
80
  getY: (p) => p.y1,
71
81
  gap: () => ({ x: NaN, y0: NaN, y1: NaN })
72
82
  }) : band;
73
- const markers = isolatedPoints(
74
- reduced,
75
- (point) => Number.isFinite(point.x) && Number.isFinite(point.y0) && Number.isFinite(point.y1)
76
- );
83
+ const markers = areaMarkers(reduced);
77
84
  return {
78
85
  series,
79
86
  points: reduced,
@@ -140,7 +147,7 @@ function drawAreaSketch(ctx, model, bands, pen, stacked, strokeWidth, markerR, m
140
147
  }
141
148
  ctx.globalAlpha = 1;
142
149
  }
143
- function areaGeometry(model, bands) {
150
+ function areaMetrics(model, bands) {
144
151
  const markerR = markerRadius(model.plot, maxBandLength(bands));
145
152
  return {
146
153
  strokeWidth: lineStrokeWidth(model.plot, Math.max(1.5, model.tokens.stroke.base)),
@@ -237,17 +244,19 @@ function drawAreaNormal(ctx, model, bands, stacked, geometry, areaGen, lineGen)
237
244
  drawSeriesMarkers(ctx, tokens, bands, geometry, (point) => ({ x: point.x, y: point.y1 }), false, false);
238
245
  drawMatchedPointMarkers(ctx, tokens, bands, geometry);
239
246
  }
240
- function drawArea(surface, model) {
241
- surface.evidence?.begin("rows");
247
+ function layoutArea(model) {
248
+ const stacked = model.stacked;
249
+ const bands = buildBands(model, stacked);
250
+ return { kind: "area", bands, metrics: areaMetrics(model, bands), stacked, baseline: model.y.baseline };
251
+ }
252
+ function paintArea(surface, model, geometry) {
242
253
  const ctx = surface.marks.ctx;
243
254
  const spec = model.spec;
244
255
  const curve = resolveCurve(spec.curve);
245
256
  const areaGen = area({ curve });
246
257
  const lineGen = line({ curve });
247
- const stacked = model.stacked;
248
- const bands = buildBands(model, stacked);
249
- const geometry = areaGeometry(model, bands);
250
- recordAreaEvidence(surface, model, bands, stacked, geometry);
258
+ const { bands, stacked, metrics } = geometry;
259
+ recordAreaEvidence(surface, model, bands, stacked, metrics);
251
260
  ctx.save();
252
261
  clipPlot(ctx, model);
253
262
  if (model.sketch) {
@@ -257,17 +266,26 @@ function drawArea(surface, model) {
257
266
  bands,
258
267
  new RoughPen(ctx, model.sketch),
259
268
  stacked,
260
- geometry.strokeWidth,
261
- geometry.markerR,
262
- geometry.markerSW
269
+ metrics.strokeWidth,
270
+ metrics.markerR,
271
+ metrics.markerSW
263
272
  );
264
273
  ctx.restore();
265
274
  return;
266
275
  }
267
- drawAreaNormal(ctx, model, bands, stacked, geometry, areaGen, lineGen);
276
+ drawAreaNormal(ctx, model, bands, stacked, metrics, areaGen, lineGen);
268
277
  ctx.restore();
269
278
  }
279
+ function drawArea(surface, model) {
280
+ surface.evidence?.begin("rows");
281
+ const geometry = layoutArea(model);
282
+ model.geometry = geometry;
283
+ paintArea(surface, model, geometry);
284
+ }
270
285
  export {
271
- drawArea
286
+ areaMarkers,
287
+ drawArea,
288
+ layoutArea,
289
+ paintArea
272
290
  };
273
291
  //# sourceMappingURL=area.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/charts/area.ts"],
4
- "sourcesContent": ["/**\n * Area chart. Two modes:\n * - overlapping (default): each series filled from the zero baseline with a\n * translucent fill + opaque top stroke, so overlaps stay legible.\n * - stacked (`stack: true`): series are accumulated per x value; each band\n * spans from the running total below it to the new total, with mostly-opaque\n * fills for a clean stacked look.\n *\n * Consumes the prebuilt `CartesianModel` (x/y scales, resolved series, baseline).\n */\n\nimport type { Surface } from '../render/surface';\nimport type { AreaSpec } from '../spec/types';\nimport { accessor, toKey, toNumber } from '../util/data';\nimport { area, line, type AreaPoint } from '../shape';\nimport { decimate } from '../decimate';\nimport { resolveCurve, type CartesianModel, type ResolvedSeries } from '../runtime/cartesian';\nimport { RoughPen } from '../rough';\nimport type { Point } from '../types';\nimport { maxFinite, minFinite, verticalFill } from './fill';\nimport { seriesEmphasisMode, type SeriesEmphasisMode } from './emphasis';\nimport { isolatedPoints, lineStrokeWidth, markerRadius, markerStroke } from '../render/metrics';\nimport { recordRuns } from '../render/evidence';\nimport { drawMatchedPointMarkers, drawSeriesMarkers } from './pointMarkers';\n\n/** Longest single-band point run \u2014 drives density-aware marker sizing. */\nfunction maxBandLength(bands: BandPoints[]): number {\n let n = 0;\n for (const b of bands) {\n const finite = b.points.filter((p) => !Number.isNaN(p.x) && !Number.isNaN(p.y1)).length;\n if (finite > n) n = finite;\n }\n return n;\n}\n\ninterface BandPoints {\n series: ResolvedSeries;\n points: AreaPoint[];\n markers: AreaPoint[];\n alpha: number;\n mode: SeriesEmphasisMode;\n matchPoints: Point[];\n usableRows: number;\n}\n\ninterface AreaGeometry {\n strokeWidth: number;\n markerR: number;\n markerSW: number;\n}\n\n/** Build per-series area bands, stacking cumulatively in value-space when asked. */\nfunction buildBands(model: CartesianModel, stacked: boolean): BandPoints[] {\n const readX = accessor(model.x.field);\n const readY = accessor(model.y.field ?? '');\n const positiveTotals = new Map<string, number>();\n const negativeTotals = new Map<string, number>();\n // Stacked bands must share x samples to stay aligned, so only the\n // independent (overlapping) mode is downsampled.\n const threshold = stacked ? Infinity : Math.max(2, Math.round(model.plot.width));\n\n return model.series.map((series) => {\n const mode = seriesEmphasisMode(model.emphasis, series);\n const matchPoints: Point[] = [];\n const points: Array<AreaPoint & { sortKey: number }> = [];\n let usableRows = 0;\n for (const row of series.rows) {\n const xv = readX(row);\n const px = model.x.pixel(xv);\n const raw = readY(row);\n const value = toNumber(raw);\n const missing = raw == null || raw === '' || Number.isNaN(value);\n\n if (stacked) {\n const key = toKey(xv);\n const totals = value >= 0 || missing ? positiveTotals : negativeTotals;\n const base = totals.get(key) ?? 0;\n const top = base + (missing ? 0 : value);\n totals.set(key, top);\n const y1 = missing ? NaN : model.y.pixel(top);\n points.push({\n x: px == null ? NaN : px,\n y0: model.y.pixel(base),\n y1,\n sortKey: px == null ? Number.POSITIVE_INFINITY : px,\n });\n if (model.emphasis?.match(row) && px != null && !Number.isNaN(y1))\n matchPoints.push({ x: px, y: y1 });\n } else {\n const y1 = missing ? NaN : model.y.pixel(value);\n points.push({\n x: px == null ? NaN : px,\n y0: model.y.baseline,\n y1,\n sortKey: px == null ? Number.POSITIVE_INFINITY : px,\n });\n if (model.emphasis?.match(row) && px != null && !Number.isNaN(y1))\n matchPoints.push({ x: px, y: y1 });\n }\n const last = points[points.length - 1];\n if (Number.isFinite(last.x) && Number.isFinite(last.y1) && Number.isFinite(last.y0))\n usableRows++;\n }\n points.sort((a, b) => a.sortKey - b.sortKey);\n const band: AreaPoint[] = points.map(({ x, y0, y1 }) => ({ x, y0, y1 }));\n const reduced = Number.isFinite(threshold)\n ? decimate(band, threshold, {\n getX: (p) => p.x,\n getY: (p) => p.y1,\n gap: () => ({ x: NaN, y0: NaN, y1: NaN }),\n })\n : band;\n const markers = isolatedPoints(\n reduced,\n (point) => Number.isFinite(point.x) && Number.isFinite(point.y0) && Number.isFinite(point.y1),\n );\n return {\n series,\n points: reduced,\n markers,\n alpha: mode === 'all' ? 1 : (model.emphasis?.dim ?? 1),\n mode,\n matchPoints,\n usableRows,\n };\n });\n}\n\n/** Hand-drawn path: hachure-filled bands with wobbly top edges (gap-aware). */\nfunction drawAreaSketch(\n ctx: CanvasRenderingContext2D,\n model: CartesianModel,\n bands: BandPoints[],\n pen: RoughPen,\n stacked: boolean,\n strokeWidth: number,\n markerR: number,\n markerSW: number,\n): void {\n for (const { series, points, alpha } of bands) {\n const prev = ctx.globalAlpha;\n if (alpha !== 1) ctx.globalAlpha = alpha;\n let run: AreaPoint[] = [];\n const flush = (): void => {\n if (run.length >= 2) {\n const top: Point[] = run.map((p) => ({ x: p.x, y: p.y1 }));\n const bottom: Point[] = run.map((p) => ({ x: p.x, y: p.y0 })).reverse();\n pen.polygon([...top, ...bottom], {\n fill: series.color,\n fillAlpha: stacked ? 0.85 : 0.5,\n });\n }\n run = [];\n };\n for (const p of points) {\n if (Number.isNaN(p.x) || Number.isNaN(p.y1)) flush();\n else run.push(p);\n }\n flush();\n if (alpha !== 1) ctx.globalAlpha = prev;\n }\n\n for (const { series, points, alpha } of bands) {\n const prev = ctx.globalAlpha;\n if (alpha !== 1) ctx.globalAlpha = alpha;\n pen.trendStroke(\n points.map((p) => ({ x: p.x, y: p.y1 })),\n { stroke: series.color, strokeWidth },\n );\n if (alpha !== 1) ctx.globalAlpha = prev;\n }\n\n for (const { series, markers, alpha } of bands) {\n ctx.globalAlpha = alpha;\n for (const point of markers) {\n pen.circle(point.x, point.y1, markerR, {\n fill: series.color,\n stroke: model.tokens.color.background,\n strokeWidth: markerSW,\n });\n }\n }\n\n for (const { series, mode, matchPoints } of bands) {\n if (mode !== 'partial') continue;\n ctx.globalAlpha = 1;\n for (const p of matchPoints) {\n pen.circle(p.x, p.y, markerR, {\n fill: series.color,\n stroke: model.tokens.color.background,\n strokeWidth: markerSW,\n });\n }\n }\n ctx.globalAlpha = 1;\n}\n\nfunction areaGeometry(model: CartesianModel, bands: BandPoints[]): AreaGeometry {\n const markerR = markerRadius(model.plot, maxBandLength(bands));\n return {\n strokeWidth: lineStrokeWidth(model.plot, Math.max(1.5, model.tokens.stroke.base)),\n markerR,\n markerSW: markerStroke(markerR),\n };\n}\n\nfunction recordAreaEvidence(\n surface: Surface,\n model: CartesianModel,\n bands: BandPoints[],\n stacked: boolean,\n geometry: AreaGeometry,\n): void {\n let represented = 0;\n let reduced = 0;\n for (const b of bands) {\n const runs = recordRuns(\n surface.evidence,\n b.points,\n b.series.color,\n (stacked ? 1 : 0.95) * b.alpha,\n model.plot,\n geometry.strokeWidth,\n true,\n undefined,\n b.alpha < 1,\n );\n represented += b.usableRows;\n reduced += Math.max(0, b.usableRows - runs.observations);\n for (const point of b.markers) {\n surface.evidence?.mark(\n 'point',\n point.x - geometry.markerR,\n point.y1 - geometry.markerR,\n geometry.markerR * 2,\n geometry.markerR * 2,\n b.series.color,\n b.alpha,\n model.plot,\n 1,\n undefined,\n b.alpha < 1,\n );\n }\n if (b.mode === 'partial')\n for (const p of b.matchPoints) {\n surface.evidence?.mark(\n 'point',\n p.x - geometry.markerR,\n p.y - geometry.markerR,\n geometry.markerR * 2,\n geometry.markerR * 2,\n b.series.color,\n 1,\n model.plot,\n );\n }\n }\n surface.evidence?.data(represented, 'rows', reduced);\n}\n\nfunction clipPlot(ctx: CanvasRenderingContext2D, model: CartesianModel): void {\n const { plot } = model;\n ctx.beginPath();\n ctx.rect(plot.x, plot.y, plot.width, plot.height);\n ctx.clip();\n}\n\nfunction drawAreaNormal(\n ctx: CanvasRenderingContext2D,\n model: CartesianModel,\n bands: BandPoints[],\n stacked: boolean,\n geometry: AreaGeometry,\n areaGen: ReturnType<typeof area>,\n lineGen: ReturnType<typeof line>,\n): void {\n const { plot, tokens } = model;\n // Gradient fills: overlapping bands fade to near-transparent at the baseline;\n // stacked bands stay mostly opaque with a subtle vertical sheen for depth.\n for (const { series, points, alpha } of bands) {\n const top = minFinite(\n points.map((p) => p.y1),\n plot.y,\n );\n const bottom = stacked\n ? maxFinite(\n points.map((p) => p.y0),\n model.y.baseline,\n )\n : model.y.baseline;\n ctx.beginPath();\n areaGen(points, ctx);\n ctx.globalAlpha = alpha;\n ctx.fillStyle = stacked\n ? verticalFill(ctx, series.color, top, bottom, 0.96, 0.74)\n : verticalFill(ctx, series.color, top, bottom, 0.3, 0.02);\n ctx.fill();\n ctx.globalAlpha = 1;\n }\n\n // Top edge strokes for crisp band separation.\n ctx.lineJoin = 'round';\n ctx.lineCap = 'round';\n ctx.lineWidth = geometry.strokeWidth;\n for (const { series, points, alpha } of bands) {\n ctx.beginPath();\n lineGen(\n points.map((p) => ({ x: p.x, y: p.y1 })),\n ctx,\n );\n ctx.strokeStyle = series.color;\n ctx.globalAlpha = (stacked ? 1 : 0.95) * alpha;\n ctx.stroke();\n ctx.globalAlpha = 1;\n }\n\n drawSeriesMarkers(ctx, tokens, bands, geometry, (point) => ({ x: point.x, y: point.y1 }), false, false);\n drawMatchedPointMarkers(ctx, tokens, bands, geometry);\n}\n\nexport function drawArea(surface: Surface, model: CartesianModel): void {\n surface.evidence?.begin('rows');\n const ctx = surface.marks.ctx;\n const spec = model.spec as AreaSpec;\n const curve = resolveCurve(spec.curve);\n const areaGen = area({ curve });\n const lineGen = line({ curve });\n const stacked = model.stacked;\n\n // Painter's order: for stacked charts the topmost band must paint last so its\n // edge sits above neighbours; bottom-up matches the resolved series order.\n const bands = buildBands(model, stacked);\n\n // Adaptive: top-edge weight grows with plot size; markers scale with size and\n // density so overlapping areas read cleanly at any extent.\n const geometry = areaGeometry(model, bands);\n recordAreaEvidence(surface, model, bands, stacked, geometry);\n\n ctx.save();\n clipPlot(ctx, model);\n\n if (model.sketch) {\n drawAreaSketch(\n ctx,\n model,\n bands,\n new RoughPen(ctx, model.sketch),\n stacked,\n geometry.strokeWidth,\n geometry.markerR,\n geometry.markerSW,\n );\n ctx.restore();\n return;\n }\n\n drawAreaNormal(ctx, model, bands, stacked, geometry, areaGen, lineGen);\n ctx.restore();\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Area chart. Two modes:\n * - overlapping (default): each series filled from the zero baseline with a\n * translucent fill + opaque top stroke, so overlaps stay legible.\n * - stacked (`stack: true`): series are accumulated per x value; each band\n * spans from the running total below it to the new total, with mostly-opaque\n * fills for a clean stacked look.\n *\n * Consumes the prebuilt `CartesianModel` (x/y scales, resolved series, baseline).\n */\n\nimport type { Surface } from '../render/surface';\nimport type { AreaSpec } from '../spec/types';\nimport { accessor, toKey, toNumber } from '../util/data';\nimport { area, line, type AreaPoint } from '../shape';\nimport { decimate } from '../decimate';\nimport { resolveCurve, type CartesianModel, type ResolvedSeries } from '../runtime/cartesian';\nimport { RoughPen } from '../rough';\nimport type { Point } from '../types';\nimport { maxFinite, minFinite, verticalFill } from './fill';\nimport { seriesEmphasisMode, type SeriesEmphasisMode } from './emphasis';\nimport { isolatedPoints, lineStrokeWidth, markerRadius, markerStroke } from '../render/metrics';\nimport { recordRuns } from '../render/evidence';\nimport { drawMatchedPointMarkers, drawSeriesMarkers } from './pointMarkers';\nimport { vertexKey } from './line';\n\n/** Longest single-band point run \u2014 drives density-aware marker sizing. */\nfunction maxBandLength(bands: BandPoints[]): number {\n let n = 0;\n for (const b of bands) {\n const finite = b.points.filter((p) => !Number.isNaN(p.x) && !Number.isNaN(p.y1)).length;\n if (finite > n) n = finite;\n }\n return n;\n}\n\n/** A band vertex that remembers which datum (x key) it came from. */\nexport type KeyedAreaPoint = AreaPoint & { key?: string };\n\nexport interface BandPoints {\n series: ResolvedSeries;\n points: KeyedAreaPoint[];\n markers: AreaPoint[];\n alpha: number;\n mode: SeriesEmphasisMode;\n matchPoints: Point[];\n usableRows: number;\n}\n\nexport interface AreaMetrics {\n strokeWidth: number;\n markerR: number;\n markerSW: number;\n}\n\n/** Resolved pixel geometry for an area chart (one band per series, paint order). */\nexport interface AreaGeometry {\n kind: 'area';\n bands: BandPoints[];\n metrics: AreaMetrics;\n stacked: boolean;\n /** Value-axis pixel of the zero baseline. */\n baseline: number;\n}\n\n/** Vertices that get markers: only isolated ones (a lone vertex can't make a band). */\nexport function areaMarkers(points: readonly AreaPoint[]): AreaPoint[] {\n return isolatedPoints(\n points,\n (point) => Number.isFinite(point.x) && Number.isFinite(point.y0) && Number.isFinite(point.y1),\n );\n}\n\n/** Build per-series area bands, stacking cumulatively in value-space when asked. */\nfunction buildBands(model: CartesianModel, stacked: boolean): BandPoints[] {\n const readX = accessor(model.x.field);\n const readY = accessor(model.y.field ?? '');\n const positiveTotals = new Map<string, number>();\n const negativeTotals = new Map<string, number>();\n // Stacked bands must share x samples to stay aligned, so only the\n // independent (overlapping) mode is downsampled.\n const threshold = stacked ? Infinity : Math.max(2, Math.round(model.plot.width));\n\n return model.series.map((series) => {\n const mode = seriesEmphasisMode(model.emphasis, series);\n const matchPoints: Point[] = [];\n const points: Array<KeyedAreaPoint & { sortKey: number }> = [];\n const seen = new Map<string, number>();\n let usableRows = 0;\n for (const row of series.rows) {\n const xv = readX(row);\n const px = model.x.pixel(xv);\n const raw = readY(row);\n const value = toNumber(raw);\n const missing = raw == null || raw === '' || Number.isNaN(value);\n const vertex = vertexKey(seen, toKey(xv));\n\n if (stacked) {\n const key = toKey(xv);\n const totals = value >= 0 || missing ? positiveTotals : negativeTotals;\n const base = totals.get(key) ?? 0;\n const top = base + (missing ? 0 : value);\n totals.set(key, top);\n const y1 = missing ? NaN : model.y.pixel(top);\n points.push({\n x: px == null ? NaN : px,\n y0: model.y.pixel(base),\n y1,\n sortKey: px == null ? Number.POSITIVE_INFINITY : px,\n });\n if (model.emphasis?.match(row) && px != null && !Number.isNaN(y1))\n matchPoints.push({ x: px, y: y1 });\n } else {\n const y1 = missing ? NaN : model.y.pixel(value);\n points.push({\n x: px == null ? NaN : px,\n y0: model.y.baseline,\n y1,\n sortKey: px == null ? Number.POSITIVE_INFINITY : px,\n });\n if (model.emphasis?.match(row) && px != null && !Number.isNaN(y1))\n matchPoints.push({ x: px, y: y1 });\n }\n const last = points[points.length - 1];\n last.key = vertex;\n if (Number.isFinite(last.x) && Number.isFinite(last.y1) && Number.isFinite(last.y0))\n usableRows++;\n }\n points.sort((a, b) => a.sortKey - b.sortKey);\n const band: KeyedAreaPoint[] = points.map(({ x, y0, y1, key }) => ({ x, y0, y1, key }));\n const reduced = Number.isFinite(threshold)\n ? decimate(band, threshold, {\n getX: (p) => p.x,\n getY: (p) => p.y1,\n gap: () => ({ x: NaN, y0: NaN, y1: NaN }),\n })\n : band;\n const markers = areaMarkers(reduced);\n return {\n series,\n points: reduced,\n markers,\n alpha: mode === 'all' ? 1 : (model.emphasis?.dim ?? 1),\n mode,\n matchPoints,\n usableRows,\n };\n });\n}\n\n/** Hand-drawn path: hachure-filled bands with wobbly top edges (gap-aware). */\nfunction drawAreaSketch(\n ctx: CanvasRenderingContext2D,\n model: CartesianModel,\n bands: BandPoints[],\n pen: RoughPen,\n stacked: boolean,\n strokeWidth: number,\n markerR: number,\n markerSW: number,\n): void {\n for (const { series, points, alpha } of bands) {\n const prev = ctx.globalAlpha;\n if (alpha !== 1) ctx.globalAlpha = alpha;\n let run: AreaPoint[] = [];\n const flush = (): void => {\n if (run.length >= 2) {\n const top: Point[] = run.map((p) => ({ x: p.x, y: p.y1 }));\n const bottom: Point[] = run.map((p) => ({ x: p.x, y: p.y0 })).reverse();\n pen.polygon([...top, ...bottom], {\n fill: series.color,\n fillAlpha: stacked ? 0.85 : 0.5,\n });\n }\n run = [];\n };\n for (const p of points) {\n if (Number.isNaN(p.x) || Number.isNaN(p.y1)) flush();\n else run.push(p);\n }\n flush();\n if (alpha !== 1) ctx.globalAlpha = prev;\n }\n\n for (const { series, points, alpha } of bands) {\n const prev = ctx.globalAlpha;\n if (alpha !== 1) ctx.globalAlpha = alpha;\n pen.trendStroke(\n points.map((p) => ({ x: p.x, y: p.y1 })),\n { stroke: series.color, strokeWidth },\n );\n if (alpha !== 1) ctx.globalAlpha = prev;\n }\n\n for (const { series, markers, alpha } of bands) {\n ctx.globalAlpha = alpha;\n for (const point of markers) {\n pen.circle(point.x, point.y1, markerR, {\n fill: series.color,\n stroke: model.tokens.color.background,\n strokeWidth: markerSW,\n });\n }\n }\n\n for (const { series, mode, matchPoints } of bands) {\n if (mode !== 'partial') continue;\n ctx.globalAlpha = 1;\n for (const p of matchPoints) {\n pen.circle(p.x, p.y, markerR, {\n fill: series.color,\n stroke: model.tokens.color.background,\n strokeWidth: markerSW,\n });\n }\n }\n ctx.globalAlpha = 1;\n}\n\nfunction areaMetrics(model: CartesianModel, bands: BandPoints[]): AreaMetrics {\n const markerR = markerRadius(model.plot, maxBandLength(bands));\n return {\n strokeWidth: lineStrokeWidth(model.plot, Math.max(1.5, model.tokens.stroke.base)),\n markerR,\n markerSW: markerStroke(markerR),\n };\n}\n\nfunction recordAreaEvidence(\n surface: Surface,\n model: CartesianModel,\n bands: BandPoints[],\n stacked: boolean,\n geometry: AreaMetrics,\n): void {\n let represented = 0;\n let reduced = 0;\n for (const b of bands) {\n const runs = recordRuns(\n surface.evidence,\n b.points,\n b.series.color,\n (stacked ? 1 : 0.95) * b.alpha,\n model.plot,\n geometry.strokeWidth,\n true,\n undefined,\n b.alpha < 1,\n );\n represented += b.usableRows;\n reduced += Math.max(0, b.usableRows - runs.observations);\n for (const point of b.markers) {\n surface.evidence?.mark(\n 'point',\n point.x - geometry.markerR,\n point.y1 - geometry.markerR,\n geometry.markerR * 2,\n geometry.markerR * 2,\n b.series.color,\n b.alpha,\n model.plot,\n 1,\n undefined,\n b.alpha < 1,\n );\n }\n if (b.mode === 'partial')\n for (const p of b.matchPoints) {\n surface.evidence?.mark(\n 'point',\n p.x - geometry.markerR,\n p.y - geometry.markerR,\n geometry.markerR * 2,\n geometry.markerR * 2,\n b.series.color,\n 1,\n model.plot,\n );\n }\n }\n surface.evidence?.data(represented, 'rows', reduced);\n}\n\nfunction clipPlot(ctx: CanvasRenderingContext2D, model: CartesianModel): void {\n const { plot } = model;\n ctx.beginPath();\n ctx.rect(plot.x, plot.y, plot.width, plot.height);\n ctx.clip();\n}\n\nfunction drawAreaNormal(\n ctx: CanvasRenderingContext2D,\n model: CartesianModel,\n bands: BandPoints[],\n stacked: boolean,\n geometry: AreaMetrics,\n areaGen: ReturnType<typeof area>,\n lineGen: ReturnType<typeof line>,\n): void {\n const { plot, tokens } = model;\n // Gradient fills: overlapping bands fade to near-transparent at the baseline;\n // stacked bands stay mostly opaque with a subtle vertical sheen for depth.\n for (const { series, points, alpha } of bands) {\n const top = minFinite(\n points.map((p) => p.y1),\n plot.y,\n );\n const bottom = stacked\n ? maxFinite(\n points.map((p) => p.y0),\n model.y.baseline,\n )\n : model.y.baseline;\n ctx.beginPath();\n areaGen(points, ctx);\n ctx.globalAlpha = alpha;\n ctx.fillStyle = stacked\n ? verticalFill(ctx, series.color, top, bottom, 0.96, 0.74)\n : verticalFill(ctx, series.color, top, bottom, 0.3, 0.02);\n ctx.fill();\n ctx.globalAlpha = 1;\n }\n\n // Top edge strokes for crisp band separation.\n ctx.lineJoin = 'round';\n ctx.lineCap = 'round';\n ctx.lineWidth = geometry.strokeWidth;\n for (const { series, points, alpha } of bands) {\n ctx.beginPath();\n lineGen(\n points.map((p) => ({ x: p.x, y: p.y1 })),\n ctx,\n );\n ctx.strokeStyle = series.color;\n ctx.globalAlpha = (stacked ? 1 : 0.95) * alpha;\n ctx.stroke();\n ctx.globalAlpha = 1;\n }\n\n drawSeriesMarkers(ctx, tokens, bands, geometry, (point) => ({ x: point.x, y: point.y1 }), false, false);\n drawMatchedPointMarkers(ctx, tokens, bands, geometry);\n}\n\n/** Resolve every band's pixel vertices and adaptive metrics without drawing. */\nexport function layoutArea(model: CartesianModel): AreaGeometry {\n const stacked = model.stacked;\n // Painter's order: for stacked charts the topmost band must paint last so its\n // edge sits above neighbours; bottom-up matches the resolved series order.\n const bands = buildBands(model, stacked);\n // Adaptive: top-edge weight grows with plot size; markers scale with size and\n // density so overlapping areas read cleanly at any extent.\n return { kind: 'area', bands, metrics: areaMetrics(model, bands), stacked, baseline: model.y.baseline };\n}\n\n/** Paint resolved area geometry onto the marks layer, clipped to the plot. */\nexport function paintArea(surface: Surface, model: CartesianModel, geometry: AreaGeometry): void {\n const ctx = surface.marks.ctx;\n const spec = model.spec as AreaSpec;\n const curve = resolveCurve(spec.curve);\n const areaGen = area({ curve });\n const lineGen = line({ curve });\n const { bands, stacked, metrics } = geometry;\n recordAreaEvidence(surface, model, bands, stacked, metrics);\n\n ctx.save();\n clipPlot(ctx, model);\n\n if (model.sketch) {\n drawAreaSketch(\n ctx,\n model,\n bands,\n new RoughPen(ctx, model.sketch),\n stacked,\n metrics.strokeWidth,\n metrics.markerR,\n metrics.markerSW,\n );\n ctx.restore();\n return;\n }\n\n drawAreaNormal(ctx, model, bands, stacked, metrics, areaGen, lineGen);\n ctx.restore();\n}\n\nexport function drawArea(surface: Surface, model: CartesianModel): void {\n surface.evidence?.begin('rows');\n const geometry = layoutArea(model);\n model.geometry = geometry;\n paintArea(surface, model, geometry);\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }