leaflet routing.control update when marker is moved - leaflet

I am using leaflet and routing.control to show a route. I have it working fine, but I would like one of the markers to move with the users location using watch.position. But for now I a just trying to move the marker when I click a button. Again this works fine but when the marker moves I would like the route to update automatically. Its possible if you drag the marker so surely its possible when marker is moved in a different way? I can it if I remove the control and add a new one but this flickers too much. Any advice?
The code for the routing.control is
myroute = L.Routing.control({
waypoints: [
L.latLng(window.my_lat, window.my_lng),
L.latLng(window.job_p_lat, window.job_p_lng)
],show: true, units: 'imperial',
router: L.Routing.mapbox('API KEY HERE'),
createMarker: function(i, wp, nWps) {
if (i === 0 || i === nWps + 1) {
return mymarker = L.marker(wp.latLng, {
icon: redIcon
});
} else {
return job_start = L.marker(wp.latLng, {
icon: greenIcon
});
}
}
}).addTo(map);
and the code for moving the marker is
function movemarker() {
var lat = "52.410490";
var lng = "-1.575950";
var newLatLng = new L.LatLng(lat, lng);
mymarker.setLatLng(newLatLng);
// I assume I call something here?
}

Sorted, I did it with this, which removes first point and replaces it with new data
myroutewithout.spliceWaypoints(0, 1, newLatLng);

Related

Allow point delete in polygon drawing mode

I'm working on a project with Mapbox and I want to customize how I draw the polygon, basically I want to allow point delete on button click and keep in drawing mode.I implemented the behavior, but the point does not get deleted.
I appreciate your help!
var description = "<button id='popup'> Button</button>"
function handlePop(coords) {
var feature = { type: 'Point', coordinates: coords };
draw.delete(feature);
}
let point = 0;
map.on('click', () => {
const coords = draw.getAll().features[0].geometry.coordinates[0];
if (point) {
new mapboxgl.Popup({ closeButton: false })
.setLngLat(coords[point])
.setHTML(description)
.addTo(map);
document.getElementById('popup').addEventListener('click', handlePop(coords[point]));
}
point++;
});

Leaflet Trigger Event on Clustered Marker by external element

