How to project pixel coordinates in leaflet? - javascript

I am trying to create a map based on an image which is 16384x16384 px, but I would also like to add markers at specific locations using pixel coordinates of this given image.
I created a tile layer, a map element and set maximum boundaries, so that I can't scroll out of the image, using this code:
var map = L.map('map', {
maxZoom: 6,
minZoom: 2,
crs: L.CRS.Simple
}).setView([0, 0], 2);
var southWest = map.unproject([0,16384], map.getMaxZoom());
var northEast = map.unproject([16384,0], map.getMaxZoom());
map.setMaxBounds(new L.LatLngBounds(southWest, northEast));
L.tileLayer('tiles/{z}/{x}/{y}.png', {
tms: true
}).addTo(map);
The points i'd like to add to the map are stored in an external file as GeoJSON, and they look like this http://www.de-egge.de/maps/terranigma/terraPoints.js
I load them using this snippet of code:
var terraPoints = new L.geoJson(points, {
onEachFeature: function (feature, layer) {
layer.bindPopup(
"<b>Ort: </b>" + feature.properties["points[, 1]"]
);
}
});
map.addLayer(terraPoints);
But of course, they don't show up, because the reference systems don't match. The points use pixel coordinates, but my map uses geographic coordinates.
Is there a way to "unproject" the points while loading them?
Any help is much appreciated and thanks in advance!

var geoJsonTest = new L.geoJson(geojsonFeature, {
coordsToLatLng: function (newcoords) {
return (map.unproject([newcoords[1], newcoords[0]], map.getMaxZoom()));
},
pointToLayer: function (feature, coords) {
return L.circleMarker(coords, geojsonMarkerOptions);
}
});
This is how you use in case you didn't figure it out yet. Seeing the coordinates are inverted I changed them around in the option. Works for perfectly for me.

L.GeoJSON has the coordsToLatLng() which should be useful for mapping the coordinates.
http://leafletjs.com/reference.html#geojson-coordstolatlng

Related

Leaflet clickable grid in polygon

I'm using leaflet.js to show reforestation efforts.
Is there any possibility to create a grid-pattern where every square of the pattern can be linked to a click-event?
Something similar like this.
It would need small squares that would together form a similar polygon as shown above.
I tried Leaflet-pattern, but the squares resize on zoom and there is no option to add an event to the pattern shapes.
Could I use the leaflet rectangle for this? How would I find the correct latitude and longitudes for each square?
You probably want to create a square grid, then calculate the intersection between each grid cell with each polygon.
It's up to you to decide the details of the square grid, and whether you want the same grid for all polygons, or a different grid for each polygon.
Thanks to Ivan Sanchez I found the solution.
For anyone looking for it see this JSFiddle.
'''
// initialize the map on the "map" div with a given center and zoom
var map = L.map(
'map', {
layers: [map]
}
).setView([-5.0, 19.40], 11);
//HexGrid
var bbox = [19.35, -5, 19.5, -5.15];
var cellSide = 1;
var options = {
units: 'kilometers'
};
var hexgrid = turf.hexGrid(bbox, cellSide, options);
//Polygram that will contain the hexagons
let poly1 = turf.polygon([
[
[19.4, -5],
[19.5, -5.1],
[19.4, -5.1],
[19.4, -5]
]
]);
_.each(hexgrid.features, function(hex) {
var intersection = turf.intersect(poly1, hex.geometry);
if (intersection) {
hex.geometry = intersection.geometry;
} else {
hex.geometry = {
type: "Polygon",
coordinates: []
}
}
})
L.geoJSON(hexgrid, {
style: function(feature) {
return {
weight: 1
};
}
}).addTo(map);
L.geoJSON(poly1).addTo(map);
'''

Adding an animated arrow on an offset Leaflet polyline

