ggaction 0.0.5 → 0.0.7

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 (69) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +77 -14
  3. package/package.json +19 -2
  4. package/src/BasicChartProgram.js +10 -0
  5. package/src/actions/basic.js +21 -0
  6. package/src/actions/boxPlots/edit.js +455 -3
  7. package/src/actions/boxPlots/options.js +3 -3
  8. package/src/actions/canvas/actions.js +42 -0
  9. package/src/actions/canvas/index.js +5 -1
  10. package/src/actions/charts/basic.js +13 -0
  11. package/src/actions/composition/actions.js +13 -3
  12. package/src/actions/data/basic.js +11 -0
  13. package/src/actions/data/basicBin2d.js +43 -0
  14. package/src/actions/data/bin2d.js +138 -40
  15. package/src/actions/data/bin2dMaterialize.js +29 -0
  16. package/src/actions/data/index.js +6 -1
  17. package/src/actions/data/intervalEdit.js +76 -0
  18. package/src/actions/distributions/revision.js +326 -0
  19. package/src/actions/encodings/appearance.js +41 -3
  20. package/src/actions/encodings/basic.js +21 -0
  21. package/src/actions/encodings/density.js +215 -80
  22. package/src/actions/encodings/index.js +2 -0
  23. package/src/actions/encodings/position/index.js +5 -1
  24. package/src/actions/encodings/ranged.js +6 -2
  25. package/src/actions/encodings/remove.js +268 -0
  26. package/src/actions/errorBands/edit.js +121 -13
  27. package/src/actions/errorBars/edit.js +45 -8
  28. package/src/actions/errorBars/options.js +7 -1
  29. package/src/actions/facets/actions.js +136 -1
  30. package/src/actions/gradientPlots/edit.js +352 -4
  31. package/src/actions/guides/axes/edit.js +129 -47
  32. package/src/actions/guides/axes/index.js +10 -2
  33. package/src/actions/guides/basic.js +19 -0
  34. package/src/actions/guides/grids/grid.js +7 -3
  35. package/src/actions/guides/grids/index.js +1 -1
  36. package/src/actions/guides/legends/categorical/actions.js +19 -8
  37. package/src/actions/guides/legends/categorical/index.js +6 -2
  38. package/src/actions/guides/legends/continuous/common.js +3 -3
  39. package/src/actions/guides/legends/continuous/index.js +6 -2
  40. package/src/actions/guides/legends/edit.js +61 -3
  41. package/src/actions/guides/legends/remove.js +124 -23
  42. package/src/actions/guides/legends/strokeWidth.js +42 -14
  43. package/src/actions/marks/arc/actions.js +46 -14
  44. package/src/actions/marks/bar/index.js +5 -1
  45. package/src/actions/marks/basic.js +11 -0
  46. package/src/actions/marks/line/actions.js +5 -1
  47. package/src/actions/marks/line/index.js +4 -1
  48. package/src/actions/marks/point/edit.js +15 -3
  49. package/src/actions/marks/point/index.js +5 -1
  50. package/src/actions/marks/point/materialize.js +9 -3
  51. package/src/actions/marks/rect/actions.js +5 -1
  52. package/src/actions/marks/rect/index.js +4 -1
  53. package/src/actions/marks/rule/actions.js +4 -1
  54. package/src/actions/regression/edit.js +235 -74
  55. package/src/actions/scales/index.js +5 -1
  56. package/src/actions/selection/actions.js +122 -2
  57. package/src/actions/selection/index.js +6 -0
  58. package/src/basic.js +2 -0
  59. package/src/core/vocabulary.js +7 -0
  60. package/src/renderers/canvas/index.js +96 -60
  61. package/src/renderers/canvas/text.js +3 -14
  62. package/src/renderers/pdf.js +112 -0
  63. package/src/renderers/svg.js +559 -0
  64. package/src/renderers/text.js +11 -0
  65. package/types/basic.d.ts +107 -0
  66. package/types/index.d.ts +1 -0
  67. package/types/pdf.d.ts +26 -0
  68. package/types/program.d.ts +71 -7
  69. package/types/svg.d.ts +11 -0
@@ -9,7 +9,10 @@ import {
9
9
  resolveAppearanceScaleDefinition,
10
10
  resolveOpacityScaleDefinition
11
11
  } from "../scales/definitions.js";
