ggaction 0.0.9 → 0.0.11

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 (222) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/README.md +5 -4
  3. package/knowledge/action-card.schema.json +1 -0
  4. package/knowledge/action-cards.json +1 -10941
  5. package/knowledge/action-cards.schema.json +1 -0
  6. package/knowledge/extension-authoring.md +248 -0
  7. package/knowledge/intent-taxonomy.json +1 -183
  8. package/knowledge/intent-taxonomy.schema.json +1 -0
  9. package/knowledge/mcp-resources.json +1 -95
  10. package/knowledge/mcp-resources.schema.json +1 -0
  11. package/knowledge/task-packet.schema.json +1 -159
  12. package/knowledge/task-resolver.js +1 -1230
  13. package/package.json +19 -2
  14. package/src/actions/boxPlots/edit.js +45 -298
  15. package/src/actions/boxPlots/options.js +46 -77
  16. package/src/actions/boxPlots/resolve.js +1 -1
  17. package/src/actions/charts/bar.js +3 -0
  18. package/src/actions/charts/heatmap.js +73 -83
  19. package/src/actions/charts/index.js +1 -1
  20. package/src/actions/charts/parallel.js +35 -1
  21. package/src/actions/charts/shared.js +20 -0
  22. package/src/actions/composition/actions.js +46 -49
  23. package/src/actions/data/bin2d.js +105 -2
  24. package/src/actions/data/box.js +17 -17
  25. package/src/actions/data/density.js +42 -78
  26. package/src/actions/data/gradientProfile.js +22 -52
  27. package/src/actions/data/horizon.js +16 -41
  28. package/src/actions/data/index.js +10 -10
  29. package/src/actions/data/interval.js +16 -38
  30. package/src/actions/data/intervalEdit.js +55 -0
  31. package/src/actions/data/regression.js +7 -17
  32. package/src/actions/data/shared.js +47 -0
  33. package/src/actions/data/timeUnit.js +14 -38
  34. package/src/actions/data/window.js +14 -38
  35. package/src/actions/distributions/revision.js +154 -34
  36. package/src/actions/encodings/angle.js +9 -10
  37. package/src/actions/encodings/appearance.js +17 -51
  38. package/src/actions/encodings/density/resolve.js +3 -1
  39. package/src/actions/encodings/density.js +1 -15
  40. package/src/actions/encodings/horizon/resolve.js +13 -3
  41. package/src/actions/encodings/horizon.js +8 -7
  42. package/src/actions/encodings/index.js +9 -9
  43. package/src/actions/encodings/offset.js +8 -24
  44. package/src/actions/encodings/parallel.js +9 -10
  45. package/src/actions/encodings/pathOrder.js +6 -13
  46. package/src/actions/encodings/position/policies/index.js +4 -4
  47. package/src/actions/encodings/position/policies/line.js +47 -17
  48. package/src/actions/encodings/position/resolve.js +24 -5
  49. package/src/actions/encodings/ranged.js +18 -23
  50. package/src/actions/encodings/remove.js +15 -25
  51. package/src/actions/encodings/ruleAppearance.js +9 -24
  52. package/src/actions/encodings/shared.js +37 -0
  53. package/src/actions/encodings/strokeDash.js +8 -23
  54. package/src/actions/encodings/text.js +9 -10
  55. package/src/actions/errorBands/create.js +105 -39
  56. package/src/actions/errorBands/edit.js +89 -93
  57. package/src/actions/errorBands/index.js +1 -2
  58. package/src/actions/errorBars/create.js +78 -27
  59. package/src/actions/errorBars/edit.js +81 -48
  60. package/src/actions/errorBars/index.js +1 -2
  61. package/src/actions/facets/actions.js +45 -69
  62. package/src/actions/facets/derive.js +38 -53
  63. package/src/actions/facets/replay.js +0 -1
  64. package/src/actions/gradientPlots/components.js +59 -48
  65. package/src/actions/gradientPlots/edit.js +35 -216
  66. package/src/actions/gradientPlots/index.js +11 -10
  67. package/src/actions/gradientPlots/materialize.js +21 -35
  68. package/src/actions/gradientPlots/options.js +5 -7
  69. package/src/actions/gradientPlots/paint.js +9 -6
  70. package/src/actions/gradientPlots/resolve.js +1 -1
  71. package/src/actions/guides/axes/index.js +3 -3
  72. package/src/actions/guides/axes/labels.js +68 -26
  73. package/src/actions/guides/axes/lines.js +22 -2
  74. package/src/actions/guides/axes/policy.js +28 -8
  75. package/src/actions/guides/axes/ticks.js +27 -9
  76. package/src/actions/guides/axes/titles.js +113 -65
  77. package/src/actions/guides/grids/resolve.js +14 -0
  78. package/src/actions/guides/guides.js +2 -4
  79. package/src/actions/guides/index.js +2 -2
  80. package/src/actions/guides/legends/categorical/actions.js +44 -68
  81. package/src/actions/guides/legends/categorical/components.js +6 -1
  82. package/src/actions/guides/legends/categorical/index.js +2 -2
  83. package/src/actions/guides/legends/categorical/layout.js +148 -175
  84. package/src/actions/guides/legends/categorical/recipes.js +5 -0
  85. package/src/actions/guides/legends/categorical/resolve.js +8 -1
  86. package/src/actions/guides/legends/continuous/common.js +117 -66
  87. package/src/actions/guides/legends/continuous/gradient.js +38 -37
  88. package/src/actions/guides/legends/continuous/interval.js +97 -76
  89. package/src/actions/guides/legends/continuous/opacity.js +28 -38
  90. package/src/actions/guides/legends/edit.js +14 -1
  91. package/src/actions/guides/legends/index.js +1 -1
  92. package/src/actions/guides/legends/lane.js +2 -1
  93. package/src/actions/guides/legends/remove.js +8 -0
  94. package/src/actions/guides/legends/size.js +36 -43
  95. package/src/actions/guides/legends/strokeWidth.js +20 -26
  96. package/src/actions/guides/polar/axes/labels.js +17 -1
  97. package/src/actions/guides/polar/axes/shared.js +7 -1
  98. package/src/actions/guides/polar/axes/titles.js +19 -2
  99. package/src/actions/guides/polar/grids.js +4 -0
  100. package/src/actions/guides/polar/resolve.js +6 -0
  101. package/src/actions/index.js +13 -13
  102. package/src/actions/intervals/resolve.js +87 -117
  103. package/src/actions/marks/arc/actions.js +31 -36
  104. package/src/actions/marks/area/actions.js +23 -31
  105. package/src/actions/marks/index.js +6 -6
  106. package/src/actions/marks/line/actions.js +33 -52
  107. package/src/actions/marks/line/materialize.js +7 -5
  108. package/src/actions/marks/point/materialize.js +5 -3
  109. package/src/actions/marks/remove.js +21 -0
  110. package/src/actions/marks/rule/actions.js +53 -53
  111. package/src/actions/marks/shared.js +8 -4
  112. package/src/actions/marks/text/actions.js +14 -6
  113. package/src/actions/marks/text/layout.js +21 -45
  114. package/src/actions/marks/tick/actions.js +22 -21
  115. package/src/actions/primitives/createGraphics.js +4 -0
  116. package/src/actions/primitives/editGraphics.js +4 -0
  117. package/src/actions/primitives/index.js +3 -3
  118. package/src/actions/primitives/semantic.js +1 -1
  119. package/src/actions/primitives/semanticValidation/index.js +2 -2
  120. package/src/actions/primitives/semanticValidation/layer.js +1 -1
  121. package/src/actions/regression/edit.js +3 -43
  122. package/src/actions/scales/consumers/families.js +24 -4
  123. package/src/actions/scales/consumers/index.js +1 -1
  124. package/src/actions/scales/consumers/seriesLayout.js +17 -0
  125. package/src/actions/scales/definitions.js +100 -103
  126. package/src/actions/scales/materialize.js +5 -0
  127. package/src/actions/selection/actions.js +79 -121
  128. package/src/actions/titles/actions.js +48 -94
  129. package/src/actions/titles/resolve.js +14 -27
  130. package/src/actions/violinPlots/create.js +37 -44
  131. package/src/core/action.js +20 -5
  132. package/src/core/extensionRegistry.js +104 -0
  133. package/src/core/textMetrics.js +74 -37
  134. package/src/core/validation.js +18 -0
  135. package/src/extension.js +8 -1
  136. package/src/grammar/aggregate.js +48 -28
  137. package/src/grammar/arcs.js +58 -11
  138. package/src/grammar/areaSeries.js +14 -16
  139. package/src/grammar/bin2d.js +37 -23
  140. package/src/grammar/boxPlot.js +14 -13
  141. package/src/grammar/categoricalDensity.js +14 -14
  142. package/src/grammar/categoryOrder.js +8 -14
  143. package/src/grammar/curveCommands.js +87 -20
  144. package/src/grammar/density.js +162 -141
  145. package/src/grammar/facets/index.js +14 -0
  146. package/src/grammar/facets/scales.js +7 -4
  147. package/src/grammar/gradientProfile.js +12 -15
  148. package/src/grammar/histogram.js +145 -83
  149. package/src/grammar/horizon.js +60 -23
  150. package/src/grammar/interval.js +14 -13
  151. package/src/grammar/lineSeries.js +91 -61
  152. package/src/grammar/numeric.js +290 -0
  153. package/src/grammar/paint.js +3 -4
  154. package/src/grammar/palettes.js +21 -32
  155. package/src/grammar/pathCommands.js +6 -0
  156. package/src/grammar/polarPaths.js +5 -5
  157. package/src/grammar/regression/derive.js +48 -9
  158. package/src/grammar/regression/models.js +248 -69
  159. package/src/grammar/regression/parameters.js +8 -0
  160. package/src/grammar/scales/color.js +35 -26
  161. package/src/grammar/scales/continuous.js +71 -24
  162. package/src/grammar/scales/definition.js +1 -1
  163. package/src/grammar/scales/discretized.js +42 -12
  164. package/src/grammar/scales/fields.js +21 -4
  165. package/src/grammar/scales/ordinal.js +117 -61
  166. package/src/grammar/scales/temporal.js +40 -11
  167. package/src/grammar/scales/transformed.js +199 -52
  168. package/src/grammar/schemas/graphicBounds.js +270 -79
  169. package/src/grammar/seriesLayout.js +50 -18
  170. package/src/grammar/ticks.js +123 -53
  171. package/src/grammar/timeUnit.js +18 -8
  172. package/src/grammar/transforms.js +4 -1
  173. package/src/grammar/window.js +70 -57
  174. package/src/index.js +1 -1
  175. package/src/layout/canvas.js +4 -8
  176. package/src/layout/composition.js +39 -40
  177. package/src/layout/facets.js +10 -14
  178. package/src/layout/labels.js +91 -15
  179. package/src/layout/legend.js +22 -20
  180. package/src/layout/legendLane.js +54 -40
  181. package/src/layout/title.js +7 -7
  182. package/src/materialization/bars/aggregate.js +14 -40
  183. package/src/materialization/bars/grouped.js +7 -18
  184. package/src/materialization/bars/histogram.js +2 -19
  185. package/src/materialization/bars/ranged.js +20 -15
  186. package/src/materialization/bars/resolve.js +21 -0
  187. package/src/materialization/facetGuides/legacyCategorical.js +2 -1
  188. package/src/materialization/facetGuides/placement.js +34 -19
  189. package/src/materialization/facetGuides/preparation.js +9 -5
  190. package/src/materialization/facets.js +39 -27
  191. package/src/materialization/guides/resources.js +2 -1
  192. package/src/materialization/marks/capabilities.js +5 -2
  193. package/src/materialization/marks/index.js +24 -4
  194. package/src/materialization/scales/policies/bar.js +61 -59
  195. package/src/materialization/scales/policies/binnedPosition.js +34 -0
  196. package/src/materialization/scales/policies/series.js +13 -7
  197. package/src/materialization/scales/resolve.js +4 -5
  198. package/src/materialization/selection/items/arc.js +16 -2
  199. package/src/materialization/selection/items/bar.js +4 -2
  200. package/src/materialization/selection/items/common.js +21 -1
  201. package/src/materialization/selection/items/path.js +19 -2
  202. package/src/materialization/selection/items/point.js +4 -16
  203. package/src/materialization/selection/items/tick.js +13 -21
  204. package/src/materialization/selection/point.js +11 -4
  205. package/src/materialization/selection/styles.js +19 -27
  206. package/src/materialization/text.js +4 -1
  207. package/src/mcp/adapter.js +8 -3
  208. package/src/renderers/canvas/fill.js +2 -2
  209. package/src/renderers/canvas/index.js +35 -2
  210. package/src/renderers/canvas/native.js +160 -0
  211. package/src/renderers/pdf.js +14 -0
  212. package/src/renderers/svg.js +37 -4
  213. package/types/extension.d.ts +19 -0
  214. package/types/index.d.ts +3 -0
  215. package/types/program.d.ts +509 -131
  216. package/types/svg.d.ts +1 -0
  217. package/src/actions/errorBands/components.js +0 -81
  218. package/src/actions/errorBands/options.js +0 -39
  219. package/src/actions/errorBands/resolve.js +0 -28
  220. package/src/actions/errorBars/components.js +0 -62
  221. package/src/actions/errorBars/options.js +0 -58
  222. package/src/actions/errorBars/resolve.js +0 -25
