Leaflet: misalignment of tiles and negative y coordinates - javascript

I am trying to generate a custom non-geographical map with Leaflet using my own tiles.
For the moment I created 10x10 dummy tiles of size 256x256px each with a random solid color using imagemagick.
They are placed in public/map-tiles/1/map_x_y.png where x takes values from 0 to 9 (resp. y).
Since this is a non-geographical map, I paid attention to change crs to L.CRS.Simple (see http://leafletjs.com/examples/crs-simple/crs-simple.html):
var map = L.map('map', {
minZoom: 1,
maxZoom: 1,
center: [0, 0],
crs: L.CRS.Simple
}).setView([0, 0], 1);
L.tileLayer('/map-tiles/{z}/map_{x}_{y}.png', {
bounds: [[0, 0], [2560, 2560]],
tms: true
}).addTo(map);
However this produces tiles slightly shifted and thus misaligned:
Also, tiles with negative y coordinates are fetched, which results in 404d requests, as seen in the console.
What can be the cause of this behavior?
EDIT 1: as IvanSanchez pointed out, the misalignment was caused by the missing leaflet.css stylesheet.
I still have the problem with negative coordinates. As suggested, I added bounds (see updated code above). Observations:
with bounds [[0, 0], [2560, 2560]]: no tiles displayed altogether, blank screen.
with bounds [[-1280, -1280], [1280, 1280]]: all tiles displayed, but negative tiles fetched (eg (5,-1)) resulting in 404s.
EDIT 2: after several tests it looks like the negative tiles are indeed the product of the y-axis handling (http://leafletjs.com/examples/wms/wms.html). The origin is top left, y going downward. I expected the tiles below the origin to be fetched, not above.
What I tried in order to keep my convention with x and y both increasing (that is x increases to the right, y increases downward, tiles with positive coordinate components are fetched from 0 to 9):
setting tms: true for tileLayer. No success, tiles with negative y are still fetched .
changing {y} to {-y} in the tileLayer source path. Results in Error: No value provided for variable {-y}. My script is using Leaflet 1.3.1.

In a map with L.CRS.Simple, all TileLayers have infinite bounds by default.
If you want a TileLayer to request tiles only in a given area, read the Leaflet API documentation, specifically a TileLayer option named bounds (inherited from GridLayer options). Let me quote:
bounds
type LatLngBounds
default undefined
If set, tiles will only be loaded inside the set LatLngBounds.
You also mention:
Weirdly enough, it tries to fetch tiles with negative coordinates [...]
That's not weird, it's behaviour as designed. There is nothing inherently wrong (nor weird) with negative coordinates, and negative tile coordinates are valid and documented in some tile standards
So if you have 10x10 tiles of 256px in size ranging from [0, 0] to [10, 10], you might want something like
L.tileLayer('/map-tiles/map_{x}_{y}.png', {
bounds: [[0, 0], [2560, 2560]]
}).addTo(map);
If the center of your data is the [0, 0] point and your tiles span from [-5, -5] to [5, 5] you might instead want something like
L.tileLayer('/map-tiles/map_{x}_{y}.png', {
bounds: [[-1280, -1280], [1280, 1280]]
}).addTo(map);

The problem boils down to two aspects:
misalignment: the leaflet.css stylesheet was missing and simply needed to be linked to in the HTML of the page.
negative tiles fetched: for Leaflet the y-axis goes downward. I expected tiles to be fetched from left to right, top to bottom with an origin set to the top left corner. Instead, negative y's were fetched. Since my tiles' names are map_x_y.png where x and y take values in {0:9}, this resulted in 404d requests. Setting negative bounds fixed the issue with bounds: [[0,0],[-1230,1230]] (notice the minus sign). 1230 corresponds to the number of tiles at zoom 0 times the size in pixel of one tile.

Related

Overview Map to show always whole map

I use open layers 4 and I want that Overview Map to show always a whole map in central position, only the red box should move around overview map.
Specifying a overview map view with a single resolution and extent (i.e. center constraint) will work as long as the main map isn't panned so far that the center constraint on the overview is exceeded. e.g. this will give an almost global overview
new ol.control.OverviewMap({
view: new ol.View({
resolutions: [ol.tilegrid.createXYZ().getResolution(0)],
extent: [0, 0, 0, 0]
})
})
If you are using 2180 trying to show a world overview is going to cause reprojection errors! The overview will also need to be in EPSG:2180 with resolution and center constraint appropriate for that
new ol.control.OverviewMap({
view: new ol.View({
projection: 'EPSG:2180'
resolutions: [ ?? ],
extent: [x, y, x, y]
})
})
where ?? needs to be large enough to get all of Poland (and a bit more) in the overview and x, y is somewhere in the center of Poland in EPSG:2180 coordinates.

Preciseness of leaflet measurement conversions

map.layerPointToLatLng(map.latLngToLayerPoint(L.latLng(40.687, -73.9035)))
results in
{lat: 40.686886382151116, lng: -73.90228271484375}
The imprecizeness seems to be unreasonably high, especially for the longitude.
map.getZoom()
results in
9
map.getSize()
results in
{x: 1335, y: 430}
Is there a way to increase preciseness?
If I understand correctly, you first convert your LatLng to a pixel position on your current map view (zoom 9, whatever view port dimensions).
Then you convert that pixel position back to a LatLng, and notice a discrepancy with your original LatLng.
It seems to me that you simply observe the effect of pixel rounding: map.latLngToLayerPoint will give you integer pixel coordinates, hence your precision will be no better than what a pixel covers in terms of actual distance.
At zoom 9 and New York latitude (40.687), the scale is about 20km for 86px, so about 230m per pixel.
The distance between the 2 LatLng coordinates you report is about 103m. Therefore it is well within a single pixel.
Live demo: https://jsfiddle.net/3v7hd2vx/149/ (results are printed in the console)
You can play with map zoom to see the precision improving, as each pixel will cover a smaller distance (area actually).

Global map tiles disappear past zoom level 19

I use OpenStreetMap with Leaflet.js.
I have a map with an indoor picture on it. The problem is when I zoom in, streets disapears. Do you know anything that can solve this plz? Tricks or tips!
EDIT:
// Load the Map
this.map_ = L.map($(selector)[0], {
center: [
48.8459382,
2.2863024,
],
maxZoom: 24,
zoom: 20,
});
I guess you have used map.options.maxZoom at a high number to let the user zoom to see your indoor image details.
However, OSM tiles are not available past zoom level 19, so the server returns 404 errors and your tiles are replaced by the Error Tile (or just a grey tile if not specified).
In that case, you would simply need to use these 2 options (together) on Tile Layer to tell Leaflet to re-use tiles from a lower zoom and to expand them:
maxNativeZoom set at 19.
maxZoom set at whatever you need, and equal to map.options.maxZoom if specified.
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
maxNativeZoom: 19, // OSM max available zoom is at 19.
maxZoom: 22 // Match the map maxZoom, or leave map.options.maxZoom undefined.
}).addTo(map);
Demo: http://jsfiddle.net/ve2huzxw/68/

