Domphy

@domphy/chart vs ECharts

Series coverage

Series@domphy/chartECharts
Line / Area
Bar (grouped, stacked, horizontal)
Scatter / Bubble
Pie / Donut / Rose
Radar / Spider
Heatmap (cartesian)
Heatmap (calendar)
Candlestick / OHLC
Boxplot / Whisker
Gauge
Treemap
Funnel
Sankey
Graph / Network
Parallel coordinates
ThemeRiver / Stream
Map / Choropleth
Custom render
scatter3D / bar3D / line3DECharts GL
surface3D✓ (SVG)ECharts GL (WebGL mesh)
Calendar coordinate
Geo coordinate
Polar coordinatetyped only (not rendered)
ThemeRiver (multi-series)
Lines (flow map)✓ (SVG + animateMotion)
EffectScatter✓ (SVG ripple animation)
PictorialBar✓ (SVG symbol repeat/clip)

Architecture

@domphy/chartECharts
RendererWebGL (luma.gl) for hot series + SVG overlay for everything elseCanvas (default) or SVG mode — no mixed mode
3DSVG perspective projection (built-in, no extra package)ECharts GL (separate npm package, WebGL)
FrameworkDomphy patch — integrates into element treeStandalone (echarts.init(dom))
ReactivityPass State<ChartOption> — auto re-renders on changeCall setOption() manually
SSRWorks with @domphy/app renderToStringPartial (SVG mode only)
Shadow DOM✓ (SVG output, no canvas clipping issues)Canvas has shadow DOM issues

Color system

This is the biggest architectural difference.

ECharts hardcodes palette hex values:

// ECharts default — breaks in dark mode, no contrast guarantee
color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', ...]

@domphy/chart uses theme families that resolve at render time:

// Adapts to any dataTone context, WCAG 4.5:1 guaranteed
series: [
  { type: "line", color: "primary" },    // resolves via themeColor()
  { type: "bar",  color: "secondary" },  // follows dataTone cascade of parent
]

Set dataTone="shift-11" on the chart container → all series colors invert automatically. Zero manual dark-mode config.

Spacing / density cascade

@domphy/chartECharts
Axis label paddingthemeSpacing(density * n)Fixed px
Tick densitycascade from dataDensityFixed
Legend gapcascadeFixed
Compact modedataDensity="decrease-1" on parentNo built-in

Components

Component@domphy/chartECharts
Title
Legend (plain/scroll)
Tooltip (axis/item)✓ (Domphy element or string)✓ (HTML or richText)
DataZoom (slider/inside)
VisualMap (continuous/piecewise)
Brush✓ (option type)
Toolbox✓ (option type)
Mark point/line/area
Dataset + transforms
Axis pointer
Geo roam (interactive pan/zoom)static (zoom/center only)

Bundle size

@domphy/chartECharts (tree-shaken)ECharts (full)
Core~120 KB~400 KB~1 MB
3Dbuilt-in (SVG, 0 extra)+ECharts GL ~800 KB
Peer deps@domphy/core, @domphy/themenonenone

Migration from ECharts

The ChartOption interface is intentionally ECharts-compatible. Most options migrate without changes:

// ECharts
echarts.init(document.getElementById("chart")).setOption({
  xAxis: { type: "category", data: ["Mon","Tue","Wed"] },
  yAxis: { type: "value" },
  series: [{ type: "bar", data: [120, 200, 150] }],
})

// @domphy/chart — same option object, different mount
import { chart } from "@domphy/chart"
const App = {
  div: null,
  style: { width: "600px", height: "300px" },
  $: [chart({
    xAxis: { type: "category", data: ["Mon","Tue","Wed"] },
    yAxis: { type: "value" },
    series: [{ type: "bar", data: [120, 200, 150] }],
  })],
}

Key differences when migrating:

  • color in series takes a ThemeFamily string ("primary") not a hex — drop hex colors and let the theme system assign them, or keep hex in itemStyle.color
  • No echarts.init() — use the chart() patch directly
  • No setOption() — pass a State<ChartOption> for reactive updates
  • tooltip.formatter can return a DomphyElement (plain object) in addition to a string