Conditional drawing of markers based on zoom & extent

1,476 views
Skip to first unread message

Ishmael Smyrnow

unread,
Nov 2, 2012, 1:22:46 PM11/2/12
to leafl...@googlegroups.com
I'm drawing a large number of markers (>1,000), and for performance reasons, would like to have the ability to only show the markers at a certain range of zoom levels (lower levels), and only draw the markers which are in the visible area.

I'm considering creating a plugin for this, but am not entirely sure where to start. I think it would require creating a custom FeatureGroup, and adding/removing markers in the onMove or onZoomEnd events. However, wouldn't this require me to keep all of the markers loaded in memory?

I'd like to get a better sense of how to achieve this before starting a plugin.

Ishmael Smyrnow

unread,
Nov 2, 2012, 6:14:44 PM11/2/12
to leafl...@googlegroups.com
Through some guidance, I was able to create a plugin which will draw markers only for certain zoom levels, and also only within the map bounds.

The problem with my implementation is that I am redrawing everything after each zoom or move of the map. Someone mentioned that extending TileLayer gives me things like partial redraws, but I'm not sure how.

Any suggestions?

mic...@timeglider.com

unread,
Jan 5, 2013, 7:19:11 PM1/5/13
to leafl...@googlegroups.com

Hey there Ishmael

This was a couple months ago, but maybe still relevant.

My issues are different than yours, but I think we're after the same thing — the ability to gather
all the "Layer" objects (which can be icons, shapes, or tiles) at any point to manipulate them
(or gather info from them).  For me, I need to assign properties to icons such that when they're
clicked, I can affect other JS components on the page...

Here's what I came up with --- maybe it's relevant to you.

First, I created a method to get all the Layer objects in the map ------ these
include the icons, but also shapes and tiles.

L.Map.prototype.getLayers = function() {
return this._layers;
}

Also (as I don't see this anywhere in the API, but maybe it's there) I made a method to see whether 
any object with latlng values is visible in the frame. 

function isInBounds(latlng, bounds) {

var is_in_x_view = (latlng.lng < bounds._northEast.lng && latlng.lng > bounds._southWest.lng);
var is_in_y_view = (latlng.lat < bounds._northEast.lat && latlng.lat > bounds._southWest.lat);
return (is_in_y_view && is_in_x_view);
}

Finally I created a method to inspect the situation when the map is loaded, or when zoom/scope 
changes (using Underscore.js's "each()" for traversing the Layers). I also set a "test_id" value on 
every icon in the icon options when they were first created so that I'd have a hook into some related data.

      // m here is the central map object
      function inspectLayers(m) {

var bounds = m.getBounds();
var layers = m.getLayers();
var $layer_icon = {};
var inBnds = false;
var test_id = "";
_.each (layers, function (layer) {
if (typeof layer._icon != "undefined") {
$layer_icon = $(layer._icon);
test_id = layer.options.test_id;
inBnds = isInBounds(layer._latlng, bounds);
console.log("is (id:" + test_id + ") marker in bounds?:", inBnds);
                                        // if inBnds is true, you can manipulate the $layer_iconn
                                        // DOM object or do something else with layer.options data
}
});

}

I'd love to see your plugin, if you're able to share.

Best,
Michael Richardson


tags (getLayers, get layers, is an icon in bounds)


Ishmael Smyrnow

unread,
Jan 6, 2013, 9:09:41 PM1/6/13
to leafl...@googlegroups.com
Here is the plugin I made. It does some similar things to the code you posted, except that it manages a single layer internally, instead of working with all layers in the map.

As options, it takes minZoom, maxZoom, and viewportPadding. The first two are self-explanatory, but the last controls how far outside of the visible area to draw markers. For example, a value of "1" draws only markers in the viewport, while "2" pads the viewport by a factor of 2, and draws markers in that area.

Lastly, your function "isInBounds" can be replaced by L.Bounds.contains(L.LatLng).
leaflet.conditionalmarkers.js

Robert Gordon

unread,
Jun 8, 2013, 7:38:03 PM6/8/13
to leafl...@googlegroups.com
Would it be possible for you to show a small example of how to implement this script?
Thank you!

Ishmael Smyrnow

unread,
Jun 9, 2013, 9:53:13 PM6/9/13
to leafl...@googlegroups.com
The plugin is for a custom layer that extends leaflet's FeatureGroup. Include the plugin on your page, then after initializing the map, add the new layer.


      // Initialize markers
      var markerLayer = new L.ConditionalMarkers({
        minZoomShow: 16,
        viewportPadding: 0.0
      });
      markerLayer.addTo(map);

Then, add markers to your layer as you would normally, using markerLayer.addLayer().


Once you've added all of your markers to the layer, you should be able to see markers redrawing as you pan.


--
 
---
You received this message because you are subscribed to a topic in the Google Groups "Leaflet" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/leaflet-js/fiuubelyKzI/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to leaflet-js+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Ralf Schieferdecker

unread,
Jul 13, 2014, 2:11:59 AM7/13/14
to leafl...@googlegroups.com
Thanky you Ishmael 
Your plugin works very good for me!
Good Work!
Reply all
Reply to author
Forward
0 new messages