ggaction 0.0.21 → 0.0.23

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 (265) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +83 -90
  3. package/knowledge/action-card.schema.json +1 -1
  4. package/knowledge/action-cards.json +1 -1
  5. package/knowledge/intent-taxonomy.json +1 -1
  6. package/knowledge/mcp-resources.json +1 -1
  7. package/package.json +11 -4
  8. package/src/BasicChartProgram.js +1 -1
  9. package/src/accessibility.js +1 -0
  10. package/src/actions/boxPlots/components.js +1 -96
  11. package/src/actions/boxPlots/create.js +6 -1
  12. package/src/actions/boxPlots/edit.js +8 -0
  13. package/src/actions/boxPlots/materialize.js +3 -0
  14. package/src/actions/boxPlots/options.js +1 -1
  15. package/src/actions/canvas/actions.js +2 -1
  16. package/src/actions/canvas/index.js +3 -0
  17. package/src/actions/canvas/plotBorder.js +2 -1
  18. package/src/actions/canvas/plotOrder.js +14 -0
  19. package/src/actions/charts/area.js +1 -1
  20. package/src/actions/charts/bar.js +4 -4
  21. package/src/actions/charts/density.js +1 -1
  22. package/src/actions/charts/ecdf.js +1 -1
  23. package/src/actions/charts/endpoints.js +54 -5
  24. package/src/actions/charts/heatmap.js +1 -1
  25. package/src/actions/charts/histogram.js +1 -1
  26. package/src/actions/charts/horizon.js +1 -1
  27. package/src/actions/charts/index.js +2 -1
  28. package/src/actions/charts/interval-regression.js +3 -3
  29. package/src/actions/charts/line.js +1 -1
  30. package/src/actions/charts/radar.js +63 -3
  31. package/src/actions/charts/raincloud.js +37 -6
  32. package/src/actions/charts/rug-strip.js +2 -2
  33. package/src/actions/charts/scatter.js +3 -3
  34. package/src/actions/charts/text.js +1 -1
  35. package/src/actions/composition/actions.js +10 -3
  36. package/src/actions/coordinates/actions.js +2 -0
  37. package/src/actions/data/basic.js +6 -0
  38. package/src/actions/data/derived.js +6 -2
  39. package/src/actions/data/edit.js +22 -36
  40. package/src/actions/data/filter.js +1 -376
  41. package/src/actions/data/flatten.js +19 -0
  42. package/src/actions/data/index.js +6 -0
  43. package/src/actions/data/lookup.js +50 -0
  44. package/src/actions/data/raincloudFilter.js +56 -0
  45. package/src/actions/data/shared.js +10 -0
  46. package/src/actions/data/timeUnit.js +1 -1
  47. package/src/actions/distributions/revision.js +3 -1
  48. package/src/actions/encodings/angle.js +2 -1
  49. package/src/actions/encodings/appearance.js +38 -13
  50. package/src/actions/encodings/channels.js +14 -3
  51. package/src/actions/encodings/color/continuous.js +26 -10
  52. package/src/actions/encodings/color/index.js +50 -20
  53. package/src/actions/encodings/color/policy.js +57 -4
  54. package/src/actions/encodings/parallel.js +4 -0
  55. package/src/actions/encodings/position/policies/bar.js +10 -6
  56. package/src/actions/encodings/position/policies/line.js +1 -152
  57. package/src/actions/encodings/position/resolve.js +4 -1
  58. package/src/actions/encodings/ranged.js +46 -0
  59. package/src/actions/encodings/remove.js +1 -1
  60. package/src/actions/encodings/ruleAppearance.js +7 -6
  61. package/src/actions/encodings/shared.js +14 -2
  62. package/src/actions/encodings/stroke.js +20 -14
  63. package/src/actions/encodings/strokeDash.js +9 -11
  64. package/src/actions/encodings/text.js +30 -2
  65. package/src/actions/errorBars/edit.js +24 -4
  66. package/src/actions/facets/actions.js +1 -793
  67. package/src/actions/facets/derive.js +34 -5
  68. package/src/actions/facets/replay.js +1 -38
  69. package/src/actions/gradientPlots/components.js +21 -9
  70. package/src/actions/gradientPlots/create.js +4 -2
  71. package/src/actions/gradientPlots/edit.js +18 -1
  72. package/src/actions/gradientPlots/materialize.js +35 -36
  73. package/src/actions/gradientPlots/options.js +1 -1
  74. package/src/actions/gradientPlots/paint.js +13 -7
  75. package/src/actions/guides/applicability.js +2 -0
  76. package/src/actions/guides/axes/axes.js +39 -0
  77. package/src/actions/guides/axes/axis.js +9 -5
  78. package/src/actions/guides/axes/edit.js +11 -8
  79. package/src/actions/guides/axes/labels.js +24 -8
  80. package/src/actions/guides/axes/parallel/policy.js +3 -5
  81. package/src/actions/guides/axes/parallel/resolve.js +4 -3
  82. package/src/actions/guides/axes/policy.js +22 -0
  83. package/src/actions/guides/axes/tickGroups.js +4 -2
  84. package/src/actions/guides/axes/ticks.js +22 -4
  85. package/src/actions/guides/axes/titles.js +19 -6
  86. package/src/actions/guides/facadeAxes.js +3 -0
  87. package/src/actions/guides/grids/grid.js +3 -1
  88. package/src/actions/guides/grids/resolve.js +7 -11
  89. package/src/actions/guides/guides.js +21 -1
  90. package/src/actions/guides/legends/categorical/actions.js +1 -515
  91. package/src/actions/guides/legends/categorical/components.js +1 -4
  92. package/src/actions/guides/legends/categorical/layout.js +5 -2
  93. package/src/actions/guides/legends/categorical/options.js +4 -0
  94. package/src/actions/guides/legends/categorical/resolve.js +8 -3
  95. package/src/actions/guides/legends/categorical/symbols.js +3 -3
  96. package/src/actions/guides/legends/colorSize.js +2 -0
  97. package/src/actions/guides/legends/continuous/common.js +1 -1
  98. package/src/actions/guides/legends/continuous/gradient.js +1 -360
  99. package/src/actions/guides/legends/continuous/interval.js +1 -1
  100. package/src/actions/guides/legends/continuous/opacity.js +15 -1
  101. package/src/actions/guides/legends/edit.js +1 -1
  102. package/src/actions/guides/legends/focused.js +1 -1
  103. package/src/actions/guides/legends/lane.js +1 -1
  104. package/src/actions/guides/legends/sampling.js +1 -140
  105. package/src/actions/guides/legends/strokeWidth.js +3 -2
  106. package/src/actions/guides/legends/transition.js +19 -2
  107. package/src/actions/guides/polar/axes/facade.js +5 -4
  108. package/src/actions/guides/polar/axes/labels.js +5 -4
  109. package/src/actions/guides/polar/axes/titles.js +5 -4
  110. package/src/actions/guides/polar/resolve.js +2 -1
  111. package/src/actions/guides/tickValues.js +7 -7
  112. package/src/actions/marks/arc/actions.js +5 -7
  113. package/src/actions/marks/area/actions.js +9 -3
  114. package/src/actions/marks/bar/create.js +4 -2
  115. package/src/actions/marks/bar/edit.js +9 -6
  116. package/src/actions/marks/bar/materialize.js +5 -3
  117. package/src/actions/marks/dependentReferences.js +87 -0
  118. package/src/actions/marks/index.js +2 -0
  119. package/src/actions/marks/lifecycle.js +2 -1
  120. package/src/actions/marks/line/actions.js +24 -6
  121. package/src/actions/marks/line/materialize.js +7 -3
  122. package/src/actions/marks/point/create.js +5 -4
  123. package/src/actions/marks/point/edit.js +6 -3
  124. package/src/actions/marks/point/jitter.js +6 -6
  125. package/src/actions/marks/point/materialize.js +36 -39
  126. package/src/actions/marks/rect/actions.js +16 -4
  127. package/src/actions/marks/references.js +183 -35
  128. package/src/actions/marks/rule/actions.js +20 -9
  129. package/src/actions/marks/shared.js +2 -1
  130. package/src/actions/marks/text/actions.js +10 -3
  131. package/src/actions/marks/tick/actions.js +11 -2
  132. package/src/actions/primitives/editGraphics.js +28 -3
  133. package/src/actions/primitives/index.js +9 -0
  134. package/src/actions/primitives/semanticAction.js +13 -7
  135. package/src/actions/primitives/semanticValidation/layer.js +20 -0
  136. package/src/actions/primitives/semanticValidation/scale.js +8 -1
  137. package/src/actions/regression/create.js +6 -1
  138. package/src/actions/regression/edit.js +10 -1
  139. package/src/actions/scales/channels.js +1 -1
  140. package/src/actions/scales/consumers/common.js +19 -1
  141. package/src/actions/scales/consumers/families.js +2 -2
  142. package/src/actions/scales/consumers/seriesLayout.js +4 -3
  143. package/src/actions/scales/edit.js +11 -0
  144. package/src/actions/scales/editPolicy.js +5 -3
  145. package/src/actions/scales/preview.js +2 -1
  146. package/src/actions/scales/quantitativeColor.js +2 -4
  147. package/src/actions/selection/actions.js +10 -1
  148. package/src/actions/theme/reconcile.js +37 -9
  149. package/src/core/compositionState.js +26 -7
  150. package/src/core/datasetReferences.js +17 -0
  151. package/src/core/facetAxisPolicy.js +30 -0
  152. package/src/core/immutable.js +1 -0
  153. package/src/core/resourceReferences.js +5 -3
  154. package/src/core/validation.js +4 -0
  155. package/src/core/vocabulary.js +24 -2
  156. package/src/grammar/aggregate.js +1 -0
  157. package/src/grammar/arcs.js +1 -1
  158. package/src/grammar/areaSeries.js +1 -1
  159. package/src/grammar/axisTextPlacement.js +1 -1
  160. package/src/grammar/bars/policy.js +2 -2
  161. package/src/grammar/curveCommands.js +35 -2
  162. package/src/grammar/datasetDependencies.js +97 -0
  163. package/src/grammar/datasetSchema.js +32 -2
  164. package/src/grammar/facetHeaders.js +1 -0
  165. package/src/grammar/facets/dependencies.js +6 -2
  166. package/src/grammar/facets/guides.js +7 -5
  167. package/src/grammar/facets/legendIntent.js +6 -2
  168. package/src/grammar/facets/scales.js +27 -7
  169. package/src/grammar/flatten.js +85 -0
  170. package/src/grammar/histogram.js +13 -1
  171. package/src/grammar/horizon.js +1 -494
  172. package/src/grammar/jitter.js +2 -2
  173. package/src/grammar/legendSpacing.js +45 -0
  174. package/src/grammar/lineMissing.js +90 -0
  175. package/src/grammar/lineSeries.js +1 -376
  176. package/src/grammar/lookup.js +97 -0
  177. package/src/grammar/markFilter.js +4 -2
  178. package/src/grammar/markLabels.js +8 -3
  179. package/src/grammar/numeric.js +1 -1
  180. package/src/grammar/pathCommands.js +1 -1
  181. package/src/grammar/pathSeries.js +1 -109
  182. package/src/grammar/pointPolygon.js +81 -0
  183. package/src/grammar/pointShapes.js +15 -15
  184. package/src/grammar/rects.js +1 -1
  185. package/src/grammar/regression/derive.js +1 -195
  186. package/src/grammar/regression/parameters.js +7 -0
  187. package/src/grammar/scales/appearance.js +1 -1
  188. package/src/grammar/scales/color.js +1 -1
  189. package/src/grammar/scales/colorConsumers.js +1 -63
  190. package/src/grammar/scales/continuous.js +58 -1
  191. package/src/grammar/scales/definition.js +1 -1
  192. package/src/grammar/scales/ordinal.js +5 -2
  193. package/src/grammar/scales/policies.js +3 -3
  194. package/src/grammar/schemas/graphicBounds.js +40 -12
  195. package/src/grammar/schemas/graphicClip.js +23 -0
  196. package/src/grammar/schemas/graphicTree.js +16 -0
  197. package/src/grammar/statisticalReference.js +22 -0
  198. package/src/grammar/text.js +65 -1
  199. package/src/grammar/ticks.js +92 -1
  200. package/src/grammar/timeUnit.js +9 -3
  201. package/src/grammar/transformTopology.js +3 -1
  202. package/src/grammar/transforms.js +24 -0
  203. package/src/inspection.js +1 -495
  204. package/src/inspectionDescriptors.js +1 -1
  205. package/src/layout/canvas.js +1 -1
  206. package/src/layout/facetContentFlow.js +101 -0
  207. package/src/layout/facetHeaderTitles.js +1 -0
  208. package/src/layout/facetTopLane.js +29 -0
  209. package/src/layout/facets.js +1 -1
  210. package/src/layout/guideCollisions.js +9 -3
  211. package/src/layout/legendGroup.js +1 -1
  212. package/src/layout/legendItems.js +26 -10
  213. package/src/layout/legendSpacing.js +66 -0
  214. package/src/layout/plotDrawOrder.js +17 -0
  215. package/src/materialization/bars/histogram.js +8 -2
  216. package/src/materialization/bars/resolve.js +1 -1
  217. package/src/materialization/composition.js +1 -0
  218. package/src/materialization/compositionSnapshot.js +22 -2
  219. package/src/materialization/dataProvenance.js +1 -1
  220. package/src/materialization/facetContentBounds.js +96 -0
  221. package/src/materialization/facetGuides/layout.js +1 -1
  222. package/src/materialization/facetGuides/placement.js +39 -11
  223. package/src/materialization/facetGuides/preparation.js +43 -24
  224. package/src/materialization/facetHeaders.js +1 -1
  225. package/src/materialization/facetTopLane.js +25 -0
  226. package/src/materialization/facets.js +1 -1
  227. package/src/materialization/graphicHierarchy.js +30 -1
  228. package/src/materialization/graphicTranslation.js +2 -0
  229. package/src/materialization/guides/layout.js +1 -1
  230. package/src/materialization/guides/resources.js +1 -1
  231. package/src/materialization/legends.js +1 -1
  232. package/src/materialization/markClip.js +26 -0
  233. package/src/materialization/marks/capabilities.js +3 -2
  234. package/src/materialization/marks/grouping.js +7 -5
  235. package/src/materialization/marks/index.js +4 -2
  236. package/src/materialization/marks/policies.js +4 -0
  237. package/src/materialization/plotDrawOrder.js +44 -0
  238. package/src/materialization/rect.js +11 -3
  239. package/src/materialization/scaleGuideDependencies.js +13 -5
  240. package/src/materialization/selection/items/common.js +1 -1
  241. package/src/materialization/selection/items/path.js +1 -0
  242. package/src/materialization/selection/policies/index.js +2 -1
  243. package/src/materialization/text.js +10 -5
  244. package/src/mcp/cli.js +0 -0
  245. package/src/persistence/validation.js +114 -18
  246. package/src/persistence.js +4 -2
  247. package/src/renderers/canvas/index.js +16 -0
  248. package/src/renderers/canvas/isolated.js +11 -1
  249. package/src/renderers/canvas/native.js +7 -0
  250. package/src/renderers/canvas/scene.js +66 -0
  251. package/src/renderers/canvas/text.js +3 -2
  252. package/src/renderers/svg.js +1 -617
  253. package/src/renderers/svgSerialization.js +643 -0
  254. package/src/renderers/transitionScene.js +67 -0
  255. package/src/scene.js +89 -0
  256. package/src/selectors/axes.js +1 -1
  257. package/src/selectors/datasets.js +1 -0
  258. package/src/selectors/grids.js +9 -0
  259. package/src/selectors/markClip.js +28 -0
  260. package/src/selectors/raincloud.js +7 -0
  261. package/src/version.js +1 -1
  262. package/types/basic.d.ts +7 -0
  263. package/types/index.d.ts +8 -0
  264. package/types/program.d.ts +286 -70
  265. package/types/scene.d.ts +35 -0
