Custom earthquake symbols using a shader
This example customizes the symbols displayed by the earthquakes
layer using a custom fragment shader.
Custom shaders can be used for symbol
or circle
layer types to create a unique animated visual effect for each symbol based on the feature's data and properties.
custom-earthquake-shader.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>MapsGL SDK - Custom earthquake symbols using a shader</title>
<meta name="description" content="Use a custom WebGL fragment shader to apply unique and animated visual effects to earthquake data." />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://api.mapbox.com/mapbox-gl-js/v2.8.0/mapbox-gl.css" rel="stylesheet" />
<script defer src="https://api.mapbox.com/mapbox-gl-js/v2.8.0/mapbox-gl.js"></script>
<link href="https://cdn.aerisapi.com/sdk/js/mapsgl/latest/aerisweather.mapsgl.css" rel="stylesheet" />
<script defer src="https://cdn.aerisapi.com/sdk/js/mapsgl/latest/aerisweather.mapsgl.js"></script>
<style>
body, html {
margin: 0;
padding: 0;
}
#map {
height: 100vh;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
window.addEventListener('load', () => {
mapboxgl.accessToken = 'MAPBOX_TOKEN';
const map = new mapboxgl.Map({
container: document.getElementById('map'),
style: 'mapbox://styles/mapbox/light-v9',
center: [124.091, 26.232],
zoom: 2
});
const account = new aerisweather.mapsgl.Account('CLIENT_ID', 'CLIENT_SECRET');
const controller = new aerisweather.mapsgl.MapboxMapController(map, { account });
controller.on('load', () => {
controller.addWeatherLayer('earthquakes', {
type: 'symbol',
source: 'earthquakes',
paint: {
symbol: {
shader: `
// https://www.shadertoy.com/view/ldycR3
#extension GL_OES_standard_derivatives : enable
precision mediump float;
uniform vec2 resolution;
uniform float dpr;
uniform float time;
varying vec2 vUv;
varying vec2 vPosition;
varying float vFactor;
varying float vRandom;
float saturate(float x) {
return clamp(x, 0.0, 1.0);
}
vec3 hsb2rgb(in vec3 c) {
vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0,
0.0,
1.0);
rgb = rgb*rgb*(3.0-2.0*rgb);
return c.z * mix( vec3(1.0), rgb, c.y);
}
void main() {
vec2 pos = vUv;
float t = time;
float dist = length(2.0 * pos - 1.0) * 2.0;
vec2 p = vec2(dist);
float r = length(p) * 0.9;
vec3 color = hsb2rgb(vec3(0.03, 0.7, 0.6));
float a = pow(r, 3.0);
float b = sin(r * 1.8 - 1.6);
float c = sin(r - 0.010);
float s = sin(a - t * 2.0 + b) * c;
color *= abs(1.0 / (s * 1.8)) - 0.01;
float d = length(2.0 * pos - 1.0);
// float delta = fwidth(d);
float alpha = 1.0 - d;
// alpha *= min(1.0, 0.2 + vFactor);
gl_FragColor = vec4(color, alpha);
gl_FragColor.rgb *= gl_FragColor.a;
}
`,
animated: true,
pitchWithMap: true,
// blending: 2,
size: (data) => {
const mag = Math.max(data.report?.mag || 1);
const size = 20 + 100 * (mag / 10);
return { width: size, height: size };
}
}
}
});
});
});
</script>
</body>
</html>