Google Maps API v3 binding events to multiple maps - javascript

I've got a page with two Google maps on, using the v3 API. Currently they have one pin each, with the same lat & long set for each pin, although one of the maps will have other pins added at a later date (when I can get this to work!) The maps are generated by looping through an object, so further maps can be added simply if needed.
What I am trying to do is bind the bounds_changed event once to both maps, to run map.setZoom() after map.fitBounds() has been run. The event, however, only binds to the last map to be set up, so does not reset the zoom on the first map.
Link to JSFiddle replicating the issue: http://jsfiddle.net/pkhb8mvz/7/
(For a more clear example of what the event is being bound to, change the event to listen on click rather than bounds_changed then try clicking on the first map and watch the zoom level change on the second map)
Any help greatly appreciated!

The problem is that the map variable is being redefined on each iteration of your loop, so by the time your event listener callback runs it will operate on the second google.maps.Map object. The simplest solution is to capture the value of the map variable on each iteration using a closure, like so:
(function (map) {
var listener = new google.maps.event.addListenerOnce(map, "bounds_changed", function () {
if (!opts.center) {
map.setZoom(opts.zoom);
};
});
}) (map);
I forked your JSFiddle to demonstrate the idea: https://jsfiddle.net/e8qbr8qL/

Created this fiddle that works based on this answer https://stackoverflow.com/a/5839041/2321666.
Apart from the function you need to add, your map variable should be an array so that there is one instance of each map.
map[i] = new google.maps.Map($(maps[i].mapElement)[0], opts);
If you need any explanation of the code please ask, but i think there is enough info about javascript closures in the post added.

