ggaction 0.0.17 → 0.0.18
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 +46 -0
- package/README.md +2 -2
- package/knowledge/action-card.schema.json +1 -1
- package/knowledge/action-cards.json +1 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/knowledge/task-resolver.js +1 -1
- package/package.json +3 -3
- package/src/BasicChartProgram.js +1 -1
- package/src/accessibility.js +3 -2
- package/src/actions/boxPlots/create.js +14 -4
- package/src/actions/boxPlots/edit.js +39 -33
- package/src/actions/boxPlots/materialize.js +7 -3
- package/src/actions/boxPlots/options.js +37 -11
- package/src/actions/canvas/actions.js +70 -95
- package/src/actions/canvas/fitting.js +16 -1
- package/src/actions/canvas/index.js +3 -0
- package/src/actions/canvas/plotBorder.js +28 -0
- package/src/actions/charts/area.js +2 -2
- package/src/actions/charts/bar.js +34 -7
- package/src/actions/charts/ecdf.js +4 -18
- package/src/actions/charts/endpoints.js +4 -18
- package/src/actions/charts/heatmap.js +4 -4
- package/src/actions/charts/index.js +2 -0
- package/src/actions/charts/interval-regression.js +2 -2
- package/src/actions/charts/line.js +1 -1
- package/src/actions/charts/pie.js +3 -47
- package/src/actions/charts/radial.js +34 -12
- package/src/actions/charts/scatter.js +16 -2
- package/src/actions/charts/shared.js +2 -2
- package/src/actions/charts/text.js +35 -0
- package/src/actions/composition/actions.js +6 -2
- package/src/actions/data/box.js +2 -1
- package/src/actions/data/edit.js +1 -1
- package/src/actions/data/regression.js +2 -1
- package/src/actions/data/shared.js +3 -2
- package/src/actions/data/stack.js +3 -1
- package/src/actions/encodings/appearance.js +37 -29
- package/src/actions/encodings/barWidth.js +36 -11
- package/src/actions/encodings/channels.js +0 -1
- package/src/actions/encodings/color/continuous.js +1 -1
- package/src/actions/encodings/color/index.js +1 -1
- package/src/actions/encodings/color/policy.js +10 -3
- package/src/actions/encodings/density/resolve.js +1 -6
- package/src/actions/encodings/position/policies/arc.js +12 -10
- package/src/actions/encodings/position/policies/area.js +3 -3
- package/src/actions/encodings/position/policies/bar.js +15 -6
- package/src/actions/encodings/position/policies/line.js +17 -6
- package/src/actions/encodings/position/resolve.js +3 -2
- package/src/actions/encodings/ranged.js +17 -0
- package/src/actions/encodings/remove.js +3 -2
- package/src/actions/encodings/seriesLayout.js +1 -0
- package/src/actions/encodings/text.js +6 -3
- package/src/actions/errorBands/create.js +2 -2
- package/src/actions/errorBands/edit.js +2 -1
- package/src/actions/facets/actions.js +158 -240
- package/src/actions/gradientPlots/resolve.js +2 -17
- package/src/actions/guides/applicability.js +1 -1
- package/src/actions/guides/axes/axis.js +16 -4
- package/src/actions/guides/axes/edit.js +4 -4
- package/src/actions/guides/axes/labels.js +120 -46
- package/src/actions/guides/axes/lines.js +6 -5
- package/src/actions/guides/axes/parallel/lifecycle.js +1 -1
- package/src/actions/guides/axes/parallel/policy.js +8 -7
- package/src/actions/guides/axes/remove.js +3 -2
- package/src/actions/guides/axes/tickGroups.js +5 -2
- package/src/actions/guides/axes/ticks.js +6 -3
- package/src/actions/guides/axes/titles.js +71 -26
- package/src/actions/guides/basic.js +2 -0
- package/src/actions/guides/facadeLegend.js +10 -2
- package/src/actions/guides/grids/grid.js +7 -1
- package/src/actions/guides/grids/resolve.js +59 -12
- package/src/actions/guides/legends/blocks.js +3 -1
- package/src/actions/guides/legends/categorical/actions.js +70 -17
- package/src/actions/guides/legends/categorical/components.js +12 -8
- package/src/actions/guides/legends/categorical/index.js +6 -0
- package/src/actions/guides/legends/categorical/layout.js +37 -8
- package/src/actions/guides/legends/categorical/options.js +31 -20
- package/src/actions/guides/legends/categorical/resolve.js +2 -2
- package/src/actions/guides/legends/categorical/symbols.js +18 -12
- package/src/actions/guides/legends/categorical/validation.js +1 -6
- package/src/actions/guides/legends/continuous/colorSymbols.js +1 -0
- package/src/actions/guides/legends/continuous/common.js +1 -447
- package/src/actions/guides/legends/continuous/gradient.js +47 -34
- package/src/actions/guides/legends/continuous/interval.js +4 -4
- package/src/actions/guides/legends/continuous/opacity.js +19 -12
- package/src/actions/guides/legends/edit.js +1 -604
- package/src/actions/guides/legends/focused.js +2 -2
- package/src/actions/guides/legends/group.js +1 -0
- package/src/actions/guides/legends/lane.js +1 -516
- package/src/actions/guides/legends/remove.js +3 -0
- package/src/actions/guides/legends/sampling.js +1 -1
- package/src/actions/guides/legends/size.js +51 -43
- package/src/actions/guides/legends/strokeWidth.js +11 -29
- package/src/actions/guides/legends/target.js +3 -3
- package/src/actions/guides/legends/transition.js +21 -7
- package/src/actions/guides/polar/axes/labels.js +4 -2
- package/src/actions/guides/polar/axes/titles.js +7 -5
- package/src/actions/guides/polar/resolve.js +6 -14
- package/src/actions/index.js +16 -16
- package/src/actions/marks/arc/actions.js +3 -10
- package/src/actions/marks/area/actions.js +8 -5
- package/src/actions/marks/area/materialize.js +8 -9
- package/src/actions/marks/bar/create.js +10 -4
- package/src/actions/marks/bar/edit.js +8 -4
- package/src/actions/marks/bar/materialize.js +9 -6
- package/src/actions/marks/line/actions.js +11 -4
- package/src/actions/marks/line/materialize.js +9 -5
- package/src/actions/marks/point/edit.js +1 -1
- package/src/actions/marks/rect/actions.js +3 -3
- package/src/actions/marks/remove.js +2 -0
- package/src/actions/marks/rule/actions.js +7 -4
- package/src/actions/marks/text/actions.js +17 -5
- package/src/actions/marks/text/layout.js +3 -0
- package/src/actions/primitives/semanticValidation/layer.js +4 -0
- package/src/actions/regression/create.js +1 -1
- package/src/actions/regression/edit.js +3 -3
- package/src/actions/regression/resolve.js +2 -6
- package/src/actions/scales/channels.js +9 -4
- package/src/actions/scales/consumers/families.js +16 -5
- package/src/actions/scales/create.js +8 -3
- package/src/actions/scales/definitions.js +1 -425
- package/src/actions/scales/edit.js +2 -2
- package/src/actions/scales/editPolicy.js +9 -3
- package/src/actions/scales/materialize.js +1 -1
- package/src/actions/scales/preview.js +21 -1
- package/src/actions/scales/quantitativeColor.js +3 -3
- package/src/actions/selection/actions.js +1 -13
- package/src/actions/theme/reconcile.js +81 -27
- package/src/actions/theme/state.js +12 -0
- package/src/actions/titles/actions.js +5 -18
- package/src/actions/titles/resolve.js +41 -19
- package/src/actions/violinPlots/edit.js +3 -20
- package/src/core/compositionState.js +4 -1
- package/src/core/font.js +9 -2
- package/src/core/optionRequirements.js +1 -0
- package/src/core/resourceReferences.js +3 -0
- package/src/core/textMetricProfile.js +3 -2
- package/src/core/textMetrics.js +41 -4
- package/src/core/validation.js +26 -0
- package/src/core/vocabulary.js +4 -0
- package/src/grammar/aggregate.js +4 -18
- package/src/grammar/arcs.js +1 -386
- package/src/grammar/areaPaint.js +10 -0
- package/src/grammar/areaSeries.js +18 -10
- package/src/grammar/bars/geometry.js +30 -3
- package/src/grammar/bars/policy.js +12 -1
- package/src/grammar/bin.js +2 -12
- package/src/grammar/bin2d.js +1 -6
- package/src/grammar/boxPlot.js +56 -9
- package/src/grammar/categoryOrder.js +1 -6
- package/src/grammar/complete.js +15 -19
- package/src/grammar/computed.js +92 -25
- package/src/grammar/curveCommands.js +29 -16
- package/src/grammar/datasetSchema.js +3 -7
- package/src/grammar/displayLabels.js +28 -0
- package/src/grammar/ecdf.js +2 -9
- package/src/grammar/facets/dependencies.js +6 -2
- package/src/grammar/facets/guides.js +5 -0
- package/src/grammar/facets/index.js +2 -5
- package/src/grammar/fold.js +2 -12
- package/src/grammar/gradientProfile.js +1 -6
- package/src/grammar/impute.js +21 -48
- package/src/grammar/interval.js +2 -9
- package/src/grammar/legendGradient.js +18 -0
- package/src/grammar/legendGroups.js +1 -0
- package/src/grammar/legendTitleStyle.js +22 -0
- package/src/grammar/lineSeries.js +32 -17
- package/src/grammar/markLabels.js +5 -2
- package/src/grammar/normalize.js +4 -54
- package/src/grammar/numeric.js +1 -290
- package/src/grammar/parallelCoordinates.js +1 -6
- package/src/grammar/parseTime.js +41 -0
- package/src/grammar/pathCommands.js +11 -4
- package/src/grammar/polar.js +1 -184
- package/src/grammar/positionCompatibility.js +3 -3
- package/src/grammar/regression/derive.js +7 -1
- package/src/grammar/regression/models.js +83 -55
- package/src/grammar/regression/parameters.js +14 -3
- package/src/grammar/roundedRect.js +42 -54
- package/src/grammar/scales/appearance.js +1 -206
- package/src/grammar/scales/color.js +1 -382
- package/src/grammar/scales/colorConsumers.js +5 -2
- package/src/grammar/scales/definition.js +1 -197
- package/src/grammar/scales/discretized.js +1 -195
- package/src/grammar/scales/size.js +1 -456
- package/src/grammar/scales/temporal.js +2 -13
- package/src/grammar/scales/transformed.js +1 -383
- package/src/grammar/scales/types.js +1 -1
- package/src/grammar/scales/validation.js +1 -66
- package/src/grammar/schemas/concreteGraphic.js +11 -0
- package/src/grammar/schemas/graphic.js +3 -0
- package/src/grammar/schemas/semanticPath.js +2 -1
- package/src/grammar/stack.js +2 -10
- package/src/grammar/statisticalReference.js +1 -6
- package/src/grammar/summary.js +3 -26
- package/src/grammar/text.js +19 -0
- package/src/grammar/timeUnit.js +16 -7
- package/src/grammar/transformKeys.js +47 -0
- package/src/grammar/transforms.js +4 -1
- package/src/grammar/valueFormat.js +17 -5
- package/src/grammar/weightedStatistics.js +1 -6
- package/src/grammar/window.js +4 -58
- package/src/inspectionDescriptors.js +1 -1
- package/src/layout/canvas.js +1 -110
- package/src/layout/facets.js +1 -244
- package/src/layout/labels.js +1 -0
- package/src/layout/legend.js +13 -0
- package/src/layout/legendGroup.js +1 -0
- package/src/layout/legendItems.js +59 -15
- package/src/layout/legendLane.js +1 -441
- package/src/layout/legendText.js +1 -0
- package/src/layout/title.js +35 -13
- package/src/materialization/bars/aggregate.js +11 -5
- package/src/materialization/bars/histogram.js +4 -1
- package/src/materialization/bars/ranged.js +19 -6
- package/src/materialization/bars/resolve.js +22 -1
- package/src/materialization/coordinateBounds.js +8 -0
- package/src/materialization/dependencies.js +4 -44
- package/src/materialization/facetGuides/layout.js +1 -0
- package/src/materialization/facetGuides/placement.js +19 -8
- package/src/materialization/facetGuides/preparation.js +15 -7
- package/src/materialization/facetHeaders.js +1 -347
- package/src/materialization/facets.js +1 -185
- package/src/materialization/graphicHierarchy.js +1 -1
- package/src/materialization/guides/layout.js +1 -57
- package/src/materialization/guides/resources.js +1 -123
- package/src/materialization/layout.js +53 -0
- package/src/materialization/legendGroups.js +1 -0
- package/src/materialization/legendText.js +1 -0
- package/src/materialization/legends.js +1 -1
- package/src/materialization/marks/capabilities.js +5 -6
- package/src/materialization/rect.js +1 -1
- package/src/materialization/scaleGuideDependencies.js +1 -1
- package/src/materialization/scales/map.js +3 -0
- package/src/materialization/scales/policies/arc.js +8 -7
- package/src/materialization/scales/policies/bar.js +19 -7
- package/src/materialization/scales/policies/series.js +2 -1
- package/src/materialization/scales/resolve.js +5 -3
- package/src/materialization/selection/items/arc.js +1 -1
- package/src/materialization/selection/items/bar.js +7 -6
- package/src/materialization/selection/items/path.js +7 -6
- package/src/materialization/selection/items/rect.js +2 -2
- package/src/materialization/text.js +13 -4
- package/src/materialization/textLines.js +15 -0
- package/src/persistence/codec.js +37 -6
- package/src/persistence/validation.js +47 -0
- package/src/persistence.js +18 -5
- package/src/renderers/canvas/circle.js +6 -3
- package/src/renderers/canvas/fill.js +7 -1
- package/src/renderers/canvas/index.js +2 -1
- package/src/renderers/canvas/line.js +1 -0
- package/src/renderers/canvas/path.js +1 -1
- package/src/renderers/canvas/rect.js +11 -8
- package/src/renderers/canvas/stroke.js +2 -1
- package/src/renderers/canvas/text.js +5 -3
- package/src/renderers/svg.js +4 -1
- package/src/selectors/layers.js +19 -0
- package/src/theme/defaults.js +8 -2
- package/src/version.js +1 -1
- package/types/basic.d.ts +1 -0
- package/types/index.d.ts +7 -0
- package/types/program.d.ts +347 -85
|
@@ -1,197 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { validateContinuousColorInterpolation, validateSequentialMidpoint } from "./color.js";
|
|
3
|
-
import { isTransformedScaleType } from "./mapping.js";
|
|
4
|
-
import {
|
|
5
|
-
normalizeTransformParameters,
|
|
6
|
-
validateTransformedDomain
|
|
7
|
-
} from "./transformed.js";
|
|
8
|
-
import {
|
|
9
|
-
isContinuousColorScaleType,
|
|
10
|
-
validateScalePropertyForType
|
|
11
|
-
} from "./types.js";
|
|
12
|
-
|
|
13
|
-
const BOOLEAN_PROPERTIES = Object.freeze([
|
|
14
|
-
"nice", "zero", "clamp", "reverse"
|
|
15
|
-
]);
|
|
16
|
-
const TYPE_PARAMETERS = Object.freeze(["base", "exponent", "constant"]);
|
|
17
|
-
|
|
18
|
-
function retainedValue(previous, patch, defaults, property, typeChanged) {
|
|
19
|
-
if (Object.hasOwn(patch, property)) return patch[property];
|
|
20
|
-
if (!typeChanged && Object.hasOwn(previous, property)) {
|
|
21
|
-
return previous[property];
|
|
22
|
-
}
|
|
23
|
-
return defaults[property];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function validateBandParameters(definition, previous, patch, defaults, typeChanged) {
|
|
27
|
-
const hasPadding = Object.hasOwn(patch, "padding");
|
|
28
|
-
if (
|
|
29
|
-
hasPadding &&
|
|
30
|
-
(Object.hasOwn(patch, "paddingInner") || Object.hasOwn(patch, "paddingOuter"))
|
|
31
|
-
) {
|
|
32
|
-
throw new Error(
|
|
33
|
-
"Scale padding cannot be combined with paddingInner or paddingOuter."
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
if (
|
|
37
|
-
hasPadding &&
|
|
38
|
-
(!Number.isFinite(patch.padding) || patch.padding < 0 || patch.padding >= 1)
|
|
39
|
-
) {
|
|
40
|
-
throw new RangeError(
|
|
41
|
-
"Scale padding must be from 0 (inclusive) to 1 (exclusive)."
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
const normalizedPatch = hasPadding
|
|
45
|
-
? { ...patch, paddingInner: patch.padding, paddingOuter: patch.padding }
|
|
46
|
-
: patch;
|
|
47
|
-
const paddingInner = retainedValue(
|
|
48
|
-
previous, normalizedPatch, defaults, "paddingInner", typeChanged
|
|
49
|
-
) ?? 0;
|
|
50
|
-
const paddingOuter = retainedValue(
|
|
51
|
-
previous, normalizedPatch, defaults, "paddingOuter", typeChanged
|
|
52
|
-
) ?? 0;
|
|
53
|
-
const align = retainedValue(
|
|
54
|
-
previous, normalizedPatch, defaults, "align", typeChanged
|
|
55
|
-
) ?? 0.5;
|
|
56
|
-
if (!Number.isFinite(paddingInner) || paddingInner < 0 || paddingInner >= 1) {
|
|
57
|
-
throw new RangeError(
|
|
58
|
-
"Scale paddingInner must be from 0 (inclusive) to 1 (exclusive)."
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
if (!Number.isFinite(paddingOuter) || paddingOuter < 0) {
|
|
62
|
-
throw new RangeError("Scale paddingOuter must be non-negative and finite.");
|
|
63
|
-
}
|
|
64
|
-
if (!Number.isFinite(align) || align < 0 || align > 1) {
|
|
65
|
-
throw new RangeError("Scale align must be between 0 and 1.");
|
|
66
|
-
}
|
|
67
|
-
Object.assign(definition, { paddingInner, paddingOuter, align });
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function validatePointParameters(definition, previous, patch, defaults, typeChanged) {
|
|
71
|
-
const padding = retainedValue(
|
|
72
|
-
previous, patch, defaults, "padding", typeChanged
|
|
73
|
-
) ?? 0.5;
|
|
74
|
-
const align = retainedValue(previous, patch, defaults, "align", typeChanged) ?? 0.5;
|
|
75
|
-
if (!Number.isFinite(padding) || padding < 0) {
|
|
76
|
-
throw new RangeError("Scale padding must be non-negative and finite.");
|
|
77
|
-
}
|
|
78
|
-
if (!Number.isFinite(align) || align < 0 || align > 1) {
|
|
79
|
-
throw new RangeError("Scale align must be between 0 and 1.");
|
|
80
|
-
}
|
|
81
|
-
Object.assign(definition, { padding, align });
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function normalizeScaleDefinition({
|
|
85
|
-
type,
|
|
86
|
-
previous = {},
|
|
87
|
-
patch = {},
|
|
88
|
-
defaults = {},
|
|
89
|
-
retainCoreOnTypeChange = false,
|
|
90
|
-
retainCompatibleOnTypeChange = false,
|
|
91
|
-
allowOrdinalBandParameters = false,
|
|
92
|
-
validateDomain,
|
|
93
|
-
validateRange
|
|
94
|
-
}) {
|
|
95
|
-
const typeChanged = previous.type !== undefined && previous.type !== type;
|
|
96
|
-
const rawDomain = Object.hasOwn(patch, "domain")
|
|
97
|
-
? patch.domain
|
|
98
|
-
: (!typeChanged || retainCoreOnTypeChange) && Object.hasOwn(previous, "domain")
|
|
99
|
-
? previous.domain
|
|
100
|
-
: defaults.domain ?? "auto";
|
|
101
|
-
const rawRange = Object.hasOwn(patch, "range")
|
|
102
|
-
? patch.range
|
|
103
|
-
: (!typeChanged || retainCoreOnTypeChange) && Object.hasOwn(previous, "range")
|
|
104
|
-
? previous.range
|
|
105
|
-
: defaults.range ?? "auto";
|
|
106
|
-
const definition = {
|
|
107
|
-
type,
|
|
108
|
-
domain: validateDomain(type, rawDomain),
|
|
109
|
-
range: validateRange(type, rawRange)
|
|
110
|
-
};
|
|
111
|
-
const emptyDomain = retainedValue(previous, patch, defaults, "emptyDomain", typeChanged);
|
|
112
|
-
if (emptyDomain !== undefined) {
|
|
113
|
-
if (!["preserve", "require-explicit"].includes(emptyDomain)) {
|
|
114
|
-
throw new Error('Scale emptyDomain must be "preserve" or "require-explicit".');
|
|
115
|
-
}
|
|
116
|
-
definition.emptyDomain = emptyDomain;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
for (const property of BOOLEAN_PROPERTIES) {
|
|
120
|
-
let value = retainedValue(previous, patch, defaults, property, typeChanged);
|
|
121
|
-
if (
|
|
122
|
-
value === undefined &&
|
|
123
|
-
typeChanged &&
|
|
124
|
-
retainCompatibleOnTypeChange &&
|
|
125
|
-
Object.hasOwn(previous, property)
|
|
126
|
-
) {
|
|
127
|
-
try {
|
|
128
|
-
validateScalePropertyForType(type, property);
|
|
129
|
-
value = previous[property];
|
|
130
|
-
} catch {
|
|
131
|
-
value = undefined;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
if (value === undefined) continue;
|
|
135
|
-
if (typeof value !== "boolean") {
|
|
136
|
-
throw new TypeError(`Scale ${property} must be a boolean.`);
|
|
137
|
-
}
|
|
138
|
-
validateScalePropertyForType(type, property);
|
|
139
|
-
definition[property] = value;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const requested = Object.fromEntries(TYPE_PARAMETERS.flatMap(property => {
|
|
143
|
-
const value = retainedValue(previous, patch, defaults, property, typeChanged);
|
|
144
|
-
return value === undefined ? [] : [[property, value]];
|
|
145
|
-
}));
|
|
146
|
-
if (isTransformedScaleType(type)) {
|
|
147
|
-
const parameters = normalizeTransformParameters(type, requested);
|
|
148
|
-
if (type === "log") definition.base = parameters.base;
|
|
149
|
-
if (type === "pow") definition.exponent = parameters.exponent;
|
|
150
|
-
if (type === "symlog") definition.constant = parameters.constant;
|
|
151
|
-
if (definition.domain !== "auto") {
|
|
152
|
-
validateTransformedDomain(type, definition.domain, requested);
|
|
153
|
-
}
|
|
154
|
-
} else {
|
|
155
|
-
for (const property of Object.keys(requested)) {
|
|
156
|
-
validateScalePropertyForType(type, property);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const interpolate = retainedValue(
|
|
161
|
-
previous, patch, defaults, "interpolate", typeChanged
|
|
162
|
-
);
|
|
163
|
-
if (isContinuousColorScaleType(type)) {
|
|
164
|
-
definition.interpolate = validateContinuousColorInterpolation(
|
|
165
|
-
interpolate ?? "rgb"
|
|
166
|
-
);
|
|
167
|
-
} else if (interpolate !== undefined) {
|
|
168
|
-
throw new Error(`Scale type "${type}" does not support interpolate.`);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const midpoint = validateSequentialMidpoint(
|
|
172
|
-
retainedValue(previous, patch, defaults, "midpoint", typeChanged), type, definition.domain
|
|
173
|
-
);
|
|
174
|
-
if (midpoint !== undefined) definition.midpoint = midpoint;
|
|
175
|
-
|
|
176
|
-
if (type === "band" || (type === "ordinal" && allowOrdinalBandParameters)) {
|
|
177
|
-
validateBandParameters(definition, previous, patch, defaults, typeChanged);
|
|
178
|
-
} else if (type === "point") {
|
|
179
|
-
validatePointParameters(definition, previous, patch, defaults, typeChanged);
|
|
180
|
-
} else {
|
|
181
|
-
for (const property of ["paddingInner", "paddingOuter", "padding", "align"]) {
|
|
182
|
-
if (Object.hasOwn(patch, property)) {
|
|
183
|
-
validateScalePropertyForType(type, property);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const radialMapping = Object.hasOwn(patch, "radialMapping") ? patch.radialMapping : previous.radialMapping;
|
|
189
|
-
if (radialMapping !== undefined) {
|
|
190
|
-
definition.radialMapping = radialMapping;
|
|
191
|
-
validateMeasuredRadiusScale({ ...definition,
|
|
192
|
-
...(Object.hasOwn(patch, "unknown") || Object.hasOwn(previous, "unknown")
|
|
193
|
-
? { unknown: patch.unknown ?? previous.unknown } : {})
|
|
194
|
-
}, { allowAuto: true });
|
|
195
|
-
}
|
|
196
|
-
return definition;
|
|
197
|
-
}
|
|
1
|
+
import{validateMeasuredRadiusScale as I}from"./radial.js";import{validateContinuousColorInterpolation as M,validateSequentialMidpoint as x}from"./color.js";import{isTransformedScaleType as T}from"./mapping.js";import{normalizeTransformParameters as D,validateTransformedDomain as F}from"./transformed.js";import{isContinuousColorScaleType as N,validateScalePropertyForType as O}from"./types.js";const k=Object.freeze(["nice","zero","clamp","reverse"]),z=Object.freeze(["base","exponent","constant"]);function m(i,t,n,e,o){return Object.hasOwn(t,e)?t[e]:!o&&Object.hasOwn(i,e)?i[e]:n[e]}function q(i,t,n,e,o){const l=Object.hasOwn(n,"padding");if(l&&(Object.hasOwn(n,"paddingInner")||Object.hasOwn(n,"paddingOuter")))throw new Error("Scale padding cannot be combined with paddingInner or paddingOuter.");if(l&&(!Number.isFinite(n.padding)||n.padding<0||n.padding>=1))throw new RangeError("Scale padding must be from 0 (inclusive) to 1 (exclusive).");const d=l?{...n,paddingInner:n.padding,paddingOuter:n.padding}:n,g=m(t,d,e,"paddingInner",o)??0,w=m(t,d,e,"paddingOuter",o)??0,c=m(t,d,e,"align",o)??.5;if(!Number.isFinite(g)||g<0||g>=1)throw new RangeError("Scale paddingInner must be from 0 (inclusive) to 1 (exclusive).");if(!Number.isFinite(w)||w<0)throw new RangeError("Scale paddingOuter must be non-negative and finite.");if(!Number.isFinite(c)||c<0||c>1)throw new RangeError("Scale align must be between 0 and 1.");Object.assign(i,{paddingInner:g,paddingOuter:w,align:c})}function A(i,t,n,e,o){const l=m(t,n,e,"padding",o)??.5,d=m(t,n,e,"align",o)??.5;if(!Number.isFinite(l)||l<0)throw new RangeError("Scale padding must be non-negative and finite.");if(!Number.isFinite(d)||d<0||d>1)throw new RangeError("Scale align must be between 0 and 1.");Object.assign(i,{padding:l,align:d})}function V({type:i,color:t=!1,previous:n={},patch:e={},defaults:o={},retainCoreOnTypeChange:l=!1,retainCompatibleOnTypeChange:d=!1,allowOrdinalBandParameters:g=!1,validateDomain:w,validateRange:c}){const s=n.type!==void 0&&n.type!==i,R=Object.hasOwn(e,"domain")?e.domain:(!s||l)&&Object.hasOwn(n,"domain")?n.domain:o.domain??"auto",P=Object.hasOwn(e,"range")?e.range:(!s||l)&&Object.hasOwn(n,"range")?n.range:o.range??"auto",r={type:i,domain:w(i,R),range:c(i,P)},u=m(n,e,o,"emptyDomain",s);if(u!==void 0){if(!["preserve","require-explicit"].includes(u))throw new Error('Scale emptyDomain must be "preserve" or "require-explicit".');r.emptyDomain=u}for(const a of k){let f=m(n,e,o,a,s);if(f===void 0&&s&&d&&Object.hasOwn(n,a))try{O(i,a),f=n[a]}catch{f=void 0}if(f!==void 0){if(typeof f!="boolean")throw new TypeError(`Scale ${a} must be a boolean.`);O(i,a),r[a]=f}}const j=Object.fromEntries(z.flatMap(a=>{const f=m(n,e,o,a,s);return f===void 0?[]:[[a,f]]}));if(T(i)){const a=D(i,j);i==="log"&&(r.base=a.base),i==="pow"&&(r.exponent=a.exponent),i==="symlog"&&(r.constant=a.constant),r.domain!=="auto"&&F(i,r.domain,j)}else for(const a of Object.keys(j))O(i,a);let b=m(n,e,o,"interpolate",s);if(i==="sequential"||t&&N(i))b===void 0&&d&&(b=n.interpolate),r.interpolate=M(b??"rgb");else if(b!==void 0)throw new Error(`Scale type "${i}" does not support interpolate.`);const S=x(m(n,e,o,"midpoint",s),i,r.domain);if(S!==void 0&&(r.midpoint=S),i==="band"||i==="ordinal"&&g)q(r,n,e,o,s);else if(i==="point")A(r,n,e,o,s);else for(const a of["paddingInner","paddingOuter","padding","align"])Object.hasOwn(e,a)&&O(i,a);const E=Object.hasOwn(e,"radialMapping")?e.radialMapping:n.radialMapping;return E!==void 0&&(r.radialMapping=E,I({...r,...Object.hasOwn(e,"unknown")||Object.hasOwn(n,"unknown")?{unknown:e.unknown??n.unknown}:{}},{allowAuto:!0})),r}export{V as normalizeScaleDefinition};
|
|
@@ -1,195 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { validateGeneratedItemLimit } from "../../core/validation.js";
|
|
3
|
-
import { interpolateNumber } from "../numeric.js";
|
|
4
|
-
import { formatValue, validateValueFormat } from "../valueFormat.js";
|
|
5
|
-
import { resolveColorRange, validateColorRange } from "./appearance.js";
|
|
6
|
-
import { SCALE_ROLES, validateScaleTypeForRole } from "./types.js";
|
|
7
|
-
|
|
8
|
-
export const DISCRETIZED_COLOR_SCALE_TYPES = cloneAndFreeze([
|
|
9
|
-
"quantize",
|
|
10
|
-
"quantile",
|
|
11
|
-
"threshold"
|
|
12
|
-
]);
|
|
13
|
-
|
|
14
|
-
function finiteValues(values, label) {
|
|
15
|
-
if (!Array.isArray(values) || values.length === 0 || !values.every(Number.isFinite)) {
|
|
16
|
-
throw new TypeError(`${label} must contain finite numbers.`);
|
|
17
|
-
}
|
|
18
|
-
return values;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function ascending(values, label) {
|
|
22
|
-
finiteValues(values, label);
|
|
23
|
-
if (values.some((value, index) => index > 0 && value <= values[index - 1])) {
|
|
24
|
-
throw new RangeError(`${label} must be strictly increasing.`);
|
|
25
|
-
}
|
|
26
|
-
return values;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function nondecreasing(values, label) {
|
|
30
|
-
finiteValues(values, label);
|
|
31
|
-
if (values.some((value, index) => index > 0 && value < values[index - 1])) {
|
|
32
|
-
throw new RangeError(`${label} must be nondecreasing.`);
|
|
33
|
-
}
|
|
34
|
-
return values;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function quantile(sorted, probability) {
|
|
38
|
-
const position = (sorted.length - 1) * probability;
|
|
39
|
-
const lower = Math.floor(position);
|
|
40
|
-
const upper = Math.ceil(position);
|
|
41
|
-
return interpolateNumber(sorted[lower], sorted[upper], position - lower);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function validateDiscretizedColorDomain(type, domain) {
|
|
45
|
-
validateScaleTypeForRole(type, SCALE_ROLES.discretizedColor);
|
|
46
|
-
if (domain === "auto") {
|
|
47
|
-
if (type === "threshold") {
|
|
48
|
-
throw new Error("Threshold color scale requires an explicit domain.");
|
|
49
|
-
}
|
|
50
|
-
return domain;
|
|
51
|
-
}
|
|
52
|
-
if (!Array.isArray(domain)) {
|
|
53
|
-
throw new TypeError("Discretized color domain must be an array or auto.");
|
|
54
|
-
}
|
|
55
|
-
if (type === "quantize") {
|
|
56
|
-
if (domain.length !== 2 || !domain.every(Number.isFinite) || domain[0] >= domain[1]) {
|
|
57
|
-
throw new RangeError("Quantize color domain must be an increasing pair.");
|
|
58
|
-
}
|
|
59
|
-
} else if (type === "quantile") {
|
|
60
|
-
finiteValues(domain, "Quantile color domain");
|
|
61
|
-
} else {
|
|
62
|
-
ascending(domain, "Threshold color domain");
|
|
63
|
-
}
|
|
64
|
-
return cloneAndFreeze(domain);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function validateDiscretizedColorRange(range) {
|
|
68
|
-
if (Array.isArray(range)) {
|
|
69
|
-
validateGeneratedItemLimit(
|
|
70
|
-
range.length,
|
|
71
|
-
"Discretized color range length"
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
const validated = validateColorRange(range);
|
|
75
|
-
if (validated === "auto") return validated;
|
|
76
|
-
if (Array.isArray(validated) && validated.length < 2) {
|
|
77
|
-
throw new RangeError("Discretized color range requires at least two colors.");
|
|
78
|
-
}
|
|
79
|
-
return validated;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function resolveDiscretizedColorScale({ type, domain, range, values }) {
|
|
83
|
-
validateScaleTypeForRole(type, SCALE_ROLES.discretizedColor);
|
|
84
|
-
finiteValues(values, "Discretized color values");
|
|
85
|
-
const requestedDomain = validateDiscretizedColorDomain(type, domain);
|
|
86
|
-
const sample = [...values].sort((left, right) => left - right);
|
|
87
|
-
const validatedRange = validateDiscretizedColorRange(range);
|
|
88
|
-
const colorCount = type === "threshold"
|
|
89
|
-
? requestedDomain.length + 1
|
|
90
|
-
: Array.isArray(range) ? range.length : 5;
|
|
91
|
-
const colors = resolveColorRange(
|
|
92
|
-
validatedRange === "auto" ? { palette: "viridis" } : validatedRange,
|
|
93
|
-
colorCount
|
|
94
|
-
);
|
|
95
|
-
if (colors.length < 2) {
|
|
96
|
-
throw new RangeError("Discretized color range requires at least two colors.");
|
|
97
|
-
}
|
|
98
|
-
let resolvedDomain;
|
|
99
|
-
let thresholds;
|
|
100
|
-
if (type === "quantize") {
|
|
101
|
-
resolvedDomain = requestedDomain === "auto"
|
|
102
|
-
? [sample[0], sample.at(-1)]
|
|
103
|
-
: [...requestedDomain];
|
|
104
|
-
if (resolvedDomain[0] === resolvedDomain[1]) {
|
|
105
|
-
throw new RangeError("Quantize color scale requires a non-zero domain span.");
|
|
106
|
-
}
|
|
107
|
-
thresholds = Array.from(
|
|
108
|
-
{ length: colors.length - 1 },
|
|
109
|
-
(_, index) => interpolateNumber(
|
|
110
|
-
resolvedDomain[0],
|
|
111
|
-
resolvedDomain[1],
|
|
112
|
-
(index + 1) / colors.length
|
|
113
|
-
)
|
|
114
|
-
);
|
|
115
|
-
if (thresholds.some((value, index) =>
|
|
116
|
-
value <= (index === 0 ? resolvedDomain[0] : thresholds[index - 1]) ||
|
|
117
|
-
value >= resolvedDomain[1]
|
|
118
|
-
)) {
|
|
119
|
-
throw new RangeError(
|
|
120
|
-
"Quantize color range requests more classes than its numeric domain can represent."
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
} else if (type === "quantile") {
|
|
124
|
-
const source = requestedDomain === "auto"
|
|
125
|
-
? sample
|
|
126
|
-
: [...requestedDomain].sort((left, right) => left - right);
|
|
127
|
-
resolvedDomain = source;
|
|
128
|
-
thresholds = Array.from(
|
|
129
|
-
{ length: colors.length - 1 },
|
|
130
|
-
(_, index) => quantile(source, (index + 1) / colors.length)
|
|
131
|
-
);
|
|
132
|
-
} else {
|
|
133
|
-
resolvedDomain = [...requestedDomain];
|
|
134
|
-
thresholds = [...requestedDomain];
|
|
135
|
-
if (colors.length !== thresholds.length + 1) {
|
|
136
|
-
throw new RangeError(
|
|
137
|
-
"Threshold color range must contain exactly one more color than its domain."
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
return cloneAndFreeze({
|
|
142
|
-
type,
|
|
143
|
-
domain: resolvedDomain,
|
|
144
|
-
thresholds,
|
|
145
|
-
range: colors
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export function discretizedColorIndex(value, thresholds) {
|
|
150
|
-
if (!Number.isFinite(value)) {
|
|
151
|
-
throw new TypeError("Discretized color values must be finite numbers.");
|
|
152
|
-
}
|
|
153
|
-
let index = 0;
|
|
154
|
-
while (index < thresholds.length && value >= thresholds[index]) index += 1;
|
|
155
|
-
return index;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export function mapDiscretizedColors(values, scale) {
|
|
159
|
-
const hasUnknown = Object.hasOwn(scale, "unknown");
|
|
160
|
-
return cloneAndFreeze(values.map(value => {
|
|
161
|
-
if (!Number.isFinite(value) && hasUnknown) return scale.unknown;
|
|
162
|
-
return scale.range[discretizedColorIndex(value, scale.thresholds)];
|
|
163
|
-
}));
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export function formatDiscretizedIntervals(thresholds, format = "auto") {
|
|
167
|
-
nondecreasing(thresholds, "Discretized color thresholds");
|
|
168
|
-
const resolvedFormat = validateValueFormat(format, "Legend label format");
|
|
169
|
-
let resolution = Infinity;
|
|
170
|
-
for (let index = 1; index < thresholds.length; index += 1) {
|
|
171
|
-
const gap = thresholds[index] - thresholds[index - 1];
|
|
172
|
-
if (Number.isFinite(gap) && gap > 0) resolution = Math.min(resolution, gap);
|
|
173
|
-
}
|
|
174
|
-
let labels = resolvedFormat === "auto"
|
|
175
|
-
? thresholds.map(value => Number.isInteger(value) ? String(value) : value.toFixed(1))
|
|
176
|
-
: thresholds.map(value => formatValue(value, {
|
|
177
|
-
format: resolvedFormat,
|
|
178
|
-
valueType: "quantitative",
|
|
179
|
-
label: "Legend label format"
|
|
180
|
-
}));
|
|
181
|
-
if (resolvedFormat === "auto" && thresholds.some((value, index) => {
|
|
182
|
-
const rounded = Number(labels[index]);
|
|
183
|
-
return value !== 0 && rounded === 0 ||
|
|
184
|
-
index > 0 && value !== thresholds[index - 1] &&
|
|
185
|
-
labels[index] === labels[index - 1] ||
|
|
186
|
-
!Number.isInteger(value) && Math.abs(rounded - value) > resolution / 4;
|
|
187
|
-
})) labels = thresholds.map(String);
|
|
188
|
-
return cloneAndFreeze([
|
|
189
|
-
`< ${labels[0]}`,
|
|
190
|
-
...labels.slice(0, -1).map((value, index) =>
|
|
191
|
-
`${value}–${labels[index + 1]}`
|
|
192
|
-
),
|
|
193
|
-
`≥ ${labels.at(-1)}`
|
|
194
|
-
]);
|
|
195
|
-
}
|
|
1
|
+
import{cloneAndFreeze as c}from"../../core/immutable.js";import{validateGeneratedItemLimit as g}from"../../core/validation.js";import{interpolateNumber as h,quantileSorted as z}from"../numeric.js";import{formatValue as w,validateValueFormat as p}from"../valueFormat.js";import{resolveColorRange as D,validateColorRange as b}from"./appearance.js";import{SCALE_ROLES as m,validateScaleTypeForRole as f}from"./types.js";import{validatePair as E,validateFiniteScaleArray as u,validateIncreasingScaleArray as q}from"./validation.js";const Q=c(["quantize","quantile","threshold"]);function C(r,e){if(u(r,e),r.some((i,o)=>o>0&&i<r[o-1]))throw new RangeError(`${e} must be nondecreasing.`);return r}function R(r,e){return f(r,m.discretizedColor),v(r,e,"color")}function v(r,e,i){if(e==="auto"){if(r==="threshold")throw new Error(`Threshold ${i} scale requires an explicit domain.`);return e}if(i==="color"&&!Array.isArray(e))throw new TypeError("Discretized color domain must be an array or auto.");if(r==="quantize"){if(i==="size"){if(E(e,"Quantize size domain"),e[0]>=e[1])throw new RangeError("Quantize size domain must be a strictly increasing pair.")}else if(e.length!==2||!e.every(Number.isFinite)||e[0]>=e[1])throw new RangeError("Quantize color domain must be an increasing pair.")}else r==="quantile"?u(e,`Quantile ${i} domain`):q(e,`Threshold ${i} domain`);return c(e)}function A(r){Array.isArray(r)&&g(r.length,"Discretized color range length");const e=b(r);if(e==="auto")return e;if(Array.isArray(e)&&e.length<2)throw new RangeError("Discretized color range requires at least two colors.");return e}function y({type:r,domain:e,values:i,count:o,kind:a}){let t=e==="auto"?[...i].sort((s,l)=>s-l):[...e],n;if(r==="quantize"){if(e==="auto"){if(t.length===0)throw new Error("Cannot infer an automatic quantize size domain from no values.");t=[t[0],t.at(-1)]}if(t[0]===t[1])throw new RangeError(`Quantize ${a} scale requires a non-zero domain span.`);if(n=Array.from({length:o-1},(s,l)=>h(t[0],t[1],(l+1)/o)),n.some((s,l)=>s<=(l===0?t[0]:n[l-1])||s>=t[1]))throw new RangeError(a==="size"?"Quantize size range requests more buckets than its domain can represent.":"Quantize color range requests more classes than its numeric domain can represent.")}else if(r==="quantile"){if(t.length===0)throw new Error("Cannot infer automatic quantile size thresholds from no values.");t.sort((s,l)=>s-l),n=Array.from({length:o-1},(s,l)=>z(t,(l+1)/o))}else if(n=[...t],o!==n.length+1)throw new RangeError(`Threshold ${a} range must contain exactly one more ${a==="size"?"area":"color"} than its domain.`);return{domain:t,thresholds:n}}function _({type:r,domain:e,range:i,values:o}){f(r,m.discretizedColor),u(o,"Discretized color values");const a=R(r,e),t=A(i),n=r==="threshold"?a.length+1:Array.isArray(i)?i.length:5,s=D(t==="auto"?{palette:"viridis"}:t,n);if(s.length<2)throw new RangeError("Discretized color range requires at least two colors.");const{domain:l,thresholds:d}=y({type:r,domain:a,values:o,count:s.length,kind:"color"});return c({type:r,domain:l,thresholds:d,range:s})}function S(r,e,i="Discretized color"){if(!Number.isFinite(r))throw new TypeError(`${i} values must be finite numbers.`);let o=0;for(;o<e.length&&r>=e[o];)o+=1;return o}function O(r,e){const i=Object.hasOwn(e,"unknown");return c(r.map(o=>!Number.isFinite(o)&&i?e.unknown:e.range[S(o,e.thresholds)]))}function V(r,e="auto"){C(r,"Discretized color thresholds");const i=p(e,"Legend label format");let o=1/0;for(let t=1;t<r.length;t+=1){const n=r[t]-r[t-1];Number.isFinite(n)&&n>0&&(o=Math.min(o,n))}let a=i==="auto"?r.map(t=>Number.isInteger(t)?String(t):t.toFixed(1)):r.map(t=>w(t,{format:i,valueType:"quantitative",label:"Legend label format"}));return i==="auto"&&r.some((t,n)=>{const s=Number(a[n]);return t!==0&&s===0||n>0&&t!==r[n-1]&&a[n]===a[n-1]||!Number.isInteger(t)&&Math.abs(s-t)>o/4})&&(a=r.map(String)),c([`< ${a[0]}`,...a.slice(0,-1).map((t,n)=>`${t}\u2013${a[n+1]}`),`\u2265 ${a.at(-1)}`])}export{Q as DISCRETIZED_COLOR_SCALE_TYPES,S as discretizedColorIndex,V as formatDiscretizedIntervals,O as mapDiscretizedColors,_ as resolveDiscretizedColorScale,y as resolveDiscretizedDomain,R as validateDiscretizedColorDomain,A as validateDiscretizedColorRange,v as validateDiscretizedDomain};
|