ggaction 0.0.21 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +90 -0
- package/README.md +83 -90
- package/knowledge/action-card.schema.json +1 -1
- package/knowledge/action-cards.json +1 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/package.json +11 -4
- 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 +3 -3
- 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 +22 -36
- 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/data/timeUnit.js +1 -1
- 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/components.js +1 -4
- 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/regression/create.js +6 -1
- package/src/actions/regression/edit.js +10 -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 +26 -7
- package/src/core/datasetReferences.js +17 -0
- package/src/core/facetAxisPolicy.js +30 -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/curveCommands.js +35 -2
- package/src/grammar/datasetDependencies.js +97 -0
- package/src/grammar/datasetSchema.js +32 -2
- package/src/grammar/facetHeaders.js +1 -0
- package/src/grammar/facets/dependencies.js +6 -2
- package/src/grammar/facets/guides.js +7 -5
- 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/regression/parameters.js +7 -0
- 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/timeUnit.js +9 -3
- 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/guideCollisions.js +9 -3
- 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/facetContentBounds.js +96 -0
- package/src/materialization/facetGuides/layout.js +1 -1
- package/src/materialization/facetGuides/placement.js +39 -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 +30 -1
- 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 +114 -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 +286 -70
- package/types/scene.d.ts +35 -0
|
@@ -5,9 +5,10 @@ import {
|
|
|
5
5
|
readQuantitativeField,
|
|
6
6
|
transformedTicks
|
|
7
7
|
} from "../../grammar/scales/index.js";
|
|
8
|
-
import { niceTicks, timeTicks } from "../../grammar/ticks.js";
|
|
8
|
+
import { niceTicks, timeTicks, validateTickSelectionRounding, axisTickSelection } from "../../grammar/ticks.js";
|
|
9
9
|
import { findDataset } from "../../selectors/datasets.js";
|
|
10
10
|
import { findSemanticScale } from "../../selectors/scales.js";
|
|
11
|
+
import { applyItemMissingPolicy } from "../../grammar/itemMissing.js";
|
|
11
12
|
|
|
12
13
|
export const DEFAULT_TICK_COUNT = 5;
|
|
13
14
|
|
|
@@ -28,7 +29,7 @@ export function inferHistogramBoundaries(program, channel, scaleId) {
|
|
|
28
29
|
throw new Error(`Guide values require histogram data and scale "${scaleId}".`);
|
|
29
30
|
}
|
|
30
31
|
return resolveHistogramBins({
|
|
31
|
-
values: readQuantitativeField(dataset.values, encoding.field),
|
|
32
|
+
values: readQuantitativeField(applyItemMissingPolicy(layer, dataset).values, encoding.field),
|
|
32
33
|
bin: encoding.bin,
|
|
33
34
|
domain: scale.domain,
|
|
34
35
|
nice: scale.nice ?? true,
|
|
@@ -44,11 +45,11 @@ export function inferHistogramBoundaries(program, channel, scaleId) {
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
export function valuesFromTickConfig(program, config) {
|
|
47
|
-
if (config.mode === "values") return config.values;
|
|
48
|
-
|
|
49
48
|
const scale = program.resolvedScales[config.scale];
|
|
49
|
+
validateTickSelectionRounding(config, scale?.type);
|
|
50
|
+
if (config.mode === "values") return config.values;
|
|
50
51
|
if (scale?.type === "time") return timeTicks(scale.domain, config.count);
|
|
51
|
-
if (scale?.type === "linear") return niceTicks(scale.domain, config.count);
|
|
52
|
+
if (scale?.type === "linear") return niceTicks(scale.domain, config.count, config.rounding);
|
|
52
53
|
if (isTransformedScaleType(scale?.type)) {
|
|
53
54
|
return transformedTicks(scale.type, scale.domain, config.count, {
|
|
54
55
|
...(scale.base === undefined ? {} : { base: scale.base }),
|
|
@@ -64,8 +65,7 @@ export function valuesFromTickConfig(program, config) {
|
|
|
64
65
|
export function inferGridTickConfig(program, channel, scaleId) {
|
|
65
66
|
const axes = cartesianAxisOwners(program).filter(owner => owner.channel === channel &&
|
|
66
67
|
owner.config?.ticks?.scale === scaleId).map(owner => owner.config.ticks);
|
|
67
|
-
const policies = axes.map(
|
|
68
|
-
? { mode: "values", values: axis.values } : { mode: "count", count: axis.count });
|
|
68
|
+
const policies = axes.map(axisTickSelection);
|
|
69
69
|
if (new Set(policies.map(policy => JSON.stringify(policy))).size > 1) {
|
|
70
70
|
throw new Error("Grid values require explicit count or values when bound axis tick policies differ.");
|
|
71
71
|
}
|
|
@@ -8,10 +8,7 @@ import {
|
|
|
8
8
|
} from "../../../core/validation.js";
|
|
9
9
|
import { deriveArcSectors } from "../../../grammar/arcs.js";
|
|
10
10
|
import { buildAnnularSectorCommands } from "../../../grammar/polarPaths.js";
|
|
11
|
-
import {
|
|
12
|
-
mapOrdinalValues,
|
|
13
|
-
readScaleField
|
|
14
|
-
} from "../../../grammar/scales/index.js";
|
|
11
|
+
import { readScaleField } from "../../../grammar/scales/index.js";
|
|
15
12
|
import { resolveCoordinatePolarFrame } from
|
|
16
13
|
"../../../materialization/coordinateBounds.js";
|
|
17
14
|
import {
|
|
@@ -165,6 +162,7 @@ const rematerializeArcMark = /* @__PURE__ */ action(
|
|
|
165
162
|
const highlighted = rematerializeHighlightBaseline(this, {
|
|
166
163
|
target: id,
|
|
167
164
|
operation: "rematerializeArcMark",
|
|
165
|
+
scales: args.scales,
|
|
168
166
|
resetProperty: "length",
|
|
169
167
|
resetValue: 0
|
|
170
168
|
});
|
|
@@ -209,10 +207,10 @@ const rematerializeArcMark = /* @__PURE__ */ action(
|
|
|
209
207
|
}));
|
|
210
208
|
const fills = colorScaleId === undefined
|
|
211
209
|
? commands.map(() => config.fill ?? DEFAULT_COLORS.mark)
|
|
212
|
-
:
|
|
210
|
+
: mapScaleConsumerValues(
|
|
213
211
|
derived.sectors.map(sector => sector.color),
|
|
214
|
-
resolved.resolvedScales[colorScaleId]
|
|
215
|
-
|
|
212
|
+
resolved.resolvedScales[colorScaleId],
|
|
213
|
+
"color"
|
|
216
214
|
);
|
|
217
215
|
const strokeEncoding = layer.encoding?.stroke;
|
|
218
216
|
const strokeValues = strokeEncoding === undefined ? undefined : derived.sectors.map(
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { requestedMarkClip, validateMarkClipCoordinate } from "../../../selectors/markClip.js";
|
|
1
2
|
import { validateFillPaint } from "../../../grammar/paint.js";
|
|
2
3
|
import { validateAreaPaintConfig } from "../../../grammar/areaPaint.js";
|
|
3
4
|
import { validateAreaMissing } from "../../../grammar/areaEndpoints.js";
|
|
@@ -36,7 +37,7 @@ import {
|
|
|
36
37
|
} from "../../../grammar/strokeStyle.js";
|
|
37
38
|
|
|
38
39
|
const AREA_OPTIONS = Object.freeze([
|
|
39
|
-
"fill", "opacity", "stroke", "strokeWidth", "curve",
|
|
40
|
+
"clip", "fill", "opacity", "stroke", "strokeWidth", "curve",
|
|
40
41
|
...STROKE_STYLE_PROPERTIES
|
|
41
42
|
]);
|
|
42
43
|
const CREATE_OPTIONS = Object.freeze(["id", "data", "missing", ...AREA_OPTIONS]);
|
|
@@ -66,6 +67,7 @@ const createAreaMark = /* @__PURE__ */ action(
|
|
|
66
67
|
},
|
|
67
68
|
function (args = {}) {
|
|
68
69
|
validateMarkOptions(args, CREATE_OPTIONS, "createAreaMark");
|
|
70
|
+
requestedMarkClip(args);
|
|
69
71
|
const strokeDetails = requestedStrokeDetails(args, "createAreaMark");
|
|
70
72
|
const id = resolveMarkId(this, args.id, {
|
|
71
73
|
defaultId: "area",
|
|
@@ -101,6 +103,7 @@ const createAreaMark = /* @__PURE__ */ action(
|
|
|
101
103
|
...resolveMarkGraphicPlacement(created, { data, markType: "area" })
|
|
102
104
|
})
|
|
103
105
|
._withMarkConfig(id, {
|
|
106
|
+
...requestedMarkClip(args),
|
|
104
107
|
fill,
|
|
105
108
|
opacity,
|
|
106
109
|
...(Object.hasOwn(args, "curve") ? { curve } : {}),
|
|
@@ -154,6 +157,7 @@ const rematerializeAreaMark = /* @__PURE__ */ action(
|
|
|
154
157
|
const highlighted = rematerializeHighlightBaseline(this, {
|
|
155
158
|
target: id,
|
|
156
159
|
operation: "rematerializeAreaMark",
|
|
160
|
+
scales: args.scales,
|
|
157
161
|
resetProperty: "length",
|
|
158
162
|
resetValue: 0
|
|
159
163
|
});
|
|
@@ -240,9 +244,10 @@ const editAreaMark = /* @__PURE__ */ action(
|
|
|
240
244
|
},
|
|
241
245
|
function (args = {}) {
|
|
242
246
|
validateMarkOptions(args, EDIT_OPTIONS, "editAreaMark");
|
|
247
|
+
requestedMarkClip(args);
|
|
243
248
|
const strokeDetails = requestedStrokeDetails(args, "editAreaMark");
|
|
244
249
|
const changes = [
|
|
245
|
-
"fill", "opacity", "stroke", "strokeWidth", "curve", "missing",
|
|
250
|
+
"clip", "fill", "opacity", "stroke", "strokeWidth", "curve", "missing",
|
|
246
251
|
...STROKE_STYLE_PROPERTIES
|
|
247
252
|
];
|
|
248
253
|
if (!changes.some(key => Object.hasOwn(args, key))) {
|
|
@@ -272,7 +277,8 @@ const editAreaMark = /* @__PURE__ */ action(
|
|
|
272
277
|
throw new Error("editAreaMark cannot set strokeWidth while removing stroke.");
|
|
273
278
|
}
|
|
274
279
|
|
|
275
|
-
|
|
280
|
+
validateMarkClipCoordinate(this, layer, args.clip ?? this.markConfigs[layer.id]?.clip);
|
|
281
|
+
let config = { ...this.markConfigs[layer.id], ...requestedMarkClip(args) };
|
|
276
282
|
Object.assign(config, strokeDetails);
|
|
277
283
|
if (Object.hasOwn(args, "fill")) {
|
|
278
284
|
config.fill = validateFillPaint(args.fill, "Area fill");
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { requestedMarkClip } from "../../../selectors/markClip.js";
|
|
1
2
|
import { action } from "../../../core/action.js";
|
|
2
3
|
import {
|
|
3
4
|
assertMarkAvailable,
|
|
@@ -17,7 +18,7 @@ import { STROKE_STYLE_PROPERTIES } from
|
|
|
17
18
|
import { validateItemMissing } from "../../../grammar/itemMissing.js";
|
|
18
19
|
|
|
19
20
|
const CREATE_OPTIONS = Object.freeze([
|
|
20
|
-
"id", "data", "orientation", "missing", "fill", "opacity", "stroke", "strokeWidth",
|
|
21
|
+
"clip", "id", "data", "orientation", "missing", "fill", "opacity", "stroke", "strokeWidth",
|
|
21
22
|
...RECT_RADIUS_PROPERTIES, ...STROKE_STYLE_PROPERTIES
|
|
22
23
|
]);
|
|
23
24
|
|
|
@@ -28,6 +29,7 @@ export const createBarMark = /* @__PURE__ */ action(
|
|
|
28
29
|
},
|
|
29
30
|
function (args = {}) {
|
|
30
31
|
validateMarkOptions(args, CREATE_OPTIONS, "createBarMark");
|
|
32
|
+
requestedMarkClip(args);
|
|
31
33
|
requestedRectStyleDetails(args, "createBarMark");
|
|
32
34
|
if (args.orientation !== undefined && !["vertical", "horizontal"].includes(args.orientation)) {
|
|
33
35
|
throw new Error("Bar orientation must be vertical or horizontal.");
|
|
@@ -76,7 +78,7 @@ export const createBarMark = /* @__PURE__ */ action(
|
|
|
76
78
|
created = materializeInheritedMark(created, id);
|
|
77
79
|
const appearance = Object.fromEntries(
|
|
78
80
|
[
|
|
79
|
-
"fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
|
|
81
|
+
"clip", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
|
|
80
82
|
...STROKE_STYLE_PROPERTIES
|
|
81
83
|
]
|
|
82
84
|
.filter(property => Object.hasOwn(args, property))
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { requestedMarkClip, validateMarkClipCoordinate } from "../../../selectors/markClip.js";
|
|
1
2
|
import { action } from "../../../core/action.js";
|
|
2
3
|
import { validateUserId } from "../../../core/identifiers.js";
|
|
3
4
|
import {
|
|
@@ -18,7 +19,7 @@ import { validateFillPaint } from "../../../grammar/paint.js";
|
|
|
18
19
|
import { validateItemMissing } from "../../../grammar/itemMissing.js";
|
|
19
20
|
|
|
20
21
|
const EDIT_OPTIONS = Object.freeze([
|
|
21
|
-
"target", "missing", "blend", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
|
|
22
|
+
"target", "clip", "missing", "blend", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
|
|
22
23
|
...STROKE_STYLE_PROPERTIES
|
|
23
24
|
]);
|
|
24
25
|
|
|
@@ -29,9 +30,10 @@ export const editBarMark = /* @__PURE__ */ action(
|
|
|
29
30
|
},
|
|
30
31
|
function (args = {}) {
|
|
31
32
|
validateMarkOptions(args, EDIT_OPTIONS, "editBarMark");
|
|
33
|
+
requestedMarkClip(args);
|
|
32
34
|
const styleDetails = requestedRectStyleDetails(args, "editBarMark");
|
|
33
35
|
const changes = [
|
|
34
|
-
"missing", "blend", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
|
|
36
|
+
"clip", "missing", "blend", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
|
|
35
37
|
...STROKE_STYLE_PROPERTIES
|
|
36
38
|
];
|
|
37
39
|
if (!changes.some(key => Object.hasOwn(args, key))) {
|
|
@@ -71,7 +73,8 @@ export const editBarMark = /* @__PURE__ */ action(
|
|
|
71
73
|
}
|
|
72
74
|
const missing = Object.hasOwn(args, "missing")
|
|
73
75
|
? validateItemMissing(args.missing, "Bar missing") : undefined;
|
|
74
|
-
|
|
76
|
+
validateMarkClipCoordinate(this, layer, args.clip ?? this.markConfigs[layer.id]?.clip);
|
|
77
|
+
const config = { ...this.markConfigs[layer.id], ...requestedMarkClip(args) };
|
|
75
78
|
const appearance = { ...config.barAppearance };
|
|
76
79
|
Object.assign(appearance, styleDetails);
|
|
77
80
|
if (Object.hasOwn(args, "fill")) {
|
|
@@ -115,11 +118,11 @@ export const editBarMark = /* @__PURE__ */ action(
|
|
|
115
118
|
semantic = semantic.editSemantic({property: `layer[${layer.id}].mark.blend`, remove: true});
|
|
116
119
|
}
|
|
117
120
|
}
|
|
118
|
-
const editsAppearance = changes.some(key => key !== "missing" && key !== "blend" &&
|
|
121
|
+
const editsAppearance = changes.some(key => key !== "missing" && key !== "blend" && key !== "clip" &&
|
|
119
122
|
Object.hasOwn(args, key));
|
|
120
|
-
const next = editsAppearance ? semantic._withMarkConfig(layer.id, {
|
|
123
|
+
const next = editsAppearance || Object.hasOwn(args, "clip") ? semantic._withMarkConfig(layer.id, {
|
|
121
124
|
...config,
|
|
122
|
-
barAppearance: appearance
|
|
125
|
+
...(editsAppearance ? {barAppearance: appearance} : {})
|
|
123
126
|
}) : semantic;
|
|
124
127
|
const materialized = canMaterializeBar(next, layer)
|
|
125
128
|
? next.rematerializeBarMark({ id: layer.id })
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { materializeMarkClip } from "../../../materialization/markClip.js";
|
|
1
2
|
import { findLayer } from "../../../selectors/layers.js";
|
|
2
3
|
import { editGraphicProperties } from "../../primitives/graphicProperties.js";
|
|
3
4
|
import { action } from "../../../core/action.js";
|
|
@@ -29,12 +30,12 @@ function editRectangles(program, id, rectangles) {
|
|
|
29
30
|
item.properties?.blend !== undefined);
|
|
30
31
|
if (hasShapeStyle || blend !== undefined || previousBlend) {
|
|
31
32
|
const radius = appearance;
|
|
32
|
-
return replaceGraphicItems(
|
|
33
|
+
return materializeMarkClip(replaceGraphicItems(
|
|
33
34
|
program,
|
|
34
35
|
id,
|
|
35
36
|
"rect",
|
|
36
37
|
rectangles.map(rectangle => materializeRectItem(rectangle, radius))
|
|
37
|
-
);
|
|
38
|
+
), id);
|
|
38
39
|
}
|
|
39
40
|
let next = editGraphicProperties(program, id, {
|
|
40
41
|
length: rectangles.length,
|
|
@@ -53,7 +54,7 @@ function editRectangles(program, id, rectangles) {
|
|
|
53
54
|
value: rectangles.map(rect => rect.opacity ?? 1)
|
|
54
55
|
});
|
|
55
56
|
}
|
|
56
|
-
return next;
|
|
57
|
+
return materializeMarkClip(next, id);
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
export const rematerializeBarMark = /* @__PURE__ */ action(
|
|
@@ -74,6 +75,7 @@ export const rematerializeBarMark = /* @__PURE__ */ action(
|
|
|
74
75
|
const highlighted = rematerializeHighlightBaseline(this, {
|
|
75
76
|
target: id,
|
|
76
77
|
operation: "rematerializeBarMark",
|
|
78
|
+
scales: args.scales,
|
|
77
79
|
resetProperty: "items",
|
|
78
80
|
resetValue: []
|
|
79
81
|
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { findLayer } from "../../selectors/layers.js";
|
|
2
|
+
import { ownedChildren } from "../../selectors/markOwners.js";
|
|
3
|
+
import { findGraphicParent } from "../../grammar/schemas/graphicTree.js";
|
|
4
|
+
import { applyLayerDataRematerialization } from "../../materialization/dependencies.js";
|
|
5
|
+
|
|
6
|
+
export function retainStatisticalDependents(program, ownerId) {
|
|
7
|
+
const references = new Map();
|
|
8
|
+
const visited = new Set();
|
|
9
|
+
const visit = id => {
|
|
10
|
+
if (visited.has(id)) return;
|
|
11
|
+
visited.add(id);
|
|
12
|
+
const config = program.markConfigs[id]?.statisticalReference;
|
|
13
|
+
if (config !== undefined) references.set(id, {
|
|
14
|
+
config, encoding: findLayer(program, id).encoding
|
|
15
|
+
});
|
|
16
|
+
for (const child of ownedChildren(program, id)) visit(child);
|
|
17
|
+
};
|
|
18
|
+
visit(ownerId);
|
|
19
|
+
let next = program;
|
|
20
|
+
// Keep independently authored references and their labels through the
|
|
21
|
+
// component replacement; removeMark otherwise treats them as source-owned.
|
|
22
|
+
for (const id of references.keys()) {
|
|
23
|
+
const { statisticalReference, ...config } = next.markConfigs[id];
|
|
24
|
+
next = next._withMarkConfig(id, config);
|
|
25
|
+
// Detached statistics must not temporarily look like ordinary data marks:
|
|
26
|
+
// their derived value field would pollute axis-title/domain inference while
|
|
27
|
+
// replacement components fulfill their guides.
|
|
28
|
+
const encoding = findLayer(next, id).encoding;
|
|
29
|
+
for (const channel of ["x", "y", "x2", "y2"]) {
|
|
30
|
+
if (encoding[channel] !== undefined) {
|
|
31
|
+
next = next.editSemantic({ property: `layer[${id}].encoding.${channel}`, remove: true });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return { program: next, references };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function restoreStatisticalDependents(program, references, { fallbackSource, fromAxis, toAxis }) {
|
|
39
|
+
if (references.size === 0) return program;
|
|
40
|
+
let next = program;
|
|
41
|
+
const sources = new Set();
|
|
42
|
+
for (const [id, { config, encoding }] of references) {
|
|
43
|
+
const source = findLayer(next, config.source) === undefined ? fallbackSource : config.source;
|
|
44
|
+
const axis = config.axis === fromAxis ? toAxis : config.axis;
|
|
45
|
+
const channels = fromAxis === toAxis ? [["x", "x"], ["y", "y"], ["x2", "x2"], ["y2", "y2"]]
|
|
46
|
+
: [["x", "y"], ["y", "x"], ["x2", "y2"], ["y2", "x2"]];
|
|
47
|
+
for (const [from, to] of channels) {
|
|
48
|
+
for (const [key, value] of Object.entries(encoding[from] ?? {})) {
|
|
49
|
+
next = next.editSemantic({ property: `layer[${id}].encoding.${to}.${key}`, value });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
next = next._withMarkConfig(id, {
|
|
53
|
+
...next.markConfigs[id],
|
|
54
|
+
statisticalReference: { ...config, source, axis }
|
|
55
|
+
});
|
|
56
|
+
sources.add(source);
|
|
57
|
+
}
|
|
58
|
+
// Recreate these graphics after the new components, retaining overlays'
|
|
59
|
+
// authored styles while placing them above their source as before.
|
|
60
|
+
const graphics = new Map();
|
|
61
|
+
const removeGraphics = id => {
|
|
62
|
+
if (graphics.has(id)) return;
|
|
63
|
+
graphics.set(id, {
|
|
64
|
+
graphic: next.graphicSpec.objects[id],
|
|
65
|
+
parent: findGraphicParent(next.graphicSpec, id)?.id
|
|
66
|
+
});
|
|
67
|
+
for (const child of ownedChildren(next, id)) removeGraphics(child);
|
|
68
|
+
if (next.graphicSpec.objects[id] !== undefined) {
|
|
69
|
+
next = next.editGraphics({ target: id, remove: true });
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
for (const id of references.keys()) removeGraphics(id);
|
|
73
|
+
for (const [id, { graphic, parent }] of graphics) {
|
|
74
|
+
if (graphic !== undefined) {
|
|
75
|
+
next = next.createGraphics({
|
|
76
|
+
id, type: graphic.type, ...(parent === undefined ? {} : { parent }),
|
|
77
|
+
...(graphic.type === "collection" || graphic.items === undefined ? {} : { length: 0 })
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
for (const source of sources) next = applyLayerDataRematerialization(next, source);
|
|
82
|
+
for (const id of references.keys()) {
|
|
83
|
+
if (ownedChildren(next, id).length > 0) next = applyLayerDataRematerialization(next, id);
|
|
84
|
+
}
|
|
85
|
+
return next._withContext(program.context);
|
|
86
|
+
}
|
|
87
|
+
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { removeMark } from "./remove.js";
|
|
2
2
|
import {
|
|
3
|
+
createStatisticalReference,
|
|
3
4
|
createReferenceLine,
|
|
4
5
|
createReferenceBand,
|
|
5
6
|
materializeStatisticalReferenceData,
|
|
@@ -32,6 +33,7 @@ export function registerMarkActions(ProgramClass) {
|
|
|
32
33
|
registerTextMarkActions(ProgramClass);
|
|
33
34
|
registerTickMarkActions(ProgramClass);
|
|
34
35
|
ProgramClass.prototype.removeMark = removeMark;
|
|
36
|
+
ProgramClass.prototype.createStatisticalReference = createStatisticalReference;
|
|
35
37
|
ProgramClass.prototype.createReferenceLine = createReferenceLine;
|
|
36
38
|
ProgramClass.prototype.createReferenceBand = createReferenceBand;
|
|
37
39
|
ProgramClass.prototype.materializeStatisticalReferenceData =
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export function rematerializeHighlightBaseline(program, {
|
|
2
2
|
target,
|
|
3
3
|
operation,
|
|
4
|
+
scales,
|
|
4
5
|
resetProperty,
|
|
5
6
|
resetValue
|
|
6
7
|
}) {
|
|
@@ -22,6 +23,6 @@ export function rematerializeHighlightBaseline(program, {
|
|
|
22
23
|
property: resetProperty,
|
|
23
24
|
value: resetValue
|
|
24
25
|
})
|
|
25
|
-
[operation]({ id: target })
|
|
26
|
+
[operation]({ id: target, ...(scales === undefined ? {} : { scales }) })
|
|
26
27
|
.rematerializeMarkHighlights({ target, highlights });
|
|
27
28
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { requestedMarkClip, validateMarkClipCoordinate } from "../../../selectors/markClip.js";
|
|
1
2
|
import { action } from "../../../core/action.js";
|
|
2
3
|
import { validateUserId } from "../../../core/identifiers.js";
|
|
3
4
|
import {
|
|
@@ -34,6 +35,7 @@ import {
|
|
|
34
35
|
resolvePositionedLineMaterialization
|
|
35
36
|
} from "./materialize.js";
|
|
36
37
|
import { resolveLineBins } from "../../../grammar/lineSeries.js";
|
|
38
|
+
import { validateLineMissing, validateLineMissingScope } from "../../../grammar/lineMissing.js";
|
|
37
39
|
import { requireSemanticScale } from "../../../selectors/scales.js";
|
|
38
40
|
import {
|
|
39
41
|
requestedStrokeDetails,
|
|
@@ -43,11 +45,11 @@ import {
|
|
|
43
45
|
const DEFAULT_LINE_STROKE = DEFAULT_COLORS.mark;
|
|
44
46
|
const DEFAULT_LINE_WIDTH = 2;
|
|
45
47
|
const CREATE_OPTIONS = Object.freeze([
|
|
46
|
-
"id", "data", "stroke", "strokeWidth", "opacity", "curve", "tension", "closed",
|
|
48
|
+
"clip", "missing", "id", "data", "stroke", "strokeWidth", "opacity", "curve", "tension", "closed",
|
|
47
49
|
...STROKE_STYLE_PROPERTIES
|
|
48
50
|
]);
|
|
49
51
|
const EDIT_OPTIONS = Object.freeze([
|
|
50
|
-
"target", "stroke", "strokeWidth", "opacity", "curve", "tension", "closed",
|
|
52
|
+
"clip", "missing", "target", "stroke", "strokeWidth", "opacity", "curve", "tension", "closed",
|
|
51
53
|
...STROKE_STYLE_PROPERTIES
|
|
52
54
|
]);
|
|
53
55
|
const REMATERIALIZE_OPTIONS = Object.freeze(["id", "scales"]);
|
|
@@ -100,7 +102,9 @@ const createLineMark = /* @__PURE__ */ action(
|
|
|
100
102
|
},
|
|
101
103
|
function (args = {}) {
|
|
102
104
|
validateMarkOptions(args, CREATE_OPTIONS, "createLineMark");
|
|
105
|
+
requestedMarkClip(args);
|
|
103
106
|
const strokeDetails = requestedStrokeDetails(args, "createLineMark");
|
|
107
|
+
const missing = validateLineMissing(args.missing);
|
|
104
108
|
const id = resolveMarkId(this, args.id, {
|
|
105
109
|
defaultId: "line",
|
|
106
110
|
label: "Line mark id",
|
|
@@ -140,6 +144,10 @@ const createLineMark = /* @__PURE__ */ action(
|
|
|
140
144
|
value: data
|
|
141
145
|
});
|
|
142
146
|
created = applyLayeredMarkInheritance(created, id, inherited);
|
|
147
|
+
if (Object.hasOwn(args, "missing")) {
|
|
148
|
+
created = created.editSemantic({ property: `layer[${id}].mark.missing`, value: missing });
|
|
149
|
+
}
|
|
150
|
+
validateLineMissingScope(findLayer(created, id));
|
|
143
151
|
created = created
|
|
144
152
|
.createGraphics({
|
|
145
153
|
id,
|
|
@@ -159,6 +167,7 @@ const createLineMark = /* @__PURE__ */ action(
|
|
|
159
167
|
);
|
|
160
168
|
created = materializeInheritedMark(created, id);
|
|
161
169
|
const appearance = {
|
|
170
|
+
...requestedMarkClip(args),
|
|
162
171
|
...(stroke === undefined ? {} : { stroke }),
|
|
163
172
|
...(opacity === undefined ? {} : { opacity })
|
|
164
173
|
};
|
|
@@ -203,11 +212,13 @@ const rematerializeLineMark = /* @__PURE__ */ action(
|
|
|
203
212
|
const highlighted = rematerializeHighlightBaseline(this, {
|
|
204
213
|
target: id,
|
|
205
214
|
operation: "rematerializeLineMark",
|
|
215
|
+
scales: args.scales,
|
|
206
216
|
resetProperty: "length",
|
|
207
217
|
resetValue: 0
|
|
208
218
|
});
|
|
209
219
|
if (highlighted !== undefined) return highlighted;
|
|
210
220
|
const { dataset, layer } = requireLine(this, id);
|
|
221
|
+
validateLineMissingScope(layer);
|
|
211
222
|
const existingChildren = this.graphicSpec.objects[id].items;
|
|
212
223
|
const parallel = layer.encoding?.parallel;
|
|
213
224
|
const xScaleId = layer.encoding?.x?.scale;
|
|
@@ -277,9 +288,10 @@ const editLineMark = /* @__PURE__ */ action(
|
|
|
277
288
|
},
|
|
278
289
|
function (args = {}) {
|
|
279
290
|
validateMarkOptions(args, EDIT_OPTIONS, "editLineMark");
|
|
291
|
+
requestedMarkClip(args);
|
|
280
292
|
const strokeDetails = requestedStrokeDetails(args, "editLineMark");
|
|
281
|
-
if (!EDIT_OPTIONS.
|
|
282
|
-
throw new Error("editLineMark requires stroke, strokeWidth, opacity, curve, tension, or
|
|
293
|
+
if (!EDIT_OPTIONS.filter(key => key !== "target").some(key => Object.hasOwn(args, key))) {
|
|
294
|
+
throw new Error("editLineMark requires stroke, strokeWidth, opacity, curve, tension, closed, or missing.");
|
|
283
295
|
}
|
|
284
296
|
const target = Object.hasOwn(args, "target")
|
|
285
297
|
? validateUserId(args.target, "Line mark id")
|
|
@@ -306,7 +318,8 @@ const editLineMark = /* @__PURE__ */ action(
|
|
|
306
318
|
(layer.encoding?.x !== undefined || isParallelLine(layer))) {
|
|
307
319
|
throw new Error("Line closed requires theta/radius Polar position encodings.");
|
|
308
320
|
}
|
|
309
|
-
|
|
321
|
+
validateMarkClipCoordinate(this, layer, args.clip ?? this.markConfigs[layer.id]?.clip);
|
|
322
|
+
const config = { ...this.markConfigs[layer.id], ...requestedMarkClip(args) };
|
|
310
323
|
Object.assign(config, strokeDetails);
|
|
311
324
|
for (const [key, validate] of Object.entries({
|
|
312
325
|
stroke: validateNonEmptyString,
|
|
@@ -323,7 +336,12 @@ const editLineMark = /* @__PURE__ */ action(
|
|
|
323
336
|
if (Object.hasOwn(args, "tension")) config.tension = args.tension;
|
|
324
337
|
validateCardinalTension(config.tension, config.curve ?? "linear");
|
|
325
338
|
validatePolarLineConfig(layer, config);
|
|
326
|
-
|
|
339
|
+
let next = this._withMarkConfig(layer.id, config);
|
|
340
|
+
if (Object.hasOwn(args, "missing")) {
|
|
341
|
+
const missing = validateLineMissing(args.missing);
|
|
342
|
+
validateLineMissingScope({ ...layer, mark: { ...layer.mark, missing } });
|
|
343
|
+
next = next.editSemantic({ property: `layer[${layer.id}].mark.missing`, value: missing });
|
|
344
|
+
}
|
|
327
345
|
const materialized = canMaterializeLine(next, layer)
|
|
328
346
|
? next.rematerializeLineMark({ id: layer.id })
|
|
329
347
|
: next;
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
mapContinuousScaleValues,
|
|
6
6
|
mapOrdinalPositionValues,
|
|
7
|
+
readScaleField,
|
|
7
8
|
normalizeStrokeDashPattern
|
|
8
9
|
} from "../../../grammar/scales/index.js";
|
|
9
10
|
import { buildCurvePathCommands } from
|
|
@@ -55,7 +56,9 @@ export function resolveParallelLineMaterialization({
|
|
|
55
56
|
);
|
|
56
57
|
const sourceRows = items.map(item => rows[item.sourceRowIndex]);
|
|
57
58
|
const mapAppearance = appearanceMapper(layer, resolvedScales,
|
|
58
|
-
field => sourceRows.
|
|
59
|
+
(field, channel, encoding) => readScaleField(sourceRows, field, encoding.fieldType, {
|
|
60
|
+
temporalUnit: encoding.temporalUnit
|
|
61
|
+
}));
|
|
59
62
|
return {
|
|
60
63
|
commands: items.map(item => item.commands),
|
|
61
64
|
strokes: layer.encoding?.stroke?.scale !== undefined
|
|
@@ -99,7 +102,7 @@ export function resolvePositionedLineMaterialization({
|
|
|
99
102
|
const lineOptions = polar
|
|
100
103
|
? { thetaDomain: resolvedScales[thetaScaleId].domain }
|
|
101
104
|
: { xBinBoundaries, xDomain: resolvedScales[xScaleId].domain };
|
|
102
|
-
const derived = deriveLineSeries(rows, layer, lineOptions);
|
|
105
|
+
const derived = deriveLineSeries(rows, layer, { ...lineOptions, scales: resolvedScales });
|
|
103
106
|
const commands = polar
|
|
104
107
|
? derived.series.map(series => buildPolarLinePathCommands({
|
|
105
108
|
series: series.values,
|
|
@@ -134,7 +137,8 @@ export function resolvePositionedLineMaterialization({
|
|
|
134
137
|
derived.series,
|
|
135
138
|
field,
|
|
136
139
|
channel,
|
|
137
|
-
encoding
|
|
140
|
+
encoding,
|
|
141
|
+
channel === "color" ? resolvedScales[encoding.scale] : undefined
|
|
138
142
|
));
|
|
139
143
|
return {
|
|
140
144
|
commands,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { requestedMarkClip } from "../../../selectors/markClip.js";
|
|
1
2
|
import { action } from "../../../core/action.js";
|
|
2
3
|
import { validatePointShape } from "../../../grammar/pointShapes.js";
|
|
3
4
|
import { getPointGraphicType } from "../../../grammar/schemas/mark.js";
|
|
@@ -19,7 +20,7 @@ import {
|
|
|
19
20
|
import { validateItemMissing } from "../../../grammar/itemMissing.js";
|
|
20
21
|
|
|
21
22
|
const OPTIONS = Object.freeze([
|
|
22
|
-
"id", "data", "missing", "shape", "fill", "opacity", "stroke", "strokeWidth",
|
|
23
|
+
"clip", "id", "data", "missing", "shape", "fill", "opacity", "stroke", "strokeWidth",
|
|
23
24
|
...STROKE_STYLE_PROPERTIES
|
|
24
25
|
]);
|
|
25
26
|
|
|
@@ -30,6 +31,7 @@ export const createPointMark = /* @__PURE__ */ action(
|
|
|
30
31
|
},
|
|
31
32
|
function (args = {}) {
|
|
32
33
|
validateMarkOptions(args, OPTIONS, "createPointMark");
|
|
34
|
+
requestedMarkClip(args);
|
|
33
35
|
requestedStrokeDetails(args, "createPointMark");
|
|
34
36
|
const id = resolveMarkId(this, args.id, {
|
|
35
37
|
defaultId: "point",
|
|
@@ -46,8 +48,7 @@ export const createPointMark = /* @__PURE__ */ action(
|
|
|
46
48
|
? { data: inherited.data }
|
|
47
49
|
: {})
|
|
48
50
|
});
|
|
49
|
-
const shape = Object.hasOwn(args, "shape") ? args.shape : "circle";
|
|
50
|
-
validatePointShape(shape);
|
|
51
|
+
const shape = validatePointShape(Object.hasOwn(args, "shape") ? args.shape : "circle");
|
|
51
52
|
const resolvedType = getPointGraphicType(shape);
|
|
52
53
|
const graphicType = resolvedType === "path" ? "circle" : resolvedType;
|
|
53
54
|
|
|
@@ -78,7 +79,7 @@ export const createPointMark = /* @__PURE__ */ action(
|
|
|
78
79
|
._withMarkConfig(id, { shape });
|
|
79
80
|
const created = materializeInheritedMark(next, id);
|
|
80
81
|
const appearance = Object.fromEntries(
|
|
81
|
-
["fill", "opacity", "stroke", "strokeWidth", ...STROKE_STYLE_PROPERTIES]
|
|
82
|
+
["clip", "fill", "opacity", "stroke", "strokeWidth", ...STROKE_STYLE_PROPERTIES]
|
|
82
83
|
.filter(property => Object.hasOwn(args, property))
|
|
83
84
|
.map(property => [property, args[property]])
|
|
84
85
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { requestedMarkClip, validateMarkClipCoordinate } from "../../../selectors/markClip.js";
|
|
1
2
|
import { action } from "../../../core/action.js";
|
|
2
3
|
import { validateUserId } from "../../../core/identifiers.js";
|
|
3
4
|
import {
|
|
@@ -16,7 +17,7 @@ import { validateMarkOptions } from "../shared.js";
|
|
|
16
17
|
import { validateItemMissing } from "../../../grammar/itemMissing.js";
|
|
17
18
|
|
|
18
19
|
const OPTIONS = Object.freeze([
|
|
19
|
-
"target", "missing", "shape", "fill", "opacity", "stroke", "strokeWidth",
|
|
20
|
+
"target", "clip", "missing", "shape", "fill", "opacity", "stroke", "strokeWidth",
|
|
20
21
|
...STROKE_STYLE_PROPERTIES
|
|
21
22
|
]);
|
|
22
23
|
|
|
@@ -27,9 +28,10 @@ export const editPointMark = /* @__PURE__ */ action(
|
|
|
27
28
|
},
|
|
28
29
|
function (args = {}) {
|
|
29
30
|
validateMarkOptions(args, OPTIONS, "editPointMark");
|
|
31
|
+
requestedMarkClip(args);
|
|
30
32
|
const strokeDetails = requestedStrokeDetails(args, "editPointMark");
|
|
31
33
|
const editable = [
|
|
32
|
-
"missing", "shape", "fill", "opacity", "stroke", "strokeWidth",
|
|
34
|
+
"clip", "missing", "shape", "fill", "opacity", "stroke", "strokeWidth",
|
|
33
35
|
...STROKE_STYLE_PROPERTIES
|
|
34
36
|
];
|
|
35
37
|
if (!editable.some(property => Object.hasOwn(args, property))) {
|
|
@@ -62,13 +64,14 @@ export const editPointMark = /* @__PURE__ */ action(
|
|
|
62
64
|
if (Object.hasOwn(args, "opacity") && layer.encoding?.opacity?.field !== undefined) {
|
|
63
65
|
throw new Error("editPointMark opacity conflicts with a field encoding; use encodeOpacity with value to replace it.");
|
|
64
66
|
}
|
|
67
|
+
validateMarkClipCoordinate(this, layer, args.clip ?? this.markConfigs[id]?.clip);
|
|
65
68
|
const semantic = Object.hasOwn(args, "missing")
|
|
66
69
|
? this.editSemantic({
|
|
67
70
|
property: `layer[${id}].mark.missing`,
|
|
68
71
|
value: validateItemMissing(args.missing, "Point missing")
|
|
69
72
|
})
|
|
70
73
|
: this;
|
|
71
|
-
const config = { ...semantic.markConfigs[id] };
|
|
74
|
+
const config = { ...semantic.markConfigs[id], ...requestedMarkClip(args) };
|
|
72
75
|
Object.assign(config, strokeDetails);
|
|
73
76
|
if (Object.hasOwn(args, "shape")) {
|
|
74
77
|
config.shape = validatePointShape(args.shape);
|
|
@@ -10,20 +10,20 @@ const JITTER_OPTIONS = Object.freeze([
|
|
|
10
10
|
]);
|
|
11
11
|
const REMOVE_OPTIONS = Object.freeze(["target"]);
|
|
12
12
|
|
|
13
|
-
function isCartesianPoint(program, layer
|
|
13
|
+
function isCartesianPoint(program, layer) {
|
|
14
14
|
return layer.mark?.type === "point" &&
|
|
15
|
-
layer.encoding?.
|
|
16
|
-
layer.encoding?.
|
|
15
|
+
layer.encoding?.x?.scale !== undefined &&
|
|
16
|
+
layer.encoding?.y?.scale !== undefined &&
|
|
17
17
|
findCoordinate(program, layer.coordinate)?.type === "cartesian";
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
function resolveJitterTarget(program, target
|
|
20
|
+
function resolveJitterTarget(program, target) {
|
|
21
21
|
const requested = target === undefined
|
|
22
22
|
? undefined
|
|
23
23
|
: validateUserId(target, "Point jitter target");
|
|
24
24
|
return resolveEligibleLayer(program, {
|
|
25
25
|
target: requested,
|
|
26
|
-
predicate: layer => isCartesianPoint(program, layer
|
|
26
|
+
predicate: layer => isCartesianPoint(program, layer),
|
|
27
27
|
label: "point jitter"
|
|
28
28
|
});
|
|
29
29
|
}
|
|
@@ -35,7 +35,7 @@ export const jitterPoints = /* @__PURE__ */ closedAction(
|
|
|
35
35
|
}, JITTER_OPTIONS,
|
|
36
36
|
function (args = {}) {
|
|
37
37
|
const policy = normalizePointJitterPolicy(args);
|
|
38
|
-
const layer = resolveJitterTarget(this, args.target
|
|
38
|
+
const layer = resolveJitterTarget(this, args.target);
|
|
39
39
|
if (this.materializationConfigs.pointPacking?.[layer.id] !== undefined) {
|
|
40
40
|
throw new Error(`Point jitter on "${layer.id}" conflicts with point packing.`);
|
|
41
41
|
}
|