Skip to content

Commit 2ee685a

Browse files
committed
feat: Add WebGPU charting system with Bitcoin OHLCV example
Implement comprehensive WebGPU-based charting capabilities for Guix, providing high-performance financial and data visualization charts rendered entirely on the GPU. Core Features: - Declarative chart API following Guix's component model - OHLCV candlestick series with up/down coloring - Line and area series support - Configurable X/Y axes with time and numeric scales - Smart tick generation and formatting - Viewport transformation system for data-to-screen mapping Chart Components: - ChartNode: Root container with background and padding - XAxis/YAxis: Configurable axes with grid lines and ticks - CandlestickSeries: GPU-instanced candlestick rendering - LineSeries: Anti-aliased line charts with optional fill - AreaSeries: Filled area charts Data Types: - OHLCV: Open-High-Low-Close-Volume candlestick data - Point: Generic 2D data points - Range: Min-max ranges for axes - Viewport: Zoom and pan state management GPU Shaders (WGSL): - candlestick.wgsl: Instanced rendering of OHLC candles - line.wgsl: Anti-aliased line rendering with fill support Example Application: - Bitcoin price chart with 20 days of sample OHLCV data - Time-based X-axis with date formatting - Currency-formatted Y-axis for prices - Green/red candle coloring based on price movement - Comprehensive E2E tests using Playwright Technical Implementation: - All rendering happens on GPU via WebGPU - Instanced drawing for performance - Orthographic projection for 2D charts - Data culling for large datasets - Reactive data channels for real-time updates Files Added: - pkg/runtime/chart/data.go - Data types and range calculations - pkg/runtime/chart/chart.go - Chart container and options - pkg/runtime/chart/axis.go - Axis components and formatting - pkg/runtime/chart/series_candlestick.go - Candlestick series - pkg/runtime/chart/series_line.go - Line/area series - pkg/runtime/chart/viewport.go - Viewport transformation - pkg/runtime/chart/shaders/candlestick.wgsl - Candle shader - pkg/runtime/chart/shaders/line.wgsl - Line shader - examples/webgpu-chart/ - Complete Bitcoin chart example Browser Support: - Chrome/Edge 113+ (WebGPU enabled by default) - Firefox Nightly (experimental) - Safari Technology Preview (experimental) All pre-commit checks passed: - gofmt formatting - go vet linting - go test (all tests pass) - go build (native and WASM)
1 parent 0920e55 commit 2ee685a

18 files changed

Lines changed: 1898 additions & 0 deletions

examples/webgpu-chart/.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
main.wasm
2+
wasm_exec.js
3+
*_gen.go
4+
node_modules/
5+
package-lock.json
6+
playwright-report/
7+
test-results/