12
- import { findLayer } from "../../selectors/layers.js";
12
+ import {
13
+ findLayer,
14
+ resolveEligibleLayer
15
+ } from "../../selectors/layers.js";
13
16
  import { applyMaterializationPlan } from "../../materialization/dependencies.js";
14
17
  import { planEncodingRematerialization } from "../../materialization/encodings.js";
15
18
  import {
@@ -20,6 +23,7 @@ import {
20
23
  } from "./shared.js";
21
24
 
22
25
  const RADIUS_OPTIONS = Object.freeze(["value", "target"]);
26
+ const REMOVE_RADIUS_OPTIONS = Object.freeze(["target"]);
23
27
  const OPACITY_OPTIONS = Object.freeze([
24
28
  "value", "field", "target", "fieldType", "scale"
25
29
  ]);
@@ -129,6 +133,35 @@ const encodePointRadius = action(
129
133
  }
130
134
  );
131
135
 
136
+ const removePointRadius = action(
137
+ {
138
+ op: "removePointRadius",
139
+ description: "Remove a constant point radius and restore the theme default."
140
+ },
141
+ function (args = {}) {
142
+ validateOptions(args, REMOVE_RADIUS_OPTIONS, "removePointRadius");
143
+ const requested = args.target === undefined
144
+ ? undefined
145
+ : args.target;
146
+ const layer = resolveEligibleLayer(this, {
147
+ target: requested,
148
+ predicate: candidate =>
149
+ candidate.mark?.type === "point" &&
150
+ this.markConfigs[candidate.id]?.radius !== undefined,
151
+ label: "point mark with an explicit radius"
152
+ });
153
+ const next = this
154
+ ._withoutMaterializationConfig(["marks", layer.id, "radius"]);
155
+ const graphic = next.graphicSpec.objects[layer.id];
156
+ const baseline = graphic === undefined
157
+ ? next
158
+ : graphic.type === "collection"
159
+ ? next.editGraphics({ target: layer.id, property: "items", value: [] })
160
+ : next.editGraphics({ target: layer.id, property: "length", value: 0 });
161
+ return baseline.rematerializePointMark({ id: layer.id });
162
+ }
163
+ );
164
+
132
165
  const encodeSize = action(
133
166
  {
134
167
  op: "encodeSize",
@@ -244,11 +277,16 @@ const encodeOpacity = action(
244
277
  }
245
278
  );
246
279
 
280
+ export function registerBasicAppearanceEncodingActions(ProgramClass) {
281
+ ProgramClass.prototype.encodeSize = encodeSize;
282
+ ProgramClass.prototype.encodeShape = encodeShape;
283
+ }
284
+
247
285
  export function registerAppearanceEncodingAction(ProgramClass) {
286
+ registerBasicAppearanceEncodingActions(ProgramClass);
248
287
  ProgramClass.prototype.encodeRadius = encodeRadius;
249
288
  ProgramClass.prototype.encodePointRadius = encodePointRadius;
250
- ProgramClass.prototype.encodeSize = encodeSize;
251
- ProgramClass.prototype.encodeShape = encodeShape;
289
+ ProgramClass.prototype.removePointRadius = removePointRadius;
252
290
  ProgramClass.prototype.encodeOpacity = encodeOpacity;
253
291
  ProgramClass.prototype.clearOpacityEncoding = clearOpacityEncoding;
254
292
  }
@@ -0,0 +1,21 @@
1
+ import { registerBasicAppearanceEncodingActions } from "./appearance.js";
2
+ import { registerBarWidthEncodingAction } from "./barWidth.js";
3
+ import { registerColorEncodingAction } from "./color/index.js";
4
+ import { registerHistogramEncodingAction } from "./histogram.js";
5
+ import { registerOffsetEncodingAction } from "./offset.js";
6
+ import {
7
+ registerCartesianPositionEncodingActions
8
+ } from "./position/index.js";
9
+ import { registerBasicRangedEncodingActions } from "./ranged.js";
10
+ import { registerStrokeDashEncodingActions } from "./strokeDash.js";
11
+
12
+ export function registerBasicEncodingActions(ProgramClass) {
13
+ registerCartesianPositionEncodingActions(ProgramClass);
14
+ registerBasicRangedEncodingActions(ProgramClass);
15
+ registerColorEncodingAction(ProgramClass);
16
+ registerBasicAppearanceEncodingActions(ProgramClass);
17
+ registerStrokeDashEncodingActions(ProgramClass);
18
+ registerOffsetEncodingAction(ProgramClass);
19
+ registerHistogramEncodingAction(ProgramClass);
20
+ registerBarWidthEncodingAction(ProgramClass);
21
+ }
@@ -15,6 +15,7 @@ import { planDerivedDataRevision } from
15
15
  import { validateOptions } from "./shared.js";
16
16
  import { normalizeDensityPlacement } from "../../grammar/density.js";
17
17
  import { scaleEditPatch } from "../scales/patch.js";
18
+ import { removeLegendKinds } from "../guides/legends/remove.js";
18
19
  import {
19
20
  requireDensityField,
20
21
  resolveDensityCategoryScaleOptions,
@@ -29,8 +30,8 @@ const OPTIONS = Object.freeze([
29
30
  "valueScale", "densityScale", "placement"
30
31
  ]);
31
32
  const EDIT_OPTIONS = Object.freeze([
32
- "target", "bandwidth", "extent", "steps", "kernel", "normalization",
33
- "placement"
33
+ "target", "source", "field", "groupBy", "bandwidth", "extent", "steps",
34
+ "kernel", "normalization", "placement"
34
35
  ]);
35
36
  const EDITABLE = Object.freeze(EDIT_OPTIONS.filter(option => option !== "target"));
36
37
 
@@ -190,6 +191,43 @@ function findDensityArea(program, requested) {
190
191
  });
191
192
  }
