3

I have a map with 20 markers on a geojson layer. They are all from the same SVG and represent a certain area on the map (meaning they represent a circle of constant radius in meter on the map). I need these marker to adapt their size according to zoom level.

I've tried to use a circle as a marker. But my marker needs to be a SVG because it is complex graphic and radius doesn't apply to markers.

I think each time zoom level changes marker size should be resized proportionally to the new zoom level but I don't know how to achieve this.

He's how the markers are displayed, parsed from a csv sheet :

    for (i in chapters) {
        var c = chapters[i];
        if (!isNaN(parseFloat(c['Latitude'])) && !isNaN(parseFloat(c['Longitude']))) {
            var lat = parseFloat(c['Latitude']);
            var lon = parseFloat(c['Longitude']);
            var cercleDirection = parseFloat(c['Direction']);
            var photoIcon = L.icon({
                                iconUrl: 'media/Cercle.svg',
                                iconSize: [220, 220],
                                iconAnchor: [110, 110],
                            });
            markers.push(
                L.marker([lat, lon], {
                    icon: photoIcon,
                    rotationAngle: cercleDirection

                }));
        } else {
            markers.push(null);
        }

Another way maybe

I did find this approach online that seems interesting. But I couldn't have more explanation from the author that remains silent :

var layer = ''; // what would be the layer name in my case ?
map.on('zoomend', function() {
    var currentZoom = map.getZoom();

    //Update X and Y based on zoom level
    var x= 50/currentZoom; //Update x 
    var y= 50/currentZoom; //Update Y         
    var LeafIcon = L.Icon.extend({
        options: {
            iconSize:     [x, y] // Change icon size according to zoom level
        }
    });
    layer.setIcon(LeafIcon);
});

  • One possible solution would be to use L.svgOverlay layer. I played with it a bit and it works OK, but I just didn't have time to try/implement rotate. I'll be away for a few days. If nobody comes up with the solution till then, I'll continue. – TomazicM Sep 10 at 5:52
  • Thanks Tomazic. That will be very helpful !! – Laurent Sep 10 at 14:07
1

One possible solution is to use L.svgOverlay layer for resizable markers. In this case Leaflet takes care of resizing and placement of markers when zooming.

With this approach two problems have to be resolved:

  1. L.svgOverlay needs lat,lng bounds for SVG image. For this purpose L.circle layer can be used. Once created with given radius in meters, bounds can be obtained with getBounds() method. Since getBounds() method only works after layer is added to the map, it is added to temporary group layer which is removed at the end.
  2. Dynamically rotating SVG image used for L.svgOverlay layer is bit more complicated here. Since Leaflet adds it's own transform attribute to SVG when putting it on the map, this overrides any previous transforms, including rotation. Solution is to include SVG image as hidden inline HTML element and wrap actual graphics in <g> envelope on which rotation transform can be done dynamically.

Code below uses such hidden inline SVG element (arrow in circle), assuming that cercleDirection is angle of rotation:

<div style="display: none;">
  <svg id="svgMarker" viewBox="0 0 490.4 490.4" style="fill: blue">
    <g id="rotateElement">
      <path d="M245.2,490.4c135.2,0,245.2-110,245.2-245.2S380.4,0,245.2,0S0,110,0,245.2S110,490.4,245.2,490.4z M245.2,24.5
        c121.7,0,220.7,99,220.7,220.7s-99,220.7-220.7,220.7s-220.7-99-220.7-220.7S123.5,24.5,245.2,24.5z"/>
      <path transform="rotate(-90, 245.2, 245.2)" d="M138.7,257.5h183.4l-48,48c-4.8,4.8-4.8,12.5,0,17.3c2.4,2.4,5.5,3.6,8.7,3.6s6.3-1.2,8.7-3.6l68.9-68.9
        c4.8-4.8,4.8-12.5,0-17.3l-68.9-68.9c-4.8-4.8-12.5-4.8-17.3,0s-4.8,12.5,0,17.3l48,48H138.7c-6.8,0-12.3,5.5-12.3,12.3
        C126.4,252.1,131.9,257.5,138.7,257.5z"/>
    </g>
  </svg>
</div>

...

var tmpLayer = L.layerGroup();

var markerViewBoxWidth = 490.4;
var markerViewBoxHeight = 490.4;

var markerRadius = 5000;   // in map meters

var svgMarkerElement = document.getElementById("svgMarker");
var firstTime = true;

for (i in chapters) {
  var c = chapters[i];
  if (!isNaN(parseFloat(c['Latitude'])) && !isNaN(parseFloat(c['Longitude']))) {
    var lat = parseFloat(c['Latitude']);
    var lon = parseFloat(c['Longitude']);
    var cercleDirection = parseFloat(c['Direction']);

    var newSVG = svgMarkerElement.cloneNode(true);
    var rotateElement = newSVG.querySelector('#rotateElement');
    rotateElement.setAttribute('transform', 'rotate('+ cercleDirection + ',' + (markerViewBoxWidth / 2) + ',' + (markerViewBoxHeight / 2) + ')')

    var boundsCircle = L.circle([lat, lon], {radius: markerRadius, stroke: false, fill: false});
    boundCircle.addTo(tmpLayer);
    if (firstTime) {
      tmpLayer.addTo(map);
      firstTime = false;
    }
    var circleBounds = boundsCircle.getBounds();
    markers.push(L.svgOverlay(newSVG, circleBounds));
    } 
  else {
    markers.push(null);
  }
}

tmpLayer.remove();
  • Hi @TomazicM Thansk a lot for responding ! Actually I could have the code to work, there seem to be a syntax problem of some sort that I couldn't have sort out. I'm updating the original code with the end of it for a larger view. – Laurent Sep 16 at 9:34
  • I'm not sure I understand your comment. Your code doesn't seem to be updated. – TomazicM Sep 16 at 10:06
  • There"s a "else" condition at the very end that is on my original working code. I was wondering if the presence/absence of this condition would interfere in your code suggestion. – Laurent Sep 16 at 13:40
  • OK, I modified my code according to your change. – TomazicM Sep 16 at 14:57
  • Thanks Tomazic. Unfortunately, it doesn't work either. Seems like the display engine of the markers is broken, like if there was a syntax error I'ven't been able to spot. You're right about the Direction. It is used by a Leaflet Plugn to orientate the marker. By the way, I found another approach online (no answer from the author). I paste it at the end of my question for if it rings a bell to you. Thanks again for your time – Laurent Sep 16 at 15:22

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.