Is their a way to get latitude and longitude of polyline?
var firstpolyline = new L.Polyline(pointList, {
color: 'black',
opacity: 5,
smoothFactor: 1,
weight: 3,
})
map.addLayer(firstpolyline);
firstpolyline.getLatLng();
here firstpolyline is givng an error that "getLatLng() is not a function". I want to check if polyline is within the map bound or not like this
var bounds = map.getBounds();
if(bounds.contains(firstpolyline.getLatLng())){
......
}
You have to use getLatLngs() function. So try this:
var firstpolyline = new L.Polyline(pointList, {
color: 'black',
opacity: 5,
smoothFactor: 1,
weight: 3,
})
map.addLayer(firstpolyline);
var arrayOfPoints = firstpolyline.getLatLngs();
Then you can easily iterate over an array of points and get latitude and logitude or check if point is in bounds of polygon.
for(var i=0; i < arrayOfPoints.length; i++) {
if(map.getBounds().contains(arrayOfPoints[i])) {
console.log('is in bounds');
};
}
Related
I have a leaflet map with polyline data in. The polyline is styled how I want but what I would like is to have a marker at the centre of each line. Is this possible and if so what changes to the below do I need to make?
var pathstyling = {
stroke: true,
fillColor: "#b5b5b5",
color: "#b5b5b5",
weight: 5,
opacity: 1,
fillOpacity: 0.6,
dashArray: 10,
};
const path = L.geoJSON(path_line, {
style: pathstyling,
})
.bindPopup(function (layer) {
let cap_name = layer.feature.properties.name.replace(
/(^\w{1})|(\s+\w{1})/g,
(letter) => letter.toUpperCase()
);
return `<p>${cap_name}</p><a href="https://${layer.feature.properties.link}" target="_blank">View<a>`;
/******/
})
.addTo(map);
You can simply do this with leaflet core:
function calcMiddleLatLng(map, latlng1, latlng2) {
// calculate the middle coordinates between two markers
const p1 = map.project(latlng1);
const p2 = map.project(latlng2);
return map.unproject(p1._add(p2)._divideBy(2));
}
function createMiddleMarkers(line){
var latlngs = line.getLatLngs();
for(var i = 1; i < latlngs.length; i++){
var left = latlngs[i-1];
var right = latlngs[i];
var newLatLng = calcMiddleLatLng(map,left,right);
L.marker(newLatLng).addTo(map);
}
}
createMiddleMarkers(layer);
https://jsfiddle.net/falkedesign/g7e8w9tz/
In jquery 3/leaflet / turf app
I use custom class extended from CircleMarker
as I need in any marker keep info about any point and info on nearby points.
Markers are connected with polylines and I want to keep simialr information polyline
and clicking on it get this info. I failed to make it. I do
customCircleMarker = L.CircleMarker.extend({
options: {
first_market: false,
last_market: false,
point_id: null,
prior_point_id: null,
}
});
var selectedPoint= {}
var points = [
{id: 1, title:'title #1 ', lat:52.509, lng:-3.08},
{id: 2, title:'title #2 ', lat:51.503, lng:-1.06},
{id: 3, title:'title #3 ', lat:49.51, lng:-2.47}
];
var mymap = L.map('mapid').setView([51.505, -0.09], 7);
L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
id: 'mapbox/streets-v11',
tileSize: 512,
zoomOffset: -1
}).addTo(mymap);
drawPoints()
function drawPoints() {
let polylinePoints= [] // I get all info about all Polylines
let loop_index = 0
points.forEach(point => {
let priorPoint= null
if(loop_index > 0) {
priorPoint= points[loop_index - 1]
}
var myMarker = new customCircleMarker([point.lat, point.lng], {
title: 'unselected',
radius: 20,
first_market: loop_index == 0,
last_market: loop_index == points.length-1,
point_id: point.id,
prior_point_id: priorPoint ? priorPoint.id : null,
});
myMarker.on('click', function (event) { // THAT WORKS OK
console.log('myMarker.event.target.options.point_id::')
console.log(event.target.options.point_id)
});
myMarker.addTo(mymap);
polylinePoints[polylinePoints.length]=[point.lat, point.lng]
loop_index++
})
var radius = 10;
var polyline = new L.Polyline(polylinePoints, {
color: 'green',
opacity: 1,
weight: 2,
customData:{ // BUT TAT DOES NOT WORK AS POINT IS OUT OF LOOP
point_id: point.id,
prior_point_id: priorPoint ? priorPoint.id : null,
}
// offset: radius
});
// Add click listener
polyline.on('click', function (event) {
event.originalEvent.stopPropagation();
window.event.cancelBubble = true; // CAN NOT STOP Propagation
showModal(event)
// alert('Polyline clicked!');
});
// Add polyline to featuregroup
polyline.addTo(mymap);
// zoom the map to the polyline
mymap.fitBounds(polyline.getBounds());
} // function drawPoints () {
How can I add custom data to polyline ?
Thanks!
You don't have to extend the CircleMarker class to add more options. You can do this at the default way:
var myMarker = L.circleMarker([point.lat, point.lng], {
title: 'unselected',
radius: 20,
first_market: loop_index == 0,
last_market: loop_index == points.length-1,
point_id: point.id,
prior_point_id: priorPoint ? priorPoint.id : null,
});
Also don't use polylinePoints[polylinePoints.length]= if it is not necessary. Use polylinePoints.push(
What do you want with the data on the polyline? Why you not adding the whole point array to the polyline?
var polyline = new L.Polyline(polylinePoints, {
customData:{
points: points
}
});
Else you can create a array of the point ids:
let polylinePoints= [] // I get all info about all Polylines
let loop_index = 0;
let pointIds = [];
points.forEach(point => {
pointIds.push(point.id);
//...
var polyline = new L.Polyline(polylinePoints, {
customData:{
points: pointIds
}
});
Or (what I recommand) to add the markers to the polyline:
let markersForPoly = [];
points.forEach(point => {
//... Loop ...
myMarker.addTo(mymap);
markersForPoly .push(myMarker);
});
//.. Code
var polyline = new L.Polyline(polylinePoints, {
customData:{
points: markersForPoly
}
});
And the you can get the points in the click listener:
polyline.on('click', function (event) {
var layer = event.target;
var points = layer.options.customData.points;
console.log(points);
});
Example
https://jsfiddle.net/falkedesign/61sjx3bv/
With help of the StackOverflow community I built a leaflet map with markers for blogdata and articledata. The blogdata represents the IDs and geoloations of newsrooms and the articledata are the locations from articles the newsrooms wrote. So there are several articles per newsroom and I connected those with polylines (see picture below).
What I'd like now to do is make that leaflet map searchable, not for cities or countries but for the newsrooms ID. And I'd like to manage blurring all the other markers and lines out and zooming to the searched blog and it's connected articles.
This is what I got so far:
function myFunction() {
var map = L.map('map').setView([51.101516, 10.313446], 6);
// improve experience on mobile
if (map.tap) map.tap.disable();
L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles © Esri — Esri, DeLorme, NAVTEQ',
maxZoom: 16
}).addTo(map);
map._layersMinZoom=5;
var newsroomsById = {};
for(i=0; i<newsrooms.length; i++) {
newsroomsById[newsrooms[i].ID] = newsrooms[i];
}
for(i=0; i<articles.length; i++) {
// retrieve newsroom
var newsroom = newsroomsById[articles[i].ID];
// draw your polyline
var latlngs = [
[articles[i].lat, articles[i].long],
[newsroom.lat, newsroom.long]
];
var polyline = L.polyline(latlngs, {
color: 'grey',
weight: 2,
opacity: 0.5,
smoothFactor: 1,
}).addTo(map);
var room_marker = L.circleMarker([newsroom.lat, newsroom.long], {
radius: 3,
color: '#29D3A0',
fillColor: '#29D3A0',
fillOpacity: 1,
}).addTo(map);
room_marker.bindPopup("<strong style='color: #84b819'>Newsroom </strong>" + newsroom.ID + "<br>").openPopup();
var popup = L.popup();
var art_marker = L.circleMarker([articles[i].lat, articles[i].long], {
radius: 2,
color: '#000',
fillColor: '#000',
fillOpacity: 1,
}).addTo(map);
}
}
And this is how the map looks like (black is article, green is newsroom/blog)
EDIT:
To make the map searchable use the Leaflet plugin L.Search.Control
It's difficult to answer the search part of the question. I think you'll have to describe a use case for that.
However, once you have the ID of the newsroom you want to highlight, you can change the opacity of your polylines and circleMarkers using setOption
However, your code needs some adjustments: you need to keep an array of your markers and keep the ID of the newsrooms in the markers.
Another thing: you should not create newsroom markers in the article loop; it creates as many newsroom markers as your number of articles.
Here is a proposition (selection is made by clicking on the newsroom marker):
var selectedNewsroom = 0;
var newsroomsById = {};
// create newsroom markers
var newsroomMarkers = [];
for(i=0; i<newsrooms.length; i++) {
newsroomsById[newsrooms[i].ID] = newsrooms[i];
var room_marker = L.circleMarker([newsrooms[i].lat, newsrooms[i].long], {
radius: 20,
color: '#000',
opacity: .4,
fillOpacity: .4,
}).addTo(map);
//room_marker.bindPopup("<strong style='color: #84b819'>Newsroom </strong>" + newsrooms[i].ID + "<br>");
room_marker.ID = newsrooms[i].ID; // associate marker with newsroom
room_marker.on('click', function(e) {
console.log('clicked on ' + e.target.ID);
changeSelection(e.target.ID);
});
newsroomMarkers.push(room_marker); // keep marker reference for later
}
// create article markers and connections to newsrooms
var articleMarkers = [];
for(i=0; i<articles.length; i++) {
// retrieve newsroom
var newsroom = newsroomsById[articles[i].ID];
// draw your polyline
var latlngs = [
[articles[i].lat, articles[i].long],
[newsroom.lat, newsroom.long]
];
var polyline = L.polyline(latlngs, {
color: '#000',
weight: 1,
opacity: .4,
smoothFactor: 1,
}).addTo(map);
var art_marker = L.circleMarker([articles[i].lat, articles[i].long], {
radius: 2,
color: '#000',
fillColor: '#000',
opacity: .4,
fillOpacity: .4,
}).addTo(map);
art_marker.connection = polyline; // associate polyline with marker
art_marker.newsroomID = newsroom.ID;
articleMarkers.push(art_marker); // keep marker reference for later
}
// highlight or blur newsrooms base on which is selected
function changeSelection(newsroomID) {
// deselect everything
for(i=0; i<articleMarkers.length; i++) {
articleMarkers[i].setStyle({ opacity: .4, fillOpacity: .4 });
articleMarkers[i].connection.setStyle({ opacity: .4 });
}
for(i=0; i<newsroomMarkers.length; i++) {
newsroomMarkers[i].setStyle({ opacity: .4, fillOpacity: .4 });
}
if(selectedNewsroom == 0 || selectedNewsroom != newsroomID) {
selectedNewsroom = newsroomID;
for(i=0; i<articleMarkers.length; i++) {
if(articleMarkers[i].newsroomID == newsroomID) {
articleMarkers[i].setStyle({ opacity: 1, fillOpacity: 1 });
articleMarkers[i].connection.setStyle({ opacity: 1 });
}
}
for(i=0; i<newsroomMarkers.length; i++) {
if(newsroomMarkers[i].ID == newsroomID) {
newsroomMarkers[i].setStyle({ opacity: 1, fillOpacity: 1 });
}
}
}
else {
selectedNewsroom = 0;
}
}
And a working example.
For my company, I must develop a function who draw a path with GPS coordinates. Indeed, my company use GPS to track runners during multiple race.
So, i tried many differents way to draw my polyline, my last version is:
_public.drawPolyline = function(pool, id, points, color, opacity, weight) {
try {
var l = points.length;
var latlngs = [];
var j=1;
for (var i = 0; i < l; i++) {
latlngs[i] = new ol.geom.Point(ol.proj.transform([points[i].longitude, points[i].latitude], 'EPSG:4326', 'EPSG:3857'));
};
var style = new ol.style.Style({
stroke: new ol.style.Stroke({
color: color,
width: weight,
opacity: opacity,
radius: 6
})
});
//Check if pool exists, else create it
if (!_private._polyline.containsKey(pool)) {
_private._polyline.put(pool, new jQuery.Hashtable())
}
var currentPool = _private._polyline.get(pool);
//Check if line exists, if yes, update path
if (currentPool.containsKey(id)) {
var vectorLayer = currentPool.get(id).layer;
vectorLayer.setVisible(true);
} else {
var linefeature = new ol.source.Vector('Path', {styleMap: style});
var comp = new ol.geom.LineString(latlngs);
var featurecomp = new ol.Feature({
name: "Comp",
geometry: comp
});
var vector = new ol.layer.Vector({
title: pool,
visible: true,
source: linefeature
});
linefeature.addFeatures(featurecomp);
currentPool.put(id, linefeature);
currentPool.put(id, { "type": "Path", "url": id, "layer": vector });
var vectorLayer = currentPool.get(id).layer;
vectorLayer.setVisible(true);
}
} catch (e) {
console.log(e.message);
}
}
So, I wanted to draw a Polyline with a function with differents parameters:
- pool: an Hashtable storing my polyline
- id: not important
- points: Contain an array of objects (
{"location":[{"id":1854703,"latitude":42.831,"longitude":0.30087,"altitude":0,"hpl":0,"vpl":0,"speed":4,"direction":258,"date":"2012-08-25 03:43:23","device_id":786,"datereceived":"2012-08-25 03:43:23"}).
According to my test server, I have no error in my logs, but, I still don't have a polyline drawed.
If someone could help me with this, it would be great.
Regards, Brz.
You just need to create LineString points as below
points.push(ol.proj.transform([xx,yy],'EPSG:4326', 'EPSG:3857'));
Demo Link https://plnkr.co/edit/WqWoFzjQdPDRkAjeXOGn?p=preview
Edits
var vectorSource = new ol.source.Vector({});
var vectorSourcePoint = new ol.source.Vector({});
var style = new ol.style.Style({
image: new ol.style.Circle({
radius: 4,
fill: new ol.style.Fill({
color: color
}),
stroke: new ol.style.Stroke({
color: color,
width: weight,
opacity: opacity
})
})
});
var l = points.length;
var latlngs = [];
for (var i = 0; i < l; i++) {
latlngs.push(ol.proj.transform([points[i].longitude, points[i].latitude],'EPSG:4326', 'EPSG:3857'));
//below 3 lines of code creates point geometry. I think you don't need this
var point = new ol.geom.Point([points[i].longitude, points[i].latitude]).transform('EPSG:4326', 'EPSG:3857');
var fea = new ol.Feature({geometry:point});
vectorSourcePoint.addFeature(fea);
};
//below lines of code creates polyline. You are missing these lines.
var thing = new ol.geom.MultiLineString([points]);
var featurething = new ol.Feature({
name: "Thing",
geometry: thing
});
vectorSource.addFeature( featurething );
I'm trying to, given a .json containing a lot of points, determine how many there are in each region (probably returning a dictionary), which are defined in another .json file.
I'm doing this based on this example:
https://www.mapbox.com/mapbox.js/example/v1.0.0/point-in-polygon/
However, I can't get it to work.
This line:
var layer = leafletPip.pointInLayer(this.getLatLng(), states, true);
Returns empty for my test case.
Here is a jsfiddle reproducing my code:
http://jsfiddle.net/Pe5xU/346/
map = L.map('map').setView([40.658528, -73.952551], 10);
// Load a tile layer
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data © OpenStreetMap',
maxZoom: 18,
minZoom: 10
}).addTo(map);
geojson = L.geoJson(data).addTo(map);
var all_markers = [];
var layers = {};
$.each(dots, function(index, rec) {
var markers = {}
if (rec.hasOwnProperty("latitude") && rec.hasOwnProperty("longitude")) {
var marker = L.circleMarker([rec.latitude, rec.longitude], marker_style()).addTo(map);
all_markers.push(marker);
}
});
var all_layers = L.featureGroup(all_markers);
map.fitBounds(all_layers.getBounds());
function marker_style() {
return {
radius: 4,
weight: 0,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
};
}
$.each(dots, function(index, rec) {
if (rec.hasOwnProperty("latitude") && rec.hasOwnProperty("longitude")) {
var layer = leafletPip.pointInLayer([rec.latitude, rec.longitude], geojson, true);
console.log(layer);
}
});
This code example provides coordinates in latitude, longitude order. As documented in the leaflet-pip readme, leaflet-pip expects coordinates in longitude, latitude order, the same as GeoJSON and other geospatial formats.