I am integrating maps on a webpage with Overlapping Marker Spiderfier on google maps. I added a click listener on the marker as below.
$scope.setMarkers = function() {
for (var i = 0; i < $scope.markers.length; i++) {
$scope.markers[i].setMap($scope.map);
$scope.oms.addMarker($scope.markers[i]);
var marker = $scope.markers[i];
var iw = new google.maps.InfoWindow({
content: ""
});
$scope.oms.addListener('click', function(marker) {
iw.setContent(marker.desc);
iw.open($scope.map, marker);
});
}
};
and it works fine but jshint is giving me error for making function inside loop. So i changed it to.
$scope.setMarkers = function() {
for (var i = 0; i < $scope.markers.length; i++) {
$scope.markers[i].setMap($scope.map);
$scope.oms.addMarker($scope.markers[i]);
$scope.addMarkerEventListener(i);
}
};
$scope.addMarkerEventListener = function(i) {
var marker = $scope.markers[i];
var iw = new google.maps.InfoWindow({
content: ""
});
$scope.oms.addListener('click', function(marker) {
iw.setContent(marker.desc);
iw.open($scope.map, marker);
});
};
now when I am clicking on the marker its opening upto 90 info windows one behind another(i have 90 markers in an array). What am i missing.
you add the same listener each time you add a marker(Note that a listener will not overwrite previously added listeners).
It's sufficient to add 1 listener and to use 1 InfoWindow(except you want to have multiple InfoWindow's open at the same time).
Your first attempt works as expected because you overwrite iw inside the loop.
Possible solution:
//create a single InfoWindow-instance
$scope.iw = new google.maps.InfoWindow();
//add a single click-listener
$scope.oms.addListener('click', function (marker) {
$scope.iw.close();
$scope.iw.setContent(marker.desc);
$scope.iw.open($scope.map, marker);
});
//the loop
for (var i = 0; i < $scope.markers.length; ++i) {
$scope.markers[i].setMap($scope.map);
$scope.oms.addMarker($scope.markers[i]);
}
Demo: http://jsfiddle.net/doktormolle/qoko4425/
Related
I have a function that recenters the map around the marker when clicked.
google.maps.event.addListener(marker, 'click', function() {
map.panTo(marker.getPosition());
});
However, this obviously affects the addListener I have when getting the markers:
google.maps.event.addListener(map, 'idle', function() {
$.get("/map.json", function(galleries) {
var bounds = map.getBounds();
for (var i = 0; i < galleries.length; i++) {
var latitude = galleries[i].latitude;
var longitude = galleries[i].longitude;
var position = new google.maps.LatLng(latitude, longitude)
if (bounds.contains(position)){
bindInfobox(map, galleries[i]);
}
}
});
Is there a way to make an exception to the addListener, or another easy way around this? Thanks!
A quick workaround can be remove the event listener before you pan your map and then add the event listener again once the map has finished panning.
// add map idle event at load time
google.maps.event.addListener(map, 'idle', mapIdle);
//remove map idle event and then re-attach the event
google.maps.event.addListener(marker, 'click', function () {
google.maps.event.clearListeners(map, 'idle');
google.maps.event.addListenerOnce(map, 'idle', function () {
//add the idle event once the map has finised panning
google.maps.event.addListener(map, 'idle', mapIdle);
});
map.panTo(marker.getPosition());
});
function mapIdle() {
$.get("/map.json", function (galleries) {
var bounds = map.getBounds();
for (var i = 0; i < galleries.length; i++) {
var latitude = galleries[i].latitude;
var longitude = galleries[i].longitude;
var position = new google.maps.LatLng(latitude, longitude)
if (bounds.contains(position)) {
bindInfobox(map, galleries[i]);
}
}
});
}
I've got a map with a few MarkerWithLabel objects on it (http://google-maps-utility-library-v3.googlecode.com/svn/tags/markerwithlabel/1.1.9/). The labels, in this case, are integers.
I also have a MarkerClustererPlus (http://google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.1.2/) which also works fine.
However, I want to change the text on Clusters to show the sum of those integers on labels for every MarkerWithLabel inside a Cluster.
I did that by binding this function to the end of clustering:
function calculateClusterLabels() {
$.each(markerCluster.clusters_, function(i, cluster){
var sum = 0;
var cluster_markers = cluster.getMarkers();
$.each(cluster_markers, function(j, marker) {
sum += marker.labelContent;
});
cluster.clusterIcon_.sums_['text'] = sum;
cluster.updateIcon(); // also tried cluster.repaint();
});
}
And that works - at least for the Cluster text. But now we are getting to the real problem: it freezes the whole Map. Raven.js catches this: Uncaught TypeError: undefined is not a function. But nothing clearer than this.
Any ideas?
EDIT:
Some more code. Data is fetched with ajax and then the markers are set in a loop:
$.each(us_data, function(k, v) {
var markerPosition = new google.maps.LatLng(us_data[k]['lat'], us_data[k]['lon']);
var marker = new MarkerWithLabel({
position: markerPosition,
draggable: false,
map: map,
labelContent: us_data[k]['count'],
labelAnchor: anchor,
labelClass: "marker-with-label"
});
markers.push(marker);
});
And then I make the Clusters and bind the event:
markerCluster = new MarkerClusterer(map, markers, {imagePath: 'https://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclustererplus/images/m'});
google.maps.event.addListener(markerCluster, 'clusteringend', function() {
calculateClusterLabels();
});
This all happens inside the .done() of ajax, but markerCluster and markers are visible outside.
To answer myself: well, it was fairly simple after all:
function calculateClusterLabels() {
$.each(markerCluster.clusters_, function(i, cluster){
var sum = 0;
var cluster_markers = cluster.getMarkers();
$.each(cluster_markers, function(j, marker) {
sum += marker.labelContent;
});
if (cluster.clusterIcon_.sums_ != null) {
cluster.clusterIcon_.sums_['text'] = sum;
}
});
}
What I did - I added a simple if statement to check whether the .sums_ object is not null (because it wasn't null only on the visible clusters that had markers inside) and I omitted the .updateIcon call and everything works perfectly, no errors.
An even better solution, for my case, was to simply change the markerclusterer.js source file:
MarkerClusterer.CALCULATOR = function (markers, numStyles) {
var index = 0;
var title = "";
var count = 0;
if (typeof markers[0].labelContent != 'undefined') {
var sum = 0;
var i;
for (i = 0; i < markers.length; ++i) {
if (!isNaN(markers[i].labelContent) {
sum += markers[i].labelContent;
} else {
// whatever we need, perhaps we want to calculate it differently
}
}
count = sum.toString();
} else {
count = markers.length.toString();
}
var dv = count;
while (dv !== 0) {
dv = parseInt(dv / 10, 10);
index++;
}
index = Math.min(index, numStyles);
return {
text: count,
index: index,
title: title
};
};
This was even better because it updated Cluster styles, as well and it works both with regular Marker and MarkerWithLabel objects.
This question already has an answer here:
Remove all markers google map v3
(1 answer)
Closed 8 years ago.
Is there a way to do this instruction on google map v3 ? I have a button on the map, I want ,on the first click, to show markers and ,on the second, to remove them from map. Thank you for advance.
//Add hotel's markers and infowindows to the map
google.maps.event.addDomListener(hotel, 'click', function() {
for (var i = 0; i < len; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(results.rows.item(i).lat,results.rows.item(i).long),
map: map,
icon : icons[1],
animation: google.maps.Animation.DROP,
});
markers.push(marker);
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
//if we create the infowindow here, all the windows 'll stay shown
infowindow.setContent("<div style='background-color:red;'><h3>"+results.rows.item(i).nom+"</h3><br/><center>"+"<img src='"+results.rows.item(i).img+"' style='width:20px; height:20px;' /></center><br/></div>")
infowindow.open(map,marker);
}
})(marker,i));
}
});
Create a global showMarkers variable
Create a function toggleMarkers and call it when you click on the button
Here is a quick example:
var showMarkers = false;
function toggleMarkers() {
if (showMarkers === false) {
for (var i=0; i<markers.length; i++) {
markers[i].setMap(map);
}
showMarkers = true;
} else {
for (var i=0; i<markers.length; i++) {
markers[i].setMap(null);
}
showMarkers = false;
}
}
I have to manage a map of about 80.000 markers concentrated in France.
To do that, I decided to get the bounds of the viewport and call a dynamic-JSON (with PHP) which contains the markers inside the viewport. And this on the "idle" event.
I faced a problem with this solution. Indeed, the markers which already exist was re-plotted (at the same position), which consequently weigh the map for nothing...
To solve it, the markers list before and after the JSON query are compared (thanks to jQuery), in order to plot only the new markers. And it works!
Now, I would want to remove the markers which are not currently shown on the map. Or a list of markers (I get it thanks to jQuery) designated by an ID which is also the title of the marker. So, how can a delete markers like that ? I specify that I am using MarkerManager.
Otherwise, you guess that if I do not remove these markers, they will be re-plotted in some cases... For example, you are viewing the city A, you move the map to view the city B, and you get back to the city A...
Here is the code:
var map;
var mgr;
var markers = [];
function initialize(){
var mapOptions = {
zoom: 6,
center: new google.maps.LatLng(46.679594, 2.109375)
};
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
var mgrOptions = { borderPadding: 50, maxZoom: 15, trackMarkers: false };
mgr = new MarkerManager(map, mgrOptions);
google.maps.event.addListener(map, 'idle', function() {
mapEvent();
});
}
function mapEvent(){
if( map.getZoom() >= 8 ){
var bounds = map.getBounds();
getSupports(bounds.getNorthEast(), bounds.getSouthWest());
} else {
// Todo
}
}
var markerslistID = new Array();
var markerslistData = {};
function getSupports(ne, sw){
newMarkerslistID = new Array();
newMarkerslistData = {};
// Getting the markers of the current view
$.getJSON('./markerslist.php?nelat='+ne.lat()+'&nelng='+ne.lng()+'&swlat='+sw.lat()+'&swlng='+sw.lng(), function(data) {
for (var i = 0; i < data.points.length; i++) {
var val = data.points[i];
newMarkerslistID.push(val.id);
newMarkerslistData[val.id] = new Array(val.lat, val.lng, val.icon);
}
// List of New Markers TO PLOT
var diffNewMarkers = $(newMarkerslistID).not(markerslistID).get();
// List of Old markers TO REMOVE
var diffOldMarkers = $(markerslistID).not(newMarkerslistID).get();
// Plotting the NEW MARKERS
for( var i = 0; i < diffNewMarkers.length; i++ ){
var marker = new google.maps.Marker({
position: new google.maps.LatLng(newMarkerslistData[diffNewMarkers[i]][0], newMarkerslistData[diffNewMarkers[i]][1]),
title : diffNewMarkers[i],
icon : './images/'+newMarkerslistData[diffNewMarkers[i]][2]+'.png'
});
mgr.addMarker(marker, 0);
}
/*****************************************
HERE WE HAVE TO REMOVE
THE MARKERS CONTAINED IN diffOldMarkers
*****************************************/
mgr.refresh();
// Switching the new list to the old, for the next event
markerslistID = newMarkerslistID;
markerslistData = newMarkerslistData;
});
}
Thank you for your help.
A one-liner to hide all markers that ar not in the current viewport.
!map.getBounds().contains(marker.getPosition()) && marker.setVisible(false);
Or,
if (map.getBounds().contains(marker.getPosition()) && !marker.getVisible()) {
marker.setVisible(true);
}
else if (!map.getBounds().contains(marker.getPosition()) && marker.getVisible()) {
marker.setVisible(false);
}
I am new to JavaScript, i want to migrate from Google V2 to Google v3, for this i am just changing methods which are used in V2 slightly all are working but when i am trying to change the addListener from V2 to V3 i am facing problems like in v2 same listener is used to put the marker on the map but when it comes to V3 i am not able to put a marker on the map.Here i am posting v2 code and V3 code.Please help me to over come the problem. V2 is :
GEvent.addListener(map, "click", function(marker, point) {
console.debug('after Click map is '+map+' marker is '+marker+' point is '+point);
if (marker) {
if(PolygonMarkers.length == 1){ //Only one marker in the array
map.removeOverlay(PolygonMarkers[0]);
map.removeOverlay(PolygonMarkers[0]);
PolygonMarkers = [];
if(Polygon){map.removeOverlay(Polygon)};
} else{ /*More then one marker*/
var RemoveIndex = -1;
var Remove;
//Search for clicked Marker in PolygonMarkers Array
for(var m=0; m<PolygonMarkers.length; m++)
{
if(PolygonMarkers[m].getPoint().equals(marker.getPoint()))
{
RemoveIndex = m; Remove = PolygonMarkers[m];
break;
}
}
//Shift Array elements to left
for(var n=RemoveIndex; n<PolygonMarkers.length-1; n++)
{
PolygonMarkers[n] = PolygonMarkers[n+1];
}
PolygonMarkers.length = PolygonMarkers.length-1 //Decrease Array length by 1
map.removeOverlay(Remove); //Remove Marker
geofencedetails.drawPolygon(); //Redraw Polygon
}
allMarkers = PolygonMarkers;
} else {
// Adds a new Polygon boundary marker
var markerOptions = { icon: icon, draggable: true };
var marker = new GMarker(point, markerOptions);
PolygonMarkers.push(marker); //Add marker to PolygonMarkers array
map.addOverlay(marker); //Add marker on the map
GEvent.addListener(marker,'dragstart',function(){ //Add drag start event
marker.setImage(icon.image);
polygon_resizing = true;
});
GEvent.addListener(marker,'drag',function(){
geofencedetails.drawPolygon();
}); //Add drag event
GEvent.addListener(marker,'dragend',function(){ //Add drag end event
marker.setImage(icon.image);
polygon_resizing = false;
geofencedetails.drawPolygon();
});
geofencedetails.drawPolygon();
allMarkers = PolygonMarkers;
}
});`
and V3 is
google.maps.event.addListener(map, "click", function(marker, point) {
if (marker) {
//console.debug('marker '+marker.toSource());
if(PolygonMarkers.length == 1){ //Only one marker in the array
map.removeOverlay(PolygonMarkers[0]);
map.removeOverlay(PolygonMarkers[0]);
PolygonMarkers = [];
if(Polygon){
map.removeOverlay(Polygon)
};
}else { /*More then one marker*/
//console.debug('PolygonMarkers.length is '+PolygonMarkers.length);
var RemoveIndex = -1;
var Remove;
//Search for clicked Marker in PolygonMarkers Array
for(var m=0; m<PolygonMarkers.length; m++){
//console.debug('PolygonMarkers['+m+'] '+PolygonMarkers[m]);
if(PolygonMarkers[m].getPosition().equals(marker.getPosition())){
//console.debug('Both are equal ');
RemoveIndex = m;
Remove = PolygonMarkers[m];
break;
}
}
//Shift Array elements to left
for(var n=RemoveIndex; n<PolygonMarkers.length-1; n++){
PolygonMarkers[n] = PolygonMarkers[n+1];
}
PolygonMarkers.length = PolygonMarkers.length-1 //Decrease Array length by 1
/*map.removeOverlay(Remove); //Remove Marker*/
for (var i = 0; i < allMarkers.length; i++ ) {
allMarkers[i].setMap(null);
}
geofencedetails.drawPolygon(); //Redraw Polygon
}
allMarkers = PolygonMarkers;
} else {
//console.debug('In else block');
// Adds a new Polygon boundary marker
var markerOptions = { icon: icon, draggable: true };
//console.debug('1');
var marker = new GMarker(point, markerOptions);
//console.debug('2');
PolygonMarkers.push(marker); //Add marker to PolygonMarkers array
//console.debug('3');
map.addOverlay(marker); //Add marker on the map
//console.debug('4');
GEvent.addListener(marker,'dragstart',function(){ //Add drag start event
//console.debug('5');
marker.setImage(icon.image);
//console.debug('6');
polygon_resizing = true;
});
GEvent.addListener(marker,'drag',function(){
geofencedetails.drawPolygon();
}); //Add drag event
GEvent.addListener(marker,'dragend',function(){ //Add drag end event
marker.setImage(icon.image);
polygon_resizing = false;
geofencedetails.drawPolygon();
});
geofencedetails.drawPolygon();
allMarkers = PolygonMarkers;
}
});
You need to bind the click event to the marker instead of the map.
google.maps.event.addListener(marker, "click", function(event) { .... } );
UI events within the Google Maps API V3 typically pass an event
argument, which can be accessed by the event listener, noting the UI
state when the event occurred. For example, a UI 'click' event
typically passes a MouseEvent containing a latLng property denoting
the clicked location on the map. Note that this behavior is unique to
UI events; MVC state changes do not pass arguments in their events.