Add vertex to Leaflet polyline programmatically - javascript

I'm using Leaflet and Leaflet PM and their polyline tool to create a polyline. Everything works fine when clicking and adding new points to the map. This data I then use to store away somewhere else and do some other stuff with it. The thing is.
I am going to have a function to be able to press the 'e' key and 'd' key to add points to the map using DOM Eventlisteners. This is because I need to change floor elevation. And if I use the mouse for that on the same location as a previously added point it closes the polyline. Also there it works great. I use mouseover on the map, store the lat long, and then on keydown I use my workingLayer to addLatLng(latlng). It saves the latitudes and longitudes, it draws the line. But there are no vertexes added as when I'm clicking. And I need the vertexadded function to be able to add my other meta-data to it. I'm also gonna use those vertexes to customize later on.
I've been spending the whole day on this and I really need some help now, can't find anything about it.
I also tried adding a marker directly to the layer but that didn't work.
All in all. Everything works fine when I'm clicking to make the polyline. But when programmatically call the layer.addLatLng(latlng); won't add the vertex. Only the latlng and where it is, as shown in the images. Therefore pm:vertexadded is never called.
What am I missing?
An example from my code:
lmap.on('pm:drawstart', function(e){
//Layer is now the workingLayer
let layer = e.workingLayer;
//Will hold coordinates from map
let pointFromMouse;
lmap.addEventListener('mousemove', function(e){
//Assigning current position lat/long
pointFromMouse = e.latlng;
})
document.addEventListener('keydown', function(e){
if(e.keyCode == '69'){
//When pressing 'e', adds it to the polyline
layer.addLatLng(pointFromMouse);
//I also tried setLatLngs(); and redraw(); no sucess
}
})
layer.on('pm:vertexadded', function(e){
//Here I'm calling some other stuff. I stuff another array along
//with other meta-data, other than lat/long.
})
})
Image1: How it looks when I'm clicking(Everything works fine, vertexes are added).
Image2: How it looks when I'm adding a point pressing the key. No vertextes are added, Therefore pm:vertexadded is never called.

Related

Laravel Livewire set is Removing Map Marker

I am using Laravel 8 with Livewire and am displaying a Mapbox map in my page.
When I click on the map, I am getting the coordinates of the click and placing a marker on the point where clicked. All working well up to this point.
What I am then trying to do is emit the coordinates to the Livewire component ready for saving along with other form details. However, when I click the map, the marker quickly appears then disappears; although the coordinates are emitted correctly and stored.
map.on('click', function(e){
var coord = e.lngLat;
updateCoords(coord);
addMarker(coord);
});
function addMarker(coord) {
if(newMarker != undefined) {
newMarker.remove();
}
newMarker = new mapboxgl.Marker()
.setLngLat([coord.lng, coord.lat])
.addTo(map);
}
function updateCoords(coord) {
#this.set('latitude', coord.lat);
#this.set('longitude', coord.lng);
}
I've tried emitting with a listener and using #this.set, both have the same effect.
The component isn't doing anything special at the moment, but I can see that the coordinates are being passed correctly. Just the issue being that the map marker disappears from the map.
Any ideas?
Found out that it is just a case of adding
wire:ignore
to the map div.
<div id="my-map" wire:ignore></div>
I found the answer from here: Livewire Github.
When Livewire updates it replaces the DOM and removes the changes; in my case, removing the map marker.

Leaflet js 'follow' a marker as it receives live updates from GPS devices and moves around the map. Also be able to stop tracking the marker

I have a leaflet map that is populated with markers when GPS devices POST their lat and long on random intervals.
The issue is I have to manually drag the map to follow the marker as it receives updates and moves around the map.
Hours later and much research effort:
I implemented a half solution using a button which snaps to the markers current position, but again I have to click the button every time it moves to keep the marker in sight.
onclick="mymap.fitBounds(gotomarker1.getBounds());"
Is there a way I could click the marker itself which will then keep the marker in the center of the map as it receives lat and log updates and moves around? *ideally not a button as there could be many markers and I wouldn't want a page full of buttons.
I have tried applying an on.click function that loops the gotomarker1 code above but I cant stop it once its started, this is an issue as there is more than one marker that I may want to follow or not follow (to clarify I only want to follow one marker at a time).
the way i have solved a similar problem is to store the marker that is being followed into a variable
onclick="selectedMarker = myMarker"
Whenever you receive location updates simply focus the map on the selectedMarker
// update all locations
// ...
// focus selected marker
mymap.fitBounds(selectedMarker.getBounds());
#Nejc Jaminiks logic in his answer helped me work out what I needed to do.
When a marker is created I have this code appended to the marker in real time:
.on('click', focus);
I then have a function to detect when the marker is clicked and loop through setting the view to the marker until the marker (or another marker) is clicked then it will stop following it.
var focusenabled = true;
interval = null;
function focus(e) {
if (focusenabled) {
var i = 0;
interval = setInterval(function () {
mymap.setView(e.target.getLatLng());
console.log("focus active");
}, 2000);
focusenabled = false;
document.getElementById("footer").style.backgroundColor='red';
document.getElementById("footer").style.color='white';
} else {
clearInterval(interval);
document.getElementById("footer").style.backgroundColor='#222';
document.getElementById("footer").style.color='#222';
focusenabled = true;
}
};
I use the code below to change the footer div to red and text to white when a marker is being followed:
document.getElementById("footer").style.backgroundColor='red';
document.getElementById("footer").style.color='white';
And then when a marker is not being followed the footer div returns to the background color which effectivley hides it :)
document.getElementById("footer").style.backgroundColor='#222';
document.getElementById("footer").style.color='#222';