Leaflet: Are custom zoom levels possible?

Is it possible to have intermediate (2.5, 3.5, 4.5, etc.) zoom levels on a Leaflet map that is using Stamen Toner-lite tiles? This is the code I have so far that calculates the zoom level:
leafletmap.on('zoomstart', function (d){
targetZoom = leafletmap.getZoom(); //Grabs whatever current zoom level is
targetZoom = targetZoom +.5; //Adds .5
leafletmap.setZoom(targetZoom); //Sets new value to zoom level
console.log(targetZoom); //Consoles out new value
});
I tried just adding .5 to the code, but I get a too much recursion error, so I'm guessing it's not that simple. Any help or direction is greatly appreciated!
In version 1.0.0, Leaflet introduced fractional zooming:
https://leafletjs.com/examples/zoom-levels/#fractional-zoom
Before this, the zoom level of the map could be only an integer number
(0, 1, 2, and so on); but now you can use fractional numbers like 1.5
or 1.25.
...
If you set the value of zoomSnap to 0.5, the valid zoom levels of the
map will be 0, 0.5, 1, 1.5, 2, and so on.
If you set a value of 0.1, the valid zoom levels of the map will be 0,
0.1, 0.2, 0.3, 0.4, and so on.
The following example uses a zoomSnap value of 0.25:
var map = L.map('map', {
zoomSnap: 0.25
});
As you can see, Leaflet will only load the tiles for zoom levels 0 or
1, and will scale them as needed.
Leaflet will snap the zoom level to the closest valid one. For
example, if you have zoomSnap: 0.25 and you try to do
map.setZoom(0.8), the zoom will snap back to 0.75. The same happens
with map.fitBounds(bounds), or when ending a pinch-zoom gesture on a
touchscreen.
To be straight to the point: This is not possible. You would need to render your own tile-images, run them of your own server and create your own coordinate reference system (CRS) extension for Leaflet. If you look at how regular tilesets are made you'll understand why.
The URL for requesting tiles for stamen:
http://{s}.tile.stamen.com/toner/{z}/{x}/{y}.png
When requesting tiles, the {z} will be replaced with the map's current zoomlevel. The {x} and {y} are the coordinates for the tile. The {s} will be replaced with a subdomain. So if your at zoomlevel 6 at coordinate 1,1 it would try to load:
http://a.tile.stamen.com/toner/6/1/1.png
Now if you could (but you can't) zoom to level 6.5 it would try to load:
http://a.tile.stamen.com/toner/6.5/1/1.png
Those tiles simple don't exists on the stamen server and thus return a 404 for file not found. You can try for yourself just use these links:
http://a.tile.stamen.com/toner/6/1/1.png
http://a.tile.stamen.com/toner/6.5/1/1.png
http://a.tile.stamen.com/toner/7/1/1.png
So that will never work. You could, as said, run your own tile server, render your own tile images and setup your own L.CRS. You might want to take a look at this question too: Adding an extra zoom levels in Leaflet Maps

Using ClusterProvider in Nokia/Here Maps Javascript API, invalid cluster numbers

I'm trying to add the cluster to my application and so far, everything works.
However, the number of items in clusters seems to be invalid depending on zoom levels.
For example, I add 3 marker in a range of about 30 feets. If I'm zoomed in all the way, I see all 3 markers. If I zoom out just a few steps, I can see 2 markers plus a cluster indicating 3 items.
I attached a picture, top part of the pictures shows the problem. If I zoom in a bit, it shows the bottom part of the picture. If I zoom out more, it shows a cluster of 3.
Thanks
Try fiddling around with the ClusterProvider.Options. Obviously all clustering algorithms are an approximation of the actual data set, and maybe the particular distribution of points you have just doesn't look good at a high zoom using the defaults.
Here are three suggestions to try:
Lower the eps value to get a finer grid.
Set max and min or minPts to avoid clustering at lower levels.
Set the strategy to STRATEGY_GRID_BASED rather than use the density default.
e.g. something like this:
function clusterDataPoints(data){
clusterProvider = new nokia.maps.clustering.ClusterProvider(map, {
eps: 5,
minPts: 5,
min: 18,
strategy: nokia.maps.clustering.ClusterProvider.STRATEGY_GRID_BASED,
dataPoints: data
});
clusterProvider.cluster();
}
And keep altering the parameters until it "looks right"

Categories

Resources