ggaction 0.0.12 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +127 -0
- package/README.md +20 -11
- 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 +10 -3
- package/src/actions/basic.js +4 -2
- package/src/actions/boxPlots/components.js +14 -4
- package/src/actions/boxPlots/edit.js +31 -5
- package/src/actions/boxPlots/materialize.js +13 -4
- package/src/actions/boxPlots/options.js +48 -16
- 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 +18 -6
- package/src/actions/charts/area.js +51 -0
- package/src/actions/charts/bar.js +13 -6
- package/src/actions/charts/beeswarm.js +70 -0
- package/src/actions/charts/density.js +48 -0
- package/src/actions/charts/ecdf.js +186 -0
- package/src/actions/charts/endpoints.js +473 -0
- package/src/actions/charts/heatmap.js +4 -3
- package/src/actions/charts/histogram.js +5 -4
- package/src/actions/charts/horizon.js +73 -0
- package/src/actions/charts/index.js +37 -0
- package/src/actions/charts/interval-regression.js +172 -0
- package/src/actions/charts/line.js +8 -6
- package/src/actions/charts/parallel.js +8 -2
- package/src/actions/charts/pie.js +52 -0
- package/src/actions/charts/polar.js +134 -0
- package/src/actions/charts/radar.js +305 -0
- package/src/actions/charts/radial.js +50 -0
- package/src/actions/charts/raincloud.js +422 -0
- package/src/actions/charts/rug-strip.js +283 -0
- package/src/actions/charts/scatter.js +11 -3
- package/src/actions/charts/shared.js +69 -10
- package/src/actions/composition/actions.js +129 -3
- package/src/actions/coordinates/actions.js +1 -1
- package/src/actions/coordinates/edit.js +76 -0
- package/src/actions/data/bin.js +29 -0
- package/src/actions/data/bin2d.js +57 -185
- package/src/actions/data/complete.js +26 -0
- package/src/actions/data/computed.js +24 -0
- package/src/actions/data/create.js +2 -2
- package/src/actions/data/density.js +12 -20
- package/src/actions/data/derived.js +111 -15
- package/src/actions/data/ecdf.js +38 -0
- package/src/actions/data/edit.js +539 -0
- package/src/actions/data/filter.js +226 -30
- package/src/actions/data/fold.js +24 -0
- package/src/actions/data/impute.js +26 -0
- package/src/actions/data/index.js +38 -0
- package/src/actions/data/interval.js +2 -0
- package/src/actions/data/intervalEdit.js +86 -4
- package/src/actions/data/normalize.js +27 -0
- package/src/actions/data/regression.js +19 -21
- package/src/actions/data/revisionBindings.js +145 -0
- package/src/actions/data/shared.js +20 -4
- package/src/actions/data/stack.js +26 -0
- package/src/actions/data/summary.js +26 -0
- package/src/actions/data/timeUnit.js +4 -1
- package/src/actions/data/window.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/channels.js +415 -0
- package/src/actions/encodings/color/continuous.js +19 -59
- package/src/actions/encodings/color/index.js +30 -23
- 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 +124 -34
- package/src/actions/encodings/histogram.js +3 -2
- package/src/actions/encodings/horizon/resolve.js +8 -4
- package/src/actions/encodings/horizon.js +18 -8
- package/src/actions/encodings/index.js +6 -0
- package/src/actions/encodings/offset.js +30 -29
- package/src/actions/encodings/parallel.js +2 -8
- package/src/actions/encodings/position/apply.js +63 -11
- package/src/actions/encodings/position/index.js +52 -6
- package/src/actions/encodings/position/policies/arc.js +14 -0
- package/src/actions/encodings/position/policies/area.js +4 -42
- package/src/actions/encodings/position/policies/bar.js +57 -13
- package/src/actions/encodings/position/resolve.js +88 -26
- package/src/actions/encodings/ranged.js +123 -97
- package/src/actions/encodings/remove.js +44 -34
- package/src/actions/encodings/ruleAppearance.js +24 -32
- package/src/actions/encodings/seriesLayout.js +105 -0
- package/src/actions/encodings/shared.js +107 -37
- package/src/actions/encodings/stroke.js +226 -0
- 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 +41 -8
- package/src/actions/errorBands/edit.js +360 -25
- package/src/actions/errorBars/create.js +56 -17
- package/src/actions/errorBars/edit.js +372 -21
- package/src/actions/facets/actions.js +619 -41
- package/src/actions/facets/derive.js +139 -25
- package/src/actions/gradientPlots/components.js +43 -13
- package/src/actions/gradientPlots/edit.js +14 -4
- package/src/actions/gradientPlots/materialize.js +8 -8
- package/src/actions/gradientPlots/options.js +10 -2
- package/src/actions/guides/applicability.js +28 -19
- 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 +184 -28
- package/src/actions/guides/axes/lines.js +13 -7
- 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 +50 -25
- 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 +15 -8
- package/src/actions/guides/axes/ticks.js +11 -6
- package/src/actions/guides/axes/titles.js +32 -11
- 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 +17 -4
- package/src/actions/guides/guides.js +54 -31
- package/src/actions/guides/legends/blocks.js +426 -0
- package/src/actions/guides/legends/categorical/actions.js +309 -279
- package/src/actions/guides/legends/categorical/components.js +21 -17
- package/src/actions/guides/legends/categorical/index.js +37 -33
- package/src/actions/guides/legends/categorical/layout.js +123 -354
- package/src/actions/guides/legends/categorical/options.js +32 -16
- package/src/actions/guides/legends/categorical/recipes.js +114 -9
- package/src/actions/guides/legends/categorical/resolve.js +30 -15
- package/src/actions/guides/legends/categorical/symbols.js +87 -33
- package/src/actions/guides/legends/continuous/common.js +99 -26
- package/src/actions/guides/legends/continuous/gradient.js +120 -89
- package/src/actions/guides/legends/continuous/index.js +8 -2
- package/src/actions/guides/legends/continuous/interval.js +79 -95
- package/src/actions/guides/legends/continuous/opacity.js +113 -89
- package/src/actions/guides/legends/continuous/stroke.js +525 -0
- package/src/actions/guides/legends/creation.js +40 -0
- package/src/actions/guides/legends/edit.js +321 -90
- package/src/actions/guides/legends/focused.js +2 -2
- package/src/actions/guides/legends/index.js +2 -0
- package/src/actions/guides/legends/lane.js +149 -102
- package/src/actions/guides/legends/lifecycle.js +143 -0
- package/src/actions/guides/legends/remove.js +43 -78
- package/src/actions/guides/legends/sampling.js +140 -0
- package/src/actions/guides/legends/size.js +213 -116
- package/src/actions/guides/legends/strokeWidth.js +121 -73
- package/src/actions/guides/legends/target.js +123 -0
- package/src/actions/guides/legends/transition.js +192 -0
- package/src/actions/guides/polar/axes/facade.js +81 -66
- package/src/actions/guides/polar/axes/labels.js +28 -8
- package/src/actions/guides/polar/axes/lines.js +12 -5
- package/src/actions/guides/polar/axes/shared.js +22 -0
- package/src/actions/guides/polar/axes/ticks.js +6 -5
- package/src/actions/guides/polar/axes/titles.js +6 -5
- package/src/actions/guides/polar/grids.js +8 -8
- package/src/actions/guides/polar/resolve.js +12 -8
- package/src/actions/guides/reuse.js +44 -0
- package/src/actions/guides/tickValues.js +19 -21
- package/src/actions/index.js +15 -2
- package/src/actions/intervals/resolve.js +35 -15
- package/src/actions/marks/arc/actions.js +78 -20
- package/src/actions/marks/area/actions.js +51 -12
- package/src/actions/marks/area/materialize.js +22 -3
- package/src/actions/marks/bar/create.js +11 -2
- package/src/actions/marks/bar/edit.js +20 -3
- package/src/actions/marks/bar/materialize.js +33 -9
- package/src/actions/marks/index.js +14 -0
- package/src/actions/marks/line/actions.js +71 -113
- package/src/actions/marks/line/materialize.js +57 -56
- package/src/actions/marks/point/create.js +8 -2
- package/src/actions/marks/point/edit.js +29 -21
- 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 +154 -16
- package/src/actions/marks/point/packing.js +68 -0
- package/src/actions/marks/rect/actions.js +33 -12
- package/src/actions/marks/references.js +658 -0
- package/src/actions/marks/remove.js +87 -4
- package/src/actions/marks/rule/actions.js +77 -9
- package/src/actions/marks/rule/appearance.js +26 -0
- package/src/actions/marks/shared.js +13 -13
- package/src/actions/marks/text/actions.js +296 -13
- package/src/actions/marks/text/index.js +4 -0
- package/src/actions/marks/text/layout.js +156 -8
- package/src/actions/marks/text/removal.js +173 -0
- package/src/actions/marks/text/selection.js +73 -0
- package/src/actions/marks/tick/actions.js +22 -5
- package/src/actions/primitives/createGraphics.js +3 -1
- package/src/actions/primitives/editGraphics.js +26 -0
- package/src/actions/primitives/semantic.js +3 -2
- package/src/actions/primitives/semanticAction.js +120 -10
- package/src/actions/primitives/semanticValidation/guide.js +10 -0
- package/src/actions/primitives/semanticValidation/index.js +9 -1
- package/src/actions/primitives/semanticValidation/layer.js +23 -1
- package/src/actions/primitives/semanticValidation/scale.js +38 -8
- package/src/actions/regression/components.js +26 -11
- package/src/actions/regression/create.js +11 -3
- package/src/actions/regression/edit.js +40 -13
- package/src/actions/regression/resolve.js +1 -1
- package/src/actions/resources/index.js +7 -0
- package/src/actions/resources/remove.js +172 -0
- package/src/actions/scales/channels.js +212 -0
- package/src/actions/scales/consumers/common.js +21 -54
- package/src/actions/scales/consumers/families.js +28 -14
- package/src/actions/scales/consumers/index.js +42 -4
- package/src/actions/scales/consumers/seriesLayout.js +57 -12
- package/src/actions/scales/create.js +58 -26
- package/src/actions/scales/definitions.js +109 -39
- package/src/actions/scales/edit.js +101 -34
- package/src/actions/scales/editPolicy.js +95 -35
- package/src/actions/scales/index.js +6 -0
- package/src/actions/scales/materialize.js +14 -49
- package/src/actions/scales/offset.js +48 -0
- package/src/actions/scales/parallel.js +71 -0
- package/src/actions/scales/patch.js +1 -1
- package/src/actions/scales/preview.js +140 -0
- package/src/actions/scales/quantitativeColor.js +9 -5
- package/src/actions/selection/actions.js +154 -30
- package/src/actions/selection/index.js +3 -0
- package/src/actions/theme/actions.js +98 -0
- package/src/actions/theme/composition.js +238 -0
- package/src/actions/theme/index.js +16 -0
- package/src/actions/theme/reconcile.js +1130 -0
- package/src/actions/theme/state.js +160 -0
- package/src/actions/titles/actions.js +11 -10
- package/src/actions/titles/resolve.js +1 -40
- package/src/actions/violinPlots/create.js +90 -43
- package/src/actions/violinPlots/edit.js +192 -0
- package/src/actions/violinPlots/index.js +2 -0
- package/src/core/ChartProgram.js +7 -0
- package/src/core/action.js +32 -2
- package/src/core/compositionState.js +141 -8
- package/src/core/programState.js +20 -0
- package/src/core/resourceReferences.js +332 -0
- package/src/core/vocabulary.js +16 -3
- package/src/grammar/aggregate.js +66 -23
- package/src/grammar/arcs.js +58 -1
- package/src/grammar/areaEndpoints.js +46 -0
- package/src/grammar/areaSeries.js +87 -41
- package/src/grammar/bars/aggregate.js +37 -13
- package/src/grammar/bars/geometry.js +44 -0
- package/src/grammar/bars/policy.js +9 -7
- package/src/grammar/bin.js +226 -0
- package/src/grammar/categoryOrder.js +34 -0
- package/src/grammar/complete.js +279 -0
- package/src/grammar/computed.js +351 -0
- package/src/grammar/coordinates.js +37 -0
- package/src/grammar/density.js +239 -37
- package/src/grammar/displayLabels.js +57 -0
- package/src/grammar/ecdf.js +198 -0
- package/src/grammar/facets/dependencies.js +133 -1
- package/src/grammar/facets/guides.js +3 -0
- package/src/grammar/facets/index.js +123 -52
- package/src/grammar/facets/scales.js +15 -18
- package/src/grammar/fold.js +123 -0
- package/src/grammar/horizon.js +6 -4
- package/src/grammar/impute.js +340 -0
- package/src/grammar/interval.js +37 -20
- package/src/grammar/lineSeries.js +20 -63
- package/src/grammar/markFilter.js +22 -4
- package/src/grammar/markLabelSelection.js +57 -0
- package/src/grammar/markLabels.js +110 -0
- package/src/grammar/normalize.js +366 -0
- package/src/grammar/parallelAxisTitles.js +16 -0
- package/src/grammar/pathSeries.js +109 -0
- package/src/grammar/pointPacking.js +183 -0
- package/src/grammar/pointShapes.js +13 -4
- package/src/grammar/polar.js +90 -8
- 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 +8 -2
- package/src/grammar/regression/models.js +22 -7
- package/src/grammar/regression/parameters.js +63 -13
- package/src/grammar/rotation.js +29 -0
- package/src/grammar/roundedRect.js +180 -0
- package/src/grammar/rules.js +8 -21
- package/src/grammar/scales/color.js +23 -1
- package/src/grammar/scales/colorConsumers.js +57 -0
- package/src/grammar/scales/continuous.js +2 -2
- package/src/grammar/scales/definition.js +42 -5
- package/src/grammar/scales/discretized.js +11 -5
- package/src/grammar/scales/fields.js +38 -8
- package/src/grammar/scales/index.js +1 -0
- package/src/grammar/scales/mapping.js +2 -0
- package/src/grammar/scales/ordinal.js +12 -3
- package/src/grammar/scales/policies.js +2 -2
- package/src/grammar/scales/radial.js +55 -0
- package/src/grammar/scales/size.js +456 -0
- package/src/grammar/scales/types.js +1 -0
- package/src/grammar/schemas/concreteGraphic.js +14 -2
- package/src/grammar/schemas/graphic.js +15 -0
- package/src/grammar/schemas/graphicBounds.js +179 -30
- package/src/grammar/schemas/semanticPath.js +23 -4
- package/src/grammar/stack.js +170 -0
- package/src/grammar/statisticalReference.js +103 -0
- package/src/grammar/statistics/confidenceInterval.js +101 -0
- package/src/grammar/strokeStyle.js +77 -0
- package/src/grammar/summary.js +245 -0
- package/src/grammar/text.js +22 -16
- package/src/grammar/timeUnit.js +234 -13
- package/src/grammar/transformTopology.js +10 -0
- package/src/grammar/transforms.js +418 -16
- package/src/grammar/valueFormat.js +112 -0
- package/src/grammar/weightedStatistics.js +374 -0
- package/src/grammar/window.js +232 -21
- package/src/layout/aspect.js +80 -0
- package/src/layout/facets.js +100 -12
- package/src/layout/guideCollisions.js +12 -0
- package/src/layout/labels.js +343 -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 +56 -147
- package/src/materialization/bars/histogram.js +104 -20
- package/src/materialization/bars/ranged.js +19 -3
- package/src/materialization/bars/resolve.js +7 -4
- package/src/materialization/categorySlotOffset.js +40 -0
- package/src/materialization/composition.js +3 -1
- package/src/materialization/compositionSnapshot.js +1 -1
- package/src/materialization/coordinateBounds.js +204 -0
- package/src/materialization/dependencies.js +93 -16
- package/src/materialization/encodings.js +1 -1
- package/src/materialization/facetGuides/legacyCategorical.js +3 -0
- package/src/materialization/facetGuides/placement.js +8 -2
- package/src/materialization/facetGuides/preparation.js +12 -7
- package/src/materialization/facetHeaders.js +346 -0
- package/src/materialization/facets.js +23 -66
- package/src/materialization/guides/layout.js +57 -0
- package/src/materialization/guides/resources.js +28 -2
- package/src/materialization/legends.js +11 -2
- package/src/materialization/marks/capabilities.js +20 -5
- package/src/materialization/marks/grouping.js +52 -0
- package/src/materialization/marks/index.js +68 -27
- package/src/materialization/marks/policies.js +4 -1
- package/src/materialization/rect.js +55 -42
- package/src/materialization/rectConfig.js +5 -1
- package/src/materialization/rowEncoding.js +13 -13
- package/src/materialization/scaleGuideDependencies.js +8 -5
- package/src/materialization/scales/map.js +6 -3
- package/src/materialization/scales/policies/arc.js +42 -0
- package/src/materialization/scales/policies/binnedPosition.js +7 -4
- package/src/materialization/scales/policies/offset.js +50 -8
- package/src/materialization/scales/policies/series.js +5 -1
- package/src/materialization/scales/resolve.js +65 -17
- package/src/materialization/selection/compatibility.js +11 -0
- package/src/materialization/selection/items/arc.js +28 -4
- package/src/materialization/selection/items/bar.js +42 -71
- package/src/materialization/selection/items/common.js +27 -6
- package/src/materialization/selection/items/path.js +3 -13
- package/src/materialization/selection/items/rect.js +35 -8
- package/src/materialization/selection/path.js +1 -1
- package/src/materialization/selection/point.js +3 -1
- package/src/materialization/text.js +324 -14
- package/src/mcp/adapter.js +2 -2
- package/src/renderers/canvas/circle.js +2 -3
- package/src/renderers/canvas/line.js +2 -3
- package/src/renderers/canvas/native.js +4 -4
- package/src/renderers/canvas/path.js +2 -3
- package/src/renderers/canvas/rect.js +2 -3
- package/src/renderers/canvas/stroke.js +11 -0
- package/src/renderers/svg.js +19 -0
- package/src/selectors/datasets.js +44 -0
- package/src/selectors/layers.js +7 -2
- package/src/selectors/scales.js +6 -0
- package/src/theme/defaults.js +140 -0
- package/types/basic.d.ts +17 -2
- package/types/index.d.ts +211 -0
- package/types/program.d.ts +2182 -204
- package/src/materialization/bars/grouped.js +0 -144
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
import {
|
|
2
|
+
action,
|
|
3
|
+
invokeWrappedActionImplementation
|
|
4
|
+
} from "../../core/action.js";
|
|
5
|
+
import { isPlainObject } from "../../core/immutable.js";
|
|
6
|
+
import { validateUserId } from "../../core/identifiers.js";
|
|
7
|
+
import { validateOptionObject } from "../../core/validation.js";
|
|
8
|
+
import { findLayer } from "../../selectors/layers.js";
|
|
9
|
+
import { findSemanticScale } from "../../selectors/scales.js";
|
|
10
|
+
import { findScaleConsumers } from "../scales/consumers/index.js";
|
|
11
|
+
import { resolveScalePreview, validatePendingMeasuredScale } from
|
|
12
|
+
"../scales/preview.js";
|
|
13
|
+
import { isPendingMeasuredRadiusConsumer } from
|
|
14
|
+
"../../materialization/scales/policies/arc.js";
|
|
15
|
+
import {
|
|
16
|
+
getMarkRematerializationStep,
|
|
17
|
+
getScaleConsumerMarkSteps,
|
|
18
|
+
getSourceDependentMarkSteps
|
|
19
|
+
} from "../../materialization/marks/index.js";
|
|
20
|
+
import {
|
|
21
|
+
applyMaterializationPlan,
|
|
22
|
+
planScaleGuideRematerialization
|
|
23
|
+
} from "../../materialization/dependencies.js";
|
|
24
|
+
import { buildMaterializationPlan } from "../../materialization/planner.js";
|
|
25
|
+
import { hasMaterializedLegend } from "../../materialization/legends.js";
|
|
26
|
+
import { rebindPositionGuides } from "./shared.js";
|
|
27
|
+
import { withoutPreviewLayerEncodings } from
|
|
28
|
+
"../primitives/semanticAction.js";
|
|
29
|
+
|
|
30
|
+
export const ENCODING_CHANNEL_ORDER = Object.freeze([
|
|
31
|
+
"x", "y", "x2", "y2", "theta", "r", "xOffset", "yOffset",
|
|
32
|
+
"group", "pathOrder", "color", "stroke", "size", "shape",
|
|
33
|
+
"opacity", "strokeWidth", "strokeDash", "angle", "text"
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
const CHANNEL_METHODS = Object.freeze({
|
|
37
|
+
x: "encodeX",
|
|
38
|
+
y: "encodeY",
|
|
39
|
+
x2: "encodeX2",
|
|
40
|
+
y2: "encodeY2",
|
|
41
|
+
theta: "encodeTheta",
|
|
42
|
+
r: "encodeR",
|
|
43
|
+
xOffset: "encodeXOffset",
|
|
44
|
+
yOffset: "encodeYOffset",
|
|
45
|
+
group: "encodeGroup",
|
|
46
|
+
pathOrder: "encodePathOrder",
|
|
47
|
+
color: "encodeColor",
|
|
48
|
+
stroke: "encodeStroke",
|
|
49
|
+
size: "encodeSize",
|
|
50
|
+
shape: "encodeShape",
|
|
51
|
+
opacity: "encodeOpacity",
|
|
52
|
+
strokeWidth: "encodeStrokeWidth",
|
|
53
|
+
strokeDash: "encodeStrokeDash",
|
|
54
|
+
angle: "encodeAngle",
|
|
55
|
+
text: "encodeText"
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const FORBIDDEN_PAYLOAD_KEYS = Object.freeze(["target", "coordinate", "id"]);
|
|
59
|
+
|
|
60
|
+
const DEFERRED_MARK_OPERATIONS = Object.freeze([
|
|
61
|
+
"materializeEmptyMark",
|
|
62
|
+
"rematerializePointMark",
|
|
63
|
+
"rematerializeTickMark",
|
|
64
|
+
"rematerializeLineMark",
|
|
65
|
+
"rematerializeAreaMark",
|
|
66
|
+
"rematerializeArcMark",
|
|
67
|
+
"rematerializeBarMark",
|
|
68
|
+
"rematerializeRuleMark",
|
|
69
|
+
"rematerializeTextMark",
|
|
70
|
+
"rematerializeRectMark",
|
|
71
|
+
"rematerializeMarkHighlights",
|
|
72
|
+
"materializeLabelLayout"
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
const deferredClassByProgram = new WeakMap();
|
|
76
|
+
|
|
77
|
+
function sameSetting(left, right) {
|
|
78
|
+
if (Object.is(left, right)) return true;
|
|
79
|
+
if (Array.isArray(left) && Array.isArray(right)) {
|
|
80
|
+
return left.length === right.length && left.every(
|
|
81
|
+
(value, index) => sameSetting(value, right[index])
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
if (isPlainObject(left) && isPlainObject(right)) {
|
|
85
|
+
const leftKeys = Object.keys(left);
|
|
86
|
+
const rightKeys = Object.keys(right);
|
|
87
|
+
return leftKeys.length === rightKeys.length && leftKeys.every(
|
|
88
|
+
key => Object.hasOwn(right, key) && sameSetting(left[key], right[key])
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function assertCompatibleScaleRequests(requests) {
|
|
95
|
+
const patches = new Map();
|
|
96
|
+
for (const { channel, payload } of requests) {
|
|
97
|
+
if (!isPlainObject(payload.scale) || payload.scale.id === undefined) continue;
|
|
98
|
+
const id = payload.scale.id;
|
|
99
|
+
const previous = patches.get(id) ?? new Map();
|
|
100
|
+
for (const [property, value] of Object.entries(payload.scale)) {
|
|
101
|
+
if (property === "id" || value === undefined) continue;
|
|
102
|
+
const existing = previous.get(property);
|
|
103
|
+
if (existing !== undefined && !sameSetting(existing.value, value)) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
`encodeChannels scale "${id}" has conflicting explicit ${property} requests for ${existing.channel} and ${channel}.`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
if (existing === undefined) previous.set(property, { channel, value });
|
|
109
|
+
}
|
|
110
|
+
patches.set(id, previous);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function normalizeEncodeChannelsArgs(args) {
|
|
115
|
+
validateOptionObject(args, ["target", "channels"], "encodeChannels");
|
|
116
|
+
const target = validateUserId(args.target, "Mark id");
|
|
117
|
+
if (!isPlainObject(args.channels)) {
|
|
118
|
+
throw new TypeError("encodeChannels channels must be a plain object.");
|
|
119
|
+
}
|
|
120
|
+
const keys = Object.keys(args.channels);
|
|
121
|
+
if (keys.length === 0) {
|
|
122
|
+
throw new TypeError("encodeChannels channels must contain at least one channel.");
|
|
123
|
+
}
|
|
124
|
+
for (const key of keys) {
|
|
125
|
+
if (!Object.hasOwn(CHANNEL_METHODS, key)) {
|
|
126
|
+
throw new Error(`encodeChannels does not support channel "${key}".`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const requests = ENCODING_CHANNEL_ORDER
|
|
130
|
+
.filter(channel => Object.hasOwn(args.channels, channel))
|
|
131
|
+
.map(channel => {
|
|
132
|
+
const payload = args.channels[channel];
|
|
133
|
+
if (!isPlainObject(payload)) {
|
|
134
|
+
throw new TypeError(
|
|
135
|
+
`encodeChannels ${channel} payload must be a plain object.`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
for (const key of FORBIDDEN_PAYLOAD_KEYS) {
|
|
139
|
+
if (Object.hasOwn(payload, key)) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`encodeChannels ${channel} payload cannot specify ${key}.`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return Object.freeze({ channel, payload });
|
|
146
|
+
});
|
|
147
|
+
assertCompatibleScaleRequests(requests);
|
|
148
|
+
return Object.freeze({ target, requests: Object.freeze(requests) });
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function resolveScaleOnly(program, id) {
|
|
152
|
+
const semanticScale = findSemanticScale(program, id);
|
|
153
|
+
if (semanticScale === undefined) {
|
|
154
|
+
throw new Error(`Unknown scale "${id}".`);
|
|
155
|
+
}
|
|
156
|
+
const consumers = findScaleConsumers(program, id);
|
|
157
|
+
if (
|
|
158
|
+
semanticScale.radialMapping !== undefined &&
|
|
159
|
+
consumers.length > 0 &&
|
|
160
|
+
consumers.every(isPendingMeasuredRadiusConsumer)
|
|
161
|
+
) {
|
|
162
|
+
validatePendingMeasuredScale(program, semanticScale, consumers);
|
|
163
|
+
return program._withoutResolvedScale(id);
|
|
164
|
+
}
|
|
165
|
+
return program._withResolvedScale(
|
|
166
|
+
id,
|
|
167
|
+
resolveScalePreview(program, id).resolvedScale
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function deferredProgramClass(ProgramClass) {
|
|
172
|
+
const existing = deferredClassByProgram.get(ProgramClass);
|
|
173
|
+
if (existing !== undefined) return existing;
|
|
174
|
+
|
|
175
|
+
class DeferredEncodingProgram extends ProgramClass {
|
|
176
|
+
rematerializeScale({ id } = {}) {
|
|
177
|
+
return resolveScaleOnly(this, id);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
rematerializeLegend() {
|
|
181
|
+
return this;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
for (const operation of DEFERRED_MARK_OPERATIONS) {
|
|
185
|
+
Object.defineProperty(DeferredEncodingProgram.prototype, operation, {
|
|
186
|
+
configurable: true,
|
|
187
|
+
value() {
|
|
188
|
+
return this;
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
deferredClassByProgram.set(ProgramClass, DeferredEncodingProgram);
|
|
193
|
+
return DeferredEncodingProgram;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function programState(program) {
|
|
197
|
+
return Object.freeze({
|
|
198
|
+
semanticSpec: program.semanticSpec,
|
|
199
|
+
graphicSpec: program.graphicSpec,
|
|
200
|
+
resolvedScales: program.resolvedScales,
|
|
201
|
+
materializationConfigs: program.materializationConfigs,
|
|
202
|
+
children: program.children,
|
|
203
|
+
compositionSpec: program.compositionSpec,
|
|
204
|
+
context: program.context,
|
|
205
|
+
trace: program.trace,
|
|
206
|
+
actionStack: program.actionStack,
|
|
207
|
+
actionSequence: program._actionSequence
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function instantiateProgram(state, ProgramClass) {
|
|
212
|
+
return new ProgramClass({
|
|
213
|
+
semanticSpec: state.semanticSpec,
|
|
214
|
+
graphicSpec: state.graphicSpec,
|
|
215
|
+
resolvedScales: state.resolvedScales,
|
|
216
|
+
materializationConfigs: state.materializationConfigs,
|
|
217
|
+
children: state.children,
|
|
218
|
+
compositionSpec: state.compositionSpec,
|
|
219
|
+
context: state.context,
|
|
220
|
+
trace: state.trace,
|
|
221
|
+
actionStack: state.actionStack,
|
|
222
|
+
actionSequence: state.actionSequence
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function createDeferredProgram(program) {
|
|
227
|
+
return instantiateProgram(
|
|
228
|
+
programState(program),
|
|
229
|
+
deferredProgramClass(program.constructor)
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function requestedFieldType(request) {
|
|
234
|
+
if (request === undefined) return undefined;
|
|
235
|
+
return request.payload.fieldType ?? "quantitative";
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function isCategoricalBarType(fieldType) {
|
|
239
|
+
return ["nominal", "ordinal", "temporal"].includes(fieldType);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function stageFinalPositionRoles(program, target, requests) {
|
|
243
|
+
const layer = findLayer(program, target);
|
|
244
|
+
if (layer?.mark?.type !== "bar") return program;
|
|
245
|
+
const byChannel = new Map(requests.map(request => [request.channel, request]));
|
|
246
|
+
const nextX = requestedFieldType(byChannel.get("x"));
|
|
247
|
+
const nextY = requestedFieldType(byChannel.get("y"));
|
|
248
|
+
if (nextX === undefined || nextY === undefined) return program;
|
|
249
|
+
const currentX = layer.encoding?.x?.fieldType;
|
|
250
|
+
const currentY = layer.encoding?.y?.fieldType;
|
|
251
|
+
const changesOrientation =
|
|
252
|
+
isCategoricalBarType(currentX) !== isCategoricalBarType(nextX) &&
|
|
253
|
+
isCategoricalBarType(currentY) !== isCategoricalBarType(nextY);
|
|
254
|
+
if (!changesOrientation) return program;
|
|
255
|
+
|
|
256
|
+
return withoutPreviewLayerEncodings(program, {
|
|
257
|
+
id: target,
|
|
258
|
+
channels: ["x", "y"]
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const INTERNAL_SCALE_CHANNEL = Object.freeze({ r: "radius" });
|
|
263
|
+
|
|
264
|
+
function requestedScaleIds(originalLayer, finalLayer, requests) {
|
|
265
|
+
const requestedChannels = new Set(requests.map(({ channel }) =>
|
|
266
|
+
INTERNAL_SCALE_CHANNEL[channel] ?? channel
|
|
267
|
+
));
|
|
268
|
+
const ids = [];
|
|
269
|
+
for (const channel of [
|
|
270
|
+
"x", "y", "x2", "y2", "theta", "radius", "xOffset", "yOffset",
|
|
271
|
+
"color", "stroke", "size", "shape", "opacity", "strokeWidth",
|
|
272
|
+
"strokeDash", "angle", "text", "group", "pathOrder"
|
|
273
|
+
]) {
|
|
274
|
+
if (!requestedChannels.has(channel)) continue;
|
|
275
|
+
for (const layer of [originalLayer, finalLayer]) {
|
|
276
|
+
const id = layer?.encoding?.[channel]?.scale;
|
|
277
|
+
if (id !== undefined && !ids.includes(id)) ids.push(id);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return ids;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function changedScaleIds(before, after) {
|
|
284
|
+
const beforeById = new Map(before.semanticSpec.scales.map(scale => [scale.id, scale]));
|
|
285
|
+
return after.semanticSpec.scales
|
|
286
|
+
.filter(scale => !sameSetting(scale, beforeById.get(scale.id)))
|
|
287
|
+
.map(scale => scale.id)
|
|
288
|
+
.sort();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function finalScaleIds(before, after, originalLayer, finalLayer, requests) {
|
|
292
|
+
const ids = [
|
|
293
|
+
...requestedScaleIds(originalLayer, finalLayer, requests),
|
|
294
|
+
...changedScaleIds(before, after)
|
|
295
|
+
];
|
|
296
|
+
return [...new Set(ids)].filter(id =>
|
|
297
|
+
findSemanticScale(after, id) !== undefined &&
|
|
298
|
+
findScaleConsumers(after, id).length > 0
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const rematerializeEncodingScales = action(
|
|
303
|
+
{
|
|
304
|
+
op: "rematerializeEncodingScales",
|
|
305
|
+
description: "Resolve every scale affected by one atomic encoding assignment."
|
|
306
|
+
},
|
|
307
|
+
function ({ ids } = {}) {
|
|
308
|
+
let next = this;
|
|
309
|
+
for (const id of ids) next = resolveScaleOnly(next, id);
|
|
310
|
+
return next;
|
|
311
|
+
}
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
function finalMaterializationPlan(program, target, scaleIds) {
|
|
315
|
+
const layer = findLayer(program, target);
|
|
316
|
+
const targetStep = layer === undefined
|
|
317
|
+
? undefined
|
|
318
|
+
: getMarkRematerializationStep(program, layer);
|
|
319
|
+
const directMarks = [
|
|
320
|
+
...(targetStep === undefined ? [] : [targetStep]),
|
|
321
|
+
...getScaleConsumerMarkSteps(program, scaleIds)
|
|
322
|
+
];
|
|
323
|
+
const marks = [
|
|
324
|
+
...directMarks,
|
|
325
|
+
...directMarks.flatMap(step =>
|
|
326
|
+
getSourceDependentMarkSteps(program, step.args.id)
|
|
327
|
+
)
|
|
328
|
+
];
|
|
329
|
+
const guides = scaleIds.flatMap(id =>
|
|
330
|
+
planScaleGuideRematerialization(program, id)
|
|
331
|
+
);
|
|
332
|
+
if (hasMaterializedLegend(program)) {
|
|
333
|
+
guides.push({ op: "rematerializeLegend" });
|
|
334
|
+
}
|
|
335
|
+
return buildMaterializationPlan({ marks, guides });
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function applyEncodingDraft(program, target, requests) {
|
|
339
|
+
let draft = stageFinalPositionRoles(
|
|
340
|
+
createDeferredProgram(program),
|
|
341
|
+
target,
|
|
342
|
+
requests
|
|
343
|
+
);
|
|
344
|
+
for (const { channel, payload } of requests) {
|
|
345
|
+
const focusedAction = draft[CHANNEL_METHODS[channel]];
|
|
346
|
+
draft = invokeWrappedActionImplementation(
|
|
347
|
+
focusedAction,
|
|
348
|
+
draft,
|
|
349
|
+
{ ...payload, target }
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
const originalLayer = findLayer(program, target);
|
|
353
|
+
const finalLayer = findLayer(draft, target);
|
|
354
|
+
for (const channel of ["x", "y"]) {
|
|
355
|
+
const previousScale = originalLayer?.encoding?.[channel]?.scale;
|
|
356
|
+
const nextScale = finalLayer?.encoding?.[channel]?.scale;
|
|
357
|
+
if (previousScale !== undefined && nextScale !== undefined) {
|
|
358
|
+
draft = rebindPositionGuides(
|
|
359
|
+
draft,
|
|
360
|
+
channel,
|
|
361
|
+
previousScale,
|
|
362
|
+
nextScale,
|
|
363
|
+
target
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return draft;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function planEncodingAssignments(program, target, requests) {
|
|
371
|
+
const originalLayer = findLayer(program, target);
|
|
372
|
+
const draft = applyEncodingDraft(program, target, requests);
|
|
373
|
+
const finalLayer = findLayer(draft, target);
|
|
374
|
+
return Object.freeze({
|
|
375
|
+
target,
|
|
376
|
+
originalLayer,
|
|
377
|
+
finalLayer,
|
|
378
|
+
state: programState(draft),
|
|
379
|
+
scaleIds: Object.freeze(finalScaleIds(
|
|
380
|
+
program,
|
|
381
|
+
draft,
|
|
382
|
+
originalLayer,
|
|
383
|
+
finalLayer,
|
|
384
|
+
requests
|
|
385
|
+
))
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function applyEncodingAssignments(program, plan) {
|
|
390
|
+
return instantiateProgram(plan.state, program.constructor);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export const encodeChannels = action(
|
|
394
|
+
{
|
|
395
|
+
op: "encodeChannels",
|
|
396
|
+
description: "Atomically assign multiple encoding channels to one mark."
|
|
397
|
+
},
|
|
398
|
+
function (args = {}) {
|
|
399
|
+
const { target, requests } = normalizeEncodeChannelsArgs(args);
|
|
400
|
+
const plan = planEncodingAssignments(this, target, requests);
|
|
401
|
+
let next = applyEncodingAssignments(this, plan);
|
|
402
|
+
const scaleIds = plan.scaleIds;
|
|
403
|
+
if (scaleIds.length > 0) {
|
|
404
|
+
next = rematerializeEncodingScales.call(next, { ids: scaleIds });
|
|
405
|
+
}
|
|
406
|
+
return applyMaterializationPlan(
|
|
407
|
+
next,
|
|
408
|
+
finalMaterializationPlan(next, target, scaleIds)
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
export function registerAtomicEncodingAction(ProgramClass) {
|
|
414
|
+
ProgramClass.prototype.encodeChannels = encodeChannels;
|
|
415
|
+
}
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
readQuantitativeField,
|
|
3
3
|
readScaleField,
|
|
4
|
-
readTemporalField
|
|
4
|
+
readTemporalField,
|
|
5
|
+
resolveTemporalUnit
|
|
5
6
|
} from "../../../grammar/scales/index.js";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
resolveBarChannels,
|
|
9
|
-
resolveBarGrain
|
|
10
|
-
} from "../../../grammar/bars/policy.js";
|
|
11
|
-
import {
|
|
12
|
-
validateAggregate,
|
|
13
|
-
validateAggregateFieldType,
|
|
14
|
-
validateAggregateFieldValues
|
|
15
|
-
} from "../../../grammar/aggregate.js";
|
|
7
|
+
import { validateContinuousColorConsumer } from "../../../grammar/scales/colorConsumers.js";
|
|
8
|
+
import { validateAggregateFieldValues } from "../../../grammar/aggregate.js";
|
|
16
9
|
import {
|
|
17
10
|
resolveQuantitativeColorScaleDefinition
|
|
18
11
|
} from "../../scales/definitions.js";
|
|
@@ -20,7 +13,10 @@ import {
|
|
|
20
13
|
resolveReassignmentScaleOptions,
|
|
21
14
|
resolveTarget
|
|
22
15
|
} from "../shared.js";
|
|
23
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
applyDetachedScaleRematerialization,
|
|
18
|
+
applyMaterializationPlan
|
|
19
|
+
} from "../../../materialization/dependencies.js";
|
|
24
20
|
import {
|
|
25
21
|
planEncodingRematerialization
|
|
26
22
|
} from "../../../materialization/encodings.js";
|
|
@@ -29,6 +25,8 @@ import {
|
|
|
29
25
|
resolveColorScaleOptions
|
|
30
26
|
} from "./policy.js";
|
|
31
27
|
|
|
28
|
+
import { applyTemporalUnit } from "../temporal.js";
|
|
29
|
+
|
|
32
30
|
export function encodeContinuousColor(program, args) {
|
|
33
31
|
if (!["quantitative", "temporal"].includes(args.fieldType)) {
|
|
34
32
|
throw new Error(`Unsupported color field type "${args.fieldType}".`);
|
|
@@ -43,6 +41,7 @@ export function encodeContinuousColor(program, args) {
|
|
|
43
41
|
"continuous color mark"
|
|
44
42
|
);
|
|
45
43
|
assertNoConstantColor(program, layer);
|
|
44
|
+
const temporalUnit = resolveTemporalUnit(args, args.fieldType, layer.encoding?.color);
|
|
46
45
|
const requestedScale = resolveReassignmentScaleOptions(
|
|
47
46
|
layer.encoding?.color,
|
|
48
47
|
resolveColorScaleOptions(args)
|
|
@@ -52,61 +51,22 @@ export function encodeContinuousColor(program, args) {
|
|
|
52
51
|
args.fieldType,
|
|
53
52
|
requestedScale
|
|
54
53
|
);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"Continuous color scale unknown currently requires a row-owned point mark."
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
if (
|
|
61
|
-
layer.mark.type === "bar" &&
|
|
62
|
-
["nominal", "ordinal"].includes(layer.encoding?.color?.fieldType)
|
|
63
|
-
) {
|
|
64
|
-
throw new Error(
|
|
65
|
-
"Continuous bar color cannot replace an existing nominal color layout."
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
let aggregate;
|
|
69
|
-
if (["point", "rect"].includes(layer.mark.type)) {
|
|
70
|
-
if (args.aggregate !== undefined) {
|
|
71
|
-
throw new Error(`${layer.mark.type} continuous color does not support aggregate.`);
|
|
72
|
-
}
|
|
73
|
-
} else {
|
|
74
|
-
if (args.fieldType !== "quantitative") {
|
|
75
|
-
throw new Error("Aggregate bar color currently requires a quantitative field.");
|
|
76
|
-
}
|
|
77
|
-
if (resolveBarGrain(layer) !== BAR_GRAINS.aggregate) {
|
|
78
|
-
throw new Error(
|
|
79
|
-
"Continuous bar color requires a complete categorical aggregate bar."
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
const channels = resolveBarChannels(layer);
|
|
83
|
-
const measure = layer.encoding?.[channels.measure];
|
|
84
|
-
aggregate = args.aggregate ?? (
|
|
85
|
-
measure?.field === args.field ? measure.aggregate : undefined
|
|
86
|
-
);
|
|
87
|
-
if (aggregate === undefined) {
|
|
88
|
-
throw new Error(
|
|
89
|
-
"Continuous bar color requires aggregate when its field differs from the measure field."
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
aggregate = validateAggregate(aggregate);
|
|
93
|
-
validateAggregateFieldType(aggregate, args.fieldType);
|
|
94
|
-
validateAggregateFieldValues(dataset.values, args.field, args.fieldType);
|
|
95
|
-
}
|
|
54
|
+
const aggregate = validateContinuousColorConsumer(layer, args, scale, { inferAggregate: true });
|
|
55
|
+
if (aggregate !== undefined) validateAggregateFieldValues(dataset.values, args.field, args.fieldType);
|
|
96
56
|
if (layer.mark.type === "rect") {
|
|
97
57
|
readScaleField(dataset.values, args.field, args.fieldType, {
|
|
98
|
-
allowUnknown: true
|
|
58
|
+
allowUnknown: true, temporalUnit
|
|
99
59
|
});
|
|
100
60
|
} else if (Object.hasOwn(scale, "unknown")) {
|
|
101
61
|
readScaleField(dataset.values, args.field, args.fieldType, {
|
|
102
|
-
allowUnknown: true
|
|
62
|
+
allowUnknown: true, temporalUnit
|
|
103
63
|
});
|
|
104
64
|
} else if (args.fieldType === "temporal") {
|
|
105
|
-
readTemporalField(dataset.values, args.field);
|
|
65
|
+
readTemporalField(dataset.values, args.field, temporalUnit);
|
|
106
66
|
} else {
|
|
107
67
|
readQuantitativeField(dataset.values, args.field);
|
|
108
68
|
}
|
|
109
|
-
const next = program
|
|
69
|
+
const next = applyTemporalUnit(program, target, "color", temporalUnit, layer.encoding?.color)
|
|
110
70
|
.editSemantic({
|
|
111
71
|
property: `layer[${target}].encoding.color.field`,
|
|
112
72
|
value: args.field
|
|
@@ -126,12 +86,12 @@ export function encodeContinuousColor(program, args) {
|
|
|
126
86
|
value: aggregate
|
|
127
87
|
});
|
|
128
88
|
const scaled = encoded.setQuantitativeColorScale(scale);
|
|
129
|
-
return applyMaterializationPlan(
|
|
89
|
+
return applyDetachedScaleRematerialization(applyMaterializationPlan(
|
|
130
90
|
scaled,
|
|
131
91
|
planEncodingRematerialization(scaled, {
|
|
132
92
|
target,
|
|
133
93
|
channel: "color",
|
|
134
94
|
scale: scale.id
|
|
135
95
|
})
|
|
136
|
-
);
|
|
96
|
+
), [layer]);
|
|
137
97
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { inferSeriesGroup } from "../shared.js";
|
|
1
2
|
import { action } from "../../../core/action.js";
|
|
2
3
|
import {
|
|
3
4
|
readNominalField,
|
|
4
5
|
readScaleField,
|
|
6
|
+
resolveTemporalUnit,
|
|
5
7
|
validateCategoricalFieldType
|
|
6
8
|
} from "../../../grammar/scales/index.js";
|
|
7
9
|
import {
|
|
@@ -12,19 +14,21 @@ import {
|
|
|
12
14
|
applyEncodingScale,
|
|
13
15
|
resolveReassignmentScaleOptions,
|
|
14
16
|
resolveTarget,
|
|
15
|
-
validateLineSeriesCompatibility,
|
|
16
17
|
validateOptions
|
|
17
18
|
} from "../shared.js";
|
|
18
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
applyDetachedScaleRematerialization,
|
|
21
|
+
applyMaterializationPlan
|
|
22
|
+
} from "../../../materialization/dependencies.js";
|
|
19
23
|
import {
|
|
20
24
|
planEncodingRematerialization
|
|
21
25
|
} from "../../../materialization/encodings.js";
|
|
22
26
|
import { findUpstreamTransform } from
|
|
23
27
|
"../../../materialization/dataProvenance.js";
|
|
28
|
+
import { validatePathSeriesAppearance } from "../../../grammar/pathSeries.js";
|
|
24
29
|
import { encodeContinuousColor } from "./continuous.js";
|
|
25
30
|
import {
|
|
26
|
-
applyColorLayoutCompanion
|
|
27
|
-
preSynchronizeGroupedOffset
|
|
31
|
+
applyColorLayoutCompanion
|
|
28
32
|
} from "./layout.js";
|
|
29
33
|
import {
|
|
30
34
|
assertNoConstantColor,
|
|
@@ -33,6 +37,8 @@ import {
|
|
|
33
37
|
resolveColorScaleOptions
|
|
34
38
|
} from "./policy.js";
|
|
35
39
|
|
|
40
|
+
import { applyTemporalUnit } from "../temporal.js";
|
|
41
|
+
|
|
36
42
|
const encodeColor = action(
|
|
37
43
|
{
|
|
38
44
|
op: "encodeColor",
|
|
@@ -51,6 +57,7 @@ const encodeColor = action(
|
|
|
51
57
|
throw new Error("Categorical color does not support aggregate.");
|
|
52
58
|
}
|
|
53
59
|
const fieldType = validateCategoricalFieldType(requestedFieldType);
|
|
60
|
+
resolveTemporalUnit(args, fieldType);
|
|
54
61
|
const { id: target, dataset, layer } = resolveTarget(
|
|
55
62
|
this,
|
|
56
63
|
args.target,
|
|
@@ -78,10 +85,13 @@ const encodeColor = action(
|
|
|
78
85
|
}
|
|
79
86
|
const layout = resolveColorLayout(layer, args.layout, barGrain);
|
|
80
87
|
const createsCenterGroup = layer.mark.type === "area" &&
|
|
81
|
-
layout === "center" && layer.encoding?.group
|
|
88
|
+
layout === "center" && layer.encoding?.group === undefined;
|
|
89
|
+
const ordinaryGroup = layer.mark.type === "area" && !createsCenterGroup &&
|
|
90
|
+
densityTransform === undefined && horizonTransform === undefined;
|
|
82
91
|
if (
|
|
83
92
|
layer.mark.type === "area" &&
|
|
84
93
|
!createsCenterGroup &&
|
|
94
|
+
!ordinaryGroup &&
|
|
85
95
|
(layer.encoding?.group?.field === undefined ||
|
|
86
96
|
layer.encoding.group.field !== args.field) &&
|
|
87
97
|
!densitySeriesFields.includes(args.field) &&
|
|
@@ -91,7 +101,11 @@ const encodeColor = action(
|
|
|
91
101
|
"Area color encoding must match an existing group encoding."
|
|
92
102
|
);
|
|
93
103
|
}
|
|
94
|
-
|
|
104
|
+
if (layer.mark.type === "line" || ordinaryGroup) {
|
|
105
|
+
validatePathSeriesAppearance(dataset.values, {
|
|
106
|
+
...layer, encoding: { ...layer.encoding, color: { field: args.field, fieldType } }
|
|
107
|
+
});
|
|
108
|
+
}
|
|
95
109
|
const requestedScale = resolveReassignmentScaleOptions(
|
|
96
110
|
layer.encoding?.color,
|
|
97
111
|
resolveColorScaleOptions(args)
|
|
@@ -114,10 +128,10 @@ const encodeColor = action(
|
|
|
114
128
|
readNominalField(dataset.values, args.field);
|
|
115
129
|
}
|
|
116
130
|
|
|
117
|
-
let next = createsCenterGroup
|
|
118
|
-
? this
|
|
131
|
+
let next = layer.mark.type === "bar" || createsCenterGroup
|
|
132
|
+
? inferSeriesGroup(this, layer, args.field, "color")
|
|
119
133
|
: this;
|
|
120
|
-
next = next.editSemantic({
|
|
134
|
+
next = applyTemporalUnit(next, target, "color", undefined, layer.encoding?.color).editSemantic({
|
|
121
135
|
property: `layer[${target}].encoding.color.field`,
|
|
122
136
|
value: args.field
|
|
123
137
|
})
|
|
@@ -129,40 +143,33 @@ const encodeColor = action(
|
|
|
129
143
|
property: `layer[${target}].encoding.color.scale`,
|
|
130
144
|
value: scale.id
|
|
131
145
|
});
|
|
132
|
-
if (layout !== undefined) {
|
|
146
|
+
if (layout !== undefined && (layer.mark.type === "arc" || horizonTransform !== undefined)) {
|
|
133
147
|
next = next.editSemantic({
|
|
134
148
|
property: `layer[${target}].encoding.color.layout`,
|
|
135
149
|
value: layout
|
|
136
150
|
});
|
|
137
151
|
}
|
|
138
|
-
next = preSynchronizeGroupedOffset(next, {
|
|
139
|
-
target,
|
|
140
|
-
layer,
|
|
141
|
-
layout,
|
|
142
|
-
field: args.field,
|
|
143
|
-
fieldType,
|
|
144
|
-
scale,
|
|
145
|
-
requestedScale
|
|
146
|
-
});
|
|
147
152
|
next = applyEncodingScale(next, scale, requestedScale, {
|
|
148
|
-
reassignment: layer.encoding?.color?.scale === scale.id
|
|
153
|
+
reassignment: layer.encoding?.color?.scale === scale.id,
|
|
154
|
+
allowTypeChange: true
|
|
149
155
|
});
|
|
150
156
|
next = applyColorLayoutCompanion(next, {
|
|
151
157
|
target,
|
|
152
158
|
layer,
|
|
153
159
|
layout,
|
|
154
160
|
scale,
|
|
155
|
-
field: args.field
|
|
161
|
+
field: args.field,
|
|
162
|
+
horizon: horizonTransform !== undefined
|
|
156
163
|
});
|
|
157
164
|
|
|
158
|
-
return applyMaterializationPlan(
|
|
165
|
+
return applyDetachedScaleRematerialization(applyMaterializationPlan(
|
|
159
166
|
next,
|
|
160
167
|
planEncodingRematerialization(next, {
|
|
161
168
|
target,
|
|
162
169
|
channel: "color",
|
|
163
170
|
scale: scale.id
|
|
164
171
|
})
|
|
165
|
-
);
|
|
172
|
+
), [layer]);
|
|
166
173
|
}
|
|
167
174
|
);
|
|
168
175
|
|