ggaction 0.0.2 → 0.0.3
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 +28 -0
- package/README.md +12 -1
- package/package.json +6 -1
- package/src/actions/boxPlots/components.js +3 -3
- package/src/actions/boxPlots/edit.js +277 -0
- package/src/actions/boxPlots/index.js +2 -0
- package/src/actions/boxPlots/materialize.js +12 -1
- package/src/actions/boxPlots/options.js +25 -14
- package/src/actions/canvas/actions.js +21 -17
- package/src/actions/composition/actions.js +247 -0
- package/src/actions/composition/index.js +1 -0
- package/src/actions/coordinates/actions.js +2 -5
- package/src/actions/data/density.js +7 -1
- package/src/actions/data/filter.js +3 -1
- package/src/actions/encodings/appearance.js +11 -0
- package/src/actions/encodings/barWidth.js +5 -3
- package/src/actions/encodings/color.js +120 -25
- package/src/actions/encodings/index.js +2 -0
- package/src/actions/encodings/offset.js +90 -72
- package/src/actions/encodings/position/apply.js +66 -0
- package/src/actions/encodings/position/policies/arc.js +26 -0
- package/src/actions/encodings/position/policies/bar.js +9 -5
- package/src/actions/encodings/position/policies/index.js +5 -1
- package/src/actions/encodings/position/policies/line.js +20 -3
- package/src/actions/encodings/position/resolve.js +57 -8
- package/src/actions/encodings/position.js +44 -90
- package/src/actions/encodings/ranged.js +28 -6
- package/src/actions/encodings/shared.js +17 -21
- package/src/actions/encodings/text.js +73 -0
- package/src/actions/errorBands/create.js +37 -29
- package/src/actions/errorBands/edit.js +206 -0
- package/src/actions/errorBands/index.js +9 -0
- package/src/actions/errorBands/options.js +39 -0
- package/src/actions/errorBars/create.js +50 -43
- package/src/actions/errorBars/edit.js +130 -0
- package/src/actions/errorBars/index.js +3 -0
- package/src/actions/errorBars/options.js +52 -0
- package/src/actions/facets/actions.js +162 -0
- package/src/actions/facets/derive.js +200 -0
- package/src/actions/facets/guides.js +16 -0
- package/src/actions/facets/index.js +1 -0
- package/src/actions/facets/replay.js +69 -0
- package/src/actions/guides/applicability.js +113 -0
- package/src/actions/guides/axes/axes.js +70 -16
- package/src/actions/guides/axes/edit.js +126 -0
- package/src/actions/guides/axes/index.js +12 -0
- package/src/actions/guides/axes/labels.js +21 -18
- package/src/actions/guides/axes/remove.js +60 -0
- package/src/actions/guides/axes/tickGroups.js +7 -5
- package/src/actions/guides/axes/ticks.js +9 -4
- package/src/actions/guides/axes/titles.js +7 -5
- package/src/actions/guides/grids/grid.js +144 -15
- package/src/actions/guides/grids/resolve.js +5 -13
- package/src/actions/guides/guides.js +17 -75
- package/src/actions/guides/index.js +6 -0
- package/src/actions/guides/legends/categorical/actions.js +48 -9
- package/src/actions/guides/legends/categorical/components.js +16 -16
- package/src/actions/guides/legends/categorical/index.js +14 -14
- package/src/actions/guides/legends/categorical/layout.js +3 -1
- package/src/actions/guides/legends/categorical/options.js +2 -5
- package/src/actions/guides/legends/categorical/resolve.js +2 -2
- package/src/actions/guides/legends/categorical/symbols.js +14 -14
- package/src/actions/guides/legends/continuous/common.js +7 -7
- package/src/actions/guides/legends/continuous/interval.js +5 -5
- package/src/actions/guides/legends/edit.js +2 -6
- package/src/actions/guides/legends/focused.js +63 -0
- package/src/actions/guides/legends/index.js +4 -0
- package/src/actions/guides/legends/remove.js +64 -0
- package/src/actions/guides/legends/size.js +12 -14
- package/src/actions/guides/polar/axes/facade.js +219 -0
- package/src/actions/guides/polar/axes/labels.js +188 -0
- package/src/actions/guides/polar/axes/lines.js +113 -0
- package/src/actions/guides/polar/axes/shared.js +112 -0
- package/src/actions/guides/polar/axes/ticks.js +164 -0
- package/src/actions/guides/polar/axes/titles.js +165 -0
- package/src/actions/guides/polar/axes.js +55 -0
- package/src/actions/guides/polar/grids.js +252 -0
- package/src/actions/guides/polar/index.js +2 -0
- package/src/actions/guides/polar/resolve.js +269 -0
- package/src/actions/index.js +4 -0
- package/src/actions/marks/arc/actions.js +239 -0
- package/src/actions/marks/arc/index.js +1 -0
- package/src/actions/marks/{area.js → area/actions.js} +51 -38
- package/src/actions/marks/area/index.js +4 -0
- package/src/actions/marks/bar/create.js +26 -5
- package/src/actions/marks/bar/materialize.js +25 -31
- package/src/actions/marks/index.js +12 -4
- package/src/actions/marks/lifecycle.js +27 -0
- package/src/actions/marks/line/actions.js +373 -0
- package/src/actions/marks/line/index.js +1 -0
- package/src/actions/marks/{point.js → point/actions.js} +67 -108
- package/src/actions/marks/point/index.js +1 -0
- package/src/actions/marks/rect/actions.js +165 -0
- package/src/actions/marks/rect/index.js +1 -0
- package/src/actions/marks/remove.js +214 -0
- package/src/actions/marks/{rule.js → rule/actions.js} +34 -28
- package/src/actions/marks/rule/index.js +1 -0
- package/src/actions/marks/shared.js +156 -25
- package/src/actions/marks/text/actions.js +192 -0
- package/src/actions/marks/text/index.js +1 -0
- package/src/actions/primitives/createGraphics.js +13 -6
- package/src/actions/primitives/editGraphics.js +10 -3
- package/src/actions/primitives/semantic.js +26 -3
- package/src/actions/primitives/semanticValue.js +25 -3
- package/src/actions/regression/components.js +1 -1
- package/src/actions/regression/create.js +18 -1
- package/src/actions/regression/edit.js +247 -0
- package/src/actions/regression/index.js +3 -0
- package/src/actions/regression/resolve.js +3 -1
- package/src/actions/scales/consumers.js +15 -6
- package/src/actions/scales/definitions.js +13 -4
- package/src/actions/scales/edit.js +42 -19
- package/src/actions/scales/materialize.js +57 -408
- package/src/actions/selection/actions.js +38 -24
- package/src/actions/selection/index.js +2 -0
- package/src/actions/titles/actions.js +63 -2
- package/src/actions/titles/index.js +2 -0
- package/src/actions/titles/resolve.js +12 -17
- package/src/composition.js +10 -0
- package/src/core/ChartProgram.js +200 -2
- package/src/core/action.js +10 -0
- package/src/core/validation.js +16 -0
- package/src/core/vocabulary.js +154 -4
- package/src/grammar/arcs.js +154 -0
- package/src/grammar/bars/aggregate.js +2 -2
- package/src/grammar/bars/geometry.js +3 -3
- package/src/grammar/bars/policy.js +7 -1
- package/src/grammar/coordinates.js +3 -7
- package/src/grammar/density.js +20 -1
- package/src/grammar/facets/dependencies.js +185 -0
- package/src/grammar/facets/guides.js +257 -0
- package/src/grammar/facets/scales.js +254 -0
- package/src/grammar/facets.js +122 -0
- package/src/grammar/lineSeries.js +111 -3
- package/src/grammar/polar.js +102 -0
- package/src/grammar/polarGuides.js +243 -0
- package/src/grammar/polarLineCommands.js +43 -0
- package/src/grammar/polarPaths.js +161 -0
- package/src/grammar/positionCompatibility.js +18 -2
- package/src/grammar/rects.js +26 -0
- package/src/grammar/scales/continuous.js +6 -1
- package/src/grammar/scales/fields.js +7 -0
- package/src/grammar/scales/ordinal.js +5 -2
- package/src/grammar/scales/policies.js +1 -1
- package/src/grammar/schemas/graphic.js +1 -1
- package/src/grammar/schemas/graphicBounds.js +64 -9
- package/src/grammar/schemas/graphicTree.js +44 -10
- package/src/grammar/schemas/semanticPath.js +31 -9
- package/src/grammar/seriesLayout.js +13 -2
- package/src/grammar/text.js +71 -0
- package/src/grammar/ticks.js +50 -13
- package/src/index.js +1 -0
- package/src/layout/composition.js +310 -0
- package/src/layout/facets.js +131 -0
- package/src/layout/title.js +6 -0
- package/src/materialization/bars/aggregate.js +5 -2
- package/src/materialization/bars/grouped.js +75 -37
- package/src/materialization/composition.js +152 -0
- package/src/materialization/compositionSnapshot.js +114 -0
- package/src/materialization/dependencies.js +71 -16
- package/src/materialization/encodings.js +14 -28
- package/src/materialization/facetGuides.js +426 -0
- package/src/materialization/facets.js +214 -0
- package/src/materialization/graphicHierarchy.js +15 -5
- package/src/materialization/guides/resources.js +46 -0
- package/src/materialization/marks.js +220 -14
- package/src/materialization/planner.js +105 -12
- package/src/materialization/rect.js +138 -0
- package/src/materialization/rectConfig.js +38 -0
- package/src/materialization/rowEncoding.js +33 -0
- package/src/materialization/scales/map.js +40 -0
- package/src/materialization/scales/policies/arc.js +37 -0
- package/src/materialization/scales/policies/bar.js +132 -0
- package/src/materialization/scales/policies/series.js +76 -0
- package/src/materialization/scales/resolve.js +326 -0
- package/src/materialization/selection/items/arc.js +29 -0
- package/src/materialization/selection/items/bar.js +255 -0
- package/src/materialization/selection/items/common.js +131 -0
- package/src/materialization/selection/items/index.js +6 -0
- package/src/materialization/selection/items/path.js +59 -0
- package/src/materialization/selection/items/point.js +55 -0
- package/src/materialization/selection/items/rect.js +23 -0
- package/src/materialization/selection/items/rule.js +25 -0
- package/src/materialization/selection/policies/arc.js +10 -0
- package/src/materialization/selection/policies/area.js +1 -1
- package/src/materialization/selection/policies/bar.js +1 -1
- package/src/materialization/selection/policies/index.js +5 -1
- package/src/materialization/selection/policies/line.js +1 -1
- package/src/materialization/selection/policies/point.js +1 -1
- package/src/materialization/selection/policies/rect.js +10 -0
- package/src/materialization/selection/policies/rule.js +1 -1
- package/src/materialization/selection/styles.js +24 -16
- package/src/materialization/text.js +156 -0
- package/src/renderers/canvas/index.js +68 -22
- package/types/extension.d.ts +1 -0
- package/types/index.d.ts +56 -1
- package/types/program.d.ts +664 -27
- package/src/actions/marks/line.js +0 -248
- package/src/materialization/selection/items.js +0 -503
|
@@ -1,103 +1,48 @@
|
|
|
1
1
|
import { action } from "../../core/action.js";
|
|
2
2
|
import { validateUserId } from "../../core/identifiers.js";
|
|
3
|
+
import { normalizePositionScaleChannel } from "../../core/vocabulary.js";
|
|
3
4
|
import { validateKeys } from "../../core/validation.js";
|
|
4
|
-
import { resolveHistogramBins } from "../../grammar/histogram.js";
|
|
5
5
|
import { resolveGraphicBounds } from "../../layout/canvas.js";
|
|
6
|
-
import { normalizeOffsetPadding } from "../../grammar/bars/geometry.js";
|
|
7
6
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from "../../grammar/bars/policy.js";
|
|
7
|
+
applyMaterializationPlan,
|
|
8
|
+
planScaleGuideRematerialization
|
|
9
|
+
} from "../../materialization/dependencies.js";
|
|
12
10
|
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
resolveOrdinalOffsetScale,
|
|
22
|
-
resolveOrdinalPositionScale,
|
|
23
|
-
resolveDiscretePositionScale,
|
|
24
|
-
resolveScaleRange,
|
|
25
|
-
resolveOpacityRange,
|
|
26
|
-
resolveSequentialColorStops,
|
|
27
|
-
resolveShapeRange,
|
|
28
|
-
resolveSizeRange,
|
|
29
|
-
resolveStrokeDashRange,
|
|
30
|
-
validateLinearScaleType,
|
|
31
|
-
validateOrdinalScaleType,
|
|
32
|
-
validateTimeScaleType,
|
|
33
|
-
isDiscretePositionScaleType,
|
|
34
|
-
isDiscretizedColorScaleType,
|
|
35
|
-
isContinuousColorScaleType,
|
|
36
|
-
isOrdinalScaleType,
|
|
37
|
-
isTransformedScaleType,
|
|
38
|
-
normalizeTransformParameters,
|
|
39
|
-
resolveTransformedDomain,
|
|
40
|
-
SCALE_ROLES,
|
|
41
|
-
validateScaleTypeForRole
|
|
42
|
-
} from "../../grammar/scales.js";
|
|
11
|
+
canDeferScaleConsumerApplication,
|
|
12
|
+
getMarkRematerializationStep,
|
|
13
|
+
getScaleConsumerMaterializationMode
|
|
14
|
+
} from "../../materialization/marks.js";
|
|
15
|
+
import { mapScaleConsumerValues } from
|
|
16
|
+
"../../materialization/scales/map.js";
|
|
17
|
+
import { resolveScaleMaterialization } from
|
|
18
|
+
"../../materialization/scales/resolve.js";
|
|
43
19
|
import {
|
|
44
20
|
findScale,
|
|
45
21
|
findScaleConsumers,
|
|
46
22
|
resolveConsumerValues,
|
|
47
23
|
resolveSeriesLayoutScaleValues
|
|
48
24
|
} from "./consumers.js";
|
|
49
|
-
import {
|
|
50
|
-
applyMaterializationPlan,
|
|
51
|
-
planScaleGuideRematerialization
|
|
52
|
-
} from "../../materialization/dependencies.js";
|
|
53
25
|
|
|
54
|
-
const OPTIONS = Object.freeze(["id", "guides"]);
|
|
26
|
+
const OPTIONS = Object.freeze(["id", "guides", "marks"]);
|
|
55
27
|
|
|
56
|
-
function
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
channels?.category === consumer.channel &&
|
|
61
|
-
consumer.encoding.fieldType === "temporal";
|
|
62
|
-
});
|
|
63
|
-
if (temporalBars.length === 0) return undefined;
|
|
64
|
-
if (temporalBars.length !== consumers.length) {
|
|
65
|
-
throw new Error("A temporal bar position scale cannot share a non-bar layout policy.");
|
|
66
|
-
}
|
|
67
|
-
const ordered = [...new Set(values)].sort((left, right) => left - right);
|
|
68
|
-
if (ordered.length < 2) {
|
|
69
|
-
throw new Error("Temporal bar position requires at least two distinct values.");
|
|
28
|
+
function validateOptions(args) {
|
|
29
|
+
validateKeys(args, OPTIONS, "rematerializeScale");
|
|
30
|
+
if (args.guides !== undefined && typeof args.guides !== "boolean") {
|
|
31
|
+
throw new TypeError("rematerializeScale guides must be a boolean.");
|
|
70
32
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
);
|
|
74
|
-
const domainSpan = Math.abs(domain[1] - domain[0]);
|
|
75
|
-
if (!(minimumGap > 0) || !(domainSpan > 0)) {
|
|
76
|
-
throw new Error("Temporal bar position requires an increasing time domain.");
|
|
33
|
+
if (args.marks !== undefined && typeof args.marks !== "boolean") {
|
|
34
|
+
throw new TypeError("rematerializeScale marks must be a boolean.");
|
|
77
35
|
}
|
|
78
|
-
const direction = Math.sign(range[1] - range[0]) || 1;
|
|
79
|
-
const estimatedBandwidth = Math.abs(range[1] - range[0]) * minimumGap /
|
|
80
|
-
(domainSpan + minimumGap);
|
|
81
|
-
const resolvedRange = [
|
|
82
|
-
range[0] + direction * estimatedBandwidth / 2,
|
|
83
|
-
range[1] - direction * estimatedBandwidth / 2
|
|
84
|
-
];
|
|
85
|
-
const positions = ordered.map(value =>
|
|
86
|
-
resolvedRange[0] +
|
|
87
|
-
(value - domain[0]) / (domain[1] - domain[0]) *
|
|
88
|
-
(resolvedRange[1] - resolvedRange[0])
|
|
89
|
-
);
|
|
90
|
-
const bandwidth = Math.min(
|
|
91
|
-
...positions.slice(1).map((value, index) => Math.abs(value - positions[index]))
|
|
92
|
-
);
|
|
93
|
-
return {
|
|
94
|
-
bandwidth,
|
|
95
|
-
range: resolvedRange
|
|
96
|
-
};
|
|
97
36
|
}
|
|
98
37
|
|
|
99
|
-
function
|
|
100
|
-
|
|
38
|
+
function resolveScaleChannel(id, consumers) {
|
|
39
|
+
const channels = new Set(
|
|
40
|
+
consumers.map(consumer => normalizePositionScaleChannel(consumer.channel))
|
|
41
|
+
);
|
|
42
|
+
if (channels.size !== 1) {
|
|
43
|
+
throw new Error(`Scale "${id}" cannot be shared across channels.`);
|
|
44
|
+
}
|
|
45
|
+
return normalizePositionScaleChannel(consumers[0].channel);
|
|
101
46
|
}
|
|
102
47
|
|
|
103
48
|
export const rematerializeScale = action(
|
|
@@ -107,352 +52,56 @@ export const rematerializeScale = action(
|
|
|
107
52
|
},
|
|
108
53
|
function (args = {}) {
|
|
109
54
|
validateOptions(args);
|
|
110
|
-
if (args.guides !== undefined && typeof args.guides !== "boolean") {
|
|
111
|
-
throw new TypeError("rematerializeScale guides must be a boolean.");
|
|
112
|
-
}
|
|
113
55
|
const id = validateUserId(args.id, "Scale id");
|
|
114
56
|
const scale = findScale(this, id);
|
|
115
57
|
const consumers = findScaleConsumers(this, id);
|
|
116
|
-
|
|
117
58
|
if (consumers.length === 0) {
|
|
118
59
|
throw new Error(`Scale "${id}" has no supported consumers.`);
|
|
119
60
|
}
|
|
120
|
-
const
|
|
121
|
-
consumers.map(consumer =>
|
|
122
|
-
consumer.channel === "x2"
|
|
123
|
-
? "x"
|
|
124
|
-
: consumer.channel === "y2" ? "y" : consumer.channel
|
|
125
|
-
)
|
|
126
|
-
);
|
|
127
|
-
if (channels.size !== 1) {
|
|
128
|
-
throw new Error(`Scale "${id}" cannot be shared across channels.`);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const channel = consumers[0].channel === "x2"
|
|
132
|
-
? "x"
|
|
133
|
-
: consumers[0].channel === "y2" ? "y" : consumers[0].channel;
|
|
61
|
+
const channel = resolveScaleChannel(id, consumers);
|
|
134
62
|
const valuesByConsumer = consumers.map(consumer => ({
|
|
135
63
|
consumer,
|
|
136
|
-
values: resolveConsumerValues(this, consumer)
|
|
64
|
+
values: resolveConsumerValues(this, consumer),
|
|
65
|
+
seriesLayout: resolveSeriesLayoutScaleValues(this, consumer)
|
|
137
66
|
}));
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
["color", "strokeDash", "shape"].includes(channel) &&
|
|
147
|
-
isOrdinalScaleType(scale.type);
|
|
148
|
-
const isOrdinalOffset = channel === "xOffset";
|
|
149
|
-
const isOrdinalPosition =
|
|
150
|
-
!isOrdinalAppearance && !isOrdinalOffset && isOrdinalScaleType(scale.type);
|
|
151
|
-
const isDiscretePosition =
|
|
152
|
-
!isOrdinalAppearance && !isOrdinalOffset &&
|
|
153
|
-
isDiscretePositionScaleType(scale.type);
|
|
154
|
-
const binnedBars = valuesByConsumer.filter(
|
|
155
|
-
({ consumer }) =>
|
|
156
|
-
consumer.layer.mark?.type === "bar" &&
|
|
157
|
-
consumer.encoding.bin !== undefined
|
|
158
|
-
);
|
|
159
|
-
const seriesLayouts = valuesByConsumer.map(({ consumer }) =>
|
|
160
|
-
resolveSeriesLayoutScaleValues(this, consumer)
|
|
161
|
-
);
|
|
162
|
-
let domain;
|
|
163
|
-
|
|
164
|
-
let discretizedScale;
|
|
165
|
-
if (isDiscretizedColor) {
|
|
166
|
-
discretizedScale = resolveDiscretizedColorScale({
|
|
167
|
-
type: scale.type,
|
|
168
|
-
domain: scale.domain,
|
|
169
|
-
range: scale.range,
|
|
170
|
-
values: allValues
|
|
171
|
-
});
|
|
172
|
-
domain = discretizedScale.domain;
|
|
173
|
-
} else if (binnedBars.length > 0) {
|
|
174
|
-
if (channel !== "x" || binnedBars.length !== valuesByConsumer.length) {
|
|
175
|
-
throw new Error(
|
|
176
|
-
`Binned scale "${id}" cannot be shared with an unbinned consumer.`
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
const binDefinitions = new Set(
|
|
180
|
-
binnedBars.map(({ consumer }) => JSON.stringify(consumer.encoding.bin))
|
|
181
|
-
);
|
|
182
|
-
if (binDefinitions.size !== 1) {
|
|
183
|
-
throw new Error(
|
|
184
|
-
`Binned scale "${id}" requires one shared bin definition.`
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
domain = resolveHistogramBins({
|
|
188
|
-
values: allValues,
|
|
189
|
-
bin: binnedBars[0].consumer.encoding.bin,
|
|
190
|
-
domain: scale.domain,
|
|
191
|
-
nice: scale.nice ?? true,
|
|
192
|
-
zero: scale.zero ?? false
|
|
193
|
-
}).domain;
|
|
194
|
-
} else if (seriesLayouts.some(Boolean)) {
|
|
195
|
-
const activeLayouts = seriesLayouts.filter(Boolean);
|
|
196
|
-
const layouts = new Set(activeLayouts.map(item => item.layout));
|
|
197
|
-
if (layouts.size !== 1) {
|
|
198
|
-
throw new Error(`Series layout scale "${id}" requires one layout policy.`);
|
|
199
|
-
}
|
|
200
|
-
const layoutConsumers = valuesByConsumer.filter(
|
|
201
|
-
(_, index) => seriesLayouts[index] !== undefined
|
|
202
|
-
);
|
|
203
|
-
const directConsumers = valuesByConsumer.filter(
|
|
204
|
-
(_, index) => seriesLayouts[index] === undefined
|
|
205
|
-
);
|
|
206
|
-
const compatibleDirect = directConsumers.every(({ consumer }) =>
|
|
207
|
-
layoutConsumers.every(({ consumer: layoutConsumer }) => {
|
|
208
|
-
const aggregate = layoutConsumer.encoding.aggregate;
|
|
209
|
-
return aggregate !== "count" &&
|
|
210
|
-
consumer.encoding.fieldType === "quantitative" &&
|
|
211
|
-
consumer.encoding.field === layoutConsumer.encoding.field;
|
|
212
|
-
})
|
|
213
|
-
);
|
|
214
|
-
if (!compatibleDirect) {
|
|
215
|
-
throw new Error(
|
|
216
|
-
`Series layout scale "${id}" cannot be shared with another policy.`
|
|
217
|
-
);
|
|
218
|
-
}
|
|
219
|
-
const layout = activeLayouts[0].layout;
|
|
220
|
-
const values = [
|
|
221
|
-
...activeLayouts.flatMap(item => item.values),
|
|
222
|
-
...directConsumers.flatMap(item => item.values)
|
|
223
|
-
];
|
|
224
|
-
domain = resolveContinuousDomain({
|
|
225
|
-
domain: scale.domain,
|
|
226
|
-
values,
|
|
227
|
-
type: scale.type,
|
|
228
|
-
nice: layout === "fill" && scale.domain === "auto"
|
|
229
|
-
? false
|
|
230
|
-
: scale.nice,
|
|
231
|
-
zero: layout === "fill" && scale.domain === "auto"
|
|
232
|
-
? false
|
|
233
|
-
: scale.zero
|
|
234
|
-
});
|
|
235
|
-
} else {
|
|
236
|
-
domain = isOrdinalAppearance || isOrdinalOffset || isOrdinalPosition ||
|
|
237
|
-
isDiscretePosition
|
|
238
|
-
? resolveOrdinalDomain(scale.domain, allValues)
|
|
239
|
-
: isTransformedScaleType(scale.type)
|
|
240
|
-
? resolveTransformedDomain({
|
|
241
|
-
type: scale.type,
|
|
242
|
-
domain: scale.domain,
|
|
243
|
-
values: allValues,
|
|
244
|
-
nice: scale.nice ?? false,
|
|
245
|
-
zero: scale.zero ?? false,
|
|
246
|
-
...(scale.base === undefined ? {} : { base: scale.base }),
|
|
247
|
-
...(scale.exponent === undefined ? {} : { exponent: scale.exponent }),
|
|
248
|
-
...(scale.constant === undefined ? {} : { constant: scale.constant })
|
|
249
|
-
})
|
|
250
|
-
: resolveContinuousDomain({
|
|
251
|
-
domain: scale.domain,
|
|
252
|
-
values: allValues,
|
|
253
|
-
type: scale.type,
|
|
254
|
-
nice: scale.nice,
|
|
255
|
-
zero: scale.zero
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
let range;
|
|
260
|
-
if (channel === "color") {
|
|
261
|
-
range = isDiscretizedColor
|
|
262
|
-
? discretizedScale.range
|
|
263
|
-
: isSequentialColor
|
|
264
|
-
? resolveSequentialColorStops(scale.range)
|
|
265
|
-
: resolveColorRange(scale.range, domain.length);
|
|
266
|
-
}
|
|
267
|
-
else if (channel === "strokeDash") range = resolveStrokeDashRange(scale.range);
|
|
268
|
-
else if (channel === "shape") range = resolveShapeRange(scale.range);
|
|
269
|
-
else if (channel === "size") range = resolveSizeRange(scale.range);
|
|
270
|
-
else if (channel === "opacity") range = resolveOpacityRange(scale.range);
|
|
271
|
-
else if (isOrdinalOffset) range = undefined;
|
|
272
|
-
else {
|
|
273
|
-
range = resolveScaleRange(
|
|
274
|
-
scale.range,
|
|
275
|
-
channel,
|
|
276
|
-
resolveGraphicBounds(this)
|
|
277
|
-
);
|
|
278
|
-
}
|
|
279
|
-
if (channel === "shape" && domain.length > range.length) {
|
|
280
|
-
throw new Error(
|
|
281
|
-
`Shape scale "${id}" requires at least one distinct shape per domain value.`
|
|
282
|
-
);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
let resolvedScale = isDiscretizedColor
|
|
286
|
-
? discretizedScale
|
|
287
|
-
: isOrdinalOffset
|
|
288
|
-
? resolveOrdinalOffsetScale({
|
|
289
|
-
domain: scale.domain,
|
|
290
|
-
values: allValues,
|
|
291
|
-
range: scale.range,
|
|
292
|
-
parentBandwidth: (() => {
|
|
293
|
-
const bandwidths = consumers.map(consumer => {
|
|
294
|
-
if (consumer.layer.encoding?.x?.bin !== undefined) return 1;
|
|
295
|
-
const xScaleId = consumer.layer.encoding?.x?.scale;
|
|
296
|
-
return this.resolvedScales[xScaleId]?.bandwidth;
|
|
297
|
-
});
|
|
298
|
-
if (
|
|
299
|
-
bandwidths.some(value => !Number.isFinite(value)) ||
|
|
300
|
-
new Set(bandwidths).size !== 1
|
|
301
|
-
) {
|
|
302
|
-
throw new Error(
|
|
303
|
-
`xOffset scale "${id}" requires one shared resolved x bandwidth.`
|
|
304
|
-
);
|
|
305
|
-
}
|
|
306
|
-
return bandwidths[0];
|
|
307
|
-
})(),
|
|
308
|
-
...(() => {
|
|
309
|
-
const paddings = consumers.map(consumer => normalizeOffsetPadding(
|
|
310
|
-
this.markConfigs[consumer.layer.id]?.xOffset
|
|
311
|
-
));
|
|
312
|
-
const signatures = new Set(
|
|
313
|
-
paddings.map(padding => JSON.stringify(padding))
|
|
314
|
-
);
|
|
315
|
-
if (signatures.size !== 1) {
|
|
316
|
-
throw new Error(
|
|
317
|
-
`xOffset scale "${id}" requires one shared padding policy.`
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
return paddings[0];
|
|
321
|
-
})()
|
|
322
|
-
})
|
|
323
|
-
: isDiscretePosition
|
|
324
|
-
? resolveDiscretePositionScale({
|
|
325
|
-
type: scale.type,
|
|
326
|
-
domain: scale.domain,
|
|
327
|
-
values: allValues,
|
|
328
|
-
range: scale.range,
|
|
329
|
-
channel,
|
|
330
|
-
bounds: resolveGraphicBounds(this),
|
|
331
|
-
...(scale.type === "band"
|
|
332
|
-
? {
|
|
333
|
-
paddingInner: scale.paddingInner,
|
|
334
|
-
paddingOuter: scale.paddingOuter
|
|
335
|
-
}
|
|
336
|
-
: { padding: scale.padding }),
|
|
337
|
-
align: scale.align,
|
|
338
|
-
unknown: scale.unknown
|
|
339
|
-
})
|
|
340
|
-
: isOrdinalPosition
|
|
341
|
-
? resolveOrdinalPositionScale({
|
|
342
|
-
domain: scale.domain,
|
|
343
|
-
values: allValues,
|
|
344
|
-
range: scale.range,
|
|
345
|
-
channel,
|
|
346
|
-
bounds: resolveGraphicBounds(this),
|
|
347
|
-
unknown: scale.unknown
|
|
348
|
-
})
|
|
349
|
-
: {
|
|
350
|
-
type: isSequentialColor
|
|
351
|
-
? "sequential"
|
|
352
|
-
: isOrdinalAppearance
|
|
353
|
-
? validateOrdinalScaleType(scale.type)
|
|
354
|
-
: scale.type === "time"
|
|
355
|
-
? validateTimeScaleType(scale.type)
|
|
356
|
-
: isTransformedScaleType(scale.type)
|
|
357
|
-
? validateScaleTypeForRole(
|
|
358
|
-
scale.type,
|
|
359
|
-
SCALE_ROLES.quantitativePosition
|
|
360
|
-
)
|
|
361
|
-
: validateLinearScaleType(scale.type),
|
|
362
|
-
domain,
|
|
363
|
-
range,
|
|
364
|
-
...(scale.clamp === undefined ? {} : { clamp: scale.clamp }),
|
|
365
|
-
...(scale.type === "log"
|
|
366
|
-
? { base: normalizeTransformParameters("log", {
|
|
367
|
-
...(scale.base === undefined ? {} : { base: scale.base })
|
|
368
|
-
}).base }
|
|
369
|
-
: scale.type === "pow"
|
|
370
|
-
? { exponent: normalizeTransformParameters("pow", {
|
|
371
|
-
...(scale.exponent === undefined
|
|
372
|
-
? {}
|
|
373
|
-
: { exponent: scale.exponent })
|
|
374
|
-
}).exponent }
|
|
375
|
-
: scale.type === "symlog"
|
|
376
|
-
? { constant: normalizeTransformParameters("symlog", {
|
|
377
|
-
...(scale.constant === undefined
|
|
378
|
-
? {}
|
|
379
|
-
: { constant: scale.constant })
|
|
380
|
-
}).constant }
|
|
381
|
-
: {}),
|
|
382
|
-
...(isSequentialColor ? { interpolate: scale.interpolate ?? "rgb" } : {}),
|
|
383
|
-
...(Object.hasOwn(scale, "unknown")
|
|
384
|
-
? { unknown: scale.unknown }
|
|
385
|
-
: {})
|
|
386
|
-
};
|
|
387
|
-
if (Object.hasOwn(scale, "unknown") && !Object.hasOwn(resolvedScale, "unknown")) {
|
|
388
|
-
resolvedScale = { ...resolvedScale, unknown: scale.unknown };
|
|
389
|
-
}
|
|
390
|
-
if (scale.type === "time" && ["x", "y"].includes(channel)) {
|
|
391
|
-
const temporalBarBand = resolveTemporalBarBand(
|
|
392
|
-
consumers,
|
|
393
|
-
domain,
|
|
394
|
-
range,
|
|
395
|
-
allValues
|
|
396
|
-
);
|
|
397
|
-
if (temporalBarBand !== undefined) {
|
|
398
|
-
resolvedScale = {
|
|
399
|
-
...resolvedScale,
|
|
400
|
-
range: temporalBarBand.range,
|
|
401
|
-
bandwidth: temporalBarBand.bandwidth
|
|
402
|
-
};
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
if (scale.reverse === true) {
|
|
406
|
-
const range = [...resolvedScale.range].reverse();
|
|
407
|
-
const direction = Math.sign(range[1] - range[0]) || 1;
|
|
408
|
-
const offset = resolvedScale.start === undefined
|
|
67
|
+
const resolvedScale = resolveScaleMaterialization({
|
|
68
|
+
id,
|
|
69
|
+
scale,
|
|
70
|
+
channel,
|
|
71
|
+
consumers,
|
|
72
|
+
valuesByConsumer,
|
|
73
|
+
bounds: ["color", "strokeDash", "shape", "size", "opacity", "xOffset", "yOffset"]
|
|
74
|
+
.includes(channel)
|
|
409
75
|
? undefined
|
|
410
|
-
:
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
...(resolvedScale.step === undefined
|
|
415
|
-
? {}
|
|
416
|
-
: { step: -resolvedScale.step }),
|
|
417
|
-
...(offset === undefined ? {} : { start: range[0] + direction * offset })
|
|
418
|
-
};
|
|
419
|
-
}
|
|
76
|
+
: resolveGraphicBounds(this),
|
|
77
|
+
resolvedScales: this.resolvedScales,
|
|
78
|
+
markConfigs: this.markConfigs
|
|
79
|
+
});
|
|
420
80
|
let next = this._withResolvedScale(id, resolvedScale);
|
|
421
81
|
|
|
422
82
|
for (const { consumer, values } of valuesByConsumer) {
|
|
423
83
|
if (
|
|
424
|
-
|
|
425
|
-
|
|
84
|
+
args.marks === false &&
|
|
85
|
+
canDeferScaleConsumerApplication(consumer.layer)
|
|
426
86
|
) {
|
|
427
|
-
next = next.rematerializePointMark({ id: consumer.layer.id });
|
|
428
87
|
continue;
|
|
429
88
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
89
|
+
const materializationMode = getScaleConsumerMaterializationMode(
|
|
90
|
+
consumer.layer,
|
|
91
|
+
channel
|
|
92
|
+
);
|
|
93
|
+
if (materializationMode === "rematerialize") {
|
|
94
|
+
if (args.marks !== false) {
|
|
95
|
+
const step = getMarkRematerializationStep(consumer.layer);
|
|
96
|
+
if (step !== undefined) next = next[step.op](step.args);
|
|
97
|
+
}
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (materializationMode === "defer") continue;
|
|
436
101
|
next = next.editGraphics({
|
|
437
102
|
target: consumer.layer.id,
|
|
438
103
|
property: channel === "color" ? "fill" : channel,
|
|
439
|
-
value:
|
|
440
|
-
? mapDiscretizedColors(values, resolvedScale)
|
|
441
|
-
: isSequentialColor
|
|
442
|
-
? mapSequentialColors(values, resolvedScale.domain, resolvedScale.range, {
|
|
443
|
-
interpolation: resolvedScale.interpolate,
|
|
444
|
-
clamp: resolvedScale.clamp ?? false,
|
|
445
|
-
...(Object.hasOwn(resolvedScale, "unknown")
|
|
446
|
-
? { unknown: resolvedScale.unknown }
|
|
447
|
-
: {})
|
|
448
|
-
})
|
|
449
|
-
: isOrdinalAppearance
|
|
450
|
-
? mapOrdinalValues(values, domain, resolvedScale.range, {
|
|
451
|
-
...(Object.hasOwn(resolvedScale, "unknown")
|
|
452
|
-
? { unknown: resolvedScale.unknown }
|
|
453
|
-
: {})
|
|
454
|
-
})
|
|
455
|
-
: mapContinuousScaleValues(values, resolvedScale)
|
|
104
|
+
value: mapScaleConsumerValues(values, resolvedScale, channel)
|
|
456
105
|
});
|
|
457
106
|
}
|
|
458
107
|
|
|
@@ -117,31 +117,42 @@ export const applyPointHighlight = action(
|
|
|
117
117
|
}
|
|
118
118
|
);
|
|
119
119
|
|
|
120
|
+
function applyRectangularHighlight(program, args, operation, markType) {
|
|
121
|
+
validateKeys(args, INTERNAL_SELECTION_OPTIONS, operation);
|
|
122
|
+
const resolved = resolveStoredSelection(program, args.selection);
|
|
123
|
+
const keys = selectedKeys(args, resolved);
|
|
124
|
+
if (resolved.items[0]?.markType !== markType && resolved.items.length > 0) {
|
|
125
|
+
throw new Error(`${operation} requires a ${markType} selection.`);
|
|
126
|
+
}
|
|
127
|
+
if (keys.length === 0) return program;
|
|
128
|
+
const selected = new Set(keys);
|
|
129
|
+
const graphic = program.graphicSpec.objects[resolved.definition.target];
|
|
130
|
+
const keyByGraphic = new Map(resolved.items.flatMap(item =>
|
|
131
|
+
item.graphicIds.map(id => [id, item.key])
|
|
132
|
+
));
|
|
133
|
+
return program.editGraphics({
|
|
134
|
+
target: resolved.definition.target,
|
|
135
|
+
property: "items",
|
|
136
|
+
value: graphic.items.map(child => ({
|
|
137
|
+
type: child.type ?? graphic.type,
|
|
138
|
+
properties: selected.has(keyByGraphic.get(child.id))
|
|
139
|
+
? { ...child.properties, ...args.style }
|
|
140
|
+
: child.properties
|
|
141
|
+
}))
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
120
145
|
export const applyBarHighlight = action(
|
|
121
146
|
{ op: "applyBarHighlight", description: "Apply selected bar appearance." },
|
|
122
147
|
function (args = {}) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const graphic = this.graphicSpec.objects[resolved.definition.target];
|
|
132
|
-
const keyByGraphic = new Map(resolved.items.flatMap(item =>
|
|
133
|
-
item.graphicIds.map(id => [id, item.key])
|
|
134
|
-
));
|
|
135
|
-
return this.editGraphics({
|
|
136
|
-
target: resolved.definition.target,
|
|
137
|
-
property: "items",
|
|
138
|
-
value: graphic.items.map(child => ({
|
|
139
|
-
type: child.type ?? graphic.type,
|
|
140
|
-
properties: selected.has(keyByGraphic.get(child.id))
|
|
141
|
-
? { ...child.properties, ...args.style }
|
|
142
|
-
: child.properties
|
|
143
|
-
}))
|
|
144
|
-
});
|
|
148
|
+
return applyRectangularHighlight(this, args, "applyBarHighlight", "bar");
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
export const applyRectHighlight = action(
|
|
153
|
+
{ op: "applyRectHighlight", description: "Apply selected rect appearance." },
|
|
154
|
+
function (args = {}) {
|
|
155
|
+
return applyRectangularHighlight(this, args, "applyRectHighlight", "rect");
|
|
145
156
|
}
|
|
146
157
|
);
|
|
147
158
|
|
|
@@ -152,8 +163,11 @@ export const applyPathHighlight = action(
|
|
|
152
163
|
const resolved = resolveStoredSelection(this, args.selection);
|
|
153
164
|
const keys = selectedKeys(args, resolved);
|
|
154
165
|
const markType = resolved.items[0]?.markType;
|
|
155
|
-
if (
|
|
156
|
-
|
|
166
|
+
if (
|
|
167
|
+
resolved.items.length > 0 &&
|
|
168
|
+
requireSelectionPolicy(markType).applyHighlightOp !== "applyPathHighlight"
|
|
169
|
+
) {
|
|
170
|
+
throw new Error("applyPathHighlight requires a path selection policy.");
|
|
157
171
|
}
|
|
158
172
|
if (keys.length === 0) return this;
|
|
159
173
|
const selected = new Set(keys);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
applyBarHighlight,
|
|
3
|
+
applyRectHighlight,
|
|
3
4
|
applyPathHighlight,
|
|
4
5
|
applyPointHighlight,
|
|
5
6
|
applyRuleHighlight,
|
|
@@ -14,6 +15,7 @@ export function registerSelectionActions(ProgramClass) {
|
|
|
14
15
|
ProgramClass.prototype.selectMarks = selectMarks;
|
|
15
16
|
ProgramClass.prototype.highlightMarks = highlightMarks;
|
|
16
17
|
ProgramClass.prototype.applyBarHighlight = applyBarHighlight;
|
|
18
|
+
ProgramClass.prototype.applyRectHighlight = applyRectHighlight;
|
|
17
19
|
ProgramClass.prototype.applyPathHighlight = applyPathHighlight;
|
|
18
20
|
ProgramClass.prototype.applyPointHighlight = applyPointHighlight;
|
|
19
21
|
ProgramClass.prototype.applyRuleHighlight = applyRuleHighlight;
|