I just starting to learn about Leaflet.js for my upcoming project.
What i am trying to accomplish:
I need to make a list of marker which displayed on the map, and when the list item is being hovered (or mouseover) it will show where the position on the map (for single marker, it should change its color. For Clustered marker, it should display Coverage Line like how it behave when we hover it.. and perhaps change its color too if possible).
The map should not be changed as well as the zoom level, to put it simply, i need to highlight the marker/ Cluster on the map.
What i have accomplished now : I am able to do it on Single Marker.
what i super frustrated about : I failed to find a way to make it happen on Clustered Marker.
I use global var object to store any created marker.
function updateMapMarkerResult(data) {
markers.clearLayers();
for (var i = 0; i < data.length; i++) {
var a = data[i];
var myIcon = L.divIcon({
className: 'prop-div-icon',
html: a.Description
});
var marker = L.marker(new L.LatLng(a.Latitude, a.Longitude), {
icon: myIcon
}, {
title: a.Name
});
marker.bindPopup('<div><div class="row"><h5>Name : ' + a.Name + '</h5></div><div class="row">Lat : ' + a.Latitude + '</div><div class="row">Lng : ' + a.Longitude + '</div>' + '</div>');
marker.on('mouseover', function(e) {
if (this._icon != null) {
this._icon.classList.remove("prop-div-icon");
this._icon.classList.add("prop-div-icon-shadow");
}
});
marker.on('mouseout', function(e) {
if (this._icon != null) {
this._icon.classList.remove("prop-div-icon-shadow");
this._icon.classList.add("prop-div-icon");
}
});
markersRef[a.LocId] = marker; // <-- Store Reference
markers.addLayer(marker);
updateMapListResult(a, i + 1);
}
map.addLayer(markers);
}
But i don't know which object or property to get the Clustered Marker reference.
And i trigger the marker event by my global variable (which only works on single marker).
...
li.addEventListener("mouseover", function(e) {
jQuery(this).addClass("btn-info");
markersRef[this.getAttribute('marker')].fire('mouseover'); // --> Trigger Marker Event "mouseover"
// TODO : Trigger ClusteredMarker Event "mouseover"
});
...
This is my current https://jsfiddle.net/oryza_anggara/2gze75L6/, any lead could be a very big help. Thank you.
Note: the only js lib i'm familiar is JQuery, i have no knowledge for others such as Angular.js
You are probably looking for markers.getVisibleParent(marker) method, to retrieve the containing cluster in case your marker is clustered.
Unfortunately, it is then not enough to fire your event on that cluster. The coverage display functionality is set on the Cluster Group, not on its individual clusters. Therefore you need to fire your event on that group:
function _fireEventOnMarkerOrVisibleParentCluster(marker, eventName) {
var visibleLayer = markers.getVisibleParent(marker);
if (visibleLayer instanceof L.MarkerCluster) {
// In case the marker is hidden in a cluster, have the clusterGroup
// show the regular coverage polygon.
markers.fire(eventName, {
layer: visibleLayer
});
} else {
marker.fire(eventName);
}
}
var marker = markersRef[this.getAttribute('marker')];
_fireEventOnMarkerOrVisibleParentCluster(marker, 'mouseover');
Updated JSFiddle: https://jsfiddle.net/2gze75L6/5/
That being said, I think another interesting UI, instead of showing the regular coverage polygon that you get when "manually" hovering a cluster, would be to spiderfy the cluster and highlight your marker. Not very easy to implement, but the result seems nice to me. Here is a quick try, it would probably need more work to make it bullet proof:
Demo: https://jsfiddle.net/2gze75L6/6/
function _fireEventOnMarkerOrVisibleParentCluster(marker, eventName) {
if (eventName === 'mouseover') {
var visibleLayer = markers.getVisibleParent(marker);
if (visibleLayer instanceof L.MarkerCluster) {
// We want to show a marker that is currently hidden in a cluster.
// Make sure it will get highlighted once revealed.
markers.once('spiderfied', function() {
marker.fire(eventName);
});
// Now spiderfy its containing cluster to reveal it.
// This will automatically unspiderfy other clusters.
visibleLayer.spiderfy();
} else {
// The marker is already visible, unspiderfy other clusters if
// they do not contain the marker.
_unspiderfyPreviousClusterIfNotParentOf(marker);
marker.fire(eventName);
}
} else {
// For mouseout, marker should be unclustered already, unless
// the next mouseover happened before?
marker.fire(eventName);
}
}
function _unspiderfyPreviousClusterIfNotParentOf(marker) {
// Check if there is a currently spiderfied cluster.
// If so and it does not contain the marker, unspiderfy it.
var spiderfiedCluster = markers._spiderfied;
if (
spiderfiedCluster
&& !_clusterContainsMarker(spiderfiedCluster, marker)
) {
spiderfiedCluster.unspiderfy();
}
}
function _clusterContainsMarker(cluster, marker) {
var currentLayer = marker;
while (currentLayer && currentLayer !== cluster) {
currentLayer = currentLayer.__parent;
}
// Say if we found a cluster or nothing.
return !!currentLayer;
}

marker with polyline while dragging the marker using leaflet

