Skip to content

createChart

Creates a new Velo Plot instance.

Signature

typescript
function createChart(options: ChartOptions): Chart

Options

PropertyTypeDefaultDescription
containerHTMLElementrequiredContainer element for the chart
idstringauto-generatedStable chart id for sync groups (chart.getId())
renderer'webgl' | 'webgpu' | 'svg''webgl'Chart renderer backend (see Renderer backend)
xAxisAxisOptions{ auto: true }X-axis configuration
yAxisAxisOptions{ auto: true }Y-axis configuration
themestring | ChartTheme'dark'Theme name or custom theme object
backgroundstringTheme defaultBackground color
showControlsbooleanfalseShow toolbar controls
showLegendbooleantrue (theme)Show series legend — defaults to theme.legend.visible
showStatisticsbooleanfalseEnable stats panel (requires StatsPlugin)
devicePixelRationumberwindow.devicePixelRatioPixel ratio for rendering
loadingboolean | LoadingConfigfalse (implicit)Show loading indicator — opt-in in v3 core
animationsboolean | AnimationConfigtrueEnable navigation animations
responsiveboolean | ResponsiveConfigtrueAuto-resize on container change
layoutLayoutOptionsdefaultsControl margins and axis title spacing

Bundle entry

Series types and chart methods depend on which entry you import. Core supports line/scatter/step/band/area; candlestick and trading APIs require velo-plot/trading. See Bundle Architecture and Trading Bundle.

Modular Architecture

From version 1.5.0, Velo Plot uses a modular plugin architecture. Advanced features (tooltips, analysis, annotations) must be loaded with chart.use(). In v3, bundle entry also determines built-in series and trading methods.

AxisOptions

typescript
interface AxisOptions {
  scale?: 'linear' | 'log'  // Scale type
  label?: string            // Axis label
  auto?: boolean            // Auto-scale to fit data
  min?: number              // Fixed minimum (if auto=false)
  max?: number              // Fixed maximum (if auto=false)
  invertAxis?: boolean      // Render the axis in descending order
}

Inverted Axes

Set invertAxis: true when a domain conventionally reads high-to-low. The data arrays stay in their natural order, but the rendered axis direction and interaction coordinates are reversed.

typescript
const chart = createChart({
  container: document.getElementById('chart'),
  xAxis: {
    label: 'Wavenumber (cm^-1)',
    auto: true,
    invertAxis: true,
  },
  yAxis: {
    label: 'Transmittance (%)',
    auto: true,
  },
})

Axis Label Spacing

Adjust the distance between the axis label and the plot border with layout settings:

typescript
const chart = createChart({
  container: document.getElementById('chart'),
  layout: {
    xAxisLayout: { titleGap: 48 },
    yAxisLayout: { titleGap: 24 },
  },
})

xAxisLayout.titleGap moves the X-axis label vertically. yAxisLayout.titleGap moves Y-axis labels horizontally.

By default, the X-axis label gap is 45 and the Y-axis label gap is 50.

Renderer backend

Velo Plot renders series with WebGL2 by default (NativeWebGLRenderer).

WebGPU (renderer: 'webgpu') requires an extended bundle import (velo-plot/trading, velo-plot/scientific, or velo-plot/full). On core-only imports, 'webgpu' is silently ignored — the chart stays on WebGL2.

SVG (renderer: 'svg') renders the chart as a live vector layer (same createChart API, pan/zoom, plugins, interactions). Requires an extended bundle entry so exportSVG is patched. Canvases are hidden; each frame rebuilds the SVG from the same export pipeline used by chart.exportSVG(). 3D series are not supported in SVG mode. Use showLegend: true for the interactive DOM legend (vector frame skips duplicate legend markup).

typescript
import { createChart } from 'velo-plot/trading'

const chart = createChart({
  container: document.getElementById('chart')!,
  renderer: 'webgl', // default — NativeWebGLRenderer
});

const webgpuChart = createChart({
  container: document.getElementById('chart')!,
  renderer: 'webgpu', // WebGPU when available, else WebGL2 fallback
});

const svgChart = createChart({
  container: document.getElementById('chart')!,
  renderer: 'svg', // live vector — extended bundle only
});

console.log(webgpuChart.getActiveRenderer()); // 'webgpu' | 'webgl'
console.log(svgChart.getActiveRenderer()); // 'svg'
ValueBehavior
'webgl'Native WebGL2 renderer (default). All series types for your bundle entry.
'webgpu'GpuChartRenderer when extended entry loaded. WebGL2 fallback if unavailable (ADR 001).
'svg'Live SVG vector renderer. Same chart API; no WebGL draw path. Extended bundle required. No 3D.

For WebGPU compute experiments (not chart rendering), use PluginGpu from velo-plot/plugins/gpu.

Returns

Returns a Chart instance with the following methods:

Series Management

typescript
chart.addSeries({
  id: 'my-series',
  type: 'line',           // 'line' | 'scatter' | 'line+scatter' | 'step' | 'area' | 'band' (+ extended types per bundle)
  data: { x, y },         // Float32Array or Float64Array
  style: { color: '#00f2ff', width: 2 },
})


// Update series data
chart.updateSeries('my-series', { x: newX, y: newY })

// Append data to existing series
chart.updateSeries('my-series', { x: newX, y: newY, append: true })

// Remove a series
chart.removeSeries('my-series')

// Get a series
const series = chart.getSeries('my-series')

// Get all series
const allSeries = chart.getAllSeries()

View Control

typescript
// Zoom to specific bounds
chart.zoom({ x: [0, 100], y: [-1, 1] })

// Pan by pixel delta
chart.pan(50, 0)  // Pan right 50px