You can't add a listener to multiple maps unless you keep references to all of them, currently you are only keeping a reference to the last map created.
// use function closure to associate the map with its bounds listener
addBoundsListener(map, opts, bounds);
map.fitBounds(bounds);
}
function addBoundsListener(map, opts, bounds) {
// If no center option has been specified, center the map to
// contain all pins and reset the zoom
var listener = new google.maps.event.addListenerOnce(map, "bounds_changed", function () {
if (!opts.center) {
map.setZoom(opts.zoom);
}
});
}
updated fiddle
code snippet:
var maps = {
"propertyLocation": {
"mapElement": "#map1",
"options": {
"zoom": 10,
"streetViewControl": false
},
"pins": [{
"title": "Test 1",
"lat": "52.1975331616",
"long": "0.9771180153"
}]
},
"localArea": {
"mapElement": "#map2",
"options": {
"zoom": 14,
"streetViewControl": false
},
"pins": [{
"title": "Test 2",
"lat": "52.1975331616",
"long": "0.9771180153"
}]
}
};
// Sensible defaults
var defaults = {
zoom: 9,
mapTypeId: google.maps.MapTypeId.ROADMAP,
draggable: true
};
for (var i in maps) {
// Extend the options
var opts = $.extend(true, defaults, maps[i].options),
marker,
map,
bounds = new google.maps.LatLngBounds();
// Create the map
map = new google.maps.Map($(maps[i].mapElement)[0], opts);
// Create all pins
for (var p = 0; p < maps[i].pins.length; p++) {
var pin = maps[i].pins[p];
marker = new google.maps.Marker({
position: new google.maps.LatLng(pin.lat, pin.long),
map: map,
title: pin.title,
icon: pin.icon
});
// Extend the bounds of the map to contain the marker
bounds.extend(marker.position);
}
// use function closure to associate the map with its bounds listener
addBoundsListener(map, opts, bounds);
map.fitBounds(bounds);
}
function addBoundsListener(map, opts, bounds) {
// If no center option has been specified, center the map to
// contain all pins and reset the zoom
var listener = new google.maps.event.addListenerOnce(map, "bounds_changed", function() {
if (!opts.center) {
map.setZoom(opts.zoom);
}
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://maps.googleapis.com/maps/api/js?libraries=places&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<div style="width: 500px; height: 500px;" id="map1"></div>
<div style="width: 500px; height: 500px;" id="map2"></div>

Related

JSON feed on Google map is showing nothing

I want the Google map show marker with JSON feeds. but it's not working. I can't find the actual problem. so here is my code:
var map;
// The JSON data
var json = [{
"OpperationErrorMsg":"",
"IsSuccess":true,
"ResultId":1000,
"Timestamp":"2016-10-12T18:00:07.0232702Z",
"Echo":null,
"InSandbox":true,
"DebugMessages":[
],
"MissingDetails":[
],
"ResponseData":[
{
"CallTimeLocal":"2016-10-10T06:28:48.7330000",
"IncidentId":3374,
"IncidentNumber":"HC2016004034",
"CallTime":"2016-10-10T10:28:48.7330000",
"ElapsedSeconds":0,
"Location":"2712 E HANNA AVE",
"BuildingName":null,
"BuildingNumber":null,
"NatureId":6743,
"FirePriorityId":1,
"CoordinateX":-82.429500000000,
"CoordinateY":28.003389000000
},
{
"CallTimeLocal":"2016-10-10T11:28:36.7000000",
"IncidentId":3382,
"IncidentNumber":"HC2016004042",
"CallTime":"2016-10-10T15:28:36.7000000",
"ElapsedSeconds":0,
"Location":"1220 APOLLO BEACH BLVD S",
"BuildingName":"Apollo Beach Marina",
"BuildingNumber":null,
"NatureId":8035,
"FirePriorityId":1,
"CoordinateX":-82.422369000000,
"CoordinateY":27.781254000000
},
{
"CallTimeLocal":"2016-10-10T14:29:59.8830000",
"IncidentId":3387,
"IncidentNumber":"HC2016004047",
"CallTime":"2016-10-10T18:29:59.8830000",
"ElapsedSeconds":0,
"Location":"9600 SHELDONWOOD RD",
"BuildingName":null,
"BuildingNumber":null,
"NatureId":6420,
"FirePriorityId":12,
"CoordinateX":-82.580530000000,
"CoordinateY":28.034779000000
},
{
"CallTimeLocal":"2016-10-10T15:27:37.7270000",
"IncidentId":3389,
"IncidentNumber":"HC2016004049",
"CallTime":"2016-10-10T19:27:37.7270000",
"ElapsedSeconds":0,
"Location":"4691 GALLAGHER RD",
"BuildingName":"Strawberry Crest High School",
"BuildingNumber":null,
"NatureId":7873,
"FirePriorityId":2,
"CoordinateX":-82.236450000000,
"CoordinateY":28.021233000000
}
],
"CurrentStatusData":null
}];
function initialize() {
// Giving the map som options
var mapOptions = {
zoom: 6,
center: new google.maps.LatLng(25.0,-80.0)
};
// Creating the map
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
// Looping through all the entries from the JSON data
for(var i = 0; i < json.length; i++) {
// Current object
var obj = json[i];
// Adding a new marker for the object
var marker = new google.maps.Marker({
position: new google.maps.LatLng(obj.CoordinateY,obj.CoordinateX),
map: map,
draggable: true,
animation: google.maps.Animation.DROP,
title: obj.BuildingName // this works, giving the marker a title with the correct title
});
// Adding a new info window for the object
var clicker = addClicker(marker, obj.title);
} // end loop
// Adding a new click event listener for the object
function addClicker(marker, content) {
google.maps.event.addListener(marker, 'click', function() {
if (infowindow) {infowindow.close();}
infowindow = new google.maps.InfoWindow({content: content});
infowindow.open(map, marker);
});
}
}
// Initialize the map
google.maps.event.addDomListener(window, 'load', initialize);
html, body, #map-canvas {
height: 100%;
margin: 0;
padding: 0;
}
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=true"></script>
<script src="https:////cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<div id="map-canvas"></div>
I will be using it on a HTML page. Though the JSON data will be updated automatically so i can't change the JSON Arrays.
Thanks!
I found these problems in your code:
In your loop where you create each marker, you are looping over the json array. However, this is not your array of marker data. json[0] is your main object, and json[0].ResponseData is the marker array that you need to loop over. So I put that value in a variable named responses and looped over that instead. I don't know if the JSON data could have more than one object in its outermost array; if it does you would need an outer loop to handle those. For now I assumed there is just one outer object addressed with json[0].
When you call addClicker you pass in obj.title which doesn't exist. Presumably you meant obj.BuildingName.
Your click handler references a variable called infowindow, but on the first click that variable does not exist and causes an error. So I declared infowindow as a global window.
So, how did I find these problems? Using the JavaScript debugger. Normally I would add a debugger; statement at the beginning of the initialize() function and single step through the code to see what is going on. This would reveal that where the main loop sets var obj = json[i]; it isn't getting the expected value.
That works great on a normal web page, but it doesn't seem to work well in the embedded snippet here on SO. (The debugger shows the wrong source line.) So instead I started adding console.log(); statements where it looked like things might be going wrong, such as console.log( 'obj:', obj ); immediately after the var obj = assignment.
Also, it's nice to automatically zoom and center the map according to where the markers are located. I added a bit of code using a LatLngBounds which is extended for each marker, and then a map.fitBounds() after all the markers are created. If you do that you don't need to explicitly zoom and center the map when first creating it, so I removed those. (Otherwise the map is displayed at one position and then repositioned.)
One caveat with the fitBounds(): if there were no markers, then the map wouldn't get displayed at all. To handle that case you would want to check for the case where responses.length is zero and call map.setZoom() and map.setCenter() with default values.
I marked the changed lines with //// to make them easy to find:
var map, infowindow; ////
// The JSON data
var json = [{
"OpperationErrorMsg":"",
"IsSuccess":true,
"ResultId":1000,
"Timestamp":"2016-10-12T18:00:07.0232702Z",
"Echo":null,
"InSandbox":true,
"DebugMessages":[
],
"MissingDetails":[
],
"ResponseData":[
{
"CallTimeLocal":"2016-10-10T06:28:48.7330000",
"IncidentId":3374,
"IncidentNumber":"HC2016004034",
"CallTime":"2016-10-10T10:28:48.7330000",
"ElapsedSeconds":0,
"Location":"2712 E HANNA AVE",
"BuildingName":null,
"BuildingNumber":null,
"NatureId":6743,
"FirePriorityId":1,
"CoordinateX":-82.429500000000,
"CoordinateY":28.003389000000
},
{
"CallTimeLocal":"2016-10-10T11:28:36.7000000",
"IncidentId":3382,
"IncidentNumber":"HC2016004042",
"CallTime":"2016-10-10T15:28:36.7000000",
"ElapsedSeconds":0,
"Location":"1220 APOLLO BEACH BLVD S",
"BuildingName":"Apollo Beach Marina",
"BuildingNumber":null,
"NatureId":8035,
"FirePriorityId":1,
"CoordinateX":-82.422369000000,
"CoordinateY":27.781254000000
},
{
"CallTimeLocal":"2016-10-10T14:29:59.8830000",
"IncidentId":3387,
"IncidentNumber":"HC2016004047",
"CallTime":"2016-10-10T18:29:59.8830000",
"ElapsedSeconds":0,
"Location":"9600 SHELDONWOOD RD",
"BuildingName":null,
"BuildingNumber":null,
"NatureId":6420,
"FirePriorityId":12,
"CoordinateX":-82.580530000000,
"CoordinateY":28.034779000000
},
{
"CallTimeLocal":"2016-10-10T15:27:37.7270000",
"IncidentId":3389,
"IncidentNumber":"HC2016004049",
"CallTime":"2016-10-10T19:27:37.7270000",
"ElapsedSeconds":0,
"Location":"4691 GALLAGHER RD",
"BuildingName":"Strawberry Crest High School",
"BuildingNumber":null,
"NatureId":7873,
"FirePriorityId":2,
"CoordinateX":-82.236450000000,
"CoordinateY":28.021233000000
}
],
"CurrentStatusData":null
}];
function initialize() {
// Giving the map som options
var mapOptions = {
////
};
// Creating the map
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
var bounds = new google.maps.LatLngBounds(); ////
// Looping through all the entries from the JSON data
var responses = json[0].ResponseData; ////
for(var i = 0; i < responses.length; i++) { ////
// Current object
var obj = responses[i]; ////
// Adding a new marker for the object
var position =
new google.maps.LatLng( obj.CoordinateY, obj.CoordinateX ); ////
bounds.extend( position ); ////
var marker = new google.maps.Marker({
position: position, ////
map: map,
draggable: true,
animation: google.maps.Animation.DROP,
title: obj.BuildingName
});
// Adding a new info window for the object
var clicker = addClicker(marker, obj.BuildingName); ////
} // end loop
map.fitBounds( bounds ); ////
// Adding a new click event listener for the object
function addClicker(marker, content) {
google.maps.event.addListener(marker, 'click', function() {
if (infowindow) {infowindow.close();}
infowindow = new google.maps.InfoWindow({content: content});
infowindow.open(map, marker);
});
}
}
// Initialize the map
google.maps.event.addDomListener(window, 'load', initialize);
html, body, #map-canvas {
height: 100%;
margin: 0;
padding: 0;
}
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=true"></script>
<script src="https:////cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<div id="map-canvas"></div>

Kendo UI Map - How to add marker with javascript

I have a map that a user will utilize in order to mark their position. I use geolocation and Bing layer to give them a good start. I want them to click on the map, have it recenter to the point they click, remove the existing marker, then create a new one where the map is centered.
function onClick(e) {
var resultArray = e.location.toString().split(',');
$('#map').data("kendoMap").center([parseFloat(resultArray[0]), parseFloat(resultArray[1])]);
$('#map').data("kendoMap").markers.clear();
$('#map').data("kendoMap").markers.add([parseFloat(resultArray[0]), parseFloat(resultArray[1])]);
}
The function above centers the map, removes the previous marker, and does not give an error on the ADD. However, the new marker doesn't show up.
Any help would be appreciated.
** Thanks for pointing me in the right direction. I am creating my map as a result of the geolocation. It is working now with this.
function createMap(Lat, Long) {
$("#map").kendoMap({
center: [Lat, Long],
zoom: 17,
layers: [{
type: "bing",
imagerySet: "aerialWithLabels",
key: "###MYKEY###"
}],
markers: [{
location: [Lat, Long],
shape: "pinTarget",
tooltip: {
content: "You are Here!!"
}
}],
click: onClick,
panEnd: onPanEnd
});
}
function onClick(e) {
var map = $("#map").data("kendoMap");
var loc = map.eventToLocation(e);
map.center(loc);
map.markers.clear();
map.markers.add({ location: loc });
}
You should define:
var map = $("#map").data("kendoMap");
outise the on click event
and then use map variable
map.center(loc);
map.markers.clear();
map.markers.add({location: loc});
http://dojo.telerik.com/AMoHA

Google Maps JavaScript - adding multiple markers to one map

I'm having difficulty setting event handlers to Google Maps markers in JavaScript. Below is my code:
var map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 8,
center: {lat: -35, lng: 149}
});
for (var i = 0; i < basketballCourts.length; i++) {
var marker = new google.maps.Marker({
position: new google.maps.LatLng(basketballCourts[i].latitude, basketballCourts[i].longitude),
map: map,
title: 'Hello World!'
});
marker.set("data-index", i);
google.maps.event.addListener(marker, 'click', function() {
console.log(marker.get("data-index"));
});
}
You'll notice that there is a click event for the markers. However, the click event is the same for all the markers. A different number should be logged for every marker click, but no matter what marker I click on, I get the same response.
I'm not sure how to fix this.
What's happening is you're looping over all your basketballCourts, creating an event listener for each marker. That's all well and good. However that event listener function looks like:
console.log(marker.get("data-index"));
The function executes in response to a marker click, not when you define it. And the value of marker when the function executes will be the value it had at the end of your loop over all the basketballCourts.
Using #MiltoxBeyond's suggestion, try using this.get("data-index")