192
193
 
194
+ function densityCategoryField(layer, transform, groupBy) {
195
+ if (transform.placement === undefined) return undefined;
196
+ if (transform.placement.categoryField !== transform.groupBy) {
197
+ return transform.placement.categoryField;
198
+ }
199
+ return groupBy ?? `${layer.id}DensityCategory`;
200
+ }
201
+
202
+ function assertGroupingSelectionCompatibility(program, layer, changesGroup) {
203
+ if (!changesGroup) return;
204
+ const referenced = Object.entries(
205
+ program.materializationConfigs.selections ?? {}
206
+ ).find(([, selection]) =>
207
+ selection.target === layer.id &&
208
+ ["group", "color"].includes(selection.selector?.channel)
209
+ );
210
+ if (referenced !== undefined) {
211
+ throw new Error(
212
+ `editDensity cannot change groupBy while selection "${referenced[0]}" ` +
213
+ `references ${referenced[1].selector.channel}.`
214
+ );
215
+ }
216
+ }
217
+
218
+ function removeOwnedColorLegends(program, target) {
219
+ const kinds = Object.entries(program.guideConfigs.legend ?? {})
220
+ .filter(([kind, config]) =>
221
+ config?.target === target &&
222
+ (
223
+ config.channels?.includes("color") ||
224
+ ["gradient", "interval"].includes(kind)
225
+ )
226
+ )
227
+ .map(([kind]) => kind);
228
+ return kinds.length === 0 ? program : removeLegendKinds(program, kinds);
229
+ }
230
+
193
231
  const editDensity = action(
194
232
  {
195
233
  op: "editDensity",
@@ -203,21 +241,55 @@ const editDensity = action(
203
241
  const layer = findDensityArea(this, args.target);
204
242
  const previous = findDataset(this, layer.data);
205
243
  const transform = previous.transform[0];
244
+ const source = Object.hasOwn(args, "source")
245
+ ? validateUserId(args.source, "Density source dataset id")
246
+ : previous.source;
247
+ const field = Object.hasOwn(args, "field")
248
+ ? requireDensityField(args.field, "Density field")
249
+ : transform.field;
250
+ const groupBy = Object.hasOwn(args, "groupBy")
251
+ ? args.groupBy === false
252
+ ? undefined
253
+ : requireDensityField(args.groupBy, "Density groupBy")
254
+ : transform.groupBy;
255
+ const changesGroup = groupBy !== transform.groupBy;
256
+ assertGroupingSelectionCompatibility(this, layer, changesGroup);
257
+ const categoryField = densityCategoryField(layer, transform, groupBy);
206
258
  const requestedPlacement = Object.hasOwn(args, "placement")
207
259
  ? normalizeDensityPlacement(args.placement, {
208
260
  densityChannel: transform.placement?.channel ?? "x",
209
- groupBy: transform.groupBy,
210
- categoryField: transform.groupBy ??
211
- transform.placement?.categoryField ??
261
+ groupBy,
262
+ categoryField: categoryField ?? groupBy ??
212
263
  `${layer.id}DensityCategory`
213
264
  })
214
- : transform.placement;
265
+ : transform.placement === undefined || !changesGroup
266
+ ? transform.placement
267
+ : normalizeDensityPlacement({
268
+ type: "category",
269
+ ...(transform.placement.side === undefined
270
+ ? {}
271
+ : { side: transform.placement.side }),
272
+ width: transform.placement.width,
273
+ ...(transform.placement.split === undefined
274
+ ? {}
275
+ : { split: transform.placement.split })
276
+ }, {
277
+ densityChannel: transform.placement.channel,
278
+ groupBy,
279
+ categoryField
280
+ });
215
281
  const colorField = layer.encoding?.color?.field;
282
+ const colorFollowsGroup = transform.groupBy !== undefined &&
283
+ colorField === transform.groupBy;
216
284
  const availableColorFields = [
217
- transform.groupBy,
285
+ groupBy,
218
286
  requestedPlacement?.split?.field
219
287
  ].filter(Boolean);
220
- if (colorField !== undefined && !availableColorFields.includes(colorField)) {
288
+ if (
289
+ colorField !== undefined &&
290
+ !colorFollowsGroup &&
291
+ !availableColorFields.includes(colorField)
292
+ ) {
221
293
  throw new Error(
222
294
  `editDensity placement would remove color field "${colorField}" from the density series.`
223
295
  );
@@ -234,11 +306,11 @@ const editDensity = action(
234
306
 
235
307
  const dataArgs = {
236
308
  id: revision.id,
237
- source: previous.source,
238
- field: transform.field,
239
- ...(transform.groupBy === undefined
309
+ source,
310
+ field,
311
+ ...(groupBy === undefined
240
312
  ? {}
241
- : { groupBy: transform.groupBy }),
313
+ : { groupBy }),
242
314
  bandwidth: option("bandwidth"),
243
315
  extent: option("extent"),
244
316
  steps: option("steps"),
@@ -249,78 +321,141 @@ const editDensity = action(
249
321
  ? {}
250
322
  : { placement: requestedPlacement })
251
323
  };
252
- let next = requestedPlacement === undefined
253
- ? this.createDensityData(dataArgs)
254
- : this.createCategoricalDensityData(dataArgs);
255
- next = next.rebindLayerData(revision.rebinds[0])
256
- .releaseDerivedData(revision.release);
257
-
258
324
  const changesPlacementMode = Object.hasOwn(args, "placement") &&
259
325
  (transform.placement === undefined) !== (requestedPlacement === undefined);
260
- if (changesPlacementMode) {
261
- const xScaleId = layer.encoding?.x?.scale;
262
- const yScaleId = layer.encoding?.y?.scale;
263
- const scaleDefinitions = resolveDensityTransitionScaleDefinitions(
264
- this,
265
- layer,
266
- transform,
267
- requestedPlacement,
268
- args.placement
269
- );
270
- next = next
271
- .editSemantic({ property: `layer[${layer.id}].encoding.x`, remove: true })
272
- .editSemantic({ property: `layer[${layer.id}].encoding.y`, remove: true });
273
- next = next
274
- .editScale(scaleEditPatch(xScaleId, scaleDefinitions.x))
275
- .editScale(scaleEditPatch(yScaleId, scaleDefinitions.y));
276
- const densityChannel = requestedPlacement?.channel ?? (
277
- layer.encoding.x.field === transform.as[1] ? "x" : "y"
278
- );
279
- const definition = resolveDensityPositionDefinition({
280
- layer: { densityChannel },
281
- output: transform.as,
282
- groupBy: transform.groupBy,
283
- placement: requestedPlacement,
284
- coordinate: layer.coordinate,
285
- valueScale: {
286
- id: requestedPlacement?.channel === "x" ? yScaleId : xScaleId,
287
- ...scaleDefinitions[requestedPlacement?.channel === "x" ? "y" : "x"]
288
- },
289
- densityScale: requestedPlacement === undefined
290
- ? {
291
- id: densityChannel === "x" ? xScaleId : yScaleId,
292
- ...scaleDefinitions[densityChannel]
293
- }
294
- : undefined,
295
- placementScale: requestedPlacement === undefined
296
- ? undefined
297
- : {
298
- id: requestedPlacement.channel === "x" ? xScaleId : yScaleId,
299
- ...scaleDefinitions[requestedPlacement.channel]
300
- }
301
- });
302
- next = applyDensityPosition(next, layer.id, definition);
303
- } else if (
304
- requestedPlacement !== undefined &&
305
- Object.hasOwn(args.placement ?? {}, "scale")
306
- ) {
307
- const channel = requestedPlacement.channel;
308
- const scaleId = layer.encoding[channel].scale;
309
- const requestedScale = resolveDensityCategoryScaleOptions(
310
- args.placement.scale,
311
- scaleId
312
- );
313
- if (requestedScale.id !== scaleId) {
314
- throw new Error("editDensity placement scale cannot change its id.");
326
+ const applyEdit = program => {
327
+ let next = requestedPlacement === undefined
328
+ ? program.createDensityData(dataArgs)
329
+ : program.createCategoricalDensityData(dataArgs);
330
+ next = next.rebindLayerData(revision.rebinds[0])
331
+ .releaseDerivedData(revision.release);
332
+
333
+ if (changesGroup) {
334
+ if (groupBy === undefined) {
335
+ if (findLayer(next, layer.id).encoding?.group !== undefined) {
336
+ next = next.editSemantic({
337
+ property: `layer[${layer.id}].encoding.group`,
338
+ remove: true
339
+ });
340
+ }
341
+ if (colorFollowsGroup) {
342
+ next = next.editSemantic({
343
+ property: `layer[${layer.id}].encoding.color`,
344
+ remove: true
345
+ });
346
+ next = removeOwnedColorLegends(next, layer.id);
347
+ }
348
+ } else {
349
+ next = next
350
+ .editSemantic({
351
+ property: `layer[${layer.id}].encoding.group.field`,
352
+ value: groupBy
353
+ })
354
+ .editSemantic({
355
+ property: `layer[${layer.id}].encoding.group.fieldType`,
356
+ value: "nominal"
357
+ });
358
+ if (colorFollowsGroup) {
359
+ next = next.editSemantic({
360
+ property: `layer[${layer.id}].encoding.color.field`,
361
+ value: groupBy
362
+ });
363
+ }
364
+ }
365
+ if (
366
+ requestedPlacement !== undefined &&
367
+ transform.placement?.categoryField !== requestedPlacement.categoryField
368
+ ) {
369
+ next = next.editSemantic({
370
+ property: `layer[${layer.id}].encoding.${requestedPlacement.channel}.field`,
371
+ value: requestedPlacement.categoryField
372
+ });
373
+ }
315
374
  }
316
- next = next.editScale(scaleEditPatch(scaleId, requestedScale));
317
- }
318
375
 
319
- next = applyMaterializationPlan(
320
- next,
321
- planDensityRematerialization(next, layer.id)
322
- );
323
- return next;
376
+ if (changesPlacementMode) {
377
+ const xScaleId = layer.encoding?.x?.scale;
378
+ const yScaleId = layer.encoding?.y?.scale;
379
+ const scaleDefinitions = resolveDensityTransitionScaleDefinitions(
380
+ program,
381
+ layer,
382
+ transform,
383
+ requestedPlacement,
384
+ args.placement
385
+ );
386
+ next = next
387
+ .editSemantic({
388
+ property: `layer[${layer.id}].encoding.x`,
389
+ remove: true
390
+ })
391
+ .editSemantic({
392
+ property: `layer[${layer.id}].encoding.y`,
393
+ remove: true
394
+ });
395
+ next = next
396
+ .editScale(scaleEditPatch(xScaleId, scaleDefinitions.x))
397
+ .editScale(scaleEditPatch(yScaleId, scaleDefinitions.y));
398
+ const densityChannel = requestedPlacement?.channel ?? (
399
+ layer.encoding.x.field === transform.as[1] ? "x" : "y"
400
+ );
401
+ const valueChannel = requestedPlacement?.channel === "x" ? "y" : "x";
402
+ const definition = resolveDensityPositionDefinition({
403
+ layer: { densityChannel },
404
+ output: transform.as,
405
+ groupBy,
406
+ placement: requestedPlacement,
407
+ coordinate: layer.coordinate,
408
+ valueScale: {
409
+ id: valueChannel === "y" ? yScaleId : xScaleId,
410
+ ...scaleDefinitions[valueChannel]
411
+ },
412
+ densityScale: requestedPlacement === undefined
413
+ ? {
414
+ id: densityChannel === "x" ? xScaleId : yScaleId,
415
+ ...scaleDefinitions[densityChannel]
416
+ }
417
+ : undefined,
418
+ placementScale: requestedPlacement === undefined
419
+ ? undefined
420
+ : {
421
+ id: requestedPlacement.channel === "x" ? xScaleId : yScaleId,
422
+ ...scaleDefinitions[requestedPlacement.channel]
423
+ }
424
+ });
425
+ next = applyDensityPosition(next, layer.id, definition, groupBy);
426
+ } else if (
427
+ requestedPlacement !== undefined &&
428
+ Object.hasOwn(args.placement ?? {}, "scale")
429
+ ) {
430
+ const channel = requestedPlacement.channel;
431
+ const scaleId = layer.encoding[channel].scale;
432
+ const requestedScale = resolveDensityCategoryScaleOptions(
433
+ args.placement.scale,
434
+ scaleId
435
+ );
436
+ if (requestedScale.id !== scaleId) {
437
+ throw new Error("editDensity placement scale cannot change its id.");
438
+ }
439
+ next = next.editScale(scaleEditPatch(scaleId, requestedScale));
440
+ }
441
+
442
+ next = applyMaterializationPlan(
443
+ next,
444
+ planDensityRematerialization(next, layer.id)
445
+ );
446
+ if (
447
+ changesGroup &&
448
+ colorFollowsGroup &&
449
+ groupBy !== undefined &&
450
+ Object.values(next.guideConfigs.legend ?? {})
451
+ .some(config => config?.target === layer.id)
452
+ ) {
453
+ next = next.rematerializeLegend();
454
+ }
455
+ return next;
456
+ };
457
+ applyEdit(this);
458
+ return applyEdit(this);
324
459
  }
325
460
  );
326
461
 
@@ -12,6 +12,7 @@ import { registerStrokeDashEncodingActions } from "./strokeDash.js";
12
12
  import { registerRuleAppearanceEncodingActions } from "./ruleAppearance.js";
13
13
  import { registerTextEncodingAction } from "./text.js";
14
14
  import { registerParallelEncodingAction } from "./parallel.js";
15
+ import { registerEncodingRemovalAction } from "./remove.js";
15
16
 
16
17
  export function registerEncodingActions(ProgramClass) {
17
18
  registerPositionEncodingActions(ProgramClass);
@@ -28,4 +29,5 @@ export function registerEncodingActions(ProgramClass) {
28
29
  registerRuleAppearanceEncodingActions(ProgramClass);
29
30
  registerTextEncodingAction(ProgramClass);
30
31
  registerParallelEncodingAction(ProgramClass);
32
+ registerEncodingRemovalAction(ProgramClass);
31
33
  }
@@ -135,9 +135,13 @@ const encodeR = action(
135
135
  }
136
136
  );
137
137
 
138
- export function registerPositionEncodingActions(ProgramClass) {
138
+ export function registerCartesianPositionEncodingActions(ProgramClass) {
139
139
  ProgramClass.prototype.encodeX = encodeX;
140
140
  ProgramClass.prototype.encodeY = encodeY;
141
+ }
142
+
143
+ export function registerPositionEncodingActions(ProgramClass) {
144
+ registerCartesianPositionEncodingActions(ProgramClass);
141
145
  ProgramClass.prototype.encodeTheta = encodeTheta;
142
146
  ProgramClass.prototype.encodeR = encodeR;
143
147
  }
@@ -291,10 +291,14 @@ const encodeGroup = action(
291
291
  }
292
292
  );
293
293
 
294
- export function registerRangedEncodingActions(ProgramClass) {
294
+ export function registerBasicRangedEncodingActions(ProgramClass) {
295
295
  ProgramClass.prototype.encodeX2 = encodeX2;
296
296
  ProgramClass.prototype.encodeY2 = encodeY2;
297
+ ProgramClass.prototype.encodeGroup = encodeGroup;
298
+ }
299
+
300
+ export function registerRangedEncodingActions(ProgramClass) {
301
+ registerBasicRangedEncodingActions(ProgramClass);
297
302
  ProgramClass.prototype.encodeXRange = encodeXRange;
298
303
  ProgramClass.prototype.encodeYRange = encodeYRange;
299
- ProgramClass.prototype.encodeGroup = encodeGroup;
300
304
  }