ggaction 0.0.15 → 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 (236) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +22 -2
  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 +33 -6
  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/boxPlots/components.js +6 -8
  13. package/src/actions/boxPlots/create.js +4 -5
  14. package/src/actions/boxPlots/edit.js +3 -4
  15. package/src/actions/boxPlots/materialize.js +1 -1
  16. package/src/actions/canvas/actions.js +3 -3
  17. package/src/actions/canvas/fitting.js +1 -1
  18. package/src/actions/categoryOrder/index.js +6 -8
  19. package/src/actions/charts/area.js +1 -1
  20. package/src/actions/charts/bar.js +1 -1
  21. package/src/actions/charts/beeswarm.js +1 -1
  22. package/src/actions/charts/density.js +1 -1
  23. package/src/actions/charts/ecdf.js +2 -2
  24. package/src/actions/charts/endpoints.js +4 -4
  25. package/src/actions/charts/heatmap.js +1 -1
  26. package/src/actions/charts/histogram.js +1 -1
  27. package/src/actions/charts/horizon.js +1 -1
  28. package/src/actions/charts/interval-regression.js +2 -2
  29. package/src/actions/charts/line.js +1 -1
  30. package/src/actions/charts/parallel.js +1 -1
  31. package/src/actions/charts/pie.js +1 -1
  32. package/src/actions/charts/polar.js +2 -2
  33. package/src/actions/charts/radar.js +1 -1
  34. package/src/actions/charts/radial.js +2 -2
  35. package/src/actions/charts/raincloud.js +2 -2
  36. package/src/actions/charts/rug-strip.js +2 -2
  37. package/src/actions/charts/scatter.js +1 -1
  38. package/src/actions/composition/actions.js +20 -24
  39. package/src/actions/coordinates/actions.js +1 -1
  40. package/src/actions/coordinates/edit.js +1 -1
  41. package/src/actions/data/basicBin2d.js +4 -5
  42. package/src/actions/data/bin.js +2 -2
  43. package/src/actions/data/bin2d.js +6 -8
  44. package/src/actions/data/bin2dMaterialize.js +4 -5
  45. package/src/actions/data/box.js +4 -4
  46. package/src/actions/data/complete.js +2 -2
  47. package/src/actions/data/computed.js +2 -2
  48. package/src/actions/data/create.js +5 -12
  49. package/src/actions/data/density.js +3 -3
  50. package/src/actions/data/derived.js +10 -14
  51. package/src/actions/data/ecdf.js +2 -2
  52. package/src/actions/data/edit.js +35 -23
  53. package/src/actions/data/filter.js +14 -20
  54. package/src/actions/data/fold.js +2 -2
  55. package/src/actions/data/gradientProfile.js +2 -2
  56. package/src/actions/data/horizon.js +2 -2
  57. package/src/actions/data/impute.js +2 -2
  58. package/src/actions/data/index.js +55 -54
  59. package/src/actions/data/interval.js +2 -2
  60. package/src/actions/data/intervalEdit.js +26 -18
  61. package/src/actions/data/normalize.js +2 -2
  62. package/src/actions/data/regression.js +5 -6
  63. package/src/actions/data/revise.js +48 -0
  64. package/src/actions/data/revisionBindings.js +13 -33
  65. package/src/actions/data/stack.js +2 -2
  66. package/src/actions/data/summary.js +2 -2
  67. package/src/actions/data/timeUnit.js +2 -2
  68. package/src/actions/data/window.js +2 -2
  69. package/src/actions/encodings/angle.js +1 -1
  70. package/src/actions/encodings/appearance.js +4 -4
  71. package/src/actions/encodings/barWidth.js +1 -1
  72. package/src/actions/encodings/channels.js +2 -2
  73. package/src/actions/encodings/color/index.js +1 -1
  74. package/src/actions/encodings/density.js +2 -2
  75. package/src/actions/encodings/histogram.js +1 -1
  76. package/src/actions/encodings/horizon.js +6 -8
  77. package/src/actions/encodings/offset.js +2 -2
  78. package/src/actions/encodings/parallel.js +4 -5
  79. package/src/actions/encodings/pathOrder.js +6 -11
  80. package/src/actions/encodings/position/index.js +4 -4
  81. package/src/actions/encodings/ranged.js +5 -5
  82. package/src/actions/encodings/remove.js +4 -5
  83. package/src/actions/encodings/ruleAppearance.js +1 -1
  84. package/src/actions/encodings/seriesLayout.js +1 -1
  85. package/src/actions/encodings/stroke.js +1 -1
  86. package/src/actions/encodings/strokeDash.js +2 -2
  87. package/src/actions/encodings/text.js +1 -1
  88. package/src/actions/errorBands/create.js +11 -17
  89. package/src/actions/errorBands/edit.js +13 -131
  90. package/src/actions/errorBars/create.js +8 -13
  91. package/src/actions/errorBars/edit.js +10 -121
  92. package/src/actions/facets/actions.js +30 -16
  93. package/src/actions/facets/derive.js +8 -2
  94. package/src/actions/facets/guides.js +4 -5
  95. package/src/actions/facets/replay.js +4 -5
  96. package/src/actions/gradientPlots/components.js +5 -6
  97. package/src/actions/gradientPlots/create.js +4 -5
  98. package/src/actions/gradientPlots/edit.js +4 -5
  99. package/src/actions/gradientPlots/materialize.js +2 -2
  100. package/src/actions/gradientPlots/rebind.js +4 -5
  101. package/src/actions/guides/axes/axes.js +23 -4
  102. package/src/actions/guides/axes/axis.js +2 -2
  103. package/src/actions/guides/axes/edit.js +2 -2
  104. package/src/actions/guides/axes/labels.js +9 -9
  105. package/src/actions/guides/axes/lines.js +9 -7
  106. package/src/actions/guides/axes/parallel/lifecycle.js +13 -13
  107. package/src/actions/guides/axes/parallel.js +5 -5
  108. package/src/actions/guides/axes/remove.js +4 -4
  109. package/src/actions/guides/axes/tickGroups.js +4 -4
  110. package/src/actions/guides/axes/ticks.js +13 -4
  111. package/src/actions/guides/axes/titles.js +10 -10
  112. package/src/actions/guides/grids/grid.js +18 -29
  113. package/src/actions/guides/guides.js +1 -1
  114. package/src/actions/guides/legends/blocks.js +1 -1
  115. package/src/actions/guides/legends/categorical/actions.js +4 -4
  116. package/src/actions/guides/legends/categorical/components.js +38 -33
  117. package/src/actions/guides/legends/categorical/layout.js +1 -1
  118. package/src/actions/guides/legends/categorical/symbols.js +27 -30
  119. package/src/actions/guides/legends/continuous/common.js +46 -8
  120. package/src/actions/guides/legends/continuous/gradient.js +89 -155
  121. package/src/actions/guides/legends/continuous/interval.js +13 -13
  122. package/src/actions/guides/legends/continuous/opacity.js +30 -79
  123. package/src/actions/guides/legends/continuous/stroke.js +22 -322
  124. package/src/actions/guides/legends/edit.js +1 -1
  125. package/src/actions/guides/legends/focused.js +5 -5
  126. package/src/actions/guides/legends/lane.js +6 -6
  127. package/src/actions/guides/legends/remove.js +4 -5
  128. package/src/actions/guides/legends/size.js +21 -82
  129. package/src/actions/guides/legends/strokeWidth.js +17 -77
  130. package/src/actions/guides/polar/axes/facade.js +4 -4
  131. package/src/actions/guides/polar/axes/labels.js +5 -5
  132. package/src/actions/guides/polar/axes/lines.js +9 -15
  133. package/src/actions/guides/polar/axes/ticks.js +9 -15
  134. package/src/actions/guides/polar/axes/titles.js +5 -5
  135. package/src/actions/guides/polar/grids.js +11 -13
  136. package/src/actions/index.js +2 -0
  137. package/src/actions/intervals/revision.js +126 -0
  138. package/src/actions/marks/arc/actions.js +3 -3
  139. package/src/actions/marks/area/actions.js +4 -4
  140. package/src/actions/marks/bar/create.js +1 -1
  141. package/src/actions/marks/bar/edit.js +1 -1
  142. package/src/actions/marks/bar/materialize.js +12 -38
  143. package/src/actions/marks/line/actions.js +3 -3
  144. package/src/actions/marks/point/create.js +1 -1
  145. package/src/actions/marks/point/edit.js +1 -1
  146. package/src/actions/marks/point/jitter.js +6 -8
  147. package/src/actions/marks/point/materialize.js +16 -24
  148. package/src/actions/marks/point/packing.js +6 -8
  149. package/src/actions/marks/rect/actions.js +3 -3
  150. package/src/actions/marks/references.js +8 -10
  151. package/src/actions/marks/remove.js +5 -49
  152. package/src/actions/marks/rule/actions.js +4 -4
  153. package/src/actions/marks/text/actions.js +5 -5
  154. package/src/actions/marks/text/layout.js +12 -20
  155. package/src/actions/marks/text/removal.js +1 -1
  156. package/src/actions/marks/text/selection.js +4 -5
  157. package/src/actions/marks/tick/actions.js +3 -3
  158. package/src/actions/primitives/createGraphics.js +5 -4
  159. package/src/actions/primitives/editGraphics.js +5 -4
  160. package/src/actions/primitives/graphicProperties.js +6 -0
  161. package/src/actions/primitives/semantic.js +10 -3
  162. package/src/actions/primitives/semanticAction.js +7 -4
  163. package/src/actions/primitives/semanticValidation/dataset.js +2 -4
  164. package/src/actions/regression/components.js +10 -14
  165. package/src/actions/regression/create.js +3 -4
  166. package/src/actions/regression/edit.js +3 -4
  167. package/src/actions/resources/remove.js +12 -11
  168. package/src/actions/scales/create.js +1 -1
  169. package/src/actions/scales/edit.js +1 -1
  170. package/src/actions/scales/materialize.js +1 -1
  171. package/src/actions/scales/offset.js +2 -2
  172. package/src/actions/scales/parallel.js +1 -1
  173. package/src/actions/scales/quantitativeColor.js +4 -5
  174. package/src/actions/selection/actions.js +25 -36
  175. package/src/actions/textMetrics/index.js +56 -0
  176. package/src/actions/theme/actions.js +2 -2
  177. package/src/actions/theme/reconcile.js +65 -121
  178. package/src/actions/titles/actions.js +8 -8
  179. package/src/actions/titles/resolve.js +3 -3
  180. package/src/actions/violinPlots/create.js +1 -1
  181. package/src/actions/violinPlots/edit.js +1 -1
  182. package/src/core/action.js +107 -35
  183. package/src/core/diagnostics.js +16 -0
  184. package/src/core/extensionRegistry.js +27 -0
  185. package/src/core/font.js +18 -0
  186. package/src/core/identifiers.js +5 -4
  187. package/src/core/immutable.js +10 -3
  188. package/src/core/optionRequirements.js +8 -0
  189. package/src/core/programState.js +1 -1
  190. package/src/core/resourceReferences.js +15 -6
  191. package/src/core/textMetricProfile.js +28 -0
  192. package/src/core/textMetrics.js +24 -3
  193. package/src/core/validation.js +22 -10
  194. package/src/diagnostics.js +1 -0
  195. package/src/grammar/impute.js +3 -2
  196. package/src/grammar/scales/types.js +8 -0
  197. package/src/grammar/schemas/graphicBounds.js +11 -11
  198. package/src/layout/labels.js +11 -10
  199. package/src/layout/legend.js +4 -4
  200. package/src/layout/legendItems.js +6 -6
  201. package/src/layout/text.js +10 -9
  202. package/src/layout/title.js +9 -9
  203. package/src/materialization/facetGuides/placement.js +1 -1
  204. package/src/materialization/facetGuides/preparation.js +1 -1
  205. package/src/materialization/facetHeaders.js +11 -10
  206. package/src/materialization/guides/layout.js +3 -3
  207. package/src/materialization/scaleGuideDependencies.js +10 -0
  208. package/src/materialization/selection/items/common.js +1 -1
  209. package/src/materialization/text.js +2 -2
  210. package/src/materialization/typography.js +31 -0
  211. package/src/mcp/cli.js +5 -3
  212. package/src/persistence/codec.js +65 -0
  213. package/src/persistence/validation.js +185 -0
  214. package/src/persistence.js +74 -0
  215. package/src/renderers/canvas/index.js +5 -4
  216. package/src/renderers/nativeBackend.js +10 -0
  217. package/src/renderers/options.js +13 -0
  218. package/src/renderers/pdf.js +25 -54
  219. package/src/renderers/png.js +22 -17
  220. package/src/renderers/svg.js +10 -14
  221. package/src/renderers/text.js +1 -11
  222. package/src/selectors/coordinates.js +3 -1
  223. package/src/selectors/datasets.js +8 -6
  224. package/src/selectors/layers.js +6 -4
  225. package/src/selectors/markOwners.js +46 -0
  226. package/src/selectors/scales.js +6 -4
  227. package/src/theme/defaults.js +2 -1
  228. package/src/version.js +2 -0
  229. package/types/accessibility.d.ts +37 -0
  230. package/types/basic.d.ts +4 -2
  231. package/types/diagnostics.d.ts +15 -0
  232. package/types/index.d.ts +5 -0
  233. package/types/pdf.d.ts +9 -0
  234. package/types/persistence.d.ts +7 -0
  235. package/types/png.d.ts +9 -0
  236. package/types/program.d.ts +34 -1