@@ -8,6 +8,7 @@ import {
8
8
  import {
9
9
  assertMarkAvailable,
10
10
  applyLayeredMarkInheritance,
11
+ editMarkGraphic,
11
12
  materializeInheritedMark,
12
13
  resolveLayeredMarkInheritance,
13
14
  resolveMarkId,
@@ -26,12 +27,11 @@ import { resolveMarkGraphicPlacement } from
26
27
  import { rematerializeHighlightBaseline } from "../lifecycle.js";
27
28
  import { resolveAreaMaterialization } from "./materialize.js";
28
29
 
29
- const CREATE_OPTIONS = Object.freeze([
30
- "id", "data", "fill", "opacity", "stroke", "strokeWidth", "curve"
31
- ]);
32
- const EDIT_OPTIONS = Object.freeze([
33
- "target", "fill", "opacity", "stroke", "strokeWidth", "curve"
30
+ const AREA_OPTIONS = Object.freeze([
31
+ "fill", "opacity", "stroke", "strokeWidth", "curve"
34
32
  ]);
33
+ const CREATE_OPTIONS = Object.freeze(["id", "data", ...AREA_OPTIONS]);
34
+ const EDIT_OPTIONS = Object.freeze(["target", ...AREA_OPTIONS]);
35
35
  const REMATERIALIZE_OPTIONS = Object.freeze(["id", "scales"]);
36
36
  const STROKE_FROM_FILL_OPTIONS = Object.freeze(["id", "strokeWidth"]);
37
37
 
@@ -194,29 +194,20 @@ const rematerializeAreaMark = action(
194
194
  const removesOutline = !hasOutline && existingChildren.some(
195
195
  child => child.properties.stroke !== undefined
196
196
  );
197
- let next = removesOutline
197
+ const next = removesOutline
198
198
  ? resolved
199
199
  .editGraphics({ target: id, property: "length", value: 0 })
200
- .editGraphics({ target: id, property: "length", value: paths.length })
201
- : resolved.editGraphics({ target: id, property: "length", value: paths.length });
202
- next = next
203
- .editGraphics({ target: id, property: "commands", value: paths })
204
- .editGraphics({ target: id, property: "fill", value: fills })
205
- .editGraphics({ target: id, property: "opacity", value: config.opacity });
206
- if (hasOutline) {
207
- next = next
208
- .editGraphics({
209
- target: id,
210
- property: "stroke",
211
- value: config.strokeFromFill === true ? fills : config.stroke
212
- })
213
- .editGraphics({
214
- target: id,
215
- property: "strokeWidth",
216
- value: config.strokeWidth
217
- });
218
- }
219
- return next;
200
+ : resolved;
201
+ return editMarkGraphic(next, id, {
202
+ length: paths.length,
203
+ commands: paths,
204
+ fill: fills,
205
+ opacity: config.opacity,
206
+ ...(hasOutline ? {
207
+ stroke: config.strokeFromFill === true ? fills : config.stroke,
208
+ strokeWidth: config.strokeWidth
209
+ } : {})
210
+ });
220
211
  }
221
212
  );
222
213
 
@@ -300,9 +291,10 @@ const editAreaMark = action(
300
291
  );
301
292
 
302
293
  export function registerAreaMarkActions(ProgramClass) {
303
- ProgramClass.prototype.createAreaMark = createAreaMark;
304
- ProgramClass.prototype.configureAreaStrokeFromFill =
305
- configureAreaStrokeFromFill;
306
- ProgramClass.prototype.editAreaMark = editAreaMark;
307
- ProgramClass.prototype.rematerializeAreaMark = rematerializeAreaMark;
294
+ Object.assign(ProgramClass.prototype, {
295
+ createAreaMark,
296
+ configureAreaStrokeFromFill,
297
+ editAreaMark,
298
+ rematerializeAreaMark
299
+ });
308
300
  }
@@ -1,16 +1,16 @@
1
- import { registerBarMarkActions } from "./bar/index.js";
1
+ import { removeMark } from "./remove.js";
2
+ import { registerRuleMarkActions } from "./rule/index.js";
2
3
  import { registerAreaMarkActions } from "./area/index.js";
3
- import { registerArcMarkActions } from "./arc/index.js";
4
+ import { registerTickMarkActions } from "./tick/index.js";
5
+ import { registerBarMarkActions } from "./bar/index.js";
4
6
  import { registerLineMarkActions } from "./line/index.js";
7
+ import { registerArcMarkActions } from "./arc/index.js";
8
+ import { registerRectMarkActions } from "./rect/index.js";
5
9
  import {
6
10
  registerPointJitterActions,
7
11
  registerPointMarkActions
8
12
  } from "./point/index.js";
9
- import { registerRectMarkActions } from "./rect/index.js";
10
- import { registerRuleMarkActions } from "./rule/index.js";
11
13
  import { registerTextMarkActions } from "./text/index.js";
12
- import { registerTickMarkActions } from "./tick/index.js";
13
- import { removeMark } from "./remove.js";
14
14
 
15
15
  export function registerMarkActions(ProgramClass) {
16
16
  registerPointMarkActions(ProgramClass);
@@ -8,6 +8,7 @@ import {
8
8
  import {
9
9
  assertMarkAvailable,
10
10
  applyLayeredMarkInheritance,
11
+ editMarkGraphic,
11
12
  materializeInheritedMark,
12
13
  resolveLayeredMarkInheritance,
13
14
  resolveMarkId,
@@ -28,6 +29,8 @@ import {
28
29
  resolveParallelLineMaterialization,
29
30
  resolvePositionedLineMaterialization
30
31
  } from "./materialize.js";
32
+ import { resolveLineBins } from "../../../grammar/lineSeries.js";
33
+ import { requireSemanticScale } from "../../../selectors/scales.js";
31
34
 
32
35
  const DEFAULT_LINE_STROKE = DEFAULT_COLORS.mark;
33
36
  const DEFAULT_LINE_WIDTH = 2;
@@ -68,6 +71,17 @@ function validatePolarLineConfig(layer, config) {
68
71
  }
69
72
  }
70
73
 
74
+ function applyLineMaterialization(program, id, materialization, opacity) {
75
+ return editMarkGraphic(program, id, {
76
+ length: materialization.commands.length,
77
+ commands: materialization.commands,
78
+ stroke: materialization.strokes,
79
+ strokeWidth: materialization.strokeWidths,
80
+ strokeDash: materialization.strokeDashes,
81
+ ...(opacity === undefined ? {} : { opacity })
82
+ });
83
+ }
84
+
71
85
  const createLineMark = action(
72
86
  {
73
87
  op: "createLineMark",
@@ -215,36 +229,12 @@ const rematerializeLineMark = action(
215
229
  existingChildren,
216
230
  defaults: { stroke: DEFAULT_LINE_STROKE, strokeWidth: DEFAULT_LINE_WIDTH }
217
231
  });
218
- let next = resolved
219
- .editGraphics({
220
- target: id,
221
- property: "length",
222
- value: materialization.commands.length
223
- })
224
- .editGraphics({
225
- target: id,
226
- property: "commands",
227
- value: materialization.commands
228
- })
229
- .editGraphics({ target: id, property: "stroke", value: materialization.strokes })
230
- .editGraphics({
231
- target: id,
232
- property: "strokeWidth",
233
- value: materialization.strokeWidths
234
- })
235
- .editGraphics({
236
- target: id,
237
- property: "strokeDash",
238
- value: materialization.strokeDashes
239
- });
240
- if (config.opacity !== undefined) {
241
- next = next.editGraphics({
242
- target: id,
243
- property: "opacity",
244
- value: config.opacity
245
- });
246
- }
247
- return next;
232
+ return applyLineMaterialization(
233
+ resolved,
234
+ id,
235
+ materialization,
236
+ config.opacity
237
+ );
248
238
  }
249
239
 
250
240
  if (
@@ -280,6 +270,13 @@ const rematerializeLineMark = action(
280
270
  rows: dataset.values,
281
271
  layer,
282
272
  resolvedScales: resolved.resolvedScales,
273
+ xBinBoundaries: layer.encoding?.x?.bin === undefined
274
+ ? undefined
275
+ : resolveLineBins(
276
+ dataset.values,
277
+ layer,
278
+ requireSemanticScale(resolved, xScaleId)
279
+ ).boundaries,
283
280
  bounds: resolveGraphicBounds(resolved),
284
281
  config,
285
282
  existingChildren,
@@ -287,28 +284,12 @@ const rematerializeLineMark = action(
287
284
  defaults: { stroke: DEFAULT_LINE_STROKE, strokeWidth: DEFAULT_LINE_WIDTH }
288
285
  });
289
286
 
290
- let next = resolved
291
- .editGraphics({
292
- target: id,
293
- property: "length",
294
- value: materialization.commands.length
295
- })
296
- .editGraphics({ target: id, property: "commands", value: materialization.commands })
297
- .editGraphics({ target: id, property: "stroke", value: materialization.strokes })
298
- .editGraphics({ target: id, property: "strokeWidth", value: materialization.strokeWidths })
299
- .editGraphics({
300
- target: id,
301
- property: "strokeDash",
302
- value: materialization.strokeDashes
303
- });
304
- if (config.opacity !== undefined) {
305
- next = next.editGraphics({
306
- target: id,
307
- property: "opacity",
308
- value: config.opacity
309
- });
310
- }
311
- return next;
287
+ return applyLineMaterialization(
288
+ resolved,
289
+ id,
290
+ materialization,
291
+ config.opacity
292
+ );
312
293
  }
313
294
  );
314
295
 
@@ -76,6 +76,7 @@ export function resolvePositionedLineMaterialization({
76
76
  rows,
77
77
  layer,
78
78
  resolvedScales,
79
+ xBinBoundaries,
79
80
  bounds,
80
81
  config,
81
82
  existingChildren,
@@ -86,11 +87,12 @@ export function resolvePositionedLineMaterialization({
86
87
  const yScaleId = layer.encoding?.y?.scale;
87
88
  const thetaScaleId = layer.encoding?.theta?.scale;
88
89
  const radiusScaleId = layer.encoding?.radius?.scale;
89
- const derived = deriveLineSeries(
90
- rows,
91
- layer,
92
- polar ? { thetaDomain: resolvedScales[thetaScaleId].domain } : undefined
93
- );
90
+ const lineOptions = polar
91
+ ? { thetaDomain: resolvedScales[thetaScaleId].domain }
92
+ : layer.encoding?.x?.bin === undefined
93
+ ? undefined
94
+ : { xBinBoundaries };
95
+ const derived = deriveLineSeries(rows, layer, lineOptions);
94
96
  const commands = polar
95
97
  ? derived.series.map(series => buildPolarLinePathCommands({
96
98
  series: series.values,
@@ -78,8 +78,8 @@ function existingArea(child, parentType) {
78
78
  }
79
79
  if (
80
80
  type === "rect" &&
81
- Number.isFinite(child.properties?.width) &&
82
- Number.isFinite(child.properties?.height)
81
+ Number.isFinite(child?.properties?.width) &&
82
+ Number.isFinite(child?.properties?.height)
83
83
  ) {
84
84
  return child.properties.width * child.properties.height;
85
85
  }
@@ -354,7 +354,9 @@ export const rematerializePointMark = action(
354
354
  ? dataset.values.map((_, index) => {
355
355
  const existing = existingArea(existingChildren[index], graphic.type);
356
356
  return Math.sqrt(
357
- existing ?? Math.PI * (config.radius ?? DEFAULT_POINT_RADIUS) ** 2
357
+ config.radius === undefined
358
+ ? existing ?? Math.PI * DEFAULT_POINT_RADIUS ** 2
359
+ : Math.PI * config.radius ** 2
358
360
  );
359
361
  })
360
362
  : area.map(value => Math.sqrt(value));
@@ -138,6 +138,27 @@ function cleanupSelectionState(program, ids) {
138
138
  };
139
139
  }
140
140
 
141
+ export function removeOwnedMark(program, id, partial = false) {
142
+ const layer = findLayer(program, id);
143
+ if (!partial && layer === undefined) return program;
144
+ const cleaned = cleanupSelectionState(program, [id]);
145
+ let next = cleaned.program;
146
+ if (layer !== undefined) {
147
+ next = next.editSemantic({ property: `layer[${id}]`, remove: true });
148
+ }
149
+ if (next.graphicSpec.objects[id] !== undefined) {
150
+ next = next.editGraphics({ target: id, remove: true });
151
+ }
152
+ return next
153
+ ._withoutMaterializationConfig(["marks", id])
154
+ ._withContext({
155
+ ...(program.context.currentMark === id ? { currentMark: undefined } : {}),
156
+ ...(cleaned.selectionIds.includes(program.context.currentSelection)
157
+ ? { currentSelection: undefined }
158
+ : {})
159
+ });
160
+ }
161
+
141
162
  function hasScaleConsumer(program, channel, scale) {
142
163
  return program.semanticSpec.layers.some(
143
164
  layer => layer.encoding?.[channel]?.scale === scale
@@ -15,6 +15,7 @@ import { DEFAULT_COLORS } from "../../../theme/defaults.js";
15
15
  import {
16
16
  assertMarkAvailable,
17
17
  applyLayeredMarkInheritance,
18
+ editMarkGraphic,
18
19
  materializeInheritedMark,
19
20
  resolveLayeredMarkInheritance,
20
21
  resolveMarkData,
@@ -183,59 +184,59 @@ const rematerializeRuleMark = action(
183
184
  const x2 = [];
184
185
  const y2 = [];
185
186
  for (let index = 0; index < derived.length; index += 1) {
187
+ let startX;
188
+ let startY;
189
+ let endX;
190
+ let endY;
186
191
  if (mode === "vertical-span") {
187
- x1.push(mapped.x[index]);
188
- y1.push(bounds.y);
189
- x2.push(mapped.x[index]);
190
- y2.push(bounds.y + bounds.height);
192
+ startX = endX = mapped.x[index];
193
+ startY = bounds.y;
194
+ endY = bounds.y + bounds.height;
191
195
  } else if (mode === "horizontal-span") {
192
- x1.push(bounds.x);
193
- y1.push(mapped.y[index]);
194
- x2.push(bounds.x + bounds.width);
195
- y2.push(mapped.y[index]);
196
+ startX = bounds.x;
197
+ endX = bounds.x + bounds.width;
198
+ startY = endY = mapped.y[index];
196
199
  } else if (mode === "vertical-interval") {
197
- x1.push(mapped.x[index]);
198
- y1.push(mapped.y[index]);
199
- x2.push(mapped.x[index]);
200
- y2.push(mapped.y2[index]);
200
+ startX = endX = mapped.x[index];
201
+ startY = mapped.y[index];
202
+ endY = mapped.y2[index];
201
203
  } else if (mode === "horizontal-interval") {
202
- x1.push(mapped.x[index]);
203
- y1.push(mapped.y[index]);
204
- x2.push(mapped.x2[index]);
205
- y2.push(mapped.y[index]);
204
+ startX = mapped.x[index];
205
+ endX = mapped.x2[index];
206
+ startY = endY = mapped.y[index];
206
207
  } else if (mode === "box-span") {
207
208
  const owner = resolved.graphicSpec.objects[boxSpan];
208
209
  const box = owner?.items?.[index]?.properties;
209
210
  if (box === undefined) throw new Error(`Rule mark "${id}" requires box span owner "${boxSpan}".`);
210
211
  if (layer.encoding?.x?.fieldType === "quantitative") {
211
- x1.push(mapped.x[index]);
212
- y1.push(box.y);
213
- x2.push(mapped.x[index]);
214
- y2.push(box.y + box.height);
212
+ startX = endX = mapped.x[index];
213
+ startY = box.y;
214
+ endY = box.y + box.height;
215
215
  } else {
216
- x1.push(box.x);
217
- y1.push(mapped.y[index]);
218
- x2.push(box.x + box.width);
219
- y2.push(mapped.y[index]);
216
+ startX = box.x;
217
+ endX = box.x + box.width;
218
+ startY = endY = mapped.y[index];
220
219
  }
221
220
  } else if (mode === "fixed-span") {
222
221
  if (fixedSpan.orientation === "horizontal") {
223
- x1.push(mapped.x[index] - fixedSpan.size / 2);
224
- y1.push(mapped.y[index]);
225
- x2.push(mapped.x[index] + fixedSpan.size / 2);
226
- y2.push(mapped.y[index]);
222
+ startX = mapped.x[index] - fixedSpan.size / 2;
223
+ endX = mapped.x[index] + fixedSpan.size / 2;
224
+ startY = endY = mapped.y[index];
227
225
  } else {
228
- x1.push(mapped.x[index]);
229
- y1.push(mapped.y[index] - fixedSpan.size / 2);
230
- x2.push(mapped.x[index]);
231
- y2.push(mapped.y[index] + fixedSpan.size / 2);
226
+ startX = endX = mapped.x[index];
227
+ startY = mapped.y[index] - fixedSpan.size / 2;
228
+ endY = mapped.y[index] + fixedSpan.size / 2;
232
229
  }
233
230
  } else {
234
- x1.push(mapped.x[index]);
235
- y1.push(mapped.y[index]);
236
- x2.push(mapped.x2[index]);
237
- y2.push(mapped.y2[index]);
231
+ startX = mapped.x[index];
232
+ startY = mapped.y[index];
233
+ endX = mapped.x2[index];
234
+ endY = mapped.y2[index];
238
235
  }
236
+ x1.push(startX);
237
+ y1.push(startY);
238
+ x2.push(endX);
239
+ y2.push(endY);
239
240
  }
240
241
 
241
242
  const resolvedConfig = {
@@ -270,20 +271,17 @@ const rematerializeRuleMark = action(
270
271
  resolved.resolvedScales[strokeWidthEncoding.scale]
271
272
  );
272
273
 
273
- return resolved
274
- .editGraphics({ target: id, property: "length", value: derived.length })
275
- .editGraphics({ target: id, property: "x1", value: x1 })
276
- .editGraphics({ target: id, property: "y1", value: y1 })
277
- .editGraphics({ target: id, property: "x2", value: x2 })
278
- .editGraphics({ target: id, property: "y2", value: y2 })
279
- .editGraphics({ target: id, property: "stroke", value: resolvedConfig.stroke })
280
- .editGraphics({
281
- target: id,
282
- property: "strokeWidth",
283
- value: strokeWidth
284
- })
285
- .editGraphics({ target: id, property: "strokeDash", value: strokeDash })
286
- .editGraphics({ target: id, property: "opacity", value: opacity });
274
+ return editMarkGraphic(resolved, id, {
275
+ length: derived.length,
276
+ x1,
277
+ y1,
278
+ x2,
279
+ y2,
280
+ stroke: resolvedConfig.stroke,
281
+ strokeWidth,
282
+ strokeDash,
283
+ opacity
284
+ });
287
285
  }
288
286
  );
289
287
 
@@ -312,7 +310,9 @@ export const materializeRuleSpan = action(
312
310
  );
313
311
 
314
312
  export function registerRuleMarkActions(ProgramClass) {
315
- ProgramClass.prototype.createRuleMark = createRuleMark;
316
- ProgramClass.prototype.rematerializeRuleMark = rematerializeRuleMark;
317
- ProgramClass.prototype.materializeRuleSpan = materializeRuleSpan;
313
+ Object.assign(ProgramClass.prototype, {
314
+ createRuleMark,
315
+ rematerializeRuleMark,
316
+ materializeRuleSpan
317
+ });
318
318
  }
@@ -155,10 +155,7 @@ export function resolveCompatibleEncodings(program, source, markType) {
155
155
  };
156
156
  pending.delete(channel);
157
157
  break;
158
- } catch {
159
- // Try the next target-compatible policy subset. Another channel may
160
- // also make a richer subset resolvable on the next pass.
161
- }
158
+ } catch {}
162
159
  }
163
160
  }
164
161
  }
@@ -241,3 +238,10 @@ export function materializeInheritedMark(program, id) {
241
238
  : getMarkMaterializationStep(program, layer);
242
239
  return step === undefined ? program : program[step.op](step.args);
243
240
  }
241
+
242
+ export function editMarkGraphic(program, target, properties) {
243
+ for (const [property, value] of Object.entries(properties)) {
244
+ program = program.editGraphics({ target, property, value });
245
+ }
246
+ return program;
247
+ }
@@ -4,7 +4,10 @@ import {
4
4
  DEFAULT_TEXT_MARK,
5
5
  normalizeTextMarkConfig
6
6
  } from "../../../grammar/text.js";
7
- import { canMaterializeText } from "../../../materialization/marks/index.js";
7
+ import {
8
+ canMaterializeArc,
9
+ canMaterializeText
10
+ } from "../../../materialization/marks/index.js";
8
11
  import { resolveTextGraphicItems } from "../../../materialization/text.js";
9
12
  import { findLayer, resolveEligibleLayer } from "../../../selectors/layers.js";
10
13
  import {
@@ -25,7 +28,7 @@ const STYLE_OPTIONS = Object.freeze([
25
28
  const CREATE_OPTIONS = Object.freeze(["id", "data", "text", ...STYLE_OPTIONS]);
26
29
  const EDIT_OPTIONS = Object.freeze(["target", ...STYLE_OPTIONS]);
27
30
  const REMATERIALIZE_OPTIONS = Object.freeze(["id", "replayLayout"]);
28
- const SOURCE_TYPES = new Set(["point", "bar", "rule", "rect"]);
31
+ const SOURCE_TYPES = new Set(["point", "bar", "rule", "rect", "arc"]);
29
32
 
30
33
  function sourceMatchesData(program, layer, requestedData) {
31
34
  if (requestedData === undefined || layer?.data === requestedData) return true;
@@ -38,6 +41,7 @@ function eligibleSource(program, layer, requestedData) {
38
41
  layer.data === undefined ||
39
42
  !sourceMatchesData(program, layer, requestedData)
40
43
  ) return false;
44
+ if (layer.mark.type === "arc") return canMaterializeArc(program, layer);
41
45
  const encodings = resolveCompatibleEncodings(program, layer, "text");
42
46
  return encodings.x !== undefined && encodings.y !== undefined;
43
47
  }
@@ -64,7 +68,9 @@ function resolveTextInheritance(program, args) {
64
68
  source: source.id,
65
69
  data: source.data,
66
70
  coordinate: source.coordinate,
67
- encoding: resolveCompatibleEncodings(program, source, "text")
71
+ encoding: source.mark.type === "arc"
72
+ ? {}
73
+ : resolveCompatibleEncodings(program, source, "text")
68
74
  };
69
75
  }
70
76
 
@@ -201,7 +207,9 @@ const editTextMark = action(
201
207
  );
202
208
 
203
209
  export function registerTextMarkActions(ProgramClass) {
204
- ProgramClass.prototype.createTextMark = createTextMark;
205
- ProgramClass.prototype.editTextMark = editTextMark;
206
- ProgramClass.prototype.rematerializeTextMark = rematerializeTextMark;
210
+ Object.assign(ProgramClass.prototype, {
211
+ createTextMark,
212
+ editTextMark,
213
+ rematerializeTextMark
214
+ });
207
215
  }
@@ -14,6 +14,7 @@ import { resolveGraphicBounds } from "../../../layout/canvas.js";
14
14
  import { canMaterializeText } from "../../../materialization/marks/index.js";
15
15
  import { resolveTextGraphicEntries } from "../../../materialization/text.js";
16
16
  import { findLayer, resolveEligibleLayer } from "../../../selectors/layers.js";
17
+ import { editMarkGraphic } from "../shared.js";
17
18
 
18
19
  const LAYOUT_OPTIONS = Object.freeze([
19
20
  "target", "axis", "padding", "maxDisplacement", "bounds", "leader"
@@ -170,42 +171,22 @@ function materializeLeaders(program, layer, config, resolved) {
170
171
  if (config.leader === false) return { program: next, count: 0 };
171
172
  const leaders = resolved.items.map(resolveLabelLeader).filter(Boolean);
172
173
  if (leaders.length === 0) return { program: next, count: 0 };
173
- next = next
174
- .createGraphics({
174
+ next = next.createGraphics({
175
175
  id: config.leaderId,
176
176
  type: "line",
177
177
  length: leaders.length,
178
178
  ...leaderPlacement(next, layer)
179
- })
180
- .editGraphics({
181
- target: config.leaderId,
182
- property: "x1",
183
- value: leaders.map(line => line.x1)
184
- })
185
- .editGraphics({
186
- target: config.leaderId,
187
- property: "y1",
188
- value: leaders.map(line => line.y1)
189
- })
190
- .editGraphics({
191
- target: config.leaderId,
192
- property: "x2",
193
- value: leaders.map(line => line.x2)
194
- })
195
- .editGraphics({
196
- target: config.leaderId,
197
- property: "y2",
198
- value: leaders.map(line => line.y2)
199
179
  });
200
- for (const property of ["stroke", "strokeWidth", "strokeDash", "opacity"]) {
201
- next = next.editGraphics({
202
- target: config.leaderId,
203
- property,
204
- value: property === "strokeDash"
205
- ? leaders.map(() => config.leader.strokeDash)
206
- : config.leader[property]
207
- });
208
- }
180
+ next = editMarkGraphic(next, config.leaderId, {
181
+ x1: leaders.map(line => line.x1),
182
+ y1: leaders.map(line => line.y1),
183
+ x2: leaders.map(line => line.x2),
184
+ y2: leaders.map(line => line.y2),
185
+ stroke: config.leader.stroke,
186
+ strokeWidth: config.leader.strokeWidth,
187
+ strokeDash: leaders.map(() => config.leader.strokeDash),
188
+ opacity: config.leader.opacity
189
+ });
209
190
  return { program: next, count: leaders.length };
210
191
  }
211
192
 
@@ -237,17 +218,10 @@ const materializeLabelLayout = action(
237
218
  padding: config.padding,
238
219
  maxDisplacement: config.maxDisplacement
239
220
  });
240
- next = next
241
- .editGraphics({
242
- target: id,
243
- property: "x",
244
- value: resolved.items.map(item => item.x)
245
- })
246
- .editGraphics({
247
- target: id,
248
- property: "y",
249
- value: resolved.items.map(item => item.y)
250
- });
221
+ next = editMarkGraphic(next, id, {
222
+ x: resolved.items.map(item => item.x),
223
+ y: resolved.items.map(item => item.y)
224
+ });
251
225
  const leaders = materializeLeaders(next, layer, config, resolved);
252
226
  next = leaders.program;
253
227
  return next._withMaterializationConfig(["labelLayouts", id], {
@@ -315,7 +289,9 @@ const removeLabelLayout = action(
315
289
  );
316
290
 
317
291
  export function registerTextLabelLayoutActions(ProgramClass) {
318
- ProgramClass.prototype.layoutLabels = layoutLabels;
319
- ProgramClass.prototype.removeLabelLayout = removeLabelLayout;
320
- ProgramClass.prototype.materializeLabelLayout = materializeLabelLayout;
292
+ Object.assign(ProgramClass.prototype, {
293
+ layoutLabels,
294
+ removeLabelLayout,
295
+ materializeLabelLayout
296
+ });
321
297
  }