Having trouble combining hover state and click to zoom capability (fitToBounds?)

Extreme beginner here. I found this (https://www.mapbox.com/mapbox-gl-js/example/hover-styles/) tutorial that does the first part of what I'm trying to do (hover effect on US States) but I would like to add the ability to click on a state and have the map zoom to the bounds of that state.
Basically looking to do something like this https://leafletjs.com/examples/choropleth/ but in mapbox gl.
Many thanks, even if only pointing out where I should start.
You can use map.on('click', <layer-name> ... to set up your click listener. This example should help you with the structure: https://www.mapbox.com/mapbox-gl-js/example/polygon-popup-on-click/
In order to properly use fitBounds within the listener, you'll need to "convert" the raw polygon coordinates to a mapgoxgl.LngLatBounds object. This example does it for a LineString (but the approach can be adapted to work with a polygon): https://www.mapbox.com/mapbox-gl-js/example/zoomto-linestring/
Without knowing the names of your layers, I can recommend something that looks roughly like the following:
map.on('click', 'state-fills', function(e) {
var coordinates = e.features[0].geometry.coordinates[0];
var bounds = coordinates.reduce(function(bounds, coord) {
return bounds.extend(coord);
}, new mapboxgl.LngLatBounds(coordinates[0], coordinates[0]));
map.fitBounds(bounds, {
padding: 20
});
});

HTML Link to a Leaflet / Mapbox marker

I use Mapbox for a dynamic map on a website. It works really well except, I have a sidebar which list the pins with a little more description and an image. I want to make it so when I click on that sidebar, it would fire the click event of that marker on the map.
I used to do this all the time with Google Maps but now I'm stuck because even in the case that I can keep the instance of the marker, I cannot fire the click on it for some reason. It simply does nothing (maybe I need to re-bind the click event on it but I don't know how with mapbox)
I've encountered a few questions about this on Google and SO but none bring a real answer to that question except "keep the instance" which isn't always possible in some cases.
So basically I have a jQuery click event like this:
var marker = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [lng, lat]
},
properties: {}
};
if (isPin) {
marker.properties = pinStyles.pin;
} else if (isWinery) {
marker.properties = pinStyles.winery;
} else {
marker.properties = pinStyles.user;
}
marker.properties.title = locationName;
marker.properties.description = pin.description;
var markerObject = L.mapbox.markerLayer(marker);
// Add to cluster
markers.addLayer(markerObject);
$('#marker_list a.marker_item:last').click(function() {
var geoJson = markerObject.getGeoJSON();
markerObject.fire('click'); // does nothing (openPopup makes "Uncaught TypeError: Object [object Object] has no method 'openPopup' " so I guess I'm not doing it right)
});
And I have this (click event for mapbox marker):
map.markerLayer.on('click', function(e) {
map.setView(e.layer.getLatLng(), map.getZoom());
});
Anyone has an idea about wether 1) fix the non-firing event OR 2) make an HTML link fire a mapbox marker click event OR .openPopup?
Thanks and have a nice day!
MapBox's marker layer is a collection of Leaflet markers. You can create an href to a function that look for a particular marker based on it's layer id.
map.markerLayer.getLayers() returns an array of layer objects that contain both a _leaflet_id and the method togglePopup.
Try matching your href call to the leaflet id and then fire map.markerLayer.getLayers()[i].togglePopup()
Let me know if this helps.

How do I work out which of my markers are visible in my Google map?

Here is what I am trying to do. I have about 160 places of interest. The user enters their address (postcode, full address, whatever) which I use Google to geo-encode. I then create a Google map centred about this point and I add a marker for each of my points of interest to the map (using a MarkerManager). So far so good.
I want to display a list of items beside the map that correspond to the markers being displayed. When the user drags the window, or zooms in or out, or whatever, I want to update this list. If too many items are shown at once, I want to display a message to the user.
What is the best way to do this? I tried adding a listener to the MarkerManager so that when it changed I could work out which markers were still shown. However, the event doesn't seem to fire as I expected, i.e. when the markers being displayed change. Also, I doubt that looping over 160+ markers like this every time is going to be efficient.
GEvent.addListener(mgr, "changed",
function(bounds, markerCount)
{
var visibleBounds = map.getBounds();
for (var i = 0; i < gmarkers.length; i++)
{
//alert(gmarkers[i].getPoint());
if (visibleBounds.containsLatLng(gmarkers[i].getLatLng())) {
// this will need to be replaced with an ajax call
// to get the details from the server
strHtml += "<div>Another item</div>";
count ++;
}
}
alert(count);
});
What is the best way to accomplish this?
UPDATE: This code works, but the event only seems to fire when the map is moved by a certain minimum distance. So if the user drags the map a short distance, the event doesn't seem to fire.
The 'changed' event only fires if markers have changed, so there would certainly be instances when small movements don't change anything. MarkerManager expands its working bounds quite a bit, to make things more smooth when moving around (it shows markers that are off the map, within a certain distance).
You need to listen to the "idle" event, which is fired when the map becomes idle after panning or zooming.
google.maps.event.addListener(map, 'idle', function() {
var bounds = map.getBounds();
...
});
To Get all the Markers first you have to find the Bounds of the current Viewport then you have to loop all the markers and see if they are contains in the bound. The following is a example.
var bounds =map.getBounds();
for(var i = 0; i < markers.length; i++){ // looping through my Markers Collection
if(bounds.contains(markers[i].position))
console.log("Marker"+ i +" - matched");
}

Categories