Leaflet update position on dragend of marker - javascript

I want to update the value of two hidden fields on my form based on marker position. I read this link to get my answer, and this is my final code
<script>
var map = L.map('map', {
center: [33.505, 53.9],
zoom: 5
});
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
map.on('dblclick', addMarker);
var Marker;
function addMarker(e) {
//remove previous markers
if (Marker) {
map.removeLayer(Marker);
UpdateLatLng(e);
}
// Add marker to map at click location; add popup window
Marker = new L.marker(e.latlng, {
draggable: true
}).addTo(map);
}
function UpdateLatLng(e) {
var latValue, lngValue;
latValue = e.latlng.lat;
lngValue = e.latlng.lng;
document.getElementById("map_lat").value = latValue;
document.getElementById("map_lng").value = lngValue;
//$("#map_lat").val() = latValue;
}
function UpdateLatLng2(e) {
var latValue, lngValue;
var position = marker.getLatLng();
latValue = position.lat;
lngValue = position.lng;
document.getElementById("map_lat").value = latValue;
document.getElementById("map_lng").value = lngValue;
//$("#map_lat").val() = latValue;
}
Marker.on('dragend', UpdateLatLng2);
</script>
The result is that my form fields are not updated on the first double click event, but they get updated on the next double clicks or after marker's dragend event instead. Why?
And why would the following code does not work while getElementById does?
$("#map_lat").val() = latValue;
Any help would be appreciated.

My form fields are not updated on the first double click, but get updated on the next double clicks. The form fields don't get updated after marker dragend; why?
This is how the first time your script runs,
map.on('dblclick', addMarker); //|You attach the double click event handler.
var Marker; //|You instansiate an undefined variable.
function addMarker(e) {
if (Marker) { //|On the first double click, Marker is undefined. Your code will not get into this if condition.
map.removeLayer(Marker);
UpdateLatLng(e); // But your function is here.
}
// Add marker to map at click location; add popup window
Marker = new L.marker(e.latlng, {
draggable: true
}).addTo(map);
}
On the first double click, UpdateLatLng(e) will never get called because your Marker is undefined. And the second double click, it will then get called.
You can update your addMarker function like,
function addMarker(e) {
//remove previous markers
if (Marker) {
map.removeLayer(Marker);
}
// Add marker to map at click location; add popup window
Marker = new L.marker(e.latlng, {
draggable: true
}).addTo(map);
UpdateLatLng(e);
}
But that's the worst way to update the marker position. I'd suggest that your code is a bit more like,
<script>
var map = L.map('map', {
center: [33.505, 53.9],
zoom: 5
});
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
map.on('dblclick', addOrUpdateMarkerPosition);
var Marker;
function addOrUpdateMarkerPosition(e) {
if (!Marker) {
// Marker is undefined, create a new marker..
// Add marker to map at click location; add popup window
Marker = new L.marker(e.latlng, {
draggable: true
}).addTo(map);
// Bind the event handlers
Marker.addListener('dragend', UpdateLatLng2);
}
else {
// Marker already exists, just update the position
Marker.setPosition(e.latlng);
}
}
function UpdateLatLng(e) {
var latValue, lngValue;
latValue = e.latlng.lat;
lngValue = e.latlng.lng;
document.getElementById("map_lat").value = latValue;
document.getElementById("map_lng").value = lngValue;
}
function UpdateLatLng2(e) {
var latValue, lngValue;
var position = marker.getLatLng();
latValue = position.lat;
lngValue = position.lng;
document.getElementById("map_lat").value = latValue;
document.getElementById("map_lng").value = lngValue;
}
</script>
BTW, do you know why this code is not working but getElementById works?
$("#map_lat").val() = latValue;
This code is using javascript external library which is jQuery. While getElementById is pure JS and does not need any library. To use it, you have basically just have to include the following script in your page.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Related

Google Maps info windows only displays info from the first click

