ggaction 0.0.13 → 0.0.15
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 +78 -0
- package/README.md +20 -11
- package/knowledge/action-cards.json +1 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/package.json +8 -3
- package/src/actions/basic.js +2 -2
- package/src/actions/boxPlots/components.js +14 -4
- package/src/actions/boxPlots/edit.js +31 -5
- package/src/actions/boxPlots/materialize.js +11 -3
- package/src/actions/boxPlots/options.js +48 -16
- package/src/actions/categoryOrder/index.js +15 -4
- package/src/actions/charts/area.js +5 -1
- package/src/actions/charts/bar.js +2 -1
- package/src/actions/charts/density.js +6 -2
- package/src/actions/charts/ecdf.js +4 -1
- package/src/actions/charts/endpoints.js +25 -3
- package/src/actions/charts/heatmap.js +2 -1
- package/src/actions/charts/histogram.js +4 -3
- package/src/actions/charts/horizon.js +3 -1
- package/src/actions/charts/interval-regression.js +5 -2
- package/src/actions/charts/line.js +3 -1
- package/src/actions/charts/parallel.js +8 -2
- package/src/actions/charts/pie.js +10 -2
- package/src/actions/charts/polar.js +15 -4
- package/src/actions/charts/radar.js +8 -2
- package/src/actions/charts/radial.js +10 -2
- package/src/actions/charts/rug-strip.js +6 -2
- package/src/actions/charts/scatter.js +3 -1
- package/src/actions/composition/actions.js +13 -4
- package/src/actions/coordinates/actions.js +1 -1
- package/src/actions/coordinates/edit.js +76 -0
- package/src/actions/data/bin.js +1 -1
- package/src/actions/data/bin2d.js +57 -185
- package/src/actions/data/complete.js +26 -0
- package/src/actions/data/computed.js +2 -2
- package/src/actions/data/create.js +2 -2
- package/src/actions/data/density.js +12 -20
- package/src/actions/data/derived.js +47 -17
- package/src/actions/data/edit.js +539 -0
- package/src/actions/data/filter.js +14 -2
- package/src/actions/data/impute.js +26 -0
- package/src/actions/data/index.js +14 -0
- package/src/actions/data/normalize.js +27 -0
- package/src/actions/data/regression.js +16 -21
- package/src/actions/data/revisionBindings.js +145 -0
- package/src/actions/data/shared.js +20 -4
- package/src/actions/data/summary.js +1 -1
- package/src/actions/data/timeUnit.js +4 -1
- package/src/actions/data/window.js +1 -1
- package/src/actions/encodings/channels.js +415 -0
- package/src/actions/encodings/color/index.js +2 -1
- package/src/actions/encodings/density.js +5 -2
- package/src/actions/encodings/histogram.js +3 -2
- package/src/actions/encodings/index.js +4 -0
- package/src/actions/encodings/offset.js +20 -13
- package/src/actions/encodings/position/apply.js +53 -7
- package/src/actions/encodings/position/index.js +10 -2
- package/src/actions/encodings/position/policies/bar.js +9 -0
- package/src/actions/encodings/position/resolve.js +24 -7
- package/src/actions/encodings/remove.js +9 -4
- package/src/actions/encodings/ruleAppearance.js +1 -23
- package/src/actions/encodings/seriesLayout.js +1 -0
- package/src/actions/encodings/shared.js +82 -14
- package/src/actions/encodings/stroke.js +226 -0
- package/src/actions/errorBands/create.js +23 -3
- package/src/actions/errorBands/edit.js +21 -6
- package/src/actions/errorBars/create.js +35 -7
- package/src/actions/errorBars/edit.js +19 -4
- package/src/actions/facets/actions.js +237 -57
- package/src/actions/facets/derive.js +91 -26
- package/src/actions/gradientPlots/components.js +10 -2
- package/src/actions/gradientPlots/edit.js +14 -4
- package/src/actions/gradientPlots/materialize.js +3 -1
- package/src/actions/gradientPlots/options.js +10 -2
- package/src/actions/guides/applicability.js +8 -2
- package/src/actions/guides/axes/labels.js +58 -12
- package/src/actions/guides/axes/lines.js +6 -2
- package/src/actions/guides/axes/parallel/resolve.js +6 -2
- package/src/actions/guides/axes/tickGroups.js +2 -1
- package/src/actions/guides/axes/ticks.js +6 -2
- package/src/actions/guides/axes/titles.js +11 -3
- package/src/actions/guides/grids/resolve.js +7 -2
- package/src/actions/guides/guides.js +19 -3
- package/src/actions/guides/legends/blocks.js +426 -0
- package/src/actions/guides/legends/categorical/actions.js +134 -48
- package/src/actions/guides/legends/categorical/components.js +17 -12
- package/src/actions/guides/legends/categorical/index.js +37 -33
- package/src/actions/guides/legends/categorical/layout.js +97 -15
- package/src/actions/guides/legends/categorical/options.js +2 -2
- package/src/actions/guides/legends/categorical/recipes.js +111 -20
- package/src/actions/guides/legends/categorical/resolve.js +12 -8
- package/src/actions/guides/legends/categorical/symbols.js +85 -30
- package/src/actions/guides/legends/continuous/common.js +30 -12
- package/src/actions/guides/legends/continuous/gradient.js +10 -7
- package/src/actions/guides/legends/continuous/index.js +2 -0
- package/src/actions/guides/legends/continuous/interval.js +8 -3
- package/src/actions/guides/legends/continuous/opacity.js +8 -5
- package/src/actions/guides/legends/continuous/stroke.js +525 -0
- package/src/actions/guides/legends/creation.js +14 -1
- package/src/actions/guides/legends/edit.js +158 -59
- package/src/actions/guides/legends/index.js +2 -0
- package/src/actions/guides/legends/lane.js +54 -19
- package/src/actions/guides/legends/lifecycle.js +19 -8
- package/src/actions/guides/legends/remove.js +13 -3
- package/src/actions/guides/legends/sampling.js +140 -0
- package/src/actions/guides/legends/size.js +93 -40
- package/src/actions/guides/legends/strokeWidth.js +34 -28
- package/src/actions/guides/legends/target.js +112 -1
- package/src/actions/guides/legends/transition.js +165 -16
- package/src/actions/guides/polar/axes/facade.js +4 -4
- package/src/actions/guides/polar/axes/labels.js +24 -5
- package/src/actions/guides/polar/axes/lines.js +10 -4
- package/src/actions/guides/polar/axes/shared.js +16 -0
- package/src/actions/guides/polar/axes/ticks.js +1 -1
- package/src/actions/guides/polar/axes/titles.js +1 -1
- package/src/actions/guides/polar/grids.js +1 -1
- package/src/actions/guides/polar/resolve.js +12 -8
- package/src/actions/index.js +14 -3
- package/src/actions/marks/arc/actions.js +77 -19
- package/src/actions/marks/area/actions.js +34 -9
- package/src/actions/marks/area/materialize.js +17 -1
- package/src/actions/marks/bar/create.js +11 -2
- package/src/actions/marks/bar/edit.js +20 -3
- package/src/actions/marks/bar/materialize.js +22 -2
- package/src/actions/marks/index.js +10 -1
- package/src/actions/marks/line/actions.js +37 -14
- package/src/actions/marks/line/materialize.js +29 -10
- package/src/actions/marks/point/create.js +8 -2
- package/src/actions/marks/point/edit.js +18 -6
- package/src/actions/marks/point/materialize.js +49 -15
- package/src/actions/marks/rect/actions.js +33 -12
- package/src/actions/marks/references.js +601 -30
- package/src/actions/marks/remove.js +71 -1
- package/src/actions/marks/rule/actions.js +47 -10
- package/src/actions/marks/shared.js +1 -1
- package/src/actions/marks/text/actions.js +74 -9
- package/src/actions/marks/text/index.js +4 -0
- package/src/actions/marks/text/layout.js +154 -6
- package/src/actions/marks/text/removal.js +173 -0
- package/src/actions/marks/text/selection.js +73 -0
- package/src/actions/marks/tick/actions.js +22 -5
- package/src/actions/primitives/editGraphics.js +26 -0
- package/src/actions/primitives/semantic.js +2 -1
- package/src/actions/primitives/semanticAction.js +83 -10
- package/src/actions/primitives/semanticValidation/guide.js +1 -1
- package/src/actions/primitives/semanticValidation/index.js +9 -1
- package/src/actions/primitives/semanticValidation/layer.js +5 -0
- package/src/actions/primitives/semanticValidation/scale.js +28 -7
- package/src/actions/regression/components.js +26 -11
- package/src/actions/regression/create.js +10 -2
- package/src/actions/regression/edit.js +21 -7
- package/src/actions/resources/index.js +7 -0
- package/src/actions/resources/remove.js +172 -0
- package/src/actions/scales/channels.js +212 -0
- package/src/actions/scales/consumers/common.js +1 -1
- package/src/actions/scales/consumers/families.js +3 -2
- package/src/actions/scales/consumers/index.js +19 -2
- package/src/actions/scales/consumers/seriesLayout.js +28 -14
- package/src/actions/scales/create.js +54 -22
- package/src/actions/scales/definitions.js +94 -40
- package/src/actions/scales/edit.js +66 -11
- package/src/actions/scales/editPolicy.js +81 -11
- package/src/actions/scales/index.js +6 -0
- package/src/actions/scales/materialize.js +4 -3
- package/src/actions/scales/offset.js +48 -0
- package/src/actions/scales/parallel.js +71 -0
- package/src/actions/scales/preview.js +111 -10
- package/src/actions/selection/actions.js +154 -30
- package/src/actions/selection/index.js +3 -0
- package/src/actions/theme/actions.js +68 -13
- package/src/actions/theme/composition.js +238 -0
- package/src/actions/theme/index.js +9 -2
- package/src/actions/theme/reconcile.js +315 -67
- package/src/actions/theme/state.js +160 -0
- package/src/actions/violinPlots/create.js +5 -2
- package/src/actions/violinPlots/edit.js +1 -0
- package/src/core/action.js +10 -0
- package/src/core/compositionState.js +6 -1
- package/src/core/programState.js +20 -0
- package/src/core/resourceReferences.js +332 -0
- package/src/core/vocabulary.js +16 -3
- package/src/grammar/bars/aggregate.js +4 -1
- package/src/grammar/bars/geometry.js +44 -0
- package/src/grammar/bin.js +54 -9
- package/src/grammar/complete.js +279 -0
- package/src/grammar/computed.js +265 -64
- package/src/grammar/coordinates.js +37 -0
- package/src/grammar/density.js +239 -37
- package/src/grammar/displayLabels.js +57 -0
- package/src/grammar/facets/dependencies.js +133 -1
- package/src/grammar/facets/guides.js +3 -0
- package/src/grammar/facets/index.js +7 -47
- package/src/grammar/facets/scales.js +15 -18
- package/src/grammar/impute.js +340 -0
- package/src/grammar/markLabelSelection.js +57 -0
- package/src/grammar/markLabels.js +18 -1
- package/src/grammar/normalize.js +366 -0
- package/src/grammar/pathSeries.js +26 -8
- package/src/grammar/pointShapes.js +13 -4
- package/src/grammar/polar.js +90 -8
- package/src/grammar/regression/index.js +1 -0
- package/src/grammar/regression/parameters.js +23 -0
- package/src/grammar/roundedRect.js +180 -0
- package/src/grammar/rules.js +1 -0
- package/src/grammar/scales/colorConsumers.js +20 -1
- package/src/grammar/scales/continuous.js +2 -2
- package/src/grammar/scales/definition.js +27 -4
- package/src/grammar/scales/index.js +1 -0
- package/src/grammar/scales/ordinal.js +12 -3
- package/src/grammar/scales/policies.js +2 -2
- package/src/grammar/scales/size.js +456 -0
- package/src/grammar/schemas/concreteGraphic.js +14 -2
- package/src/grammar/schemas/graphic.js +15 -0
- package/src/grammar/schemas/graphicBounds.js +179 -30
- package/src/grammar/schemas/semanticPath.js +7 -2
- package/src/grammar/statisticalReference.js +103 -0
- package/src/grammar/strokeStyle.js +77 -0
- package/src/grammar/summary.js +78 -16
- package/src/grammar/timeUnit.js +216 -5
- package/src/grammar/transformTopology.js +4 -0
- package/src/grammar/transforms.js +394 -28
- package/src/grammar/weightedStatistics.js +374 -0
- package/src/grammar/window.js +221 -16
- package/src/layout/aspect.js +80 -0
- package/src/layout/facets.js +59 -5
- package/src/layout/labels.js +343 -0
- package/src/materialization/bars/aggregate.js +25 -2
- package/src/materialization/bars/histogram.js +84 -24
- package/src/materialization/bars/ranged.js +19 -3
- package/src/materialization/bars/resolve.js +7 -4
- package/src/materialization/composition.js +3 -1
- package/src/materialization/coordinateBounds.js +204 -0
- package/src/materialization/dependencies.js +36 -0
- package/src/materialization/facetGuides/legacyCategorical.js +3 -0
- package/src/materialization/facetGuides/placement.js +8 -2
- package/src/materialization/facetGuides/preparation.js +12 -7
- package/src/materialization/facetHeaders.js +346 -0
- package/src/materialization/facets.js +15 -65
- package/src/materialization/guides/resources.js +26 -0
- package/src/materialization/legends.js +1 -1
- package/src/materialization/marks/index.js +11 -5
- package/src/materialization/marks/policies.js +2 -1
- package/src/materialization/rect.js +25 -12
- package/src/materialization/rectConfig.js +5 -1
- package/src/materialization/scales/map.js +5 -3
- package/src/materialization/scales/policies/binnedPosition.js +2 -2
- package/src/materialization/scales/policies/offset.js +50 -8
- package/src/materialization/scales/policies/series.js +4 -1
- package/src/materialization/scales/resolve.js +22 -6
- package/src/materialization/selection/items/arc.js +28 -4
- package/src/materialization/selection/items/bar.js +30 -3
- package/src/materialization/selection/items/common.js +19 -4
- package/src/materialization/selection/items/rect.js +28 -4
- package/src/materialization/selection/path.js +1 -1
- package/src/materialization/selection/point.js +3 -1
- package/src/materialization/text.js +265 -14
- package/src/renderers/canvas/circle.js +2 -3
- package/src/renderers/canvas/line.js +2 -3
- package/src/renderers/canvas/native.js +4 -4
- package/src/renderers/canvas/path.js +2 -3
- package/src/renderers/canvas/rect.js +2 -3
- package/src/renderers/canvas/stroke.js +11 -0
- package/src/renderers/svg.js +19 -0
- package/src/selectors/datasets.js +32 -1
- package/src/selectors/layers.js +4 -0
- package/src/theme/defaults.js +101 -0
- package/types/basic.d.ts +6 -0
- package/types/index.d.ts +85 -0
- package/types/program.d.ts +910 -117
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cloneAndFreeze,
|
|
3
|
+
freezeOwned,
|
|
4
|
+
isPlainObject
|
|
5
|
+
} from "../../core/immutable.js";
|
|
6
|
+
import {
|
|
7
|
+
normalizeThemeDefinition,
|
|
8
|
+
resolveThemeTokens
|
|
9
|
+
} from "../../theme/defaults.js";
|
|
10
|
+
|
|
11
|
+
export const LOCAL_THEME_OWNER = "local";
|
|
12
|
+
|
|
13
|
+
function ownArray(value) {
|
|
14
|
+
return freezeOwned([...(value ?? [])]);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function requireThemeScope(value) {
|
|
18
|
+
if (!["self", "descendants"].includes(value)) {
|
|
19
|
+
throw new Error(`Unsupported theme scope "${value}".`);
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function requireThemeOwner(value) {
|
|
25
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
26
|
+
throw new TypeError("Theme frame owner must be a non-empty string.");
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function compositionThemeOwner(id, scope = "descendants") {
|
|
32
|
+
if (typeof id !== "string" || id.length === 0) {
|
|
33
|
+
throw new TypeError("Composition theme owner requires a non-empty id.");
|
|
34
|
+
}
|
|
35
|
+
requireThemeScope(scope);
|
|
36
|
+
return scope === "self" ? `composition:${id}:self` : `composition:${id}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function createThemeFrame({
|
|
40
|
+
owner = LOCAL_THEME_OWNER,
|
|
41
|
+
scope = "self",
|
|
42
|
+
definition
|
|
43
|
+
}) {
|
|
44
|
+
const normalized = normalizeThemeDefinition(definition);
|
|
45
|
+
return freezeOwned({
|
|
46
|
+
owner: requireThemeOwner(owner),
|
|
47
|
+
scope: requireThemeScope(scope),
|
|
48
|
+
name: normalized.name,
|
|
49
|
+
tokens: normalized.tokens
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function upsertThemeFrame(frames = [], frame) {
|
|
54
|
+
if (!Array.isArray(frames)) {
|
|
55
|
+
throw new TypeError("Theme frames must be an array.");
|
|
56
|
+
}
|
|
57
|
+
if (!isPlainObject(frame)) {
|
|
58
|
+
throw new TypeError("Theme frame must be a plain object.");
|
|
59
|
+
}
|
|
60
|
+
return freezeOwned([
|
|
61
|
+
...frames.filter(current => current.owner !== frame.owner),
|
|
62
|
+
frame
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function removeThemeFrameOwner(frames = [], owner) {
|
|
67
|
+
if (!Array.isArray(frames)) {
|
|
68
|
+
throw new TypeError("Theme frames must be an array.");
|
|
69
|
+
}
|
|
70
|
+
requireThemeOwner(owner);
|
|
71
|
+
const next = frames.filter(frame => frame.owner !== owner);
|
|
72
|
+
return freezeOwned({
|
|
73
|
+
frames: freezeOwned(next),
|
|
74
|
+
removed: next.length !== frames.length
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function moveLocalThemeScope(localOrder = [], scope) {
|
|
79
|
+
if (!Array.isArray(localOrder)) {
|
|
80
|
+
throw new TypeError("Theme localOrder must be an array.");
|
|
81
|
+
}
|
|
82
|
+
requireThemeScope(scope);
|
|
83
|
+
return freezeOwned([
|
|
84
|
+
...localOrder.filter(current => current !== scope),
|
|
85
|
+
scope
|
|
86
|
+
]);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function ownCanonicalThemeState(state, composition) {
|
|
90
|
+
const frames = ownArray(state.frames);
|
|
91
|
+
const localOrder = ownArray(state.localOrder);
|
|
92
|
+
const overrides = ownArray(state.overrides);
|
|
93
|
+
const result = { frames, localOrder, overrides };
|
|
94
|
+
if (composition || state.descendantFrames !== undefined) {
|
|
95
|
+
result.descendantFrames = ownArray(state.descendantFrames);
|
|
96
|
+
}
|
|
97
|
+
return cloneAndFreeze(result);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function normalizeThemeState(state, { composition = false } = {}) {
|
|
101
|
+
if (state === undefined) {
|
|
102
|
+
return freezeOwned({
|
|
103
|
+
frames: freezeOwned([]),
|
|
104
|
+
...(composition ? { descendantFrames: freezeOwned([]) } : {}),
|
|
105
|
+
localOrder: freezeOwned([]),
|
|
106
|
+
overrides: freezeOwned([])
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
if (!isPlainObject(state)) {
|
|
110
|
+
throw new TypeError("Program theme state must be a plain object.");
|
|
111
|
+
}
|
|
112
|
+
if (Array.isArray(state.frames)) {
|
|
113
|
+
return ownCanonicalThemeState(state, composition);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const name = state.name ?? "light";
|
|
117
|
+
const tokens = state.tokens ?? {};
|
|
118
|
+
const scope = state.scope ?? "self";
|
|
119
|
+
const origin = state.origin?.ownerCompositionId;
|
|
120
|
+
const owner = origin === undefined
|
|
121
|
+
? LOCAL_THEME_OWNER
|
|
122
|
+
: compositionThemeOwner(origin, "descendants");
|
|
123
|
+
const frame = createThemeFrame({
|
|
124
|
+
owner,
|
|
125
|
+
scope,
|
|
126
|
+
definition: { base: name, tokens }
|
|
127
|
+
});
|
|
128
|
+
return freezeOwned({
|
|
129
|
+
frames: freezeOwned([frame]),
|
|
130
|
+
...(composition && scope === "descendants"
|
|
131
|
+
? { descendantFrames: freezeOwned([frame]) }
|
|
132
|
+
: composition
|
|
133
|
+
? { descendantFrames: freezeOwned([]) }
|
|
134
|
+
: {}),
|
|
135
|
+
localOrder: origin === undefined ? freezeOwned([scope]) : freezeOwned([]),
|
|
136
|
+
overrides: cloneAndFreeze(state.overrides ?? [])
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function resolveEffectiveThemeFrame(state) {
|
|
141
|
+
const frames = state?.frames;
|
|
142
|
+
return Array.isArray(frames) ? frames.at(-1) : undefined;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function resolveEffectiveThemeTokens(state) {
|
|
146
|
+
const frame = resolveEffectiveThemeFrame(state);
|
|
147
|
+
return frame === undefined
|
|
148
|
+
? resolveThemeTokens("light")
|
|
149
|
+
: resolveThemeTokens({ base: frame.name, tokens: frame.tokens });
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function setThemeStateOverrides(state, overrides) {
|
|
153
|
+
if (!Array.isArray(overrides)) {
|
|
154
|
+
throw new TypeError("Theme overrides must be an array.");
|
|
155
|
+
}
|
|
156
|
+
return freezeOwned({
|
|
157
|
+
...state,
|
|
158
|
+
overrides: cloneAndFreeze([...overrides].sort())
|
|
159
|
+
});
|
|
160
|
+
}
|
|
@@ -2,6 +2,7 @@ import { action } from "../../core/action.js";
|
|
|
2
2
|
import { validateOptionObject } from "../../core/validation.js";
|
|
3
3
|
import { findDataset } from "../../selectors/datasets.js";
|
|
4
4
|
import { findLayer } from "../../selectors/layers.js";
|
|
5
|
+
import { STROKE_STYLE_PROPERTIES } from "../../grammar/strokeStyle.js";
|
|
5
6
|
import {
|
|
6
7
|
applyFacadeGuides,
|
|
7
8
|
normalizeAppearance,
|
|
@@ -20,12 +21,13 @@ const OPTIONS = Object.freeze([
|
|
|
20
21
|
]);
|
|
21
22
|
const POSITION_OPTIONS = Object.freeze(["field", "fieldType", "scale"]);
|
|
22
23
|
const DENSITY_OPTIONS = Object.freeze([
|
|
23
|
-
"bandwidth", "extent", "steps", "kernel", "normalization", "width", "side"
|
|
24
|
+
"bandwidth", "extent", "steps", "kernel", "normalization", "weight", "width", "side"
|
|
24
25
|
]);
|
|
25
26
|
const WIDTH_OPTIONS = Object.freeze(["band", "resolve"]);
|
|
26
27
|
const SPLIT_OPTIONS = Object.freeze(["field", "domain"]);
|
|
27
28
|
const AREA_OPTIONS = Object.freeze([
|
|
28
|
-
"fill", "opacity", "stroke", "strokeWidth", "curve"
|
|
29
|
+
"fill", "opacity", "stroke", "strokeWidth", "curve",
|
|
30
|
+
...STROKE_STYLE_PROPERTIES
|
|
29
31
|
]);
|
|
30
32
|
const CATEGORICAL_TYPES = Object.freeze(["nominal", "ordinal"]);
|
|
31
33
|
const OPERATION = "createViolinPlot";
|
|
@@ -221,6 +223,7 @@ export const createViolinPlot = action(
|
|
|
221
223
|
steps: transform.steps,
|
|
222
224
|
kernel: transform.kernel,
|
|
223
225
|
normalization: transform.normalization,
|
|
226
|
+
...(transform.weight === undefined ? {} : { weight: transform.weight }),
|
|
224
227
|
width: transform.placement.width,
|
|
225
228
|
side: transform.placement.side
|
|
226
229
|
},
|
|
@@ -181,6 +181,7 @@ export const editViolinPlot = action(
|
|
|
181
181
|
steps: transform.steps,
|
|
182
182
|
kernel: transform.kernel,
|
|
183
183
|
normalization: transform.normalization,
|
|
184
|
+
...(transform.weight === undefined ? {} : { weight: transform.weight }),
|
|
184
185
|
width: transform.placement.width,
|
|
185
186
|
side: transform.placement.side
|
|
186
187
|
}
|
package/src/core/action.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { cloneAndFreeze, freezeOwned, isPlainObject } from "./immutable.js";
|
|
2
2
|
|
|
3
3
|
const metadataByWrappedAction = new WeakMap();
|
|
4
|
+
const implementationByWrappedAction = new WeakMap();
|
|
4
5
|
let actionCompletionHook;
|
|
5
6
|
|
|
6
7
|
export function setActionCompletionHook(hook) {
|
|
@@ -14,6 +15,14 @@ export function getWrappedActionMetadata(value) {
|
|
|
14
15
|
return metadataByWrappedAction.get(value);
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
export function invokeWrappedActionImplementation(value, program, args = {}) {
|
|
19
|
+
const implementation = implementationByWrappedAction.get(value);
|
|
20
|
+
if (implementation === undefined) {
|
|
21
|
+
throw new TypeError("Expected an action created by action().");
|
|
22
|
+
}
|
|
23
|
+
return implementation.call(program, args);
|
|
24
|
+
}
|
|
25
|
+
|
|
17
26
|
function summarizeObject(value, ancestors = new WeakSet()) {
|
|
18
27
|
if (ancestors.has(value)) {
|
|
19
28
|
throw new TypeError("Action arguments must not contain circular references.");
|
|
@@ -161,5 +170,6 @@ export function action(metadata, implementation) {
|
|
|
161
170
|
};
|
|
162
171
|
|
|
163
172
|
metadataByWrappedAction.set(wrappedAction, ownedMetadata);
|
|
173
|
+
implementationByWrappedAction.set(wrappedAction, implementation);
|
|
164
174
|
return wrappedAction;
|
|
165
175
|
}
|
|
@@ -150,8 +150,13 @@ function validateFacetSpec(compositionSpec) {
|
|
|
150
150
|
"compositionSpec.facet.repeat requires target, channel, and fields."
|
|
151
151
|
);
|
|
152
152
|
}
|
|
153
|
+
const repeatChannel = ["x", "y", "theta", "r"].includes(repeat.channel) ||
|
|
154
|
+
(isPlainObject(repeat.channel) &&
|
|
155
|
+
Object.keys(repeat.channel).length === 1 &&
|
|
156
|
+
typeof repeat.channel.parallelDimension === "string" &&
|
|
157
|
+
repeat.channel.parallelDimension.length > 0);
|
|
153
158
|
if (typeof repeat.target !== "string" || repeat.target.length === 0 ||
|
|
154
|
-
!
|
|
159
|
+
!repeatChannel ||
|
|
155
160
|
!Array.isArray(repeat.fields) || repeat.fields.length === 0 ||
|
|
156
161
|
repeat.fields.some(field => typeof field !== "string" || field.length === 0) ||
|
|
157
162
|
new Set(repeat.fields).size !== repeat.fields.length) {
|
package/src/core/programState.js
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
isOwned,
|
|
5
5
|
isPlainObject
|
|
6
6
|
} from "./immutable.js";
|
|
7
|
+
import { removeMaterializationConfig } from "./materializationState.js";
|
|
7
8
|
|
|
8
9
|
export function ownProgramState(value) {
|
|
9
10
|
return isOwned(value) ? value : cloneAndFreeze(value);
|
|
@@ -26,3 +27,22 @@ export function ownChildPrograms(children, ProgramClass) {
|
|
|
26
27
|
}
|
|
27
28
|
return freezeOwned(owned);
|
|
28
29
|
}
|
|
30
|
+
|
|
31
|
+
// Semantic entries, resolved scale caches, and physical current-resource IDs
|
|
32
|
+
// are removed by editSemantic. A logical data owner also retains its own ID
|
|
33
|
+
// and replay configuration; release those non-semantic references after the
|
|
34
|
+
// domain's dependency validation and before the primitive deletion.
|
|
35
|
+
export function releaseNamedResourceOwnership(program, { kind, id, dataOwner }) {
|
|
36
|
+
if (kind !== "data") return program;
|
|
37
|
+
const materializationConfigs = dataOwner === undefined
|
|
38
|
+
? program.materializationConfigs
|
|
39
|
+
: removeMaterializationConfig(
|
|
40
|
+
program.materializationConfigs,
|
|
41
|
+
["data", dataOwner.family, dataOwner.owner]
|
|
42
|
+
).value;
|
|
43
|
+
const context = program.context.currentData === id
|
|
44
|
+
? freezeOwned({ ...program.context, currentData: undefined })
|
|
45
|
+
: program.context;
|
|
46
|
+
if (context === program.context && materializationConfigs === program.materializationConfigs) return program;
|
|
47
|
+
return program._clone({ context, materializationConfigs });
|
|
48
|
+
}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { freezeOwned, isPlainObject } from "./immutable.js";
|
|
2
|
+
import { validateUserId } from "./identifiers.js";
|
|
3
|
+
|
|
4
|
+
export const RESOURCE_KINDS = Object.freeze([
|
|
5
|
+
"data", "scale", "coordinate", "mark", "selection"
|
|
6
|
+
]);
|
|
7
|
+
|
|
8
|
+
const DATA_VALUE_KEYS = new Set([
|
|
9
|
+
"data", "dataset", "dataId", "filteredData", "originalData",
|
|
10
|
+
"outlierDataId", "profileId", "summaryId"
|
|
11
|
+
]);
|
|
12
|
+
const DATA_SOURCE_CONFIGS = new Set([
|
|
13
|
+
"boxPlot", "density", "ecdfPlot", "endpointPlot", "errorBand", "errorBar",
|
|
14
|
+
"gradientPlot", "horizon", "intervalPlot", "markFilter", "raincloudPlot",
|
|
15
|
+
"regression", "violinPlot"
|
|
16
|
+
]);
|
|
17
|
+
const MARK_ID_KEYS = new Set([
|
|
18
|
+
"bandId", "bodyId", "centerId", "connectorId", "intervalId", "lineId",
|
|
19
|
+
"lowerBoundaryId", "lowerCapId", "medianId", "outlierId", "startId",
|
|
20
|
+
"stemId", "upperBoundaryId", "upperCapId", "whiskerId"
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
function ownedPath(path) {
|
|
24
|
+
return freezeOwned([...path]);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function reference(kind, id, ownerKind, ownerId, path, strength = "live") {
|
|
28
|
+
if (typeof id !== "string" || id.length === 0) return undefined;
|
|
29
|
+
return freezeOwned({
|
|
30
|
+
kind,
|
|
31
|
+
id,
|
|
32
|
+
ownerKind,
|
|
33
|
+
ownerId,
|
|
34
|
+
path: ownedPath(path),
|
|
35
|
+
strength
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function append(references, value) {
|
|
40
|
+
if (value !== undefined) references.push(value);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function collectKnownKeys(value, path, visit) {
|
|
44
|
+
if (Array.isArray(value)) {
|
|
45
|
+
value.forEach((item, index) => collectKnownKeys(item, [...path, index], visit));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (!isPlainObject(value)) return;
|
|
49
|
+
for (const [key, child] of Object.entries(value)) {
|
|
50
|
+
visit(key, child, [...path, key], path);
|
|
51
|
+
collectKnownKeys(child, [...path, key], visit);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function canonicalResourcePath(path) {
|
|
56
|
+
if (!Array.isArray(path)) {
|
|
57
|
+
throw new TypeError("Resource reference path must be an array.");
|
|
58
|
+
}
|
|
59
|
+
return path.map(part => {
|
|
60
|
+
if (Number.isInteger(part) && part >= 0) return `[${part}]`;
|
|
61
|
+
if (typeof part !== "string" || part.length === 0) {
|
|
62
|
+
throw new TypeError("Resource reference path parts must be names or indexes.");
|
|
63
|
+
}
|
|
64
|
+
return `.${part}`;
|
|
65
|
+
}).join("");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function collectSemanticDataReferences(program) {
|
|
69
|
+
const references = [];
|
|
70
|
+
for (const layer of program.semanticSpec.layers) {
|
|
71
|
+
append(references, reference("data", layer.data, "layer", layer.id, ["data"]));
|
|
72
|
+
}
|
|
73
|
+
for (const dataset of program.semanticSpec.datasets) {
|
|
74
|
+
append(references, reference(
|
|
75
|
+
"data", dataset.source, "dataset", dataset.id, ["source"]
|
|
76
|
+
));
|
|
77
|
+
}
|
|
78
|
+
return freezeOwned(references);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function collectSemanticScaleReferences(program) {
|
|
82
|
+
const references = [];
|
|
83
|
+
for (const layer of program.semanticSpec.layers) {
|
|
84
|
+
for (const [channel, encoding] of Object.entries(layer.encoding ?? {})) {
|
|
85
|
+
append(references, reference(
|
|
86
|
+
"scale", encoding?.scale, "layer", layer.id,
|
|
87
|
+
["encoding", channel, "scale"]
|
|
88
|
+
));
|
|
89
|
+
if (channel === "parallel") {
|
|
90
|
+
for (const [index, dimension] of (encoding?.dimensions ?? []).entries()) {
|
|
91
|
+
append(references, reference(
|
|
92
|
+
"scale", dimension.scale, "layer", layer.id,
|
|
93
|
+
["encoding", "parallel", "dimensions", index, "scale"]
|
|
94
|
+
));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
collectKnownKeys(program.semanticSpec.guides, [], (key, value, path) => {
|
|
100
|
+
if (key === "scale") {
|
|
101
|
+
append(references, reference(
|
|
102
|
+
"scale", value, "semanticGuide", "guides", path
|
|
103
|
+
));
|
|
104
|
+
} else if (key === "scales" && Array.isArray(value)) {
|
|
105
|
+
value.forEach((id, index) => append(references, reference(
|
|
106
|
+
"scale", id, "semanticGuide", "guides", [...path, index]
|
|
107
|
+
)));
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
return freezeOwned(references);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function collectSemanticCoordinateReferences(program) {
|
|
114
|
+
const references = [];
|
|
115
|
+
for (const layer of program.semanticSpec.layers) {
|
|
116
|
+
append(references, reference(
|
|
117
|
+
"coordinate", layer.coordinate, "layer", layer.id, ["coordinate"]
|
|
118
|
+
));
|
|
119
|
+
}
|
|
120
|
+
collectKnownKeys(program.semanticSpec.guides, [], (key, value, path) => {
|
|
121
|
+
if (key === "coordinate") {
|
|
122
|
+
append(references, reference(
|
|
123
|
+
"coordinate", value, "semanticGuide", "guides", path
|
|
124
|
+
));
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
return freezeOwned(references);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function collectMarkConfigReferences(program) {
|
|
131
|
+
const references = [];
|
|
132
|
+
for (const layer of program.semanticSpec.layers) {
|
|
133
|
+
append(references, reference(
|
|
134
|
+
"mark", layer.source, "layer", layer.id, ["source"]
|
|
135
|
+
));
|
|
136
|
+
}
|
|
137
|
+
for (const [ownerId, config] of Object.entries(program.markConfigs)) {
|
|
138
|
+
collectKnownKeys(config, [], (key, value, path, parentPath) => {
|
|
139
|
+
if (DATA_VALUE_KEYS.has(key)) {
|
|
140
|
+
append(references, reference("data", value, "markConfig", ownerId, path));
|
|
141
|
+
}
|
|
142
|
+
const root = parentPath[0];
|
|
143
|
+
if (key === "source" && DATA_SOURCE_CONFIGS.has(root)) {
|
|
144
|
+
append(references, reference("data", value, "markConfig", ownerId, path));
|
|
145
|
+
}
|
|
146
|
+
if (key === "coordinate") {
|
|
147
|
+
append(references, reference(
|
|
148
|
+
"coordinate", value, "markConfig", ownerId, path
|
|
149
|
+
));
|
|
150
|
+
}
|
|
151
|
+
if ((key === "scale" || key.endsWith("Scale")) && typeof value === "string") {
|
|
152
|
+
append(references, reference("scale", value, "markConfig", ownerId, path));
|
|
153
|
+
} else if (key === "scale" && isPlainObject(value)) {
|
|
154
|
+
append(references, reference(
|
|
155
|
+
"scale", value.id, "markConfig", ownerId, [...path, "id"]
|
|
156
|
+
));
|
|
157
|
+
}
|
|
158
|
+
if (MARK_ID_KEYS.has(key)) {
|
|
159
|
+
append(references, reference("mark", value, "markConfig", ownerId, path));
|
|
160
|
+
}
|
|
161
|
+
if (
|
|
162
|
+
(root === "errorBandBoundary" && key === "owner") ||
|
|
163
|
+
(parentPath.length === 0 && key === "boxSpanOwner") ||
|
|
164
|
+
(root === "raincloudPlot" && (
|
|
165
|
+
key === "ownerId" || parentPath[1] === "childIds" ||
|
|
166
|
+
parentPath[1] === "ownedChildIds"
|
|
167
|
+
))
|
|
168
|
+
) {
|
|
169
|
+
append(references, reference("mark", value, "markConfig", ownerId, path));
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
append(references, reference(
|
|
173
|
+
"mark", config.statisticalReference?.source,
|
|
174
|
+
"markConfig", ownerId, ["statisticalReference", "source"]
|
|
175
|
+
));
|
|
176
|
+
for (const [index, id] of (
|
|
177
|
+
config.raincloudPlot?.ownedChildIds ?? []
|
|
178
|
+
).entries()) {
|
|
179
|
+
append(references, reference(
|
|
180
|
+
"mark", id, "markConfig", ownerId,
|
|
181
|
+
["raincloudPlot", "ownedChildIds", index]
|
|
182
|
+
));
|
|
183
|
+
}
|
|
184
|
+
const selection = config.labelAuthoring?.selection;
|
|
185
|
+
if (selection?.kind === "named") {
|
|
186
|
+
append(references, reference(
|
|
187
|
+
"selection", selection.id, "markConfig", ownerId,
|
|
188
|
+
["labelAuthoring", "selection", "id"]
|
|
189
|
+
));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return freezeOwned(references);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function collectGuideConfigReferences(program) {
|
|
196
|
+
const references = [];
|
|
197
|
+
for (const [family, configs] of Object.entries(program.guideConfigs ?? {})) {
|
|
198
|
+
collectKnownKeys(configs, [], (key, value, path, parentPath) => {
|
|
199
|
+
const ownerId = parentPath.length === 0 ? family : parentPath.join(".");
|
|
200
|
+
const relativePath = parentPath.length === 0
|
|
201
|
+
? path
|
|
202
|
+
: path.slice(parentPath.length);
|
|
203
|
+
if (key === "scale") {
|
|
204
|
+
append(references, reference(
|
|
205
|
+
"scale", value, family, ownerId, relativePath
|
|
206
|
+
));
|
|
207
|
+
} else if (key === "scales" && Array.isArray(value)) {
|
|
208
|
+
value.forEach((id, index) => append(references, reference(
|
|
209
|
+
"scale", id, family, ownerId, [...relativePath, index]
|
|
210
|
+
)));
|
|
211
|
+
} else if (key === "coordinate") {
|
|
212
|
+
append(references, reference(
|
|
213
|
+
"coordinate", value, family, ownerId, relativePath
|
|
214
|
+
));
|
|
215
|
+
} else if (key === "target") {
|
|
216
|
+
append(references, reference(
|
|
217
|
+
"mark", value, family, ownerId, relativePath
|
|
218
|
+
));
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
return freezeOwned(references);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function collectSelectionReferences(program) {
|
|
226
|
+
const references = [];
|
|
227
|
+
for (const [id, config] of Object.entries(
|
|
228
|
+
program.materializationConfigs.selections ?? {}
|
|
229
|
+
)) {
|
|
230
|
+
append(references, reference(
|
|
231
|
+
"mark", config.target, "selection", id, ["target"]
|
|
232
|
+
));
|
|
233
|
+
}
|
|
234
|
+
for (const [id, config] of Object.entries(
|
|
235
|
+
program.materializationConfigs.highlights ?? {}
|
|
236
|
+
)) {
|
|
237
|
+
append(references, reference(
|
|
238
|
+
"mark", config.target, "highlight", id, ["target"]
|
|
239
|
+
));
|
|
240
|
+
append(references, reference(
|
|
241
|
+
"selection", config.selection, "highlight", id, ["selection"]
|
|
242
|
+
));
|
|
243
|
+
}
|
|
244
|
+
return freezeOwned(references);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export function collectDataOwnerReferences(program) {
|
|
248
|
+
const references = [];
|
|
249
|
+
for (const [family, owners] of Object.entries(
|
|
250
|
+
program.materializationConfigs.data ?? {}
|
|
251
|
+
)) {
|
|
252
|
+
for (const [owner, config] of Object.entries(owners ?? {})) {
|
|
253
|
+
for (const key of ["current", "source", "previous"]) {
|
|
254
|
+
append(references, reference(
|
|
255
|
+
"data", config?.[key], "dataOwner", owner,
|
|
256
|
+
["data", family, owner, key]
|
|
257
|
+
));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return freezeOwned(references);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function collectCompositionReferences(program) {
|
|
265
|
+
const references = [];
|
|
266
|
+
const composition = program.compositionSpec;
|
|
267
|
+
if (composition?.type !== "facet") return freezeOwned(references);
|
|
268
|
+
append(references, reference(
|
|
269
|
+
"data", composition.facet.data, "composition", composition.id,
|
|
270
|
+
["facet", "data"]
|
|
271
|
+
));
|
|
272
|
+
append(references, reference(
|
|
273
|
+
"mark", composition.facet.repeat?.target, "composition", composition.id,
|
|
274
|
+
["facet", "repeat", "target"]
|
|
275
|
+
));
|
|
276
|
+
return freezeOwned(references);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export function collectContextReferences(program) {
|
|
280
|
+
const references = [];
|
|
281
|
+
for (const [key, kind] of Object.entries({
|
|
282
|
+
currentData: "data",
|
|
283
|
+
currentScale: "scale",
|
|
284
|
+
currentCoordinate: "coordinate",
|
|
285
|
+
currentMark: "mark",
|
|
286
|
+
currentSelection: "selection"
|
|
287
|
+
})) {
|
|
288
|
+
append(references, reference(
|
|
289
|
+
kind, program.context[key], "context", "program", [key], "context"
|
|
290
|
+
));
|
|
291
|
+
}
|
|
292
|
+
return freezeOwned(references);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function referenceKey(value) {
|
|
296
|
+
return [
|
|
297
|
+
value.kind, value.id, value.ownerKind, value.ownerId,
|
|
298
|
+
canonicalResourcePath(value.path), value.strength
|
|
299
|
+
].join("\u0000");
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function compareReferences(left, right) {
|
|
303
|
+
const leftKey = [
|
|
304
|
+
left.ownerKind, left.ownerId, canonicalResourcePath(left.path),
|
|
305
|
+
left.kind, left.id, left.strength
|
|
306
|
+
].join("\u0000");
|
|
307
|
+
const rightKey = [
|
|
308
|
+
right.ownerKind, right.ownerId, canonicalResourcePath(right.path),
|
|
309
|
+
right.kind, right.id, right.strength
|
|
310
|
+
].join("\u0000");
|
|
311
|
+
return leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export function collectResourceReferences(program, { kind, id }) {
|
|
315
|
+
if (!RESOURCE_KINDS.includes(kind)) {
|
|
316
|
+
throw new Error(`Unknown resource kind "${kind}".`);
|
|
317
|
+
}
|
|
318
|
+
const target = validateUserId(id, "Resource id");
|
|
319
|
+
const combined = [
|
|
320
|
+
...collectSemanticDataReferences(program),
|
|
321
|
+
...collectSemanticScaleReferences(program),
|
|
322
|
+
...collectSemanticCoordinateReferences(program),
|
|
323
|
+
...collectMarkConfigReferences(program),
|
|
324
|
+
...collectGuideConfigReferences(program),
|
|
325
|
+
...collectSelectionReferences(program),
|
|
326
|
+
...collectDataOwnerReferences(program),
|
|
327
|
+
...collectCompositionReferences(program),
|
|
328
|
+
...collectContextReferences(program)
|
|
329
|
+
].filter(value => value.kind === kind && value.id === target);
|
|
330
|
+
const unique = new Map(combined.map(value => [referenceKey(value), value]));
|
|
331
|
+
return freezeOwned([...unique.values()].sort(compareReferences));
|
|
332
|
+
}
|
package/src/core/vocabulary.js
CHANGED
|
@@ -13,13 +13,13 @@ export const MARK_TYPES = Object.freeze([
|
|
|
13
13
|
export const MARK_GRAPHIC_TYPES = Object.freeze({
|
|
14
14
|
point: Object.freeze(["circle", "rect", "path", "collection"]),
|
|
15
15
|
line: Object.freeze(["path"]),
|
|
16
|
-
bar: Object.freeze(["rect"]),
|
|
16
|
+
bar: Object.freeze(["rect", "collection"]),
|
|
17
17
|
area: Object.freeze(["path"]),
|
|
18
18
|
arc: Object.freeze(["path"]),
|
|
19
19
|
rule: Object.freeze(["line"]),
|
|
20
20
|
tick: Object.freeze(["line"]),
|
|
21
21
|
text: Object.freeze(["text"]),
|
|
22
|
-
rect: Object.freeze(["rect"])
|
|
22
|
+
rect: Object.freeze(["rect", "collection"])
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
export const ENCODING_CHANNELS = Object.freeze([
|
|
@@ -32,6 +32,7 @@ export const ENCODING_CHANNELS = Object.freeze([
|
|
|
32
32
|
"theta",
|
|
33
33
|
"radius",
|
|
34
34
|
"color",
|
|
35
|
+
"stroke",
|
|
35
36
|
"strokeDash",
|
|
36
37
|
"strokeWidth",
|
|
37
38
|
"size",
|
|
@@ -155,13 +156,21 @@ export const FACET_SCALE_CHANNELS = Object.freeze([
|
|
|
155
156
|
"y",
|
|
156
157
|
"xOffset",
|
|
157
158
|
"yOffset",
|
|
159
|
+
"theta",
|
|
160
|
+
"r",
|
|
158
161
|
"color",
|
|
162
|
+
"stroke",
|
|
159
163
|
"size",
|
|
160
164
|
"shape",
|
|
161
165
|
"opacity",
|
|
162
|
-
"strokeDash"
|
|
166
|
+
"strokeDash",
|
|
167
|
+
"parallelDimensions"
|
|
163
168
|
]);
|
|
164
169
|
|
|
170
|
+
export function facetSemanticChannel(channel) {
|
|
171
|
+
return channel === "r" ? "radius" : channel;
|
|
172
|
+
}
|
|
173
|
+
|
|
165
174
|
export const FACET_SCALE_RESOLUTIONS = Object.freeze([
|
|
166
175
|
"shared",
|
|
167
176
|
"independent"
|
|
@@ -198,6 +207,7 @@ export const STACK_MODES = Object.freeze(["zero", "normalize", "center"]);
|
|
|
198
207
|
|
|
199
208
|
export const CATEGORICAL_LEGEND_CHANNELS = Object.freeze([
|
|
200
209
|
"color",
|
|
210
|
+
"stroke",
|
|
201
211
|
"strokeDash",
|
|
202
212
|
"shape"
|
|
203
213
|
]);
|
|
@@ -212,9 +222,12 @@ export const LEGEND_CHANNELS = Object.freeze([
|
|
|
212
222
|
export const LEGEND_CONFIG_KINDS = Object.freeze([
|
|
213
223
|
"series",
|
|
214
224
|
"color",
|
|
225
|
+
"stroke",
|
|
215
226
|
"size",
|
|
216
227
|
"gradient",
|
|
217
228
|
"interval",
|
|
229
|
+
"strokeGradient",
|
|
230
|
+
"strokeInterval",
|
|
218
231
|
"opacity",
|
|
219
232
|
"strokeWidth"
|
|
220
233
|
]);
|