How to get onclick event of marker generated by getroute

In this jsfiddle is simplified version of my js: http://jsfiddle.net/Drecker/2m4kvxb8/4/ Note that interesting part of the jsfiddle is only showRoute method. And method showMarker only shows desired behavior on normal marker.
Basically I generate a route via gmap3 getroute with some waypoints. After clicking on a waypoint I need to open a small infobox with more custom information of that point - so basically somehow get onclick event of such waypoint (with some identification of that waypoint so I would be able to get proper information). I'm able to achieve desired behavior on a separate marker (as you can see in the jsfiddle - that's the fully functional separate marker on the top left), but not on the markers generated by directionrenderer.
Furthermore please note that my waypoints have stopover: false and such markers for some reason ignore (some) options like title, as you can see in jsfiddle.
Any help is very appreciated - I've tried several things none of them works.
Hope you are using the google APIs library some version, in case something like this
<script src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places,geometry" type="text/javascript"></script>
You have one div space to show the map, say
<div id="map" style="width: 700px; height: 600px;"></div>
So you can use this for adding listener on markers
//location is an array variable where you store your co ordinates
//code to show map
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 10,
center: new google.maps.LatLng(locations[0].latitude, locations[0].longitude),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
//adding listener
var marker,i;
var infowindow = new google.maps.InfoWindow();
google.maps.event.addListener(marker, 'click', (function (marker, i) {
return function () {
infowindow.setContent(locations[i].city);
infowindow.open(map, marker);
}
})(marker, i));
where
marker
is the varible which will be something like this,
//adding marker
for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i].latitude, locations[i].longitude),
map: map
});
Hope from above you got some idea, might be helpful for you with your problem
There is no such option, according to the documentation and a lot of similar questions here on the stackoverflow, you can't bind click action to waypoints.
I have a workaround for that problem. The main idea is to add markers instead of waypoints and change their icon. Marker has much more options than waypoint. So I removed waypoints and added markers. Note that you have to be much more precise when adding marker's location
options without waypoints:
options: {origin: {lat:49.9, lng: 14.9},
destination: {lat: 50.1, lng: 15.1},
travelMode: google.maps.DirectionsTravelMode.DRIVING
},
added markers with a new icon and click event:
marker:{
values:[
{latLng:[49.96485, 14.88392], data:"Waypoint1", options:{icon: "http://mt.google.com/vt/icon/name=icons/spotlight/directions_transfer_icon_10px.png&scale=1"}},
{latLng:[49.97730, 14.88185], data:"Waypoint2", options:{icon: "http://mt.google.com/vt/icon/name=icons/spotlight/directions_transfer_icon_10px.png&scale=1"}}
],
options:{
draggable: false
},
events:{
click: function(marker, event, context){
var map = $(this).gmap3("get"),
infowindow = $(this).gmap3({get:{name:"infowindow"}});
if (infowindow){
infowindow.open(map, marker);
infowindow.setContent(context.data);
} else {
$(this).gmap3({
infowindow:{
anchor:marker,
options:{content: context.data}
}
});
}
}
}
}
Here is my workaround for that problem : DEMO

