ggaction 0.0.21 → 0.0.22
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.
- package/CHANGELOG.md +73 -0
- package/README.md +3 -2
- package/knowledge/action-cards.json +1 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/package.json +6 -2
- package/src/BasicChartProgram.js +1 -1
- package/src/accessibility.js +1 -0
- package/src/actions/boxPlots/components.js +1 -96
- package/src/actions/boxPlots/create.js +6 -1
- package/src/actions/boxPlots/edit.js +8 -0
- package/src/actions/boxPlots/materialize.js +3 -0
- package/src/actions/boxPlots/options.js +1 -1
- package/src/actions/canvas/actions.js +2 -1
- package/src/actions/canvas/index.js +3 -0
- package/src/actions/canvas/plotBorder.js +2 -1
- package/src/actions/canvas/plotOrder.js +14 -0
- package/src/actions/charts/area.js +1 -1
- package/src/actions/charts/bar.js +4 -4
- package/src/actions/charts/density.js +1 -1
- package/src/actions/charts/ecdf.js +1 -1
- package/src/actions/charts/endpoints.js +54 -5
- package/src/actions/charts/heatmap.js +1 -1
- package/src/actions/charts/histogram.js +1 -1
- package/src/actions/charts/horizon.js +1 -1
- package/src/actions/charts/index.js +2 -1
- package/src/actions/charts/interval-regression.js +1 -1
- package/src/actions/charts/line.js +1 -1
- package/src/actions/charts/radar.js +63 -3
- package/src/actions/charts/raincloud.js +37 -6
- package/src/actions/charts/rug-strip.js +2 -2
- package/src/actions/charts/scatter.js +3 -3
- package/src/actions/charts/text.js +1 -1
- package/src/actions/composition/actions.js +10 -3
- package/src/actions/coordinates/actions.js +2 -0
- package/src/actions/data/basic.js +6 -0
- package/src/actions/data/derived.js +6 -2
- package/src/actions/data/edit.js +21 -35
- package/src/actions/data/filter.js +1 -376
- package/src/actions/data/flatten.js +19 -0
- package/src/actions/data/index.js +6 -0
- package/src/actions/data/lookup.js +50 -0
- package/src/actions/data/raincloudFilter.js +56 -0
- package/src/actions/data/shared.js +10 -0
- package/src/actions/distributions/revision.js +3 -1
- package/src/actions/encodings/angle.js +2 -1
- package/src/actions/encodings/appearance.js +38 -13
- package/src/actions/encodings/channels.js +14 -3
- package/src/actions/encodings/color/continuous.js +26 -10
- package/src/actions/encodings/color/index.js +50 -20
- package/src/actions/encodings/color/policy.js +57 -4
- package/src/actions/encodings/parallel.js +4 -0
- package/src/actions/encodings/position/policies/bar.js +10 -6
- package/src/actions/encodings/position/policies/line.js +1 -152
- package/src/actions/encodings/position/resolve.js +4 -1
- package/src/actions/encodings/ranged.js +46 -0
- package/src/actions/encodings/remove.js +1 -1
- package/src/actions/encodings/ruleAppearance.js +7 -6
- package/src/actions/encodings/shared.js +14 -2
- package/src/actions/encodings/stroke.js +20 -14
- package/src/actions/encodings/strokeDash.js +9 -11
- package/src/actions/encodings/text.js +30 -2
- package/src/actions/errorBars/edit.js +24 -4
- package/src/actions/facets/actions.js +1 -793
- package/src/actions/facets/derive.js +34 -5
- package/src/actions/facets/replay.js +1 -38
- package/src/actions/gradientPlots/components.js +21 -9
- package/src/actions/gradientPlots/create.js +4 -2
- package/src/actions/gradientPlots/edit.js +18 -1
- package/src/actions/gradientPlots/materialize.js +35 -36
- package/src/actions/gradientPlots/options.js +1 -1
- package/src/actions/gradientPlots/paint.js +13 -7
- package/src/actions/guides/applicability.js +2 -0
- package/src/actions/guides/axes/axes.js +39 -0
- package/src/actions/guides/axes/axis.js +9 -5
- package/src/actions/guides/axes/edit.js +11 -8
- package/src/actions/guides/axes/labels.js +24 -8
- package/src/actions/guides/axes/parallel/policy.js +3 -5
- package/src/actions/guides/axes/parallel/resolve.js +4 -3
- package/src/actions/guides/axes/policy.js +22 -0
- package/src/actions/guides/axes/tickGroups.js +4 -2
- package/src/actions/guides/axes/ticks.js +22 -4
- package/src/actions/guides/axes/titles.js +19 -6
- package/src/actions/guides/facadeAxes.js +3 -0
- package/src/actions/guides/grids/grid.js +3 -1
- package/src/actions/guides/grids/resolve.js +7 -11
- package/src/actions/guides/guides.js +21 -1
- package/src/actions/guides/legends/categorical/actions.js +1 -515
- package/src/actions/guides/legends/categorical/layout.js +5 -2
- package/src/actions/guides/legends/categorical/options.js +4 -0
- package/src/actions/guides/legends/categorical/resolve.js +8 -3
- package/src/actions/guides/legends/categorical/symbols.js +3 -3
- package/src/actions/guides/legends/colorSize.js +2 -0
- package/src/actions/guides/legends/continuous/common.js +1 -1
- package/src/actions/guides/legends/continuous/gradient.js +1 -360
- package/src/actions/guides/legends/continuous/interval.js +1 -1
- package/src/actions/guides/legends/continuous/opacity.js +15 -1
- package/src/actions/guides/legends/edit.js +1 -1
- package/src/actions/guides/legends/focused.js +1 -1
- package/src/actions/guides/legends/lane.js +1 -1
- package/src/actions/guides/legends/sampling.js +1 -140
- package/src/actions/guides/legends/strokeWidth.js +3 -2
- package/src/actions/guides/legends/transition.js +19 -2
- package/src/actions/guides/polar/axes/facade.js +5 -4
- package/src/actions/guides/polar/axes/labels.js +5 -4
- package/src/actions/guides/polar/axes/titles.js +5 -4
- package/src/actions/guides/polar/resolve.js +2 -1
- package/src/actions/guides/tickValues.js +7 -7
- package/src/actions/marks/arc/actions.js +5 -7
- package/src/actions/marks/area/actions.js +9 -3
- package/src/actions/marks/bar/create.js +4 -2
- package/src/actions/marks/bar/edit.js +9 -6
- package/src/actions/marks/bar/materialize.js +5 -3
- package/src/actions/marks/dependentReferences.js +87 -0
- package/src/actions/marks/index.js +2 -0
- package/src/actions/marks/lifecycle.js +2 -1
- package/src/actions/marks/line/actions.js +24 -6
- package/src/actions/marks/line/materialize.js +7 -3
- package/src/actions/marks/point/create.js +5 -4
- package/src/actions/marks/point/edit.js +6 -3
- package/src/actions/marks/point/jitter.js +6 -6
- package/src/actions/marks/point/materialize.js +36 -39
- package/src/actions/marks/rect/actions.js +16 -4
- package/src/actions/marks/references.js +183 -35
- package/src/actions/marks/rule/actions.js +20 -9
- package/src/actions/marks/shared.js +2 -1
- package/src/actions/marks/text/actions.js +10 -3
- package/src/actions/marks/tick/actions.js +11 -2
- package/src/actions/primitives/editGraphics.js +28 -3
- package/src/actions/primitives/index.js +9 -0
- package/src/actions/primitives/semanticAction.js +13 -7
- package/src/actions/primitives/semanticValidation/layer.js +20 -0
- package/src/actions/primitives/semanticValidation/scale.js +8 -1
- package/src/actions/scales/channels.js +1 -1
- package/src/actions/scales/consumers/common.js +19 -1
- package/src/actions/scales/consumers/families.js +2 -2
- package/src/actions/scales/consumers/seriesLayout.js +4 -3
- package/src/actions/scales/edit.js +11 -0
- package/src/actions/scales/editPolicy.js +5 -3
- package/src/actions/scales/preview.js +2 -1
- package/src/actions/scales/quantitativeColor.js +2 -4
- package/src/actions/selection/actions.js +10 -1
- package/src/actions/theme/reconcile.js +37 -9
- package/src/core/compositionState.js +21 -4
- package/src/core/datasetReferences.js +17 -0
- package/src/core/immutable.js +1 -0
- package/src/core/resourceReferences.js +5 -3
- package/src/core/validation.js +4 -0
- package/src/core/vocabulary.js +24 -2
- package/src/grammar/aggregate.js +1 -0
- package/src/grammar/arcs.js +1 -1
- package/src/grammar/areaSeries.js +1 -1
- package/src/grammar/axisTextPlacement.js +1 -1
- package/src/grammar/bars/policy.js +2 -2
- package/src/grammar/datasetDependencies.js +97 -0
- package/src/grammar/datasetSchema.js +31 -1
- package/src/grammar/facetHeaders.js +1 -0
- package/src/grammar/facets/dependencies.js +6 -2
- package/src/grammar/facets/legendIntent.js +6 -2
- package/src/grammar/facets/scales.js +27 -7
- package/src/grammar/flatten.js +85 -0
- package/src/grammar/histogram.js +13 -1
- package/src/grammar/horizon.js +1 -494
- package/src/grammar/jitter.js +2 -2
- package/src/grammar/legendSpacing.js +45 -0
- package/src/grammar/lineMissing.js +90 -0
- package/src/grammar/lineSeries.js +1 -376
- package/src/grammar/lookup.js +97 -0
- package/src/grammar/markFilter.js +4 -2
- package/src/grammar/markLabels.js +8 -3
- package/src/grammar/numeric.js +1 -1
- package/src/grammar/pathCommands.js +1 -1
- package/src/grammar/pathSeries.js +1 -109
- package/src/grammar/pointPolygon.js +81 -0
- package/src/grammar/pointShapes.js +15 -15
- package/src/grammar/rects.js +1 -1
- package/src/grammar/regression/derive.js +1 -195
- package/src/grammar/scales/appearance.js +1 -1
- package/src/grammar/scales/color.js +1 -1
- package/src/grammar/scales/colorConsumers.js +1 -63
- package/src/grammar/scales/continuous.js +58 -1
- package/src/grammar/scales/definition.js +1 -1
- package/src/grammar/scales/ordinal.js +5 -2
- package/src/grammar/scales/policies.js +3 -3
- package/src/grammar/schemas/graphicBounds.js +40 -12
- package/src/grammar/schemas/graphicClip.js +23 -0
- package/src/grammar/schemas/graphicTree.js +16 -0
- package/src/grammar/statisticalReference.js +22 -0
- package/src/grammar/text.js +65 -1
- package/src/grammar/ticks.js +92 -1
- package/src/grammar/transformTopology.js +3 -1
- package/src/grammar/transforms.js +24 -0
- package/src/inspection.js +1 -495
- package/src/inspectionDescriptors.js +1 -1
- package/src/layout/canvas.js +1 -1
- package/src/layout/facetContentFlow.js +101 -0
- package/src/layout/facetHeaderTitles.js +1 -0
- package/src/layout/facetTopLane.js +29 -0
- package/src/layout/facets.js +1 -1
- package/src/layout/legendGroup.js +1 -1
- package/src/layout/legendItems.js +26 -10
- package/src/layout/legendSpacing.js +66 -0
- package/src/layout/plotDrawOrder.js +17 -0
- package/src/materialization/bars/histogram.js +8 -2
- package/src/materialization/bars/resolve.js +1 -1
- package/src/materialization/composition.js +1 -0
- package/src/materialization/compositionSnapshot.js +22 -2
- package/src/materialization/dataProvenance.js +1 -1
- package/src/materialization/facetGuides/layout.js +1 -1
- package/src/materialization/facetGuides/placement.js +23 -11
- package/src/materialization/facetGuides/preparation.js +43 -24
- package/src/materialization/facetHeaders.js +1 -1
- package/src/materialization/facetTopLane.js +25 -0
- package/src/materialization/facets.js +1 -1
- package/src/materialization/graphicHierarchy.js +5 -0
- package/src/materialization/graphicTranslation.js +2 -0
- package/src/materialization/guides/layout.js +1 -1
- package/src/materialization/guides/resources.js +1 -1
- package/src/materialization/legends.js +1 -1
- package/src/materialization/markClip.js +26 -0
- package/src/materialization/marks/capabilities.js +3 -2
- package/src/materialization/marks/grouping.js +7 -5
- package/src/materialization/marks/index.js +4 -2
- package/src/materialization/marks/policies.js +4 -0
- package/src/materialization/plotDrawOrder.js +44 -0
- package/src/materialization/rect.js +11 -3
- package/src/materialization/scaleGuideDependencies.js +13 -5
- package/src/materialization/selection/items/common.js +1 -1
- package/src/materialization/selection/items/path.js +1 -0
- package/src/materialization/selection/policies/index.js +2 -1
- package/src/materialization/text.js +10 -5
- package/src/mcp/cli.js +0 -0
- package/src/persistence/validation.js +108 -18
- package/src/persistence.js +4 -2
- package/src/renderers/canvas/index.js +16 -0
- package/src/renderers/canvas/isolated.js +11 -1
- package/src/renderers/canvas/native.js +7 -0
- package/src/renderers/canvas/scene.js +66 -0
- package/src/renderers/canvas/text.js +3 -2
- package/src/renderers/svg.js +1 -617
- package/src/renderers/svgSerialization.js +643 -0
- package/src/renderers/transitionScene.js +67 -0
- package/src/scene.js +89 -0
- package/src/selectors/axes.js +1 -1
- package/src/selectors/datasets.js +1 -0
- package/src/selectors/grids.js +9 -0
- package/src/selectors/markClip.js +28 -0
- package/src/selectors/raincloud.js +7 -0
- package/src/version.js +1 -1
- package/types/basic.d.ts +7 -0
- package/types/index.d.ts +8 -0
- package/types/program.d.ts +270 -60
- package/types/scene.d.ts +35 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { materializeMarkClip } from "../../../materialization/markClip.js";
|
|
2
|
+
import { requestedMarkClip, validateMarkClipCoordinate } from "../../../selectors/markClip.js";
|
|
1
3
|
import { TEXT_LABEL_LAYOUT_OPTIONS } from "./layout.js";
|
|
2
4
|
import { action } from "../../../core/action.js";
|
|
3
5
|
import { validateUserId } from "../../../core/identifiers.js";
|
|
4
6
|
import {
|
|
5
7
|
DEFAULT_TEXT_MARK,
|
|
6
|
-
TEXT_MARK_STYLE_OPTIONS
|
|
8
|
+
TEXT_MARK_STYLE_OPTIONS,
|
|
7
9
|
isSourceOwnedText,
|
|
8
10
|
normalizeTextMarkConfig
|
|
9
11
|
} from "../../../grammar/text.js";
|
|
@@ -42,6 +44,7 @@ import { resolveMarkGraphicPlacement } from
|
|
|
42
44
|
"../../../materialization/graphicHierarchy.js";
|
|
43
45
|
import { validateItemMissing } from "../../../grammar/itemMissing.js";
|
|
44
46
|
|
|
47
|
+
const STYLE_OPTIONS = Object.freeze(["clip", ...TEXT_MARK_STYLE_OPTIONS]);
|
|
45
48
|
const CREATE_OPTIONS = Object.freeze(["id", "data", "source", "text", "missing", ...STYLE_OPTIONS]);
|
|
46
49
|
const EDIT_OPTIONS = Object.freeze(["target", "missing", ...STYLE_OPTIONS]);
|
|
47
50
|
const REMATERIALIZE_OPTIONS = Object.freeze(["id", "replayLayout"]);
|
|
@@ -130,6 +133,7 @@ const createTextMark = /* @__PURE__ */ action(
|
|
|
130
133
|
},
|
|
131
134
|
function (args = {}) {
|
|
132
135
|
validateMarkOptions(args, CREATE_OPTIONS, "createTextMark");
|
|
136
|
+
requestedMarkClip(args);
|
|
133
137
|
const id = resolveMarkId(this, args.id, {
|
|
134
138
|
defaultId: "text",
|
|
135
139
|
label: "Text mark id",
|
|
@@ -456,7 +460,7 @@ const rematerializeTextMark = /* @__PURE__ */ action(
|
|
|
456
460
|
? next
|
|
457
461
|
: next.materializeMarkLabelPlacement({ id });
|
|
458
462
|
}
|
|
459
|
-
let next = this.editGraphics({
|
|
463
|
+
let next = materializeMarkClip(this.editGraphics({
|
|
460
464
|
target: id,
|
|
461
465
|
property: "items",
|
|
462
466
|
value: resolveTextGraphicItems(
|
|
@@ -464,7 +468,7 @@ const rematerializeTextMark = /* @__PURE__ */ action(
|
|
|
464
468
|
layer,
|
|
465
469
|
this.markConfigs[id] ?? DEFAULT_TEXT_MARK
|
|
466
470
|
)
|
|
467
|
-
});
|
|
471
|
+
}), id);
|
|
468
472
|
if (replayLayout && next.materializationConfigs.labelLayouts?.[id] !== undefined) {
|
|
469
473
|
return next.materializeLabelLayout({ id, rematerializeBase: false });
|
|
470
474
|
}
|
|
@@ -481,6 +485,7 @@ const editTextMark = /* @__PURE__ */ action(
|
|
|
481
485
|
},
|
|
482
486
|
function (args = {}) {
|
|
483
487
|
validateMarkOptions(args, EDIT_OPTIONS, "editTextMark");
|
|
488
|
+
requestedMarkClip(args);
|
|
484
489
|
if (!["missing", ...STYLE_OPTIONS].some(option => Object.hasOwn(args, option))) {
|
|
485
490
|
throw new Error("editTextMark requires at least one editable property.");
|
|
486
491
|
}
|
|
@@ -494,6 +499,7 @@ const editTextMark = /* @__PURE__ */ action(
|
|
|
494
499
|
if (Object.hasOwn(args, "fill") && layer.encoding?.color !== undefined) {
|
|
495
500
|
throw new Error("Text fill conflicts with its color encoding.");
|
|
496
501
|
}
|
|
502
|
+
validateMarkClipCoordinate(this, layer, args.clip ?? this.markConfigs[layer.id]?.clip);
|
|
497
503
|
const semantic = Object.hasOwn(args, "missing")
|
|
498
504
|
? this.editSemantic({
|
|
499
505
|
property: `layer[${layer.id}].mark.missing`,
|
|
@@ -507,6 +513,7 @@ const editTextMark = /* @__PURE__ */ action(
|
|
|
507
513
|
args,
|
|
508
514
|
semantic.markConfigs[layer.id] ?? DEFAULT_TEXT_MARK
|
|
509
515
|
),
|
|
516
|
+
...requestedMarkClip(args),
|
|
510
517
|
fillExplicit: Object.hasOwn(args, "fill")
|
|
511
518
|
? true
|
|
512
519
|
: semantic.markConfigs[layer.id]?.fillExplicit ?? false
|
|
@@ -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 {
|
|
@@ -15,6 +16,7 @@ import { resolveMarkGraphicPlacement } from
|
|
|
15
16
|
import { resolveRowEncodingValues } from
|
|
16
17
|
"../../../materialization/rowEncoding.js";
|
|
17
18
|
import { findDataset } from "../../../selectors/datasets.js";
|
|
19
|
+
import { validateTickColorChannels } from "../../../grammar/scales/colorConsumers.js";
|
|
18
20
|
import { findLayer } from "../../../selectors/layers.js";
|
|
19
21
|
import { DEFAULT_COLORS } from "../../../theme/defaults.js";
|
|
20
22
|
import {
|
|
@@ -37,7 +39,7 @@ import {
|
|
|
37
39
|
} from "../shared.js";
|
|
38
40
|
|
|
39
41
|
const APPEARANCE_OPTIONS = Object.freeze([
|
|
40
|
-
"length", "stroke", "strokeWidth", "opacity", ...STROKE_STYLE_PROPERTIES
|
|
42
|
+
"clip", "length", "stroke", "strokeWidth", "opacity", ...STROKE_STYLE_PROPERTIES
|
|
41
43
|
]);
|
|
42
44
|
const CREATE_OPTIONS = Object.freeze(["id", "data", "missing", ...APPEARANCE_OPTIONS]);
|
|
43
45
|
const EDIT_OPTIONS = Object.freeze(["target", "missing", ...APPEARANCE_OPTIONS]);
|
|
@@ -74,6 +76,7 @@ function resolveTick(program, requested, operation) {
|
|
|
74
76
|
function validateTickConfig(args, current = DEFAULT_TICK_CONFIG) {
|
|
75
77
|
return {
|
|
76
78
|
...current,
|
|
79
|
+
...requestedMarkClip(args),
|
|
77
80
|
length: Object.hasOwn(args, "length")
|
|
78
81
|
? validatePositiveFinite(args.length, "Tick length")
|
|
79
82
|
: current.length,
|
|
@@ -97,6 +100,7 @@ export const createTickMark = /* @__PURE__ */ action(
|
|
|
97
100
|
},
|
|
98
101
|
function (args = {}) {
|
|
99
102
|
validateMarkOptions(args, CREATE_OPTIONS, "createTickMark");
|
|
103
|
+
requestedMarkClip(args);
|
|
100
104
|
requestedStrokeDetails(args, "createTickMark");
|
|
101
105
|
const id = resolveMarkId(this, args.id, {
|
|
102
106
|
defaultId: "tick",
|
|
@@ -148,6 +152,7 @@ export const editTickMark = /* @__PURE__ */ action(
|
|
|
148
152
|
},
|
|
149
153
|
function (args = {}) {
|
|
150
154
|
validateMarkOptions(args, EDIT_OPTIONS, "editTickMark");
|
|
155
|
+
requestedMarkClip(args);
|
|
151
156
|
requestedStrokeDetails(args, "editTickMark");
|
|
152
157
|
if (!["missing", ...APPEARANCE_OPTIONS].some(property => Object.hasOwn(args, property))) {
|
|
153
158
|
throw new Error(
|
|
@@ -155,11 +160,13 @@ export const editTickMark = /* @__PURE__ */ action(
|
|
|
155
160
|
);
|
|
156
161
|
}
|
|
157
162
|
const layer = resolveTick(this, args.target, "editTickMark");
|
|
163
|
+
if (Object.hasOwn(args, "stroke")) validateTickColorChannels(layer, "stroke");
|
|
158
164
|
if (Object.hasOwn(args, "stroke") && layer.encoding?.stroke !== undefined) {
|
|
159
165
|
throw new Error(
|
|
160
166
|
"editTickMark stroke conflicts with a field encoding; use encodeStroke with value to replace it."
|
|
161
167
|
);
|
|
162
168
|
}
|
|
169
|
+
validateMarkClipCoordinate(this, layer, args.clip ?? this.markConfigs[layer.id]?.clip);
|
|
163
170
|
const semantic = Object.hasOwn(args, "missing")
|
|
164
171
|
? this.editSemantic({
|
|
165
172
|
property: `layer[${layer.id}].mark.missing`,
|
|
@@ -200,6 +207,7 @@ export const rematerializeTickMark = /* @__PURE__ */ action(
|
|
|
200
207
|
if (layer?.mark?.type !== "tick") {
|
|
201
208
|
throw new Error(`Unknown tick mark "${id}".`);
|
|
202
209
|
}
|
|
210
|
+
validateTickColorChannels(layer);
|
|
203
211
|
const graphic = this.graphicSpec.objects[id];
|
|
204
212
|
if (graphic?.type !== "line" || !Array.isArray(graphic.items)) {
|
|
205
213
|
throw new Error(`Tick mark "${id}" requires line collection graphics.`);
|
|
@@ -220,7 +228,8 @@ export const rematerializeTickMark = /* @__PURE__ */ action(
|
|
|
220
228
|
|
|
221
229
|
const x = resolveRowEncodingValues(this, layer, dataset, "x");
|
|
222
230
|
const y = resolveRowEncodingValues(this, layer, dataset, "y");
|
|
223
|
-
const stroke = resolveRowEncodingValues(this, layer, dataset,
|
|
231
|
+
const stroke = resolveRowEncodingValues(this, layer, dataset,
|
|
232
|
+
layer.encoding?.color === undefined ? "stroke" : "color");
|
|
224
233
|
const angles = resolveDirectionValues(dataset.values, layer.encoding?.angle);
|
|
225
234
|
const config = validateTickConfig({}, {
|
|
226
235
|
...DEFAULT_TICK_CONFIG,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { validateGraphicClip } from "../../grammar/schemas/graphicClip.js";
|
|
1
2
|
import { validateGraphicItemLimit } from "../../core/validation.js";
|
|
2
3
|
import { closedAction } from "../../core/action.js";
|
|
3
4
|
import { cloneAndFreeze, freezeOwned, isPlainObject } from "../../core/immutable.js";
|
|
@@ -13,7 +14,8 @@ import { validateConcreteGraphicValue } from
|
|
|
13
14
|
import {
|
|
14
15
|
collectGraphicSubtreeIds,
|
|
15
16
|
findGraphicParent,
|
|
16
|
-
requireGraphic
|
|
17
|
+
requireGraphic,
|
|
18
|
+
resolveGraphicChildOrder
|
|
17
19
|
} from "../../grammar/schemas/graphicTree.js";
|
|
18
20
|
|
|
19
21
|
function setGraphicProperty(properties, property, value) {
|
|
@@ -96,6 +98,7 @@ function editGeneratedItem(owner, itemIndex, property, value) {
|
|
|
96
98
|
const type = item.type ?? owner.type;
|
|
97
99
|
validateGraphicProperty(type, property);
|
|
98
100
|
validateConcreteGraphicValue(type, property, value);
|
|
101
|
+
if (Object.is(item.properties[property], value)) return owner;
|
|
99
102
|
items[itemIndex] = freezeOwned({
|
|
100
103
|
...item,
|
|
101
104
|
properties: setGraphicProperty(item.properties, property, value)
|
|
@@ -126,17 +129,20 @@ function editItems(owner, property, value, id, program) {
|
|
|
126
129
|
`${owner.type}.${property} requires ${owner.items.length} values, received ${value.length}.`
|
|
127
130
|
);
|
|
128
131
|
}
|
|
132
|
+
let changed = false;
|
|
129
133
|
const items = owner.items.map((item, index) => {
|
|
130
134
|
const itemValue = Array.isArray(value) ? value[index] : value;
|
|
131
135
|
const type = item.type ?? owner.type;
|
|
132
136
|
validateGraphicProperty(type, property);
|
|
133
137
|
validateConcreteGraphicValue(type, property, itemValue);
|
|
138
|
+
if (Object.is(item.properties[property], itemValue)) return item;
|
|
139
|
+
changed = true;
|
|
134
140
|
return freezeOwned({
|
|
135
141
|
...item,
|
|
136
142
|
properties: setGraphicProperty(item.properties, property, itemValue)
|
|
137
143
|
});
|
|
138
144
|
});
|
|
139
|
-
return freezeOwned({ ...owner, items: freezeOwned(items) });
|
|
145
|
+
return changed ? freezeOwned({ ...owner, items: freezeOwned(items) }) : owner;
|
|
140
146
|
}
|
|
141
147
|
|
|
142
148
|
function removeGraphicTree(graphicSpec, id) {
|
|
@@ -188,11 +194,27 @@ const editGraphics = /* @__PURE__ */ closedAction(
|
|
|
188
194
|
return this._clone({ graphicSpec: removeGraphicTree(this.graphicSpec, found.id) });
|
|
189
195
|
}
|
|
190
196
|
|
|
197
|
+
if (property === "children") {
|
|
198
|
+
const children = freezeOwned(resolveGraphicChildOrder(this.graphicSpec, target, value));
|
|
199
|
+
const updated = freezeOwned({ ...found.object, children });
|
|
200
|
+
return this._clone({ graphicSpec: freezeOwned({ ...this.graphicSpec,
|
|
201
|
+
objects: freezeOwned({ ...this.graphicSpec.objects, [target]: updated }) }) });
|
|
202
|
+
}
|
|
203
|
+
|
|
191
204
|
const ownerId = found.kind === "item" ? found.ownerId : found.id;
|
|
192
205
|
const owner = found.kind === "item" ? found.owner : found.object;
|
|
193
206
|
if (owner.items !== undefined) validateGraphicItemLimit(owner.items.length, resolveGraphicItemCapacity(this, {
|
|
194
207
|
id: ownerId, label: "Graphic collection length"
|
|
195
208
|
}));
|
|
209
|
+
if (property === "clip") {
|
|
210
|
+
if (found.kind !== "object") throw new Error("Graphic clip requires a named owner, not a generated item.");
|
|
211
|
+
if (owner.type === "canvas") validateGraphicClip(value, owner.type);
|
|
212
|
+
if (value !== false) validateGraphicClip(value, owner.type);
|
|
213
|
+
const {clip: previous, ...rest} = owner;
|
|
214
|
+
const updated = value === false ? freezeOwned(rest) : freezeOwned({...rest, clip: cloneAndFreeze(value)});
|
|
215
|
+
return this._clone({graphicSpec: freezeOwned({...this.graphicSpec,
|
|
216
|
+
objects: freezeOwned({...this.graphicSpec.objects, [ownerId]: updated})})});
|
|
217
|
+
}
|
|
196
218
|
const replacesDrawableItems =
|
|
197
219
|
found.kind === "object" && property === "items" &&
|
|
198
220
|
owner.items !== undefined && owner.type !== "collection";
|
|
@@ -203,7 +225,8 @@ const editGraphics = /* @__PURE__ */ closedAction(
|
|
|
203
225
|
: owner.type, property);
|
|
204
226
|
let updated;
|
|
205
227
|
if (replacesDrawableItems) {
|
|
206
|
-
updated = replaceDrawableItems(value, ownerId, owner.type, this)
|
|
228
|
+
updated = freezeOwned({...replaceDrawableItems(value, ownerId, owner.type, this),
|
|
229
|
+
...(owner.clip === undefined ? {} : {clip: owner.clip})});
|
|
207
230
|
} else if (found.kind === "item") {
|
|
208
231
|
if (validatedProperty === "length" || validatedProperty === "items") {
|
|
209
232
|
throw new Error(`${validatedProperty} can only target an owning graphic.`);
|
|
@@ -224,6 +247,7 @@ const editGraphics = /* @__PURE__ */ closedAction(
|
|
|
224
247
|
validateGraphicItemLimit(value, resolveGraphicItemCapacity(this, { id: ownerId, label: "Graphic collection length" }));
|
|
225
248
|
updated = freezeOwned({
|
|
226
249
|
type: owner.type,
|
|
250
|
+
...(owner.clip === undefined ? {} : {clip: owner.clip}),
|
|
227
251
|
items: freezeOwned(Array.from({ length: value }, (_, index) => freezeOwned({
|
|
228
252
|
id: `${ownerId}:${index}`,
|
|
229
253
|
properties: index === 0 ? owner.properties : freezeOwned({})
|
|
@@ -236,6 +260,7 @@ const editGraphics = /* @__PURE__ */ closedAction(
|
|
|
236
260
|
properties: setGraphicProperty(owner.properties, validatedProperty, value)
|
|
237
261
|
});
|
|
238
262
|
}
|
|
263
|
+
if (updated === owner) return this;
|
|
239
264
|
return this._clone({
|
|
240
265
|
graphicSpec: freezeOwned({
|
|
241
266
|
...this.graphicSpec,
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { createSemanticValueValidator } from "./semanticValidation/index.js";
|
|
2
2
|
import { isPlainObject } from "../../core/immutable.js";
|
|
3
3
|
import { validateBin2DTransform } from "../../grammar/bin2d.js";
|
|
4
|
+
import { validateFlattenTransform } from "../../grammar/flatten.js";
|
|
5
|
+
import {validateLookupTransform} from "../../grammar/lookup.js";
|
|
4
6
|
import { registerSemanticPrimitiveAction } from "./semantic.js";
|
|
5
7
|
import { registerEditGraphicsAction } from "./editGraphics.js";
|
|
6
8
|
import { registerCreateGraphicsAction } from "./createGraphics.js";
|
|
@@ -12,6 +14,13 @@ function validateBasicDatasetTransforms(value) {
|
|
|
12
14
|
"Dataset transform must contain exactly one plain object."
|
|
13
15
|
);
|
|
14
16
|
}
|
|
17
|
+
if (value[0].type === "flatten") {
|
|
18
|
+
validateFlattenTransform(value[0]);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if(value[0].type==="lookup"){
|
|
22
|
+
validateLookupTransform(value[0]);return;
|
|
23
|
+
}
|
|
15
24
|
if (value[0].type !== "bin2d") {
|
|
16
25
|
throw new Error(`Unsupported dataset transform "${value[0].type}".`);
|
|
17
26
|
}
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
removeOwnedPath
|
|
8
8
|
} from "../../core/immutable.js";
|
|
9
9
|
import { parseSemanticPath } from "../../grammar/schemas/semanticPath.js";
|
|
10
|
-
import { deriveTransformSchema, inferDatasetSchema, validateRowsAgainstSchema } from "../../grammar/datasetSchema.js";
|
|
10
|
+
import { deriveTransformSchema, inferDatasetSchema, validateRowsAgainstSchema,datasetSchemaContext } from "../../grammar/datasetSchema.js";
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
const CONTEXT_KEYS = Object.freeze({
|
|
@@ -57,7 +57,7 @@ function updateEntity(spec, parsed, value) {
|
|
|
57
57
|
source.schema,
|
|
58
58
|
value[0],
|
|
59
59
|
undefined,
|
|
60
|
-
|
|
60
|
+
datasetSchemaContext(source,value[0],parsed.id,id=>collection.find(d=>d.id===id))
|
|
61
61
|
));
|
|
62
62
|
}
|
|
63
63
|
}
|
|
@@ -70,11 +70,8 @@ function updateEntity(spec, parsed, value) {
|
|
|
70
70
|
? undefined
|
|
71
71
|
: collection.find(dataset => dataset.id === current.source);
|
|
72
72
|
const schema = source?.schema !== undefined && current.transform?.length === 1
|
|
73
|
-
? deriveTransformSchema(source.schema, current.transform[0], value,
|
|
74
|
-
|
|
75
|
-
sourceTransform: source.transform?.[0],
|
|
76
|
-
ownerId: parsed.id
|
|
77
|
-
})
|
|
73
|
+
? deriveTransformSchema(source.schema, current.transform[0], value,
|
|
74
|
+
datasetSchemaContext(source,current.transform[0],parsed.id,id=>collection.find(d=>d.id===id)))
|
|
78
75
|
: inferDatasetSchema(value);
|
|
79
76
|
validateRowsAgainstSchema(value, schema, `Dataset "${parsed.id}"`);
|
|
80
77
|
updated = setNestedProperty(updated, ["schema"], schema);
|
|
@@ -207,6 +204,15 @@ export function withRematerializedDerivedDataset(program, {
|
|
|
207
204
|
// replaying their canonical primitive owners. Keep that speculative clone in
|
|
208
205
|
// the primitive boundary and preserve the caller's layer for later dependency
|
|
209
206
|
// and guide reconciliation.
|
|
207
|
+
export function withPreviewLayerEncodings(program, { id, encodings }) {
|
|
208
|
+
return program._clone({ semanticSpec: {
|
|
209
|
+
...program.semanticSpec,
|
|
210
|
+
layers: program.semanticSpec.layers.map(layer => layer.id === id
|
|
211
|
+
? { ...layer, encoding: { ...layer.encoding, ...encodings } }
|
|
212
|
+
: layer)
|
|
213
|
+
} });
|
|
214
|
+
}
|
|
215
|
+
|
|
210
216
|
export function withoutPreviewLayerEncodings(program, { id, channels }) {
|
|
211
217
|
const removed = new Set(channels);
|
|
212
218
|
const semanticSpec = {
|
|
@@ -21,6 +21,8 @@ import { normalizeStatisticalWeight } from
|
|
|
21
21
|
"../../../grammar/weightedStatistics.js";
|
|
22
22
|
import { ITEM_MISSING_MARK_TYPES, validateItemMissing } from
|
|
23
23
|
"../../../grammar/itemMissing.js";
|
|
24
|
+
import { isIndependentText, validateTextOffsetEncoding } from "../../../grammar/text.js";
|
|
25
|
+
import { validateLineMissing, validateLineMissingScope } from "../../../grammar/lineMissing.js";
|
|
24
26
|
|
|
25
27
|
function validateLayerSource(program, parsed, value, sourceMarkTypes) {
|
|
26
28
|
validateUserId(value, "Layer source id");
|
|
@@ -51,6 +53,20 @@ export function validateLayerSemanticValue(
|
|
|
51
53
|
} = {}
|
|
52
54
|
) {
|
|
53
55
|
const property = parsed.path.join(".");
|
|
56
|
+
if (/^encoding\.(dx|dy)(\.|$)/.test(property)) {
|
|
57
|
+
if (!isIndependentText(findLayer(program, parsed.id))) {
|
|
58
|
+
throw new Error("Numeric text offsets require independent Text marks.");
|
|
59
|
+
}
|
|
60
|
+
const channel = parsed.path[1];
|
|
61
|
+
if (parsed.path.length === 2) validateTextOffsetEncoding(value, channel);
|
|
62
|
+
else if (property.endsWith(".fieldType") && value !== "quantitative") {
|
|
63
|
+
throw new Error(`Text ${channel} field type must be quantitative.`);
|
|
64
|
+
} else if (property.endsWith(".datum") && !Number.isFinite(value)) {
|
|
65
|
+
throw new TypeError(`Text ${channel} datum must be finite logical pixels.`);
|
|
66
|
+
} else if (property.endsWith(".field")) {
|
|
67
|
+
validateNonEmptySemanticString(value, `Text ${channel} field`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
54
70
|
if (property === "mark.type" && !MARK_TYPES.includes(value)) {
|
|
55
71
|
throw new Error(`Unknown mark type "${value}".`);
|
|
56
72
|
}
|
|
@@ -60,6 +76,10 @@ export function validateLayerSemanticValue(
|
|
|
60
76
|
if (!["error", "break"].includes(value)) {
|
|
61
77
|
throw new Error(`Unsupported area missing policy "${value}".`);
|
|
62
78
|
}
|
|
79
|
+
} else if (markType === "line") {
|
|
80
|
+
validateLineMissing(value);
|
|
81
|
+
const layer = findLayer(program, parsed.id);
|
|
82
|
+
validateLineMissingScope({ ...layer, mark: { ...layer.mark, missing: value } });
|
|
63
83
|
} else if (ITEM_MISSING_MARK_TYPES.includes(markType)) {
|
|
64
84
|
validateItemMissing(value, `${markType} missing`);
|
|
65
85
|
} else {
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
validateSemanticScaleType
|
|
9
9
|
} from "../../../grammar/scales/index.js";
|
|
10
10
|
import { findSemanticScale } from "../../../selectors/scales.js";
|
|
11
|
+
import { normalizeScaleNice } from "../../../grammar/scales/continuous.js";
|
|
11
12
|
import { findScaleConsumers } from "../../scales/consumers/index.js";
|
|
12
13
|
|
|
13
14
|
function isOffsetScale(program, id, existing) {
|
|
@@ -51,6 +52,7 @@ export function validateScaleSemanticValue(program, parsed, value) {
|
|
|
51
52
|
["paddingInner", "paddingOuter", "align"].includes(owned)
|
|
52
53
|
) continue;
|
|
53
54
|
validateScalePropertyForType(value, owned);
|
|
55
|
+
if (owned === "nice") normalizeScaleNice(value, existing[owned]);
|
|
54
56
|
}
|
|
55
57
|
return;
|
|
56
58
|
}
|
|
@@ -62,7 +64,12 @@ export function validateScaleSemanticValue(program, parsed, value) {
|
|
|
62
64
|
return;
|
|
63
65
|
}
|
|
64
66
|
if (property === "range") return validateSemanticScaleRange(value);
|
|
65
|
-
if (
|
|
67
|
+
if (property === "nice") {
|
|
68
|
+
normalizeScaleNice(existing?.type, value);
|
|
69
|
+
validateOwnedProperty(program, parsed.id, existing, property);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (["zero", "clamp", "reverse"].includes(property)) {
|
|
66
73
|
if (typeof value !== "boolean") {
|
|
67
74
|
throw new TypeError(`Scale ${property} must be a boolean.`);
|
|
68
75
|
}
|
|
@@ -79,7 +79,7 @@ const DEFINITIONS = Object.freeze({
|
|
|
79
79
|
}),
|
|
80
80
|
editStrokeDashScale: Object.freeze({
|
|
81
81
|
channel: "strokeDash",
|
|
82
|
-
options: Object.freeze(["type", "domain", "range", "emptyDomain"])
|
|
82
|
+
options: Object.freeze(["type", "domain", "range", "emptyDomain", "unknown"])
|
|
83
83
|
})
|
|
84
84
|
});
|
|
85
85
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { isSourceOwnedText } from "../../../grammar/text.js";
|
|
2
2
|
import { readSeriesIdentity, validatePathSeriesAppearance } from "../../../grammar/pathSeries.js";
|
|
3
3
|
import { readAreaEndpoint } from "../../../grammar/areaEndpoints.js";
|
|
4
|
-
import {
|
|
4
|
+
import { readLinePosition } from "../../../grammar/lineMissing.js";
|
|
5
|
+
import { readNominalField, readScaleField } from "../../../grammar/scales/index.js";
|
|
6
|
+
import { readCategoricalLineColor, validateCategoricalColorConsumer } from "../../../grammar/scales/colorConsumers.js";
|
|
7
|
+
import { readArcColorValues } from "../../../grammar/arcs.js";
|
|
5
8
|
import { findDataset } from "../../../selectors/datasets.js";
|
|
6
9
|
import { requireSemanticScale } from "../../../selectors/scales.js";
|
|
7
10
|
import { SCALED_ENCODING_CHANNELS } from "../../../core/vocabulary.js";
|
|
@@ -56,6 +59,21 @@ export function readConsumerFieldValues(
|
|
|
56
59
|
scale = findScale(program, consumer.encoding.scale)
|
|
57
60
|
) {
|
|
58
61
|
const { field, fieldType, temporalUnit } = consumer.encoding;
|
|
62
|
+
if (consumer.layer.mark.type === "line" && consumer.layer.mark.missing === "break" &&
|
|
63
|
+
["x", "y"].includes(consumer.channel)) {
|
|
64
|
+
return readLinePosition(dataset.values, consumer.encoding).filter(value => value !== null);
|
|
65
|
+
}
|
|
66
|
+
if (consumer.channel === "strokeDash") {
|
|
67
|
+
validateCategoricalColorConsumer(consumer.layer, consumer.encoding, scale, "strokeDash");
|
|
68
|
+
return readNominalField(dataset.values, field);
|
|
69
|
+
}
|
|
70
|
+
if (consumer.channel === "color" && ["nominal", "ordinal"].includes(fieldType) &&
|
|
71
|
+
validateCategoricalColorConsumer(consumer.layer, consumer.encoding, scale)) {
|
|
72
|
+
return readCategoricalLineColor(dataset.values, field);
|
|
73
|
+
}
|
|
74
|
+
if (consumer.layer.mark.type === "arc" && consumer.channel === "color") {
|
|
75
|
+
return readArcColorValues(dataset.values, consumer.layer);
|
|
76
|
+
}
|
|
59
77
|
if (consumer.layer.mark.type === "bar" && consumer.layer.encoding?.group !== undefined && ["xOffset", "yOffset"].includes(consumer.channel)) {
|
|
60
78
|
return readSeriesIdentity(dataset.values, consumer.layer).values;
|
|
61
79
|
}
|
|
@@ -19,13 +19,13 @@ import { findScale } from "./common.js";
|
|
|
19
19
|
|
|
20
20
|
function lineDerivationOptions(program, consumer, dataset) {
|
|
21
21
|
const x = consumer.layer.encoding?.x;
|
|
22
|
-
if (x?.bin === undefined) return
|
|
22
|
+
if (x?.bin === undefined) return { scales: program.semanticSpec.scales };
|
|
23
23
|
const bins = resolveLineBins(
|
|
24
24
|
dataset.values,
|
|
25
25
|
consumer.layer,
|
|
26
26
|
findScale(program, x.scale)
|
|
27
27
|
);
|
|
28
|
-
return { xBinBoundaries: bins.boundaries };
|
|
28
|
+
return { xBinBoundaries: bins.boundaries, scales: program.semanticSpec.scales };
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export function resolveMarkFamilyConsumerValues(program, consumer, dataset) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { applyItemMissingPolicy } from "../../../grammar/itemMissing.js";
|
|
1
2
|
import { readSeriesIdentity } from "../../../grammar/pathSeries.js";
|
|
2
3
|
import { deriveAreaSeries } from "../../../grammar/areaSeries.js";
|
|
3
4
|
import { deriveBarAggregates } from "../../../grammar/bars/aggregate.js";
|
|
@@ -44,7 +45,7 @@ export function resolveHistogramCountValues(program, consumer) {
|
|
|
44
45
|
`Histogram mark "${consumer.layer.id}" requires an existing dataset.`
|
|
45
46
|
);
|
|
46
47
|
}
|
|
47
|
-
const input = resolveHistogramInput(dataset, xEncoding);
|
|
48
|
+
const input = resolveHistogramInput(dataset, xEncoding, consumer.layer.encoding.y);
|
|
48
49
|
const xValues = input.values;
|
|
49
50
|
const bins = resolveHistogramBins({
|
|
50
51
|
values: xValues,
|
|
@@ -63,10 +64,10 @@ export function resolveHistogramCountValues(program, consumer) {
|
|
|
63
64
|
|
|
64
65
|
function resolveHistogramPartitions(program, consumer) {
|
|
65
66
|
const layer = consumer.layer;
|
|
66
|
-
const dataset = findDataset(program, layer.data);
|
|
67
|
+
const dataset = applyItemMissingPolicy(layer, findDataset(program, layer.data));
|
|
67
68
|
const xEncoding = layer.encoding.x;
|
|
68
69
|
const xScale = findScale(program, xEncoding.scale);
|
|
69
|
-
const input = resolveHistogramInput(dataset, xEncoding);
|
|
70
|
+
const input = resolveHistogramInput(dataset, xEncoding, consumer.layer.encoding.y);
|
|
70
71
|
const xValues = input.values;
|
|
71
72
|
const bins = resolveHistogramBins({
|
|
72
73
|
values: xValues,
|
|
@@ -35,6 +35,17 @@ const EDITABLE = Object.freeze(
|
|
|
35
35
|
);
|
|
36
36
|
const REQUESTED_CHANGES = Object.freeze(OPTIONS.filter(option => option !== "id"));
|
|
37
37
|
|
|
38
|
+
// Encoding assignment reuses the wrapped owner without exposing Full editors in Basic.
|
|
39
|
+
export function editScaleForEncoding(program, args) {
|
|
40
|
+
const available = program.editScale;
|
|
41
|
+
if (typeof available === "function") return available.call(program, args);
|
|
42
|
+
const existing = requireSemanticScale(program, args.id);
|
|
43
|
+
if (args.type !== undefined && args.type !== existing.type) {
|
|
44
|
+
throw new Error("Color scale type transitions require the Full ChartProgram; use a new scale id in Basic.");
|
|
45
|
+
}
|
|
46
|
+
return editScale.call(program, args);
|
|
47
|
+
}
|
|
48
|
+
|
|
38
49
|
function resolveScaleId(program, requested) {
|
|
39
50
|
if (requested !== undefined) {
|
|
40
51
|
const id = validateUserId(requested, "Scale id");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { validateContinuousColorConsumer } from "../../grammar/scales/colorConsumers.js";
|
|
1
|
+
import { validateCategoricalColorConsumer, validateContinuousColorConsumer } from "../../grammar/scales/colorConsumers.js";
|
|
2
2
|
import {
|
|
3
3
|
hasOrdinalDomain,
|
|
4
4
|
isContinuousColorScaleType,
|
|
@@ -249,8 +249,10 @@ function normalizeDefinition(program, scale, channel, consumers, patch) {
|
|
|
249
249
|
? normalizedPatch.unknown
|
|
250
250
|
: typeChanged ? undefined : scale.unknown;
|
|
251
251
|
if (unknown !== undefined) {
|
|
252
|
-
|
|
253
|
-
|
|
252
|
+
for (const consumer of consumers) {
|
|
253
|
+
if (consumer.layer.mark?.type !== "point") {
|
|
254
|
+
validateCategoricalColorConsumer(consumer.layer, consumer.encoding, { ...definition, unknown }, consumer.channel);
|
|
255
|
+
}
|
|
254
256
|
}
|
|
255
257
|
definition.unknown = consumers.length === 0
|
|
256
258
|
? unknown
|
|
@@ -42,7 +42,8 @@ function resolveScalePreviewAtBounds(program, id, bounds) {
|
|
|
42
42
|
const valuesByConsumer = consumers.map(consumer => {
|
|
43
43
|
if (
|
|
44
44
|
program.markConfigs?.[consumer.layer.id]?.markFilter?.empty === true ||
|
|
45
|
-
program.markConfigs?.[consumer.layer.id]?.statisticalReference !== undefined
|
|
45
|
+
(program.markConfigs?.[consumer.layer.id]?.statisticalReference !== undefined &&
|
|
46
|
+
["x", "y", "x2", "y2"].includes(consumer.channel))
|
|
46
47
|
) {
|
|
47
48
|
return {
|
|
48
49
|
consumer,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { editScaleForEncoding } from "./edit.js";
|
|
1
2
|
import { closedAction } from "../../core/action.js";
|
|
2
3
|
|
|
3
4
|
import { findSemanticScale } from "../../selectors/scales.js";
|
|
@@ -24,10 +25,7 @@ export const setQuantitativeColorScale = /* @__PURE__ */ closedAction(
|
|
|
24
25
|
}
|
|
25
26
|
const existing = findSemanticScale(this, args.id);
|
|
26
27
|
if (existing !== undefined && existing.type !== args.type) {
|
|
27
|
-
|
|
28
|
-
throw new Error("Color scale type transitions require the Full ChartProgram; use a new scale id in Basic.");
|
|
29
|
-
}
|
|
30
|
-
return this.editScale(args);
|
|
28
|
+
return editScaleForEncoding(this, args);
|
|
31
29
|
}
|
|
32
30
|
let next = this;
|
|
33
31
|
for (const property of ["whitePoint", "gamma"]) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { action, closedAction } from "../../core/action.js";
|
|
2
2
|
import { validateUserId } from "../../core/identifiers.js";
|
|
3
3
|
import { isPlainObject } from "../../core/immutable.js";
|
|
4
|
-
import { validateKeys } from "../../core/validation.js";
|
|
4
|
+
import { validateKeys, validateWorkLimit } from "../../core/validation.js";
|
|
5
|
+
import { validatePointShape } from "../../grammar/pointShapes.js";
|
|
5
6
|
import { collectResourceReferences } from "../../core/resourceReferences.js";
|
|
6
7
|
import { findLayer, resolveEligibleLayer } from "../../selectors/layers.js";
|
|
7
8
|
import { isSourceOwnedText } from "../../grammar/text.js";
|
|
@@ -369,6 +370,14 @@ export const applyPointHighlight = /* @__PURE__ */ closedAction(
|
|
|
369
370
|
throw new Error("applyPointHighlight requires a point selection.");
|
|
370
371
|
}
|
|
371
372
|
if (keys.length === 0) return this;
|
|
373
|
+
if (isPlainObject(args.style.shape)) {
|
|
374
|
+
const shape = validatePointShape(args.style.shape);
|
|
375
|
+
const { selected, items } = selectedGraphicItems(this, resolved, keys);
|
|
376
|
+
validateWorkLimit(items.reduce((sum, { key, child }) => sum +
|
|
377
|
+
(selected.has(key) ? shape.polygon.length + 1
|
|
378
|
+
: child.type === "path" ? child.properties.commands.length : 0), 0),
|
|
379
|
+
"Point polygon highlight");
|
|
380
|
+
}
|
|
372
381
|
return editSelectedItems(this, resolved, keys, item =>
|
|
373
382
|
transformPointHighlightChild(item, args.style)
|
|
374
383
|
);
|