I have a project which consist in visualizing the exchange of data between points on a map.
I'm using Leaflet to draw polylines from coordinates in a GeoJson file and Leaflet.polylineDecorator (https://github.com/bbecquet/Leaflet.PolylineDecorator) to put an animated arrow on the polyline.
The thing is that I need to visualize the stream in both directions. I started by adding to my Geojson file polylines in the other direction but the issue is when I zoom out, the two polylines are stacked.
So I found Leaflet.polylineOffset (https://github.com/bbecquet/Leaflet.PolylineOffset) which allows to create an another polyline just by setting the offset option.
I thought, i just had to do the same to put the animated arrow on it but when i'm doing it, the animation is affected to the original polyline. In fact, the offset polyline keeps the coordinates from the original one.
I wanted to know if there is a way to apply this animation to the offset polyline.
Here is my code:
d3.json("data/trajetsFibreDCSigma.json",function (data){ // getting polylines' data from a json file to add them on the map
L.geoJson(data, {
style: function(feature){return {color : feature.properties.stroke,opacity: 1};}, // setting the style of the polylines
onEachFeature: function(feature){
// getting the coordinates of the polyline from the json file
var latlng = feature.geometry.coordinates;
var size = feature.geometry.coordinates.length;
var buffer;
// reversing the order of latitude and longitude in the array because a L.latLng object needs the latitude first and I have the opposite in my json file
for (i=0;i<size;i++)
{
buffer = latlng[i][0];
latlng[i][0] = latlng[i][1];
latlng[i][1] = buffer;
}
var polylineOffset = L.polyline(latlng,{offset: 5,color: 'blue',opacity: 1}).addTo(map); // putting an offset to the polyline
addArrow(latlng,feature);
addArrow(polylineOffset,feature);
}
}).addTo(map);
});
function addArrow(polyline,feature){ // function to add an arrow on the map
var arrowHead = L.polylineDecorator(polyline).addTo(map); // creating an arrow which will be put on the polyline
var arrowOffset = 0;
window.setInterval(function() { // creating an animation for the arrow to cross the polyline
arrowHead.setPatterns([
{offset: arrowOffset+'%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 10, polygon: false,
pathOptions: {stroke: true,color: feature.properties.stroke,opacity: 1}})}
]);
if(++arrowOffset > 100)
arrowOffset = 0;
}, 100);
}
(If I'm just calling addArrow with the offset polyline, it will pop on the original one).
I found a solution to get the offset polyline's coordinates.
The PolylineOffset plugin has a function which returns the offset coordinates.
You can use it like this:
var pts = L.PolylineOffset.offsetLatLngs(latlng,10,map); // getting the coordinates from the offset polyline
where latlng is the array of the original coordinates
; 10 is the offset
; map is your leaflet map

Mapbox draw direction via two markers

How can i draw route direction from start to finish if I have coordinates of this two points?
Now my code looks like this and it just gave me 2 static markers on map
var map = L.mapbox.map('map', 'mapbox.streets', {
zoomControl: false
}).setView([start.lat, start.lng], 12);
map.attributionControl.setPosition('bottomleft');
var directions = L.mapbox.directions({
profile: 'mapbox.walking'
});
var directionsLayer = L.mapbox.directions.layer(directions).addTo(map);
L.marker([start.lat, start.lng], {}).addTo(map);
L.marker([finish.lat, finish.lng], {}).addTo(map);
If I understand correctly, you wish to use Mapbox's direction and routing layer to get the walking route between the two points and display it. To do so you need to set the origin and destination points and call the query() function of direction. You also need to add a routes control to the map. The revised code is as follows.
// example origin and destination
var start = {lat: 22.3077423, lng: 114.2287582};
var finish = {lat: 22.3131334, lng: 114.2205973};
var map = L.mapbox.map('map', 'mapbox.streets', {
zoomControl: false }).setView([start.lat, start.lng], 14);
map.attributionControl.setPosition('bottomleft');
var directions = L.mapbox.directions({
profile: 'mapbox.walking'
});
// Set the origin and destination for the direction and call the routing service
directions.setOrigin(L.latLng(start.lat, start.lng));
directions.setDestination(L.latLng(finish.lat, finish.lng));
directions.query();
var directionsLayer = L.mapbox.directions.layer(directions).addTo(map);
var directionsRoutesControl = L.mapbox.directions.routesControl('routes', directions)
.addTo(map);
You may not need to add the origin / destination markers yourself, as origin / destination markers would be displayed as part of the directions control.
You'll need a polyline for that. Leaflet's (Mapbox is an extended version of Leaflet) class L.Polyline is what you need:
Reference: http://leafletjs.com/reference.html#polyline
Code:
var polyline = new L.Polyline([
[start.lat, start.lng],
[finish.lat, finish.lng]
]).addTo(map);
Example on Plunker: http://plnkr.co/edit/2XSeS1?p=preview

Show a marker for polygons from a GeoJSON file in Leaflet

I have a leaflet JS map that displays data from a GeoJSON file. However some of the features in the geojson are polygons, and some are points. I would like to replace each polygon with a point (in the centroid, in the average of the bbox, whatever, it doesn't matter, the accuracy isn't that important), so that I can "point-ify" the whole geojson file, and just display one leaflet marker for each point, or polygon-that-was-turned-into-a-point. I don't want to display the outline of the polygons.
You could use the onEachFeature option of the L.GeoJSON layer, it takes a function which is run for each feature in your featurecollection. In there you can differentiate between points and polygons. A quick example:
var map = L.map('map', {
center: [0, 0],
zoom: 0
});
var geoJsonLayer = L.geoJson(featureCollection, {
onEachFeature: function (feature, layer) {
// Check if feature is a polygon
if (feature.geometry.type === 'Polygon') {
// Don't stroke and do opaque fill
layer.setStyle({
'weight': 0,
'fillOpacity': 0
});
// Get bounds of polygon
var bounds = layer.getBounds();
// Get center of bounds
var center = bounds.getCenter();
// Use center to put marker on map
var marker = L.marker(center).addTo(map);
}
}
}).addTo(map);

Leaflet OSM: Center mapview on polygon

I want generate a html file including Leaflet library to show an OpenStreetMap view with a polygon. The polygon on the map should be centered. To do so i followed this discussion, but its still unclear to me, how to center an arbitrary polygon and autozoom it. Autozoom means to me, that the polygon is completly in the visible map excerpt and fills it.
As example this would be the desired result:
This is my code so far:
var map;
var ajaxRequest;
var plotlist;
var plotlayers=[];
function initmap() {
// set up the map
map = new L.Map('map');
/* --- Replace for different URL for OSM tiles */
var url_base ='URL_TO_MY_OPENSTREETMAPS_SERVER';
var latitude = 50.2222;
var longtitude = 3.322343;
var poly = L.polygon([
[50.2222, 3.322343],
[50.2322, 3.323353],
[...]
]);
// create the tile layer with correct attribution
var osmUrl=url_base+'{z}/{x}/{y}.png';
var osmAttrib='Map data ɠOpenStreetMap contributors';
var osm = new L.TileLayer(osmUrl, {minZoom: 4, maxZoom: 20, attribution: osmAttrib});
// start the map at specific point
map.setView(new L.LatLng(latitude, longtitude),15);
map.addLayer(osm);
poly.addTo(map);
}
Especially it would be great, if there are "onboard" methods of Leaflet that i can use. How to calculate the center of a polygon is clear to (e.g. here) but maybe there are already implemnented methods i can use.
Solution:
// start the map at specific point
// map.setView(new L.LatLng(latitude, longtitude),15); <- Remove this line
map.addLayer(osm);
poly.addTo(map);
map.fitBounds(poly.getBounds()); // <- Add this line
Not exactly centering, but if you want the map to be fitted to the polygon:
map.fitBounds(poly.getBounds());
(doc).
To center more than one polygon is good to know that .fitBounds also accepts an array as argument, so you could do this:
const poly = [polygonA,polygonB,polygonC];
const bounds = poly.map(p=>p.getBounds());
mymap.fitBounds(bounds);

Categories