Mapbox Javascript API function event call order - javascript
I am only attaching the script tag. Below is the flow of events that happen and the problem I see. I would appreciate any suggestions/advice.
I trigger the businessGeocoder by searching for an address, which triggers the businessAddress function inside the initialize function, which in turn triggers the businessLocationClickInfo function. This works perfectly.
Without refreshing the page I decide to use the employeeResidenceGeocoder by searching for an address, which triggers the employeeResidenceAddress function inside the initialize function, which in turn triggers the employeeResidenceLocationClickInfo function. This works perfectly. too.
Again, without refreshing the page I decide to use the businessGeocoder again by searching for an address, which triggers the businessAddress function inside the initialize function, which in turn SHOULD trigger the businessLocationClickInfo function, but instead, it triggers the employeeResidenceLocationClickInfo function. The employeeResidenceLocationClickInfo function, while it should have not been called, returns the correct data. I am having a hard time understanding why it is being called instead of the businessLocationClickInfo function.
Please note that doing it the other way, using employeeResidenceGeocoder first and then businessGeocoder, and then back to employeeResidenceGeocoder causes the same problem.
Update>> I ran console logs after each line and found out that because the click events are called in the initialize function, every time I click on the map both businessLocationClickInfo and employeeResidenceLocationClickInfo are being called, one replacing the other output div, whereas I want to only call one of them, depending on the geocoder. But I still haven't found a way/order to fix it.
<script>
var map;
var businessGeocoder;
var employeeResidenceGeocoder;
var businessLocationClickFeature;
var employeeResidenceLocationClickFeature;
var screenPoint;
var address;
var geocodeFeature;
var geocodePopup;
var geocodeCensusTract;
var geocodeCensusBlockGroup;
var businessLocationPolygon;
var employeeResidenceLocationPolygon;
function initialize() {
businessGeocoder = new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
flyTo: {
speed: 100
},
zoom: 17,
placeholder: "Search for a business location",
mapboxgl: mapboxgl
})
employeeResidenceGeocoder = new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
flyTo: {
speed: 100
},
zoom: 17,
placeholder: "Search for an employee's residence",
mapboxgl: mapboxgl
})
// // // adds geocoder outside of map (inside of map would make it a 'map control')
// document.getElementById('geocoder1').appendChild(businessGeocoder.onAdd(map));
// document.getElementById('geocoder2').appendChild(employeeResidenceGeocoder.onAdd(map));
map.addControl(businessGeocoder);
map.addControl(employeeResidenceGeocoder);
businessGeocoder.on('result', businessAddress);
employeeResidenceGeocoder.on('result', employeeResidenceAddress);
}
function businessAddress (obj) {
address = obj.result.place_name;
$(".geocode-result-area").html('<b>Geocoded Business Address: </b>' + address + '<br/><div class="medium-font">Click the blue address pin on the map for updated results.</div>');
$(".geocode-click-result-area").html("");
map.on('click', businessLocationClickInfo);
}
function employeeResidenceAddress (obj) {
address = obj.result.place_name;
$(".geocode-result-area").html('<b>Geocoded Employee Residence Address: </b>' + address + '<br/><div class="medium-font">Click the blue address pin on the map for updated results.</div>');
$(".geocode-click-result-area").html("");
map.on('click', employeeResidenceLocationClickInfo);
}
function businessLocationClickInfo (obj) {
businessLocationClickFeature = map.queryRenderedFeatures(obj.point, {
layers: ['tract-4332-1sbuyl','blockgroups-4332-9mehvk','businesslocation']
});
if (businessLocationClickFeature.length == 3) {
$(".geocode-click-result-area").html('<br/>This area meets the <span style="background-color:yellow">business location criteria</span> based on the following thresholds:'
+ '<table><tr><td>Renewal Community</td><td>' + businessLocationClickFeature[2].properties.Inquiry1 + '</td></tr>'
+ '<tr><td>CT & BG Poverty Rate ≥ 20%</td><td>' + businessLocationClickFeature[2].properties.Inquiry2 + '</td></tr></table>'
+ '<p><b>' + businessLocationClickFeature[0].properties.CountyName + " County" + '<br/>'
+ businessLocationClickFeature[0].properties.NAMELSAD + '<br/>'
+ businessLocationClickFeature[1].properties.NAMELSAD + '</b></p>'
+'<table><tr><th></th><th>Poverty Rate</th></tr><tr><td>CT '
+ businessLocationClickFeature[0].properties.TRACTCE + '</td><td>'
+ businessLocationClickFeature[0].properties.PovRate + "%" + '</td></tr><tr><td>BG '
+ businessLocationClickFeature[1].properties.BLKGRPCE + '</td><td>'
+ businessLocationClickFeature[1].properties.PovRate + "%" + '</td></tr></table>'
);
}
else {
$(".geocode-click-result-area").html('<br/> This area <u style = "color:red;">does not</u> meet the business location criteria based on the following thresholds:'
+ '<table><tr><td>Renewal Community</td><td>No</td></tr>'
+ '<tr><td>CT & BG Poverty Rate ≥ 20%</td><td>No</td></tr></table>'
+ '<p><b>' + businessLocationClickFeature[0].properties.CountyName + " County" + '<br/>'
+ businessLocationClickFeature[0].properties.NAMELSAD + '<br/>'
+ businessLocationClickFeature[1].properties.NAMELSAD + '</b></p>'
+ '<table><tr><th></th><th>Poverty Rate</th></tr><tr><td>CT '
+ businessLocationClickFeature[0].properties.TRACTCE + '</td><td>'
+ businessLocationClickFeature[0].properties.PovRate + "%" + '</td></tr><tr><td>BG '
+ businessLocationClickFeature[1].properties.BLKGRPCE + '</td><td>'
+ businessLocationClickFeature[1].properties.PovRate + "%" + '</td></tr></table>'
);
}
}
function employeeResidenceLocationClickInfo (obj) {
employeeResidenceLocationClickFeature = map.queryRenderedFeatures(obj.point, {
layers: ['tract-4332-1sbuyl','blockgroups-4332-9mehvk','employeeresidencelocation']
});
if (employeeResidenceLocationClickFeature.length == 3) {
$(".geocode-click-result-area").html('<br/>This area meets the <span style="background-color:yellow">employee residence location criteria</span> based on the following thresholds:'
+ '<table><tr><td>Renewal Community</td><td>' + employeeResidenceLocationClickFeature[2].properties.Inquiry1 + '</td></tr>'
+ '<tr><td>CT % LMI ≥ 70%</td><td>' + employeeResidenceLocationClickFeature[2].properties.Inquiry2 + '</td></tr>'
+ '<tr><td>CT & all BG Poverty Rate ≥ 20%</td><td>' + employeeResidenceLocationClickFeature[2].properties.Inquiry3 + '</td></tr></table>'
+ '<p><b>' + employeeResidenceLocationClickFeature[0].properties.CountyName + " County" + '<br/>'
+ employeeResidenceLocationClickFeature[0].properties.NAMELSAD + '<br/>'
+ employeeResidenceLocationClickFeature[1].properties.NAMELSAD + '</b></p>'
+ '<table id="CensusTable"><tr><th></th><th>Poverty Rate</th><th>LMI</th></tr><tr><td>CT '
+ employeeResidenceLocationClickFeature[0].properties.TRACTCE + '</td><td>'
+ employeeResidenceLocationClickFeature[0].properties.PovRate + "%" + '</td><td>'
+ employeeResidenceLocationClickFeature[0].properties.LMIPerc + "%" + '</td></tr>');
var BGsin20PovertyCT = map.queryRenderedFeatures(
{ layers: ['blockgroups-4332-9mehvk'],
filter: ["==", "TRACTCE", employeeResidenceLocationClickFeature[0].properties.TRACTCE]
});
var unique = [];
var distinct = [];
for (let i = 0; i < BGsin20PovertyCT.length; i++ ){
if (!unique[BGsin20PovertyCT[i].properties.BLKGRPCE]){
distinct.push(BGsin20PovertyCT[i]);
unique[BGsin20PovertyCT[i].properties.BLKGRPCE] = 1;
}
}
for (let i = 0; i < distinct.length; i++ ){
$("#CensusTable").append('<tr><td>BG ' + distinct[i].properties.BLKGRPCE + '</td><td>'
+ distinct[i].properties.PovRate + "%" + '</td><td>-</td></tr></table>'
);
}
}
else {
$(".geocode-click-result-area").html('<br/> This area <u style = "color:red;">does not</u> meet the employee residence location criteria based on the following thresholds:'
+ '<table><tr><td>Renewal Community</td><td>No</td></tr>'
+ '<tr><td>CT % LMI ≥ 70%</td><td>No</td></tr>'
+ '<tr><td>CT & all BG Poverty Rate ≥ 20%</td><td>No</td></tr></table>'
+ '<p><b>' + employeeResidenceLocationClickFeature[0].properties.CountyName + " County" + '<br/>'
+ employeeResidenceLocationClickFeature[0].properties.NAMELSAD + '<br/>'
+ employeeResidenceLocationClickFeature[1].properties.NAMELSAD + '</b></p>'
+ '<table id="CensusTable"><tr><th></th><th>Poverty Rate</th><th>LMI</th></tr><tr><td>CT '
+ employeeResidenceLocationClickFeature[0].properties.TRACTCE + '</td><td>'
+ employeeResidenceLocationClickFeature[0].properties.PovRate + "%" + '</td><td>'
+ employeeResidenceLocationClickFeature[0].properties.LMIPerc + "%" + '</td></tr>');
var BGsin20PovertyCT = map.queryRenderedFeatures(
{ layers: ['blockgroups-4332-9mehvk'],
filter: ["==", "TRACTCE", employeeResidenceLocationClickFeature[0].properties.TRACTCE]
});
var unique = [];
var distinct = [];
for (let i = 0; i < BGsin20PovertyCT.length; i++ ){
if (!unique[BGsin20PovertyCT[i].properties.BLKGRPCE]){
distinct.push(BGsin20PovertyCT[i]);
unique[BGsin20PovertyCT[i].properties.BLKGRPCE] = 1;
}
}
for (let i = 0; i < distinct.length; i++ ){
$("#CensusTable").append('<tr><td>BG ' + distinct[i].properties.BLKGRPCE + '</td><td>'
+ distinct[i].properties.PovRate + "%" + '</td><td>-</td></tr></table>'
);
}
}
}
mapboxgl.accessToken = 'pk.eyJ1Ijoia3l1bmdhaGxpbSIsImEiOiJjanJyejQyeHUyNGwzNGFuMzdzazh1M2k1In0.TcQEe2aebuQZ4G7d827A9Q';
map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/kyungahlim/ckd226uao1p7i1iqo8ag2ewmu',
center: [-95.925, 29.575],
zoom: 7
});
map.on('load', initialize);
// // Center the map on the coordinates of any clicked symbol from the 'symbols' layer.
// map.on('click', 'symbols', function(e) {
// map.flyTo({
// center: e.features[0].geometry.coordinates
// });
// });
// // Change the cursor to a pointer when the it enters a feature in the 'symbols' layer.
// map.on('mouseenter', 'symbols', function() {
// map.getCanvas().style.cursor = 'pointer';
// });
// // Change it back to a pointer when it leaves.
// map.on('mouseleave', 'symbols', function() {
// map.getCanvas().style.cursor = '';
// });
var geojson = {
type: 'FeatureCollection',
features: [{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [-95.925, 29.575]
},
properties: {
title: 'Mapbox',
description: 'Washington, D.C.'
}
},
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [-122.414, 37.776]
},
properties: {
title: 'Mapbox',
description: 'San Francisco, California'
}
}]
};
// // geocode the typed-in address, zoom to the location, and put a pin on address
// function codeAddress() {
// sAddress = document.getElementById('inputTextAddress').value;
// geocoder.geocode( { 'address': sAddress}, function(results, status) {
// //latitude = results[0].geometry.location.lat();
// //longitude = results[0].geometry.location.lng();
// coordinate = results[0].geometry.location;
// if (status == google.maps.GeocoderStatus.OK) {
// if (GeocodeMarker){
// GeocodeMarker.setMap(null);
// }
// // bounds.extend(results[0].geometry.location);
// // PuppyMap.fitBounds(bounds);
// PuppyMap.setCenter(results[0].geometry.location);
// PuppyMap.setZoom(14);
// GeocodeMarker = new google.maps.Marker({
// map:PuppyMap,
// position: results[0].geometry.location,
// animation: google.maps.Animation.DROP,
// icon: housePin,
// zoom: 0
// });
// }
// else{
// alert("Geocode was not successful for the following reason: " + status);
// }
// });
// }
var marker = new mapboxgl.Marker(document.createElement('div'))
.setLngLat( [-95.925, 29.575])
.addTo(map);
// // add markers to map
// geojson.features.forEach(function(marker) {
// // create a HTML element for each feature
// var el = document.createElement('div');
// el.className = 'marker';
// // make a marker for each feature and add to the map
// new mapboxgl.Marker(el)
// .setLngLat(marker.geometry.coordinates)
// .addTo(map);
// });
</script>
Related
Update position marker on Leaflet map on double click
I have this code to add to Leaflet map marker genereted by JSON file jQuery().ready(function (){ $.getJSON( '/EUREKA/json/map_container/json_map_container.php', function(data){ for ( var i=0; i < data.length; ++i ) { k=i; var myIcon = L.icon({ iconUrl: 'maps/images/' + data[i].type + '.png', iconRetinaUrl: 'maps/images/' + data[i].type + '.png', iconSize: [42, 55], iconAnchor: [9, 21], popupAnchor: [0, -14] }); markerArray[i] = L.marker( [data[i].latitude, data[i].longitude], {id: data[i].id, icon: myIcon, draggable:'true'} ) .bindPopup( '<div>' + '<b>PDL di riferimento:</b> ' + data[i].codice + '<br/>' + '<b>Riferimento appaltatore:</b> ' + data[i].companyId + '<br/>' + '<b>Tipo contenitore:</b> ' + data[i].type + '<br/>' + '<b>Numero RDP:</b> ' + data[i].rdpNumber + '<br/>' + '<b>Preposto di riferimento:</b> ' + data[i].preposto + '<br/>' + '<b>Descrizione del rifiuto:</b> ' + data[i].description + '</div>', {direction: 'left'} ) .addTo( map ); //markerArray[i] = marker1; markerArray[i].on('dblclick', function(e){ console.log("ID Marker Array: " + markerArray[k].options.id); var latitudeMarker = markerArray[k].getLatLng().lat; var longitudeMarker = markerArray[k].getLatLng().lng; $.getJSON( '/EUREKA/json/map_container/json_update_position.php?&lat=' + latitudeMarker + '&lng=' + longitudeMarker + '&id=' + markerArray[k].options.id, function(data){ console.log("Posizione aggiornata") }); }); } }); The JSON 'json_map_container.php' file return date from a sql query. I want to update the position of a marker in the map when i drag it in a new position at the doubleclick event, I think to call a JSON 'json_update_position.php' with new position and id of marker and The JSON execute a UPDATE query on my db but when I doubleclick on marker I have ever the last id generated. Can anyone help me?
Read about closures in JavaScript, and have a look at example 5 in this excellent answer that describes your problem : basically, k will always be the last value set when read in your callback. You could apply what's explained in this answer or get the reference to the marker in the event object passed to your callback by e.target: markerArray[i].on('dblclick', function(e){ var marker = e.target; console.log("ID Marker Array: " + marker.options.id); var latitudeMarker = marker.getLatLng().lat; var longitudeMarker = marker.getLatLng().lng; $.getJSON( '/EUREKA/json/map_container/json_update_position.php?&lat=' + latitudeMarker + '&lng=' + longitudeMarker + '&id=' + marker.options.id, function(data){ console.log("Posizione aggiornata") }); });
Make Google maps callback wait for rest of functions to finish
I am having difficulty with the way google calls its maps api. I have the following calling initMap <script defer src="https://maps.googleapis.com/maps/api/js?key=API_KEY_REMOVED&callback=initMap"> </script> but inside initMap, the following condition if(getPosition() !== false) { never evaluates to true because init map is done before getPosition() has set its object values. function initMap() { // set new map, assign default properties map = new google.maps.Map(document.getElementById('map'), { center: { lat, lng }, zoom: 14 }); // check if the requested data is usable (lat, lng === numbers) before trying to use it if(getPosition() !== false) { map.setCenter( getPosition() ); // set latest position as the map center addMarker(); console.log("InitMap ran here"); } } How can I make it so initMap waits until getPosition() has had a chance to wait for other functions to do their thing? Here is my complete script so it makes more sense. <script> console.log(formatTime(Date())); // https://developers.google.com/maps/documentation/javascript/geolocation var map; var marker; var lat = 65.025984; var lng = 25.470794; // default map location in case no position response is available var res_data; var res_longitude; var res_latitude; var res_speed; var res_time; // res = response (data from the ajax call) var xhr = new XMLHttpRequest(); function getPosition() { pos = { lat: res_latitude, lng: res_longitude, }; return ( isNaN(pos.lat) || isNaN(pos.lng) ) ? false : pos; // return pos only if lat and lng values are numbers } function initMap() { // set new map, assign default properties map = new google.maps.Map(document.getElementById('map'), { center: { lat, lng }, zoom: 14 }); // check if the requested data is usable (lat, lng === numbers) before trying to use it if(getPosition() !== false) { map.setCenter( getPosition() ); // set latest position as the map center addMarker(); console.log("InitMap ran here"); } } // place marker on the map function addMarker() { //console.log("Add Marker ran"); //https://developers.google.com/maps/documentation/javascript/markers if(marker){ marker.setMap(null); } // remove visibility of current marker marker = new google.maps.Marker({ position: getPosition(), map: map, title: formatTime(res_time), }); marker.setMap(map); // set the marker } function getData() { xhr.addEventListener("load", reqListener); xhr.open("GET", "http://example.com/data.txt"); xhr.send(); } function reqListener() { // res_data = long, lat, accuracy, speed, time //console.log("reqListener: " + xhr.responseText); res_data = '[' + xhr.responseText + ']'; res_data = JSON.parse(res_data); res_latitude = res_data[0]; res_longitude = res_data[1]; res_accuracy = res_data[2]; res_speed = res_data[3]; res_time = res_data[4]; var formatted_time = formatTime(res_time); document.getElementById('info').innerHTML = '<span class="info">Lat: ' + res_latitude + '</span><span class="info">Long: ' + res_longitude + '</span><span class="info">Accuracy: ' + res_accuracy + '</span><span class="info">Speed: ' + res_speed + '</span><span class="info">' + formatted_time + '</span>'; addMarker(); } function formatTime(time) { var t = new Date(time); var hours, mins, secs; if(t.getHours() < 10) { hours = "0" + t.getHours(); } else { hours = t.getHours(); } if(t.getMinutes() < 10) { mins = "0" + t.getMinutes(); } else { mins = t.getMinutes(); } if(t.getSeconds() < 10) { secs = "0" + t.getSeconds(); } else { secs = t.getSeconds(); } var hms = hours +':'+ mins +':'+ secs; return 'Updated: ' + hms; } function init() { getData(); setInterval(getData, 5000); } init(); </script> <script defer src="https://maps.googleapis.com/maps/api/js?key=API_KEY_REMOVED&callback=initMap"> </script>
Get rid of the callback=initMap from where you load in the Maps API. Instead make a call to initMap only from where you are then certain everything is loaded. e.g. at the end of reqListener. function reqListener() { res_data = '[' + xhr.responseText + ']'; res_data = JSON.parse(res_data); res_latitude = res_data[0]; res_longitude = res_data[1]; res_accuracy = res_data[2]; res_speed = res_data[3]; res_time = res_data[4]; var formatted_time = formatTime(res_time); document.getElementById('info').innerHTML = '<span class="info">Lat: ' + res_latitude + '</span><span class="info">Long: ' + res_longitude + '</span><span class="info">Accuracy: ' + res_accuracy + '</span><span class="info">Speed: ' + res_speed + '</span><span class="info">' + formatted_time + '</span>'; initMap(); addMarker(); } If you're calling reqListener at repeated intervals and don't want to recreate your map, add some logic to the top of initMap like: if (map !== null) { return; }
Google Map Geocoded TypeError in Callback function
I have the following 2 functions to pull in, geocode, and place markers in a google map. I keep getting a TypeError: adds[i] is undefined, which of course is causing the rest of the map to bomb. Here is my code: // Place Markers on the Map var PlaceMarkers = function (iw, adds, gc) { var image = {url: "http://meatmysite.com/Images/star2.png", size: new google.maps.Size(24, 24)}; var aCt = adds.length; for(var i = 0; i < aCt; ++i) { GetLatLng(gc, adds[i].address, function(pos) { if(pos) { var ipop = '<h1>' + adds[i].title + '</h1>'; // <----- TypeError: adds[i] is undefined if(!isBlank(adds[i].url)){ ipop += '' + adds[i].url + '<br />'; } ipop += '<div class="map_item_content" id="mi_content' + i + '">' + adds[i].content + '</div>'; if(!isBlank(adds[i].mainphone)){ ipop += '<br /><strong>Phone:</strong> ' + adds[i].mainphone + ''; } if(!isBlank(adds[i].mainemail)){ ipop += '<br /><strong>Email:</strong> ' + adds[i].mainemail + ''; } console.log('HEY NOW: ' + pos.toString() + ' - Location Found!'); var mark = new google.maps.Marker({title: adds[i].title, position: pos, map: map, icon: image, html: ipop}); google.maps.event.addListener(mark, 'click', function(){ iw.setContent(this.html); iw.open(map, this); }); } }); } }; // Get Lat/Lng Location var GetLatLng = function(gc, add, f) { var ret = ''; gc.geocode({'address': add}, function(res, status) { if (status == 'OK') { f(res[0].geometry.location); console.log('Found Here: ' + ret.toString()); } }); return -1; }; DEMO RETURNED DATA FOR adds [ { "address": "1 My Street Gilbert, AZ 85234", "title": "My Title 1", "url": "http://www.myurl.com/", "mainphone": null, "mainemail": null, "content": "1 My Street<br />Gilbert, AZ 85234" }, { "address": "2 My Street North Richland Hills, TX 76182", "title": "My Title 2", "url": null, "mainphone": null, "mainemail": null, "content": "2 My Street<br />North Richland Hills, TX 76182" } ]
One option, pass the complete "address" object into the GetLatLng function, and from there into its callback (so you get function closure on it): // Get Lat/Lng Location var GetLatLng = function (gc, add, f) { gc.geocode({ 'address': add.address }, function (res, status) { if (status == 'OK') { f(res[0].geometry.location, add); } }); }; Then use it like this inside the callback (you could pass just the index into the array also): GetLatLng(gc, adds[i], function (pos, add) { if (pos) { var ipop = '<h1>' + add.title + '</h1>'; if (!isBlank(add.url)) { ipop += '' + add.url + '<br />'; } ipop += '<div class="map_item_content" id="mi_content' + i + '">' + add.content + '</div>'; if (!isBlank(add.mainphone)) { ipop += '<br /><strong>Phone:</strong> ' + add.mainphone + ''; } if (!isBlank(add.mainemail)) { ipop += '<br /><strong>Email:</strong> ' + add.mainemail + ''; } console.log('HEY NOW: ' + pos.toString() + ' - Location Found!'); var mark = new google.maps.Marker({ title: add.title, position: pos, map: map, icon: image, html: ipop }); google.maps.event.addListener(mark, 'click', function () { iw.setContent(this.html); iw.open(map, this); }); } }); proof of concept fiddle code snippet: var geocoder = new google.maps.Geocoder(); var map; var infoWindow = new google.maps.InfoWindow(); function initialize() { map = new google.maps.Map( document.getElementById("map_canvas"), { center: new google.maps.LatLng(37.4419, -122.1419), zoom: 13, mapTypeId: google.maps.MapTypeId.ROADMAP }); PlaceMarkers(infoWindow, adds, geocoder); } google.maps.event.addDomListener(window, "load", initialize); // Place Markers on the Map var PlaceMarkers = function(iw, adds, gc) { var bounds = new google.maps.LatLngBounds(); var image = { url: "http://meatmysite.com/Images/star2.png", size: new google.maps.Size(24, 24) }; var aCt = adds.length; for (var i = 0; i < aCt; ++i) { GetLatLng(gc, adds[i], function(pos, add) { if (pos) { var ipop = '<h1>' + add.title + '</h1>'; // <----- TypeError: adds[i] is undefined if (!isBlank(add.url)) { ipop += '' + add.url + '<br />'; } ipop += '<div class="map_item_content" id="mi_content' + i + '">' + add.content + '</div>'; if (!isBlank(add.mainphone)) { ipop += '<br /><strong>Phone:</strong> ' + add.mainphone + ''; } if (!isBlank(add.mainemail)) { ipop += '<br /><strong>Email:</strong> ' + add.mainemail + ''; } console.log('HEY NOW: ' + pos.toString() + ' - Location Found!'); var mark = new google.maps.Marker({ title: add.title, position: pos, map: map, // icon: image, html: ipop }); bounds.extend(mark.getPosition()); map.fitBounds(bounds); google.maps.event.addListener(mark, 'click', function() { iw.setContent(this.html); iw.open(map, this); }); } }); } }; // Get Lat/Lng Location var GetLatLng = function(gc, add, f) { gc.geocode({ 'address': add.address }, function(res, status) { if (status == 'OK') { f(res[0].geometry.location, add); } }); }; var adds = [{ "address": "1 My Street Gilbert, AZ 85234", "title": "My Title 1", "url": "http://www.myurl.com/", "mainphone": null, "mainemail": null, "content": "1 My Street<br />Gilbert, AZ 85234" }, { "address": "2 My Street North Richland Hills, TX 76182", "title": "My Title 2", "url": null, "mainphone": null, "mainemail": null, "content": "2 My Street<br />North Richland Hills, TX 76182" }]; function isBlank(str) { return (!str || /^\s*$/.test(str)); } html, body, #map_canvas { height: 100%; width: 100%; margin: 0px; padding: 0px } <script src="https://maps.googleapis.com/maps/api/js"></script> <div id="map_canvas"></div>
This looks like a typical binding issue. By the time your callback is called, the value of adds[i] will have changed. It is likely that the loop terminated and i has now a value of last index + 1, which is pointing to nothing. Note that it could also point to the wrong index, that would not fail but use the wrong data. You must bind the value of adds[i] locally for each iteration or the callback will just use a reference to a global value. There a multiple ways to go about this, here is a simple one where we keep passing adds[i] along as a function argument. Replace adds[i].address with adds[i] when calling GetLatLng and add a second parameter add to the callback: GetLatLng(gc, adds[i], function(pos, add) { ... }); Then modify GetLatLng to use add.address instead of just add and add add to the callback call: // Get Lat/Lng Location var GetLatLng = function(gc, add, f) { var ret = ''; gc.geocode({'address': add.address}, function(res, status) { if (status == 'OK') { f(res[0].geometry.location, add); console.log('Found Here: ' + ret.toString()); } }); return -1; }; Then in the callback function, replace all instances of adds[i] with add to use the local variable. I didn't set up a test but it should theoretically work.
you appear to be overcomplicating things. Any reason why you can't do this? // Place Markers on the Map var PlaceMarkers = function (iw, adds, gc) { var aCt = adds.length; for(var i = 0; i < aCt; ++i) { var obj=adds[i]; GetLatLng(gc, obj) } }; // Get Lat/Lng Location var GetLatLng = function(gc, obj) { var ret = ''; gc.geocode({'address': obj.address}, function(res, status) { if (status == 'OK') { var pos=res[0].geometry.location; var ipop = '<h1>' + obj.title + '</h1>'; // <----- TypeError: adds[i] is undefined if(!isBlank(obj.url)){ ipop += '' + obj.url + '<br />'; } ipop += '<div class="map_item_content" id="mi_content">' + obj.content + '</div>'; if(!isBlank(obj.mainphone)){ ipop += '<br /><strong>Phone:</strong> ' + obj.mainphone + ''; } if(!isBlank(obj.mainemail)){ ipop += '<br /><strong>Email:</strong> ' + obj.mainemail + ''; } console.log('HEY NOW: ' + pos.toString() + ' - Location Found!'); var mark = new google.maps.Marker({title: obj.title, position: pos, map: map, html: ipop}); google.maps.event.addListener(mark, 'click', function(){ iw.setContent(this.html); iw.open(map, this); }); } else { console.log("geocoder problem!") } }); };
for(var i = 0; i < aCt - 1; ++i). You need to add "-1" in you for-loop. The array starts at index 0 and not 1. You also need to be careful with using functions in a for loop. Within javascript a for-loop does not have a scope from itself. Only functions create new scopes.
Why markers do not move correcly on map
Sample of JSON data (from the comments): [{"id":"280","id_vehicle":"VL0847810531","lat":"30.0761","longi":"1.01981","speed":"144","time":"2014-12-03 12:07:23"},{"id":"202","id_vehicle":"VL0645210631","lat":"34.7344","longi":"7.32019","speed":"78","time":"2014-12-03 11:55:44"}] function updateLocations(jsonData) { for (i=0 ;i< jsonData.length; i++) //for all vehicles { var id_vehicle = jsonData[i]["id_vehicle"]; var lat = jsonData[i]["lat"]; var lng = jsonData[i]["longi"]; var speed = jsonData[i]["speed"]; var str_time = jsonData[i]["time"]; /************************update list*******************************/ var state_icon, marker_icon, state; var time = moment(str_time); var last_10_Min = moment().subtract({minutes: 60 + 10}); if(time.isBefore(last_10_Min)) //if before 10 last minutes { state_icon = INACTIVE_IMG; marker_icon = INACTIVE_VEHICLE; state = "INACTIVE"; } else //if befor { if(jsonData[i]["speed"] > 10) //if > 2 km/h then running { state_icon = RUN_IMG; marker_icon = RUN_VEHICLE; state = "RUN"; } else { state_icon = STOP_IMG; marker_icon = STOP_VEHICLE; state = "STOP"; } } $("#state_img_"+id_vehicle).attr("src", state_icon); $("#state_img_"+id_vehicle).attr('state',state); $("#select_"+id_vehicle).attr("disabled" , false ); // enable selection /************************update location info*******************************/ var locationInfo = new Array(); img = "<img src=" + state_icon + " width='16' height='16' >"; locationInfo.push("Etat : " + state + " " + img + "<br>"); locationInfo.push("Latitude : " + lat + "<br>"); locationInfo.push("Longitude : " + lng + "<br>"); locationInfo.push("Vitess: " + speed + " klm/h<br>"); locationInfo.push("Temps : " + str_time + "<br>"); $("#info_location_" +id_vehicle).html(locationInfo.join("")); /*****************update vehicles on map *************/ try { cBox = $("#select_"+id_vehicle); if(cBox.is(':checked')) //update selected only { //get marker index var id_map = cBox.attr("id_map"); //change title title = "Latitude: "+ lat + "\nLongitude: " + lng + "\nSpeed: " + speed + "\nTime: " + str_time; arrayMarker[id_map].setTitle(title); //update title arrayMarker[id_map].setIcon(marker_icon); //move marker arrayMarker[id_map].setPosition( new google.maps.LatLng(parseFloat(lat),parseFloat(lng)) ); } }catch(error){}; } } //////////////////////////////////////////////////////////////////////////////////////////////////////////// my question is why whene this function is executed (updating locations) just fisrt vehicle on map is moved correctly, the ohers are updated (title, icon ...) but do not move? I noticed that , they move and return to their old location quickly. Thanks for any suggestion.
finaly i found problem, it was here: var marker = new MarkerWithLabel({......}); arrayMarker[id_map] = marker; //put marker in arrayMarker at indexMarker position the bug occur whene i filled my arrayMarker using MarkerWithLabel (3th lib) whene changed to native google.maps.Marker it work correcly: var marker = new google.maps.Marker({......}); arrayMarker[id_map] = marker;
Uncaught ReferenceError: google is not defined (Wordpress)
Below is the code I am working with. I'm trying to fix an error with a map not displaying in all browsers. In dev tools (chrome), I'm getting a Uncaught ReferenceError: google is not defined error. $(document).ready(function(){ //google map function loadGoogleMap() { var mapOptions = { scrollwheel: false, zoom: 14, mapTypeId: google.maps.MapTypeId.HYBRID }; var map = new google.maps.Map($("#map")[0], mapOptions); var bounds = new google.maps.LatLngBounds(); var count = 0; $.each(dealers, function(ind,dealer){ var point = new google.maps.LatLng(dealer.lat,dealer.lng) var marker = new google.maps.Marker({ position: point, map: map, title: dealer.post_title, icon: icons[count] }); var infowindow = new google.maps.InfoWindow({ content:'<div class="infowindow">'+ '<strong>' + dealer.post_title + '</strong><br/>' + '<address>' + dealer.address1 + '<br/>' + dealer.city + ', ' + dealer.state + '<br/>' + '</address>' + dealer.phone + '<br/>' + (dealer.url != '' ? 'Dealer Website<br/>' : '') + (dealer.email != '' ? 'Email Dealer<br/>' : '') + 'Get Directions'+ '</div>' }); google.maps.event.addListener(marker,'click',function(){ infowindow.open(map,marker); }); // add event listener to distributor list $('#distributors-list li:eq(' + count + ')').click(function(){ infowindow.open(map,marker); }); bounds.extend(point); count++; }); map.fitBounds(bounds); } loadGoogleMap(); // reuse fancybox loading icon script var loadingTimer, loadingFrame = 1; var locator_animate_loading = function() { locatorLoading = $('#ajax-loading-overlay'); if (!locatorLoading.is(':visible')){ clearInterval(loadingTimer); return; } $(locatorLoading).css('background-position', '0 ' + (loadingFrame * -40) + 'px'); loadingFrame = (loadingFrame + 1) % 12; }; $('form.distributor-search').submit(function(e){ locatorLoading = $('#ajax-loading-overlay'); locatorLoading.show(); loadingTimer = setInterval(locator_animate_loading, 66); $('#locator-content').load(site_url + '/graceports/find-a-distributor?ajax=1&address=' + encodeURIComponent($('#address_search').val()) + ' #ajax-contents', function() { // load updated list of dealers $('#locator-content').append('<script src="' + site_url + '/js/dealers.php?address=' + encodeURIComponent($('#address_search').val()) + '"></script>'); loadGoogleMap(); locatorLoading.hide(); }); e.preventDefault(); }); navigator.geolocation.getCurrentPosition(function(position){ $.get(site_url + '/cms/wp-content/themes/grace/inc/latlng-to-zip.php?latlng=' + encodeURIComponent(position.coords.latitude + ' ' + position.coords.longitude), function(data){ $('#address_search').val(data); $('form.distributor-search').trigger('submit'); }); }); });
You need to wait until google has loaded before running your scripts. Put this somewhere in your document: $(document).ready(function(){ //google map function loadGoogleMap() { var mapOptions = { scrollwheel: false, zoom: 14, mapTypeId: google.maps.MapTypeId.HYBRID }; var map = new google.maps.Map($("#map")[0], mapOptions); var bounds = new google.maps.LatLngBounds(); function loadScript() { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp&' + 'callback=initialize'; document.body.appendChild(script); } var count = 0; $.each(dealers, function(ind,dealer){ var point = new google.maps.LatLng(dealer.lat,dealer.lng) var marker = new google.maps.Marker({ position: point, map: map, title: dealer.post_title, icon: icons[count] }); var infowindow = new google.maps.InfoWindow({ content:'<div class="infowindow">'+ '<strong>' + dealer.post_title + '</strong><br/>' + '<address>' + dealer.address1 + '<br/>' + dealer.city + ', ' + dealer.state + '<br/>' + '</address>' + dealer.phone + '<br/>' + (dealer.url != '' ? 'Dealer Website<br/>' : '') + (dealer.email != '' ? 'Email Dealer<br/>' : '') + 'Get Directions'+ '</div>' }); google.maps.event.addListener(marker,'click',function(){ infowindow.open(map,marker); }); // add event listener to distributor list $('#distributors-list li:eq(' + count + ')').click(function(){ infowindow.open(map,marker); }); bounds.extend(point); count++; }); map.fitBounds(bounds); } loadGoogleMap(); // reuse fancybox loading icon script var loadingTimer, loadingFrame = 1; var locator_animate_loading = function() { locatorLoading = $('#ajax-loading-overlay'); if (!locatorLoading.is(':visible')){ clearInterval(loadingTimer); return; } $(locatorLoading).css('background-position', '0 ' + (loadingFrame * -40) + 'px'); loadingFrame = (loadingFrame + 1) % 12; }; $('form.distributor-search').submit(function(e){ locatorLoading = $('#ajax-loading-overlay'); locatorLoading.show(); loadingTimer = setInterval(locator_animate_loading, 66); $('#locator-content').load(site_url + '/graceports/find-a-distributor?ajax=1&address=' + encodeURIComponent($('#address_search').val()) + ' #ajax-contents', function() { // load updated list of dealers $('#locator-content').append('<script src="' + site_url + '/js/dealers.php?address=' + encodeURIComponent($('#address_search').val()) + '"></script>'); loadGoogleMap(); locatorLoading.hide(); }); e.preventDefault(); }); navigator.geolocation.getCurrentPosition(function(position){ $.get(site_url + '/cms/wp-content/themes/grace/inc/latlng-to-zip.php?latlng=' + encodeURIComponent(position.coords.latitude + ' ' + position.coords.longitude), function(data){ $('#address_search').val(data); $('form.distributor-search').trigger('submit'); }); }); });