@@ -1,4 +1,4 @@
1
- import { action } from "../../../core/action.js";
1
+ import { action, closedAction } from "../../../core/action.js";
2
2
  import {
3
3
  validateNonEmptyString,
4
4
  validateKeys
@@ -17,7 +17,8 @@ import { resolveLegendGraphicPlacement } from
17
17
  "../../../materialization/graphicHierarchy.js";
18
18
  import {
19
19
  assertLegendBoundsInsideCanvas,
20
- editLegendBackground,
20
+ materializeItemLegend,
21
+ createItemLegendGraphics,
21
22
  normalizeItemLegendLayout,
22
23
  normalizeLegendBorder,
23
24
  normalizeLegendTextOptions,
@@ -25,8 +26,7 @@ import {
25
26
  resolveContinuousBounds,
26
27
  resolveLegendBackgroundFromBounds,
27
28
  formatContinuousValues,
28
- selectLegendLayer,
29
- styleContinuousText
29
+ selectLegendLayer
30
30
  } from "./continuous/common.js";
31
31
  import { legendResourcePolicies } from "../../../materialization/guides/resources.js";
32
32
  import {
@@ -139,20 +139,19 @@ export function resolveSizeLegendLayout(program, config) {
139
139
  top: -r - symbolExtent,
140
140
  bottom: r + symbolExtent
141
141
  }))
142
- });
142
+ }, undefined, program.materializationConfigs.textMetrics);
143
143
  assertLegendBoundsInsideCanvas(layout.bounds, canvas, "Size legend layout", { ...effective, ...geometry });