I have a script that:
pulls results from a database in the form of an XML file
parses those results
creates a marker for each result and places it on a map (a single map for all markers)
at the same times, builds a clickable HTML list (sidebar) containing all those results.
When the user clicks on a place name in the sidebar, the info window from the corresponding marker on the map is automatically displayed. Of course the user can also click directly on a marker on the map, and the same info window is also displayed.
This code has been working fine for several years, but last week I noticed that its behavior was now bugged. When viewing some given results, the first click (either on the map or in the sidebar) works fine (the info window opens and displays the correct information), but the following clicks all show the same information from the first click, all in their respective info window. (To be clear: the information shown is the one from the very first click, not from the previous click.)
I've been trying to debug that for hours but I don't understand why it doesn't work anymore. As you can see in my code below, I tried adding a console.log in the google.maps.event.addListener function, to see what data is being worked with when the marker is clicked, but even there, I don't see anything wrong.
Here is my code (simplified to be more readable):
var side_bar_html = '\n';
var gmarkers = []; // array for created markers
var infoWindow;
var center_lat = <?php echo $position_lat; ?>;
var center_lng = <?php echo $position_lng; ?>;
function createMarker(point, name, html, place_id, map) {
var marker, markerOptions;
markerOptions = {
map: map,
position: point,
dataId: place_id,
icon : 'theme/marker.png',
shadow: 'theme/marker_shadow.png'
};
marker = new google.maps.Marker(markerOptions);
infoWindow = new google.maps.InfoWindow({content: html});
google.maps.event.addListener(marker, 'click', function() {
console.log(this, marker, html);
infoWindow.content = html;
infoWindow.open(map, this);
});
gmarkers.push(marker);
side_bar_html += '\n<li>' + name + '</li>';
return marker;
}
function showPlace(i) {
google.maps.event.trigger(gmarkers[i], 'click');
}
function loadEarth(opt, zoom) {
var map, point, mapCenter, mapOptions;
if (zoom === null) {zoom = 7;}
mapCenter = new google.maps.LatLng(center_lat, center_lng);
mapOptions = {
zoom: zoom,
center: mapCenter,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
point = new google.maps.LatLng(parseFloat(center_lat), parseFloat(center_lng));
if (opt != 0) {
map.setMap(new google.maps.Marker(point));
}
}
// receiving results via XML
function go() {
var map, bounds;
var mapOptions = {
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
bounds = new google.maps.LatLngBounds();
$.ajax({
url : 'url/to/data.xml',
type : 'GET',
dataType : 'xml',
success : function(xml) {
var markers, lat, lng, place_id, point, label, html, marker;
markers = xml.documentElement.getElementsByTagName("marker");
for (var i = 0; i < markers.length; i++) {
// extract data for each marker
lat = parseFloat(markers[i].getAttribute("lat"));
lng = parseFloat(markers[i].getAttribute("lng"));
place_id = parseFloat(markers[i].getAttribute("place_id"));
point = new google.maps.LatLng(lat,lng);
label = $(markers[i]).find('label').eq(0).text();
html = $(markers[i]).find('infowindow').eq(0).text();
// marker creation
marker = createMarker(point, label, html, place_id, map);
// extend visible zone to newly added marker
bounds.extend(point);
}
map.setCenter(new google.maps.LatLng(center_lat, center_lng), 7);
bounds.extend(point);
if (markers.length>0) {
document.getElementById("side_results").innerHTML = side_bar_html;
map.fitBounds(bounds);
map.setCenter(bounds.getCenter());
} else {
loadEarth();
}
} // end AJAX success
}); // end AJAX
} // end go()
if ($('#places_page').is('.empty')) {
loadEarth(0,8);
} else go();
Any help would be greatly appreciated.
Edit:
As requested, here's a sample of the XML received. In this case, the PHP variables at the start of the script would receive the following values:
$position_lat: 46.9479222
$position_lng: 7.4446085
<?xml version="1.0" encoding="UTF-8"?><markers>
<marker place_id="955" lat="46.950218" lng="7.442429">
<label><![CDATA[<em>Place 955</em><strong>3011 Bern</strong>]]></label>
<infowindow>
<![CDATA[<p><em>Place 955</em><br />Speichergasse 35<br />3011 <ins>Bern</ins></p>]]>
</infowindow>
</marker>
<marker place_id="985" lat="46.942032" lng="7.389993">
<label><![CDATA[<em>Place 985</em><strong>3018 Bern</strong>]]></label>
<infowindow>
<![CDATA[<p><em>Place 985</em><br />Brünnenstrasse 106A<br />3018 <ins>Bern</ins></p>]]>
</infowindow>
</marker>
</markers>
The Google Maps API is included via this line:
<script src="http://maps.google.com/maps/api/js?v=3&sensor=true&language=fr&key=..."></script>
Edit 2:
Changing the API call to force it to use version 3.18 does fix the problem:
<script src="http://maps.google.com/maps/api/js?v=3.18&sensor=true&language=fr&key=..."></script>
Obviously this is a temporary fix, since v. 3.18 won't always be available. Now I need to understand what change in the 3.19 version made this bug appear. Any suggestion is still appreciated. :)
This undocumented usage:
infoWindow.content = html;
May be the issue. Should be:
infoWindow.setContent(html);
The .content property went away or is no longer supported issue

How can I add new markers to Google Map in Meteor?

I'm currently adding markers on a google map when I click on a given location. The markers are currently saved both to a Collection - Markers - and in to a more classical array. What I would like to now is to add new marker to the map as they are added by other users.
My question is: Is there any way to get notified when the collection is modified (e.g. another user add a marker) ?
Maybe this is not the best way to do it. Any other suggestion?
if (Meteor.isClient) {
Template.hello.rendered = function(){
markersArray = [];
var latlng = new google.maps.LatLng(46.123, 8.843);
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
latlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
map.setCenter(latlng);
});
}
var opts = {
zoom: 16,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map-canvas"), opts);
// add a click event handler to the map object
google.maps.event.addListener(map, "click", function(event)
{
placeMarker(event.latLng);
});
Session.set('map', true);
function placeMarker(location) {
var marker = new google.maps.Marker({
position: location,
map: map
});
Markers.insert({"marker": location, "date": new Date()});
markersArray.push(marker);
}
}
}
As per the previous answer, you should use an observestructure, but you really need to avoid leaving the observer running forever:
Template.hello.rendered = function() {
this.markerObserve = Markers.find({}).observe({
added: function(m) {
placeMarker(m.location) // obviously depends on the structure of Markers documents
}
});
};
Template.hello.destroyed = function() {
this.markerObserve.stop();
}
You have to use observer
Template.hello.rendered = function(){
Markers.find({}).observe({
added: function (m) {
// Add marker
}
});
}

