Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LeafletJS L.DivIcon HTML marker text - scale relative to map zoom

So I'm using the latest version of leaflet (v1.0.2), and am trying to dynamically apply text labels to specific lat lng points on a custom (geo aligned) map.

My issue is that I need the text on the map to maintain it's the size (as though the text is actually part of the tile image) when zooming. Using a Marker of any kind results in the text staying at its correct size. If I use something like an image overlay and add an SVG with text in, it scales with the map zoom.

I've noticed that the image overlay has a CSS3 scale added to its transform property when zooming whereas the marker does not.

Can I extend the marker to scale as the image overlay does?

I've already written code that listens to the zoom event and adjusts the font size of markers but this is CPU intensive (especially for mobile browsers) and I don't really want to render the text dynamically within svgs either!

I've provided a demo so that this makes more sense. You can see that example_1 (the marker) maintains it's size however far you zoom in or out. Example_2 (the svg image) scales relative to the map when zooming. This (Example_2) is what I'm trying to get an L.DivIcon with html text content to do!

Any help or suggestions are appreciated!

https://jsfiddle.net/z96L7hdu/

Example Code

HTML

<div id="map" style="width:500px; height:600px;"></div>

JavaScript

var map = L.map('map', {
  zoomSnap: 0
}).setView([0, 0], 3);

L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

var img = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciICAgICB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiB2aWV3Qm94PSIwIDAgNTAwIDQwIj4gIDx0ZXh0IHg9IjAiIHk9IjAiIGZvbnQtZmFtaWx5PSJWZXJkYW5hIiBmb250LXNpemU9IjM1Ij4gICAgRXhhbXBsZV8yICA8L3RleHQ+PC9zdmc+";

imageBounds = [[-8.636810901898114, -12.135975261193327], [-18.28136415046407, 17.181122017133486]];
L.imageOverlay(img, imageBounds).addTo(map);

var myIcon = L.divIcon({className: 'my-div-icon', html:"Example_1"});
L.marker({lat: 0.7800052024755708, lng: 0.010986328125}, {icon: myIcon}).addTo(map);
like image 732
Ross Avatar asked Dec 11 '16 01:12

Ross


1 Answers

Apologies for the late answer, but I thought it was an interesting question. You can indeed extend the L.Marker class, to create markers that resize the font of their DivIcon to match the zoom level:

L.FixedSizeMarker = L.Marker.extend({
  options: {
    fontSize: 12,   // starting size of icon in pixels
    zoomBase: 3     // Zoom level where fontSize is the correct size
  },
  update: function () {
    if (this._icon && this._icon.tagName === 'DIV' && this._map) {
      let size = this.options.fontSize * Math.pow(2, (this._map.getZoom() - this.options.zoomBase));
      this._icon.style.fontSize = size + 'px';
    }
    return L.Marker.prototype.update.call(this);
  }
});
L.fixedSizeMarker = (latlng, options) => new L.FixedSizeMarker(latlng, options);

The code above defines a new FixedSizeMarker, which behaves just like a normal Marker, but if you add a DivIcon to it, it will resize the font. It takes two options, to specify the font size in pixels, and the zoom level that you want that font size to be correct for. In the example in the OP's JSFiddle, you would use it like this:

var myIcon3 = L.divIcon({className: 'my-div-icon', html:"Example_3"});
L.fixedSizeMarker({lat: 0.7800052024755708, lng: -12.135975261193327},
                  {icon: myIcon3, fontSize: 24, zoomBase: 3}).addTo(map);

When using these markers, it may look better to set {markerZoomAnimation: false} in the map options. The marker size change is otherwise quite obvious when you zoom the map.

like image 181
JRI Avatar answered Nov 07 '22 08:11

JRI