ggaction 0.0.15 → 0.0.17
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 +88 -0
- package/README.md +23 -2
- 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 +40 -7
- package/src/BasicChartProgram.js +3 -1
- package/src/ChartProgram.js +2 -0
- package/src/accessibility.js +157 -0
- package/src/actions/boxPlots/components.js +6 -8
- package/src/actions/boxPlots/create.js +4 -5
- package/src/actions/boxPlots/edit.js +3 -4
- package/src/actions/boxPlots/materialize.js +1 -1
- package/src/actions/canvas/actions.js +3 -3
- package/src/actions/canvas/fitting.js +1 -1
- package/src/actions/categoryOrder/index.js +6 -8
- package/src/actions/charts/area.js +1 -1
- package/src/actions/charts/bar.js +1 -1
- package/src/actions/charts/beeswarm.js +1 -1
- package/src/actions/charts/density.js +1 -1
- package/src/actions/charts/ecdf.js +2 -2
- package/src/actions/charts/endpoints.js +4 -4
- package/src/actions/charts/heatmap.js +1 -1
- package/src/actions/charts/histogram.js +1 -1
- package/src/actions/charts/horizon.js +1 -1
- package/src/actions/charts/interval-regression.js +2 -2
- package/src/actions/charts/line.js +1 -1
- package/src/actions/charts/parallel.js +1 -1
- package/src/actions/charts/pie.js +1 -1
- package/src/actions/charts/polar.js +2 -2
- package/src/actions/charts/radar.js +1 -1
- package/src/actions/charts/radial.js +2 -2
- package/src/actions/charts/raincloud.js +2 -2
- package/src/actions/charts/rug-strip.js +2 -2
- package/src/actions/charts/scatter.js +1 -1
- package/src/actions/composition/actions.js +20 -24
- package/src/actions/coordinates/actions.js +1 -1
- package/src/actions/coordinates/edit.js +1 -1
- package/src/actions/data/basicBin2d.js +4 -5
- package/src/actions/data/bin.js +3 -3
- package/src/actions/data/bin2d.js +6 -8
- package/src/actions/data/bin2dMaterialize.js +4 -5
- package/src/actions/data/box.js +4 -4
- package/src/actions/data/complete.js +2 -2
- package/src/actions/data/computed.js +2 -2
- package/src/actions/data/create.js +23 -17
- package/src/actions/data/density.js +4 -4
- package/src/actions/data/derived.js +25 -15
- package/src/actions/data/ecdf.js +2 -2
- package/src/actions/data/edit.js +54 -29
- package/src/actions/data/filter.js +29 -24
- 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 +2 -2
- package/src/actions/data/index.js +58 -54
- package/src/actions/data/interval.js +4 -2
- package/src/actions/data/intervalEdit.js +26 -18
- package/src/actions/data/normalize.js +2 -2
- package/src/actions/data/regression.js +9 -7
- package/src/actions/data/revise.js +80 -0
- package/src/actions/data/revisionBindings.js +13 -33
- package/src/actions/data/shared.js +30 -2
- package/src/actions/data/sort.js +21 -0
- package/src/actions/data/stack.js +2 -2
- package/src/actions/data/summary.js +3 -3
- package/src/actions/data/timeUnit.js +2 -2
- package/src/actions/data/window.js +2 -2
- package/src/actions/encodings/angle.js +5 -2
- package/src/actions/encodings/appearance.js +10 -6
- package/src/actions/encodings/barWidth.js +1 -1
- package/src/actions/encodings/channels.js +2 -2
- package/src/actions/encodings/color/continuous.js +4 -1
- package/src/actions/encodings/color/index.js +5 -2
- package/src/actions/encodings/density.js +2 -2
- package/src/actions/encodings/histogram.js +1 -1
- package/src/actions/encodings/horizon.js +6 -8
- package/src/actions/encodings/offset.js +6 -3
- package/src/actions/encodings/parallel.js +4 -5
- package/src/actions/encodings/pathOrder.js +6 -11
- package/src/actions/encodings/position/index.js +4 -4
- package/src/actions/encodings/position/resolve.js +6 -1
- package/src/actions/encodings/ranged.js +11 -6
- package/src/actions/encodings/remove.js +4 -5
- package/src/actions/encodings/ruleAppearance.js +5 -2
- package/src/actions/encodings/seriesLayout.js +1 -1
- package/src/actions/encodings/stroke.js +5 -2
- package/src/actions/encodings/strokeDash.js +8 -3
- package/src/actions/encodings/text.js +7 -2
- package/src/actions/errorBands/create.js +11 -17
- package/src/actions/errorBands/edit.js +13 -131
- package/src/actions/errorBars/create.js +8 -13
- package/src/actions/errorBars/edit.js +10 -121
- package/src/actions/facets/actions.js +30 -16
- package/src/actions/facets/derive.js +8 -2
- package/src/actions/facets/guides.js +4 -5
- package/src/actions/facets/replay.js +4 -5
- package/src/actions/gradientPlots/components.js +5 -6
- package/src/actions/gradientPlots/create.js +4 -5
- package/src/actions/gradientPlots/edit.js +4 -5
- package/src/actions/gradientPlots/materialize.js +2 -2
- package/src/actions/gradientPlots/rebind.js +4 -5
- 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 +9 -9
- package/src/actions/guides/axes/lines.js +9 -7
- package/src/actions/guides/axes/parallel/lifecycle.js +13 -13
- 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 +4 -4
- package/src/actions/guides/axes/ticks.js +13 -4
- package/src/actions/guides/axes/titles.js +10 -10
- package/src/actions/guides/grids/grid.js +18 -29
- package/src/actions/guides/guides.js +1 -1
- package/src/actions/guides/legends/blocks.js +1 -1
- package/src/actions/guides/legends/categorical/actions.js +4 -4
- package/src/actions/guides/legends/categorical/components.js +38 -33
- package/src/actions/guides/legends/categorical/layout.js +1 -1
- package/src/actions/guides/legends/categorical/symbols.js +27 -30
- package/src/actions/guides/legends/continuous/common.js +46 -8
- package/src/actions/guides/legends/continuous/gradient.js +89 -155
- package/src/actions/guides/legends/continuous/interval.js +13 -13
- package/src/actions/guides/legends/continuous/opacity.js +30 -79
- package/src/actions/guides/legends/continuous/stroke.js +22 -322
- package/src/actions/guides/legends/edit.js +1 -1
- package/src/actions/guides/legends/focused.js +5 -5
- package/src/actions/guides/legends/lane.js +6 -6
- package/src/actions/guides/legends/remove.js +4 -5
- package/src/actions/guides/legends/size.js +21 -82
- package/src/actions/guides/legends/strokeWidth.js +17 -77
- package/src/actions/guides/polar/axes/facade.js +4 -4
- package/src/actions/guides/polar/axes/labels.js +5 -5
- package/src/actions/guides/polar/axes/lines.js +9 -15
- package/src/actions/guides/polar/axes/ticks.js +9 -15
- package/src/actions/guides/polar/axes/titles.js +5 -5
- package/src/actions/guides/polar/grids.js +11 -13
- package/src/actions/index.js +2 -0
- package/src/actions/intervals/revision.js +126 -0
- package/src/actions/marks/arc/actions.js +3 -3
- package/src/actions/marks/area/actions.js +4 -4
- package/src/actions/marks/bar/create.js +9 -2
- package/src/actions/marks/bar/edit.js +13 -6
- package/src/actions/marks/bar/materialize.js +12 -38
- package/src/actions/marks/line/actions.js +3 -3
- package/src/actions/marks/point/create.js +9 -2
- package/src/actions/marks/point/edit.js +13 -6
- package/src/actions/marks/point/jitter.js +6 -8
- package/src/actions/marks/point/materialize.js +20 -26
- package/src/actions/marks/point/packing.js +6 -8
- package/src/actions/marks/rect/actions.js +26 -11
- package/src/actions/marks/references.js +8 -10
- package/src/actions/marks/remove.js +5 -49
- package/src/actions/marks/rule/actions.js +28 -12
- package/src/actions/marks/text/actions.js +30 -11
- package/src/actions/marks/text/layout.js +12 -20
- package/src/actions/marks/text/removal.js +1 -1
- package/src/actions/marks/text/selection.js +4 -5
- package/src/actions/marks/tick/actions.js +26 -11
- package/src/actions/primitives/createGraphics.js +5 -4
- package/src/actions/primitives/editGraphics.js +5 -4
- package/src/actions/primitives/graphicProperties.js +6 -0
- package/src/actions/primitives/semantic.js +10 -3
- package/src/actions/primitives/semanticAction.js +44 -7
- package/src/actions/primitives/semanticValidation/dataset.js +14 -4
- package/src/actions/primitives/semanticValidation/layer.js +22 -2
- package/src/actions/primitives/semanticValidation/scale.js +6 -0
- package/src/actions/regression/components.js +10 -14
- package/src/actions/regression/create.js +28 -8
- package/src/actions/regression/edit.js +50 -16
- package/src/actions/regression/follow.js +22 -0
- package/src/actions/resources/remove.js +12 -11
- package/src/actions/scales/channels.js +11 -11
- package/src/actions/scales/consumers/common.js +2 -1
- package/src/actions/scales/create.js +3 -2
- package/src/actions/scales/definitions.js +1 -1
- package/src/actions/scales/edit.js +2 -2
- package/src/actions/scales/materialize.js +1 -1
- package/src/actions/scales/offset.js +2 -2
- package/src/actions/scales/parallel.js +2 -2
- package/src/actions/scales/patch.js +1 -1
- package/src/actions/scales/preview.js +28 -1
- package/src/actions/scales/quantitativeColor.js +4 -5
- package/src/actions/selection/actions.js +25 -36
- package/src/actions/textMetrics/index.js +56 -0
- package/src/actions/theme/actions.js +2 -2
- package/src/actions/theme/reconcile.js +67 -121
- package/src/actions/titles/actions.js +8 -8
- package/src/actions/titles/resolve.js +3 -3
- package/src/actions/violinPlots/create.js +1 -1
- package/src/actions/violinPlots/edit.js +1 -1
- package/src/core/action.js +109 -36
- 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 +6 -2
- package/src/core/resourceReferences.js +15 -6
- package/src/core/textMetricProfile.js +28 -0
- package/src/core/textMetrics.js +24 -3
- package/src/core/validation.js +22 -10
- package/src/diagnostics.js +1 -0
- package/src/grammar/bin.js +39 -10
- package/src/grammar/datasetSchema.js +386 -0
- package/src/grammar/density.js +53 -5
- package/src/grammar/filter.js +133 -39
- package/src/grammar/impute.js +3 -2
- package/src/grammar/interval.js +32 -1
- package/src/grammar/itemMissing.js +59 -0
- package/src/grammar/regression/derive.js +57 -16
- package/src/grammar/regression/index.js +1 -0
- package/src/grammar/regression/models.js +51 -22
- package/src/grammar/regression/parameters.js +56 -4
- package/src/grammar/scales/definition.js +7 -0
- package/src/grammar/scales/types.js +8 -0
- package/src/grammar/schemas/graphicBounds.js +11 -11
- package/src/grammar/schemas/semanticPath.js +3 -2
- package/src/grammar/sort.js +88 -0
- package/src/grammar/summary.js +117 -19
- package/src/grammar/transformTopology.js +1 -0
- package/src/grammar/transforms.js +21 -11
- package/src/inspection.js +495 -0
- package/src/inspectionDescriptors.js +3 -0
- package/src/layout/labels.js +11 -10
- 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/resolve.js +4 -2
- package/src/materialization/facetGuides/placement.js +1 -1
- package/src/materialization/facetGuides/preparation.js +1 -1
- package/src/materialization/facetHeaders.js +11 -10
- package/src/materialization/guides/layout.js +3 -3
- package/src/materialization/revisionIdentity.js +19 -0
- package/src/materialization/scaleGuideDependencies.js +10 -0
- package/src/materialization/scales/resolve.js +67 -4
- package/src/materialization/selection/items/common.js +1 -1
- package/src/materialization/text.js +6 -4
- 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 +147 -0
- package/src/renderers/canvas/index.js +5 -4
- 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 +10 -14
- package/src/renderers/text.js +1 -11
- package/src/selectors/coordinates.js +3 -1
- package/src/selectors/datasets.js +8 -6
- package/src/selectors/layers.js +6 -4
- package/src/selectors/markOwners.js +46 -0
- package/src/selectors/scales.js +6 -4
- package/src/theme/defaults.js +2 -1
- package/src/version.js +2 -0
- package/types/accessibility.d.ts +37 -0
- package/types/basic.d.ts +4 -2
- package/types/diagnostics.d.ts +15 -0
- package/types/index.d.ts +5 -0
- package/types/inspection.d.ts +17 -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 +181 -28
|
@@ -1,40 +1,20 @@
|
|
|
1
|
-
import { action } from "../../../../core/action.js";
|
|
2
|
-
|
|
3
|
-
import { validateKeys, validateOptionObject } from
|
|
4
|
-
"../../../../core/validation.js";
|
|
5
|
-
import { formatDiscretizedIntervals } from
|
|
6
|
-
"../../../../grammar/scales/index.js";
|
|
7
|
-
import { inverseLerp, interpolateNumber } from
|
|
8
|
-
"../../../../grammar/numeric.js";
|
|
9
|
-
import { resolveLegendItemLayout } from "../../../../layout/legendItems.js";
|
|
1
|
+
import { action, closedAction } from "../../../../core/action.js";
|
|
2
|
+
|
|
10
3
|
import { resolveLegendGraphicPlacement } from
|
|
11
4
|
"../../../../materialization/graphicHierarchy.js";
|
|
12
|
-
import { mapScaleConsumerValues } from
|
|
13
|
-
"../../../../materialization/scales/map.js";
|
|
14
5
|
import { findLayer } from "../../../../selectors/layers.js";
|
|
15
6
|
import { DEFAULT_COLORS } from "../../../../theme/defaults.js";
|
|
16
7
|
import {
|
|
17
|
-
assertLegendBoundsInsideCanvas,
|
|
18
8
|
editGraphicProperties,
|
|
19
9
|
editLegendBackground,
|
|
20
|
-
formatContinuousValues,
|
|
21
|
-
normalizeContinuousLegend,
|
|
22
|
-
requireResolvedLegendScale,
|
|
23
|
-
resolveContinuousBounds,
|
|
24
10
|
resolveContinuousColorLayer,
|
|
25
|
-
resolveLegendBackgroundFromBounds,
|
|
26
|
-
resolveLegendTextBounds,
|
|
27
|
-
sampleContinuousValues,
|
|
28
11
|
styleContinuousText,
|
|
29
12
|
validateNonNegative,
|
|
30
|
-
validatePositive
|
|
31
13
|
} from "./common.js";
|
|
32
|
-
import {
|
|
33
|
-
import { normalizeIntervalLegend } from "./interval.js";
|
|
14
|
+
import { materializeGradientLegend, resolveGradientConfig, resolveGradientLegendCreation, createGradientLegendFromConfig } from "./gradient.js";
|
|
15
|
+
import { normalizeIntervalLegend, resolveIntervalLayout, resolveIntervalConfig } from "./interval.js";
|
|
34
16
|
import { resolveEffectiveLegendBlockConfig } from "../blocks.js";
|
|
35
17
|
|
|
36
|
-
const GRADIENT_OPTIONS = Object.freeze(["length", "thickness"]);
|
|
37
|
-
|
|
38
18
|
function requireChannels(args, operation) {
|
|
39
19
|
if (
|
|
40
20
|
!Array.isArray(args.channels) ||
|
|
@@ -65,278 +45,34 @@ function sampleFill(program, target) {
|
|
|
65
45
|
return properties?.fill ?? DEFAULT_COLORS.mark;
|
|
66
46
|
}
|
|
67
47
|
|
|
68
|
-
function resolveGradientConfig(program, stored) {
|
|
69
|
-
const layer = resolveContinuousColorLayer(program, stored.target, "stroke");
|
|
70
|
-
const encoding = layer.encoding.stroke;
|
|
71
|
-
if (!["quantitative", "temporal"].includes(encoding.fieldType)) {
|
|
72
|
-
throw new Error("Stroke gradient legend requires quantitative or temporal stroke.");
|
|
73
|
-
}
|
|
74
|
-
const scale = requireResolvedLegendScale(program, encoding.scale, "sequential");
|
|
75
|
-
return {
|
|
76
|
-
encoding,
|
|
77
|
-
scale,
|
|
78
|
-
config: {
|
|
79
|
-
...stored,
|
|
80
|
-
target: layer.id,
|
|
81
|
-
scale: encoding.scale,
|
|
82
|
-
fieldType: encoding.fieldType,
|
|
83
|
-
title: stored.inferredTitle ? encoding.field : stored.title,
|
|
84
|
-
domain: scale.domain
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function resolveGradientLayout(program, config, scale) {
|
|
90
|
-
const { plot, canvas } = resolveContinuousBounds(program);
|
|
91
|
-
const vertical = ["right", "left"].includes(config.position);
|
|
92
|
-
const { length, thickness } = config.gradient;
|
|
93
|
-
const titleGap = config.blockGap ?? 12;
|
|
94
|
-
let x;
|
|
95
|
-
let y;
|
|
96
|
-
if (config.position === "right") {
|
|
97
|
-
x = plot.x + plot.width + config.offset;
|
|
98
|
-
y = plot.y + 46 + titleGap - 12;
|
|
99
|
-
} else if (config.position === "left") {
|
|
100
|
-
x = plot.x - config.offset - thickness;
|
|
101
|
-
y = plot.y + 46 + titleGap - 12;
|
|
102
|
-
} else {
|
|
103
|
-
x = config.align === "left" ? plot.x
|
|
104
|
-
: config.align === "right" ? plot.x + plot.width - length
|
|
105
|
-
: plot.x + (plot.width - length) / 2;
|
|
106
|
-
y = config.position === "top"
|
|
107
|
-
? plot.y - config.offset - thickness - config.labels.offset -
|
|
108
|
-
config.labels.fontSize
|
|
109
|
-
: plot.y + plot.height + config.offset +
|
|
110
|
-
(config.titleVisible === false ? 0 : config.titleStyle.fontSize + titleGap);
|
|
111
|
-
}
|
|
112
|
-
const title = vertical
|
|
113
|
-
? { x, y: plot.y + 20, align: "left" }
|
|
114
|
-
: { x: x + length / 2, y: y - titleGap - config.titleStyle.fontSize / 2,
|
|
115
|
-
align: "center" };
|
|
116
|
-
const values = [...sampleContinuousValues(scale.domain, config.count)];
|
|
117
|
-
if (scale.midpoint !== undefined && !values.includes(scale.midpoint)) {
|
|
118
|
-
values.push(scale.midpoint);
|
|
119
|
-
values.sort((a, b) => scale.domain[1] > scale.domain[0] ? a - b : b - a);
|
|
120
|
-
}
|
|
121
|
-
const texts = formatContinuousValues(
|
|
122
|
-
values,
|
|
123
|
-
scale.domain,
|
|
124
|
-
config.fieldType,
|
|
125
|
-
config.labels.format
|
|
126
|
-
);
|
|
127
|
-
const fractions = values.map((value, index) => scale.midpoint === undefined
|
|
128
|
-
? index / (values.length - 1)
|
|
129
|
-
: inverseLerp(value, ...scale.domain));
|
|
130
|
-
const labels = vertical
|
|
131
|
-
? fractions.map(fraction => ({
|
|
132
|
-
x: config.position === "right"
|
|
133
|
-
? x + thickness + config.labels.offset
|
|
134
|
-
: x - config.labels.offset,
|
|
135
|
-
y: y + length * (1 - fraction),
|
|
136
|
-
align: config.position === "right" ? "left" : "right"
|
|
137
|
-
}))
|
|
138
|
-
: fractions.map(fraction => ({
|
|
139
|
-
x: x + length * fraction,
|
|
140
|
-
y: y + thickness + config.labels.offset + config.labels.fontSize / 2,
|
|
141
|
-
align: "center"
|
|
142
|
-
}));
|
|
143
|
-
const ticks = vertical
|
|
144
|
-
? labels.map(label => ({
|
|
145
|
-
x1: config.position === "right" ? x + thickness : x,
|
|
146
|
-
y1: label.y,
|
|
147
|
-
x2: config.position === "right" ? x + thickness + 6 : x - 6,
|
|
148
|
-
y2: label.y
|
|
149
|
-
}))
|
|
150
|
-
: labels.map(label => ({
|
|
151
|
-
x1: label.x,
|
|
152
|
-
y1: y + thickness,
|
|
153
|
-
x2: label.x,
|
|
154
|
-
y2: y + thickness + 6
|
|
155
|
-
}));
|
|
156
|
-
const occupied = [
|
|
157
|
-
{ left: x, right: x + (vertical ? thickness : length), top: y,
|
|
158
|
-
bottom: y + (vertical ? length : thickness) },
|
|
159
|
-
...ticks.map(tick => ({
|
|
160
|
-
left: Math.min(tick.x1, tick.x2) - 0.5,
|
|
161
|
-
right: Math.max(tick.x1, tick.x2) + 0.5,
|
|
162
|
-
top: Math.min(tick.y1, tick.y2) - 0.5,
|
|
163
|
-
bottom: Math.max(tick.y1, tick.y2) + 0.5
|
|
164
|
-
})),
|
|
165
|
-
...labels.map((label, index) =>
|
|
166
|
-
resolveLegendTextBounds(label, texts[index], config.labels)),
|
|
167
|
-
...(config.titleVisible === false ? [] : [
|
|
168
|
-
resolveLegendTextBounds(title, config.title, config.titleStyle)
|
|
169
|
-
])
|
|
170
|
-
];
|
|
171
|
-
assertLegendBoundsInsideCanvas(occupied, canvas, "Stroke gradient legend layout", config);
|
|
172
|
-
return {
|
|
173
|
-
vertical,
|
|
174
|
-
x,
|
|
175
|
-
y,
|
|
176
|
-
length,
|
|
177
|
-
thickness,
|
|
178
|
-
values,
|
|
179
|
-
texts,
|
|
180
|
-
labels,
|
|
181
|
-
ticks,
|
|
182
|
-
title,
|
|
183
|
-
background: resolveLegendBackgroundFromBounds(
|
|
184
|
-
occupied,
|
|
185
|
-
config.border,
|
|
186
|
-
canvas,
|
|
187
|
-
"Stroke gradient legend",
|
|
188
|
-
config
|
|
189
|
-
)
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
|
|
193
48
|
export function resolveStrokeGradientLegendCreation(program, args = {}) {
|
|
194
49
|
requireChannels(args, "Stroke gradient legend");
|
|
195
|
-
|
|
196
|
-
if (args.gradient !== undefined && !isPlainObject(args.gradient)) {
|
|
197
|
-
throw new TypeError("createLegend.gradient must be a plain object.");
|
|
198
|
-
}
|
|
199
|
-
validateKeys(args.gradient ?? {}, GRADIENT_OPTIONS, "createLegend.gradient");
|
|
200
|
-
config.gradient = {
|
|
201
|
-
length: args.gradient?.length ?? DEFAULT_GRADIENT_SIZE.length,
|
|
202
|
-
thickness: args.gradient?.thickness ?? DEFAULT_GRADIENT_SIZE.thickness
|
|
203
|
-
};
|
|
204
|
-
config.titleVisible = true;
|
|
205
|
-
validatePositive(config.gradient.length, "Gradient length");
|
|
206
|
-
validatePositive(config.gradient.thickness, "Gradient thickness");
|
|
207
|
-
return resolveGradientConfig(program, config);
|
|
50
|
+
return resolveGradientLegendCreation(program, args, "stroke");
|
|
208
51
|
}
|
|
209
52
|
|
|
210
|
-
export const rematerializeStrokeGradientLegend =
|
|
53
|
+
export const rematerializeStrokeGradientLegend = /* @__PURE__ */ closedAction(
|
|
211
54
|
{
|
|
212
55
|
op: "rematerializeStrokeGradientLegend",
|
|
213
56
|
description: "Rematerialize a continuous stroke gradient legend."
|
|
214
|
-
},
|
|
57
|
+
}, [],
|
|
215
58
|
function (args = {}) {
|
|
216
|
-
validateKeys(args, [], "rematerializeStrokeGradientLegend");
|
|
217
59
|
const stored = this.guideConfigs.legend?.strokeGradient;
|
|
218
60
|
if (stored === undefined) {
|
|
219
61
|
throw new Error("Stroke gradient legend requires stored configuration.");
|
|
220
62
|
}
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const width = strokeWidth(this, config.target);
|
|
226
|
-
const stripCount = 60;
|
|
227
|
-
const stripSize = layout.length / stripCount;
|
|
228
|
-
const strips = Array.from({ length: stripCount }, (_, index) => {
|
|
229
|
-
const fraction = (index + 0.5) / stripCount;
|
|
230
|
-
const position = layout.vertical ? 1 - fraction : fraction;
|
|
231
|
-
const samplingScale = scale.midpoint === undefined
|
|
232
|
-
? { ...scale, domain: [0, 1] }
|
|
233
|
-
: scale;
|
|
234
|
-
const value = scale.midpoint === undefined
|
|
235
|
-
? position
|
|
236
|
-
: interpolateNumber(...scale.domain, position);
|
|
237
|
-
const [color] = mapScaleConsumerValues([value], samplingScale, "stroke");
|
|
238
|
-
return {
|
|
239
|
-
x: layout.x + (layout.vertical ? 0 : index * stripSize),
|
|
240
|
-
y: layout.y + (layout.vertical ? index * stripSize : 0),
|
|
241
|
-
width: layout.vertical ? layout.thickness : stripSize,
|
|
242
|
-
height: layout.vertical ? stripSize : layout.thickness,
|
|
243
|
-
fill,
|
|
244
|
-
stroke: color,
|
|
245
|
-
strokeWidth: width
|
|
246
|
-
};
|
|
247
|
-
});
|
|
248
|
-
let next = this
|
|
249
|
-
.editSemantic({ property: "guide.legend.stroke.scale", value: encoding.scale })
|
|
250
|
-
.editSemantic({ property: "guide.legend.stroke.title", value: config.title })
|
|
251
|
-
._withLegendConfig("strokeGradient", currentConfig);
|
|
252
|
-
next = editLegendBackground(
|
|
253
|
-
next,
|
|
254
|
-
"strokeGradientBackground",
|
|
255
|
-
layout.background,
|
|
256
|
-
config.border
|
|
257
|
-
);
|
|
258
|
-
next = editGraphicProperties(next, "strokeGradientStrips", {
|
|
259
|
-
length: strips.length,
|
|
260
|
-
x: strips.map(strip => strip.x),
|
|
261
|
-
y: strips.map(strip => strip.y),
|
|
262
|
-
width: strips.map(strip => strip.width),
|
|
263
|
-
height: strips.map(strip => strip.height),
|
|
264
|
-
fill: strips.map(strip => strip.fill),
|
|
265
|
-
stroke: strips.map(strip => strip.stroke),
|
|
266
|
-
strokeWidth: strips.map(strip => strip.strokeWidth)
|
|
267
|
-
});
|
|
268
|
-
next = editGraphicProperties(next, "strokeGradientTicks", {
|
|
269
|
-
length: layout.ticks.length,
|
|
270
|
-
x1: layout.ticks.map(tick => tick.x1),
|
|
271
|
-
y1: layout.ticks.map(tick => tick.y1),
|
|
272
|
-
x2: layout.ticks.map(tick => tick.x2),
|
|
273
|
-
y2: layout.ticks.map(tick => tick.y2),
|
|
274
|
-
stroke: DEFAULT_COLORS.mutedText,
|
|
275
|
-
strokeWidth: 1
|
|
276
|
-
});
|
|
277
|
-
next = editGraphicProperties(next, "strokeGradientLabels", {
|
|
278
|
-
length: layout.labels.length,
|
|
279
|
-
x: layout.labels.map(label => label.x),
|
|
280
|
-
y: layout.labels.map(label => label.y),
|
|
281
|
-
text: layout.texts
|
|
282
|
-
});
|
|
283
|
-
next = styleContinuousText(next, "strokeGradientLabels", config.labels, {
|
|
284
|
-
align: layout.labels[0].align
|
|
285
|
-
});
|
|
286
|
-
if (config.titleVisible === false) return next;
|
|
287
|
-
next = editGraphicProperties(next, "strokeGradientTitle", {
|
|
288
|
-
x: layout.title.x,
|
|
289
|
-
y: layout.title.y,
|
|
290
|
-
text: config.title
|
|
291
|
-
});
|
|
292
|
-
return styleContinuousText(next, "strokeGradientTitle", config.titleStyle, {
|
|
293
|
-
align: layout.title.align
|
|
63
|
+
const resolved = resolveGradientConfig(this, stored, "stroke");
|
|
64
|
+
return materializeGradientLegend(this, resolved, {
|
|
65
|
+
fill: sampleFill(this, resolved.config.target),
|
|
66
|
+
strokeWidth: strokeWidth(this, resolved.config.target)
|
|
294
67
|
});
|
|
295
68
|
}
|
|
296
69
|
);
|
|
297
70
|
|
|
298
71
|
export function createStrokeGradientLegendFromConfig(program, config) {
|
|
299
|
-
|
|
300
|
-
resolveGradientLayout(program, resolved.config, resolved.scale);
|
|
301
|
-
let next = program
|
|
302
|
-
.editSemantic({
|
|
303
|
-
property: "guide.legend.stroke.scale",
|
|
304
|
-
value: resolved.encoding.scale
|
|
305
|
-
})
|
|
306
|
-
.editSemantic({
|
|
307
|
-
property: "guide.legend.stroke.title",
|
|
308
|
-
value: resolved.config.title
|
|
309
|
-
})
|
|
310
|
-
._withLegendConfig("strokeGradient", resolved.config);
|
|
311
|
-
const placement = resolveLegendGraphicPlacement(next);
|
|
312
|
-
if (resolved.config.border !== false) {
|
|
313
|
-
next = next.createGraphics({
|
|
314
|
-
id: "strokeGradientBackground",
|
|
315
|
-
type: "rect",
|
|
316
|
-
...placement
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
next = next
|
|
320
|
-
.createGraphics({
|
|
321
|
-
id: "strokeGradientStrips",
|
|
322
|
-
type: "rect",
|
|
323
|
-
length: 0,
|
|
324
|
-
...resolveLegendGraphicPlacement(next, resolved.config.border === false
|
|
325
|
-
? {}
|
|
326
|
-
: { after: "strokeGradientBackground" })
|
|
327
|
-
})
|
|
328
|
-
.createGraphics({ id: "strokeGradientTicks", type: "line", length: 0,
|
|
329
|
-
...resolveLegendGraphicPlacement(next) })
|
|
330
|
-
.createGraphics({ id: "strokeGradientLabels", type: "text", length: 0,
|
|
331
|
-
...resolveLegendGraphicPlacement(next) });
|
|
332
|
-
if (resolved.config.titleVisible !== false) {
|
|
333
|
-
next = next.createGraphics({ id: "strokeGradientTitle", type: "text",
|
|
334
|
-
...resolveLegendGraphicPlacement(next) });
|
|
335
|
-
}
|
|
336
|
-
return next.rematerializeStrokeGradientLegend();
|
|
72
|
+
return createGradientLegendFromConfig(program, config, "stroke");
|
|
337
73
|
}
|
|
338
74
|
|
|
339
|
-
export const createStrokeGradientLegend = action(
|
|
75
|
+
export const createStrokeGradientLegend = /* @__PURE__ */ action(
|
|
340
76
|
{
|
|
341
77
|
op: "createStrokeGradientLegend",
|
|
342
78
|
description: "Create a continuous stroke gradient legend."
|
|
@@ -351,49 +87,15 @@ export const createStrokeGradientLegend = action(
|
|
|
351
87
|
);
|
|
352
88
|
|
|
353
89
|
export function resolveStrokeIntervalConfig(program, stored) {
|
|
354
|
-
const
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
}
|
|
359
|
-
const scale = program.resolvedScales[encoding.scale];
|
|
360
|
-
if (!["quantize", "quantile", "threshold"].includes(scale?.type)) {
|
|
361
|
-
throw new Error(
|
|
362
|
-
`Stroke interval legend requires a resolved discretized scale "${encoding.scale}".`
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
return { encoding, scale, config: {
|
|
366
|
-
...stored,
|
|
367
|
-
target: layer.id,
|
|
368
|
-
scale: encoding.scale,
|
|
369
|
-
title: stored.inferredTitle ? encoding.field : stored.title,
|
|
370
|
-
...(stored.inferredStrokeWidth === true ? {
|
|
371
|
-
symbol: { ...stored.symbol, strokeWidth: strokeWidth(program, layer.id) }
|
|
372
|
-
} : {})
|
|
90
|
+
const resolved = resolveIntervalConfig(program, stored, "stroke");
|
|
91
|
+
if (stored.inferredStrokeWidth !== true) return resolved;
|
|
92
|
+
return { ...resolved, config: { ...resolved.config,
|
|
93
|
+
symbol: { ...stored.symbol, strokeWidth: strokeWidth(program, resolved.config.target) }
|
|
373
94
|
} };
|
|
374
95
|
}
|
|
375
96
|
|
|
376
97
|
export function resolveStrokeIntervalLayout(program, config, scale) {
|
|
377
|
-
|
|
378
|
-
const labels = formatDiscretizedIntervals(scale.thresholds, config.labels.format);
|
|
379
|
-
const layout = resolveLegendItemLayout(plot, config, labels, config.symbol);
|
|
380
|
-
assertLegendBoundsInsideCanvas(
|
|
381
|
-
layout.bounds,
|
|
382
|
-
canvas,
|
|
383
|
-
"Stroke interval legend layout",
|
|
384
|
-
config
|
|
385
|
-
);
|
|
386
|
-
return {
|
|
387
|
-
labels,
|
|
388
|
-
...layout,
|
|
389
|
-
background: resolveLegendBackgroundFromBounds(
|
|
390
|
-
layout.bounds,
|
|
391
|
-
config.border,
|
|
392
|
-
canvas,
|
|
393
|
-
"Stroke interval legend",
|
|
394
|
-
config
|
|
395
|
-
)
|
|
396
|
-
};
|
|
98
|
+
return resolveIntervalLayout(program, config, scale, "Stroke interval legend");
|
|
397
99
|
}
|
|
398
100
|
|
|
399
101
|
export function resolveStrokeIntervalLegendCreation(program, args = {}) {
|
|
@@ -411,13 +113,12 @@ export function resolveStrokeIntervalLegendCreation(program, args = {}) {
|
|
|
411
113
|
return resolveStrokeIntervalConfig(program, config);
|
|
412
114
|
}
|
|
413
115
|
|
|
414
|
-
export const rematerializeStrokeIntervalLegend =
|
|
116
|
+
export const rematerializeStrokeIntervalLegend = /* @__PURE__ */ closedAction(
|
|
415
117
|
{
|
|
416
118
|
op: "rematerializeStrokeIntervalLegend",
|
|
417
119
|
description: "Rematerialize a discretized stroke interval legend."
|
|
418
|
-
},
|
|
120
|
+
}, [],
|
|
419
121
|
function (args = {}) {
|
|
420
|
-
validateKeys(args, [], "rematerializeStrokeIntervalLegend");
|
|
421
122
|
const stored = this.guideConfigs.legend?.strokeInterval;
|
|
422
123
|
if (stored === undefined) {
|
|
423
124
|
throw new Error("Stroke interval legend requires stored configuration.");
|
|
@@ -500,13 +201,12 @@ export function createStrokeIntervalLegendFromConfig(program, config) {
|
|
|
500
201
|
return next.rematerializeStrokeIntervalLegend();
|
|
501
202
|
}
|
|
502
203
|
|
|
503
|
-
export const createStrokeIntervalLegend =
|
|
204
|
+
export const createStrokeIntervalLegend = /* @__PURE__ */ closedAction(
|
|
504
205
|
{
|
|
505
206
|
op: "createStrokeIntervalLegend",
|
|
506
207
|
description: "Create a discretized stroke interval legend."
|
|
507
|
-
},
|
|
208
|
+
}, undefined,
|
|
508
209
|
function (args = {}) {
|
|
509
|
-
validateOptionObject(args, undefined, "createStrokeIntervalLegend");
|
|
510
210
|
const resolved = resolveStrokeIntervalLegendCreation(this, args);
|
|
511
211
|
if (this.guideConfigs.legend?.strokeInterval !== undefined) {
|
|
512
212
|
throw new Error("createStrokeIntervalLegend requires a missing stroke legend.");
|
|
@@ -542,7 +542,7 @@ function editLegendContent(program, target, args) {
|
|
|
542
542
|
return next.rematerializeLegend();
|
|
543
543
|
}
|
|
544
544
|
|
|
545
|
-
export const editLegend = action(
|
|
545
|
+
export const editLegend = /* @__PURE__ */ action(
|
|
546
546
|
{ op: "editLegend", description: "Edit one stable legend content, layout or appearance." },
|
|
547
547
|
withGuideLayoutValidation(function (args = {}) {
|
|
548
548
|
validateOptionObject(args, OPTIONS, "editLegend");
|
|
@@ -17,7 +17,7 @@ function makeFocusedLegendEdit({ name, options, map }) {
|
|
|
17
17
|
);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
const editLegendLayout = makeFocusedLegendEdit({
|
|
20
|
+
const editLegendLayout = /* @__PURE__ */ makeFocusedLegendEdit({
|
|
21
21
|
name: "editLegendLayout",
|
|
22
22
|
options: [
|
|
23
23
|
"position", "layout", "align", "direction", "columns", "offset",
|
|
@@ -26,13 +26,13 @@ const editLegendLayout = makeFocusedLegendEdit({
|
|
|
26
26
|
map: args => args
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
const editLegendLabels = makeFocusedLegendEdit({
|
|
29
|
+
const editLegendLabels = /* @__PURE__ */ makeFocusedLegendEdit({
|
|
30
30
|
name: "editLegendLabels",
|
|
31
31
|
options: ["offset", "color", "fontSize", "fontFamily", "fontWeight", "format"],
|
|
32
32
|
map: ({ target, ...labels }) => ({ target, labels })
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
const editLegendTitle = makeFocusedLegendEdit({
|
|
35
|
+
const editLegendTitle = /* @__PURE__ */ makeFocusedLegendEdit({
|
|
36
36
|
name: "editLegendTitle",
|
|
37
37
|
options: ["title", "color", "fontSize", "fontFamily", "fontWeight"],
|
|
38
38
|
map: ({ target, title, ...titleStyle }) => ({
|
|
@@ -42,13 +42,13 @@ const editLegendTitle = makeFocusedLegendEdit({
|
|
|
42
42
|
})
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
const editLegendSymbols = makeFocusedLegendEdit({
|
|
45
|
+
const editLegendSymbols = /* @__PURE__ */ makeFocusedLegendEdit({
|
|
46
46
|
name: "editLegendSymbols",
|
|
47
47
|
options: ["symbol", "count", "gradient"],
|
|
48
48
|
map: args => args
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
const editLegendBorder = makeFocusedLegendEdit({
|
|
51
|
+
const editLegendBorder = /* @__PURE__ */ makeFocusedLegendEdit({
|
|
52
52
|
name: "editLegendBorder",
|
|
53
53
|
options: ["border"],
|
|
54
54
|
map: args => args
|
|
@@ -67,7 +67,7 @@ function componentIds(program, kind) {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
function legendGraphicBounds(program, id) {
|
|
70
|
-
let bounds = resolveConcreteGraphicBounds(program.graphicSpec, id);
|
|
70
|
+
let bounds = resolveConcreteGraphicBounds(program.graphicSpec, id, program.materializationConfigs.textMetrics);
|
|
71
71
|
const graphic = program.graphicSpec.objects[id];
|
|
72
72
|
if (!id.includes("LegendSymbol") || graphic?.type !== "line") return bounds;
|
|
73
73
|
const properties = graphic.items?.map(item => item.properties) ??
|
|
@@ -126,7 +126,7 @@ function blockDescriptor(program, kind, config) {
|
|
|
126
126
|
const labels = resolveConcreteGraphicBounds(
|
|
127
127
|
program.graphicSpec,
|
|
128
128
|
components.labelId
|
|
129
|
-
);
|
|
129
|
+
, program.materializationConfigs.textMetrics);
|
|
130
130
|
const title = components.titleId === undefined
|
|
131
131
|
? undefined
|
|
132
132
|
: (() => {
|
|
@@ -134,7 +134,7 @@ function blockDescriptor(program, kind, config) {
|
|
|
134
134
|
const titleBounds = resolveConcreteGraphicBounds(
|
|
135
135
|
program.graphicSpec,
|
|
136
136
|
components.titleId
|
|
137
|
-
);
|
|
137
|
+
, program.materializationConfigs.textMetrics);
|
|
138
138
|
return {
|
|
139
139
|
x: graphic.properties.x,
|
|
140
140
|
y: graphic.properties.y,
|
|
@@ -374,7 +374,7 @@ function applyHorizontalPlan(program, groups, plan) {
|
|
|
374
374
|
return next;
|
|
375
375
|
}
|
|
376
376
|
|
|
377
|
-
export const rematerializeSideLegendLane = action(
|
|
377
|
+
export const rematerializeSideLegendLane = /* @__PURE__ */ action(
|
|
378
378
|
{
|
|
379
379
|
op: "rematerializeSideLegendLane",
|
|
380
380
|
description: "Align and stack every right or left legend block."
|
|
@@ -457,7 +457,7 @@ export const rematerializeSideLegendLane = action(
|
|
|
457
457
|
}
|
|
458
458
|
);
|
|
459
459
|
|
|
460
|
-
export const rematerializeHorizontalLegendLane = action(
|
|
460
|
+
export const rematerializeHorizontalLegendLane = /* @__PURE__ */ action(
|
|
461
461
|
{
|
|
462
462
|
op: "rematerializeHorizontalLegendLane",
|
|
463
463
|
description: "Pack and align every top or bottom legend block."
|
|
@@ -479,7 +479,7 @@ export const rematerializeHorizontalLegendLane = action(
|
|
|
479
479
|
if (entries.length === 1) {
|
|
480
480
|
const [kind, config] = entries[0];
|
|
481
481
|
const ids = existingIds(next, kind);
|
|
482
|
-
const bounds = unionConcreteGraphicBounds(next.graphicSpec, ids);
|
|
482
|
+
const bounds = unionConcreteGraphicBounds(next.graphicSpec, ids, next.materializationConfigs.textMetrics);
|
|
483
483
|
const { dx, dy } = resolveSingleHorizontalLegendPlacement({
|
|
484
484
|
plot, canvas, config, bounds
|
|
485
485
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { closedAction } from "../../../core/action.js";
|
|
2
|
+
|
|
3
3
|
import {
|
|
4
4
|
removeLegendKinds,
|
|
5
5
|
resolveCategoricalLegendRevision,
|
|
@@ -67,10 +67,9 @@ export function removeOwnedColorLegends(program, target) {
|
|
|
67
67
|
return kinds.length === 0 ? program : removeLegendKinds(program, kinds);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
export const removeLegend =
|
|
71
|
-
{ op: "removeLegend", description: "Remove selected legend content or every block owned by one mark." },
|
|
70
|
+
export const removeLegend = /* @__PURE__ */ closedAction(
|
|
71
|
+
{ op: "removeLegend", description: "Remove selected legend content or every block owned by one mark." }, OPTIONS,
|
|
72
72
|
function (args = {}) {
|
|
73
|
-
validateKeys(args, OPTIONS, "removeLegend");
|
|
74
73
|
const target = resolveLegendTarget(this, args.target, "removeLegend");
|
|
75
74
|
const targetKinds = Object.entries(this.guideConfigs.legend ?? {})
|
|
76
75
|
.filter(([, config]) => config?.target === target)
|