ggaction 0.0.9 → 0.0.11
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 +84 -0
- package/README.md +5 -4
- package/knowledge/action-card.schema.json +1 -0
- package/knowledge/action-cards.json +1 -10941
- package/knowledge/action-cards.schema.json +1 -0
- package/knowledge/extension-authoring.md +248 -0
- package/knowledge/intent-taxonomy.json +1 -183
- package/knowledge/intent-taxonomy.schema.json +1 -0
- package/knowledge/mcp-resources.json +1 -95
- package/knowledge/mcp-resources.schema.json +1 -0
- package/knowledge/task-packet.schema.json +1 -159
- package/knowledge/task-resolver.js +1 -1230
- package/package.json +19 -2
- package/src/actions/boxPlots/edit.js +45 -298
- package/src/actions/boxPlots/options.js +46 -77
- package/src/actions/boxPlots/resolve.js +1 -1
- package/src/actions/charts/bar.js +3 -0
- package/src/actions/charts/heatmap.js +73 -83
- package/src/actions/charts/index.js +1 -1
- package/src/actions/charts/parallel.js +35 -1
- package/src/actions/charts/shared.js +20 -0
- package/src/actions/composition/actions.js +46 -49
- package/src/actions/data/bin2d.js +105 -2
- package/src/actions/data/box.js +17 -17
- package/src/actions/data/density.js +42 -78
- package/src/actions/data/gradientProfile.js +22 -52
- package/src/actions/data/horizon.js +16 -41
- package/src/actions/data/index.js +10 -10
- package/src/actions/data/interval.js +16 -38
- package/src/actions/data/intervalEdit.js +55 -0
- package/src/actions/data/regression.js +7 -17
- package/src/actions/data/shared.js +47 -0
- package/src/actions/data/timeUnit.js +14 -38
- package/src/actions/data/window.js +14 -38
- package/src/actions/distributions/revision.js +154 -34
- package/src/actions/encodings/angle.js +9 -10
- package/src/actions/encodings/appearance.js +17 -51
- package/src/actions/encodings/density/resolve.js +3 -1
- package/src/actions/encodings/density.js +1 -15
- package/src/actions/encodings/horizon/resolve.js +13 -3
- package/src/actions/encodings/horizon.js +8 -7
- package/src/actions/encodings/index.js +9 -9
- package/src/actions/encodings/offset.js +8 -24
- package/src/actions/encodings/parallel.js +9 -10
- package/src/actions/encodings/pathOrder.js +6 -13
- package/src/actions/encodings/position/policies/index.js +4 -4
- package/src/actions/encodings/position/policies/line.js +47 -17
- package/src/actions/encodings/position/resolve.js +24 -5
- package/src/actions/encodings/ranged.js +18 -23
- package/src/actions/encodings/remove.js +15 -25
- package/src/actions/encodings/ruleAppearance.js +9 -24
- package/src/actions/encodings/shared.js +37 -0
- package/src/actions/encodings/strokeDash.js +8 -23
- package/src/actions/encodings/text.js +9 -10
- package/src/actions/errorBands/create.js +105 -39
- package/src/actions/errorBands/edit.js +89 -93
- package/src/actions/errorBands/index.js +1 -2
- package/src/actions/errorBars/create.js +78 -27
- package/src/actions/errorBars/edit.js +81 -48
- package/src/actions/errorBars/index.js +1 -2
- package/src/actions/facets/actions.js +45 -69
- package/src/actions/facets/derive.js +38 -53
- package/src/actions/facets/replay.js +0 -1
- package/src/actions/gradientPlots/components.js +59 -48
- package/src/actions/gradientPlots/edit.js +35 -216
- package/src/actions/gradientPlots/index.js +11 -10
- package/src/actions/gradientPlots/materialize.js +21 -35
- package/src/actions/gradientPlots/options.js +5 -7
- package/src/actions/gradientPlots/paint.js +9 -6
- package/src/actions/gradientPlots/resolve.js +1 -1
- package/src/actions/guides/axes/index.js +3 -3
- package/src/actions/guides/axes/labels.js +68 -26
- package/src/actions/guides/axes/lines.js +22 -2
- package/src/actions/guides/axes/policy.js +28 -8
- package/src/actions/guides/axes/ticks.js +27 -9
- package/src/actions/guides/axes/titles.js +113 -65
- package/src/actions/guides/grids/resolve.js +14 -0
- package/src/actions/guides/guides.js +2 -4
- package/src/actions/guides/index.js +2 -2
- package/src/actions/guides/legends/categorical/actions.js +44 -68
- package/src/actions/guides/legends/categorical/components.js +6 -1
- package/src/actions/guides/legends/categorical/index.js +2 -2
- package/src/actions/guides/legends/categorical/layout.js +148 -175
- package/src/actions/guides/legends/categorical/recipes.js +5 -0
- package/src/actions/guides/legends/categorical/resolve.js +8 -1
- package/src/actions/guides/legends/continuous/common.js +117 -66
- package/src/actions/guides/legends/continuous/gradient.js +38 -37
- package/src/actions/guides/legends/continuous/interval.js +97 -76
- package/src/actions/guides/legends/continuous/opacity.js +28 -38
- package/src/actions/guides/legends/edit.js +14 -1
- package/src/actions/guides/legends/index.js +1 -1
- package/src/actions/guides/legends/lane.js +2 -1
- package/src/actions/guides/legends/remove.js +8 -0
- package/src/actions/guides/legends/size.js +36 -43
- package/src/actions/guides/legends/strokeWidth.js +20 -26
- package/src/actions/guides/polar/axes/labels.js +17 -1
- package/src/actions/guides/polar/axes/shared.js +7 -1
- package/src/actions/guides/polar/axes/titles.js +19 -2
- package/src/actions/guides/polar/grids.js +4 -0
- package/src/actions/guides/polar/resolve.js +6 -0
- package/src/actions/index.js +13 -13
- package/src/actions/intervals/resolve.js +87 -117
- package/src/actions/marks/arc/actions.js +31 -36
- package/src/actions/marks/area/actions.js +23 -31
- package/src/actions/marks/index.js +6 -6
- package/src/actions/marks/line/actions.js +33 -52
- package/src/actions/marks/line/materialize.js +7 -5
- package/src/actions/marks/point/materialize.js +5 -3
- package/src/actions/marks/remove.js +21 -0
- package/src/actions/marks/rule/actions.js +53 -53
- package/src/actions/marks/shared.js +8 -4
- package/src/actions/marks/text/actions.js +14 -6
- package/src/actions/marks/text/layout.js +21 -45
- package/src/actions/marks/tick/actions.js +22 -21
- package/src/actions/primitives/createGraphics.js +4 -0
- package/src/actions/primitives/editGraphics.js +4 -0
- package/src/actions/primitives/index.js +3 -3
- package/src/actions/primitives/semantic.js +1 -1
- package/src/actions/primitives/semanticValidation/index.js +2 -2
- package/src/actions/primitives/semanticValidation/layer.js +1 -1
- package/src/actions/regression/edit.js +3 -43
- package/src/actions/scales/consumers/families.js +24 -4
- package/src/actions/scales/consumers/index.js +1 -1
- package/src/actions/scales/consumers/seriesLayout.js +17 -0
- package/src/actions/scales/definitions.js +100 -103
- package/src/actions/scales/materialize.js +5 -0
- package/src/actions/selection/actions.js +79 -121
- package/src/actions/titles/actions.js +48 -94
- package/src/actions/titles/resolve.js +14 -27
- package/src/actions/violinPlots/create.js +37 -44
- package/src/core/action.js +20 -5
- package/src/core/extensionRegistry.js +104 -0
- package/src/core/textMetrics.js +74 -37
- package/src/core/validation.js +18 -0
- package/src/extension.js +8 -1
- package/src/grammar/aggregate.js +48 -28
- package/src/grammar/arcs.js +58 -11
- package/src/grammar/areaSeries.js +14 -16
- package/src/grammar/bin2d.js +37 -23
- package/src/grammar/boxPlot.js +14 -13
- package/src/grammar/categoricalDensity.js +14 -14
- package/src/grammar/categoryOrder.js +8 -14
- package/src/grammar/curveCommands.js +87 -20
- package/src/grammar/density.js +162 -141
- package/src/grammar/facets/index.js +14 -0
- package/src/grammar/facets/scales.js +7 -4
- package/src/grammar/gradientProfile.js +12 -15
- package/src/grammar/histogram.js +145 -83
- package/src/grammar/horizon.js +60 -23
- package/src/grammar/interval.js +14 -13
- package/src/grammar/lineSeries.js +91 -61
- package/src/grammar/numeric.js +290 -0
- package/src/grammar/paint.js +3 -4
- package/src/grammar/palettes.js +21 -32
- package/src/grammar/pathCommands.js +6 -0
- package/src/grammar/polarPaths.js +5 -5
- package/src/grammar/regression/derive.js +48 -9
- package/src/grammar/regression/models.js +248 -69
- package/src/grammar/regression/parameters.js +8 -0
- package/src/grammar/scales/color.js +35 -26
- package/src/grammar/scales/continuous.js +71 -24
- package/src/grammar/scales/definition.js +1 -1
- package/src/grammar/scales/discretized.js +42 -12
- package/src/grammar/scales/fields.js +21 -4
- package/src/grammar/scales/ordinal.js +117 -61
- package/src/grammar/scales/temporal.js +40 -11
- package/src/grammar/scales/transformed.js +199 -52
- package/src/grammar/schemas/graphicBounds.js +270 -79
- package/src/grammar/seriesLayout.js +50 -18
- package/src/grammar/ticks.js +123 -53
- package/src/grammar/timeUnit.js +18 -8
- package/src/grammar/transforms.js +4 -1
- package/src/grammar/window.js +70 -57
- package/src/index.js +1 -1
- package/src/layout/canvas.js +4 -8
- package/src/layout/composition.js +39 -40
- package/src/layout/facets.js +10 -14
- package/src/layout/labels.js +91 -15
- package/src/layout/legend.js +22 -20
- package/src/layout/legendLane.js +54 -40
- package/src/layout/title.js +7 -7
- package/src/materialization/bars/aggregate.js +14 -40
- package/src/materialization/bars/grouped.js +7 -18
- package/src/materialization/bars/histogram.js +2 -19
- package/src/materialization/bars/ranged.js +20 -15
- package/src/materialization/bars/resolve.js +21 -0
- package/src/materialization/facetGuides/legacyCategorical.js +2 -1
- package/src/materialization/facetGuides/placement.js +34 -19
- package/src/materialization/facetGuides/preparation.js +9 -5
- package/src/materialization/facets.js +39 -27
- package/src/materialization/guides/resources.js +2 -1
- package/src/materialization/marks/capabilities.js +5 -2
- package/src/materialization/marks/index.js +24 -4
- package/src/materialization/scales/policies/bar.js +61 -59
- package/src/materialization/scales/policies/binnedPosition.js +34 -0
- package/src/materialization/scales/policies/series.js +13 -7
- package/src/materialization/scales/resolve.js +4 -5
- package/src/materialization/selection/items/arc.js +16 -2
- package/src/materialization/selection/items/bar.js +4 -2
- package/src/materialization/selection/items/common.js +21 -1
- package/src/materialization/selection/items/path.js +19 -2
- package/src/materialization/selection/items/point.js +4 -16
- package/src/materialization/selection/items/tick.js +13 -21
- package/src/materialization/selection/point.js +11 -4
- package/src/materialization/selection/styles.js +19 -27
- package/src/materialization/text.js +4 -1
- package/src/mcp/adapter.js +8 -3
- package/src/renderers/canvas/fill.js +2 -2
- package/src/renderers/canvas/index.js +35 -2
- package/src/renderers/canvas/native.js +160 -0
- package/src/renderers/pdf.js +14 -0
- package/src/renderers/svg.js +37 -4
- package/types/extension.d.ts +19 -0
- package/types/index.d.ts +3 -0
- package/types/program.d.ts +509 -131
- package/types/svg.d.ts +1 -0
- package/src/actions/errorBands/components.js +0 -81
- package/src/actions/errorBands/options.js +0 -39
- package/src/actions/errorBands/resolve.js +0 -28
- package/src/actions/errorBars/components.js +0 -62
- package/src/actions/errorBars/options.js +0 -58
- package/src/actions/errorBars/resolve.js +0 -25
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { isPlainObject } from "../../../../core/immutable.js";
|
|
2
|
+
import { resolveTextBounds } from "../../../../core/textMetrics.js";
|
|
2
3
|
import {
|
|
3
4
|
validateKeys,
|
|
4
5
|
validateOptionObject,
|
|
5
6
|
validateNonEmptyString,
|
|
6
7
|
validateNonNegativeFinite,
|
|
7
|
-
validatePositiveFinite
|
|
8
|
+
validatePositiveFinite,
|
|
9
|
+
validateGeneratedItemLimit
|
|
8
10
|
} from "../../../../core/validation.js";
|
|
9
11
|
import { formatTimeTick } from "../../../../grammar/ticks.js";
|
|
12
|
+
import {
|
|
13
|
+
formatDistinctNumericSamples,
|
|
14
|
+
sampleNumericRange
|
|
15
|
+
} from "../../../../grammar/numeric.js";
|
|
10
16
|
import { resolveGraphicBounds } from "../../../../layout/canvas.js";
|
|
11
17
|
import { DEFAULT_COLORS, DEFAULT_FONT_FAMILY } from
|
|
12
18
|
"../../../../theme/defaults.js";
|
|
@@ -14,41 +20,48 @@ import { findLayer } from "../../../../selectors/layers.js";
|
|
|
14
20
|
import { findCanvasGraphic } from
|
|
15
21
|
"../../../../materialization/graphicHierarchy.js";
|
|
16
22
|
|
|
17
|
-
const OPTIONS =
|
|
23
|
+
const OPTIONS = [
|
|
18
24
|
"target", "channels", "position", "align", "offset", "title", "count",
|
|
19
25
|
"gradient", "symbol", "labels", "titleStyle", "itemGap", "border",
|
|
20
26
|
"direction", "columns", "titlePosition"
|
|
21
|
-
]
|
|
22
|
-
const TEXT_OPTIONS =
|
|
27
|
+
];
|
|
28
|
+
const TEXT_OPTIONS = [
|
|
23
29
|
"offset", "color", "fontSize", "fontFamily", "fontWeight"
|
|
24
|
-
]
|
|
25
|
-
const BORDER_OPTIONS =
|
|
30
|
+
];
|
|
31
|
+
const BORDER_OPTIONS = [
|
|
26
32
|
"color", "lineWidth", "padding", "background"
|
|
27
|
-
]
|
|
28
|
-
const POSITIONS =
|
|
29
|
-
const DEFAULT_LABELS =
|
|
33
|
+
];
|
|
34
|
+
const POSITIONS = ["right", "left", "top", "bottom"];
|
|
35
|
+
const DEFAULT_LABELS = {
|
|
30
36
|
offset: 12,
|
|
31
37
|
color: DEFAULT_COLORS.text,
|
|
32
38
|
fontSize: 12,
|
|
33
39
|
fontFamily: DEFAULT_FONT_FAMILY,
|
|
34
40
|
fontWeight: "normal"
|
|
35
|
-
}
|
|
36
|
-
const DEFAULT_TITLE =
|
|
41
|
+
};
|
|
42
|
+
const DEFAULT_TITLE = {
|
|
37
43
|
color: DEFAULT_COLORS.text,
|
|
38
44
|
fontSize: 13,
|
|
39
45
|
fontFamily: DEFAULT_FONT_FAMILY,
|
|
40
46
|
fontWeight: 600
|
|
41
|
-
}
|
|
42
|
-
const DEFAULT_BORDER =
|
|
47
|
+
};
|
|
48
|
+
const DEFAULT_BORDER = {
|
|
43
49
|
color: DEFAULT_COLORS.border,
|
|
44
50
|
lineWidth: 1,
|
|
45
51
|
padding: 12,
|
|
46
52
|
background: "transparent"
|
|
47
|
-
}
|
|
53
|
+
};
|
|
48
54
|
|
|
49
55
|
export const validatePositive = validatePositiveFinite;
|
|
50
56
|
export const validateNonNegative = validateNonNegativeFinite;
|
|
51
57
|
|
|
58
|
+
export function editGraphicProperties(program, target, properties) {
|
|
59
|
+
for (const [property, value] of Object.entries(properties)) {
|
|
60
|
+
program = program.editGraphics({ target, property, value });
|
|
61
|
+
}
|
|
62
|
+
return program;
|
|
63
|
+
}
|
|
64
|
+
|
|
52
65
|
export function normalizeLegendTextOptions(value, label, defaults) {
|
|
53
66
|
if (value === undefined) return { ...defaults };
|
|
54
67
|
if (!isPlainObject(value)) {
|
|
@@ -72,7 +85,7 @@ export function normalizeLegendTextOptions(value, label, defaults) {
|
|
|
72
85
|
return result;
|
|
73
86
|
}
|
|
74
87
|
|
|
75
|
-
function
|
|
88
|
+
export function normalizeLegendBorder(value) {
|
|
76
89
|
if (value === undefined || value === false) return false;
|
|
77
90
|
if (value !== true && !isPlainObject(value)) {
|
|
78
91
|
throw new TypeError("createLegend.border must be a boolean or plain object.");
|
|
@@ -103,6 +116,7 @@ export function normalizeContinuousLegend(args, kind) {
|
|
|
103
116
|
"Continuous legend count must be an integer of at least 2."
|
|
104
117
|
);
|
|
105
118
|
}
|
|
119
|
+
validateGeneratedItemLimit(count, "Continuous legend count");
|
|
106
120
|
const offset = args.offset ?? 30;
|
|
107
121
|
validateNonNegative(offset, "Legend offset");
|
|
108
122
|
const titlePosition = args.titlePosition ?? "top";
|
|
@@ -155,21 +169,26 @@ export function normalizeContinuousLegend(args, kind) {
|
|
|
155
169
|
),
|
|
156
170
|
itemGap,
|
|
157
171
|
titlePosition,
|
|
158
|
-
border:
|
|
172
|
+
border: normalizeLegendBorder(args.border)
|
|
159
173
|
};
|
|
160
174
|
}
|
|
161
175
|
|
|
176
|
+
export function selectLegendLayer(program, requested, predicate) {
|
|
177
|
+
const candidates = program.semanticSpec.layers.filter(predicate);
|
|
178
|
+
if (requested === undefined) return candidates.length === 1
|
|
179
|
+
? candidates[0]
|
|
180
|
+
: undefined;
|
|
181
|
+
const candidate = findLayer(program, requested);
|
|
182
|
+
return candidates.includes(candidate) ? candidate : undefined;
|
|
183
|
+
}
|
|
184
|
+
|
|
162
185
|
export function resolveContinuousPoint(program, requested, channel) {
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
186
|
+
const layer = selectLegendLayer(
|
|
187
|
+
program,
|
|
188
|
+
requested,
|
|
189
|
+
candidate => candidate.mark?.type === "point" &&
|
|
190
|
+
candidate.encoding?.[channel]?.scale !== undefined
|
|
166
191
|
);
|
|
167
|
-
const layer = requested === undefined
|
|
168
|
-
? candidates.length === 1 ? candidates[0] : undefined
|
|
169
|
-
: (() => {
|
|
170
|
-
const candidate = findLayer(program, requested);
|
|
171
|
-
return candidates.includes(candidate) ? candidate : undefined;
|
|
172
|
-
})();
|
|
173
192
|
if (layer === undefined) {
|
|
174
193
|
throw new Error(
|
|
175
194
|
requested === undefined
|
|
@@ -181,16 +200,12 @@ export function resolveContinuousPoint(program, requested, channel) {
|
|
|
181
200
|
}
|
|
182
201
|
|
|
183
202
|
export function resolveContinuousColorLayer(program, requested) {
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
203
|
+
const layer = selectLegendLayer(
|
|
204
|
+
program,
|
|
205
|
+
requested,
|
|
206
|
+
candidate => ["point", "bar", "rect"].includes(candidate.mark?.type) &&
|
|
207
|
+
candidate.encoding?.color?.scale !== undefined
|
|
187
208
|
);
|
|
188
|
-
const layer = requested === undefined
|
|
189
|
-
? candidates.length === 1 ? candidates[0] : undefined
|
|
190
|
-
: (() => {
|
|
191
|
-
const candidate = findLayer(program, requested);
|
|
192
|
-
return candidates.includes(candidate) ? candidate : undefined;
|
|
193
|
-
})();
|
|
194
209
|
if (layer === undefined) {
|
|
195
210
|
throw new Error(
|
|
196
211
|
requested === undefined
|
|
@@ -209,7 +224,10 @@ export function requireResolvedLegendScale(program, id, type) {
|
|
|
209
224
|
return scale;
|
|
210
225
|
}
|
|
211
226
|
|
|
212
|
-
export function resolveContinuousBounds(
|
|
227
|
+
export function resolveContinuousBounds(
|
|
228
|
+
program,
|
|
229
|
+
message = "Continuous legend layout requires Canvas bounds."
|
|
230
|
+
) {
|
|
213
231
|
const plot = resolveGraphicBounds(program);
|
|
214
232
|
const canvas = findCanvasGraphic(program);
|
|
215
233
|
if (
|
|
@@ -219,22 +237,24 @@ export function resolveContinuousBounds(program) {
|
|
|
219
237
|
!Number.isFinite(canvas.properties.width) ||
|
|
220
238
|
!Number.isFinite(canvas.properties.height)
|
|
221
239
|
) {
|
|
222
|
-
throw new Error(
|
|
240
|
+
throw new Error(message);
|
|
223
241
|
}
|
|
224
242
|
return { plot, canvas: canvas.properties };
|
|
225
243
|
}
|
|
226
244
|
|
|
227
245
|
export function sampleContinuousValues(domain, count) {
|
|
228
|
-
return
|
|
229
|
-
domain[0]
|
|
246
|
+
return sampleNumericRange(
|
|
247
|
+
domain[0],
|
|
248
|
+
domain[1],
|
|
249
|
+
count,
|
|
250
|
+
"Continuous legend domain"
|
|
230
251
|
);
|
|
231
252
|
}
|
|
232
253
|
|
|
233
254
|
export function formatContinuousValues(values, domain, fieldType) {
|
|
234
|
-
return
|
|
235
|
-
? formatTimeTick(value, domain)
|
|
236
|
-
:
|
|
237
|
-
);
|
|
255
|
+
return fieldType === "temporal"
|
|
256
|
+
? values.map(value => formatTimeTick(value, domain))
|
|
257
|
+
: formatDistinctNumericSamples(values);
|
|
238
258
|
}
|
|
239
259
|
|
|
240
260
|
export function styleContinuousText(
|
|
@@ -243,30 +263,63 @@ export function styleContinuousText(
|
|
|
243
263
|
style,
|
|
244
264
|
{ align = "left" } = {}
|
|
245
265
|
) {
|
|
246
|
-
return program
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
266
|
+
return editGraphicProperties(program, id, {
|
|
267
|
+
fill: style.color,
|
|
268
|
+
fontSize: style.fontSize,
|
|
269
|
+
fontFamily: style.fontFamily,
|
|
270
|
+
fontWeight: style.fontWeight,
|
|
271
|
+
textAlign: align,
|
|
272
|
+
textBaseline: "middle"
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export function resolveLegendTextBounds(position, text, style) {
|
|
277
|
+
return resolveTextBounds({
|
|
278
|
+
x: position.x,
|
|
279
|
+
y: position.y,
|
|
280
|
+
text: String(text),
|
|
281
|
+
...style,
|
|
282
|
+
textAlign: position.align ?? "left",
|
|
283
|
+
textBaseline: "middle"
|
|
284
|
+
});
|
|
253
285
|
}
|
|
254
286
|
|
|
255
|
-
export function
|
|
256
|
-
if (
|
|
257
|
-
item.
|
|
287
|
+
export function assertLegendBoundsInsideCanvas(bounds, canvas, label) {
|
|
288
|
+
if (bounds.some(item =>
|
|
289
|
+
item.left < 0 || item.right > canvas.width ||
|
|
290
|
+
item.top < 0 || item.bottom > canvas.height
|
|
258
291
|
)) {
|
|
259
292
|
throw new Error(`${label} requires more Canvas margin space.`);
|
|
260
293
|
}
|
|
261
294
|
}
|
|
262
295
|
|
|
263
|
-
export function
|
|
296
|
+
export function resolveLegendBackgroundFromBounds(
|
|
297
|
+
bounds,
|
|
298
|
+
border,
|
|
299
|
+
canvas,
|
|
300
|
+
label
|
|
301
|
+
) {
|
|
264
302
|
if (border === false) return undefined;
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
303
|
+
const strokeExtent = border.lineWidth / 2;
|
|
304
|
+
let x = Infinity;
|
|
305
|
+
let y = Infinity;
|
|
306
|
+
let right = -Infinity;
|
|
307
|
+
let bottom = -Infinity;
|
|
308
|
+
for (const item of bounds) {
|
|
309
|
+
x = Math.min(x, item.left);
|
|
310
|
+
y = Math.min(y, item.top);
|
|
311
|
+
right = Math.max(right, item.right);
|
|
312
|
+
bottom = Math.max(bottom, item.bottom);
|
|
313
|
+
}
|
|
314
|
+
x -= border.padding;
|
|
315
|
+
y -= border.padding;
|
|
316
|
+
right += border.padding;
|
|
317
|
+
bottom += border.padding;
|
|
318
|
+
if (
|
|
319
|
+
x - strokeExtent < 0 || y - strokeExtent < 0 ||
|
|
320
|
+
right + strokeExtent > canvas.width ||
|
|
321
|
+
bottom + strokeExtent > canvas.height
|
|
322
|
+
) {
|
|
270
323
|
throw new Error(`${label} background requires more Canvas margin space.`);
|
|
271
324
|
}
|
|
272
325
|
return { x, y, width: right - x, height: bottom - y };
|
|
@@ -274,12 +327,10 @@ export function resolveLegendBackgroundBounds(points, border, canvas, label) {
|
|
|
274
327
|
|
|
275
328
|
export function editLegendBackground(program, id, bounds, border) {
|
|
276
329
|
if (bounds === undefined) return program;
|
|
277
|
-
return program
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
.editGraphics({ target: id, property: "stroke", value: border.color })
|
|
284
|
-
.editGraphics({ target: id, property: "strokeWidth", value: border.lineWidth });
|
|
330
|
+
return editGraphicProperties(program, id, {
|
|
331
|
+
...bounds,
|
|
332
|
+
fill: border.background,
|
|
333
|
+
stroke: border.color,
|
|
334
|
+
strokeWidth: border.lineWidth
|
|
335
|
+
});
|
|
285
336
|
}
|
|
@@ -4,14 +4,15 @@ import { validateKeys } from "../../../../core/validation.js";
|
|
|
4
4
|
import { interpolateColorStops } from "../../../../grammar/scales/color.js";
|
|
5
5
|
import { DEFAULT_COLORS } from "../../../../theme/defaults.js";
|
|
6
6
|
import {
|
|
7
|
-
|
|
7
|
+
assertLegendBoundsInsideCanvas,
|
|
8
8
|
editLegendBackground,
|
|
9
9
|
formatContinuousValues,
|
|
10
10
|
normalizeContinuousLegend,
|
|
11
11
|
requireResolvedLegendScale,
|
|
12
12
|
resolveContinuousBounds,
|
|
13
13
|
resolveContinuousColorLayer,
|
|
14
|
-
|
|
14
|
+
resolveLegendBackgroundFromBounds,
|
|
15
|
+
resolveLegendTextBounds,
|
|
15
16
|
sampleContinuousValues,
|
|
16
17
|
styleContinuousText,
|
|
17
18
|
validatePositive
|
|
@@ -52,6 +53,7 @@ function resolveGradientLayout(program, config, scale) {
|
|
|
52
53
|
align: "center"
|
|
53
54
|
};
|
|
54
55
|
const values = sampleContinuousValues(scale.domain, config.count);
|
|
56
|
+
const texts = formatContinuousValues(values, scale.domain, config.fieldType);
|
|
55
57
|
const fractions = values.map((_, index) => index / (values.length - 1));
|
|
56
58
|
const labelOffset = config.labels.offset;
|
|
57
59
|
const labels = vertical
|
|
@@ -80,38 +82,41 @@ function resolveGradientLayout(program, config, scale) {
|
|
|
80
82
|
x2: label.x,
|
|
81
83
|
y2: y + thickness + 6
|
|
82
84
|
}));
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const background = resolveLegendBackgroundBounds([
|
|
100
|
-
{ x, y },
|
|
101
|
-
{
|
|
102
|
-
x: x + (vertical ? thickness : length),
|
|
103
|
-
y: y + (vertical ? length : thickness)
|
|
104
|
-
},
|
|
85
|
+
const stripBounds = {
|
|
86
|
+
left: x,
|
|
87
|
+
right: x + (vertical ? thickness : length),
|
|
88
|
+
top: y,
|
|
89
|
+
bottom: y + (vertical ? length : thickness)
|
|
90
|
+
};
|
|
91
|
+
const tickBounds = ticks.map(tick => ({
|
|
92
|
+
left: Math.min(tick.x1, tick.x2) - 0.5,
|
|
93
|
+
right: Math.max(tick.x1, tick.x2) + 0.5,
|
|
94
|
+
top: Math.min(tick.y1, tick.y2) - 0.5,
|
|
95
|
+
bottom: Math.max(tick.y1, tick.y2) + 0.5
|
|
96
|
+
}));
|
|
97
|
+
const labelBounds = labels.map((label, index) =>
|
|
98
|
+
resolveLegendTextBounds(label, texts[index], config.labels)
|
|
99
|
+
);
|
|
100
|
+
const titleBounds = resolveLegendTextBounds(
|
|
105
101
|
title,
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
102
|
+
config.title,
|
|
103
|
+
config.titleStyle
|
|
104
|
+
);
|
|
105
|
+
const occupiedBounds = [stripBounds, ...tickBounds, ...labelBounds, titleBounds];
|
|
106
|
+
assertLegendBoundsInsideCanvas(
|
|
107
|
+
occupiedBounds,
|
|
108
|
+
canvas,
|
|
109
|
+
"Gradient legend layout"
|
|
110
|
+
);
|
|
111
|
+
const background = resolveLegendBackgroundFromBounds(
|
|
112
|
+
occupiedBounds,
|
|
113
|
+
config.border,
|
|
114
|
+
canvas,
|
|
115
|
+
"Gradient legend"
|
|
116
|
+
);
|
|
113
117
|
return {
|
|
114
|
-
vertical, x, y, length, thickness, values, labels, ticks, title,
|
|
118
|
+
vertical, x, y, length, thickness, values, texts, labels, ticks, title,
|
|
119
|
+
background
|
|
115
120
|
};
|
|
116
121
|
}
|
|
117
122
|
|
|
@@ -244,11 +249,7 @@ export const rematerializeGradientLegend = action(
|
|
|
244
249
|
.editGraphics({
|
|
245
250
|
target: "colorGradientLabels",
|
|
246
251
|
property: "text",
|
|
247
|
-
value:
|
|
248
|
-
layout.values,
|
|
249
|
-
scale.domain,
|
|
250
|
-
config.fieldType
|
|
251
|
-
)
|
|
252
|
+
value: layout.texts
|
|
252
253
|
});
|
|
253
254
|
next = styleContinuousText(
|
|
254
255
|
next,
|