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
|
@@ -80,30 +80,30 @@ export function normalizePointHighlightStyle(args) {
|
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
function normalizeRectangularHighlightStyle(args, mark) {
|
|
84
84
|
for (const option of ["shape", "size", "offset", "strokeDash"]) {
|
|
85
85
|
if (args[option] !== undefined) {
|
|
86
|
-
throw new Error(
|
|
86
|
+
throw new Error(`${mark} highlight does not support ${option}.`);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
if (args.color !== undefined && args.fill !== undefined) {
|
|
90
|
-
throw new Error(
|
|
90
|
+
throw new Error(`${mark} highlight accepts color or fill, not both.`);
|
|
91
91
|
}
|
|
92
92
|
const fill = validateNonEmptyString(
|
|
93
93
|
args.fill ?? args.color ?? DEFAULT_COLORS.highlight,
|
|
94
|
-
|
|
94
|
+
`${mark} highlight fill`
|
|
95
95
|
);
|
|
96
96
|
const opacity = args.opacity === undefined
|
|
97
97
|
? undefined
|
|
98
|
-
: validateUnitInterval(args.opacity,
|
|
98
|
+
: validateUnitInterval(args.opacity, `${mark} highlight opacity`);
|
|
99
99
|
const stroke = args.stroke === undefined
|
|
100
100
|
? undefined
|
|
101
|
-
: validateNonEmptyString(args.stroke,
|
|
101
|
+
: validateNonEmptyString(args.stroke, `${mark} highlight stroke`);
|
|
102
102
|
const strokeWidth = args.strokeWidth === undefined
|
|
103
103
|
? undefined
|
|
104
|
-
: validateNonNegativeFinite(args.strokeWidth,
|
|
104
|
+
: validateNonNegativeFinite(args.strokeWidth, `${mark} highlight strokeWidth`);
|
|
105
105
|
if (strokeWidth !== undefined && stroke === undefined) {
|
|
106
|
-
throw new Error(
|
|
106
|
+
throw new Error(`${mark} highlight strokeWidth requires stroke.`);
|
|
107
107
|
}
|
|
108
108
|
return {
|
|
109
109
|
fill,
|
|
@@ -113,6 +113,14 @@ export function normalizeBarHighlightStyle(args) {
|
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
export function normalizeBarHighlightStyle(args) {
|
|
117
|
+
return normalizeRectangularHighlightStyle(args, "Bar");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function normalizeRectHighlightStyle(args) {
|
|
121
|
+
return normalizeRectangularHighlightStyle(args, "Rect");
|
|
122
|
+
}
|
|
123
|
+
|
|
116
124
|
function rejectHighlightOptions(args, mark, options) {
|
|
117
125
|
for (const option of options) {
|
|
118
126
|
if (args[option] !== undefined) {
|
|
@@ -154,28 +162,28 @@ export function normalizeStrokeHighlightStyle(args, mark) {
|
|
|
154
162
|
};
|
|
155
163
|
}
|
|
156
164
|
|
|
157
|
-
export function normalizeAreaHighlightStyle(args) {
|
|
158
|
-
rejectHighlightOptions(args,
|
|
165
|
+
export function normalizeAreaHighlightStyle(args, mark = "Area") {
|
|
166
|
+
rejectHighlightOptions(args, mark, ["shape", "size", "strokeDash"]);
|
|
159
167
|
if (args.color !== undefined && args.fill !== undefined) {
|
|
160
|
-
throw new Error(
|
|
168
|
+
throw new Error(`${mark} highlight accepts color or fill, not both.`);
|
|
161
169
|
}
|
|
162
170
|
const stroke = args.stroke === undefined
|
|
163
171
|
? undefined
|
|
164
|
-
: validateNonEmptyString(args.stroke,
|
|
172
|
+
: validateNonEmptyString(args.stroke, `${mark} highlight stroke`);
|
|
165
173
|
const strokeWidth = args.strokeWidth === undefined
|
|
166
174
|
? undefined
|
|
167
|
-
: validateNonNegativeFinite(args.strokeWidth,
|
|
175
|
+
: validateNonNegativeFinite(args.strokeWidth, `${mark} highlight strokeWidth`);
|
|
168
176
|
if (strokeWidth !== undefined && stroke === undefined) {
|
|
169
|
-
throw new Error(
|
|
177
|
+
throw new Error(`${mark} highlight strokeWidth requires stroke.`);
|
|
170
178
|
}
|
|
171
179
|
return {
|
|
172
180
|
fill: validateNonEmptyString(
|
|
173
181
|
args.fill ?? args.color ?? DEFAULT_COLORS.highlight,
|
|
174
|
-
|
|
182
|
+
`${mark} highlight fill`
|
|
175
183
|
),
|
|
176
184
|
...(args.opacity === undefined
|
|
177
185
|
? {}
|
|
178
|
-
: { opacity: validateUnitInterval(args.opacity,
|
|
186
|
+
: { opacity: validateUnitInterval(args.opacity, `${mark} highlight opacity`) }),
|
|
179
187
|
...(stroke === undefined ? {} : { stroke }),
|
|
180
188
|
...(strokeWidth === undefined ? {} : { strokeWidth }),
|
|
181
189
|
offset: normalizeOffset(args.offset)
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { resolveBarChannels } from "../grammar/bars/policy.js";
|
|
2
|
+
import { formatTextValue } from "../grammar/text.js";
|
|
3
|
+
import { findDataset } from "../selectors/datasets.js";
|
|
4
|
+
import { findLayer } from "../selectors/layers.js";
|
|
5
|
+
import { resolveMarkItems } from "./selection/policies/index.js";
|
|
6
|
+
import { mapScaleConsumerValues } from "./scales/map.js";
|
|
7
|
+
import { resolveRowEncodingValues } from "./rowEncoding.js";
|
|
8
|
+
|
|
9
|
+
function sourceValue(item, source, field) {
|
|
10
|
+
if (Object.hasOwn(item.fields, field)) return item.fields[field];
|
|
11
|
+
for (const [channel, encoding] of Object.entries(source.encoding ?? {})) {
|
|
12
|
+
if (encoding?.field !== field || item.channels[channel] === undefined) continue;
|
|
13
|
+
if (source.mark.type === "bar" && item.channels[`${channel}2`] !== undefined) {
|
|
14
|
+
return item.channels[`${channel}2`];
|
|
15
|
+
}
|
|
16
|
+
return item.channels[channel];
|
|
17
|
+
}
|
|
18
|
+
if (item.members.length === 1 && Object.hasOwn(item.members[0], field)) {
|
|
19
|
+
return item.members[0][field];
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function barAnchor(program, source, item) {
|
|
25
|
+
const channels = resolveBarChannels(source);
|
|
26
|
+
const measure = channels.measure;
|
|
27
|
+
const endpoint = item.channels[`${measure}2`];
|
|
28
|
+
const scale = program.resolvedScales[source.encoding[measure].scale];
|
|
29
|
+
const mapped = endpoint === undefined || scale === undefined
|
|
30
|
+
? undefined
|
|
31
|
+
: mapScaleConsumerValues([endpoint], scale, measure)[0];
|
|
32
|
+
return measure === "x"
|
|
33
|
+
? {
|
|
34
|
+
x: mapped ?? item.properties.x + item.properties.width,
|
|
35
|
+
y: item.properties.y + item.properties.height / 2
|
|
36
|
+
}
|
|
37
|
+
: {
|
|
38
|
+
x: item.properties.x + item.properties.width / 2,
|
|
39
|
+
y: mapped ?? item.properties.y
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function sourceAnchor(program, source, item) {
|
|
44
|
+
if (source.mark.type === "bar") return barAnchor(program, source, item);
|
|
45
|
+
if (source.mark.type === "rect") {
|
|
46
|
+
return {
|
|
47
|
+
x: item.properties.x + item.properties.width / 2,
|
|
48
|
+
y: item.properties.y + item.properties.height / 2
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (source.mark.type === "rule") {
|
|
52
|
+
return {
|
|
53
|
+
x: item.properties.x2,
|
|
54
|
+
y: item.properties.y2
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return { x: item.properties.x, y: item.properties.y };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function contentValue(encoding, rowOrItem, source) {
|
|
61
|
+
return Object.hasOwn(encoding, "field")
|
|
62
|
+
? source === undefined
|
|
63
|
+
? rowOrItem[encoding.field]
|
|
64
|
+
: sourceValue(rowOrItem, source, encoding.field)
|
|
65
|
+
: encoding.datum;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function concreteItem(config, position, value, format) {
|
|
69
|
+
const text = formatTextValue(value, format);
|
|
70
|
+
const x = position.x;
|
|
71
|
+
const y = position.y;
|
|
72
|
+
if (text === undefined || !Number.isFinite(x) || !Number.isFinite(y)) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
type: "text",
|
|
77
|
+
properties: {
|
|
78
|
+
x: x + config.dx,
|
|
79
|
+
y: y + config.dy,
|
|
80
|
+
text,
|
|
81
|
+
fill: config.fill,
|
|
82
|
+
opacity: config.opacity,
|
|
83
|
+
fontSize: config.fontSize,
|
|
84
|
+
fontFamily: config.fontFamily,
|
|
85
|
+
fontWeight: config.fontWeight,
|
|
86
|
+
textAlign: config.align,
|
|
87
|
+
textBaseline: config.baseline,
|
|
88
|
+
rotation: config.rotation
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function relativeLuminance(color) {
|
|
94
|
+
if (typeof color !== "string" || !/^#[0-9a-f]{6}$/i.test(color)) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
const channels = [1, 3, 5].map(offset =>
|
|
98
|
+
Number.parseInt(color.slice(offset, offset + 2), 16) / 255
|
|
99
|
+
).map(value => value <= 0.04045
|
|
100
|
+
? value / 12.92
|
|
101
|
+
: ((value + 0.055) / 1.055) ** 2.4
|
|
102
|
+
);
|
|
103
|
+
return 0.2126 * channels[0] + 0.7152 * channels[1] + 0.0722 * channels[2];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function sourceTextConfig(config, source, item) {
|
|
107
|
+
if (source.mark.type !== "rect" || config.fillExplicit === true) return config;
|
|
108
|
+
const luminance = relativeLuminance(item.properties.fill);
|
|
109
|
+
if (luminance === undefined) return config;
|
|
110
|
+
return {
|
|
111
|
+
...config,
|
|
112
|
+
fill: luminance >= 0.26 ? "#0f172a" : "#f8fafc"
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function resolveSourceTextItems(program, layer, config) {
|
|
117
|
+
const source = findLayer(program, layer.source);
|
|
118
|
+
if (source === undefined) {
|
|
119
|
+
throw new Error(`Text mark "${layer.id}" requires source layer "${layer.source}".`);
|
|
120
|
+
}
|
|
121
|
+
const items = resolveMarkItems(program, source.id);
|
|
122
|
+
return items.flatMap(item => {
|
|
123
|
+
const concrete = concreteItem(
|
|
124
|
+
sourceTextConfig(config, source, item),
|
|
125
|
+
sourceAnchor(program, source, item),
|
|
126
|
+
contentValue(layer.encoding.text, item, source),
|
|
127
|
+
layer.encoding.text.format
|
|
128
|
+
);
|
|
129
|
+
return concrete === undefined ? [] : [concrete];
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function resolveRowTextItems(program, layer, config) {
|
|
134
|
+
const dataset = findDataset(program, layer.data);
|
|
135
|
+
if (dataset === undefined) {
|
|
136
|
+
throw new Error(`Text mark "${layer.id}" requires an existing dataset.`);
|
|
137
|
+
}
|
|
138
|
+
const x = resolveRowEncodingValues(program, layer, dataset, "x");
|
|
139
|
+
const y = resolveRowEncodingValues(program, layer, dataset, "y");
|
|
140
|
+
if (x === undefined || y === undefined) return [];
|
|
141
|
+
return dataset.values.flatMap((row, index) => {
|
|
142
|
+
const concrete = concreteItem(
|
|
143
|
+
config,
|
|
144
|
+
{ x: x[index], y: y[index] },
|
|
145
|
+
contentValue(layer.encoding.text, row),
|
|
146
|
+
layer.encoding.text.format
|
|
147
|
+
);
|
|
148
|
+
return concrete === undefined ? [] : [concrete];
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function resolveTextGraphicItems(program, layer, config) {
|
|
153
|
+
return layer.source === undefined
|
|
154
|
+
? resolveRowTextItems(program, layer, config)
|
|
155
|
+
: resolveSourceTextItems(program, layer, config);
|
|
156
|
+
}
|
|
@@ -4,7 +4,10 @@ import { drawPathGraphic } from "./path.js";
|
|
|
4
4
|
import { drawRectGraphic } from "./rect.js";
|
|
5
5
|
import { drawTextGraphic } from "./text.js";
|
|
6
6
|
import { requireFiniteProperty } from "./validation.js";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
requireSingleOrderedGraphicByType,
|
|
9
|
+
walkGraphicTreeEvents
|
|
10
|
+
} from "../../grammar/schemas/graphicTree.js";
|
|
8
11
|
|
|
9
12
|
const DRAWERS = Object.freeze({
|
|
10
13
|
circle: drawCircleGraphic,
|
|
@@ -46,16 +49,41 @@ function requireCanvasContext(context) {
|
|
|
46
49
|
}
|
|
47
50
|
}
|
|
48
51
|
|
|
49
|
-
function
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
function requireContextMethod(context, method, label) {
|
|
53
|
+
if (typeof context[method] !== "function") {
|
|
54
|
+
throw new TypeError(`${label} requires Canvas context ${method}().`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
53
57
|
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
function fillCanvasBackground(context, id, canvas, width, height) {
|
|
59
|
+
if (canvas.properties.background === undefined) return;
|
|
60
|
+
if (typeof canvas.properties.background !== "string") {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`Graphic "${id}" requires a string background property.`
|
|
63
|
+
);
|
|
56
64
|
}
|
|
65
|
+
context.globalAlpha = 1;
|
|
66
|
+
context.fillStyle = canvas.properties.background;
|
|
67
|
+
context.fillRect(0, 0, width, height);
|
|
68
|
+
}
|
|
57
69
|
|
|
58
|
-
|
|
70
|
+
function enterNestedCanvas(context, id, canvas) {
|
|
71
|
+
const properties = canvas.properties ?? {};
|
|
72
|
+
const x = requireFiniteProperty(properties, "x", id);
|
|
73
|
+
const y = requireFiniteProperty(properties, "y", id);
|
|
74
|
+
const width = requireFiniteProperty(properties, "width", id);
|
|
75
|
+
const height = requireFiniteProperty(properties, "height", id);
|
|
76
|
+
if (width < 0 || height < 0) {
|
|
77
|
+
throw new Error(`Nested Canvas "${id}" width and height must not be negative.`);
|
|
78
|
+
}
|
|
79
|
+
requireContextMethod(context, "rect", `Nested Canvas "${id}"`);
|
|
80
|
+
requireContextMethod(context, "clip", `Nested Canvas "${id}"`);
|
|
81
|
+
context.save();
|
|
82
|
+
context.translate(x, y);
|
|
83
|
+
context.beginPath();
|
|
84
|
+
context.rect(0, 0, width, height);
|
|
85
|
+
context.clip();
|
|
86
|
+
fillCanvasBackground(context, id, canvas, width, height);
|
|
59
87
|
}
|
|
60
88
|
|
|
61
89
|
export function render(program, context, { pixelRatio = 1 } = {}) {
|
|
@@ -77,7 +105,8 @@ export function render(program, context, { pixelRatio = 1 } = {}) {
|
|
|
77
105
|
throw new RangeError("render pixelRatio must be a positive finite number.");
|
|
78
106
|
}
|
|
79
107
|
|
|
80
|
-
const { id: canvasId,
|
|
108
|
+
const { id: canvasId, object: canvas } =
|
|
109
|
+
requireSingleOrderedGraphicByType(graphicSpec, "canvas");
|
|
81
110
|
const width = requireFiniteProperty(canvas.properties ?? {}, "width", canvasId);
|
|
82
111
|
const height = requireFiniteProperty(
|
|
83
112
|
canvas.properties ?? {},
|
|
@@ -97,20 +126,37 @@ export function render(program, context, { pixelRatio = 1 } = {}) {
|
|
|
97
126
|
context.scale(pixelRatio, pixelRatio);
|
|
98
127
|
context.clearRect(0, 0, width, height);
|
|
99
128
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
);
|
|
129
|
+
fillCanvasBackground(context, canvasId, canvas, width, height);
|
|
130
|
+
|
|
131
|
+
walkGraphicTreeEvents(graphicSpec, {
|
|
132
|
+
enter({ id, object }) {
|
|
133
|
+
if (id === canvasId) return;
|
|
134
|
+
if (object.type === "canvas") {
|
|
135
|
+
enterNestedCanvas(context, id, object);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (object.type === "collection") {
|
|
139
|
+
context.save();
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (!Array.isArray(object.items)) {
|
|
143
|
+
drawConcreteGraphic(context, id, object);
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
item({ id, object, owner }) {
|
|
147
|
+
drawConcreteGraphic(context, id, {
|
|
148
|
+
...object,
|
|
149
|
+
type: object.type ?? owner.type
|
|
150
|
+
});
|
|
151
|
+
},
|
|
152
|
+
exit({ id, object }) {
|
|
153
|
+
if (
|
|
154
|
+
id !== canvasId &&
|
|
155
|
+
(object.type === "collection" || object.type === "canvas")
|
|
156
|
+
) {
|
|
157
|
+
context.restore();
|
|
158
|
+
}
|
|
105
159
|
}
|
|
106
|
-
|
|
107
|
-
context.globalAlpha = 1;
|
|
108
|
-
context.fillStyle = canvas.properties.background;
|
|
109
|
-
context.fillRect(0, 0, width, height);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
walkGraphicDrawOrder(graphicSpec, ({ id, object }) => {
|
|
113
|
-
if (id !== canvasId) drawConcreteGraphic(context, id, object);
|
|
114
160
|
});
|
|
115
161
|
} finally {
|
|
116
162
|
context.restore();
|
package/types/extension.d.ts
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChartProgram } from "./program.js";
|
|
1
|
+
import type { ChartProgram, CompositionOptions } from "./program.js";
|
|
2
2
|
|
|
3
3
|
export type {
|
|
4
4
|
ActionOptions,
|
|
@@ -18,19 +18,56 @@ export type {
|
|
|
18
18
|
ColorLayout,
|
|
19
19
|
ColorEncodingOptions,
|
|
20
20
|
CompleteAxisOptions,
|
|
21
|
+
ConcatCompositionSpec,
|
|
22
|
+
CompositionAlign,
|
|
23
|
+
CompositionOptions,
|
|
24
|
+
CompositionPadding,
|
|
25
|
+
CompositionProgramEntry,
|
|
26
|
+
CompositionSpec,
|
|
21
27
|
ChartProgram,
|
|
22
28
|
ConcretePathCommand,
|
|
23
29
|
CurveInterpolation,
|
|
30
|
+
CreateDerivedDataOptions,
|
|
24
31
|
CreateAxesOptions,
|
|
32
|
+
CreateCoordinateOptions,
|
|
33
|
+
CreateGuidesOptions,
|
|
25
34
|
CreateGridOptions,
|
|
35
|
+
CreateRegressionBandOptions,
|
|
36
|
+
CreateRegressionLineOptions,
|
|
37
|
+
CreateScaleOptions,
|
|
26
38
|
DashPattern,
|
|
27
39
|
DashScaleOptions,
|
|
28
40
|
DashStyle,
|
|
41
|
+
DatasetDensityTransform,
|
|
42
|
+
DatasetFilterTransform,
|
|
43
|
+
DatasetIntervalOutputFields,
|
|
44
|
+
DatasetIntervalTransform,
|
|
45
|
+
DatasetRegressionTransform,
|
|
46
|
+
DatasetScalar,
|
|
47
|
+
DatasetTransform,
|
|
29
48
|
EditGraphicsOptions,
|
|
49
|
+
EditCompositionLayoutOptions,
|
|
50
|
+
EditFacetHeadersOptions,
|
|
51
|
+
EditAxisOptions,
|
|
52
|
+
EditGridDirectionsOptions,
|
|
30
53
|
EditGridOptions,
|
|
54
|
+
EditErrorBandBoundaryOptions,
|
|
55
|
+
EditErrorBandOptions,
|
|
56
|
+
EditErrorBarOptions,
|
|
57
|
+
EditBoxPlotOptions,
|
|
58
|
+
EditLegendBorderOptions,
|
|
59
|
+
EditLegendLabelsOptions,
|
|
60
|
+
EditLegendLayoutOptions,
|
|
61
|
+
EditLegendSymbolsOptions,
|
|
62
|
+
EditLegendTitleOptions,
|
|
31
63
|
EditScaleOptions,
|
|
32
64
|
EditSemanticOptions,
|
|
33
65
|
FieldType,
|
|
66
|
+
FacetCompositionSpec,
|
|
67
|
+
FacetGuideOptions,
|
|
68
|
+
FacetOptions,
|
|
69
|
+
FacetScaleResolution,
|
|
70
|
+
FacetScaleResolutions,
|
|
34
71
|
GraphicObject,
|
|
35
72
|
GraphicSpec,
|
|
36
73
|
GraphicType,
|
|
@@ -57,23 +94,41 @@ export type {
|
|
|
57
94
|
RegressionInterval,
|
|
58
95
|
RegressionMethod,
|
|
59
96
|
RegressionOptions,
|
|
97
|
+
RectMarkOptions,
|
|
98
|
+
ReplaceCompositionChildOptions,
|
|
99
|
+
EditRegressionOptions,
|
|
100
|
+
EditRectMarkOptions,
|
|
101
|
+
RemoveAxisOptions,
|
|
102
|
+
RemoveGridOptions,
|
|
103
|
+
RemoveLegendOptions,
|
|
104
|
+
RemoveMarkOptions,
|
|
60
105
|
ScaleRange,
|
|
61
106
|
ScaleOptions,
|
|
62
107
|
ScaleType,
|
|
63
108
|
StackMode,
|
|
109
|
+
SemanticCoordinate,
|
|
110
|
+
SemanticDataset,
|
|
111
|
+
SemanticLayer,
|
|
112
|
+
SemanticScale,
|
|
64
113
|
SemanticSpec,
|
|
65
114
|
SelectMarksOptions,
|
|
66
115
|
StrokeDashEncodingOptions,
|
|
67
116
|
TraceNode,
|
|
68
117
|
TitleOptions,
|
|
69
118
|
EditTitleOptions,
|
|
119
|
+
EditTextMarkOptions,
|
|
70
120
|
TitleTextStyleOptions,
|
|
121
|
+
TextEncodingOptions,
|
|
122
|
+
TextFormat,
|
|
123
|
+
TextMarkOptions,
|
|
71
124
|
XAxisPosition,
|
|
72
125
|
YAxisPosition,
|
|
73
126
|
XOffsetEncodingOptions
|
|
74
127
|
} from "./program.js";
|
|
75
128
|
|
|
76
129
|
export function chart(): ChartProgram;
|
|
130
|
+
export function hconcat(options: CompositionOptions): ChartProgram;
|
|
131
|
+
export function vconcat(options: CompositionOptions): ChartProgram;
|
|
77
132
|
export function render(
|
|
78
133
|
program: Pick<ChartProgram, "graphicSpec">,
|
|
79
134
|
context: CanvasRenderingContext2D,
|