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,57 +1,47 @@
1
1
  import { paintCanvasText } from "../../render/overlayText.js";
2
- import { fontString, measureText, ellipsize } from "../../render/text.js";
2
+ import { ellipsize, measureText } from "../../render/text.js";
3
3
  import { RoughPen } from "../../rough/index.js";
4
4
  import { roundedRect } from "../../shape/index.js";
5
5
  import { recordCanvasLabel } from "../../render/labelLedger.js";
6
- import { densityMetrics, normalizedHeaderRows, sumWidths, computeFittedWidths, MIN_COL_WIDTH, FILL_EPS, formatDisplayValue } from "./types.js";
7
- import { canvasRowBackground, negativeTextColor, resolveCanvasConditional, paintDataBar } from "./conditional.js";
6
+ import {
7
+ BAR_GAP,
8
+ BAR_LANE_ALPHA,
9
+ BAR_OVERLAY_ALPHA,
10
+ barFill,
11
+ barTrack,
12
+ buildColumnFormatter,
13
+ negativeTextColor
14
+ } from "./conditional.js";
15
+ import { layoutColumns } from "./layout.js";
16
+ import { sparklineGeometry } from "./sparkline.js";
17
+ import { fontFor, resolveTableStyle, rowBackground } from "./style.js";
18
+ import {
19
+ cellText,
20
+ defaultRowInfo,
21
+ normalizedHeaderRows,
22
+ sumWidths
23
+ } from "./types.js";
24
+ const DEFAULT_FORMAT_KINDS = ["leaf"];
8
25
  function paintTableCanvas(opts) {
9
26
  const { ctx, rect, tokens } = opts;
10
- const metrics = densityMetrics(opts.density);
27
+ const style = resolveTableStyle(tokens, opts.density, opts.gridlines);
28
+ const m = style.metrics;
29
+ const formatters = opts.formatters ?? opts.columns.map((column, i) => buildColumnFormatter(column.conditionalFormat, opts.conditionalDomains?.[i] ?? null, tokens, style.color.background));
11
30
  const available = Math.max(0, rect.width - 2);
12
- const minimum = Math.min(MIN_COL_WIDTH, Math.max(48, tokens.font.size.small * 3 + metrics.paddingX * 2));
13
- let widths = available > FILL_EPS ? computeFittedWidths(opts.columns, available, minimum) : [];
14
- if (sumWidths(widths) > available + FILL_EPS) {
15
- let used = 0;
16
- let visible = 0;
17
- for (const width of widths) {
18
- const needed = Math.min(width, minimum);
19
- if (visible > 0 && used + needed > available) break;
20
- used += needed;
21
- visible++;
22
- }
23
- widths = computeFittedWidths(opts.columns.slice(0, visible), available, Math.min(minimum, available));
24
- }
31
+ const layout = layoutColumns(opts.measure ? { ...opts, ...opts.measure } : opts, style, formatters, available, "static");
32
+ const widths = layout.widths.slice(0, layout.visibleCount);
25
33
  const hiddenColumns = opts.columns.length - widths.length;
26
34
  opts.widths = widths;
27
- const pen = opts.sketch ? new RoughPen(ctx, opts.sketch) : null;
28
- const w = Math.max(0, rect.width);
29
- const h = Math.max(0, rect.height);
30
- ctx.save();
31
- ctx.beginPath();
32
- if (pen) {
33
- ctx.rect(rect.x, rect.y, w, h);
34
- ctx.fillStyle = tokens.color.background;
35
- ctx.fill();
36
- } else {
37
- roundedRect(ctx, rect.x, rect.y, w, h, tokens.radius.sm);
38
- ctx.fillStyle = tokens.color.background;
39
- ctx.fill();
40
- ctx.lineWidth = 1;
41
- ctx.strokeStyle = tokens.color.border;
42
- ctx.stroke();
43
- }
44
- ctx.clip();
45
35
  const headerRows = normalizedHeaderRows(opts);
46
- const headerHeight = headerRows.length * metrics.headerHeight;
47
- const footerHeight = opts.footerRow ? metrics.rowHeight : 0;
48
- const bodyTop = rect.y + headerHeight;
49
- const bodyBottom = rect.y + rect.height - footerHeight;
50
- const bodyHeight = Math.max(0, bodyBottom - bodyTop);
51
- const rowCapacity = Math.max(0, Math.floor(bodyHeight / metrics.rowHeight));
52
- const clipped = rowCapacity < opts.rowCount || hiddenColumns > 0;
53
- const cueReserve = clipped && opts.clippedCue !== false && rowCapacity > 1 ? metrics.rowHeight : 0;
54
- const rowsToDraw = Math.max(0, Math.min(opts.rowCount, rowCapacity - (cueReserve > 0 ? 1 : 0)));
36
+ const headerHeight = headerRows.length * m.headerHeight;
37
+ const footerHeight = opts.footerRow ? m.rowHeight : 0;
38
+ const capacity = Math.max(0, Math.floor((rect.height - 2 - headerHeight - footerHeight) / m.rowHeight));
39
+ const clipped = capacity < opts.rowCount || hiddenColumns > 0;
40
+ const cue = clipped && opts.clippedCue !== false && capacity > 1;
41
+ const rowsToDraw = Math.max(0, Math.min(opts.rowCount, capacity - (cue ? 1 : 0)));
42
+ const bodyRows = rowsToDraw + (cue ? 1 : 0);
43
+ const frameHeight = Math.max(0, Math.min(rect.height, headerHeight + bodyRows * m.rowHeight + footerHeight + 2));
44
+ const frameWidth = Math.max(0, Math.min(rect.width, sumWidths(widths) + 2));
55
45
  opts.labels?.omit({
56
46
  role: "data-label",
57
47
  reason: "static-viewport",
@@ -63,252 +53,371 @@ function paintTableCanvas(opts) {
63
53
  else if (opts.dataRepresentation === "aggregate") {
64
54
  opts.evidence?.data(opts.sourceRepresentedRows ?? opts.evidence.snapshot().data.inputRows, "aggregate");
65
55
  }
66
- paintHeaderCanvas(opts, widths, headerRows, metrics, pen);
67
- for (let rowIndex = 0; rowIndex < rowsToDraw; rowIndex += 1) {
68
- paintBodyRowCanvas(opts, widths, rowIndex, bodyTop + rowIndex * metrics.rowHeight, metrics, pen);
69
- }
70
- if (cueReserve > 0) {
71
- paintClippedCueCanvas(opts, bodyTop + rowsToDraw * metrics.rowHeight, metrics, opts.rowCount - rowsToDraw, hiddenColumns);
56
+ const pen = opts.sketch ? new RoughPen(ctx, opts.sketch) : null;
57
+ const f = { o: opts, ctx, style, widths, valueWidths: layout.valueWidths, formatters, pen, x0: rect.x + 1, width: frameWidth };
58
+ ctx.save();
59
+ ctx.beginPath();
60
+ if (pen) ctx.rect(rect.x, rect.y, frameWidth, frameHeight);
61
+ else roundedRect(ctx, rect.x, rect.y, frameWidth, frameHeight, style.radius);
62
+ ctx.fillStyle = style.color.background;
63
+ ctx.fill();
64
+ ctx.clip();
65
+ paintHeader(f, headerRows);
66
+ const info = opts.rowInfo ?? defaultRowInfo;
67
+ const bodyTop = rect.y + 1 + headerHeight;
68
+ for (let row = 0; row < rowsToDraw; row++) paintRow(f, row, info(row), bodyTop + row * m.rowHeight);
69
+ if (cue) {
70
+ paintCue(f, bodyTop + rowsToDraw * m.rowHeight, opts.rowCount - rowsToDraw, hiddenColumns);
72
71
  } else if (clipped && opts.clippedCue !== false) {
73
- opts.labels?.omit({
74
- role: "other",
75
- reason: "space",
76
- required: false,
77
- example: "Additional rows or columns",
78
- path: "/dimensions"
79
- });
80
- }
81
- if (opts.footerRow) {
82
- paintFooterCanvas(opts, widths, rect.y + rect.height - metrics.rowHeight, metrics, pen);
72
+ opts.labels?.omit({ role: "other", reason: "space", required: false, example: "Additional rows or columns", path: "/dimensions" });
83
73
  }
74
+ if (opts.footerRow) paintFooter(f, bodyTop + bodyRows * m.rowHeight);
75
+ const rulesBottom = bodyTop + rowsToDraw * m.rowHeight;
76
+ paintVerticalRules(f, bodyTop - headerHeight, rulesBottom, headerRows.length);
77
+ if (opts.footerRow) paintVerticalRules(f, bodyTop + bodyRows * m.rowHeight, bodyTop + bodyRows * m.rowHeight + footerHeight, 0);
84
78
  ctx.restore();
85
- if (pen) pen.rect(rect.x, rect.y, w, h, { stroke: tokens.color.border });
79
+ if (pen) pen.rect(rect.x, rect.y, frameWidth, frameHeight, { stroke: tokens.color.border });
80
+ else {
81
+ ctx.save();
82
+ ctx.beginPath();
83
+ roundedRect(ctx, rect.x + 0.5, rect.y + 0.5, Math.max(0, frameWidth - 1), Math.max(0, frameHeight - 1), style.radius);
84
+ ctx.lineWidth = 1;
85
+ ctx.strokeStyle = tokens.color.border;
86
+ ctx.stroke();
87
+ ctx.restore();
88
+ }
89
+ }
90
+ function colX(f, col) {
91
+ return f.x0 + sumWidths(f.widths, 0, col);
86
92
  }
87
- function paintHeaderCanvas(opts, widths, rows, metrics, pen) {
93
+ function paintHeader(f, rows) {
94
+ const { o, style } = f;
95
+ const m = style.metrics;
96
+ const top = o.rect.y + 1;
97
+ fillRect(f, f.x0, top, f.width - 2, rows.length * m.headerHeight, style.color.headerBg);
88
98
  rows.forEach((row, rowIndex) => {
89
99
  let cursor = 0;
90
100
  for (const cell of row) {
91
101
  const start = cell.colIndex ?? cursor;
92
- const colSpan = Math.max(1, cell.colSpan ?? 1);
93
- const rowSpan = Math.max(1, cell.rowSpan ?? 1);
94
- if (start >= widths.length) {
95
- opts.labels?.omit({
96
- role: "axis-label",
97
- reason: "static-viewport",
98
- required: true,
99
- example: cell.title,
100
- path: "/columns"
101
- });
102
- cursor = start + colSpan;
102
+ const span = Math.max(1, cell.colSpan ?? 1);
103
+ cursor = start + span;
104
+ if (start >= f.widths.length) {
105
+ o.labels?.omit({ role: "axis-label", reason: "static-viewport", required: true, example: cell.title, path: "/columns" });
103
106
  continue;
104
107
  }
105
- const x = opts.rect.x + sumWidths(widths.slice(0, start));
106
- const y = opts.rect.y + rowIndex * metrics.headerHeight;
107
- const w = sumWidths(widths.slice(start, start + colSpan));
108
- const h = metrics.headerHeight * rowSpan;
109
- paintCellBox(opts.ctx, x, y, w, h, opts.tokens.color.surface, opts.tokens.color.border, false, pen);
110
- paintCellText(opts, {
111
- x,
108
+ const x = colX(f, start);
109
+ const w = sumWidths(f.widths, start, Math.min(f.widths.length, start + span));
110
+ const y = top + rowIndex * m.headerHeight;
111
+ const h = m.headerHeight * Math.max(1, cell.rowSpan ?? 1);
112
+ const band = cell.colIndex == null && span > 1;
113
+ const sorted = cell.colIndex != null && o.sortState?.col === cell.colIndex;
114
+ const arrow = sorted ? o.sortState?.dir === "desc" ? "\u2193" : "\u2191" : "";
115
+ const align = cell.align ?? "left";
116
+ const arrowRoom = arrow ? 14 : 0;
117
+ paintText(f, {
118
+ x: align === "right" ? x + arrowRoom : x,
112
119
  y,
113
- width: w,
120
+ width: w - arrowRoom,
114
121
  height: h,
115
122
  text: cell.title,
116
- align: cell.align ?? "left",
117
- color: opts.tokens.color.text,
118
- weight: opts.tokens.font.weight.bold,
119
- paddingX: metrics.paddingX,
120
- background: opts.tokens.color.surface,
121
- role: "axis-label"
123
+ align,
124
+ color: sorted ? style.color.text : style.color.headerText,
125
+ weight: style.weight.bold,
126
+ background: style.color.headerBg,
127
+ role: "axis-label",
128
+ padLeft: m.paddingX,
129
+ padRight: m.paddingX
122
130
  });
123
- cursor = start + colSpan;
131
+ if (arrow) {
132
+ const font = fontFor(style, style.weight.bold);
133
+ const label = Math.min(measureText(cell.title, font).width, w - m.paddingX * 2 - arrowRoom);
134
+ const ax = align === "right" ? x + w - m.paddingX - label - 12 : align === "center" ? x + (w + label) / 2 + 3 : x + m.paddingX + label + 3;
135
+ paintCanvasText(f.ctx, { x: ax, y: y + h / 2, text: arrow, font, color: style.color.accent, size: m.fontSize, baseline: "middle" });
136
+ }
137
+ hRule(f, x, x + w, y + h, band ? style.color.rule : style.color.ruleStrong);
138
+ if (start > 0 && o.columns[start]?.groupStart) vRule(f, x, y, y + h, style.color.rule);
124
139
  }
125
140
  });
126
141
  }
127
- function paintBodyRowCanvas(opts, widths, rowIndex, y, metrics, pen) {
128
- const cls = opts.rowClass?.(rowIndex) ?? "normal";
129
- let x = opts.rect.x;
130
- for (let colIndex = 0; colIndex < widths.length; colIndex += 1) {
131
- const column = opts.columns[colIndex];
132
- const width = widths[colIndex] ?? 0;
133
- const cell = opts.getCell(rowIndex, colIndex);
134
- const baseBg = canvasRowBackground(opts, rowIndex, cls);
135
- const conditional = resolveCanvasConditional(opts, column, colIndex, cell, baseBg);
136
- const bg = conditional.background ?? baseBg;
137
- paintCellBox(opts.ctx, x, y, width, metrics.rowHeight, bg, opts.tokens.color.border, false, pen);
138
- if (conditional.bar) paintDataBar(opts, x, y, width, metrics.rowHeight, conditional.bar, pen);
139
- const indent = opts.cellIndent?.(rowIndex, colIndex) ?? 0;
140
- const text = conditional.showValue === false ? "" : formatDisplayValue(cell.value, column);
141
- const color = negativeTextColor(cell.value, column, conditional.color ?? opts.tokens.color.text);
142
- if (opts.dataRepresentation !== "aggregate" || colIndex >= (opts.rowHeaderSpan ?? 0) && cell.raw != null && Number.isFinite(cell.raw)) {
143
- opts.evidence?.mark("cell", x, y, width, metrics.rowHeight, color, 1, opts.rect, 1, bg);
142
+ function paintRow(f, row, info, y) {
143
+ const { o, style } = f;
144
+ const m = style.metrics;
145
+ const stripe = o.striped === true && row % 2 === 1 && info.kind === "leaf";
146
+ const rowBg = o.highlighted?.(row) ? style.color.highlight : rowBackground(style, info.kind, stripe);
147
+ fillRect(f, f.x0, y, f.width - 2, m.rowHeight, rowBg);
148
+ const kinds = o.formatKinds ?? DEFAULT_FORMAT_KINDS;
149
+ const rowFormatters = o.rowFormatters ? o.rowFormatters(row) : kinds.includes(info.kind) ? f.formatters : null;
150
+ for (let col = 0; col < f.widths.length; col++) {
151
+ const cell = o.getCell(row, col);
152
+ const formatter = rowFormatters?.[col] ?? null;
153
+ const paint = formatter ? formatter(cell) : null;
154
+ paintCell(f, row, col, info, cell, paint, y, rowBg);
155
+ }
156
+ if (info.kind === "subtotal") hRule(f, f.x0, f.x0 + f.width - 2, y, style.color.rule);
157
+ if (style.gridlines === "horizontal" || style.gridlines === "both") hRule(f, f.x0, f.x0 + f.width - 2, y + m.rowHeight, style.color.rule);
158
+ }
159
+ function paintCell(f, row, col, info, cell, paint, y, rowBg) {
160
+ const { o, style } = f;
161
+ const m = style.metrics;
162
+ const column = o.columns[col];
163
+ const x = colX(f, col);
164
+ const w = f.widths[col];
165
+ const bg = paint?.background ?? rowBg;
166
+ if (paint?.background) fillRect(f, x, y, w, m.rowHeight, paint.background);
167
+ const strong = info.kind !== "leaf";
168
+ const weight = paint?.weight ?? (strong || column.total ? style.weight.bold : style.weight.normal);
169
+ const color = paint?.color ?? negativeTextColor(cell.value, column, style.color.text, style.color.negative);
170
+ const text = paint?.showValue === false ? "" : cellText(cell, column);
171
+ if (countsAsMark(o, col, cell)) o.evidence?.mark("cell", x, y, w, m.rowHeight, color, 1, o.rect, 1, bg);
172
+ if (column.rowHeader) {
173
+ const indent = info.depth * m.indent;
174
+ const toggleX = x + m.paddingX + indent;
175
+ if (info.expandable) paintChevron(f, toggleX, y + m.rowHeight / 2, info.expanded !== false);
176
+ const hierarchy = info.expandable || hasHierarchy(o);
177
+ const left = m.paddingX + indent + (hierarchy ? m.toggle + 4 : 0);
178
+ paintText(f, { x, y, width: w, height: m.rowHeight, text, align: "left", color, weight, background: bg, padLeft: left, padRight: m.paddingX });
179
+ return;
180
+ }
181
+ if (column.sparkline && Array.isArray(cell.value)) {
182
+ paintSparkline(f, cell.value, column.sparkline, x + m.paddingX, y + 6, Math.max(0, w - m.paddingX * 2), m.rowHeight - 12);
183
+ return;
184
+ }
185
+ if (paint?.bar) {
186
+ const track = barTrack(w, m.paddingX, f.valueWidths[col] ?? 0, column.align, paint.showValue !== false);
187
+ paintBar(f, x + track.left, y, track.width, paint, track.overlay);
188
+ }
189
+ const iconFont = fontFor(style, style.weight.bold);
190
+ const iconW = paint?.icon ? measureText(paint.icon, iconFont).width : 0;
191
+ const gap = paint?.icon ? 6 : 0;
192
+ const font = fontFor(style, weight);
193
+ const budget = Math.max(0, w - m.paddingX * 2 - iconW - gap);
194
+ const shown = ellipsize(text, budget, font);
195
+ const textW = measureText(shown, font).width;
196
+ const group = textW + iconW + gap;
197
+ const start = column.align === "right" ? x + w - m.paddingX - group : column.align === "center" ? x + (w - group) / 2 : x + m.paddingX;
198
+ const iconFirst = paint?.icon && paint.iconPosition !== "right";
199
+ const textX = iconFirst ? start + iconW + gap : start;
200
+ const midY = y + m.rowHeight / 2;
201
+ if (paint?.icon) {
202
+ const iconX = iconFirst ? start : start + textW + gap;
203
+ const command2 = { x: iconX, y: midY, text: paint.icon, font: iconFont, color: paint.iconColor ?? color, size: m.fontSize, baseline: "middle" };
204
+ recordCanvasLabel(o.labels, command2, { background: bg, clip: o.rect });
205
+ paintCanvasText(f.ctx, command2);
206
+ }
207
+ if (!text) return;
208
+ const command = { x: textX, y: midY, text: shown, font, color, size: m.fontSize, baseline: "middle" };
209
+ recordCanvasLabel(o.labels, command, { fullText: text, budget, background: bg, clip: o.rect });
210
+ if (!shown) o.labels?.omit({ role: "data-label", reason: "space", required: false });
211
+ else paintCanvasText(f.ctx, command);
212
+ }
213
+ function hasHierarchy(o) {
214
+ const source = o.measure ?? o;
215
+ const info = source.rowInfo;
216
+ if (!info) return false;
217
+ for (let i = 0; i < Math.min(source.rowCount, 200); i++) if (info(i).expandable) return true;
218
+ return false;
219
+ }
220
+ function paintBar(f, left, y, track, paint, overlay) {
221
+ const { ctx, style } = f;
222
+ const m = style.metrics;
223
+ const bar = paint.bar;
224
+ const bx = left + bar.from * track;
225
+ const bw = Math.max(0, (bar.to - bar.from) * track);
226
+ const by = y + (m.rowHeight - m.barHeight) / 2;
227
+ const fill = barFill(bar.color, overlay ? BAR_OVERLAY_ALPHA : BAR_LANE_ALPHA);
228
+ if (bar.zero !== void 0) {
229
+ const zx = Math.round(left + bar.zero * track) + 0.5;
230
+ ctx.save();
231
+ ctx.strokeStyle = style.color.ruleStrong;
232
+ ctx.lineWidth = 1;
233
+ ctx.beginPath();
234
+ ctx.moveTo(zx, by - 2);
235
+ ctx.lineTo(zx, by + m.barHeight + 2);
236
+ ctx.stroke();
237
+ ctx.restore();
238
+ }
239
+ if (bw <= 0) return;
240
+ if (f.pen) {
241
+ f.pen.rect(bx, by, bw, m.barHeight, { stroke: fill, fill, fillAlpha: 0.9, strokeAlpha: 0.9 });
242
+ return;
243
+ }
244
+ ctx.save();
245
+ ctx.beginPath();
246
+ roundedRect(ctx, bx, by, bw, m.barHeight, Math.min(2, bw / 2));
247
+ ctx.fillStyle = fill;
248
+ ctx.fill();
249
+ ctx.restore();
250
+ }
251
+ function paintSparkline(f, values, spark, x, y, w, h) {
252
+ if (w <= 2 || h <= 2) return;
253
+ const shape = sparklineGeometry(values, spark, w, h);
254
+ if (!shape.points.length) return;
255
+ const ctx = f.ctx;
256
+ const color = spark.color ?? f.o.tokens.color.accent;
257
+ ctx.save();
258
+ ctx.translate(x, y);
259
+ if (spark.type === "bar") {
260
+ ctx.fillStyle = barFill(color, 0.85);
261
+ for (const p of shape.points) ctx.fillRect(p.x - shape.barWidth / 2, Math.min(p.y, p.base), shape.barWidth, Math.max(0.5, Math.abs(p.base - p.y)));
262
+ } else {
263
+ if (spark.type === "area") {
264
+ ctx.fillStyle = barFill(color, 0.18);
265
+ for (const run of shape.runs) {
266
+ if (run.length < 2) continue;
267
+ ctx.beginPath();
268
+ ctx.moveTo(run[0].x, run[0].base);
269
+ for (const p of run) ctx.lineTo(p.x, p.y);
270
+ ctx.lineTo(run[run.length - 1].x, run[run.length - 1].base);
271
+ ctx.closePath();
272
+ ctx.fill();
273
+ }
144
274
  }
145
- const weight = conditional.weight ?? (cls === "normal" ? opts.tokens.font.weight.normal : opts.tokens.font.weight.bold);
146
- paintCellValueWithIcon(opts, {
147
- x,
148
- y,
149
- width,
150
- height: metrics.rowHeight,
151
- text,
152
- align: column.align,
153
- color,
154
- weight,
155
- paddingX: metrics.paddingX + indent,
156
- icon: conditional.icon,
157
- iconColor: conditional.iconColor,
158
- iconPosition: conditional.iconPosition,
159
- background: bg
160
- });
161
- x += width;
275
+ ctx.strokeStyle = color;
276
+ ctx.lineWidth = 1.5;
277
+ ctx.lineJoin = "round";
278
+ ctx.lineCap = "round";
279
+ for (const run of shape.runs) {
280
+ ctx.beginPath();
281
+ run.forEach((p, i) => i ? ctx.lineTo(p.x, p.y) : ctx.moveTo(p.x, p.y));
282
+ if (run.length === 1) ctx.lineTo(run[0].x + 0.01, run[0].y);
283
+ ctx.stroke();
284
+ }
285
+ }
286
+ ctx.restore();
287
+ f.o.evidence?.segments(shape.points.length);
288
+ }
289
+ function paintChevron(f, x, cy, expanded) {
290
+ const { ctx, style } = f;
291
+ const box = style.metrics.toggle;
292
+ const cx = x + box / 2;
293
+ ctx.save();
294
+ ctx.strokeStyle = style.color.textMuted;
295
+ ctx.lineWidth = 1.6;
296
+ ctx.lineCap = "round";
297
+ ctx.lineJoin = "round";
298
+ ctx.beginPath();
299
+ if (expanded) {
300
+ ctx.moveTo(cx - 3, cy - 1.5);
301
+ ctx.lineTo(cx, cy + 1.5);
302
+ ctx.lineTo(cx + 3, cy - 1.5);
303
+ } else {
304
+ ctx.moveTo(cx - 1.5, cy - 3);
305
+ ctx.lineTo(cx + 1.5, cy);
306
+ ctx.lineTo(cx - 1.5, cy + 3);
162
307
  }
308
+ ctx.stroke();
309
+ ctx.restore();
163
310
  }
164
- function paintFooterCanvas(opts, widths, y, metrics, pen) {
165
- let x = opts.rect.x;
166
- for (let colIndex = 0; colIndex < widths.length; colIndex += 1) {
167
- const column = opts.columns[colIndex];
168
- const width = widths[colIndex] ?? 0;
169
- const cell = opts.footerRow?.cells[colIndex] ?? { value: null, raw: null };
170
- paintCellBox(opts.ctx, x, y, width, metrics.rowHeight, opts.tokens.color.surface, opts.tokens.color.border, true, pen);
171
- paintCellText(opts, {
172
- x,
311
+ function paintFooter(f, y) {
312
+ const { o, style } = f;
313
+ const m = style.metrics;
314
+ const kind = o.footerRow?.kind === "grandtotal" ? "grandtotal" : "subtotal";
315
+ fillRect(f, f.x0, y, f.width - 2, m.rowHeight, style.color.totalBg);
316
+ hRule(f, f.x0, f.x0 + f.width - 2, y, style.color.ruleStrong);
317
+ for (let col = 0; col < f.widths.length; col++) {
318
+ const cell = o.footerRow?.cells[col] ?? { value: null, raw: null };
319
+ const info = { kind, depth: 0 };
320
+ if (o.dataRepresentation === "aggregate" || o.columns[col]?.rowHeader) {
321
+ paintCell(f, -1, col, info, cell, null, y, style.color.totalBg);
322
+ continue;
323
+ }
324
+ const column = o.columns[col];
325
+ const color = negativeTextColor(cell.value, column, style.color.text, style.color.negative);
326
+ paintText(f, {
327
+ x: colX(f, col),
173
328
  y,
174
- width,
175
- height: metrics.rowHeight,
176
- text: cell.label ? String(cell.value ?? "") : formatDisplayValue(cell.value, column),
329
+ width: f.widths[col],
330
+ height: m.rowHeight,
331
+ text: cellText(cell, column),
177
332
  align: column.align,
178
- color: negativeTextColor(cell.value, column, opts.tokens.color.text),
179
- weight: opts.tokens.font.weight.bold,
180
- paddingX: metrics.paddingX
333
+ color,
334
+ weight: style.weight.bold,
335
+ background: style.color.totalBg,
336
+ padLeft: m.paddingX,
337
+ padRight: m.paddingX
181
338
  });
182
- x += width;
183
339
  }
184
340
  }
185
- function paintClippedCueCanvas(opts, y, metrics, remaining, hiddenColumns = 0) {
186
- paintCellBox(opts.ctx, opts.rect.x, y, opts.rect.width, metrics.rowHeight, opts.tokens.color.background, opts.tokens.color.border);
187
- paintCellText(opts, {
188
- x: opts.rect.x,
341
+ function paintCue(f, y, remaining, hiddenColumns) {
342
+ const { style } = f;
343
+ const m = style.metrics;
344
+ fillRect(f, f.x0, y, f.width - 2, m.rowHeight, style.color.background);
345
+ paintText(f, {
346
+ x: f.x0,
189
347
  y,
190
- width: opts.rect.width,
191
- height: metrics.rowHeight,
348
+ width: f.width - 2,
349
+ height: m.rowHeight,
192
350
  text: hiddenColumns ? `\u2026${remaining ? `${remaining} more rows \xB7 ` : ""}${hiddenColumns} more columns` : `\u2026${remaining} more`,
193
351
  align: "center",
194
- color: opts.tokens.color.textMuted,
195
- weight: opts.tokens.font.weight.medium,
196
- paddingX: metrics.paddingX
352
+ color: style.color.textMuted,
353
+ weight: style.weight.medium,
354
+ background: style.color.background,
355
+ padLeft: m.paddingX,
356
+ padRight: m.paddingX
197
357
  });
198
358
  }
199
- function paintCellBox(ctx, x, y, width, height, background, border, topBorder = false, pen) {
200
- ctx.save();
201
- ctx.fillStyle = background;
202
- ctx.fillRect(x, y, width, height);
203
- if (pen) {
204
- pen.polyline(
205
- [
206
- { x: x + width, y },
207
- { x: x + width, y: y + height },
208
- { x, y: y + height }
209
- ],
210
- { stroke: border, strokeWidth: 1 }
211
- );
212
- if (topBorder) {
213
- pen.polyline([{ x, y }, { x: x + width, y }], { stroke: border, strokeWidth: 1 });
214
- }
215
- ctx.restore();
216
- return;
359
+ function paintVerticalRules(f, top, bottom, headerRowCount) {
360
+ const { o, style } = f;
361
+ const all = style.gridlines === "vertical" || style.gridlines === "both";
362
+ const bodyTop = top + headerRowCount * style.metrics.headerHeight;
363
+ for (let col = 1; col < f.widths.length; col++) {
364
+ const x = colX(f, col);
365
+ if (all) vRule(f, x, top, bottom, style.color.rule);
366
+ else if (o.columns[col]?.groupStart) vRule(f, x, bodyTop, bottom, style.color.rule);
367
+ if (col === (o.frozenColumns ?? 0) && col > 0 && !all) vRule(f, x, bodyTop, bottom, style.color.ruleStrong);
217
368
  }
218
- ctx.strokeStyle = border;
219
- ctx.lineWidth = 1;
220
- ctx.beginPath();
221
- ctx.moveTo(x + width, y);
222
- ctx.lineTo(x + width, y + height);
223
- ctx.moveTo(x, y + height);
224
- ctx.lineTo(x + width, y + height);
225
- if (topBorder) {
226
- ctx.moveTo(x, y);
227
- ctx.lineTo(x + width, y);
369
+ }
370
+ function fillRect(f, x, y, w, h, color) {
371
+ f.ctx.fillStyle = color;
372
+ f.ctx.fillRect(x, y, w, h);
373
+ }
374
+ function hRule(f, x1, x2, y, color) {
375
+ if (f.pen) {
376
+ f.pen.polyline([{ x: x1, y }, { x: x2, y }], { stroke: f.o.tokens.color.border, strokeWidth: 1 });
377
+ return;
228
378
  }
229
- ctx.stroke();
230
- ctx.restore();
379
+ const yy = Math.round(y) - 0.5;
380
+ f.ctx.save();
381
+ f.ctx.strokeStyle = color;
382
+ f.ctx.lineWidth = 1;
383
+ f.ctx.beginPath();
384
+ f.ctx.moveTo(x1, yy);
385
+ f.ctx.lineTo(x2, yy);
386
+ f.ctx.stroke();
387
+ f.ctx.restore();
231
388
  }
232
- function paintCellValueWithIcon(opts, input) {
233
- const font = fontString(opts.tokens.font.size.small, opts.tokens.font.family, input.weight);
234
- const gap = input.icon ? 6 : 0;
235
- const iconFont = fontString(opts.tokens.font.size.small, opts.tokens.font.family, opts.tokens.font.weight.bold);
236
- const iconW = input.icon ? measureText(input.icon, iconFont).width : 0;
237
- const textMax = Math.max(0, input.width - input.paddingX * 2 - iconW - gap);
238
- const text = ellipsize(input.text, textMax, font);
239
- const textW = measureText(text, font).width;
240
- const groupW = textW + iconW + gap;
241
- let start = input.x + input.paddingX;
242
- if (input.align === "right") start = input.x + input.width - input.paddingX - groupW;
243
- else if (input.align === "center") start = input.x + (input.width - groupW) / 2;
244
- const midY = input.y + input.height / 2;
245
- const iconFirst = input.icon && input.iconPosition !== "right";
246
- const iconX = iconFirst ? start : start + textW + gap;
247
- const textX = iconFirst ? start + iconW + gap : start;
248
- recordCanvasLabel(opts.labels, {
249
- x: textX,
250
- y: midY,
251
- text,
252
- font,
253
- color: input.color,
254
- size: opts.tokens.font.size.small,
255
- baseline: "middle"
256
- }, { fullText: input.text, budget: textMax, background: input.background, clip: opts.rect });
257
- if (!text && input.text) opts.labels?.omit({ role: "data-label", reason: "space", required: false });
258
- if (input.icon) {
259
- recordCanvasLabel(opts.labels, {
260
- x: iconX,
261
- y: midY,
262
- text: input.icon,
263
- font: iconFont,
264
- color: input.iconColor ?? input.color,
265
- size: opts.tokens.font.size.small,
266
- baseline: "middle"
267
- }, { background: input.background, clip: opts.rect });
268
- paintCanvasText(opts.ctx, {
269
- x: iconX,
270
- y: midY,
271
- text: input.icon,
272
- font: iconFont,
273
- color: input.iconColor ?? input.color,
274
- size: opts.tokens.font.size.small,
275
- baseline: "middle"
276
- });
389
+ function vRule(f, x, y1, y2, color) {
390
+ if (f.pen) {
391
+ f.pen.polyline([{ x, y: y1 }, { x, y: y2 }], { stroke: f.o.tokens.color.border, strokeWidth: 1 });
392
+ return;
277
393
  }
278
- paintRawCellText(opts, textX, midY, text, font, input.color, opts.tokens.font.size.small);
394
+ const xx = Math.round(x) + 0.5;
395
+ f.ctx.save();
396
+ f.ctx.strokeStyle = color;
397
+ f.ctx.lineWidth = 1;
398
+ f.ctx.beginPath();
399
+ f.ctx.moveTo(xx, y1);
400
+ f.ctx.lineTo(xx, y2);
401
+ f.ctx.stroke();
402
+ f.ctx.restore();
279
403
  }
280
- function paintCellText(opts, input) {
281
- const font = fontString(opts.tokens.font.size.small, opts.tokens.font.family, input.weight);
282
- const maxWidth = Math.max(0, input.width - input.paddingX * 2);
283
- const text = ellipsize(input.text, maxWidth, font);
284
- const x = input.align === "right" ? input.x + input.width - input.paddingX : input.align === "center" ? input.x + input.width / 2 : input.x + input.paddingX;
285
- recordCanvasLabel(opts.labels, {
286
- x,
287
- y: input.y + input.height / 2,
288
- text,
289
- font,
290
- color: input.color,
291
- size: opts.tokens.font.size.small,
292
- align: input.align,
293
- baseline: "middle"
294
- }, { fullText: input.text, budget: maxWidth, background: input.background, role: input.role, clip: opts.rect });
295
- if (!text && input.text) opts.labels?.omit({ role: input.role ?? "data-label", reason: "space", required: input.role === "axis-label" });
296
- paintRawCellText(opts, x, input.y + input.height / 2, text, font, input.color, opts.tokens.font.size.small, input.align);
404
+ function paintText(f, input) {
405
+ const { o, style } = f;
406
+ const font = fontFor(style, input.weight);
407
+ const budget = Math.max(0, input.width - input.padLeft - input.padRight);
408
+ const text = ellipsize(input.text, budget, font);
409
+ const x = input.align === "right" ? input.x + input.width - input.padRight : input.align === "center" ? input.x + input.padLeft + budget / 2 : input.x + input.padLeft;
410
+ const command = { x, y: input.y + input.height / 2, text, font, color: input.color, size: style.metrics.fontSize, align: input.align, baseline: "middle" };
411
+ recordCanvasLabel(o.labels, command, { fullText: input.text, budget, background: input.background, role: input.role, clip: o.rect });
412
+ if (!text && input.text) o.labels?.omit({ role: input.role ?? "data-label", reason: "space", required: input.role === "axis-label" });
413
+ if (text) paintCanvasText(f.ctx, command);
297
414
  }
298
- function paintRawCellText(opts, x, y, text, font, color, size, align = "left") {
299
- if (!text) return;
300
- paintCanvasText(opts.ctx, {
301
- x,
302
- y,
303
- text,
304
- font,
305
- color,
306
- size,
307
- align,
308
- baseline: "middle"
309
- });
415
+ function countsAsMark(o, col, cell) {
416
+ if (o.dataRepresentation !== "aggregate") return true;
417
+ return !o.columns[col]?.rowHeader && typeof cell.raw === "number" && Number.isFinite(cell.raw);
310
418
  }
311
419
  export {
420
+ BAR_GAP,
312
421
  paintTableCanvas
313
422
  };
314
423
  //# sourceMappingURL=canvas.js.map