@@ -5,9 +5,10 @@ import {
5
5
  readQuantitativeField,
6
6
  transformedTicks
7
7
  } from "../../grammar/scales/index.js";
8
- import { niceTicks, timeTicks } from "../../grammar/ticks.js";
8
+ import { niceTicks, timeTicks, validateTickSelectionRounding, axisTickSelection } from "../../grammar/ticks.js";
9
9
  import { findDataset } from "../../selectors/datasets.js";
10
10
  import { findSemanticScale } from "../../selectors/scales.js";
11
+ import { applyItemMissingPolicy } from "../../grammar/itemMissing.js";
11
12
 
12
13
  export const DEFAULT_TICK_COUNT = 5;
13
14
 
@@ -28,7 +29,7 @@ export function inferHistogramBoundaries(program, channel, scaleId) {
28
29
  throw new Error(`Guide values require histogram data and scale "${scaleId}".`);
29
30
  }
30
31
  return resolveHistogramBins({
31
- values: readQuantitativeField(dataset.values, encoding.field),
32
+ values: readQuantitativeField(applyItemMissingPolicy(layer, dataset).values, encoding.field),
32
33
  bin: encoding.bin,
33
34
  domain: scale.domain,
34
35
  nice: scale.nice ?? true,
@@ -44,11 +45,11 @@ export function inferHistogramBoundaries(program, channel, scaleId) {
44
45
  }
45
46
 
46
47
  export function valuesFromTickConfig(program, config) {
47
- if (config.mode === "values") return config.values;
48
-
49
48
  const scale = program.resolvedScales[config.scale];
49
+ validateTickSelectionRounding(config, scale?.type);
50
+ if (config.mode === "values") return config.values;
50
51
  if (scale?.type === "time") return timeTicks(scale.domain, config.count);
51
- if (scale?.type === "linear") return niceTicks(scale.domain, config.count);
52
+ if (scale?.type === "linear") return niceTicks(scale.domain, config.count, config.rounding);
52
53
  if (isTransformedScaleType(scale?.type)) {
53
54
  return transformedTicks(scale.type, scale.domain, config.count, {
54
55
  ...(scale.base === undefined ? {} : { base: scale.base }),
@@ -64,8 +65,7 @@ export function valuesFromTickConfig(program, config) {
64
65
  export function inferGridTickConfig(program, channel, scaleId) {
65
66
  const axes = cartesianAxisOwners(program).filter(owner => owner.channel === channel &&
66
67
  owner.config?.ticks?.scale === scaleId).map(owner => owner.config.ticks);
67
- const policies = axes.map(axis => axis.mode === "values"
68
- ? { mode: "values", values: axis.values } : { mode: "count", count: axis.count });
68
+ const policies = axes.map(axisTickSelection);
69
69
  if (new Set(policies.map(policy => JSON.stringify(policy))).size > 1) {
70
70
  throw new Error("Grid values require explicit count or values when bound axis tick policies differ.");
71
71
  }
@@ -8,10 +8,7 @@ import {
8
8
  } from "../../../core/validation.js";
9
9
  import { deriveArcSectors } from "../../../grammar/arcs.js";
10
10
  import { buildAnnularSectorCommands } from "../../../grammar/polarPaths.js";
11
- import {
12
- mapOrdinalValues,
13
- readScaleField
14
- } from "../../../grammar/scales/index.js";
11
+ import { readScaleField } from "../../../grammar/scales/index.js";
15
12
  import { resolveCoordinatePolarFrame } from
16
13
  "../../../materialization/coordinateBounds.js";
17
14
  import {
@@ -165,6 +162,7 @@ const rematerializeArcMark = /* @__PURE__ */ action(
165
162
  const highlighted = rematerializeHighlightBaseline(this, {
166
163
  target: id,
167
164
  operation: "rematerializeArcMark",
165
+ scales: args.scales,
168
166
  resetProperty: "length",
169
167
  resetValue: 0
170
168
  });
@@ -209,10 +207,10 @@ const rematerializeArcMark = /* @__PURE__ */ action(
209
207
  }));
210
208
  const fills = colorScaleId === undefined
211
209
  ? commands.map(() => config.fill ?? DEFAULT_COLORS.mark)
212
- : mapOrdinalValues(
210
+ : mapScaleConsumerValues(
213
211
  derived.sectors.map(sector => sector.color),
214
- resolved.resolvedScales[colorScaleId].domain,
215
- resolved.resolvedScales[colorScaleId].range
212
+ resolved.resolvedScales[colorScaleId],
213
+ "color"
216
214
  );
217
215
  const strokeEncoding = layer.encoding?.stroke;
218
216
  const strokeValues = strokeEncoding === undefined ? undefined : derived.sectors.map(
@@ -1,3 +1,4 @@
1
+ import { requestedMarkClip, validateMarkClipCoordinate } from "../../../selectors/markClip.js";
1
2
  import { validateFillPaint } from "../../../grammar/paint.js";
2
3
  import { validateAreaPaintConfig } from "../../../grammar/areaPaint.js";
3
4
  import { validateAreaMissing } from "../../../grammar/areaEndpoints.js";
@@ -36,7 +37,7 @@ import {
36
37
  } from "../../../grammar/strokeStyle.js";
37
38
 
38
39
  const AREA_OPTIONS = Object.freeze([
39
- "fill", "opacity", "stroke", "strokeWidth", "curve",
40
+ "clip", "fill", "opacity", "stroke", "strokeWidth", "curve",
40
41
  ...STROKE_STYLE_PROPERTIES
41
42
  ]);
42
43
  const CREATE_OPTIONS = Object.freeze(["id", "data", "missing", ...AREA_OPTIONS]);
@@ -66,6 +67,7 @@ const createAreaMark = /* @__PURE__ */ action(
66
67
  },
67
68
  function (args = {}) {
68
69
  validateMarkOptions(args, CREATE_OPTIONS, "createAreaMark");
70
+ requestedMarkClip(args);
69
71
  const strokeDetails = requestedStrokeDetails(args, "createAreaMark");
70
72
  const id = resolveMarkId(this, args.id, {
71
73
  defaultId: "area",
@@ -101,6 +103,7 @@ const createAreaMark = /* @__PURE__ */ action(
101
103
  ...resolveMarkGraphicPlacement(created, { data, markType: "area" })
102
104
  })
103
105
  ._withMarkConfig(id, {
106
+ ...requestedMarkClip(args),
104
107
  fill,
105
108
  opacity,
106
109
  ...(Object.hasOwn(args, "curve") ? { curve } : {}),
@@ -154,6 +157,7 @@ const rematerializeAreaMark = /* @__PURE__ */ action(
154
157
  const highlighted = rematerializeHighlightBaseline(this, {
155
158
  target: id,
156
159
  operation: "rematerializeAreaMark",
160
+ scales: args.scales,
157
161
  resetProperty: "length",
158
162
  resetValue: 0
159
163
  });
@@ -240,9 +244,10 @@ const editAreaMark = /* @__PURE__ */ action(
240
244
  },
241
245
  function (args = {}) {
242
246
  validateMarkOptions(args, EDIT_OPTIONS, "editAreaMark");
247
+ requestedMarkClip(args);
243
248
  const strokeDetails = requestedStrokeDetails(args, "editAreaMark");
244
249
  const changes = [
245
- "fill", "opacity", "stroke", "strokeWidth", "curve", "missing",
250
+ "clip", "fill", "opacity", "stroke", "strokeWidth", "curve", "missing",
246
251
  ...STROKE_STYLE_PROPERTIES
247
252
  ];
248
253
  if (!changes.some(key => Object.hasOwn(args, key))) {
@@ -272,7 +277,8 @@ const editAreaMark = /* @__PURE__ */ action(
272
277
  throw new Error("editAreaMark cannot set strokeWidth while removing stroke.");
273
278
  }
274
279
 
275
- let config = { ...this.markConfigs[layer.id] };
280
+ validateMarkClipCoordinate(this, layer, args.clip ?? this.markConfigs[layer.id]?.clip);
281
+ let config = { ...this.markConfigs[layer.id], ...requestedMarkClip(args) };
276
282
  Object.assign(config, strokeDetails);
277
283
  if (Object.hasOwn(args, "fill")) {
278
284
  config.fill = validateFillPaint(args.fill, "Area fill");
@@ -1,3 +1,4 @@
1
+ import { requestedMarkClip } from "../../../selectors/markClip.js";
1
2
  import { action } from "../../../core/action.js";
2
3
  import {
3
4
  assertMarkAvailable,
@@ -17,7 +18,7 @@ import { STROKE_STYLE_PROPERTIES } from
17
18
  import { validateItemMissing } from "../../../grammar/itemMissing.js";
18
19
 
19
20
  const CREATE_OPTIONS = Object.freeze([
20
- "id", "data", "orientation", "missing", "fill", "opacity", "stroke", "strokeWidth",
21
+ "clip", "id", "data", "orientation", "missing", "fill", "opacity", "stroke", "strokeWidth",
21
22
  ...RECT_RADIUS_PROPERTIES, ...STROKE_STYLE_PROPERTIES
22
23
  ]);
23
24
 
@@ -28,6 +29,7 @@ export const createBarMark = /* @__PURE__ */ action(
28
29
  },
29
30
  function (args = {}) {
30
31
  validateMarkOptions(args, CREATE_OPTIONS, "createBarMark");
32
+ requestedMarkClip(args);
31
33
  requestedRectStyleDetails(args, "createBarMark");
32
34
  if (args.orientation !== undefined && !["vertical", "horizontal"].includes(args.orientation)) {
33
35
  throw new Error("Bar orientation must be vertical or horizontal.");
@@ -76,7 +78,7 @@ export const createBarMark = /* @__PURE__ */ action(
76
78
  created = materializeInheritedMark(created, id);
77
79
  const appearance = Object.fromEntries(
78
80
  [
79
- "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
81
+ "clip", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
80
82
  ...STROKE_STYLE_PROPERTIES
81
83
  ]
82
84
  .filter(property => Object.hasOwn(args, property))
@@ -1,3 +1,4 @@
1
+ import { requestedMarkClip, validateMarkClipCoordinate } from "../../../selectors/markClip.js";
1
2
  import { action } from "../../../core/action.js";
2
3
  import { validateUserId } from "../../../core/identifiers.js";
3
4
  import {
@@ -18,7 +19,7 @@ import { validateFillPaint } from "../../../grammar/paint.js";
18
19
  import { validateItemMissing } from "../../../grammar/itemMissing.js";
19
20
 
20
21
  const EDIT_OPTIONS = Object.freeze([
21
- "target", "missing", "blend", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
22
+ "target", "clip", "missing", "blend", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
22
23
  ...STROKE_STYLE_PROPERTIES
23
24
  ]);
24
25
 
@@ -29,9 +30,10 @@ export const editBarMark = /* @__PURE__ */ action(
29
30
  },
30
31
  function (args = {}) {
31
32
  validateMarkOptions(args, EDIT_OPTIONS, "editBarMark");
33
+ requestedMarkClip(args);
32
34
  const styleDetails = requestedRectStyleDetails(args, "editBarMark");
33
35
  const changes = [
34
- "missing", "blend", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
36
+ "clip", "missing", "blend", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
35
37
  ...STROKE_STYLE_PROPERTIES
36
38
  ];
37
39
  if (!changes.some(key => Object.hasOwn(args, key))) {
@@ -71,7 +73,8 @@ export const editBarMark = /* @__PURE__ */ action(
71
73
  }
72
74
  const missing = Object.hasOwn(args, "missing")
73
75
  ? validateItemMissing(args.missing, "Bar missing") : undefined;
74
- const config = { ...this.markConfigs[layer.id] };
76
+ validateMarkClipCoordinate(this, layer, args.clip ?? this.markConfigs[layer.id]?.clip);
77
+ const config = { ...this.markConfigs[layer.id], ...requestedMarkClip(args) };
75
78
  const appearance = { ...config.barAppearance };
76
79
  Object.assign(appearance, styleDetails);
77
80
  if (Object.hasOwn(args, "fill")) {
@@ -115,11 +118,11 @@ export const editBarMark = /* @__PURE__ */ action(
115
118
  semantic = semantic.editSemantic({property: `layer[${layer.id}].mark.blend`, remove: true});
116
119
  }
117
120
  }
118
- const editsAppearance = changes.some(key => key !== "missing" && key !== "blend" &&
121
+ const editsAppearance = changes.some(key => key !== "missing" && key !== "blend" && key !== "clip" &&
119
122
  Object.hasOwn(args, key));
120
- const next = editsAppearance ? semantic._withMarkConfig(layer.id, {
123
+ const next = editsAppearance || Object.hasOwn(args, "clip") ? semantic._withMarkConfig(layer.id, {
121
124
  ...config,
122
- barAppearance: appearance
125
+ ...(editsAppearance ? {barAppearance: appearance} : {})
123
126
  }) : semantic;
124
127
  const materialized = canMaterializeBar(next, layer)
125
128
  ? next.rematerializeBarMark({ id: layer.id })
@@ -1,3 +1,4 @@
1
+ import { materializeMarkClip } from "../../../materialization/markClip.js";
1
2
  import { findLayer } from "../../../selectors/layers.js";
2
3
  import { editGraphicProperties } from "../../primitives/graphicProperties.js";
3
4
  import { action } from "../../../core/action.js";
@@ -29,12 +30,12 @@ function editRectangles(program, id, rectangles) {
29
30
  item.properties?.blend !== undefined);
30
31
  if (hasShapeStyle || blend !== undefined || previousBlend) {
31
32
  const radius = appearance;
32
- return replaceGraphicItems(
33
+ return materializeMarkClip(replaceGraphicItems(
33
34
  program,
34
35
  id,
35
36
  "rect",
36
37
  rectangles.map(rectangle => materializeRectItem(rectangle, radius))
37
- );
38
+ ), id);
38
39
  }
39
40
  let next = editGraphicProperties(program, id, {
40
41
  length: rectangles.length,
@@ -53,7 +54,7 @@ function editRectangles(program, id, rectangles) {
53
54
  value: rectangles.map(rect => rect.opacity ?? 1)
54
55
  });
55
56
  }
56
- return next;
57
+ return materializeMarkClip(next, id);
57
58
  }
58
59
 
59
60
  export const rematerializeBarMark = /* @__PURE__ */ action(
@@ -74,6 +75,7 @@ export const rematerializeBarMark = /* @__PURE__ */ action(
74
75
  const highlighted = rematerializeHighlightBaseline(this, {
75
76
  target: id,
76
77
  operation: "rematerializeBarMark",
78
+ scales: args.scales,
77
79
  resetProperty: "items",
78
80
  resetValue: []
79
81
  });
@@ -0,0 +1,87 @@
1
+ import { findLayer } from "../../selectors/layers.js";
2
+ import { ownedChildren } from "../../selectors/markOwners.js";
3
+ import { findGraphicParent } from "../../grammar/schemas/graphicTree.js";
4
+ import { applyLayerDataRematerialization } from "../../materialization/dependencies.js";
5
+
6
+ export function retainStatisticalDependents(program, ownerId) {
7
+ const references = new Map();
8
+ const visited = new Set();
9
+ const visit = id => {
10
+ if (visited.has(id)) return;
11
+ visited.add(id);
12
+ const config = program.markConfigs[id]?.statisticalReference;
13
+ if (config !== undefined) references.set(id, {
14
+ config, encoding: findLayer(program, id).encoding
15
+ });
16
+ for (const child of ownedChildren(program, id)) visit(child);
17
+ };
18
+ visit(ownerId);
19
+ let next = program;
20
+ // Keep independently authored references and their labels through the
21
+ // component replacement; removeMark otherwise treats them as source-owned.
22
+ for (const id of references.keys()) {
23
+ const { statisticalReference, ...config } = next.markConfigs[id];
24
+ next = next._withMarkConfig(id, config);
25
+ // Detached statistics must not temporarily look like ordinary data marks:
26
+ // their derived value field would pollute axis-title/domain inference while
27
+ // replacement components fulfill their guides.
28
+ const encoding = findLayer(next, id).encoding;
29
+ for (const channel of ["x", "y", "x2", "y2"]) {
30
+ if (encoding[channel] !== undefined) {
31
+ next = next.editSemantic({ property: `layer[${id}].encoding.${channel}`, remove: true });
32
+ }
33
+ }
34
+ }
35
+ return { program: next, references };
36
+ }
37
+
38
+ export function restoreStatisticalDependents(program, references, { fallbackSource, fromAxis, toAxis }) {
39
+ if (references.size === 0) return program;
40
+ let next = program;
41
+ const sources = new Set();
42
+ for (const [id, { config, encoding }] of references) {
43
+ const source = findLayer(next, config.source) === undefined ? fallbackSource : config.source;
44
+ const axis = config.axis === fromAxis ? toAxis : config.axis;
45
+ const channels = fromAxis === toAxis ? [["x", "x"], ["y", "y"], ["x2", "x2"], ["y2", "y2"]]
46
+ : [["x", "y"], ["y", "x"], ["x2", "y2"], ["y2", "x2"]];
47
+ for (const [from, to] of channels) {
48
+ for (const [key, value] of Object.entries(encoding[from] ?? {})) {
49
+ next = next.editSemantic({ property: `layer[${id}].encoding.${to}.${key}`, value });
50
+ }
51
+ }
52
+ next = next._withMarkConfig(id, {
53
+ ...next.markConfigs[id],
54
+ statisticalReference: { ...config, source, axis }
55
+ });
56
+ sources.add(source);
57
+ }
58
+ // Recreate these graphics after the new components, retaining overlays'
59
+ // authored styles while placing them above their source as before.
60
+ const graphics = new Map();
61
+ const removeGraphics = id => {
62
+ if (graphics.has(id)) return;
63
+ graphics.set(id, {
64
+ graphic: next.graphicSpec.objects[id],
65
+ parent: findGraphicParent(next.graphicSpec, id)?.id
66
+ });
67
+ for (const child of ownedChildren(next, id)) removeGraphics(child);
68
+ if (next.graphicSpec.objects[id] !== undefined) {
69
+ next = next.editGraphics({ target: id, remove: true });
70
+ }
71
+ };
72
+ for (const id of references.keys()) removeGraphics(id);
73
+ for (const [id, { graphic, parent }] of graphics) {
74
+ if (graphic !== undefined) {
75
+ next = next.createGraphics({
76
+ id, type: graphic.type, ...(parent === undefined ? {} : { parent }),
77
+ ...(graphic.type === "collection" || graphic.items === undefined ? {} : { length: 0 })
78
+ });
79
+ }
80
+ }
81
+ for (const source of sources) next = applyLayerDataRematerialization(next, source);
82
+ for (const id of references.keys()) {
83
+ if (ownedChildren(next, id).length > 0) next = applyLayerDataRematerialization(next, id);
84
+ }
85
+ return next._withContext(program.context);
86
+ }
87
+
@@ -1,5 +1,6 @@
1
1
  import { removeMark } from "./remove.js";
2
2
  import {
3
+ createStatisticalReference,
3
4
  createReferenceLine,
4
5
  createReferenceBand,
5
6
  materializeStatisticalReferenceData,
@@ -32,6 +33,7 @@ export function registerMarkActions(ProgramClass) {
32
33
  registerTextMarkActions(ProgramClass);
33
34
  registerTickMarkActions(ProgramClass);
34
35
  ProgramClass.prototype.removeMark = removeMark;
36
+ ProgramClass.prototype.createStatisticalReference = createStatisticalReference;
35
37
  ProgramClass.prototype.createReferenceLine = createReferenceLine;
36
38
  ProgramClass.prototype.createReferenceBand = createReferenceBand;
37
39
  ProgramClass.prototype.materializeStatisticalReferenceData =
@@ -1,6 +1,7 @@
1
1
  export function rematerializeHighlightBaseline(program, {
2
2
  target,
3
3
  operation,
4
+ scales,
4
5
  resetProperty,
5
6
  resetValue
6
7
  }) {
@@ -22,6 +23,6 @@ export function rematerializeHighlightBaseline(program, {
22
23
  property: resetProperty,
23
24
  value: resetValue
24
25
  })
25
- [operation]({ id: target })
26
+ [operation]({ id: target, ...(scales === undefined ? {} : { scales }) })
26
27
  .rematerializeMarkHighlights({ target, highlights });
27
28
  }
@@ -1,3 +1,4 @@
1
+ import { requestedMarkClip, validateMarkClipCoordinate } from "../../../selectors/markClip.js";
1
2
  import { action } from "../../../core/action.js";
2
3
  import { validateUserId } from "../../../core/identifiers.js";
3
4
  import {
@@ -34,6 +35,7 @@ import {
34
35
  resolvePositionedLineMaterialization
35
36
  } from "./materialize.js";
36
37
  import { resolveLineBins } from "../../../grammar/lineSeries.js";
38
+ import { validateLineMissing, validateLineMissingScope } from "../../../grammar/lineMissing.js";
37
39
  import { requireSemanticScale } from "../../../selectors/scales.js";
38
40
  import {
39
41
  requestedStrokeDetails,
@@ -43,11 +45,11 @@ import {
43
45
  const DEFAULT_LINE_STROKE = DEFAULT_COLORS.mark;
44
46
  const DEFAULT_LINE_WIDTH = 2;
45
47
  const CREATE_OPTIONS = Object.freeze([
46
- "id", "data", "stroke", "strokeWidth", "opacity", "curve", "tension", "closed",
48
+ "clip", "missing", "id", "data", "stroke", "strokeWidth", "opacity", "curve", "tension", "closed",
47
49
  ...STROKE_STYLE_PROPERTIES
48
50
  ]);
49
51
  const EDIT_OPTIONS = Object.freeze([
50
- "target", "stroke", "strokeWidth", "opacity", "curve", "tension", "closed",
52
+ "clip", "missing", "target", "stroke", "strokeWidth", "opacity", "curve", "tension", "closed",
51
53
  ...STROKE_STYLE_PROPERTIES
52
54
  ]);
53
55
  const REMATERIALIZE_OPTIONS = Object.freeze(["id", "scales"]);
@@ -100,7 +102,9 @@ const createLineMark = /* @__PURE__ */ action(
100
102
  },
101
103
  function (args = {}) {
102
104
  validateMarkOptions(args, CREATE_OPTIONS, "createLineMark");
105
+ requestedMarkClip(args);
103
106
  const strokeDetails = requestedStrokeDetails(args, "createLineMark");
107
+ const missing = validateLineMissing(args.missing);
104
108
  const id = resolveMarkId(this, args.id, {
105
109
  defaultId: "line",
106
110
  label: "Line mark id",
@@ -140,6 +144,10 @@ const createLineMark = /* @__PURE__ */ action(
140
144
  value: data
141
145
  });
142
146
  created = applyLayeredMarkInheritance(created, id, inherited);
147
+ if (Object.hasOwn(args, "missing")) {
148
+ created = created.editSemantic({ property: `layer[${id}].mark.missing`, value: missing });
149
+ }
150
+ validateLineMissingScope(findLayer(created, id));
143
151
  created = created
144
152
  .createGraphics({
145
153
  id,
@@ -159,6 +167,7 @@ const createLineMark = /* @__PURE__ */ action(
159
167
  );
160
168
  created = materializeInheritedMark(created, id);
161
169
  const appearance = {
170
+ ...requestedMarkClip(args),
162
171
  ...(stroke === undefined ? {} : { stroke }),
163
172
  ...(opacity === undefined ? {} : { opacity })
164
173
  };
@@ -203,11 +212,13 @@ const rematerializeLineMark = /* @__PURE__ */ action(
203
212
  const highlighted = rematerializeHighlightBaseline(this, {
204
213
  target: id,
205
214
  operation: "rematerializeLineMark",
215
+ scales: args.scales,
206
216
  resetProperty: "length",
207
217
  resetValue: 0
208
218
  });
209
219
  if (highlighted !== undefined) return highlighted;
210
220
  const { dataset, layer } = requireLine(this, id);
221
+ validateLineMissingScope(layer);
211
222
  const existingChildren = this.graphicSpec.objects[id].items;
212
223
  const parallel = layer.encoding?.parallel;
213
224
  const xScaleId = layer.encoding?.x?.scale;
@@ -277,9 +288,10 @@ const editLineMark = /* @__PURE__ */ action(
277
288
  },
278
289
  function (args = {}) {
279
290
  validateMarkOptions(args, EDIT_OPTIONS, "editLineMark");
291
+ requestedMarkClip(args);
280
292
  const strokeDetails = requestedStrokeDetails(args, "editLineMark");
281
- if (!EDIT_OPTIONS.slice(1).some(key => Object.hasOwn(args, key))) {
282
- throw new Error("editLineMark requires stroke, strokeWidth, opacity, curve, tension, or closed.");
293
+ if (!EDIT_OPTIONS.filter(key => key !== "target").some(key => Object.hasOwn(args, key))) {
294
+ throw new Error("editLineMark requires stroke, strokeWidth, opacity, curve, tension, closed, or missing.");
283
295
  }
284
296
  const target = Object.hasOwn(args, "target")
285
297
  ? validateUserId(args.target, "Line mark id")
@@ -306,7 +318,8 @@ const editLineMark = /* @__PURE__ */ action(
306
318
  (layer.encoding?.x !== undefined || isParallelLine(layer))) {
307
319
  throw new Error("Line closed requires theta/radius Polar position encodings.");
308
320
  }
309
- const config = { ...this.markConfigs[layer.id] };
321
+ validateMarkClipCoordinate(this, layer, args.clip ?? this.markConfigs[layer.id]?.clip);
322
+ const config = { ...this.markConfigs[layer.id], ...requestedMarkClip(args) };
310
323
  Object.assign(config, strokeDetails);
311
324
  for (const [key, validate] of Object.entries({
312
325
  stroke: validateNonEmptyString,
@@ -323,7 +336,12 @@ const editLineMark = /* @__PURE__ */ action(
323
336
  if (Object.hasOwn(args, "tension")) config.tension = args.tension;
324
337
  validateCardinalTension(config.tension, config.curve ?? "linear");
325
338
  validatePolarLineConfig(layer, config);
326
- const next = this._withMarkConfig(layer.id, config);
339
+ let next = this._withMarkConfig(layer.id, config);
340
+ if (Object.hasOwn(args, "missing")) {
341
+ const missing = validateLineMissing(args.missing);
342
+ validateLineMissingScope({ ...layer, mark: { ...layer.mark, missing } });
343
+ next = next.editSemantic({ property: `layer[${layer.id}].mark.missing`, value: missing });
344
+ }
327
345
  const materialized = canMaterializeLine(next, layer)
328
346
  ? next.rematerializeLineMark({ id: layer.id })
329
347
  : next;
@@ -4,6 +4,7 @@ import {
4
4
  import {
5
5
  mapContinuousScaleValues,
6
6
  mapOrdinalPositionValues,
7
+ readScaleField,
7
8
  normalizeStrokeDashPattern
8
9
  } from "../../../grammar/scales/index.js";
9
10
  import { buildCurvePathCommands } from
@@ -55,7 +56,9 @@ export function resolveParallelLineMaterialization({
55
56
  );
56
57
  const sourceRows = items.map(item => rows[item.sourceRowIndex]);
57
58
  const mapAppearance = appearanceMapper(layer, resolvedScales,
58
- field => sourceRows.map(row => row[field]));
59
+ (field, channel, encoding) => readScaleField(sourceRows, field, encoding.fieldType, {
60
+ temporalUnit: encoding.temporalUnit
61
+ }));
59
62
  return {
60
63
  commands: items.map(item => item.commands),
61
64
  strokes: layer.encoding?.stroke?.scale !== undefined
@@ -99,7 +102,7 @@ export function resolvePositionedLineMaterialization({
99
102
  const lineOptions = polar
100
103
  ? { thetaDomain: resolvedScales[thetaScaleId].domain }
101
104
  : { xBinBoundaries, xDomain: resolvedScales[xScaleId].domain };
102
- const derived = deriveLineSeries(rows, layer, lineOptions);
105
+ const derived = deriveLineSeries(rows, layer, { ...lineOptions, scales: resolvedScales });
103
106
  const commands = polar
104
107
  ? derived.series.map(series => buildPolarLinePathCommands({
105
108
  series: series.values,
@@ -134,7 +137,8 @@ export function resolvePositionedLineMaterialization({
134
137
  derived.series,
135
138
  field,
136
139
  channel,
137
- encoding
140
+ encoding,
141
+ channel === "color" ? resolvedScales[encoding.scale] : undefined
138
142
  ));
139
143
  return {
140
144
  commands,
@@ -1,3 +1,4 @@
1
+ import { requestedMarkClip } from "../../../selectors/markClip.js";
1
2
  import { action } from "../../../core/action.js";
2
3
  import { validatePointShape } from "../../../grammar/pointShapes.js";
3
4
  import { getPointGraphicType } from "../../../grammar/schemas/mark.js";
@@ -19,7 +20,7 @@ import {
19
20
  import { validateItemMissing } from "../../../grammar/itemMissing.js";
20
21
 
21
22
  const OPTIONS = Object.freeze([
22
- "id", "data", "missing", "shape", "fill", "opacity", "stroke", "strokeWidth",
23
+ "clip", "id", "data", "missing", "shape", "fill", "opacity", "stroke", "strokeWidth",
23
24
  ...STROKE_STYLE_PROPERTIES
24
25
  ]);
25
26
 
@@ -30,6 +31,7 @@ export const createPointMark = /* @__PURE__ */ action(
30
31
  },
31
32
  function (args = {}) {
32
33
  validateMarkOptions(args, OPTIONS, "createPointMark");
34
+ requestedMarkClip(args);
33
35
  requestedStrokeDetails(args, "createPointMark");
34
36
  const id = resolveMarkId(this, args.id, {
35
37
  defaultId: "point",
@@ -46,8 +48,7 @@ export const createPointMark = /* @__PURE__ */ action(
46
48
  ? { data: inherited.data }
47
49
  : {})
48
50
  });
49
- const shape = Object.hasOwn(args, "shape") ? args.shape : "circle";
50
- validatePointShape(shape);
51
+ const shape = validatePointShape(Object.hasOwn(args, "shape") ? args.shape : "circle");
51
52
  const resolvedType = getPointGraphicType(shape);
52
53
  const graphicType = resolvedType === "path" ? "circle" : resolvedType;
53
54
 
@@ -78,7 +79,7 @@ export const createPointMark = /* @__PURE__ */ action(
78
79
  ._withMarkConfig(id, { shape });
79
80
  const created = materializeInheritedMark(next, id);
80
81
  const appearance = Object.fromEntries(
81
- ["fill", "opacity", "stroke", "strokeWidth", ...STROKE_STYLE_PROPERTIES]
82
+ ["clip", "fill", "opacity", "stroke", "strokeWidth", ...STROKE_STYLE_PROPERTIES]
82
83
  .filter(property => Object.hasOwn(args, property))
83
84
  .map(property => [property, args[property]])
84
85
  );
@@ -1,3 +1,4 @@
1
+ import { requestedMarkClip, validateMarkClipCoordinate } from "../../../selectors/markClip.js";
1
2
  import { action } from "../../../core/action.js";
2
3
  import { validateUserId } from "../../../core/identifiers.js";
3
4
  import {
@@ -16,7 +17,7 @@ import { validateMarkOptions } from "../shared.js";
16
17
  import { validateItemMissing } from "../../../grammar/itemMissing.js";
17
18
 
18
19
  const OPTIONS = Object.freeze([
19
- "target", "missing", "shape", "fill", "opacity", "stroke", "strokeWidth",
20
+ "target", "clip", "missing", "shape", "fill", "opacity", "stroke", "strokeWidth",
20
21
  ...STROKE_STYLE_PROPERTIES
21
22
  ]);
22
23
 
@@ -27,9 +28,10 @@ export const editPointMark = /* @__PURE__ */ action(
27
28
  },
28
29
  function (args = {}) {
29
30
  validateMarkOptions(args, OPTIONS, "editPointMark");
31
+ requestedMarkClip(args);
30
32
  const strokeDetails = requestedStrokeDetails(args, "editPointMark");
31
33
  const editable = [
32
- "missing", "shape", "fill", "opacity", "stroke", "strokeWidth",
34
+ "clip", "missing", "shape", "fill", "opacity", "stroke", "strokeWidth",
33
35
  ...STROKE_STYLE_PROPERTIES
34
36
  ];
35
37
  if (!editable.some(property => Object.hasOwn(args, property))) {
@@ -62,13 +64,14 @@ export const editPointMark = /* @__PURE__ */ action(
62
64
  if (Object.hasOwn(args, "opacity") && layer.encoding?.opacity?.field !== undefined) {
63
65
  throw new Error("editPointMark opacity conflicts with a field encoding; use encodeOpacity with value to replace it.");
64
66
  }
67
+ validateMarkClipCoordinate(this, layer, args.clip ?? this.markConfigs[id]?.clip);
65
68
  const semantic = Object.hasOwn(args, "missing")
66
69
  ? this.editSemantic({
67
70
  property: `layer[${id}].mark.missing`,
68
71
  value: validateItemMissing(args.missing, "Point missing")
69
72
  })
70
73
  : this;
71
- const config = { ...semantic.markConfigs[id] };
74
+ const config = { ...semantic.markConfigs[id], ...requestedMarkClip(args) };
72
75
  Object.assign(config, strokeDetails);
73
76
  if (Object.hasOwn(args, "shape")) {
74
77
  config.shape = validatePointShape(args.shape);
@@ -10,20 +10,20 @@ const JITTER_OPTIONS = Object.freeze([
10
10
  ]);
11
11
  const REMOVE_OPTIONS = Object.freeze(["target"]);
12
12
 
13
- function isCartesianPoint(program, layer, channel) {
13
+ function isCartesianPoint(program, layer) {
14
14
  return layer.mark?.type === "point" &&
15
- layer.encoding?.[channel]?.scale !== undefined &&
16
- layer.encoding?.[channel === "x" ? "y" : "x"]?.scale !== undefined &&
15
+ layer.encoding?.x?.scale !== undefined &&
16
+ layer.encoding?.y?.scale !== undefined &&
17
17
  findCoordinate(program, layer.coordinate)?.type === "cartesian";
18
18
  }
19
19
 
20
- function resolveJitterTarget(program, target, channel) {
20
+ function resolveJitterTarget(program, target) {
21
21
  const requested = target === undefined
22
22
  ? undefined
23
23
  : validateUserId(target, "Point jitter target");
24
24
  return resolveEligibleLayer(program, {
25
25
  target: requested,
26
- predicate: layer => isCartesianPoint(program, layer, channel),
26
+ predicate: layer => isCartesianPoint(program, layer),
27
27
  label: "point jitter"
28
28
  });
29
29
  }
@@ -35,7 +35,7 @@ export const jitterPoints = /* @__PURE__ */ closedAction(
35
35
  }, JITTER_OPTIONS,
36
36
  function (args = {}) {
37
37
  const policy = normalizePointJitterPolicy(args);
38
- const layer = resolveJitterTarget(this, args.target, policy.channel);
38
+ const layer = resolveJitterTarget(this, args.target);
39
39
  if (this.materializationConfigs.pointPacking?.[layer.id] !== undefined) {
40
40
  throw new Error(`Point jitter on "${layer.id}" conflicts with point packing.`);
41
41
  }