DOM rendering
Use @sectile/dom/chart when your application owns the HTML and does not need Vue components. It measures the chart container, draws into a Canvas element, updates when the container size changes, and adds the elements needed for keyboard and screen-reader access.
Orders by region
Compare category magnitudes from a common baseline.
- Hovered datum
- None
- Selected datum
- None
// HTML: <div data-chart><canvas></canvas></div>
// Give the container a height and make the canvas fill it with CSS.
import { createChartController } from '@sectile/chart/controller'
import { createDOMChart } from '@sectile/dom/chart'
const orders = [
{ id: 'seoul', region: 'Seoul', orders: 812 },
{ id: 'busan', region: 'Busan', orders: 594 },
{ id: 'daegu', region: 'Daegu', orders: 436 },
{ id: 'incheon', region: 'Incheon', orders: 521 },
]
const datumLabels = new Map(orders.map(order => [order.id, order.region]))
const definition = {
coordinate: { kind: 'cartesian', axes: [
{ id: 'x', orientation: 'x', scale: 'categorical', field: 'region', label: 'Region' },
{ id: 'y', orientation: 'y', scale: 'linear', field: 'orders', label: 'Order volume', unit: 'orders' },
] },
layers: [{
kind: 'bar', id: 'regional-orders', data: orders,
xAxis: 'x', yAxis: 'y', label: 'Orders',
}],
} as const
const root = document.querySelector('[data-chart]')
const canvas = root?.querySelector('canvas')
if (!(root instanceof HTMLElement) || !(canvas instanceof HTMLCanvasElement)) {
throw new Error('Chart container is missing')
}
const controller = createChartController({
definition,
viewCapabilities: [{ axisID: 'x', minimumSpan: 1 }],
})
const chart = createDOMChart({
root,
canvas,
controller,
renderer: 'auto',
accessibilityLabel: 'Orders by region',
getAccessibleDatumLabel: id => datumLabels.get(String(id)) ?? String(id),
navigation: { wheel: 'native', keyboard: true },
})
window.addEventListener('pagehide', () => {
chart.disconnect()
controller.dispose()
}, { once: true })Install
pnpm add @sectile/chart @sectile/domConnect existing elements
Start with the definition and revenue records from Data and scales. The container needs an explicit height; the Canvas can then fill it.
<div data-chart>
<canvas></canvas>
</div>[data-chart] {
position: relative;
height: 24rem;
}
[data-chart] canvas {
display: block;
width: 100%;
height: 100%;
}import { createChartController } from '@sectile/chart/controller'
import { createDOMChart } from '@sectile/dom/chart'
const root = document.querySelector('[data-chart]')
const canvas = root?.querySelector('canvas')
if (!(root instanceof HTMLElement) || !(canvas instanceof HTMLCanvasElement)) {
throw new Error('Chart container is missing')
}
const controller = createChartController({
definition,
viewCapabilities: [{ axisID: 'date', minimumSpan: 86_400_000 }],
})
const revenueLabels = new Map(revenue.map(point => [
point.id,
`${point.date.toLocaleDateString()}: ${point.amount.toLocaleString()}`,
]))
const chart = createDOMChart({
root,
canvas,
controller,
renderer: 'auto',
accessibilityLabel: 'Weekly revenue',
getAccessibleDatumLabel: id => revenueLabels.get(id) ?? String(id),
navigation: { wheel: 'native', keyboard: true },
})
window.addEventListener('pagehide', () => {
chart.disconnect()
controller.dispose()
}, { once: true })In a single-page application, run the same two cleanup calls when the route or owning component unmounts instead of waiting for pagehide.
Choose a renderer
auto uses WebGL2 when available and falls back to Canvas2D. It is the right default for most applications. Choose canvas2d when diagnosing compatibility, or webgl2 when the application must fail instead of using the slower fallback.
import { createChartRenderer } from '@sectile/dom/chart'
const renderer = createChartRenderer(canvas, {
mode: 'auto',
style: {
color: [0.18, 0.42, 0.86, 1],
pointRadius: 4,
lineWidth: 2,
},
})Pass this renderer object as the renderer option of createDOMChart. Because your code created it, your code must also call renderer.disconnect(). When you pass the string 'auto', 'canvas2d', or 'webgl2' instead, the chart connection creates and cleans up the renderer.
Keep page input predictable
By default, the chart leaves wheel scrolling to the page and disables drag, pinch, and keyboard navigation. Enable only the inputs the chart needs. Drag or pinch also requires controlAlternative: 'built-in' or 'external', which ensures the same action is available through visible controls.
Limit drawing work per frame
renderPolicy: {
type: 'adaptive',
minimumRenderScale: 0.5,
maximumRenderScale: 1,
frameBudgetMs: 12,
maximumRepresentatives: 100_000,
}The item limit follows the detail rules in Large datasets. Adaptive rendering may lower Canvas resolution to meet the frame budget, but it does not change values, IDs, selection, or visible axis ranges.
Clean up
chart.disconnect()
controller.dispose()
renderer.disconnect() // only for an application-owned rendererchart.disconnect() removes event listeners and resize observers, cancels pending frames, removes accessibility elements, and releases graphics resources created by the connection. Calling it more than once is safe.
