Skip to content

Commit 1a3a6e0

Browse files
committed
styling map page and global tsunami vector tiles
1 parent 519009b commit 1a3a6e0

File tree

3 files changed

+1065
-91
lines changed

3 files changed

+1065
-91
lines changed
Lines changed: 391 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,391 @@
1+
# Global Tsunami Hazard Vector Tile Visualization
2+
3+
## Overview
4+
5+
This document describes the implementation and rendering of global tsunami hazard vector tiles in the geospatial dataset publishing platform. The visualization displays over 200,000 tsunami hazard points worldwide with interactive charts and risk-based color coding.
6+
7+
## Data Structure
8+
9+
### Source Dataset
10+
11+
- **Format**: GeoJSON (94MB) converted to FlatGeobuf (64MB) for efficient streaming
12+
- **Points**: ~200,000 global tsunami hazard locations
13+
- **Coordinate System**: WGS84 (EPSG:4326)
14+
- **Tile Format**: Mapbox Vector Tiles (MVT) using Tippecanoe
15+
16+
### Feature Properties
17+
18+
Each tsunami hazard point contains the following attributes:
19+
20+
#### Core Location Data
21+
22+
- `Longitude`: Longitude coordinate
23+
- `Latitude`: Latitude coordinate
24+
- `id`: Unique identifier
25+
26+
#### Annual Recurrence Interval (ARI) Runup Heights
27+
28+
- `ari10`: 10-year return period runup height (meters)
29+
- `ari50`: 50-year return period runup height (meters)
30+
- `ari100`: 100-year return period runup height (meters)
31+
- `ari200`: 200-year return period runup height (meters)
32+
- `ari500`: 500-year return period runup height (meters)
33+
- `ari1000`: 1000-year return period runup height (meters)
34+
- `ari2500`: 2500-year return period runup height (meters)
35+
36+
#### Statistical Variants (500-year focus)
37+
38+
- `ari500LL`: 500-year ARI with sigma=0.5
39+
- `ari500ZL`: 500-year ARI with sigma=0.0
40+
- `ari500M`: 500-year ARI lower 95% confidence
41+
- `ari500P`: 500-year ARI upper 95% confidence
42+
43+
#### Rate Data
44+
45+
- `rate_5`: Exceedance rate for 5m threshold
46+
- `rate_10`: Exceedance rate for 10m threshold
47+
- `rate_25`: Exceedance rate for 25m threshold
48+
- `rate_50`: Exceedance rate for 50m threshold
49+
- `rate_100`: Exceedance rate for 100m threshold
50+
- `rate_300`: Exceedance rate for 300m threshold
51+
- `rate_500`: Exceedance rate for 500m threshold
52+
- `rate_1000`: Exceedance rate for 1000m threshold
53+
- `rate_2000`: Exceedance rate for 2000m threshold
54+
55+
## Vector Tile Configuration
56+
57+
### Tile Service Setup
58+
59+
```yaml
60+
# pygeoapi configuration
61+
collections:
62+
hazardglobal:
63+
type: collection
64+
title: Global Tsunami Hazard Points
65+
description: Global tsunami hazard points with ARI runup heights
66+
provider:
67+
name: MVT-tippecanoe
68+
data: data/tiles/global-hazard/
69+
format: pbf
70+
```
71+
72+
### Tippecanoe Generation
73+
74+
```bash
75+
# Generate vector tiles from source data
76+
make hazard-tiles
77+
78+
# Equivalent docker command:
79+
docker run --rm -v $(pwd)/data:/data \
80+
tippecanoe/tippecanoe:latest \
81+
tippecanoe \
82+
--output-to-directory=/data/tiles/global-hazard/ \
83+
--force \
84+
--minimum-zoom=0 \
85+
--maximum-zoom=15 \
86+
--layer=globalhazardpoints \
87+
/data/hazard/global-hazard-points.fgb
88+
```
89+
90+
## Rendering Implementation
91+
92+
### 1. MapLibre GL JS Layer Configuration
93+
94+
#### Vector Source
95+
96+
```javascript
97+
map.addSource("global-hazard-source", {
98+
type: "vector",
99+
tiles: [
100+
`${apiBaseUrl}/collections/hazardglobal/tiles/WebMercatorQuad/{z}/{y}/{x}?f=mvt`,
101+
],
102+
minzoom: 0,
103+
maxzoom: 15,
104+
bounds: [-180, -90, 180, 90],
105+
});
106+
```
107+
108+
#### Circle Layer with Dynamic Styling
109+
110+
```javascript
111+
map.addLayer({
112+
id: "hazard-pt",
113+
type: "circle",
114+
source: "global-hazard-source",
115+
"source-layer": "globalhazardpoints",
116+
layout: {
117+
visibility: "visible",
118+
},
119+
paint: {
120+
// Dynamic sizing based on zoom level
121+
"circle-radius": [
122+
"interpolate",
123+
["linear"],
124+
["zoom"],
125+
0,
126+
1, // Continental view: 1px dots
127+
5,
128+
2, // Regional view: 2px dots
129+
10,
130+
4, // Local view: 4px dots
131+
15,
132+
8, // Detailed view: 8px dots
133+
],
134+
135+
// Risk-based color coding using ari500 values
136+
"circle-color": [
137+
"case",
138+
["has", "ari500"],
139+
[
140+
"interpolate",
141+
["linear"],
142+
["get", "ari500"],
143+
0,
144+
"#4CAF50", // Green: Low risk (0-5m)
145+
5,
146+
"#FFC107", // Yellow: Medium risk (5-10m)
147+
10,
148+
"#FF9800", // Orange: High risk (10-20m)
149+
20,
150+
"#F44336", // Red: Very high risk (>20m)
151+
],
152+
"#1a73e8", // Default blue for missing data
153+
],
154+
155+
// Progressive opacity for performance
156+
"circle-opacity": [
157+
"interpolate",
158+
["linear"],
159+
["zoom"],
160+
0,
161+
0.6, // More transparent at low zoom
162+
10,
163+
0.8, // Medium opacity at mid zoom
164+
15,
165+
0.9, // Full opacity at high zoom
166+
],
167+
168+
// Zoom-dependent stroke
169+
"circle-stroke-width": [
170+
"interpolate",
171+
["linear"],
172+
["zoom"],
173+
0,
174+
0, // No stroke at low zoom
175+
10,
176+
0.5, // Thin stroke at mid zoom
177+
15,
178+
1, // Full stroke at high zoom
179+
],
180+
"circle-stroke-color": "#ffffff",
181+
},
182+
});
183+
```
184+
185+
### 2. Interactive Popup System
186+
187+
#### Popup Configuration
188+
189+
```javascript
190+
const popup = new maplibregl.Popup({
191+
maxWidth: "480px",
192+
className: "chart-popup",
193+
closeOnClick: false,
194+
closeOnMove: false,
195+
anchor: "bottom",
196+
offset: [0, -10],
197+
});
198+
```
199+
200+
#### Smart Positioning
201+
202+
The popup system includes intelligent positioning to prevent jumping outside the viewport:
203+
204+
```javascript
205+
// Adjust popup position if it goes off screen
206+
setTimeout(() => {
207+
const popupElement = popup.getElement();
208+
const rect = popupElement.getBoundingClientRect();
209+
const mapContainer = map.getContainer().getBoundingClientRect();
210+
211+
// Check boundaries and adjust offset
212+
if (rect.right > mapContainer.right) {
213+
popup.setOffset([-rect.width / 2, -10]);
214+
}
215+
if (rect.left < mapContainer.left) {
216+
popup.setOffset([rect.width / 2, -10]);
217+
}
218+
if (rect.top < mapContainer.top) {
219+
popup.setOffset([0, 10]);
220+
}
221+
}, 50);
222+
```
223+
224+
### 3. Chart.js Integration
225+
226+
#### ARI Runup Height Visualization
227+
228+
```javascript
229+
const ariKeys = [
230+
"ari10",
231+
"ari50",
232+
"ari100",
233+
"ari200",
234+
"ari500",
235+
"ari1000",
236+
"ari2500",
237+
];
238+
239+
const datasets = [
240+
{
241+
label: "Runup height (m)",
242+
data: ariKeys.map((k) => ({
243+
x: Number(k.replace("ari", "")),
244+
y: Number(properties[k] || 0),
245+
})),
246+
borderColor: "#1a73e8",
247+
backgroundColor: "rgba(26, 115, 232, 0.1)",
248+
fill: true,
249+
tension: 0.4,
250+
},
251+
];
252+
```
253+
254+
#### Statistical Variants Display
255+
256+
```javascript
257+
const variants = [
258+
["ari500LL", "σ=0.5", "#FF9800"],
259+
["ari500ZL", "σ=0.0", "#4CAF50"],
260+
["ari500M", "Lower 95%", "#F44336"],
261+
["ari500P", "Upper 95%", "#9C27B0"],
262+
];
263+
264+
variants.forEach(([key, label, color]) => {
265+
if (properties[key] !== undefined) {
266+
datasets.push({
267+
label,
268+
data: [{ x: 500, y: Number(properties[key]) }],
269+
showLine: false,
270+
pointRadius: 5,
271+
pointBackgroundColor: color,
272+
pointBorderColor: "#ffffff",
273+
pointBorderWidth: 2,
274+
});
275+
}
276+
});
277+
```
278+
279+
## Performance Optimization
280+
281+
### 1. Vector Tile Advantages
282+
283+
- **Efficient Loading**: 64MB FlatGeobuf vs 94MB GeoJSON (32% reduction)
284+
- **Progressive Loading**: Only visible tiles loaded based on zoom/pan
285+
- **Client-side Styling**: No server re-rendering needed for style changes
286+
- **Scalable**: Handles 200K+ points smoothly
287+
288+
### 2. Zoom-based LOD (Level of Detail)
289+
290+
- **Zoom 0-5**: Minimal 1-2px dots for overview
291+
- **Zoom 6-10**: Medium 2-4px dots for regional view
292+
- **Zoom 11-15**: Large 4-8px dots for detailed analysis
293+
294+
### 3. Conditional Rendering
295+
296+
- **Opacity ramping**: Reduces visual clutter at low zoom levels
297+
- **Stroke simplification**: No borders at low zoom for performance
298+
- **Color computation**: Only when ari500 data exists
299+
300+
## Risk Assessment Color Scheme
301+
302+
The visualization uses a scientifically-informed color scheme based on tsunami runup heights:
303+
304+
| Runup Height | Risk Level | Color | Hex Code | Description |
305+
| ------------ | ---------- | ------ | -------- | --------------------------------- |
306+
| 0-5m | Low | Green | #4CAF50 | Minimal infrastructure damage |
307+
| 5-10m | Medium | Yellow | #FFC107 | Moderate coastal impact |
308+
| 10-20m | High | Orange | #FF9800 | Significant infrastructure damage |
309+
| >20m | Very High | Red | #F44336 | Catastrophic damage potential |
310+
311+
## Data Export Features
312+
313+
### CSV Download
314+
315+
Each popup includes a download button that generates a CSV file with all point attributes:
316+
317+
```javascript
318+
const header = Object.keys(properties).join(",");
319+
const values = Object.values(properties).join(",");
320+
const csv = `${header}\n${values}`;
321+
const blob = new Blob([csv], { type: "text/csv" });
322+
```
323+
324+
## Technical Requirements
325+
326+
### Browser Support
327+
328+
- **Modern browsers** with WebGL support
329+
- **MapLibre GL JS**: Vector tile rendering engine
330+
- **Chart.js**: Interactive chart generation
331+
332+
### Server Components
333+
334+
- **pygeoapi**: OGC API compliance and MVT serving
335+
- **Tippecanoe**: Vector tile generation
336+
- **Docker**: Containerized tile generation
337+
338+
## Usage Instructions
339+
340+
### 1. Basic Interaction
341+
342+
- **Pan/Zoom**: Standard map navigation
343+
- **Click point**: Opens interactive popup with chart
344+
- **Hover**: Cursor changes to pointer over points
345+
346+
### 2. Popup Features
347+
348+
- **Runup Chart**: Shows ARI values across return periods
349+
- **Statistical Variants**: Uncertainty quantification at 500-year ARI
350+
- **Properties**: Expandable table with all attributes
351+
- **CSV Export**: Download point data
352+
353+
### 3. Map Controls
354+
355+
- **Satellite Toggle**: Switch between map and satellite view
356+
- **Navigation**: Zoom in/out and compass controls
357+
- **Full Screen**: Responsive design with fixed viewport
358+
359+
## Configuration Options
360+
361+
### Environment Variables
362+
363+
```bash
364+
API_BASE_URL=http://localhost:5000 # API endpoint
365+
```
366+
367+
### Build Process
368+
369+
```bash
370+
cd frontend
371+
npm run build # Compiles and copies assets to dist/
372+
```
373+
374+
## Future Enhancements
375+
376+
### Planned Features
377+
378+
1. **Clustering**: Point aggregation at low zoom levels
379+
2. **Time Series**: Animation through different return periods
380+
3. **Filtering**: Risk-level and region-based filtering
381+
4. **3D Visualization**: Height-based extrusion of runup values
382+
383+
### Performance Improvements
384+
385+
1. **WebGL Point Rendering**: For even better performance with 200K+ points
386+
2. **Adaptive Simplification**: Dynamic point reduction based on screen density
387+
3. **Caching**: Browser-based tile caching for offline usage
388+
389+
---
390+
391+
_This documentation covers the complete implementation of tsunami hazard vector tile visualization. For technical support or feature requests, please refer to the project repository._

0 commit comments

Comments
 (0)