Converting pixels to coordinates on a Mapbox map - maps

I have the lat and lon coordinates to a location on a Mapbox map. The map is set to zoom level 15 and is of bearing 30 degrees. I need to travel +500px horizontally and +300px vertically as the map is displayed on the screen. How do I work out what the destination is in lat and lon coordinates?
I need to do this calculation (and many like it) in a ruby script.
Whilst I've found some information describing how to achieve the reverse of what I want its difficult for me to understand how it works and thus I can't reverse the calculations.
Can someone help me?

There's a method named project and unproject.
project converts LngLat into pixel and unproject converts pixel into LngLat.
You can use something like:
const currentCenterPixel = map.project(map.getCenter());
currentCenterPixel.x += 500;
currentCenterPixel.y += 300;
map.once("idle", () => {
map.panTo(map.unproject(currentCenterPixel));
});
https://jsfiddle.net/cs09g/q3x1ohun/8/

Related

How to create a grid of 50sq km Rectangles or Hexagons in React Map GL(Mapbox) and Deck.gl, that covers an entire country

I'm trying to create a Grid Layer of Either Rectangles or Hexagons in React Map GL(Map Box) and Deck GL, that cover an entire country.
This is what I'm trying to achieve: http://webcoveragemap.rootmetrics.com/en-US
These are the Solutions I've found:
https://deck.gl/#/documentation/deckgl-api-reference/layers/s2-layer
https://deck.gl/#/documentation/deckgl-api-reference/layers/h3-cluster-layer
The problem I'm facing with is that s2-layer uses S2 Cell token (Which I can't seem to understand how to calculate and similarly h3-cluster-layer uses H3 and for that too I can't find any code samples for React. So can anybody explain me either how to use H3, S2 and calculate 50sq km boxes that can be viewed on React Map Gl with Deck GL (if needed). Or suggest another Solution?
Turns out there's java script version of H3-Core Library (A hexagon-based geographic grid system). https://www.npmjs.com/package/h3-js
All it require's to convert a lat/lng point to a hexagon index at some resolution is following code:
const h3Index = h3.geoToH3(37.3615593, -122.0553238, 7);
// -> '87283472bffffff'

react zoom/pan scatter plot, data filtering vs clip

I have a question in React implementation for zoom/pan function for a scatter plot.
I wonder what approach would be good and want to hear opinions of React & data visualization expert.
I am specifically interested in implementing zoom/pan function of a scatter plot that is dynamically changing data range to visualize.
(Approach 1) Given a data range (controlled by mouse wheel event), first, filter the data, and render circles () for the filtered data. In this case, each circle will be generated with new key such that
const circles = [];
filteredData.forEach( (d, index) => {
circleProps = { /*..compute circle props... (e.g. position within a SVG) */ }
circles.push(
<circle key={`circle-${index}`} {...circleProps} />
);
});
Thus, every time the data range changes, it will create new set of circles located within the range.
(Approach 2) Similar to Approach 1 but no filtering on the data. Instead, use clip path to visualize only the circles within the range. In this case, it will update entire circles according to re-calculated positions but it will only create the circles one time at the beginning.
What would better approach? Or, any other options to handle large-scale data? Also, please correct me if anything is wrong.
Thanks.

Leaflet JS: Custom 2D projection that uses meters instead of lat,long

I am working on a custom game map. This map is basically a raster image, overlayed with some paths and markers. I want to use Leaflet to display the map.
What I am struggling with, is that Leaflet uses Latitude and Longitude to calculate positions, while it uses meters for distances (path lengths, radii of circles, etc).
This is very understandable when dealing with a spherical world like our Earth, but it complicates the custom map, which is flat a lot.
I would like to be able to specify the positions in the same unit as the distances.
Now, by default Leaflet uses a Spherical Mercator projection. According to the Docs, it is possible to define your own projections and coordinate reference systems, but I have been unable to do this thus far.
How would this be possible? Or is there a simpler way?
You should take a look at the simple coordinate reference system (L.CRS.Simple) included with Leaflet:
A simple CRS that maps longitude and latitude into x and y directly. May be used for maps of flat surfaces (e.g. game maps).
You can define the CRS of your L.Map instead upon initialization like so:
new L.Map('myDiv', {
crs: L.CRS.Simple
});
Some further elaboration: As #ghybs pointed out in the comment below and the comment to your question the default sperical mercator projection (L.CRS.EPSG3857) already works in meters. When you calculate the distance between two coordinates, Leaflet returns meters, example:
var startCoordinate = new L.LatLng(0, -1);
var endCoordinate = new L.LatLng(0, 1);
var distance = startCoordinate.distanceTo(endCoordinate);
console.log(distance);
The above will print 222638.98158654713 to your console which is the distance between those two coordinates in meters. Problem is that when using spherical projection, distance between two coordinates will become less the further you get from the equator which will become problematic when creating a flat gameworld. That's why you should use L.CRS.Simple, you won't have said problem.

