I'm trying to create a straight line network in Leaflet, which at each junction has a marker, and on drag of each marker, update the position of the corresponding polyline which connects to it.
I've done some research (mostly this question) & reworked a fiddle to strip it down a bit to try & get it to do what I want. I am able to draw the network with individual polylines, however, I need to add multiple parentLines to the marker which is connected to two polylines. I can't find it in the Leaflet documentation, but punted with this:
marker_arr[1].parentLine = [polyline_a,polyline_b];
My issue is when I call the dragstart/drag/dragend handlers, it doesn't work with multiple polylines. (Edit) I have made some headway in capturing the parentLines as an array, but can only make it work for the first parentLine
function dragHandler(e) {
var polyline=[]
console.log("drag")
if(e.target.parentLine.length){
polyline.push(e.target.parentLine[0]);
} else {
polyline.push(e.target.parentLine);
}
if(polyline){
var latlngPoly = polyline[0].getLatLngs(), // Get the polyline's latlngs
latlngMarker = this.getLatLng(); // Get the marker's current latlng
latlngPoly.splice(this.polylineLatlng, 1, latlngMarker); // Replace the old latlng with the new
polyline[0].setLatLngs(latlngPoly); // Update the polyline with the new latlngs
}
}
Can anyone point me to either the documentation about parentLine, or how I might make this work? Using Leaflet v1.6.0 and cannot use more recent versions as this is to extend an already existing implementation of Leaflet based on 1.6.
Fiddle here
Here is a sample.
Add to the marker the parentLines always as array:
marker_arr[0].parentLine = [polyline_a];
marker_arr[1].parentLine = [polyline_a,polyline_b];
marker_arr[2].parentLine = [polyline_b];
and then loop through all parentLines in the dragstart handler:
// Now on dragstart you'll need to find the latlng from the polyline which corresponds
// with your marker's latlng and store it's key in your marker instance so you can use it later on:
function dragStartHandler(e) {
var marker = e.target;
marker.polylineLatlng = {};
e.target.parentLine.forEach((line)=>{
var latlngPoly = line.getLatLngs(), // Get the polyline's latlngs
latlngMarker = marker.getLatLng(); // Get the marker's current latlng
for (var i = 0; i < latlngPoly.length; i++) { // Iterate the polyline's latlngs
if (latlngMarker.equals(latlngPoly[i])) { // Compare marker's latlng ot the each polylines
marker.polylineLatlng[L.stamp(line)] = i; // If equals store key in marker instance
}
}
})
}
And in the drag handler:
// Now you know the key of the polyline's latlng you can change it
// when dragging the marker on the dragevent:
function dragHandler(e) {
var marker = e.target;
e.target.parentLine.forEach((line)=>{
var latlngPoly = line.getLatLngs(), // Get the polyline's latlngs
latlngMarker = marker.getLatLng(); // Get the marker's current latlng
latlngPoly.splice(marker.polylineLatlng[L.stamp(line)], 1, latlngMarker); // Replace the old latlng with the new
line.setLatLngs(latlngPoly); // Update the polyline with the new latlngs
})
}
And clean it in the dragend handler:
// Just to be clean and tidy remove the stored key on dragend:
function dragEndHandler(e) {
var marker = e.target;
delete marker.polylineLatlng;
console.log("end");
}
Related
I am trying to getBounds of dynamically added markers to the map. My goal is to dynamically add markers to a map and have the view automatically zoom to fit the bounds of all the markers on the map. Below is my current code and what I have tried so far:
The starting point is an array of lat & lng:
The web page offers a list of addresses and checkboxes that a user can select and deselect. When the desired addresses are selected the user can click view on map and the makrers will appear on the map (this is working perfectly, I just can't get the view to zoom to the bounds of these markers)
I have a loop that pulls the lat and lng for each checked address and pushes it into an array like this:
latLng.push(42.9570316,-86.04564429999999);
latLng.push(43.009381,-85.890041);
...this is in a loop so it always contains the desired amount of values and outputs this:
latLng = [42.9570316,-86.04564429999999,43.009381,-85.890041,43.11996200000001,-85.42854699999998,43.153376,-85.4730639,42.8976947,-85.88893200000001];
var thisLatLng = L.latLng(latLng);
console.log(thisLatLng); // this returns Null
mymap.fitBounds(group); // returns Error: Bounds are not Valid
mymap.fitBounds(group.getBounds()); // returns group.getBounds() is not a function
I have also tried this as a starting point:
latlng.push(L.marker([42.9570316,-86.04564429999999]));
latlng.push(L.marker([43.009381,-85.890041]));
...this is contained in a loop that results in the output below
latLng = [L.marker([42.9570316,-86.04564429999999]),L.marker([43.009381,-85.890041]),L.marker([43.11996200000001,-85.42854699999998]),L.marker([43.153376,-85.4730639]),L.marker([42.8976947,-85.88893200000001])];
console.log(latLng); // this returns makrers with the correct lat & lng above
var group = new L.featureGroup(latLng);
console.log(group); //this returns a Null featureGroup
mymap.fitBounds(group); // returns Error: Bounds are not valid
mymap.fitBounds(group.getBounds()); // returns Error: Bounds are not valid
I am at a loss on how to make this work I have tried several answers posted on stackoverflow and attempted to try and follow the documentation but nothing seems to give the desired outcome.
Update
I removed latLng.push(L.marker([42.9570316,-86.04564429999999])); loop and replaced with the following:
I created a featuregroup with var group = new L.featureGroup(); then added markers to it in the loop by using marker.addTo(group); this pushed all of the markers into the featuregroup as I would expect but was unable to get bounds.
mymap.fitBounds(group.getBounds()); // returns Error: Bounds are not valid
here is what console.log(group); outputs:
I don't think at all that
latLng = [L.marker([42.9570316,-86.04564429999999]),L.marker([43.009381,-85.890041]),L.marker([43.11996200000001,-85.42854699999998]),L.marker([43.153376,-85.4730639]),L.marker([42.8976947,-85.88893200000001])];
Can work. In leaflet you can't just create a variable and say that it's a marker object. You need to use method like L.marker()
What you need to do is create a single marker and add it to a featureGroup
var group = new L.featureGroup();
for (var i = 0; i < yourMarkers.length; i++) {
L.marker([51.5, -0.09]).addTo(group);
}
map.fitBounds(group.getBounds());
group will now contains multiple markers.
And you can also try this :
var coordinates = new Array();
for (var i = 0; i < yourMarkers.length; i++) {
var marker = L.marker([51.5, -0.09]);
coordinates.push(marker);
}
var group = new L.featureGroup(coordinates);
map.fitBounds(group.getBounds());
UPDATE
The concerned function was this one :
function showResult(lat, lng) {
var marker = L.marker([lat, lng])
.bindPopup('yourPopup').on("popupopen", onPopupOpen).addTo(group);
map.addLayer(group);
map.fitBounds(group.getBounds());
}
You only need to add the fitBounds() inside it.
I'm trying to integrate Gmaps in my application, drawing front-end using ExtJs 6.0, and I want to show and hide some user position inside the map.
Adding a marker with user position is quite easy (though I get some strange Cannot read property 'getBounds' of undefined, but I think that's not a big deal).
On the other side, removing a marker it's revealing a little bit more complicated than I thought.
I've read some questions on Stack and Google's Documentation on add/remove markers, and I understand that the "right" way to do it is calling
marker.setMap(null);
But I got a strange behaviour: the marker won't disappear and remains on the map.
This is how I add the marker on the map:
addMarker : function(record) {
var me = this;
var map = me.lookupController().lookupReference('map');
var latitude = record.get('latitude');
var longitude = record.get('longitude');
var description = record.get('fullName');
var marker = new google.maps.Marker({
lat: latitude,
lng: longitude,
title : description
});
me.lookupViewModel().get('techniciansMaker').push(marker);
map.addMarker(marker);
}
And this is how I try to remove marker from the map:
removeMarker : function(record){
var me = this;
var markers = me.lookupViewModel().get('techniciansMaker');
for(var i = 0; i < markers.length; i++){
var m = markers[i];
if (markers[i].getTitle() == record.get('fullName')){
markers[i].setMap(null);
Ext.Array.remove(markers, markers[i]);
}
}
}
Also I'm keeping markers in a list to recognize which one I have to delete.
I can't figure out what I'm doing wrong....
EDIT - SOLVED
I figured out by myself that I was pointing to map container and not the map itself.
Calling map.gmap did the trick.
When using Ext.ux.GMapPanel you should not create the marker yourself with new google.maps.Marker(). Instead addMarker will do this and make listeners:{click:...} work on the marker. You pass the config to addMarker which returns a marker object:
markerConfig = {
lat: latitude,
lng: longitude,
title : description
}
marker = mapPanel.addMarker(markerConfig)
// hide the marker
marker.setMap(null)
// show it again
marker.setMap(mapPanel.gmap)
This allows you to remove the marker and gets rid of that TypeError: Cannot read property 'getBounds' of undefined.
When I push a marker to the array it plots the marker correctly and adds a title to the array too.
I know this works because when I console.log the console.log(markersArray); it returns the following. the title of the marker is next door.
The below is my marker click that opens up the info window, but when I console.log out the data which is called mll it doesn't have the title inside it.
google.maps.event.addListener(marker, 'click', function(mll) {
console.log(mll);
var html= "<div style='color:#000;background-color:#fff;padding:5px;width:150px;'><p>"+mll+"</p></div>";
iw = new google.maps.InfoWindow({content:html});
iw.open(map,marker);
});
How would I be able to get the click function to pull in the title when the array has it and has pushed it successfully?
I remember doing something similar before. In my case, I used infoWindows with circle markers. Essentially, I had both in separate arrays. When I made the circle marker, I gave it a unique value, called place, which was basically it's count (the value of the n-th circle created, was n). On the event listener, I called the infoWindow from the other array based on the position of the current circle.
You can make an array var titles = []; to hold titles.
Each time you make a new marker, increment a var count = 0;, keeping track of how many markers you have.
In your marker options, add place: count. When you need a specific title, you can call titles[marker.place];
var infos = [];
var count = 0;
var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
var lastWindow;
count++;
var populationOptions = {
//leaving out defaults
place: count
};
var circle = new google.maps.Circle(populationOptions);
lastCircle = circle;
var contentString = 'just a string...';
var infowindow = new google.maps.InfoWindow({
content: contentString,
position: new google.maps.LatLng(data.lon, data.lad)
});
infos.push(infowindow);
google.maps.event.addListener(circle, 'mouseover', function() {
if(lastWindow){
lastWindow.close();
}
infos[circle.place].open(map);
lastWindow = infos[circle.place];
});
When I initialize the map I add 1 marker to the map. When I zoom the map out I can see the added marker multiple times on the map 'copies'.
When I then search for a location the map it adds a new marker.
After that I use fitBounds to fit the two markers on the map.
Normally this would result in the following:
But sometimes it does this:
I have the feeling the fitBounds method sometimes uses the marker on 'the other world'.
The latitude and longitude for both markers are correct and as you can see there are now 2 markers on the left.
Can someone please explain to me why this happens and how I can avoid/fix it?
Here is a part of the search submit function where I calculate the bounds:
var searchResultLocation = mapSearchPlaces[0].geometry.location;
//Create search marker
marker = new google.maps.Marker({
position: searchResultLocation,
animation: google.maps.Animation.BOUNCE,
map: map
});
searchMarkers.push(marker);
//Find map bounds
var closestMarker = null;
var closest = Number.MAX_VALUE;
for (var i=0; i < markerLocations.length; i++) {
var distance = google.maps.geometry.spherical.computeDistanceBetween(searchResultLocation, markerLocations[i]);
if (distance < closest) {
closest = distance;
closestMarker = markerLocations[i];
}
}
var bounds = new google.maps.LatLngBounds(searchResultLocation, closestMarker);
map.fitBounds(bounds);
The google.maps.LatLngBounds constructor take two very specific arguments, in a specific order:
LatLngBounds(sw?:LatLng, ne?:LatLng) | Constructs a rectangle from the points at its south-west and north-east corners.
You should create an empty LatLngBounds object and extend it with the two points:
var bounds = new google.maps.LatLngBounds();
bounds.extend(searchResultLocation);
bounds.extend(closestMarker);
map.fitBounds(bounds);
I am developing am app that shows a list of different places using google maps, i have everything working fine and working with currentLocation and the closestsLocation and it zooms to show this, but I have tried to change this to set it so that it zooms out to show all the buildings and not just the closest one
EDIT: this is the working code
// Sets the bounds of the map to include at lease one visable marker
function setBounds(){
if ( markerCluster.getMarkers().length > 0 && homeMarker != null){
map.setZoom(17);
var visableMarkers = markerCluster.getMarkers();
// want to set the starting position at the homeMarker
//Make an array of the LatLng's of the markers you want to show
var LatLngList = new Array ();
LatLngList.push(homeMarker.position);
$.each(visableMarkers, function() {
LatLngList.push(this.position);
});
// Create a new viewpoint bound
var bounds = new google.maps.LatLngBounds ();
// Go through each...
for (var i = 0, LtLgLen = LatLngList.length; i < LtLgLen; i++) {
// And increase the bounds to take this point
bounds.extend (LatLngList[i]);
}
// Fit these bounds to the map
map.fitBounds (bounds);
}
}
The code for your array LatLngList is incorrect, I think it should say
var LatLngList = new Array (new google.maps.LatLng (52.537,-2.061), new google.maps.LatLng (52.564,-2.017));