I'm using LeafletJS to display maps in a number of places on my site.
In most cases, it is working fine, but on one specific page I am getting a weird rendering glitch, which looks like this:
As you can see, the map is rendering with vertical grey bars at each tile boundary. Additionally, if I add markers to the map, they also display squashed.
The weird thing is that I'm using the same code (ie the exact same JS file) to render similar maps on other pages without any problems. I'm also using similar code to render two other maps on the same page, again without problems.
The JS code looks like this:
(function(L) {
var element = document.querySelector('.details-map');
if (!element) { return; }
var coords = element.getAttribute('data-coords');
var latlng = coords.split(',');
var location = {lat: parseFloat(latlng[0]), lng: parseFloat(latlng[1])};
var zoom = element.getAttribute('data-zoom');
var map = new L.Map(element, {center: location, zoom: zoom, gestureHandling: true});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors',
}).addTo(map);
})(L);
And the associated HTML looks like this:
<div class="details-map" data-coords="51.5216,-0.71998" data-zoom="14"></div>
The rendering glitch occurs at all zoom levels and persists after the doing things like map.invalidateSize() to force a redraw.
Can anyone explain why I'm getting this glitch and how to fix it? Thank you.
After much digging, I finally resolved this.
The problem was some CSS that was linked to an element some distance further up the DOM tree, and not really relevant to the map. It looks like this:
.local-branch img {
vertical-align: top;
display: inline-block;
width: 25%;
padding: 0 10px;
}
The intention of this CSS is to lay out a set of images related to the branch. The map is being added later as part of the branch details, within the .local-branch element. The styles are obviously not intended to apply to the map, but are applying anyway as the CSS selector is too broad.
I'll need to find a way to fix it that doesn't break the existing image layout, which still needs some thought, but at least I've worked out what was going on, so the mystery is solved.
Related
I have a leafletmap that only renders into one corner. When I resize the browser window, the whole map renders.
That is how I invoce the map
var map = L.map('map',
{ crs: L.CRS.EPSG3857 }
).setView([105.2, 100], 6);
var tiles = L.tileLayer('http://stamen-tiles-{s}.a.ssl.fastly.net/toner/{z}/{x}/{y}.{ext}', {
attribution: 'Map tiles by Stamen Design, CC BY 3.0 — Map data © OpenStreetMap',
subdomains: 'abcd',
ext: 'png'
}).addTo(map);
And this is my css
.myContainer {
width: 1024px;
height: 800px;
position: relative;
}
.map {
width: 1024px;
height: 800px;
z-index: 0;
}
The map is wrapped in a container. Everything I found online regarding this problem points to relative sizes in the map- or its parent container. However, I have absolute sizes. I load the .css before the .js (where I initialize the map). The map will be displayed not on the startpage, but when you click on a submenue point.
Why is the map not rendered properly?
The map will be displayed not on the startpage, but when you click on a submenue point.
You're initializing the map on a hidden or zero-size container, which makes this question a duplicate of 2nd leaflet map not rendering correctly
The answer is the same: run map.invalidateSize() whenever the map should become visible, or when you change its dimensions or visibility.
As IvanSanchez stated, map.invalidateSize() is indeed the way to go.
A useful code example for map refresh every 2 seconds in Javascript would be:
//Using setInterval can help the reloading or refreshing of the map itself.
setInterval(function() {
map.invalidateSize();
}, 2000);
...Note that setInterval() counts time in milliseconds so for example , 2000 are 2 seconds.
map in map.invalidateSize() is the name of the variable you set your map to when you initialized it:
Map initialization example:
var map = L.map(...
I have a full page map, and what I would like to do is fix a polygon/rectangle over a portion of the map like such, so that the polygon will remain in the same place even if, say, the map was dragged. Then, I would like to set the center of the polygon to whatever the search query might be. Here is another image to illustrate what I mean. Unfortunately, from the documentation it seems as if you can only create polygons in another layer that remain attached, so to speak, to specific tiles on the base map. In addition to that, aside from setting its bounds, the documentation does not list any methods to set the center of a polygon.
Thus I have a couple of questions:
Is it even possible to fix a polygon/rectangle on the map, not in relation to but, independent of the positions of map tiles in the base layer?
Is it possible to set the center of a polygon/rectangle to a LatLng Object (or something similar), and then use this orientation to position the map as a whole?
P.S. If you're going to downvote my question, at least state why and give me a chance to address whatever your issue with the question might be...
I would recommend absolute positioning a div like this
<div id="mapdiv">
<div id="rect"></div>
</div>
and the css
#mapdiv {
position:relative;
width:600px;
height:400px;
background-color:#333;
}
#rect {
position:absolute;
top: 10%;
left: 10%;
width:80%;
height:80%;
background-color:#FFF;
}
as for using the co-ordinates and polys through the map. I have some experience with routes and such and would have to say it possible to get the shape but you would require a map refresh each time and for absolute positioning it. Not sure if thats possible
Sorry for that last answer...misunderstood. Have you tried this plus adding an offset of window width
function polygonCenter(poly) {
var lowx,
highx,
lowy,
highy,
lats = [],
lngs = [],
vertices = poly.getPath();
for(var i=0; i<vertices.length; i++) {
lngs.push(vertices.getAt(i).lng());
lats.push(vertices.getAt(i).lat());
}
lats.sort();
lngs.sort();
lowx = lats[0];
highx = lats[vertices.length - 1];
lowy = lngs[0];
highy = lngs[vertices.length - 1];
center_x = lowx + ((highx-lowx) / 2);
center_y = lowy + ((highy - lowy) / 2);
return (new google.maps.LatLng(center_x, center_y));
}
Again as for absolute positioning it after that I am still not quite certain
Might be a good starting point tho
Edit: found this link here on stack should actually work without knowing your setup how-do-i-get-google-maps-to-show-a-whole-polygon
I'm trying to create a small example using Leaflet and use it on my web app, however I'm having some dificulties.
I already made a standalone Leaflet example from the quick start guide of their page, which has a static map div and overlays a few objects (marker, circle and polygon).
However in my app, the map div container is positioned and sized dynamically with jquery, and it's a pretty complex app so I can't post here the whole code.
The problem is that after the correct processing of the div the map is drawn correctly in the div (wherever it is), however in the overlays layer I can only see the marker. The circle and polygonare not visible.
var map = L.map(this.$el.attr('id')).setView([51.505, -0.09], 13);
L.tileLayer('http://{s}.tile.cloudmade.com/<APIKEY>/997/256/{z}/{x}/{y}.png', {
attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © CloudMade',
maxZoom: 18
}).addTo(map);
var circle = L.circle([51.508, -0.11], 500, {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
}).addTo(map);
var polygon = L.polygon([
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047]
]).addTo(map);
var marker = L.marker([51.5, -0.09]).addTo(map);
marker.bindPopup("<b>Hello world!</b><br>I am a popup.");
circle.bindPopup("<b>Hello world!</b><br>I am a popup.").openPopup();
I believe there's nothing wrong in the way I create the map and objects and I even call map.invalidateSize() after the whole resizing of the div. And the curious part is that the popup is shown in the correct position, but no circle behind it.
Could the problem be in the way I resize and position the div containers. Is there any specific CSS property I should be using in the div container?
Thanks for all the help.
After sleeping on this problem I thought about making a JSFiddle example to reproduce the issue.
However no matter how hard I tried I couldn't replicate the issue in a simpler standalone example, so the problem had to be in some conflict within my app.
Every symptom pointed to a CSS problem, however my CSS was well scoped.
So my last theory was that it had to be a conflict in some library I was using.
It turned out to be correct. The problem was a conflict in the CSS stylesheet of the library NVD3
I have a number of pins on the map and a few metheods to allow me to click on a pin and the infobox will popup. This seems to be working fine apart from the infobox itself is below the Pins. I have tried setting the zIndex of both the pins and the infobox in a number of differant ways but still the infobox is below the pins. Any thoughts on how to achieve this?
For me, setting the .Infobox style did not work, but wrapping the infobox within it's own entity collection, and setting the zIndex on that, did work. I also tried quite a number of variations on setting zIndexes on my pushpins and pushpin collection entities before trying this option. Perhaps we are seeing this behavior only because we are putting pushpins within their own entity collections, but trying to add the InfoBox seperately.
Some example code of what works for me:
var infoBox = CreateMyInfoBox(); // create the Microsoft InfoBox here.
var entityCollectionInfoBox = new Microsoft.Maps.EntityCollection({zIndex:2000});
entityCollectionInfoBox.push(infobox)
map.entities.push(entityCollectionInfoBox);
There's no obvious semantic difference between setting a high z-Index on the infobox directly, and wrapping it in an EntityCollection with a high z-Index, but apparently there is.
For me the following worked, not very nice but better than having the pins above the Infobox
<style type="text/css">
.Infobox
{
z-index:150;
}
</style>
Set these three values on the Infobox:
zIndex: google.maps.Marker.MAX_ZINDEX + 1,
pane: "floatPane",
enableEventPropagation: false
Did work for me.
I have two different types of pushpins - each type has an infobox. I set the zIndex of the first set of pushpins to -2, the second set of pushpins to -1 and left the infobox alone - since it didn't care what I set the zIndex to.
Based on samples, I can see that you can set a default view in OpenLayers by saying something along the lines of:
var bounds = new OpenLayers.Bounds(-125, 25, -65, 50);
var map = new OpenLayers.Map('map', {restrictedExtent: bounds });
However, this also (as the name implies), restricts me to be able to ONLY navigate within these bounds. I can zoom out and see things outside of these bounds, but I can't then zoom back onto them, or scroll to them.
I've tried not having any restrictedExtent (or making it the entire map), but then I can't get it to focus on the area I want. I tried using:
map.setCenter(new OpenLayers.LonLat(0,0), 3);
console.log(map.getCenter());
To set the zoom and the center...but it doesn't seem to do ANYTHING, other than set the variable "center" which I can then read from map.getCenter() (if I don't set it, it's null, if I do set it, I can see it...but the map itself stays fully extended and it's center doesn't seem to change at all...)
The Map layer I am using is:
OpenLayers.Layer.OSM.Mapnik
with displayOutsideMaxExtent set to true... I'm really at a loss here.
My goal is to have a default region of the world zoomed in to and in view (such as the United States), with the option of viewers being able to go outside the default to view things.
I think I've figured it out. For whatever reason, the zoom was never changing, but the center apparently WAS moving (it was just so zoomed out I couldn't tell). Add to the fact that I needed to transform the center to use the google projection, and it seems to work just fine.
What I ended up doing was:
var lonlat = new OpenLayers.LonLat(20,37).transform(new OpenLayers.Projection("EPSG:4326"),new OpenLayers.Projection("EPSG:900913"));
map.setCenter(lonlat);
map.zoomTo(4);