I have a leaflet map with a few layers on it.
Whenever layers are not in the viewport, they are hidden untill panning has completed:
Regular view with layers:
Panning right, to show layers outside viewport:
Panning stopped:
As illustrated above, the layers will first become visible once panning has stopped and mouse(finger) released.
I have tried the following, which didn't work
var map = L.map('map',{ bounceAtZoomLimits: false, removeOutsideVisibleBounds: false}).setView([40, 0], 2);
L.geoJson(mapData).addTo(map);
Seems the solution was right in front of me
Adding the following will render the entire map:
var map = new L.Map('map');
map.getRenderer(map).options.padding = 100;
Solution found here
Related
I can't figure out why the radiusmap layer (first map shown) and the isochronemap layer (second map shown) don't scale correctly when I zoom in and out. The third map, which has the exact same layers, works just fine.
Here's the code for a) creating the circle and polygon layers and then b) adding them to the radiusmap, the isochronemap and finally, the combined map.
var isochrone = L.polygon(isochronedetails, {color: 'red'});
var radius = L.circle([radiuslat, radiuslng], {fillColor: circleStyle.color[0], fillOpacity: circleStyle.opacity[0],radius: radiusmeters});
radius.addTo(radiusmap);
isochrone.addTo(drivetimemap);
radius.addTo(combinedmap);
isochrone.addTo(combinedmap);
The code that is creating / initializing the three maps is here:
radiusmap = L.map('radiusmap').setView([radiuslat, radiuslng],10);
radiusmap.addControl(new L.Control.Fullscreen());
drivetimemap = L.map('drivetimemap').setView([isochronelat, isochronelng], 10);
drivetimemap.addControl(new L.Control.Fullscreen());
combinedmap = L.map('combinedmap').setView([isochronelat, isochronelng], 10);
combinedmap.addControl(new L.Control.Fullscreen());
And here's a gif of what happens on zoom in/out for each map. You'll see that when the zoom happens for the first two maps, the circle or polygon moves away from the original drawing position. But, on the third map, it behaves correctly.
https://screencast-o-matic.com/watch/cYe1VQx6pZ
What am I doing wrong? I just want the first two maps to behave like the third map. :-)
Simply do not add your layers (namely isochrone and radius) to several maps, but create different layers (possibly with same parameters) for each separate map.
Leaflet makes the assumption for simplicity that when a layer is added to a map, it belongs only to that map.
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.
Using Leaflet 0.7.3 and last version of markercluster (https://github.com/Leaflet/Leaflet.markercluster), I would like to reproduce a behavior I have been able to do using Google API and associated libraries (Google Marker Cluster V3 & Overlapping Marker Spiderfier V3).
When you have a map with your clusters and you click on one cluster, the API will zoom to bound the markers contained in this cluster. But when all your markers are exactly on the same position, the zoom will be set to its maximum value which is often ugly (no context around the markers or just one street). I would like to limit the zoom level when user click on one cluster with a code like this :
markers.on('clusterclick', function (a) {
map.fitBounds(a.layer.getBounds());
if (map.getZoom() > 14) {
map.setZoom(14);
}
});
With such code the zoom is correctly limited to 14 but the spiderfy is not done (even if I explicitly call a.layer.spiderfy(). Is there something I am missing ?
Here is the fiddle : http://jsfiddle.net/953u41ax/ (click for exemple on 36 then on 12)
Eric, you can achieve this by preventing zoom on click and then manually calling spiderfy on the layer.
Map Settings:
var stationsCluster = new L.MarkerClusterGroup({
maxClusterRadius: 60,
iconCreateFunction: null,
spiderfyOnMaxZoom: true,
showCoverageOnHover: true,
zoomToBoundsOnClick: false
Spidery Listener:
stationsCluster.on('clusterclick', function (a) {
a.layer.spiderfy();
});
You can set the maximum zoom level on the map:
map._layersMaxZoom=8
and then disable the clustering at the same zoom level:
var markers = L.markerClusterGroup({
disableClusteringAtZoom: 8
});
You can play around with this to get the desired effect, this is just an example. JSFiddle is here http://jsfiddle.net/953u41ax/2/
I want center my marker on popup open.. and centering map not in marker latlng, but on center of marker and popup!
The problem is that popup has dinamic content(loaded on click).
The map size is full display size in a mobile device!
I'm just used autoPanPadding option in popup but not sufficient
Refer to follow picture:
Using fitzpaddy's answer I was able to make this code which works and is much more flexible.
map.on('popupopen', function(e) {
var px = map.project(e.target._popup._latlng); // find the pixel location on the map where the popup anchor is
px.y -= e.target._popup._container.clientHeight/2; // find the height of the popup container, divide by 2, subtract from the Y axis of marker location
map.panTo(map.unproject(px),{animate: true}); // pan to new center
});
Ciao Stefano,
This is untested pseudocode, but Leaflet project/unproject functions should provide assistance.
i.e;
// Obtain latlng from mouse event
var latlng;
// Convert latlng to pixels
var px = project(latlng);
// Add pixel height offset to converted pixels (screen origin is top left)
px.y -= mypopup.height/2
// Convert back to coordinates
latlng = unproject(px);
// Pan map
map.panTo(latlng,{animate: true});
This depends on zoom scale being constant during calculation, so you might be required to pan the map and then calculate the pan offset to update correctly (using animation, this will only be a gentle transition).
Good luck!
Here's an easy solution:
First you center the map to your marker.
map.setView(marker.latLng);
Then you open the popup.
var popup.openOn(map); = L.popup()
.setLatLng(marker.latLng)
.setContent(dynamic-content)
.openOn(map);
Leaflet will automatically pan the map so the popup fits on the map. To make it look more beautiful you can add a margin-top to the popup with CSS.
My very simple solution keeps the current zoom level as well for better usability.
map.on('popupopen', function (e) {
map.setView(e.target._popup._latlng, e.target._zoom);
});
I have a Google V3 map which uses steetView and some map markers.
The little yellow streetView pegman sits on the map on top of the markers.
Is there a way to change the z-indexes so that my markers will be above the pegman
(so that they can be easlly clicked on without having to zoom in)?
In case anything is not clear, here is a fiddle....
http://jsfiddle.net/spiderplant0/BRkCA/
After a bit of experimenting I came up with this...
$("#map_canvas img[src*=cb_scout]").parent("div").css({'zIndex': -200});
$($("#map_canvas img[src*=cb_scout]")[1]).parent("div").parent("div").css({'zIndex': -200});
This forces the pegman to sit beneath the markers but now the pegman is no longer dragable and each time the map is moved etc, the pegman jumps above the markers again.
To keep the pegman under your markers you can watch for the pov_changed event and reset the z-index after a short delay
$google.maps.event.addListener(panorama, 'pov_changed', function() {
var func=function(){
$("#map_canvas img[src*=cb_scout]").parent("div").css({'zIndex': -200});
}
setTimeout(func,1000);
}
});
You will also need to change the depth of the pegman after the maps moves, which can be accomplished with the following snippet
google.maps.event.addListener(map, 'idle', function() {
google.maps.event.trigger(panorama, 'pov_changed');
})
If you want to be able to drag the pegman, you must first place it above the markers by having a toggle button swap the pegman's depth and add an exception to the pov_changed event handler preventing the pagman from dropping depths when the toggle button is active.
Okay, this may be a bit hacky... (and I hope I understood what you were doing)
1) Disable street view control
2) Make another control with a lower zIndex than the marker you have.
3) Update street view control with the position of the fake street view marker.
http://jsfiddle.net/z7Lp8/
You can set the zIndex of the marker above google.maps.Marker.MAX_ZINDEX in order for the pegman to remain under the marker. MAX_ZINDEX is the maximum default z-index that the API will assign to a marker. Marker z-indexes only work when optimizations are turned off on all markers on the map.
Forked fiddle from question to illustrate: http://jsfiddle.net/brendaz/t4v8nhoq/
var marker1 = new google.maps.Marker({
position: new google.maps.LatLng(54.975, -2.020),
map: map,
zIndex: google.maps.Marker.MAX_ZINDEX + 1,
optimized: false
});