ggaction 0.0.23 → 0.0.26
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 +65 -0
- package/README.md +2 -2
- 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 +1 -1
- package/src/accessibility.js +13 -0
- package/src/actions/canvas/actions.js +2 -1
- package/src/actions/canvas/fitting.js +68 -13
- package/src/actions/charts/beeswarm.js +2 -1
- package/src/actions/charts/ecdf.js +2 -1
- package/src/actions/charts/endpoints.js +25 -16
- package/src/actions/charts/heatmap.js +6 -4
- package/src/actions/charts/missing.js +17 -0
- package/src/actions/charts/radar.js +70 -33
- package/src/actions/charts/raincloud.js +18 -4
- package/src/actions/charts/rug-strip.js +2 -2
- package/src/actions/charts/shared.js +17 -0
- package/src/actions/composition/actions.js +24 -7
- package/src/actions/composition/adjacent.js +90 -0
- package/src/actions/composition/index.js +11 -1
- package/src/actions/composition/layer.js +42 -0
- package/src/actions/composition/layerPlan.js +176 -0
- package/src/actions/composition/targets.js +105 -0
- package/src/actions/data/basicBin2d.js +1 -1
- package/src/actions/data/bin2d.js +2 -2
- package/src/actions/data/derived.js +3 -0
- package/src/actions/data/filter.js +1 -1
- package/src/actions/data/raincloudFilter.js +3 -1
- package/src/actions/encodings/appearance.js +26 -7
- package/src/actions/encodings/channels.js +1 -0
- package/src/actions/encodings/color/continuous.js +37 -34
- package/src/actions/encodings/color/index.js +57 -43
- package/src/actions/encodings/color/policy.js +15 -0
- package/src/actions/encodings/density/resolve.js +3 -2
- package/src/actions/encodings/density.js +2 -2
- package/src/actions/encodings/offset.js +2 -0
- package/src/actions/encodings/pathOrder.js +2 -0
- package/src/actions/encodings/position/areaAlignment.js +42 -0
- package/src/actions/encodings/position/index.js +37 -3
- package/src/actions/encodings/position/policies/line.js +1 -1
- package/src/actions/encodings/ranged.js +4 -2
- package/src/actions/encodings/remove.js +13 -10
- package/src/actions/encodings/ruleAppearance.js +14 -2
- package/src/actions/facets/actions.js +1 -1
- package/src/actions/guides/axes/axes.js +2 -1
- package/src/actions/guides/axes/components.js +5 -0
- package/src/actions/guides/axes/edit.js +1 -188
- package/src/actions/guides/axes/labels.js +2 -537
- package/src/actions/guides/axes/parallel/lifecycle.js +11 -4
- package/src/actions/guides/axes/parallel/policy.js +5 -2
- package/src/actions/guides/axes/parallel/resolve.js +3 -1
- package/src/actions/guides/axes/parallel.js +9 -4
- package/src/actions/guides/axes/tickGroups.js +16 -1
- package/src/actions/guides/axes/ticks.js +33 -24
- package/src/actions/guides/axes/titles.js +1 -389
- package/src/actions/guides/facadeLegend.js +3 -2
- package/src/actions/guides/grids/grid.js +3 -2
- package/src/actions/guides/grids/resolve.js +2 -1
- package/src/actions/guides/guides.js +3 -2
- package/src/actions/guides/legends/automatic.js +28 -0
- package/src/actions/guides/legends/blocks.js +15 -21
- package/src/actions/guides/legends/categorical/actions.js +1 -1
- package/src/actions/guides/legends/categorical/components.js +4 -3
- package/src/actions/guides/legends/categorical/layout.js +5 -2
- package/src/actions/guides/legends/categorical/options.js +9 -14
- package/src/actions/guides/legends/categorical/recipes.js +3 -0
- package/src/actions/guides/legends/categorical/resolve.js +7 -5
- package/src/actions/guides/legends/colorSize.js +51 -14
- package/src/actions/guides/legends/continuous/common.js +1 -1
- package/src/actions/guides/legends/continuous/gradient.js +1 -1
- package/src/actions/guides/legends/continuous/opacity.js +2 -0
- package/src/actions/guides/legends/edit.js +1 -1
- package/src/actions/guides/legends/focused.js +2 -2
- package/src/actions/guides/legends/group.js +1 -1
- package/src/actions/guides/legends/lane.js +1 -1
- package/src/actions/guides/legends/lifecycle.js +2 -2
- package/src/actions/guides/legends/remove.js +18 -4
- package/src/actions/guides/legends/size.js +1 -1
- package/src/actions/guides/legends/transition.js +15 -6
- package/src/actions/guides/polar/axes/facade.js +4 -2
- package/src/actions/guides/polar/axes/labels.js +6 -1
- package/src/actions/guides/polar/axes/shared.js +4 -4
- package/src/actions/guides/polar/axes/titles.js +13 -2
- package/src/actions/guides/polar/grids.js +6 -3
- package/src/actions/guides/tickValues.js +7 -1
- package/src/actions/index.js +2 -0
- package/src/actions/marks/area/actions.js +9 -2
- package/src/actions/marks/area/materialize.js +1 -1
- package/src/actions/marks/bar/materialize.js +4 -4
- package/src/actions/marks/lifecycle.js +14 -0
- package/src/actions/marks/line/actions.js +3 -0
- package/src/actions/marks/line/materialize.js +4 -2
- package/src/actions/marks/point/edit.js +2 -0
- package/src/actions/marks/point/jitter.js +2 -0
- package/src/actions/marks/point/materialize.js +5 -4
- package/src/actions/marks/point/packing.js +2 -0
- package/src/actions/marks/references.js +5 -3
- package/src/actions/marks/remove.js +16 -0
- package/src/actions/marks/shared.js +2 -1
- package/src/actions/marks/text/actions.js +5 -2
- package/src/actions/overlays/index.js +168 -0
- package/src/actions/overlays/snapshot.js +45 -0
- package/src/actions/primitives/editGraphics.js +21 -27
- package/src/actions/primitives/semanticAction.js +4 -5
- package/src/actions/primitives/semanticValidation/guide.js +1 -0
- package/src/actions/primitives/semanticValidation/layer.js +7 -0
- package/src/actions/scales/consumers/common.js +10 -0
- package/src/actions/scales/consumers/families.js +1 -1
- package/src/actions/scales/preview.js +1 -1
- package/src/actions/selection/actions.js +63 -11
- package/src/actions/titles/actions.js +3 -14
- package/src/actions/titles/resolve.js +23 -10
- package/src/core/action.js +41 -25
- package/src/core/compositionScales.js +12 -0
- package/src/core/compositionState.js +20 -3
- package/src/core/facetGap.js +44 -0
- package/src/core/immutable.js +11 -6
- package/src/core/programState.js +16 -0
- package/src/core/resourceReferences.js +19 -3
- package/src/core/validation.js +7 -0
- package/src/core/vocabulary.js +8 -2
- package/src/grammar/actionTargets.js +24 -0
- package/src/grammar/axisTextPlacement.js +1 -1
- package/src/grammar/bin2d.js +41 -4
- package/src/grammar/colorSizeLegend.js +56 -5
- package/src/grammar/displayLabels.js +10 -0
- package/src/grammar/facetHeaders.js +1 -1
- package/src/grammar/facets/dependencies.js +10 -3
- package/src/grammar/facets/guides.js +2 -1
- package/src/grammar/facets/legendIntent.js +7 -5
- package/src/grammar/legendBlocks.js +1 -1
- package/src/grammar/legendCombinations.js +1 -1
- package/src/grammar/legendGroups.js +1 -1
- package/src/grammar/legendItemsOffset.js +12 -0
- package/src/grammar/legendOverflow.js +25 -0
- package/src/grammar/lineSeries.js +1 -1
- package/src/grammar/markSelection.js +23 -0
- package/src/grammar/overlay.js +51 -0
- package/src/grammar/parallelCoordinates.js +1 -208
- package/src/grammar/pathCommands.js +8 -2
- package/src/grammar/pathSeries.js +1 -1
- package/src/grammar/plotComposition.js +152 -0
- package/src/grammar/pointShapes.js +18 -0
- package/src/grammar/scales/transformed.js +1 -1
- package/src/grammar/schemas/concreteGraphic.js +8 -1
- package/src/grammar/schemas/graphicBounds.js +8 -1
- package/src/grammar/schemas/graphicTree.js +18 -2
- package/src/grammar/schemas/semanticPath.js +3 -0
- package/src/grammar/strokeStyle.js +14 -8
- package/src/grammar/text.js +72 -0
- package/src/inspection.js +1 -1
- package/src/inspectionDescriptors.js +1 -1
- package/src/layout/composition.js +32 -10
- package/src/layout/compositionLegend.js +91 -0
- package/src/layout/facetContentFlow.js +15 -7
- package/src/layout/facetHeaderTitles.js +1 -1
- package/src/layout/facets.js +1 -1
- package/src/layout/labels.js +55 -27
- package/src/layout/legend.js +3 -2
- package/src/layout/legendGroup.js +1 -1
- package/src/layout/legendItems.js +7 -6
- package/src/layout/legendLane.js +1 -1
- package/src/layout/legendText.js +1 -1
- package/src/layout/title.js +1 -1
- package/src/materialization/adjacentSource.js +27 -0
- package/src/materialization/composition.js +165 -52
- package/src/materialization/compositionLegends.js +120 -0
- package/src/materialization/compositionScales.js +125 -0
- package/src/materialization/compositionTitle.js +96 -0
- package/src/materialization/facetGuides/edit.js +22 -2
- package/src/materialization/facetGuides/layout.js +1 -1
- package/src/materialization/facetGuides/owner.js +4 -3
- package/src/materialization/facetGuides/ownerLayout.js +12 -6
- package/src/materialization/facetGuides/placement.js +19 -22
- package/src/materialization/facetGuides/preparation.js +17 -5
- package/src/materialization/facetHeaders.js +5 -1
- package/src/materialization/facets.js +1 -1
- package/src/materialization/guides/layout.js +1 -1
- package/src/materialization/guides/resources.js +1 -1
- package/src/materialization/guides/visibility.js +105 -0
- package/src/materialization/legendClip.js +1 -1
- package/src/materialization/legendGroups.js +1 -1
- package/src/materialization/legendItemsOffset.js +68 -0
- package/src/materialization/legendSuppression.js +22 -0
- package/src/materialization/legends.js +3 -2
- package/src/materialization/marks/capabilities.js +4 -0
- package/src/materialization/marks/index.js +5 -1
- package/src/materialization/marks/pathOrder.js +1 -1
- package/src/materialization/marks/policies.js +2 -1
- package/src/materialization/overlayItems.js +154 -0
- package/src/materialization/planner.js +19 -4
- package/src/materialization/scales/policies/binnedPosition.js +43 -5
- package/src/materialization/scales/policies/series.js +12 -4
- package/src/materialization/scales/resolve.js +2 -0
- package/src/materialization/selection/items/bar.js +21 -3
- package/src/materialization/selection/items/common.js +18 -5
- package/src/materialization/selection/items/overlay.js +15 -0
- package/src/materialization/selection/items/path.js +1 -0
- package/src/materialization/selection/items/point.js +2 -3
- package/src/materialization/selection/items/tick.js +3 -12
- package/src/materialization/selection/path.js +2 -2
- package/src/materialization/selection/policies/bar.js +2 -0
- package/src/materialization/selection/policies/index.js +35 -1
- package/src/materialization/selection/policies/point.js +2 -0
- package/src/materialization/selection/policies/text.js +17 -0
- package/src/materialization/selection/rows.js +103 -0
- package/src/materialization/selection/state.js +19 -3
- package/src/materialization/selection/styles.js +8 -0
- package/src/materialization/text.js +6 -489
- package/src/materialization/textGeometry.js +503 -0
- package/src/materialization/textLines.js +20 -0
- package/src/persistence/validation.js +116 -25
- package/src/renderers/canvas/index.js +12 -7
- package/src/renderers/canvas/text.js +5 -5
- package/src/renderers/nativeBackend.js +25 -0
- package/src/renderers/pdf.js +3 -3
- package/src/renderers/png.js +4 -3
- package/src/renderers/svgSerialization.js +1 -643
- package/src/scene.js +5 -3
- package/src/selectors/plotComposition.js +115 -0
- package/src/selectors/selectionTargets.js +19 -0
- package/src/version.js +1 -1
- package/types/basic.d.ts +4 -2
- package/types/index.d.ts +14 -0
- package/types/inspection.d.ts +34 -0
- package/types/program.d.ts +572 -372
|
@@ -1 +1 @@
|
|
|
1
|
-
import{normalizeFacetAxes as R,validateFacetAxisPolicy as x}from"../../core/facetAxisPolicy.js";import{DEFAULT_ACTION_METHODS as te}from"../../core/vocabulary.js";import{axisGraphicIds as ie}from"../../materialization/guides/resources.js";import{cartesianAxisOwners as ne,axisTargetArgs as ae}from"../../selectors/axes.js";import{resolveGraphicBounds as oe}from"../../layout/canvas.js";import{action as z,closedAction as T,getWrappedActionMetadata as ce}from"../../core/action.js";import{registerFacetDataRevision as se,reviseUnitData as re}from"../data/revise.js";import{applyMaterializationPlan as de}from"../../materialization/dependencies.js";import{getMarkMaterializationStep as le}from"../../materialization/marks/index.js";import{buildMaterializationPlan as fe}from"../../materialization/planner.js";import{freezeOwned as A,isPlainObject as S}from"../../core/immutable.js";import{validateUserId as P}from"../../core/identifiers.js";import{validateNonEmptyString as $,validateNonNegativeFinite as pe,validateOptionObject as w,validatePositiveFinite as ue}from"../../core/validation.js";import{resolveFacetDefinition as G,resolveFacetGridDefinition as I}from"../../grammar/facets/index.js";import{collectFacetScaleBindings as N,resolveFacetFamily as k}from"../../grammar/facets/dependencies.js";import{FACET_SCALE_CHANNELS as _,normalizeFacetScalePolicies as j}from"../../grammar/facets/scales.js";import{resolveFacetLayout as he}from"../../layout/facets.js";import{compositionChildDescriptor as me}from"../../materialization/composition.js";import{deriveFacetChildren as H}from"./derive.js";import{resolveFacetChildrenScales as ge}from"./derive.js";import{replayDerivedData as Se}from"./replay.js";import{composeFacetGuides as we}from"./guides.js";import{applyCompositionState as q}from"../composition/actions.js";import{replayCompositionThemeState as ye}from"../theme/composition.js";import{findDataset as Fe}from"../../selectors/datasets.js";import{findLayer as U}from"../../selectors/layers.js";import{findSemanticScale as be}from"../../selectors/scales.js";import{normalizeDisplayLabelMap as W}from"../../grammar/displayLabels.js";import{resolveRotation as ve}from"../../grammar/rotation.js";import{normalizeFacetHeaderTitle as Ce}from"../../grammar/facetHeaders.js";import{createDefaultFacetHeaders as Ee,normalizeFacetHeadersConfig as K,resolveFacetHeaderConfig as Oe}from"../../materialization/facetHeaders.js";const xe=Object.freeze(["id","field","data","values","columns","gap","spacing","topLane","align","padding","scales","guides","headers"]),ze=Object.freeze(["id","data","rows","columns","combinations","gap","spacing","topLane","align","padding","scales","guides","headers"]),Te=Object.freeze(["id","target","channel","fields","columns","gap","spacing","topLane","align","padding","scales","guides","headers"]),$e=new Set(te),ke=Object.freeze(["program","action"]),V=Object.freeze(["axes","legend"]),B=Object.freeze(["fontSize","fontFamily","fontWeight","color","offset","role","labelMap","side","align","rotation","title","anchor"]),Y=Object.freeze(["fontSize","fontFamily","fontWeight","color","offset","align","rotation","anchor"]);function b(t,e=!1){if(t===void 0)return{axes:"each",legend:!1};w(t,V,"facet.guides");const n=R(t.axes),i=t.legend??!1;if(i!==!1&&i!=="shared"&&!S(i))throw new Error('facet guides.legend must be false, "shared", or legend options.');if(!e&&S(i)&&Object.hasOwn(i,"type"))throw new Error("Facet legend options do not accept internal type tags.");return{axes:n,legend:i}}function v(t,e){if(t._assertCompositionProgram(e),t.compositionSpec.type!=="facet")throw new Error(`${e} requires a facet composition.`)}function C(t,e){const n=new Set(N(t.semanticSpec).map(i=>i.policyKey));return Object.fromEntries(_.flatMap(i=>n.has(i)&&e[i]!==void 0?[[i,e[i]]]:[]))}function E(t,e=!1){const n=t.compositionSpec.children.find(l=>t.children[l]?.semanticSpec.layers.length>0)??t.compositionSpec.children[0],i=t.children[n];if(i===void 0)throw new Error(`Facet "${t.compositionSpec.id}" requires a retained child.`);const{facets:c,guides:o,...d}=t.materializationConfigs,{legend:s,...r}=t.semanticSpec.guides,a={...i.materializationConfigs.guides,axis:o?.axis??i.guideConfigs.axis,grid:o?.grid??i.guideConfigs.grid};return e&&delete d.title,new t.constructor({semanticSpec:e?{...t.semanticSpec,title:{},guides:{...r,...i.semanticSpec.guides.legend===void 0?{}:{legend:i.semanticSpec.guides.legend}}}:t.semanticSpec,graphicSpec:i.graphicSpec,resolvedScales:t.resolvedScales,materializationConfigs:A({...d,...i.materializationConfigs.theme===void 0?{}:{theme:i.materializationConfigs.theme},...a===void 0?{}:{guides:a},canvas:i.materializationConfigs.canvas}),children:{},context:t.context,trace:t.trace,actionStack:t.actionStack,actionSequence:t._actionSequence})}function D(t,{scales:e,guides:n}){const i=t.compositionSpec;if(i.facet.repeat!==void 0){const f=E(t),u=Q(f,{id:i.id,...i.facet.repeat}),m=Z(f,u,C(f,e),!0);return q(t,{children:m.children,compositionSpec:{...i,facet:{...i.facet,scales:e,guides:n}}},i.children)}const c=i.facet.grid===void 0?G(t.semanticSpec,{id:i.id,data:i.facet.data,field:i.facet.field,values:i.facet.values}):I(t.semanticSpec,{id:i.id,data:i.facet.data,rows:i.facet.grid.rows,columns:i.facet.grid.columns,combinations:i.facet.grid.combinations}),o=C(t,e),d=j(t.semanticSpec,o),s=E(t),r=H(s,c,{closeInheritedAction:!0,stripTitle:!0,scales:o}),a={...i,facet:{...i.facet,scales:d.channels,guides:n}};let l=t._withoutMaterializationConfig(["guides","legend"]);for(const[f,u]of Object.entries(s.guideConfigs.legend??{}))l=l._withLegendConfig(f,u);return q(l,{children:r.children,compositionSpec:a},a.children)}function L(t,e,n,i="editFacetHeaders"){w(e,B,i,{allowEmpty:!1,emptyMessage:`${i} requires at least one change.`});const c=e.role??"all";if(!["all","row","column"].includes(c))throw new Error(`Unknown facet header role "${c}".`);if(c==="all"&&Object.hasOwn(e,"side"))throw new Error(`${i} side requires an explicit row or column role.`);if(c==="all"&&Object.hasOwn(e,"title"))throw new Error(`${i} title requires an explicit row or column role.`);if(c==="row"&&n===void 0)throw new Error(`${i} row role requires a row-column facet grid.`);if(Object.hasOwn(e,"side")){const a=c==="row"?["left","right"]:n===void 0?["top","bottom","left","right"]:["top","bottom"];if(!a.includes(e.side))throw new Error(`${i} ${c} side must be ${a.join(" or ")}.`)}if(Object.hasOwn(e,"align")&&!["start","center","end"].includes(e.align))throw new Error(`${i} align must be start, center, or end.`);if(c==="all"&&Object.keys(e).every(a=>a==="role"))throw new Error(`${i} requires at least one change.`);const o=K(t),d=c==="all"?"common":c,s={...o[d]};if(Object.hasOwn(e,"title")){const a=Ce(s.title,e.title);a===void 0?delete s.title:s.title=a}for(const a of Y)Object.hasOwn(e,a)&&(s[a]=e[a]);Object.hasOwn(e,"rotation")&&(s.rotation=ve(e.rotation,`${i} ${c} rotation`)),Object.hasOwn(e,"side")&&(s.side=e.side),Object.hasOwn(e,"labelMap")&&(e.labelMap==="auto"?delete s.labelMap:s.labelMap=W(e.labelMap,`${i} ${c} labelMap`));const r={...o,...c==="all"?{}:{mode:"roles"},[d]:s};for(const a of["all","row","column"]){const l=Oe(r,a);if(ue(l.fontSize,`Facet ${a} header fontSize`),$(l.fontFamily,`Facet ${a} header fontFamily`),$(l.color,`Facet ${a} header color`),pe(l.offset,`Facet ${a} header offset`),l.rotation!==void 0&&!Number.isFinite(l.rotation))throw new TypeError(`Facet ${a} header rotation must resolve to finite radians.`);if(!(typeof l.fontWeight=="string"&&l.fontWeight.length>0||Number.isFinite(l.fontWeight)))throw new TypeError(`Facet ${a} header fontWeight must be a non-empty string or number.`);if(!["start","center","end"].includes(l.align))throw new Error(`Facet ${a} header align must be start, center, or end.`);l.labelMap!==void 0&&W(l.labelMap,`Facet ${a} header labelMap`)}return r}function _e(t,e){let n=Ee();if(t===void 0)return n;w(t,[...Y,"labelMap","row","column"],"facet.headers");const{row:i,column:c,...o}=t;Object.keys(o).length>0&&(n=L(n,o,e,"facet.headers"));for(const[d,s]of[["row",i],["column",c]])s!==void 0&&(w(s,B.filter(r=>r!=="role"),`facet.headers.${d}`),n=L(n,{...s,role:d},e,`facet.headers.${d}`));return n}function X(t,e,{definition:n,derived:i,guides:c,scalePolicies:o,facet:d}){const s=t.materializationConfigs.facets?.[n.id]?.headers,r=e.headers===void 0&&s!==void 0?K(s):_e(e.headers,n.grid),a=he({spacing:e.spacing,topLane:e.topLane,plots:Object.entries(i.children).map(([f,u])=>({id:f,...oe(u)})),children:n.cells.map(f=>({...me(f.id,i.children[f.id]),value:f.value,...n.grid===void 0?{}:{row:f.row,column:f.column}})),columns:n.grid?.columns.values.length??e.columns,gap:e.gap,align:e.align,padding:e.padding,sharedLegend:c.legend==="shared"}),l={id:n.id,type:"facet",children:n.cells.map(f=>f.id),columns:a.columns,gap:a.gap,align:a.align,padding:a.padding,...a.spacing===void 0?{}:{spacing:a.spacing},...a.topLane===void 0?{}:{topLane:a.topLane},facet:{data:n.data,...d,scales:o.channels,guides:c}};return q(t._withMaterializationConfig(["facets",n.id],{headers:r}),{children:i.children,compositionSpec:l},l.children)}function J(t,e,n){return T({op:t,description:e},t==="facet"?xe:ze,function(i={}){const c=b(i.guides),o=n(this.semanticSpec,i);x(c.axes,o.family);const d=j(this.semanticSpec,i.scales??{}),s=H(this,o,{closeInheritedAction:!0,stripTitle:!0,scales:i.scales??{}}),r=o.grid===void 0?{field:o.field,values:o.values}:{values:o.cells.map(a=>a.value),grid:{...o.grid,cells:o.cells.map(a=>({id:a.id,row:a.row,column:a.column,rowValue:a.rowValue,columnValue:a.columnValue,empty:a.empty}))}};return X(this,i,{definition:o,derived:s,guides:c,scalePolicies:d,facet:r})})}const je=J("facet","Repeat one direct-source chart by field value.",G);function Q(t,e){if(!S(e))throw new TypeError("repeatCharts options must be a plain object.");const n=P(e.id??"repeat","Repeat id"),i=S(e.channel);if(i){const p=Object.keys(e.channel);if(p.length!==1||p[0]!=="parallelDimension"||typeof e.channel.parallelDimension!="string"||e.channel.parallelDimension.length===0)throw new Error("repeatCharts Parallel channel must contain exactly one non-empty parallelDimension.")}else if(!["x","y","theta","r"].includes(e.channel))throw new Error('repeatCharts channel must be "x", "y", "theta", "r", or one parallelDimension.');if(!Array.isArray(e.fields)||e.fields.length===0||e.fields.some(p=>typeof p!="string"||p.length===0))throw new TypeError("repeatCharts fields must be a non-empty array of field names.");if(new Set(e.fields).size!==e.fields.length)throw new Error("repeatCharts fields must be unique.");const c=k(t.semanticSpec).family,o=e.channel==="r"?"radius":e.channel,d=t.semanticSpec.layers.filter(p=>{if(i){const F=(p.encoding?.parallel?.dimensions??[]).filter(y=>y.field===e.channel.parallelDimension);return c==="parallel"&&p.mark?.type==="line"&&F.length===1}if(["x","y"].includes(e.channel))return c==="cartesian"&&p.encoding?.x?.scale!==void 0&&p.encoding?.y?.scale!==void 0&&p.encoding?.[e.channel]?.field!==void 0&&["point","line","area","bar","rule","tick","rect"].includes(p.mark?.type);const g=t.markConfigs[p.id]?.compositionRole;return c!=="polar"||["pie","radar"].includes(g)?!1:["point","line","arc"].includes(p.mark?.type)&&p.encoding?.[o]?.field!==void 0});let s;if(e.target!==void 0){if(s=P(e.target,"Repeat target"),!d.some(p=>p.id===s))throw new Error(`repeatCharts target "${s}" is not eligible for the requested field role.`)}else if(d.length===1)s=d[0].id;else throw new Error(d.length===0?"repeatCharts requires one eligible complete mark for the requested field role.":"repeatCharts target is ambiguous; provide target.");if(t.semanticSpec.layers.filter(p=>{if(p.id===s)return!1;const g=p.mark?.type==="text"&&p.source===s,F=t.markConfigs[p.id]?.statisticalReference?.source===s;return!g&&!F}).length>0)throw new Error("repeatCharts currently supports one direct mark only.");const a=t.markConfigs[s]??{},l=["boxPlot","gradientPlot","violinPlot","regressionPlot","endpointPlot","ecdfPlot","raincloudPlot","intervalPlot"].find(p=>a[p]!==void 0);if(l!==void 0)throw new Error(`repeatCharts does not replace the ${l} composite role.`);const f=U(t,s),u=Fe(t,f.data);if(u?.transform?.length>0&&u.transform[0].type!=="lookup")throw new Error("repeatCharts does not rewrite a derived dataset dependency.");const m=i?f.encoding.parallel:f.encoding[o],h=i?m.dimensions.findIndex(p=>p.field===e.channel.parallelDimension):void 0;return{id:n,target:s,channel:i?{...e.channel}:e.channel,policyKey:i?"parallelDimensions":e.channel,fields:[...e.fields],data:f.data,encoding:m,...h===void 0?{}:{dimensionIndex:h},cells:e.fields.map((p,g)=>({id:`${n}-field-${g+1}`,field:p,value:p}))}}function qe(t,e){const n=t.encoding;return{target:t.target,field:e,fieldType:n.fieldType,...n.temporalUnit===void 0?{}:{temporalUnit:n.temporalUnit},...n.aggregate===void 0?{}:{aggregate:n.aggregate},...n.bin===void 0?{}:{bin:n.bin},...n.stack===void 0?{}:{stack:n.stack},...n.weight===void 0?{}:{weight:n.weight},scale:{id:n.scale}}}function De(t,e,n){return e.encoding.dimensions.map((i,c)=>{const o=be(t,i.scale);if(o===void 0)throw new Error(`repeatCharts Parallel dimension scale "${i.scale}" is missing.`);const{id:d,...s}=o,r=c===e.dimensionIndex;return{field:r?n:i.field,fieldType:i.fieldType,title:r&&i.title===i.field?n:i.title,scale:s}})}function Le(t,e,n){if(S(e.channel))return t.encodeParallelCoordinates({target:e.target,coordinate:U(t,e.target).coordinate,dimensions:De(t,e,n),...e.encoding.key===void 0?{}:{key:e.encoding.key},missing:e.encoding.missing});const i={x:"encodeX",y:"encodeY",theta:"encodeTheta",r:"encodeR"}[e.channel];return t[i](qe(e,n))}function Z(t,e,n,i){const c=t.semanticSpec.title.text===void 0?t:t.removeTitle(),o=Object.fromEntries(e.cells.map(d=>[d.id,Le(c,e,d.field)]));return ge(c,e.cells.map(d=>d.id),o,n,i)}const Me=T({op:"repeatCharts",description:"Repeat one direct chart across an ordered field-role list."},Te,function(t={}){const e=b(t.guides),n=Q(this,t);x(e.axes,k(this.semanticSpec).family,!0);const i={...t.scales??{},[n.policyKey]:t.scales?.[n.policyKey]??"independent"},c=j(this.semanticSpec,i),o=Z(this,n,i,!0);return X(this,t,{definition:n,derived:o,guides:e,scalePolicies:c,facet:{values:n.fields,repeat:{target:n.target,channel:n.channel,fields:n.fields}}})}),Re=J("facetGrid","Repeat one direct-source Cartesian chart across a row and column field grid.",I),Ae=z({op:"editFacetHeaders",description:"Edit parent-owned facet header appearance.",scope:"composition"},function(t={}){v(this,"editFacetHeaders");const e=this.compositionSpec.id,n=this.materializationConfigs.facets?.[e];if(!S(n?.headers))throw new Error(`Facet "${e}" requires header configuration.`);const i=L(n.headers,t,this.compositionSpec.facet.grid);return this._withMaterializationConfig(["facets",e],{...n,headers:i}).materializeComposition()}),Pe=z({op:"editFacetScales",description:"Edit facet scale-resolution policies and rederive every cell.",scope:"composition"},function(t={}){v(this,"editFacetScales"),w(t,_,"editFacetScales",{allowEmpty:!1,emptyMessage:"editFacetScales requires at least one channel policy change."});for(const i of Object.keys(t))if(!N(this.semanticSpec).some(c=>c.policyKey===i))throw new Error(`Facet scale channel "${i}" is not used by an affected layer.`);const e=this.compositionSpec.facet,n={...e.scales,...t};if(_.every(i=>n[i]===e.scales[i]))throw new Error("editFacetScales requires at least one channel policy change.");return D(this,{scales:n,guides:e.guides})}),Ge=z({op:"editFacetGuides",description:"Edit facet guide ownership and rederive every cell.",scope:"composition"},function(t={}){v(this,"editFacetGuides"),w(t,V,"editFacetGuides",{allowEmpty:!1,emptyMessage:"editFacetGuides requires at least one guide policy."});const e=this.compositionSpec.facet;Object.hasOwn(t,"legend")&&b({legend:t.legend});const n=b({...e.guides,...t,...Object.hasOwn(t,"axes")?{axes:R(t.axes,e.guides.axes)}:{}},!0),i=k(this.semanticSpec).family;return x(n.axes,i,e.repeat!==void 0),D(this,{scales:e.scales,guides:n})});function Ie(t,e,n=!1){if(!(t instanceof e.constructor))throw new TypeError("editFacetSource program must be a ChartProgram.");if(t.compositionSpec!==void 0)throw new Error("editFacetSource program must be a complete unit ChartProgram.");if(t.actionStack.length!==0)throw new Error("editFacetSource program has an unfinished action stack.");const i=e.compositionSpec.children.find(a=>e.children[a]?.semanticSpec.layers.length>0)??e.compositionSpec.children[0],c=e.children[i]?.materializationConfigs??{},{canvas:o,theme:d,facets:s,...r}=c;return new e.constructor({semanticSpec:t.semanticSpec,graphicSpec:t.graphicSpec,resolvedScales:t.resolvedScales,materializationConfigs:A({...n?{...r,...t.materializationConfigs}:{...t.materializationConfigs,...r},...t.materializationConfigs.canvas===void 0?{}:{canvas:t.materializationConfigs.canvas},...t.materializationConfigs.theme===void 0?{}:{theme:t.materializationConfigs.theme}}),children:{},context:t.context,trace:e.trace,actionStack:e.actionStack,actionSequence:e._actionSequence})}const Ne=T({op:"editFacetSource",description:"Reapply one facet, grid, or repeat recipe to a revised complete unit program.",scope:"composition"},ke,function(t={}){v(this,"editFacetSource");const e=this.compositionSpec,n=this.materializationConfigs.facets?.[e.id];if(Object.hasOwn(t,"program")===Object.hasOwn(t,"action"))throw new Error("editFacetSource requires exactly one of program or action.");let i=t.program,c=this;if(t.action!==void 0){w(t.action,["method","options"],"editFacetSource action");const l=$(t.action.method,"editFacetSource action method");let f=E(this,!0);const u=typeof f[l]=="function"?ce(f[l]):void 0;if(!u||!$e.has(l)||u.scope==="composition"||/^(?:_|materialize|rematerialize|replay|editSemantic$|editGraphics$|createGraphics$)/.test(l))throw new Error("editFacetSource action requires a unit chart-authoring action.");f=de(f,fe({marks:f.semanticSpec.layers.map(h=>le(f,h))}));for(const h of ne(f)){const p=f.guideConfigs.axis?.[h.id]??{},g=ie(h.channel,h.id);for(const[F,y]of["line","ticks","labels","title"].entries()){if(!p[y]||f.graphicSpec.objects[g[F]])continue;const{mode:M,inferredValues:He,inferredText:Ue,inferredRotation:We,inferredOffset:Ke,...O}=p[y];M==="values"&&delete O.count,M==="count"&&delete O.values;const ee=y[0].toUpperCase()+y.slice(1);f=f[`create${h.channel.toUpperCase()}Axis${ee}`]({...O,...ae(h.id,h.channel)})}}const m=f[l](t.action.options??{});c=new this.constructor({...this,trace:m.trace,actionStack:m.actionStack,actionSequence:m._actionSequence}),i=new this.constructor({...m,actionStack:[],actionSequence:m._actionSequence})}let o=Ie(i,c,t.action!==void 0);n!==void 0&&(o=o._withMaterializationConfig(["facets",e.id],n));const d=S(e.facet.guides.legend),s=d?{...e.facet.guides,legend:!1}:e.facet.guides;let r;const a=C(o,C(this,e.facet.scales));if(e.facet.grid!==void 0?r=o.facetGrid({id:e.id,data:e.facet.data,rows:e.facet.grid.rows,columns:e.facet.grid.columns,combinations:e.facet.grid.combinations,gap:e.gap,...e.spacing===void 0?{}:{spacing:e.spacing},...e.topLane===void 0?{}:{topLane:e.topLane},align:e.align,padding:e.padding,scales:a,guides:s}):e.facet.repeat!==void 0?r=o.repeatCharts({id:e.id,...e.facet.repeat,columns:e.columns,gap:e.gap,...e.spacing===void 0?{}:{spacing:e.spacing},...e.topLane===void 0?{}:{topLane:e.topLane},align:e.align,padding:e.padding,scales:a,guides:s}):r=o.facet({id:e.id,data:e.facet.data,field:e.facet.field,values:e.facet.values,columns:e.columns,gap:e.gap,...e.spacing===void 0?{}:{spacing:e.spacing},...e.topLane===void 0?{}:{topLane:e.topLane},align:e.align,padding:e.padding,scales:a,guides:s}),d){const l=r.compositionSpec;r=r._withCompositionState({children:r.children,compositionSpec:{...l,facet:{...l.facet,guides:e.facet.guides}}})}return n!==void 0&&(r=r._withMaterializationConfig(["facets",e.id],n).materializeComposition()),r.semanticSpec.title.text!==void 0&&(r=r.removeTitle()),this.semanticSpec.title.text!==void 0&&(r=r.createTitle({...this.titleConfig,...this.semanticSpec.title})),ye(r,this.materializationConfigs.theme)});function Et(t){se((e,n)=>{const{program:i,plan:c}=re(E(e),n),o=e.compositionSpec,d=new e.constructor({...i,graphicSpec:e.graphicSpec,children:e.children,materializationConfigs:{...i.materializationConfigs,facets:e.materializationConfigs.facets,...e.titleConfig===void 0?{}:{title:e.titleConfig}},actionSequence:i._actionSequence,compositionSpec:{...o,facet:{...o.facet,data:c.replacements.get(o.facet.data)??o.facet.data}}});return D(d,o.facet)}),t.prototype.replayDerivedData=Se,t.prototype.composeFacetGuides=we,t.prototype.facet=je,t.prototype.facetGrid=Re,t.prototype.repeatCharts=Me,t.prototype.editFacetHeaders=Ae,t.prototype.editFacetScales=Pe,t.prototype.editFacetGuides=Ge,t.prototype.editFacetSource=Ne}export{Ge as editFacetGuides,Ae as editFacetHeaders,Pe as editFacetScales,Ne as editFacetSource,je as facet,Re as facetGrid,Et as registerFacetActions,Me as repeatCharts};
|
|
1
|
+
import{normalizeFacetAxes as P,validateFacetAxisPolicy as k}from"../../core/facetAxisPolicy.js";import{DEFAULT_ACTION_METHODS as ne}from"../../core/vocabulary.js";import{axisGraphicIds as ae}from"../../materialization/guides/resources.js";import{facetLegendIntent as oe}from"../../materialization/facetGuides/owner.js";import{legendBlockChannels as ce}from"../../grammar/legendBlocks.js";import{cartesianAxisOwners as se,axisTargetArgs as re}from"../../selectors/axes.js";import{resolveGraphicBounds as de}from"../../layout/canvas.js";import{action as T,closedAction as $,getWrappedActionMetadata as le}from"../../core/action.js";import{registerFacetDataRevision as fe,reviseUnitData as pe}from"../data/revise.js";import{applyMaterializationPlan as ue}from"../../materialization/dependencies.js";import{getMarkMaterializationStep as he}from"../../materialization/marks/index.js";import{buildMaterializationPlan as me}from"../../materialization/planner.js";import{freezeOwned as G,isPlainObject as b}from"../../core/immutable.js";import{validateUserId as I}from"../../core/identifiers.js";import{validateNonEmptyString as j,validateNonNegativeFinite as ge,validateOptionObject as v,validatePositiveFinite as Se}from"../../core/validation.js";import{resolveFacetDefinition as N,resolveFacetGridDefinition as H}from"../../grammar/facets/index.js";import{collectFacetScaleBindings as U,resolveFacetFamily as _}from"../../grammar/facets/dependencies.js";import{FACET_SCALE_CHANNELS as L,normalizeFacetScalePolicies as q}from"../../grammar/facets/scales.js";import{resolveFacetLayout as we}from"../../layout/facets.js";import{compositionChildDescriptor as ye}from"../../materialization/composition.js";import{deriveFacetChildren as W}from"./derive.js";import{resolveFacetChildrenScales as be}from"./derive.js";import{replayDerivedData as ve}from"./replay.js";import{composeFacetGuides as Ce}from"./guides.js";import{applyCompositionState as D}from"../composition/actions.js";import{replayCompositionThemeState as Fe}from"../theme/composition.js";import{findDataset as Ee}from"../../selectors/datasets.js";import{findLayer as K}from"../../selectors/layers.js";import{findSemanticScale as Oe}from"../../selectors/scales.js";import{normalizeDisplayLabelMap as V}from"../../grammar/displayLabels.js";import{resolveRotation as xe}from"../../grammar/rotation.js";import{normalizeFacetHeaderTitle as ze}from"../../grammar/facetHeaders.js";import{createDefaultFacetHeaders as ke,normalizeFacetHeadersConfig as B,resolveFacetHeaderConfig as Te}from"../../materialization/facetHeaders.js";const $e=Object.freeze(["id","field","data","values","columns","gap","spacing","topLane","align","padding","scales","guides","headers"]),je=Object.freeze(["id","data","rows","columns","combinations","gap","spacing","topLane","align","padding","scales","guides","headers"]),_e=Object.freeze(["id","target","channel","fields","columns","gap","spacing","topLane","align","padding","scales","guides","headers"]),Le=new Set(ne),qe=Object.freeze(["program","action"]),Y=Object.freeze(["axes","legend"]),X=Object.freeze(["fontSize","fontFamily","fontWeight","color","offset","role","labelMap","side","align","rotation","title","anchor"]),J=Object.freeze(["fontSize","fontFamily","fontWeight","color","offset","align","rotation","anchor"]);function F(t,e=!1){if(t===void 0)return{axes:"each",legend:!1};v(t,Y,"facet.guides");const n=P(t.axes),i=t.legend??!1;if(i!==!1&&i!=="shared"&&!b(i))throw new Error('facet guides.legend must be false, "shared", or legend options.');if(!e&&b(i)&&Object.hasOwn(i,"type"))throw new Error("Facet legend options do not accept internal type tags.");return{axes:n,legend:i}}function E(t,e){if(t._assertCompositionProgram(e),t.compositionSpec.type!=="facet")throw new Error(`${e} requires a facet composition.`)}function O(t,e){const n=new Set(U(t.semanticSpec).map(i=>i.policyKey));return Object.fromEntries(L.flatMap(i=>n.has(i)&&e[i]!==void 0?[[i,e[i]]]:[]))}function x(t,e=!1){const n=t.compositionSpec.children.find(f=>t.children[f]?.semanticSpec.layers.length>0)??t.compositionSpec.children[0],i=t.children[n];if(i===void 0)throw new Error(`Facet "${t.compositionSpec.id}" requires a retained child.`);const{facets:s,guides:o,...d}=t.materializationConfigs,{legend:c,...p}=t.semanticSpec.guides,a={...i.materializationConfigs.guides,axis:o?.axis??i.guideConfigs.axis,grid:o?.grid??i.guideConfigs.grid};return e&&delete d.title,new t.constructor({semanticSpec:e?{...t.semanticSpec,title:{},guides:{...p,...i.semanticSpec.guides.legend===void 0?{}:{legend:i.semanticSpec.guides.legend}}}:t.semanticSpec,graphicSpec:i.graphicSpec,resolvedScales:t.resolvedScales,materializationConfigs:G({...d,...i.materializationConfigs.theme===void 0?{}:{theme:i.materializationConfigs.theme},...a===void 0?{}:{guides:a},canvas:i.materializationConfigs.canvas}),children:{},context:t.context,trace:t.trace,actionStack:t.actionStack,actionSequence:t._actionSequence})}function M(t,{scales:e,guides:n}){const i=t.compositionSpec;if(i.facet.repeat!==void 0){const l=x(t),u=ee(l,{id:i.id,...i.facet.repeat}),w=te(l,u,O(l,e),!0);return D(t,{children:w.children,compositionSpec:{...i,facet:{...i.facet,scales:e,guides:n}}},i.children)}const s=i.facet.grid===void 0?N(t.semanticSpec,{id:i.id,data:i.facet.data,field:i.facet.field,values:i.facet.values}):H(t.semanticSpec,{id:i.id,data:i.facet.data,rows:i.facet.grid.rows,columns:i.facet.grid.columns,combinations:i.facet.grid.combinations}),o=O(t,e),d=q(t.semanticSpec,o),c=x(t),p=W(c,s,{closeInheritedAction:!0,stripTitle:!0,scales:o}),a={...i,facet:{...i.facet,scales:d.channels,guides:n}};let f=t._withoutMaterializationConfig(["guides","legend"]);for(const[l,u]of Object.entries(c.guideConfigs.legend??{}))f=f._withLegendConfig(l,u);return D(f,{children:p.children,compositionSpec:a},a.children)}function R(t,e,n,i="editFacetHeaders"){v(e,X,i,{allowEmpty:!1,emptyMessage:`${i} requires at least one change.`});const s=e.role??"all";if(!["all","row","column"].includes(s))throw new Error(`Unknown facet header role "${s}".`);if(s==="all"&&Object.hasOwn(e,"side"))throw new Error(`${i} side requires an explicit row or column role.`);if(s==="all"&&Object.hasOwn(e,"title"))throw new Error(`${i} title requires an explicit row or column role.`);if(s==="row"&&n===void 0)throw new Error(`${i} row role requires a row-column facet grid.`);if(Object.hasOwn(e,"side")){const a=s==="row"?["left","right"]:n===void 0?["top","bottom","left","right"]:["top","bottom"];if(!a.includes(e.side))throw new Error(`${i} ${s} side must be ${a.join(" or ")}.`)}if(Object.hasOwn(e,"align")&&!["start","center","end"].includes(e.align))throw new Error(`${i} align must be start, center, or end.`);if(s==="all"&&Object.keys(e).every(a=>a==="role"))throw new Error(`${i} requires at least one change.`);const o=B(t),d=s==="all"?"common":s,c={...o[d]};if(Object.hasOwn(e,"title")){const a=ze(c.title,e.title);a===void 0?delete c.title:c.title=a}for(const a of J)Object.hasOwn(e,a)&&(c[a]=e[a]);Object.hasOwn(e,"rotation")&&(c.rotation=xe(e.rotation,`${i} ${s} rotation`)),Object.hasOwn(e,"side")&&(c.side=e.side),Object.hasOwn(e,"labelMap")&&(e.labelMap==="auto"?delete c.labelMap:c.labelMap=V(e.labelMap,`${i} ${s} labelMap`));const p={...o,...s==="all"?{}:{mode:"roles"},[d]:c};for(const a of["all","row","column"]){const f=Te(p,a);if(Se(f.fontSize,`Facet ${a} header fontSize`),j(f.fontFamily,`Facet ${a} header fontFamily`),j(f.color,`Facet ${a} header color`),ge(f.offset,`Facet ${a} header offset`),f.rotation!==void 0&&!Number.isFinite(f.rotation))throw new TypeError(`Facet ${a} header rotation must resolve to finite radians.`);if(!(typeof f.fontWeight=="string"&&f.fontWeight.length>0||Number.isFinite(f.fontWeight)))throw new TypeError(`Facet ${a} header fontWeight must be a non-empty string or number.`);if(!["start","center","end"].includes(f.align))throw new Error(`Facet ${a} header align must be start, center, or end.`);f.labelMap!==void 0&&V(f.labelMap,`Facet ${a} header labelMap`)}return p}function De(t,e){let n=ke();if(t===void 0)return n;v(t,[...J,"labelMap","row","column"],"facet.headers");const{row:i,column:s,...o}=t;Object.keys(o).length>0&&(n=R(n,o,e,"facet.headers"));for(const[d,c]of[["row",i],["column",s]])c!==void 0&&(v(c,X.filter(p=>p!=="role"),`facet.headers.${d}`),n=R(n,{...c,role:d},e,`facet.headers.${d}`));return n}function Q(t,e,{definition:n,derived:i,guides:s,scalePolicies:o,facet:d}){const c=t.materializationConfigs.facets?.[n.id]?.headers,p=e.headers===void 0&&c!==void 0?B(c):De(e.headers,n.grid),a=we({spacing:e.spacing,topLane:e.topLane,plots:Object.entries(i.children).map(([l,u])=>({id:l,...de(u)})),children:n.cells.map(l=>({...ye(l.id,i.children[l.id]),value:l.value,...n.grid===void 0?{}:{row:l.row,column:l.column}})),columns:n.grid?.columns.values.length??e.columns,gap:e.gap,align:e.align,padding:e.padding,sharedLegend:s.legend==="shared"}),f={id:n.id,type:"facet",children:n.cells.map(l=>l.id),columns:a.columns,gap:a.gap,align:a.align,padding:a.padding,...a.spacing===void 0?{}:{spacing:a.spacing},...a.topLane===void 0?{}:{topLane:a.topLane},facet:{data:n.data,...d,scales:o.channels,guides:s}};return D(t._withMaterializationConfig(["facets",n.id],{headers:p}),{children:i.children,compositionSpec:f},f.children)}function Z(t,e,n){return $({op:t,description:e},t==="facet"?$e:je,function(i={}){const s=F(i.guides),o=n(this.semanticSpec,i);k(s.axes,o.family);const d=q(this.semanticSpec,i.scales??{}),c=W(this,o,{closeInheritedAction:!0,stripTitle:!0,scales:i.scales??{}}),p=o.grid===void 0?{field:o.field,values:o.values}:{values:o.cells.map(a=>a.value),grid:{...o.grid,cells:o.cells.map(a=>({id:a.id,row:a.row,column:a.column,rowValue:a.rowValue,columnValue:a.columnValue,empty:a.empty}))}};return Q(this,i,{definition:o,derived:c,guides:s,scalePolicies:d,facet:p})})}const Me=Z("facet","Repeat one direct-source chart by field value.",N);function ee(t,e){if(!b(e))throw new TypeError("repeatCharts options must be a plain object.");const n=I(e.id??"repeat","Repeat id"),i=b(e.channel);if(i){const r=Object.keys(e.channel);if(r.length!==1||r[0]!=="parallelDimension"||typeof e.channel.parallelDimension!="string"||e.channel.parallelDimension.length===0)throw new Error("repeatCharts Parallel channel must contain exactly one non-empty parallelDimension.")}else if(!["x","y","theta","r"].includes(e.channel))throw new Error('repeatCharts channel must be "x", "y", "theta", "r", or one parallelDimension.');if(!Array.isArray(e.fields)||e.fields.length===0||e.fields.some(r=>typeof r!="string"||r.length===0))throw new TypeError("repeatCharts fields must be a non-empty array of field names.");if(new Set(e.fields).size!==e.fields.length)throw new Error("repeatCharts fields must be unique.");const s=_(t.semanticSpec).family,o=e.channel==="r"?"radius":e.channel,d=t.semanticSpec.layers.filter(r=>{if(i){const g=(r.encoding?.parallel?.dimensions??[]).filter(S=>S.field===e.channel.parallelDimension);return s==="parallel"&&r.mark?.type==="line"&&g.length===1}if(["x","y"].includes(e.channel))return s==="cartesian"&&r.encoding?.x?.scale!==void 0&&r.encoding?.y?.scale!==void 0&&r.encoding?.[e.channel]?.field!==void 0&&["point","line","area","bar","rule","tick","rect"].includes(r.mark?.type);const h=t.markConfigs[r.id]?.compositionRole;return s!=="polar"||["pie","radar"].includes(h)?!1:["point","line","arc"].includes(r.mark?.type)&&r.encoding?.[o]?.field!==void 0});let c;if(e.target!==void 0){if(c=I(e.target,"Repeat target"),!d.some(r=>r.id===c))throw new Error(`repeatCharts target "${c}" is not eligible for the requested field role.`)}else if(d.length===1)c=d[0].id;else throw new Error(d.length===0?"repeatCharts requires one eligible complete mark for the requested field role.":"repeatCharts target is ambiguous; provide target.");if(t.semanticSpec.layers.filter(r=>{if(r.id===c)return!1;const h=r.mark?.type==="text"&&r.source===c,g=t.markConfigs[r.id]?.statisticalReference?.source===c;return!h&&!g}).length>0)throw new Error("repeatCharts currently supports one direct mark only.");const a=t.markConfigs[c]??{},f=["boxPlot","gradientPlot","violinPlot","regressionPlot","endpointPlot","ecdfPlot","raincloudPlot","intervalPlot"].find(r=>a[r]!==void 0);if(f!==void 0)throw new Error(`repeatCharts does not replace the ${f} composite role.`);const l=K(t,c),u=Ee(t,l.data);if(u?.transform?.length>0&&u.transform[0].type!=="lookup")throw new Error("repeatCharts does not rewrite a derived dataset dependency.");const w=i?l.encoding.parallel:l.encoding[o],m=i?w.dimensions.findIndex(r=>r.field===e.channel.parallelDimension):void 0;return{id:n,target:c,channel:i?{...e.channel}:e.channel,policyKey:i?"parallelDimensions":e.channel,fields:[...e.fields],data:l.data,encoding:w,...m===void 0?{}:{dimensionIndex:m},cells:e.fields.map((r,h)=>({id:`${n}-field-${h+1}`,field:r,value:r}))}}function Re(t,e){const n=t.encoding;return{target:t.target,field:e,fieldType:n.fieldType,...n.temporalUnit===void 0?{}:{temporalUnit:n.temporalUnit},...n.aggregate===void 0?{}:{aggregate:n.aggregate},...n.bin===void 0?{}:{bin:n.bin},...n.stack===void 0?{}:{stack:n.stack},...n.weight===void 0?{}:{weight:n.weight},scale:{id:n.scale}}}function Ae(t,e,n){return e.encoding.dimensions.map((i,s)=>{const o=Oe(t,i.scale);if(o===void 0)throw new Error(`repeatCharts Parallel dimension scale "${i.scale}" is missing.`);const{id:d,...c}=o,p=s===e.dimensionIndex;return{field:p?n:i.field,fieldType:i.fieldType,title:p&&i.title===i.field?n:i.title,scale:c}})}function Pe(t,e,n){if(b(e.channel))return t.encodeParallelCoordinates({target:e.target,coordinate:K(t,e.target).coordinate,dimensions:Ae(t,e,n),...e.encoding.key===void 0?{}:{key:e.encoding.key},missing:e.encoding.missing});const i={x:"encodeX",y:"encodeY",theta:"encodeTheta",r:"encodeR"}[e.channel];return t[i](Re(e,n))}function te(t,e,n,i){const s=t.semanticSpec.title.text===void 0?t:t.removeTitle(),o=Object.fromEntries(e.cells.map(d=>[d.id,Pe(s,e,d.field)]));return be(s,e.cells.map(d=>d.id),o,n,i)}const Ge=$({op:"repeatCharts",description:"Repeat one direct chart across an ordered field-role list."},_e,function(t={}){const e=F(t.guides),n=ee(this,t);k(e.axes,_(this.semanticSpec).family,!0);const i={...t.scales??{},[n.policyKey]:t.scales?.[n.policyKey]??"independent"},s=q(this.semanticSpec,i),o=te(this,n,i,!0);return Q(this,t,{definition:n,derived:o,guides:e,scalePolicies:s,facet:{values:n.fields,repeat:{target:n.target,channel:n.channel,fields:n.fields}}})}),Ie=Z("facetGrid","Repeat one direct-source Cartesian chart across a row and column field grid.",H),Ne=T({op:"editFacetHeaders",description:"Edit parent-owned facet header appearance.",scope:"composition"},function(t={}){E(this,"editFacetHeaders");const e=this.compositionSpec.id,n=this.materializationConfigs.facets?.[e];if(!b(n?.headers))throw new Error(`Facet "${e}" requires header configuration.`);const i=R(n.headers,t,this.compositionSpec.facet.grid);return this._withMaterializationConfig(["facets",e],{...n,headers:i}).materializeComposition()}),He=T({op:"editFacetScales",description:"Edit facet scale-resolution policies and rederive every cell.",scope:"composition"},function(t={}){E(this,"editFacetScales"),v(t,L,"editFacetScales",{allowEmpty:!1,emptyMessage:"editFacetScales requires at least one channel policy change."});for(const i of Object.keys(t))if(!U(this.semanticSpec).some(s=>s.policyKey===i))throw new Error(`Facet scale channel "${i}" is not used by an affected layer.`);const e=this.compositionSpec.facet,n={...e.scales,...t};if(L.every(i=>n[i]===e.scales[i]))throw new Error("editFacetScales requires at least one channel policy change.");return M(this,{scales:n,guides:e.guides})}),Ue=T({op:"editFacetGuides",description:"Edit facet guide ownership and rederive every cell.",scope:"composition"},function(t={}){E(this,"editFacetGuides"),v(t,Y,"editFacetGuides",{allowEmpty:!1,emptyMessage:"editFacetGuides requires at least one guide policy."});const e=this.compositionSpec.facet;Object.hasOwn(t,"legend")&&F({legend:t.legend});const n=F({...e.guides,...t,...Object.hasOwn(t,"axes")?{axes:P(t.axes,e.guides.axes)}:{}},!0),i=_(this.semanticSpec).family;return k(n.axes,i,e.repeat!==void 0),M(this,{scales:e.scales,guides:n})});function We(t,e,n=!1){if(!(t instanceof e.constructor))throw new TypeError("editFacetSource program must be a ChartProgram.");if(t.compositionSpec!==void 0)throw new Error("editFacetSource program must be a complete unit ChartProgram.");if(t.actionStack.length!==0)throw new Error("editFacetSource program has an unfinished action stack.");const i=e.compositionSpec.children.find(a=>e.children[a]?.semanticSpec.layers.length>0)??e.compositionSpec.children[0],s=e.children[i]?.materializationConfigs??{},{canvas:o,theme:d,facets:c,...p}=s;return new e.constructor({semanticSpec:t.semanticSpec,graphicSpec:t.graphicSpec,resolvedScales:t.resolvedScales,materializationConfigs:G({...n?{...p,...t.materializationConfigs}:{...t.materializationConfigs,...p},...t.materializationConfigs.canvas===void 0?{}:{canvas:t.materializationConfigs.canvas},...t.materializationConfigs.theme===void 0?{}:{theme:t.materializationConfigs.theme}}),children:{},context:t.context,trace:e.trace,actionStack:e.actionStack,actionSequence:e._actionSequence})}const Ke=$({op:"editFacetSource",description:"Reapply one facet, grid, or repeat recipe to a revised complete unit program.",scope:"composition"},qe,function(t={}){E(this,"editFacetSource");const e=this.compositionSpec,n=this.materializationConfigs.facets?.[e.id];if(Object.hasOwn(t,"program")===Object.hasOwn(t,"action"))throw new Error("editFacetSource requires exactly one of program or action.");let i=t.program,s=this,o=e.facet.guides;if(t.action!==void 0){v(t.action,["method","options"],"editFacetSource action");const l=j(t.action.method,"editFacetSource action method");let u=x(this,!0);const w=typeof u[l]=="function"?le(u[l]):void 0;if(!w||!Le.has(l)||w.scope==="composition"||/^(?:_|materialize|rematerialize|replay|editSemantic$|editGraphics$|createGraphics$)/.test(l))throw new Error("editFacetSource action requires a unit chart-authoring action.");u=ue(u,me({marks:u.semanticSpec.layers.map(r=>he(u,r))}));for(const r of se(u)){const h=u.guideConfigs.axis?.[r.id]??{},g=ae(r.channel,r.id);for(const[S,y]of["line","ticks","labels","title"].entries()){if(!h[y]||u.graphicSpec.objects[g[S]])continue;const{mode:C,inferredValues:A,inferredText:Ve,inferredRotation:Be,inferredOffset:Ye,...z}=h[y];C==="values"&&delete z.count,C==="count"&&delete z.values;const ie=y[0].toUpperCase()+y.slice(1);u=u[`create${r.channel.toUpperCase()}Axis${ie}`]({...z,...re(r.id,r.channel)})}}const m=u[l](t.action.options??{});if(l==="createLegend"&&o.legend?.type==="authored-legend"){const r=Object.entries(u.guideConfigs.suppressedLegends??{}).flatMap(([h,{channels:g}])=>g.filter(S=>!m.guideConfigs.suppressedLegends?.[h]?.channels.includes(S)).map(S=>[h,S]));if(r.length){const h=oe(m),g=Object.fromEntries(Object.entries(h.blocks).filter(([S,{config:y}])=>r.some(([C,A])=>y.target===C&&ce(S,y).includes(A))));o={...o,legend:{...o.legend,blocks:{...o.legend.blocks,...g}}}}}s=new this.constructor({...this,trace:m.trace,actionStack:m.actionStack,actionSequence:m._actionSequence}),i=new this.constructor({...m,actionStack:[],actionSequence:m._actionSequence})}let d=We(i,s,t.action!==void 0);n!==void 0&&(d=d._withMaterializationConfig(["facets",e.id],n));const c=b(o.legend),p=c?{...o,legend:!1}:o;let a;const f=O(d,O(this,e.facet.scales));if(e.facet.grid!==void 0?a=d.facetGrid({id:e.id,data:e.facet.data,rows:e.facet.grid.rows,columns:e.facet.grid.columns,combinations:e.facet.grid.combinations,gap:e.gap,...e.spacing===void 0?{}:{spacing:e.spacing},...e.topLane===void 0?{}:{topLane:e.topLane},align:e.align,padding:e.padding,scales:f,guides:p}):e.facet.repeat!==void 0?a=d.repeatCharts({id:e.id,...e.facet.repeat,columns:e.columns,gap:e.gap,...e.spacing===void 0?{}:{spacing:e.spacing},...e.topLane===void 0?{}:{topLane:e.topLane},align:e.align,padding:e.padding,scales:f,guides:p}):a=d.facet({id:e.id,data:e.facet.data,field:e.facet.field,values:e.facet.values,columns:e.columns,gap:e.gap,...e.spacing===void 0?{}:{spacing:e.spacing},...e.topLane===void 0?{}:{topLane:e.topLane},align:e.align,padding:e.padding,scales:f,guides:p}),c){const l=a.compositionSpec;a=a._withCompositionState({children:a.children,compositionSpec:{...l,facet:{...l.facet,guides:o}}})}return n!==void 0&&(a=a._withMaterializationConfig(["facets",e.id],n).materializeComposition()),a.semanticSpec.title.text!==void 0&&(a=a.removeTitle()),this.semanticSpec.title.text!==void 0&&(a=a.createTitle({...this.titleConfig,...this.semanticSpec.title})),Fe(a,this.materializationConfigs.theme)});function Tt(t){fe((e,n)=>{const i=x(e),s=i.semanticSpec.title.text===void 0?i:i.removeTitle(),{program:o,plan:d}=pe(s,n),c=e.compositionSpec,p=new e.constructor({...o,semanticSpec:{...o.semanticSpec,title:e.semanticSpec.title},graphicSpec:e.graphicSpec,children:e.children,materializationConfigs:{...o.materializationConfigs,facets:e.materializationConfigs.facets,...e.titleConfig===void 0?{}:{title:e.titleConfig}},actionSequence:o._actionSequence,compositionSpec:{...c,facet:{...c.facet,data:d.replacements.get(c.facet.data)??c.facet.data}}});return M(p,c.facet)}),t.prototype.replayDerivedData=ve,t.prototype.composeFacetGuides=Ce,t.prototype.facet=Me,t.prototype.facetGrid=Ie,t.prototype.repeatCharts=Ge,t.prototype.editFacetHeaders=Ne,t.prototype.editFacetScales=He,t.prototype.editFacetGuides=Ue,t.prototype.editFacetSource=Ke}export{Ue as editFacetGuides,Ne as editFacetHeaders,He as editFacetScales,Ke as editFacetSource,Me as facet,Ie as facetGrid,x as facetUnitTemplate,Tt as registerFacetActions,Ge as repeatCharts};
|
|
@@ -156,7 +156,7 @@ function resolvePolarAxisArgs(program, layers, channel, option, descriptor) {
|
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
function hasChannel(layers, channel) {
|
|
159
|
-
return layers.some(layer => layer.encoding?.[channel] !== undefined);
|
|
159
|
+
return layers.some(layer => layer.encoding?.[channel] !== undefined && !(layer.mark?.type === "tick" && Object.hasOwn(layer.encoding[channel], "datum")));
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
function resolveAxisArgs(layers, channel, option) {
|
|
@@ -170,6 +170,7 @@ function resolveAxisArgs(layers, channel, option) {
|
|
|
170
170
|
const encodedScaleIds = [
|
|
171
171
|
...new Set(
|
|
172
172
|
layers
|
|
173
|
+
.filter(layer => !(layer.mark?.type === "tick" && Object.hasOwn(layer.encoding?.[channel] ?? {}, "datum")))
|
|
173
174
|
.map(layer => layer.encoding?.[channel]?.scale)
|
|
174
175
|
.filter(id => id !== undefined)
|
|
175
176
|
)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { axisGraphicIds } from "../../../materialization/guides/resources.js";
|
|
2
|
+
import { isLabelRelativeTitleOffset } from "../../../grammar/axisTextPlacement.js";
|
|
2
3
|
|
|
3
4
|
export const AXIS_COMPONENTS = Object.freeze(["line", "ticks", "labels", "title"]);
|
|
4
5
|
|
|
@@ -31,6 +32,10 @@ export function assertRemovableAxisComponent(program, channel, component, operat
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export function removeAxisComponent(program, channel, component, axisId = channel) {
|
|
35
|
+
if (component === "labels" && isLabelRelativeTitleOffset(program.guideConfigs.axis?.[axisId]?.title?.offset) &&
|
|
36
|
+
program.context.pendingRelativeTitleAxis !== axisId) {
|
|
37
|
+
throw new Error("Remove the label-relative axis title together with its labels.");
|
|
38
|
+
}
|
|
34
39
|
const id = axisComponentId(channel, component, axisId);
|
|
35
40
|
let next = program;
|
|
36
41
|
if (component === "title" && next.semanticSpec.guides.axis?.[axisId]?.title !== undefined) {
|
|
@@ -1,188 +1 @@
|
|
|
1
|
-
import { selectCartesianAxis,
|
|
2
|
-
import { validateAxisPosition, resolveAxisFrameConfig } from "./policy.js";
|
|
3
|
-
import { withGuideLayoutValidation } from "../../../materialization/guides/layout.js";
|
|
4
|
-
import { action } from "../../../core/action.js";
|
|
5
|
-
import { isPlainObject } from "../../../core/immutable.js";
|
|
6
|
-
import { validateKeys, validateOptionObject, validateNonNegativeFinite } from "../../../core/validation.js";
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
AXIS_COMPONENTS,
|
|
10
|
-
axisComponentId as graphicId,
|
|
11
|
-
hasAxisComponent as hasComponent,
|
|
12
|
-
assertRemovableAxisComponent as assertRemovable,
|
|
13
|
-
removeAxisComponent as removeComponent
|
|
14
|
-
} from "./components.js";
|
|
15
|
-
|
|
16
|
-
const OPTIONS = Object.freeze([
|
|
17
|
-
"target", "position", "line", "ticks", "labels", "ticksAndLabels", "title", "offset", "underlay"
|
|
18
|
-
]);
|
|
19
|
-
const LINE_OPTIONS = Object.freeze(["color", "lineWidth"]);
|
|
20
|
-
const TICK_OPTIONS = Object.freeze([
|
|
21
|
-
"count", "values", "rounding", "length", "color", "lineWidth", "alongOffset", "strokeDash", "strokeDashMap"
|
|
22
|
-
]);
|
|
23
|
-
const LABEL_OPTIONS = Object.freeze([
|
|
24
|
-
"count", "values", "rounding", "offset", "format", "color", "fontSize",
|
|
25
|
-
"fontFamily", "fontWeight", "rotation", "maxWidth", "wrap",
|
|
26
|
-
"lineHeight", "overlap", "alongOffset", "labelMap", "flush", "colorMap", "align"
|
|
27
|
-
]);
|
|
28
|
-
const GROUP_OPTIONS = Object.freeze(["count", "values", "rounding", "ticks", "labels"]);
|
|
29
|
-
const TITLE_OPTIONS = Object.freeze([
|
|
30
|
-
"text", "at", "offset", "rotation", "color", "fontSize",
|
|
31
|
-
"fontFamily", "fontWeight", "alongOffset", "align", "baseline", "overlap"
|
|
32
|
-
]);
|
|
33
|
-
|
|
34
|
-
function validateNested(args, key, options, operation, { allowFalse = false } = {}) {
|
|
35
|
-
if (!Object.hasOwn(args, key)) return;
|
|
36
|
-
if (allowFalse && args[key] === false) return;
|
|
37
|
-
if (!isPlainObject(args[key])) {
|
|
38
|
-
const accepted = allowFalse ? "false or a plain object" : "a plain object";
|
|
39
|
-
throw new TypeError(`${operation}.${key} must be ${accepted}.`);
|
|
40
|
-
}
|
|
41
|
-
validateKeys(args[key], options, `${operation}.${key}`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function validateArgs(args, operation) {
|
|
45
|
-
if (Object.hasOwn(args, "offset")) validateNonNegativeFinite(args.offset, "Axis frame offset");
|
|
46
|
-
resolveAxisFrameConfig(undefined, args);
|
|
47
|
-
validateOptionObject(args, OPTIONS, operation, {
|
|
48
|
-
allowEmpty: false,
|
|
49
|
-
emptyMessage: `${operation} requires at least one axis change.`,
|
|
50
|
-
emptyError: Error
|
|
51
|
-
});
|
|
52
|
-
const removable = { allowFalse: true };
|
|
53
|
-
validateNested(args, "line", LINE_OPTIONS, operation, removable);
|
|
54
|
-
validateNested(args, "ticks", TICK_OPTIONS, operation, removable);
|
|
55
|
-
validateNested(args, "labels", LABEL_OPTIONS, operation, removable);
|
|
56
|
-
validateNested(args, "ticksAndLabels", GROUP_OPTIONS, operation, removable);
|
|
57
|
-
validateNested(args, "title", TITLE_OPTIONS, operation, removable);
|
|
58
|
-
if (args.ticksAndLabels !== undefined && (
|
|
59
|
-
args.ticks !== undefined || args.labels !== undefined
|
|
60
|
-
)) {
|
|
61
|
-
throw new Error(
|
|
62
|
-
`${operation} cannot combine ticksAndLabels with ticks or labels.`
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
if (args.ticksAndLabels !== false && args.ticksAndLabels?.ticks !== undefined) {
|
|
66
|
-
validateNested(args.ticksAndLabels, "ticks", ["length", "color", "lineWidth", "alongOffset", "strokeDash", "strokeDashMap"], `${operation}.ticksAndLabels`);
|
|
67
|
-
}
|
|
68
|
-
if (args.ticksAndLabels !== false && args.ticksAndLabels?.labels !== undefined) {
|
|
69
|
-
validateNested(args.ticksAndLabels, "labels", [
|
|
70
|
-
"offset", "format", "color", "fontSize", "fontFamily", "fontWeight",
|
|
71
|
-
"rotation", "maxWidth", "wrap", "lineHeight", "overlap", "alongOffset", "labelMap", "flush", "colorMap", "align"
|
|
72
|
-
], `${operation}.ticksAndLabels`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function names(channel) {
|
|
77
|
-
const prefix = channel === "x" ? "X" : "Y";
|
|
78
|
-
return {
|
|
79
|
-
operation: `edit${prefix}Axis`,
|
|
80
|
-
line: `edit${prefix}AxisLine`,
|
|
81
|
-
ticks: `edit${prefix}AxisTicks`,
|
|
82
|
-
labels: `edit${prefix}AxisLabels`,
|
|
83
|
-
group: `edit${prefix}AxisTicksAndLabels`,
|
|
84
|
-
title: `edit${prefix}AxisTitle`,
|
|
85
|
-
remove: `remove${prefix}Axis`
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function buildPlan(program, channel, args, operation, axisId = channel) {
|
|
90
|
-
const shared = { ...axisTargetArgs(axisId, channel),
|
|
91
|
-
...(Object.hasOwn(args, "position") ? { position: args.position } : {}) };
|
|
92
|
-
const plan = [];
|
|
93
|
-
const addLeaf = (component, edit) => {
|
|
94
|
-
const value = args[component];
|
|
95
|
-
if (value === false) {
|
|
96
|
-
assertRemovable(program, channel, component, operation.operation, axisId);
|
|
97
|
-
plan.push({ kind: "remove", component });
|
|
98
|
-
} else if (value !== undefined) {
|
|
99
|
-
plan.push({ kind: "edit", operation: edit, args: { ...shared, ...value } });
|
|
100
|
-
} else if ((args.position !== undefined || Object.hasOwn(args, "offset") || Object.hasOwn(args, "underlay")) && hasComponent(program, channel, component, axisId)) {
|
|
101
|
-
plan.push({ kind: "edit", operation: edit, args: shared });
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
addLeaf("line", operation.line);
|
|
106
|
-
if (args.ticksAndLabels === false) {
|
|
107
|
-
assertRemovable(program, channel, "ticks", operation.operation, axisId);
|
|
108
|
-
assertRemovable(program, channel, "labels", operation.operation, axisId);
|
|
109
|
-
plan.push(
|
|
110
|
-
{ kind: "remove", component: "ticks" },
|
|
111
|
-
{ kind: "remove", component: "labels" }
|
|
112
|
-
);
|
|
113
|
-
} else if (args.ticksAndLabels !== undefined) {
|
|
114
|
-
plan.push({
|
|
115
|
-
kind: "edit",
|
|
116
|
-
operation: operation.group,
|
|
117
|
-
args: { ...shared, ...args.ticksAndLabels }
|
|
118
|
-
});
|
|
119
|
-
} else {
|
|
120
|
-
addLeaf("ticks", operation.ticks);
|
|
121
|
-
addLeaf("labels", operation.labels);
|
|
122
|
-
}
|
|
123
|
-
addLeaf("title", operation.title);
|
|
124
|
-
|
|
125
|
-
if (plan.length === 0) {
|
|
126
|
-
throw new Error(`${operation.operation} requires an existing ${channel}-axis component.`);
|
|
127
|
-
}
|
|
128
|
-
return plan;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function applyPlan(program, channel, plan, operation, axisId = channel) {
|
|
132
|
-
let next = program;
|
|
133
|
-
for (const step of plan) {
|
|
134
|
-
next = step.kind === "remove"
|
|
135
|
-
? removeComponent(next, channel, step.component, axisId)
|
|
136
|
-
: next[step.operation](step.args);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const hasRetainedGraphic = AXIS_COMPONENTS.some(
|
|
140
|
-
component => next.graphicSpec.objects[graphicId(channel, component, axisId)] !== undefined
|
|
141
|
-
);
|
|
142
|
-
if (!hasRetainedGraphic && (
|
|
143
|
-
next.semanticSpec.guides.axis?.[axisId] !== undefined ||
|
|
144
|
-
next.guideConfigs.axis?.[axisId] !== undefined
|
|
145
|
-
)) {
|
|
146
|
-
next = next[operation.remove](axisId === channel ? undefined : axisTargetArgs(axisId, channel));
|
|
147
|
-
}
|
|
148
|
-
return next;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function makeEditAxis(channel) {
|
|
152
|
-
const operation = names(channel);
|
|
153
|
-
return action(
|
|
154
|
-
{
|
|
155
|
-
op: operation.operation,
|
|
156
|
-
description: `Edit selected existing ${channel}-axis components.`
|
|
157
|
-
},
|
|
158
|
-
withGuideLayoutValidation(function (args = {}) {
|
|
159
|
-
validateArgs(args, operation.operation);
|
|
160
|
-
const selected = selectCartesianAxis(this, channel, args, { whole: true });
|
|
161
|
-
const axisId = selected.id; args = selected.options;
|
|
162
|
-
let source = this;
|
|
163
|
-
if (selected.owner?.named && args.position !== undefined) {
|
|
164
|
-
const position = validateAxisPosition(channel, args.position);
|
|
165
|
-
assertCartesianAxisSideAvailable(this, { id: axisId, channel,
|
|
166
|
-
coordinate: selected.owner.coordinate, position });
|
|
167
|
-
source = source.editSemantic({ property: `guide.axis.${axisId}.position`, value: position });
|
|
168
|
-
}
|
|
169
|
-
const frame = resolveAxisFrameConfig(source.guideConfigs.axis?.[axisId]?.frame, args);
|
|
170
|
-
source = frame === undefined ? source._withoutMaterializationConfig(["guides", "axis", axisId, "frame"])
|
|
171
|
-
: source._withGuideConfig(axisId, "frame", frame);
|
|
172
|
-
const plan = buildPlan(source, channel, args, operation, axisId);
|
|
173
|
-
|
|
174
|
-
// Run the complete proposal against an immutable speculative branch so a
|
|
175
|
-
// later leaf failure cannot begin the returned action trace or state.
|
|
176
|
-
applyPlan(source, channel, plan, operation, axisId);
|
|
177
|
-
return applyPlan(source, channel, plan, operation, axisId);
|
|
178
|
-
})
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const editXAxis = /* @__PURE__ */ makeEditAxis("x");
|
|
183
|
-
const editYAxis = /* @__PURE__ */ makeEditAxis("y");
|
|
184
|
-
|
|
185
|
-
export function registerCompleteAxisEditActions(ProgramClass) {
|
|
186
|
-
ProgramClass.prototype.editXAxis = editXAxis;
|
|
187
|
-
ProgramClass.prototype.editYAxis = editYAxis;
|
|
188
|
-
}
|
|
1
|
+
import{splitGuideVisibility as L,patchGuideVisibility as T}from"../../../materialization/guides/visibility.js";import{resolveAxisTickEditConfig as w}from"./ticks.js";import{resolveAxisLabelEditConfig as C}from"./labels.js";import{validateAxisTickGroupEditConfig as $}from"./tickGroups.js";import{selectCartesianAxis as j,axisTargetArgs as A,assertCartesianAxisSideAvailable as y}from"../../../selectors/axes.js";import{validateAxisPosition as E,resolveAxisFrameConfig as h}from"./policy.js";import{withGuideLayoutValidation as S,withPendingRelativeAxisTitle as N}from"../../../materialization/guides/layout.js";import{action as P}from"../../../core/action.js";import{applyMaterializationPlan as g}from"../../../materialization/planner.js";import{isPlainObject as u}from"../../../core/immutable.js";import{isLabelRelativeTitleOffset as O}from"../../../grammar/axisTextPlacement.js";import{validateKeys as z,validateOptionObject as M,validateNonNegativeFinite as G}from"../../../core/validation.js";import{AXIS_COMPONENTS as R,axisComponentId as W,hasAxisComponent as _,assertRemovableAxisComponent as m,removeAxisComponent as F}from"./components.js";const D=Object.freeze(["target","position","line","ticks","labels","ticksAndLabels","title","offset","underlay"]),X=Object.freeze(["color","lineWidth"]),V=Object.freeze(["count","values","rounding","length","color","lineWidth","alongOffset","strokeDash","strokeDashMap"]),Y=Object.freeze(["count","values","rounding","offset","format","color","fontSize","fontFamily","fontWeight","rotation","maxWidth","wrap","lineHeight","overlap","alongOffset","labelMap","flush","flushThreshold","colorMap","align"]),q=Object.freeze(["count","values","rounding","ticks","labels"]),H=Object.freeze(["text","at","offset","rotation","color","fontSize","fontFamily","fontWeight","alongOffset","align","baseline","overlap"]);function a(e,i,t,l,{allowFalse:s=!1}={}){if(Object.hasOwn(e,i)&&!(s&&e[i]===!1)){if(!u(e[i])){const f=s?"false or a plain object":"a plain object";throw new TypeError(`${l}.${i} must be ${f}.`)}z(e[i],t,`${l}.${i}`)}}function v(e,i){Object.hasOwn(e,"offset")&&G(e.offset,"Axis frame offset"),h(void 0,e),M(e,D,i,{allowEmpty:!1,emptyMessage:`${i} requires at least one axis change.`,emptyError:Error});const t={allowFalse:!0};if(a(e,"line",X,i,t),a(e,"ticks",V,i,t),a(e,"labels",Y,i,t),a(e,"ticksAndLabels",q,i,t),a(e,"title",H,i,t),e.ticksAndLabels!==void 0&&(e.ticks!==void 0||e.labels!==void 0))throw new Error(`${i} cannot combine ticksAndLabels with ticks or labels.`);e.ticksAndLabels!==!1&&e.ticksAndLabels?.ticks!==void 0&&a(e.ticksAndLabels,"ticks",["length","color","lineWidth","alongOffset","strokeDash","strokeDashMap"],`${i}.ticksAndLabels`),e.ticksAndLabels!==!1&&e.ticksAndLabels?.labels!==void 0&&a(e.ticksAndLabels,"labels",["offset","format","color","fontSize","fontFamily","fontWeight","rotation","maxWidth","wrap","lineHeight","overlap","alongOffset","labelMap","flush","flushThreshold","colorMap","align"],`${i}.ticksAndLabels`)}function K(e){const i=e==="x"?"X":"Y";return{operation:`edit${i}Axis`,line:`edit${i}AxisLine`,ticks:`edit${i}AxisTicks`,labels:`edit${i}AxisLabels`,group:`edit${i}AxisTicksAndLabels`,title:`edit${i}AxisTitle`,remove:`remove${i}Axis`}}function B(e,i,t,l){u(t.ticks)&&w(e,i,t.ticks,l),u(t.labels)&&C(e,i,t.labels,l),u(t.ticksAndLabels)&&$(e,i,t.ticksAndLabels,l)}function U(e,i,t,l,s=i){const f={...A(s,i),...Object.hasOwn(t,"position")?{position:t.position}:{}},n=[],d=(c,o)=>{const r=t[c];r===!1?(m(e,i,c,l.operation,s),n.push({kind:"remove",component:c})):r!==void 0?n.push({kind:"edit",operation:o,args:{...f,...r}}):(t.position!==void 0||Object.hasOwn(t,"offset")||Object.hasOwn(t,"underlay"))&&_(e,i,c,s)&&n.push({kind:"edit",operation:o,args:f})};if(d("line",l.line),t.ticksAndLabels===!1?(m(e,i,"ticks",l.operation,s),m(e,i,"labels",l.operation,s),n.push({kind:"remove",component:"ticks"},{kind:"remove",component:"labels"})):t.ticksAndLabels!==void 0?n.push({kind:"edit",operation:l.group,args:{...f,...t.ticksAndLabels}}):(d("ticks",l.ticks),d("labels",l.labels)),d("title",l.title),n.length===0)throw new Error(`${l.operation} requires an existing ${i}-axis component.`);return n}function p(e,i,t,l,s=i){if(O(e.guideConfigs.axis?.[s]?.title?.offset)&&t.some(o=>o.kind==="edit"&&o.operation===l.title)&&e.context.pendingRelativeTitleAxis!==s)return N(e,s,o=>p(o,i,t,l,s));let n=e;const d=O(e.guideConfigs.axis?.[s]?.title?.offset)&&t.some(o=>o.kind==="remove"&&o.component==="title")?[...t.filter(o=>o.kind==="remove"&&o.component==="title"),...t.filter(o=>!(o.kind==="remove"&&o.component==="title"))]:t;for(let o=0;o<d.length;){const r=d[o];if(r.kind==="remove"){n=F(n,i,r.component,s),o+=1;continue}const b=[];for(;o<d.length&&d[o].kind==="edit";){const k=d[o++];b.push({op:k.operation,args:k.args})}n=g(n,b)}return!R.some(o=>n.graphicSpec.objects[W(i,o,s)]!==void 0)&&(n.semanticSpec.guides.axis?.[s]!==void 0||n.guideConfigs.axis?.[s]!==void 0)&&(n=n[l.remove](s===i?void 0:A(s,i))),n}function x(e){const i=K(e);return P({op:i.operation,description:`Edit selected existing ${e}-axis components.`},S(function(t={}){const l=L(t);t=l.args,Object.keys(t).some(o=>o!=="target")&&v(t,i.operation);const s=j(this,e,t,{whole:!0}),f=s.id;t=s.options,B(this,e,t,f);let n=T(this,"axis",f,l.visibility);if(!Object.keys(t).some(o=>o!=="target"))return Object.keys(l.visibility).length||v(t,i.operation),n;if(s.owner?.named&&t.position!==void 0){const o=E(e,t.position);y(this,{id:f,channel:e,coordinate:s.owner.coordinate,position:o}),n=n.editSemantic({property:`guide.axis.${f}.position`,value:o})}const d=h(n.guideConfigs.axis?.[f]?.frame,t);n=d===void 0?n._withoutMaterializationConfig(["guides","axis",f,"frame"]):n._withGuideConfig(f,"frame",d);const c=U(n,e,t,i,f);return p(n,e,c,i,f),p(n,e,c,i,f)}))}const J=x("x"),Q=x("y");function re(e){e.prototype.editXAxis=J,e.prototype.editYAxis=Q}export{re as registerCompleteAxisEditActions};
|