144
144
  const background = resolveLegendBackgroundFromBounds(layout.bounds, effective.border, canvas, "Size legend", { ...effective, ...geometry });
145
145
  return { ...layout, symbolX: layout.symbolX.map(x => x + sampleWidth / 2), radii, text,
146
146
  labels, titleStyle, background, config: effective };
147
147
  }
148
148
 
149
- export const rematerializeSizeLegend = action(
149
+ export const rematerializeSizeLegend = /* @__PURE__ */ closedAction(
150
150
  {
151
151
  op: "rematerializeSizeLegend",
152
152
  description: "Rematerialize a quantitative point-size legend."
153
- },
153
+ }, [],
154
154
  function (args = {}) {
155
- validateKeys(args, [], "rematerializeSizeLegend");
156
155
  const config = this.guideConfigs.legend?.size;
157
156
  if (config === undefined) throw new Error("Size legend requires stored configuration.");
158
157
  const layer = findLayer(this, config.target);
@@ -169,51 +168,18 @@ export const rematerializeSizeLegend = action(
169
168
  domain: scale.domain
170
169
  };
171
170
  const layout = resolveSizeLegendLayout(this, currentConfig);
172
- const effective = layout.config;
173
- const { itemY, symbolX, labelX, radii, labels, titleStyle } = layout;
174
- let next = this
175
- .editSemantic({ property: "guide.legend.size.scale", value: encoding.scale })
176
- .editSemantic({ property: "guide.legend.size.title", value: title })
177
- ._withLegendConfig("size", currentConfig)
178
- .editGraphics({ target: "sizeLegendSymbols", property: "length", value: radii.length })
179
- .editGraphics({ target: "sizeLegendSymbols", property: "x", value: symbolX })
180
- .editGraphics({ target: "sizeLegendSymbols", property: "y", value: itemY })
181
- .editGraphics({
182
- target: "sizeLegendSymbols",
183
- property: "radius",
184
- value: radii
185
- })
186
- .editGraphics({
187
- target: "sizeLegendSymbols",
188
- property: "fill",
189
- value: effective.blockSymbol?.fill ?? DEFAULT_COLORS.sizeSymbol
190
- })
191
- .editGraphics({ target: "sizeLegendSymbols", property: "opacity",
192
- value: effective.blockSymbol?.opacity ?? 0.7 })
193
- .editGraphics({ target: "sizeLegendLabels", property: "length", value: radii.length })
194
- .editGraphics({ target: "sizeLegendLabels", property: "x", value: labelX })
195
- .editGraphics({ target: "sizeLegendLabels", property: "y", value: itemY })
196
- .editGraphics({
197
- target: "sizeLegendLabels",
198
- property: "text",
199
- value: layout.text
200
- });
201
- next = editLegendBackground(next, "sizeLegendBackground", layout.background, currentConfig.border);
202
- if (effective.blockSymbol?.stroke !== undefined) {
203
- next = next.editGraphics({ target: "sizeLegendSymbols", property: "stroke",
204
- value: effective.blockSymbol.stroke });
205
- }
206
- if (effective.blockSymbol?.strokeWidth !== undefined) {
207
- next = next.editGraphics({ target: "sizeLegendSymbols", property: "strokeWidth",
208
- value: effective.blockSymbol.strokeWidth });
209
- }
210
- next = styleContinuousText(next, "sizeLegendLabels", labels);
211
- if (effective.titleVisible === false) return next;
212
- next = next
213
- .editGraphics({ target: "sizeLegendTitle", property: "x", value: layout.title.x })
214
- .editGraphics({ target: "sizeLegendTitle", property: "y", value: layout.title.y })
215
- .editGraphics({ target: "sizeLegendTitle", property: "text", value: effective.title });
216
- return styleContinuousText(next, "sizeLegendTitle", titleStyle, { align: layout.title.align });
171
+ return materializeItemLegend(this, "size", currentConfig, layout, {
172
+ text: layout.text, labels: layout.labels, titleStyle: layout.titleStyle,
173
+ symbols: {
174
+ x: layout.symbolX, y: layout.itemY, radius: layout.radii,
175
+ fill: layout.config.blockSymbol?.fill ?? DEFAULT_COLORS.sizeSymbol,
176
+ opacity: layout.config.blockSymbol?.opacity ?? 0.7
177
+ },
178
+ optional: {
179
+ stroke: layout.config.blockSymbol?.stroke,
180
+ strokeWidth: layout.config.blockSymbol?.strokeWidth
181
+ }
182
+ });
217
183
  }
218
184
  );
