graphein 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/dist/animation/animate.d.ts +6 -1
  2. package/dist/animation/animate.d.ts.map +1 -1
  3. package/dist/animation/animate.js +2 -2
  4. package/dist/animation/animate.js.map +2 -2
  5. package/dist/animation/env.d.ts +5 -0
  6. package/dist/animation/env.d.ts.map +1 -1
  7. package/dist/animation/env.js +4 -0
  8. package/dist/animation/env.js.map +2 -2
  9. package/dist/animation/index.d.ts +1 -0
  10. package/dist/animation/index.d.ts.map +1 -1
  11. package/dist/animation/index.js +1 -0
  12. package/dist/animation/index.js.map +2 -2
  13. package/dist/animation/stagger.d.ts +13 -0
  14. package/dist/animation/stagger.d.ts.map +1 -0
  15. package/dist/animation/stagger.js +13 -0
  16. package/dist/animation/stagger.js.map +7 -0
  17. package/dist/axes/draw.d.ts +5 -1
  18. package/dist/axes/draw.d.ts.map +1 -1
  19. package/dist/axes/draw.js +13 -1
  20. package/dist/axes/draw.js.map +2 -2
  21. package/dist/axes/morph.d.ts +111 -0
  22. package/dist/axes/morph.d.ts.map +1 -0
  23. package/dist/axes/morph.js +207 -0
  24. package/dist/axes/morph.js.map +7 -0
  25. package/dist/axes/overlay.d.ts.map +1 -1
  26. package/dist/axes/overlay.js +88 -25
  27. package/dist/axes/overlay.js.map +2 -2
  28. package/dist/axes/text.d.ts +2 -0
  29. package/dist/axes/text.d.ts.map +1 -1
  30. package/dist/axes/text.js +1 -0
  31. package/dist/axes/text.js.map +2 -2
  32. package/dist/axes/tickLabels.d.ts +2 -0
  33. package/dist/axes/tickLabels.d.ts.map +1 -1
  34. package/dist/axes/tickLabels.js +2 -2
  35. package/dist/axes/tickLabels.js.map +2 -2
  36. package/dist/charts/annotations.d.ts +9 -3
  37. package/dist/charts/annotations.d.ts.map +1 -1
  38. package/dist/charts/annotations.js +82 -27
  39. package/dist/charts/annotations.js.map +2 -2
  40. package/dist/charts/area.d.ts +37 -1
  41. package/dist/charts/area.d.ts.map +1 -1
  42. package/dist/charts/area.js +35 -17
  43. package/dist/charts/area.js.map +2 -2
  44. package/dist/charts/bar.d.ts +53 -0
  45. package/dist/charts/bar.d.ts.map +1 -1
  46. package/dist/charts/bar.js +117 -83
  47. package/dist/charts/bar.js.map +2 -2
  48. package/dist/charts/box.d.ts +31 -0
  49. package/dist/charts/box.d.ts.map +1 -1
  50. package/dist/charts/box.js +93 -70
  51. package/dist/charts/box.js.map +2 -2
  52. package/dist/charts/bubbleMap.d.ts +20 -0
  53. package/dist/charts/bubbleMap.d.ts.map +1 -0
  54. package/dist/charts/bubbleMap.js +951 -0
  55. package/dist/charts/bubbleMap.js.map +7 -0
  56. package/dist/charts/bullet.d.ts.map +1 -1
  57. package/dist/charts/bullet.js +69 -51
  58. package/dist/charts/bullet.js.map +2 -2
  59. package/dist/charts/calendarHeatmap.d.ts.map +1 -1
  60. package/dist/charts/calendarHeatmap.js +56 -19
  61. package/dist/charts/calendarHeatmap.js.map +2 -2
  62. package/dist/charts/candlestick.d.ts +40 -0
  63. package/dist/charts/candlestick.d.ts.map +1 -0
  64. package/dist/charts/candlestick.js +325 -0
  65. package/dist/charts/candlestick.js.map +7 -0
  66. package/dist/charts/choropleth.d.ts.map +1 -1
  67. package/dist/charts/choropleth.js +46 -67
  68. package/dist/charts/choropleth.js.map +2 -2
  69. package/dist/charts/combo.d.ts.map +1 -1
  70. package/dist/charts/combo.js +127 -27
  71. package/dist/charts/combo.js.map +3 -3
  72. package/dist/charts/dumbbell.d.ts.map +1 -1
  73. package/dist/charts/dumbbell.js +100 -31
  74. package/dist/charts/dumbbell.js.map +2 -2
  75. package/dist/charts/funnel.d.ts.map +1 -1
  76. package/dist/charts/funnel.js +93 -28
  77. package/dist/charts/funnel.js.map +3 -3
  78. package/dist/charts/gantt.d.ts +22 -0
  79. package/dist/charts/gantt.d.ts.map +1 -0
  80. package/dist/charts/gantt.js +564 -0
  81. package/dist/charts/gantt.js.map +7 -0
  82. package/dist/charts/gauge.d.ts.map +1 -1
  83. package/dist/charts/gauge.js +30 -4
  84. package/dist/charts/gauge.js.map +2 -2
  85. package/dist/charts/geo.d.ts +87 -0
  86. package/dist/charts/geo.d.ts.map +1 -0
  87. package/dist/charts/geo.js +140 -0
  88. package/dist/charts/geo.js.map +7 -0
  89. package/dist/charts/geometry.d.ts +20 -0
  90. package/dist/charts/geometry.d.ts.map +1 -0
  91. package/dist/charts/geometry.js +25 -0
  92. package/dist/charts/geometry.js.map +7 -0
  93. package/dist/charts/heatmap.d.ts.map +1 -1
  94. package/dist/charts/heatmap.js +58 -49
  95. package/dist/charts/heatmap.js.map +2 -2
  96. package/dist/charts/histogram.d.ts +1 -1
  97. package/dist/charts/histogram.d.ts.map +1 -1
  98. package/dist/charts/histogram.js +49 -31
  99. package/dist/charts/histogram.js.map +2 -2
  100. package/dist/charts/index.d.ts +35 -1
  101. package/dist/charts/index.d.ts.map +1 -1
  102. package/dist/charts/index.js +12 -0
  103. package/dist/charts/index.js.map +2 -2
  104. package/dist/charts/legibility.d.ts +38 -0
  105. package/dist/charts/legibility.d.ts.map +1 -0
  106. package/dist/charts/legibility.js +72 -0
  107. package/dist/charts/legibility.js.map +7 -0
  108. package/dist/charts/line.d.ts +39 -1
  109. package/dist/charts/line.d.ts.map +1 -1
  110. package/dist/charts/line.js +48 -16
  111. package/dist/charts/line.js.map +2 -2
  112. package/dist/charts/matrix.d.ts +2 -1
  113. package/dist/charts/matrix.d.ts.map +1 -1
  114. package/dist/charts/matrix.js +481 -319
  115. package/dist/charts/matrix.js.map +3 -3
  116. package/dist/charts/morphFrame.d.ts +83 -0
  117. package/dist/charts/morphFrame.d.ts.map +1 -0
  118. package/dist/charts/morphFrame.js +128 -0
  119. package/dist/charts/morphFrame.js.map +7 -0
  120. package/dist/charts/pie.d.ts.map +1 -1
  121. package/dist/charts/pie.js +89 -26
  122. package/dist/charts/pie.js.map +2 -2
  123. package/dist/charts/pieState.d.ts +27 -0
  124. package/dist/charts/pieState.d.ts.map +1 -0
  125. package/dist/charts/pieState.js +55 -0
  126. package/dist/charts/pieState.js.map +7 -0
  127. package/dist/charts/radar.d.ts +62 -0
  128. package/dist/charts/radar.d.ts.map +1 -0
  129. package/dist/charts/radar.js +912 -0
  130. package/dist/charts/radar.js.map +7 -0
  131. package/dist/charts/radialBar.d.ts +60 -0
  132. package/dist/charts/radialBar.d.ts.map +1 -0
  133. package/dist/charts/radialBar.js +708 -0
  134. package/dist/charts/radialBar.js.map +7 -0
  135. package/dist/charts/sankey.d.ts.map +1 -1
  136. package/dist/charts/sankey.js +223 -57
  137. package/dist/charts/sankey.js.map +3 -3
  138. package/dist/charts/scatter.d.ts +31 -0
  139. package/dist/charts/scatter.d.ts.map +1 -1
  140. package/dist/charts/scatter.js +48 -12
  141. package/dist/charts/scatter.js.map +2 -2
  142. package/dist/charts/slope.d.ts.map +1 -1
  143. package/dist/charts/slope.js +55 -3
  144. package/dist/charts/slope.js.map +2 -2
  145. package/dist/charts/sunburst.d.ts +14 -0
  146. package/dist/charts/sunburst.d.ts.map +1 -0
  147. package/dist/charts/sunburst.js +885 -0
  148. package/dist/charts/sunburst.js.map +7 -0
  149. package/dist/charts/table.d.ts +2 -1
  150. package/dist/charts/table.d.ts.map +1 -1
  151. package/dist/charts/table.js +214 -224
  152. package/dist/charts/table.js.map +3 -3
  153. package/dist/charts/tableView/canvas.d.ts +16 -1
  154. package/dist/charts/tableView/canvas.d.ts.map +1 -1
  155. package/dist/charts/tableView/canvas.js +361 -252
  156. package/dist/charts/tableView/canvas.js.map +3 -3
  157. package/dist/charts/tableView/conditional.d.ts +66 -40
  158. package/dist/charts/tableView/conditional.d.ts.map +1 -1
  159. package/dist/charts/tableView/conditional.js +163 -256
  160. package/dist/charts/tableView/conditional.js.map +3 -3
  161. package/dist/charts/tableView/dom.d.ts +26 -2
  162. package/dist/charts/tableView/dom.d.ts.map +1 -1
  163. package/dist/charts/tableView/dom.js +609 -269
  164. package/dist/charts/tableView/dom.js.map +3 -3
  165. package/dist/charts/tableView/layout.d.ts +22 -0
  166. package/dist/charts/tableView/layout.d.ts.map +1 -0
  167. package/dist/charts/tableView/layout.js +246 -0
  168. package/dist/charts/tableView/layout.js.map +7 -0
  169. package/dist/charts/tableView/sketch.d.ts +3 -2
  170. package/dist/charts/tableView/sketch.d.ts.map +1 -1
  171. package/dist/charts/tableView/sketch.js +2 -2
  172. package/dist/charts/tableView/sketch.js.map +2 -2
  173. package/dist/charts/tableView/sketchBar.d.ts +7 -0
  174. package/dist/charts/tableView/sketchBar.d.ts.map +1 -0
  175. package/dist/charts/tableView/sketchBar.js +32 -0
  176. package/dist/charts/tableView/sketchBar.js.map +7 -0
  177. package/dist/charts/tableView/sort.d.ts +9 -0
  178. package/dist/charts/tableView/sort.d.ts.map +1 -0
  179. package/dist/charts/tableView/sort.js +70 -0
  180. package/dist/charts/tableView/sort.js.map +7 -0
  181. package/dist/charts/tableView/sparkline.d.ts +30 -0
  182. package/dist/charts/tableView/sparkline.d.ts.map +1 -0
  183. package/dist/charts/tableView/sparkline.js +63 -0
  184. package/dist/charts/tableView/sparkline.js.map +7 -0
  185. package/dist/charts/tableView/style.d.ts +67 -0
  186. package/dist/charts/tableView/style.d.ts.map +1 -0
  187. package/dist/charts/tableView/style.js +131 -0
  188. package/dist/charts/tableView/style.js.map +7 -0
  189. package/dist/charts/tableView/types.d.ts +69 -46
  190. package/dist/charts/tableView/types.d.ts.map +1 -1
  191. package/dist/charts/tableView/types.js +22 -87
  192. package/dist/charts/tableView/types.js.map +2 -2
  193. package/dist/charts/tableView.d.ts +10 -5
  194. package/dist/charts/tableView.d.ts.map +1 -1
  195. package/dist/charts/tableView.js +12 -8
  196. package/dist/charts/tableView.js.map +2 -2
  197. package/dist/charts/treemap.d.ts.map +1 -1
  198. package/dist/charts/treemap.js +177 -68
  199. package/dist/charts/treemap.js.map +3 -3
  200. package/dist/charts/trendline.d.ts +13 -5
  201. package/dist/charts/trendline.d.ts.map +1 -1
  202. package/dist/charts/trendline.js +205 -56
  203. package/dist/charts/trendline.js.map +2 -2
  204. package/dist/charts/waterfall.d.ts.map +1 -1
  205. package/dist/charts/waterfall.js +76 -5
  206. package/dist/charts/waterfall.js.map +2 -2
  207. package/dist/index.d.ts +1 -1
  208. package/dist/index.js +1 -1
  209. package/dist/index.js.map +1 -1
  210. package/dist/interaction/cartesian.d.ts +4 -1
  211. package/dist/interaction/cartesian.d.ts.map +1 -1
  212. package/dist/interaction/cartesian.js +104 -34
  213. package/dist/interaction/cartesian.js.map +2 -2
  214. package/dist/interaction/controller.d.ts +29 -1
  215. package/dist/interaction/controller.d.ts.map +1 -1
  216. package/dist/interaction/controller.js +131 -8
  217. package/dist/interaction/controller.js.map +2 -2
  218. package/dist/interaction/focus.d.ts +23 -0
  219. package/dist/interaction/focus.d.ts.map +1 -0
  220. package/dist/interaction/focus.js +65 -0
  221. package/dist/interaction/focus.js.map +7 -0
  222. package/dist/interaction/tooltip.d.ts +6 -0
  223. package/dist/interaction/tooltip.d.ts.map +1 -1
  224. package/dist/interaction/tooltip.js +41 -16
  225. package/dist/interaction/tooltip.js.map +2 -2
  226. package/dist/interaction/types.d.ts +19 -0
  227. package/dist/interaction/types.d.ts.map +1 -1
  228. package/dist/interaction/veil.d.ts +25 -0
  229. package/dist/interaction/veil.d.ts.map +1 -0
  230. package/dist/interaction/veil.js +35 -0
  231. package/dist/interaction/veil.js.map +7 -0
  232. package/dist/pivot/pivot.d.ts +18 -0
  233. package/dist/pivot/pivot.d.ts.map +1 -1
  234. package/dist/pivot/pivot.js +46 -34
  235. package/dist/pivot/pivot.js.map +2 -2
  236. package/dist/render/chromeMotion.d.ts +65 -0
  237. package/dist/render/chromeMotion.d.ts.map +1 -0
  238. package/dist/render/chromeMotion.js +79 -0
  239. package/dist/render/chromeMotion.js.map +7 -0
  240. package/dist/render/pathSample.d.ts +24 -0
  241. package/dist/render/pathSample.d.ts.map +1 -0
  242. package/dist/render/pathSample.js +76 -0
  243. package/dist/render/pathSample.js.map +7 -0
  244. package/dist/render/transient.d.ts +18 -0
  245. package/dist/render/transient.d.ts.map +1 -0
  246. package/dist/render/transient.js +19 -0
  247. package/dist/render/transient.js.map +7 -0
  248. package/dist/runtime/candlestick.d.ts +112 -0
  249. package/dist/runtime/candlestick.d.ts.map +1 -0
  250. package/dist/runtime/candlestick.js +531 -0
  251. package/dist/runtime/candlestick.js.map +7 -0
  252. package/dist/runtime/cartesian.d.ts +14 -3
  253. package/dist/runtime/cartesian.d.ts.map +1 -1
  254. package/dist/runtime/cartesian.js.map +2 -2
  255. package/dist/runtime/chartAnimation.d.ts +54 -7
  256. package/dist/runtime/chartAnimation.d.ts.map +1 -1
  257. package/dist/runtime/chartAnimation.js +146 -28
  258. package/dist/runtime/chartAnimation.js.map +2 -2
  259. package/dist/runtime/chartRuntime.d.ts +42 -0
  260. package/dist/runtime/chartRuntime.d.ts.map +1 -1
  261. package/dist/runtime/chartRuntime.js +196 -30
  262. package/dist/runtime/chartRuntime.js.map +2 -2
  263. package/dist/runtime/dashboardDom.d.ts.map +1 -1
  264. package/dist/runtime/dashboardDom.js +45 -0
  265. package/dist/runtime/dashboardDom.js.map +2 -2
  266. package/dist/runtime/facet.d.ts +1 -1
  267. package/dist/runtime/facet.d.ts.map +1 -1
  268. package/dist/runtime/gantt.d.ts +137 -0
  269. package/dist/runtime/gantt.d.ts.map +1 -0
  270. package/dist/runtime/gantt.js +647 -0
  271. package/dist/runtime/gantt.js.map +7 -0
  272. package/dist/runtime/morph.d.ts +33 -0
  273. package/dist/runtime/morph.d.ts.map +1 -0
  274. package/dist/runtime/morph.js +332 -0
  275. package/dist/runtime/morph.js.map +7 -0
  276. package/dist/runtime/radar.d.ts +75 -0
  277. package/dist/runtime/radar.d.ts.map +1 -0
  278. package/dist/runtime/radar.js +201 -0
  279. package/dist/runtime/radar.js.map +7 -0
  280. package/dist/runtime/radialBar.d.ts +81 -0
  281. package/dist/runtime/radialBar.d.ts.map +1 -0
  282. package/dist/runtime/radialBar.js +125 -0
  283. package/dist/runtime/radialBar.js.map +7 -0
  284. package/dist/runtime/report/constants.d.ts +2 -2
  285. package/dist/runtime/report/constants.d.ts.map +1 -1
  286. package/dist/runtime/runtimeShared.d.ts +3 -3
  287. package/dist/runtime/runtimeShared.d.ts.map +1 -1
  288. package/dist/runtime/sunburst.d.ts +74 -0
  289. package/dist/runtime/sunburst.d.ts.map +1 -0
  290. package/dist/runtime/sunburst.js +150 -0
  291. package/dist/runtime/sunburst.js.map +7 -0
  292. package/dist/runtime/wire.d.ts.map +1 -1
  293. package/dist/runtime/wire.js +3 -1
  294. package/dist/runtime/wire.js.map +2 -2
  295. package/dist/shape/arc.d.ts +15 -2
  296. package/dist/shape/arc.d.ts.map +1 -1
  297. package/dist/shape/arc.js +204 -32
  298. package/dist/shape/arc.js.map +2 -2
  299. package/dist/spec/chartDefinitions.d.ts +6 -0
  300. package/dist/spec/chartDefinitions.d.ts.map +1 -1
  301. package/dist/spec/chartDefinitions.js +7 -1
  302. package/dist/spec/chartDefinitions.js.map +2 -2
  303. package/dist/spec/templates.d.ts.map +1 -1
  304. package/dist/spec/templates.js +177 -2
  305. package/dist/spec/templates.js.map +2 -2
  306. package/dist/spec/types.d.ts +258 -6
  307. package/dist/spec/types.d.ts.map +1 -1
  308. package/dist/spec/types.js +6 -0
  309. package/dist/spec/types.js.map +2 -2
  310. package/dist/spec/validate/charts.js +147 -15
  311. package/dist/spec/validate/charts.js.map +2 -2
  312. package/dist/spec/validate/common.d.ts +6 -0
  313. package/dist/spec/validate/common.d.ts.map +1 -1
  314. package/dist/spec/validate/overlays.js +2 -2
  315. package/dist/spec/validate/overlays.js.map +2 -2
  316. package/dist/spec/validate.data.d.ts.map +1 -1
  317. package/dist/spec/validate.data.js +8 -3
  318. package/dist/spec/validate.data.js.map +2 -2
  319. package/package.json +1 -1
