1

Based on good explanation in this post Leaftletjs load XML and GeoJSON I managed to get earthquake points that works fine. Now my idea was instead of circle to use SVG or PNG marker to show earthquake wave.

Something like this

enter image description here

On Leaflet page I found below code and adjusted also created circle.png.

var LeafIcon = L.Icon.extend({
    options: {
        iconSize:     [200, 200],
        iconAnchor:   [100, 100],
    }
});
var greenIcon = new LeafIcon({iconUrl: 'circle.png'});
L.marker([45.6524,15.4909], {icon: greenIcon}).addTo(map);

This is also fine but how can I use above code into below code and resize icon based on earthquake magnitude and set center where earthquake is?

 pointToLayer: function (feature, latlng) {
        var color,
            mag,
            radius,
            weight;
            mag = feature.properties.mag;
        if (mag === null) {
            color = '#FF0000';
            radius = 2;
            weight = 0.9;
        } else {
            color = '#FF0000';
            radius = 2 * Math.max(mag, 1);
            weight = 0.9;
        }
        if (feature.properties.type === 'quarry blast') {
            color = '#FF00FF';
        }
        return L.circleMarker(latlng, {
            color: color,
            radius: radius,
            weight: weight
        });
    }
0
2

I'm gonna go with an approach based on Leaflet.GLMarkers, adapted from some of its demos with time-dependent symbols.

It would involve the following vertex shader:

attribute vec2 aCRSCoords;
attribute vec2 aExtrudeCoords;
uniform mat4 uTransformMatrix;
uniform vec2 uPixelSize;
varying vec2 vPixel;

void main(void) {
    // Copy the input extrude coords to the varying
    vPixel = aExtrudeCoords * 30.0;

    gl_Position =
        uTransformMatrix * vec4(aCRSCoords, 1.0, 1.0) +
        vec4(aExtrudeCoords * uPixelSize * 80.0, 0.0, 0.0);
}

...and the following fragment shader:

precision highp float;
varying vec2 vPixel;
uniform float uNow;

void main(void) {
    float radiusSquared = vPixel.x * vPixel.x + vPixel.y * vPixel.y;
    float hue = pow(radiusSquared, 1.2) / (800.0);

    hue -= uNow / 2000.0;
    hue = fract(hue);
    vec3 colour = vec3(1., 0., 0.);

    float alpha = smoothstep(30.0*30.0, 28.0*28.0, radiusSquared);
    alpha *= min(
        smoothstep(0.57, 0.65, hue),
        1. - smoothstep(0.92, 1., hue)
     );

    gl_FragColor = vec4(colour, alpha);
}

This includes a some basic antialiasing of the waves (the smoothsteps), and the opacity of the pixels depends on the radius to the power of 2.4 plus the time, building the desired effect (or something very close to the desired effect).

animation of result

This is a textbook application of a 2D signed distance field. In the end, the math boils down to creating a mathematical function that has the radius and time as input, and the opacity as an output. In regards to 2D shaders and SDFs, I can always recommend reading https://thebookofshaders.com/ (do read the GLMarkers documentation and examples as well).

The above example can be tried live on https://ivansanchez.gitlab.io/Leaflet.GLMarkers/demo/repl.html - replace the vertex and fragment shader code as needed. Note that per-marker attributes can be used as variables inside the shaders (e.g. to control the extrusion distance, or the opacity thresholds, or the speed), as demonstrated by other examples in that same REPL.

1
  • Thank you so much. I will check and read more about options also..
    – Tkalac
    Sep 1 at 18:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.