google maps v3 event trigger on markers created by json - javascript

We have a dynamic json feed that is parsed into markers on our google map.
the parsing function looks something like this:
function parse_json(json) {
// alert('start parse: '+json.length);
if (json.length > 0) {
var markers = [];
for (i=0; i<json.length; i++) {
var report = json[i];
//alert(report.longitude +','+report.latitude);
// addLocation(report);
markers[i] = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(report.latitude, report.longitude),
pop_title: report.area1.name,
pop_body: '<b>'+ report.spot.name +'</b>'+
'<br>'+ report.report_description,
draggable: false,
title: 'title',
zIndex: i,
icon: '/images/map_icon.png'
});
markers[i].metadata = {type: "point", id: report.id};
google.maps.event.addListener(markers[i], 'click', onMarkerClick);
}
};
i have added metadata info to the markers created so their id is the report.id - but i want to use the google.maps.event.trigger(SOMETHING_HERE, 'click'); construct to trigger a click event on a given marker when a button outside of the map is pressed. how do i get the object name, or is there a way to do this using the object's id?
thanks!

If you declare your markers array at a higher scope than your parse_json function, then you will be able to refer to it later, something like this:
var markers = new Array();
function parse_json(json) {
//code removed for brevity
}
Then later, when you need to find the marker you want to fire a click event against, you could use the id like this:
for ( var i = 0; i < markers.length; i++ ) {
var mkr = markers[i];
if ( mkr.metadata.id === idYouAreSearchingFor ) {
//do whatever is needed here and fire your event
}
}

Related

Iterate Over Table with jQuery and Create a New Variable from Element Value