219
185
 
@@ -261,37 +227,10 @@ export function createSizeLegendFromConfig(program, config) {
261
227
  ).flatMap(policy => policy.graphicIds));
262
228
  const before = program.graphicSpec.objects.canvas?.children?.find(id => following.has(id));
263
229
  const placement = resolveLegendGraphicPlacement(program, before === undefined ? {} : { before });
264
- let next = program
265
- .editSemantic({ property: "guide.legend.size.scale", value: config.scale })
266
- .editSemantic({ property: "guide.legend.size.title", value: config.title })
267
- ._withLegendConfig("size", config);
268
- if (config.border !== false) {
269
- next = next.createGraphics({ id: "sizeLegendBackground", type: "rect",
270
- ...placement });
271
- }
272
- next = next.createGraphics({
273
- id: "sizeLegendSymbols",
274
- type: "circle",
275
- length: count,
276
- ...placement
277
- })
278
- .createGraphics({
279
- id: "sizeLegendLabels",
280
- type: "text",
281
- length: count,
282
- ...placement
283
- });
284
- if (config.titleVisible !== false) {
285
- next = next.createGraphics({
286
- id: "sizeLegendTitle",
287
- type: "text",
288
- ...placement
289
- });
290
- }
291
- return next.rematerializeSizeLegend();
230
+ return createItemLegendGraphics(program, "size", config, count, "circle", placement).rematerializeSizeLegend();
292
231
  }
293
232
 
