I have a set of markers on my map and am trying to update their position form an ajax call...
The ajax call works fine and I can loop through the new values; however I cannot find a way to reference the markers (say by ID) so I can update their latLng.
Basically in the end I will need to..
1.) Obtain a reference to a marker by a unique id
2.) Possibly loop through all markers
Thanks in advance - I am new and need a little help getting going - hopefully I can pass along the good will when I can :)
Code for ajax below - I the part about modifying the location of the marker is the part I don't know how to do - so in the code below I just add a new marker where I would really need to just update the position
var json = $.getJSON("json/tracking.php",function(data){
console.log("updated");
$.each(data,function(key,value){
//console.log(value.unit + " " + value.lat + " " + value.lng);
new google.maps.Marker({
map:map,
position: new google.maps.LatLng(value.lat,value.lng),
});
});
})
.success(function(){
//console.log("success");
})
.error(function(){
//console.log("error");
})
.complete(function(){
//console.log("complete");
});
},2000);
I'm inclined to store these in an array of objects as I create them, with any other information (e.g. id) stored as a property of the object. So create a markers array in the appropriate scope (probably outside of the scope of the json callback):
var markers = [];
var json = ...
markers.push({
id: //.. your unique id, or index
obj: new google.maps.Marker(...
});
Try this approach: I'm assuming your JSON is consistent in ordering the markers. newData is pretending to be the new JSON data, when the map is clicked (outside a marker), the "new data" is fetched.
Here's the demo
function initialize() {
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
var data = [{unit:1, lat:0, lng:0},
{unit:2, lat:10, lng:0},
{unit:3, lat:20, lng:0}
];
var newData = [{unit:1, lat:0, lng:10},
{unit:2, lat:10, lng:20},
{unit:3, lat:20, lng:30}
];
var markers = {};
$.each(data,function(key,value){
//console.log(value.unit + " " + value.lat + " " + value.lng);
markers[key] = markers[key] || new google.maps.Marker({ map: map });
markers[key].setPosition(new google.maps.LatLng(value.lat,value.lng));
markers[key].setTitle(value.unit.toString());
});
google.maps.event.addListener(map, 'click', function() {
$.each(newData,function(key,value){
//console.log(value.unit + " " + value.lat + " " + value.lng);
markers[key] = markers[key] || new google.maps.Marker({ map: map });
markers[key].setPosition(new google.maps.LatLng(value.lat,value.lng));
markers[key].setTitle(value.unit.toString());
});
});
}
Related
I would like to add a click event to (subsequently) clustered icons on a leaflet map (using the Leaflet.markercluster plugin). The event itself works, but the alert always yields the very last element of the array for every icon that is clicked. I don't see the reason. declaring 'marker' as array did not change the result.
map.clearLayers;
var marker = [];
var markers = L.markerClusterGroup({
disableClusteringAtZoom: 10,
spiderfyOnMaxZoom: true,
chunkedLoading: true
});
for (id in reclist) {
var posn = reclist[id]['info'][1];
var pose = reclist[id]['info'][2];
var title = reclist[id]['info'][0];
var mapicon = L.icon({iconUrl: 'url of icon');
marker[id] = new L.marker(new L.LatLng(posn, pose), {icon: mapicon})
.on('click', function(){alert(title)});
markers.addLayer(marker[id]);
}
map.addLayer(markers);
There are special events for that: see documentation
markers.on('clusterclick', function() {});
Note that it is one event for your cluster. So it is NOT defined in your loop.
var markers = L.markerClusterGroup({ ... });
markers.on('clusterclick', function() { ... });
for (id in reclist) { ... }
In case I misunderstood your question and you want to define a click event for each markers: if you want to display title, you cannot use the variable as you do. Should do like this:
var title = reclist[id]['info'][0];
var marker = new L.marker(new L.LatLng(posn, pose), {icon: mapicon});
marker.title = title;
marker.on('click', function(e){alert(e.target.title)});
Here is an example
I am using ionic to display benefits data on Google map. It works fine except on click of any marker, it opens the last markup content. Follownig is my google map js code
.controller('BenefitsMapCtrl', function ($scope, LocationBenefits, Utilities, $ionicLoading, $compile) {
$scope.init = function () {
var userId = Utilities.getUserId();
LocationBenefits.getLocationBenefits(userId, function (userBenefits) {
console.log("Got location benefits data for Google mp for user id "+userId);
$scope.userBenefits = userBenefits;
var centerLatlng;
if (typeof $scope.userBenefits !== "undefined" && $scope.userBenefits.length > 0) {
var firstBenefitLocation = $scope.userBenefits[0];
centerLatlng = new google.maps.LatLng(firstBenefitLocation.location.lat, firstBenefitLocation.location.lng);
}
var mapOptions = {
center: centerLatlng,
zoom: 16,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
$scope.markers=[];
//Loop in each benefits and place on Google map
if (typeof $scope.userBenefits !== "undefined" && $scope.userBenefits.length > 0) {
for (var i = 0; i < $scope.userBenefits.length; i++) {
var benefit = $scope.userBenefits[i];
//Marker + infowindow + angularjs compiled ng-click
var contentString = "<div><div><img class='shop-icon' src='" + benefit.shopicon + "' alt='" + benefit.shopName + "'/><span class='item-text-wrap'>" + benefit.shopName + "</span></div><div class='shop-offer'>"+benefit.benefits.short_benefitText+"</div><div class='card'><img class='card-art' src='"+benefit.cardart+"' alt='"+benefit.card+"'/></div></div>";
var compiled = $compile(contentString)($scope);
var infowindow = new google.maps.InfoWindow({
content: compiled[0]
});
//Get location
var locationLatLng = new google.maps.LatLng(benefit.location.lat, benefit.location.lng);
var marker = new google.maps.Marker({
position: locationLatLng,
map: map,
title: benefit.shopName
});
google.maps.event.addListener(marker, 'click', function () {
infowindow.open(map, marker);
});
$scope.markers.push(marker);
}
}
//Finally set the map
$scope.map = map;
});
};
// google.maps.event.addDomListener(window, 'load', initialize);
$scope.centerOnMe = function () {
if (!$scope.map) {
return;
}
$scope.loading = $ionicLoading.show({
content: 'Getting current location...',
showBackdrop: false
});
navigator.geolocation.getCurrentPosition(function (pos) {
$scope.map.setCenter(new google.maps.LatLng(pos.coords.latitude, pos.coords.longitude));
$scope.loading.hide();
}, function (error) {
alert('Unable to get location: ' + error.message);
});
};
$scope.clickTest = function () {
alert('Example of infowindow with ng-click')
};
});
Issue: On click of any markup on Google map, it always opens the last markup.
Please help.
I had the same problem and spend a lot of time to figure out what's going on so I'd like to add the answer for the future generations,lol.
First of all it's a good idea to refer to official Google maps API docs and take a look at "Events section". I found there one interface of adding event listeners to markers that I never seen before(even after googling this issue for few hours).
marker.addListener('click', function() {});
google.maps.event.addListener(marker, 'click', function () {});
It pointed me out to the idea that when you are trying to do it in the loop using an "old" way, your marker variable is obviously equals to the last element of your markers array. And when event really can be triggered your initialization process is finished what means that your variable has always wrong value in anonymous function at the moment it can be really called. So, again, you didn't passed marker as a parameter to that anonymous event handler.
But you still can do what you want. Just use this.inside your event handler. Bellow is my code sample
marker.addListener('click', function() {
var it = this;
$scope.$apply(function() {
$scope.activeEvent = EventService.getShort($scope.events[it.id]);
});
});
I believe that you can try to use this. in "old-style" interface as well.
I had the same problem and I found the solution here. Apparently, you just have to create a function to create the markers and call that function inside the for loop:
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
$scope.map = map; //Attach the map to the scope before adding the markers
$scope.markers=[];
var infowindow = new google.maps.InfoWindow();
var createMarkers = function (benefit){
//Info window's content
var contentString = "<div><div><img class='shop-icon' src='" + benefit.shopicon + "' alt='" + benefit.shopName + "'/><span class='item-text-wrap'>" + benefit.shopName + "</span></div><div class='shop-offer'>"+benefit.benefits.short_benefitText+"</div><div class='card'><img class='card-art' src='"+benefit.cardart+"' alt='"+benefit.card+"'/></div></div>";
var compiled = $compile(contentString)($scope);
//Get location
var locationLatLng = new google.maps.LatLng(benefit.location.lat, benefit.location.lng);
//Create marker
var marker = new google.maps.Marker({
position: locationLatLng,
map: map,
title: benefit.shopName
});
google.maps.event.addListener(marker, 'click', function () {
infoWindow.setContent(compiled[0]);
infoWindow.open($scope.map, marker);
});
$scope.markers.push(marker);
}
//Loop in each benefits and place on Google map
if (typeof $scope.userBenefits !== "undefined" && $scope.userBenefits.length > 0) {
for (var i = 0; i < $scope.userBenefits.length; i++) {
var benefit = $scope.userBenefits[i];
createMarkers(benefit);
}
}
I have a fully-functioning Google Maps V3 map that works fine the way it is. However, I dislike InfoWindows because they take up too much map space when displaying the info. My solution around that is to place information in a sidebar to the right of the map. The information inside the InfoWindow would be transferred to a in that sidebar using an event to first clear existing data and then repopulate it with the current data.
I'm not sure how to take data from inside the map and bring it outside, nor how to use an event inside to move that that data outside on a 'click'.
var infoWindow = new google.maps.InfoWindow;
// Change this depending on the name of your PHP file
downloadUrl("tests/cfdstationsxml.php", function(data) {
var xml = data.responseXML;
var markers = xml.documentElement.getElementsByTagName("marker");
for (var i = 0; i < markers.length; i++) {
var name = markers[i].getAttribute("name");
var address = markers[i].getAttribute("address");
var city = markers[i].getAttribute("city");
var state = markers[i].getAttribute("state");
var zip = markers[i].getAttribute("zip");
var engine = markers[i].getAttribute("engine");
var truck = markers[i].getAttribute("truck");
var ambulance = markers[i].getAttribute("ambulance");
var special_units = markers[i].getAttribute("special_units");
var battalion = markers[i].getAttribute("battalion");
var district = markers[i].getAttribute("district");
var office = markers[i].getAttribute("office");
var point = new google.maps.LatLng(
parseFloat(markers[i].getAttribute("lat")),
parseFloat(markers[i].getAttribute("lng")));
var html = "<div id='info' style='overflow:hidden;line-height:15px;color:black;height:200px;width:225px;'><span style='font-weight:500;text-decoration:underline;font-size:13px;'>" + name + "</span><br><span style='font-size:10px;'>" + address + "<br>" + city + ", " + state + " " + zip + "</span><br><table style='color:black;font-size:12;'><tr><td>Engine:</td><td>" + engine + "</td></tr><tr><td>Truck:</td><td>" + truck + "</td></tr><tr><td>Ambulance:</td><td>" + ambulance + "</td></tr><tr><td>Special Units:</td><td>" + special_units + "</td></tr><tr><td>Battalion:</td><td>" + battalion + "</td></tr><tr><td>District:</td><td>" + district + "</td><tr><td>Office:</td><td>" + office + "</td></tr></tr></table></div>";
var icon = 'http://www.radioman911.com/images/9px_marker.png'; // anywhere from 3px_marker.png to 8px_marker.png
var marker = new google.maps.Marker({
map: map,
position: point,
icon: icon,
title: name,
});
bindInfoWindow(marker, map, infoWindow, html);
}
});
}
function bindInfoWindow(marker, map, infoWindow, html) {
google.maps.event.addListener(marker, 'click', function() {
$("#info").appendTo("#sidebar");
//infoWindow.setContent(lmth);
infoWindow.open(map, marker);
});
}
function downloadUrl(url, callback) {
var request = window.ActiveXObject ?
new ActiveXObject('Microsoft.XMLHTTP') :
new XMLHttpRequest;
request.onreadystatechange = function() {
if (request.readyState == 4) {
request.onreadystatechange = doNothing;
callback(request, request.status);
}
};
request.open('GET', url, true);
request.send(null);
}
function doNothing() {}
ANY help at all would be much appreciated - this has been driving me nuts on and off for a month!!
Tim
This should work for the correct value of 'id of your sidebar div';
function bindInfoWindow(marker, map, infoWindow, html) {
google.maps.event.addListener(marker, 'click', function() {
document.getElementById('id of your sidebar div').innerHTML = html;
});
}
working example
I'm managing this website: http://www.gprprojecten.nl
Basically what I'm doing with is is getting a stream of data from a webservice and chaching this. Afterwards I do all kinds of things to this data, including displaying all the projects on a google map.
Problem is, that as the projectnumber grows, the (custom)pins start to overlap (not visible, not clickable).
So I want to cluster my pins.
I started working on a google maps clusterer library using A32.blog as my starting point.
But now a problem arises. As I have chosen a client side filter system called filter.js, I depend on that way of using google maps, which is with objects rather then an array of markers as used in the clusterer library.
Here is the code I use to generate my map in combination with filter.js:
var googleMap = {
center_lat_lng: [52.14, 5.3],
map: null,
markers: {},
addMarker: function (project) {
var that = this;
var image = new google.maps.MarkerImage('#Url.Content("~/Content/img/marker.png")',
new google.maps.Size(63, 27),
new google.maps.Point(0, 0),
new google.maps.Point(23, 27));
var marker = new google.maps.Marker({
position: new google.maps.LatLng(project.loclat, project.loclong),
map: this.map,
title: project.gebouwnaam,
icon: image
});
marker.info_window_content = "<div class=\"gmapcontentwindow\"><h4>" + project.gebouwnaam + "</h4><img src=\"" + project.thumburl + "\" alt=\"" + project.gebouwnaam + "\" /><div class=\"gebouwdata\"><span class=\"date\">" + project.publicatiedatum + "</span><h5>" + project.plaats + "</h5><span>" + project.gebruiksfunctie + " | " + project.gebouwcategorie + "</span><span>" + project.licentiehouder + "</span><span class=\"stars " + project.rating + "\"></span>"
if (project.akkoorddoorexpert == "True") {
marker.info_window_content += "<span class=\"expert\"></span>"
}
var forwardUrl = '#Url.Content("~/Home/Details/")';
marker.info_window_content += "<span class=\"forward\">Lees meer >></b></span></div></div>"
this.markers[project.id] = marker
google.maps.event.addListener(marker, 'click', function () {
that.infowindow.setContent(marker.info_window_content)
that.infowindow.open(that.map, marker);
});
},
updateMarkers: function (filtering_result) {
var google_map = this;
$.each(google_map.markers, function () { this.setMap(null); })
$.each(filtering_result, function () {
google_map.markers[this.id].setMap(google_map.map);
});
},
init: function () {
var options = {
center: new google.maps.LatLng(this.center_lat_lng[0], this.center_lat_lng[1]),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
this.map = new google.maps.Map(document.getElementById("gmap"), options)
this.infowindow = new google.maps.InfoWindow({
});
//var markersarray = $(this.markers).toArray();
//console.log(markersarray);
//doet het nog niet???
//http://a32.me/2012/05/handling-huge-amount-of-markers-on-google-maps-with-clusters/
//var markerCluster = new MarkerClusterer(this.map, markersarray, {
// gridSize: 10,
// minimumClusterSize: 2
//});
}
};
project is an object that is passed to the init function from filter.js
You need to add the Marker Clusterer to the global scope or keep a reference to it in your object.
I've 2 function as below:
function addMarker() {
marker = new google.maps.Marker({
position: Gpoint,
map: map,
draggable: true,
animation: google.maps.Animation.DROP
});
map.panTo(Gpoint);
google.maps.event.addListener(marker, "rightclick",
function (point) {
showContextMarker(point.latLng); } );
$('.contextmenu').remove();
};
function delMarker() { marker.setMap(null); $('.contextmenu').remove(); };
So, as may understand I have a Context Menu having "Delete Marker" option on it.
I am binding a "rightclick" listener during adding a marker, to show this menu.
Everything is working without any problem till this moment.
But when I try to click on a marker to delete; it is effecting only the last added marker.
When I try again; nothing happens.
So my idea is to get the clicked marker's id (or something that may well be useful) and run this deleting function according to this.
Briefly; I want to delete the marker that I clicked on, from a map having multiple markers.
Do you have any approach to solve this problem ?
Thanks in advance!
SOLVED!
Here is the solution. Thank you Fatih. it was impossible without your guidance:
var id;
var markers = {};
var addMarker = function () {
marker = new google.maps.Marker({
position: Gpoint,
map: map,
draggable: true,
animation: google.maps.Animation.DROP
});
map.panTo(Gpoint);
id = marker.__gm_id
markers[id] = marker;
google.maps.event.addListener(marker, "rightclick", function (point) { id = this.__gm_id; delMarker(id) });
}
var delMarker = function (id) {
marker = markers[id];
marker.setMap(null);
}
Calling delete function by: delMarker(id)
Ps: "Right clicking is enough on this case"
Thank you!
Working Sample on jsFiddle
Google Maps doesn't manage your markers. So all your markers should be managed by yourself.
Make a global marker object and push all markers to this object. And give unique id to each marker when getting a marker instance. Then when you want to delete a marker take its id and find this marker in global marker object and finally call this marker instance's setMap method with passing null argument.
Also I've added a demo that works on jsFiddle. Code is heavily documented.
Your psuedo code should be like this. For more detailed code please look the demo.
var currentId = 0;
var uniqueId = function() {
return ++currentId;
}
var markers = {};
var createMarker = function() {
var id = uniqueId(); // get new id
var marker = new google.maps.Marker({ // create a marker and set id
id: id,
position: Gpoint,
map: map,
draggable: true,
animation: google.maps.Animation.DROP
});
markers[id] = marker; // cache created marker to markers object with id as its key
return marker;
}
var deleteMarker = function(id) {
var marker = markers[id]; // find the marker by given id
marker.setMap(null);
}
Complementing the #Fatih answer you should manage the markers. For example you could add each marker in a array and then to remove, you could find this marker into the array and set the val in the map null.
Just pass your marker in the rightclick function. For example:
var marker = new google.maps.Marker({
position: event.latLng,
map: map,
draggable: true,
title: 'Hello World!'
});
google.maps.event.addListener(marker, "rightclick", function (point) {delMarker(marker)});
And make the function look this:
var delMarker = function (markerPar) {
markerPar.setMap(null);
}
Your markers will be removeable on the rightclicks.
this worked for me:
a second currentId, if you have a better idea, let me know
var actualMarkerId = 0;
var currentId = 0;
if (actualMarkerId>0) {
deleteMarker(actualMarkerId);
console.log(actualMarkerId);
}
var id = uniqueId(); // get new id
actualMarkerId = id;
For minimal changes
var newid=0;
for (var index in results){
var marker = new google.maps.Marker({
map: map,
icon: image,
__gm_id: = newid+1,
});
}
Now marker['__gm_id'] still has a value
Simple,Use Global array for marker Objects.
Push marker object in that array on plotting marker.
Yes,We can use Id in Marker Object for Unique Reference.
Code As Below
MarkerArray = []
marker = new google.maps.Marker({
Id: 1,
position: new google.maps.LatLng(Lat,Long),
type: 'info'
});
MarkerArray.push(marker);
To remove particular Marker,Find that Element Index using Unique Id for Each Marker.
var MarkerIndex = MarkerArray.findIndex(function GetIndex(element) {
return element.Id == 1;
});
MarkerArray[MarkerIndex].setMap(null);
MarkerArray.splice(MarkerIndex, 1); // to remove element from global array