Remove marker from Google Maps API V3

I have a map where I want to add a marker (with info window) via a checkbox. It also works quite well, but I just can not get it deleted again when I uncheck the checkbox. Can anyone help?
See also here: http://jsfiddle.net/x8D7y/
function clearOverlays() {
google.maps.event.clearListeners(marker300, 'click');
}
function showOverlays() {
var marker300 = new google.maps.Marker({
position: new google.maps.LatLng(45.0, 1.0),
map: map /*,
icon: 'img/bike5.png' */
});
var infowindow300 = new google.maps.InfoWindow({
content: '<div style="width: 200px;">Test 300 - Link</div>'
});
google.maps.event.addListener(marker300, 'click', function() {
infowindow300.open(map, marker300);
});
}
You have to use an external Array which holds the extra markers you use with the map. In your case I have added the following array:
var extraMarkers = [];
Then when I click the checkbox, I am getting the ID of that checkbox, and send it in both showOverlays() and clearOverlays() as function argument.
Then, in showOverlays(), I am using the checkbox ID as extraMarkers key and the marker as value.
Finally, in clearOverlays() I use again the checkbox ID to get the element with this ID from the extraMarkers array and I see the map to null, in order to remove the marker.
See here the working example : http://jsfiddle.net/x8D7y/1/
Here is the full code required by you:
var map;
var extraMarkers = [];
var myOptions = {
zoom: 8,
center: new google.maps.LatLng(45.0, 1.0)
};
map = new google.maps.Map($('#map')[0], myOptions);
var marker1 = new google.maps.Marker(
{
position: new google.maps.LatLng(45.5, 1.5),
map: map /*,
icon: 'img/bike5.png' */
}
);
var infowindow1 = new google.maps.InfoWindow(
{
content: '<div style="width: 200px;">Test 1 - Link</div>'
}
);
google.maps.event.addListener(
marker1,
'click',
function()
{
infowindow1.open(map, marker1);
}
);
function clearOverlays(myID)
{
google.maps.event.clearListeners(extraMarkers[myID], 'click');
extraMarkers[myID].setMap(null);
}
function showOverlays(myID)
{
var marker300 = new google.maps.Marker(
{
position: new google.maps.LatLng(45.0, 1.0),
map: map /*,
icon: 'img/bike5.png' */
}
);
extraMarkers[myID] = marker300;
var infowindow300 = new google.maps.InfoWindow(
{
content: '<div style="width: 200px;">Test 300 - Link</div>'
}
);
google.maps.event.addListener(
marker300,
'click',
function()
{
infowindow300.open(map, marker300);
}
);
}
$('#mapall').change(
function()
{
var myID = $(this).attr('id');
if($('#mapall').attr('checked'))
{
showOverlays(myID);
}
else
{
clearOverlays(myID);
}
}
);
if you have single marker on map then use marker.setMap(null);
if Multiple marker make an array for marker
markersArray.push(marker);
if (markersArray) {
for (i in markersArray) {
markersArray[i].setMap(null);
}
}
Try this:
marker300.setMap(null);
Your marker was not visible outside of showOverlays() function. Error was reported in console:
Uncaught ReferenceError: marker300 is not defined
Minimum change is to define marker300 as global:
var map;
var marker300;
and delete marker in
function clearOverlays() {
google.maps.event.clearListeners(marker300, 'click');
marker300.setMap(null);
}
and remove var in front of variable marker300 in function showOverlays()
See example in fiddle
If you want to have several markers than you will have to follow solution from user Merianos Nikos