294
- export const createSizeLegend = action(
233
+ export const createSizeLegend = /* @__PURE__ */ action(
295
234
  {
296
235
  op: "createSizeLegend",
297
236
  description: "Create an equal-area point-size legend."
@@ -1,4 +1,4 @@
1
- import { action } from "../../../core/action.js";
1
+ import { action, closedAction } from "../../../core/action.js";
2
2
  import {
3
3
  validateNonEmptyString,
4
4
  validateKeys
@@ -12,7 +12,8 @@ import { DEFAULT_COLORS, DEFAULT_FONT_FAMILY } from
12
12
  "../../../theme/defaults.js";
13
13
  import {
14
14
  assertLegendBoundsInsideCanvas,
15
- editLegendBackground,
15
+ materializeItemLegend,
16
+ createItemLegendGraphics,
16
17
  normalizeItemLegendLayout,
17
18
  normalizeLegendBorder,
18
19
  normalizeLegendTextOptions,
@@ -20,8 +21,7 @@ import {
20
21
  resolveContinuousBounds,
21
22
  resolveLegendBackgroundFromBounds,
22
23
  formatContinuousValues,
23
- selectLegendLayer,
24
- styleContinuousText
24
+ selectLegendLayer
25
25
  } from "./continuous/common.js";
26
26
  import {
27
27
  normalizeLegendSampling,
@@ -88,19 +88,18 @@ export function resolveStrokeWidthLegendLayout(program, config) {
88
88
  "quantitative",
89
89
  effective.labels.format
90
90
  );
91
- const layout = resolveLegendItemLayout(plot, effective, labels, { width: 32, height: 0, strokeWidth: widths });
91
+ const layout = resolveLegendItemLayout(plot, effective, labels, { width: 32, height: 0, strokeWidth: widths }, undefined, program.materializationConfigs.textMetrics);
92
92
  assertLegendBoundsInsideCanvas(layout.bounds, canvas, "Stroke-width legend layout", effective);
93
93
  const background = resolveLegendBackgroundFromBounds(layout.bounds, effective.border, canvas, "Stroke-width legend", effective);
94
94
  return { ...layout, widths, labels, background, config: effective };
95
95
  }
96
96
 
97
- export const rematerializeStrokeWidthLegend = /* @__PURE__ */ action(
97
+ export const rematerializeStrokeWidthLegend = /* @__PURE__ */ closedAction(
98
98
  {
99
99
  op: "rematerializeStrokeWidthLegend",
100
100
  description: "Rematerialize a quantitative stroke-width legend."
101
- },
101
+ }, [],
102
102
  function (args = {}) {
103
- validateKeys(args, [], "rematerializeStrokeWidthLegend");
104
103
  const stored = this.guideConfigs.legend?.strokeWidth;
105
104
  if (stored === undefined) {
106
105
  throw new Error("Stroke-width legend requires stored configuration.");
@@ -120,47 +119,15 @@ export const rematerializeStrokeWidthLegend = /* @__PURE__ */ action(
120
119
  const title = config.inferredTitle === true ? encoding.field : config.title;
121
120
  const currentConfig = { ...config, scale: encoding.scale, title };
122
121
  const layout = resolveStrokeWidthLegendLayout(this, currentConfig);
123
- const effective = layout.config;
124
- const { itemY: y, widths } = layout;
125
- let next = this
126
- .editSemantic({ property: "guide.legend.strokeWidth.scale", value: encoding.scale })
127
- .editSemantic({ property: "guide.legend.strokeWidth.title", value: title })
128
- ._withLegendConfig("strokeWidth", {
129
- ...currentConfig,
130
- domain: scale.domain
131
- })
132
- .editGraphics({ target: "strokeWidthLegendSymbols", property: "length", value: widths.length })
133
- .editGraphics({ target: "strokeWidthLegendSymbols", property: "x1", value: layout.symbolX })
134
- .editGraphics({ target: "strokeWidthLegendSymbols", property: "x2", value: layout.symbolX.map(x => x + 32) })
135
- .editGraphics({ target: "strokeWidthLegendSymbols", property: "y1", value: y })
136
- .editGraphics({ target: "strokeWidthLegendSymbols", property: "y2", value: y })
137
- .editGraphics({ target: "strokeWidthLegendSymbols", property: "stroke",
138
- value: effective.blockSymbol?.stroke ?? DEFAULT_COLORS.mark })
139
- .editGraphics({ target: "strokeWidthLegendSymbols", property: "strokeWidth", value: widths })
140
- .editGraphics({ target: "strokeWidthLegendLabels", property: "length", value: widths.length })
141
- .editGraphics({
142
- target: "strokeWidthLegendLabels",
143
- property: "x",
144
- value: layout.labelX
145
- })
146
- .editGraphics({ target: "strokeWidthLegendLabels", property: "y", value: y })
147
- .editGraphics({
148
- target: "strokeWidthLegendLabels",
149
- property: "text",
150
- value: layout.labels
151
- });
152
- next = editLegendBackground(next, "strokeWidthLegendBackground", layout.background, config.border);
153
- if (effective.blockSymbol?.opacity !== undefined) {
154
- next = next.editGraphics({ target: "strokeWidthLegendSymbols", property: "opacity",
155
- value: effective.blockSymbol.opacity });
156
- }
157
- next = styleContinuousText(next, "strokeWidthLegendLabels", effective.labels);
158
- if (effective.titleVisible === false) return next;
159
- next = next
160
- .editGraphics({ target: "strokeWidthLegendTitle", property: "x", value: layout.title.x })
161
- .editGraphics({ target: "strokeWidthLegendTitle", property: "y", value: layout.title.y })
162
- .editGraphics({ target: "strokeWidthLegendTitle", property: "text", value: effective.title });
163
- return styleContinuousText(next, "strokeWidthLegendTitle", effective.titleStyle, { align: layout.title.align });
122
+ return materializeItemLegend(this, "strokeWidth", { ...currentConfig, domain: scale.domain }, layout, {
123
+ symbols: {
124
+ x1: layout.symbolX, x2: layout.symbolX.map(x => x + 32),
125
+ y1: layout.itemY, y2: layout.itemY,
126
+ stroke: layout.config.blockSymbol?.stroke ?? DEFAULT_COLORS.mark,
127
+ strokeWidth: layout.widths
128
+ },
129
+ optional: { opacity: layout.config.blockSymbol?.opacity }
130
+ });
164
131
  }
165
132
  );
166
133
 
@@ -192,34 +159,7 @@ export function resolveStrokeWidthLegendConfig(program, args = {}) {
192
159
  export function createStrokeWidthLegendFromConfig(program, config) {
193
160
  const layout = resolveStrokeWidthLegendLayout(program, config);
194
161
  const count = layout.widths.length;
195
- let next = program
196
- .editSemantic({ property: "guide.legend.strokeWidth.scale", value: config.scale })
197
- .editSemantic({ property: "guide.legend.strokeWidth.title", value: config.title })
198
- ._withLegendConfig("strokeWidth", config);
199
- if (config.border !== false) {
200
- next = next.createGraphics({ id: "strokeWidthLegendBackground", type: "rect",
201
- ...resolveLegendGraphicPlacement(program) });
202
- }
203
- next = next.createGraphics({
204
- id: "strokeWidthLegendSymbols",
205
- type: "line",
206
- length: count,
207
- ...resolveLegendGraphicPlacement(program)
208
- })
209
- .createGraphics({
210
- id: "strokeWidthLegendLabels",
211
- type: "text",
212
- length: count,
213
- ...resolveLegendGraphicPlacement(program)
214
- });
215
- if (config.titleVisible !== false) {
216
- next = next.createGraphics({
217
- id: "strokeWidthLegendTitle",
218
- type: "text",
219
- ...resolveLegendGraphicPlacement(program)
220
- });
221
- }
222
- return next.rematerializeStrokeWidthLegend();
162
+ return createItemLegendGraphics(program, "strokeWidth", config, count, "line", resolveLegendGraphicPlacement(program)).rematerializeStrokeWidthLegend();
223
163
  }
224
164
 
225
165
  export const createStrokeWidthLegend = /* @__PURE__ */ action(
@@ -228,7 +228,7 @@ function makeEditAxis(kind) {
228
228
  });
229
229
  }
230
230
 
231
- export const createThetaAxis = makeCreateAxis("theta");
232
- export const createRadialAxis = makeCreateAxis("radius");
233
- export const editThetaAxis = makeEditAxis("theta");
234
- export const editRadialAxis = makeEditAxis("radius");
231
+ export const createThetaAxis = /* @__PURE__ */ makeCreateAxis("theta");
232
+ export const createRadialAxis = /* @__PURE__ */ makeCreateAxis("radius");
233
+ export const editThetaAxis = /* @__PURE__ */ makeEditAxis("theta");
234
+ export const editRadialAxis = /* @__PURE__ */ makeEditAxis("radius");
@@ -66,7 +66,7 @@ function labelGeometry(program, kind, config, angle = resolveAngle(program, kind
66
66
  textAlign: geometry.textAlign[index],
67
67
  textBaseline: geometry.textBaseline[index]
68
68
  }))
69
- });
69
+ }, program.materializationConfigs.textMetrics);
70
70
  return geometry;
71
71
  }
72
72
 
@@ -218,7 +218,7 @@ function makeCreateLabels(kind) {
218
218
  });