// Safe fit — no-op when series have no valid bounds
chart.fit({ padding: { x: 0.02, y: 0.05 } })
chart.fit({ x: [t0, t1], y: [0, 100] })

// Reset to fit from data (calls fit(), not blind autoScale)
chart.resetZoom()

// Force auto-scale (legacy; prefer fit() for empty-safe behavior)
chart.autoScale()

// Stable id for ChartGroup / createMasterSlave
chart.getId()

// Current device pixel ratio
chart.getDPR()
chart.setDPR(window.devicePixelRatio)

// { xMin: 0, xMax: 100, yMin: -1, yMax: 1 }

// NOTE: autoScale() uses 0.5% padding. fit() uses 2% X / 5% Y padding by default.

fit()

Safe alternative to autoScale() that skips empty series:

typescript
interface FitOptions {
  x?: [number, number]     // explicit X range
  y?: [number, number]     // explicit Y range (primary axis)
  padding?: number | { x?: number; y?: number }  // default 2% X, 5% Y
  animate?: boolean
}

chart.fit()                              // fit from visible series
chart.fit({ x: [0, 1e6] })               // lock X, auto Y
chart.resetZoom()                        // equivalent to chart.fit()

Sharp rendering (HiDPI)

Charts can look blurry on Retina displays when canvas backing-store pixels are fractional. Velo Plot:

  • Rounds canvas dimensions to integer device pixels
  • Uses setTransform(dpr, …) instead of cumulative scale()
  • Re-reads window.devicePixelRatio on each resize (unless devicePixelRatio is fixed in options)
typescript
const chart = createChart({
  container,
  devicePixelRatio: window.devicePixelRatio, // recommended on HiDPI
})

Loading State

The loading overlay is opt-in in v3 core — pass loading: true in createChart options. Until the loading plugin is loaded, chart.loading is a no-op stub.

typescript
const chart = createChart({
  container,
  loading: true, // required in v3 core to show overlay
})

// Show with custom message
chart.loading.show("Processing large dataset...")

// Update progress (0-100)
chart.loading.setProgress(45)

// Hide manually
chart.loading.hide()

Cursor

typescript
// Enable crosshair cursor
chart.enableCursor({
  snap: true,           // Snap to nearest data point
  crosshair: true,      // Show crosshair lines
  formatter: (x, y) => `X: ${x.toFixed(2)}\nY: ${y.toFixed(2)}`,
})

// Disable cursor
chart.disableCursor()

Events

typescript
// Listen to render events (for FPS monitoring)
chart.on('render', ({ fps, frameTime }) => {
  console.log(`${fps} FPS, ${frameTime}ms per frame`)
})

// Listen to zoom events
chart.on('zoom', ({ x, y }) => {
  console.log(`View: X[${x[0]}, ${x[1]}], Y[${y[0]}, ${y[1]}]`)
})

// Listen to pan events
chart.on('pan', ({ deltaX, deltaY }) => {
  console.log(`Panned: ${deltaX}, ${deltaY}`)
})

// Remove listener
chart.off('render', handler)

Lifecycle

typescript
// Manually resize (usually automatic via ResizeObserver)
chart.resize(800, 600)

// Force a render
chart.render()

// Export as image (built-in raster — available on core)
const dataUrl = chart.exportImage('png')  // or 'jpeg'

// Export as SVG string (vector) — requires extended bundle
// import from 'velo-plot/trading', 'velo-plot/scientific', or 'velo-plot/full'
const svg = chart.exportSVG()  // throws on core-only import

// High-res / WebP / SVG download via plugin:
// chart.use(PluginSnapshot())
// await chart.snapshot.downloadSnapshot({ format: 'svg' })

// Use a plugin
chart.use(myPlugin)

// Clean up when done
chart.destroy()

Example

typescript
import { createChart } from 'velo-plot'

// Create chart
const chart = createChart({
  container: document.getElementById('chart'),
  xAxis: { label: 'Time (s)', auto: true },
  yAxis: { label: 'Amplitude', auto: true },
  theme: 'midnight',
  showControls: true,
  showLegend: true,
})

// Generate data
const n = 10000
const x = new Float32Array(n)
const y = new Float32Array(n)

for (let i = 0; i < n; i++) {
  x[i] = i / 100
  y[i] = Math.sin(x[i]) + Math.random() * 0.1
}

// Add series
chart.addSeries({
  id: 'signal',
  type: 'line',
  data: { x, y },
  style: { color: '#00f2ff', width: 1.5 },
})

// Enable cursor with custom formatting
chart.enableCursor({
  snap: true,
  crosshair: true,
  formatter: (xVal, yVal) => 
    `Time: ${xVal.toFixed(2)}s\nValue: ${yVal.toFixed(4)}`,
})

// Monitor performance
chart.on('render', ({ fps }) => {
  document.getElementById('fps').textContent = `${fps} FPS`
})

Themes

Built-in themes: 'dark', 'light', 'midnight', 'electrochemistry'

typescript
// Use built-in theme
const chart = createChart({
  container,
  theme: 'midnight',
})

// Use custom theme
import { createTheme } from 'velo-plot'

const myTheme = createTheme({
  name: 'custom',
  backgroundColor: '#1a1a2e',
  gridColor: 'rgba(255,255,255,0.1)',
  axisColor: '#888',
  // ... more options
})

const chart = createChart({
  container,
  theme: myTheme,
})

Known limitations

  • Series types and renderer: 'webgpu' depend on bundle entry — see Bundle Architecture.
  • Polar, gauge, and sankey series render on the Canvas 2D path when WebGPU is selected — they fall back to WebGL/Canvas automatically.
  • Default loading is off in v3 core — pass loading: true for the init overlay.

Released under the MIT License.