ggaction 0.0.18 → 0.0.19
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 +50 -0
- package/README.md +6 -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 +1 -1
- package/src/actions/canvas/fitting.js +6 -2
- package/src/actions/charts/heatmap.js +4 -3
- package/src/actions/data/derived.js +11 -1
- package/src/actions/data/edit.js +2 -0
- package/src/actions/data/index.js +4 -0
- package/src/actions/data/regression.js +24 -16
- package/src/actions/data/regressionStatistics.js +73 -0
- package/src/actions/data/shared.js +5 -2
- package/src/actions/distributions/revision.js +24 -18
- package/src/actions/encodings/remove.js +11 -6
- package/src/actions/encodings/shared.js +26 -24
- package/src/actions/facets/actions.js +18 -7
- package/src/actions/facets/guides.js +2 -1
- package/src/actions/guides/axes/axes.js +30 -11
- package/src/actions/guides/axes/axis.js +58 -8
- package/src/actions/guides/axes/components.js +13 -13
- package/src/actions/guides/axes/edit.js +36 -24
- package/src/actions/guides/axes/labels.js +37 -27
- package/src/actions/guides/axes/lines.js +22 -20
- package/src/actions/guides/axes/remove.js +10 -6
- package/src/actions/guides/axes/tickGroups.js +8 -7
- package/src/actions/guides/axes/ticks.js +31 -22
- package/src/actions/guides/axes/titles.js +53 -60
- package/src/actions/guides/facadeAxes.js +33 -24
- package/src/actions/guides/facadeLegend.js +3 -3
- package/src/actions/guides/grids/grid.js +1 -1
- package/src/actions/guides/grids/resolve.js +48 -51
- package/src/actions/guides/legends/blocks.js +43 -19
- package/src/actions/guides/legends/categorical/actions.js +30 -7
- package/src/actions/guides/legends/categorical/components.js +3 -10
- package/src/actions/guides/legends/categorical/index.js +2 -0
- package/src/actions/guides/legends/categorical/layout.js +9 -13
- package/src/actions/guides/legends/categorical/options.js +8 -2
- package/src/actions/guides/legends/categorical/recipes.js +7 -3
- package/src/actions/guides/legends/categorical/resolve.js +9 -2
- package/src/actions/guides/legends/categorical/symbols.js +22 -8
- package/src/actions/guides/legends/colorSize.js +110 -0
- package/src/actions/guides/legends/combine.js +37 -0
- package/src/actions/guides/legends/continuous/colorSymbols.js +1 -1
- package/src/actions/guides/legends/continuous/common.js +1 -1
- package/src/actions/guides/legends/continuous/gradient.js +27 -13
- package/src/actions/guides/legends/continuous/opacity.js +16 -11
- package/src/actions/guides/legends/creation.js +2 -0
- package/src/actions/guides/legends/edit.js +1 -1
- package/src/actions/guides/legends/focused.js +6 -5
- package/src/actions/guides/legends/lane.js +1 -1
- package/src/actions/guides/legends/lifecycle.js +2 -1
- package/src/actions/guides/legends/remove.js +6 -3
- package/src/actions/guides/legends/size.js +16 -6
- package/src/actions/guides/legends/strokeWidth.js +2 -0
- package/src/actions/guides/legends/target.js +2 -79
- package/src/actions/guides/legends/transition.js +24 -5
- package/src/actions/guides/tickValues.js +8 -5
- package/src/actions/marks/bar/edit.js +23 -12
- package/src/actions/marks/bar/materialize.js +6 -1
- package/src/actions/marks/point/materialize.js +5 -1
- package/src/actions/marks/remove.js +10 -10
- package/src/actions/primitives/createGraphics.js +3 -2
- package/src/actions/primitives/editGraphics.js +15 -11
- package/src/actions/primitives/graphicProperties.js +1 -6
- package/src/actions/primitives/semanticAction.js +27 -1
- package/src/actions/primitives/semanticValidation/guide.js +11 -1
- package/src/actions/primitives/semanticValidation/layer.js +4 -0
- package/src/actions/regression/edit.js +15 -3
- package/src/actions/scales/channels.js +2 -2
- package/src/actions/scales/create.js +3 -3
- package/src/actions/scales/definitions.js +1 -1
- package/src/actions/scales/edit.js +1 -1
- package/src/actions/scales/editPolicy.js +3 -0
- package/src/actions/scales/patch.js +1 -1
- package/src/actions/scales/quantitativeColor.js +8 -3
- package/src/actions/theme/reconcile.js +50 -23
- package/src/core/compositionState.js +2 -2
- package/src/core/graphicProperties.js +1 -0
- package/src/core/programState.js +4 -0
- package/src/core/resourceReferences.js +2 -2
- package/src/core/validation.js +9 -0
- package/src/core/vocabulary.js +3 -0
- package/src/grammar/axisTextPlacement.js +1 -0
- package/src/grammar/colorSizeLegend.js +39 -0
- package/src/grammar/computed.js +23 -1
- package/src/grammar/datasetSchema.js +10 -2
- package/src/grammar/displayLabels.js +8 -0
- package/src/grammar/facets/guides.js +54 -31
- package/src/grammar/facets/legendIntent.js +65 -0
- package/src/grammar/guideDash.js +1 -0
- package/src/grammar/legendBlocks.js +1 -0
- package/src/grammar/legendBorder.js +9 -0
- package/src/grammar/legendClip.js +19 -0
- package/src/grammar/legendCombinations.js +45 -0
- package/src/grammar/legendGradient.js +9 -0
- package/src/grammar/legendGroups.js +1 -1
- package/src/grammar/legendOpacity.js +6 -0
- package/src/grammar/pointShapes.js +16 -2
- package/src/grammar/regression/derive.js +9 -1
- package/src/grammar/regression/models.js +60 -0
- package/src/grammar/regression/parameters.js +9 -1
- package/src/grammar/regression/statistics.js +64 -0
- package/src/grammar/scales/color.js +1 -1
- package/src/grammar/scales/colorConsumers.js +1 -1
- package/src/grammar/scales/definition.js +1 -1
- package/src/grammar/scales/types.js +1 -1
- package/src/grammar/schemas/concreteGraphic.js +3 -0
- package/src/grammar/schemas/graphic.js +3 -0
- package/src/grammar/schemas/graphicBounds.js +31 -7
- package/src/grammar/schemas/semanticPath.js +17 -2
- package/src/grammar/summary.js +1 -1
- package/src/grammar/timeUnit.js +6 -4
- package/src/grammar/transformTopology.js +1 -0
- package/src/grammar/transforms.js +11 -1
- package/src/inspectionDescriptors.js +1 -1
- package/src/layout/guideCollisions.js +9 -1
- package/src/layout/legendGroup.js +1 -1
- package/src/materialization/compositionSnapshot.js +2 -7
- package/src/materialization/coordinateBounds.js +17 -4
- package/src/materialization/facetGuides/edit.js +30 -0
- package/src/materialization/facetGuides/layout.js +1 -1
- package/src/materialization/facetGuides/owner.js +125 -0
- package/src/materialization/facetGuides/ownerLayout.js +71 -0
- package/src/materialization/facetGuides/placement.js +52 -6
- package/src/materialization/facetGuides/preparation.js +7 -0
- package/src/materialization/facets.js +1 -1
- package/src/materialization/graphicHierarchy.js +5 -1
- package/src/materialization/graphicTranslation.js +73 -0
- package/src/materialization/guides/layout.js +1 -1
- package/src/materialization/guides/resources.js +1 -1
- package/src/materialization/legendBorder.js +28 -0
- package/src/materialization/legendClip.js +76 -0
- package/src/materialization/legendGroups.js +1 -1
- package/src/materialization/legends.js +1 -1
- package/src/materialization/scaleGuideDependencies.js +13 -14
- package/src/materialization/scales/map.js +3 -0
- package/src/materialization/scales/resolve.js +2 -0
- package/src/materialization/typography.js +10 -2
- package/src/persistence/validation.js +174 -1
- package/src/persistence.js +1 -1
- package/src/renderers/canvas/index.js +20 -10
- package/src/renderers/canvas/isolated.js +166 -0
- package/src/renderers/canvas/limits.js +3 -0
- package/src/renderers/canvas/rect.js +1 -1
- package/src/renderers/pdf.js +2 -2
- package/src/renderers/png.js +2 -2
- package/src/renderers/svg.js +10 -3
- package/src/selectors/axes.js +1 -0
- package/src/selectors/graphicCapacity.js +38 -0
- package/src/version.js +1 -1
- package/types/basic.d.ts +2 -0
- package/types/index.d.ts +5 -0
- package/types/program.d.ts +206 -61
|
@@ -18,20 +18,20 @@ import { validateFillPaint } from "../../../grammar/paint.js";
|
|
|
18
18
|
import { validateItemMissing } from "../../../grammar/itemMissing.js";
|
|
19
19
|
|
|
20
20
|
const EDIT_OPTIONS = Object.freeze([
|
|
21
|
-
"target", "missing", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
|
|
21
|
+
"target", "missing", "blend", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
|
|
22
22
|
...STROKE_STYLE_PROPERTIES
|
|
23
23
|
]);
|
|
24
24
|
|
|
25
25
|
export const editBarMark = /* @__PURE__ */ action(
|
|
26
26
|
{
|
|
27
27
|
op: "editBarMark",
|
|
28
|
-
description: "Edit whole-bar fill, opacity, and
|
|
28
|
+
description: "Edit whole-bar fill, opacity, outline, and compositing appearance."
|
|
29
29
|
},
|
|
30
30
|
function (args = {}) {
|
|
31
31
|
validateMarkOptions(args, EDIT_OPTIONS, "editBarMark");
|
|
32
32
|
const styleDetails = requestedRectStyleDetails(args, "editBarMark");
|
|
33
33
|
const changes = [
|
|
34
|
-
"missing", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
|
|
34
|
+
"missing", "blend", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
|
|
35
35
|
...STROKE_STYLE_PROPERTIES
|
|
36
36
|
];
|
|
37
37
|
if (!changes.some(key => Object.hasOwn(args, key))) {
|
|
@@ -66,13 +66,12 @@ export const editBarMark = /* @__PURE__ */ action(
|
|
|
66
66
|
);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const config = { ...semantic.markConfigs[layer.id] };
|
|
69
|
+
if (Object.hasOwn(args, "blend") && !["normal", "difference"].includes(args.blend)) {
|
|
70
|
+
throw new Error("Bar blend must be normal or difference.");
|
|
71
|
+
}
|
|
72
|
+
const missing = Object.hasOwn(args, "missing")
|
|
73
|
+
? validateItemMissing(args.missing, "Bar missing") : undefined;
|
|
74
|
+
const config = { ...this.markConfigs[layer.id] };
|
|
76
75
|
const appearance = { ...config.barAppearance };
|
|
77
76
|
Object.assign(appearance, styleDetails);
|
|
78
77
|
if (Object.hasOwn(args, "fill")) {
|
|
@@ -106,10 +105,22 @@ export const editBarMark = /* @__PURE__ */ action(
|
|
|
106
105
|
);
|
|
107
106
|
}
|
|
108
107
|
|
|
109
|
-
|
|
108
|
+
let semantic = missing === undefined ? this : this.editSemantic({
|
|
109
|
+
property: `layer[${layer.id}].mark.missing`, value: missing
|
|
110
|
+
});
|
|
111
|
+
if (Object.hasOwn(args, "blend")) {
|
|
112
|
+
if (args.blend === "difference") {
|
|
113
|
+
semantic = semantic.editSemantic({property: `layer[${layer.id}].mark.blend`, value: "difference"});
|
|
114
|
+
} else if (layer.mark.blend !== undefined) {
|
|
115
|
+
semantic = semantic.editSemantic({property: `layer[${layer.id}].mark.blend`, remove: true});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const editsAppearance = changes.some(key => key !== "missing" && key !== "blend" &&
|
|
119
|
+
Object.hasOwn(args, key));
|
|
120
|
+
const next = editsAppearance ? semantic._withMarkConfig(layer.id, {
|
|
110
121
|
...config,
|
|
111
122
|
barAppearance: appearance
|
|
112
|
-
});
|
|
123
|
+
}) : semantic;
|
|
113
124
|
const materialized = canMaterializeBar(next, layer)
|
|
114
125
|
? next.rematerializeBarMark({ id: layer.id })
|
|
115
126
|
: next;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { findLayer } from "../../../selectors/layers.js";
|
|
1
2
|
import { editGraphicProperties } from "../../primitives/graphicProperties.js";
|
|
2
3
|
import { action } from "../../../core/action.js";
|
|
3
4
|
import { validateUserId } from "../../../core/identifiers.js";
|
|
@@ -20,9 +21,13 @@ const REMATERIALIZE_OPTIONS = Object.freeze(["id", "scales"]);
|
|
|
20
21
|
|
|
21
22
|
function editRectangles(program, id, rectangles) {
|
|
22
23
|
const appearance = program.markConfigs[id]?.barAppearance ?? {};
|
|
24
|
+
const blend = findLayer(program, id)?.mark?.blend;
|
|
25
|
+
if (blend !== undefined) rectangles = rectangles.map(rect => ({...rect, blend}));
|
|
23
26
|
const hasShapeStyle = RECT_STYLE_PROPERTIES
|
|
24
27
|
.some(property => Object.hasOwn(appearance, property));
|
|
25
|
-
|
|
28
|
+
const previousBlend = program.graphicSpec.objects[id]?.items?.some(item =>
|
|
29
|
+
item.properties?.blend !== undefined);
|
|
30
|
+
if (hasShapeStyle || blend !== undefined || previousBlend) {
|
|
26
31
|
const radius = appearance;
|
|
27
32
|
return replaceGraphicItems(
|
|
28
33
|
program,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { validateGraphicItemLimit } from "../../../core/validation.js";
|
|
1
2
|
import { editGraphicProperties } from "../../primitives/graphicProperties.js";
|
|
2
3
|
import { action } from "../../../core/action.js";
|
|
3
4
|
import { validateUserId } from "../../../core/identifiers.js";
|
|
@@ -29,6 +30,8 @@ import {
|
|
|
29
30
|
} from "../../../theme/defaults.js";
|
|
30
31
|
import { findDataset } from "../../../selectors/datasets.js";
|
|
31
32
|
import { findLayer } from "../../../selectors/layers.js";
|
|
33
|
+
import { resolveGraphicItemCapacity } from "../../../selectors/graphicCapacity.js";
|
|
34
|
+
import { getMarkGraphicTypes } from "../../../core/vocabulary.js";
|
|
32
35
|
import { canMaterializePoint } from "../../../materialization/marks/capabilities.js";
|
|
33
36
|
import { rematerializeHighlightBaseline } from "../lifecycle.js";
|
|
34
37
|
import {
|
|
@@ -335,13 +338,14 @@ export const rematerializePointMark = /* @__PURE__ */ action(
|
|
|
335
338
|
if (layer?.mark?.type !== "point") {
|
|
336
339
|
throw new Error(`Unknown point mark "${id}".`);
|
|
337
340
|
}
|
|
338
|
-
if (!
|
|
341
|
+
if (!getMarkGraphicTypes("point").includes(graphic?.type)) {
|
|
339
342
|
throw new Error(`Point mark "${id}" requires point graphics.`);
|
|
340
343
|
}
|
|
341
344
|
const sourceDataset = findDataset(resolved, layer.data);
|
|
342
345
|
if (sourceDataset === undefined) {
|
|
343
346
|
throw new Error(`Point mark "${id}" requires an existing dataset.`);
|
|
344
347
|
}
|
|
348
|
+
validateGraphicItemLimit(sourceDataset.values.length, resolveGraphicItemCapacity(resolved, { id, label: "Point mark item count" }));
|
|
345
349
|
const dataset = applyItemMissingPolicy(layer, sourceDataset);
|
|
346
350
|
|
|
347
351
|
if (graphic.items.length === 0 && !canMaterializePoint(resolved, layer)) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cartesianAxisOwners, axisTargetArgs } from "../../selectors/axes.js";
|
|
1
2
|
import { ownedChildren, ownership } from "../../selectors/markOwners.js";
|
|
2
3
|
import { isSourceOwnedText } from "../../grammar/text.js";
|
|
3
4
|
import { closedAction } from "../../core/action.js";
|
|
@@ -183,16 +184,15 @@ function cleanupPositionGuides(program, scales) {
|
|
|
183
184
|
let next = program;
|
|
184
185
|
for (const channel of POSITION_CHANNELS) {
|
|
185
186
|
const definition = getPositionChannelDefinition(channel);
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
});
|
|
187
|
+
const owners = ["x", "y"].includes(channel)
|
|
188
|
+
? cartesianAxisOwners(next).filter(owner => owner.channel === channel)
|
|
189
|
+
: [{ id: channel, channel, semantic: next.semanticSpec.guides.axis?.[channel] }];
|
|
190
|
+
for (const owner of owners) {
|
|
191
|
+
const axis = owner.semantic;
|
|
192
|
+
if (axis !== undefined && scales[channel].has(axis.scale) && !hasScaleConsumer(next, channel, axis.scale)) {
|
|
193
|
+
next = next[REMOVE_AXIS[channel]]({ ...axisTargetArgs(owner.id, channel), scale: axis.scale,
|
|
194
|
+
...(axis.coordinate === undefined ? {} : { coordinate: axis.coordinate }) });
|
|
195
|
+
}
|
|
196
196
|
}
|
|
197
197
|
const grid = next.semanticSpec.guides.grid?.[definition.gridDirection];
|
|
198
198
|
if (
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { validateGraphicItemLimit } from "../../core/validation.js";
|
|
1
2
|
import { closedAction } from "../../core/action.js";
|
|
2
3
|
import { validateUserId } from "../../core/identifiers.js";
|
|
3
4
|
import { freezeOwned } from "../../core/immutable.js";
|
|
4
|
-
import {
|
|
5
|
+
import { resolveGraphicItemCapacity } from "../../selectors/graphicCapacity.js";
|
|
5
6
|
import {
|
|
6
7
|
isDrawableGraphicType,
|
|
7
8
|
isGraphicContainerType,
|
|
@@ -118,7 +119,7 @@ const createGraphics = /* @__PURE__ */ closedAction(
|
|
|
118
119
|
throw new TypeError("createGraphics length must be a non-negative integer.");
|
|
119
120
|
}
|
|
120
121
|
if (length !== undefined) {
|
|
121
|
-
|
|
122
|
+
validateGraphicItemLimit(length, resolveGraphicItemCapacity(this, { id, label: "createGraphics length", type: validatedType }));
|
|
122
123
|
}
|
|
123
124
|
if (validatedType === "collection" && length !== undefined) {
|
|
124
125
|
throw new Error("Heterogeneous collections use editGraphics items instead of length.");
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { validateGraphicItemLimit } from "../../core/validation.js";
|
|
1
2
|
import { closedAction } from "../../core/action.js";
|
|
2
3
|
import { cloneAndFreeze, freezeOwned, isPlainObject } from "../../core/immutable.js";
|
|
3
|
-
import {
|
|
4
|
+
import { resolveGraphicItemCapacity } from "../../selectors/graphicCapacity.js";
|
|
4
5
|
import {
|
|
5
6
|
isPrimitiveDrawableGraphicType,
|
|
6
7
|
isStructuralGraphicType,
|
|
@@ -43,14 +44,14 @@ function validateCollectionItem(item, ownerId, index) {
|
|
|
43
44
|
});
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
function replaceCollectionItems(value, id) {
|
|
47
|
+
function replaceCollectionItems(value, id, program) {
|
|
47
48
|
if (!Array.isArray(value)) throw new TypeError("collection.items must be an array.");
|
|
48
|
-
|
|
49
|
+
validateGraphicItemLimit(value.length, resolveGraphicItemCapacity(program, { id, label: "collection.items length" }));
|
|
49
50
|
return freezeOwned(value.map((item, index) => validateCollectionItem(item, id, index)));
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
function replaceDrawableItems(value, id, type) {
|
|
53
|
-
const items = replaceCollectionItems(value, id);
|
|
53
|
+
function replaceDrawableItems(value, id, type, program) {
|
|
54
|
+
const items = replaceCollectionItems(value, id, program);
|
|
54
55
|
if (!items.every(item => item.type === type)) {
|
|
55
56
|
return freezeOwned({ type: "collection", items });
|
|
56
57
|
}
|
|
@@ -102,15 +103,15 @@ function editGeneratedItem(owner, itemIndex, property, value) {
|
|
|
102
103
|
return freezeOwned({ ...owner, items: freezeOwned(items) });
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
function editItems(owner, property, value, id) {
|
|
106
|
+
function editItems(owner, property, value, id, program) {
|
|
106
107
|
if (owner.type === "collection" && property === "items") {
|
|
107
|
-
return freezeOwned({ ...owner, items: replaceCollectionItems(value, id) });
|
|
108
|
+
return freezeOwned({ ...owner, items: replaceCollectionItems(value, id, program) });
|
|
108
109
|
}
|
|
109
110
|
if (property === "length") {
|
|
110
111
|
if (!Number.isInteger(value) || value < 0) {
|
|
111
112
|
throw new TypeError("Graphic collection length must be a non-negative integer.");
|
|
112
113
|
}
|
|
113
|
-
|
|
114
|
+
validateGraphicItemLimit(value, resolveGraphicItemCapacity(program, { id, label: "Graphic collection length" }));
|
|
114
115
|
const items = owner.items.slice(0, value);
|
|
115
116
|
for (let index = items.length; index < value; index += 1) {
|
|
116
117
|
if (owner.type === "collection") {
|
|
@@ -189,6 +190,9 @@ const editGraphics = /* @__PURE__ */ closedAction(
|
|
|
189
190
|
|
|
190
191
|
const ownerId = found.kind === "item" ? found.ownerId : found.id;
|
|
191
192
|
const owner = found.kind === "item" ? found.owner : found.object;
|
|
193
|
+
if (owner.items !== undefined) validateGraphicItemLimit(owner.items.length, resolveGraphicItemCapacity(this, {
|
|
194
|
+
id: ownerId, label: "Graphic collection length"
|
|
195
|
+
}));
|
|
192
196
|
const replacesDrawableItems =
|
|
193
197
|
found.kind === "object" && property === "items" &&
|
|
194
198
|
owner.items !== undefined && owner.type !== "collection";
|
|
@@ -199,7 +203,7 @@ const editGraphics = /* @__PURE__ */ closedAction(
|
|
|
199
203
|
: owner.type, property);
|
|
200
204
|
let updated;
|
|
201
205
|
if (replacesDrawableItems) {
|
|
202
|
-
updated = replaceDrawableItems(value, ownerId, owner.type);
|
|
206
|
+
updated = replaceDrawableItems(value, ownerId, owner.type, this);
|
|
203
207
|
} else if (found.kind === "item") {
|
|
204
208
|
if (validatedProperty === "length" || validatedProperty === "items") {
|
|
205
209
|
throw new Error(`${validatedProperty} can only target an owning graphic.`);
|
|
@@ -212,12 +216,12 @@ const editGraphics = /* @__PURE__ */ closedAction(
|
|
|
212
216
|
properties: setGraphicProperty(owner.properties, validatedProperty, value)
|
|
213
217
|
});
|
|
214
218
|
} else if (owner.items !== undefined) {
|
|
215
|
-
updated = editItems(owner, validatedProperty, value, ownerId);
|
|
219
|
+
updated = editItems(owner, validatedProperty, value, ownerId, this);
|
|
216
220
|
} else if (validatedProperty === "length") {
|
|
217
221
|
if (!Number.isInteger(value) || value < 0) {
|
|
218
222
|
throw new TypeError("Graphic collection length must be a non-negative integer.");
|
|
219
223
|
}
|
|
220
|
-
|
|
224
|
+
validateGraphicItemLimit(value, resolveGraphicItemCapacity(this, { id: ownerId, label: "Graphic collection length" }));
|
|
221
225
|
updated = freezeOwned({
|
|
222
226
|
type: owner.type,
|
|
223
227
|
items: freezeOwned(Array.from({ length: value }, (_, index) => freezeOwned({
|
|
@@ -1,6 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
for (const [property, value] of Object.entries(properties)) {
|
|
3
|
-
program = program.editGraphics({ target, property, value });
|
|
4
|
-
}
|
|
5
|
-
return program;
|
|
6
|
-
}
|
|
1
|
+
export { editGraphicProperties } from "../../core/graphicProperties.js";
|
|
@@ -57,7 +57,7 @@ function updateEntity(spec, parsed, value) {
|
|
|
57
57
|
source.schema,
|
|
58
58
|
value[0],
|
|
59
59
|
undefined,
|
|
60
|
-
{ sourceId: source.id, ownerId: parsed.id }
|
|
60
|
+
{ sourceId: source.id, ownerId: parsed.id, sourceTransform: source.transform?.[0] }
|
|
61
61
|
));
|
|
62
62
|
}
|
|
63
63
|
}
|
|
@@ -72,6 +72,7 @@ function updateEntity(spec, parsed, value) {
|
|
|
72
72
|
const schema = source?.schema !== undefined && current.transform?.length === 1
|
|
73
73
|
? deriveTransformSchema(source.schema, current.transform[0], value, {
|
|
74
74
|
sourceId: source.id,
|
|
75
|
+
sourceTransform: source.transform?.[0],
|
|
75
76
|
ownerId: parsed.id
|
|
76
77
|
})
|
|
77
78
|
: inferDatasetSchema(value);
|
|
@@ -225,6 +226,31 @@ export function withoutPreviewLayerEncodings(program, { id, channels }) {
|
|
|
225
226
|
return program._clone({ semanticSpec });
|
|
226
227
|
}
|
|
227
228
|
|
|
229
|
+
// Composition materialization may retain this native two-scale guide meaning.
|
|
230
|
+
// Use the existing semantic primitives on a private unit adapter; this does not
|
|
231
|
+
// relax the public composition guard or accept arbitrary semantic paths.
|
|
232
|
+
export function synchronizeFacetColorSizeMeaning(program, meaning) {
|
|
233
|
+
if (program.compositionSpec?.type !== "facet") {
|
|
234
|
+
throw new Error("Color-size parent meaning requires a facet composition.");
|
|
235
|
+
}
|
|
236
|
+
if (meaning !== undefined && (!isPlainObject(meaning) ||
|
|
237
|
+
Object.keys(meaning).some(key => !["colorScale", "sizeScale", "title"].includes(key)))) {
|
|
238
|
+
throw new Error("Color-size parent meaning requires its native scale bindings and title.");
|
|
239
|
+
}
|
|
240
|
+
let unit = new program.constructor({ semanticSpec: program.semanticSpec, graphicSpec: program.graphicSpec,
|
|
241
|
+
resolvedScales: program.resolvedScales, materializationConfigs: program.materializationConfigs,
|
|
242
|
+
context: program.context, trace: program.trace, actionStack: program.actionStack,
|
|
243
|
+
actionSequence: program._actionSequence });
|
|
244
|
+
if (unit.semanticSpec.guides.legend?.colorSize !== undefined) {
|
|
245
|
+
unit = unit.editSemantic({ property: "guide.legend.colorSize", remove: true });
|
|
246
|
+
}
|
|
247
|
+
if (meaning !== undefined) for (const [property, value] of Object.entries(meaning)) {
|
|
248
|
+
unit = unit.editSemantic({ property: `guide.legend.colorSize.${property}`, value });
|
|
249
|
+
}
|
|
250
|
+
return program._clone({ semanticSpec: unit.semanticSpec, context: unit.context,
|
|
251
|
+
trace: unit.trace, actionStack: unit.actionStack, actionSequence: unit._actionSequence });
|
|
252
|
+
}
|
|
253
|
+
|
|
228
254
|
export function createSemanticPrimitiveAction(validateSemanticValue, planNamedRemoval) {
|
|
229
255
|
return closedAction(
|
|
230
256
|
{
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {isSizeShapeChannels} from "../../../grammar/legendCombinations.js";
|
|
1
2
|
import { normalizeLegendOrder } from "../../../grammar/categoryOrder.js";
|
|
2
3
|
import { validateUserId } from "../../../core/identifiers.js";
|
|
3
4
|
import { CATEGORICAL_LEGEND_CHANNELS } from "../../../core/vocabulary.js";
|
|
@@ -16,7 +17,7 @@ function validateLegend(property, value) {
|
|
|
16
17
|
throw new Error(`Legend ${property} must not contain duplicates.`);
|
|
17
18
|
}
|
|
18
19
|
if (property === "channels") {
|
|
19
|
-
if (!value.every(channel => CATEGORICAL_LEGEND_CHANNELS.includes(channel))) {
|
|
20
|
+
if (!isSizeShapeChannels(value) && !value.every(channel => CATEGORICAL_LEGEND_CHANNELS.includes(channel))) {
|
|
20
21
|
throw new Error("Legend channels support only color, strokeDash, and shape.");
|
|
21
22
|
}
|
|
22
23
|
return;
|
|
@@ -26,6 +27,11 @@ function validateLegend(property, value) {
|
|
|
26
27
|
|
|
27
28
|
export function validateGuideSemanticValue(_program, parsed, value) {
|
|
28
29
|
const property = parsed.path.at(-1);
|
|
30
|
+
if (parsed.id === "legend.colorSize") {
|
|
31
|
+
if(property === "title") validateNonEmptySemanticString(value,"Legend title");
|
|
32
|
+
else validateUserId(value,"Legend scale id");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
29
35
|
if (parsed.id === "axis.parallel" && property === "titles") {
|
|
30
36
|
validateParallelAxisTitles(value);
|
|
31
37
|
return;
|
|
@@ -44,6 +50,10 @@ export function validateGuideSemanticValue(_program, parsed, value) {
|
|
|
44
50
|
throw new TypeError("Parallel axis scales must contain at least two ids.");
|
|
45
51
|
}
|
|
46
52
|
value.forEach(id => validateUserId(id, "Parallel axis scale id"));
|
|
53
|
+
} else if (parsed.id.startsWith("axis.") && property === "channel") {
|
|
54
|
+
if (!["x", "y"].includes(value)) throw new Error("Named Cartesian axis channel requires x or y.");
|
|
55
|
+
} else if (parsed.id.startsWith("axis.") && property === "position") {
|
|
56
|
+
if (!["top", "bottom", "left", "right"].includes(value)) throw new Error("Named Cartesian axis position requires a physical side.");
|
|
47
57
|
} else if (property === "title") {
|
|
48
58
|
validateNonEmptySemanticString(value, "Axis title");
|
|
49
59
|
} else {
|
|
@@ -70,6 +70,10 @@ export function validateLayerSemanticValue(
|
|
|
70
70
|
!["vertical", "horizontal"].includes(value))) {
|
|
71
71
|
throw new Error("Bar orientation must be vertical or horizontal.");
|
|
72
72
|
}
|
|
73
|
+
if (property === "mark.blend" &&
|
|
74
|
+
(findLayer(program, parsed.id)?.mark?.type !== "bar" || value !== "difference")) {
|
|
75
|
+
throw new Error("Bar blend must be difference; remove the optional intent for normal painting.");
|
|
76
|
+
}
|
|
73
77
|
if (property === "derivedBindings.regression") {
|
|
74
78
|
if (!value || typeof value !== "object" || Array.isArray(value) ||
|
|
75
79
|
Object.keys(value).length !== 2 || value.mode !== "follow" ||
|
|
@@ -19,6 +19,7 @@ import { findLayer } from "../../selectors/layers.js";
|
|
|
19
19
|
import { removeOwnedMark } from "../marks/remove.js";
|
|
20
20
|
import { removeOwnedColorLegends } from "../guides/legends/remove.js";
|
|
21
21
|
import { requireRegressionField } from "./resolve.js";
|
|
22
|
+
import { buildSourceRevisionPlan, applyRevisionPlan } from "../data/edit.js";
|
|
22
23
|
|
|
23
24
|
const OPTIONS = Object.freeze([
|
|
24
25
|
"target", "data", "x", "y", "groupBy", "method", "degree", "span", "robustIterations",
|
|
@@ -128,7 +129,7 @@ function resolveParameters(previous, args) {
|
|
|
128
129
|
raw[key] = previous[key];
|
|
129
130
|
}
|
|
130
131
|
}
|
|
131
|
-
} else if (
|
|
132
|
+
} else if (!["loess", "exp"].includes(method) && !["loess", "exp"].includes(previous.method) && args.interval !== false) {
|
|
132
133
|
for (const key of ["confidenceMethod", "level", "interval"]) {
|
|
133
134
|
if (
|
|
134
135
|
!Object.hasOwn(raw, key) &&
|
|
@@ -295,6 +296,11 @@ export const editRegression = /* @__PURE__ */ closedAction(
|
|
|
295
296
|
const changesParameters = JSON.stringify(parameters) !==
|
|
296
297
|
JSON.stringify(current.parameters);
|
|
297
298
|
const changesStatistics = changesProvenance || changesParameters;
|
|
299
|
+
const hasStatistics = this.semanticSpec.datasets.some(dataset =>
|
|
300
|
+
dataset.source === current.dataId && dataset.transform?.[0]?.type === "regressionStatistics");
|
|
301
|
+
if (hasStatistics && parameters.method !== "linear") {
|
|
302
|
+
throw new Error("Remove dependent regression statistics before changing the linear fit method.");
|
|
303
|
+
}
|
|
298
304
|
const bandPatch = Object.hasOwn(args, "band")
|
|
299
305
|
? validateBandPatch(args.band)
|
|
300
306
|
: undefined;
|
|
@@ -302,14 +308,16 @@ export const editRegression = /* @__PURE__ */ closedAction(
|
|
|
302
308
|
? validateLinePatch(args.line)
|
|
303
309
|
: undefined;
|
|
304
310
|
if ((parameters.method === "loess" || parameters.interval === false) && bandPatch !== undefined && bandPatch !== false) {
|
|
305
|
-
throw new Error(
|
|
311
|
+
throw new Error(parameters.method === "loess"
|
|
312
|
+
? "LOESS regression does not support a band object."
|
|
313
|
+
: "Regression interval false cannot include a band object.");
|
|
306
314
|
}
|
|
307
315
|
|
|
308
316
|
const hadBand = current.bandId !== undefined;
|
|
309
317
|
const wantsBand = parameters.method !== "loess" && parameters.interval !== false &&
|
|
310
318
|
(bandPatch === false
|
|
311
319
|
? false
|
|
312
|
-
: hadBand || bandPatch !== undefined || current.parameters.method
|
|
320
|
+
: hadBand || bandPatch !== undefined || ["loess", "exp"].includes(current.parameters.method));
|
|
313
321
|
const revision = changesStatistics
|
|
314
322
|
? planDerivedDataRevision(this, {
|
|
315
323
|
owner: owner.id,
|
|
@@ -321,6 +329,8 @@ export const editRegression = /* @__PURE__ */ closedAction(
|
|
|
321
329
|
]
|
|
322
330
|
})
|
|
323
331
|
: undefined;
|
|
332
|
+
const statisticsRevision = changesStatistics && hasStatistics
|
|
333
|
+
? buildSourceRevisionPlan(this, current.dataId, revision.id) : undefined;
|
|
324
334
|
|
|
325
335
|
const applyEdit = program => {
|
|
326
336
|
let dataId = current.dataId;
|
|
@@ -412,6 +422,8 @@ export const editRegression = /* @__PURE__ */ closedAction(
|
|
|
412
422
|
}
|
|
413
423
|
});
|
|
414
424
|
if (changesStatistics) {
|
|
425
|
+
if (statisticsRevision !== undefined) next = applyRevisionPlan(next, undefined,
|
|
426
|
+
statisticsRevision, { retain: new Set([current.dataId]) });
|
|
415
427
|
next = next.releaseDerivedData(revision.release);
|
|
416
428
|
}
|
|
417
429
|
const binding = findLayer(next, owner.id)?.derivedBindings?.regression;
|
|
@@ -42,7 +42,7 @@ const DEFINITIONS = Object.freeze({
|
|
|
42
42
|
channel: "color",
|
|
43
43
|
options: Object.freeze([
|
|
44
44
|
"type", "domain", "range", "emptyDomain", "clamp", "reverse", "palette",
|
|
45
|
-
"interpolate", "midpoint", "base", "constant", "unknown"
|
|
45
|
+
"interpolate", "whitePoint", "gamma", "midpoint", "base", "exponent", "constant", "unknown"
|
|
46
46
|
])
|
|
47
47
|
}),
|
|
48
48
|
editStrokeScale: Object.freeze({
|
|
@@ -50,7 +50,7 @@ const DEFINITIONS = Object.freeze({
|
|
|
50
50
|
targetOnly: true,
|
|
51
51
|
options: Object.freeze([
|
|
52
52
|
"type", "domain", "range", "emptyDomain", "clamp", "reverse", "palette",
|
|
53
|
-
"interpolate", "midpoint", "base", "constant", "unknown"
|
|
53
|
+
"interpolate", "whitePoint", "gamma", "midpoint", "base", "exponent", "constant", "unknown"
|
|
54
54
|
])
|
|
55
55
|
}),
|
|
56
56
|
editSizeScale: Object.freeze({
|
|
@@ -38,7 +38,7 @@ const CREATE_SCALE_OPTIONS = Object.freeze([
|
|
|
38
38
|
"padding",
|
|
39
39
|
"align",
|
|
40
40
|
"palette",
|
|
41
|
-
"interpolate", "midpoint",
|
|
41
|
+
"interpolate", "whitePoint", "gamma", "midpoint",
|
|
42
42
|
"radialMapping", "unknown"
|
|
43
43
|
]);
|
|
44
44
|
|
|
@@ -88,7 +88,7 @@ export const createScale = /* @__PURE__ */ action(
|
|
|
88
88
|
const id = validateUserId(args.id, "Scale id");
|
|
89
89
|
const type = validateScaleType(args.type ?? "linear");
|
|
90
90
|
const colorType = isColorScaleType(type) && (
|
|
91
|
-
!["log", "sqrt", "symlog"].includes(type) || args.palette !== undefined ||
|
|
91
|
+
!["log", "pow", "sqrt", "symlog"].includes(type) || args.palette !== undefined ||
|
|
92
92
|
args.interpolate !== undefined || (Array.isArray(args.range) && typeof args.range[0] === "string") ||
|
|
93
93
|
args.range?.palette !== undefined
|
|
94
94
|
);
|
|
@@ -171,7 +171,7 @@ export const createScale = /* @__PURE__ */ action(
|
|
|
171
171
|
|
|
172
172
|
for (const property of [
|
|
173
173
|
"emptyDomain", "nice", "zero", "clamp", "reverse", "base", "exponent", "constant",
|
|
174
|
-
"paddingInner", "paddingOuter", "padding", "align", "interpolate", "midpoint",
|
|
174
|
+
"paddingInner", "paddingOuter", "padding", "align", "interpolate", "whitePoint", "gamma", "midpoint",
|
|
175
175
|
"radialMapping", "unknown"
|
|
176
176
|
]) {
|
|
177
177
|
if (definition[property] === undefined) continue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{prepareScaleEdit as
|
|
1
|
+
import{prepareScaleEdit as U}from"./editPolicy.js";import{validateUserId as p}from"../../core/identifiers.js";import{isPlainObject as B}from"../../core/immutable.js";import{validateKeys as f}from"../../core/validation.js";import{validateColorRange as F,isContinuousColorScaleType as E,normalizeTransformParameters as K,validateTransformedDomain as Q,validateContinuousColorInterpolation as H,normalizeColorInterpolationOptions as V,validateSequentialMidpoint as Y,validateLinearScaleType as _,validateOpacityRange as Z,validateOrdinalDomain as h,validateOrdinalScaleType as j,validateScaleDomain as P,validateScaleRange as k,validateShapeRange as G,validateStrokeDashRange as J,validateStrokeWidthRange as X,validateSequentialColorRange as ee,validateDiscretizedColorDomain as te,validateDiscretizedColorRange as ne,validateTimeScaleType as ae,normalizeScaleDefinition as A,SCALE_ROLES as R,validateScalePropertyForType as L,validateScaleTypeForRole as I,isDiscretePositionScaleType as ie,normalizeSizeScaleDefinition as re,withScaleUnknown as w}from"../../grammar/scales/index.js";import{validateRadialRange as oe,validateThetaRange as ce}from"../../grammar/polar.js";import{findSemanticScale as g}from"../../selectors/scales.js";import{normalizeOffsetScalePolicy as le}from"../../grammar/bars/geometry.js";import{resolveRequestedOffsetPolicy as de}from"../../materialization/scales/policies/offset.js";import{findScaleConsumers as se}from"./consumers/index.js";const C=["id","type","domain","range","emptyDomain"],M=[...C,"unknown"],S=["clamp","reverse"],O=["nice","zero",...S],q=["base","exponent","constant"],ue=[...C,...O,...q,"paddingInner","paddingOuter","padding","align","unknown"],D=[...C,"palette","unknown"],$=[...D,"interpolate","whitePoint","gamma","midpoint","base","exponent","constant",...S],fe=[...C,...O,"unknown"],me=[...C,...O,...q],pe=[...M,"clamp","reverse","base","exponent"];function y(i){if(!B(i))throw new TypeError("Encoding scale must be a plain object.")}function b(i,t,e){for(const n of t){if(i[n]!==void 0&&typeof i[n]!="boolean")throw new TypeError(`Scale ${n} must be a boolean.`);e!==void 0&&i[n]!==void 0&&L(e,n)}}function x(i,t,e,n){for(const a of n){const o=t[a]??e?.[a];o!==void 0&&(i[a]=o)}return i}function z(i){if(i.palette!==void 0&&i.range!==void 0)throw new Error("Color scale cannot specify both palette and range.")}function be(i,t,e,n,a={}){y(n),f(n,ue,"scale");const o=p(n.id??t,"Scale id"),r=g(i,o),c=["ordinal","nominal"].includes(e),m=e==="temporal"?"time":c?a.discreteType??"point":"linear",l=n.type??r?.type??m;if(e==="temporal")ae(l);else if(c){if(!ie(l))throw new Error(`Scale type "${l}" is not valid for discrete position.`)}else t==="theta"?_(l):I(l,R.quantitativePosition);const s={id:o,...A({type:l,previous:r,patch:{...n,...a.radialMapping===void 0?{}:{radialMapping:a.radialMapping}},defaults:{...r===void 0&&a.nice!==void 0?{nice:a.nice}:{},...r===void 0&&a.zero!==void 0&&(l!=="log"||a.zero)?{zero:a.zero}:{}},retainCoreOnTypeChange:!0,retainCompatibleOnTypeChange:!0,validateDomain:(v,u)=>c?h(u):P(u),validateRange:(v,u)=>t==="theta"?ce(u):t==="radius"?oe(u):k(u)})};return w(s,{...r,...n},t)}function xe(i,t,e="color"){y(t),f(t,D,"scale"),z(t);const n=p(t.id??e,"Scale id"),a=g(i,n),o=a?.type==="ordinal"?a:void 0,r=t.palette===void 0?t.range:{palette:t.palette};return w({id:n,type:j(t.type??o?.type??"ordinal"),domain:h(t.domain??o?.domain??"auto"),range:F(r??o?.range??"auto")},{...o,...t},e)}function ge(i,t){if(i==="auto")return i;if(!Array.isArray(i)||i.length!==2)throw new TypeError("Continuous color domain must contain two values or auto.");const e=i.map(n=>t==="quantitative"?n:typeof n=="string"?Date.parse(n):n);if(!e.every(Number.isFinite)||e[0]===e[1])throw new TypeError("Continuous color domain requires two distinct valid values.");return e}function ye(i,t,e,n="color"){y(e),f(e,$,"scale"),z(e);const a=p(e.id??n,"Scale id"),o=g(i,a),r=E(o?.type)?o:void 0,c=e.type??r?.type??"sequential";if(!E(c))throw new Error(`Unsupported continuous color scale type "${c}".`);b(e,S);const m=e.palette===void 0?e.range:{palette:e.palette},l={id:a,type:c,domain:ge(e.domain??r?.domain??"auto",t),range:ee(m??r?.range??{palette:"viridis"}),interpolate:H(e.interpolate??r?.interpolate??"rgb")},s=Object.hasOwn(e,"interpolate")&&e.interpolate!==r?.interpolate,v=Object.fromEntries(["whitePoint","gamma"].flatMap(d=>{const T=Object.hasOwn(e,d)?e[d]:s?void 0:r?.[d];return T===void 0?[]:[[d,T]]}));if(Object.assign(l,V(l.interpolate,v)),c!=="sequential"&&t!=="quantitative")throw new Error(`Scale type "${c}" requires quantitative color.`);const u=Object.fromEntries(["base","exponent","constant"].flatMap(d=>{const T=e[d]??(c===r?.type?r?.[d]:void 0);return T===void 0?[]:[[d,T]]}));if(c!=="sequential"){const d=K(c,u);c==="log"&&(l.base=d.base),c==="pow"&&(l.exponent=d.exponent),c==="symlog"&&(l.constant=d.constant),l.domain!=="auto"&&Q(c,l.domain,u)}else if(Object.keys(u).length)throw new Error("Sequential color does not support transform parameters.");const N=Y(Object.hasOwn(e,"midpoint")?e.midpoint:r?.midpoint,c,l.domain);if(N!==void 0){if(t!=="quantitative")throw new Error("Scale midpoint requires quantitative color consumers.");l.midpoint=N}return w(x(l,e,r,S),{...r,...e},n)}function Pe(i,t,e,n="color"){y(e);const a=g(i,e.id??n),o=a!==void 0&&(E(a.type)||["quantize","quantile","threshold"].includes(a.type)),r=e.type??(o?a.type:"sequential");if(o&&a.type!==r){if(f(e,E(r)?$:[...D,...S],"scale"),t!=="quantitative")throw new Error("Color scale type transition requires quantitative color.");return{id:a.id,...U(i,a,n,[],e)}}if(E(r))return ye(i,t,e,n);if(f(e,[...D,...S],"scale"),t!=="quantitative")throw new Error(`Scale type "${r}" requires quantitative color.`);I(r,R.discretizedColor),z(e),b(e,S,r);const c=p(e.id??n,"Scale id"),m=a?.type===r?a:void 0,l=e.palette===void 0?e.range:{palette:e.palette},s={id:c,type:r,domain:te(r,e.domain??m?.domain??"auto"),range:ne(l??m?.range??{palette:"viridis"})};return w(x(s,e,m,S),{...a,...e},n)}function W(i,t,e,n){y(t),f(t,M,"scale");const a=p(t.id??e,"Scale id"),o=g(i,a);return w({id:a,type:j(t.type??o?.type??"ordinal"),domain:h(t.domain??o?.domain??"auto"),range:n(t.range??o?.range??"auto")},{...o,...t},e)}function Re(i,t){return W(i,t,"strokeDash",J)}function Ie(i,t,e,n="quantitative"){if(y(e),t==="size"){f(e,pe,"scale");const a=p(e.id??t,"Scale id"),o=g(i,a),r=["nominal","ordinal"].includes(n),c=re({previous:o,patch:{...e,type:e.type??o?.type??(r?"ordinal":"linear")}});if(c.type==="ordinal"!==r)throw new Error("Size scale type must match its field type.");return{id:a,...c}}return W(i,e,t,G)}function ze(i,t){y(t),f(t,fe,"scale");const e=p(t.id??"opacity","Scale id"),n=g(i,e),a=_(t.type??n?.type??"linear");b(t,O,a);const o={id:e,type:a,domain:P(t.domain??n?.domain??"auto"),range:Z(t.range??n?.range??"auto")};return w(x(o,t,n,O),{...n,...t},"opacity")}function Ne(i,t){y(t),f(t,me,"scale");const e=p(t.id??"strokeWidth","Scale id"),n=g(i,e),a=t.type??n?.type??"linear";I(a,R.quantitativePosition),b(t,O,a);for(const c of q)t[c]!==void 0&&L(a,c);const o=P(t.domain??n?.domain??"auto");if(o!=="auto"&&o.some(c=>c<0))throw new RangeError("StrokeWidth scale domain cannot contain negative values.");const r={id:e,type:a,domain:o,range:X(t.range??n?.range??"auto")};return x(r,t,n,[...O,...q])}function _e(i,t,e="xOffset"){y(t),f(t,["id","type","domain","range","reverse","padding","paddingInner","paddingOuter","align"],"scale");const n=p(t.id??e,"Scale id"),a=g(i,n),o=t.type??a?.type??"ordinal";if(o!=="ordinal")throw new Error(`Scale type "${o}" is not valid for ${e}.`);if(Object.hasOwn(t,"range")&&t.range!=="auto")throw new Error(`${e} scale range is derived from its parent categorical slot.`);const r=se(i,n).filter(s=>s.channel===e),c=de({scale:a,consumers:r,markConfigs:i.markConfigs,id:n,channel:e}),m=le(t,c,e),l=Object.fromEntries(Object.entries(t).filter(([s])=>!["id","padding"].includes(s)));return{id:n,...A({type:o,previous:a,patch:{...l,...m},allowOrdinalBandParameters:!0,validateDomain:(s,v)=>h(v),validateRange:(s,v)=>k(v)})}}export{Ie as resolveAppearanceScaleDefinition,xe as resolveColorScaleDefinition,_e as resolveOffsetScaleDefinition,ze as resolveOpacityScaleDefinition,be as resolvePositionScaleDefinition,Pe as resolveQuantitativeColorScaleDefinition,ye as resolveSequentialColorScaleDefinition,Re as resolveStrokeDashScaleDefinition,Ne as resolveStrokeWidthScaleDefinition};
|
|
@@ -28,7 +28,7 @@ import { hasExactLegendSamplingForScale } from
|
|
|
28
28
|
const OPTIONS = Object.freeze([
|
|
29
29
|
"id", "type", "domain", "range", "emptyDomain", "nice", "zero", "clamp", "reverse",
|
|
30
30
|
"base", "exponent", "constant", "paddingInner", "paddingOuter", "padding",
|
|
31
|
-
"align", "interpolate", "midpoint", "unknown", "palette", "radialMapping"
|
|
31
|
+
"align", "interpolate", "whitePoint", "gamma", "midpoint", "unknown", "palette", "radialMapping"
|
|
32
32
|
]);
|
|
33
33
|
const EDITABLE = Object.freeze(
|
|
34
34
|
OPTIONS.filter(option => !["id", "palette"].includes(option))
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
validateDiscretizedColorDomain,
|
|
13
13
|
validateDiscretizedColorRange,
|
|
14
14
|
validateOrdinalDomain,
|
|
15
|
+
validateOrdinalRange,
|
|
15
16
|
validateScaleDomain,
|
|
16
17
|
validateScaleRange,
|
|
17
18
|
validateScaleType,
|
|
@@ -66,6 +67,7 @@ function validateRangeForChannel(scale, channel, value) {
|
|
|
66
67
|
if (channel === "strokeDash") return validateStrokeDashRange(value);
|
|
67
68
|
if (channel === "size") return validateSizeRange(value);
|
|
68
69
|
if (channel === "strokeWidth") return validateStrokeWidthRange(value);
|
|
70
|
+
if (channel === undefined) return validateOrdinalRange(value);
|
|
69
71
|
return validateScaleRange(value);
|
|
70
72
|
}
|
|
71
73
|
|
|
@@ -217,6 +219,7 @@ function normalizeDefinition(program, scale, channel, consumers, patch) {
|
|
|
217
219
|
patch: normalizedPatch,
|
|
218
220
|
retainCoreOnTypeChange: true,
|
|
219
221
|
retainCompatibleOnTypeChange: true,
|
|
222
|
+
allowColorReset: true,
|
|
220
223
|
allowOrdinalBandParameters: offset,
|
|
221
224
|
validateDomain: (scaleType, value) =>
|
|
222
225
|
isDiscretizedColorScaleType(scaleType)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const SCALE_EDIT_PROPERTIES = Object.freeze([
|
|
2
2
|
"type", "domain", "range", "emptyDomain", "nice", "zero", "clamp", "reverse",
|
|
3
3
|
"base", "exponent", "constant", "paddingInner", "paddingOuter",
|
|
4
|
-
"padding", "align", "interpolate", "midpoint", "unknown"
|
|
4
|
+
"padding", "align", "interpolate", "whitePoint", "gamma", "midpoint", "unknown"
|
|
5
5
|
]);
|
|
6
6
|
|
|
7
7
|
function sameValue(left, right) {
|
|
@@ -7,7 +7,7 @@ const OPTIONS = Object.freeze([
|
|
|
7
7
|
"type",
|
|
8
8
|
"domain",
|
|
9
9
|
"range",
|
|
10
|
-
"interpolate", "midpoint", "base", "constant",
|
|
10
|
+
"interpolate", "whitePoint", "gamma", "midpoint", "base", "exponent", "constant",
|
|
11
11
|
"clamp",
|
|
12
12
|
"reverse",
|
|
13
13
|
"unknown"
|
|
@@ -19,7 +19,7 @@ export const setQuantitativeColorScale = /* @__PURE__ */ closedAction(
|
|
|
19
19
|
description: "Create or update an internal quantitative color scale."
|
|
20
20
|
}, OPTIONS,
|
|
21
21
|
function (args = {}) {
|
|
22
|
-
if (!["sequential", "log", "sqrt", "symlog", "quantize", "quantile", "threshold"].includes(args.type)) {
|
|
22
|
+
if (!["sequential", "log", "pow", "sqrt", "symlog", "quantize", "quantile", "threshold"].includes(args.type)) {
|
|
23
23
|
throw new Error(`Unsupported quantitative color scale type "${args.type}".`);
|
|
24
24
|
}
|
|
25
25
|
const existing = findSemanticScale(this, args.id);
|
|
@@ -30,11 +30,16 @@ export const setQuantitativeColorScale = /* @__PURE__ */ closedAction(
|
|
|
30
30
|
return this.editScale(args);
|
|
31
31
|
}
|
|
32
32
|
let next = this;
|
|
33
|
+
for (const property of ["whitePoint", "gamma"]) {
|
|
34
|
+
if (existing?.[property] !== undefined && args[property] === undefined) {
|
|
35
|
+
next = next.editSemantic({ property: `scale[${args.id}].${property}`, remove: true });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
33
38
|
if (existing?.midpoint !== undefined && args.midpoint === undefined) {
|
|
34
39
|
next = next.editSemantic({ property: `scale[${args.id}].midpoint`, remove: true });
|
|
35
40
|
}
|
|
36
41
|
for (const property of [
|
|
37
|
-
"type", "domain", "range", "interpolate", "midpoint", "base", "constant", "clamp", "reverse", "unknown"
|
|
42
|
+
"type", "domain", "range", "interpolate", "whitePoint", "gamma", "midpoint", "base", "exponent", "constant", "clamp", "reverse", "unknown"
|
|
38
43
|
]) {
|
|
39
44
|
if (!Object.hasOwn(args, property)) continue;
|
|
40
45
|
if (existing?.[property] === args[property]) continue;
|