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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { editGraphicProperties } from "../../../primitives/graphicProperties.js";
|
|
1
2
|
import { action } from "../../../../core/action.js";
|
|
2
3
|
import {
|
|
3
4
|
activeConfig,
|
|
@@ -11,6 +12,18 @@ import {
|
|
|
11
12
|
} from "./layout.js";
|
|
12
13
|
import { resolveCategoricalLegendPlacement } from "../lifecycle.js";
|
|
13
14
|
import { createPointShapeGraphic } from "../../../../grammar/pointShapes.js";
|
|
15
|
+
import {
|
|
16
|
+
materializeRectItem,
|
|
17
|
+
requestedRectStyleDetails
|
|
18
|
+
} from "../../../../grammar/roundedRect.js";
|
|
19
|
+
import { requestedStrokeDetails } from "../../../../grammar/strokeStyle.js";
|
|
20
|
+
import { replaceGraphicItems } from "../../../primitives/editGraphics.js";
|
|
21
|
+
|
|
22
|
+
function applyLayerOpacity(program, id, opacity) {
|
|
23
|
+
return opacity === undefined
|
|
24
|
+
? program
|
|
25
|
+
: program.editGraphics({ target: id, property: "opacity", value: opacity });
|
|
26
|
+
}
|
|
14
27
|
|
|
15
28
|
function makeEditSymbol(type) {
|
|
16
29
|
const suffix = { line: "Lines", point: "Points", swatch: "Swatches" }[type];
|
|
@@ -19,20 +32,23 @@ function makeEditSymbol(type) {
|
|
|
19
32
|
{ op, description: `Rematerialize categorical legend ${type} symbols.` },
|
|
20
33
|
function (args = {}) {
|
|
21
34
|
noOptions(args, op);
|
|
22
|
-
const { config } = activeConfig(this);
|
|
35
|
+
const { config } = activeConfig(this, args.kind);
|
|
23
36
|
const layer = layerFor(config, type);
|
|
24
37
|
const id = symbolGraphic(config, type);
|
|
25
38
|
const dynamicPoint = type === "point" && config.channels.includes("shape");
|
|
26
|
-
const
|
|
39
|
+
const styledSwatch = type === "swatch" && Object.hasOwn(layer, "cornerRadius");
|
|
40
|
+
const expected = dynamicPoint || styledSwatch
|
|
27
41
|
? "collection"
|
|
28
42
|
: { line: "line", point: "circle", swatch: "rect" }[type];
|
|
29
|
-
|
|
43
|
+
const actual = this.graphicSpec.objects[id]?.type;
|
|
44
|
+
const compatibleStyledSwatch = styledSwatch && ["rect", "collection"].includes(actual);
|
|
45
|
+
if (actual !== expected && !compatibleStyledSwatch) {
|
|
30
46
|
throw new Error(`${op} requires existing ${type} symbols.`);
|
|
31
47
|
}
|
|
32
48
|
const layout = resolveLayout(this, config);
|
|
33
49
|
const appearance = resolveAppearance(this, config);
|
|
34
50
|
let next = this;
|
|
35
|
-
if (!dynamicPoint) {
|
|
51
|
+
if (!dynamicPoint && !styledSwatch) {
|
|
36
52
|
next = next.editGraphics({
|
|
37
53
|
target: id,
|
|
38
54
|
property: "length",
|
|
@@ -43,18 +59,29 @@ function makeEditSymbol(type) {
|
|
|
43
59
|
const x1 = layout.symbolX.map(
|
|
44
60
|
value => value + (symbolWidth(config) - layer.length) / 2
|
|
45
61
|
);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
62
|
+
next = editGraphicProperties(editGraphicProperties(editGraphicProperties(next, id, {
|
|
63
|
+
x1: x1,
|
|
64
|
+
y1: layout.itemY
|
|
65
|
+
}), id, {
|
|
66
|
+
x2: x1.map(value => value + layer.length),
|
|
67
|
+
y2: layout.itemY
|
|
68
|
+
})
|
|
49
69
|
.editGraphics({
|
|
50
70
|
target: id,
|
|
51
|
-
property: "
|
|
52
|
-
value:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
71
|
+
property: "stroke",
|
|
72
|
+
value: layer.stroke ?? (config.channels.includes("stroke")
|
|
73
|
+
? appearance.strokes
|
|
74
|
+
: appearance.colors)
|
|
75
|
+
}), id, {
|
|
76
|
+
strokeWidth: layer.lineWidth,
|
|
77
|
+
strokeDash: appearance.dashes
|
|
78
|
+
});
|
|
79
|
+
for (const [property, value] of Object.entries(
|
|
80
|
+
requestedStrokeDetails(layer, "Legend line symbol")
|
|
81
|
+
)) {
|
|
82
|
+
next = next.editGraphics({ target: id, property, value });
|
|
83
|
+
}
|
|
84
|
+
return applyLayerOpacity(next, id, layer.opacity);
|
|
58
85
|
}
|
|
59
86
|
if (type === "point") {
|
|
60
87
|
const x = layout.symbolX.map(value => value + symbolWidth(config) / 2);
|
|
@@ -67,8 +94,12 @@ function makeEditSymbol(type) {
|
|
|
67
94
|
y: layout.itemY[index],
|
|
68
95
|
area: Math.PI * layer.size ** 2,
|
|
69
96
|
fill,
|
|
70
|
-
stroke:
|
|
71
|
-
|
|
97
|
+
stroke: config.channels.includes("stroke")
|
|
98
|
+
? appearance.strokes[index]
|
|
99
|
+
: layer.stroke,
|
|
100
|
+
strokeWidth: layer.strokeWidth,
|
|
101
|
+
opacity: layer.opacity,
|
|
102
|
+
...requestedStrokeDetails(layer, "Legend point symbol")
|
|
72
103
|
});
|
|
73
104
|
});
|
|
74
105
|
return next.editGraphics({
|
|
@@ -77,33 +108,53 @@ function makeEditSymbol(type) {
|
|
|
77
108
|
value: items
|
|
78
109
|
});
|
|
79
110
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
111
|
+
next = editGraphicProperties(next, id, {
|
|
112
|
+
x: x,
|
|
113
|
+
y: layout.itemY,
|
|
114
|
+
radius: layer.size,
|
|
115
|
+
fill: layer.fill ?? appearance.colors
|
|
116
|
+
})
|
|
84
117
|
.editGraphics({
|
|
85
118
|
target: id,
|
|
86
|
-
property: "
|
|
87
|
-
value:
|
|
119
|
+
property: "stroke",
|
|
120
|
+
value: config.channels.includes("stroke")
|
|
121
|
+
? appearance.strokes
|
|
122
|
+
: layer.stroke
|
|
88
123
|
})
|
|
89
|
-
.editGraphics({ target: id, property: "stroke", value: layer.stroke })
|
|
90
124
|
.editGraphics({ target: id, property: "strokeWidth", value: layer.strokeWidth });
|
|
125
|
+
for (const [property, value] of Object.entries(
|
|
126
|
+
requestedStrokeDetails(layer, "Legend point symbol")
|
|
127
|
+
)) {
|
|
128
|
+
next = next.editGraphics({ target: id, property, value });
|
|
129
|
+
}
|
|
130
|
+
return applyLayerOpacity(next, id, layer.opacity);
|
|
91
131
|
}
|
|
92
132
|
const x = layout.symbolX.map(
|
|
93
133
|
value => value + (symbolWidth(config) - layer.width) / 2
|
|
94
134
|
);
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
.
|
|
135
|
+
const details = requestedRectStyleDetails(layer, "Legend swatch symbol");
|
|
136
|
+
const fills = layer.fill === undefined
|
|
137
|
+
? appearance.colors
|
|
138
|
+
: config.domain.map(() => layer.fill);
|
|
139
|
+
const strokes = config.channels.includes("stroke")
|
|
140
|
+
? appearance.strokes
|
|
141
|
+
: config.domain.map(() => layer.stroke);
|
|
142
|
+
return replaceGraphicItems(
|
|
143
|
+
next,
|
|
144
|
+
id,
|
|
145
|
+
"rect",
|
|
146
|
+
config.domain.map((_, index) => materializeRectItem({
|
|
147
|
+
x: x[index],
|
|
148
|
+
y: layout.itemY[index] - layer.height / 2,
|
|
149
|
+
width: layer.width,
|
|
150
|
+
height: layer.height,
|
|
151
|
+
fill: fills[index],
|
|
152
|
+
stroke: strokes[index],
|
|
153
|
+
strokeWidth: layer.strokeWidth,
|
|
154
|
+
...(layer.opacity === undefined ? {} : { opacity: layer.opacity }),
|
|
155
|
+
...requestedStrokeDetails(details, "Legend swatch symbol")
|
|
156
|
+
}, details.cornerRadius ?? 0))
|
|
157
|
+
);
|
|
107
158
|
}
|
|
108
159
|
);
|
|
109
160
|
}
|
|
@@ -115,13 +166,14 @@ function makeCreateSymbol(type, edit) {
|
|
|
115
166
|
{ op, description: `Create categorical legend ${type} symbols.` },
|
|
116
167
|
function (args = {}) {
|
|
117
168
|
noOptions(args, op);
|
|
118
|
-
const { config } = activeConfig(this);
|
|
119
|
-
layerFor(config, type);
|
|
169
|
+
const { config } = activeConfig(this, args.kind);
|
|
170
|
+
const layer = layerFor(config, type);
|
|
120
171
|
const id = symbolGraphic(config, type);
|
|
121
172
|
if (this.graphicSpec.objects[id] !== undefined) {
|
|
122
173
|
throw new Error(`${op} requires missing ${type} symbols.`);
|
|
123
174
|
}
|
|
124
|
-
const graphicType = type === "point" && config.channels.includes("shape")
|
|
175
|
+
const graphicType = type === "point" && config.channels.includes("shape") ||
|
|
176
|
+
type === "swatch" && (layer.cornerRadius ?? 0) > 0
|
|
125
177
|
? "collection"
|
|
126
178
|
: { line: "line", point: "circle", swatch: "rect" }[type];
|
|
127
179
|
return this
|
|
@@ -136,32 +188,32 @@ function makeCreateSymbol(type, edit) {
|
|
|
136
188
|
? {}
|
|
137
189
|
: { length: config.domain.length })
|
|
138
190
|
})
|
|
139
|
-
[edit]();
|
|
191
|
+
[edit]({ kind: config.kind });
|
|
140
192
|
}
|
|
141
193
|
);
|
|
142
194
|
}
|
|
143
195
|
|
|
144
|
-
export const rematerializeLegendSymbolLines = makeEditSymbol("line");
|
|
145
|
-
export const rematerializeLegendSymbolPoints = makeEditSymbol("point");
|
|
146
|
-
export const rematerializeLegendSymbolSwatches = makeEditSymbol("swatch");
|
|
147
|
-
export const createLegendSymbolLines = makeCreateSymbol(
|
|
196
|
+
export const rematerializeLegendSymbolLines = /* @__PURE__ */ makeEditSymbol("line");
|
|
197
|
+
export const rematerializeLegendSymbolPoints = /* @__PURE__ */ makeEditSymbol("point");
|
|
198
|
+
export const rematerializeLegendSymbolSwatches = /* @__PURE__ */ makeEditSymbol("swatch");
|
|
199
|
+
export const createLegendSymbolLines = /* @__PURE__ */ makeCreateSymbol(
|
|
148
200
|
"line",
|
|
149
201
|
"rematerializeLegendSymbolLines"
|
|
150
202
|
);
|
|
151
|
-
export const createLegendSymbolPoints = makeCreateSymbol(
|
|
203
|
+
export const createLegendSymbolPoints = /* @__PURE__ */ makeCreateSymbol(
|
|
152
204
|
"point",
|
|
153
205
|
"rematerializeLegendSymbolPoints"
|
|
154
206
|
);
|
|
155
|
-
export const createLegendSymbolSwatches = makeCreateSymbol(
|
|
207
|
+
export const createLegendSymbolSwatches = /* @__PURE__ */ makeCreateSymbol(
|
|
156
208
|
"swatch",
|
|
157
209
|
"rematerializeLegendSymbolSwatches"
|
|
158
210
|
);
|
|
159
211
|
|
|
160
|
-
export const createLegendSymbols = action(
|
|
212
|
+
export const createLegendSymbols = /* @__PURE__ */ action(
|
|
161
213
|
{ op: "createLegendSymbols", description: "Create layered legend symbols." },
|
|
162
214
|
function (args = {}) {
|
|
163
215
|
noOptions(args, "createLegendSymbols");
|
|
164
|
-
const { config } = activeConfig(this);
|
|
216
|
+
const { config } = activeConfig(this, args.kind);
|
|
165
217
|
let next = this;
|
|
166
218
|
for (const layer of config.symbol.layers) {
|
|
167
219
|
const operation = {
|
|
@@ -169,17 +221,17 @@ export const createLegendSymbols = action(
|
|
|
169
221
|
point: "createLegendSymbolPoints",
|
|
170
222
|
swatch: "createLegendSymbolSwatches"
|
|
171
223
|
}[layer.type];
|
|
172
|
-
next = next[operation]();
|
|
224
|
+
next = next[operation]({ kind: config.kind });
|
|
173
225
|
}
|
|
174
226
|
return next;
|
|
175
227
|
}
|
|
176
228
|
);
|
|
177
229
|
|
|
178
|
-
export const rematerializeLegendSymbols = action(
|
|
230
|
+
export const rematerializeLegendSymbols = /* @__PURE__ */ action(
|
|
179
231
|
{ op: "rematerializeLegendSymbols", description: "Rematerialize layered legend symbols." },
|
|
180
232
|
function (args = {}) {
|
|
181
233
|
noOptions(args, "rematerializeLegendSymbols");
|
|
182
|
-
const { config } = activeConfig(this);
|
|
234
|
+
const { config } = activeConfig(this, args.kind);
|
|
183
235
|
let next = this;
|
|
184
236
|
for (const layer of config.symbol.layers) {
|
|
185
237
|
const operation = {
|
|
@@ -187,13 +239,13 @@ export const rematerializeLegendSymbols = action(
|
|
|
187
239
|
point: "rematerializeLegendSymbolPoints",
|
|
188
240
|
swatch: "rematerializeLegendSymbolSwatches"
|
|
189
241
|
}[layer.type];
|
|
190
|
-
next = next[operation]();
|
|
242
|
+
next = next[operation]({ kind: config.kind });
|
|
191
243
|
}
|
|
192
244
|
return next;
|
|
193
245
|
}
|
|
194
246
|
);
|
|
195
247
|
|
|
196
|
-
export const rematerializeBasicLegendHighlights = action(
|
|
248
|
+
export const rematerializeBasicLegendHighlights = /* @__PURE__ */ action(
|
|
197
249
|
{
|
|
198
250
|
op: "rematerializeLegendHighlights",
|
|
199
251
|
description: "Reflect exact categorical mark highlights in legend symbols."
|
|
@@ -25,9 +25,12 @@ import { findLayer } from "../../../../selectors/layers.js";
|
|
|
25
25
|
import { isOpacityLegendLayer } from "../../../../materialization/legends.js";
|
|
26
26
|
import { findCanvasGraphic } from
|
|
27
27
|
"../../../../materialization/graphicHierarchy.js";
|
|
28
|
+
import { normalizeLegendSampling } from "../sampling.js";
|
|
29
|
+
import { editGraphicProperties } from "../../../primitives/graphicProperties.js";
|
|
28
30
|
|
|
29
31
|
const OPTIONS = [
|
|
30
32
|
"target", "channels", "position", "align", "offset", "title", "count",
|
|
33
|
+
"values",
|
|
31
34
|
"gradient", "symbol", "labels", "titleStyle", "itemGap", "border",
|
|
32
35
|
"direction", "columns", "titlePosition"
|
|
33
36
|
];
|
|
@@ -61,12 +64,7 @@ const DEFAULT_BORDER = {
|
|
|
61
64
|
export const validatePositive = validatePositiveFinite;
|
|
62
65
|
export const validateNonNegative = validateNonNegativeFinite;
|
|
63
66
|
|
|
64
|
-
export
|
|
65
|
-
for (const [property, value] of Object.entries(properties)) {
|
|
66
|
-
program = program.editGraphics({ target, property, value });
|
|
67
|
-
}
|
|
68
|
-
return program;
|
|
69
|
-
}
|
|
67
|
+
export { editGraphicProperties };
|
|
70
68
|
|
|
71
69
|
export function normalizeLegendTextOptions(value, label, defaults) {
|
|
72
70
|
if (value === undefined) return { ...defaults };
|
|
@@ -129,13 +127,24 @@ export function normalizeContinuousLegend(args, kind) {
|
|
|
129
127
|
if (["left", "right"].includes(position) && align !== "center") {
|
|
130
128
|
throw new Error("Side continuous legends require center alignment.");
|
|
131
129
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
130
|
+
if (kind === "gradient" && Object.hasOwn(args, "values")) {
|
|
131
|
+
throw new Error("Gradient legends do not support exact sample values.");
|
|
132
|
+
}
|
|
133
|
+
const sampling = kind === "opacity"
|
|
134
|
+
? normalizeLegendSampling(args, {
|
|
135
|
+
operation: "create",
|
|
136
|
+
label: "Opacity legend"
|
|
137
|
+
})
|
|
138
|
+
: undefined;
|
|
139
|
+
const count = kind === "gradient" ? args.count ?? 5 : undefined;
|
|
140
|
+
if (kind === "gradient") {
|
|
141
|
+
if (!Number.isInteger(count) || count < 2) {
|
|
142
|
+
throw new RangeError(
|
|
143
|
+
"Continuous legend count must be an integer of at least 2."
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
validateGeneratedItemLimit(count, "Continuous legend count");
|
|
137
147
|
}
|
|
138
|
-
validateGeneratedItemLimit(count, "Continuous legend count");
|
|
139
148
|
const offset = args.offset ?? 30;
|
|
140
149
|
validateNonNegative(offset, "Legend offset");
|
|
141
150
|
const titlePosition = args.titlePosition ?? "top";
|
|
@@ -171,7 +180,7 @@ export function normalizeContinuousLegend(args, kind) {
|
|
|
171
180
|
position,
|
|
172
181
|
align,
|
|
173
182
|
offset,
|
|
174
|
-
count,
|
|
183
|
+
...(kind === "gradient" ? { count } : { sampling }),
|
|
175
184
|
title: args.title,
|
|
176
185
|
inferredTitle: args.title === undefined,
|
|
177
186
|
labels: normalizeLegendTextOptions(
|
|
@@ -218,18 +227,23 @@ export function resolveContinuousLegendLayer(program, requested, channel) {
|
|
|
218
227
|
return layer;
|
|
219
228
|
}
|
|
220
229
|
|
|
221
|
-
export function resolveContinuousColorLayer(program, requested) {
|
|
230
|
+
export function resolveContinuousColorLayer(program, requested, channel = "color") {
|
|
222
231
|
const layer = selectLegendLayer(
|
|
223
232
|
program,
|
|
224
233
|
requested,
|
|
225
|
-
candidate =>
|
|
226
|
-
|
|
234
|
+
candidate => (channel === "stroke"
|
|
235
|
+
? ["point", "line", "area", "bar", "rect", "arc", "rule", "tick"]
|
|
236
|
+
: ["point", "bar", "rect"]
|
|
237
|
+
).includes(candidate.mark?.type) &&
|
|
238
|
+
candidate.encoding?.[channel]?.scale !== undefined
|
|
227
239
|
);
|
|
228
240
|
if (layer === undefined) {
|
|
229
241
|
throw new Error(
|
|
230
242
|
requested === undefined
|
|
231
|
-
?
|
|
232
|
-
|
|
243
|
+
? channel === "color"
|
|
244
|
+
? "color legend requires one eligible point, bar, or rect mark."
|
|
245
|
+
: "stroke legend requires one eligible mark."
|
|
246
|
+
: `Unknown ${channel} legend target "${requested}".`
|
|
233
247
|
);
|
|
234
248
|
}
|
|
235
249
|
return layer;
|
|
@@ -300,7 +314,7 @@ export function styleContinuousText(
|
|
|
300
314
|
});
|
|
301
315
|
}
|
|
302
316
|
|
|
303
|
-
export function resolveLegendTextBounds(position, text, style) {
|
|
317
|
+
export function resolveLegendTextBounds(position, text, style, profile) {
|
|
304
318
|
return resolveTextBounds({
|
|
305
319
|
x: position.x,
|
|
306
320
|
y: position.y,
|
|
@@ -308,7 +322,7 @@ export function resolveLegendTextBounds(position, text, style) {
|
|
|
308
322
|
...style,
|
|
309
323
|
textAlign: position.align ?? "left",
|
|
310
324
|
textBaseline: "middle"
|
|
311
|
-
});
|
|
325
|
+
}, profile);
|
|
312
326
|
}
|
|
313
327
|
|
|
314
328
|
export function assertLegendBoundsInsideCanvas(bounds, canvas, label, config) {
|
|
@@ -389,3 +403,45 @@ export function normalizeItemLegendLayout(args) {
|
|
|
389
403
|
validatePositive(itemGap, "Legend itemGap");
|
|
390
404
|
return { position, layout, align, direction, columns, titlePosition, offset, itemGap };
|
|
391
405
|
}
|
|
406
|
+
|
|
407
|
+
export function materializeItemLegend(program, kind, config, layout, {
|
|
408
|
+
symbols, optional = {}, text = layout.labels,
|
|
409
|
+
labels = layout.config.labels, titleStyle = layout.config.titleStyle
|
|
410
|
+
}) {
|
|
411
|
+
const prefix = `${kind}Legend`;
|
|
412
|
+
let next = program
|
|
413
|
+
.editSemantic({ property: `guide.legend.${kind}.scale`, value: config.scale })
|
|
414
|
+
.editSemantic({ property: `guide.legend.${kind}.title`, value: config.title })
|
|
415
|
+
._withLegendConfig(kind, config);
|
|
416
|
+
next = editGraphicProperties(next, `${prefix}Symbols`, {
|
|
417
|
+
length: text.length,
|
|
418
|
+
...symbols
|
|
419
|
+
});
|
|
420
|
+
next = editGraphicProperties(next, `${prefix}Labels`, {
|
|
421
|
+
length: text.length, x: layout.labelX, y: layout.itemY, text
|
|
422
|
+
});
|
|
423
|
+
next = editLegendBackground(next, `${prefix}Background`, layout.background, config.border);
|
|
424
|
+
next = editGraphicProperties(next, `${prefix}Symbols`, Object.fromEntries(
|
|
425
|
+
Object.entries(optional).filter(([, value]) => value !== undefined)
|
|
426
|
+
));
|
|
427
|
+
next = styleContinuousText(next, `${prefix}Labels`, labels);
|
|
428
|
+
const effective = layout.config;
|
|
429
|
+
if (effective.titleVisible === false) return next;
|
|
430
|
+
next = editGraphicProperties(next, `${prefix}Title`, {
|
|
431
|
+
x: layout.title.x, y: layout.title.y, text: effective.title
|
|
432
|
+
});
|
|
433
|
+
return styleContinuousText(next, `${prefix}Title`, titleStyle, { align: layout.title.align });
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export function createItemLegendGraphics(program, kind, config, count, type, placement) {
|
|
437
|
+
const prefix = `${kind}Legend`;
|
|
438
|
+
let next = program
|
|
439
|
+
.editSemantic({ property: `guide.legend.${kind}.scale`, value: config.scale })
|
|
440
|
+
.editSemantic({ property: `guide.legend.${kind}.title`, value: config.title })
|
|
441
|
+
._withLegendConfig(kind, config);
|
|
442
|
+
if (config.border !== false) next = next.createGraphics({ id: `${prefix}Background`, type: "rect", ...placement });
|
|
443
|
+
next = next.createGraphics({ id: `${prefix}Symbols`, type, length: count, ...placement })
|
|
444
|
+
.createGraphics({ id: `${prefix}Labels`, type: "text", length: count, ...placement });
|
|
445
|
+
if (config.titleVisible !== false) next = next.createGraphics({ id: `${prefix}Title`, type: "text", ...placement });
|
|
446
|
+
return next;
|
|
447
|
+
}
|