219
219
  }
220
220
 
221
- export const createThetaAxisLabels = makeCreateLabels("theta");
222
- export const createRadialAxisLabels = makeCreateLabels("radius");
223
- export const editThetaAxisLabels = makeEditLabels("theta");
224
- export const editRadialAxisLabels = makeEditLabels("radius");
221
+ export const createThetaAxisLabels = /* @__PURE__ */ makeCreateLabels("theta");
222
+ export const createRadialAxisLabels = /* @__PURE__ */ makeCreateLabels("radius");
223
+ export const editThetaAxisLabels = /* @__PURE__ */ makeEditLabels("theta");
224
+ export const editRadialAxisLabels = /* @__PURE__ */ makeEditLabels("radius");
@@ -1,3 +1,4 @@
1
+ import { editGraphicProperties } from "../../../primitives/graphicProperties.js";
1
2
  import { action } from "../../../../core/action.js";
2
3
  import {
3
4
  buildPolarCircleCommands,
@@ -63,17 +64,10 @@ function makeEditLine(kind) {
63
64
  for (const [property, value] of Object.entries(geometry)) {
64
65
  next = next.editGraphics({ target: names.line, property, value });
65
66
  }
66
- return next
67
- .editGraphics({
68
- target: names.line,
69
- property: "stroke",
70
- value: config.color
71
- })
72
- .editGraphics({
73
- target: names.line,
74
- property: "strokeWidth",
75
- value: config.lineWidth
76
- });
67
+ return editGraphicProperties(next, names.line, {
68
+ stroke: config.color,
69
+ strokeWidth: config.lineWidth
70
+ });
77
71
  });
78
72
  }
79
73
 
@@ -114,7 +108,7 @@ function makeCreateLine(kind) {
114
108
  });
115
109
  }
116
110
 
117
- export const createThetaAxisLine = makeCreateLine("theta");
118
- export const createRadialAxisLine = makeCreateLine("radius");
119
- export const editThetaAxisLine = makeEditLine("theta");
120
- export const editRadialAxisLine = makeEditLine("radius");
111
+ export const createThetaAxisLine = /* @__PURE__ */ makeCreateLine("theta");
112
+ export const createRadialAxisLine = /* @__PURE__ */ makeCreateLine("radius");
113
+ export const editThetaAxisLine = /* @__PURE__ */ makeEditLine("theta");
114
+ export const editRadialAxisLine = /* @__PURE__ */ makeEditLine("radius");
@@ -1,3 +1,4 @@
1
+ import { editGraphicProperties } from "../../../primitives/graphicProperties.js";
1
2
  import { action } from "../../../../core/action.js";
2
3
  import { validateNonNegativeFinite } from "../../../../core/validation.js";
3
4
  import {
@@ -112,17 +113,10 @@ function makeEditTicks(kind) {
112
113
  value: geometry[property]
113
114
  });
114
115
  }
115
- return next
116
- .editGraphics({
117
- target: names.ticks,
118
- property: "stroke",
119
- value: config.color
120
- })
121
- .editGraphics({
122
- target: names.ticks,
123
- property: "strokeWidth",
124
- value: config.lineWidth
125
- });
116
+ return editGraphicProperties(next, names.ticks, {
117
+ stroke: config.color,
118
+ strokeWidth: config.lineWidth
119
+ });
126
120
  });
127
121
  }
128
122
 
@@ -159,7 +153,7 @@ function makeCreateTicks(kind) {
159
153
  });
