ggaction 0.0.10 → 0.0.12

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 (224) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/README.md +5 -3
  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/intent-taxonomy.json +1 -183
  7. package/knowledge/intent-taxonomy.schema.json +1 -0
  8. package/knowledge/mcp-resources.json +1 -95
  9. package/knowledge/mcp-resources.schema.json +1 -0
  10. package/knowledge/task-packet.schema.json +1 -159
  11. package/knowledge/task-resolver.js +1 -1230
  12. package/package.json +18 -2
  13. package/src/actions/boxPlots/edit.js +45 -298
  14. package/src/actions/boxPlots/options.js +46 -77
  15. package/src/actions/boxPlots/resolve.js +1 -1
  16. package/src/actions/charts/bar.js +3 -0
  17. package/src/actions/charts/heatmap.js +73 -83
  18. package/src/actions/charts/index.js +1 -1
  19. package/src/actions/charts/parallel.js +35 -1
  20. package/src/actions/charts/shared.js +20 -0
  21. package/src/actions/composition/actions.js +46 -49
  22. package/src/actions/data/bin2d.js +105 -2
  23. package/src/actions/data/box.js +17 -17
  24. package/src/actions/data/density.js +42 -78
  25. package/src/actions/data/gradientProfile.js +22 -52
  26. package/src/actions/data/horizon.js +16 -41
  27. package/src/actions/data/index.js +10 -10
  28. package/src/actions/data/interval.js +16 -38
  29. package/src/actions/data/intervalEdit.js +55 -0
  30. package/src/actions/data/regression.js +7 -17
  31. package/src/actions/data/shared.js +47 -0
  32. package/src/actions/data/timeUnit.js +14 -38
  33. package/src/actions/data/window.js +14 -38
  34. package/src/actions/distributions/revision.js +154 -34
  35. package/src/actions/encodings/angle.js +9 -10
  36. package/src/actions/encodings/appearance.js +17 -51
  37. package/src/actions/encodings/density/resolve.js +3 -1
  38. package/src/actions/encodings/density.js +1 -15
  39. package/src/actions/encodings/horizon/resolve.js +13 -3
  40. package/src/actions/encodings/horizon.js +8 -7
  41. package/src/actions/encodings/index.js +9 -9
  42. package/src/actions/encodings/offset.js +41 -45
  43. package/src/actions/encodings/parallel.js +9 -10
  44. package/src/actions/encodings/pathOrder.js +6 -13
  45. package/src/actions/encodings/position/apply.js +30 -0
  46. package/src/actions/encodings/position/policies/arc.js +23 -2
  47. package/src/actions/encodings/position/policies/index.js +4 -4
  48. package/src/actions/encodings/position/policies/line.js +47 -17
  49. package/src/actions/encodings/position/resolve.js +36 -7
  50. package/src/actions/encodings/ranged.js +18 -23
  51. package/src/actions/encodings/remove.js +15 -25
  52. package/src/actions/encodings/ruleAppearance.js +9 -24
  53. package/src/actions/encodings/shared.js +37 -0
  54. package/src/actions/encodings/strokeDash.js +8 -23
  55. package/src/actions/encodings/text.js +9 -10
  56. package/src/actions/errorBands/create.js +105 -39
  57. package/src/actions/errorBands/edit.js +89 -93
  58. package/src/actions/errorBands/index.js +1 -2
  59. package/src/actions/errorBars/create.js +212 -30
  60. package/src/actions/errorBars/edit.js +91 -48
  61. package/src/actions/errorBars/index.js +1 -2
  62. package/src/actions/facets/actions.js +45 -69
  63. package/src/actions/facets/derive.js +38 -53
  64. package/src/actions/facets/replay.js +0 -1
  65. package/src/actions/gradientPlots/components.js +59 -48
  66. package/src/actions/gradientPlots/edit.js +35 -216
  67. package/src/actions/gradientPlots/index.js +11 -10
  68. package/src/actions/gradientPlots/materialize.js +21 -35
  69. package/src/actions/gradientPlots/options.js +5 -7
  70. package/src/actions/gradientPlots/paint.js +9 -6
  71. package/src/actions/gradientPlots/resolve.js +1 -1
  72. package/src/actions/guides/axes/index.js +3 -3
  73. package/src/actions/guides/axes/labels.js +68 -26
  74. package/src/actions/guides/axes/lines.js +22 -2
  75. package/src/actions/guides/axes/policy.js +28 -8
  76. package/src/actions/guides/axes/ticks.js +27 -9
  77. package/src/actions/guides/axes/titles.js +113 -65
  78. package/src/actions/guides/grids/resolve.js +14 -0
  79. package/src/actions/guides/guides.js +2 -4
  80. package/src/actions/guides/index.js +2 -2
  81. package/src/actions/guides/legends/categorical/actions.js +44 -68
  82. package/src/actions/guides/legends/categorical/components.js +6 -1
  83. package/src/actions/guides/legends/categorical/index.js +2 -2
  84. package/src/actions/guides/legends/categorical/layout.js +148 -175
  85. package/src/actions/guides/legends/categorical/recipes.js +5 -0
  86. package/src/actions/guides/legends/categorical/resolve.js +8 -1
  87. package/src/actions/guides/legends/continuous/common.js +117 -66
  88. package/src/actions/guides/legends/continuous/gradient.js +38 -37
  89. package/src/actions/guides/legends/continuous/interval.js +97 -76
  90. package/src/actions/guides/legends/continuous/opacity.js +28 -38
  91. package/src/actions/guides/legends/edit.js +14 -1
  92. package/src/actions/guides/legends/index.js +1 -1
  93. package/src/actions/guides/legends/lane.js +2 -1
  94. package/src/actions/guides/legends/remove.js +8 -0
  95. package/src/actions/guides/legends/size.js +36 -43
  96. package/src/actions/guides/legends/strokeWidth.js +20 -26
  97. package/src/actions/guides/polar/axes/labels.js +17 -1
  98. package/src/actions/guides/polar/axes/shared.js +7 -1
  99. package/src/actions/guides/polar/axes/titles.js +19 -2
  100. package/src/actions/guides/polar/grids.js +4 -0
  101. package/src/actions/guides/polar/resolve.js +6 -0
  102. package/src/actions/index.js +13 -13
  103. package/src/actions/intervals/resolve.js +87 -117
  104. package/src/actions/marks/arc/actions.js +31 -36
  105. package/src/actions/marks/area/actions.js +23 -31
  106. package/src/actions/marks/index.js +6 -6
  107. package/src/actions/marks/line/actions.js +33 -52
  108. package/src/actions/marks/line/materialize.js +7 -5
  109. package/src/actions/marks/point/materialize.js +38 -16
  110. package/src/actions/marks/remove.js +21 -0
  111. package/src/actions/marks/rule/actions.js +79 -54
  112. package/src/actions/marks/shared.js +8 -4
  113. package/src/actions/marks/text/actions.js +14 -6
  114. package/src/actions/marks/text/layout.js +21 -45
  115. package/src/actions/marks/tick/actions.js +22 -21
  116. package/src/actions/primitives/createGraphics.js +4 -0
  117. package/src/actions/primitives/editGraphics.js +4 -0
  118. package/src/actions/primitives/index.js +3 -3
  119. package/src/actions/primitives/semantic.js +1 -1
  120. package/src/actions/primitives/semanticValidation/index.js +2 -2
  121. package/src/actions/primitives/semanticValidation/layer.js +1 -1
  122. package/src/actions/regression/edit.js +3 -43
  123. package/src/actions/scales/consumers/families.js +24 -4
  124. package/src/actions/scales/consumers/index.js +1 -1
  125. package/src/actions/scales/consumers/seriesLayout.js +17 -0
  126. package/src/actions/scales/definitions.js +100 -103
  127. package/src/actions/scales/materialize.js +5 -0
  128. package/src/actions/selection/actions.js +79 -121
  129. package/src/actions/titles/actions.js +48 -94
  130. package/src/actions/titles/resolve.js +14 -27
  131. package/src/actions/violinPlots/create.js +37 -44
  132. package/src/core/textMetrics.js +74 -37
  133. package/src/core/validation.js +18 -0
  134. package/src/core/vocabulary.js +2 -2
  135. package/src/grammar/aggregate.js +48 -28
  136. package/src/grammar/arcs.js +170 -32
  137. package/src/grammar/areaSeries.js +14 -16
  138. package/src/grammar/bin2d.js +37 -23
  139. package/src/grammar/boxPlot.js +14 -13
  140. package/src/grammar/categoricalDensity.js +14 -14
  141. package/src/grammar/categoryOrder.js +8 -14
  142. package/src/grammar/curveCommands.js +87 -20
  143. package/src/grammar/density.js +162 -141
  144. package/src/grammar/facets/index.js +14 -0
  145. package/src/grammar/facets/scales.js +7 -4
  146. package/src/grammar/gradientProfile.js +12 -15
  147. package/src/grammar/histogram.js +145 -83
  148. package/src/grammar/horizon.js +60 -23
  149. package/src/grammar/interval.js +14 -13
  150. package/src/grammar/lineSeries.js +91 -61
  151. package/src/grammar/numeric.js +290 -0
  152. package/src/grammar/paint.js +3 -4
  153. package/src/grammar/palettes.js +21 -32
  154. package/src/grammar/pathCommands.js +6 -0
  155. package/src/grammar/polarPaths.js +5 -5
  156. package/src/grammar/positionCompatibility.js +1 -1
  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/rules.js +2 -0
  161. package/src/grammar/scales/color.js +35 -26
  162. package/src/grammar/scales/continuous.js +71 -24
  163. package/src/grammar/scales/definition.js +1 -1
  164. package/src/grammar/scales/discretized.js +42 -12
  165. package/src/grammar/scales/fields.js +21 -4
  166. package/src/grammar/scales/ordinal.js +139 -60
  167. package/src/grammar/scales/temporal.js +40 -11
  168. package/src/grammar/scales/transformed.js +199 -52
  169. package/src/grammar/schemas/graphicBounds.js +270 -79
  170. package/src/grammar/seriesLayout.js +50 -18
  171. package/src/grammar/ticks.js +123 -53
  172. package/src/grammar/timeUnit.js +18 -8
  173. package/src/grammar/transforms.js +4 -1
  174. package/src/grammar/window.js +70 -57
  175. package/src/index.js +1 -1
  176. package/src/layout/canvas.js +4 -8
  177. package/src/layout/composition.js +39 -40
  178. package/src/layout/facets.js +55 -30
  179. package/src/layout/labels.js +91 -15
  180. package/src/layout/legend.js +22 -20
  181. package/src/layout/legendLane.js +54 -40
  182. package/src/layout/title.js +7 -7
  183. package/src/materialization/bars/aggregate.js +14 -40
  184. package/src/materialization/bars/grouped.js +7 -18
  185. package/src/materialization/bars/histogram.js +2 -19
  186. package/src/materialization/bars/ranged.js +20 -15
  187. package/src/materialization/bars/resolve.js +21 -0
  188. package/src/materialization/facetGuides/legacyCategorical.js +9 -2
  189. package/src/materialization/facetGuides/placement.js +49 -19
  190. package/src/materialization/facetGuides/preparation.js +35 -6
  191. package/src/materialization/facets.js +42 -28
  192. package/src/materialization/guides/resources.js +2 -1
  193. package/src/materialization/marks/capabilities.js +15 -4
  194. package/src/materialization/marks/index.js +29 -6
  195. package/src/materialization/rowEncoding.js +57 -1
  196. package/src/materialization/scales/policies/bar.js +61 -102
  197. package/src/materialization/scales/policies/binnedPosition.js +34 -0
  198. package/src/materialization/scales/policies/offset.js +54 -0
  199. package/src/materialization/scales/policies/series.js +13 -7
  200. package/src/materialization/scales/resolve.js +6 -9
  201. package/src/materialization/selection/items/arc.js +16 -2
  202. package/src/materialization/selection/items/bar.js +4 -2
  203. package/src/materialization/selection/items/common.js +21 -1
  204. package/src/materialization/selection/items/path.js +19 -2
  205. package/src/materialization/selection/items/point.js +4 -16
  206. package/src/materialization/selection/items/tick.js +13 -21
  207. package/src/materialization/selection/point.js +11 -4
  208. package/src/materialization/selection/styles.js +19 -27
  209. package/src/materialization/text.js +4 -1
  210. package/src/mcp/adapter.js +8 -3
  211. package/src/renderers/canvas/fill.js +2 -2
  212. package/src/renderers/canvas/index.js +35 -2
  213. package/src/renderers/canvas/native.js +160 -0
  214. package/src/renderers/pdf.js +14 -0
  215. package/src/renderers/svg.js +37 -4
  216. package/types/index.d.ts +3 -0
  217. package/types/program.d.ts +523 -131
  218. package/types/svg.d.ts +1 -0
  219. package/src/actions/errorBands/components.js +0 -81
  220. package/src/actions/errorBands/options.js +0 -39
  221. package/src/actions/errorBands/resolve.js +0 -28
  222. package/src/actions/errorBars/components.js +0 -62
  223. package/src/actions/errorBars/options.js +0 -58
  224. 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,