How can I change the location center of a map using Leaflet API?

My map (Mapbox) takes up the whole background of the site so the center is in the middle of the site. But the focus of the map for the user is on the right side because I have content overlapping the map on the left side. When leaflet grabs the location, it's from the center of the map, but it would be more convenient if I could set it to grab the location from the center of the right third of the site, so that way the user won't be centering the map on targets bordering content on the left half of the site.
Is there a way I could set the center or location focus of the leaflet API for the map?
Here's how I have it set up currently,
mapOptions: {
maxZoom: 18,
zoomControl: false,
worldCopyJump: true
},
createMap: function() {
Map.map = L.map('map', Map.mapOptions);
Map.layer = L.mapbox.tileLayer(Map.mapID, {
unloadInvisibleTiles: true,
}).addTo(Map.map);
Map.map.locate({setView: true});
Map.map.addControl(L.mapbox.geocoderControl(Map.mapID));
new L.Control.Zoom({ position: 'topright' }).addTo(Map.map);
},
You can use a combo of panBy() and getSize() to offset the map the width of your overlay.
Here's a snippet that should get you a started:
// Calculate the offset
var offset = map.getSize().x*0.15;
// Then move the map
map.panBy(new L.Point(-offset, 0), {animate: false});
In my example, my overlay is 33% of the width of the map. So I grab the size of the map area, then multiple by 0.15 (this was based on some experimenting to see what the best offset amount was) and use panBy() to offset the map center.
Here's a full example.
If you have multiple markers and want to center the map in their bounds and at the same time you have overlapping container, you can use the fitBounds options (paddingTopLeft, paddingBottomRight, padding).
http://leafletjs.com/reference.html#map-paddingtopleft
First you will need to know the lat and long of the point on the map you want to center on. Then it is simple, just call Map.map.setView passing in your coordinates and zoom level.
Api reference: http://leafletjs.com/reference.html#map-set-methods
If you don't know your coordinates then you can find it by trial and error, just create a marker and add it to the map.
Found this solution by ghybs over on GIS which helped me solve this problem:
Leaflet-active-area
This plugin allows you to use a smaller portion of the map as an active area. All positioning methods (setView, fitBounds, setZoom) will be applied on this portion instead of the all map.

Configuring maxExtent and restrictExtent coordinates in OpenLayers

I'm very new to OpenLayers and working with GeoData; as such, I think I have a pretty noob question about configuring map bounds with OpenLayers. First, here's the map code I've made up...
function createMap(containerId){
return new OpenLayers.Map(containerId, {
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326"),
units: "m",
maxResolution:156543.0339,
numZoomLevels:4,
controls: [],
maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
restrictExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34)
});
}
I have my map and I've loaded a GeoJSON layer of vector country shapes on top of it. So far so good. However, if I call zoomToMaxExtent on the map, the map zooms out to be a little tiny thumbnail-sized graphic in the center of my viewport rather than filling the frame. Then if I zoom in on the map, I can (seemingly) pan the map indefinitely in any direction rather than being constrained at the edges of the map shapes.
So I assume I'm doing something wrong with my maxExtent and restrictExtent settings, although I have no idea what it is. To be honest, I'm not sure what those huge bounding numbers are (found them in sample code). Essentially, by Lon/Lat coordinates, I think I'm just trying to restrict bounding to -180, -90, 180, 90 – which should provide a tight frame around the map geography, right? Unfortunately setting those Lon/Lat's to the bounding params don't seem to do anything. Any insight would be greatly appreciated!

Resources