I'm trying to save marker to DB with fields
lat, lon , marker description.
If there is only one marker on the map everything is fine, but when I add a second one, my code generate 2 sql-s instead 1 and duplicates 1st added marker info.
This is my code:
map.on('draw:created', function (e) {
var type = e.layerType;
var layer = e.layer;
var marker_lat = layer._latlng.lat;
var marker_lng = layer._latlng.lng;
// Here I open Popup to save Marker discription
$('#point_description').modal('show');
// Here save marker lat, Lng + marker description
$(document).on('click', '#save_point', function () {
var point_description_text = $('#point_description_text').val();
insertPlaques(marker_lat, marker_lng, point_description_text, modal_window);
});
drawnItems.addLayer(layer);
});
Your 'draw:created' function is going to be called everytime a new shape is created by Leaflet.Draw. Everytime that method is called, a new on 'click' listener is added to the '#save_point' element. So the second time 'draw:created' is called (and the user clicks '#save_point'), two listeners will be invoked. The third time, three listeners will be invoked.
You should either remove your click listener using off() after the insertPlaques method is called, or consider using a method like one() to add your click listener instead of on() (https://api.jquery.com/one/)
Related
I have a set of markers that have binded popups, but I can't figure out how to show all the popups when the marker group is toggled in the layers control.
For example, I have my markers like so:
var testMarker = L.marker([32.9076,33.35449]).bindPopup('Marker 1');
var testMarkerTwo = L.marker([33.58259,34.64539]).bindPopup('Marker 2');
Then, I put it in a freature group and append the openPopup method:
var markerGroup = L.featureGroup([testMarker,testMarkerTwo]).openPopup().addTo(map);
This doesn't work.
My final goal is to add that featureGroup to my layers control where I can toggle the group off/on. Before I get to that part, I need to first understand why the openPopup method is not working.
Edit: The answer below appears to only work with the plain Leaflet API, not the Mapbox API.
There are a couple problems here. The first is that by default, Leaflet closes the previously opened popup each time another is opened. The second is that, while your markers have popups bound to them, markerGroup does not, and even if it did, markerGroup.openPopup would only cause a single popup to open.
To get around the first problem, you can use the hack from this answer. If you place the following code at the beginning of your script (before you define your map) it will override the default behavior and allow you to open multiple popups at once:
L.Map = L.Map.extend({
openPopup: function(popup) {
this._popup = popup;
return this.addLayer(popup).fire('popupopen', {
popup: this._popup
});
}
});
Then, once you are able to open multiple popups, you can open all popups in markerGroup using the eachLayer method:
var markerGroup = L.featureGroup([testMarker,testMarkerTwo]).addTo(map);
markerGroup.eachLayer(function(layer) {
layer.openPopup();
});
Here is an example fiddle:
http://fiddle.jshell.net/nathansnider/02gsb1Lt/
It is easy enough to get the lat lng of a map click using something like:
map.on('click', function (e) {
coords= e.latlng.lat + ", " + e.latlng.lng;
});
But if there are shapes on the map the function doesn't get called if you click a place covered by a shape.
Ultimately I want to produce a popup window triggered when a shape is clicked and populated with information based on lat/long.
Welcome to SO!
You could bind your event listener on your shapes as well (possibly through an L.FeatureGroup to avoid having to bind to each individual shape), and you can even use that event listener to fire the "click" event on the map as well.
var shapes = L.featureGroup().addTo(map);
shapes.addLayer(/* some vector shape */); // As many times as individual shapes
shapes.on("click", function (event) {
shapecoords.innerHTML = event.latlng.toString();
map.fire("click", event); // Trigger a map click as well.
});
Demo: http://jsfiddle.net/ve2huzxw/40/
How can I add a mouse over pop up on leaflet.js marker . the pop up data will be dynamic.
I have a service which returns a lat & lon positions which will mark on a map.
I would require a popup on mouse over a marker . the event should send the lat and long position for ex to : http://api.openweathermap.org/data/2.5/weather?lat=40&lon=-100
the data from service should be in popup content.
I have tried but cant build the pop up content dynamically each marker
Please do the needful.
below is the code i have used for markers statesdata is array which stores the lat and longitude values
for ( var i=0; i < totalLength1; i++ ) {
var LamMarker = new L.marker([statesData1[i].KK, statesData1[i].LL]).on('contextmenu',function(e) {
onClick(this, i);
}).on('click',function(e) {
onClick1(this, i)
});
marker_a1.push(LamMarker);
map.addLayer(marker_a1[i]);
on click we call click1 function on context of marker we call click function
How can i add a pop on mouse over passing lat and long from the above code?
Attaching a popup to a marker is fairly easy. It is done by calling the bindPopup method of your L.Marker instance. Per default a popup opens on the click event of the L.Marker instance and closes on the click event of your L.Map instance. Now if you want to do something when a popup opens you can listen to the popupopen event of your L.Map instance.
When you want fetch external data in the background on the popupopen event that is usually done via XHR/AJAX. You can write your own logic or use something like jQuery's XHR/AJAX methods like $.getJSON. Once you receive response data you can then update your popup's content.
In code with comments to explain further:
// A new marker
var marker = new L.Marker([40.7127, -74.0059]).addTo(map);
// Bind popup with content
marker.bindPopup('No data yet, please wait...');
// Listen for the popupopen event on the map
map.on('popupopen', function(event){
// Grab the latitude and longitude from the popup
var ll = event.popup.getLatLng();
// Create url to use for getting the data
var url = 'http://api.openweathermap.org/data/2.5/weather?lat='+ll.lat+'&lon='+ll.lng;
// Fetch the data with the created url
$.getJSON(url, function(response){
// Use response data to update the popup's content
event.popup.setContent('Temperature: ' + response.main.temp);
});
});
// Listen for the popupclose event on the map
map.on('popupclose', function(event){
// Restore previous content
event.popup.setContent('No data yet, please wait...');
});
Here's a working example on Plunker: http://plnkr.co/edit/oq7RO5?p=preview
After comments:
If you want to open the popup on hover instead of click you can add this:
marker.on('mouseover', function(event){
marker.openPopup();
});
If you want to close the popup when you stop hovering instead of map click add this:
marker.on('mouseout', function(event){
marker.closePopup();
});
Here's an updated example: http://plnkr.co/edit/wlPV4F?p=preview
I got fed up with fighting with leaflet's built in functionality. The first thing I did was use the alt option to assign a key to the marker:
var myLocation = myMap.addLayer(L.marker(lat,lng],{icon: icon,alt: myKey}))
The next thing was assign an id using this alt and a title via jQuery (why you can't do that by default irritates me):
$('img[alt='+myKey+']').attr('id','marker_'+myKey).attr('title',sRolloverContent)
Then, I used jQuery tooltip (html will only render this way):
$('#marker_'+myKey).tooltip({
content: sRolloverContent
})
Also, by using the jQuery tooltip instead of the click-only bindPopup, I am able to fire the tooltip from my list, where the row has a matching key id:
$('.search-result-list').live('mouseover',function(){
$('#marker_'+$(this).attr('id')).tooltip('open')
})
$('.search-result-list').live('mouseout',function(){
$('#marker_'+$(this).attr('id')).tooltip('close')
})
By adding the id, I can easily use jQuery to do whatever I want, like highlight a list of locations when the marker is hovered:
$('#marker_'+iFireRescue_id).on('mouseover',function(){
('tr#'+getIndex($(this).attr('id'))).removeClass('alt').removeClass('alt-not').addClass('highlight')
})
$('#marker_'+myKey).on('mouseout',function(){
$('tr#'+getIndex($(this).attr('id'))).removeClass('highlight')
$('#search-results-table tbody tr:odd').addClass('alt')
$('#search-results-table tbody tr:even').addClass('alt-not')
})
I have implemented a geojson filter using toggle buttons with a LayerGroup, but would like to know if anyone has been successful with same behavior using on-map mouseclicks.
Example: map of world countries. click on Italy polygon results in only Italy being visible. Click outside Italy to show all countries again. Hope my question is clear.
It's just a matter of hooking on to the click event of the layer, clearing the group and add that single layer. Also hook on to the map click, remove the single layer and restore the rest. Here's a quick-n-dirty example:
// vars to store stuff
var geojson, source, selected;
// Load the collection
$.getJSON(url, function (collection) {
// Store collection for later use
source = collection;
// Create layer and add collection
geojson = L.geoJson(collection, {
// On each feature in collection
'onEachFeature': function (feature, layer) {
// Attach click handler
layer.on('click', function () {
// Set selected flag
selected = true;
// Clear the entire layer
geojson.clearLayers();
// Add the feature
geojson.addData(feature);
// Fit layer to map
map.fitBounds(layer.getBounds());
});
}
}).addTo(map);
});
// Attach to map click
map.on('click', function () {
// Check if something's selected
if (selected) {
// Clear the entire layer
geojson.clearLayers();
// Restore the collection
geojson.addData(source);
// Fit map to collection
map.fitBounds(geojson.getBounds());
}
});
Here's a working example on Plunker: http://plnkr.co/edit/o5Q0p3?p=preview
I'm starting to learn how to use leaflet. I'm trying to create a map with markers. If you hover them they should display a route. if the mouse leaves the marker the route should be deleted. (This part works)
When you click on the marker the route should stay on the map even when the mouse leaves the marker.
Therefore I would need to duplicate the route layer so that it doesn't get deleted when the mouse leaves the marker. Or there is a better method that I don't know.
function Route() {
DirectionsLayerLong = omnivore.gpx('GPX/ Route_long.gpx');
DirectionsLayerLong.on('ready', function() {
this.setStyle(style_long);
});
DirectionsLayerShort = omnivore.gpx('GPX/Route_short.gpx');
DirectionsLayerShort.on('ready', function() {
this.setStyle(style_short);
});
return DirectionsLayer = L.featureGroup([DirectionsLayerLong, DirectionsLayerShort]);
};
var Marker = L.marker([50, -100], {
icon: iconfu
}).addTo(map);
Marker.on('mouseover', function(e) {
Route();
DirectionsLayer.addTo(map);
});
Marker.on('mouseout', function(e) {
DirectionsLayer.remove()
});
Marker.on('click', function(e) {
DirectionsPermaLayer.remove();
Route();
DirectionsPermaLayer = DirectionsLayer;
DirectionsPermaLayer.addTo(map);
});
I could simply use omnivore with another variable but I'd like to reuse the function.
The simplest solution is just to remove the mouseout event listener when you click on the marker:
Marker.on('click', function(e) {
Marker.off('mouseout');
});
Cloning your route layer would be a little more complicated (not to mention unnecessary, if removing the event listener solves your problem), but it's worth exploring how one might do that. First of all, a concise explanation of why you can't just create a copy using DirectionsPermaLayer = DirectionsLayer can be found on w3schools:
Objects are mutable: They are addressed by reference, not by value.
If y is an object, the following statement will not create a copy of
y:
var x = y; // This will not create a copy of y.
The object x is not a copy of y. It is y. Both x and y points to the
same object.
Any changes to y will also change x, because x and y are the same
object.
There are many ways to go about cloning an object in Javascript, but I suspect that most of these will not work for cloning leaflet layers, as all Leaflet's internal ids will be copied along with the object, causing unpredictable behavior. The best strategy would probably be to convert DirectionsLayerShort and DirectionsLayerLong to GeoJSON using the .toGeoJSON method, then read them back in using L.geoJson:
var Short2 = L.geoJson(DirectionsLayerShort.toGeoJSON()).setStyle(style_short);
var Long2 = L.geoJson(DirectionsLayerLong.toGeoJSON()).setStyle(style_long);
var Directions2 = L.featureGroup([Long2, Short2]).addTo(map);
This could require a little refactoring of your code, but it should do the job.