@@ -22,7 +22,10 @@ import {
22
22
  import { findDataset } from "../../../selectors/datasets.js";
23
23
  import { findLayer } from "../../../selectors/layers.js";
24
24
  import { rematerializeHighlightBaseline } from "../lifecycle.js";
25
- import { resolveRowEncodingValues } from
25
+ import {
26
+ resolveRowEncodingValues,
27
+ resolveRowPositionValues
28
+ } from
26
29
  "../../../materialization/rowEncoding.js";
27
30
 
28
31
  const REMATERIALIZE_OPTIONS = Object.freeze(["id"]);
@@ -33,8 +36,8 @@ function resolvePointPositions(program, layer, dataset) {
33
36
  layer.encoding?.radius !== undefined;
34
37
  if (!hasPolar) {
35
38
  return {
36
- x: resolveRowEncodingValues(program, layer, dataset, "x"),
37
- y: resolveRowEncodingValues(program, layer, dataset, "y")
39
+ x: resolveRowPositionValues(program, layer, dataset, "x"),
40
+ y: resolveRowPositionValues(program, layer, dataset, "y")
38
41
  };
39
42
  }
40
43
  const theta = resolveRowEncodingValues(program, layer, dataset, "theta");
@@ -78,8 +81,8 @@ function existingArea(child, parentType) {
78
81
  }
79
82
  if (
80
83
  type === "rect" &&
81
- Number.isFinite(child.properties?.width) &&
82
- Number.isFinite(child.properties?.height)
84
+ Number.isFinite(child?.properties?.width) &&
85
+ Number.isFinite(child?.properties?.height)
83
86
  ) {
84
87
  return child.properties.width * child.properties.height;
85
88
  }
@@ -222,8 +225,20 @@ export const rematerializePointMark = action(
222
225
  resetValue: []
223
226
  });
224
227
  if (highlighted !== undefined) return highlighted;
225
- const layer = findLayer(this, id);
226
- const graphic = this.graphicSpec.objects[id];
228
+ let resolved = this;
229
+ const initialLayer = findLayer(resolved, id);
230
+ for (const channel of ["xOffset", "yOffset"]) {
231
+ const scaleId = initialLayer?.encoding?.[channel]?.scale;
232
+ if (scaleId !== undefined) {
233
+ resolved = resolved.rematerializeScale({
234
+ id: scaleId,
235
+ guides: false,
236
+ marks: false
237
+ });
238
+ }
239
+ }
240
+ const layer = findLayer(resolved, id);
241
+ const graphic = resolved.graphicSpec.objects[id];
227
242
 
228
243
  if (layer?.mark?.type !== "point") {
229
244
  throw new Error(`Unknown point mark "${id}".`);
@@ -231,18 +246,23 @@ export const rematerializePointMark = action(
231
246
  if (!["circle", "rect", "path", "collection"].includes(graphic?.type)) {
232
247
  throw new Error(`Point mark "${id}" requires point graphics.`);
233
248
  }
234
- const dataset = findDataset(this, layer.data);
249
+ const dataset = findDataset(resolved, layer.data);
235
250
  if (dataset === undefined) {
236
251
  throw new Error(`Point mark "${id}" requires an existing dataset.`);
237
252
  }
238
253
 
239
- const positions = resolvePointPositions(this, layer, dataset);
240
- const mappedFill = resolveRowEncodingValues(this, layer, dataset, "color");
241
- const area = resolveRowEncodingValues(this, layer, dataset, "size");
242
- const encodedShape = resolveRowEncodingValues(this, layer, dataset, "shape");
243
- const encodedOpacity = resolveRowEncodingValues(this, layer, dataset, "opacity");
254
+ const positions = resolvePointPositions(resolved, layer, dataset);
255
+ const mappedFill = resolveRowEncodingValues(resolved, layer, dataset, "color");
256
+ const area = resolveRowEncodingValues(resolved, layer, dataset, "size");
257
+ const encodedShape = resolveRowEncodingValues(resolved, layer, dataset, "shape");
258
+ const encodedOpacity = resolveRowEncodingValues(
259
+ resolved,
260
+ layer,
261
+ dataset,
262
+ "opacity"
263
+ );
244
264
  const angles = resolveDirectionValues(dataset.values, layer.encoding?.angle);
245
- const config = this.markConfigs[id] ?? {};
265
+ const config = resolved.markConfigs[id] ?? {};
246
266
  const fill = mappedFill ?? config.fill ?? DEFAULT_POINT_FILL;
247
267
  const shapes = encodedShape ?? dataset.values.map(() => config.shape ?? "circle");
248
268
  const existingChildren = graphic.items ?? [];
@@ -252,7 +272,7 @@ export const rematerializePointMark = action(
252
272
  angles !== undefined ||
253
273
  graphic.type === "collection" ||
254
274
  getPointGraphicType(constantShape) !== graphic.type;
255
- const jittered = applyPointJitter(this, {
275
+ const jittered = applyPointJitter(resolved, {
256
276
  id,
257
277
  layer,
258
278
  dataset,
@@ -354,7 +374,9 @@ export const rematerializePointMark = action(
354
374
  ? dataset.values.map((_, index) => {
355
375
  const existing = existingArea(existingChildren[index], graphic.type);
356
376
  return Math.sqrt(
357
- existing ?? Math.PI * (config.radius ?? DEFAULT_POINT_RADIUS) ** 2
377
+ config.radius === undefined
378
+ ? existing ?? Math.PI * DEFAULT_POINT_RADIUS ** 2
379
+ : Math.PI * config.radius ** 2
358
380
  );
359
381
  })
360
382
  : 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
@@ -3,6 +3,7 @@ import { validateUserId } from "../../../core/identifiers.js";
3
3
  import { validatePositiveFinite } from "../../../core/validation.js";
4
4
  import {
5
5
  mapContinuousScaleValues,
6
+ mapOrdinalOffsetValues,
6
7
  mapOrdinalPositionValues,
7
8
  mapOrdinalValues,
8
9
  normalizeStrokeDashPattern
@@ -15,6 +16,7 @@ import { DEFAULT_COLORS } from "../../../theme/defaults.js";
15
16
  import {
16
17
  assertMarkAvailable,
17
18
  applyLayeredMarkInheritance,
19
+ editMarkGraphic,
18
20
  materializeInheritedMark,
19
21
  resolveLayeredMarkInheritance,
20
22
  resolveMarkData,
@@ -24,6 +26,8 @@ import {
24
26
  import { resolveMarkGraphicPlacement } from
25
27
  "../../../materialization/graphicHierarchy.js";
26
28
  import { rematerializeHighlightBaseline } from "../lifecycle.js";
29
+ import { applyOffsetPositionValues } from
30
+ "../../../materialization/rowEncoding.js";
27
31
 
28
32
  const CREATE_OPTIONS = Object.freeze(["id", "data"]);
29
33
  const REMATERIALIZE_OPTIONS = Object.freeze(["id"]);
@@ -153,7 +157,10 @@ const rematerializeRuleMark = action(
153
157
  }
154
158
 
155
159
  const scaleIds = [...new Set(
156
- ["x", "y", "x2", "y2", "strokeDash", "strokeWidth", "opacity"]
160
+ [
161
+ "x", "y", "x2", "y2", "xOffset", "yOffset",
162
+ "strokeDash", "strokeWidth", "opacity"
163
+ ]
157
164
  .map(channel => layer.encoding?.[channel]?.scale)
158
165
  .filter(scale => scale !== undefined)
159
166
  )];
@@ -177,65 +184,84 @@ const rematerializeRuleMark = action(
177
184
  resolved.resolvedScales[encoding.scale]
178
185
  );
179
186
  }
187
+ for (const [channel, offsetChannel] of [
188
+ ["x", "xOffset"],
189
+ ["y", "yOffset"]
190
+ ]) {
191
+ const encoding = layer.encoding?.[offsetChannel];
192
+ if (encoding === undefined || mapped[channel] === undefined) continue;
193
+ const offsetScale = resolved.resolvedScales[encoding.scale];
194
+ const offset = mapOrdinalOffsetValues(
195
+ derived.values[offsetChannel],
196
+ offsetScale
197
+ );
198
+ mapped[channel] = applyOffsetPositionValues({
199
+ base: mapped[channel],
200
+ offset,
201
+ parentScale: resolved.resolvedScales[layer.encoding[channel].scale],
202
+ offsetScale,
203
+ channel
204
+ });
205
+ }
180
206
  const bounds = resolveGraphicBounds(resolved);
181
207
  const x1 = [];
182
208
  const y1 = [];
183
209
  const x2 = [];
184
210
  const y2 = [];
185
211
  for (let index = 0; index < derived.length; index += 1) {
212
+ let startX;
213
+ let startY;
214
+ let endX;
215
+ let endY;
186
216
  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);
217
+ startX = endX = mapped.x[index];
218
+ startY = bounds.y;
219
+ endY = bounds.y + bounds.height;
191
220
  } 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]);
221
+ startX = bounds.x;
222
+ endX = bounds.x + bounds.width;
223
+ startY = endY = mapped.y[index];
196
224
  } 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]);
225
+ startX = endX = mapped.x[index];
226
+ startY = mapped.y[index];
227
+ endY = mapped.y2[index];
201
228
  } 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]);
229
+ startX = mapped.x[index];
230
+ endX = mapped.x2[index];
231
+ startY = endY = mapped.y[index];
206
232
  } else if (mode === "box-span") {
207
233
  const owner = resolved.graphicSpec.objects[boxSpan];
208
234
  const box = owner?.items?.[index]?.properties;
209
235
  if (box === undefined) throw new Error(`Rule mark "${id}" requires box span owner "${boxSpan}".`);
210
236
  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);
237
+ startX = endX = mapped.x[index];
238
+ startY = box.y;
239
+ endY = box.y + box.height;
215
240
  } 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]);