How to get some information in google maps without click event on marker and show this in a div, other than infoWindow

Hi I am showing some markers on my google map and on click of the marker, I am calling the click event and showing some info about that place to the right side(area other than Map and not as an infoWindow). Now this event gets fired on click, and by default when page loads my div remains blank, How can I have the div the basic information being shown up once the map loads up. I need to show the information that corresponds to the marker that is the center point of the map, and later when the users click the marker icons the info should change and correspond to the particular marker being clicked
I have tried something but it doesn't work:
function loadMap() {
var myLatlng = new google.maps.LatLng(40.46998, -3.68705);
var myOptions = {
zoom: 3,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map"), myOptions);
var places = [];
places.push(new google.maps.LatLng(51.43581, -0.51744));
places.push(new google.maps.LatLng(48.87187, 2.31764));
places.push(new google.maps.LatLng(45.45979, 9.19681));
var infowindow;
for(var i = 0; i<places.length; i++) {
var marker= new google.maps.Marker({
position: places[i],
map: map,
title: 'Place' + i
});
(function (i,marker){
google.maps.event.addListener(marker, 'click' , function() {
infowindow.setContent('PLace Number' + i)
infowindow.open(i, marker)
});
});(i, marker);
}
}
$("document").ready(function () {
loadMap();
});
UPDATE EDITED
Basically I need something like Layer KML features
But the info should come on the right hand side by default for the first time. Later on when the marker is clicked, the info should change. I am also not adamant that I need this info in a kml file(xml is fine with me as well). I can just have a marker and info should popup on click and for the first time be default as well depending on the location of the user.
Bottom Line: I need the info to appear on click of a marker and by default when the page loads the info should appear corresponding to the center point of the map. which means users coming from different locations will see different info's corresponding to their location from where they are coming.(I am centering the map based on users location)
You can use the addDomListener event of the google maps api. Something like this:
<script>
function initialize() {
// Map initialization
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
<body>
<div id="map_canvas"></div>
</body>
Although the above code is Maps Javascript API code, the addDomListener() method binds to the window object of the browser and allows the API to communicate with objects outside of the API's normal domain.
further reading
Actually the basic Idea is that you need to read an XMl and parse the data and and show this in a seperate div on right side., This div you can create dynamically when you load the map e-g:
$("#body").append("<div class='newdiv'></div>")
From the google Docs in the section about InfoWindow:
Note that if you call open() without passing a marker, the InfoWindow
will use the position specified upon construction through the
InfoWindow options object.
So in your code, why don't you simply init your infoWindow and call the open() method? I am not particularly familiar with the api, but how about:
var infowindow = new google.maps.InfoWindow({
content: 'your initial text'
});
infowindow.open();
Or if you need the marker for special purposes on the infowindow, init an marker with the center position and use that in the infowindow.open(your_initial_pos) call.
You can use jQuery to .triger() a click event on the first marker on document.ready:
$(marker).trigger('click');
This will run the code you have already written and make it so when the page loads your div will be populated with data from whatever element you trigger the click on.
When you bind to document.ready you don't need encapsulate document in quotes:
$(document).ready(function () {...});
Or you could use the short-hand if you're into that sort of thing:
$(function () {...});
UPDATE
You can place the trigger function call after your for loop where you are setting up the markers:
for(var i = 0; i<places.length; i++) {
var marker= new google.maps.Marker({
position: places[i],
map: map,
title: 'Place' + i
});
(function (i,marker){
google.maps.event.addListener(marker, 'click' , function() {
infowindow.setContent('PLace Number' + i)
infowindow.open(i, marker)
});
});(i, marker);
//only run on the first marker
if (i === 0) {
//trigger a click event to show the first info-window
$(marker).trigger('click');
}
}
You can fire a tilesloaded event on the map object. Check out the Map reference for events
tilesloaded waits until the map tiles are actually loaded before firing. Using your code, you could do something like this:
function loadMap() {
var myLatlng = new google.maps.LatLng(40.46998, -3.68705);
var myOptions = {
zoom: 3,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map"), myOptions);
google.maps.event.addListener(map, 'tilesloaded', function() {
doSomething();
});

Categories