Leaflet clickable grid in polygon - javascript

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);
'''

Related

How do I find all markers/features within a given radius of any arbitrary point and store the lat/lng of said markers?

Given a point, say [-75.343, 39.984], how do I go about finding all features/markers within a 5km radius of it? I'm utilizing turf.js so I'll be using their circle() function to generate the circle about the point.
Would this work?
const center = [-75.343, 39.984];
const radius = 5;
const options = {steps: 10, units: 'kilometers', properties: {foo: 'bar'}};
const circle = turf.circle(center, radius, options);
}
const features = map.queryRenderedFeatures(
circle,
{ filter: {["within", circle] : true} }
);
I'm hoping to find all features within the circle and be able to store them in an array or in a database for further processing like accessing the feature's lat/lng, etc.
Thank you for the help!
Using queryRenderedFeatures you will be able to get the features that are actually in the viewport (visible). In case your source data is GeoJSON, you can use querySourceFeatures, so it will look to all your source features:
const filteredFeatures = map.querySourceFeatures('routes', {
filter: ['within', circle]
});

Leaflet: showing dynamic polylines together on a map using layers

I'm working on a task of showing all polylines(of different colours) on my map using leaflet. I'm getting all my dynamic polylines' latitudes and longitudes with their colours but when I merge it using layers, it just takes the last polyline and shows it.
I think I'm making some mistake in layering it. Can someone recommend the correct way to layer polylines in leaflets?
Here's a sample of the code where this is happening -
let newColour = this.returnMapColor(moment(startDate).day());
var layerGroups = {}
console.log("colour", newColour, startDate );
let range = this.props.history.filter((v) => { return moment(v.time).format("YYYY-MM-DD") == moment(startDate).format("YYYY-MM-DD") });
startDate = moment(startDate).add(1, 'days');
range.map((row)=> {
positions.push([row.latitude,row.longitude,row.sp] )
});
if(this.props.map){
const leafletMap = this.props.map.leafletElement;
this.hotlineLayer = L.layerGroup(L.polyline(positions, {color: newColour})).addTo(leafletMap);
}
++i;
A polyline requires at least two sets of lat, longs. Could you point out where in your code are you forming polylines?
In your code, the range.map the operation will only lead to creating an array of positions. And hence, your code is rendering a single line.
If you intend to create multiple polylines and render them using LayerGroup, I would suggest something in the lines of:
var latlngs1 = [
[45.51, -122.68,0],
[37.77, -122.43,1],
[34.04, -118.2,2]
];
var latlngs2 = [
[34.04, -118.2,2],
[32.08, -110.5,2]
];
const polyline1 = L.polyline(latlngs1, {color: 'red'})
var polyline2 = L.polyline(latlngs2, {color: 'blue'})
var hotlineLayer = L.layerGroup([polyline1, polyline2]).addTo(map);
Example Code: https://jsfiddle.net/idhruvs/n75omjbd/32/

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

How to project pixel coordinates in leaflet?

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

OpenLayers, nice marker clustering

Do you know how to have a nice clustering in OpenLayers such as this google example ?
You can add label to pointStyle in above example and explain context of this label.
Your code should be something like this:
var pointStyle = new OpenLayers.Style({
// ...
'label': "${label}",
// ...
}, {
context: {
// ...
label: function(feature) {
// clustered features count or blank if feature is not a cluster
return feature.cluster ? feature.cluster.length : "";
}
// ..
}
});
var styleMap = new OpenLayers.StyleMap({
'default': pointStyle,
});
var googleLikeLayer = new OpenLayers.Layer.Vector("GoogleLikeLayer", {
// ...
styleMap : styleMap,
// ...
});
Use OpenLayers.Strategy.Cluster for clustering.
Example Code
Working Example
Custom Styling
In-depth Explanation
I have just implemented a so called AnimatedCluster strategy for OpenLayers.
You can see a bit more about it at: http://www.acuriousanimal.com/2012/08/19/animated-marker-cluster-strategy-for-openlayers.html
It is only a firts version but adds a nice animation to the clusters. There are many things to improve but it is a starting point.
There's a great clustering example available in OpenLayers 3.
I created a jsFiddle from the code so you can play with it.
Basically you have to create an ol.source.Cluster with a grouping distance from an ol.source.Vector formed by an array of ol.Feature. Each ol.Feature created from your source coordinates in the form of ol.geom.Point.
var features = [
new ol.Feature(new ol.geom.Point([lon1, lat1])),
new ol.Feature(new ol.geom.Point([lon2, lat2])),
...
];
var cluster = new ol.source.Cluster({
distance: 50,
source: new ol.source.Vector({ features: features });
});
var map = new ol.Map({
layers: [
new ol.source.MapQuest({layer: 'sat'}), // Map
new ol.layer.Vector({ source: cluster }) // Clusters
],
renderer: 'canvas',
target: 'map'
});
you can do this with as igorti has said. the soltion is using OpenLayers.Strategy.Cluster class and styling your layer with OpenLayers.Style class...
for styling :
var pointStyle = new OpenLayers.Style({
'default': new OpenLayers.Style({
'pointRadius': '${radius}',
'externalGraphic': '${getgraph}'
....
},{
context:{
radius: function(feature){
return Math.min(feature.attributes.count,7)+3;
},{
getgraph : function(feature){
return 'ol/img/googlelike.png';
}}}};
it must helps you, more power to you!
Here is the JSfiddle for clustering based on custom attributes added to the layers. I struggled a bit with this so putting it here; Also shows creating a summary pie graph image when zoomed out with the clustered data http://jsfiddle.net/alexcpn/518p59k4/
Also created a small openlayer tutorial to explain this OpenLayers Advanced Clustering
var getClusterCount = function (feature) {
var clustercount = {};
var planningcount = 0;
var onaircount = 0;
var inerrorcount = 0;
for (var i = 0; i < feature.cluster.length; i++) {
if (feature.cluster[i].attributes.cluster) {
//THE MOST IMPORTANT LINE IS THE ONE BELOW, While clustering open layers removes the orginial feature layer with its own. So to get the attributes of the feature you have added add it to the openlayer created feature layer
feature.attributes.cluster = feature.cluster[i].attributes.cluster;
switch (feature.cluster[i].attributes.cluster) {
......
return clustercount;
};

Categories