ggaction 0.0.16 → 0.0.18
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 +66 -0
- package/README.md +3 -2
- 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/knowledge/task-resolver.js +1 -1
- package/package.json +10 -4
- package/src/BasicChartProgram.js +1 -1
- package/src/accessibility.js +3 -2
- package/src/actions/boxPlots/create.js +14 -4
- package/src/actions/boxPlots/edit.js +39 -33
- package/src/actions/boxPlots/materialize.js +7 -3
- package/src/actions/boxPlots/options.js +37 -11
- package/src/actions/canvas/actions.js +70 -95
- package/src/actions/canvas/fitting.js +16 -1
- package/src/actions/canvas/index.js +3 -0
- package/src/actions/canvas/plotBorder.js +28 -0
- package/src/actions/charts/area.js +2 -2
- package/src/actions/charts/bar.js +34 -7
- package/src/actions/charts/ecdf.js +4 -18
- package/src/actions/charts/endpoints.js +4 -18
- package/src/actions/charts/heatmap.js +4 -4
- package/src/actions/charts/index.js +2 -0
- package/src/actions/charts/interval-regression.js +2 -2
- package/src/actions/charts/line.js +1 -1
- package/src/actions/charts/pie.js +3 -47
- package/src/actions/charts/radial.js +34 -12
- package/src/actions/charts/scatter.js +16 -2
- package/src/actions/charts/shared.js +2 -2
- package/src/actions/charts/text.js +35 -0
- package/src/actions/composition/actions.js +6 -2
- package/src/actions/data/bin.js +1 -1
- package/src/actions/data/box.js +2 -1
- package/src/actions/data/create.js +18 -5
- package/src/actions/data/density.js +1 -1
- package/src/actions/data/derived.js +15 -1
- package/src/actions/data/edit.js +20 -7
- package/src/actions/data/filter.js +15 -4
- package/src/actions/data/index.js +3 -0
- package/src/actions/data/interval.js +2 -0
- package/src/actions/data/regression.js +6 -2
- package/src/actions/data/revise.js +37 -5
- package/src/actions/data/shared.js +33 -4
- package/src/actions/data/sort.js +21 -0
- package/src/actions/data/stack.js +3 -1
- package/src/actions/data/summary.js +1 -1
- package/src/actions/encodings/angle.js +4 -1
- package/src/actions/encodings/appearance.js +43 -31
- package/src/actions/encodings/barWidth.js +36 -11
- package/src/actions/encodings/channels.js +0 -1
- package/src/actions/encodings/color/continuous.js +5 -2
- package/src/actions/encodings/color/index.js +5 -2
- package/src/actions/encodings/color/policy.js +10 -3
- package/src/actions/encodings/density/resolve.js +1 -6
- package/src/actions/encodings/offset.js +4 -1
- package/src/actions/encodings/position/policies/arc.js +12 -10
- package/src/actions/encodings/position/policies/area.js +3 -3
- package/src/actions/encodings/position/policies/bar.js +15 -6
- package/src/actions/encodings/position/policies/line.js +17 -6
- package/src/actions/encodings/position/resolve.js +9 -3
- package/src/actions/encodings/ranged.js +23 -1
- package/src/actions/encodings/remove.js +3 -2
- package/src/actions/encodings/ruleAppearance.js +4 -1
- package/src/actions/encodings/seriesLayout.js +1 -0
- package/src/actions/encodings/stroke.js +4 -1
- package/src/actions/encodings/strokeDash.js +6 -1
- package/src/actions/encodings/text.js +12 -4
- package/src/actions/errorBands/create.js +2 -2
- package/src/actions/errorBands/edit.js +2 -1
- package/src/actions/facets/actions.js +158 -240
- package/src/actions/gradientPlots/resolve.js +2 -17
- package/src/actions/guides/applicability.js +1 -1
- package/src/actions/guides/axes/axis.js +16 -4
- package/src/actions/guides/axes/edit.js +4 -4
- package/src/actions/guides/axes/labels.js +120 -46
- package/src/actions/guides/axes/lines.js +6 -5
- package/src/actions/guides/axes/parallel/lifecycle.js +1 -1
- package/src/actions/guides/axes/parallel/policy.js +8 -7
- package/src/actions/guides/axes/remove.js +3 -2
- package/src/actions/guides/axes/tickGroups.js +5 -2
- package/src/actions/guides/axes/ticks.js +6 -3
- package/src/actions/guides/axes/titles.js +71 -26
- package/src/actions/guides/basic.js +2 -0
- package/src/actions/guides/facadeLegend.js +10 -2
- package/src/actions/guides/grids/grid.js +7 -1
- package/src/actions/guides/grids/resolve.js +59 -12
- package/src/actions/guides/legends/blocks.js +3 -1
- package/src/actions/guides/legends/categorical/actions.js +70 -17
- package/src/actions/guides/legends/categorical/components.js +12 -8
- package/src/actions/guides/legends/categorical/index.js +6 -0
- package/src/actions/guides/legends/categorical/layout.js +37 -8
- package/src/actions/guides/legends/categorical/options.js +31 -20
- package/src/actions/guides/legends/categorical/resolve.js +2 -2
- package/src/actions/guides/legends/categorical/symbols.js +18 -12
- package/src/actions/guides/legends/categorical/validation.js +1 -6
- package/src/actions/guides/legends/continuous/colorSymbols.js +1 -0
- package/src/actions/guides/legends/continuous/common.js +1 -447
- package/src/actions/guides/legends/continuous/gradient.js +47 -34
- package/src/actions/guides/legends/continuous/interval.js +4 -4
- package/src/actions/guides/legends/continuous/opacity.js +19 -12
- package/src/actions/guides/legends/edit.js +1 -604
- package/src/actions/guides/legends/focused.js +2 -2
- package/src/actions/guides/legends/group.js +1 -0
- package/src/actions/guides/legends/lane.js +1 -516
- package/src/actions/guides/legends/remove.js +3 -0
- package/src/actions/guides/legends/sampling.js +1 -1
- package/src/actions/guides/legends/size.js +51 -43
- package/src/actions/guides/legends/strokeWidth.js +11 -29
- package/src/actions/guides/legends/target.js +3 -3
- package/src/actions/guides/legends/transition.js +21 -7
- package/src/actions/guides/polar/axes/labels.js +4 -2
- package/src/actions/guides/polar/axes/titles.js +7 -5
- package/src/actions/guides/polar/resolve.js +6 -14
- package/src/actions/index.js +16 -16
- package/src/actions/marks/arc/actions.js +3 -10
- package/src/actions/marks/area/actions.js +8 -5
- package/src/actions/marks/area/materialize.js +8 -9
- package/src/actions/marks/bar/create.js +17 -4
- package/src/actions/marks/bar/edit.js +18 -7
- package/src/actions/marks/bar/materialize.js +9 -6
- package/src/actions/marks/line/actions.js +11 -4
- package/src/actions/marks/line/materialize.js +9 -5
- package/src/actions/marks/point/create.js +8 -1
- package/src/actions/marks/point/edit.js +13 -6
- package/src/actions/marks/point/materialize.js +4 -2
- package/src/actions/marks/rect/actions.js +26 -11
- package/src/actions/marks/remove.js +2 -0
- package/src/actions/marks/rule/actions.js +31 -12
- package/src/actions/marks/text/actions.js +42 -11
- package/src/actions/marks/text/layout.js +3 -0
- package/src/actions/marks/tick/actions.js +23 -8
- package/src/actions/primitives/semanticAction.js +37 -3
- package/src/actions/primitives/semanticValidation/dataset.js +13 -1
- package/src/actions/primitives/semanticValidation/layer.js +26 -2
- package/src/actions/primitives/semanticValidation/scale.js +6 -0
- package/src/actions/regression/create.js +26 -5
- package/src/actions/regression/edit.js +50 -15
- package/src/actions/regression/follow.js +22 -0
- package/src/actions/regression/resolve.js +2 -6
- package/src/actions/scales/channels.js +20 -15
- package/src/actions/scales/consumers/common.js +2 -1
- package/src/actions/scales/consumers/families.js +16 -5
- package/src/actions/scales/create.js +10 -4
- package/src/actions/scales/definitions.js +1 -425
- package/src/actions/scales/edit.js +3 -3
- package/src/actions/scales/editPolicy.js +9 -3
- package/src/actions/scales/materialize.js +1 -1
- package/src/actions/scales/parallel.js +1 -1
- package/src/actions/scales/patch.js +1 -1
- package/src/actions/scales/preview.js +49 -2
- package/src/actions/scales/quantitativeColor.js +3 -3
- package/src/actions/selection/actions.js +1 -13
- package/src/actions/theme/reconcile.js +83 -27
- package/src/actions/theme/state.js +12 -0
- package/src/actions/titles/actions.js +5 -18
- package/src/actions/titles/resolve.js +41 -19
- package/src/actions/violinPlots/edit.js +3 -20
- package/src/core/action.js +3 -2
- package/src/core/compositionState.js +4 -1
- package/src/core/font.js +9 -2
- package/src/core/optionRequirements.js +1 -0
- package/src/core/programState.js +5 -1
- package/src/core/resourceReferences.js +3 -0
- package/src/core/textMetricProfile.js +3 -2
- package/src/core/textMetrics.js +41 -4
- package/src/core/validation.js +26 -0
- package/src/core/vocabulary.js +4 -0
- package/src/grammar/aggregate.js +4 -18
- package/src/grammar/arcs.js +1 -386
- package/src/grammar/areaPaint.js +10 -0
- package/src/grammar/areaSeries.js +18 -10
- package/src/grammar/bars/geometry.js +30 -3
- package/src/grammar/bars/policy.js +12 -1
- package/src/grammar/bin.js +41 -22
- package/src/grammar/bin2d.js +1 -6
- package/src/grammar/boxPlot.js +56 -9
- package/src/grammar/categoryOrder.js +1 -6
- package/src/grammar/complete.js +15 -19
- package/src/grammar/computed.js +92 -25
- package/src/grammar/curveCommands.js +29 -16
- package/src/grammar/datasetSchema.js +382 -0
- package/src/grammar/density.js +53 -5
- package/src/grammar/displayLabels.js +28 -0
- package/src/grammar/ecdf.js +2 -9
- package/src/grammar/facets/dependencies.js +6 -2
- package/src/grammar/facets/guides.js +5 -0
- package/src/grammar/facets/index.js +2 -5
- package/src/grammar/filter.js +133 -39
- package/src/grammar/fold.js +2 -12
- package/src/grammar/gradientProfile.js +1 -6
- package/src/grammar/impute.js +21 -48
- package/src/grammar/interval.js +34 -10
- package/src/grammar/itemMissing.js +59 -0
- package/src/grammar/legendGradient.js +18 -0
- package/src/grammar/legendGroups.js +1 -0
- package/src/grammar/legendTitleStyle.js +22 -0
- package/src/grammar/lineSeries.js +32 -17
- package/src/grammar/markLabels.js +5 -2
- package/src/grammar/normalize.js +4 -54
- package/src/grammar/numeric.js +1 -290
- package/src/grammar/parallelCoordinates.js +1 -6
- package/src/grammar/parseTime.js +41 -0
- package/src/grammar/pathCommands.js +11 -4
- package/src/grammar/polar.js +1 -184
- package/src/grammar/positionCompatibility.js +3 -3
- package/src/grammar/regression/derive.js +63 -16
- package/src/grammar/regression/index.js +1 -0
- package/src/grammar/regression/models.js +116 -59
- package/src/grammar/regression/parameters.js +69 -6
- package/src/grammar/roundedRect.js +42 -54
- package/src/grammar/scales/appearance.js +1 -206
- package/src/grammar/scales/color.js +1 -382
- package/src/grammar/scales/colorConsumers.js +5 -2
- package/src/grammar/scales/definition.js +1 -190
- package/src/grammar/scales/discretized.js +1 -195
- package/src/grammar/scales/size.js +1 -456
- package/src/grammar/scales/temporal.js +2 -13
- package/src/grammar/scales/transformed.js +1 -383
- package/src/grammar/scales/types.js +1 -1
- package/src/grammar/scales/validation.js +1 -66
- package/src/grammar/schemas/concreteGraphic.js +11 -0
- package/src/grammar/schemas/graphic.js +3 -0
- package/src/grammar/schemas/semanticPath.js +5 -3
- package/src/grammar/sort.js +88 -0
- package/src/grammar/stack.js +2 -10
- package/src/grammar/statisticalReference.js +1 -6
- package/src/grammar/summary.js +120 -45
- package/src/grammar/text.js +19 -0
- package/src/grammar/timeUnit.js +16 -7
- package/src/grammar/transformKeys.js +47 -0
- package/src/grammar/transformTopology.js +1 -0
- package/src/grammar/transforms.js +25 -12
- package/src/grammar/valueFormat.js +17 -5
- package/src/grammar/weightedStatistics.js +1 -6
- package/src/grammar/window.js +4 -58
- package/src/inspection.js +495 -0
- package/src/inspectionDescriptors.js +3 -0
- package/src/layout/canvas.js +1 -110
- package/src/layout/facets.js +1 -244
- package/src/layout/labels.js +1 -0
- package/src/layout/legend.js +13 -0
- package/src/layout/legendGroup.js +1 -0
- package/src/layout/legendItems.js +59 -15
- package/src/layout/legendLane.js +1 -441
- package/src/layout/legendText.js +1 -0
- package/src/layout/title.js +35 -13
- package/src/materialization/bars/aggregate.js +11 -5
- package/src/materialization/bars/histogram.js +4 -1
- package/src/materialization/bars/ranged.js +19 -6
- package/src/materialization/bars/resolve.js +26 -3
- package/src/materialization/coordinateBounds.js +8 -0
- package/src/materialization/dependencies.js +4 -44
- package/src/materialization/facetGuides/layout.js +1 -0
- package/src/materialization/facetGuides/placement.js +19 -8
- package/src/materialization/facetGuides/preparation.js +15 -7
- package/src/materialization/facetHeaders.js +1 -347
- package/src/materialization/facets.js +1 -185
- package/src/materialization/graphicHierarchy.js +1 -1
- package/src/materialization/guides/layout.js +1 -57
- package/src/materialization/guides/resources.js +1 -123
- package/src/materialization/layout.js +53 -0
- package/src/materialization/legendGroups.js +1 -0
- package/src/materialization/legendText.js +1 -0
- package/src/materialization/legends.js +1 -1
- package/src/materialization/marks/capabilities.js +5 -6
- package/src/materialization/rect.js +1 -1
- package/src/materialization/revisionIdentity.js +19 -0
- package/src/materialization/scaleGuideDependencies.js +1 -1
- package/src/materialization/scales/map.js +3 -0
- package/src/materialization/scales/policies/arc.js +8 -7
- package/src/materialization/scales/policies/bar.js +19 -7
- package/src/materialization/scales/policies/series.js +2 -1
- package/src/materialization/scales/resolve.js +72 -7
- package/src/materialization/selection/items/arc.js +1 -1
- package/src/materialization/selection/items/bar.js +7 -6
- package/src/materialization/selection/items/path.js +7 -6
- package/src/materialization/selection/items/rect.js +2 -2
- package/src/materialization/text.js +17 -6
- package/src/materialization/textLines.js +15 -0
- package/src/persistence/codec.js +37 -6
- package/src/persistence/validation.js +47 -0
- package/src/persistence.js +94 -8
- package/src/renderers/canvas/circle.js +6 -3
- package/src/renderers/canvas/fill.js +7 -1
- package/src/renderers/canvas/index.js +2 -1
- package/src/renderers/canvas/line.js +1 -0
- package/src/renderers/canvas/path.js +1 -1
- package/src/renderers/canvas/rect.js +11 -8
- package/src/renderers/canvas/stroke.js +2 -1
- package/src/renderers/canvas/text.js +5 -3
- package/src/renderers/svg.js +4 -1
- package/src/selectors/layers.js +19 -0
- package/src/theme/defaults.js +8 -2
- package/src/version.js +1 -1
- package/types/basic.d.ts +1 -0
- package/types/index.d.ts +7 -0
- package/types/inspection.d.ts +17 -0
- package/types/program.d.ts +494 -112
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { validateFillPaint } from "../../../grammar/paint.js";
|
|
2
|
+
import { validateAreaPaintConfig } from "../../../grammar/areaPaint.js";
|
|
1
3
|
import { validateAreaMissing } from "../../../grammar/areaEndpoints.js";
|
|
2
4
|
import { action } from "../../../core/action.js";
|
|
3
5
|
import { validateUserId } from "../../../core/identifiers.js";
|
|
@@ -81,7 +83,7 @@ const createAreaMark = /* @__PURE__ */ action(
|
|
|
81
83
|
if (missing === "break" && ["density", "horizon"].some(type => findUpstreamTransform(this, findDataset(this, data), type))) {
|
|
82
84
|
throw new Error("Area missing:break does not reinterpret density or horizon data.");
|
|
83
85
|
}
|
|
84
|
-
const fill =
|
|
86
|
+
const fill = validateFillPaint(args.fill ?? DEFAULT_COLORS.mark, "Area fill");
|
|
85
87
|
const opacity = validateUnitInterval(args.opacity ?? 0.2, "Area opacity");
|
|
86
88
|
const curve = validateCurveInterpolation(args.curve ?? "linear");
|
|
87
89
|
const { stroke, strokeWidth } = validateAreaCreateOutline(args);
|
|
@@ -127,14 +129,14 @@ const configureAreaStrokeFromFill = /* @__PURE__ */ action(
|
|
|
127
129
|
}
|
|
128
130
|
const { stroke: _stroke, ...config } = this.markConfigs[id] ?? {};
|
|
129
131
|
void _stroke;
|
|
130
|
-
return this._withMarkConfig(id, {
|
|
132
|
+
return this._withMarkConfig(id, validateAreaPaintConfig({
|
|
131
133
|
...config,
|
|
132
134
|
strokeFromFill: true,
|
|
133
135
|
strokeWidth: validateNonNegativeFinite(
|
|
134
136
|
args.strokeWidth ?? 1,
|
|
135
137
|
"Area strokeWidth"
|
|
136
138
|
)
|
|
137
|
-
});
|
|
139
|
+
}));
|
|
138
140
|
}
|
|
139
141
|
);
|
|
140
142
|
|
|
@@ -199,7 +201,7 @@ const rematerializeAreaMark = /* @__PURE__ */ action(
|
|
|
199
201
|
if (args.scales !== false && strokeEncoding?.scale !== undefined) {
|
|
200
202
|
resolved = resolved.rematerializeScale({ id: strokeEncoding.scale });
|
|
201
203
|
}
|
|
202
|
-
const config = this.markConfigs[id];
|
|
204
|
+
const config = validateAreaPaintConfig(this.markConfigs[id]);
|
|
203
205
|
const { paths, fills, strokes } = resolveAreaMaterialization({
|
|
204
206
|
rows: dataset.values,
|
|
205
207
|
layer,
|
|
@@ -273,7 +275,7 @@ const editAreaMark = /* @__PURE__ */ action(
|
|
|
273
275
|
let config = { ...this.markConfigs[layer.id] };
|
|
274
276
|
Object.assign(config, strokeDetails);
|
|
275
277
|
if (Object.hasOwn(args, "fill")) {
|
|
276
|
-
config.fill =
|
|
278
|
+
config.fill = validateFillPaint(args.fill, "Area fill");
|
|
277
279
|
if (config.errorBand !== undefined) config.errorBand = { ...config.errorBand, fill: config.fill };
|
|
278
280
|
}
|
|
279
281
|
if (Object.hasOwn(args, "opacity")) {
|
|
@@ -314,6 +316,7 @@ const editAreaMark = /* @__PURE__ */ action(
|
|
|
314
316
|
);
|
|
315
317
|
}
|
|
316
318
|
|
|
319
|
+
validateAreaPaintConfig(config);
|
|
317
320
|
let next = this._withMarkConfig(layer.id, config);
|
|
318
321
|
if (Object.hasOwn(args, "missing")) {
|
|
319
322
|
const missing = validateAreaMissing(args.missing);
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from "../../../grammar/areaSeries.js";
|
|
7
7
|
import {
|
|
8
8
|
mapContinuousScaleValues,
|
|
9
|
+
mapOrdinalPositionValues,
|
|
9
10
|
mapOrdinalValues
|
|
10
11
|
} from "../../../grammar/scales/index.js";
|
|
11
12
|
import { mapScaleConsumerValues } from
|
|
@@ -37,9 +38,8 @@ function resolveAreaPaths({
|
|
|
37
38
|
}
|
|
38
39
|
return derived.series.map(series => {
|
|
39
40
|
if (densityTransform === undefined && derived.orientation === "horizontal") {
|
|
40
|
-
const y = mapContinuousScaleValues(
|
|
41
|
-
series.values.map(value => value.y),
|
|
42
|
-
yScale
|
|
41
|
+
const y = (["point", "band"].includes(yScale.type) ? mapOrdinalPositionValues : mapContinuousScaleValues)(
|
|
42
|
+
series.values.map(value => value.y), yScale
|
|
43
43
|
);
|
|
44
44
|
const lower = mapContinuousScaleValues(
|
|
45
45
|
series.values.map(value => value.x),
|
|
@@ -57,9 +57,8 @@ function resolveAreaPaths({
|
|
|
57
57
|
);
|
|
58
58
|
}
|
|
59
59
|
if (densityTransform !== undefined && derived.mode === "x-density") {
|
|
60
|
-
const y = mapContinuousScaleValues(
|
|
61
|
-
series.values.map(value => value.y),
|
|
62
|
-
yScale
|
|
60
|
+
const y = (["point", "band"].includes(yScale.type) ? mapOrdinalPositionValues : mapContinuousScaleValues)(
|
|
61
|
+
series.values.map(value => value.y), yScale
|
|
63
62
|
);
|
|
64
63
|
const upper = mapContinuousScaleValues(
|
|
65
64
|
series.values.map(value => value.x),
|
|
@@ -80,7 +79,7 @@ function resolveAreaPaths({
|
|
|
80
79
|
{ independentAxis: "y" }
|
|
81
80
|
);
|
|
82
81
|
}
|
|
83
|
-
const x = mapContinuousScaleValues(
|
|
82
|
+
const x = (["point", "band"].includes(xScale.type) ? mapOrdinalPositionValues : mapContinuousScaleValues)(
|
|
84
83
|
series.values.map(value => value.x),
|
|
85
84
|
xScale
|
|
86
85
|
);
|
|
@@ -134,8 +133,8 @@ export function resolveAreaMaterialization({
|
|
|
134
133
|
layer.encoding?.y?.stack === "center";
|
|
135
134
|
const rawDerived = densityTransform === undefined
|
|
136
135
|
? centered
|
|
137
|
-
? deriveCenteredAreaSeries(rows, layer)
|
|
138
|
-
: deriveAreaSeries(rows, layer)
|
|
136
|
+
? deriveCenteredAreaSeries(rows, layer, { xDomain: xScale.domain })
|
|
137
|
+
: deriveAreaSeries(rows, layer, { xDomain: xScale.domain, yDomain: yScale.domain })
|
|
139
138
|
: deriveDensityAreaSeries(rows, layer, densityTransform);
|
|
140
139
|
const colorEncoding = layer.encoding?.color;
|
|
141
140
|
const layout = layer.layout?.mode ?? colorEncoding?.layout ?? "overlay";
|
|
@@ -10,14 +10,15 @@ import {
|
|
|
10
10
|
} from "../shared.js";
|
|
11
11
|
import { resolveMarkGraphicPlacement } from
|
|
12
12
|
"../../../materialization/graphicHierarchy.js";
|
|
13
|
-
import { requestedRectStyleDetails } from
|
|
13
|
+
import { requestedRectStyleDetails, RECT_RADIUS_PROPERTIES } from
|
|
14
14
|
"../../../grammar/roundedRect.js";
|
|
15
15
|
import { STROKE_STYLE_PROPERTIES } from
|
|
16
16
|
"../../../grammar/strokeStyle.js";
|
|
17
|
+
import { validateItemMissing } from "../../../grammar/itemMissing.js";
|
|
17
18
|
|
|
18
19
|
const CREATE_OPTIONS = Object.freeze([
|
|
19
|
-
"id", "data", "fill", "opacity", "stroke", "strokeWidth",
|
|
20
|
-
|
|
20
|
+
"id", "data", "orientation", "missing", "fill", "opacity", "stroke", "strokeWidth",
|
|
21
|
+
...RECT_RADIUS_PROPERTIES, ...STROKE_STYLE_PROPERTIES
|
|
21
22
|
]);
|
|
22
23
|
|
|
23
24
|
export const createBarMark = /* @__PURE__ */ action(
|
|
@@ -28,6 +29,9 @@ export const createBarMark = /* @__PURE__ */ action(
|
|
|
28
29
|
function (args = {}) {
|
|
29
30
|
validateMarkOptions(args, CREATE_OPTIONS, "createBarMark");
|
|
30
31
|
requestedRectStyleDetails(args, "createBarMark");
|
|
32
|
+
if (args.orientation !== undefined && !["vertical", "horizontal"].includes(args.orientation)) {
|
|
33
|
+
throw new Error("Bar orientation must be vertical or horizontal.");
|
|
34
|
+
}
|
|
31
35
|
const id = resolveMarkId(this, args.id, {
|
|
32
36
|
defaultId: "bar",
|
|
33
37
|
label: "Bar mark id",
|
|
@@ -52,6 +56,15 @@ export const createBarMark = /* @__PURE__ */ action(
|
|
|
52
56
|
property: `layer[${id}].data`,
|
|
53
57
|
value: data
|
|
54
58
|
});
|
|
59
|
+
if (Object.hasOwn(args, "missing")) {
|
|
60
|
+
created = created.editSemantic({
|
|
61
|
+
property: `layer[${id}].mark.missing`,
|
|
62
|
+
value: validateItemMissing(args.missing, "Bar missing")
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (args.orientation !== undefined) {
|
|
66
|
+
created = created.editSemantic({ property: `layer[${id}].mark.orientation`, value: args.orientation });
|
|
67
|
+
}
|
|
55
68
|
created = applyLayeredMarkInheritance(created, id, inherited);
|
|
56
69
|
created = created
|
|
57
70
|
.createGraphics({
|
|
@@ -63,7 +76,7 @@ export const createBarMark = /* @__PURE__ */ action(
|
|
|
63
76
|
created = materializeInheritedMark(created, id);
|
|
64
77
|
const appearance = Object.fromEntries(
|
|
65
78
|
[
|
|
66
|
-
"fill", "opacity", "stroke", "strokeWidth",
|
|
79
|
+
"fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
|
|
67
80
|
...STROKE_STYLE_PROPERTIES
|
|
68
81
|
]
|
|
69
82
|
.filter(property => Object.hasOwn(args, property))
|
|
@@ -9,14 +9,16 @@ import { canMaterializeBar } from "../../../materialization/marks/index.js";
|
|
|
9
9
|
import { DEFAULT_BAR_STROKE_WIDTH } from "../../../materialization/bars/resolve.js";
|
|
10
10
|
import { resolveEligibleLayer } from "../../../selectors/layers.js";
|
|
11
11
|
import { validateMarkOptions } from "../shared.js";
|
|
12
|
-
import { requestedRectStyleDetails } from
|
|
12
|
+
import { requestedRectStyleDetails, RECT_RADIUS_PROPERTIES } from
|
|
13
13
|
"../../../grammar/roundedRect.js";
|
|
14
14
|
import { STROKE_STYLE_PROPERTIES } from
|
|
15
15
|
"../../../grammar/strokeStyle.js";
|
|
16
16
|
import { rematerializeExistingLegend } from "../../encodings/shared.js";
|
|
17
|
+
import { validateFillPaint } from "../../../grammar/paint.js";
|
|
18
|
+
import { validateItemMissing } from "../../../grammar/itemMissing.js";
|
|
17
19
|
|
|
18
20
|
const EDIT_OPTIONS = Object.freeze([
|
|
19
|
-
"target", "fill", "opacity", "stroke", "strokeWidth",
|
|
21
|
+
"target", "missing", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
|
|
20
22
|
...STROKE_STYLE_PROPERTIES
|
|
21
23
|
]);
|
|
22
24
|
|
|
@@ -29,12 +31,12 @@ export const editBarMark = /* @__PURE__ */ action(
|
|
|
29
31
|
validateMarkOptions(args, EDIT_OPTIONS, "editBarMark");
|
|
30
32
|
const styleDetails = requestedRectStyleDetails(args, "editBarMark");
|
|
31
33
|
const changes = [
|
|
32
|
-
"fill", "opacity", "stroke", "strokeWidth",
|
|
34
|
+
"missing", "fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
|
|
33
35
|
...STROKE_STYLE_PROPERTIES
|
|
34
36
|
];
|
|
35
37
|
if (!changes.some(key => Object.hasOwn(args, key))) {
|
|
36
38
|
throw new Error(
|
|
37
|
-
"editBarMark requires fill, opacity, stroke, or strokeWidth."
|
|
39
|
+
"editBarMark requires fill, opacity, stroke, or strokeWidth; missing is also editable."
|
|
38
40
|
);
|
|
39
41
|
}
|
|
40
42
|
const requested = Object.hasOwn(args, "target")
|
|
@@ -55,17 +57,26 @@ export const editBarMark = /* @__PURE__ */ action(
|
|
|
55
57
|
"editBarMark stroke conflicts with a field encoding; use encodeStroke with value to replace it."
|
|
56
58
|
);
|
|
57
59
|
}
|
|
60
|
+
if (Object.hasOwn(args, "opacity") && layer.encoding?.opacity !== undefined) {
|
|
61
|
+
throw new Error("editBarMark opacity conflicts with a field encoding; use encodeOpacity with value to replace it.");
|
|
62
|
+
}
|
|
58
63
|
if (args.stroke === false && Object.hasOwn(args, "strokeWidth")) {
|
|
59
64
|
throw new Error(
|
|
60
65
|
"editBarMark cannot set strokeWidth while removing stroke."
|
|
61
66
|
);
|
|
62
67
|
}
|
|
63
68
|
|
|
64
|
-
const
|
|
69
|
+
const semantic = Object.hasOwn(args, "missing")
|
|
70
|
+
? this.editSemantic({
|
|
71
|
+
property: `layer[${layer.id}].mark.missing`,
|
|
72
|
+
value: validateItemMissing(args.missing, "Bar missing")
|
|
73
|
+
})
|
|
74
|
+
: this;
|
|
75
|
+
const config = { ...semantic.markConfigs[layer.id] };
|
|
65
76
|
const appearance = { ...config.barAppearance };
|
|
66
77
|
Object.assign(appearance, styleDetails);
|
|
67
78
|
if (Object.hasOwn(args, "fill")) {
|
|
68
|
-
appearance.fill =
|
|
79
|
+
appearance.fill = validateFillPaint(args.fill, "Bar fill");
|
|
69
80
|
}
|
|
70
81
|
if (Object.hasOwn(args, "opacity")) {
|
|
71
82
|
appearance.opacity = validateUnitInterval(args.opacity, "Bar opacity");
|
|
@@ -95,7 +106,7 @@ export const editBarMark = /* @__PURE__ */ action(
|
|
|
95
106
|
);
|
|
96
107
|
}
|
|
97
108
|
|
|
98
|
-
const next =
|
|
109
|
+
const next = semantic._withMarkConfig(layer.id, {
|
|
99
110
|
...config,
|
|
100
111
|
barAppearance: appearance
|
|
101
112
|
});
|
|
@@ -13,19 +13,17 @@ import {
|
|
|
13
13
|
import { rematerializeHighlightBaseline } from "../lifecycle.js";
|
|
14
14
|
import { offsetCategoryRectangles } from
|
|
15
15
|
"../../../materialization/categorySlotOffset.js";
|
|
16
|
-
import { materializeRectItem } from "../../../grammar/roundedRect.js";
|
|
17
|
-
import { STROKE_STYLE_PROPERTIES } from
|
|
18
|
-
"../../../grammar/strokeStyle.js";
|
|
16
|
+
import { materializeRectItem, RECT_STYLE_PROPERTIES } from "../../../grammar/roundedRect.js";
|
|
19
17
|
import { replaceGraphicItems } from "../../primitives/editGraphics.js";
|
|
20
18
|
|
|
21
19
|
const REMATERIALIZE_OPTIONS = Object.freeze(["id", "scales"]);
|
|
22
20
|
|
|
23
21
|
function editRectangles(program, id, rectangles) {
|
|
24
22
|
const appearance = program.markConfigs[id]?.barAppearance ?? {};
|
|
25
|
-
const hasShapeStyle =
|
|
23
|
+
const hasShapeStyle = RECT_STYLE_PROPERTIES
|
|
26
24
|
.some(property => Object.hasOwn(appearance, property));
|
|
27
25
|
if (hasShapeStyle) {
|
|
28
|
-
const radius = appearance
|
|
26
|
+
const radius = appearance;
|
|
29
27
|
return replaceGraphicItems(
|
|
30
28
|
program,
|
|
31
29
|
id,
|
|
@@ -92,6 +90,11 @@ export const rematerializeBarMark = /* @__PURE__ */ action(
|
|
|
92
90
|
resolved = resolved.rematerializeScale({ id: strokeScaleId });
|
|
93
91
|
}
|
|
94
92
|
|
|
93
|
+
const opacityScaleId = required.layer.encoding?.opacity?.scale;
|
|
94
|
+
if (opacityScaleId !== undefined && args.scales !== false) {
|
|
95
|
+
resolved = resolved.rematerializeScale({ id: opacityScaleId });
|
|
96
|
+
}
|
|
97
|
+
|
|
95
98
|
if (required.materialization === "aggregate") {
|
|
96
99
|
const offsetChannel = resolveBarOffsetChannel(required.layer);
|
|
97
100
|
const offsetScaleId = required.layer.encoding?.[offsetChannel]?.scale;
|
|
@@ -104,7 +107,7 @@ export const rematerializeBarMark = /* @__PURE__ */ action(
|
|
|
104
107
|
));
|
|
105
108
|
}
|
|
106
109
|
|
|
107
|
-
if (
|
|
110
|
+
if ([BAR_GRAINS.ranged, BAR_GRAINS.centered].includes(required.materialization)) {
|
|
108
111
|
const width = resolved.markConfigs[id]?.barWidth;
|
|
109
112
|
return editRectangles(resolved, id, offsetCategoryRectangles(
|
|
110
113
|
resolved, required.layer, deriveRangedRectangles(required, resolved, width)
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
import { DEFAULT_COLORS } from "../../../theme/defaults.js";
|
|
19
19
|
import { findDataset } from "../../../selectors/datasets.js";
|
|
20
20
|
import { findLayer, resolveEligibleLayer } from "../../../selectors/layers.js";
|
|
21
|
-
import { validateCurveInterpolation } from "../../../grammar/curveCommands.js";
|
|
21
|
+
import { validateCurveInterpolation, validateCardinalTension } from "../../../grammar/curveCommands.js";
|
|
22
22
|
import {
|
|
23
23
|
resolveCoordinateBounds,
|
|
24
24
|
resolveCoordinatePolarFrame
|
|
@@ -43,11 +43,11 @@ import {
|
|
|
43
43
|
const DEFAULT_LINE_STROKE = DEFAULT_COLORS.mark;
|
|
44
44
|
const DEFAULT_LINE_WIDTH = 2;
|
|
45
45
|
const CREATE_OPTIONS = Object.freeze([
|
|
46
|
-
"id", "data", "stroke", "strokeWidth", "opacity", "curve", "closed",
|
|
46
|
+
"id", "data", "stroke", "strokeWidth", "opacity", "curve", "tension", "closed",
|
|
47
47
|
...STROKE_STYLE_PROPERTIES
|
|
48
48
|
]);
|
|
49
49
|
const EDIT_OPTIONS = Object.freeze([
|
|
50
|
-
"target", "stroke", "strokeWidth", "opacity", "curve", "closed",
|
|
50
|
+
"target", "stroke", "strokeWidth", "opacity", "curve", "tension", "closed",
|
|
51
51
|
...STROKE_STYLE_PROPERTIES
|
|
52
52
|
]);
|
|
53
53
|
const REMATERIALIZE_OPTIONS = Object.freeze(["id", "scales"]);
|
|
@@ -118,6 +118,7 @@ const createLineMark = /* @__PURE__ */ action(
|
|
|
118
118
|
"Line strokeWidth"
|
|
119
119
|
);
|
|
120
120
|
const curve = validateCurveInterpolation(args.curve ?? "linear");
|
|
121
|
+
validateCardinalTension(args.tension, curve);
|
|
121
122
|
const closed = Object.hasOwn(args, "closed")
|
|
122
123
|
? validateClosed(args.closed)
|
|
123
124
|
: false;
|
|
@@ -151,6 +152,7 @@ const createLineMark = /* @__PURE__ */ action(
|
|
|
151
152
|
{
|
|
152
153
|
...(Object.hasOwn(args, "strokeWidth") ? { strokeWidth } : {}),
|
|
153
154
|
...(Object.hasOwn(args, "curve") ? { curve } : {}),
|
|
155
|
+
...(args.tension === undefined ? {} : { tension: args.tension }),
|
|
154
156
|
...(Object.hasOwn(args, "closed") ? { closed } : {}),
|
|
155
157
|
...strokeDetails
|
|
156
158
|
}
|
|
@@ -277,7 +279,7 @@ const editLineMark = /* @__PURE__ */ action(
|
|
|
277
279
|
validateMarkOptions(args, EDIT_OPTIONS, "editLineMark");
|
|
278
280
|
const strokeDetails = requestedStrokeDetails(args, "editLineMark");
|
|
279
281
|
if (!EDIT_OPTIONS.slice(1).some(key => Object.hasOwn(args, key))) {
|
|
280
|
-
throw new Error("editLineMark requires stroke, strokeWidth, opacity, curve, or closed.");
|
|
282
|
+
throw new Error("editLineMark requires stroke, strokeWidth, opacity, curve, tension, or closed.");
|
|
281
283
|
}
|
|
282
284
|
const target = Object.hasOwn(args, "target")
|
|
283
285
|
? validateUserId(args.target, "Line mark id")
|
|
@@ -315,6 +317,11 @@ const editLineMark = /* @__PURE__ */ action(
|
|
|
315
317
|
})) {
|
|
316
318
|
if (Object.hasOwn(args, key)) config[key] = validate(args[key], `Line ${key}`);
|
|
317
319
|
}
|
|
320
|
+
if (args.curve !== undefined && args.curve !== "cardinal" && args.tension === undefined) {
|
|
321
|
+
delete config.tension;
|
|
322
|
+
}
|
|
323
|
+
if (Object.hasOwn(args, "tension")) config.tension = args.tension;
|
|
324
|
+
validateCardinalTension(config.tension, config.curve ?? "linear");
|
|
318
325
|
validatePolarLineConfig(layer, config);
|
|
319
326
|
const next = this._withMarkConfig(layer.id, config);
|
|
320
327
|
const materialized = canMaterializeLine(next, layer)
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
} from "../../../grammar/lineSeries.js";
|
|
4
4
|
import {
|
|
5
5
|
mapContinuousScaleValues,
|
|
6
|
+
mapOrdinalPositionValues,
|
|
6
7
|
normalizeStrokeDashPattern
|
|
7
8
|
} from "../../../grammar/scales/index.js";
|
|
8
9
|
import { buildCurvePathCommands } from
|
|
@@ -97,9 +98,7 @@ export function resolvePositionedLineMaterialization({
|
|
|
97
98
|
const radiusScaleId = layer.encoding?.radius?.scale;
|
|
98
99
|
const lineOptions = polar
|
|
99
100
|
? { thetaDomain: resolvedScales[thetaScaleId].domain }
|
|
100
|
-
:
|
|
101
|
-
? undefined
|
|
102
|
-
: { xBinBoundaries };
|
|
101
|
+
: { xBinBoundaries, xDomain: resolvedScales[xScaleId].domain };
|
|
103
102
|
const derived = deriveLineSeries(rows, layer, lineOptions);
|
|
104
103
|
const commands = polar
|
|
105
104
|
? derived.series.map(series => buildPolarLinePathCommands({
|
|
@@ -111,7 +110,9 @@ export function resolvePositionedLineMaterialization({
|
|
|
111
110
|
closed: config.closed ?? false
|
|
112
111
|
}))
|
|
113
112
|
: derived.series.map(series => {
|
|
114
|
-
const
|
|
113
|
+
const mapX = ["nominal", "ordinal"].includes(layer.encoding.x.fieldType)
|
|
114
|
+
? mapOrdinalPositionValues : mapContinuousScaleValues;
|
|
115
|
+
const x = mapX(
|
|
115
116
|
series.values.map(value => value.x),
|
|
116
117
|
resolvedScales[xScaleId]
|
|
117
118
|
);
|
|
@@ -119,9 +120,12 @@ export function resolvePositionedLineMaterialization({
|
|
|
119
120
|
series.values.map(value => value.y),
|
|
120
121
|
resolvedScales[yScaleId]
|
|
121
122
|
);
|
|
123
|
+
// A raw singleton retains its data position and series identity, but
|
|
124
|
+
// contributes no segment. Do not fabricate another observation.
|
|
125
|
+
if (series.values.length === 1) return [{ op: "M", x: x[0], y: y[0] }];
|
|
122
126
|
return buildCurvePathCommands(
|
|
123
127
|
series.values.map((_, index) => ({ x: x[index], y: y[index] })),
|
|
124
|
-
config.curve ?? "linear"
|
|
128
|
+
config.curve ?? "linear", config.tension
|
|
125
129
|
);
|
|
126
130
|
});
|
|
127
131
|
const appearance = appearanceMapper(layer, resolvedScales,
|
|
@@ -16,9 +16,10 @@ import {
|
|
|
16
16
|
resolveMarkId,
|
|
17
17
|
validateMarkOptions
|
|
18
18
|
} from "../shared.js";
|
|
19
|
+
import { validateItemMissing } from "../../../grammar/itemMissing.js";
|
|
19
20
|
|
|
20
21
|
const OPTIONS = Object.freeze([
|
|
21
|
-
"id", "data", "shape", "fill", "opacity", "stroke", "strokeWidth",
|
|
22
|
+
"id", "data", "missing", "shape", "fill", "opacity", "stroke", "strokeWidth",
|
|
22
23
|
...STROKE_STYLE_PROPERTIES
|
|
23
24
|
]);
|
|
24
25
|
|
|
@@ -61,6 +62,12 @@ export const createPointMark = /* @__PURE__ */ action(
|
|
|
61
62
|
property: `layer[${id}].data`,
|
|
62
63
|
value: data
|
|
63
64
|
});
|
|
65
|
+
if (Object.hasOwn(args, "missing")) {
|
|
66
|
+
next = next.editSemantic({
|
|
67
|
+
property: `layer[${id}].mark.missing`,
|
|
68
|
+
value: validateItemMissing(args.missing, "Point missing")
|
|
69
|
+
});
|
|
70
|
+
}
|
|
64
71
|
next = applyLayeredMarkInheritance(next, id, inherited)
|
|
65
72
|
.createGraphics({
|
|
66
73
|
id,
|
|
@@ -13,9 +13,10 @@ import {
|
|
|
13
13
|
import { resolveEligibleLayer } from "../../../selectors/layers.js";
|
|
14
14
|
import { rematerializeExistingLegend } from "../../encodings/shared.js";
|
|
15
15
|
import { validateMarkOptions } from "../shared.js";
|
|
16
|
+
import { validateItemMissing } from "../../../grammar/itemMissing.js";
|
|
16
17
|
|
|
17
18
|
const OPTIONS = Object.freeze([
|
|
18
|
-
"target", "shape", "fill", "opacity", "stroke", "strokeWidth",
|
|
19
|
+
"target", "missing", "shape", "fill", "opacity", "stroke", "strokeWidth",
|
|
19
20
|
...STROKE_STYLE_PROPERTIES
|
|
20
21
|
]);
|
|
21
22
|
|
|
@@ -28,12 +29,12 @@ export const editPointMark = /* @__PURE__ */ action(
|
|
|
28
29
|
validateMarkOptions(args, OPTIONS, "editPointMark");
|
|
29
30
|
const strokeDetails = requestedStrokeDetails(args, "editPointMark");
|
|
30
31
|
const editable = [
|
|
31
|
-
"shape", "fill", "opacity", "stroke", "strokeWidth",
|
|
32
|
+
"missing", "shape", "fill", "opacity", "stroke", "strokeWidth",
|
|
32
33
|
...STROKE_STYLE_PROPERTIES
|
|
33
34
|
];
|
|
34
35
|
if (!editable.some(property => Object.hasOwn(args, property))) {
|
|
35
36
|
throw new Error(
|
|
36
|
-
"editPointMark requires shape, fill, opacity, stroke, or
|
|
37
|
+
"editPointMark requires shape, fill, opacity, stroke, strokeWidth, or missing."
|
|
37
38
|
);
|
|
38
39
|
}
|
|
39
40
|
if (args.target !== undefined) validateUserId(args.target, "Point mark id");
|
|
@@ -61,7 +62,13 @@ export const editPointMark = /* @__PURE__ */ action(
|
|
|
61
62
|
if (Object.hasOwn(args, "opacity") && layer.encoding?.opacity?.field !== undefined) {
|
|
62
63
|
throw new Error("editPointMark opacity conflicts with a field encoding; use encodeOpacity with value to replace it.");
|
|
63
64
|
}
|
|
64
|
-
const
|
|
65
|
+
const semantic = Object.hasOwn(args, "missing")
|
|
66
|
+
? this.editSemantic({
|
|
67
|
+
property: `layer[${id}].mark.missing`,
|
|
68
|
+
value: validateItemMissing(args.missing, "Point missing")
|
|
69
|
+
})
|
|
70
|
+
: this;
|
|
71
|
+
const config = { ...semantic.markConfigs[id] };
|
|
65
72
|
Object.assign(config, strokeDetails);
|
|
66
73
|
if (Object.hasOwn(args, "shape")) {
|
|
67
74
|
config.shape = validatePointShape(args.shape);
|
|
@@ -89,7 +96,7 @@ export const editPointMark = /* @__PURE__ */ action(
|
|
|
89
96
|
}
|
|
90
97
|
}
|
|
91
98
|
if (Object.hasOwn(args, "strokeWidth")) {
|
|
92
|
-
if (typeof config.stroke !== "string") {
|
|
99
|
+
if (typeof config.stroke !== "string" && layer.encoding?.stroke?.field === undefined) {
|
|
93
100
|
throw new Error("Point strokeWidth requires an active stroke.");
|
|
94
101
|
}
|
|
95
102
|
config.strokeWidth = validateNonNegativeFinite(
|
|
@@ -97,7 +104,7 @@ export const editPointMark = /* @__PURE__ */ action(
|
|
|
97
104
|
"Point strokeWidth"
|
|
98
105
|
);
|
|
99
106
|
}
|
|
100
|
-
const next =
|
|
107
|
+
const next = semantic
|
|
101
108
|
._withMarkConfig(id, config)
|
|
102
109
|
.rematerializePointMark({ id });
|
|
103
110
|
return rematerializeExistingLegend(next);
|
|
@@ -40,6 +40,7 @@ import { offsetCategoryPositions } from
|
|
|
40
40
|
"../../../materialization/categorySlotOffset.js";
|
|
41
41
|
import { requestedStrokeDetails } from
|
|
42
42
|
"../../../grammar/strokeStyle.js";
|
|
43
|
+
import { applyItemMissingPolicy } from "../../../grammar/itemMissing.js";
|
|
43
44
|
|
|
44
45
|
const REMATERIALIZE_OPTIONS = Object.freeze(["id"]);
|
|
45
46
|
const DEFAULT_POINT_FILL = DEFAULT_COLORS.mark;
|
|
@@ -337,10 +338,11 @@ export const rematerializePointMark = /* @__PURE__ */ action(
|
|
|
337
338
|
if (!["circle", "rect", "path", "collection"].includes(graphic?.type)) {
|
|
338
339
|
throw new Error(`Point mark "${id}" requires point graphics.`);
|
|
339
340
|
}
|
|
340
|
-
const
|
|
341
|
-
if (
|
|
341
|
+
const sourceDataset = findDataset(resolved, layer.data);
|
|
342
|
+
if (sourceDataset === undefined) {
|
|
342
343
|
throw new Error(`Point mark "${id}" requires an existing dataset.`);
|
|
343
344
|
}
|
|
345
|
+
const dataset = applyItemMissingPolicy(layer, sourceDataset);
|
|
344
346
|
|
|
345
347
|
if (graphic.items.length === 0 && !canMaterializePoint(resolved, layer)) {
|
|
346
348
|
return resolved;
|
|
@@ -25,17 +25,19 @@ import { resolveMarkGraphicPlacement } from
|
|
|
25
25
|
import { rematerializeExistingLegend } from "../../encodings/shared.js";
|
|
26
26
|
import { rematerializeHighlightBaseline } from "../lifecycle.js";
|
|
27
27
|
import {
|
|
28
|
-
requestedRectStyleDetails
|
|
28
|
+
requestedRectStyleDetails, hasRectRadius, RECT_RADIUS_PROPERTIES
|
|
29
29
|
} from "../../../grammar/roundedRect.js";
|
|
30
30
|
import { STROKE_STYLE_PROPERTIES } from
|
|
31
31
|
"../../../grammar/strokeStyle.js";
|
|
32
|
+
import { applyItemMissingPolicy, validateItemMissing } from
|
|
33
|
+
"../../../grammar/itemMissing.js";
|
|
32
34
|
|
|
33
35
|
const STYLE_OPTIONS = Object.freeze([
|
|
34
|
-
"fill", "opacity", "stroke", "strokeWidth",
|
|
36
|
+
"fill", "opacity", "stroke", "strokeWidth", ...RECT_RADIUS_PROPERTIES,
|
|
35
37
|
...STROKE_STYLE_PROPERTIES
|
|
36
38
|
]);
|
|
37
|
-
const CREATE_OPTIONS = Object.freeze(["id", "data", ...STYLE_OPTIONS]);
|
|
38
|
-
const EDIT_OPTIONS = Object.freeze(["target", ...STYLE_OPTIONS]);
|
|
39
|
+
const CREATE_OPTIONS = Object.freeze(["id", "data", "missing", ...STYLE_OPTIONS]);
|
|
40
|
+
const EDIT_OPTIONS = Object.freeze(["target", "missing", ...STYLE_OPTIONS]);
|
|
39
41
|
const REMATERIALIZE_OPTIONS = Object.freeze(["id", "scales"]);
|
|
40
42
|
|
|
41
43
|
function requireRectLayer(program, requested, operation) {
|
|
@@ -71,6 +73,12 @@ const createRectMark = /* @__PURE__ */ action(
|
|
|
71
73
|
let next = this
|
|
72
74
|
.editSemantic({ property: `layer[${id}].mark.type`, value: "rect" })
|
|
73
75
|
.editSemantic({ property: `layer[${id}].data`, value: data });
|
|
76
|
+
if (Object.hasOwn(args, "missing")) {
|
|
77
|
+
next = next.editSemantic({
|
|
78
|
+
property: `layer[${id}].mark.missing`,
|
|
79
|
+
value: validateItemMissing(args.missing, "Rect missing")
|
|
80
|
+
});
|
|
81
|
+
}
|
|
74
82
|
next = applyLayeredMarkInheritance(next, id, inherited)
|
|
75
83
|
.createGraphics({
|
|
76
84
|
id,
|
|
@@ -109,7 +117,7 @@ const rematerializeRectMark = /* @__PURE__ */ action(
|
|
|
109
117
|
const graphic = this.graphicSpec.objects[id];
|
|
110
118
|
if (layer?.mark?.type !== "rect") throw new Error(`Unknown rect mark "${id}".`);
|
|
111
119
|
const roundedCollection = graphic?.type === "collection" &&
|
|
112
|
-
|
|
120
|
+
hasRectRadius(this.markConfigs[id]) &&
|
|
113
121
|
graphic.items?.every(item => ["rect", "path"].includes(item.type));
|
|
114
122
|
if (
|
|
115
123
|
(graphic?.type !== "rect" && !roundedCollection) ||
|
|
@@ -120,10 +128,11 @@ const rematerializeRectMark = /* @__PURE__ */ action(
|
|
|
120
128
|
if (this.markConfigs[id]?.gradientPlot?.materialized === true) {
|
|
121
129
|
return this.materializeGradientPlotFill({ id });
|
|
122
130
|
}
|
|
123
|
-
const
|
|
124
|
-
if (
|
|
131
|
+
const sourceDataset = findDataset(this, layer.data);
|
|
132
|
+
if (sourceDataset === undefined) {
|
|
125
133
|
throw new Error(`Rect mark "${id}" requires an existing dataset.`);
|
|
126
134
|
}
|
|
135
|
+
const dataset = applyItemMissingPolicy(layer, sourceDataset);
|
|
127
136
|
if (!canMaterializeRect(this, layer)) {
|
|
128
137
|
return replaceGraphicItems(this, id, "rect", []);
|
|
129
138
|
}
|
|
@@ -151,7 +160,7 @@ const editRectMark = /* @__PURE__ */ action(
|
|
|
151
160
|
function (args = {}) {
|
|
152
161
|
validateMarkOptions(args, EDIT_OPTIONS, "editRectMark");
|
|
153
162
|
requestedRectStyleDetails(args, "editRectMark");
|
|
154
|
-
if (!STYLE_OPTIONS.some(option => Object.hasOwn(args, option))) {
|
|
163
|
+
if (!["missing", ...STYLE_OPTIONS].some(option => Object.hasOwn(args, option))) {
|
|
155
164
|
throw new Error("editRectMark requires at least one editable property.");
|
|
156
165
|
}
|
|
157
166
|
const layer = requireRectLayer(this, args.target, "editRectMark");
|
|
@@ -163,16 +172,22 @@ const editRectMark = /* @__PURE__ */ action(
|
|
|
163
172
|
"editRectMark stroke conflicts with a field encoding; use encodeStroke with value to replace it."
|
|
164
173
|
);
|
|
165
174
|
}
|
|
166
|
-
const
|
|
175
|
+
const semantic = Object.hasOwn(args, "missing")
|
|
176
|
+
? this.editSemantic({
|
|
177
|
+
property: `layer[${layer.id}].mark.missing`,
|
|
178
|
+
value: validateItemMissing(args.missing, "Rect missing")
|
|
179
|
+
})
|
|
180
|
+
: this;
|
|
181
|
+
const next = semantic._withMarkConfig(
|
|
167
182
|
layer.id,
|
|
168
183
|
{
|
|
169
184
|
...normalizeRectMarkConfig(
|
|
170
185
|
args,
|
|
171
|
-
|
|
186
|
+
semantic.markConfigs[layer.id] ?? DEFAULT_RECT_MARK
|
|
172
187
|
),
|
|
173
188
|
fillExplicit: Object.hasOwn(args, "fill")
|
|
174
189
|
? true
|
|
175
|
-
:
|
|
190
|
+
: semantic.markConfigs[layer.id]?.fillExplicit ?? false
|
|
176
191
|
}
|
|
177
192
|
);
|
|
178
193
|
const materialized = canMaterializeRect(next, layer)
|
|
@@ -163,6 +163,7 @@ export function removeOwnedMark(program, id, partial = false) {
|
|
|
163
163
|
next = next.editGraphics({ target: id, remove: true });
|
|
164
164
|
}
|
|
165
165
|
return next
|
|
166
|
+
._withoutMaterializationConfig(["guides", "legendGroups", id])
|
|
166
167
|
._withoutMaterializationConfig(["marks", id])
|
|
167
168
|
._withContext({
|
|
168
169
|
...(program.context.currentMark === id ? { currentMark: undefined } : {}),
|
|
@@ -262,6 +263,7 @@ export const removeMark = /* @__PURE__ */ closedAction(
|
|
|
262
263
|
if (next.graphicSpec.objects[id] !== undefined) {
|
|
263
264
|
next = next.editGraphics({ target: id, remove: true });
|
|
264
265
|
}
|
|
266
|
+
next = next._withoutMaterializationConfig(["guides", "legendGroups", id]);
|
|
265
267
|
next = next._withoutMaterializationConfig(["marks", id]);
|
|
266
268
|
next = next._withoutMaterializationConfig(["jitters", id]);
|
|
267
269
|
next = next._withoutMaterializationConfig(["pointPacking", id]);
|