I've iterated over a table with javascript so I can use the data as a variable for creating markers on a Google Map. My map and the code that iterates over the table both work, but I cannot figure out how to make the gridmap value available inside my marker variable. I assume I need to do a for loop around my marker variable, which I can probably figure out, I am simple stuck on taking my element variables, and making them available as variables for my markers. Below is my code, if this makes any sense. I've been at this for hours and it is 3:30am; I will refractor the question in the morning if needed. Thank you.
This is the updated and working code:
I iterated over the DOM to grab the <tr> elements from tbody only. Note the tr:gt(0) part - this skips the first header row. Then I create a new array by filtering out the markers against the gdata array. I still need to clean this up a bit add more functionality like clustering, but I am very happy at this point and hopefully this will help someone else.
<script>
function initMap() {
var map;
var table = $("table");
var labels = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var labelIndex = 0;
var htmlLabel = labels.split(""); // Add Labels to Html Columns for Matching
var gdata = new Array();
$("table tbody tr:gt(0)").each(function (i) {
gdata[i] = new Array();
$(this).children('td').each(function (ii) {
gdata[i][ii] = $(this).text();
});
});
var bounds = new google.maps.LatLngBounds();
var mapOptions = {
mapTypeId: 'satellite',
disableDefaultUI: true,
scrollwheel: false,
draggable: true
};
// Display a map on the page
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
map.setTilt(45);
// Multiple Markers
var markers = [
['a0', 32.840801, -117.244842],
['a10', 32.840801, -117.244842],
['a20', 32.840777, -117.244864],
['a30', 32.840758, -117.244881],
['a40', 32.840732, -117.244899],
['aa0', 32.840828, -117.244794],
['aa10', 32.840828, -117.244794],
['b0', 32.840624, -117.24493],
['b10', 32.840624, -117.24493],
['b20', 32.840594, -117.244928],
['b30', 32.840567, -117.244924],
['b40', 32.840544, -117.244918],
['b60', 32.840544, -117.244918],
['bb0', 32.840495, -117.244897],
['bb10', 32.840495, -117.244897],
['bb20', 32.840468, -117.244885],
['c0', 32.84082, -117.244712],
['c10', 32.84082, -117.244712],
['c20', 32.840815, -117.244729],
['c30', 32.840806, -117.244749],
['c40', 32.840793, -117.244767],
['c50', 32.840779, -117.244789],
['c70', 32.840755, -117.244816],
['cc0', 32.840828, -117.244661],
['cc10', 32.840828, -117.244661],
['d0', 32.840607, -117.244867],
['d10', 32.840607, -117.244867],
['d20', 32.840586, -117.24486],
['d30', 32.840567, -117.244856],
['d40', 32.840543, -117.244841],
['d50', 32.840514, -117.244824],
['dd0', 32.84046, -117.244774],
['dd10', 32.84046, -117.244774],
['e0', 32.840788, -117.244598],
['e10', 32.840788, -117.244598],
['e20', 32.840791, -117.24462],
['e30', 32.840788, -117.244644],
['e40', 32.840787, -117.244665],
['e50', 32.840783, -117.244687],
['e60', 32.84078, -117.244707],
['e70', 32.840769, -117.244729],
['ee0', 32.84078, -117.244539],
['ee10', 32.84078, -117.244539],
['f10', 32.840607, -117.244809],
['f20', 32.840586, -117.244802],
['f30', 32.840564, -117.244785],
['f40', 32.840543, -117.244765],
['f50', 32.840532, -117.244749],
['f60', 32.840519, -117.244731],
['f70', 32.840508, -117.244714],
['ff0', 32.840473, -117.244632],
['ff10', 32.840473, -117.244632],
['g0', 32.840709, -117.244468],
['g10', 32.840709, -117.244468],
['g20', 32.840718, -117.244484],
['g30', 32.840737, -117.244499],
['g40', 32.840739, -117.244515],
['g50', 32.840747, -117.244531],
['h0', 32.840681, -117.244569],
['h10', 32.840681, -117.244569],
['h20', 32.840707, -117.244574],
['i0', 32.840611, -117.24458],
['i10', 32.840611, -117.24458],
['i20', 32.840576, -117.24461]
];
var filteredMarkers = []; // the results array
for (var iii = 0; iii < gdata.length; iii++) // iterate for every marker key
{
filteredMarkers = filteredMarkers.concat(markers.filter(function (item) {
return item[0] == gdata[iii][0];
}));
}
console.log(filteredMarkers);
console.log(gdata);
console.log(markers);
// Info Window Content
var infoWindowContent = [
['<div class="">' +
'<h3>Add Code Here</h3>' +
'<p>Add Code Here</p>' + '</div>']
];
// Display multiple markers on a map
var infoWindow = new google.maps.InfoWindow(), marker, i;
for (i = 0; i < filteredMarkers.length; i++) {
var position = new google.maps.LatLng(filteredMarkers[i][1], filteredMarkers[i][2]);
bounds.extend(position);
marker = new google.maps.Marker({
position: position,
map: map,
title: filteredMarkers[i][0],
label: labels[labelIndex++ % labels.length]
});
// Allow each marker to have an info window
google.maps.event.addListener(marker, 'click', (function (marker, i) {
return function () {
infoWindow.setContent(infoWindowContent[i][0]);
infoWindow.open(map, marker);
}
})(marker, i));
// Automatically center the map fitting all markers on the screen
map.fitBounds(bounds);
}
// Override our map zoom level once our fitBounds function runs (Make sure it only runs once)
var boundsListener = google.maps.event.addListener((map), 'bounds_changed', function (event) {
this.setZoom(24);
google.maps.event.removeListener(boundsListener);
});
}
</script>
It appears you're also using Angular and that the id='gridmap' div is returning the object name and not the content. The nature of the div content looks like the crux of problem and so would suggest looking at this SO question: How to show object property with Angularjs
From here if you can generate HTML that looks something like this below after Angular has done its thing, keeping the property out of view by inserting its elements into data tags:
<tr>
<td> ..... </td>
<td> ..... </td>
<td> ..... </td>
<td class='gridmap' data-lat='23.424' data-lng='-117.233'>a0</td>
</tr>
If you insert the whole object including curly brackets you may have to do additional JSON stringification and parsing which at this point are better avoided.
Note that HTML id labels should only used for unique DOM elements, so if you have more than one table row it should be a class (which also means adjusting your css accordingly)
Now we can use jquery data to interrogate the same HTML cell tag and pass to grLat and grLng variables :
$('tr').each(function (i) {
var $tds = $(this).find('td').eq(8), // moved the eq(8) here
gLabel = htmlLabel[i],
gridmap = $tds.text(),
grLat = Number($tds.data('lat')), // get the lat data
grLng = Number($tds.data('lng')); // get the lng data
console.log(
'Marker:' + gLabel
+ '\nRow:' + (i + 1)
+ '\nGrid Map: ' + gridmap
+ '\nGrid lat: ' + grLat
+ '\nGrid lng: ' + grLng // check components
);
var marker = new google.maps.Marker({
position: {lat: grLat, lng:grLng}, // recomposed object
map: map,
label: labels[labelIndex++ % labels.length],
animation: google.maps.Animation.DROP
});
})
This should put you in a better position to debug

