Skip to content

Commit da4b19f

Browse files
committed
Horizon Layer
1 parent b67a0b1 commit da4b19f

10 files changed

Lines changed: 1057 additions & 9 deletions

File tree

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// deck.gl-community
2+
// SPDX-License-Identifier: MIT
3+
// Copyright (c) vis.gl contributors
4+
5+
import React from 'react';
6+
import DeckGL from '@deck.gl/react';
7+
import {OrthographicView} from '@deck.gl/core';
8+
import {HorizonGraphLayer} from '@deck.gl-community/layers';
9+
10+
const INITIAL_VIEW_STATE = {
11+
target: [0, 0, 0],
12+
zoom: 1
13+
};
14+
15+
export default function App(): React.ReactElement {
16+
const [bands, setBands] = React.useState(4);
17+
18+
// Generate sample time-series data
19+
const sampleData = React.useMemo(() => {
20+
const data = [];
21+
const seriesCount = 3;
22+
const pointsPerSeries = 100;
23+
24+
for (let series = 0; series < seriesCount; series++) {
25+
for (let i = 0; i < pointsPerSeries; i++) {
26+
const x = i;
27+
const y = Math.sin(i * 0.1 + series) * 50 + Math.random() * 20 - 10;
28+
data.push({
29+
x,
30+
y,
31+
series
32+
});
33+
}
34+
}
35+
return data;
36+
}, []);
37+
38+
const layers = [
39+
new HorizonGraphLayer({
40+
id: 'horizon-graph-layer',
41+
data: sampleData,
42+
getX: (d: any) => d.x,
43+
getY: (d: any) => d.y,
44+
getSeries: (d: any) => d.series,
45+
bands,
46+
height: 300,
47+
width: 800,
48+
positiveColor: [0, 123, 255],
49+
negativeColor: [220, 53, 69],
50+
dividerColor: [0, 0, 0]
51+
})
52+
];
53+
54+
return (
55+
<div style={{ position: 'relative', width: '100vw', height: '100vh' }}>
56+
<div style={{
57+
position: 'absolute',
58+
top: 10,
59+
left: 10,
60+
zIndex: 1000,
61+
background: 'rgba(255, 255, 255, 0.9)',
62+
padding: '10px',
63+
borderRadius: '4px',
64+
fontFamily: 'Arial, sans-serif'
65+
}}>
66+
<label>
67+
Bands:
68+
<select
69+
value={bands}
70+
onChange={(e) => setBands(Number(e.target.value))}
71+
style={{ marginLeft: '10px' }}
72+
>
73+
<option value={1}>1 (Regular Area Chart)</option>
74+
<option value={2}>2</option>
75+
<option value={3}>3</option>
76+
<option value={4}>4</option>
77+
<option value={5}>5</option>
78+
<option value={6}>6</option>
79+
</select>
80+
</label>
81+
</div>
82+
<DeckGL
83+
views={new OrthographicView()}
84+
initialViewState={INITIAL_VIEW_STATE}
85+
controller={true}
86+
layers={layers}
87+
/>
88+
</div>
89+
);
90+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>deck.gl Community Example</title>
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
</head>
8+
<body></body>
9+
<script type="module" src="./index.tsx"></script>
10+
</html>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import React from 'react';
2+
import {createRoot} from 'react-dom/client';
3+
import App from './app';
4+
5+
const root = createRoot(document.body.appendChild(document.createElement('div')));
6+
root.render(<App />);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"license": "MIT",
3+
"scripts": {
4+
"start": "vite --open",
5+
"start-local": "vite --config ../../vite.config.local.mjs"
6+
},
7+
"dependencies": {
8+
"@deck.gl-community/layers": "^9.0.0",
9+
"@deck.gl/core": "^9.0.0",
10+
"@deck.gl/layers": "^9.0.0",
11+
"@deck.gl/react": "^9.0.0",
12+
"react": "^18.2.0",
13+
"react-dom": "^18.2.0"
14+
},
15+
"devDependencies": {
16+
"vite": "^5.0.12"
17+
}
18+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"extends": "../../../tsconfig.json",
3+
"include": ["./*.tsx"]
4+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
export default `#version 300 es
2+
#define SHADER_NAME horizon-graph-layer-fragment-shader
3+
4+
precision highp float;
5+
6+
uniform float uBands;
7+
uniform vec3 uPositiveColor;
8+
uniform vec3 uNegativeColor;
9+
uniform vec3 uDividerColor;
10+
uniform vec2 uYDomain;
11+
12+
in vec2 vUv;
13+
in float vValue;
14+
in float vSeries;
15+
in float vType;
16+
out vec4 fragColor;
17+
18+
void main(void) {
19+
// Check if this is a divider line
20+
if (vType > 100.0) {
21+
fragColor = vec4(uDividerColor, 1.0);
22+
return;
23+
}
24+
25+
// Skip zero-value fragments
26+
if (abs(vValue) < 0.001) {
27+
discard;
28+
}
29+
30+
// Handle 1 band case (regular area chart)
31+
if (uBands <= 1.0) {
32+
bool isPositive = vValue > 0.0;
33+
vec3 color = isPositive ? uPositiveColor : uNegativeColor;
34+
fragColor = vec4(color, 0.8);
35+
return;
36+
}
37+
38+
// Use the band index from geometry (stored in vType)
39+
float bandIndex = vType;
40+
bool isPositive = vValue > 0.0;
41+
42+
// Choose base color
43+
vec3 baseColor = isPositive ? uPositiveColor : uNegativeColor;
44+
45+
// Apply band-based intensity - each band gets progressively darker
46+
float intensity = 1.0 - (bandIndex * 0.2);
47+
intensity = max(intensity, 0.3); // Don't go completely dark
48+
49+
vec3 finalColor = baseColor * intensity;
50+
51+
fragColor = vec4(finalColor, 0.8);
52+
}
53+
`;

0 commit comments

Comments
 (0)