ggaction 0.0.13 → 0.0.16

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 (359) hide show
  1. package/CHANGELOG.md +146 -0
  2. package/README.md +41 -12
  3. package/knowledge/action-cards.json +1 -1
  4. package/knowledge/intent-taxonomy.json +1 -1
  5. package/knowledge/mcp-resources.json +1 -1
  6. package/knowledge/task-packet.schema.json +1 -1
  7. package/knowledge/task-resolver.js +1 -1
  8. package/package.json +39 -7
  9. package/src/BasicChartProgram.js +3 -1
  10. package/src/ChartProgram.js +2 -0
  11. package/src/accessibility.js +157 -0
  12. package/src/actions/basic.js +2 -2
  13. package/src/actions/boxPlots/components.js +20 -12
  14. package/src/actions/boxPlots/create.js +4 -5
  15. package/src/actions/boxPlots/edit.js +34 -9
  16. package/src/actions/boxPlots/materialize.js +12 -4
  17. package/src/actions/boxPlots/options.js +48 -16
  18. package/src/actions/canvas/actions.js +3 -3
  19. package/src/actions/canvas/fitting.js +1 -1
  20. package/src/actions/categoryOrder/index.js +21 -12
  21. package/src/actions/charts/area.js +6 -2
  22. package/src/actions/charts/bar.js +3 -2
  23. package/src/actions/charts/beeswarm.js +1 -1
  24. package/src/actions/charts/density.js +7 -3
  25. package/src/actions/charts/ecdf.js +6 -3
  26. package/src/actions/charts/endpoints.js +29 -7
  27. package/src/actions/charts/heatmap.js +3 -2
  28. package/src/actions/charts/histogram.js +5 -4
  29. package/src/actions/charts/horizon.js +4 -2
  30. package/src/actions/charts/interval-regression.js +7 -4
  31. package/src/actions/charts/line.js +4 -2
  32. package/src/actions/charts/parallel.js +9 -3
  33. package/src/actions/charts/pie.js +11 -3
  34. package/src/actions/charts/polar.js +17 -6
  35. package/src/actions/charts/radar.js +9 -3
  36. package/src/actions/charts/radial.js +12 -4
  37. package/src/actions/charts/raincloud.js +2 -2
  38. package/src/actions/charts/rug-strip.js +8 -4
  39. package/src/actions/charts/scatter.js +4 -2
  40. package/src/actions/composition/actions.js +29 -24
  41. package/src/actions/coordinates/actions.js +2 -2
  42. package/src/actions/coordinates/edit.js +76 -0
  43. package/src/actions/data/basicBin2d.js +4 -5
  44. package/src/actions/data/bin.js +3 -3
  45. package/src/actions/data/bin2d.js +63 -193
  46. package/src/actions/data/bin2dMaterialize.js +4 -5
  47. package/src/actions/data/box.js +4 -4
  48. package/src/actions/data/complete.js +26 -0
  49. package/src/actions/data/computed.js +4 -4
  50. package/src/actions/data/create.js +7 -14
  51. package/src/actions/data/density.js +15 -23
  52. package/src/actions/data/derived.js +57 -31
  53. package/src/actions/data/ecdf.js +2 -2
  54. package/src/actions/data/edit.js +551 -0
  55. package/src/actions/data/filter.js +28 -22
  56. package/src/actions/data/fold.js +2 -2
  57. package/src/actions/data/gradientProfile.js +2 -2
  58. package/src/actions/data/horizon.js +2 -2
  59. package/src/actions/data/impute.js +26 -0
  60. package/src/actions/data/index.js +62 -47
  61. package/src/actions/data/interval.js +2 -2
  62. package/src/actions/data/intervalEdit.js +26 -18
  63. package/src/actions/data/normalize.js +27 -0
  64. package/src/actions/data/regression.js +21 -27
  65. package/src/actions/data/revise.js +48 -0
  66. package/src/actions/data/revisionBindings.js +125 -0
  67. package/src/actions/data/shared.js +20 -4
  68. package/src/actions/data/stack.js +2 -2
  69. package/src/actions/data/summary.js +3 -3
  70. package/src/actions/data/timeUnit.js +6 -3
  71. package/src/actions/data/window.js +3 -3
  72. package/src/actions/encodings/angle.js +1 -1
  73. package/src/actions/encodings/appearance.js +4 -4
  74. package/src/actions/encodings/barWidth.js +1 -1
  75. package/src/actions/encodings/channels.js +415 -0
  76. package/src/actions/encodings/color/index.js +3 -2
  77. package/src/actions/encodings/density.js +7 -4
  78. package/src/actions/encodings/histogram.js +4 -3
  79. package/src/actions/encodings/horizon.js +6 -8
  80. package/src/actions/encodings/index.js +4 -0
  81. package/src/actions/encodings/offset.js +22 -15
  82. package/src/actions/encodings/parallel.js +4 -5
  83. package/src/actions/encodings/pathOrder.js +6 -11
  84. package/src/actions/encodings/position/apply.js +53 -7
  85. package/src/actions/encodings/position/index.js +14 -6
  86. package/src/actions/encodings/position/policies/bar.js +9 -0
  87. package/src/actions/encodings/position/resolve.js +24 -7
  88. package/src/actions/encodings/ranged.js +5 -5
  89. package/src/actions/encodings/remove.js +13 -9
  90. package/src/actions/encodings/ruleAppearance.js +2 -24
  91. package/src/actions/encodings/seriesLayout.js +2 -1
  92. package/src/actions/encodings/shared.js +82 -14
  93. package/src/actions/encodings/stroke.js +226 -0
  94. package/src/actions/encodings/strokeDash.js +2 -2
  95. package/src/actions/encodings/text.js +1 -1
  96. package/src/actions/errorBands/create.js +34 -20
  97. package/src/actions/errorBands/edit.js +34 -137
  98. package/src/actions/errorBars/create.js +43 -20
  99. package/src/actions/errorBars/edit.js +29 -125
  100. package/src/actions/facets/actions.js +267 -73
  101. package/src/actions/facets/derive.js +99 -28
  102. package/src/actions/facets/guides.js +4 -5
  103. package/src/actions/facets/replay.js +4 -5
  104. package/src/actions/gradientPlots/components.js +15 -8
  105. package/src/actions/gradientPlots/create.js +4 -5
  106. package/src/actions/gradientPlots/edit.js +18 -9
  107. package/src/actions/gradientPlots/materialize.js +5 -3
  108. package/src/actions/gradientPlots/options.js +10 -2
  109. package/src/actions/gradientPlots/rebind.js +4 -5
  110. package/src/actions/guides/applicability.js +8 -2
  111. package/src/actions/guides/axes/axes.js +23 -4
  112. package/src/actions/guides/axes/axis.js +2 -2
  113. package/src/actions/guides/axes/edit.js +2 -2
  114. package/src/actions/guides/axes/labels.js +67 -21
  115. package/src/actions/guides/axes/lines.js +15 -9
  116. package/src/actions/guides/axes/parallel/lifecycle.js +13 -13
  117. package/src/actions/guides/axes/parallel/resolve.js +6 -2
  118. package/src/actions/guides/axes/parallel.js +5 -5
  119. package/src/actions/guides/axes/remove.js +4 -4
  120. package/src/actions/guides/axes/tickGroups.js +6 -5
  121. package/src/actions/guides/axes/ticks.js +19 -6
  122. package/src/actions/guides/axes/titles.js +21 -13
  123. package/src/actions/guides/grids/grid.js +18 -29
  124. package/src/actions/guides/grids/resolve.js +7 -2
  125. package/src/actions/guides/guides.js +20 -4
  126. package/src/actions/guides/legends/blocks.js +426 -0
  127. package/src/actions/guides/legends/categorical/actions.js +138 -52
  128. package/src/actions/guides/legends/categorical/components.js +55 -45
  129. package/src/actions/guides/legends/categorical/index.js +37 -33
  130. package/src/actions/guides/legends/categorical/layout.js +98 -16
  131. package/src/actions/guides/legends/categorical/options.js +2 -2
  132. package/src/actions/guides/legends/categorical/recipes.js +111 -20
  133. package/src/actions/guides/legends/categorical/resolve.js +12 -8
  134. package/src/actions/guides/legends/categorical/symbols.js +104 -52
  135. package/src/actions/guides/legends/continuous/common.js +76 -20
  136. package/src/actions/guides/legends/continuous/gradient.js +95 -158
  137. package/src/actions/guides/legends/continuous/index.js +2 -0
  138. package/src/actions/guides/legends/continuous/interval.js +21 -16
  139. package/src/actions/guides/legends/continuous/opacity.js +37 -83
  140. package/src/actions/guides/legends/continuous/stroke.js +225 -0
  141. package/src/actions/guides/legends/creation.js +14 -1
  142. package/src/actions/guides/legends/edit.js +159 -60
  143. package/src/actions/guides/legends/focused.js +5 -5
  144. package/src/actions/guides/legends/index.js +2 -0
  145. package/src/actions/guides/legends/lane.js +59 -24
  146. package/src/actions/guides/legends/lifecycle.js +19 -8
  147. package/src/actions/guides/legends/remove.js +17 -8
  148. package/src/actions/guides/legends/sampling.js +140 -0
  149. package/src/actions/guides/legends/size.js +100 -108
  150. package/src/actions/guides/legends/strokeWidth.js +38 -92
  151. package/src/actions/guides/legends/target.js +112 -1
  152. package/src/actions/guides/legends/transition.js +165 -16
  153. package/src/actions/guides/polar/axes/facade.js +8 -8
  154. package/src/actions/guides/polar/axes/labels.js +29 -10
  155. package/src/actions/guides/polar/axes/lines.js +19 -19
  156. package/src/actions/guides/polar/axes/shared.js +16 -0
  157. package/src/actions/guides/polar/axes/ticks.js +10 -16
  158. package/src/actions/guides/polar/axes/titles.js +6 -6
  159. package/src/actions/guides/polar/grids.js +12 -14
  160. package/src/actions/guides/polar/resolve.js +12 -8
  161. package/src/actions/index.js +16 -3
  162. package/src/actions/intervals/revision.js +126 -0
  163. package/src/actions/marks/arc/actions.js +80 -22
  164. package/src/actions/marks/area/actions.js +38 -13
  165. package/src/actions/marks/area/materialize.js +17 -1
  166. package/src/actions/marks/bar/create.js +12 -3
  167. package/src/actions/marks/bar/edit.js +21 -4
  168. package/src/actions/marks/bar/materialize.js +34 -40
  169. package/src/actions/marks/index.js +10 -1
  170. package/src/actions/marks/line/actions.js +40 -17
  171. package/src/actions/marks/line/materialize.js +29 -10
  172. package/src/actions/marks/point/create.js +9 -3
  173. package/src/actions/marks/point/edit.js +19 -7
  174. package/src/actions/marks/point/jitter.js +6 -8
  175. package/src/actions/marks/point/materialize.js +48 -22
  176. package/src/actions/marks/point/packing.js +6 -8
  177. package/src/actions/marks/rect/actions.js +36 -15
  178. package/src/actions/marks/references.js +602 -33
  179. package/src/actions/marks/remove.js +67 -41
  180. package/src/actions/marks/rule/actions.js +51 -14
  181. package/src/actions/marks/shared.js +1 -1
  182. package/src/actions/marks/text/actions.js +79 -14
  183. package/src/actions/marks/text/index.js +4 -0
  184. package/src/actions/marks/text/layout.js +157 -17
  185. package/src/actions/marks/text/removal.js +173 -0
  186. package/src/actions/marks/text/selection.js +72 -0
  187. package/src/actions/marks/tick/actions.js +25 -8
  188. package/src/actions/primitives/createGraphics.js +5 -4
  189. package/src/actions/primitives/editGraphics.js +31 -4
  190. package/src/actions/primitives/graphicProperties.js +6 -0
  191. package/src/actions/primitives/semantic.js +11 -3
  192. package/src/actions/primitives/semanticAction.js +90 -14
  193. package/src/actions/primitives/semanticValidation/dataset.js +2 -4
  194. package/src/actions/primitives/semanticValidation/guide.js +1 -1
  195. package/src/actions/primitives/semanticValidation/index.js +9 -1
  196. package/src/actions/primitives/semanticValidation/layer.js +5 -0
  197. package/src/actions/primitives/semanticValidation/scale.js +28 -7
  198. package/src/actions/regression/components.js +36 -25
  199. package/src/actions/regression/create.js +13 -6
  200. package/src/actions/regression/edit.js +24 -11
  201. package/src/actions/resources/index.js +7 -0
  202. package/src/actions/resources/remove.js +173 -0
  203. package/src/actions/scales/channels.js +212 -0
  204. package/src/actions/scales/consumers/common.js +1 -1
  205. package/src/actions/scales/consumers/families.js +3 -2
  206. package/src/actions/scales/consumers/index.js +19 -2
  207. package/src/actions/scales/consumers/seriesLayout.js +28 -14
  208. package/src/actions/scales/create.js +55 -23
  209. package/src/actions/scales/definitions.js +94 -40
  210. package/src/actions/scales/edit.js +67 -12
  211. package/src/actions/scales/editPolicy.js +81 -11
  212. package/src/actions/scales/index.js +6 -0
  213. package/src/actions/scales/materialize.js +5 -4
  214. package/src/actions/scales/offset.js +48 -0
  215. package/src/actions/scales/parallel.js +71 -0
  216. package/src/actions/scales/preview.js +111 -10
  217. package/src/actions/scales/quantitativeColor.js +4 -5
  218. package/src/actions/selection/actions.js +179 -66
  219. package/src/actions/selection/index.js +3 -0
  220. package/src/actions/textMetrics/index.js +56 -0
  221. package/src/actions/theme/actions.js +70 -15
  222. package/src/actions/theme/composition.js +238 -0
  223. package/src/actions/theme/index.js +9 -2
  224. package/src/actions/theme/reconcile.js +313 -121
  225. package/src/actions/theme/state.js +160 -0
  226. package/src/actions/titles/actions.js +8 -8
  227. package/src/actions/titles/resolve.js +3 -3
  228. package/src/actions/violinPlots/create.js +6 -3
  229. package/src/actions/violinPlots/edit.js +2 -1
  230. package/src/core/action.js +117 -35
  231. package/src/core/compositionState.js +6 -1
  232. package/src/core/diagnostics.js +16 -0
  233. package/src/core/extensionRegistry.js +27 -0
  234. package/src/core/font.js +18 -0
  235. package/src/core/identifiers.js +5 -4
  236. package/src/core/immutable.js +10 -3
  237. package/src/core/optionRequirements.js +8 -0
  238. package/src/core/programState.js +21 -1
  239. package/src/core/resourceReferences.js +341 -0
  240. package/src/core/textMetricProfile.js +28 -0
  241. package/src/core/textMetrics.js +24 -3
  242. package/src/core/validation.js +22 -10
  243. package/src/core/vocabulary.js +16 -3
  244. package/src/diagnostics.js +1 -0
  245. package/src/grammar/bars/aggregate.js +4 -1
  246. package/src/grammar/bars/geometry.js +44 -0
  247. package/src/grammar/bin.js +54 -9
  248. package/src/grammar/complete.js +279 -0
  249. package/src/grammar/computed.js +265 -64
  250. package/src/grammar/coordinates.js +37 -0
  251. package/src/grammar/density.js +239 -37
  252. package/src/grammar/displayLabels.js +57 -0
  253. package/src/grammar/facets/dependencies.js +133 -1
  254. package/src/grammar/facets/guides.js +3 -0
  255. package/src/grammar/facets/index.js +7 -47
  256. package/src/grammar/facets/scales.js +15 -18
  257. package/src/grammar/impute.js +341 -0
  258. package/src/grammar/markLabelSelection.js +57 -0
  259. package/src/grammar/markLabels.js +18 -1
  260. package/src/grammar/normalize.js +366 -0
  261. package/src/grammar/pathSeries.js +26 -8
  262. package/src/grammar/pointShapes.js +13 -4
  263. package/src/grammar/polar.js +90 -8
  264. package/src/grammar/regression/index.js +1 -0
  265. package/src/grammar/regression/parameters.js +23 -0
  266. package/src/grammar/roundedRect.js +180 -0
  267. package/src/grammar/rules.js +1 -0
  268. package/src/grammar/scales/colorConsumers.js +20 -1
  269. package/src/grammar/scales/continuous.js +2 -2
  270. package/src/grammar/scales/definition.js +27 -4
  271. package/src/grammar/scales/index.js +1 -0
  272. package/src/grammar/scales/ordinal.js +12 -3
  273. package/src/grammar/scales/policies.js +2 -2
  274. package/src/grammar/scales/size.js +456 -0
  275. package/src/grammar/scales/types.js +8 -0
  276. package/src/grammar/schemas/concreteGraphic.js +14 -2
  277. package/src/grammar/schemas/graphic.js +15 -0
  278. package/src/grammar/schemas/graphicBounds.js +190 -41
  279. package/src/grammar/schemas/semanticPath.js +7 -2
  280. package/src/grammar/statisticalReference.js +103 -0
  281. package/src/grammar/strokeStyle.js +77 -0
  282. package/src/grammar/summary.js +78 -16
  283. package/src/grammar/timeUnit.js +216 -5
  284. package/src/grammar/transformTopology.js +4 -0
  285. package/src/grammar/transforms.js +394 -28
  286. package/src/grammar/weightedStatistics.js +374 -0
  287. package/src/grammar/window.js +221 -16
  288. package/src/layout/aspect.js +80 -0
  289. package/src/layout/facets.js +59 -5
  290. package/src/layout/labels.js +351 -7
  291. package/src/layout/legend.js +4 -4
  292. package/src/layout/legendItems.js +6 -6
  293. package/src/layout/text.js +10 -9
  294. package/src/layout/title.js +9 -9
  295. package/src/materialization/bars/aggregate.js +25 -2
  296. package/src/materialization/bars/histogram.js +84 -24
  297. package/src/materialization/bars/ranged.js +19 -3
  298. package/src/materialization/bars/resolve.js +7 -4
  299. package/src/materialization/composition.js +3 -1
  300. package/src/materialization/coordinateBounds.js +204 -0
  301. package/src/materialization/dependencies.js +36 -0
  302. package/src/materialization/facetGuides/legacyCategorical.js +3 -0
  303. package/src/materialization/facetGuides/placement.js +9 -3
  304. package/src/materialization/facetGuides/preparation.js +13 -8
  305. package/src/materialization/facetHeaders.js +347 -0
  306. package/src/materialization/facets.js +15 -65
  307. package/src/materialization/guides/layout.js +3 -3
  308. package/src/materialization/guides/resources.js +26 -0
  309. package/src/materialization/legends.js +1 -1
  310. package/src/materialization/marks/index.js +11 -5
  311. package/src/materialization/marks/policies.js +2 -1
  312. package/src/materialization/rect.js +25 -12
  313. package/src/materialization/rectConfig.js +5 -1
  314. package/src/materialization/scaleGuideDependencies.js +10 -0
  315. package/src/materialization/scales/map.js +5 -3
  316. package/src/materialization/scales/policies/binnedPosition.js +2 -2
  317. package/src/materialization/scales/policies/offset.js +50 -8
  318. package/src/materialization/scales/policies/series.js +4 -1
  319. package/src/materialization/scales/resolve.js +22 -6
  320. package/src/materialization/selection/items/arc.js +28 -4
  321. package/src/materialization/selection/items/bar.js +30 -3
  322. package/src/materialization/selection/items/common.js +20 -5
  323. package/src/materialization/selection/items/rect.js +28 -4
  324. package/src/materialization/selection/path.js +1 -1
  325. package/src/materialization/selection/point.js +3 -1
  326. package/src/materialization/text.js +265 -14
  327. package/src/materialization/typography.js +31 -0
  328. package/src/mcp/cli.js +5 -3
  329. package/src/persistence/codec.js +65 -0
  330. package/src/persistence/validation.js +185 -0
  331. package/src/persistence.js +74 -0
  332. package/src/renderers/canvas/circle.js +2 -3
  333. package/src/renderers/canvas/index.js +5 -4
  334. package/src/renderers/canvas/line.js +2 -3
  335. package/src/renderers/canvas/native.js +4 -4
  336. package/src/renderers/canvas/path.js +2 -3
  337. package/src/renderers/canvas/rect.js +2 -3
  338. package/src/renderers/canvas/stroke.js +11 -0
  339. package/src/renderers/nativeBackend.js +10 -0
  340. package/src/renderers/options.js +13 -0
  341. package/src/renderers/pdf.js +25 -54
  342. package/src/renderers/png.js +22 -17
  343. package/src/renderers/svg.js +29 -14
  344. package/src/renderers/text.js +1 -11
  345. package/src/selectors/coordinates.js +3 -1
  346. package/src/selectors/datasets.js +38 -5
  347. package/src/selectors/layers.js +10 -4
  348. package/src/selectors/markOwners.js +46 -0
  349. package/src/selectors/scales.js +6 -4
  350. package/src/theme/defaults.js +103 -1
  351. package/src/version.js +2 -0
  352. package/types/accessibility.d.ts +37 -0
  353. package/types/basic.d.ts +10 -2
  354. package/types/diagnostics.d.ts +15 -0
  355. package/types/index.d.ts +90 -0
  356. package/types/pdf.d.ts +9 -0
  357. package/types/persistence.d.ts +7 -0
  358. package/types/png.d.ts +9 -0
  359. package/types/program.d.ts +944 -118
