ggaction 0.0.12 → 0.0.15
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 +127 -0
- package/README.md +20 -11
- package/knowledge/action-card.schema.json +1 -1
- package/knowledge/action-cards.json +1 -1
- package/knowledge/action-cards.schema.json +1 -1
- package/knowledge/extension-authoring.md +2 -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 -3
- package/src/actions/basic.js +4 -2
- package/src/actions/boxPlots/components.js +14 -4
- package/src/actions/boxPlots/edit.js +31 -5
- package/src/actions/boxPlots/materialize.js +13 -4
- package/src/actions/boxPlots/options.js +48 -16
- package/src/actions/canvas/actions.js +3 -1
- package/src/actions/canvas/fitting.js +211 -0
- package/src/actions/canvas/index.js +2 -0
- package/src/actions/categoryOrder/index.js +18 -6
- package/src/actions/charts/area.js +51 -0
- package/src/actions/charts/bar.js +13 -6
- package/src/actions/charts/beeswarm.js +70 -0
- package/src/actions/charts/density.js +48 -0
- package/src/actions/charts/ecdf.js +186 -0
- package/src/actions/charts/endpoints.js +473 -0
- package/src/actions/charts/heatmap.js +4 -3
- package/src/actions/charts/histogram.js +5 -4
- package/src/actions/charts/horizon.js +73 -0
- package/src/actions/charts/index.js +37 -0
- package/src/actions/charts/interval-regression.js +172 -0
- package/src/actions/charts/line.js +8 -6
- package/src/actions/charts/parallel.js +8 -2
- package/src/actions/charts/pie.js +52 -0
- package/src/actions/charts/polar.js +134 -0
- package/src/actions/charts/radar.js +305 -0
- package/src/actions/charts/radial.js +50 -0
- package/src/actions/charts/raincloud.js +422 -0
- package/src/actions/charts/rug-strip.js +283 -0
- package/src/actions/charts/scatter.js +11 -3
- package/src/actions/charts/shared.js +69 -10
- package/src/actions/composition/actions.js +129 -3
- package/src/actions/coordinates/actions.js +1 -1
- package/src/actions/coordinates/edit.js +76 -0
- package/src/actions/data/bin.js +29 -0
- package/src/actions/data/bin2d.js +57 -185
- package/src/actions/data/complete.js +26 -0
- package/src/actions/data/computed.js +24 -0
- package/src/actions/data/create.js +2 -2
- package/src/actions/data/density.js +12 -20
- package/src/actions/data/derived.js +111 -15
- package/src/actions/data/ecdf.js +38 -0
- package/src/actions/data/edit.js +539 -0
- package/src/actions/data/filter.js +226 -30
- package/src/actions/data/fold.js +24 -0
- package/src/actions/data/impute.js +26 -0
- package/src/actions/data/index.js +38 -0
- package/src/actions/data/interval.js +2 -0
- package/src/actions/data/intervalEdit.js +86 -4
- package/src/actions/data/normalize.js +27 -0
- package/src/actions/data/regression.js +19 -21
- package/src/actions/data/revisionBindings.js +145 -0
- package/src/actions/data/shared.js +20 -4
- package/src/actions/data/stack.js +26 -0
- package/src/actions/data/summary.js +26 -0
- package/src/actions/data/timeUnit.js +4 -1
- package/src/actions/data/window.js +1 -1
- package/src/actions/encodings/appearance.js +32 -13
- package/src/actions/encodings/barWidth.js +8 -0
- package/src/actions/encodings/basic.js +2 -0
- package/src/actions/encodings/channels.js +415 -0
- package/src/actions/encodings/color/continuous.js +19 -59
- package/src/actions/encodings/color/index.js +30 -23
- package/src/actions/encodings/color/layout.js +3 -97
- package/src/actions/encodings/color/policy.js +5 -8
- package/src/actions/encodings/density/resolve.js +37 -5
- package/src/actions/encodings/density.js +124 -34
- package/src/actions/encodings/histogram.js +3 -2
- package/src/actions/encodings/horizon/resolve.js +8 -4
- package/src/actions/encodings/horizon.js +18 -8
- package/src/actions/encodings/index.js +6 -0
- package/src/actions/encodings/offset.js +30 -29
- package/src/actions/encodings/parallel.js +2 -8
- package/src/actions/encodings/position/apply.js +63 -11
- package/src/actions/encodings/position/index.js +52 -6
- package/src/actions/encodings/position/policies/arc.js +14 -0
- package/src/actions/encodings/position/policies/area.js +4 -42
- package/src/actions/encodings/position/policies/bar.js +57 -13
- package/src/actions/encodings/position/resolve.js +88 -26
- package/src/actions/encodings/ranged.js +123 -97
- package/src/actions/encodings/remove.js +44 -34
- package/src/actions/encodings/ruleAppearance.js +24 -32
- package/src/actions/encodings/seriesLayout.js +105 -0
- package/src/actions/encodings/shared.js +107 -37
- package/src/actions/encodings/stroke.js +226 -0
- package/src/actions/encodings/strokeDash.js +9 -6
- package/src/actions/encodings/temporal.js +7 -0
- package/src/actions/encodings/text.js +30 -15
- package/src/actions/errorBands/create.js +41 -8
- package/src/actions/errorBands/edit.js +360 -25
- package/src/actions/errorBars/create.js +56 -17
- package/src/actions/errorBars/edit.js +372 -21
- package/src/actions/facets/actions.js +619 -41
- package/src/actions/facets/derive.js +139 -25
- package/src/actions/gradientPlots/components.js +43 -13
- package/src/actions/gradientPlots/edit.js +14 -4
- package/src/actions/gradientPlots/materialize.js +8 -8
- package/src/actions/gradientPlots/options.js +10 -2
- package/src/actions/guides/applicability.js +28 -19
- package/src/actions/guides/axes/axes.js +4 -3
- package/src/actions/guides/axes/axis.js +18 -18
- package/src/actions/guides/axes/components.js +43 -0
- package/src/actions/guides/axes/edit.js +16 -51
- package/src/actions/guides/axes/labels.js +184 -28
- package/src/actions/guides/axes/lines.js +13 -7
- package/src/actions/guides/axes/parallel/lifecycle.js +117 -0
- package/src/actions/guides/axes/parallel/policy.js +137 -0
- package/src/actions/guides/axes/parallel/resolve.js +50 -25
- package/src/actions/guides/axes/parallel.js +93 -217
- package/src/actions/guides/axes/policy.js +21 -67
- package/src/actions/guides/axes/tickGroups.js +15 -8
- package/src/actions/guides/axes/ticks.js +11 -6
- package/src/actions/guides/axes/titles.js +32 -11
- package/src/actions/guides/basic.js +2 -0
- package/src/actions/guides/facade.js +106 -0
- package/src/actions/guides/facadeAxes.js +200 -0
- package/src/actions/guides/facadeLegend.js +63 -0
- package/src/actions/guides/grids/grid.js +37 -33
- package/src/actions/guides/grids/resolve.js +17 -4
- package/src/actions/guides/guides.js +54 -31
- package/src/actions/guides/legends/blocks.js +426 -0
- package/src/actions/guides/legends/categorical/actions.js +309 -279
- package/src/actions/guides/legends/categorical/components.js +21 -17
- package/src/actions/guides/legends/categorical/index.js +37 -33
- package/src/actions/guides/legends/categorical/layout.js +123 -354
- package/src/actions/guides/legends/categorical/options.js +32 -16
- package/src/actions/guides/legends/categorical/recipes.js +114 -9
- package/src/actions/guides/legends/categorical/resolve.js +30 -15
- package/src/actions/guides/legends/categorical/symbols.js +87 -33
- package/src/actions/guides/legends/continuous/common.js +99 -26
- package/src/actions/guides/legends/continuous/gradient.js +120 -89
- package/src/actions/guides/legends/continuous/index.js +8 -2
- package/src/actions/guides/legends/continuous/interval.js +79 -95
- package/src/actions/guides/legends/continuous/opacity.js +113 -89
- package/src/actions/guides/legends/continuous/stroke.js +525 -0
- package/src/actions/guides/legends/creation.js +40 -0
- package/src/actions/guides/legends/edit.js +321 -90
- package/src/actions/guides/legends/focused.js +2 -2
- package/src/actions/guides/legends/index.js +2 -0
- package/src/actions/guides/legends/lane.js +149 -102
- package/src/actions/guides/legends/lifecycle.js +143 -0
- package/src/actions/guides/legends/remove.js +43 -78
- package/src/actions/guides/legends/sampling.js +140 -0
- package/src/actions/guides/legends/size.js +213 -116
- package/src/actions/guides/legends/strokeWidth.js +121 -73
- package/src/actions/guides/legends/target.js +123 -0
- package/src/actions/guides/legends/transition.js +192 -0
- package/src/actions/guides/polar/axes/facade.js +81 -66
- package/src/actions/guides/polar/axes/labels.js +28 -8
- package/src/actions/guides/polar/axes/lines.js +12 -5
- package/src/actions/guides/polar/axes/shared.js +22 -0
- package/src/actions/guides/polar/axes/ticks.js +6 -5
- package/src/actions/guides/polar/axes/titles.js +6 -5
- package/src/actions/guides/polar/grids.js +8 -8
- package/src/actions/guides/polar/resolve.js +12 -8
- package/src/actions/guides/reuse.js +44 -0
- package/src/actions/guides/tickValues.js +19 -21
- package/src/actions/index.js +15 -2
- package/src/actions/intervals/resolve.js +35 -15
- package/src/actions/marks/arc/actions.js +78 -20
- package/src/actions/marks/area/actions.js +51 -12
- package/src/actions/marks/area/materialize.js +22 -3
- package/src/actions/marks/bar/create.js +11 -2
- package/src/actions/marks/bar/edit.js +20 -3
- package/src/actions/marks/bar/materialize.js +33 -9
- package/src/actions/marks/index.js +14 -0
- package/src/actions/marks/line/actions.js +71 -113
- package/src/actions/marks/line/materialize.js +57 -56
- package/src/actions/marks/point/create.js +8 -2
- package/src/actions/marks/point/edit.js +29 -21
- package/src/actions/marks/point/index.js +1 -0
- package/src/actions/marks/point/jitter.js +3 -0
- package/src/actions/marks/point/materialize.js +154 -16
- package/src/actions/marks/point/packing.js +68 -0
- package/src/actions/marks/rect/actions.js +33 -12
- package/src/actions/marks/references.js +658 -0
- package/src/actions/marks/remove.js +87 -4
- package/src/actions/marks/rule/actions.js +77 -9
- package/src/actions/marks/rule/appearance.js +26 -0
- package/src/actions/marks/shared.js +13 -13
- package/src/actions/marks/text/actions.js +296 -13
- package/src/actions/marks/text/index.js +4 -0
- package/src/actions/marks/text/layout.js +156 -8
- package/src/actions/marks/text/removal.js +173 -0
- package/src/actions/marks/text/selection.js +73 -0
- package/src/actions/marks/tick/actions.js +22 -5
- package/src/actions/primitives/createGraphics.js +3 -1
- package/src/actions/primitives/editGraphics.js +26 -0
- package/src/actions/primitives/semantic.js +3 -2
- package/src/actions/primitives/semanticAction.js +120 -10
- package/src/actions/primitives/semanticValidation/guide.js +10 -0
- package/src/actions/primitives/semanticValidation/index.js +9 -1
- package/src/actions/primitives/semanticValidation/layer.js +23 -1
- package/src/actions/primitives/semanticValidation/scale.js +38 -8
- package/src/actions/regression/components.js +26 -11
- package/src/actions/regression/create.js +11 -3
- package/src/actions/regression/edit.js +40 -13
- package/src/actions/regression/resolve.js +1 -1
- package/src/actions/resources/index.js +7 -0
- package/src/actions/resources/remove.js +172 -0
- package/src/actions/scales/channels.js +212 -0
- package/src/actions/scales/consumers/common.js +21 -54
- package/src/actions/scales/consumers/families.js +28 -14
- package/src/actions/scales/consumers/index.js +42 -4
- package/src/actions/scales/consumers/seriesLayout.js +57 -12
- package/src/actions/scales/create.js +58 -26
- package/src/actions/scales/definitions.js +109 -39
- package/src/actions/scales/edit.js +101 -34
- package/src/actions/scales/editPolicy.js +95 -35
- package/src/actions/scales/index.js +6 -0
- package/src/actions/scales/materialize.js +14 -49
- package/src/actions/scales/offset.js +48 -0
- package/src/actions/scales/parallel.js +71 -0
- package/src/actions/scales/patch.js +1 -1
- package/src/actions/scales/preview.js +140 -0
- package/src/actions/scales/quantitativeColor.js +9 -5
- package/src/actions/selection/actions.js +154 -30
- package/src/actions/selection/index.js +3 -0
- package/src/actions/theme/actions.js +98 -0
- package/src/actions/theme/composition.js +238 -0
- package/src/actions/theme/index.js +16 -0
- package/src/actions/theme/reconcile.js +1130 -0
- package/src/actions/theme/state.js +160 -0
- package/src/actions/titles/actions.js +11 -10
- package/src/actions/titles/resolve.js +1 -40
- package/src/actions/violinPlots/create.js +90 -43
- package/src/actions/violinPlots/edit.js +192 -0
- package/src/actions/violinPlots/index.js +2 -0
- package/src/core/ChartProgram.js +7 -0
- package/src/core/action.js +32 -2
- package/src/core/compositionState.js +141 -8
- package/src/core/programState.js +20 -0
- package/src/core/resourceReferences.js +332 -0
- package/src/core/vocabulary.js +16 -3
- package/src/grammar/aggregate.js +66 -23
- package/src/grammar/arcs.js +58 -1
- package/src/grammar/areaEndpoints.js +46 -0
- package/src/grammar/areaSeries.js +87 -41
- package/src/grammar/bars/aggregate.js +37 -13
- package/src/grammar/bars/geometry.js +44 -0
- package/src/grammar/bars/policy.js +9 -7
- package/src/grammar/bin.js +226 -0
- package/src/grammar/categoryOrder.js +34 -0
- package/src/grammar/complete.js +279 -0
- package/src/grammar/computed.js +351 -0
- package/src/grammar/coordinates.js +37 -0
- package/src/grammar/density.js +239 -37
- package/src/grammar/displayLabels.js +57 -0
- package/src/grammar/ecdf.js +198 -0
- package/src/grammar/facets/dependencies.js +133 -1
- package/src/grammar/facets/guides.js +3 -0
- package/src/grammar/facets/index.js +123 -52
- package/src/grammar/facets/scales.js +15 -18
- package/src/grammar/fold.js +123 -0
- package/src/grammar/horizon.js +6 -4
- package/src/grammar/impute.js +340 -0
- package/src/grammar/interval.js +37 -20
- package/src/grammar/lineSeries.js +20 -63
- package/src/grammar/markFilter.js +22 -4
- package/src/grammar/markLabelSelection.js +57 -0
- package/src/grammar/markLabels.js +110 -0
- package/src/grammar/normalize.js +366 -0
- package/src/grammar/parallelAxisTitles.js +16 -0
- package/src/grammar/pathSeries.js +109 -0
- package/src/grammar/pointPacking.js +183 -0
- package/src/grammar/pointShapes.js +13 -4
- package/src/grammar/polar.js +90 -8
- package/src/grammar/positionDatum.js +12 -0
- package/src/grammar/rects.js +9 -1
- package/src/grammar/regression/derive.js +4 -0
- package/src/grammar/regression/index.js +8 -2
- package/src/grammar/regression/models.js +22 -7
- package/src/grammar/regression/parameters.js +63 -13
- package/src/grammar/rotation.js +29 -0
- package/src/grammar/roundedRect.js +180 -0
- package/src/grammar/rules.js +8 -21
- package/src/grammar/scales/color.js +23 -1
- package/src/grammar/scales/colorConsumers.js +57 -0
- package/src/grammar/scales/continuous.js +2 -2
- package/src/grammar/scales/definition.js +42 -5
- package/src/grammar/scales/discretized.js +11 -5
- package/src/grammar/scales/fields.js +38 -8
- package/src/grammar/scales/index.js +1 -0
- package/src/grammar/scales/mapping.js +2 -0
- package/src/grammar/scales/ordinal.js +12 -3
- package/src/grammar/scales/policies.js +2 -2
- package/src/grammar/scales/radial.js +55 -0
- package/src/grammar/scales/size.js +456 -0
- package/src/grammar/scales/types.js +1 -0
- package/src/grammar/schemas/concreteGraphic.js +14 -2
- package/src/grammar/schemas/graphic.js +15 -0
- package/src/grammar/schemas/graphicBounds.js +179 -30
- package/src/grammar/schemas/semanticPath.js +23 -4
- package/src/grammar/stack.js +170 -0
- package/src/grammar/statisticalReference.js +103 -0
- package/src/grammar/statistics/confidenceInterval.js +101 -0
- package/src/grammar/strokeStyle.js +77 -0
- package/src/grammar/summary.js +245 -0
- package/src/grammar/text.js +22 -16
- package/src/grammar/timeUnit.js +234 -13
- package/src/grammar/transformTopology.js +10 -0
- package/src/grammar/transforms.js +418 -16
- package/src/grammar/valueFormat.js +112 -0
- package/src/grammar/weightedStatistics.js +374 -0
- package/src/grammar/window.js +232 -21
- package/src/layout/aspect.js +80 -0
- package/src/layout/facets.js +100 -12
- package/src/layout/guideCollisions.js +12 -0
- package/src/layout/labels.js +343 -0
- package/src/layout/legend.js +2 -10
- package/src/layout/legendItems.js +102 -0
- package/src/layout/legendLane.js +100 -11
- package/src/materialization/bars/aggregate.js +56 -147
- package/src/materialization/bars/histogram.js +104 -20
- package/src/materialization/bars/ranged.js +19 -3
- package/src/materialization/bars/resolve.js +7 -4
- package/src/materialization/categorySlotOffset.js +40 -0
- package/src/materialization/composition.js +3 -1
- package/src/materialization/compositionSnapshot.js +1 -1
- package/src/materialization/coordinateBounds.js +204 -0
- package/src/materialization/dependencies.js +93 -16
- package/src/materialization/encodings.js +1 -1
- package/src/materialization/facetGuides/legacyCategorical.js +3 -0
- package/src/materialization/facetGuides/placement.js +8 -2
- package/src/materialization/facetGuides/preparation.js +12 -7
- package/src/materialization/facetHeaders.js +346 -0
- package/src/materialization/facets.js +23 -66
- package/src/materialization/guides/layout.js +57 -0
- package/src/materialization/guides/resources.js +28 -2
- package/src/materialization/legends.js +11 -2
- package/src/materialization/marks/capabilities.js +20 -5
- package/src/materialization/marks/grouping.js +52 -0
- package/src/materialization/marks/index.js +68 -27
- package/src/materialization/marks/policies.js +4 -1
- package/src/materialization/rect.js +55 -42
- package/src/materialization/rectConfig.js +5 -1
- package/src/materialization/rowEncoding.js +13 -13
- package/src/materialization/scaleGuideDependencies.js +8 -5
- package/src/materialization/scales/map.js +6 -3
- package/src/materialization/scales/policies/arc.js +42 -0
- package/src/materialization/scales/policies/binnedPosition.js +7 -4
- package/src/materialization/scales/policies/offset.js +50 -8
- package/src/materialization/scales/policies/series.js +5 -1
- package/src/materialization/scales/resolve.js +65 -17
- package/src/materialization/selection/compatibility.js +11 -0
- package/src/materialization/selection/items/arc.js +28 -4
- package/src/materialization/selection/items/bar.js +42 -71
- package/src/materialization/selection/items/common.js +27 -6
- package/src/materialization/selection/items/path.js +3 -13
- package/src/materialization/selection/items/rect.js +35 -8
- package/src/materialization/selection/path.js +1 -1
- package/src/materialization/selection/point.js +3 -1
- package/src/materialization/text.js +324 -14
- package/src/mcp/adapter.js +2 -2
- package/src/renderers/canvas/circle.js +2 -3
- package/src/renderers/canvas/line.js +2 -3
- package/src/renderers/canvas/native.js +4 -4
- package/src/renderers/canvas/path.js +2 -3
- package/src/renderers/canvas/rect.js +2 -3
- package/src/renderers/canvas/stroke.js +11 -0
- package/src/renderers/svg.js +19 -0
- package/src/selectors/datasets.js +44 -0
- package/src/selectors/layers.js +7 -2
- package/src/selectors/scales.js +6 -0
- package/src/theme/defaults.js +140 -0
- package/types/basic.d.ts +17 -2
- package/types/index.d.ts +211 -0
- package/types/program.d.ts +2182 -204
- package/src/materialization/bars/grouped.js +0 -144
|
@@ -1,12 +1,19 @@
|
|
|
1
|
+
import { isSourceOwnedText } from "../../grammar/text.js";
|
|
1
2
|
import { action } from "../../core/action.js";
|
|
2
3
|
import { validateUserId } from "../../core/identifiers.js";
|
|
3
4
|
import { validateKeys } from "../../core/validation.js";
|
|
4
5
|
import { findDataset } from "../../selectors/datasets.js";
|
|
5
6
|
import { findLayer } from "../../selectors/layers.js";
|
|
7
|
+
import { applyDetachedScaleRematerialization } from "../../materialization/dependencies.js";
|
|
8
|
+
import { markLabelPlacementLeaderId } from "../../layout/labels.js";
|
|
6
9
|
import {
|
|
7
10
|
getPositionChannelDefinition,
|
|
8
11
|
POSITION_CHANNELS
|
|
9
12
|
} from "../../core/vocabulary.js";
|
|
13
|
+
import {
|
|
14
|
+
canonicalResourcePath,
|
|
15
|
+
collectResourceReferences
|
|
16
|
+
} from "../../core/resourceReferences.js";
|
|
10
17
|
|
|
11
18
|
const OPTIONS = Object.freeze(["target"]);
|
|
12
19
|
const REMOVE_AXIS = Object.freeze({
|
|
@@ -28,18 +35,32 @@ function ownedChildren(program, id) {
|
|
|
28
35
|
config.boxPlot?.whiskerId,
|
|
29
36
|
config.boxPlot?.medianId,
|
|
30
37
|
config.boxPlot?.outlierId,
|
|
31
|
-
config.gradientPlot?.centerId
|
|
38
|
+
config.gradientPlot?.centerId,
|
|
39
|
+
config.intervalPlot?.intervalId,
|
|
40
|
+
config.endpointPlot?.roles?.stemId,
|
|
41
|
+
config.endpointPlot?.roles?.startId,
|
|
42
|
+
config.endpointPlot?.roles?.connectorId,
|
|
43
|
+
...(config.raincloudPlot?.ownedChildIds ?? [])
|
|
32
44
|
].concat(
|
|
33
45
|
program.semanticSpec.layers
|
|
34
46
|
.filter(layer => layer.source === id)
|
|
35
47
|
.map(layer => layer.id)
|
|
36
|
-
).
|
|
48
|
+
).concat(
|
|
49
|
+
program.semanticSpec.layers
|
|
50
|
+
.filter(layer =>
|
|
51
|
+
program.markConfigs[layer.id]?.statisticalReference?.source === id
|
|
52
|
+
)
|
|
53
|
+
.map(layer => layer.id)
|
|
54
|
+
).filter(child => child !== undefined && child !== id && findLayer(program, child) !== undefined);
|
|
37
55
|
}
|
|
38
56
|
|
|
39
57
|
function ownership(program) {
|
|
40
58
|
const ownerByChild = new Map();
|
|
41
59
|
for (const layer of program.semanticSpec.layers) {
|
|
42
60
|
for (const child of ownedChildren(program, layer.id)) {
|
|
61
|
+
if (program.markConfigs[child]?.statisticalReference !== undefined) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
43
64
|
ownerByChild.set(child, layer.id);
|
|
44
65
|
}
|
|
45
66
|
}
|
|
@@ -79,6 +100,37 @@ function collectClosure(program, root) {
|
|
|
79
100
|
return result;
|
|
80
101
|
}
|
|
81
102
|
|
|
103
|
+
function externalMarkReferences(program, ids) {
|
|
104
|
+
const closure = new Set(ids);
|
|
105
|
+
const references = ids.flatMap(id => collectResourceReferences(program, {
|
|
106
|
+
kind: "mark",
|
|
107
|
+
id
|
|
108
|
+
})).filter(reference => {
|
|
109
|
+
if (reference.strength === "context") return false;
|
|
110
|
+
if (["layer", "markConfig"].includes(reference.ownerKind)) {
|
|
111
|
+
return !closure.has(reference.ownerId);
|
|
112
|
+
}
|
|
113
|
+
if (["selection", "highlight", "legend"].includes(reference.ownerKind)) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
if (
|
|
117
|
+
reference.ownerKind === "axis" &&
|
|
118
|
+
reference.ownerId === "parallel.axes"
|
|
119
|
+
) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
});
|
|
124
|
+
const unique = new Map(references.map(reference => [[
|
|
125
|
+
reference.ownerKind,
|
|
126
|
+
reference.ownerId,
|
|
127
|
+
canonicalResourcePath(reference.path)
|
|
128
|
+
].join("\u0000"), reference]));
|
|
129
|
+
return [...unique.entries()]
|
|
130
|
+
.sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
|
|
131
|
+
.map(([, reference]) => reference);
|
|
132
|
+
}
|
|
133
|
+
|
|
82
134
|
function ownedDerivedData(program, ids) {
|
|
83
135
|
const candidates = new Set();
|
|
84
136
|
for (const id of ids) {
|
|
@@ -90,7 +142,11 @@ function ownedDerivedData(program, ids) {
|
|
|
90
142
|
config.regression?.dataId,
|
|
91
143
|
config.boxPlot?.summaryId,
|
|
92
144
|
config.boxPlot?.outlierDataId,
|
|
93
|
-
config.gradientPlot?.profileId
|
|
145
|
+
config.gradientPlot?.profileId,
|
|
146
|
+
config.violinPlot?.materialized === true ? layer?.data : undefined,
|
|
147
|
+
config.ecdfPlot?.data,
|
|
148
|
+
config.endpointPlot?.data,
|
|
149
|
+
config.statisticalReference?.dataId
|
|
94
150
|
]) {
|
|
95
151
|
if (candidate !== undefined) candidates.add(candidate);
|
|
96
152
|
}
|
|
@@ -161,7 +217,7 @@ export function removeOwnedMark(program, id, partial = false) {
|
|
|
161
217
|
|
|
162
218
|
function hasScaleConsumer(program, channel, scale) {
|
|
163
219
|
return program.semanticSpec.layers.some(
|
|
164
|
-
layer => layer.encoding?.[channel]?.scale === scale
|
|
220
|
+
layer => !isSourceOwnedText(layer) && layer.encoding?.[channel]?.scale === scale
|
|
165
221
|
);
|
|
166
222
|
}
|
|
167
223
|
|
|
@@ -198,10 +254,26 @@ export const removeMark = action(
|
|
|
198
254
|
validateKeys(args, OPTIONS, "removeMark");
|
|
199
255
|
const owner = resolveOwner(this, args.target);
|
|
200
256
|
const ids = collectClosure(this, owner.id);
|
|
257
|
+
const external = externalMarkReferences(this, ids);
|
|
258
|
+
if (external.length > 0) {
|
|
259
|
+
throw new Error(
|
|
260
|
+
`removeMark cannot remove externally referenced marks: ${external.map(
|
|
261
|
+
reference => `${reference.ownerKind} "${reference.ownerId}" at ` +
|
|
262
|
+
canonicalResourcePath(reference.path)
|
|
263
|
+
).join("; ")}.`
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
const previousLayers = ids.map(id => findLayer(this, id));
|
|
201
267
|
const derived = ownedDerivedData(this, ids);
|
|
202
268
|
const positionScales = usedPositionScales(this, ids);
|
|
203
269
|
let next = this;
|
|
204
270
|
|
|
271
|
+
if (ids.includes(next.guideConfigs.axis?.parallel?.axes?.target)) {
|
|
272
|
+
next = next.removeParallelAxes({
|
|
273
|
+
target: next.guideConfigs.axis.parallel.axes.target
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
205
277
|
const legendTargets = [...new Set(Object.values(next.guideConfigs.legend ?? {})
|
|
206
278
|
.filter(config => ids.includes(config?.target))
|
|
207
279
|
.map(config => config.target))];
|
|
@@ -219,6 +291,15 @@ export const removeMark = action(
|
|
|
219
291
|
) {
|
|
220
292
|
next = next.editGraphics({ target: labelLayout.leaderId, remove: true });
|
|
221
293
|
}
|
|
294
|
+
const placement = next.markConfigs[id]?.labelAuthoring?.placement;
|
|
295
|
+
const placementLeaderId = markLabelPlacementLeaderId(id);
|
|
296
|
+
if (
|
|
297
|
+
placement?.leader !== undefined &&
|
|
298
|
+
placement.leader !== false &&
|
|
299
|
+
next.graphicSpec.objects[placementLeaderId] !== undefined
|
|
300
|
+
) {
|
|
301
|
+
next = next.editGraphics({ target: placementLeaderId, remove: true });
|
|
302
|
+
}
|
|
222
303
|
if (findLayer(next, id) !== undefined) {
|
|
223
304
|
next = next.editSemantic({ property: `layer[${id}]`, remove: true });
|
|
224
305
|
}
|
|
@@ -227,6 +308,7 @@ export const removeMark = action(
|
|
|
227
308
|
}
|
|
228
309
|
next = next._withoutMaterializationConfig(["marks", id]);
|
|
229
310
|
next = next._withoutMaterializationConfig(["jitters", id]);
|
|
311
|
+
next = next._withoutMaterializationConfig(["pointPacking", id]);
|
|
230
312
|
next = next._withoutMaterializationConfig(["labelLayouts", id]);
|
|
231
313
|
}
|
|
232
314
|
|
|
@@ -236,6 +318,7 @@ export const removeMark = action(
|
|
|
236
318
|
next = next.releaseDerivedData({ id });
|
|
237
319
|
}
|
|
238
320
|
}
|
|
321
|
+
next = applyDetachedScaleRematerialization(next, previousLayers);
|
|
239
322
|
return next._withContext({
|
|
240
323
|
...(ids.includes(this.context.currentMark) ? { currentMark: undefined } : {}),
|
|
241
324
|
...(selectionCleanup.selectionIds.includes(this.context.currentSelection)
|
|
@@ -9,10 +9,13 @@ import {
|
|
|
9
9
|
normalizeStrokeDashPattern
|
|
10
10
|
} from "../../../grammar/scales/index.js";
|
|
11
11
|
import { deriveRuleValues, resolveRuleMode } from "../../../grammar/rules.js";
|
|
12
|
-
import {
|
|
12
|
+
import { resolveCoordinateBounds } from "../../../materialization/coordinateBounds.js";
|
|
13
|
+
import { readRectItemGeometry } from "../../../grammar/roundedRect.js";
|
|
13
14
|
import { findDataset } from "../../../selectors/datasets.js";
|
|
14
|
-
import { findLayer } from "../../../selectors/layers.js";
|
|
15
|
+
import { findLayer, resolveEligibleLayer } from "../../../selectors/layers.js";
|
|
16
|
+
import { applyRuleAppearance, planRuleAppearance } from "./appearance.js";
|
|
15
17
|
import { DEFAULT_COLORS } from "../../../theme/defaults.js";
|
|
18
|
+
import { rematerializeExistingLegend } from "../../encodings/shared.js";
|
|
16
19
|
import {
|
|
17
20
|
assertMarkAvailable,
|
|
18
21
|
applyLayeredMarkInheritance,
|
|
@@ -28,8 +31,21 @@ import { resolveMarkGraphicPlacement } from
|
|
|
28
31
|
import { rematerializeHighlightBaseline } from "../lifecycle.js";
|
|
29
32
|
import { applyOffsetPositionValues } from
|
|
30
33
|
"../../../materialization/rowEncoding.js";
|
|
34
|
+
import { resolveCategorySlotOffset } from
|
|
35
|
+
"../../../materialization/categorySlotOffset.js";
|
|
36
|
+
import { mapScaleConsumerValues } from
|
|
37
|
+
"../../../materialization/scales/map.js";
|
|
38
|
+
import {
|
|
39
|
+
requestedStrokeDetails,
|
|
40
|
+
STROKE_STYLE_PROPERTIES
|
|
41
|
+
} from "../../../grammar/strokeStyle.js";
|
|
31
42
|
|
|
32
|
-
const
|
|
43
|
+
const APPEARANCE_OPTIONS = Object.freeze([
|
|
44
|
+
"stroke", "strokeWidth", "strokeDash", "opacity",
|
|
45
|
+
...STROKE_STYLE_PROPERTIES
|
|
46
|
+
]);
|
|
47
|
+
const CREATE_OPTIONS = Object.freeze(["id", "data", ...APPEARANCE_OPTIONS]);
|
|
48
|
+
const EDIT_OPTIONS = Object.freeze(["target", ...APPEARANCE_OPTIONS]);
|
|
33
49
|
const REMATERIALIZE_OPTIONS = Object.freeze(["id"]);
|
|
34
50
|
const SPAN_OPTIONS = Object.freeze(["id", "orientation", "size"]);
|
|
35
51
|
const DEFAULT_RULE_CONFIG = Object.freeze({
|
|
@@ -83,6 +99,7 @@ const createRuleMark = action(
|
|
|
83
99
|
},
|
|
84
100
|
function (args = {}) {
|
|
85
101
|
validateMarkOptions(args, CREATE_OPTIONS, "createRuleMark");
|
|
102
|
+
const strokeDetails = requestedStrokeDetails(args, "createRuleMark");
|
|
86
103
|
const id = resolveMarkId(this, args.id, {
|
|
87
104
|
defaultId: "rule",
|
|
88
105
|
label: "Rule mark id",
|
|
@@ -96,6 +113,7 @@ const createRuleMark = action(
|
|
|
96
113
|
inherited?.data !== undefined ? { data: inherited.data } : {})
|
|
97
114
|
});
|
|
98
115
|
assertMarkAvailable(this, id);
|
|
116
|
+
const appearance = planRuleAppearance(args, inherited);
|
|
99
117
|
|
|
100
118
|
let created = this
|
|
101
119
|
.editSemantic({ property: `layer[${id}].mark.type`, value: "rule" })
|
|
@@ -110,6 +128,7 @@ const createRuleMark = action(
|
|
|
110
128
|
})
|
|
111
129
|
._withMarkConfig(id, {
|
|
112
130
|
...DEFAULT_RULE_CONFIG,
|
|
131
|
+
...strokeDetails,
|
|
113
132
|
...(inherited === undefined
|
|
114
133
|
? {}
|
|
115
134
|
: {
|
|
@@ -119,7 +138,33 @@ const createRuleMark = action(
|
|
|
119
138
|
}
|
|
120
139
|
})
|
|
121
140
|
});
|
|
122
|
-
return materializeInheritedMark(created, id);
|
|
141
|
+
return applyRuleAppearance(materializeInheritedMark(created, id), id, appearance);
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
const editRuleMark = action(
|
|
146
|
+
{ op: "editRuleMark", description: "Edit constant rule appearance through its encoding owners." },
|
|
147
|
+
function (args = {}) {
|
|
148
|
+
validateMarkOptions(args, EDIT_OPTIONS, "editRuleMark");
|
|
149
|
+
const strokeDetails = requestedStrokeDetails(args, "editRuleMark");
|
|
150
|
+
if (args.target !== undefined) validateUserId(args.target, "Rule mark id");
|
|
151
|
+
const layer = resolveEligibleLayer(this, {
|
|
152
|
+
target: args.target,
|
|
153
|
+
predicate: candidate => candidate.mark?.type === "rule",
|
|
154
|
+
label: "rule mark"
|
|
155
|
+
});
|
|
156
|
+
const appearance = planRuleAppearance(args, layer);
|
|
157
|
+
if (appearance.length === 0 && Object.keys(strokeDetails).length === 0) {
|
|
158
|
+
throw new Error("editRuleMark requires an appearance change.");
|
|
159
|
+
}
|
|
160
|
+
const configured = this._withMarkConfig(layer.id, {
|
|
161
|
+
...this.markConfigs[layer.id],
|
|
162
|
+
...strokeDetails
|
|
163
|
+
});
|
|
164
|
+
const materialized = appearance.length === 0
|
|
165
|
+
? configured.rematerializeRuleMark({ id: layer.id })
|
|
166
|
+
: applyRuleAppearance(configured, layer.id, appearance);
|
|
167
|
+
return rematerializeExistingLegend(materialized);
|
|
123
168
|
}
|
|
124
169
|
);
|
|
125
170
|
|
|
@@ -159,7 +204,7 @@ const rematerializeRuleMark = action(
|
|
|
159
204
|
const scaleIds = [...new Set(
|
|
160
205
|
[
|
|
161
206
|
"x", "y", "x2", "y2", "xOffset", "yOffset",
|
|
162
|
-
"strokeDash", "strokeWidth", "opacity"
|
|
207
|
+
"stroke", "strokeDash", "strokeWidth", "opacity"
|
|
163
208
|
]
|
|
164
209
|
.map(channel => layer.encoding?.[channel]?.scale)
|
|
165
210
|
.filter(scale => scale !== undefined)
|
|
@@ -203,7 +248,7 @@ const rematerializeRuleMark = action(
|
|
|
203
248
|
channel
|
|
204
249
|
});
|
|
205
250
|
}
|
|
206
|
-
const bounds =
|
|
251
|
+
const bounds = resolveCoordinateBounds(resolved, layer.coordinate);
|
|
207
252
|
const x1 = [];
|
|
208
253
|
const y1 = [];
|
|
209
254
|
const x2 = [];
|
|
@@ -231,7 +276,11 @@ const rematerializeRuleMark = action(
|
|
|
231
276
|
startY = endY = mapped.y[index];
|
|
232
277
|
} else if (mode === "box-span") {
|
|
233
278
|
const owner = resolved.graphicSpec.objects[boxSpan];
|
|
234
|
-
const
|
|
279
|
+
const item = owner?.items?.[index];
|
|
280
|
+
const box = readRectItemGeometry({
|
|
281
|
+
type: item?.type ?? owner?.type,
|
|
282
|
+
properties: item?.properties
|
|
283
|
+
});
|
|
235
284
|
if (box === undefined) throw new Error(`Rule mark "${id}" requires box span owner "${boxSpan}".`);
|
|
236
285
|
if (layer.encoding?.x?.fieldType === "quantitative") {
|
|
237
286
|
startX = endX = mapped.x[index];
|
|
@@ -263,12 +312,22 @@ const rematerializeRuleMark = action(
|
|
|
263
312
|
x2.push(endX);
|
|
264
313
|
y2.push(endY);
|
|
265
314
|
}
|
|
315
|
+
const categoryOffset = resolveCategorySlotOffset(resolved, layer);
|
|
316
|
+
if (categoryOffset?.pixels) {
|
|
317
|
+
const targets = categoryOffset.channel === "x" ? [x1, x2] : [y1, y2];
|
|
318
|
+
for (const values of targets) {
|
|
319
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
320
|
+
if (Number.isFinite(values[index])) values[index] += categoryOffset.pixels;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
266
324
|
|
|
267
325
|
const resolvedConfig = {
|
|
268
326
|
...DEFAULT_RULE_CONFIG,
|
|
269
327
|
...resolved.markConfigs[id]
|
|
270
328
|
};
|
|
271
329
|
const dashEncoding = layer.encoding?.strokeDash;
|
|
330
|
+
const strokeEncoding = layer.encoding?.stroke;
|
|
272
331
|
const opacityEncoding = layer.encoding?.opacity;
|
|
273
332
|
const strokeWidthEncoding = layer.encoding?.strokeWidth;
|
|
274
333
|
const strokeDash = dashEncoding?.scale === undefined
|
|
@@ -295,6 +354,13 @@ const rematerializeRuleMark = action(
|
|
|
295
354
|
derived.values.strokeWidth,
|
|
296
355
|
resolved.resolvedScales[strokeWidthEncoding.scale]
|
|
297
356
|
);
|
|
357
|
+
const stroke = strokeEncoding?.scale === undefined
|
|
358
|
+
? resolvedConfig.stroke
|
|
359
|
+
: mapScaleConsumerValues(
|
|
360
|
+
derived.values.stroke,
|
|
361
|
+
resolved.resolvedScales[strokeEncoding.scale],
|
|
362
|
+
"stroke"
|
|
363
|
+
);
|
|
298
364
|
|
|
299
365
|
return editMarkGraphic(resolved, id, {
|
|
300
366
|
length: derived.length,
|
|
@@ -302,10 +368,11 @@ const rematerializeRuleMark = action(
|
|
|
302
368
|
y1,
|
|
303
369
|
x2,
|
|
304
370
|
y2,
|
|
305
|
-
stroke
|
|
371
|
+
stroke,
|
|
306
372
|
strokeWidth,
|
|
307
373
|
strokeDash,
|
|
308
|
-
opacity
|
|
374
|
+
opacity,
|
|
375
|
+
...requestedStrokeDetails(resolvedConfig, "Rule mark")
|
|
309
376
|
});
|
|
310
377
|
}
|
|
311
378
|
);
|
|
@@ -337,6 +404,7 @@ export const materializeRuleSpan = action(
|
|
|
337
404
|
export function registerRuleMarkActions(ProgramClass) {
|
|
338
405
|
Object.assign(ProgramClass.prototype, {
|
|
339
406
|
createRuleMark,
|
|
407
|
+
editRuleMark,
|
|
340
408
|
rematerializeRuleMark,
|
|
341
409
|
materializeRuleSpan
|
|
342
410
|
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { validateRuleStroke, validateRuleStrokeWidth } from "../../../grammar/ruleAppearance.js";
|
|
2
|
+
import { normalizeStrokeDashPattern, validateOpacityValue } from "../../../grammar/scales/index.js";
|
|
3
|
+
|
|
4
|
+
const STYLE_ACTIONS = Object.freeze({
|
|
5
|
+
stroke: ["encodeStroke", validateRuleStroke],
|
|
6
|
+
strokeWidth: ["encodeStrokeWidth", validateRuleStrokeWidth],
|
|
7
|
+
strokeDash: ["encodeStrokeDash", normalizeStrokeDashPattern],
|
|
8
|
+
opacity: ["encodeOpacity", validateOpacityValue]
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export function planRuleAppearance(args, layer) {
|
|
12
|
+
return Object.entries(STYLE_ACTIONS).flatMap(([property, [op, validate]]) => {
|
|
13
|
+
if (!Object.hasOwn(args, property)) return [];
|
|
14
|
+
if (layer?.encoding?.[property]?.field !== undefined) {
|
|
15
|
+
throw new Error(`Rule ${property} conflicts with a field encoding; use ${op} with value to replace it.`);
|
|
16
|
+
}
|
|
17
|
+
validate(args[property], `Rule ${property}`);
|
|
18
|
+
return [{ op, value: args[property] }];
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function applyRuleAppearance(program, target, plan) {
|
|
23
|
+
let next = program;
|
|
24
|
+
for (const { op, value } of plan) next = next[op]({ target, value });
|
|
25
|
+
return next;
|
|
26
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { isSourceOwnedText } from "../../grammar/text.js";
|
|
1
2
|
import {
|
|
2
3
|
resolveOptionalUserId,
|
|
3
4
|
validateUserId
|
|
4
5
|
} from "../../core/identifiers.js";
|
|
5
|
-
import { findDataset } from "../../selectors/datasets.js";
|
|
6
|
+
import { findDataset, requireMaterializedDataset } from "../../selectors/datasets.js";
|
|
6
7
|
import { findLayer, hasLayer } from "../../selectors/layers.js";
|
|
7
8
|
import { findSemanticScale } from "../../selectors/scales.js";
|
|
8
9
|
import { resolveMarkPositionPolicy } from "../encodings/position/policies/index.js";
|
|
@@ -27,13 +28,8 @@ export function resolveMarkData(program, requested) {
|
|
|
27
28
|
throw new Error("Mark creation requires data or a current dataset.");
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
const dataset =
|
|
31
|
-
|
|
32
|
-
if (dataset === undefined) {
|
|
33
|
-
throw new Error(`Unknown dataset "${data}".`);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return { data, dataset };
|
|
31
|
+
const dataset = requireMaterializedDataset(program, data);
|
|
32
|
+
return { data: dataset.id, dataset };
|
|
37
33
|
}
|
|
38
34
|
|
|
39
35
|
export function resolveMarkId(program, requested, {
|
|
@@ -60,7 +56,7 @@ export function assertMarkAvailable(program, id) {
|
|
|
60
56
|
throw new Error(`Mark "${id}" already exists.`);
|
|
61
57
|
}
|
|
62
58
|
|
|
63
|
-
if (program.graphicSpec.objects
|
|
59
|
+
if (Object.hasOwn(program.graphicSpec.objects, id)) {
|
|
64
60
|
throw new Error(`Graphic "${id}" already exists.`);
|
|
65
61
|
}
|
|
66
62
|
}
|
|
@@ -78,9 +74,9 @@ const POSITION_POLICY_SUBSETS = Object.freeze([
|
|
|
78
74
|
]);
|
|
79
75
|
|
|
80
76
|
function inheritedPositionEncodings(encoding) {
|
|
81
|
-
if (encoding?.field === undefined) return undefined;
|
|
77
|
+
if (encoding?.field === undefined && encoding?.aggregate !== "count") return undefined;
|
|
82
78
|
const base = Object.fromEntries(
|
|
83
|
-
["field", "fieldType", "scale", "title"]
|
|
79
|
+
["field", "fieldType", "scale", "title", "temporalUnit"]
|
|
84
80
|
.filter(property => Object.hasOwn(encoding, property))
|
|
85
81
|
.map(property => [property, encoding[property]])
|
|
86
82
|
);
|
|
@@ -104,6 +100,9 @@ function inheritedPositionEncodings(encoding) {
|
|
|
104
100
|
function scaleSupportsEncoding(program, markType, channel, encoding) {
|
|
105
101
|
const scale = findSemanticScale(program, encoding.scale);
|
|
106
102
|
if (scale === undefined) return false;
|
|
103
|
+
if (scale.radialMapping !== undefined) {
|
|
104
|
+
return markType === "arc" && channel === "radius" && ["count", "sum"].includes(encoding.aggregate);
|
|
105
|
+
}
|
|
107
106
|
const categorical = ["nominal", "ordinal"].includes(encoding.fieldType);
|
|
108
107
|
if (categorical) {
|
|
109
108
|
if (["bar", "rect"].includes(markType)) return scale.type === "band";
|
|
@@ -143,7 +142,8 @@ export function resolveCompatibleEncodings(program, source, markType) {
|
|
|
143
142
|
layer: candidate,
|
|
144
143
|
dataset,
|
|
145
144
|
channel,
|
|
146
|
-
args: encoding,
|
|
145
|
+
args: { ...encoding, ...(channel === "radius" && findSemanticScale(program, encoding.scale)?.radialMapping !== undefined
|
|
146
|
+
? { mapping: findSemanticScale(program, encoding.scale).radialMapping } : {}) },
|
|
147
147
|
field: encoding.field,
|
|
148
148
|
fieldType: encoding.fieldType
|
|
149
149
|
});
|
|
@@ -163,7 +163,7 @@ export function resolveCompatibleEncodings(program, source, markType) {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
function eligibleLayeredSource(program, layer, requestedData, markType) {
|
|
166
|
-
if (layer?.data === undefined) return false;
|
|
166
|
+
if (layer?.data === undefined || isSourceOwnedText(layer)) return false;
|
|
167
167
|
if (requestedData !== undefined && layer.data !== requestedData) return false;
|
|
168
168
|
return Object.keys(resolveCompatibleEncodings(program, layer, markType)).length > 0;
|
|
169
169
|
}
|