examples/webgpu-chart/README.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# WebGPU Chart Example
2+
3+
This example demonstrates Guix's WebGPU-powered charting capabilities with a Bitcoin price candlestick chart.
4+
5+
## Features
6+
7+
- **GPU-accelerated rendering**: All chart elements rendered via WebGPU for high performance
8+
- **Candlestick charts**: OHLCV (Open-High-Low-Close-Volume) visualization
9+
- **Declarative syntax**: Define charts using Guix's component-based approach
10+
- **Automatic axis scaling**: Smart tick generation and formatting
11+
- **Responsive design**: Adapts to different screen sizes
12+
13+
## Prerequisites
14+
15+
- Go 1.21 or later
16+
- A WebGPU-enabled browser:
17+
- Chrome/Edge 113+
18+
- Firefox Nightly (with `dom.webgpu.enabled` flag)
19+
- Safari Technology Preview
20+
21+
## Building
22+
23+
### 1. Generate Guix Components
24+
25+
```bash
26+
go generate
27+
```
28+
29+
This will generate `app_gen.go` and `chart_gen.go` from the `.gx` source files.
30+
31+
### 2. Build WASM Binary
32+
33+
```bash
34+
GOOS=js GOARCH=wasm go build -o main.wasm
35+
```
36+
37+
### 3. Copy wasm_exec.js
38+
39+
```bash
40+
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
41+
```
42+
43+
## Running
44+
45+
Start a local web server:
46+
47+
```bash
48+
# Using Python
49+
python3 -m http.server 8080
50+
51+
# Or using Go
52+
go run ../../cmd/serve/main.go -port 8080
53+
```
54+
55+
Then open http://localhost:8080 in your WebGPU-enabled browser.
56+
57+
## Chart Components
58+
59+
The chart is defined declaratively in `chart.gx`:
60+
61+
```go
62+
chart.ChartNode(
63+
chart.ChartBackground(0.08, 0.09, 0.12, 1.0),
64+
chart.ChartPaddingProp(60, 20, 40, 80),
65+
66+
// X-Axis with time scale
67+
chart.XAxis(
68+
chart.TimeScale(true),
69+
chart.GridLines(true),
70+
),
71+
72+
// Y-Axis with price formatting
73+
chart.YAxis(
74+
chart.TickFormat(func(v float64) string {
75+
return chart.FormatCurrency(v, "USD")
76+
}),
77+
),
78+
79+
// Candlestick series
80+
chart.CandlestickSeries(
81+
chart.DataProp(data),
82+
chart.UpColor(0.18, 0.80, 0.44, 1.0), // Green
83+
chart.DownColor(0.91, 0.27, 0.38, 1.0), // Red
84+
),
85+
)
86+
```
87+
88+
## Data Format
89+
90+
OHLCV data is defined as:
91+
92+
```go
93+
type OHLCV struct {
94+
Timestamp int64 // Unix timestamp in milliseconds
95+
Open float64 // Opening price
96+
High float64 // Highest price
97+
Low float64 // Lowest price
98+
Close float64 // Closing price
99+
Volume float64 // Trading volume
100+
}
101+
```
102+
103+
## Browser Compatibility
104+
105+
| Browser | Version | Status |
106+
|---------|---------|--------|
107+
| Chrome | 113+ | ✅ Supported |
108+
| Edge | 113+ | ✅ Supported |
109+
| Firefox | Nightly | ⚠️ Experimental |
110+
| Safari | TP | ⚠️ Experimental |
111+
112+
## Troubleshooting
113+
114+
### WebGPU not available
115+
116+
If you see "WebGPU Not Supported", make sure you're using a compatible browser:
117+
118+
- **Chrome/Edge**: WebGPU is enabled by default in version 113+
119+
- **Firefox**: Enable `dom.webgpu.enabled` in `about:config`
120+
- **Safari**: Use Safari Technology Preview
121+
122+
### Chart not rendering
123+
124+
1. Check the browser console for errors
125+
2. Verify WebGPU is available: `navigator.gpu`
126+
3. Make sure the WASM binary loaded correctly
127+
4. Check that `wasm_exec.js` matches your Go version
128+
129+
## Architecture
130+
131+
The chart system follows Guix's declarative component model:
132+
133+
- **Chart Container** (`ChartNode`): Root container with background and padding
134+
- **Axes** (`XAxis`, `YAxis`): Configurable axes with scales and ticks
135+
- **Series** (`CandlestickSeries`): Data visualization components
136+
- **Shaders** (WGSL): GPU shaders for rendering chart elements
137+
138+
All rendering happens on the GPU via WebGPU for maximum performance.
139+
140+
## License
141+
142+
MIT License - see LICENSE file for details

examples/webgpu-chart/app.gx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package main
2+
3+
func App() (Component) {
4+
Div(
5+
ID("app"),
6+
Class("chart-container"),
7+
TabIndex(0),
8+
) {
9+
H1(Class("title")) {
10+
"Bitcoin Price Chart"
11+
}
12+
P(Class("subtitle")) {
13+
"WebGPU-powered candlestick chart"
14+
}
15+
Canvas(
16+
ID("chart-canvas"),
17+
Width(1200),
18+
Height(700),
19+
) {
20+
GPUChart(NewBitcoinChart())
21+
}
22+
Div(Class("info")) {
23+
P() {
24+
"This chart demonstrates Guix's WebGPU charting capabilities."
25+
}
26+
P() {
27+
"Data: Bitcoin daily OHLCV candles from December 2024"
28+
}
29+
}
30+
}
31+
}

