mapbox-gl-layer
v0.1.9
Published
A high-performance wind field animation layer for Mapbox GL JS using WebGL2 particle system
Maintainers
Readme
Mapbox Wind Layer
A high-performance wind field animation layer for Mapbox GL JS using WebGL2 particle system.
Features
- 🌊 Smooth particle-based wind animation
- 🎨 Customizable color gradients
- ⚡ WebGL2 accelerated rendering
- 🔄 Double-buffered trail effects
- 🌍 Cross-world rendering for seamless global wind data
- 🎯 Automatic particle lifecycle management
- 💨 Speed-based color mapping
- 🔍 Works at all zoom levels
- 📱 Mobile device performance optimization
- 🚀 Automatic device detection and adaptive quality
Installation
npm install mapbox-gl-layer mapbox-glor with yarn:
yarn add mapbox-gl-layer mapbox-glor with pnpm:
pnpm add mapbox-gl-layer mapbox-glUsage
import mapboxgl from 'mapbox-gl';
import { MapboxWindLayer } from 'mapbox-gl-layer';
import type { WindData } from 'mapbox-gl-layer';
mapboxgl.accessToken = 'YOUR_MAPBOX_TOKEN';
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/dark-v11',
center: [0, 20],
zoom: 2
});
map.on('load', () => {
// Create wind layer
const windLayer = new MapboxWindLayer('wind', {
particleCount: 5000,
particleAge: 100,
speedFactor: 0.5,
fadeOpacity: 0.94,
colorRamp: [
'#3288bd', '#66c2a5', '#abdda4', '#e6f598',
'#fee08b', '#fdae61', '#f46d43', '#d53e4f'
]
});
// Set wind data
const windData: WindData = {
uv: Float32Array, // [u0, v0, u1, v1, ...]
width: 100,
height: 50,
minU: -10,
maxU: 10,
minV: -10,
maxV: 10,
bounds: {
minLon: -180,
minLat: -85,
maxLon: 180,
maxLat: 85
}
};
windLayer.setData(windData);
// Add to map
map.addLayer(windLayer);
});API
MapboxWindLayer
Constructor
new MapboxWindLayer(id: string, options?: WindLayerOptions)Options
particleCount(number): Number of particles (default: auto-detected based on device)particleAge(number): Particle lifetime in frames (default: auto-detected)speedFactor(number): Speed multiplier (default: 0.5)fadeOpacity(number): Trail fade opacity (default: auto-detected)colorRamp(string[]): Color gradient array (default: blue to red)wrapX(boolean): Enable horizontal wrapping (default: auto-detected)pauseOnInteraction(boolean): Pause rendering during map interactions (default: true)interactionDelay(number): Delay before resuming after interaction (default: 150ms)devicePerformance('high' | 'medium' | 'low' | 'auto'): Device performance level (default: 'auto')maxTextureSize(number): Maximum texture size for mobile devices (default: 4096)enableAdaptiveQuality(boolean): Enable adaptive quality based on device (default: true)
Methods
setData(data: WindData): Update wind field datagetPerformanceInfo(): Get device performance information{ detected: 'high' | 'medium' | 'low', isMobile: boolean, particleCount: number, renderScale: number }
WindData
interface WindData {
uv: Float32Array; // UV data [u0, v0, u1, v1, ...]
width: number; // Data width
height: number; // Data height
minU: number; // Min U component
maxU: number; // Max U component
minV: number; // Min V component
maxV: number; // Max V component
alpha?: Float32Array; // Optional alpha channel
bounds?: { // Geographic bounds
minLon: number;
minLat: number;
maxLon: number;
maxLat: number;
};
}ColorLayer
For displaying scalar rasters (e.g., temperature/precipitation) with a custom color ramp. Uses a WebGL2 custom layer with world wrapping and optional mask support.
Constructor
import { ColorLayer } from 'mapbox-gl-layer';
const layer = new ColorLayer('color-layer', {
image: dataImage, // HTMLImageElement | ImageBitmap
colorImage: colorbarImage, // HTMLImageElement | ImageBitmap
maskImage: maskImage, // optional mask (alpha) image
meta: {
min_lon: -180,
max_lon: 180,
min_lat: -85,
max_lat: 85,
range: [0, 100], // data value range in the image
},
colorRange: [10, 80], // optional display range; defaults to meta.range
opacity: 0.85, // optional global opacity (0-1), default 1
});
map.addLayer(layer);Runtime methods
setImage(image): update the raster texture.setMaskImage(maskImage | null): update or clear the mask texture.setColorbarImage(colorImage): update the color ramp texture.setMeta(meta): update geographic bounds and data range; invalidates cached world copies.setColorRange(range | null): override or reset the display range used for ramp mapping.setOpacity(opacity): set global opacity (0-1).
Mobile Device Optimization
The library automatically detects device performance and adjusts rendering parameters:
Automatic Detection (Recommended)
const windLayer = new MapboxWindLayer('wind', {
devicePerformance: 'auto', // Auto-detect (default)
enableAdaptiveQuality: true // Enable adaptive quality (default)
});
// Get performance info
const info = windLayer.getPerformanceInfo();
console.log('Device:', info.detected); // 'high' | 'medium' | 'low'
console.log('Mobile:', info.isMobile); // true | false
console.log('Particles:', info.particleCount); // Actual particle count
console.log('Scale:', info.renderScale); // Render resolution scalePerformance Levels
| Level | Particles | Render Scale | Wrap X | Use Case | |-------|-----------|--------------|--------|----------| | High | 5000 | 100% | ✅ | Desktop, high-end mobile | | Medium | 3500 | 75% | ✅ | Mid-range mobile | | Low | 2000 | 50% | ❌ | Low-end mobile |
Manual Override
const windLayer = new MapboxWindLayer('wind', {
devicePerformance: 'low', // Force low performance mode
maxTextureSize: 2048 // Limit texture size
});Examples
Development
# Install dependencies
npm install
# Start dev server
npm run dev
# Build library
npm run buildBrowser Compatibility
| Browser | Minimum Version | Notes | |---------|----------------|-------| | Chrome | 56+ | Full support | | Firefox | 51+ | Full support | | Safari | 15+ | Full support | | Edge | 79+ | Full support |
Requirements:
- WebGL2 support
EXT_color_buffer_floatextension
Performance
- Desktop: 5,000-50,000 particles at 60 FPS
- Mobile (High-end): 3,500-20,000 particles at 60 FPS
- Mobile (Low-end): 2,000-10,000 particles at 30-60 FPS
Performance is automatically optimized based on device capabilities.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Changelog
See CHANGELOG.md for a list of changes.
License
MIT © [Your Name]
See LICENSE for more information.
Acknowledgments
- Inspired by earth.nullschool.net
- Built with Mapbox GL JS
- Uses WebGL2 for GPU-accelerated rendering