160
154
  }
161
155
 
162
- export const createThetaAxisTicks = makeCreateTicks("theta");
163
- export const createRadialAxisTicks = makeCreateTicks("radius");
164
- export const editThetaAxisTicks = makeEditTicks("theta");
165
- export const editRadialAxisTicks = makeEditTicks("radius");
156
+ export const createThetaAxisTicks = /* @__PURE__ */ makeCreateTicks("theta");
157
+ export const createRadialAxisTicks = /* @__PURE__ */ makeCreateTicks("radius");
158
+ export const editThetaAxisTicks = /* @__PURE__ */ makeEditTicks("theta");
159
+ export const editRadialAxisTicks = /* @__PURE__ */ makeEditTicks("radius");
@@ -52,7 +52,7 @@ function validateTitleGeometry(program, kind, config, geometry, text) {
52
52
  fontFamily: config.fontFamily,
53
53
  fontWeight: config.fontWeight
54
54
  }]
55
- });
55
+ }, program.materializationConfigs.textMetrics);
56
56
  }
57
57
 
58
58
  function resolveTitleConfig(kind, args, resources, previous) {
@@ -177,7 +177,7 @@ function makeCreateTitle(kind) {
177
177
  });
178
178
  }
179
179
 
180
- export const createThetaAxisTitle = makeCreateTitle("theta");
181
- export const createRadialAxisTitle = makeCreateTitle("radius");
182
- export const editThetaAxisTitle = makeEditTitle("theta");
183
- export const editRadialAxisTitle = makeEditTitle("radius");
180
+ export const createThetaAxisTitle = /* @__PURE__ */ makeCreateTitle("theta");
181
+ export const createRadialAxisTitle = /* @__PURE__ */ makeCreateTitle("radius");
182
+ export const editThetaAxisTitle = /* @__PURE__ */ makeEditTitle("theta");
183
+ export const editRadialAxisTitle = /* @__PURE__ */ makeEditTitle("radius");
@@ -1,3 +1,4 @@
1
+ import { editGraphicProperties } from "../../primitives/graphicProperties.js";
1
2
  import { action } from "../../../core/action.js";
