简体   繁体   中英

Leaflet map with popup above legend

I have a situation where I have a map with a custom legend formatted as either an SVG or a PNG. The legend is always placed in the bottom left corner but can be quite large (user can turn it off and on).

The map also has many markers. Each marker will have a tooltip, which can also be large-ish. Tooltips show when the mouse is hovering over the marker. The problem arises when a user hovers over a marker close to the legend - the tooltip appears behind the legends. I'd like to make it so the popups appear above the legend. So, from bottom to top: marker, legend, marker popup.

Here is a JSFiddle https://jsfiddle.net/e51mydwa/9/ to describe what I mean. I add the legends in the same way, although the < div id="legend"> tag contains a < img> or < svg> in reality.

<div id="map">
  <div id="legend">
    I am Legend
  </div>
</div>

I've had a look at http://leafletjs.com/examples/choropleth/ , but as you can see by inspecting the DOM, this will suffer the same problem, as the legend is added into the same div as the leaflet controls, which is always above the map layers (as it should be, controls should always be at the top).

I've also tried inserting the legend into a div which is on a sibling layer to the popup containing layer. This fixes the z-index issue, however the parent div of both of these contains a transform which changes as the user drags the map around - meaning the legends change places and aren't static.

Any and all suggestions appreciated.

This requires some heavy hacking, due to the architecture of the Leaflet layers and controls.

One possible approach is to make a custom layer class which stays in a static position, by repositioning its pixel offset at every change of the map's view.

I heartily recommend reading the Leaflet tutorials , in particular the one about map panes and the one about custom layers, to understand how this works.

// Create a 'static' map pane
L.Map.addInitHook(function(){
  this.createPane('static');
  this.getPane('static').style.zIndex = 675;
});

// Define a custom layer class
L.Layer.StaticOverlay = L.Layer.extend({
  onAdd: function(map) {
    this._map = map;

    var pane = map.getPane('static');
    this._container = L.DomUtil.create('div');

    pane.appendChild(this._container);

    // styling, content, etc
    this._container.style.background = 'white';
    this._container.style.width = '100px';
    this._container.style.height = '50px';
    this._container.innerHTML = 'Hi!'


    map.on('move zoom viewreset zoomend moveend', this._update, this);

    this._update();
  },

  onRemove: function(map) {
    L.DomUtil.remove(this._container);
    map.off('move zoom viewreset zoomend moveend', this._update, this);
  },

  _update: function() {
    // Calculate the offset of the top-left corner of the map, relative to
    // the [0,0] coordinate of the DOM container for the map's main pane

    var offset = map.containerPointToLayerPoint([0, 0]);

    // Add some offset so our overlay appears more or less in the middle of the map
    offset = offset.add([340, 220]);

    L.DomUtil.setPosition(this._container, offset);

  }
});

When that's defined, you can simply

var static = new L.Layer.StaticOverlay().addTo(map);

Obviously there are some bits missing, such as how to position the overlay properly (get the map pixel size with getSize() , do the proper arithmetic), and how to set the contents of the overlay with some custom options in the layer constructor.

These are left as an exercise to the reader :-)

See a working example here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM