PNG Overlay not correct using L.CRS.EPSG3857 projection - leaflet

I am using leaflet and openstreet maps. I created a png using EPSG3857 however the image is not laying correctly on the map.
if you look at the Baja Region and Florida you will see the data on land. The data should be over the water not the land.
var map = L.map('map', { editable: true },{crs: L.CRS.EPSG3857}).setView(initialCoordinates , initialZoom),
tilelayer =
L.tileLayer(url_tile,
{
noWrap: true,
maxZoom: 12, minZoom: 2, attribution: 'Data \u00a9 OpenStreetMap Contributors Tiles \u00a9 HOT'
}).addTo(map);
var overlay_image = 'images/webmercator-google.png';
imageBounds = [[-90, -180], [90, 180]];
L.imageOverlay(overlay_image, imageBounds, { opacity: 0.8 }).addTo(map);

When using EPSG:3857, Leaflet clamps all latitude data to +/-85.05° (or, to be precise, +/-20037508.34 on the EPSG:3857 Y coordinate). This is done to prevent data appearing outside of the coverage area of default EPSG:3857 tiles.
To illustrate this, consider the following bit of code:
for (var i=83; i<90; i+=0.1) {
L.marker([i, i]).addTo(map);
}
That should (naïvely) display a lot of markers in a diagonal-ish line. But when actually doing that, the result looks like:
See how the markers don't go north of the 85.01° parallel, and how that fits the limit of tiles (blue sea versus grey out-of-map background).
Remember, EPSG:3857 and any other (non-traverse, non-oblique) cylindrical projections cannot display the north/south poles because they get projected to an infinite Y coordinate.
OK, so what does this have to do with your problem? You're using:
imageBounds = [[-90, -180], [90, 180]];
But, since Leaflet will clamp latitudes, that's actually the same as doing:
imageBounds = [[-85.01, -180], [85.01, 180]];
Keep this in mind when using L.ImageOverlays that cover areas near the poles. You probably want to recreate your image using a narrower band of latitudes.

Related

Converting from WGS84 to EPSG:27700 raster tiles without drawing a map

Using this example from OS Data Hub - https://labs.os.uk/public/os-data-hub-examples/os-maps-api/zxy-27700-basic-map
I can get a list of tiles displayed on the map, I would like to get the coordinates of the tile without drawing the map.
Starting from a single point in WGS84 (lat/long) I can convert this to EPSG:27700 using Proj4js
var source = new proj4.Proj('EPSG:4326');
proj4.defs("EPSG:27700","+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs");
var dest = new proj4.Proj('EPSG:27700');
var coords=proj4.transform(source, dest, [X,Y]);
I then need to translate this into coordinates for the raster tile, which is done in the leaflet example with this code:
var crs = new L.Proj.CRS('EPSG:27700', '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 +units=m +no_defs', {
resolutions: [ 896.0, 448.0, 224.0, 112.0, 56.0, 28.0, 14.0, 7.0, 3.5, 1.75 ],
origin: [ -238375.0, 1376256.0 ]
});
How can i replicate this step to produce the tile coordinates, without having to draw the leaflet map?
I ultimately want to use the coordinates to grab & save a single tile from the OS Data Hub with this format:
https://api.os.uk/maps/raster/v1/zxy/layer/%7Bz%7D/%7Bx%7D/%7By%7D.png?key=
Using the EPSG:27700 coords calculated using proj4, and the zoom level resolutions (which are meters per pixel) and tile grid origin coordinates used in the definition you can calculate the {x} and {y} values in https://api.os.uk/maps/raster/v1/zxy/layer/{z}/{x}/{y}.png?key= for any zoom level {z} based on the standard tile size of 256 pixels as
x = Math.floor((coords[0] - origin[0]) / (resolutions[z] * 256));
y = Math.floor((origin[1] - coords[1]) / (resolutions[z] * 256));

How can I ensure that labels align with GeoJSON