2
3
  import {
3
4
  noOptions,
@@ -139,13 +140,10 @@ function editConcrete(program, kind, config, geometry) {
139
140
  for (const [property, value] of Object.entries(properties)) {
140
141
  next = next.editGraphics({ target: graphic, property, value });
141
142
  }
142
- return next
143
- .editGraphics({ target: graphic, property: "stroke", value: config.color })
144
- .editGraphics({
145
- target: graphic,
146
- property: "strokeWidth",
147
- value: config.lineWidth
148
- })
143
+ return editGraphicProperties(next, graphic, {
144
+ stroke: config.color,
145
+ strokeWidth: config.lineWidth
146
+ })
149
147
  .editGraphics({
150
148
  target: graphic,
151
149
  property: "strokeDash",
@@ -239,12 +237,12 @@ function makeEdit(kind) {
239
237
  });
240
238
  }
241
239
 
242
- const createThetaGrid = makeCreate("theta");
243
- const createRadialGrid = makeCreate("radial");
244
- const editThetaGrid = makeEdit("theta");
245
- const editRadialGrid = makeEdit("radial");
246
- const rematerializeThetaGrid = makeRematerialize("theta");
247
- const rematerializeRadialGrid = makeRematerialize("radial");
240
+ const createThetaGrid = /* @__PURE__ */ makeCreate("theta");
241
+ const createRadialGrid = /* @__PURE__ */ makeCreate("radial");
242
+ const editThetaGrid = /* @__PURE__ */ makeEdit("theta");
243
+ const editRadialGrid = /* @__PURE__ */ makeEdit("radial");
244
+ const rematerializeThetaGrid = /* @__PURE__ */ makeRematerialize("theta");
245
+ const rematerializeRadialGrid = /* @__PURE__ */ makeRematerialize("radial");
248
246
 
249
247
  export function registerPolarGridActions(ProgramClass) {
250
248
  ProgramClass.prototype.createThetaGrid = createThetaGrid;
@@ -1,3 +1,4 @@
1
+ import { registerTextMetricActions } from "./textMetrics/index.js";
1
2
  import { registerPrimitiveActions } from "./primitives/index.js";
2
3
  import { registerSelectionActions } from "./selection/index.js";
3
4
  import { registerDataActions } from "./data/index.js";
@@ -53,4 +54,5 @@ export function registerActions(ProgramClass) {
53
54
  registerCategoryOrderActions(ProgramClass);
54
55
  registerSelectionActions(ProgramClass);
55
56
  registerResourceActions(ProgramClass);
57
+ registerTextMetricActions(ProgramClass);
56
58
  }
@@ -0,0 +1,126 @@
1
+ import { findSemanticScale } from "../../selectors/scales.js";
2
+ import {
3
+ findIntervalTransform,
4
+ mergeIntervalStatistics,
5
+ validateIntervalStatistics
6
+ } from "../data/intervalEdit.js";
7
+ import { resolveDistributionScalePlan } from "../distributions/revision.js";
8
+ import { resolveIntervalComposite } from "./resolve.js";
9
+
10
+ export function currentIntervalRoleArgs(program, owner, current, bar) {
11
+ const transform = findIntervalTransform(program, current.data);
12
+ const intervalChannel = current.orientation === "vertical" ? "y" : "x";
13
+ const positionChannel = intervalChannel === "x" ? "y" : "x";
14
+ const storedPosition = bar
15
+ ? {
16
+ field: current.positionField,
17
+ fieldType: current.positionFieldType,
18
+ temporalUnit: current.positionTemporalUnit
19
+ }
20
+ : current.position;
21
+ const position = {
22
+ field: storedPosition.field,
23
+ fieldType: storedPosition.fieldType,
24
+ ...(storedPosition.temporalUnit === undefined
25
+ ? {}
26
+ : { temporalUnit: storedPosition.temporalUnit }),
27
+ scale: { id: current.positionScale }
28
+ };
29
+ const interval = transform === undefined
30
+ ? {
31
+ center: current.centerField ?? owner.encoding[intervalChannel].title,
32
+ lower: current.lowerField,
33
+ upper: current.upperField,
34
+ scale: { id: current.intervalScale }
35
+ }
36
+ : {
37
+ field: transform.field,
38
+ center: transform.center,
39
+ extent: transform.extent,
40
+ ...(transform.method === undefined ? {} : { method: transform.method }),
41
+ ...(transform.level === undefined ? {} : { level: transform.level }),
42
+ scale: { id: current.intervalScale }
43
+ };
44
+ return {
45
+ source: current.source ?? transform?.source ?? current.data,
46
+ x: positionChannel === "x" ? position : interval,
47
+ y: positionChannel === "y" ? position : interval,
48
+ groupBy: bar ? current.groupField ?? transform?.groupBy?.find(
49
+ field => field !== current.positionField
50
+ ) : current.groupBy
51
+ };
52
+ }
53
+
54
+ export function resolveIntervalRoleScales(program, resolved, current, policy, owner, previous) {
55
+ const positionRole = {
56
+ field: resolved.position.field,
57
+ fieldType: resolved.position.fieldType,
58
+ scale: resolved.position.scale
59
+ };
60
+ const intervalTitle = resolved.interval.mode === "statistical"
61
+ ? resolved.interval.field
62
+ : resolved.interval.title;
63
+ const intervalRole = {
64
+ field: intervalTitle,
65
+ fieldType: "quantitative",
66
+ scale: resolved.interval.scale
67
+ };
68
+ const x = resolved.position.channel === "x" ? positionRole : intervalRole;
69
+ const y = resolved.position.channel === "y" ? positionRole : intervalRole;
70
+ const plan = (channel, role) => {
71
+ const fallback = role === intervalRole
72
+ ? current.intervalScale
73
+ : current.positionScale;
74
+ const stored = findSemanticScale(program, fallback);
75
+ const compatible = role.fieldType === "temporal"
76
+ ? stored?.type === "time"
77
+ : ["nominal", "ordinal"].includes(role.fieldType)
78
+ ? ["band", "point"].includes(stored?.type)
79
+ : ["linear", "log", "pow", "sqrt", "symlog"].includes(stored?.type);
80
+ const defaultType = role.fieldType === "temporal"
81
+ ? "time"
82
+ : ["nominal", "ordinal"].includes(role.fieldType) ? "band" : "linear";
83
+ const requested = role.scale.type !== undefined || compatible
84
+ ? role.scale
85
+ : { ...role.scale, type: defaultType };
86
+ return resolveDistributionScalePlan(program, {
87
+ channel,
88
+ fieldType: role.fieldType,
89
+ requested,
90
+ fallback,
91
+ defaults: role === intervalRole
92
+ ? policy.intervalScaleDefaults
93
+ : policy.scaleDefaults(role.fieldType)
94
+ });
95
+ };
96
+ const xScale = plan("x", x);
97
+ const yScale = plan("y", y);
98
+ return {
99
+ x: { ...x, scale: xScale.id },
100
+ y: { ...y, scale: yScale.id },
101
+ xScale,
102
+ yScale,
103
+ category: resolved.position.field,
104
+ categoryType: resolved.position.fieldType,
105
+ measure: intervalTitle,
106
+ previous: {
107
+ x: { field: previous.x.center ?? previous.x.field,
108
+ fieldType: owner.encoding.x.fieldType, scale: owner.encoding.x.scale },
109
+ y: { field: previous.y.center ?? previous.y.field,
110
+ fieldType: owner.encoding.y.fieldType, scale: owner.encoding.y.scale }
111
+ }
112
+ };
113
+ }
114
+
115
+ export function applyIntervalStatistics(program, full, policy, args, resolved) {
116
+ if (Object.hasOwn(args, "statistics")) {
117
+ validateIntervalStatistics(args.statistics, policy.operation);
118
+ const { method, level, ...interval } = full[resolved.interval.channel];
119
+ full[resolved.interval.channel] = {
120
+ ...interval,
121
+ ...mergeIntervalStatistics(resolved.interval, args.statistics)
122
+ };
123
+ resolved = resolveIntervalComposite(program, full, policy);
124
+ }
125
+ return resolved;
126
+ }
@@ -102,7 +102,7 @@ function normalizeConfig(
102
102
  return config;
103
103
  }
104
104
 
105
- const createArcMark = action(
105
+ const createArcMark = /* @__PURE__ */ action(
106
106
  {
107
107
  op: "createArcMark",
108
108
  description: "Create a semantic arc mark and empty path collection."
@@ -158,7 +158,7 @@ function requireArc(program, id) {
158
158
  return { layer, dataset };
159
159
  }
160
160
 
161
- const rematerializeArcMark = action(
161
+ const rematerializeArcMark = /* @__PURE__ */ action(
162
162
  {
163
163
  op: "rematerializeArcMark",
164
164
  description: "Recompute concrete annular-sector paths."
@@ -256,7 +256,7 @@ const rematerializeArcMark = action(
256
256
  }
257
257
  );
258
258
 
259
- const editArcMark = action(
259
+ const editArcMark = /* @__PURE__ */ action(
260
260
  {
261
261
  op: "editArcMark",
262
262
  description: "Edit arc geometry and appearance."