Major Changes
-
breaking(BrushContext|TransformContext): Rename
bind:brushContext/bind:transformContexttobind:state(#663)Both
BrushContextandTransformContextnow usebind:stateinstead of their previous named bindings. Additionally, properties onChartStatehave been renamed:chartContext.brushContext→chartContext.brushStatechartContext.transformContext→chartContext.transformState
<BrushContext bind:brushContext> <BrushContext bind:state> <TransformContext bind:transformContext> <TransformContext bind:state> -
breaking(TransformContext): Rename
domainExtent: 'original'todomainExtent: 'data'(#663)The
'original'value fordomainExtenthas been renamed to'data'to better describe that it constrains pan/zoom to the data's domain bounds:<Chart transform={{ domainExtent: 'original' }}> <Chart transform={{ domainExtent: 'data' }}> -
breaking(GeoContext): Rename
GeoContextcomponent toGeoProjection(#663)The
GeoContextcomponent has been renamed toGeoProjectionto better describe its purpose. Update your imports and template usage:import { GeoContext } from 'layerchart' import { GeoProjection } from 'layerchart'<GeoContext projection={geoAlbersUsa}> <GeoProjection projection={geoAlbersUsa}> -
breaking: Rename render context APIs to layer context (#663)
getRenderContext()→getLayerContext()setRenderContext()→setLayerContext()supportedContextsprop →layersprop on components- Internal
layout/directory moved tolayers/(affects deep imports)
import { getRenderContext } from 'layerchart' import { getLayerContext } from 'layerchart' -
breaking(Chart): Remove
isVerticalfrom ChartState, addvalueAxisprop toChart(#663)ChartState.isVerticalhas been removed in favor ofChartState.valueAxis('x'|'y'), which explicitly defines which axis represents the value (dependent variable).Simplified charts (
BarChart,LineChart,AreaChart,ScatterChart) still accept theorientationprop as before — each chart maps it to the correctvalueAxisinternally. The<Chart>component itself now usesvalueAxisdirectly, sinceorientationis ambiguous at that level (a "vertical" BarChart hasvalueAxis="y"while a "vertical" LineChart hasvalueAxis="x").When accessing chart state:
if (chartContext.isVertical) { ... } if (chartContext.valueAxis === 'y') { ... }When using
<Chart>directly (not simplified charts):<Chart ...> <Chart valueAxis="x" ...> -
breaking: Remove standalone context getter/setter functions (#663)
The following standalone context functions have been removed in favor of the unified
getChartContext()API:getTooltipContext()/setTooltipContext()→ usegetChartContext().tooltipgetBrushContext()/setBrushContext()→ usegetChartContext().brushStategetTransformContext()/setTransformContext()→ usegetChartContext().transformState
import { getTooltipContext } from 'layerchart' const tooltip = getTooltipContext() import { getChartContext } from 'layerchart' const chart = getChartContext() // access via chart.tooltip -
breaking(Arc|Pie|Calendar|GeoPath): Rename
tooltipContextto simpletooltip(boolean), simplifying use case (#663)
Minor Changes
-
feat: Add BoxPlot component for box-and-whisker plots (#663)
New composite mark that renders whiskers, caps, IQR box, median line, and outlier dots. Supports both pre-computed statistics (
min,q1,median,q3,max,outliersaccessors) and automatic computation from raw values via thevaluesprop. Orientation-aware viavalueAxiscontext. -
feat: Add statistical utility functions
computeBoxStats()andkde()(#663)computeBoxStats(values, k?)computes the five-number summary and outliers using the Tukey IQR methodkde(values, options?)computes kernel density estimation using the Epanechnikov kernel with Silverman's rule-of-thumb bandwidth
-
feat: Add Violin component for violin plots (#663)
New composite mark that renders a symmetric density curve (mirrored area) from raw data using kernel density estimation (Epanechnikov kernel). Supports pre-computed density data via
densityprop or automatic KDE from raw values viavaluesprop. Optionalboxandmedianoverlays. Configurablebandwidth,thresholds, andcurve. -
feat(Spline): Support geo projection (#663)
-
feat: Add geo projection support for primitives (Circle, Rect, etc) (#663)
-
feat(Highlight): Add
rprop to scale highlight points using the chart's rScale. Supportsr={true}to use the chart's r config or a custom accessor. (#663) -
breaking(Brush): Redesign brush API (#663)
Breaking changes:
- Remove
modeprop ('integrated' | 'separated') — sync behavior is now driven by presence ofx/yprops - Remove
resetOnEnd— calle.brush.reset()in youronBrushEndhandler instead - Remove
ignoreResetClick— replaced byclickToReset(defaulttrue) - Remove
onResetevent — checkbrush.active === falseinonBrushEnd/onChangeinstead
New features:
- Add
BrushState.move({ x?, y? })for programmatic selection control (like d3'sbrush.move()) - Add
BrushState.selectAll()to select the full domain extent - Add
BrushState.reset()to clear the selection - Add
clickToResetprop (defaulttrue) - Add
zoomOnBrushprop on Chart for simplified charts to opt into brush-to-zoom - Move domain clamping, edge adjustment, and range computation logic into
BrushStateclass - Add
BrushChartContextinterface for easier testing
- Remove
-
feat: Unified component tree for Canvas rendering with proper Group transform scoping. Fixes #662 (#663)
- New
registerComponentNode({ name, kind, canvasRender })API replaces bothregisterCanvasComponentand theInsideCompositeMarkboolean context with a single unified component tree. - Canvas rendering now walks the tree recursively with proper
save()/restore()scoping, fixing Group transforms (translate, opacity) leaking to sibling components instead of only affecting children. - Composite marks (Area, Threshold, Hull, Labels, Grid) register as
'composite-mark'nodes, automatically preventing child marks from registering with the chart without manual_skipRegistrationprops. - Removed
retainStateandnamefromComponentRendertype — Group's transform scoping is handled by tree position, and component names live on the tree node.
- New
-
feat: add
downloadImage,downloadSvg,getChartImageBlob, andgetChartSvgStringutilities to export charts as PNG/JPEG/WebP images or SVG files (#663) -
feat: Add Image component. Resolves #628 (#663)
-
feat(SeriesState): Support passing
selectedas part of series declaration (Ex.<Chart series={...}>) (#663) -
feat: Add data mode to primitive components (Circle, Ellipse, Group, Line, Polygon, Rect, Text) (#663)
Primitives now accept string or function accessors for positional props (e.g.
x="date",y={d => d.value}) to automatically resolve values through chart scales and iterate over data. Components also accept an optionaldataprop to override chart context data.Color properties (
fill,stroke) can also be data-driven, resolving per-item through the chart's color scale (cScale). String values are disambiguated: data property names resolve throughcScale, while literal CSS colors pass through unchanged. -
feat: Mark registration for automatic domain calculation, accessor aggregation, and implicit series (#663)
- Marks (Spline, Area, Points, Bars) now register their data, accessors, and colors with the Chart via
registerMark(). - Chart automatically aggregates y/x accessors from marks, removing the need to pass
y={['apples', 'oranges']}when each mark specifies its owny. Works for both horizontal (valueAxis='y') and vertical (valueAxis='x') charts. - Per-mark
dataprops are included in the chart's domain calculation automatically. - Implicit series are generated from mark registrations when no explicit
seriesprop is provided, enabling tooltip and legend support without requiring series definitions.
- Marks (Spline, Area, Points, Bars) now register their data, accessors, and colors with the Chart via
-
feat: Add inertia (momentum) support for transform drag gestures (#663)
-
feat: Add Cell mark. Resolves #627. (#663)
-
breaking(Chart): Rename
tooltipprop totooltipContextto better describe purpose and fix conflict with newtooltipsnippet (#663) -
feat: Add Chord layout and Ribbon primitive (#663)
-
breaking(TransformContext): Rename
initialScrollModetoscrollModeand make it reactive (#663) -
feat(TransformContext): Add
scrollActivationKeyoption to require a modifier key (meta, alt, control, shift) for scroll/wheel zoom/pan, preventing accidental page scroll from triggering transforms (#663) -
feat(Transform): Add zoom/pan constraints (
scaleExtent,translateExtent,constrain,domainExtent), replacegeo.applyTransformwithtransform.mode: 'projection' | 'rotate', and reactively sync initial transform values on projection changes (#663) -
feat(Bar): Support fixed
widthandheightprops to override scale-derived dimensions, centering the bar within its band. Resolves #360 (#663) -
feat: Auto-compute Bar/Bars mount animation initial values from chart scales (#663)
Bar now automatically derives
initialY/initialHeight(vertical) orinitialX/initialWidth(horizontal) from the chart's scale range whenmotionis configured, removing the need to hardcode pixel values.Also improves
valueAxisinference onChartState— when not explicitly set, it is now derived from scale types (band scale on y →valueAxis: 'x', band scale on x →valueAxis: 'y'). -
feat(Chart): Add cartesian pan/zoom via
transform={{ mode: 'domain' }}with single or both axis support. Resolves #366 (#663) -
feat(Spline): Add motion support for mount animation from baseline (#663)
-
feat: Support continuous color scales via
cScaleprop without requiringcRange(#663)- Allow
cScale(e.g.scaleSequential(interpolateTurbo)) to activate withoutcRange, enabling pre-configured sequential/diverging color scales - Guard
createScaleagainst undefinedrangeto avoid breaking interpolator-based scales - Auto-detect numeric
cDomainvalues and useextentinstead ofunique, producing correct[min, max]domains for continuous scales - Prefer
cScalecolor over default series color in tooltip/highlight when a color scale is configured
- Allow
-
feat(Labels): Support
seriesKeyinlabelsprop to filter which series renders labels. Resolves #633 (#663) -
feat(Rect): New edge-based props (
x0/x1/y0/y1) along with existing (x/y/width/height) andinsetssupport (#663) -
feat: Add Vector component (#663)
Patch Changes
-
fix(Area): Default y0 baseline to chart's yBaseline when set (#663)
Area's y0 fallback now respects the chart's
yBaselineprop (e.g.yBaseline={0}set by AreaChart) instead of always usingmin(yScale.domain()). This fixes areas filling to the bottom of the chart instead of to the baseline when data goes negative. -
fix(Points|Labels): Correctly position when using x1 / y1 scales (issue #773) (#663)
-
refactor(Chart): Add
debugprop and updatesettingscontext (#663) -
fix: Default chart padding now applied when using ChartChildren layout (marks snippet) (#663)
When
<Chart>is used withmarks/grid/axissnippets (no explicitchildrensnippet), default padding is now applied to match the axes that ChartChildren renders by default. Whenchildrenis provided directly (e.g. Treemap, Pack), no default padding is applied since the user controls layout. This can still be overridden with explicitaxisorpaddingprops. -
fix(Tooltip): Apply inverse transform for quadtree lookup when zoomed/panned (#663)
-
fix(Area): Handle degenerate domains (e.g. all-zero data) and unify y0/y1 baseline logic (#663)
- Guard against degenerate scale domains where min === max (e.g.
[0, 0]), which causedyScale()to returnNaNand break area path rendering - Unify Area y0/y1 path computation to consistently use accessors through the scale, removing duplicate fallback logic
- Guard against degenerate scale domains where min === max (e.g.
-
fix(BarChart): automatically round the outer edge of each direction in
stackDiverginglayout (#663) -
fix:
flattenPathDatanow handles relative arc commands, fixing rounded bars starting below the baseline during mount animation (#663) -
fix(Area|Highlight): Properly handling diveraging stack layouts for negative values (line, highlight point) (#663)
-
fix(Points|Labels): Correctly position when using array accessors (duration charts, etc). Fixes #633 (#663)
-
fix(TooltipContext): correct
bisect-bandhit detection by accounting for chart padding (#806) -
fix(ClipPath): Support canvas layers. Resolves #660 (#663)
-
feat(Chart): Support
motionprop to transition x/y scales using tween or spring (#663) -
fix(Canavs): support
strokeOpacityfor Path component (#663) -
fix(Text): handle inline styles and CSS class-based text-anchor (#663)
-
fix(Tooltip): Fade non-highlighted series items on hover to match chart highlight state (#663)
-
fix(TooltipContext): Support band mode with array-based range accessors (e.g. histograms using
x={['x0', 'x1']}) (#663)