examples/webgpu-chart/chart.gx

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package main
2+
3+
import (
4+
"github.com/gaarutyunov/guix/pkg/runtime/chart"
5+
)
6+
7+
// BitcoinChart creates a Bitcoin OHLCV candlestick chart
8+
func BitcoinChart() (Chart) {
9+
// Sample Bitcoin OHLCV data (daily candles from Dec 2024)
10+
data := []chart.OHLCV{
11+
{Timestamp: 1701388800000, Open: 37500, High: 38200, Low: 37100, Close: 37800, Volume: 28500000000},
12+
{Timestamp: 1701475200000, Open: 37800, High: 39100, Low: 37600, Close: 38900, Volume: 32100000000},
13+
{Timestamp: 1701561600000, Open: 38900, High: 40200, Low: 38500, Close: 39800, Volume: 41200000000},
14+
{Timestamp: 1701648000000, Open: 39800, High: 41500, Low: 39200, Close: 41200, Volume: 45600000000},
15+
{Timestamp: 1701734400000, Open: 41200, High: 42100, Low: 40800, Close: 40500, Volume: 38900000000},
16+
{Timestamp: 1701820800000, Open: 40500, High: 41800, Low: 39900, Close: 41600, Volume: 35200000000},
17+
{Timestamp: 1701907200000, Open: 41600, High: 43500, Low: 41200, Close: 43200, Volume: 52100000000},
18+
{Timestamp: 1701993600000, Open: 43200, High: 44100, Low: 42500, Close: 43800, Volume: 48700000000},
19+
{Timestamp: 1702080000000, Open: 43800, High: 44500, Low: 42200, Close: 42800, Volume: 39400000000},
20+
{Timestamp: 1702166400000, Open: 42800, High: 43900, Low: 41800, Close: 43500, Volume: 36800000000},
21+
{Timestamp: 1702252800000, Open: 43500, High: 44200, Low: 42900, Close: 43100, Volume: 34200000000},
22+
{Timestamp: 1702339200000, Open: 43100, High: 44800, Low: 42800, Close: 44600, Volume: 42800000000},
23+
{Timestamp: 1702425600000, Open: 44600, High: 45500, Low: 43900, Close: 45200, Volume: 46100000000},
24+
{Timestamp: 1702512000000, Open: 45200, High: 46100, Low: 44800, Close: 45800, Volume: 43900000000},
25+
{Timestamp: 1702598400000, Open: 45800, High: 46500, Low: 44900, Close: 45100, Volume: 38700000000},
26+
{Timestamp: 1702684800000, Open: 45100, High: 45900, Low: 44200, Close: 44800, Volume: 35600000000},
27+
{Timestamp: 1702771200000, Open: 44800, High: 46200, Low: 44500, Close: 46000, Volume: 41200000000},
28+
{Timestamp: 1702857600000, Open: 46000, High: 47100, Low: 45700, Close: 46900, Volume: 48300000000},
29+
{Timestamp: 1702944000000, Open: 46900, High: 47800, Low: 46200, Close: 47500, Volume: 51200000000},
30+
{Timestamp: 1703030400000, Open: 47500, High: 48200, Low: 46800, Close: 47100, Volume: 44800000000},
31+
}
32+
33+
chart.ChartNode(
34+
chart.ChartBackground(0.08, 0.09, 0.12, 1.0),
35+
chart.ChartPaddingProp(60, 20, 40, 80),
36+
chart.ChartInteractive(true),
37+
38+
// X-Axis: Time scale
39+
chart.XAxis(
40+
chart.AxisPos(chart.AxisBottom),
41+
chart.TimeScale(true),
42+
chart.TickFormat(func(t float64) string {
43+
return chart.FormatTime(int64(t), "short")
44+
}),
45+
chart.GridLines(true),
46+
chart.GridColor(0.2, 0.2, 0.25, 0.5),
47+
chart.Label("Date"),
48+
),
49+
50+
// Y-Axis: Price scale
51+
chart.YAxis(
52+
chart.AxisPos(chart.AxisRight),
53+
chart.TickFormat(func(v float64) string {
54+
return chart.FormatCurrency(v, "USD")
55+
}),
56+
chart.GridLines(true),
57+
chart.GridColor(0.2, 0.2, 0.25, 0.5),
58+
chart.Label("Price (USD)"),
59+
),
60+
61+
// Main candlestick series
62+
chart.CandlestickSeries(
63+
chart.DataProp(data),
64+
chart.UpColor(0.18, 0.80, 0.44, 1.0), // Green for gains
65+
chart.DownColor(0.91, 0.27, 0.38, 1.0), // Red for losses
66+
chart.WickColor(0.6, 0.6, 0.65, 1.0),
67+
chart.BarWidth(0.8),
68+
),
69+
)
70+
}

examples/webgpu-chart/gen.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//go:build generate
2+
3+
package main
4+
5+
//go:generate go run ../../cmd/guix/main.go -input=app.gx -output=app_gen.go
6+
//go:generate go run ../../cmd/guix/main.go -input=chart.gx -output=chart_gen.go

0 commit comments

Comments
 (0)