@@ -0,0 +1,647 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+ import { accessor, inferType, toDate, toKey, toNumber } from "../util/data.js";
5
+ import { ticks as numericTicks, timeTicks } from "../ticks/index.js";
6
+ import { linearScale, timeScale } from "../scales/index.js";
7
+ import { formatDate, formatNumber, formatValue, prettyDate } from "../format/index.js";
8
+ import { computeFrame, NO_PADDING } from "../layout/index.js";
9
+ import { fontString, measureText } from "../render/text.js";
10
+ import { resolveSketch } from "../spec/sketch.js";
11
+ import { ordinalColorScale, rgbaToCss } from "../color/index.js";
12
+ import { resolvePalette } from "./categories.js";
13
+ const MINUTE = 6e4;
14
+ const HOUR = 60 * MINUTE;
15
+ const DAY = 24 * HOUR;
16
+ const YEAR = 365 * DAY;
17
+ const MIN_BAR_WIDTH = 3;
18
+ const MAX_BAR_HEIGHT = 26;
19
+ const MAX_MILESTONE_RADIUS = 11;
20
+ function isFiniteNumber(value) {
21
+ return typeof value === "number" && Number.isFinite(value);
22
+ }
23
+ function clamp(value, min, max) {
24
+ return Math.max(min, Math.min(max, value));
25
+ }
26
+ function labelFor(value) {
27
+ if (value == null || value === "") return "(blank)";
28
+ if (value instanceof Date) return Number.isFinite(value.getTime()) ? formatDate(value, "%b %e, %Y") : String(value);
29
+ return String(value);
30
+ }
31
+ function titleInput(spec) {
32
+ if (typeof spec.title === "string") return { text: spec.title };
33
+ if (spec.title) return { text: spec.title.text, subtitle: spec.title.subtitle, align: spec.title.align };
34
+ return void 0;
35
+ }
36
+ function ganttScaleKind(spec, data) {
37
+ const { start, end } = spec.encoding;
38
+ const declared = start.type ?? end.type;
39
+ if (declared === "quantitative") return "linear";
40
+ if (declared === "temporal") return "time";
41
+ const inferred = inferType(data, start.field);
42
+ if (inferred === "quantitative") return "linear";
43
+ if (inferred === "temporal") return "time";
44
+ return inferType(data, end.field) === "quantitative" ? "linear" : "time";
45
+ }
46
+ function ganttValue(kind, value) {
47
+ if (kind === "linear") return toNumber(value);
48
+ const date = toDate(value);
49
+ return date ? date.getTime() : NaN;
50
+ }
51
+ function parseRows(spec, data, kind) {
52
+ const enc = spec.encoding;
53
+ const readTask = accessor(enc.task.field);
54
+ const readStart = accessor(enc.start.field);
55
+ const readEnd = accessor(enc.end.field);
56
+ const readGroup = enc.group ? accessor(enc.group.field) : null;
57
+ const readProgress = enc.progress ? accessor(enc.progress.field) : null;
58
+ const tasks = [];
59
+ let skipped = 0;
60
+ data.forEach((row, sourceIndex) => {
61
+ const start = ganttValue(kind, readStart(row));
62
+ const end = ganttValue(kind, readEnd(row));
63
+ if (!isFiniteNumber(start) || !isFiniteNumber(end) || end < start) {
64
+ skipped++;
65
+ return;
66
+ }
67
+ const raw = readTask(row);
68
+ const groupRaw = readGroup ? readGroup(row) : void 0;
69
+ const progressValue = readProgress ? toNumber(readProgress(row)) : NaN;
70
+ tasks.push({
71
+ key: toKey(raw),
72
+ raw,
73
+ label: labelFor(raw),
74
+ start,
75
+ end,
76
+ milestone: end === start,
77
+ groupKey: readGroup ? toKey(groupRaw) : void 0,
78
+ groupLabel: readGroup ? labelFor(groupRaw) : void 0,
79
+ groupRaw,
80
+ color: "",
81
+ progress: isFiniteNumber(progressValue) ? clamp(progressValue, 0, 1) : void 0,
82
+ sourceIndex,
83
+ row,
84
+ lane: 0,
85
+ rect: { x: 0, y: 0, width: 0, height: 0 }
86
+ });
87
+ });
88
+ return { tasks, skipped };
89
+ }
90
+ function orderLanes(tasks, sort) {
91
+ const byKey = /* @__PURE__ */ new Map();
92
+ const lanes = [];
93
+ tasks.forEach((task, index) => {
94
+ let lane = byKey.get(task.key);
95
+ if (!lane) {
96
+ lane = { key: task.key, raw: task.raw, label: task.label, first: index, minStart: task.start, minEnd: task.end, total: 0, tasks: [] };
97
+ byKey.set(task.key, lane);
98
+ lanes.push(lane);
99
+ }
100
+ lane.minStart = Math.min(lane.minStart, task.start);
101
+ lane.minEnd = Math.min(lane.minEnd, task.end);
102
+ lane.total += task.end - task.start;
103
+ lane.tasks.push(task);
104
+ });
105
+ const metric = {
106
+ start: (lane) => lane.minStart,
107
+ end: (lane) => lane.minEnd,
108
+ duration: (lane) => -lane.total
109
+ };
110
+ const by = sort ? metric[sort] : void 0;
111
+ return by ? lanes.slice().sort((a, b) => by(a) - by(b) || a.first - b.first) : lanes;
112
+ }
113
+ function resolveGroups(spec, tokens, tasks, colorSource) {
114
+ const palette = resolvePalette(spec.palette, tokens);
115
+ const plain = spec.palette !== void 0 && palette.length > 0 ? palette[0] : tokens.color.accent;
116
+ const groupDef = spec.encoding.group;
117
+ if (!groupDef) return { groups: [], colorOf: () => plain, grouped: false, plain, plainMilestone: tokens.color.text };
118
+ const explicit = groupDef.scale?.domain;
119
+ const order = /* @__PURE__ */ new Map();
120
+ const note = (key) => {
121
+ if (!order.has(key)) order.set(key, order.size);
122
+ };
123
+ if (Array.isArray(explicit)) for (const value of explicit) note(toKey(value));
124
+ const read = accessor(groupDef.field);
125
+ for (const row of colorSource) note(toKey(read(row)));
126
+ for (const task of tasks) note(task.groupKey);
127
+ const scale = ordinalColorScale({ domain: [...order.keys()], palette });
128
+ const cache = /* @__PURE__ */ new Map();
129
+ const colorOf = (key) => {
130
+ let color = cache.get(key);
131
+ if (!color) cache.set(key, color = rgbaToCss(scale.map(key)));
132
+ return color;
133
+ };
134
+ const present = /* @__PURE__ */ new Map();
135
+ for (const task of tasks) {
136
+ const key = task.groupKey;
137
+ if (!present.has(key)) present.set(key, { key, label: task.groupLabel, raw: task.groupRaw, color: colorOf(key) });
138
+ }
139
+ const groups = [...present.values()].sort((a, b) => (order.get(a.key) ?? 0) - (order.get(b.key) ?? 0));
140
+ return { groups, colorOf, grouped: true, plain, plainMilestone: tokens.color.text };
141
+ }
142
+ function legendShown(spec, count) {
143
+ const cfg = spec.legend;
144
+ if (cfg === false) return false;
145
+ if (typeof cfg === "object" && cfg.show === false) return false;
146
+ return count > 1;
147
+ }
148
+ function annotationValues(spec, kind) {
149
+ const list = Array.isArray(spec.annotations) ? spec.annotations : [];
150
+ const out = [];
151
+ const add = (value) => {
152
+ const n = ganttValue(kind, value);
153
+ if (isFiniteNumber(n)) out.push(n);
154
+ };
155
+ for (const ann of list) {
156
+ if (!ann || typeof ann !== "object") continue;
157
+ if (ann.type === "point") add(ann.x);
158
+ else if (ann.axis === "x") {
159
+ if (ann.value !== void 0) add(ann.value);
160
+ if (ann.from !== void 0) add(ann.from);
161
+ if (ann.to !== void 0) add(ann.to);
162
+ }
163
+ }
164
+ return out;
165
+ }
166
+ function explicitDomain(spec, kind) {
167
+ const domain = spec.encoding.start.scale?.domain ?? spec.encoding.end.scale?.domain;
168
+ if (!Array.isArray(domain) || domain.length !== 2) return null;
169
+ const lo = ganttValue(kind, domain[0]);
170
+ const hi = ganttValue(kind, domain[1]);
171
+ return isFiniteNumber(lo) && isFiniteNumber(hi) && hi > lo ? [lo, hi] : null;
172
+ }
173
+ function dataExtent(spec, kind, tasks) {
174
+ let lo = Infinity;
175
+ let hi = -Infinity;
176
+ for (const task of tasks) {
177
+ lo = Math.min(lo, task.start);
178
+ hi = Math.max(hi, task.end);
179
+ }
180
+ if (tasks.length > 0) {
181
+ for (const value of annotationValues(spec, kind)) {
182
+ lo = Math.min(lo, value);
183
+ hi = Math.max(hi, value);
184
+ }
185
+ }
186
+ if (!isFiniteNumber(lo) || !isFiniteNumber(hi)) return kind === "time" ? [0, DAY] : [0, 1];
187
+ if (!isFiniteNumber(hi - lo)) return [lo, hi];
188
+ if (hi === lo) {
189
+ const pad = kind === "time" ? DAY : Math.abs(lo) > 0 ? Math.abs(lo) * 0.1 : 1;
190
+ return [lo - pad, hi + pad];
191
+ }
192
+ return [lo, hi];
193
+ }
194
+ function rawTicks(kind, lo, hi, count) {
195
+ return kind === "time" ? timeTicks(lo, hi, count) : numericTicks(lo, hi, count);
196
+ }
197
+ function axisTicks(spec, kind, extent, explicit, count) {
198
+ const [lo, hi] = explicit ?? extent;
199
+ const values = rawTicks(kind, lo, hi, count).filter(isFiniteNumber);
200
+ const userTicks = spec.axes?.x?.tickValues;
201
+ const parsed = Array.isArray(userTicks) ? userTicks.map((v) => ganttValue(kind, v)).filter(isFiniteNumber).sort((a, b) => a - b) : [];
202
+ const ticks = parsed.length > 0 ? parsed : values;
203
+ if (explicit) return { domain: explicit, values: ticks };
204
+ const span = hi - lo;
205
+ if (!(span > 0) || !isFiniteNumber(span) || values.length < 2) return { domain: [lo, hi], values: ticks };
206
+ const first = values[0];
207
+ const last = values[values.length - 1];
208
+ return {
209
+ domain: [
210
+ first <= lo && lo - first <= span * 0.08 ? first : lo,
211
+ last >= hi && last - hi <= span * 0.08 ? last : hi
212
+ ],
213
+ values: ticks
214
+ };
215
+ }
216
+ function tickCountFor(spec, width) {
217
+ const explicit = spec.axes?.x?.ticks;
218
+ if (typeof explicit === "number" && Number.isFinite(explicit) && explicit >= 1) return Math.round(explicit);
219
+ return clamp(Math.round(width / 80), 2, 10);
220
+ }
221
+ function annotationStrips(spec, tokens, height) {
222
+ const list = Array.isArray(spec.annotations) ? spec.annotations : [];
223
+ const strip = Math.ceil(tokens.font.size.small * 1.2 + 6);
224
+ let top = 0;
225
+ let bottom = 0;
226
+ for (const ann of list) {
227
+ if (!ann || typeof ann !== "object" || !ann.label || ann.type === "point" || ann.axis !== "x") continue;
228
+ const position = ann.labelPosition ?? "end";
229
+ if (position === "end") top = strip;
230
+ else if (position === "start") bottom = strip;
231
+ }
232
+ return height >= (top + bottom) * 3 ? { top, bottom } : { top: 0, bottom: 0 };
233
+ }
234
+ function ganttTimeTickLabels(values, format) {
235
+ if (format) return values.map((value) => formatValue(value, format));
236
+ let step = Infinity;
237
+ for (let i = 1; i < values.length; i++) step = Math.min(step, Math.abs(values[i] - values[i - 1]));
238
+ if (!Number.isFinite(step)) step = DAY;
239
+ return values.map((value, i) => {
240
+ const date = new Date(value);
241
+ if (step >= YEAR * 0.9) return formatDate(date, "%Y");
242
+ if (step >= 27 * DAY) return i === 0 || date.getMonth() === 0 ? formatDate(date, "%b %Y") : formatDate(date, "%b");
243
+ if (step >= DAY * 0.9) return formatDate(date, "%b %e");
244
+ const midnight = date.getHours() === 0 && date.getMinutes() === 0;
245
+ if (midnight) return formatDate(date, "%b %e");
246
+ return i === 0 ? formatDate(date, "%b %e %H:%M") : formatDate(date, "%H:%M");
247
+ });
248
+ }
249
+ function linearTickLabels(values, format) {
250
+ return values.map((value) => format ? formatValue(value, format) : formatNumber(value, ","));
251
+ }
252
+ function axisFormat(spec) {
253
+ return spec.axes?.x?.format ?? spec.encoding.start.format;
254
+ }
255
+ function tickLabels(spec, kind, values) {
256
+ return kind === "time" ? ganttTimeTickLabels(values, axisFormat(spec)) : linearTickLabels(values, axisFormat(spec));
257
+ }
258
+ function ganttFrame(spec, tokens, opts, xLabels, inputs, position) {
259
+ const axes = spec.axes;
260
+ const legendAt = position ?? inputs.legendPosition;
261
+ return computeFrame({
262
+ width: Math.max(0, opts.width),
263
+ height: Math.max(0, opts.height),
264
+ originX: opts.originX,
265
+ originY: opts.originY,
266
+ titleGap: opts.titleGap,
267
+ minimumPlotSize: opts.minimumPlotSize,
268
+ padding: { ...NO_PADDING, ...spec.padding },
269
+ font: tokens.font,
270
+ title: titleInput(spec),
271
+ legend: legendAt && inputs.legendItems.length > 0 ? { items: inputs.legendItems, position: legendAt } : void 0,
272
+ xAxis: {
273
+ show: axes?.x?.show !== false,
274
+ labels: axes?.x?.labels === false ? [] : xLabels,
275
+ title: axes?.x?.title,
276
+ edgeAnchored: true
277
+ },
278
+ yAxis: {
279
+ show: axes?.y?.show !== false,
280
+ labels: axes?.y?.labels === false ? [] : inputs.laneLabels,
281
+ title: axes?.y?.title ?? spec.encoding.task.title
282
+ }
283
+ });
284
+ }
285
+ function chooseLegendFrame(spec, tokens, opts, xLabels, inputs) {
286
+ if (!inputs.legendPosition || inputs.legendItems.length === 0) return ganttFrame(spec, tokens, opts, xLabels, inputs);
287
+ const explicit = typeof spec.legend === "object" ? spec.legend.position : void 0;
288
+ if (explicit) return ganttFrame(spec, tokens, opts, xLabels, inputs, explicit);
289
+ const order = inputs.legendItems.length > 8 ? ["right", "top"] : ["top", "right"];
290
+ let best = null;
291
+ for (const position of order) {
292
+ const frame = ganttFrame(spec, tokens, opts, xLabels, inputs, position);
293
+ const complete = frame.legendOverflow === 0 && !frame.dropped.includes("legend");
294
+ if (complete) return frame;
295
+ if (!best || hiddenGroups(frame, inputs) < hiddenGroups(best, inputs)) best = frame;
296
+ }
297
+ return best;
298
+ }
299
+ function hiddenGroups(frame, inputs) {
300
+ return frame.dropped.includes("legend") ? inputs.legendItems.length : frame.legendOverflow;
301
+ }
302
+ function placeTasks(tasks, lanes, xScale, plot, barHeight, radius) {
303
+ const right = plot.x + plot.width;
304
+ for (const task of tasks) {
305
+ const lane = lanes[task.lane];
306
+ const x0 = xScale.map(task.start);
307
+ if (task.milestone) {
308
+ task.rect = { x: x0 - radius, y: lane.center - radius, width: radius * 2, height: radius * 2 };
309
+ continue;
310
+ }
311
+ const x1 = xScale.map(task.end);
312
+ let width = x1 - x0;
313
+ let x = x0;
314
+ if (width < MIN_BAR_WIDTH) {
315
+ width = MIN_BAR_WIDTH;
316
+ if (x + width > right && x <= right) x = Math.max(plot.x, right - width);
317
+ }
318
+ task.rect = { x, y: lane.center - barHeight / 2, width, height: barHeight };
319
+ }
320
+ }
321
+ function finiteRect(rect) {
322
+ return isFiniteNumber(rect.x) && isFiniteNumber(rect.y) && isFiniteNumber(rect.width) && isFiniteNumber(rect.height) && isFiniteNumber(rect.x + rect.width) && isFiniteNumber(rect.y + rect.height);
323
+ }
324
+ function ganttLabelSize(tokens, extent) {
325
+ return extent >= 18 ? tokens.font.size.small : tokens.font.size.tiny;
326
+ }
327
+ function lowerBound(values, value) {
328
+ let lo = 0;
329
+ let hi = values.length;
330
+ while (lo < hi) {
331
+ const mid = lo + hi >> 1;
332
+ if (values[mid] < value) lo = mid + 1;
333
+ else hi = mid;
334
+ }
335
+ return lo;
336
+ }
337
+ const NARROW_SPAN = 128;
338
+ class LaneSpans {
339
+ constructor(tasks, xScale, radius) {
340
+ __publicField(this, "lefts", []);
341
+ __publicField(this, "rights", []);
342
+ __publicField(this, "owners", []);
343
+ __publicField(this, "reach", 0);
344
+ __publicField(this, "wide", []);
345
+ const narrow = [];
346
+ for (const task of tasks) {
347
+ const pad = task.milestone ? radius : 0;
348
+ const left = xScale.map(task.start) - pad;
349
+ const right = xScale.map(task.end) + pad;
350
+ if (!isFiniteNumber(left) || !isFiniteNumber(right)) continue;
351
+ (right - left <= NARROW_SPAN ? narrow : this.wide).push({ left, right, task });
352
+ }
353
+ narrow.sort((a, b) => a.left - b.left);
354
+ for (const span of narrow) {
355
+ this.lefts.push(span.left);
356
+ this.rights.push(span.right);
357
+ this.owners.push(span.task);
358
+ this.reach = Math.max(this.reach, span.right - span.left);
359
+ }
360
+ }
361
+ /** Whether a mark other than `self` overlaps the open interval (lo, hi). */
362
+ hits(lo, hi, self) {
363
+ if (this.wide.some((span) => span.task !== self && span.left < hi && span.right > lo)) return true;
364
+ for (let i = lowerBound(this.lefts, lo - this.reach); i < this.lefts.length && this.lefts[i] < hi; i++) {
365
+ if (this.rights[i] > lo && this.owners[i] !== self) return true;
366
+ }
367
+ return false;
368
+ }
369
+ }
370
+ function milestoneLabelRoom(tasks, xScale, plot, radius, laneHeight, tokens, textOf) {
371
+ const size = ganttLabelSize(tokens, laneHeight);
372
+ if (laneHeight < size * 1.2 + 1) return 0;
373
+ const font = fontString(size, tokens.font.family, tokens.font.weight.medium);
374
+ const right = plot.x + plot.width;
375
+ const members = /* @__PURE__ */ new Map();
376
+ for (const task of tasks) {
377
+ const lane = members.get(task.key);
378
+ if (lane) lane.push(task);
379
+ else members.set(task.key, [task]);
380
+ }
381
+ const lanes = /* @__PURE__ */ new Map();
382
+ const spansOf = (key) => {
383
+ let spans = lanes.get(key);
384
+ if (!spans) lanes.set(key, spans = new LaneSpans(members.get(key) ?? [], xScale, radius));
385
+ return spans;
386
+ };
387
+ let need = 0;
388
+ for (const task of tasks) {
389
+ if (!task.milestone) continue;
390
+ const x = xScale.map(task.start);
391
+ const text = textOf(task);
392
+ if (!isFiniteNumber(x) || !text) continue;
393
+ const width = measureText(text, font).width;
394
+ const overflow = x + radius + 4 + width + 2 - right;
395
+ if (overflow <= need) continue;
396
+ const leftEdge = x - radius - 4 - width;
397
+ const leftFree = leftEdge >= plot.x + 1 && !spansOf(task.key).hits(leftEdge - 1, x - radius - 3, task);
398
+ if (!leftFree) need = overflow;
399
+ }
400
+ return need;
401
+ }
402
+ function buildXModel(spec, kind, xScale) {
403
+ return {
404
+ kind,
405
+ field: spec.encoding.start.field,
406
+ type: kind === "time" ? "temporal" : "quantitative",
407
+ continuous: xScale,
408
+ bandwidth: 0,
409
+ pixel: (value) => {
410
+ const n = ganttValue(kind, value);
411
+ if (!isFiniteNumber(n)) return void 0;
412
+ const px = xScale.map(n);
413
+ return isFiniteNumber(px) ? px : void 0;
414
+ }
415
+ };
416
+ }
417
+ function buildYModel(spec, lanes, area, plot) {
418
+ const centers = new Map(lanes.map((lane) => [lane.key, lane.center]));
419
+ const scale = linearScale({ domain: [0, Math.max(1, lanes.length)], range: [area.y, area.y + area.height] });
420
+ return {
421
+ field: spec.encoding.task.field,
422
+ scale,
423
+ baseline: plot.y + plot.height,
424
+ // Lanes are keyed by task: a task (string, number or date) lands on its lane center.
425
+ pixel: (value) => centers.get(toKey(value)) ?? NaN
426
+ };
427
+ }
428
+ function baseSpec(spec, data) {
429
+ const axes = spec.axes;
430
+ return {
431
+ type: "bar",
432
+ data,
433
+ encoding: {
434
+ x: { field: spec.encoding.start.field },
435
+ y: { field: spec.encoding.task.field, title: spec.encoding.task.title }
436
+ },
437
+ // Lanes carry their own separators; horizontal gridlines at lane centers would strike through bars.
438
+ axes: { ...axes, x: { ...axes?.x }, y: { ...axes?.y, grid: false } },
439
+ title: spec.title,
440
+ padding: spec.padding,
441
+ legend: spec.legend,
442
+ tooltip: spec.tooltip,
443
+ background: spec.background,
444
+ annotations: spec.annotations
445
+ };
446
+ }
447
+ function buildGanttModel(spec, tokens, opts) {
448
+ const data = Array.isArray(spec.data) ? spec.data : [];
449
+ const sketch = resolveSketch(spec);
450
+ const kind = ganttScaleKind(spec, data);
451
+ const { tasks: parsed, skipped: invalid } = parseRows(spec, data, kind);
452
+ const laneOrder = orderLanes(parsed, spec.sort);
453
+ const groupInfo = resolveGroups(spec, tokens, parsed, opts.colorSource ?? data);
454
+ for (const task of parsed) {
455
+ task.color = groupInfo.grouped ? groupInfo.colorOf(task.groupKey) : task.milestone ? groupInfo.plainMilestone : groupInfo.plain;
456
+ }
457
+ const explicit = explicitDomain(spec, kind);
458
+ const extent = explicit ?? dataExtent(spec, kind, parsed);
459
+ const legendItems = legendShown(spec, groupInfo.groups.length) ? groupInfo.groups.map((group) => ({ label: group.label, color: group.color, symbol: "square" })) : [];
460
+ const inputs = {
461
+ laneLabels: laneOrder.map((lane) => lane.label),
462
+ legendItems,
463
+ legendPosition: legendItems.length > 0 ? "top" : null
464
+ };
465
+ let count = tickCountFor(spec, Math.max(0, opts.width) * 0.75);
466
+ let axis = axisTicks(spec, kind, extent, explicit, count);
467
+ let frame = chooseLegendFrame(spec, tokens, opts, tickLabels(spec, kind, axis.values), inputs);
468
+ const refined = tickCountFor(spec, frame.plot.width);
469
+ if (refined !== count) {
470
+ count = refined;
471
+ axis = axisTicks(spec, kind, extent, explicit, count);
472
+ frame = chooseLegendFrame(spec, tokens, opts, tickLabels(spec, kind, axis.values), inputs);
473
+ }
474
+ const { domain } = axis;
475
+ const plot = frame.plot;
476
+ const laneCount = Math.max(1, laneOrder.length);
477
+ const strips = annotationStrips(spec, tokens, plot.height);
478
+ const laneArea = { y: plot.y + strips.top, height: Math.max(0, plot.height - strips.top - strips.bottom) };
479
+ const laneHeight = laneArea.height / laneCount;
480
+ const barHeight = laneHeight >= 6 ? Math.min(laneHeight * 0.62, MAX_BAR_HEIGHT) : laneHeight * 0.8;
481
+ const milestoneRadius = Math.max(2, Math.min(barHeight * 0.62, laneHeight * 0.46, MAX_MILESTONE_RADIUS));
482
+ const lanes = laneOrder.map((lane, index) => {
483
+ const top = laneArea.y + index * laneHeight;
484
+ return { key: lane.key, raw: lane.raw, label: lane.label, index, top, height: laneHeight, center: top + laneHeight / 2, tasks: lane.tasks };
485
+ });
486
+ for (const lane of lanes) for (const task of lane.tasks) task.lane = lane.index;
487
+ const laneAxis = spec.axes?.y?.show !== false && spec.axes?.y?.labels !== false;
488
+ const showLabels = spec.labels !== false;
489
+ const inset = Math.min(milestoneRadius + 3, plot.width * 0.08);
490
+ const scaleWith = (right) => {
491
+ const range = [plot.x + inset, plot.x + plot.width - right];
492
+ return kind === "time" ? timeScale({ domain, range }) : linearScale({ domain, range });
493
+ };
494
+ let xScale = scaleWith(inset);
495
+ if (showLabels) {
496
+ const room = milestoneLabelRoom(
497
+ parsed,
498
+ xScale,
499
+ plot,
500
+ milestoneRadius,
501
+ laneHeight,
502
+ tokens,
503
+ (task) => ganttLabelText({ laneAxis, kind, spec, extent }, task)
504
+ );
505
+ if (room > 0) xScale = scaleWith(Math.min(inset + room, Math.max(inset, plot.width * 0.3)));
506
+ }
507
+ placeTasks(parsed, lanes, xScale, plot, barHeight, milestoneRadius);
508
+ const tasks = parsed.filter((task) => finiteRect(task.rect));
509
+ const skipped = invalid + (parsed.length - tasks.length);
510
+ const labels = tickLabels(spec, kind, axis.values);
511
+ const xTicks = [];
512
+ axis.values.forEach((value, i) => {
513
+ const pos = xScale.map(value);
514
+ if (isFiniteNumber(pos) && pos >= plot.x - 0.5 && pos <= plot.x + plot.width + 0.5) xTicks.push({ value, pos, label: labels[i] });
515
+ });
516
+ const yTicks = lanes.map((lane) => ({ value: lane.key, pos: lane.center, label: lane.label }));
517
+ const shownGroups = frame.legendItems ? groupInfo.groups.slice(0, frame.legendItems.length) : [];
518
+ const groupRows = /* @__PURE__ */ new Map();
519
+ for (const task of tasks) {
520
+ if (task.groupKey === void 0) continue;
521
+ const list = groupRows.get(task.groupKey);
522
+ if (list) list.push(task.row);
523
+ else groupRows.set(task.groupKey, [task.row]);
524
+ }
525
+ const series = shownGroups.map((group) => ({
526
+ key: group.key,
527
+ label: group.label,
528
+ color: group.color,
529
+ value: group.raw,
530
+ rows: groupRows.get(group.key) ?? []
531
+ }));
532
+ const base = {
533
+ spec: baseSpec(spec, data),
534
+ tokens,
535
+ frame,
536
+ plot,
537
+ x: buildXModel(spec, kind, xScale),
538
+ y: buildYModel(spec, lanes, laneArea, plot),
539
+ series,
540
+ seriesField: spec.encoding.group?.field,
541
+ stacked: false,
542
+ orientation: "vertical",
543
+ project: (c, v) => ({ x: c, y: v }),
544
+ xTicks,
545
+ yTicks,
546
+ colorOf: (key) => groupInfo.colorOf(key),
547
+ colorDomain: groupInfo.groups.map((group) => group.key),
548
+ sketch
549
+ };
550
+ return {
551
+ spec,
552
+ tokens,
553
+ frame,
554
+ plot,
555
+ kind,
556
+ tasks,
557
+ lanes,
558
+ groups: groupInfo.groups,
559
+ grouped: groupInfo.grouped,
560
+ domain,
561
+ extent,
562
+ xScale,
563
+ laneHeight,
564
+ barHeight,
565
+ milestoneRadius,
566
+ cornerRadius: Math.max(0, spec.cornerRadius ?? 3),
567
+ showLabels,
568
+ laneAxis,
569
+ skipped,
570
+ base,
571
+ sketch
572
+ };
573
+ }
574
+ function round1(value) {
575
+ return Math.round(value * 10) / 10;
576
+ }
577
+ function plural(value, unit) {
578
+ return `${formatNumber(value, ",")} ${unit}${value === 1 ? "" : "s"}`;
579
+ }
580
+ function isNextCalendarDay(start, end) {
581
+ const a = new Date(start);
582
+ const b = new Date(end);
583
+ if (a.getHours() !== b.getHours() || a.getMinutes() !== b.getMinutes() || a.getSeconds() !== b.getSeconds() || a.getMilliseconds() !== b.getMilliseconds()) return false;
584
+ const next = new Date(a.getFullYear(), a.getMonth(), a.getDate() + 1);
585
+ return b.getFullYear() === next.getFullYear() && b.getMonth() === next.getMonth() && b.getDate() === next.getDate();
586
+ }
587
+ function ganttDuration(model, task) {
588
+ const span = task.end - task.start;
589
+ if (model.kind === "linear") {
590
+ const text = formatValue(span, model.spec.encoding.end.format ?? model.spec.encoding.start.format ?? ",");
591
+ return { short: text, long: text };
592
+ }
593
+ if (span < HOUR) {
594
+ const minutes = round1(span / MINUTE);
595
+ return { short: `${formatNumber(minutes, ",")}m`, long: `${formatNumber(minutes, ",")} min` };
596
+ }
597
+ if (span < DAY) {
598
+ if (isNextCalendarDay(task.start, task.end)) return { short: "1d", long: plural(1, "day") };
599
+ const hours = round1(span / HOUR);
600
+ return { short: `${formatNumber(hours, ",")}h`, long: plural(hours, "hour") };
601
+ }
602
+ if (span < YEAR) {
603
+ const exact = span / DAY;
604
+ const days = Math.abs(exact - Math.round(exact)) < 0.05 ? Math.round(exact) : round1(exact);
605
+ return { short: `${formatNumber(days, ",")}d`, long: plural(days, "day") };
606
+ }
607
+ const years = round1(span / (365.25 * DAY));
608
+ return { short: `${formatNumber(years, ",")}y`, long: plural(years, "year") };
609
+ }
610
+ function ganttInstant(model, value, which) {
611
+ const def = which === "start" ? model.spec.encoding.start : model.spec.encoding.end;
612
+ const format = def.format ?? (which === "end" ? model.spec.encoding.start.format : void 0);
613
+ if (model.kind === "linear") return format ? formatValue(value, format) : formatNumber(value, ",");
614
+ return format ? formatValue(value, format) : prettyDate(value);
615
+ }
616
+ function ganttShortInstant(model, value) {
617
+ const format = model.spec.encoding.start.format;
618
+ if (model.kind === "linear") return format ? formatValue(value, format) : formatNumber(value, ",");
619
+ if (format) return formatValue(value, format);
620
+ const date = new Date(value);
621
+ const [lo, hi] = model.extent;
622
+ const span = hi - lo;
623
+ const midnight = date.getHours() === 0 && date.getMinutes() === 0;
624
+ if (!midnight && span <= 2 * DAY) return formatDate(date, "%H:%M");
625
+ const crossesYears = span > 31 * DAY && new Date(lo).getFullYear() !== new Date(hi).getFullYear();
626
+ const day = crossesYears ? "%b %e, %Y" : "%b %e";
627
+ return midnight ? formatDate(date, day) : formatDate(date, `${day} %H:%M`);
628
+ }
629
+ function ganttLabelText(model, task) {
630
+ if (!model.laneAxis) return task.label;
631
+ if (task.milestone) return ganttShortInstant(model, task.start);
632
+ if (task.progress !== void 0) return `${Math.round(task.progress * 100)}%`;
633
+ return ganttDuration(model, task).short;
634
+ }
635
+ export {
636
+ buildGanttModel,
637
+ ganttDuration,
638
+ ganttInstant,
639
+ ganttLabelSize,
640
+ ganttLabelText,
641
+ ganttScaleKind,
642
+ ganttShortInstant,
643
+ ganttTimeTickLabels,
644
+ ganttValue,
645
+ lowerBound
646
+ };
647
+ //# sourceMappingURL=gantt.js.map