241
+ startX = box.x;
242
+ endX = box.x + box.width;
243
+ startY = endY = mapped.y[index];
220
244
  }
221
245
  } else if (mode === "fixed-span") {
222
246
  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]);
247
+ startX = mapped.x[index] - fixedSpan.size / 2;
248
+ endX = mapped.x[index] + fixedSpan.size / 2;
249
+ startY = endY = mapped.y[index];
227
250
  } 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);
251
+ startX = endX = mapped.x[index];
252
+ startY = mapped.y[index] - fixedSpan.size / 2;
253
+ endY = mapped.y[index] + fixedSpan.size / 2;
232
254
  }
233
255
  } 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]);
256
+ startX = mapped.x[index];
257
+ startY = mapped.y[index];
258
+ endX = mapped.x2[index];
259
+ endY = mapped.y2[index];
238
260
  }
261
+ x1.push(startX);
262
+ y1.push(startY);
263
+ x2.push(endX);
264
+ y2.push(endY);
239
265
  }
240
266
 
241
267
  const resolvedConfig = {
@@ -270,20 +296,17 @@ const rematerializeRuleMark = action(
270
296
  resolved.resolvedScales[strokeWidthEncoding.scale]
271
297
  );
272
298
 
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 });
299
+ return editMarkGraphic(resolved, id, {
300
+ length: derived.length,
301
+ x1,
302
+ y1,
303
+ x2,
304
+ y2,
305
+ stroke: resolvedConfig.stroke,
306
+ strokeWidth,
307
+ strokeDash,
308
+ opacity
309
+ });
287
310
  }
288
311
  );
289
312
 
@@ -312,7 +335,9 @@ export const materializeRuleSpan = action(
312
335
  );
313
336
 
314
337
  export function registerRuleMarkActions(ProgramClass) {
315
- ProgramClass.prototype.createRuleMark = createRuleMark;
316
- ProgramClass.prototype.rematerializeRuleMark = rematerializeRuleMark;
317
- ProgramClass.prototype.materializeRuleSpan = materializeRuleSpan;
338
+ Object.assign(ProgramClass.prototype, {
339
+ createRuleMark,
340
+ rematerializeRuleMark,
341
+ materializeRuleSpan
342
+ });
318
343
  }
@@ -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
  }