问题描述:

I've created a multiple choropleth map using the Mapbox tutorial, and would like to switch out the legends based on what the current data layer is.

This is the function I am trying to use to change the legend:

function changeLegend() {

var previousLegend = $('.map-legends').html()

map.legendControl.removeLegend(previousLegend)

map.legendControl.addLegend(getLegendHTML());

}

But it does not remove the legends properly, it just adds them on top of each other. When I remove the legends using jQuery instead of map.legendControl.removeLegend, the previous legend gets removed, but when I then call map.legendControl.addLegend, it adds 2 legends even though the function that generates the legend html is only hit once.

Could someone please help me get the legends removed and added properly?

网友答案:

After I checked how L.mapbox.legendControl works I think I may have a reason of your issue, let me first explain how it works under the hood

  • map.legendControl._legends is an object which saves legends as as keys, the value is the quantity of equal strings added through map.legendControl.addLegend, similarly map.legendControl.removeLegend decrements the value of the given key if it exists

e.g.

// at this point:
//   map.legendControl._legends = {}

map.legendControl.addLegend('<span>hello world</span>')
// at this point:
//   map.legendControl._legends = {
//     '<span>hello world</span>': 1
//   }

map.legendControl.addLegend('random string')
// at this point:
//   map.legendControl._legends = {
//     '<span>hello world</span>': 1,
//     'random string': 1
//   }

map.legendControl.addLegend('random string')
// at this point:
//   map.legendControl._legends = {
//     '<span>hello world</span>': 1,
//     'random string': 2
//   }

map.legendControl.removeLegend('random string')
// at this point:
//   map.legendControl._legends = {
//     '<span>hello world</span>': 1,
//     'random string': 1
//   }

Now that we know how it saves them, lets see how it renders them (this is done automatically every time you addLegend or removeLegend through its _update method

  • it iterates the _legend object, for each key found it will wrap the element with <div class="map-legend wax-legend"></div> and render it once per key (it actually uses _legend[some key] as a simple counter, it doesn't use it to render stuff)

Important note: if there's html in the key it will be sanitized first

The above example will then be rendered as

<div class="map-legend wax-legend"><span>hello world</span></div>
<div class="map-legend wax-legend">random string</div>

This is the content of the .map-legends container

<div class="map-legends wax-legends leaflet-control">
  <div class="map-legend wax-legend"><span>hello world</span></div>
  <div class="map-legend wax-legend">random string</div>
</div>

Back to your code you're doing var previousLegend = $('.map-legends').html() which as seen above will return you your legends wrapped inside <div class="map-legend"> and they won't be removed

A simple solution is to avoid using $('.map-legends').html() to get the previous inserted html, instead save it in a variable like this

var previousLegend;
function changeLegend() {
  if (previousLegend) map.legendControl.removeLegend(previousLegend)
  var newLegend = getLegendHTML();
  map.legendControl.addLegend(newLegend);
  previousLegend = newLegend;
}
相关阅读:
Top