A powerful streaming data visualization library based on the Grammar of Graphics. Designed for real-time data visualization with support for time series, bar/column charts, single value metrics, and data tables.
Introduction Blog https://www.timeplus.com/post/vistral
Examples and Playground can be found here https://timeplus-io.github.io/vistral/
Concept Introduction https://timeplus-io.github.io/vistra-temporal-binding/
API Reference docs/api-reference.md
Design Principles docs/design-principles.md
- Features
- Installation
- Quick Start
- Chart Types
- Temporal Binding Modes
- Using Individual Chart Components
- Data Format
- Streaming Data with Hooks
- Color Palettes
- API Reference
- Design Principles
- Development
- Browser Support
- License
- 📊 Multiple Chart Types: Line, Area, Bar, Column, Single Value, Data Table, and Geo Map
- 🔄 Streaming Support: Built for real-time data with efficient updates
- ⏱️ Temporal Binding: Three modes for handling streaming data (axis-bound, frame-bound, key-bound)
- 🎨 Beautiful Themes: Dark and light themes with customizable color palettes
- 📱 Responsive: Auto-fit to container with resize detection
- 🎯 TypeScript: Full TypeScript support with comprehensive types
- ⚡ Performant: Optimized for streaming data with minimal re-renders
- đź§© Modular: Use the unified
StreamChartor individual chart components
npm install @timeplus/vistralVistral is available as a UMD bundle, allowing you to use it directly in the browser via script tags.
<!-- 1. Dependencies -->
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/lodash@4/lodash.min.js"></script>
<script src="https://unpkg.com/ramda@0.29/dist/ramda.min.js"></script>
<script src="https://unpkg.com/@antv/g2@5/dist/g2.min.js"></script>
<script src="https://unpkg.com/@antv/s2@2/dist/s2.min.js"></script>
<!-- 2. Vistral -->
<script src="https://unpkg.com/@timeplus/vistral/dist/index.umd.min.js"></script>
<!-- 3. Usage -->
<script>
const { Vistral, React, ReactDOM } = window;
const { StreamChart } = Vistral;
const data = {
columns: [{ name: 'val', type: 'number' }],
data: [{ val: 10 }, { val: 20 }]
};
const config = { chartType: 'table' };
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(React.createElement(StreamChart, { data, config }));
</script>Make sure you have React installed (if using NPM):
npm install react react-domimport { StreamChart } from '@timeplus/vistral';
function App() {
const data = {
columns: [
{ name: 'timestamp', type: 'datetime64' },
{ name: 'value', type: 'float64' },
{ name: 'category', type: 'string' },
],
data: [
['2024-01-01T10:00:00Z', 42.5, 'A'],
['2024-01-01T10:01:00Z', 45.2, 'A'],
['2024-01-01T10:02:00Z', 38.1, 'B'],
// ... more data
],
};
const config = {
chartType: 'line',
xAxis: 'timestamp',
yAxis: 'value',
color: 'category',
legend: true,
gridlines: true,
};
return (
<div style={{ width: '100%', height: '400px' }}>
<StreamChart config={config} data={data} theme="dark" />
</div>
);
}Perfect for time series data showing trends over time.
import { StreamChart } from '@timeplus/vistral';
<StreamChart
config={{
chartType: 'line',
xAxis: 'timestamp',
yAxis: 'value',
color: 'series',
lineStyle: 'curve', // or 'straight'
points: true,
legend: true,
gridlines: true,
temporal: {
mode: 'axis',
field: 'timestamp',
range: 5, // Show last 5 minutes
},
fractionDigits: 2,
}}
data={data}
theme="dark"
/>Similar to line charts but with filled areas, great for showing volume or stacked data.
<StreamChart
config={{
chartType: 'area',
xAxis: 'timestamp',
yAxis: 'value',
color: 'category', // Creates stacked areas
legend: true,
}}
data={data}
/>Horizontal bar charts for categorical comparisons.
<StreamChart
config={{
chartType: 'bar',
xAxis: 'category',
yAxis: 'value',
color: 'subcategory',
groupType: 'stack', // or 'dodge'
dataLabel: true,
}}
data={data}
/>Vertical column charts for categorical data.
<StreamChart
config={{
chartType: 'column',
xAxis: 'month',
yAxis: 'sales',
color: 'region',
groupType: 'dodge',
gridlines: true,
}}
data={data}
/>Display a single metric with optional sparkline and delta indicator.
<StreamChart
config={{
chartType: 'singleValue',
yAxis: 'activeUsers',
fontSize: 72,
color: 'green',
fractionDigits: 0,
sparkline: true,
delta: true,
unit: { position: 'left', value: '$' },
}}
data={data}
/>Display streaming data in a tabular format with column configuration.
<StreamChart
config={{
chartType: 'table',
tableStyles: {
timestamp: { name: 'Time', width: 200 },
value: {
name: 'Value',
miniChart: 'sparkline',
color: {
type: 'condition',
conditions: [
{ operator: 'gt', value: 100, color: '#22C55E' },
{ operator: 'lt', value: 50, color: '#EF4444' },
],
},
},
},
temporal: {
mode: 'key', // Deduplicate by key
field: 'id',
},
}}
data={data}
/>Display geographic data points on an interactive map with pan and zoom.
<StreamChart
config={{
chartType: 'geo',
latitude: 'lat',
longitude: 'lng',
color: 'category', // Color points by category
size: {
key: 'value', // Size points by value
min: 4,
max: 20,
},
zoom: 3,
center: [40.7128, -74.006], // [lat, lng]
showZoomControl: true,
showCenterDisplay: true,
pointOpacity: 0.8,
}}
data={data}
/>Vistral provides three temporal binding modes for handling streaming data:
| Mode | Description | Use Case |
|---|---|---|
| axis | Time mapped to axis with sliding window | Time-series trends |
| frame | Only latest timestamp visible | Real-time snapshots |
| key | Latest value per unique key | Live dashboards |
For time series charts, shows a sliding time window:
<StreamChart
config={{
chartType: 'line',
xAxis: 'timestamp',
yAxis: 'value',
temporal: {
mode: 'axis',
field: 'timestamp',
range: 5, // 5-minute window
},
}}
data={data}
/>Shows only rows with the latest timestamp - useful for real-time snapshots:
<StreamChart
config={{
chartType: 'table',
temporal: {
mode: 'frame',
field: 'timestamp',
},
}}
data={data}
/>Keeps the latest value for each unique key. Supports composite keys by passing an array of fields:
<StreamChart
config={{
chartType: 'geo',
latitude: 'lat',
longitude: 'lng',
temporal: {
mode: 'key',
field: ['region', 'vehicle_id'], // Composite key
},
}}
data={data}
/>For complex use cases not covered by StreamChart, you can use the lower-level VistralChart with a raw grammar specification, or the specialized SingleValueChart and DataTable components.
import {
VistralChart,
SingleValueChart,
DataTable
} from '@timeplus/vistral';
// Advanced: Use Grammar directly
<VistralChart spec={mySpec} source={data} />
// Specialized Components
<SingleValueChart config={config} data={data} theme="dark" />
<DataTable config={config} data={data} theme="dark" />interface StreamDataSource {
columns: ColumnDefinition[];
data: DataRow[];
isStreaming?: boolean;
}
interface ColumnDefinition {
name: string;
type: string; // 'string' | 'number' | 'datetime64' | 'float64' | etc.
nullable?: boolean;
}
// Data rows can be arrays or objects
type DataRow = unknown[] | Record<string, unknown>;const data = {
columns: [
{ name: 'time', type: 'datetime64' },
{ name: 'cpu', type: 'float64' },
{ name: 'memory', type: 'float64' },
],
data: [
[1704067200000, 45.2, 62.1],
[1704067260000, 48.1, 63.5],
[1704067320000, 42.8, 61.2],
],
};const data = {
columns: [
{ name: 'time', type: 'datetime64' },
{ name: 'cpu', type: 'float64' },
],
data: [
{ time: '2024-01-01T10:00:00Z', cpu: 45.2 },
{ time: '2024-01-01T10:01:00Z', cpu: 48.1 },
],
};Use the provided hooks for managing streaming data:
import { StreamChart, useStreamingData } from '@timeplus/vistral';
function LiveChart() {
const { data, append, clear } = useStreamingData([], 1000); // Max 1000 items
useEffect(() => {
const ws = new WebSocket('ws://your-streaming-endpoint');
ws.onmessage = (event) => {
const newData = JSON.parse(event.data);
append(newData);
};
return () => ws.close();
}, [append]);
return (
<StreamChart
config={config}
data={{
columns: [...],
data: data,
isStreaming: true,
}}
/>
);
}import {
multiColorPalettes,
singleColorPalettes,
findPaletteByLabel
} from '@timeplus/vistral';
// Multi-color palettes for categorical data
// Available: 'Dawn', 'Morning', 'Midnight', 'Ocean', 'Sunset'
// Single-color palettes for sequential data
// Available: 'red', 'pink', 'purple', 'blue', 'green', 'orange', 'yellow', 'cyan', 'gray'
// Use by label
const palette = findPaletteByLabel('Dawn');
// Apply to chart
<StreamChart
config={{
chartType: 'line',
xAxis: 'time',
yAxis: 'value',
colors: palette.values,
}}
data={data}
/><StreamChart
config={{
chartType: 'line',
xAxis: 'time',
yAxis: 'value',
colors: ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7'],
}}
data={data}
/>For detailed API documentation including configuration options for all chart types, hooks, and utilities, see the API Reference.
- Node.js >= 16
- npm, yarn, or pnpm
# Clone the repository
git clone https://github.com/timeplus-io/vistral.git
cd vistral
# Install dependencies
npm install| Command | Description |
|---|---|
npm run build |
Build the library (CommonJS + ESM + TypeScript declarations) |
npm run dev |
Start development mode with watch (library rebuild) |
npm run dev:examples |
Start Vite dev server to view examples at http://localhost:3000 |
npm run test |
Run tests with Vitest |
npm run test:coverage |
Run tests with coverage report |
npm run lint |
Run ESLint |
npm run typecheck |
Run TypeScript type checking |
To view the interactive examples during development:
# Install dependencies first
npm install
# Start the examples dev server
npm run dev:examplesThis will open http://localhost:3000 with a sidebar navigation showing all available chart examples.
Built with:
- AntV G2 - Visualization grammar
- React - UI framework
- TypeScript - Type safety
Developed by Timeplus







