@timeplus/vistral 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +530 -0
- package/dist/index.d.ts +999 -0
- package/dist/index.esm.js +4774 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +4850 -0
- package/dist/index.js.map +1 -0
- package/package.json +82 -0
package/README.md
ADDED
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
# @timeplus/vistral
|
|
2
|
+
|
|
3
|
+
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.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Features](#features)
|
|
8
|
+
- [Installation](#installation)
|
|
9
|
+
- [Quick Start](#quick-start)
|
|
10
|
+
- [Chart Types](#chart-types)
|
|
11
|
+
- [Line Chart](#line-chart)
|
|
12
|
+
- [Area Chart](#area-chart)
|
|
13
|
+
- [Bar Chart](#bar-chart-horizontal)
|
|
14
|
+
- [Column Chart](#column-chart-vertical)
|
|
15
|
+
- [Single Value](#single-value)
|
|
16
|
+
- [Data Table](#data-table)
|
|
17
|
+
- [Geo Chart](#geo-chart)
|
|
18
|
+
- [Temporal Binding Modes](#temporal-binding-modes)
|
|
19
|
+
- [Using Individual Chart Components](#using-individual-chart-components)
|
|
20
|
+
- [Data Format](#data-format)
|
|
21
|
+
- [Streaming Data with Hooks](#streaming-data-with-hooks)
|
|
22
|
+
- [Color Palettes](#color-palettes)
|
|
23
|
+
- [API Reference](./docs/api-reference.md)
|
|
24
|
+
- [Development](#development)
|
|
25
|
+
- [Browser Support](#browser-support)
|
|
26
|
+
- [License](#license)
|
|
27
|
+
|
|
28
|
+
## Features
|
|
29
|
+
|
|
30
|
+
- 📊 **Multiple Chart Types**: Line, Area, Bar, Column, Single Value, Data Table, and Geo Map
|
|
31
|
+
- 🔄 **Streaming Support**: Built for real-time data with efficient updates
|
|
32
|
+
- ⏱️ **Temporal Binding**: Three modes for handling streaming data (axis-bound, frame-bound, key-bound)
|
|
33
|
+
- 🎨 **Beautiful Themes**: Dark and light themes with customizable color palettes
|
|
34
|
+
- 📱 **Responsive**: Auto-fit to container with resize detection
|
|
35
|
+
- 🎯 **TypeScript**: Full TypeScript support with comprehensive types
|
|
36
|
+
- ⚡ **Performant**: Optimized for streaming data with minimal re-renders
|
|
37
|
+
- 🧩 **Modular**: Use the unified `StreamChart` or individual chart components
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install @timeplus/vistral
|
|
43
|
+
|
|
44
|
+
# or with yarn
|
|
45
|
+
yarn add @timeplus/vistral
|
|
46
|
+
|
|
47
|
+
# or with pnpm
|
|
48
|
+
pnpm add @timeplus/vistral
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Peer Dependencies
|
|
52
|
+
|
|
53
|
+
Make sure you have React installed:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install react react-dom
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Quick Start
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
import { StreamChart } from '@timeplus/vistral';
|
|
63
|
+
|
|
64
|
+
function App() {
|
|
65
|
+
const data = {
|
|
66
|
+
columns: [
|
|
67
|
+
{ name: 'timestamp', type: 'datetime64' },
|
|
68
|
+
{ name: 'value', type: 'float64' },
|
|
69
|
+
{ name: 'category', type: 'string' },
|
|
70
|
+
],
|
|
71
|
+
data: [
|
|
72
|
+
['2024-01-01T10:00:00Z', 42.5, 'A'],
|
|
73
|
+
['2024-01-01T10:01:00Z', 45.2, 'A'],
|
|
74
|
+
['2024-01-01T10:02:00Z', 38.1, 'B'],
|
|
75
|
+
// ... more data
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const config = {
|
|
80
|
+
chartType: 'line',
|
|
81
|
+
xAxis: 'timestamp',
|
|
82
|
+
yAxis: 'value',
|
|
83
|
+
color: 'category',
|
|
84
|
+
legend: true,
|
|
85
|
+
gridlines: true,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div style={{ width: '100%', height: '400px' }}>
|
|
90
|
+
<StreamChart config={config} data={data} theme="dark" />
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Chart Types
|
|
97
|
+
|
|
98
|
+
### Line Chart
|
|
99
|
+
|
|
100
|
+
Perfect for time series data showing trends over time.
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
import { StreamChart } from '@timeplus/vistral';
|
|
104
|
+
|
|
105
|
+
<StreamChart
|
|
106
|
+
config={{
|
|
107
|
+
chartType: 'line',
|
|
108
|
+
xAxis: 'timestamp',
|
|
109
|
+
yAxis: 'value',
|
|
110
|
+
color: 'series',
|
|
111
|
+
lineStyle: 'curve', // or 'straight'
|
|
112
|
+
points: true,
|
|
113
|
+
legend: true,
|
|
114
|
+
gridlines: true,
|
|
115
|
+
temporal: {
|
|
116
|
+
mode: 'axis',
|
|
117
|
+
field: 'timestamp',
|
|
118
|
+
range: 5, // Show last 5 minutes
|
|
119
|
+
},
|
|
120
|
+
fractionDigits: 2,
|
|
121
|
+
}}
|
|
122
|
+
data={data}
|
|
123
|
+
theme="dark"
|
|
124
|
+
/>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Area Chart
|
|
128
|
+
|
|
129
|
+
Similar to line charts but with filled areas, great for showing volume or stacked data.
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
<StreamChart
|
|
133
|
+
config={{
|
|
134
|
+
chartType: 'area',
|
|
135
|
+
xAxis: 'timestamp',
|
|
136
|
+
yAxis: 'value',
|
|
137
|
+
color: 'category', // Creates stacked areas
|
|
138
|
+
legend: true,
|
|
139
|
+
}}
|
|
140
|
+
data={data}
|
|
141
|
+
/>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Bar Chart (Horizontal)
|
|
145
|
+
|
|
146
|
+
Horizontal bar charts for categorical comparisons.
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
<StreamChart
|
|
150
|
+
config={{
|
|
151
|
+
chartType: 'bar',
|
|
152
|
+
xAxis: 'category',
|
|
153
|
+
yAxis: 'value',
|
|
154
|
+
color: 'subcategory',
|
|
155
|
+
groupType: 'stack', // or 'dodge'
|
|
156
|
+
dataLabel: true,
|
|
157
|
+
}}
|
|
158
|
+
data={data}
|
|
159
|
+
/>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Column Chart (Vertical)
|
|
163
|
+
|
|
164
|
+
Vertical column charts for categorical data.
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
<StreamChart
|
|
168
|
+
config={{
|
|
169
|
+
chartType: 'column',
|
|
170
|
+
xAxis: 'month',
|
|
171
|
+
yAxis: 'sales',
|
|
172
|
+
color: 'region',
|
|
173
|
+
groupType: 'dodge',
|
|
174
|
+
gridlines: true,
|
|
175
|
+
}}
|
|
176
|
+
data={data}
|
|
177
|
+
/>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Single Value
|
|
181
|
+
|
|
182
|
+
Display a single metric with optional sparkline and delta indicator.
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
<StreamChart
|
|
186
|
+
config={{
|
|
187
|
+
chartType: 'singleValue',
|
|
188
|
+
yAxis: 'activeUsers',
|
|
189
|
+
fontSize: 72,
|
|
190
|
+
color: 'green',
|
|
191
|
+
fractionDigits: 0,
|
|
192
|
+
sparkline: true,
|
|
193
|
+
delta: true,
|
|
194
|
+
unit: { position: 'left', value: '$' },
|
|
195
|
+
}}
|
|
196
|
+
data={data}
|
|
197
|
+
/>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Data Table
|
|
201
|
+
|
|
202
|
+
Display streaming data in a tabular format with column configuration.
|
|
203
|
+
|
|
204
|
+
```tsx
|
|
205
|
+
<StreamChart
|
|
206
|
+
config={{
|
|
207
|
+
chartType: 'table',
|
|
208
|
+
tableStyles: {
|
|
209
|
+
timestamp: { name: 'Time', width: 200 },
|
|
210
|
+
value: {
|
|
211
|
+
name: 'Value',
|
|
212
|
+
miniChart: 'sparkline',
|
|
213
|
+
color: {
|
|
214
|
+
type: 'condition',
|
|
215
|
+
conditions: [
|
|
216
|
+
{ operator: 'gt', value: 100, color: '#22C55E' },
|
|
217
|
+
{ operator: 'lt', value: 50, color: '#EF4444' },
|
|
218
|
+
],
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
temporal: {
|
|
223
|
+
mode: 'key', // Deduplicate by key
|
|
224
|
+
field: 'id',
|
|
225
|
+
},
|
|
226
|
+
}}
|
|
227
|
+
data={data}
|
|
228
|
+
/>
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Geo Chart
|
|
232
|
+
|
|
233
|
+
Display geographic data points on an interactive map with pan and zoom.
|
|
234
|
+
|
|
235
|
+
```tsx
|
|
236
|
+
<StreamChart
|
|
237
|
+
config={{
|
|
238
|
+
chartType: 'geo',
|
|
239
|
+
latitude: 'lat',
|
|
240
|
+
longitude: 'lng',
|
|
241
|
+
color: 'category', // Color points by category
|
|
242
|
+
size: {
|
|
243
|
+
key: 'value', // Size points by value
|
|
244
|
+
min: 4,
|
|
245
|
+
max: 20,
|
|
246
|
+
},
|
|
247
|
+
zoom: 3,
|
|
248
|
+
center: [40.7128, -74.006], // [lat, lng]
|
|
249
|
+
showZoomControl: true,
|
|
250
|
+
showCenterDisplay: true,
|
|
251
|
+
pointOpacity: 0.8,
|
|
252
|
+
}}
|
|
253
|
+
data={data}
|
|
254
|
+
/>
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Temporal Binding Modes
|
|
258
|
+
|
|
259
|
+
Vistral provides three temporal binding modes for handling streaming data:
|
|
260
|
+
|
|
261
|
+
| Mode | Description | Use Case |
|
|
262
|
+
|------|-------------|----------|
|
|
263
|
+
| **axis** | Time mapped to axis with sliding window | Time-series trends |
|
|
264
|
+
| **frame** | Only latest timestamp visible | Real-time snapshots |
|
|
265
|
+
| **key** | Latest value per unique key | Live dashboards |
|
|
266
|
+
|
|
267
|
+
### Axis-Bound (Sliding Window)
|
|
268
|
+
|
|
269
|
+
For time series charts, shows a sliding time window:
|
|
270
|
+
|
|
271
|
+
```tsx
|
|
272
|
+
<StreamChart
|
|
273
|
+
config={{
|
|
274
|
+
chartType: 'line',
|
|
275
|
+
xAxis: 'timestamp',
|
|
276
|
+
yAxis: 'value',
|
|
277
|
+
temporal: {
|
|
278
|
+
mode: 'axis',
|
|
279
|
+
field: 'timestamp',
|
|
280
|
+
range: 5, // 5-minute window
|
|
281
|
+
},
|
|
282
|
+
}}
|
|
283
|
+
data={data}
|
|
284
|
+
/>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Frame-Bound (Latest Timestamp)
|
|
288
|
+
|
|
289
|
+
Shows only rows with the latest timestamp - useful for real-time snapshots:
|
|
290
|
+
|
|
291
|
+
```tsx
|
|
292
|
+
<StreamChart
|
|
293
|
+
config={{
|
|
294
|
+
chartType: 'table',
|
|
295
|
+
temporal: {
|
|
296
|
+
mode: 'frame',
|
|
297
|
+
field: 'timestamp',
|
|
298
|
+
},
|
|
299
|
+
}}
|
|
300
|
+
data={data}
|
|
301
|
+
/>
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Key-Bound (Deduplicate by Key)
|
|
305
|
+
|
|
306
|
+
Keeps the latest value for each unique key. Supports **composite keys** by passing an array of fields:
|
|
307
|
+
|
|
308
|
+
```tsx
|
|
309
|
+
<StreamChart
|
|
310
|
+
config={{
|
|
311
|
+
chartType: 'geo',
|
|
312
|
+
latitude: 'lat',
|
|
313
|
+
longitude: 'lng',
|
|
314
|
+
temporal: {
|
|
315
|
+
mode: 'key',
|
|
316
|
+
field: ['region', 'vehicle_id'], // Composite key
|
|
317
|
+
},
|
|
318
|
+
}}
|
|
319
|
+
data={data}
|
|
320
|
+
/>
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Using Individual Chart Components
|
|
324
|
+
|
|
325
|
+
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.
|
|
326
|
+
|
|
327
|
+
```tsx
|
|
328
|
+
import {
|
|
329
|
+
VistralChart,
|
|
330
|
+
SingleValueChart,
|
|
331
|
+
DataTable
|
|
332
|
+
} from '@timeplus/vistral';
|
|
333
|
+
|
|
334
|
+
// Advanced: Use Grammar directly
|
|
335
|
+
<VistralChart spec={mySpec} source={data} />
|
|
336
|
+
|
|
337
|
+
// Specialized Components
|
|
338
|
+
<SingleValueChart config={config} data={data} theme="dark" />
|
|
339
|
+
<DataTable config={config} data={data} theme="dark" />
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Data Format
|
|
343
|
+
|
|
344
|
+
### StreamDataSource
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
interface StreamDataSource {
|
|
348
|
+
columns: ColumnDefinition[];
|
|
349
|
+
data: DataRow[];
|
|
350
|
+
isStreaming?: boolean;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
interface ColumnDefinition {
|
|
354
|
+
name: string;
|
|
355
|
+
type: string; // 'string' | 'number' | 'datetime64' | 'float64' | etc.
|
|
356
|
+
nullable?: boolean;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Data rows can be arrays or objects
|
|
360
|
+
type DataRow = unknown[] | Record<string, unknown>;
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Example with Array Format
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
const data = {
|
|
367
|
+
columns: [
|
|
368
|
+
{ name: 'time', type: 'datetime64' },
|
|
369
|
+
{ name: 'cpu', type: 'float64' },
|
|
370
|
+
{ name: 'memory', type: 'float64' },
|
|
371
|
+
],
|
|
372
|
+
data: [
|
|
373
|
+
[1704067200000, 45.2, 62.1],
|
|
374
|
+
[1704067260000, 48.1, 63.5],
|
|
375
|
+
[1704067320000, 42.8, 61.2],
|
|
376
|
+
],
|
|
377
|
+
};
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### Example with Object Format
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
const data = {
|
|
384
|
+
columns: [
|
|
385
|
+
{ name: 'time', type: 'datetime64' },
|
|
386
|
+
{ name: 'cpu', type: 'float64' },
|
|
387
|
+
],
|
|
388
|
+
data: [
|
|
389
|
+
{ time: '2024-01-01T10:00:00Z', cpu: 45.2 },
|
|
390
|
+
{ time: '2024-01-01T10:01:00Z', cpu: 48.1 },
|
|
391
|
+
],
|
|
392
|
+
};
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## Streaming Data with Hooks
|
|
396
|
+
|
|
397
|
+
Use the provided hooks for managing streaming data:
|
|
398
|
+
|
|
399
|
+
```tsx
|
|
400
|
+
import { StreamChart, useStreamingData } from '@timeplus/vistral';
|
|
401
|
+
|
|
402
|
+
function LiveChart() {
|
|
403
|
+
const { data, append, clear } = useStreamingData([], 1000); // Max 1000 items
|
|
404
|
+
|
|
405
|
+
useEffect(() => {
|
|
406
|
+
const ws = new WebSocket('ws://your-streaming-endpoint');
|
|
407
|
+
|
|
408
|
+
ws.onmessage = (event) => {
|
|
409
|
+
const newData = JSON.parse(event.data);
|
|
410
|
+
append(newData);
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
return () => ws.close();
|
|
414
|
+
}, [append]);
|
|
415
|
+
|
|
416
|
+
return (
|
|
417
|
+
<StreamChart
|
|
418
|
+
config={config}
|
|
419
|
+
data={{
|
|
420
|
+
columns: [...],
|
|
421
|
+
data: data,
|
|
422
|
+
isStreaming: true,
|
|
423
|
+
}}
|
|
424
|
+
/>
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Color Palettes
|
|
430
|
+
|
|
431
|
+
### Built-in Palettes
|
|
432
|
+
|
|
433
|
+
```tsx
|
|
434
|
+
import {
|
|
435
|
+
multiColorPalettes,
|
|
436
|
+
singleColorPalettes,
|
|
437
|
+
findPaletteByLabel
|
|
438
|
+
} from '@timeplus/vistral';
|
|
439
|
+
|
|
440
|
+
// Multi-color palettes for categorical data
|
|
441
|
+
// Available: 'Dawn', 'Morning', 'Midnight', 'Ocean', 'Sunset'
|
|
442
|
+
|
|
443
|
+
// Single-color palettes for sequential data
|
|
444
|
+
// Available: 'red', 'pink', 'purple', 'blue', 'green', 'orange', 'yellow', 'cyan', 'gray'
|
|
445
|
+
|
|
446
|
+
// Use by label
|
|
447
|
+
const palette = findPaletteByLabel('Dawn');
|
|
448
|
+
|
|
449
|
+
// Apply to chart
|
|
450
|
+
<StreamChart
|
|
451
|
+
config={{
|
|
452
|
+
chartType: 'line',
|
|
453
|
+
xAxis: 'time',
|
|
454
|
+
yAxis: 'value',
|
|
455
|
+
colors: palette.values,
|
|
456
|
+
}}
|
|
457
|
+
data={data}
|
|
458
|
+
/>
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### Custom Colors
|
|
462
|
+
|
|
463
|
+
```tsx
|
|
464
|
+
<StreamChart
|
|
465
|
+
config={{
|
|
466
|
+
chartType: 'line',
|
|
467
|
+
xAxis: 'time',
|
|
468
|
+
yAxis: 'value',
|
|
469
|
+
colors: ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7'],
|
|
470
|
+
}}
|
|
471
|
+
data={data}
|
|
472
|
+
/>
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
## API Reference
|
|
476
|
+
|
|
477
|
+
For detailed API documentation including configuration options for all chart types, hooks, and utilities, see the [API Reference](./docs/api-reference.md).
|
|
478
|
+
|
|
479
|
+
## Development
|
|
480
|
+
|
|
481
|
+
### Prerequisites
|
|
482
|
+
|
|
483
|
+
- Node.js >= 16
|
|
484
|
+
- npm, yarn, or pnpm
|
|
485
|
+
|
|
486
|
+
### Setup
|
|
487
|
+
|
|
488
|
+
```bash
|
|
489
|
+
# Clone the repository
|
|
490
|
+
git clone https://github.com/timeplus-io/vistral.git
|
|
491
|
+
cd vistral
|
|
492
|
+
|
|
493
|
+
# Install dependencies
|
|
494
|
+
npm install
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Scripts
|
|
498
|
+
|
|
499
|
+
| Command | Description |
|
|
500
|
+
|---------|-------------|
|
|
501
|
+
| `npm run build` | Build the library (CommonJS + ESM + TypeScript declarations) |
|
|
502
|
+
| `npm run dev` | Start development mode with watch (library rebuild) |
|
|
503
|
+
| `npm run dev:examples` | Start Vite dev server to view examples at http://localhost:3000 |
|
|
504
|
+
| `npm run test` | Run tests with Vitest |
|
|
505
|
+
| `npm run test:coverage` | Run tests with coverage report |
|
|
506
|
+
| `npm run lint` | Run ESLint |
|
|
507
|
+
| `npm run typecheck` | Run TypeScript type checking |
|
|
508
|
+
|
|
509
|
+
### Viewing Examples
|
|
510
|
+
|
|
511
|
+
To view the interactive examples during development:
|
|
512
|
+
|
|
513
|
+
```bash
|
|
514
|
+
# Install dependencies first
|
|
515
|
+
npm install
|
|
516
|
+
|
|
517
|
+
# Start the examples dev server
|
|
518
|
+
npm run dev:examples
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
This will open http://localhost:3000 with a sidebar navigation showing all available chart examples.
|
|
522
|
+
|
|
523
|
+
## Credits
|
|
524
|
+
|
|
525
|
+
Built with:
|
|
526
|
+
- [AntV G2](https://g2.antv.antgroup.com/) - Visualization grammar
|
|
527
|
+
- [React](https://reactjs.org/) - UI framework
|
|
528
|
+
- [TypeScript](https://www.typescriptlang.org/) - Type safety
|
|
529
|
+
|
|
530
|
+
Developed by [Timeplus](https://timeplus.com/)
|