Hi I have connection between marker with polyline like this Image .
I am attaching a sample here.
How Can I make drag possible that when I drag the the marker with polyline.
example , If I drag the marker 3 it should also update the polyline point and where ever I put the marker 3 polyline should connect with marker 3.
I need this type of drag event that can update the polyline also when dragging the marker.
I am using leaflet for this purpose but still unable to solve the dragging logic of marker with polyline.
Here is the sample code I am using
$http.get("db/getConnectionData.php").then(function (response) {
$scope.links1 = response.data.records;
// $scope.showArrow();
angular.forEach($scope.links1, function(value, i) {
var source_panoId = $scope.links1[i].s_panoId;
var dest_panoId = $scope.links1[i].d_panoId;
var sPanoID = $scope.links1[i].sourcePano_id;
var dPpanoID = $scope.links1[i].destPano_id;
angular.forEach($scope.panoramas, function(value, index) {
if($scope.panoramas[index].panoId == source_panoId){
if($scope.links.indexOf($scope.panoramas[index])== -1){
$scope.links.push($scope.panoramas[index]);
}
var SlatLang = $scope.panoramas[index].project_latLng ;
var SLatLngArr = SlatLang.split(",");
var Slat = parseFloat(SLatLngArr[0]);
var Slang = parseFloat(SLatLngArr[1]);
var polypoint1 = [Slat, Slang];
angular.forEach($scope.panoramas, function(value, index1) {
if($scope.panoramas[index1].panoId == dest_panoId){
if($scope.links.indexOf($scope.panoramas[index1])== -1){
$scope.links.push($scope.panoramas[index1]);
}
var DlatLang = $scope.panoramas[index1].project_latLng ;
var DLatLngArr = DlatLang.split(",");
var Dlat = parseFloat(DLatLngArr[0]);
var Dlang = parseFloat(DLatLngArr[1]);
var polypoint2 = [Dlat, Dlang];
// Draw seperate polyline for each connection
polyline = L.polyline([[Slat, Slang],[Dlat, Dlang]],
{
color: 'blue',
weight: 5,
opacity: .7,
}
).addTo(map);
$scope.polycoords.push(polyline);
}
});
}
});
Here is the code that I am using to make drag of marker with polyline
angular.forEach($scope.panoramas, function(value, index4){
$scope.markers[index4].on('dragstart', function(e){
var latlngs = polyline.getLatLngs(),
latlng = $scope.markers[index4].getLatLng();
for (var i = 0; i < latlngs.length; i++) {
if (latlng.equals(latlngs[i])) {
this.polylineLatlng = i;
}
}
});//dragstart
$scope.markers[index4].on('drag', function(e){
var latlngs = polyline.getLatLngs(),
latlng = $scope.markers[index4].getLatLng();
latlngs.splice(this.polylineLatlng, 1, latlng);
polyline.setLatLngs(latlngs);
});//drag
$scope.markers[index4].on('dragend', function(e){
delete this.polylineLatlng;
});//dragEnd
});
First, when creating the marker, remember to pass the draggable option as true, like this:
var marker = L.marker(latLng, { draggable: true });
Now, check which drag event you want to attach a listener to and then call the redraw function of the polyline inside the callback, like this:
// var polyline defined somewhere
marker.on('drag', function (e) {
polyline.redraw();
});
If this doesn't work, please provide sample code so we can work around with it.
Edit
You also need to change the coordinates of the polyline, otherwise redraw will do nothing. Check out this answer on SO and see if it fits your needs.
Edit 2
You're using an array of polylines while the answer just uses one polyline which has the array of coordinates, so in your case you need to use two loops to accomplish the same task. You can make this faster and maybe use an object as a lookup table to get the right polyline for each marker, for example, like this:
var table = {};
// ...
table[marker] = polyline;
Then later you can get the polyline used for each marker. But anyway, here's what I think would work in your case the way it is in the sample (it was a little hard to understand but I hope it works for you).
I don't know where you are putting the second part of your sample (the event handlers) but I assume it's not inside the double loop that is creating the polylines, right? So this is what I came up with:
marker.on('dragstart', function (e) {
var markerLatLng = marker.getLatLng();
this.polylineLatLngs = [];
for (var i = 0; i < $scope.polycoords.length; i++) {
var polyline = $scope.polycoords[i];
var latLngs = polyline.getLatLngs()
for (var j = 0; j < latLngs.length; j++) {
if (markerLatLng.equals(latLngs[j])) {
this.polylineLatLngs.push([i, j]);
}
}
}
});
marker.on('drag', function (e) {
for (var i = 0; i < this.polylineLatLngs.length; i++) {
var polyline = $scope.polycoords[this.polylineLatLngs[i][0]];
var latLngs = polyline.getLatLngs();
var markerLatLng = marker.getLatLng();
latLngs.splice(this.polylineLatLngs[i][1], 1, markerLatLng);
polyline.setLatLngs(latLngs);
}
});
I am getting this type of behavior. Please let me know how I can solve this .
Thank you for your time.
This is the polyline created by getting data from db or by making the connection between panorama.
This Image when I start dragging the marker 2 I got the result like this
This image when I dragged the marker 3.
This type of result I am getting using the source code you provided above.

Leaflet & Mapbox: OpenPopup not working

I've an issue with the leaflet openPopup method.
showMap = function(elements) {
var jsonp = 'http://a.tiles.mapbox.com/v3/blahblahblah.jsonp';
var m = new L.Map("my_map").setView(new L.LatLng(51.5, -0.09), 15);
var geojsonLayer = new L.GeoJSON();
var PlaceIcon = L.Icon.extend({
iconSize: new L.Point(25, 41),
shadowSize: new L.Point(40, 35),
popupAnchor: new L.Point(0, -30)
});
var icon = new PlaceIcon(__HOME__ + '/images/leaflet/marker.png');
var marker;
for (var i = 0; i < elements.length; i++) {
var address = $("<div/>").html(elements[i].address).text();
var latlng = new L.LatLng(elements[i].latitude, elements[i].longitude);
marker = new L.Marker(latlng, {icon: icon}).bindPopup(address);
if (i == 0) {
marker.openPopup();
}
m.addLayer(geojsonLayer).addLayer(marker);
}
// Get metadata about the map from MapBox
wax.tilejson(jsonp, function(tilejson) {
m.addLayer(new wax.leaf.connector(tilejson));
});
}
When I click on a marker I have the popup open. But I would like to have the first popup open when the map is loaded. (and open other popups on markers click)
AnNy ideas ?
Put openPopup call after you add the marker to the map and you should be fine.
I'm assuming that when you click on a marker you see the popup but you're not getting the popup of the first marker to show automatically when the map is loaded?
First, it doesn't look like you're actually using GeoJSON so a GeoJSON layer isn't necessary (you can just use a FeatureLayer) but that shouldn't cause any issues. Whatever layer group you use you should only be adding it to the map once and then adding all child layers to the LayerGroup. You're currently adding the geojsonLayer multiple times in your "for" loop which you don't want to do.
Second, you have to call marker.openPopup() after the marker is added to the map.
Try changing your code around to looks something like this:
var layerGroup = new L.FeatureGroup();
layerGroup.addTo( m );
for (var i = 0; i < elements.length; i++) {
var address = $("<div/>").html(elements[i].address).text();
var latlng = new L.LatLng(elements[i].latitude, elements[i].longitude);
marker = new L.Marker(latlng, {icon: icon}).bindPopup(address);
//You don't add the marker directly to the map. The layerGroup has already
//been added to the map so it will take care of adding the marker to the map
layerGroup.addLayer( marker );
if (i == 0) {
marker.openPopup();
}
}
I had this issue and fixed it with adding a timeout right after I added the marker on the map.
marker.addTo(this.map).bindPopup('Info');
setTimeout(() => {
marker.openPopup();
}, 500);
I don't know why but on some page, I need to apply timeout. In any case it's my workaround, hope this works for some of you too.
First add your map then put openPopup():
L.marker([lat, long]).bindPopup('Your message').addTo(map).openPopup();

Google Map Makers Sprite in OSX not displaying

I can't seem to get the my map markers to display when I use an image sprite on the iphone. They appear when I use the standard google map markers on iphone and when viewing the site in the desktop the sprite icons work fine.
Here is the code I use to create the markers, I am using Zepto but JQuery could as easily apply.
$.ajax({
dataType: 'jsonp',
url: myLocations.LocatorUrl,
timeout: 8000,
success: function(data) {
var infoWindow = new google.maps.InfoWindow();
var bounds = new google.maps.LatLngBounds();
$.each(data, function(index, item){
var data = item, pincolor,
latLng = new google.maps.LatLng(data.lat, data.lng);
var d = 'http://blah';
var pinImage = new google.maps.MarkerImage(d+"/assets/img/sprite.locator.png",
new google.maps.Size(24, 36),
new google.maps.Point(0,25),
new google.maps.Point(10, 34));
// Creating a marker and putting it on the map
var marker = new google.maps.Marker({
position: latLng,
map: map,
title: data.type,
icon: pinImage
});
bounds.extend(latLng); // Extend the Latlng bound method
var bubbleHtml = '<div class="bubble"><h2>'+item.type+'</h2><p>'+item.address+'</p></div>'; // Custom HTML for the bubble
(function(marker, data) {
// Attaching a click event to the current marker
google.maps.event.addListener(marker, "click", function(e) {
infoWindow.setContent(bubbleHtml);
infoWindow.open(map, marker);
});
markers.push(marker); // Push markers into an array so they can be removed
})(marker, data);
});
map.fitBounds(bounds); // Center based on values added to bounds
}, error: function(x, t, m) {
console.log('errors')
if(t==="timeout") {
alert("got timeout");
} else {
alert(t);
}
}
});
Got it. Turns out the images I was referencing were on localhost, when I swapped this to the actual IP address of my local machine it worked.