5

I am often creating hex grid layers in Leaflet which use circlemarker for styling.

enter image description here

I would like to shift / offset the shadow circle under each marker in order to give the layer some depth.

enter image description here

Which would be the best way to achieve this?

Could I possibly create a style function which creates two circlemarker for each feature with the lower circle being shifted and opaque.

I could just duplicate the layer. But how can I apply a shift to a layer or a circlemarker?

At the moment I just add a second layer with a lat/lon shift to the elements based on the zoom level.

var gridZoomShift = {
  12: 0.0004,
  13: 0.0002,
  14: 0.0001,
  15: 0.00005,
  16: 0.000025,
  17: 0.0000125
};

Not perfect but good enough for now.

enter image description here

I chose in the end the L.divIcon solution due to browser compatibility with filter:drop-shadow.

new L.geoJson(dots, {
  pointToLayer: function (feature, latlng) {
    return L.marker(latlng, divStyle(feature));
  }
}).addTo(map_geodata);

function divStyle(feature){
    var c = feature.properties.c;

    var s = c < circleRadiusArray[0] ? 4 :
        c < circleRadiusArray[1] ? 4.5 :
            c < circleRadiusArray[2] ? 5 :
                c < circleRadiusArray[3] ? 5.5 :
                    c < circleRadiusArray[4] ? 6 :
                        c < circleRadiusArray[5] ? 6.5 :
                            c < circleRadiusArray[6] ? 7 :
                                c < circleRadiusArray[7] ? 7.5 :
                                    c < circleRadiusArray[8] ? 8 :
                                        c < circleRadiusArray[9] ? 8.5 :
                                            9;

    return {
        icon: L.divIcon({
            className: 'circle',
            iconSize: [s, s]
        })
    };
}

enter image description here

The style for a bivariate map:

function divStyle(feature){
    var c = feature.properties.c;
    var v = feature.properties.v;

    var s = c < circleRadiusArray[0] ? 4 :
            c < circleRadiusArray[1] ? 4.5 :
            c < circleRadiusArray[2] ? 5 :
            c < circleRadiusArray[3] ? 5.5 :
            c < circleRadiusArray[4] ? 6 :
            c < circleRadiusArray[5] ? 6.5 :
            c < circleRadiusArray[6] ? 7 :
            c < circleRadiusArray[7] ? 7.5 :
                                       8.5;

    var circle_colour = v < circleColorArray[0] ? 'circle_c51b7d' :
                        v < circleColorArray[1] ? 'circle_de77ae' :
                        v < circleColorArray[2] ? 'circle_f1b6da' :
                        v < circleColorArray[3] ? 'circle_fde0ef' :
                        v < circleColorArray[4] ? 'circle_f7f7f7' :
                        v < circleColorArray[5] ? 'circle_e6f5d0' :
                        v < circleColorArray[6] ? 'circle_b8e186' :
                        v < circleColorArray[7] ? 'circle_b8e186' :
                                                  'circle_4d9221';

    return {
        icon: L.divIcon({
            className: circle_colour,
            iconSize: [s, s]
        })
    };
}

enter image description here

2 Answers 2

4

A very similar answer to IvanSanchez, but you could switch from L.CircleMarker and use L.DivIcon to instead create your circle completely with CSS:

.circle {
  background: #0000ff; /* color of the circle */
  border-radius: 50%; /* make the div a circular shape */
  box-shadow: 4px 4px 3px grey; /* see http://www.w3schools.com/css/css3_shadows.asp */
  -moz-box-shadow: 4px 4px 3px grey;
  -webkit-box-shadow: 4px 4px 3px grey;
}

HTML:

var div_circle = L.divIcon({ className: 'circle'})
var marker = L.marker([51.509, -0.08], {icon: div_circle} ).addTo(mymap);

Here's an (updated) demo: https://jsfiddle.net/Lna57q3m/1/

6
  • That's pretty smart. The webkit-box-shadow does work on Chrome. Commented Feb 2, 2017 at 14:35
  • Thanks. :) I just changed the CSS slightly (horizontal and vertical offset changed from 10px to 4px) so that the shadow is aligned more like your image above (updated fiddle, too). Commented Feb 2, 2017 at 14:42
  • How would you size the circle? Commented Feb 2, 2017 at 14:52
  • 1
    Don't worry. I worked it out with iconSize. Let me update my demo. Commented Feb 2, 2017 at 15:04
  • 1
    You can have a look how it works in action on my dev server. It's the Media and Communications layer (only on Desktop) atap.geolytix.net/?geodata Commented Feb 2, 2017 at 15:26
2

If you are using the L.SVG renderer, you can use some CSS (as per this answer) and the className option of the L.CircleMarkers to achieve this.

e.g.:

<style>
.shadow {
  filter: drop-shadow( 5px 2px 5px #000 );
}
</style>

and then

var marker = L.circleMarker(myCenter, {
  className: 'shadow'
});
map.addLayer(marker);

See a working example at https://playground-leaflet.rhcloud.com/duyu/edit?html,output

If you are using a L.Canvas renderer for your points, you'll have to create duplicate elements.

3
  • 1
    Hi Ivan, great to hear from you. This works great on FF but I am having problem with the drop shadow on Chrome. I added a -webkit-filter but this doesn't seem to work. Have you got the example to work in Chrome? Commented Feb 2, 2017 at 14:27
  • No. Apparently support for this feature is not complete across all browsers. Commented Feb 2, 2017 at 15:15
  • No problem I got this to work with the L.divIcon solution + -webkit-box-shadow. Thanks anyways. Remind me to buy you a beer at the next FOSS4G. Commented Feb 2, 2017 at 15:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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