ggaction 0.0.17 → 0.0.19
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 +96 -0
- package/README.md +6 -2
- package/knowledge/action-card.schema.json +1 -1
- package/knowledge/action-cards.json +1 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/knowledge/task-resolver.js +1 -1
- package/package.json +3 -3
- package/src/BasicChartProgram.js +1 -1
- package/src/accessibility.js +3 -2
- package/src/actions/boxPlots/create.js +14 -4
- package/src/actions/boxPlots/edit.js +39 -33
- package/src/actions/boxPlots/materialize.js +7 -3
- package/src/actions/boxPlots/options.js +37 -11
- package/src/actions/canvas/actions.js +70 -95
- package/src/actions/canvas/fitting.js +20 -1
- package/src/actions/canvas/index.js +3 -0
- package/src/actions/canvas/plotBorder.js +28 -0
- package/src/actions/charts/area.js +2 -2
- package/src/actions/charts/bar.js +34 -7
- package/src/actions/charts/ecdf.js +4 -18
- package/src/actions/charts/endpoints.js +4 -18
- package/src/actions/charts/heatmap.js +8 -7
- package/src/actions/charts/index.js +2 -0
- package/src/actions/charts/interval-regression.js +2 -2
- package/src/actions/charts/line.js +1 -1
- package/src/actions/charts/pie.js +3 -47
- package/src/actions/charts/radial.js +34 -12
- package/src/actions/charts/scatter.js +16 -2
- package/src/actions/charts/shared.js +2 -2
- package/src/actions/charts/text.js +35 -0
- package/src/actions/composition/actions.js +6 -2
- package/src/actions/data/box.js +2 -1
- package/src/actions/data/derived.js +11 -1
- package/src/actions/data/edit.js +3 -1
- package/src/actions/data/index.js +4 -0
- package/src/actions/data/regression.js +25 -16
- package/src/actions/data/regressionStatistics.js +73 -0
- package/src/actions/data/shared.js +8 -4
- package/src/actions/data/stack.js +3 -1
- package/src/actions/distributions/revision.js +24 -18
- package/src/actions/encodings/appearance.js +37 -29
- package/src/actions/encodings/barWidth.js +36 -11
- package/src/actions/encodings/channels.js +0 -1
- package/src/actions/encodings/color/continuous.js +1 -1
- package/src/actions/encodings/color/index.js +1 -1
- package/src/actions/encodings/color/policy.js +10 -3
- package/src/actions/encodings/density/resolve.js +1 -6
- package/src/actions/encodings/position/policies/arc.js +12 -10
- package/src/actions/encodings/position/policies/area.js +3 -3
- package/src/actions/encodings/position/policies/bar.js +15 -6
- package/src/actions/encodings/position/policies/line.js +17 -6
- package/src/actions/encodings/position/resolve.js +3 -2
- package/src/actions/encodings/ranged.js +17 -0
- package/src/actions/encodings/remove.js +14 -8
- package/src/actions/encodings/seriesLayout.js +1 -0
- package/src/actions/encodings/shared.js +26 -24
- package/src/actions/encodings/text.js +6 -3
- package/src/actions/errorBands/create.js +2 -2
- package/src/actions/errorBands/edit.js +2 -1
- package/src/actions/facets/actions.js +176 -247
- package/src/actions/facets/guides.js +2 -1
- package/src/actions/gradientPlots/resolve.js +2 -17
- package/src/actions/guides/applicability.js +1 -1
- package/src/actions/guides/axes/axes.js +30 -11
- package/src/actions/guides/axes/axis.js +72 -10
- package/src/actions/guides/axes/components.js +13 -13
- package/src/actions/guides/axes/edit.js +36 -24
- package/src/actions/guides/axes/labels.js +155 -71
- package/src/actions/guides/axes/lines.js +27 -24
- package/src/actions/guides/axes/parallel/lifecycle.js +1 -1
- package/src/actions/guides/axes/parallel/policy.js +8 -7
- package/src/actions/guides/axes/remove.js +13 -8
- package/src/actions/guides/axes/tickGroups.js +11 -7
- package/src/actions/guides/axes/ticks.js +36 -24
- package/src/actions/guides/axes/titles.js +107 -69
- package/src/actions/guides/basic.js +2 -0
- package/src/actions/guides/facadeAxes.js +33 -24
- package/src/actions/guides/facadeLegend.js +12 -4
- package/src/actions/guides/grids/grid.js +8 -2
- package/src/actions/guides/grids/resolve.js +102 -58
- package/src/actions/guides/legends/blocks.js +46 -20
- package/src/actions/guides/legends/categorical/actions.js +95 -19
- package/src/actions/guides/legends/categorical/components.js +15 -18
- package/src/actions/guides/legends/categorical/index.js +8 -0
- package/src/actions/guides/legends/categorical/layout.js +45 -20
- package/src/actions/guides/legends/categorical/options.js +39 -22
- package/src/actions/guides/legends/categorical/recipes.js +7 -3
- package/src/actions/guides/legends/categorical/resolve.js +11 -4
- package/src/actions/guides/legends/categorical/symbols.js +38 -18
- package/src/actions/guides/legends/categorical/validation.js +1 -6
- package/src/actions/guides/legends/colorSize.js +110 -0
- package/src/actions/guides/legends/combine.js +37 -0
- package/src/actions/guides/legends/continuous/colorSymbols.js +1 -0
- package/src/actions/guides/legends/continuous/common.js +1 -447
- package/src/actions/guides/legends/continuous/gradient.js +73 -46
- package/src/actions/guides/legends/continuous/interval.js +4 -4
- package/src/actions/guides/legends/continuous/opacity.js +33 -21
- package/src/actions/guides/legends/creation.js +2 -0
- package/src/actions/guides/legends/edit.js +1 -604
- package/src/actions/guides/legends/focused.js +8 -7
- package/src/actions/guides/legends/group.js +1 -0
- package/src/actions/guides/legends/lane.js +1 -516
- package/src/actions/guides/legends/lifecycle.js +2 -1
- package/src/actions/guides/legends/remove.js +9 -3
- package/src/actions/guides/legends/sampling.js +1 -1
- package/src/actions/guides/legends/size.js +65 -47
- package/src/actions/guides/legends/strokeWidth.js +13 -29
- package/src/actions/guides/legends/target.js +2 -79
- package/src/actions/guides/legends/transition.js +44 -11
- package/src/actions/guides/polar/axes/labels.js +4 -2
- package/src/actions/guides/polar/axes/titles.js +7 -5
- package/src/actions/guides/polar/resolve.js +6 -14
- package/src/actions/guides/tickValues.js +8 -5
- package/src/actions/index.js +16 -16
- package/src/actions/marks/arc/actions.js +3 -10
- package/src/actions/marks/area/actions.js +8 -5
- package/src/actions/marks/area/materialize.js +8 -9
- package/src/actions/marks/bar/create.js +10 -4
- package/src/actions/marks/bar/edit.js +29 -14
- package/src/actions/marks/bar/materialize.js +15 -7
- package/src/actions/marks/line/actions.js +11 -4
- package/src/actions/marks/line/materialize.js +9 -5
- package/src/actions/marks/point/edit.js +1 -1
- package/src/actions/marks/point/materialize.js +5 -1
- package/src/actions/marks/rect/actions.js +3 -3
- package/src/actions/marks/remove.js +12 -10
- package/src/actions/marks/rule/actions.js +7 -4
- package/src/actions/marks/text/actions.js +17 -5
- package/src/actions/marks/text/layout.js +3 -0
- package/src/actions/primitives/createGraphics.js +3 -2
- package/src/actions/primitives/editGraphics.js +15 -11
- package/src/actions/primitives/graphicProperties.js +1 -6
- package/src/actions/primitives/semanticAction.js +27 -1
- package/src/actions/primitives/semanticValidation/guide.js +11 -1
- package/src/actions/primitives/semanticValidation/layer.js +8 -0
- package/src/actions/regression/create.js +1 -1
- package/src/actions/regression/edit.js +18 -6
- package/src/actions/regression/resolve.js +2 -6
- package/src/actions/scales/channels.js +9 -4
- package/src/actions/scales/consumers/families.js +16 -5
- package/src/actions/scales/create.js +10 -5
- package/src/actions/scales/definitions.js +1 -425
- package/src/actions/scales/edit.js +3 -3
- package/src/actions/scales/editPolicy.js +12 -3
- package/src/actions/scales/materialize.js +1 -1
- package/src/actions/scales/patch.js +1 -1
- package/src/actions/scales/preview.js +21 -1
- package/src/actions/scales/quantitativeColor.js +8 -3
- package/src/actions/selection/actions.js +1 -13
- package/src/actions/theme/reconcile.js +126 -45
- package/src/actions/theme/state.js +12 -0
- package/src/actions/titles/actions.js +5 -18
- package/src/actions/titles/resolve.js +41 -19
- package/src/actions/violinPlots/edit.js +3 -20
- package/src/core/compositionState.js +6 -3
- package/src/core/font.js +9 -2
- package/src/core/graphicProperties.js +1 -0
- package/src/core/optionRequirements.js +1 -0
- package/src/core/programState.js +4 -0
- package/src/core/resourceReferences.js +5 -2
- package/src/core/textMetricProfile.js +3 -2
- package/src/core/textMetrics.js +41 -4
- package/src/core/validation.js +35 -0
- package/src/core/vocabulary.js +7 -0
- package/src/grammar/aggregate.js +4 -18
- package/src/grammar/arcs.js +1 -386
- package/src/grammar/areaPaint.js +10 -0
- package/src/grammar/areaSeries.js +18 -10
- package/src/grammar/axisTextPlacement.js +1 -0
- package/src/grammar/bars/geometry.js +30 -3
- package/src/grammar/bars/policy.js +12 -1
- package/src/grammar/bin.js +2 -12
- package/src/grammar/bin2d.js +1 -6
- package/src/grammar/boxPlot.js +56 -9
- package/src/grammar/categoryOrder.js +1 -6
- package/src/grammar/colorSizeLegend.js +39 -0
- package/src/grammar/complete.js +15 -19
- package/src/grammar/computed.js +115 -26
- package/src/grammar/curveCommands.js +29 -16
- package/src/grammar/datasetSchema.js +13 -9
- package/src/grammar/displayLabels.js +36 -0
- package/src/grammar/ecdf.js +2 -9
- package/src/grammar/facets/dependencies.js +6 -2
- package/src/grammar/facets/guides.js +58 -30
- package/src/grammar/facets/index.js +2 -5
- package/src/grammar/facets/legendIntent.js +65 -0
- package/src/grammar/fold.js +2 -12
- package/src/grammar/gradientProfile.js +1 -6
- package/src/grammar/guideDash.js +1 -0
- package/src/grammar/impute.js +21 -48
- package/src/grammar/interval.js +2 -9
- package/src/grammar/legendBlocks.js +1 -0
- package/src/grammar/legendBorder.js +9 -0
- package/src/grammar/legendClip.js +19 -0
- package/src/grammar/legendCombinations.js +45 -0
- package/src/grammar/legendGradient.js +27 -0
- package/src/grammar/legendGroups.js +1 -0
- package/src/grammar/legendOpacity.js +6 -0
- package/src/grammar/legendTitleStyle.js +22 -0
- package/src/grammar/lineSeries.js +32 -17
- package/src/grammar/markLabels.js +5 -2
- package/src/grammar/normalize.js +4 -54
- package/src/grammar/numeric.js +1 -290
- package/src/grammar/parallelCoordinates.js +1 -6
- package/src/grammar/parseTime.js +41 -0
- package/src/grammar/pathCommands.js +11 -4
- package/src/grammar/pointShapes.js +16 -2
- package/src/grammar/polar.js +1 -184
- package/src/grammar/positionCompatibility.js +3 -3
- package/src/grammar/regression/derive.js +16 -2
- package/src/grammar/regression/models.js +142 -54
- package/src/grammar/regression/parameters.js +23 -4
- package/src/grammar/regression/statistics.js +64 -0
- package/src/grammar/roundedRect.js +42 -54
- package/src/grammar/scales/appearance.js +1 -206
- package/src/grammar/scales/color.js +1 -382
- package/src/grammar/scales/colorConsumers.js +5 -2
- package/src/grammar/scales/definition.js +1 -197
- package/src/grammar/scales/discretized.js +1 -195
- package/src/grammar/scales/size.js +1 -456
- package/src/grammar/scales/temporal.js +2 -13
- package/src/grammar/scales/transformed.js +1 -383
- package/src/grammar/scales/types.js +1 -1
- package/src/grammar/scales/validation.js +1 -66
- package/src/grammar/schemas/concreteGraphic.js +14 -0
- package/src/grammar/schemas/graphic.js +6 -0
- package/src/grammar/schemas/graphicBounds.js +31 -7
- package/src/grammar/schemas/semanticPath.js +19 -3
- package/src/grammar/stack.js +2 -10
- package/src/grammar/statisticalReference.js +1 -6
- package/src/grammar/summary.js +4 -27
- package/src/grammar/text.js +19 -0
- package/src/grammar/timeUnit.js +22 -11
- package/src/grammar/transformKeys.js +47 -0
- package/src/grammar/transformTopology.js +1 -0
- package/src/grammar/transforms.js +15 -2
- package/src/grammar/valueFormat.js +17 -5
- package/src/grammar/weightedStatistics.js +1 -6
- package/src/grammar/window.js +4 -58
- package/src/inspectionDescriptors.js +1 -1
- package/src/layout/canvas.js +1 -110
- package/src/layout/facets.js +1 -244
- package/src/layout/guideCollisions.js +9 -1
- package/src/layout/labels.js +1 -0
- package/src/layout/legend.js +13 -0
- package/src/layout/legendGroup.js +1 -0
- package/src/layout/legendItems.js +59 -15
- package/src/layout/legendLane.js +1 -441
- package/src/layout/legendText.js +1 -0
- package/src/layout/title.js +35 -13
- package/src/materialization/bars/aggregate.js +11 -5
- package/src/materialization/bars/histogram.js +4 -1
- package/src/materialization/bars/ranged.js +19 -6
- package/src/materialization/bars/resolve.js +22 -1
- package/src/materialization/compositionSnapshot.js +2 -7
- package/src/materialization/coordinateBounds.js +21 -0
- package/src/materialization/dependencies.js +4 -44
- package/src/materialization/facetGuides/edit.js +30 -0
- package/src/materialization/facetGuides/layout.js +1 -0
- package/src/materialization/facetGuides/owner.js +125 -0
- package/src/materialization/facetGuides/ownerLayout.js +71 -0
- package/src/materialization/facetGuides/placement.js +71 -14
- package/src/materialization/facetGuides/preparation.js +22 -7
- package/src/materialization/facetHeaders.js +1 -347
- package/src/materialization/facets.js +1 -185
- package/src/materialization/graphicHierarchy.js +5 -1
- package/src/materialization/graphicTranslation.js +73 -0
- package/src/materialization/guides/layout.js +1 -57
- package/src/materialization/guides/resources.js +1 -123
- package/src/materialization/layout.js +53 -0
- package/src/materialization/legendBorder.js +28 -0
- package/src/materialization/legendClip.js +76 -0
- package/src/materialization/legendGroups.js +1 -0
- package/src/materialization/legendText.js +1 -0
- package/src/materialization/legends.js +2 -2
- package/src/materialization/marks/capabilities.js +5 -6
- package/src/materialization/rect.js +1 -1
- package/src/materialization/scaleGuideDependencies.js +14 -15
- package/src/materialization/scales/map.js +6 -0
- package/src/materialization/scales/policies/arc.js +8 -7
- package/src/materialization/scales/policies/bar.js +19 -7
- package/src/materialization/scales/policies/series.js +2 -1
- package/src/materialization/scales/resolve.js +7 -3
- package/src/materialization/selection/items/arc.js +1 -1
- package/src/materialization/selection/items/bar.js +7 -6
- package/src/materialization/selection/items/path.js +7 -6
- package/src/materialization/selection/items/rect.js +2 -2
- package/src/materialization/text.js +13 -4
- package/src/materialization/textLines.js +15 -0
- package/src/materialization/typography.js +10 -2
- package/src/persistence/codec.js +37 -6
- package/src/persistence/validation.js +220 -0
- package/src/persistence.js +19 -6
- package/src/renderers/canvas/circle.js +6 -3
- package/src/renderers/canvas/fill.js +7 -1
- package/src/renderers/canvas/index.js +22 -11
- package/src/renderers/canvas/isolated.js +166 -0
- package/src/renderers/canvas/limits.js +3 -0
- package/src/renderers/canvas/line.js +1 -0
- package/src/renderers/canvas/path.js +1 -1
- package/src/renderers/canvas/rect.js +11 -8
- package/src/renderers/canvas/stroke.js +2 -1
- package/src/renderers/canvas/text.js +5 -3
- package/src/renderers/pdf.js +2 -2
- package/src/renderers/png.js +2 -2
- package/src/renderers/svg.js +14 -4
- package/src/selectors/axes.js +1 -0
- package/src/selectors/graphicCapacity.js +38 -0
- package/src/selectors/layers.js +19 -0
- package/src/theme/defaults.js +8 -2
- package/src/version.js +1 -1
- package/types/basic.d.ts +3 -0
- package/types/index.d.ts +12 -0
- package/types/program.d.ts +536 -129
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveGraphicBounds } from "../../layout/canvas.js";
|
|
1
2
|
import { action, closedAction } from "../../core/action.js";
|
|
2
3
|
import { registerFacetDataRevision, reviseUnitData } from "../data/revise.js";
|
|
3
4
|
import { freezeOwned, isPlainObject } from "../../core/immutable.js";
|
|
@@ -38,16 +39,16 @@ import {
|
|
|
38
39
|
} from "../../materialization/facetHeaders.js";
|
|
39
40
|
|
|
40
41
|
const FACET_OPTIONS = Object.freeze([
|
|
41
|
-
"id", "field", "data", "values", "columns", "gap", "align", "padding", "scales",
|
|
42
|
-
"guides"
|
|
42
|
+
"id", "field", "data", "values", "columns", "gap", "spacing", "align", "padding", "scales",
|
|
43
|
+
"guides", "headers"
|
|
43
44
|
]);
|
|
44
45
|
const FACET_GRID_OPTIONS = Object.freeze([
|
|
45
|
-
"id", "data", "rows", "columns", "combinations", "gap", "align",
|
|
46
|
-
"padding", "scales", "guides"
|
|
46
|
+
"id", "data", "rows", "columns", "combinations", "gap", "spacing", "align",
|
|
47
|
+
"padding", "scales", "guides", "headers"
|
|
47
48
|
]);
|
|
48
49
|
const REPEAT_OPTIONS = Object.freeze([
|
|
49
|
-
"id", "target", "channel", "fields", "columns", "gap", "align",
|
|
50
|
-
"padding", "scales", "guides"
|
|
50
|
+
"id", "target", "channel", "fields", "columns", "gap", "spacing", "align",
|
|
51
|
+
"padding", "scales", "guides", "headers"
|
|
51
52
|
]);
|
|
52
53
|
const SOURCE_EDIT_OPTIONS = Object.freeze(["program"]);
|
|
53
54
|
const GUIDE_OPTIONS = Object.freeze(["axes", "legend"]);
|
|
@@ -59,7 +60,7 @@ const HEADER_STYLE_OPTIONS = Object.freeze([
|
|
|
59
60
|
"fontSize", "fontFamily", "fontWeight", "color", "offset", "align"
|
|
60
61
|
]);
|
|
61
62
|
|
|
62
|
-
function normalizeGuides(guides) {
|
|
63
|
+
function normalizeGuides(guides, allowStored = false) {
|
|
63
64
|
if (guides === undefined) return { axes: "each", legend: false };
|
|
64
65
|
validateOptionObject(guides, GUIDE_OPTIONS, "facet.guides");
|
|
65
66
|
const axes = guides.axes ?? "each";
|
|
@@ -67,8 +68,11 @@ function normalizeGuides(guides) {
|
|
|
67
68
|
throw new Error('facet guides.axes must be "each" or "outer".');
|
|
68
69
|
}
|
|
69
70
|
const legend = guides.legend ?? false;
|
|
70
|
-
if (legend !== false && legend !== "shared") {
|
|
71
|
-
throw new Error('facet guides.legend must be false
|
|
71
|
+
if (legend !== false && legend !== "shared" && !isPlainObject(legend)) {
|
|
72
|
+
throw new Error('facet guides.legend must be false, "shared", or legend options.');
|
|
73
|
+
}
|
|
74
|
+
if (!allowStored && isPlainObject(legend) && Object.hasOwn(legend, "type")) {
|
|
75
|
+
throw new Error("Facet legend options do not accept internal type tags.");
|
|
72
76
|
}
|
|
73
77
|
return { axes, legend };
|
|
74
78
|
}
|
|
@@ -184,65 +188,149 @@ function rederiveFacet(program, { scales, guides }) {
|
|
|
184
188
|
}, compositionSpec.children);
|
|
185
189
|
}
|
|
186
190
|
|
|
187
|
-
|
|
188
|
-
{
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
191
|
+
function resolveEditedFacetHeaders(currentHeaders, args, grid, operation = "editFacetHeaders") {
|
|
192
|
+
validateOptionObject(args, HEADER_OPTIONS, operation, {
|
|
193
|
+
allowEmpty: false,
|
|
194
|
+
emptyMessage: `${operation} requires at least one change.`
|
|
195
|
+
});
|
|
196
|
+
const role = args.role ?? "all";
|
|
197
|
+
if (!["all", "row", "column"].includes(role)) {
|
|
198
|
+
throw new Error(`Unknown facet header role "${role}".`);
|
|
199
|
+
}
|
|
200
|
+
if (role === "all" && Object.hasOwn(args, "side")) {
|
|
201
|
+
throw new Error(`${operation} side requires an explicit row or column role.`);
|
|
202
|
+
}
|
|
203
|
+
if (role === "row" && grid === undefined) {
|
|
204
|
+
throw new Error(`${operation} row role requires a row-column facet grid.`);
|
|
205
|
+
}
|
|
206
|
+
if (Object.hasOwn(args, "side")) {
|
|
207
|
+
const sides = role === "row" ? ["left", "right"]
|
|
208
|
+
: grid === undefined
|
|
209
|
+
? ["top", "bottom", "left", "right"] : ["top", "bottom"];
|
|
210
|
+
if (!sides.includes(args.side)) {
|
|
211
|
+
throw new Error(`${operation} ${role} side must be ${sides.join(" or ")}.`);
|
|
197
212
|
}
|
|
198
|
-
const scalePolicies = normalizeFacetScalePolicies(
|
|
199
|
-
this.semanticSpec,
|
|
200
|
-
args.scales ?? {}
|
|
201
|
-
);
|
|
202
|
-
const derived = deriveFacetChildren(this, definition, {
|
|
203
|
-
closeInheritedAction: true,
|
|
204
|
-
stripTitle: true,
|
|
205
|
-
scales: args.scales ?? {}
|
|
206
|
-
});
|
|
207
|
-
const preflight = resolveFacetLayout({
|
|
208
|
-
children: definition.cells.map(cell => ({
|
|
209
|
-
...compositionChildDescriptor(cell.id, derived.children[cell.id]),
|
|
210
|
-
value: cell.value
|
|
211
|
-
})),
|
|
212
|
-
...(Object.hasOwn(args, "columns") ? { columns: args.columns } : {}),
|
|
213
|
-
...(Object.hasOwn(args, "gap") ? { gap: args.gap } : {}),
|
|
214
|
-
...(Object.hasOwn(args, "align") ? { align: args.align } : {}),
|
|
215
|
-
...(Object.hasOwn(args, "padding") ? { padding: args.padding } : {}),
|
|
216
|
-
sharedLegend: guides.legend === "shared"
|
|
217
|
-
});
|
|
218
|
-
const compositionSpec = {
|
|
219
|
-
id: definition.id,
|
|
220
|
-
type: "facet",
|
|
221
|
-
children: definition.cells.map(cell => cell.id),
|
|
222
|
-
columns: preflight.columns,
|
|
223
|
-
gap: preflight.gap,
|
|
224
|
-
align: preflight.align,
|
|
225
|
-
padding: preflight.padding,
|
|
226
|
-
facet: {
|
|
227
|
-
data: definition.data,
|
|
228
|
-
field: definition.field,
|
|
229
|
-
values: definition.values,
|
|
230
|
-
scales: scalePolicies.channels,
|
|
231
|
-
guides
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
return applyCompositionState(
|
|
235
|
-
this._withMaterializationConfig(["facets", definition.id], {
|
|
236
|
-
headers: createDefaultFacetHeaders()
|
|
237
|
-
}),
|
|
238
|
-
{
|
|
239
|
-
children: derived.children,
|
|
240
|
-
compositionSpec
|
|
241
|
-
},
|
|
242
|
-
compositionSpec.children
|
|
243
|
-
);
|
|
244
213
|
}
|
|
245
|
-
)
|
|
214
|
+
if (Object.hasOwn(args, "align") &&
|
|
215
|
+
!["start", "center", "end"].includes(args.align)) {
|
|
216
|
+
throw new Error(`${operation} align must be start, center, or end.`);
|
|
217
|
+
}
|
|
218
|
+
if (role === "all" && Object.keys(args).every(key => key === "role")) {
|
|
219
|
+
throw new Error(`${operation} requires at least one change.`);
|
|
220
|
+
}
|
|
221
|
+
const current = normalizeFacetHeadersConfig(currentHeaders);
|
|
222
|
+
const owner = role === "all" ? "common" : role;
|
|
223
|
+
const patch = { ...current[owner] };
|
|
224
|
+
for (const key of HEADER_STYLE_OPTIONS) {
|
|
225
|
+
if (Object.hasOwn(args, key)) patch[key] = args[key];
|
|
226
|
+
}
|
|
227
|
+
if (Object.hasOwn(args, "side")) patch.side = args.side;
|
|
228
|
+
if (Object.hasOwn(args, "labelMap")) {
|
|
229
|
+
if (args.labelMap === "auto") delete patch.labelMap;
|
|
230
|
+
else {
|
|
231
|
+
patch.labelMap = normalizeDisplayLabelMap(
|
|
232
|
+
args.labelMap,
|
|
233
|
+
`${operation} ${role} labelMap`
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const headers = {
|
|
238
|
+
...current,
|
|
239
|
+
...(role === "all" ? {} : { mode: "roles" }),
|
|
240
|
+
[owner]: patch
|
|
241
|
+
};
|
|
242
|
+
for (const headerRole of ["all", "row", "column"]) {
|
|
243
|
+
const resolved = resolveFacetHeaderConfig(headers, headerRole);
|
|
244
|
+
validatePositiveFinite(resolved.fontSize, `Facet ${headerRole} header fontSize`);
|
|
245
|
+
validateNonEmptyString(resolved.fontFamily, `Facet ${headerRole} header fontFamily`);
|
|
246
|
+
validateNonEmptyString(resolved.color, `Facet ${headerRole} header color`);
|
|
247
|
+
validateNonNegativeFinite(resolved.offset, `Facet ${headerRole} header offset`);
|
|
248
|
+
if (!(
|
|
249
|
+
(typeof resolved.fontWeight === "string" && resolved.fontWeight.length > 0) ||
|
|
250
|
+
Number.isFinite(resolved.fontWeight)
|
|
251
|
+
)) {
|
|
252
|
+
throw new TypeError(
|
|
253
|
+
`Facet ${headerRole} header fontWeight must be a non-empty string or number.`
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
if (!["start", "center", "end"].includes(resolved.align)) {
|
|
257
|
+
throw new Error(`Facet ${headerRole} header align must be start, center, or end.`);
|
|
258
|
+
}
|
|
259
|
+
if (resolved.labelMap !== undefined) {
|
|
260
|
+
normalizeDisplayLabelMap(
|
|
261
|
+
resolved.labelMap,
|
|
262
|
+
`Facet ${headerRole} header labelMap`
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return headers;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function initialFacetHeaders(value, grid) {
|
|
270
|
+
let headers = createDefaultFacetHeaders();
|
|
271
|
+
if (value === undefined) return headers;
|
|
272
|
+
validateOptionObject(value, [...HEADER_STYLE_OPTIONS, "labelMap", "row", "column"], "facet.headers");
|
|
273
|
+
const { row, column, ...common } = value;
|
|
274
|
+
if (Object.keys(common).length > 0) headers = resolveEditedFacetHeaders(headers, common, grid, "facet.headers");
|
|
275
|
+
for (const [role, patch] of [["row", row], ["column", column]]) {
|
|
276
|
+
if (patch === undefined) continue;
|
|
277
|
+
validateOptionObject(patch, HEADER_OPTIONS.filter(key => key !== "role"), `facet.headers.${role}`);
|
|
278
|
+
headers = resolveEditedFacetHeaders(headers, { ...patch, role }, grid, `facet.headers.${role}`);
|
|
279
|
+
}
|
|
280
|
+
return headers;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function composeDerivedFacet(program, args, { definition, derived, guides, scalePolicies, facet }) {
|
|
284
|
+
const headers = initialFacetHeaders(args.headers, definition.grid);
|
|
285
|
+
const preflight = resolveFacetLayout({
|
|
286
|
+
spacing: args.spacing,
|
|
287
|
+
plots: Object.entries(derived.children).map(([id, child]) => ({ id, ...resolveGraphicBounds(child) })),
|
|
288
|
+
children: definition.cells.map(cell => ({
|
|
289
|
+
...compositionChildDescriptor(cell.id, derived.children[cell.id]), value: cell.value,
|
|
290
|
+
...(definition.grid === undefined ? {} : { row: cell.row, column: cell.column })
|
|
291
|
+
})),
|
|
292
|
+
columns: definition.grid?.columns.values.length ?? args.columns,
|
|
293
|
+
gap: args.gap, align: args.align, padding: args.padding,
|
|
294
|
+
sharedLegend: guides.legend === "shared"
|
|
295
|
+
});
|
|
296
|
+
const compositionSpec = {
|
|
297
|
+
id: definition.id, type: "facet", children: definition.cells.map(cell => cell.id),
|
|
298
|
+
columns: preflight.columns, gap: preflight.gap, align: preflight.align, padding: preflight.padding,
|
|
299
|
+
...(preflight.spacing === undefined ? {} : { spacing: preflight.spacing }),
|
|
300
|
+
facet: { data: definition.data, ...facet, scales: scalePolicies.channels, guides }
|
|
301
|
+
};
|
|
302
|
+
return applyCompositionState(
|
|
303
|
+
program._withMaterializationConfig(["facets", definition.id], { headers }),
|
|
304
|
+
{ children: derived.children, compositionSpec }, compositionSpec.children
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function partitionFacetAction(op, description, definitionResolver) {
|
|
309
|
+
return closedAction({ op, description }, op === "facet" ? FACET_OPTIONS : FACET_GRID_OPTIONS,
|
|
310
|
+
function (args = {}) {
|
|
311
|
+
const guides = normalizeGuides(args.guides);
|
|
312
|
+
const definition = definitionResolver(this.semanticSpec, args);
|
|
313
|
+
if (definition.family !== "cartesian" && guides.axes === "outer") {
|
|
314
|
+
throw new Error("Polar and Parallel facets do not support outer axes.");
|
|
315
|
+
}
|
|
316
|
+
const scalePolicies = normalizeFacetScalePolicies(this.semanticSpec, args.scales ?? {});
|
|
317
|
+
const derived = deriveFacetChildren(this, definition, {
|
|
318
|
+
closeInheritedAction: true, stripTitle: true, scales: args.scales ?? {}
|
|
319
|
+
});
|
|
320
|
+
const facet = definition.grid === undefined
|
|
321
|
+
? { field: definition.field, values: definition.values }
|
|
322
|
+
: { values: definition.cells.map(cell => cell.value), grid: {
|
|
323
|
+
...definition.grid, cells: definition.cells.map(cell => ({
|
|
324
|
+
id: cell.id, row: cell.row, column: cell.column,
|
|
325
|
+
rowValue: cell.rowValue, columnValue: cell.columnValue, empty: cell.empty
|
|
326
|
+
}))
|
|
327
|
+
} };
|
|
328
|
+
return composeDerivedFacet(this, args, { definition, derived, guides, scalePolicies, facet });
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export const facet = /* @__PURE__ */ partitionFacetAction("facet",
|
|
333
|
+
"Repeat one direct-source chart by field value.", resolveFacetDefinition);
|
|
246
334
|
|
|
247
335
|
function resolveRepeatDefinition(program, args) {
|
|
248
336
|
if (!isPlainObject(args)) {
|
|
@@ -453,115 +541,16 @@ export const repeatCharts = /* @__PURE__ */ closedAction(
|
|
|
453
541
|
requestedScales,
|
|
454
542
|
true
|
|
455
543
|
);
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
})),
|
|
461
|
-
...(Object.hasOwn(args, "columns") ? { columns: args.columns } : {}),
|
|
462
|
-
...(Object.hasOwn(args, "gap") ? { gap: args.gap } : {}),
|
|
463
|
-
...(Object.hasOwn(args, "align") ? { align: args.align } : {}),
|
|
464
|
-
...(Object.hasOwn(args, "padding") ? { padding: args.padding } : {}),
|
|
465
|
-
sharedLegend: guides.legend === "shared"
|
|
544
|
+
return composeDerivedFacet(this, args, {
|
|
545
|
+
definition, derived, guides, scalePolicies,
|
|
546
|
+
facet: { values: definition.fields,
|
|
547
|
+
repeat: { target: definition.target, channel: definition.channel, fields: definition.fields } }
|
|
466
548
|
});
|
|
467
|
-
const compositionSpec = {
|
|
468
|
-
id: definition.id,
|
|
469
|
-
type: "facet",
|
|
470
|
-
children: definition.cells.map(cell => cell.id),
|
|
471
|
-
columns: preflight.columns,
|
|
472
|
-
gap: preflight.gap,
|
|
473
|
-
align: preflight.align,
|
|
474
|
-
padding: preflight.padding,
|
|
475
|
-
facet: {
|
|
476
|
-
data: definition.data,
|
|
477
|
-
values: definition.fields,
|
|
478
|
-
repeat: {
|
|
479
|
-
target: definition.target,
|
|
480
|
-
channel: definition.channel,
|
|
481
|
-
fields: definition.fields
|
|
482
|
-
},
|
|
483
|
-
scales: scalePolicies.channels,
|
|
484
|
-
guides
|
|
485
|
-
}
|
|
486
|
-
};
|
|
487
|
-
return applyCompositionState(
|
|
488
|
-
this._withMaterializationConfig(["facets", definition.id], {
|
|
489
|
-
headers: createDefaultFacetHeaders()
|
|
490
|
-
}),
|
|
491
|
-
{ children: derived.children, compositionSpec },
|
|
492
|
-
compositionSpec.children
|
|
493
|
-
);
|
|
494
549
|
}
|
|
495
550
|
);
|
|
496
551
|
|
|
497
|
-
export const facetGrid = /* @__PURE__ */
|
|
498
|
-
|
|
499
|
-
op: "facetGrid",
|
|
500
|
-
description: "Repeat one direct-source Cartesian chart across a row and column field grid."
|
|
501
|
-
}, FACET_GRID_OPTIONS,
|
|
502
|
-
function (args = {}) {
|
|
503
|
-
const guides = normalizeGuides(args.guides);
|
|
504
|
-
const definition = resolveFacetGridDefinition(this.semanticSpec, args);
|
|
505
|
-
if (definition.family !== "cartesian" && guides.axes === "outer") {
|
|
506
|
-
throw new Error("Polar and Parallel facets do not support outer axes.");
|
|
507
|
-
}
|
|
508
|
-
const scalePolicies = normalizeFacetScalePolicies(
|
|
509
|
-
this.semanticSpec,
|
|
510
|
-
args.scales ?? {}
|
|
511
|
-
);
|
|
512
|
-
const derived = deriveFacetChildren(this, definition, {
|
|
513
|
-
closeInheritedAction: true,
|
|
514
|
-
stripTitle: true,
|
|
515
|
-
scales: args.scales ?? {}
|
|
516
|
-
});
|
|
517
|
-
const preflight = resolveFacetLayout({
|
|
518
|
-
children: definition.cells.map(cell => ({
|
|
519
|
-
...compositionChildDescriptor(cell.id, derived.children[cell.id]),
|
|
520
|
-
value: cell.value,
|
|
521
|
-
row: cell.row,
|
|
522
|
-
column: cell.column
|
|
523
|
-
})),
|
|
524
|
-
columns: definition.grid.columns.values.length,
|
|
525
|
-
...(Object.hasOwn(args, "gap") ? { gap: args.gap } : {}),
|
|
526
|
-
...(Object.hasOwn(args, "align") ? { align: args.align } : {}),
|
|
527
|
-
...(Object.hasOwn(args, "padding") ? { padding: args.padding } : {}),
|
|
528
|
-
sharedLegend: guides.legend === "shared"
|
|
529
|
-
});
|
|
530
|
-
const compositionSpec = {
|
|
531
|
-
id: definition.id,
|
|
532
|
-
type: "facet",
|
|
533
|
-
children: definition.cells.map(cell => cell.id),
|
|
534
|
-
columns: preflight.columns,
|
|
535
|
-
gap: preflight.gap,
|
|
536
|
-
align: preflight.align,
|
|
537
|
-
padding: preflight.padding,
|
|
538
|
-
facet: {
|
|
539
|
-
data: definition.data,
|
|
540
|
-
values: definition.cells.map(cell => cell.value),
|
|
541
|
-
grid: {
|
|
542
|
-
...definition.grid,
|
|
543
|
-
cells: definition.cells.map(cell => ({
|
|
544
|
-
id: cell.id,
|
|
545
|
-
row: cell.row,
|
|
546
|
-
column: cell.column,
|
|
547
|
-
rowValue: cell.rowValue,
|
|
548
|
-
columnValue: cell.columnValue,
|
|
549
|
-
empty: cell.empty
|
|
550
|
-
}))
|
|
551
|
-
},
|
|
552
|
-
scales: scalePolicies.channels,
|
|
553
|
-
guides
|
|
554
|
-
}
|
|
555
|
-
};
|
|
556
|
-
return applyCompositionState(
|
|
557
|
-
this._withMaterializationConfig(["facets", definition.id], {
|
|
558
|
-
headers: createDefaultFacetHeaders()
|
|
559
|
-
}),
|
|
560
|
-
{ children: derived.children, compositionSpec },
|
|
561
|
-
compositionSpec.children
|
|
562
|
-
);
|
|
563
|
-
}
|
|
564
|
-
);
|
|
552
|
+
export const facetGrid = /* @__PURE__ */ partitionFacetAction("facetGrid",
|
|
553
|
+
"Repeat one direct-source Cartesian chart across a row and column field grid.", resolveFacetGridDefinition);
|
|
565
554
|
|
|
566
555
|
export const editFacetHeaders = /* @__PURE__ */ action(
|
|
567
556
|
{
|
|
@@ -576,78 +565,7 @@ export const editFacetHeaders = /* @__PURE__ */ action(
|
|
|
576
565
|
if (!isPlainObject(config?.headers)) {
|
|
577
566
|
throw new Error(`Facet "${id}" requires header configuration.`);
|
|
578
567
|
}
|
|
579
|
-
|
|
580
|
-
allowEmpty: false,
|
|
581
|
-
emptyMessage: "editFacetHeaders requires at least one change."
|
|
582
|
-
});
|
|
583
|
-
const role = args.role ?? "all";
|
|
584
|
-
if (!["all", "row", "column"].includes(role)) {
|
|
585
|
-
throw new Error(`Unknown facet header role "${role}".`);
|
|
586
|
-
}
|
|
587
|
-
if (role === "all" && Object.hasOwn(args, "side")) {
|
|
588
|
-
throw new Error("editFacetHeaders side requires an explicit row or column role.");
|
|
589
|
-
}
|
|
590
|
-
if (role === "row" && this.compositionSpec.facet.grid === undefined) {
|
|
591
|
-
throw new Error("editFacetHeaders row role requires a row-column facet grid.");
|
|
592
|
-
}
|
|
593
|
-
if (Object.hasOwn(args, "side")) {
|
|
594
|
-
const sides = role === "row" ? ["left", "right"] : ["top", "bottom"];
|
|
595
|
-
if (!sides.includes(args.side)) {
|
|
596
|
-
throw new Error(`editFacetHeaders ${role} side must be ${sides.join(" or ")}.`);
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
if (Object.hasOwn(args, "align") &&
|
|
600
|
-
!["start", "center", "end"].includes(args.align)) {
|
|
601
|
-
throw new Error("editFacetHeaders align must be start, center, or end.");
|
|
602
|
-
}
|
|
603
|
-
if (role === "all" && Object.keys(args).every(key => key === "role")) {
|
|
604
|
-
throw new Error("editFacetHeaders requires at least one change.");
|
|
605
|
-
}
|
|
606
|
-
const current = normalizeFacetHeadersConfig(config.headers);
|
|
607
|
-
const owner = role === "all" ? "common" : role;
|
|
608
|
-
const patch = { ...current[owner] };
|
|
609
|
-
for (const key of HEADER_STYLE_OPTIONS) {
|
|
610
|
-
if (Object.hasOwn(args, key)) patch[key] = args[key];
|
|
611
|
-
}
|
|
612
|
-
if (Object.hasOwn(args, "side")) patch.side = args.side;
|
|
613
|
-
if (Object.hasOwn(args, "labelMap")) {
|
|
614
|
-
if (args.labelMap === "auto") delete patch.labelMap;
|
|
615
|
-
else {
|
|
616
|
-
patch.labelMap = normalizeDisplayLabelMap(
|
|
617
|
-
args.labelMap,
|
|
618
|
-
`editFacetHeaders ${role} labelMap`
|
|
619
|
-
);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
const headers = {
|
|
623
|
-
...current,
|
|
624
|
-
...(role === "all" ? {} : { mode: "roles" }),
|
|
625
|
-
[owner]: patch
|
|
626
|
-
};
|
|
627
|
-
for (const headerRole of ["all", "row", "column"]) {
|
|
628
|
-
const resolved = resolveFacetHeaderConfig(headers, headerRole);
|
|
629
|
-
validatePositiveFinite(resolved.fontSize, `Facet ${headerRole} header fontSize`);
|
|
630
|
-
validateNonEmptyString(resolved.fontFamily, `Facet ${headerRole} header fontFamily`);
|
|
631
|
-
validateNonEmptyString(resolved.color, `Facet ${headerRole} header color`);
|
|
632
|
-
validateNonNegativeFinite(resolved.offset, `Facet ${headerRole} header offset`);
|
|
633
|
-
if (!(
|
|
634
|
-
(typeof resolved.fontWeight === "string" && resolved.fontWeight.length > 0) ||
|
|
635
|
-
Number.isFinite(resolved.fontWeight)
|
|
636
|
-
)) {
|
|
637
|
-
throw new TypeError(
|
|
638
|
-
`Facet ${headerRole} header fontWeight must be a non-empty string or number.`
|
|
639
|
-
);
|
|
640
|
-
}
|
|
641
|
-
if (!["start", "center", "end"].includes(resolved.align)) {
|
|
642
|
-
throw new Error(`Facet ${headerRole} header align must be start, center, or end.`);
|
|
643
|
-
}
|
|
644
|
-
if (resolved.labelMap !== undefined) {
|
|
645
|
-
normalizeDisplayLabelMap(
|
|
646
|
-
resolved.labelMap,
|
|
647
|
-
`Facet ${headerRole} header labelMap`
|
|
648
|
-
);
|
|
649
|
-
}
|
|
650
|
-
}
|
|
568
|
+
const headers = resolveEditedFacetHeaders(config.headers, args, this.compositionSpec.facet.grid);
|
|
651
569
|
return this
|
|
652
570
|
._withMaterializationConfig(["facets", id], { ...config, headers })
|
|
653
571
|
.materializeComposition();
|
|
@@ -702,7 +620,8 @@ export const editFacetGuides = /* @__PURE__ */ action(
|
|
|
702
620
|
emptyMessage: "editFacetGuides requires at least one guide policy."
|
|
703
621
|
});
|
|
704
622
|
const current = this.compositionSpec.facet;
|
|
705
|
-
|
|
623
|
+
if (Object.hasOwn(args, "legend")) normalizeGuides({ legend: args.legend });
|
|
624
|
+
const guides = normalizeGuides({ ...current.guides, ...args }, true);
|
|
706
625
|
const family = resolveFacetFamily(this.semanticSpec).family;
|
|
707
626
|
if (family !== "cartesian" && guides.axes === "outer") {
|
|
708
627
|
throw new Error("Polar and Parallel facets do not support outer axes.");
|
|
@@ -773,6 +692,8 @@ export const editFacetSource = /* @__PURE__ */ closedAction(
|
|
|
773
692
|
const current = this.compositionSpec;
|
|
774
693
|
const facetConfig = this.materializationConfigs.facets?.[current.id];
|
|
775
694
|
const base = adoptUnitState(args.program, this);
|
|
695
|
+
const authored = isPlainObject(current.facet.guides.legend);
|
|
696
|
+
const guides = authored ? { ...current.facet.guides, legend: false } : current.facet.guides;
|
|
776
697
|
let revised;
|
|
777
698
|
const scales = usedFacetScalePolicies(base, current.facet.scales);
|
|
778
699
|
if (current.facet.grid !== undefined) {
|
|
@@ -783,10 +704,11 @@ export const editFacetSource = /* @__PURE__ */ closedAction(
|
|
|
783
704
|
columns: current.facet.grid.columns,
|
|
784
705
|
combinations: current.facet.grid.combinations,
|
|
785
706
|
gap: current.gap,
|
|
707
|
+
...(current.spacing === undefined ? {} : { spacing: current.spacing }),
|
|
786
708
|
align: current.align,
|
|
787
709
|
padding: current.padding,
|
|
788
710
|
scales,
|
|
789
|
-
guides
|
|
711
|
+
guides
|
|
790
712
|
});
|
|
791
713
|
} else if (current.facet.repeat !== undefined) {
|
|
792
714
|
revised = base.repeatCharts({
|
|
@@ -794,10 +716,11 @@ export const editFacetSource = /* @__PURE__ */ closedAction(
|
|
|
794
716
|
...current.facet.repeat,
|
|
795
717
|
columns: current.columns,
|
|
796
718
|
gap: current.gap,
|
|
719
|
+
...(current.spacing === undefined ? {} : { spacing: current.spacing }),
|
|
797
720
|
align: current.align,
|
|
798
721
|
padding: current.padding,
|
|
799
722
|
scales,
|
|
800
|
-
guides
|
|
723
|
+
guides
|
|
801
724
|
});
|
|
802
725
|
} else {
|
|
803
726
|
revised = base.facet({
|
|
@@ -807,12 +730,18 @@ export const editFacetSource = /* @__PURE__ */ closedAction(
|
|
|
807
730
|
values: current.facet.values,
|
|
808
731
|
columns: current.columns,
|
|
809
732
|
gap: current.gap,
|
|
733
|
+
...(current.spacing === undefined ? {} : { spacing: current.spacing }),
|
|
810
734
|
align: current.align,
|
|
811
735
|
padding: current.padding,
|
|
812
736
|
scales,
|
|
813
|
-
guides
|
|
737
|
+
guides
|
|
814
738
|
});
|
|
815
739
|
}
|
|
740
|
+
if (authored) {
|
|
741
|
+
const spec = revised.compositionSpec;
|
|
742
|
+
revised = revised._withCompositionState({ children: revised.children,
|
|
743
|
+
compositionSpec: { ...spec, facet: { ...spec.facet, guides: current.facet.guides } } });
|
|
744
|
+
}
|
|
816
745
|
if (facetConfig !== undefined) {
|
|
817
746
|
revised = revised
|
|
818
747
|
._withMaterializationConfig(["facets", current.id], facetConfig)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { synchronizeFacetColorSizeMeaning } from "../primitives/semanticAction.js";
|
|
1
2
|
import { closedAction } from "../../core/action.js";
|
|
2
3
|
|
|
3
4
|
import { applyFacetGuideComposition } from
|
|
@@ -10,6 +11,6 @@ export const composeFacetGuides = /* @__PURE__ */ closedAction(
|
|
|
10
11
|
scope: "composition"
|
|
11
12
|
}, ["layout", "plot"],
|
|
12
13
|
function ({ layout, plot } = {}) {
|
|
13
|
-
return applyFacetGuideComposition(this, { layout, plot });
|
|
14
|
+
return applyFacetGuideComposition(this, { layout, plot, synchronizeColorSizeMeaning: synchronizeFacetColorSizeMeaning });
|
|
14
15
|
}
|
|
15
16
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolveOptionalUserId, validateUserId } from "../../core/identifiers.js";
|
|
2
|
-
import { findLayer, hasLayer } from "../../selectors/layers.js";
|
|
2
|
+
import { findLayer, hasLayer, resolveConfiguredOwner } from "../../selectors/layers.js";
|
|
3
3
|
|
|
4
4
|
const CATEGORICAL = Object.freeze(["nominal", "ordinal"]);
|
|
5
5
|
|
|
@@ -62,20 +62,5 @@ export function resolveGradientPlotId(program, requested) {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
export function resolveGradientOwner(program, requested, operation) {
|
|
65
|
-
|
|
66
|
-
layer => program.markConfigs[layer.id]?.gradientPlot?.materialized === true
|
|
67
|
-
);
|
|
68
|
-
if (requested !== undefined) {
|
|
69
|
-
const id = validateUserId(requested, "Gradient-plot owner id");
|
|
70
|
-
const layer = findLayer(program, id);
|
|
71
|
-
if (layer === undefined || !eligible.includes(layer)) {
|
|
72
|
-
throw new Error(`Unknown gradient-plot owner "${id}".`);
|
|
73
|
-
}
|
|
74
|
-
return layer;
|
|
75
|
-
}
|
|
76
|
-
const current = findLayer(program, program.context.currentMark);
|
|
77
|
-
if (current !== undefined && eligible.includes(current)) return current;
|
|
78
|
-
if (eligible.length === 1) return eligible[0];
|
|
79
|
-
if (eligible.length === 0) throw new Error(`${operation} requires a gradient plot.`);
|
|
80
|
-
throw new Error(`${operation} target is ambiguous; provide target.`);
|
|
65
|
+
return resolveConfiguredOwner(program, requested, { config: "gradientPlot", operation, kind: "gradient", materialized: true }, validateUserId);
|
|
81
66
|
}
|
|
@@ -56,7 +56,7 @@ export function hasInferableLegend(program, layers = program.semanticSpec.layers
|
|
|
56
56
|
(layer.mark?.type === "point" &&
|
|
57
57
|
layer.encoding?.color?.scale !== undefined &&
|
|
58
58
|
(layer.encoding?.shape?.scale !== undefined ||
|
|
59
|
-
["sequential", "quantize", "quantile", "threshold"].includes(
|
|
59
|
+
["sequential", "log", "sqrt", "symlog", "quantize", "quantile", "threshold"].includes(
|
|
60
60
|
findSemanticScale(program, layer.encoding.color.scale)?.type
|
|
61
61
|
))) ||
|
|
62
62
|
(layer.mark?.type === "line" &&
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withGuideLayoutTransaction } from "../../../materialization/guides/layout.js";
|
|
1
2
|
import { isSourceOwnedText } from "../../../grammar/text.js";
|
|
2
3
|
import { action } from "../../../core/action.js";
|
|
3
4
|
import { isPlainObject } from "../../../core/immutable.js";
|
|
@@ -15,6 +16,13 @@ const COORDINATE_API_TYPES = new Set([
|
|
|
15
16
|
]);
|
|
16
17
|
|
|
17
18
|
function validateAxisOption(value, channel) {
|
|
19
|
+
if (["x", "y"].includes(channel) && Array.isArray(value)) {
|
|
20
|
+
if (value.length === 0 || value.some(entry => !isPlainObject(entry) || !Object.hasOwn(entry, "id"))) {
|
|
21
|
+
throw new TypeError(`createAxes ${channel} arrays require nonempty named axis descriptors.`);
|
|
22
|
+
}
|
|
23
|
+
for (const entry of value) validateUserId(entry.id, "Axis id");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
18
26
|
if (value !== undefined && value !== false && !isPlainObject(value)) {
|
|
19
27
|
throw new TypeError(`createAxes ${channel} must be false or a plain object.`);
|
|
20
28
|
}
|
|
@@ -287,23 +295,34 @@ const createAxes = /* @__PURE__ */ action(
|
|
|
287
295
|
coordinateDescriptor,
|
|
288
296
|
cartesianLayers
|
|
289
297
|
);
|
|
290
|
-
const
|
|
291
|
-
|
|
298
|
+
const resolve = (channel, value) => Array.isArray(value)
|
|
299
|
+
? value.map(entry => resolveAxisArgs(coordinate.layers, channel, entry))
|
|
300
|
+
: resolveAxisArgs(coordinate.layers, channel, value);
|
|
301
|
+
const x = resolve("x", args.x);
|
|
302
|
+
const y = resolve("y", args.y);
|
|
292
303
|
|
|
293
304
|
if (x === undefined && y === undefined) {
|
|
294
305
|
throw new Error("createAxes requires at least one selected axis.");
|
|
295
306
|
}
|
|
296
307
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
308
|
+
const apply = source => {
|
|
309
|
+
let program = source;
|
|
310
|
+
for (const [channel, option] of [["x", x], ["y", y]]) {
|
|
311
|
+
if (option === undefined) continue;
|
|
312
|
+
for (const entry of Array.isArray(option) ? option : [option]) {
|
|
313
|
+
program = program[`create${channel.toUpperCase()}Axis`]({ ...entry, coordinate: coordinate.id });
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return program;
|
|
317
|
+
};
|
|
318
|
+
if (Array.isArray(x) || Array.isArray(y)) {
|
|
319
|
+
const ids = [...(Array.isArray(x) ? x : x === undefined ? [] : [x]),
|
|
320
|
+
...(Array.isArray(y) ? y : y === undefined ? [] : [y])].map((entry, index) => entry.id ?? (index === 0 ? "x" : "y"));
|
|
321
|
+
if (new Set(ids).size !== ids.length) throw new Error("createAxes requires unique axis ids across its descriptors.");
|
|
322
|
+
withGuideLayoutTransaction(this, apply);
|
|
323
|
+
return withGuideLayoutTransaction(this, apply);
|
|
304
324
|
}
|
|
305
|
-
|
|
306
|
-
return program;
|
|
325
|
+
return apply(this);
|
|
307
326
|
}
|
|
308
327
|
);
|
|
309
328
|
|