I have a very large map project which uses labels (and only labels from mapbox. That is, I don't get any boundaries or terrain from mapbox.)
I bring those vector tiles into Leaflet Using mapbox-gl-leaflet.
Generally, everything works great. However as soon as the map is taller than it is wide, the labels no longer align with the countries (which have been drawn as polygons using GeoJSON). Here is a pic of what happens and the relevant code is below.map with labels unaligned
map with labels not alignted
Any thoughts or insights would be helpful. Here is the code that brings in the tiles:
settings.globalVariables.labelTiles = L.mapboxGL({
accessToken: myAccessToken,
style: 'mapbox://styles/markslawton/ckgsqyzhi0diy19rwi98mlt4g',
pane: 'labels',
}).addTo(settings.globalVariables.map);
Here is the code that creates the map:
Window.map = settings.globalVariables.map = new L.map('map', {
zoomControl: false,
zoomDelta: settings.map.zoomDelta,
zoomSnap: settings.map.zoomSnap,
minZoom: settings.map.minZoom,
maxZoom: settings.map.maxZoom,
dragging: true,
trackResize: true,
attributionControl: false,
// maxBounds:[[-90,-180],[90,180]]
});
I'm not 100% sure, but I suspect the issue is with the north/south bounds of your map. Mapbox is constrained to the Web Mercator projection, which tops out at around 85º/-85º latitude. Judging from your image here, you are trying to show latitudes well north of there.
You probably need to constrain the bounds of your map with tighter bounds, or increase the minimum zoom, so this situation doesn't arise.

How to change the map center position to top place using Leaflet open street map in angular

In my angular application I have created the leaflet map and over the leaflet map I have created two more panels data in overlapping manner And I have created the circle of 5 km radius on the map. But my problem is the panels are covering the circle on the leaflet map
So my requirement is to move the center position of the map i.e circle to top position(top middle) than only the circle will be visible otherwise it will be covered by the panels on the map.
component.ts
map = L.map('map').setView([13.0827, 80.2707], 12);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
L.control.zoom({
position: 'bottomright',
}).addTo(map);
I am new to leaflet map Can anyone help me regarding this.
You can let the map fit the circle bounds, like:
var circle = L.circle() // Your circle
map.fitBounds(circle.getBounds())
To show the circle on the left side of the map:
map.setView(circle.getLatLng(),map.getZoom(),{animate: false})
sw = map.getBounds().getSouthWest();
psw = map.latLngToContainerPoint(sw);
center = map.getCenter();
pc = map.latLngToContainerPoint(center);
dis = pc.x - psw.x;
middle = dis / 2
pnewCenter = L.point(pc.x+middle,pc.y)
center2 = map.containerPointToLatLng(pnewCenter);
map.setView(center2,map.getZoom(),{animate: true})

Can map.getBounds be executed for a different coordinate system?

I execute the following code in my leaflet webmap
map.getBounds().getWest() + "&y1=" +
map.getBounds().getSouth() + "&x2=" +
map.getBounds().getEast() + "&y2=" +
map.getBounds().getNorth()
This results in a result showing me four coordinates in the WGS84 (standard) coordinate system.
Is there any way to alter this so it will output 28992 coordinates instead?
I guess that by "28992 coordinates" you're referring to the EPSG:28992 Coordinate Reference System.
The canonical way to use "non-standard" CRSs in Leaflet is to leverage proj4leaflet. This answer assumes that you're already doing so.
So the getBounds() method of L.Map always returns a L.LatLngBounds instance, which refer to unprojected WGS84 coordinates. However, we can use the map's CRS to project a L.LatLng into a L.Point with the projected coordinates, in the map's display CRS; e.g.
var map = L.map('containerId`, { crs: crsForEpsg28992 });
var foo = map.options.crs.project(L.latLng([60.3,21.1]));
var qux = map.options.crs.project(map.getCenter());
Because of how map projections work (they rotate and bend the coordinate spaces), and because of how proj4js is implemented, it's not possible to project a bounding box into a bounding box. (In most cases, the projection of a bounding box would be a curved polygon!). This image from an article by Gregor Aisch illustrates the issue:
We can, however, do an approximation: project the four corners of the bounding box, e.g.:
var mapBounds = map.getBounds();
var crs = map.options.crs;
var nw = crs.project(mapBounds.getNorthWest());
var ne = crs.project(mapBounds.getNorthEast());
var sw = crs.project(mapBounds.getSouthWest());
var se = crs.project(mapBounds.getSouthEast());
We can even create a L.Bounds (but not a L.LatLngBounds!) from those projected coordinates; that'll be a bbox in the specified CRS that contains all corners, e.g.:
var bbox = L.bounds([nw, ne, sw, se]);
It's not gonna be perfect, but that approximation should be enough for most use cases.
See also this working example (based off on one of the proj4leaflet examples), which should further illustrate the issue.

How to set correct image dimensions by LatLngBounds using ImageOverlay?

I want to use ImageOverlays as markers, because I want the images to scale with zoom. Markers icons always resize to keep their size the same when you zoom.
My problem is that I can't figure out how to transform pixels to cords, so my image isn't stretched.
For instance, I decided my south-west LatLng to be [50, 50]. My image dimensions are 24px/24px.
How do I calculate the north-east LatLng based on the image pixels?
You are probably looking for map conversion methods.
In particular, you could use:
latLngToContainerPoint: Given a geographical coordinate, returns the corresponding pixel coordinate relative to the map container.
containerPointToLatLng: Given a pixel coordinate relative to the map container, returns the corresponding geographical coordinate (for the current zoom level).
// 1) Convert LatLng into container pixel position.
var originPoint = map.latLngToContainerPoint(originLatLng);
// 2) Add the image pixel dimensions.
// Positive x to go right (East).
// Negative y to go up (North).
var nextCornerPoint = originPoint.add({x: 24, y: -24});
// 3) Convert back into LatLng.
var nextCornerLatLng = map.containerPointToLatLng(nextCornerPoint);
var imageOverlay = L.imageOverlay(
'path/to/image',
[originLatLng, nextCornerLatLng]
).addTo(map);
Demo: http://playground-leaflet.rhcloud.com/tehi/1/edit?html,output