@@ -9,7 +9,7 @@ import {
9
9
  validateNonNegativeFinite,
10
10
  validatePositiveFinite
11
11
  } from "../../../core/validation.js";
12
- import { resolveGraphicBounds } from "../../../layout/canvas.js";
12
+ import { resolveGuideCoordinateBounds } from "../../../materialization/coordinateBounds.js";
13
13
  import {
14
14
  isTransformedScaleType,
15
15
  mapContinuousScaleValues,
@@ -38,11 +38,15 @@ import {
38
38
  import { resolveConcreteGraphicBounds } from
39
39
  "../../../grammar/schemas/graphicBounds.js";
40
40
  import { wrapText } from "../../../layout/text.js";
41
+ import {
42
+ normalizeDisplayLabelMap,
43
+ resolveDisplayLabel
44
+ } from "../../../grammar/displayLabels.js";
41
45
 
42
46
  const OPTIONS = [
43
47
  "scale", "position", "count", "values", "offset", "format", "color",
44
48
  "fontSize", "fontFamily", "fontWeight", "rotation", "maxWidth", "wrap",
45
- "lineHeight", "overlap"
49
+ "lineHeight", "overlap", "labelMap"
46
50
  ];
47
51
 
48
52
  const DEFAULTS = {
@@ -136,6 +140,24 @@ function validateConfig(channel, config) {
136
140
  }
137
141
  }
138
142
 
143
+ function normalizeAxisLabelMap(program, config, args, operation) {
144
+ if (!Object.hasOwn(args, "labelMap")) return config;
145
+ const scale = program.resolvedScales[config.scale];
146
+ if (!["ordinal", "band", "point"].includes(scale?.type)) {
147
+ throw new Error(`${operation} labelMap requires a categorical scale.`);
148
+ }
149
+ const next = { ...config };
150
+ if (args.labelMap === "auto") {
151
+ delete next.labelMap;
152
+ } else {
153
+ next.labelMap = normalizeDisplayLabelMap(
154
+ args.labelMap,
155
+ `${operation} labelMap`
156
+ );
157
+ }
158
+ return next;
159
+ }
160
+
139
161
  function assertTickCompatibility(ticks, config, operation) {
140
162
  if (!ticks) return;
141
163
  if (ticks.scale !== config.scale || ticks.mode !== config.mode) throw new Error(`${operation} conflicts with axis ticks.`);
@@ -143,7 +165,7 @@ function assertTickCompatibility(ticks, config, operation) {
143
165
  if (config.mode === "values" && !sameOrderedValues(ticks.values, config.values)) throw new Error(`${operation} conflicts with axis ticks.`);
144
166
  }
145
167
 
146
- function expandWrappedLabels(resolved, text, config, channel) {
168
+ function expandWrappedLabels(resolved, text, config, channel, profile) {
147
169
  if (config.maxWidth === undefined) {
148
170
  return {
149
171
  ...resolved,
@@ -162,7 +184,7 @@ function expandWrappedLabels(resolved, text, config, channel) {
162
184
  const lines = wrapText(text[index], {
163
185
  maxWidth: config.maxWidth,
164
186
  mode: config.wrap,
165
- style
187
+ style, profile
166
188
  });
167
189
  validateGeneratedItemLimit(
168
190
  expanded.text.length + lines.length,
@@ -198,8 +220,15 @@ function unionLabelBounds(records) {
198
220
 
199
221
  function resolve(program, channel, config) {
200
222
  const scale = program.resolvedScales[config.scale];
201
- const bounds = resolveGraphicBounds(program);
223
+ const bounds = resolveGuideCoordinateBounds(program, {
224
+ coordinate: program.semanticSpec.guides.axis?.[channel]?.coordinate,
225
+ scale: config.scale,
226
+ channel
227
+ });
202
228
  const discrete = ["ordinal", "band", "point"].includes(scale?.type);
229
+ if (config.labelMap !== undefined && !discrete) {
230
+ throw new Error("Axis labelMap requires a categorical scale.");
231
+ }
203
232
  if ((
204
233
  !["linear", "time", "ordinal", "band", "point"].includes(scale?.type) &&
205
234
  !isTransformedScaleType(scale?.type)
@@ -217,9 +246,7 @@ function resolve(program, channel, config) {
217
246
  const positions = discrete
218
247
  ? mapOrdinalPositionValues(values, scale)
219
248
  : mapContinuousScaleValues(values, scale);
220
- const text = scale.type === "time" && config.format === "auto"
221
- ? formatTimeTicks(values, scale.domain)
222
- : values.map(value => formatAxisValue(
249
+ const fallback = value => formatAxisValue(
223
250
  value,
224
251
  scale.type,
225
252
  config.format,
@@ -228,7 +255,12 @@ function resolve(program, channel, config) {
228
255
  : isTransformedScaleType(scale.type)
229
256
  ? formatTransformedTick(scale.type, item)
230
257
  : String(item)
231
- ));
258
+ );
259
+ const text = discrete
260
+ ? values.map(value => resolveDisplayLabel(value, config.labelMap, fallback))
261
+ : scale.type === "time" && config.format === "auto"
262
+ ? formatTimeTicks(values, scale.domain)
263
+ : values.map(fallback);
232
264
  const geometry = {
233
265
  values,
234
266
  ...resolveAxisLabelGeometry({
@@ -239,7 +271,7 @@ function resolve(program, channel, config) {
239
271
  offset: config.offset
240
272
  })
241
273
  };
242
- const resolved = expandWrappedLabels(geometry, text, config, channel);
274
+ const resolved = expandWrappedLabels(geometry, text, config, channel, program.materializationConfigs.textMetrics);
243
275
  const canvas = findCanvasGraphic(program)?.properties;
244
276
  const labelBounds = resolved.text.map((value, index) => resolveTextBounds({
245
277
  x: Array.isArray(resolved.x) ? resolved.x[index] : resolved.x,
@@ -251,7 +283,7 @@ function resolve(program, channel, config) {
251
283
  textAlign: resolved.textAlign,
252
284
  textBaseline: resolved.textBaseline,
253
285
  rotation: config.rotation
254
- }));
286
+ }, program.materializationConfigs.textMetrics));
255
287
  const groupedBounds = unionLabelBounds(labelBounds.map((bounds, index) => ({
256
288
  bounds,
257
289
  group: resolved.groups[index]
@@ -267,7 +299,7 @@ function resolve(program, channel, config) {
267
299
  throw new Error(`The ${channel}-axis labels overlap each other.`);
268
300
  }
269
301
  const title = program.graphicSpec.objects[`${channel}AxisTitle`]
270
- ? resolveConcreteGraphicBounds(program.graphicSpec, `${channel}AxisTitle`)
302
+ ? resolveConcreteGraphicBounds(program.graphicSpec, `${channel}AxisTitle`, program.materializationConfigs.textMetrics)
271
303
  : undefined;
272
304
  if (title &&
273
305
  program.guideConfigs.axis?.[channel]?.title?.inferredOffset !== true &&
@@ -294,13 +326,14 @@ function makeEdit(channel) {
294
326
  const mode = Object.hasOwn(args, "values") || inferredValues !== undefined
295
327
  ? "values"
296
328
  : Object.hasOwn(args, "count") ? "count" : previous.mode;
297
- const config = normalizeLabelLayout({
329
+ let config = normalizeLabelLayout({
298
330
  ...previous,
299
331
  ...args,
300
332
  ...(inferredValues === undefined ? {} : { values: inferredValues }),
301
333
  ...(explicitMode ? { inferredValues: false } : {}),
302
334
  mode
303
335
  }, args, op);
336
+ config = normalizeAxisLabelMap(this, config, args, op);
304
337
  if (mode === "values") delete config.count; else delete config.values;
305
338
  validateConfig(channel, config);
306
339
  assertTickCompatibility(this.guideConfigs.axis?.[channel]?.ticks, config, op);
@@ -333,8 +366,8 @@ function makeEdit(channel) {
333
366
  }));
334
367
  }
335
368
 
336
- const editXAxisLabels = makeEdit("x");
337
- const editYAxisLabels = makeEdit("y");
369
+ const editXAxisLabels = /* @__PURE__ */ makeEdit("x");
370
+ const editYAxisLabels = /* @__PURE__ */ makeEdit("y");
338
371
 
339
372
  function makeCreate(channel) {
340
373
  const op = channel === "x" ? "createXAxisLabels" : "createYAxisLabels";
@@ -349,8 +382,15 @@ function makeCreate(channel) {
349
382
  const ticks = this.guideConfigs.axis?.[channel]?.ticks;
350
383
  const hasValues = Object.hasOwn(args, "values");
351
384
  const hasCount = Object.hasOwn(args, "count");
352
- const mode = hasValues ? "values" : hasCount ? "count" : ticks?.mode ?? "count";
353
- const config = normalizeLabelLayout({
385
+ const resolvedScale = this.resolvedScales[scale];
386
+ const inferredDiscreteValues = !hasValues && !hasCount && ticks === undefined &&
387
+ ["ordinal", "band", "point"].includes(resolvedScale?.type)
388
+ ? resolvedScale.domain
389
+ : undefined;
390
+ const mode = hasValues || inferredDiscreteValues !== undefined
391
+ ? "values"
392
+ : hasCount ? "count" : ticks?.mode ?? "count";
393
+ let config = normalizeLabelLayout({
354
394
  scale,
355
395
  position: defaultAxisPosition(channel),
356
396
  offset: channel === "x" ? 18 : 12,
@@ -362,10 +402,16 @@ function makeCreate(channel) {
362
402
  rotation: DEFAULTS.rotation,
363
403
  overlap: DEFAULTS.overlap,
364
404
  ...args,
365
- inferredValues: !hasValues && !hasCount && ticks?.inferredValues === true,
405
+ inferredValues: !hasValues && !hasCount &&
406
+ (ticks?.inferredValues === true || inferredDiscreteValues !== undefined),
366
407
  mode
367
408
  }, args, op);
368
- if (mode === "values") config.values ??= ticks?.values; else config.count ??= ticks?.count ?? DEFAULTS.count;
409
+ config = normalizeAxisLabelMap(this, config, args, op);
410
+ if (mode === "values") {
411
+ config.values ??= ticks?.values ?? inferredDiscreteValues;
412
+ } else {
413
+ config.count ??= ticks?.count ?? DEFAULTS.count;
414
+ }
369
415
  validateConfig(channel, config);
370
416
  assertTickCompatibility(ticks, config, op);
371
417
  resolve(this, channel, config);
@@ -380,8 +426,8 @@ function makeCreate(channel) {
380
426
  }));
381
427
  }
382
428
 
383
- const createXAxisLabels = makeCreate("x");
384
- const createYAxisLabels = makeCreate("y");
429
+ const createXAxisLabels = /* @__PURE__ */ makeCreate("x");
430
+ const createYAxisLabels = /* @__PURE__ */ makeCreate("y");
385
431
 
386
432
  export function registerAxisLabelActions(Class) {
387
433
  Class.prototype.editXAxisLabels = editXAxisLabels;
@@ -1,3 +1,4 @@
1
+ import { editGraphicProperties } from "../../primitives/graphicProperties.js";
1
2
  import { isSourceOwnedText } from "../../../grammar/text.js";
2
3
  import { withGuideLayoutValidation } from "../../../materialization/guides/layout.js";
3
4
  import { action } from "../../../core/action.js";
@@ -7,7 +8,7 @@ import {
7
8
  validateNonEmptyString,
8
9
  validateNonNegativeFinite
9
10
  } from "../../../core/validation.js";
10
- import { resolveGraphicBounds } from "../../../layout/canvas.js";
11
+ import { resolveGuideCoordinateBounds } from "../../../materialization/coordinateBounds.js";
11
12
  import { DEFAULT_COLORS } from "../../../theme/defaults.js";
12
13
  import {
13
14
  defaultAxisPosition,
@@ -53,7 +54,11 @@ function resolveGeometry(program, channel, scaleId, position) {
53
54
 
54
55
  const resolvedScale = program.resolvedScales[scaleId];
55
56
  const range = resolvedScale?.range;
56
- const bounds = resolveGraphicBounds(program);
57
+ const bounds = resolveGuideCoordinateBounds(program, {
58
+ coordinate: program.semanticSpec.guides.axis?.[channel]?.coordinate,
59
+ scale: scaleId,
60
+ channel
61
+ });
57
62
 
58
63
  if (!Array.isArray(range) || range.length !== 2 || !range.every(Number.isFinite)) {
59
64
  throw new Error(`Axis line requires a resolved numeric scale "${scaleId}".`);
@@ -115,15 +120,16 @@ function createEditAxisLine(channel) {
115
120
  next = next.editGraphics({ target: graphic, property, value: geometry[property] });
116
121
  }
117
122
 
118
- return next
119
- .editGraphics({ target: graphic, property: "stroke", value: color })
120
- .editGraphics({ target: graphic, property: "strokeWidth", value: lineWidth });
123
+ return editGraphicProperties(next, graphic, {
124
+ stroke: color,
125
+ strokeWidth: lineWidth
126
+ });
121
127
  })
122
128
  );
123
129
  }
124
130
 
125
- const editXAxisLine = createEditAxisLine("x");
126
- const editYAxisLine = createEditAxisLine("y");
131
+ const editXAxisLine = /* @__PURE__ */ createEditAxisLine("x");
132
+ const editYAxisLine = /* @__PURE__ */ createEditAxisLine("y");
127
133
 
128
134
  function createAxisLine(channel) {
129
135
  const operation = channel === "x" ? "createXAxisLine" : "createYAxisLine";
@@ -160,8 +166,8 @@ function createAxisLine(channel) {
160
166
  );
161
167
  }
162
168
 
163
- const createXAxisLine = createAxisLine("x");
164
- const createYAxisLine = createAxisLine("y");
169
+ const createXAxisLine = /* @__PURE__ */ createAxisLine("x");
170
+ const createYAxisLine = /* @__PURE__ */ createAxisLine("y");
165
171
 
166
172
  export function registerAxisLineActions(ProgramClass) {
167
173
  ProgramClass.prototype.editXAxisLine = editXAxisLine;
@@ -1,5 +1,5 @@
1
- import { action } from "../../../../core/action.js";
2
- import { validateNonEmptyString, validateOptionObject } from "../../../../core/validation.js";
1
+ import { action, closedAction } from "../../../../core/action.js";
2
+ import { validateNonEmptyString } from "../../../../core/validation.js";
3
3
  import { requireParallelAxisLayer, resolveParallelAxisTarget } from "./resolve.js";
4
4
  import {
5
5
  defaultParallelAxis, hasParallelAxisParts, PARALLEL_AXIS_GRAPHICS,
@@ -45,10 +45,10 @@ function withTitle(program, args, create) {
45
45
  ...(titles.length === 0 ? { remove: true } : { value: titles }) });
46
46
  }
47
47
 
48
- const createParallelAxes = action({
48
+ const createParallelAxes = /* @__PURE__ */ closedAction({
49
49
  op: "createParallelAxes", description: "Create axes for every encoded Parallel dimension."
50
- }, function (args = {}) {
51
- validateOptionObject(args, ["target", "coordinate"], "createParallelAxes");
50
+ }, ["target", "coordinate"], function (args = {}) {
51
+
52
52
  const resolved = owner(this, args, "createParallelAxes");
53
53
  if (resolved.stored !== undefined || this.guideConfigs.axis?.parallel !== undefined ||
54
54
  Object.values(PARALLEL_AXIS_GRAPHICS).some(id => this.graphicSpec.objects[id] !== undefined)) {
@@ -76,13 +76,13 @@ function makeAxisAction(create) {
76
76
  });
77
77
  }
78
78
 
79
- const createParallelAxis = makeAxisAction(true);
80
- const editParallelAxis = makeAxisAction(false);
79
+ const createParallelAxis = /* @__PURE__ */ makeAxisAction(true);
80
+ const editParallelAxis = /* @__PURE__ */ makeAxisAction(false);
81
81
 
82
- const removeParallelAxis = action({
82
+ const removeParallelAxis = /* @__PURE__ */ closedAction({
83
83
  op: "removeParallelAxis", description: "Remove every component of one Parallel field axis."
84
- }, function (args = {}) {
85
- validateOptionObject(args, ["field", "target"], "removeParallelAxis");
84
+ }, ["field", "target"], function (args = {}) {
85
+
86
86
  validateNonEmptyString(args.field, "Parallel axis field");
87
87
  const resolved = owner(this, args, "removeParallelAxis", true);
88
88
  const config = resolveParallelAxisConfigs(this, resolved.dimensions).dimensions.find(dimension => dimension.field === args.field);
@@ -91,10 +91,10 @@ const removeParallelAxis = action({
91
91
  ...Object.fromEntries(PARALLEL_AXIS_PARTS.filter(part => config[part] !== undefined).map(part => [part, false])) });
92
92
  });
93
93
 
94
- const removeParallelAxes = action({
94
+ const removeParallelAxes = /* @__PURE__ */ closedAction({
95
95
  op: "removeParallelAxes", description: "Remove all Parallel axis semantics, recipes and graphics."
96
- }, function (args = {}) {
97
- validateOptionObject(args, ["target", "coordinate"], "removeParallelAxes");
96
+ }, ["target", "coordinate"], function (args = {}) {
97
+
98
98
  const stored = this.semanticSpec.guides.axis?.parallel;
99
99
  if (stored === undefined) throw new Error("removeParallelAxes requires existing Parallel axes.");
100
100
  if (args.target !== undefined && args.target !== stored.target ||
@@ -6,7 +6,7 @@ import {
6
6
  transformedTicks
7
7
  } from "../../../../grammar/scales/index.js";
8
8
  import { niceTicks } from "../../../../grammar/ticks.js";
9
- import { resolveGraphicBounds } from "../../../../layout/canvas.js";
9
+ import { resolveCoordinateBounds } from "../../../../materialization/coordinateBounds.js";
10
10
  import { findCoordinate } from "../../../../selectors/coordinates.js";
11
11
  import { findLayer } from "../../../../selectors/layers.js";
12
12
  import { formatAxisValue } from "../policy.js";
@@ -85,7 +85,11 @@ function componentValues(program, dimension, config) {
85
85
  }
86
86
 
87
87
  export function resolveStyledParallelAxes(program, dimensions) {
88
- const bounds = resolveGraphicBounds(program);
88
+ const stored = program.guideConfigs.axis?.parallel?.axes;
89
+ const layer = stored === undefined
90
+ ? undefined
91
+ : findLayer(program, stored.target);
92
+ const bounds = resolveCoordinateBounds(program, layer?.coordinate);
89
93
  const step = bounds.width / (dimensions.length - 1);
90
94
  const configs = resolveParallelAxisConfigs(program, dimensions);
91
95
  const titles = program.semanticSpec.guides.axis?.parallel?.titles ?? [];
@@ -1,5 +1,5 @@
1
- import { action } from "../../../core/action.js";
2
- import { validateGeneratedItemLimit, validateOptionObject } from "../../../core/validation.js";
1
+ import { closedAction } from "../../../core/action.js";
2
+ import { validateGeneratedItemLimit } from "../../../core/validation.js";
3
3
  import { resolvePlotGraphicPlacement } from "../../../materialization/graphicHierarchy.js";
4
4
  import { requireParallelAxisLayer, resolveParallelAxisTarget, resolveStyledParallelAxes } from "./parallel/resolve.js";
5
5
  import { PARALLEL_AXIS_GRAPHICS, PARALLEL_AXIS_PARTS, hasParallelAxisParts } from "./parallel/policy.js";
@@ -47,11 +47,11 @@ function collectionProperties(part, axes, bounds) {
47
47
  };
48
48
  }
49
49
 
50
- export const rematerializeParallelAxes = action({
50
+ export const rematerializeParallelAxes = /* @__PURE__ */ closedAction({
51
51
  op: "rematerializeParallelAxes",
52
52
  description: "Recompute concrete Parallel dimension axes."
53
- }, function (args = {}) {
54
- validateOptionObject(args, ["target"], "rematerializeParallelAxes");
53
+ }, ["target"], function (args = {}) {
54
+
55
55
  const stored = this.semanticSpec.guides.axis?.parallel;
56
56
  if (stored === undefined) throw new Error("rematerializeParallelAxes requires existing Parallel axes.");
57
57
  const target = resolveParallelAxisTarget(this, args.target ?? stored.target);
@@ -54,7 +54,7 @@ function makeRemoveAxis(channel) {
54
54
  );
55
55
  }
56
56
 
57
- export const removeXAxis = makeRemoveAxis("x");
58
- export const removeYAxis = makeRemoveAxis("y");
59
- export const removeThetaAxis = makeRemoveAxis("theta");
60
- export const removeRadialAxis = makeRemoveAxis("radius");
57
+ export const removeXAxis = /* @__PURE__ */ makeRemoveAxis("x");
58
+ export const removeYAxis = /* @__PURE__ */ makeRemoveAxis("y");
59
+ export const removeThetaAxis = /* @__PURE__ */ makeRemoveAxis("theta");
60
+ export const removeRadialAxis = /* @__PURE__ */ makeRemoveAxis("radius");
@@ -30,7 +30,8 @@ const LABEL_OPTIONS = Object.freeze([
30
30
  "maxWidth",
31
31
  "wrap",
32
32
  "lineHeight",
33
- "overlap"
33
+ "overlap",
34
+ "labelMap"
34
35
  ]);
35
36
  const SHARED_CREATE = Object.freeze(["scale", "position", "count", "values"]);
36
37
  const SHARED_EDIT = Object.freeze(["position", "count", "values"]);
@@ -144,10 +145,10 @@ function makeEdit(channel) {
144
145
  );
145
146
  }
146
147
 
147
- const createXAxisTicksAndLabels = makeCreate("x");
148
- const createYAxisTicksAndLabels = makeCreate("y");
149
- const editXAxisTicksAndLabels = makeEdit("x");
150
- const editYAxisTicksAndLabels = makeEdit("y");
148
+ const createXAxisTicksAndLabels = /* @__PURE__ */ makeCreate("x");
149
+ const createYAxisTicksAndLabels = /* @__PURE__ */ makeCreate("y");
150
+ const editXAxisTicksAndLabels = /* @__PURE__ */ makeEdit("x");
151
+ const editYAxisTicksAndLabels = /* @__PURE__ */ makeEdit("y");
151
152
 
152
153
  export function registerAxisTickGroupActions(Class) {
153
154
  Class.prototype.createXAxisTicksAndLabels = createXAxisTicksAndLabels;
@@ -1,4 +1,7 @@
1
+ import { editGraphicProperties } from "../../primitives/graphicProperties.js";
1
2
  import { withGuideLayoutValidation } from "../../../materialization/guides/layout.js";
3
+ import { applyMaterializationPlan } from "../../../materialization/planner.js";
4
+ import { planAxisTickGridRematerialization } from "../../../materialization/scaleGuideDependencies.js";
2
5
  import { action } from "../../../core/action.js";
3
6
  import { validateUserId } from "../../../core/identifiers.js";
4
7
  import {
@@ -7,7 +10,7 @@ import {
7
10
  validateNonNegativeFinite,
8
11
  validateOptionObject
9
12
  } from "../../../core/validation.js";
10
- import { resolveGraphicBounds } from "../../../layout/canvas.js";
13
+ import { resolveGuideCoordinateBounds } from "../../../materialization/coordinateBounds.js";
11
14
  import {
12
15
  isTransformedScaleType,
13
16
  mapContinuousScaleValues,
@@ -69,7 +72,11 @@ function validateConfig(channel, config) {
69
72
 
70
73
  function geometry(program, channel, config) {
71
74
  const scale = program.resolvedScales[config.scale];
72
- const bounds = resolveGraphicBounds(program);
75
+ const bounds = resolveGuideCoordinateBounds(program, {
76
+ coordinate: program.semanticSpec.guides.axis?.[channel]?.coordinate,
77
+ scale: config.scale,
78
+ channel
79
+ });
73
80
  const discrete = ["ordinal", "band", "point"].includes(scale?.type);
74
81
  if ((
75
82
  !["linear", "time", "ordinal", "band", "point"].includes(scale?.type) &&
@@ -157,11 +164,16 @@ function makeEdit(channel) {
157
164
  const resolved = geometry(this, channel, config);
158
165
  let next = this._withGuideConfig(channel, config).editGraphics({ target: id, property: "length", value: resolved.values.length });
159
166
  for (const property of ["x1", "y1", "x2", "y2"]) next = next.editGraphics({ target: id, property, value: resolved[property] });
160
- return next.editGraphics({ target: id, property: "stroke", value: config.color }).editGraphics({ target: id, property: "strokeWidth", value: config.lineWidth });
167
+ next = editGraphicProperties(next, id, {
168
+ stroke: config.color,
169
+ strokeWidth: config.lineWidth
170
+ });
171
+ // Structural dependency plans own grids during a scale/role handoff.
172
+ return explicitMode ? applyMaterializationPlan(next, planAxisTickGridRematerialization(next, channel)) : next;
161
173
  }));
162
174
  }
163
175
 
164
- const editXAxisTicks = makeEdit("x"), editYAxisTicks = makeEdit("y");
176
+ const editXAxisTicks = /* @__PURE__ */ makeEdit("x"), editYAxisTicks = /* @__PURE__ */ makeEdit("y");
165
177
 
166
178
  function makeCreate(channel) {
167
179
  const op = channel === "x" ? "createXAxisTicks" : "createYAxisTicks";
@@ -185,7 +197,7 @@ function makeCreate(channel) {
185
197
  const config = { scale, position: defaultAxisPosition(channel), length: DEFAULTS.length, color: DEFAULTS.color, lineWidth: DEFAULTS.lineWidth, ...options, inferredValues: inferredValues !== undefined, mode: Object.hasOwn(options, "values") ? "values" : "count" };
186
198
  if (config.mode === "values") delete config.count; else config.count ??= DEFAULTS.count;
187
199
  validateConfig(channel, config); geometry(this, channel, config);
188
- return this.editSemantic({ property: `guide.axis.${channel}.scale`, value: scale })
200
+ const next = this.editSemantic({ property: `guide.axis.${channel}.scale`, value: scale })
189
201
  .createGraphics({
190
202
  id,
191
203
  type: "line",
@@ -193,10 +205,11 @@ function makeCreate(channel) {
193
205
  ...resolvePlotGraphicPlacement(this)
194
206
  })
195
207
  ._withGuideConfig(channel, config)[edit]();
208
+ return applyMaterializationPlan(next, planAxisTickGridRematerialization(next, channel));
196
209
  }));
197
210
  }
198
211
 
199
- const createXAxisTicks = makeCreate("x"), createYAxisTicks = makeCreate("y");
212
+ const createXAxisTicks = /* @__PURE__ */ makeCreate("x"), createYAxisTicks = /* @__PURE__ */ makeCreate("y");
200
213
  export function registerAxisTickActions(Class) {
201
214
  Class.prototype.editXAxisTicks = editXAxisTicks; Class.prototype.editYAxisTicks = editYAxisTicks;
202
215
  Class.prototype.createXAxisTicks = createXAxisTicks; Class.prototype.createYAxisTicks = createYAxisTicks;
@@ -7,7 +7,7 @@ import {
7
7
  validateNonEmptyString,
8
8
  validateNonNegativeFinite
9
9
  } from "../../../core/validation.js";
10
- import { resolveGraphicBounds } from "../../../layout/canvas.js";
10
+ import { resolveGuideCoordinateBounds } from "../../../materialization/coordinateBounds.js";
11
11
  import {
12
12
  isTransformedScaleType,
13
13
  mapContinuousScaleValues,
@@ -36,7 +36,7 @@ import { resolveConcreteGraphicBounds } from
36
36
  import { validateAxisTextStyle } from "./labels.js";
37
37
  import { resolveRotation } from "../../../grammar/rotation.js";
38
38
 
39
- function titleBounds(geometry, config, text) {
39
+ function titleBounds(geometry, config, text, profile) {
40
40
  return resolveTextBounds({
41
41
  ...geometry,
42
42
  text,
@@ -46,14 +46,18 @@ function titleBounds(geometry, config, text) {
46
46
  textAlign: "center",
47
47
  textBaseline: "middle",
48
48
  rotation: config.rotation
49
- });
49
+ }, profile);
50
50
  }
51
51
 
52
52
  function inferredTitleOffset(program, channel, config) {
53
- const plot = resolveGraphicBounds(program);
53
+ const plot = resolveGuideCoordinateBounds(program, {
54
+ coordinate: program.semanticSpec.guides.axis?.[channel]?.coordinate,
55
+ scale: config.scale,
56
+ channel
57
+ });
54
58
  const canvas = findCanvasGraphic(program)?.properties;
55
59
  const labels = program.graphicSpec.objects[`${channel}AxisLabels`]
56
- ? resolveConcreteGraphicBounds(program.graphicSpec, `${channel}AxisLabels`)
60
+ ? resolveConcreteGraphicBounds(program.graphicSpec, `${channel}AxisLabels`, program.materializationConfigs.textMetrics)
57
61
  : undefined;
58
62
  const preferred = channel === "x" ? 42 : 52;
59
63
  if (!plot || !canvas || !labels) return preferred;
@@ -67,7 +71,7 @@ function inferredTitleOffset(program, channel, config) {
67
71
  position: config.position,
68
72
  along: 0,
69
73
  offset: preferred
70
- }), config, program.semanticSpec.guides.axis?.[channel]?.title ?? "");
74
+ }), config, program.semanticSpec.guides.axis?.[channel]?.title ?? "", program.materializationConfigs.textMetrics);
71
75
  const needed = positive
72
76
  ? labels[far] + 4 - bounds[near]
73
77
  : bounds[far] - labels[near] + 4;
@@ -151,7 +155,11 @@ export function inferAxisTitleText(program, channel, scaleId) {
151
155
 
152
156
  function resolveGeometry(program, channel, config) {
153
157
  const scale = program.resolvedScales[config.scale];
154
- const bounds = resolveGraphicBounds(program);
158
+ const bounds = resolveGuideCoordinateBounds(program, {
159
+ coordinate: program.semanticSpec.guides.axis?.[channel]?.coordinate,
160
+ scale: config.scale,
161
+ channel
162
+ });
155
163
  const discrete = ["ordinal", "band", "point"].includes(scale?.type);
156
164
  if ((
157
165
  !["linear", "time", "ordinal", "band", "point"].includes(scale?.type) &&
@@ -183,13 +191,13 @@ function resolveGeometry(program, channel, config) {
183
191
  geometry,
184
192
  config,
185
193
  program.semanticSpec.guides.axis?.[channel]?.title ?? ""
186
- );
194
+ , program.materializationConfigs.textMetrics);
187
195
  const canvas = findCanvasGraphic(program)?.properties;
188
196
  if (!canvas || !textBoundsFitCanvas(resolvedBounds, canvas)) {
189
197
  throw new Error(`The ${channel}-axis title does not fit the Canvas margin.`);
190
198
  }
191
199
  const labelsBounds = program.graphicSpec.objects[`${channel}AxisLabels`]
192
- ? resolveConcreteGraphicBounds(program.graphicSpec, `${channel}AxisLabels`)
200
+ ? resolveConcreteGraphicBounds(program.graphicSpec, `${channel}AxisLabels`, program.materializationConfigs.textMetrics)
193
201
  : undefined;
194
202
  if (labelsBounds && textBoundsIntersect(resolvedBounds, labelsBounds)) {
195
203
  throw new Error(`The ${channel}-axis title overlaps the axis labels.`);
@@ -261,8 +269,8 @@ function makeEdit(channel) {
261
269
  }));
262
270
  }
263
271
 
264
- const editXAxisTitle = makeEdit("x");
265
- const editYAxisTitle = makeEdit("y");
272
+ const editXAxisTitle = /* @__PURE__ */ makeEdit("x");
273
+ const editYAxisTitle = /* @__PURE__ */ makeEdit("y");
266
274
 
267
275
  function makeCreate(channel) {
268
276
  const operation = names(channel);
@@ -319,8 +327,8 @@ function makeCreate(channel) {
319
327
  }));
320
328
  }
321
329
 
322
- const createXAxisTitle = makeCreate("x");
323
- const createYAxisTitle = makeCreate("y");
330
+ const createXAxisTitle = /* @__PURE__ */ makeCreate("x");
331
+ const createYAxisTitle = /* @__PURE__ */ makeCreate("y");
324
332
 
325
333
  export function registerAxisTitleActions(Class) {
326
334
  Class.prototype.createXAxisTitle = createXAxisTitle;