How to auto-update a marker on a leaflet map, with meteor

For a school project we are having this idea of making a geospatial tag-game. You log in on our app, your location is shown on the map, and whenever you get close to another player, you tag that person. (Like children's tag but with meteor)
The issue we are having, we seem not able to auto-update our marker on the leaflet map. There's an marker showing it's just not updating.
We tried using Player.update in a time but it doesn't work.
Any suggestions?
The code
if (Meteor.isClient) {
var userLatitude;
var userLongitude;
var map;
Template.map.rendered = function () {
// Setup map
map = new L.map('map', {
dragging: false,
zoomControl: false,
scrollWheelZoom: false,
doubleClickZoom: false,
boxZoom: false,
touchZoom: false
});
map.setView([52.35873, 4.908228], 17);
//map.setView([51.9074877, 4.4550772], 17);
L.tileLayer('http://{s}.tile.cloudmade.com/9950b9eba41d491090533c541f170f3e/997#2x/256/{z}/{x}/{y}.png', {
maxZoom: 17
}).addTo(map);
// If user has location then place marker on map
if (userLatitude && userLongitude) {
var marker = L.marker([userLatitude, userLongitude]).addTo(map);
}
var playersList = players.find().fetch();
playersList.forEach(function(players) {
// Change position of all markers
var marker = L.marker([players.latitude, players.longitude], options={"id" : 666}).addTo(map);
});
};
// If the collection of players changes (location or amount of players)
Meteor.autorun(function() {
var playersList = players.find().fetch();
playersList.forEach(function(players) {
// Change position of all markers
var marker = L.marker([players.latitude, players.longitude]).addTo(map);
});
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
/*
Template.hello.events({
'click input' : function () {
// template data, if any, is available in 'this'
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
*/
/*
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
userLatitude = 52.35873;
userLongitude = 4.908228;
players.insert({
name: "Martijn",
latitude: userLatitude,
longitude: userLongitude
});
});
}
*/
You need to clear the existing markers, otherwise they remain on the map. The easiest / most efficient way to do this is to attach the markers to a LayerGroup when you're creating them. Then, when you want to update, clear all the markers, and then add them again.
Add layer group declaration at the top, so you have
var map, markers;
After initialising the map,
markers = new L.LayerGroup().addTo(map);
Change this line:
var marker = L.marker([userLatitude, userLongitude]).addTo(map);
to:
var marker = L.marker([userLatitude, userLongitude]).addTo(markers);
in your autorun, before the forEach,
markers.clearLayers();
then in your foreach,
var marker = L.marker([players.latitude, players.longitude]).addTo(markers);

Allow user to create only one Google Maps marker at a time

I have the following code that allows a user to click somewhere on the map and it records the GPS location of wherever they click. It works properly on the backend but whenever the user clicks more than once it leaves multiple markers on the map. It always keeps whatever the last location is so it works but it is somewhat confusing for the user who doesn't know what is going on on the backend. Is there some little trick I can do to make it so that whenever the user clicks to create a new marker the old one is removed?
code:
var map;
var GPSlocation;
function initialize() {
var haightAshbury = new google.maps.LatLng(37.7699298, -93.4469157);
var mapOptions = {
zoom: 4,
center: haightAshbury,
mapTypeId: google.maps.MapTypeId.TERRAIN
};
map = new google.maps.Map(document.getElementById("map"), mapOptions);
google.maps.event.addListener(map, 'click', function(event) {
addMarker(event.latLng);
});
}
function addMarker(location) {
//I save the location right here
GPSlocation = location;
document.getElementById("GPSlocation").value = GPSlocation;
marker = new google.maps.Marker({
position: location,
map: map
});
}
Just use setPosition method of google.maps.Marker instance:
var map,
GPSlocation,
marker; // <-- Added
// ... snip ...
function addMarker(location) {
// ... snip ...
if (!marker) {
// Create the marker if it doesn't exist
marker = new google.maps.Marker({
position: location,
map: map
});
}
// Otherwise, simply update its location on the map.
else { marker.setPosition(location); }
}
Make the marker a global variable by declaring it outside your function:
var marker;
function addMarker(location) {
GPSlocation = location;
document.getElementById("GPSlocation").value = GPSlocation;
marker = new google.maps.Marker({
position: location,
map: map
});
}
You can also make it more efficient by only updating the location of the marker rather than creating a new object:
var marker;
function addMarker(location) {
GPSlocation = location;
document.getElementById("GPSlocation").value = GPSlocation;
if (!marker) {
marker = new google.maps.Marker({
position: location,
map: map
});
} else {
marker.setPosition(location);
}
}

Categories