Google Maps markers not incrementing array

I have looked all over but can't find an answer to this. I have a map that when I click on it adds markers to where I clicked. I am pushing those markers into an array but when I do one marker just seems to override the one that was in the array before instead of adding another index to the array. The array just always looks like this [me] no matter how many markers are on the map. Here is the code
addLatLng: function(event) {
var path = this.poly.getPath();
var markers = [];
path.push(event.latLng);
this.calcDistance(path);
var marker = new google.maps.Marker({
position: event.latLng,
title: '#' + path.getLength(),
map: this.map
});
markers.push(marker);
console.log(markers);
console.log(marker);
// debugger;
function removeMarkers(map) {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(map);
}
markers = [];
}
$('#btn-clear-map').on('click', function(event) {
event.preventDefault();
removeMarkers(null);
});
$('#btn-clear-point').on('click', function(event) {
event.preventDefault();
markers[markers.length -1].setMap(null);
});
},
this is part of a backbone view if that makes any difference. I just have no idea why when I push a marker in it seems to override the one that was already in there.
Edit: Ok I just figured out why, every time I click to make a new marker, it is resetting the marker array. Any clever ways to get around this?
The problem is that you are re-declaring the markers array on each call to addLatLng method (Also you're new event handlers and creating removeMarkers function and a closure each time)
Instead, you should keep the markers array as a property of the view as shown below:
Backbone.View.extend({
initialize: function() {
this.markers = [];
},
events: {
'click #btn-clear-map': 'removeMarkers',
'click #btn-clear-point': 'clearPoint',
},
render: function() {},
addLatLng: function(event) {
var path = this.poly.getPath();
path.push(event.latLng);
this.calcDistance(path);
var marker = new google.maps.Marker({
position: event.latLng,
title: '#' + path.getLength(),
map: this.map
});
this.markers.push(marker);
},
removeMarkers: function(event) {
event.preventDefault();
for (var i = 0; i < this.markers.length; i++) {
this.markers[i].setMap(null);
}
this.markers = [];
},
clearPoint: function(event) {
event.preventDefault();
this.markers[this.markers.length - 1].setMap(null);
}
});

Declaring google map markers in a loop

I have a weird issue with event listeners on google map markers. Basically I want to declare a bunch of markers in a loop, and have each marker have an associated infowindow. The relevant code is:
var markers=[];
var contents = [];
var infowindows = [];
for (i = 0; i < 10; i++) {
markers[i] = new google.maps.Marker({
position: new google.maps.LatLng(40+Math.random()*5, 4+Math.random()*5),
map: map,
title: 'samplemarker'
});
contents[i] = '<div class="popup_container">' +
'</div>';
infowindows[i] = new google.maps.InfoWindow({
content: contents[i],
maxWidth: 300
});
google.maps.event.addListener(markers[i], 'click', function() {
infowindows[i].open(map,markers[i]);
map.panTo(markers[i].getPosition());
});
}
The markers are created correctly, and the infowindows too, since if I do manually infowindows[i].open(map,markers[i]); they are opened correctly. However the listener does not work.
Even weirder: I have another marker, "marker_1" declared outside of the for loop, exactly the same way. If I write:
google.maps.event.addListener(marker_1, 'click', function() {
infowindows[0].open(map,markers[0]);
map.panTo(markers[0].getPosition());
});
The infowindow 0 is opened and the map is panned to marker 0 when marker_1 is clicked. However when writing, at the exact same position, the same lines except for marker_1 replaced with markers[0], a click on the marker 0 has no effect at all.
Thanks for any help and sorry if it's something stupid!
Inside your onclick handler, you don't already have that i value, in your case it would always take last value of i after the end of the loop, i.e 10, and markers[10] doesn't exist as you only have 10 markers.
To make it work you can e.g. add additional property to your markers in array, that would store marker index and use it inside your onlick handler
var markers=[];
var contents = [];
var infowindows = [];
for (i = 0; i < 10; i++) {
markers[i] = new google.maps.Marker({
position: new google.maps.LatLng(40+Math.random()*5, 4+Math.random()*5),
map: map,
title: 'samplemarker'
});
markers[i].index = i; //add index property
contents[i] = '<div class="popup_container"></div>';
infowindows[i] = new google.maps.InfoWindow({
content: contents[i],
maxWidth: 300
});
google.maps.event.addListener(markers[i], 'click', function() {
console.log(this.index); // this will give correct index
console.log(i); //this will always give 10 for you
infowindows[this.index].open(map,markers[this.index]);
map.panTo(markers[this.index].getPosition());
});
}
see corrected example

Bing Map adding infoBox from array of pins

Trying to add an infobox to each pin, each pin is loaded from a separate function and attaches the corresponding title, description, lat/lon, etc from an xml file. (source if needed)
In the function that receives the array of pins I'm trying to loop through each item and add infoboxes accordingly. Any ideas as to what I'm missing here?
function GeoRSSImportedCallback(items, bounds) {
map.entities.push(items);
for (var i = 0; i<items.length; i++) {
items.Title = items.title;
items.Description = items.description;
Microsoft.Maps.Events.addHandler(itmes, 'click', displayInfoBox);
}
map.entities.push(infoboxLayer);
map.setView({ bounds: bounds });
}
function displayInfoBox(e) {
pinInfoBox.setOptions({title: e.target.Title, description: e.target.Description, visible:true, offset: new Microsoft.Maps.Point(0,25)});
pinInfoBox.setLocation(e.target.getLocation());
}
I do initialize the following in the GetMap() function
pinInfoBox = new Microsoft.Maps.Infobox(new Microsoft.Maps.Location(0, 0), { visible: false });
infoboxLayer.push(pinInfoBox);
Your code uses properties that are not part of the various Bing Maps objects, so I am going to assume that is your intent. There are also errors with your for loop, the following should be more correct:
function GeoRSSImportedCallback(items, bounds) {
map.entities.push(items);
for (var i = 0; i<items.length; i++) {
items[i].Title = items[i].title; // Assumes .title is defined
items[i].Description = items[i].description; // Assumes .description is defined
Microsoft.Maps.Events.addHandler(items[i], 'click', displayInfoBox);
}
map.entities.push(infoboxLayer);
map.setView({ bounds: bounds });
}

Why does the javascript handler need to be attached in a different function?

In the code available here :
https://gist.github.com/1338861
if I would include the code of the function function attachEvent(marker){...}
into the body of the function
function addResults(json) {...}
like this :
function addResults(json) {
if (json.results && json.results.length) {
for (var i = 0, placemark; placemark = json.results[i]; i++) {
var pos = new google.maps.LatLng(parseFloat(placemark.point.latitude, 10),
parseFloat(placemark.point.longitude, 10));
var marker = new google.maps.Marker({
map: map,
title : placemark.name,
position: pos
});
google.maps.event.addListener(marker, 'click', function(){
var text = marker.getTitle();
showInContentWindow(text);
profileMarkers.push(marker);
}
}
}
the result would be that when clicking on any marker from the map, it would be shown in the content window only the information characteristic to the last marker added to profileMarkers array (instead of the information of the marker clicked).
My question is why does the onclick listener for the marker need to be attached in a different function (attachEvent in this context) ?
Because you keep changing marker to the last one by continuing the loop. Try this:
(function(mkr) {
google.maps.event.addListener(marker, 'click', function(){
var text = mkr.getTitle();
showInContentWindow(text);
profileMarkers.push(mkr);
}
})(marker);
In the place of the current google.maps.event.addListener code. This will create a closure and effectively "fix" the value of the variable.

Categories