ggaction 0.0.13 → 0.0.16
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 +146 -0
- package/README.md +41 -12
- package/knowledge/action-cards.json +1 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/knowledge/task-packet.schema.json +1 -1
- package/knowledge/task-resolver.js +1 -1
- package/package.json +39 -7
- package/src/BasicChartProgram.js +3 -1
- package/src/ChartProgram.js +2 -0
- package/src/accessibility.js +157 -0
- package/src/actions/basic.js +2 -2
- package/src/actions/boxPlots/components.js +20 -12
- package/src/actions/boxPlots/create.js +4 -5
- package/src/actions/boxPlots/edit.js +34 -9
- package/src/actions/boxPlots/materialize.js +12 -4
- package/src/actions/boxPlots/options.js +48 -16
- package/src/actions/canvas/actions.js +3 -3
- package/src/actions/canvas/fitting.js +1 -1
- package/src/actions/categoryOrder/index.js +21 -12
- package/src/actions/charts/area.js +6 -2
- package/src/actions/charts/bar.js +3 -2
- package/src/actions/charts/beeswarm.js +1 -1
- package/src/actions/charts/density.js +7 -3
- package/src/actions/charts/ecdf.js +6 -3
- package/src/actions/charts/endpoints.js +29 -7
- package/src/actions/charts/heatmap.js +3 -2
- package/src/actions/charts/histogram.js +5 -4
- package/src/actions/charts/horizon.js +4 -2
- package/src/actions/charts/interval-regression.js +7 -4
- package/src/actions/charts/line.js +4 -2
- package/src/actions/charts/parallel.js +9 -3
- package/src/actions/charts/pie.js +11 -3
- package/src/actions/charts/polar.js +17 -6
- package/src/actions/charts/radar.js +9 -3
- package/src/actions/charts/radial.js +12 -4
- package/src/actions/charts/raincloud.js +2 -2
- package/src/actions/charts/rug-strip.js +8 -4
- package/src/actions/charts/scatter.js +4 -2
- package/src/actions/composition/actions.js +29 -24
- package/src/actions/coordinates/actions.js +2 -2
- package/src/actions/coordinates/edit.js +76 -0
- package/src/actions/data/basicBin2d.js +4 -5
- package/src/actions/data/bin.js +3 -3
- package/src/actions/data/bin2d.js +63 -193
- package/src/actions/data/bin2dMaterialize.js +4 -5
- package/src/actions/data/box.js +4 -4
- package/src/actions/data/complete.js +26 -0
- package/src/actions/data/computed.js +4 -4
- package/src/actions/data/create.js +7 -14
- package/src/actions/data/density.js +15 -23
- package/src/actions/data/derived.js +57 -31
- package/src/actions/data/ecdf.js +2 -2
- package/src/actions/data/edit.js +551 -0
- package/src/actions/data/filter.js +28 -22
- package/src/actions/data/fold.js +2 -2
- package/src/actions/data/gradientProfile.js +2 -2
- package/src/actions/data/horizon.js +2 -2
- package/src/actions/data/impute.js +26 -0
- package/src/actions/data/index.js +62 -47
- package/src/actions/data/interval.js +2 -2
- package/src/actions/data/intervalEdit.js +26 -18
- package/src/actions/data/normalize.js +27 -0
- package/src/actions/data/regression.js +21 -27
- package/src/actions/data/revise.js +48 -0
- package/src/actions/data/revisionBindings.js +125 -0
- package/src/actions/data/shared.js +20 -4
- package/src/actions/data/stack.js +2 -2
- package/src/actions/data/summary.js +3 -3
- package/src/actions/data/timeUnit.js +6 -3
- package/src/actions/data/window.js +3 -3
- package/src/actions/encodings/angle.js +1 -1
- package/src/actions/encodings/appearance.js +4 -4
- package/src/actions/encodings/barWidth.js +1 -1
- package/src/actions/encodings/channels.js +415 -0
- package/src/actions/encodings/color/index.js +3 -2
- package/src/actions/encodings/density.js +7 -4
- package/src/actions/encodings/histogram.js +4 -3
- package/src/actions/encodings/horizon.js +6 -8
- package/src/actions/encodings/index.js +4 -0
- package/src/actions/encodings/offset.js +22 -15
- package/src/actions/encodings/parallel.js +4 -5
- package/src/actions/encodings/pathOrder.js +6 -11
- package/src/actions/encodings/position/apply.js +53 -7
- package/src/actions/encodings/position/index.js +14 -6
- package/src/actions/encodings/position/policies/bar.js +9 -0
- package/src/actions/encodings/position/resolve.js +24 -7
- package/src/actions/encodings/ranged.js +5 -5
- package/src/actions/encodings/remove.js +13 -9
- package/src/actions/encodings/ruleAppearance.js +2 -24
- package/src/actions/encodings/seriesLayout.js +2 -1
- package/src/actions/encodings/shared.js +82 -14
- package/src/actions/encodings/stroke.js +226 -0
- package/src/actions/encodings/strokeDash.js +2 -2
- package/src/actions/encodings/text.js +1 -1
- package/src/actions/errorBands/create.js +34 -20
- package/src/actions/errorBands/edit.js +34 -137
- package/src/actions/errorBars/create.js +43 -20
- package/src/actions/errorBars/edit.js +29 -125
- package/src/actions/facets/actions.js +267 -73
- package/src/actions/facets/derive.js +99 -28
- package/src/actions/facets/guides.js +4 -5
- package/src/actions/facets/replay.js +4 -5
- package/src/actions/gradientPlots/components.js +15 -8
- package/src/actions/gradientPlots/create.js +4 -5
- package/src/actions/gradientPlots/edit.js +18 -9
- package/src/actions/gradientPlots/materialize.js +5 -3
- package/src/actions/gradientPlots/options.js +10 -2
- package/src/actions/gradientPlots/rebind.js +4 -5
- package/src/actions/guides/applicability.js +8 -2
- package/src/actions/guides/axes/axes.js +23 -4
- package/src/actions/guides/axes/axis.js +2 -2
- package/src/actions/guides/axes/edit.js +2 -2
- package/src/actions/guides/axes/labels.js +67 -21
- package/src/actions/guides/axes/lines.js +15 -9
- package/src/actions/guides/axes/parallel/lifecycle.js +13 -13
- package/src/actions/guides/axes/parallel/resolve.js +6 -2
- package/src/actions/guides/axes/parallel.js +5 -5
- package/src/actions/guides/axes/remove.js +4 -4
- package/src/actions/guides/axes/tickGroups.js +6 -5
- package/src/actions/guides/axes/ticks.js +19 -6
- package/src/actions/guides/axes/titles.js +21 -13
- package/src/actions/guides/grids/grid.js +18 -29
- package/src/actions/guides/grids/resolve.js +7 -2
- package/src/actions/guides/guides.js +20 -4
- package/src/actions/guides/legends/blocks.js +426 -0
- package/src/actions/guides/legends/categorical/actions.js +138 -52
- package/src/actions/guides/legends/categorical/components.js +55 -45
- package/src/actions/guides/legends/categorical/index.js +37 -33
- package/src/actions/guides/legends/categorical/layout.js +98 -16
- package/src/actions/guides/legends/categorical/options.js +2 -2
- package/src/actions/guides/legends/categorical/recipes.js +111 -20
- package/src/actions/guides/legends/categorical/resolve.js +12 -8
- package/src/actions/guides/legends/categorical/symbols.js +104 -52
- package/src/actions/guides/legends/continuous/common.js +76 -20
- package/src/actions/guides/legends/continuous/gradient.js +95 -158
- package/src/actions/guides/legends/continuous/index.js +2 -0
- package/src/actions/guides/legends/continuous/interval.js +21 -16
- package/src/actions/guides/legends/continuous/opacity.js +37 -83
- package/src/actions/guides/legends/continuous/stroke.js +225 -0
- package/src/actions/guides/legends/creation.js +14 -1
- package/src/actions/guides/legends/edit.js +159 -60
- package/src/actions/guides/legends/focused.js +5 -5
- package/src/actions/guides/legends/index.js +2 -0
- package/src/actions/guides/legends/lane.js +59 -24
- package/src/actions/guides/legends/lifecycle.js +19 -8
- package/src/actions/guides/legends/remove.js +17 -8
- package/src/actions/guides/legends/sampling.js +140 -0
- package/src/actions/guides/legends/size.js +100 -108
- package/src/actions/guides/legends/strokeWidth.js +38 -92
- package/src/actions/guides/legends/target.js +112 -1
- package/src/actions/guides/legends/transition.js +165 -16
- package/src/actions/guides/polar/axes/facade.js +8 -8
- package/src/actions/guides/polar/axes/labels.js +29 -10
- package/src/actions/guides/polar/axes/lines.js +19 -19
- package/src/actions/guides/polar/axes/shared.js +16 -0
- package/src/actions/guides/polar/axes/ticks.js +10 -16
- package/src/actions/guides/polar/axes/titles.js +6 -6
- package/src/actions/guides/polar/grids.js +12 -14
- package/src/actions/guides/polar/resolve.js +12 -8
- package/src/actions/index.js +16 -3
- package/src/actions/intervals/revision.js +126 -0
- package/src/actions/marks/arc/actions.js +80 -22
- package/src/actions/marks/area/actions.js +38 -13
- package/src/actions/marks/area/materialize.js +17 -1
- package/src/actions/marks/bar/create.js +12 -3
- package/src/actions/marks/bar/edit.js +21 -4
- package/src/actions/marks/bar/materialize.js +34 -40
- package/src/actions/marks/index.js +10 -1
- package/src/actions/marks/line/actions.js +40 -17
- package/src/actions/marks/line/materialize.js +29 -10
- package/src/actions/marks/point/create.js +9 -3
- package/src/actions/marks/point/edit.js +19 -7
- package/src/actions/marks/point/jitter.js +6 -8
- package/src/actions/marks/point/materialize.js +48 -22
- package/src/actions/marks/point/packing.js +6 -8
- package/src/actions/marks/rect/actions.js +36 -15
- package/src/actions/marks/references.js +602 -33
- package/src/actions/marks/remove.js +67 -41
- package/src/actions/marks/rule/actions.js +51 -14
- package/src/actions/marks/shared.js +1 -1
- package/src/actions/marks/text/actions.js +79 -14
- package/src/actions/marks/text/index.js +4 -0
- package/src/actions/marks/text/layout.js +157 -17
- package/src/actions/marks/text/removal.js +173 -0
- package/src/actions/marks/text/selection.js +72 -0
- package/src/actions/marks/tick/actions.js +25 -8
- package/src/actions/primitives/createGraphics.js +5 -4
- package/src/actions/primitives/editGraphics.js +31 -4
- package/src/actions/primitives/graphicProperties.js +6 -0
- package/src/actions/primitives/semantic.js +11 -3
- package/src/actions/primitives/semanticAction.js +90 -14
- package/src/actions/primitives/semanticValidation/dataset.js +2 -4
- package/src/actions/primitives/semanticValidation/guide.js +1 -1
- package/src/actions/primitives/semanticValidation/index.js +9 -1
- package/src/actions/primitives/semanticValidation/layer.js +5 -0
- package/src/actions/primitives/semanticValidation/scale.js +28 -7
- package/src/actions/regression/components.js +36 -25
- package/src/actions/regression/create.js +13 -6
- package/src/actions/regression/edit.js +24 -11
- package/src/actions/resources/index.js +7 -0
- package/src/actions/resources/remove.js +173 -0
- package/src/actions/scales/channels.js +212 -0
- package/src/actions/scales/consumers/common.js +1 -1
- package/src/actions/scales/consumers/families.js +3 -2
- package/src/actions/scales/consumers/index.js +19 -2
- package/src/actions/scales/consumers/seriesLayout.js +28 -14
- package/src/actions/scales/create.js +55 -23
- package/src/actions/scales/definitions.js +94 -40
- package/src/actions/scales/edit.js +67 -12
- package/src/actions/scales/editPolicy.js +81 -11
- package/src/actions/scales/index.js +6 -0
- package/src/actions/scales/materialize.js +5 -4
- package/src/actions/scales/offset.js +48 -0
- package/src/actions/scales/parallel.js +71 -0
- package/src/actions/scales/preview.js +111 -10
- package/src/actions/scales/quantitativeColor.js +4 -5
- package/src/actions/selection/actions.js +179 -66
- package/src/actions/selection/index.js +3 -0
- package/src/actions/textMetrics/index.js +56 -0
- package/src/actions/theme/actions.js +70 -15
- package/src/actions/theme/composition.js +238 -0
- package/src/actions/theme/index.js +9 -2
- package/src/actions/theme/reconcile.js +313 -121
- package/src/actions/theme/state.js +160 -0
- package/src/actions/titles/actions.js +8 -8
- package/src/actions/titles/resolve.js +3 -3
- package/src/actions/violinPlots/create.js +6 -3
- package/src/actions/violinPlots/edit.js +2 -1
- package/src/core/action.js +117 -35
- package/src/core/compositionState.js +6 -1
- package/src/core/diagnostics.js +16 -0
- package/src/core/extensionRegistry.js +27 -0
- package/src/core/font.js +18 -0
- package/src/core/identifiers.js +5 -4
- package/src/core/immutable.js +10 -3
- package/src/core/optionRequirements.js +8 -0
- package/src/core/programState.js +21 -1
- package/src/core/resourceReferences.js +341 -0
- package/src/core/textMetricProfile.js +28 -0
- package/src/core/textMetrics.js +24 -3
- package/src/core/validation.js +22 -10
- package/src/core/vocabulary.js +16 -3
- package/src/diagnostics.js +1 -0
- package/src/grammar/bars/aggregate.js +4 -1
- package/src/grammar/bars/geometry.js +44 -0
- package/src/grammar/bin.js +54 -9
- package/src/grammar/complete.js +279 -0
- package/src/grammar/computed.js +265 -64
- package/src/grammar/coordinates.js +37 -0
- package/src/grammar/density.js +239 -37
- package/src/grammar/displayLabels.js +57 -0
- package/src/grammar/facets/dependencies.js +133 -1
- package/src/grammar/facets/guides.js +3 -0
- package/src/grammar/facets/index.js +7 -47
- package/src/grammar/facets/scales.js +15 -18
- package/src/grammar/impute.js +341 -0
- package/src/grammar/markLabelSelection.js +57 -0
- package/src/grammar/markLabels.js +18 -1
- package/src/grammar/normalize.js +366 -0
- package/src/grammar/pathSeries.js +26 -8
- package/src/grammar/pointShapes.js +13 -4
- package/src/grammar/polar.js +90 -8
- package/src/grammar/regression/index.js +1 -0
- package/src/grammar/regression/parameters.js +23 -0
- package/src/grammar/roundedRect.js +180 -0
- package/src/grammar/rules.js +1 -0
- package/src/grammar/scales/colorConsumers.js +20 -1
- package/src/grammar/scales/continuous.js +2 -2
- package/src/grammar/scales/definition.js +27 -4
- package/src/grammar/scales/index.js +1 -0
- package/src/grammar/scales/ordinal.js +12 -3
- package/src/grammar/scales/policies.js +2 -2
- package/src/grammar/scales/size.js +456 -0
- package/src/grammar/scales/types.js +8 -0
- package/src/grammar/schemas/concreteGraphic.js +14 -2
- package/src/grammar/schemas/graphic.js +15 -0
- package/src/grammar/schemas/graphicBounds.js +190 -41
- package/src/grammar/schemas/semanticPath.js +7 -2
- package/src/grammar/statisticalReference.js +103 -0
- package/src/grammar/strokeStyle.js +77 -0
- package/src/grammar/summary.js +78 -16
- package/src/grammar/timeUnit.js +216 -5
- package/src/grammar/transformTopology.js +4 -0
- package/src/grammar/transforms.js +394 -28
- package/src/grammar/weightedStatistics.js +374 -0
- package/src/grammar/window.js +221 -16
- package/src/layout/aspect.js +80 -0
- package/src/layout/facets.js +59 -5
- package/src/layout/labels.js +351 -7
- package/src/layout/legend.js +4 -4
- package/src/layout/legendItems.js +6 -6
- package/src/layout/text.js +10 -9
- package/src/layout/title.js +9 -9
- package/src/materialization/bars/aggregate.js +25 -2
- package/src/materialization/bars/histogram.js +84 -24
- package/src/materialization/bars/ranged.js +19 -3
- package/src/materialization/bars/resolve.js +7 -4
- package/src/materialization/composition.js +3 -1
- package/src/materialization/coordinateBounds.js +204 -0
- package/src/materialization/dependencies.js +36 -0
- package/src/materialization/facetGuides/legacyCategorical.js +3 -0
- package/src/materialization/facetGuides/placement.js +9 -3
- package/src/materialization/facetGuides/preparation.js +13 -8
- package/src/materialization/facetHeaders.js +347 -0
- package/src/materialization/facets.js +15 -65
- package/src/materialization/guides/layout.js +3 -3
- package/src/materialization/guides/resources.js +26 -0
- package/src/materialization/legends.js +1 -1
- package/src/materialization/marks/index.js +11 -5
- package/src/materialization/marks/policies.js +2 -1
- package/src/materialization/rect.js +25 -12
- package/src/materialization/rectConfig.js +5 -1
- package/src/materialization/scaleGuideDependencies.js +10 -0
- package/src/materialization/scales/map.js +5 -3
- package/src/materialization/scales/policies/binnedPosition.js +2 -2
- package/src/materialization/scales/policies/offset.js +50 -8
- package/src/materialization/scales/policies/series.js +4 -1
- package/src/materialization/scales/resolve.js +22 -6
- package/src/materialization/selection/items/arc.js +28 -4
- package/src/materialization/selection/items/bar.js +30 -3
- package/src/materialization/selection/items/common.js +20 -5
- package/src/materialization/selection/items/rect.js +28 -4
- package/src/materialization/selection/path.js +1 -1
- package/src/materialization/selection/point.js +3 -1
- package/src/materialization/text.js +265 -14
- package/src/materialization/typography.js +31 -0
- package/src/mcp/cli.js +5 -3
- package/src/persistence/codec.js +65 -0
- package/src/persistence/validation.js +185 -0
- package/src/persistence.js +74 -0
- package/src/renderers/canvas/circle.js +2 -3
- package/src/renderers/canvas/index.js +5 -4
- 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/nativeBackend.js +10 -0
- package/src/renderers/options.js +13 -0
- package/src/renderers/pdf.js +25 -54
- package/src/renderers/png.js +22 -17
- package/src/renderers/svg.js +29 -14
- package/src/renderers/text.js +1 -11
- package/src/selectors/coordinates.js +3 -1
- package/src/selectors/datasets.js +38 -5
- package/src/selectors/layers.js +10 -4
- package/src/selectors/markOwners.js +46 -0
- package/src/selectors/scales.js +6 -4
- package/src/theme/defaults.js +103 -1
- package/src/version.js +2 -0
- package/types/accessibility.d.ts +37 -0
- package/types/basic.d.ts +10 -2
- package/types/diagnostics.d.ts +15 -0
- package/types/index.d.ts +90 -0
- package/types/pdf.d.ts +9 -0
- package/types/persistence.d.ts +7 -0
- package/types/png.d.ts +9 -0
- package/types/program.d.ts +944 -118
|
@@ -3,10 +3,12 @@ import {
|
|
|
3
3
|
readScaleField
|
|
4
4
|
} from "../grammar/scales/index.js";
|
|
5
5
|
import { normalizePositionDatum } from "../grammar/positionDatum.js";
|
|
6
|
-
import {
|
|
6
|
+
import { resolveCoordinateBounds } from "./coordinateBounds.js";
|
|
7
7
|
import { RECT_MODES, resolveRectMode, rectUsesFields } from "../grammar/rects.js";
|
|
8
8
|
import { DEFAULT_RECT_MARK } from "./rectConfig.js";
|
|
9
9
|
import { mapScaleConsumerValues } from "./scales/map.js";
|
|
10
|
+
import { materializeRectItem } from "../grammar/roundedRect.js";
|
|
11
|
+
import { requestedStrokeDetails } from "../grammar/strokeStyle.js";
|
|
10
12
|
|
|
11
13
|
function optionalValues(rows, encoding, length, channel) {
|
|
12
14
|
if (Object.hasOwn(encoding, "datum")) {
|
|
@@ -22,7 +24,11 @@ function requiredChannels(layer, mode) {
|
|
|
22
24
|
const position = mode === RECT_MODES.xSpan ? ["x", "x2"]
|
|
23
25
|
: mode === RECT_MODES.ySpan ? ["y", "y2"]
|
|
24
26
|
: mode === RECT_MODES.ranged ? ["x", "x2", "y", "y2"] : ["x", "y"];
|
|
25
|
-
return [
|
|
27
|
+
return [
|
|
28
|
+
...position,
|
|
29
|
+
...(layer.encoding?.color ? ["color"] : []),
|
|
30
|
+
...(layer.encoding?.stroke ? ["stroke"] : [])
|
|
31
|
+
];
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
export function resolveRectConsumerValues(layer, dataset, channel) {
|
|
@@ -64,19 +70,22 @@ function mappedEncoding(program, layer, dataset, channel) {
|
|
|
64
70
|
};
|
|
65
71
|
}
|
|
66
72
|
|
|
67
|
-
function appearance(config, fill) {
|
|
73
|
+
function appearance(config, fill, stroke) {
|
|
68
74
|
return {
|
|
69
75
|
fill,
|
|
70
76
|
opacity: config.opacity,
|
|
71
|
-
stroke: config.stroke === false ? "transparent" : config.stroke,
|
|
72
|
-
strokeWidth:
|
|
77
|
+
stroke: stroke ?? (config.stroke === false ? "transparent" : config.stroke),
|
|
78
|
+
strokeWidth: stroke === undefined && config.stroke === false
|
|
79
|
+
? 0
|
|
80
|
+
: config.strokeWidth ?? 1,
|
|
81
|
+
...requestedStrokeDetails(config, "Rect mark")
|
|
73
82
|
};
|
|
74
83
|
}
|
|
75
84
|
|
|
76
85
|
export function resolveRectRows(program, layer, dataset) {
|
|
77
86
|
const mode = resolveRectMode(layer);
|
|
78
87
|
if (mode === undefined) return [];
|
|
79
|
-
const bounds =
|
|
88
|
+
const bounds = resolveCoordinateBounds(program, layer.coordinate);
|
|
80
89
|
const x = layer.encoding.x === undefined ? undefined : mappedEncoding(program, layer, dataset, "x");
|
|
81
90
|
const y = layer.encoding.y === undefined ? undefined : mappedEncoding(program, layer, dataset, "y");
|
|
82
91
|
const x2 = layer.encoding.x2 === undefined ? undefined : mappedEncoding(program, layer, dataset, "x2");
|
|
@@ -84,6 +93,9 @@ export function resolveRectRows(program, layer, dataset) {
|
|
|
84
93
|
const color = layer.encoding?.color === undefined
|
|
85
94
|
? undefined
|
|
86
95
|
: mappedEncoding(program, layer, dataset, "color").values;
|
|
96
|
+
const stroke = layer.encoding?.stroke === undefined
|
|
97
|
+
? undefined
|
|
98
|
+
: mappedEncoding(program, layer, dataset, "stroke").values;
|
|
87
99
|
const config = program.markConfigs[layer.id] ?? DEFAULT_RECT_MARK;
|
|
88
100
|
|
|
89
101
|
const rows = rectUsesFields(layer) ? dataset.values : [{}];
|
|
@@ -92,7 +104,8 @@ export function resolveRectRows(program, layer, dataset) {
|
|
|
92
104
|
if (
|
|
93
105
|
(x !== undefined && !Number.isFinite(x.values[index])) ||
|
|
94
106
|
(y !== undefined && !Number.isFinite(y.values[index])) ||
|
|
95
|
-
typeof fill !== "string"
|
|
107
|
+
typeof fill !== "string" ||
|
|
108
|
+
(stroke !== undefined && typeof stroke[index] !== "string")
|
|
96
109
|
) return [];
|
|
97
110
|
|
|
98
111
|
let geometry;
|
|
@@ -125,14 +138,14 @@ export function resolveRectRows(program, layer, dataset) {
|
|
|
125
138
|
return [{
|
|
126
139
|
row,
|
|
127
140
|
sourceIndex: index,
|
|
128
|
-
properties: { ...geometry, ...appearance(config, fill) }
|
|
141
|
+
properties: { ...geometry, ...appearance(config, fill, stroke?.[index]) }
|
|
129
142
|
}];
|
|
130
143
|
});
|
|
131
144
|
}
|
|
132
145
|
|
|
133
146
|
export function resolveRectGraphicItems(program, layer, dataset) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
147
|
+
const radius = program.markConfigs[layer.id]?.cornerRadius ?? 0;
|
|
148
|
+
return resolveRectRows(program, layer, dataset).map(item =>
|
|
149
|
+
materializeRectItem(item.properties, radius)
|
|
150
|
+
);
|
|
138
151
|
}
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
validateUnitInterval
|
|
5
5
|
} from "../core/validation.js";
|
|
6
6
|
import { DEFAULT_COLORS } from "../theme/defaults.js";
|
|
7
|
+
import { requestedRectStyleDetails } from "../grammar/roundedRect.js";
|
|
7
8
|
|
|
8
9
|
export const DEFAULT_RECT_MARK = Object.freeze({
|
|
9
10
|
fill: DEFAULT_COLORS.mark,
|
|
@@ -13,7 +14,10 @@ export const DEFAULT_RECT_MARK = Object.freeze({
|
|
|
13
14
|
});
|
|
14
15
|
|
|
15
16
|
export function normalizeRectMarkConfig(patch, previous = DEFAULT_RECT_MARK) {
|
|
16
|
-
const result = {
|
|
17
|
+
const result = {
|
|
18
|
+
...previous,
|
|
19
|
+
...requestedRectStyleDetails(patch, "Rect")
|
|
20
|
+
};
|
|
17
21
|
if (Object.hasOwn(patch, "fill")) {
|
|
18
22
|
result.fill = validateNonEmptyString(patch.fill, "Rect fill");
|
|
19
23
|
}
|
|
@@ -18,6 +18,16 @@ const GRIDS = Object.freeze([
|
|
|
18
18
|
Object.freeze({ role: "radial", op: "rematerializeRadialGrid" })
|
|
19
19
|
]);
|
|
20
20
|
|
|
21
|
+
export function planAxisTickGridRematerialization(program, channel) {
|
|
22
|
+
const ticks = program.guideConfigs.axis?.[channel]?.ticks;
|
|
23
|
+
const role = channel === "x" ? "vertical" : "horizontal";
|
|
24
|
+
const config = program.guideConfigs.grid?.[role];
|
|
25
|
+
return buildMaterializationPlan({ guides:
|
|
26
|
+
config?.inferredValues === true && config.scale === ticks?.scale
|
|
27
|
+
? GRIDS.filter(grid => grid.role === role).map(grid => ({ op: grid.op })) : []
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
21
31
|
function usesPositionalScale(program, id) {
|
|
22
32
|
return program.semanticSpec.layers.some(layer =>
|
|
23
33
|
!isSourceOwnedText(layer) && (
|
|
@@ -4,15 +4,17 @@ import {
|
|
|
4
4
|
isOrdinalScaleType,
|
|
5
5
|
mapContinuousScaleValues,
|
|
6
6
|
mapDiscretizedColors,
|
|
7
|
+
mapSizeValues,
|
|
7
8
|
mapOrdinalValues,
|
|
8
9
|
mapSequentialColors
|
|
9
10
|
} from "../../grammar/scales/index.js";
|
|
10
11
|
|
|
11
12
|
export function mapScaleConsumerValues(values, resolvedScale, channel) {
|
|
12
|
-
if (channel === "
|
|
13
|
+
if (channel === "size") return mapSizeValues(values, resolvedScale);
|
|
14
|
+
if (["color", "stroke"].includes(channel) && isDiscretizedColorScaleType(resolvedScale.type)) {
|
|
13
15
|
return mapDiscretizedColors(values, resolvedScale);
|
|
14
16
|
}
|
|
15
|
-
if (
|
|
17
|
+
if (["color", "stroke"].includes(channel) && isContinuousColorScaleType(resolvedScale.type)) {
|
|
16
18
|
return mapSequentialColors(
|
|
17
19
|
values,
|
|
18
20
|
resolvedScale.domain,
|
|
@@ -28,7 +30,7 @@ export function mapScaleConsumerValues(values, resolvedScale, channel) {
|
|
|
28
30
|
);
|
|
29
31
|
}
|
|
30
32
|
if (
|
|
31
|
-
["color", "strokeDash", "shape"].includes(channel) &&
|
|
33
|
+
["color", "stroke", "strokeDash", "shape"].includes(channel) &&
|
|
32
34
|
isOrdinalScaleType(resolvedScale.type)
|
|
33
35
|
) {
|
|
34
36
|
return mapOrdinalValues(values, resolvedScale.domain, resolvedScale.range, {
|
|
@@ -13,8 +13,8 @@ export function resolveBinnedPositionDomain({
|
|
|
13
13
|
consumer.encoding.bin !== undefined
|
|
14
14
|
);
|
|
15
15
|
if (binnedPositions.length === 0) return undefined;
|
|
16
|
-
const independentConsumers = valuesByConsumer.filter(({ consumer }) =>
|
|
17
|
-
!isSourceOwnedText(consumer.layer)
|
|
16
|
+
const independentConsumers = valuesByConsumer.filter(({ consumer, scalePolicy }) =>
|
|
17
|
+
scalePolicy !== false && !isSourceOwnedText(consumer.layer)
|
|
18
18
|
);
|
|
19
19
|
if (channel !== "x" || binnedPositions.length !== independentConsumers.length) {
|
|
20
20
|
throw new Error(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizeOffsetScalePolicy } from "../../../grammar/bars/geometry.js";
|
|
2
2
|
|
|
3
3
|
function resolveParentSlot(consumer, resolvedScales, parentChannel) {
|
|
4
4
|
if (parentChannel === "x" && consumer.layer.encoding?.x?.bin !== undefined) {
|
|
@@ -16,6 +16,7 @@ function resolveParentSlot(consumer, resolvedScales, parentChannel) {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function resolveOffsetScalePolicy({
|
|
19
|
+
scale,
|
|
19
20
|
consumers,
|
|
20
21
|
resolvedScales,
|
|
21
22
|
markConfigs,
|
|
@@ -34,21 +35,62 @@ export function resolveOffsetScalePolicy({
|
|
|
34
35
|
`${channel} scale "${id}" requires one shared resolved ${parentChannel} categorical slot.`
|
|
35
36
|
);
|
|
36
37
|
}
|
|
37
|
-
|
|
38
|
+
return {
|
|
39
|
+
parentBandwidth: slots[0],
|
|
40
|
+
...resolveRequestedOffsetPolicy({
|
|
41
|
+
scale,
|
|
42
|
+
consumers,
|
|
43
|
+
markConfigs,
|
|
44
|
+
id,
|
|
45
|
+
channel
|
|
46
|
+
})
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Resolve the requested offset policy independently from its parent slot.
|
|
52
|
+
* Semantic scale fields are canonical. Consistent legacy mark-owned padding is
|
|
53
|
+
* retained as a fallback until the next successful scale/encoding edit migrates
|
|
54
|
+
* it into the semantic scale.
|
|
55
|
+
*/
|
|
56
|
+
export function resolveRequestedOffsetPolicy({
|
|
57
|
+
scale,
|
|
58
|
+
consumers = [],
|
|
59
|
+
markConfigs = {},
|
|
60
|
+
id = scale?.id ?? channel,
|
|
61
|
+
channel = "xOffset"
|
|
62
|
+
}) {
|
|
63
|
+
const semanticPatch = scale === undefined
|
|
64
|
+
? {}
|
|
65
|
+
: Object.fromEntries(
|
|
66
|
+
["padding", "paddingInner", "paddingOuter", "align"]
|
|
67
|
+
.filter(property => Object.hasOwn(scale, property))
|
|
68
|
+
.map(property => [property, scale[property]])
|
|
69
|
+
);
|
|
70
|
+
if (
|
|
71
|
+
Object.hasOwn(semanticPatch, "padding") ||
|
|
72
|
+
["paddingInner", "paddingOuter", "align"].every(
|
|
73
|
+
property => Object.hasOwn(semanticPatch, property)
|
|
74
|
+
)
|
|
75
|
+
) {
|
|
76
|
+
return normalizeOffsetScalePolicy(semanticPatch, undefined, channel);
|
|
77
|
+
}
|
|
78
|
+
const legacyPolicies = consumers.map(consumer => normalizeOffsetScalePolicy(
|
|
38
79
|
markConfigs[consumer.layer.id]?.[channel],
|
|
39
80
|
undefined,
|
|
40
81
|
channel
|
|
41
82
|
));
|
|
42
83
|
const signatures = new Set(
|
|
43
|
-
|
|
84
|
+
legacyPolicies.map(policy => JSON.stringify(policy))
|
|
44
85
|
);
|
|
45
|
-
if (signatures.size
|
|
86
|
+
if (signatures.size > 1) {
|
|
46
87
|
throw new Error(
|
|
47
88
|
`${channel} scale "${id}" requires one shared padding policy.`
|
|
48
89
|
);
|
|
49
90
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
91
|
+
const legacy = legacyPolicies[0] ?? normalizeOffsetScalePolicy(
|
|
92
|
+
{}, undefined, channel
|
|
93
|
+
);
|
|
94
|
+
if (scale === undefined) return legacy;
|
|
95
|
+
return normalizeOffsetScalePolicy(semanticPatch, legacy, channel);
|
|
54
96
|
}
|
|
@@ -22,7 +22,10 @@ export function resolveSeriesLayoutDomain({
|
|
|
22
22
|
(_, index) => seriesLayouts[index] !== undefined
|
|
23
23
|
);
|
|
24
24
|
const directConsumers = valuesByConsumer.filter(
|
|
25
|
-
({ consumer }, index) =>
|
|
25
|
+
({ consumer, scalePolicy }, index) =>
|
|
26
|
+
scalePolicy !== false &&
|
|
27
|
+
seriesLayouts[index] === undefined &&
|
|
28
|
+
!isSourceOwnedText(consumer.layer)
|
|
26
29
|
);
|
|
27
30
|
const compatibleDirect = directConsumers.every(({ consumer }) =>
|
|
28
31
|
layoutConsumers.every(({ consumer: layoutConsumer }) => {
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
resolveScaleRange,
|
|
18
18
|
resolveSequentialColorStops,
|
|
19
19
|
resolveShapeRange,
|
|
20
|
+
resolveSizeScale,
|
|
20
21
|
resolveSizeRange,
|
|
21
22
|
resolveStrokeDashRange,
|
|
22
23
|
resolveStrokeWidthRange,
|
|
@@ -96,7 +97,8 @@ function resolveRange({
|
|
|
96
97
|
isSequentialColor,
|
|
97
98
|
isDiscretizedColor,
|
|
98
99
|
isOrdinalOffset,
|
|
99
|
-
discretizedScale
|
|
100
|
+
discretizedScale,
|
|
101
|
+
polarFrame
|
|
100
102
|
}) {
|
|
101
103
|
if (channel === "color") {
|
|
102
104
|
if (isDiscretizedColor) return discretizedScale.range;
|
|
@@ -114,7 +116,7 @@ function resolveRange({
|
|
|
114
116
|
scale,
|
|
115
117
|
channel,
|
|
116
118
|
domain,
|
|
117
|
-
range: resolveScaleRange(scale.range, channel, bounds),
|
|
119
|
+
range: resolveScaleRange(scale.range, channel, bounds, polarFrame),
|
|
118
120
|
markConfigs
|
|
119
121
|
});
|
|
120
122
|
}
|
|
@@ -190,14 +192,16 @@ export function resolveScaleMaterialization(options) {
|
|
|
190
192
|
const {
|
|
191
193
|
id,
|
|
192
194
|
scale,
|
|
193
|
-
channel,
|
|
195
|
+
channel: requestedChannel,
|
|
194
196
|
consumers,
|
|
195
197
|
valuesByConsumer,
|
|
196
198
|
bounds,
|
|
197
199
|
resolvedScales,
|
|
198
200
|
markConfigs,
|
|
199
|
-
thetaScales
|
|
201
|
+
thetaScales,
|
|
202
|
+
polarFrame
|
|
200
203
|
} = options;
|
|
204
|
+
const channel = requestedChannel === "stroke" ? "color" : requestedChannel;
|
|
201
205
|
const allValues = valuesByConsumer
|
|
202
206
|
.flatMap(item => item.values)
|
|
203
207
|
.filter(value => value !== undefined);
|
|
@@ -218,6 +222,9 @@ export function resolveScaleMaterialization(options) {
|
|
|
218
222
|
}))
|
|
219
223
|
});
|
|
220
224
|
}
|
|
225
|
+
if (channel === "size") {
|
|
226
|
+
return resolveSizeScale({ ...scale, values: allValues });
|
|
227
|
+
}
|
|
221
228
|
const isSequentialColor = channel === "color" &&
|
|
222
229
|
isContinuousColorScaleType(scale.type);
|
|
223
230
|
const isDiscretizedColor = channel === "color" &&
|
|
@@ -234,7 +241,14 @@ export function resolveScaleMaterialization(options) {
|
|
|
234
241
|
isDiscretePositionScaleType(scale.type);
|
|
235
242
|
|
|
236
243
|
if (isSequentialColor || isDiscretizedColor) {
|
|
237
|
-
for (const consumer of consumers)
|
|
244
|
+
for (const consumer of consumers) {
|
|
245
|
+
validateContinuousColorConsumer(
|
|
246
|
+
consumer.layer,
|
|
247
|
+
consumer.encoding,
|
|
248
|
+
scale,
|
|
249
|
+
{ channel: consumer.channel }
|
|
250
|
+
);
|
|
251
|
+
}
|
|
238
252
|
}
|
|
239
253
|
let discretizedScale;
|
|
240
254
|
if (isDiscretizedColor) {
|
|
@@ -290,7 +304,8 @@ export function resolveScaleMaterialization(options) {
|
|
|
290
304
|
isSequentialColor,
|
|
291
305
|
isDiscretizedColor,
|
|
292
306
|
isOrdinalOffset,
|
|
293
|
-
discretizedScale
|
|
307
|
+
discretizedScale,
|
|
308
|
+
polarFrame
|
|
294
309
|
});
|
|
295
310
|
validateSequentialMidpoint(scale.midpoint, scale.type, domain);
|
|
296
311
|
if (scale.midpoint !== undefined && (channel !== "color" || consumers.some(
|
|
@@ -313,6 +328,7 @@ export function resolveScaleMaterialization(options) {
|
|
|
313
328
|
values: allValues,
|
|
314
329
|
range: scale.range,
|
|
315
330
|
...resolveOffsetScalePolicy({
|
|
331
|
+
scale,
|
|
316
332
|
consumers,
|
|
317
333
|
resolvedScales,
|
|
318
334
|
markConfigs,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { deriveArcSectors } from "../../../grammar/arcs.js";
|
|
2
2
|
import { resolvePolarPoint } from "../../../grammar/polarPaths.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { readScaleField } from "../../../grammar/scales/index.js";
|
|
4
|
+
import { resolveCoordinatePolarFrame } from "../../coordinateBounds.js";
|
|
5
5
|
import {
|
|
6
6
|
concreteProperties,
|
|
7
7
|
finalizeItems,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
export function resolveArcItems(program, layer, dataset) {
|
|
12
12
|
const thetaScale = program.resolvedScales[layer.encoding?.theta?.scale];
|
|
13
13
|
const radiusScale = program.resolvedScales[layer.encoding?.radius?.scale];
|
|
14
|
-
const frame =
|
|
14
|
+
const frame = resolveCoordinatePolarFrame(program, layer.coordinate);
|
|
15
15
|
const derived = deriveArcSectors(dataset.values, layer, {
|
|
16
16
|
thetaScale,
|
|
17
17
|
...(radiusScale === undefined ? {} : { radiusScale }),
|
|
@@ -19,14 +19,25 @@ export function resolveArcItems(program, layer, dataset) {
|
|
|
19
19
|
innerRadiusRatio: program.markConfigs[layer.id]?.innerRadius ?? 0
|
|
20
20
|
});
|
|
21
21
|
const graphic = program.graphicSpec.objects[layer.id];
|
|
22
|
+
const stroke = layer.encoding?.stroke;
|
|
22
23
|
const definitions = derived.sectors.map((sector, index) => {
|
|
23
24
|
const members = sector.sourceIndices.map(index => dataset.values[index]);
|
|
25
|
+
const strokeValues = stroke === undefined ? undefined : readScaleField(
|
|
26
|
+
members,
|
|
27
|
+
stroke.field,
|
|
28
|
+
stroke.fieldType,
|
|
29
|
+
{ temporalUnit: stroke.temporalUnit }
|
|
30
|
+
);
|
|
31
|
+
if (strokeValues !== undefined && new Set(strokeValues).size !== 1) {
|
|
32
|
+
throw new Error("Arc stroke requires one value within each sector.");
|
|
33
|
+
}
|
|
24
34
|
return {
|
|
25
35
|
fields: uniqueFields(members),
|
|
26
36
|
channels: {
|
|
27
37
|
theta: sector.theta,
|
|
28
38
|
...(sector.radius === undefined ? {} : { radius: sector.radius }),
|
|
29
|
-
...(sector.color === undefined ? {} : { color: sector.color })
|
|
39
|
+
...(sector.color === undefined ? {} : { color: sector.color }),
|
|
40
|
+
...(strokeValues === undefined ? {} : { stroke: strokeValues[0] })
|
|
30
41
|
},
|
|
31
42
|
properties: {
|
|
32
43
|
...concreteProperties(graphic.items[index]?.properties),
|
|
@@ -36,6 +47,19 @@ export function resolveArcItems(program, layer, dataset) {
|
|
|
36
47
|
(sector.innerRadius + sector.outerRadius) / 2
|
|
37
48
|
)
|
|
38
49
|
},
|
|
50
|
+
geometry: {
|
|
51
|
+
kind: "arc",
|
|
52
|
+
centerX: frame.centerX,
|
|
53
|
+
centerY: frame.centerY,
|
|
54
|
+
startTheta: sector.startTheta +
|
|
55
|
+
Math.sign(sector.endTheta - sector.startTheta) *
|
|
56
|
+
(program.markConfigs[layer.id]?.padAngle ?? 0) / 2,
|
|
57
|
+
endTheta: sector.endTheta -
|
|
58
|
+
Math.sign(sector.endTheta - sector.startTheta) *
|
|
59
|
+
(program.markConfigs[layer.id]?.padAngle ?? 0) / 2,
|
|
60
|
+
innerRadius: sector.innerRadius,
|
|
61
|
+
outerRadius: sector.outerRadius
|
|
62
|
+
},
|
|
39
63
|
members
|
|
40
64
|
};
|
|
41
65
|
});
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { numericExtent } from "../../../grammar/numeric.js";
|
|
11
11
|
import {
|
|
12
12
|
readNominalField,
|
|
13
|
+
readScaleField,
|
|
13
14
|
readTemporalField
|
|
14
15
|
} from "../../../grammar/scales/index.js";
|
|
15
16
|
import { findSemanticScale } from "../../../selectors/scales.js";
|
|
@@ -52,9 +53,19 @@ function aggregateCellDefinitions(program, layer, dataset) {
|
|
|
52
53
|
const offsetChannel = resolveBarOffsetChannel(layer);
|
|
53
54
|
const offsetScale = program.resolvedScales[layer.encoding?.[offsetChannel]?.scale];
|
|
54
55
|
const layout = resolveBarColorLayout(layer);
|
|
56
|
+
const stroke = layer.encoding?.stroke;
|
|
55
57
|
|
|
56
58
|
function definition(cell, start, end) {
|
|
57
59
|
const members = aggregateMembers(dataset.values, layer, cell, channels);
|
|
60
|
+
const strokeValues = stroke === undefined ? undefined : readScaleField(
|
|
61
|
+
members,
|
|
62
|
+
stroke.field,
|
|
63
|
+
stroke.fieldType,
|
|
64
|
+
{ temporalUnit: stroke.temporalUnit }
|
|
65
|
+
);
|
|
66
|
+
if (strokeValues !== undefined && new Set(strokeValues).size !== 1) {
|
|
67
|
+
throw new Error("Bar stroke requires one value within each aggregate cell.");
|
|
68
|
+
}
|
|
58
69
|
return {
|
|
59
70
|
fields: uniqueFields(members),
|
|
60
71
|
channels: {
|
|
@@ -62,6 +73,7 @@ function aggregateCellDefinitions(program, layer, dataset) {
|
|
|
62
73
|
[channels.measure]: start,
|
|
63
74
|
[`${channels.measure}2`]: end,
|
|
64
75
|
...(cell.color === undefined ? {} : { color: cell.color }),
|
|
76
|
+
...(strokeValues === undefined ? {} : { stroke: strokeValues[0] }),
|
|
65
77
|
...(layer.encoding?.[offsetChannel] === undefined
|
|
66
78
|
? {}
|
|
67
79
|
: { [offsetChannel]: cell.series ?? cell.color })
|
|
@@ -88,8 +100,18 @@ function histogramDefinitions(program, layer, dataset) {
|
|
|
88
100
|
resolvedScales: program.resolvedScales
|
|
89
101
|
});
|
|
90
102
|
const colorScale = program.resolvedScales[colorEncoding?.scale];
|
|
103
|
+
const stroke = layer.encoding?.stroke;
|
|
91
104
|
return segments.map(segment => {
|
|
92
105
|
const colorValue = segment.colorValue ?? colorScale?.domain[segment.category];
|
|
106
|
+
const strokeValues = stroke === undefined ? undefined : readScaleField(
|
|
107
|
+
segment.members,
|
|
108
|
+
stroke.field,
|
|
109
|
+
stroke.fieldType,
|
|
110
|
+
{ temporalUnit: stroke.temporalUnit }
|
|
111
|
+
);
|
|
112
|
+
if (strokeValues !== undefined && new Set(strokeValues).size !== 1) {
|
|
113
|
+
throw new Error("Histogram stroke requires one value within each bin/series cell.");
|
|
114
|
+
}
|
|
93
115
|
return {
|
|
94
116
|
fields: uniqueFields(segment.members),
|
|
95
117
|
channels: {
|
|
@@ -97,7 +119,8 @@ function histogramDefinitions(program, layer, dataset) {
|
|
|
97
119
|
x2: segment.end,
|
|
98
120
|
y: segment.stackStart,
|
|
99
121
|
y2: segment.stackEnd,
|
|
100
|
-
...(colorValue === undefined ? {} : { color: colorValue })
|
|
122
|
+
...(colorValue === undefined ? {} : { color: colorValue }),
|
|
123
|
+
...(strokeValues === undefined ? {} : { stroke: strokeValues[0] })
|
|
101
124
|
},
|
|
102
125
|
members: segment.members
|
|
103
126
|
};
|
|
@@ -188,14 +211,18 @@ export function resolveBarItems(program, layer, dataset, selectionGrain) {
|
|
|
188
211
|
if (definitions === undefined) {
|
|
189
212
|
throw new Error(`Bar mark "${layer.id}" is incomplete for selection.`);
|
|
190
213
|
}
|
|
214
|
+
const graphicTypes = Object.hasOwn(
|
|
215
|
+
program.markConfigs[layer.id]?.barAppearance ?? {},
|
|
216
|
+
"cornerRadius"
|
|
217
|
+
) ? ["rect", "path"] : "rect";
|
|
191
218
|
if (selectionGrain === "stack") {
|
|
192
219
|
return finalizeItems(
|
|
193
220
|
program,
|
|
194
221
|
layer,
|
|
195
222
|
"stack",
|
|
196
223
|
barStackDefinitions(layer, grain, definitions),
|
|
197
|
-
|
|
224
|
+
graphicTypes
|
|
198
225
|
);
|
|
199
226
|
}
|
|
200
|
-
return finalizeItems(program, layer, grain, definitions,
|
|
227
|
+
return finalizeItems(program, layer, grain, definitions, graphicTypes);
|
|
201
228
|
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from "../../../grammar/markSelection.js";
|
|
7
7
|
import { unionConcreteGraphicBounds } from
|
|
8
8
|
"../../../grammar/schemas/graphicBounds.js";
|
|
9
|
+
import { readRectItemGeometry } from "../../../grammar/roundedRect.js";
|
|
9
10
|
|
|
10
11
|
export function itemKey(layer, grain, index) {
|
|
11
12
|
return `${layer.id}/${grain}/${index}`;
|
|
@@ -54,14 +55,15 @@ export function uniqueFields(rows) {
|
|
|
54
55
|
|
|
55
56
|
function requireResolvedGraphic(program, layer, type) {
|
|
56
57
|
const graphic = program.graphicSpec.objects[layer.id];
|
|
58
|
+
const types = Array.isArray(type) ? type : [type];
|
|
57
59
|
const compatibleCollection = graphic?.type === "collection" &&
|
|
58
|
-
graphic.items?.every(child => child.type
|
|
60
|
+
graphic.items?.every(child => types.includes(child.type));
|
|
59
61
|
if (
|
|
60
|
-
(graphic?.type
|
|
62
|
+
(!types.includes(graphic?.type) && !compatibleCollection) ||
|
|
61
63
|
!Array.isArray(graphic.items)
|
|
62
64
|
) {
|
|
63
65
|
throw new Error(
|
|
64
|
-
`Mark "${layer.id}" requires a materialized ${
|
|
66
|
+
`Mark "${layer.id}" requires a materialized ${types.join("/")} collection for selection.`
|
|
65
67
|
);
|
|
66
68
|
}
|
|
67
69
|
return graphic;
|
|
@@ -78,6 +80,13 @@ export function concreteProperties(properties) {
|
|
|
78
80
|
);
|
|
79
81
|
}
|
|
80
82
|
|
|
83
|
+
function selectableGraphicProperties(item) {
|
|
84
|
+
return {
|
|
85
|
+
...concreteProperties(item?.properties),
|
|
86
|
+
...(readRectItemGeometry(item) ?? {})
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
81
90
|
function sharedConcreteProperties(items) {
|
|
82
91
|
if (items.length === 0) return {};
|
|
83
92
|
const shared = concreteProperties(items[0].properties);
|
|
@@ -93,7 +102,7 @@ function collectionBounds(program, items) {
|
|
|
93
102
|
const bounds = unionConcreteGraphicBounds(
|
|
94
103
|
program.graphicSpec,
|
|
95
104
|
items.map(item => item.id)
|
|
96
|
-
);
|
|
105
|
+
, program.materializationConfigs.textMetrics);
|
|
97
106
|
if (bounds === undefined) return {};
|
|
98
107
|
const { left, top, right, bottom } = bounds;
|
|
99
108
|
return { x: left, y: top, width: right - left, height: bottom - top };
|
|
@@ -118,7 +127,10 @@ export function finalizeItems(program, layer, grain, definitions, graphicType) {
|
|
|
118
127
|
const items = indices.map(childIndex => graphic.items[childIndex]);
|
|
119
128
|
const properties = definition.properties ?? (
|
|
120
129
|
items.length === 1
|
|
121
|
-
?
|
|
130
|
+
? selectableGraphicProperties({
|
|
131
|
+
type: items[0].type ?? graphic.type,
|
|
132
|
+
properties: items[0].properties
|
|
133
|
+
})
|
|
122
134
|
: {
|
|
123
135
|
...sharedConcreteProperties(items),
|
|
124
136
|
...collectionBounds(program, items)
|
|
@@ -131,6 +143,9 @@ export function finalizeItems(program, layer, grain, definitions, graphicType) {
|
|
|
131
143
|
fields: cloneAndFreeze(definition.fields),
|
|
132
144
|
channels: cloneAndFreeze(definition.channels),
|
|
133
145
|
properties: cloneAndFreeze(properties),
|
|
146
|
+
...(definition.geometry === undefined
|
|
147
|
+
? {}
|
|
148
|
+
: { geometry: cloneAndFreeze(definition.geometry) }),
|
|
134
149
|
members: Object.freeze([...definition.members]),
|
|
135
150
|
graphicIds: Object.freeze(items.map((child, childOffset) =>
|
|
136
151
|
child.id ?? graphicId(layer, indices[childOffset])
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { rectUsesFields } from "../../../grammar/rects.js";
|
|
2
|
+
import { readRectItemGeometry } from "../../../grammar/roundedRect.js";
|
|
2
3
|
import { resolveRectRows } from "../../rect.js";
|
|
3
4
|
import {
|
|
4
5
|
channelMapFromRow,
|
|
@@ -9,6 +10,17 @@ import {
|
|
|
9
10
|
uniqueFields
|
|
10
11
|
} from "./common.js";
|
|
11
12
|
|
|
13
|
+
function rectSelectionProperties(graphic, index) {
|
|
14
|
+
const item = graphic.items[index];
|
|
15
|
+
return {
|
|
16
|
+
...concreteProperties(item?.properties),
|
|
17
|
+
...(readRectItemGeometry({
|
|
18
|
+
type: item?.type ?? graphic.type,
|
|
19
|
+
properties: item?.properties
|
|
20
|
+
}) ?? {})
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
12
24
|
function resolveGradientPlotItems(program, layer, dataset) {
|
|
13
25
|
const graphic = program.graphicSpec.objects[layer.id];
|
|
14
26
|
return finalizeItems(
|
|
@@ -19,7 +31,7 @@ function resolveGradientPlotItems(program, layer, dataset) {
|
|
|
19
31
|
key: itemKey(layer, "rect", index),
|
|
20
32
|
fields: ownFields(row),
|
|
21
33
|
channels: channelMapFromRow(row, layer),
|
|
22
|
-
properties:
|
|
34
|
+
properties: rectSelectionProperties(graphic, index),
|
|
23
35
|
members: [row]
|
|
24
36
|
})),
|
|
25
37
|
"rect"
|
|
@@ -28,7 +40,13 @@ function resolveGradientPlotItems(program, layer, dataset) {
|
|
|
28
40
|
|
|
29
41
|
export function resolveRectItems(program, layer, dataset) {
|
|
30
42
|
const graphic = program.graphicSpec.objects[layer.id];
|
|
31
|
-
|
|
43
|
+
const rounded = Object.hasOwn(program.markConfigs[layer.id] ?? {}, "cornerRadius");
|
|
44
|
+
const compatibleCollection = rounded && graphic?.type === "collection" &&
|
|
45
|
+
graphic.items?.every(item => ["rect", "path"].includes(item.type));
|
|
46
|
+
if (
|
|
47
|
+
(graphic?.type !== "rect" && !compatibleCollection) ||
|
|
48
|
+
!Array.isArray(graphic.items)
|
|
49
|
+
) {
|
|
32
50
|
throw new Error(`Rect mark "${layer.id}" is incomplete for selection.`);
|
|
33
51
|
}
|
|
34
52
|
if (program.markConfigs[layer.id]?.gradientPlot?.materialized === true) {
|
|
@@ -40,8 +58,14 @@ export function resolveRectItems(program, layer, dataset) {
|
|
|
40
58
|
key: itemKey(layer, "rect", item.sourceIndex),
|
|
41
59
|
fields: hasField ? ownFields(item.row) : uniqueFields(dataset.values),
|
|
42
60
|
channels: channelMapFromRow(item.row, layer),
|
|
43
|
-
properties:
|
|
61
|
+
properties: rectSelectionProperties(graphic, graphicIndex),
|
|
44
62
|
members: hasField ? [item.row] : dataset.values
|
|
45
63
|
}));
|
|
46
|
-
return finalizeItems(
|
|
64
|
+
return finalizeItems(
|
|
65
|
+
program,
|
|
66
|
+
layer,
|
|
67
|
+
"rect",
|
|
68
|
+
definitions,
|
|
69
|
+
rounded ? ["rect", "path"] : "rect"
|
|
70
|
+
);
|
|
47
71
|
}
|
|
@@ -10,7 +10,7 @@ function translateCommand(command, offset) {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export function transformPathHighlightProperties(properties, style) {
|
|
13
|
-
const { offset, ...appearance } = style;
|
|
13
|
+
const { offset = { x: 0, y: 0 }, ...appearance } = style;
|
|
14
14
|
return {
|
|
15
15
|
...properties,
|
|
16
16
|
...appearance,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createPointShapeGraphic } from "../../grammar/pointShapes.js";
|
|
2
2
|
import { finiteMidpoint } from "../../grammar/numeric.js";
|
|
3
|
+
import { requestedStrokeDetails } from "../../grammar/strokeStyle.js";
|
|
3
4
|
|
|
4
5
|
function pointCenterAndArea(child) {
|
|
5
6
|
const properties = child.properties;
|
|
@@ -75,7 +76,8 @@ export function transformPointHighlightChild(child, style) {
|
|
|
75
76
|
? (child.properties.opacity === undefined ? {} : { opacity: child.properties.opacity })
|
|
76
77
|
: { opacity: style.opacity }),
|
|
77
78
|
...(style.stroke === undefined ? {} : { stroke: style.stroke }),
|
|
78
|
-
...(style.strokeWidth === undefined ? {} : { strokeWidth: style.strokeWidth })
|
|
79
|
+
...(style.strokeWidth === undefined ? {} : { strokeWidth: style.strokeWidth }),
|
|
80
|
+
...requestedStrokeDetails(child.properties, "Point highlight source")
|
|
79
81
|
};
|
|
80
82
|
if (style.shape !== undefined) {
|
|
81
83
|
return createPointShapeGraphic({
|