ggaction 0.0.11 → 0.0.13
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 +80 -0
- package/README.md +3 -2
- package/knowledge/action-card.schema.json +1 -1
- package/knowledge/action-cards.json +1 -1
- package/knowledge/action-cards.schema.json +1 -1
- package/knowledge/extension-authoring.md +2 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/knowledge/task-resolver.js +1 -1
- package/package.json +4 -2
- package/src/actions/basic.js +2 -0
- package/src/actions/boxPlots/materialize.js +2 -1
- package/src/actions/canvas/actions.js +3 -1
- package/src/actions/canvas/fitting.js +211 -0
- package/src/actions/canvas/index.js +2 -0
- package/src/actions/categoryOrder/index.js +3 -2
- package/src/actions/charts/area.js +47 -0
- package/src/actions/charts/bar.js +11 -5
- package/src/actions/charts/beeswarm.js +70 -0
- package/src/actions/charts/density.js +44 -0
- package/src/actions/charts/ecdf.js +183 -0
- package/src/actions/charts/endpoints.js +451 -0
- package/src/actions/charts/heatmap.js +2 -2
- package/src/actions/charts/histogram.js +1 -1
- package/src/actions/charts/horizon.js +71 -0
- package/src/actions/charts/index.js +37 -0
- package/src/actions/charts/interval-regression.js +169 -0
- package/src/actions/charts/line.js +5 -5
- package/src/actions/charts/parallel.js +1 -1
- package/src/actions/charts/pie.js +44 -0
- package/src/actions/charts/polar.js +123 -0
- package/src/actions/charts/radar.js +299 -0
- package/src/actions/charts/radial.js +42 -0
- package/src/actions/charts/raincloud.js +422 -0
- package/src/actions/charts/rug-strip.js +279 -0
- package/src/actions/charts/scatter.js +9 -3
- package/src/actions/charts/shared.js +69 -10
- package/src/actions/composition/actions.js +118 -1
- package/src/actions/data/bin.js +29 -0
- package/src/actions/data/computed.js +24 -0
- package/src/actions/data/derived.js +66 -0
- package/src/actions/data/ecdf.js +38 -0
- package/src/actions/data/filter.js +212 -28
- package/src/actions/data/fold.js +24 -0
- package/src/actions/data/index.js +24 -0
- package/src/actions/data/interval.js +2 -0
- package/src/actions/data/intervalEdit.js +86 -4
- package/src/actions/data/regression.js +5 -2
- package/src/actions/data/stack.js +26 -0
- package/src/actions/data/summary.js +26 -0
- package/src/actions/data/timeUnit.js +1 -1
- package/src/actions/encodings/appearance.js +32 -13
- package/src/actions/encodings/barWidth.js +8 -0
- package/src/actions/encodings/basic.js +2 -0
- package/src/actions/encodings/color/continuous.js +19 -59
- package/src/actions/encodings/color/index.js +28 -22
- package/src/actions/encodings/color/layout.js +3 -97
- package/src/actions/encodings/color/policy.js +5 -8
- package/src/actions/encodings/density/resolve.js +37 -5
- package/src/actions/encodings/density.js +120 -33
- package/src/actions/encodings/horizon/resolve.js +8 -4
- package/src/actions/encodings/horizon.js +18 -8
- package/src/actions/encodings/index.js +2 -0
- package/src/actions/encodings/offset.js +33 -27
- package/src/actions/encodings/parallel.js +2 -8
- package/src/actions/encodings/position/apply.js +40 -4
- package/src/actions/encodings/position/index.js +43 -5
- package/src/actions/encodings/position/policies/arc.js +37 -2
- package/src/actions/encodings/position/policies/area.js +4 -42
- package/src/actions/encodings/position/policies/bar.js +48 -13
- package/src/actions/encodings/position/resolve.js +79 -24
- package/src/actions/encodings/ranged.js +123 -97
- package/src/actions/encodings/remove.js +37 -32
- package/src/actions/encodings/ruleAppearance.js +23 -9
- package/src/actions/encodings/seriesLayout.js +104 -0
- package/src/actions/encodings/shared.js +25 -23
- package/src/actions/encodings/strokeDash.js +9 -6
- package/src/actions/encodings/temporal.js +7 -0
- package/src/actions/encodings/text.js +30 -15
- package/src/actions/errorBands/create.js +18 -5
- package/src/actions/errorBands/edit.js +341 -21
- package/src/actions/errorBars/create.js +153 -11
- package/src/actions/errorBars/edit.js +365 -19
- package/src/actions/facets/actions.js +410 -12
- package/src/actions/facets/derive.js +57 -8
- package/src/actions/gradientPlots/components.js +33 -11
- package/src/actions/gradientPlots/materialize.js +5 -7
- package/src/actions/guides/applicability.js +20 -17
- package/src/actions/guides/axes/axes.js +4 -3
- package/src/actions/guides/axes/axis.js +18 -18
- package/src/actions/guides/axes/components.js +43 -0
- package/src/actions/guides/axes/edit.js +16 -51
- package/src/actions/guides/axes/labels.js +129 -19
- package/src/actions/guides/axes/lines.js +7 -5
- package/src/actions/guides/axes/parallel/lifecycle.js +117 -0
- package/src/actions/guides/axes/parallel/policy.js +137 -0
- package/src/actions/guides/axes/parallel/resolve.js +44 -23
- package/src/actions/guides/axes/parallel.js +93 -217
- package/src/actions/guides/axes/policy.js +21 -67
- package/src/actions/guides/axes/tickGroups.js +14 -8
- package/src/actions/guides/axes/ticks.js +5 -4
- package/src/actions/guides/axes/titles.js +21 -8
- package/src/actions/guides/basic.js +2 -0
- package/src/actions/guides/facade.js +106 -0
- package/src/actions/guides/facadeAxes.js +200 -0
- package/src/actions/guides/facadeLegend.js +63 -0
- package/src/actions/guides/grids/grid.js +37 -33
- package/src/actions/guides/grids/resolve.js +10 -2
- package/src/actions/guides/guides.js +35 -28
- package/src/actions/guides/legends/categorical/actions.js +193 -249
- package/src/actions/guides/legends/categorical/components.js +4 -5
- package/src/actions/guides/legends/categorical/layout.js +36 -349
- package/src/actions/guides/legends/categorical/options.js +30 -14
- package/src/actions/guides/legends/categorical/recipes.js +14 -0
- package/src/actions/guides/legends/categorical/resolve.js +21 -10
- package/src/actions/guides/legends/categorical/symbols.js +2 -3
- package/src/actions/guides/legends/continuous/common.js +69 -14
- package/src/actions/guides/legends/continuous/gradient.js +111 -83
- package/src/actions/guides/legends/continuous/index.js +6 -2
- package/src/actions/guides/legends/continuous/interval.js +71 -92
- package/src/actions/guides/legends/continuous/opacity.js +105 -84
- package/src/actions/guides/legends/creation.js +27 -0
- package/src/actions/guides/legends/edit.js +198 -66
- package/src/actions/guides/legends/focused.js +2 -2
- package/src/actions/guides/legends/lane.js +98 -86
- package/src/actions/guides/legends/lifecycle.js +132 -0
- package/src/actions/guides/legends/remove.js +31 -76
- package/src/actions/guides/legends/size.js +149 -105
- package/src/actions/guides/legends/strokeWidth.js +106 -64
- package/src/actions/guides/legends/target.js +12 -0
- package/src/actions/guides/legends/transition.js +43 -0
- package/src/actions/guides/polar/axes/facade.js +77 -62
- package/src/actions/guides/polar/axes/labels.js +5 -4
- package/src/actions/guides/polar/axes/lines.js +2 -1
- package/src/actions/guides/polar/axes/shared.js +6 -0
- package/src/actions/guides/polar/axes/ticks.js +5 -4
- package/src/actions/guides/polar/axes/titles.js +5 -4
- package/src/actions/guides/polar/grids.js +7 -7
- package/src/actions/guides/reuse.js +44 -0
- package/src/actions/guides/tickValues.js +19 -21
- package/src/actions/index.js +2 -0
- package/src/actions/intervals/resolve.js +35 -15
- package/src/actions/marks/arc/actions.js +1 -1
- package/src/actions/marks/area/actions.js +18 -4
- package/src/actions/marks/area/materialize.js +5 -2
- package/src/actions/marks/bar/materialize.js +11 -7
- package/src/actions/marks/index.js +5 -0
- package/src/actions/marks/line/actions.js +43 -108
- package/src/actions/marks/line/materialize.js +34 -52
- package/src/actions/marks/point/edit.js +11 -15
- package/src/actions/marks/point/index.js +1 -0
- package/src/actions/marks/point/jitter.js +3 -0
- package/src/actions/marks/point/materialize.js +138 -14
- package/src/actions/marks/point/packing.js +68 -0
- package/src/actions/marks/references.js +87 -0
- package/src/actions/marks/remove.js +17 -4
- package/src/actions/marks/rule/actions.js +60 -4
- package/src/actions/marks/rule/appearance.js +26 -0
- package/src/actions/marks/shared.js +12 -12
- package/src/actions/marks/text/actions.js +224 -6
- package/src/actions/marks/text/layout.js +2 -2
- package/src/actions/primitives/createGraphics.js +3 -1
- package/src/actions/primitives/semantic.js +1 -1
- package/src/actions/primitives/semanticAction.js +39 -2
- package/src/actions/primitives/semanticValidation/guide.js +10 -0
- package/src/actions/primitives/semanticValidation/layer.js +18 -1
- package/src/actions/primitives/semanticValidation/scale.js +10 -1
- package/src/actions/regression/create.js +1 -1
- package/src/actions/regression/edit.js +19 -6
- package/src/actions/regression/resolve.js +1 -1
- package/src/actions/scales/consumers/common.js +20 -53
- package/src/actions/scales/consumers/families.js +27 -14
- package/src/actions/scales/consumers/index.js +23 -2
- package/src/actions/scales/consumers/seriesLayout.js +33 -2
- package/src/actions/scales/create.js +4 -4
- package/src/actions/scales/definitions.js +19 -3
- package/src/actions/scales/edit.js +46 -34
- package/src/actions/scales/editPolicy.js +21 -31
- package/src/actions/scales/materialize.js +10 -46
- package/src/actions/scales/patch.js +1 -1
- package/src/actions/scales/preview.js +39 -0
- package/src/actions/scales/quantitativeColor.js +9 -5
- package/src/actions/theme/actions.js +43 -0
- package/src/actions/theme/index.js +9 -0
- package/src/actions/theme/reconcile.js +882 -0
- package/src/actions/titles/actions.js +11 -10
- package/src/actions/titles/resolve.js +1 -40
- package/src/actions/violinPlots/create.js +86 -42
- package/src/actions/violinPlots/edit.js +191 -0
- package/src/actions/violinPlots/index.js +2 -0
- package/src/core/ChartProgram.js +7 -0
- package/src/core/action.js +22 -2
- package/src/core/compositionState.js +136 -8
- package/src/core/vocabulary.js +2 -2
- package/src/grammar/aggregate.js +66 -23
- package/src/grammar/arcs.js +213 -65
- package/src/grammar/areaEndpoints.js +46 -0
- package/src/grammar/areaSeries.js +87 -41
- package/src/grammar/bars/aggregate.js +33 -12
- package/src/grammar/bars/policy.js +9 -7
- package/src/grammar/bin.js +181 -0
- package/src/grammar/categoryOrder.js +34 -0
- package/src/grammar/computed.js +150 -0
- package/src/grammar/ecdf.js +198 -0
- package/src/grammar/facets/index.js +117 -6
- package/src/grammar/fold.js +123 -0
- package/src/grammar/horizon.js +6 -4
- package/src/grammar/interval.js +37 -20
- package/src/grammar/lineSeries.js +20 -63
- package/src/grammar/markFilter.js +22 -4
- package/src/grammar/markLabels.js +93 -0
- package/src/grammar/parallelAxisTitles.js +16 -0
- package/src/grammar/pathSeries.js +91 -0
- package/src/grammar/pointPacking.js +183 -0
- package/src/grammar/positionCompatibility.js +1 -1
- package/src/grammar/positionDatum.js +12 -0
- package/src/grammar/rects.js +9 -1
- package/src/grammar/regression/derive.js +4 -0
- package/src/grammar/regression/index.js +7 -2
- package/src/grammar/regression/models.js +22 -7
- package/src/grammar/regression/parameters.js +40 -13
- package/src/grammar/rotation.js +29 -0
- package/src/grammar/rules.js +9 -21
- package/src/grammar/scales/color.js +23 -1
- package/src/grammar/scales/colorConsumers.js +38 -0
- package/src/grammar/scales/definition.js +15 -1
- package/src/grammar/scales/discretized.js +11 -5
- package/src/grammar/scales/fields.js +38 -8
- package/src/grammar/scales/mapping.js +2 -0
- package/src/grammar/scales/ordinal.js +23 -0
- package/src/grammar/scales/radial.js +55 -0
- package/src/grammar/scales/types.js +1 -0
- package/src/grammar/schemas/semanticPath.js +17 -3
- package/src/grammar/stack.js +170 -0
- package/src/grammar/statistics/confidenceInterval.js +101 -0
- package/src/grammar/summary.js +183 -0
- package/src/grammar/text.js +22 -16
- package/src/grammar/timeUnit.js +21 -11
- package/src/grammar/transformTopology.js +6 -0
- package/src/grammar/transforms.js +36 -0
- package/src/grammar/valueFormat.js +112 -0
- package/src/grammar/window.js +13 -7
- package/src/layout/facets.js +86 -23
- package/src/layout/guideCollisions.js +12 -0
- package/src/layout/legend.js +2 -10
- package/src/layout/legendItems.js +102 -0
- package/src/layout/legendLane.js +100 -11
- package/src/materialization/bars/aggregate.js +38 -152
- package/src/materialization/bars/histogram.js +24 -0
- package/src/materialization/categorySlotOffset.js +40 -0
- package/src/materialization/compositionSnapshot.js +1 -1
- package/src/materialization/dependencies.js +57 -16
- package/src/materialization/encodings.js +1 -1
- package/src/materialization/facetGuides/legacyCategorical.js +7 -1
- package/src/materialization/facetGuides/placement.js +16 -1
- package/src/materialization/facetGuides/preparation.js +26 -1
- package/src/materialization/facets.js +11 -2
- package/src/materialization/guides/layout.js +57 -0
- package/src/materialization/guides/resources.js +2 -2
- package/src/materialization/legends.js +10 -1
- package/src/materialization/marks/capabilities.js +30 -7
- package/src/materialization/marks/grouping.js +52 -0
- package/src/materialization/marks/index.js +63 -25
- package/src/materialization/marks/policies.js +2 -0
- package/src/materialization/rect.js +33 -33
- package/src/materialization/rowEncoding.js +70 -14
- package/src/materialization/scaleGuideDependencies.js +8 -5
- package/src/materialization/scales/map.js +1 -0
- package/src/materialization/scales/policies/arc.js +42 -0
- package/src/materialization/scales/policies/bar.js +0 -43
- package/src/materialization/scales/policies/binnedPosition.js +7 -4
- package/src/materialization/scales/policies/offset.js +54 -0
- package/src/materialization/scales/policies/series.js +2 -1
- package/src/materialization/scales/resolve.js +48 -18
- package/src/materialization/selection/compatibility.js +11 -0
- package/src/materialization/selection/items/bar.js +12 -68
- package/src/materialization/selection/items/common.js +8 -2
- package/src/materialization/selection/items/path.js +3 -13
- package/src/materialization/selection/items/rect.js +7 -4
- package/src/materialization/text.js +64 -5
- package/src/mcp/adapter.js +2 -2
- package/src/selectors/datasets.js +13 -0
- package/src/selectors/layers.js +3 -2
- package/src/selectors/scales.js +6 -0
- package/src/theme/defaults.js +39 -0
- package/types/basic.d.ts +11 -2
- package/types/index.d.ts +126 -0
- package/types/program.d.ts +1327 -124
- package/src/materialization/bars/grouped.js +0 -144
|
@@ -1,228 +1,104 @@
|
|
|
1
1
|
import { action } from "../../../core/action.js";
|
|
2
|
-
import { validateOptionObject } from "../../../core/validation.js";
|
|
3
|
-
import { resolvePlotGraphicPlacement } from
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
requireParallelAxisLayer,
|
|
9
|
-
resolveParallelAxisTarget,
|
|
10
|
-
resolveParallelAxisValues
|
|
11
|
-
} from "./parallel/resolve.js";
|
|
2
|
+
import { validateGeneratedItemLimit, validateOptionObject } from "../../../core/validation.js";
|
|
3
|
+
import { resolvePlotGraphicPlacement } from "../../../materialization/graphicHierarchy.js";
|
|
4
|
+
import { requireParallelAxisLayer, resolveParallelAxisTarget, resolveStyledParallelAxes } from "./parallel/resolve.js";
|
|
5
|
+
import { PARALLEL_AXIS_GRAPHICS, PARALLEL_AXIS_PARTS, hasParallelAxisParts } from "./parallel/policy.js";
|
|
6
|
+
import { registerParallelAxisLifecycleActions } from "./parallel/lifecycle.js";
|
|
12
7
|
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
function uniform(values) {
|
|
9
|
+
return values.length > 0 && values.every(value => value === values[0]) ? values[0] : values;
|
|
10
|
+
}
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
.editGraphics({
|
|
67
|
-
target: "parallelAxisLines",
|
|
68
|
-
property: "strokeWidth",
|
|
69
|
-
value: 1.25
|
|
70
|
-
})
|
|
71
|
-
.editGraphics({
|
|
72
|
-
target: "parallelAxisTicks",
|
|
73
|
-
property: "length",
|
|
74
|
-
value: ticks.length
|
|
75
|
-
})
|
|
76
|
-
.editGraphics({
|
|
77
|
-
target: "parallelAxisTicks",
|
|
78
|
-
property: "x1",
|
|
79
|
-
value: ticks.map(tick => tick.x - 4)
|
|
80
|
-
})
|
|
81
|
-
.editGraphics({
|
|
82
|
-
target: "parallelAxisTicks",
|
|
83
|
-
property: "y1",
|
|
84
|
-
value: ticks.map(tick => tick.y)
|
|
85
|
-
})
|
|
86
|
-
.editGraphics({
|
|
87
|
-
target: "parallelAxisTicks",
|
|
88
|
-
property: "x2",
|
|
89
|
-
value: ticks.map(tick => tick.x + 4)
|
|
90
|
-
})
|
|
91
|
-
.editGraphics({
|
|
92
|
-
target: "parallelAxisTicks",
|
|
93
|
-
property: "y2",
|
|
94
|
-
value: ticks.map(tick => tick.y)
|
|
95
|
-
})
|
|
96
|
-
.editGraphics({
|
|
97
|
-
target: "parallelAxisTicks",
|
|
98
|
-
property: "stroke",
|
|
99
|
-
value: DEFAULT_COLORS.mutedText
|
|
100
|
-
})
|
|
101
|
-
.editGraphics({
|
|
102
|
-
target: "parallelAxisTicks",
|
|
103
|
-
property: "strokeWidth",
|
|
104
|
-
value: 1
|
|
105
|
-
})
|
|
106
|
-
.editGraphics({
|
|
107
|
-
target: "parallelAxisLabels",
|
|
108
|
-
property: "length",
|
|
109
|
-
value: ticks.length
|
|
110
|
-
})
|
|
111
|
-
.editGraphics({
|
|
112
|
-
target: "parallelAxisLabels",
|
|
113
|
-
property: "x",
|
|
114
|
-
value: ticks.map(tick => tick.x - 9)
|
|
115
|
-
})
|
|
116
|
-
.editGraphics({
|
|
117
|
-
target: "parallelAxisLabels",
|
|
118
|
-
property: "y",
|
|
119
|
-
value: ticks.map(tick => tick.y)
|
|
120
|
-
})
|
|
121
|
-
.editGraphics({
|
|
122
|
-
target: "parallelAxisLabels",
|
|
123
|
-
property: "text",
|
|
124
|
-
value: ticks.map(tick => tick.text)
|
|
125
|
-
})
|
|
126
|
-
.editGraphics({ target: "parallelAxisLabels", property: "fill", value: DEFAULT_COLORS.axis })
|
|
127
|
-
.editGraphics({ target: "parallelAxisLabels", property: "fontSize", value: 11 })
|
|
128
|
-
.editGraphics({ target: "parallelAxisLabels", property: "fontFamily", value: DEFAULT_FONT_FAMILY })
|
|
129
|
-
.editGraphics({ target: "parallelAxisLabels", property: "fontWeight", value: "normal" })
|
|
130
|
-
.editGraphics({ target: "parallelAxisLabels", property: "textAlign", value: "right" })
|
|
131
|
-
.editGraphics({ target: "parallelAxisLabels", property: "textBaseline", value: "middle" })
|
|
132
|
-
.editGraphics({
|
|
133
|
-
target: "parallelAxisTitles",
|
|
134
|
-
property: "length",
|
|
135
|
-
value: axes.length
|
|
136
|
-
})
|
|
137
|
-
.editGraphics({
|
|
138
|
-
target: "parallelAxisTitles",
|
|
139
|
-
property: "x",
|
|
140
|
-
value: axes.map(axis => axis.x)
|
|
141
|
-
})
|
|
142
|
-
.editGraphics({
|
|
143
|
-
target: "parallelAxisTitles",
|
|
144
|
-
property: "y",
|
|
145
|
-
value: bounds.y - 20
|
|
146
|
-
})
|
|
147
|
-
.editGraphics({
|
|
148
|
-
target: "parallelAxisTitles",
|
|
149
|
-
property: "text",
|
|
150
|
-
value: axes.map(axis => axis.title)
|
|
151
|
-
})
|
|
152
|
-
.editGraphics({ target: "parallelAxisTitles", property: "fill", value: DEFAULT_COLORS.axisTitle })
|
|
153
|
-
.editGraphics({ target: "parallelAxisTitles", property: "fontSize", value: 13 })
|
|
154
|
-
.editGraphics({ target: "parallelAxisTitles", property: "fontFamily", value: DEFAULT_FONT_FAMILY })
|
|
155
|
-
.editGraphics({ target: "parallelAxisTitles", property: "fontWeight", value: 600 })
|
|
156
|
-
.editGraphics({ target: "parallelAxisTitles", property: "textAlign", value: "center" })
|
|
157
|
-
.editGraphics({ target: "parallelAxisTitles", property: "textBaseline", value: "middle" });
|
|
158
|
-
return next._withGuideConfig("parallel", "axes", {
|
|
159
|
-
target,
|
|
160
|
-
scales: dimensions.map(dimension => dimension.scale)
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
);
|
|
12
|
+
function collectionProperties(part, axes, bounds) {
|
|
13
|
+
if (part === "line") return {
|
|
14
|
+
length: axes.length,
|
|
15
|
+
x1: axes.map(axis => axis.x), y1: bounds.y,
|
|
16
|
+
x2: axes.map(axis => axis.x), y2: bounds.y + bounds.height,
|
|
17
|
+
stroke: uniform(axes.map(axis => axis.config.line.color)),
|
|
18
|
+
strokeWidth: uniform(axes.map(axis => axis.config.line.lineWidth))
|
|
19
|
+
};
|
|
20
|
+
if (part === "title") return {
|
|
21
|
+
length: axes.length, x: axes.map(axis => axis.x),
|
|
22
|
+
y: uniform(axes.map(axis => bounds.y - axis.config.title.offset)),
|
|
23
|
+
text: axes.map(axis => axis.title),
|
|
24
|
+
fill: uniform(axes.map(axis => axis.config.title.color)),
|
|
25
|
+
fontSize: uniform(axes.map(axis => axis.config.title.fontSize)),
|
|
26
|
+
fontFamily: uniform(axes.map(axis => axis.config.title.fontFamily)),
|
|
27
|
+
fontWeight: uniform(axes.map(axis => axis.config.title.fontWeight)),
|
|
28
|
+
textAlign: "center", textBaseline: "middle"
|
|
29
|
+
};
|
|
30
|
+
const rows = axes.flatMap(axis => axis[part].values.map((value, index) => ({
|
|
31
|
+
x: axis.x, y: axis[part].y[index], text: axis[part].text?.[index], config: axis.config[part]
|
|
32
|
+
})));
|
|
33
|
+
if (part === "ticks") return {
|
|
34
|
+
length: rows.length, x1: rows.map(row => row.x - row.config.length / 2),
|
|
35
|
+
y1: rows.map(row => row.y), x2: rows.map(row => row.x + row.config.length / 2),
|
|
36
|
+
y2: rows.map(row => row.y), stroke: uniform(rows.map(row => row.config.color)),
|
|
37
|
+
strokeWidth: uniform(rows.map(row => row.config.lineWidth))
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
length: rows.length, x: rows.map(row => row.x - row.config.offset),
|
|
41
|
+
y: rows.map(row => row.y), text: rows.map(row => row.text),
|
|
42
|
+
fill: uniform(rows.map(row => row.config.color)),
|
|
43
|
+
fontSize: uniform(rows.map(row => row.config.fontSize)),
|
|
44
|
+
fontFamily: uniform(rows.map(row => row.config.fontFamily)),
|
|
45
|
+
fontWeight: uniform(rows.map(row => row.config.fontWeight)),
|
|
46
|
+
textAlign: "right", textBaseline: "middle"
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const rematerializeParallelAxes = action({
|
|
51
|
+
op: "rematerializeParallelAxes",
|
|
52
|
+
description: "Recompute concrete Parallel dimension axes."
|
|
53
|
+
}, function (args = {}) {
|
|
54
|
+
validateOptionObject(args, ["target"], "rematerializeParallelAxes");
|
|
55
|
+
const stored = this.semanticSpec.guides.axis?.parallel;
|
|
56
|
+
if (stored === undefined) throw new Error("rematerializeParallelAxes requires existing Parallel axes.");
|
|
57
|
+
const target = resolveParallelAxisTarget(this, args.target ?? stored.target);
|
|
58
|
+
if (target !== stored.target) throw new Error("Parallel axes belong to another target.");
|
|
59
|
+
const { dimensions } = requireParallelAxisLayer(this, target);
|
|
60
|
+
const { axes, bounds, configs } = resolveStyledParallelAxes(this, dimensions);
|
|
61
|
+
if (!configs.dimensions.some(hasParallelAxisParts)) return this.removeParallelAxes({ target });
|
|
164
62
|
|
|
165
|
-
|
|
166
|
-
{
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
63
|
+
// Preflight every collection before authoring any concrete graphic.
|
|
64
|
+
const properties = Object.fromEntries(PARALLEL_AXIS_PARTS.map(part => {
|
|
65
|
+
const selected = axes.filter(axis => axis.config[part] !== undefined);
|
|
66
|
+
const value = collectionProperties(part, selected, bounds);
|
|
67
|
+
validateGeneratedItemLimit(value.length, "Parallel axis item count");
|
|
68
|
+
return [part, { enabled: selected.length > 0, value }];
|
|
69
|
+
}));
|
|
70
|
+
let next = this;
|
|
71
|
+
const scales = dimensions.map(dimension => dimension.scale);
|
|
72
|
+
if (stored.scales?.length !== scales.length || scales.some((scale, index) => scale !== stored.scales[index])) {
|
|
73
|
+
next = next.editSemantic({ property: "guide.axis.parallel.scales", value: scales });
|
|
74
|
+
}
|
|
75
|
+
const retainedTitles = stored.titles?.filter(title =>
|
|
76
|
+
configs.dimensions.some(config => config.field === title.field && config.title !== undefined));
|
|
77
|
+
if (retainedTitles !== undefined && retainedTitles.length !== stored.titles.length) {
|
|
78
|
+
next = next.editSemantic({ property: "guide.axis.parallel.titles",
|
|
79
|
+
...(retainedTitles.length === 0 ? { remove: true } : { value: retainedTitles }) });
|
|
80
|
+
}
|
|
81
|
+
for (const [index, part] of PARALLEL_AXIS_PARTS.entries()) {
|
|
82
|
+
const id = PARALLEL_AXIS_GRAPHICS[part];
|
|
83
|
+
const { enabled, value } = properties[part];
|
|
84
|
+
if (!enabled) {
|
|
85
|
+
if (next.graphicSpec.objects[id] !== undefined) next = next.editGraphics({ target: id, remove: true });
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (next.graphicSpec.objects[id] === undefined) {
|
|
89
|
+
const before = PARALLEL_AXIS_PARTS.slice(index + 1).map(key => PARALLEL_AXIS_GRAPHICS[key])
|
|
90
|
+
.find(key => next.graphicSpec.objects[key] !== undefined);
|
|
91
|
+
next = next.createGraphics({ id, type: part === "line" || part === "ticks" ? "line" : "text", length: 0,
|
|
92
|
+
...resolvePlotGraphicPlacement(next, before === undefined ? {} : { before }) });
|
|
178
93
|
}
|
|
179
|
-
for (const
|
|
180
|
-
|
|
181
|
-
"parallelAxisTitles"
|
|
182
|
-
]) {
|
|
183
|
-
if (this.graphicSpec.objects[id] !== undefined) {
|
|
184
|
-
throw new Error("createParallelAxes requires missing Parallel axes.");
|
|
185
|
-
}
|
|
94
|
+
for (const [property, item] of Object.entries(value)) {
|
|
95
|
+
next = next.editGraphics({ target: id, property, value: item });
|
|
186
96
|
}
|
|
187
|
-
const placement = resolvePlotGraphicPlacement(this);
|
|
188
|
-
let next = this
|
|
189
|
-
.editSemantic({
|
|
190
|
-
property: "guide.axis.parallel.target",
|
|
191
|
-
value: target
|
|
192
|
-
})
|
|
193
|
-
.editSemantic({
|
|
194
|
-
property: "guide.axis.parallel.coordinate",
|
|
195
|
-
value: coordinate.id
|
|
196
|
-
})
|
|
197
|
-
.editSemantic({
|
|
198
|
-
property: "guide.axis.parallel.scales",
|
|
199
|
-
value: dimensions.map(dimension => dimension.scale)
|
|
200
|
-
})
|
|
201
|
-
.createGraphics({ id: "parallelAxisLines", type: "line", length: 0, ...placement })
|
|
202
|
-
.editGraphics({ target: "parallelAxisLines", property: "stroke", value: DEFAULT_COLORS.axis })
|
|
203
|
-
.editGraphics({ target: "parallelAxisLines", property: "strokeWidth", value: 1.25 })
|
|
204
|
-
.createGraphics({ id: "parallelAxisTicks", type: "line", length: 0, ...placement })
|
|
205
|
-
.editGraphics({ target: "parallelAxisTicks", property: "stroke", value: DEFAULT_COLORS.mutedText })
|
|
206
|
-
.editGraphics({ target: "parallelAxisTicks", property: "strokeWidth", value: 1 })
|
|
207
|
-
.createGraphics({ id: "parallelAxisLabels", type: "text", length: 0, ...placement })
|
|
208
|
-
.editGraphics({ target: "parallelAxisLabels", property: "fill", value: DEFAULT_COLORS.axis })
|
|
209
|
-
.editGraphics({ target: "parallelAxisLabels", property: "fontSize", value: 11 })
|
|
210
|
-
.editGraphics({ target: "parallelAxisLabels", property: "fontFamily", value: DEFAULT_FONT_FAMILY })
|
|
211
|
-
.editGraphics({ target: "parallelAxisLabels", property: "fontWeight", value: "normal" })
|
|
212
|
-
.editGraphics({ target: "parallelAxisLabels", property: "textAlign", value: "right" })
|
|
213
|
-
.editGraphics({ target: "parallelAxisLabels", property: "textBaseline", value: "middle" })
|
|
214
|
-
.createGraphics({ id: "parallelAxisTitles", type: "text", length: 0, ...placement })
|
|
215
|
-
.editGraphics({ target: "parallelAxisTitles", property: "fill", value: DEFAULT_COLORS.axisTitle })
|
|
216
|
-
.editGraphics({ target: "parallelAxisTitles", property: "fontSize", value: 13 })
|
|
217
|
-
.editGraphics({ target: "parallelAxisTitles", property: "fontFamily", value: DEFAULT_FONT_FAMILY })
|
|
218
|
-
.editGraphics({ target: "parallelAxisTitles", property: "fontWeight", value: 600 })
|
|
219
|
-
.editGraphics({ target: "parallelAxisTitles", property: "textAlign", value: "center" })
|
|
220
|
-
.editGraphics({ target: "parallelAxisTitles", property: "textBaseline", value: "middle" });
|
|
221
|
-
return next.rematerializeParallelAxes({ target });
|
|
222
97
|
}
|
|
223
|
-
);
|
|
98
|
+
return next._withGuideConfig("parallel", "axes", { target, scales, ...configs });
|
|
99
|
+
});
|
|
224
100
|
|
|
225
101
|
export function registerParallelAxisActions(ProgramClass) {
|
|
226
|
-
ProgramClass.prototype.createParallelAxes = createParallelAxes;
|
|
227
102
|
ProgramClass.prototype.rematerializeParallelAxes = rematerializeParallelAxes;
|
|
103
|
+
registerParallelAxisLifecycleActions(ProgramClass);
|
|
228
104
|
}
|
|
@@ -1,32 +1,15 @@
|
|
|
1
1
|
import { formatVisibleText } from "../../../core/textMetrics.js";
|
|
2
|
+
import {
|
|
3
|
+
formatValue,
|
|
4
|
+
isUtcValueFormat,
|
|
5
|
+
validateValueFormat
|
|
6
|
+
} from "../../../grammar/valueFormat.js";
|
|
2
7
|
|
|
3
8
|
const AXIS_POSITIONS = Object.freeze({
|
|
4
9
|
x: Object.freeze(["bottom", "top"]),
|
|
5
10
|
y: Object.freeze(["left", "right"])
|
|
6
11
|
});
|
|
7
12
|
|
|
8
|
-
const NUMERIC_FORMATS = new Set([
|
|
9
|
-
".0f", ".1f", ".2f", ".0%", ".1%", ".2e"
|
|
10
|
-
]);
|
|
11
|
-
const TIME_DIRECTIVES = new Set(["Y", "m", "d", "b", "%"]);
|
|
12
|
-
const MONTH_NAMES = Object.freeze([
|
|
13
|
-
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
14
|
-
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
|
15
|
-
]);
|
|
16
|
-
|
|
17
|
-
function isTimeFormat(format) {
|
|
18
|
-
if (typeof format !== "string") return false;
|
|
19
|
-
let directives = 0;
|
|
20
|
-
for (let index = 0; index < format.length; index += 1) {
|
|
21
|
-
if (format[index] !== "%") continue;
|
|
22
|
-
const directive = format[index + 1];
|
|
23
|
-
if (!TIME_DIRECTIVES.has(directive)) return false;
|
|
24
|
-
if (directive !== "%") directives += 1;
|
|
25
|
-
index += 1;
|
|
26
|
-
}
|
|
27
|
-
return directives > 0;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
13
|
export function defaultAxisPosition(channel) {
|
|
31
14
|
return channel === "x" ? "bottom" : "left";
|
|
32
15
|
}
|
|
@@ -113,42 +96,9 @@ export function resolveAxisTitleGeometry({
|
|
|
113
96
|
}
|
|
114
97
|
|
|
115
98
|
export function validateAxisFormat(format) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
typeof format === "object" &&
|
|
120
|
-
Number.isInteger(format.decimals) &&
|
|
121
|
-
format.decimals >= 0 &&
|
|
122
|
-
Object.keys(format).length === 1
|
|
123
|
-
) {
|
|
124
|
-
return format;
|
|
125
|
-
}
|
|
126
|
-
if (typeof format === "string" && (
|
|
127
|
-
NUMERIC_FORMATS.has(format) || isTimeFormat(format)
|
|
128
|
-
)) {
|
|
129
|
-
return format;
|
|
130
|
-
}
|
|
131
|
-
throw new TypeError(
|
|
132
|
-
"Label format must be auto, { decimals }, or a supported format string."
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function pad(value, length = 2) {
|
|
137
|
-
return String(value).padStart(length, "0");
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function formatTime(value, format) {
|
|
141
|
-
const date = new Date(value);
|
|
142
|
-
if (!Number.isFinite(date.getTime())) {
|
|
143
|
-
throw new TypeError("Time axis format requires valid timestamps.");
|
|
144
|
-
}
|
|
145
|
-
const year = pad(date.getUTCFullYear(), 4);
|
|
146
|
-
const month = pad(date.getUTCMonth() + 1);
|
|
147
|
-
const day = pad(date.getUTCDate());
|
|
148
|
-
const values = { Y: year, m: month, d: day, b: MONTH_NAMES[date.getUTCMonth()] };
|
|
149
|
-
return format.replace(/%([Ymdb%])/g, (_, directive) =>
|
|
150
|
-
directive === "%" ? "%" : values[directive]
|
|
151
|
-
);
|
|
99
|
+
return validateValueFormat(format, "Label format", {
|
|
100
|
+
allowDecimalsObject: true
|
|
101
|
+
});
|
|
152
102
|
}
|
|
153
103
|
|
|
154
104
|
export function formatAxisValue(value, scaleType, format, autoFormatter) {
|
|
@@ -158,18 +108,22 @@ export function formatAxisValue(value, scaleType, format, autoFormatter) {
|
|
|
158
108
|
throw new Error('Discrete axis labels require format "auto".');
|
|
159
109
|
}
|
|
160
110
|
if (scaleType === "time") {
|
|
161
|
-
if (!
|
|
111
|
+
if (!isUtcValueFormat(format)) {
|
|
162
112
|
throw new Error("Time axis labels require a supported time format string.");
|
|
163
113
|
}
|
|
164
|
-
return
|
|
114
|
+
return formatValue(value, {
|
|
115
|
+
format,
|
|
116
|
+
valueType: "temporal",
|
|
117
|
+
label: "Axis label format"
|
|
118
|
+
});
|
|
165
119
|
}
|
|
166
|
-
if (
|
|
120
|
+
if (isUtcValueFormat(format)) {
|
|
167
121
|
throw new Error("Quantitative axis labels cannot use a time format string.");
|
|
168
122
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
123
|
+
return formatValue(value, {
|
|
124
|
+
format,
|
|
125
|
+
valueType: "quantitative",
|
|
126
|
+
label: "Axis label format",
|
|
127
|
+
allowDecimalsObject: true
|
|
128
|
+
});
|
|
175
129
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withGuideLayoutValidation } from "../../../materialization/guides/layout.js";
|
|
1
2
|
import { action } from "../../../core/action.js";
|
|
2
3
|
import { isPlainObject } from "../../../core/immutable.js";
|
|
3
4
|
import { validateKeys, validateOptionObject } from "../../../core/validation.js";
|
|
@@ -24,7 +25,12 @@ const LABEL_OPTIONS = Object.freeze([
|
|
|
24
25
|
"color",
|
|
25
26
|
"fontSize",
|
|
26
27
|
"fontFamily",
|
|
27
|
-
"fontWeight"
|
|
28
|
+
"fontWeight",
|
|
29
|
+
"rotation",
|
|
30
|
+
"maxWidth",
|
|
31
|
+
"wrap",
|
|
32
|
+
"lineHeight",
|
|
33
|
+
"overlap"
|
|
28
34
|
]);
|
|
29
35
|
const SHARED_CREATE = Object.freeze(["scale", "position", "count", "values"]);
|
|
30
36
|
const SHARED_EDIT = Object.freeze(["position", "count", "values"]);
|
|
@@ -37,7 +43,7 @@ function validateNested(value, supported, label) {
|
|
|
37
43
|
validateKeys(value, supported, label);
|
|
38
44
|
}
|
|
39
45
|
|
|
40
|
-
function
|
|
46
|
+
export function validateAxisTickGroupArgs(args, operation, create) {
|
|
41
47
|
validateOptionObject(
|
|
42
48
|
args,
|
|
43
49
|
create ? CREATE_OPTIONS : EDIT_OPTIONS,
|
|
@@ -89,8 +95,8 @@ function makeCreate(channel) {
|
|
|
89
95
|
op: operation.create,
|
|
90
96
|
description: `Create ${channel}-axis ticks and labels.`
|
|
91
97
|
},
|
|
92
|
-
function (args = {}) {
|
|
93
|
-
|
|
98
|
+
withGuideLayoutValidation(function (args = {}) {
|
|
99
|
+
validateAxisTickGroupArgs(args, operation.create, true);
|
|
94
100
|
const shared = select(args, SHARED_CREATE);
|
|
95
101
|
const tickArgs = { ...shared, ...(args.ticks ?? {}) };
|
|
96
102
|
const labelArgs = {
|
|
@@ -101,7 +107,7 @@ function makeCreate(channel) {
|
|
|
101
107
|
return this[operation.createTicks](tickArgs)[operation.createLabels](
|
|
102
108
|
labelArgs
|
|
103
109
|
);
|
|
104
|
-
}
|
|
110
|
+
})
|
|
105
111
|
);
|
|
106
112
|
}
|
|
107
113
|
|
|
@@ -113,8 +119,8 @@ function makeEdit(channel) {
|
|
|
113
119
|
op: operation.edit,
|
|
114
120
|
description: `Edit ${channel}-axis ticks and labels.`
|
|
115
121
|
},
|
|
116
|
-
function (args = {}) {
|
|
117
|
-
|
|
122
|
+
withGuideLayoutValidation(function (args = {}) {
|
|
123
|
+
validateAxisTickGroupArgs(args, operation.edit, false);
|
|
118
124
|
const shared = select(args, SHARED_EDIT);
|
|
119
125
|
const hasShared = Object.keys(shared).length > 0;
|
|
120
126
|
let next = this;
|
|
@@ -134,7 +140,7 @@ function makeEdit(channel) {
|
|
|
134
140
|
}
|
|
135
141
|
|
|
136
142
|
return next;
|
|
137
|
-
}
|
|
143
|
+
})
|
|
138
144
|
);
|
|
139
145
|
}
|
|
140
146
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withGuideLayoutValidation } from "../../../materialization/guides/layout.js";
|
|
1
2
|
import { action } from "../../../core/action.js";
|
|
2
3
|
import { validateUserId } from "../../../core/identifiers.js";
|
|
3
4
|
import {
|
|
@@ -126,7 +127,7 @@ function geometry(program, channel, config) {
|
|
|
126
127
|
|
|
127
128
|
function makeEdit(channel) {
|
|
128
129
|
const op = channel === "x" ? "editXAxisTicks" : "editYAxisTicks";
|
|
129
|
-
return action({ op, description: `Edit concrete ${channel}-axis ticks.` }, function (args = {}) {
|
|
130
|
+
return action({ op, description: `Edit concrete ${channel}-axis ticks.` }, withGuideLayoutValidation(function (args = {}) {
|
|
130
131
|
validateOptions(args, op, false);
|
|
131
132
|
const id = `${channel}AxisTicks`;
|
|
132
133
|
if (this.graphicSpec.objects[id]?.type !== "line") throw new Error(`${op} requires existing axis ticks.`);
|
|
@@ -157,7 +158,7 @@ function makeEdit(channel) {
|
|
|
157
158
|
let next = this._withGuideConfig(channel, config).editGraphics({ target: id, property: "length", value: resolved.values.length });
|
|
158
159
|
for (const property of ["x1", "y1", "x2", "y2"]) next = next.editGraphics({ target: id, property, value: resolved[property] });
|
|
159
160
|
return next.editGraphics({ target: id, property: "stroke", value: config.color }).editGraphics({ target: id, property: "strokeWidth", value: config.lineWidth });
|
|
160
|
-
});
|
|
161
|
+
}));
|
|
161
162
|
}
|
|
162
163
|
|
|
163
164
|
const editXAxisTicks = makeEdit("x"), editYAxisTicks = makeEdit("y");
|
|
@@ -165,7 +166,7 @@ const editXAxisTicks = makeEdit("x"), editYAxisTicks = makeEdit("y");
|
|
|
165
166
|
function makeCreate(channel) {
|
|
166
167
|
const op = channel === "x" ? "createXAxisTicks" : "createYAxisTicks";
|
|
167
168
|
const edit = channel === "x" ? "editXAxisTicks" : "editYAxisTicks";
|
|
168
|
-
return action({ op, description: `Create concrete ${channel}-axis ticks.` }, function (args = {}) {
|
|
169
|
+
return action({ op, description: `Create concrete ${channel}-axis ticks.` }, withGuideLayoutValidation(function (args = {}) {
|
|
169
170
|
validateOptions(args, op, true);
|
|
170
171
|
const scale = validateUserId(args.scale ?? channel, "Scale id");
|
|
171
172
|
const existingGuide = this.semanticSpec.guides.axis?.[channel]?.scale;
|
|
@@ -192,7 +193,7 @@ function makeCreate(channel) {
|
|
|
192
193
|
...resolvePlotGraphicPlacement(this)
|
|
193
194
|
})
|
|
194
195
|
._withGuideConfig(channel, config)[edit]();
|
|
195
|
-
});
|
|
196
|
+
}));
|
|
196
197
|
}
|
|
197
198
|
|
|
198
199
|
const createXAxisTicks = makeCreate("x"), createYAxisTicks = makeCreate("y");
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isSourceOwnedText } from "../../../grammar/text.js";
|
|
2
|
+
import { withGuideLayoutValidation } from "../../../materialization/guides/layout.js";
|
|
1
3
|
import { action } from "../../../core/action.js";
|
|
2
4
|
import { validateUserId } from "../../../core/identifiers.js";
|
|
3
5
|
import {
|
|
@@ -32,6 +34,7 @@ import {
|
|
|
32
34
|
import { resolveConcreteGraphicBounds } from
|
|
33
35
|
"../../../grammar/schemas/graphicBounds.js";
|
|
34
36
|
import { validateAxisTextStyle } from "./labels.js";
|
|
37
|
+
import { resolveRotation } from "../../../grammar/rotation.js";
|
|
35
38
|
|
|
36
39
|
function titleBounds(geometry, config, text) {
|
|
37
40
|
return resolveTextBounds({
|
|
@@ -102,7 +105,15 @@ export function inferAxisTitleText(program, channel, scaleId) {
|
|
|
102
105
|
const titles = new Set();
|
|
103
106
|
const primaryTitles = new Set();
|
|
104
107
|
for (const layer of program.semanticSpec.layers) {
|
|
105
|
-
|
|
108
|
+
if (isSourceOwnedText(layer)) continue;
|
|
109
|
+
const primary = layer.encoding?.[channel];
|
|
110
|
+
const encoding = layer.mark?.type === "area" && Object.hasOwn(primary ?? {}, "datum")
|
|
111
|
+
? layer.encoding?.[`${channel}2`] : primary;
|
|
112
|
+
if (channel === "radius" && layer.mark?.type === "arc" &&
|
|
113
|
+
encoding?.scale === scaleId && encoding.aggregate === "count" && encoding.field === undefined) {
|
|
114
|
+
titles.add(encoding.title ?? "count");
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
106
117
|
if (
|
|
107
118
|
encoding?.scale === scaleId &&
|
|
108
119
|
typeof encoding.field === "string" &&
|
|
@@ -193,12 +204,12 @@ function names(channel) {
|
|
|
193
204
|
|
|
194
205
|
function makeEdit(channel) {
|
|
195
206
|
const operation = names(channel);
|
|
196
|
-
return action({ op: operation.edit, description: `Edit the ${channel}-axis title.` }, function (args = {}) {
|
|
207
|
+
return action({ op: operation.edit, description: `Edit the ${channel}-axis title.` }, withGuideLayoutValidation(function (args = {}) {
|
|
197
208
|
validateKeys(args, EDIT_OPTIONS, operation.edit);
|
|
198
209
|
if (this.graphicSpec.objects[operation.graphic]?.type !== "text") throw new Error(`${operation.edit} requires an existing axis title.`);
|
|
199
210
|
const previous = this.guideConfigs.axis?.[channel]?.title;
|
|
200
211
|
if (!previous) throw new Error(`${operation.edit} requires title configuration.`);
|
|
201
|
-
const { text, ...appearance } = args;
|
|
212
|
+
const { text, rotation: requestedRotation, ...appearance } = args;
|
|
202
213
|
const explicitText = Object.hasOwn(args, "text");
|
|
203
214
|
const explicitRotation = Object.hasOwn(args, "rotation");
|
|
204
215
|
const position = appearance.position ?? previous.position;
|
|
@@ -211,7 +222,9 @@ function makeEdit(channel) {
|
|
|
211
222
|
position,
|
|
212
223
|
rotation: inferredRotation
|
|
213
224
|
? defaultAxisTitleRotation(channel, position)
|
|
214
|
-
:
|
|
225
|
+
: explicitRotation
|
|
226
|
+
? resolveRotation(requestedRotation, "Axis title rotation")
|
|
227
|
+
: previous.rotation,
|
|
215
228
|
inferredRotation,
|
|
216
229
|
inferredOffset: Object.hasOwn(args, "offset")
|
|
217
230
|
? false
|
|
@@ -245,7 +258,7 @@ function makeEdit(channel) {
|
|
|
245
258
|
};
|
|
246
259
|
for (const [property, value] of Object.entries(properties)) next = next.editGraphics({ target: operation.graphic, property, value });
|
|
247
260
|
return next;
|
|
248
|
-
});
|
|
261
|
+
}));
|
|
249
262
|
}
|
|
250
263
|
|
|
251
264
|
const editXAxisTitle = makeEdit("x");
|
|
@@ -253,7 +266,7 @@ const editYAxisTitle = makeEdit("y");
|
|
|
253
266
|
|
|
254
267
|
function makeCreate(channel) {
|
|
255
268
|
const operation = names(channel);
|
|
256
|
-
return action({ op: operation.create, description: `Create the ${channel}-axis title.` }, function (args = {}) {
|
|
269
|
+
return action({ op: operation.create, description: `Create the ${channel}-axis title.` }, withGuideLayoutValidation(function (args = {}) {
|
|
257
270
|
validateKeys(args, CREATE_OPTIONS, operation.create);
|
|
258
271
|
const {
|
|
259
272
|
text: requestedText,
|
|
@@ -281,7 +294,7 @@ function makeCreate(channel) {
|
|
|
281
294
|
offset: channel === "x" ? 42 : 52,
|
|
282
295
|
rotation: inferredRotation
|
|
283
296
|
? defaultAxisTitleRotation(channel, position)
|
|
284
|
-
: requestedRotation,
|
|
297
|
+
: resolveRotation(requestedRotation, "Axis title rotation"),
|
|
285
298
|
inferredRotation,
|
|
286
299
|
inferredOffset,
|
|
287
300
|
color: DEFAULTS.color,
|
|
@@ -303,7 +316,7 @@ function makeCreate(channel) {
|
|
|
303
316
|
...resolvePlotGraphicPlacement(this)
|
|
304
317
|
})
|
|
305
318
|
._withGuideConfig(channel, "title", config)[operation.edit]();
|
|
306
|
-
});
|
|
319
|
+
}));
|
|
307
320
|
}
|
|
308
321
|
|
|
309
322
|
const createXAxisTitle = makeCreate("x");
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
registerBasicCategoricalLegendActions
|
|
6
6
|
} from "./legends/categorical/index.js";
|
|
7
7
|
import {
|
|
8
|
+
registerIntervalLegendActions,
|
|
8
9
|
registerGradientLegendActions
|
|
9
10
|
} from "./legends/continuous/index.js";
|
|
10
11
|
import { registerSizeLegendActions } from "./legends/size.js";
|
|
@@ -13,6 +14,7 @@ export function registerBasicGuideActions(ProgramClass) {
|
|
|
13
14
|
registerBasicCartesianAxisActions(ProgramClass);
|
|
14
15
|
registerBasicCategoricalLegendActions(ProgramClass);
|
|
15
16
|
registerGradientLegendActions(ProgramClass);
|
|
17
|
+
registerIntervalLegendActions(ProgramClass);
|
|
16
18
|
registerSizeLegendActions(ProgramClass);
|
|
17
19
|
registerBasicGridActions(ProgramClass);
|
|
18
20
|
registerGuideCollectionActions(ProgramClass);
|