Documentation

Core

DOM-free inspection. delta(), declaration edits and planning, identity, lineage and camera helpers.

Everything on this page is exported from visdelta/core (and from the visdelta root) and runs without a DOM.

delta()

function delta(from: Visualization, to: Visualization): DeltaResult;

Compares two states of the same chart type. Throws delta() requires two states of the same chart type. otherwise.

import { delta } from 'visdelta/core';

const change = delta(base, next);
change.stateChanges;          // normalized facts in seven categories
change.hasDelta('encoding.y'); // raw semantic check
change.edits;                 // lossless declaration edits
change.lineage;               // present when both states have inline data
FieldMeaning
stateChangesStateChange[]; see State changes
deltasRaw semantic differences
hasDelta(type, action?)Whether a raw difference of type exists
editsDeclarationEdit[] describing exact serialized differences
lineageLineageCorrespondence; see Identity

Grain entries in stateChanges include previous and next descriptions of their groupby and measures. See Types.

visualizationSpec()

function visualizationSpec(input: Visualization): ViewSpec;

Resolves a builder or plain spec into a detached view spec, with field types inferred from inline data.

Declaration edits

delta().edits describes exact changes to the serialized declaration. Each edit has a path, previous and next. Values distinguish absence from null, false and zero. Arrays, including ordered transform pipelines, are atomic.

import { applyDeclarationEdits, declarationEdits } from 'visdelta/core';

const edits = declarationEdits(base.toSpec(), next.toSpec());
const target = applyDeclarationEdits(base.toSpec(), edits); // detached copy

applyDeclarationEdits() rejects edits whose previous value no longer matches. Edits are declaration differences, not animation commands.

Declaration planning

function planDeclarationTransition(
  from: ViewSpec,
  to: ViewSpec,
  codec: DeclarationOperationCodec,
  options?: DeclarationPlanOptions,
): DeclarationPlan;

Searches for a route of complete, valid declarations in which each step inserts, removes or updates exactly one canonical operation. A chart-owned codec decides what the operations are: it decomposes a spec into operations, evaluates operations back into a spec, normalizes and validates it.

import { bar, createBarGrainDeclarationOperationCodec } from 'visdelta/bar';
import { planDeclarationTransition } from 'visdelta/core';

const from = bar(data).x('state').y('population').rollup().toSpec();
const to = bar(data).x('state').y('population').breakdown('age').toSpec();

const plan = planDeclarationTransition(from, to, createBarGrainDeclarationOperationCodec());
plan.status;                                   // 'planned'
plan.stages.map((stage) => stage.operation.id); // ['__visdeltaBarGrain/grouping']

Total → grouped detail + colour. Illustrative population values for demonstration only.

Preparing transition
0.00

From

const from = bar(rows).x('state', { label: 'State' })
  .y('population', { label: 'People (millions)' })
  .rollup({ label: 'People (millions)' });

To

const to = bar(rows).x('state', { label: 'State' })
  .y('population', { label: 'People (millions)' })
  .breakdown('age', { label: 'People (millions)' })
  .layout('grouped')
  .color('#3366ff');
Planner path · computing…
Waiting for the planner…
statusMeaning
plannedstages holds a validated route, one operation per stage
directThe canonical declarations are equivalent; no stage is needed
unsupportedNo valid route, or a state outside the codec; reason explains
search-limitThe search exceeded maxSearchStates (default 2048)

The search is bounded and deterministic. Every intermediate must pass the codec's validator and round-trip through its normalizer, and source data and datum identity are fixed boundaries. Unsupported results have an empty stages array; at runtime the chart then uses its own route or the ordinary direct transition. Built-in charts use this planner internally. Pie has no codec.

A codec may also constrain individual route edges with validateStep(from, to, endpoints). See the language framework for the complete contract.

Identity

resolveMarkIdentity(...)   // explicit .key() first, then the chart's default mark key
correspondMarks(...)       // one-to-one updates, enter and exit
markKeyValue(...)          // the string value of a mark key

These serve chart plugins. Lineage (below) describes split, merge and reaggregation separately.

Lineage

compileLineage(rows, transforms, { key?, grain? })
buildGroupingTree(table)
correspondLineage(from, to, { fromField?, toField? })
viewLineageCorrespondence(...)
lineageMarkKey(...)

At the low level, key identifies immutable source records and grain identifies marks in one compiled view. Filtering, sorting, limiting, binning, time units and folding preserve lineage. sum and count produce additive contribution records. mean, median and other non-additive aggregates keep provenance but mark arithmetic decomposition as unsafe.

Data types

detectDataTypes(rows)       // field → 'quantitative' | 'temporal' | 'nominal'
resolveEncodingTypes(...)   // fill missing channel types from data

Camera

fitCamera, focusCamera, cameraPosition, cameraScale, cameraSize, pointBounds and rectBounds implement the aspect-preserving camera used by .focus(). Chart plugins supply mark bounds; Core fits one pan and zoom.

On this page