Good afternoon, I created a map that fills markers with coordinates directly from my mysql database, the map is being generated correctly and markers work when I load the page. Every minute I get new coordinates in the bank and want to update the map with a time interval. For this I used the setInterval that calls the initialization function of the markers, however, are not creating new markers on the map, is always displaying the same, they only update when I give f5 on the page, ie if reloading the page works, but with no interval. He even winked on the map when the time set by the interval, but not updated.
My code:
<script src="js/markerclusterer.js"></script>
<script src="js/jquery-1.5.2.min.js"></script>
<script src="js/jquery.maskedinput-1.3.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>
<script>
<?php
if($attmap_form > 0) {
echo 'myTimer = window.setInterval(refreshMapa,"'.$attmap_form.'");';
}
?>
function initialize() {
var mapOptions = {
zoom: 12,
center: new google.maps.LatLng(-25.4848801,-49.2918938),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
locations = [];
<?php
require('conecta.php');
$sql_lista = ("SELECT MONITLATITUDE,MONITLONGITUDE,MONITDATA,MONITHORA,MONITRAIO,MONITPROVEDOR,MONITVELOCIDADE FROM MONITORAMENTO where MONITHORA BETWEEN '$hora1_form' AND '$hora2_form' AND MONITDATA BETWEEN '$data1_form' AND '$data2_form' AND EQUIPIMEI = $imei");
$query_lista = mysql_query($sql_lista);
$achados_lista = mysql_num_rows($query_lista);
while ($achados_lista = mysql_fetch_array($query_lista)) {
$lat = $achados_lista['MONITLATITUDE'];
$lon = $achados_lista['MONITLONGITUDE'];
$Data = $achados_lista['MONITDATA'];
$hora = $achados_lista['MONITHORA'];
$raio = $achados_lista['MONITRAIO'];
$provedor = $achados_lista['MONITPROVEDOR'];
$velocidade = $achados_lista['MONITVELOCIDADE'];
echo 'locations.push ( {Data:"'.$Data.'", latlng: new google.maps.LatLng('.$lat.', '.$lon.'), hora:"'.$hora.'", raio:"'.$raio.'",provedor:"'.$provedor.'",velocidade:"'.$velocidade.'"} );';
}
?>
var bounds = new google.maps.LatLngBounds();
var infowindow = new google.maps.InfoWindow();
var markers = [];
for(var i=0;i < locations.length;i++ ) {
var marker = new google.maps.Marker({
position: locations[i].latlng,
map:map,
title:locations[i].hora
});
markers.push(marker);
bounds.extend(locations[i].latlng);
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(
'<strong>Data: ' + locations[i].Data + '<br>Hora: ' + locations[i].hora + '<br></strong>Velocidade aproximada: ' + locations[i].velocidade + ' K/H<br>Raio aproximado de: ' + locations[i].raio + ' metros <br>Provedor: ' + locations[i].provedor + '<br>Latitude: ' + locations[i].latlng
);
infowindow.open(map, marker);
}
})(marker, i));
}
markerClusterer = new MarkerClusterer(map, markers, {
maxZoom: 16,
gridSize: 60
});
map.fitBounds(bounds);
}
arrancaMapa();
function arrancaMapa() {
google.maps.event.addDomListener(window, 'load', initialize);
}
function refreshMapa() {
initialize();
arrancaMapa();
}
function clearMarkers() {
setAllMap(null);
}
function stopTimer() {
$("#campoAttMap").val("0");
clearInterval(myTimer);
}
</script>
You shouldn't have to call initialize more than once. You should implement a different logic, for example get the newest marker that is not in the map and add it via
var marker = new google.maps.Marker({
position: locations[i].latlng,
map:map,
title:locations[i].hora
});
markers.push(marker);
bounds.extend(locations[i].latlng);
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(
'<strong>Data: ' + locations[i].Data + '<br>Hora: ' + locations[i].hora + '<br></strong>Velocidade aproximada: ' + locations[i].velocidade + ' K/H<br>Raio aproximado de: ' + locations[i].raio + ' metros <br>Provedor: ' + locations[i].provedor + '<br>Latitude: ' + locations[i].latlng
);
infowindow.open(map, marker);
}
})(marker, i));
UPDATE:
I will add take the following approach. I don't like mixing PHP and Javascript together, I prefer using JSON and AJAX request.
Update your functions to look like this:
var map;
var markers = [];
setInterval(refreshMapa, 3000);
function initialize() {
var mapOptions = {
zoom: 12,
center: new google.maps.LatLng(-25.4848801,-49.2918938),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
var locations = [];
$.get("getmarkers.php", function(response){
for(var i = 0; i < response.markers.length; i++) {
var marker = response.markers[i];
var myMarker = {
Data: marker.Data,
latlng: new google.maps.LatLng(marker.lat, marker.lon),
hora: marker.hora,
raio: marker.raio,
provedor: marker.provedor,
velocidade: marker.velocidade
};
locations.push(myMarker);
addMapMarker(myMarker);
}
},'json');
markerClusterer = new MarkerClusterer(map, markers, {
maxZoom: 16,
gridSize: 60
});
map.fitBounds(bounds);
}
function refreshMapa() {
// make sure this one only returns markers that are new and not in the map
$.get("getnewmarkers.php", function(){
for(var i = 0; i < response.markers.length; i++) {
var marker = response.markers[i];
var myMarker = {
Data: marker.Data,
latlng: new google.maps.LatLng(marker.lat, marker.lon),
hora: marker.hora,
raio: marker.raio,
provedor: marker.provedor,
velocidade: marker.velocidade
};
locations.push(myMarker);
addMapMarker(myMarker);
}, 'json');
}
function addMapMarker(myMarker) {
var marker = new google.maps.Marker({
position: myMarker.latlng,
map:map,
title:myMarker.hora
});
markers.push(marker);
bounds.extend(myMarker.latlng);
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent('<strong>Data: ' + myMarker.Data + '<br>Hora: ' + myMarker.hora + '<br></strong>Velocidade aproximada: ' + myMarker.velocidade + ' K/H<br>Raio aproximado de: ' + myMarker.raio + ' metros <br>Provedor: ' + myMarker.provedor + '<br>Latitude: ' + myMarker.latlng);
infowindow.open(map, marker);
}
})(marker, i));
}
PS: I'm not sure if the implementation of the addMapMarker is correct I just assumed you had it right in the first place, you should check the documentation and make sure it is correct.
Yeah so the thing is, PHP is a server-side language that only gets executed when the page loads. I'm not sure exactly how you would expect your JS to update the markers, as there are no get/post anywhere. If you want to get data from the server, you have to contact the server.
This loop
while ($achados_lista = mysql_fetch_array($query_lista)) {
$lat = $achados_lista['MONITLATITUDE'];
$lon = $achados_lista['MONITLONGITUDE'];
$Data = $achados_lista['MONITDATA'];
$hora = $achados_lista['MONITHORA'];
$raio = $achados_lista['MONITRAIO'];
$provedor = $achados_lista['MONITPROVEDOR'];
$velocidade = $achados_lista['MONITVELOCIDADE'];
echo 'locations.push ( {Data:"'.$Data.'", latlng: new google.maps.LatLng('.$lat.', '.$lon.'), hora:"'.$hora.'", raio:"'.$raio.'",provedor:"'.$provedor.'",velocidade:"'.$velocidade.'"} );';
}
Only gets executed ONCE. The value of locations doesn't change.
You should read up on jQuery ajax requests. Make an HTTP request to a PHP file that returns the locations as JSON (just echo the JS array) and use the result to update the markers.
Reason:
There is no update function (or code blocks) to get updated or newly added DB info in your code. Also, you will not read and add new db info to your map data because your PHP code is only called once at initialization-time.
Using PHP codes, you will not do it because of the PHP features. PHP will only work on back-end service sides.
Suggestion:
1. You need client-side updates to access service side updates and receive them.
2. You need to add the updated or newly added db data to your Marker (map) array on client sides.
For this,
1. Add client side update features in AJAX or others to update the info to JSON objects.
2. Call the AJAX block (retrieving block or function to read in JSON object array and add them to map marker arrays).
3. Update null pointer of Map Markers to the new Map array.
Sorry for not creating a working code set based on your codes. It will take a fairly long while.
Related
I would like my Google Map to update markers when the map is moved - using bounds_changed or idle - by submitting a new Ajax, removing existing markers and placing the new set.
So far I have the following two scripts:
- The first reads title, latitude and longitude from a JSON array and correctly places the markers in the map. But I have not been able to add the bounds_changed code correctly.
- The second script includes a bounds_changed trigger that loads a new set of markers into a div, but I don't know how to enter that array as the data for the markers (and update them).
If you can help me fix either of these two scripts so that I can get both things to work - read markers from JSON Array as in script 1 and update array when map is moved as in script 2 - I would be very grateful.
I have tried many variations and read all questions on SO that relate to the issue without luck. Totally stuck!
Script 1 - Getting markers from JSON Array:
<script>
jQuery(function($) {
// Asynchronously Load the map API
var script = document.createElement('script');
script.src = "https://maps.googleapis.com/maps/api/js?key=SECRET&sensor=false&callback=initialize";
document.body.appendChild(script);
});
function initialize() {
var map;
var bounds = new google.maps.LatLngBounds();
var mapOptions = {
mapTypeId: 'roadmap'
};
ne_lng = -70.18087440625004;
sw_lng = -92.10958534375004;
ne_lat = 44.078852008513245;
sw_lat = 28.9109895909681;
// Display a map on the page
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
map.setTilt(45);
var latlngData = 0;
// Info Window Content
var infoWindowContent = [
['<div class="info_content">' +
'<h3>London Eye</h3>' +
'<p>The London Eye is a giant Ferris wheel situated on the banks of the River Thames. The entire structure is 135 metres (443 ft) tall and the wheel has a diameter of 120 metres (394 ft).</p>' + '</div>'],
['<div class="info_content">' +
'<h3>Palace of Westminster</h3>' +
'<p>The Palace of Westminster is the meeting place of the House of Commons and the House of Lords, the two houses of the Parliament of the United Kingdom. Commonly known as the Houses of Parliament after its tenants.</p>' +
'</div>']
];
// Display multiple markers on a map, same info for everyone, just an example
var infoWindow = new google.maps.InfoWindow(), marker, i;
// Loop through our array of markers & place each one on the map, fetching avg_gps_latitude, avg_gps_longitude from latlngData, received from ajax call ( but it dodn't work)
loadLocations().done(function (latlngData) {
for (i = 0; i < latlngData.length; i++) {
var position = new google.maps.LatLng(latlngData[i].latitude, latlngData[i].longitude);
bounds.extend(position);
marker = new google.maps.Marker({
position: position,
map: map,
title: latlngData[i].ssid
});
// Allow each marker to have an info window
google.maps.event.addListener(marker, 'click', (function (marker, i) {
return function () {
infoWindow.setContent(infoWindowContent[0][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(6);
google.maps.event.removeListener(boundsListener);
});
}
function loadLocations()
{
return $.ajax({
type:'POST',
url: 'includes/newjson.php',
dataType: 'json',
data:{
a: ne_lat,
b: ne_lng,
c: sw_lat,
d: sw_lng
},
async: true,
//cache: false,
success: function(result){
console.log("successx");
console.log(result);
var jsonStr = JSON.stringify(result);
$('#results').html(jsonStr);
// $('#results').html(result);
// initialize();
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
}
// google.maps.event.addDomListener(window, 'load', initialize);
</script>
Script 2 - Updates array in #result with JSON Array when map is moved but not passed on to Google Maps markers (original array is entered as PHP variable in script):
<script type="text/javascript">
jQuery(function($) {
// Asynchronously Load the map API
var script = document.createElement('script');
script.src = "https://maps.googleapis.com/maps/api/js?key=SECRET&sensor=false&callback=initialize";
document.body.appendChild(script);
});
function initialize() {
var map;
var bounds = new google.maps.LatLngBounds();
var mapOptions = {
mapTypeId: 'roadmap'
};
// Display a map on the page
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
map.setTilt(45);
google.maps.event.addListener(map, 'bounds_changed', function(){
// alert(this.getBounds());
ne_lng = map.getBounds().getNorthEast().lng();
sw_lng = map.getBounds().getSouthWest().lng();
ne_lat = map.getBounds().getNorthEast().lat();
sw_lat = map.getBounds().getSouthWest().lat();
console.log(ne_lng);
console.log(sw_lng);
console.log(ne_lat);
console.log(sw_lat);
$.ajax({
type:'POST',
url: 'includes/mapQuery.php',
data:{
a: ne_lat,
b: ne_lng,
c: sw_lat,
d: sw_lng
},
async: true,
cache: false,
success: function(result){
console.log("success");
$('#results').html(result);
// newmarkers = result;
// console.log(newmarkers);
} // End of success function of ajax form
}); // End of ajax call
});
// Multiple Markers
var markers =
<?php
echo str_replace('"', "'", json_encode($maparray, JSON_NUMERIC_CHECK));
?>
;
// Info Window Content
var infoWindowContent = [
['<div class="info_content">' +
'<h3>London Eye</h3>' +
'<p>The London Eye is a giant Ferris wheel situated on the banks of the River Thames. The entire structure is 135 metres (443 ft) tall and the wheel has a diameter of 120 metres (394 ft).</p>' + '</div>'],
['<div class="info_content">' +
'<h3>Palace of Westminster</h3>' +
'<p>The Palace of Westminster is the meeting place of the House of Commons and the House of Lords, the two houses of the Parliament of the United Kingdom. Commonly known as the Houses of Parliament after its tenants.</p>' +
'</div>']
];
// Display multiple markers on a map
var infoWindow = new google.maps.InfoWindow(), marker, i;
// Loop through our array of markers & place each one on the map
for( i = 0; i < markers.length; i++ ) {
var position = new google.maps.LatLng(markers[i][1], markers[i][2]);
bounds.extend(position);
var iconBase = 'img/icons/';
marker = new google.maps.Marker({
position: position,
map: map,
icon: iconBase + 'student-icon.png',
title: markers[i][0]
});
// 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(6);
google.maps.event.removeListener(boundsListener);
});
}</script>
Here is the solution that worked for me. The result can be seen here.
JSON data comes from this php-file that is updated whenever the map is moved:
include("conn.php");
$ne_lat = $_POST['a'];
$ne_lon = $_POST['b'];
$sw_lat = $_POST['c'];
$sw_lon = $_POST['d'];
$result = mysqli_query($con,"SELECT schoolname, latitude, longitude, total_students, act_composite_25, schoolid, (sat_critread_25+sat_math_25) as sat, (100 * admissions_total/applicants_total) as admrate, degree_bachelor, degree_masters, url, city, usstate, tuition_outstate, tuition_instate FROM usschools WHERE
(CASE WHEN $ne_lat < $sw_lat
THEN latitude BETWEEN $ne_lat AND $sw_lat
ELSE latitude BETWEEN $sw_lat AND $ne_lat
END)
AND
(CASE WHEN $ne_lon < $sw_lon
THEN longitude BETWEEN $ne_lon AND $sw_lon
ELSE longitude BETWEEN $sw_lon AND $ne_lon
END) and degree_bachelor = 1 order by act_composite_25 desc limit 20");
if (!$result) {
printf("Error: %s\n", mysqli_error($con));
exit();
}
while ($row = $result->fetch_assoc()) {
$data[] = $row;
}
And the map is generated and markers updated like this:
<script>
jQuery(function($) {
// Asynchronously Load the map API
var script = document.createElement('script');
script.src = "https://maps.googleapis.com/maps/api/js?key=MYKEY&sensor=false&callback=initialize";
document.body.appendChild(script);
});
ne_lng = -70.18087440625004;
sw_lng = -92.10958534375004;
ne_lat = 44.078852008513245;
sw_lat = 28.9109895909681;
function initialize() {
var markers;
var map;
var markers1 = [];
var bounds = new google.maps.LatLngBounds(
new google.maps.LatLng(46.35960484925907, -81.34113061749997),
new google.maps.LatLng(39.41643540717689, -70.37677514874997)
);
var mapOptions = {
mapTypeId: 'roadmap'
};
// Display a map on the page
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
map.setTilt(45);
var latlngData = 0;
var boundsListener = google.maps.event.addListener((map), 'bounds_changed', function (event) {
this.setZoom(6);
google.maps.event.removeListener(boundsListener);
});
// Automatically center the map fitting all markers on the screen
map.fitBounds(bounds);
// would be great if a margin could be added to prevent schools on edges from loading without marker
google.maps.event.addListener(map, 'idle', function() {
ne_lng = map.getBounds().getNorthEast().lng()-0.01;
sw_lng = map.getBounds().getSouthWest().lng()+0.01;
ne_lat = map.getBounds().getNorthEast().lat()-0.01;
sw_lat = map.getBounds().getSouthWest().lat()+0.01;
console.log(ne_lng);
console.log(sw_lng);
console.log(ne_lat);
console.log(sw_lat);
function loadLocations()
{
$("#results").empty();
return $.ajax({
type:'POST',
url: 'includes/newjson.php',
dataType: 'json',
data:{
a: ne_lat,
b: ne_lng,
c: sw_lat,
d: sw_lng
},
async: true,
success: function(result){
console.log("ajax");
console.log(result);
var len = result.length;
for(var i=0; i<len; i++){
var id = result[i].schoolid;
var name = result[i].schoolname;
var students = (result[i].total_students).toLocaleString();
var act = result[i].act_composite_25;
var sat = result[i].sat;
var acceptancerate = (result[i].admrate).toFixed(1);
var degree_bachelor = result[i].degree_bachelor;
var degree_masters = result[i].degree_masters;
var url = result[i].url;
var city = result[i].city;
var usstate = result[i].usstate;
var tuition_outstate = (result[i].tuition_outstate).toLocaleString();
var tuition_instate = (result[i].tuition_instate).toLocaleString();
var tr_str = "<div class='resultBox'>" +
"<div class='resultImg'><span class='helper'></span><object data='img/schools/logo" + id + ".png' type='image/png' class='resultLogo'><img src='img/schools/logo.png' class='resultLogo'></object></div>" +
"<div class='resultColumn1'><div class='resultName'>" + name + "</div>" +
"<div class='resultBachelor" + degree_bachelor + "'></div>" +
"<div class='resultMasters" + degree_masters + "'></div>" +
"<div class='resultAddress'>" + city + ", " + usstate + "</div>" +
"<div class='resultStudents'>Students: " + students + "</div>" +
"<div class='resultTuition'>Tuition: $" + tuition_outstate + "/$" + tuition_instate + "</div></div>" +
"<div class='resultColumn2'><div class='resultAct'><div class='testLabel'><img src='img/act.png' class='tests'></div><div class='testScore act'>" + act + "</div></div>" +
"<div class='resultSat'><div class='testLabel'><img src='img/sat.png' class='tests'></div><div class='testScore sat'>" + sat + "</div></div><div class='testLegend'>Required score</div>" +
"<div class='resultAcceptRate'><div class='acceptBar' style='height:"+acceptancerate+"%'></div><div class='acceptLabel' style='bottom:"+acceptancerate+"%'>" + acceptancerate + "%</div></div><div class='acceptLegend'>Accepted</div></div>" +
"<div class='resultColumn3'><div class='resultSaveSchool'><a href='saveSchool?id=" + id + "' target='_new' class='btn btn-result btn-save'>Save</a></div>" +
"<div class='resultMore'><a href='https://" + url + "' target='_new' class='btn btn-result btn-school-url'>Website</a></div></div>" +
"</div>";
$("#results").append(tr_str);
}
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
}
// Loop through our array of markers & place each one on the map, fetching avg_gps_latitude, avg_gps_longitude from latlngData, received from ajax call ( but it dodn't work)
loadLocations().done(function (latlngData) {
for (i = 0; i < markers1.length; i++) {
markers1[i].setMap(null);
}
markers1 = [];
markers = [];
markers = loadLocations();
for (i = 0; i < latlngData.length; i++) {
//var infoWindow = new google.maps.InfoWindow(), marker;
var letter = String.fromCharCode("A".charCodeAt(0) + i - 1);
var infoWindow = new google.maps.InfoWindow(), marker, i;
var infoWindowContent = '<div class="info_content">' +
'<p class="infoWindowName">'+' '+latlngData[i].schoolname+'</p></div>';
var tooltip = '';
var position = new google.maps.LatLng(latlngData[i].latitude, latlngData[i].longitude);
bounds.extend(position);
var iconBase = 'img/icons/';
var labeltext = latlngData[i].schoolname;
marker = new google.maps.Marker({
position: position,
map: map,
label: {
color: '#111',
text: labeltext,
fontSize: '12px'
},
icon: iconBase + 'marker_black.png'
//title: tooltip
});
markers1.push(marker);
// Allow each marker to have an info window
google.maps.event.addListener(marker, 'click', (function (marker, infoWindowContent) {
return function () {
infoWindow.setContent(infoWindowContent);
infoWindow.open(map, marker);
}
})(marker, infoWindowContent));
// Automatically center the map fitting all markers on the screen
//map.fitBounds(bounds);
}
console.log("loadLocations");
});
});
}
</script>
If I understand correctly, there are two thing you want to achieve here.
1. when initialize the map, get json from server and add makers on it.
2. when bounds changes, get json and redraws all the maps.
You are very close, I would suggest you to reorganize your code.
1. you need a global array of marks, so you can remove makers from map for redrawing.
```
// set globals
var makers = []
// clear markers
function clearMaker (markers) {
markers.map(m => {m.setmap(null)})
}
```
2. seperate drawMarkers function
```
// drawMarkers
function drawMarkers(markerJson, markers, map, infowindow) {
clearMarkers(markers);
// your draw marker code
}
```
3. Your loadLocation
```
/*search location based on geoparams
geoparam: {
a: ne_lat,
b: ne_lng,
c: sw_lat,
d: sw_lng
}
*/
function loadLocations(geoparam)
{
return $.ajax({
type:'POST',
url: 'includes/newjson.php',
dataType: 'json',
data: geoparam
})
}
```
You can call loadLocation functions when initilize and bounds_changed and it returns a promise.
```
loadLocation(geoparams).then((data) => {
drawMarkers(data, markers, map, inforwindow);
}).catch(err => { console.log(error)});
```
I've been around the block on this over the past week and just haven't found a working solution. I know I'm missing something simple and believe it is that I need to loop through each existing marker to remove them before posting the new data set.
GOAL:
Load an initial set of markers and infoWindows on page load. Update markers and infoWindows on new data retrieved via ajax and set new bounds.
The initial load is no problem and I'm returning a new set of arrays via ajax with a dataset that has the same formatting as the initial map markers and infoWindows. My thought was to use the same function for the initial map load and then simply pass the new data arrays to that same function to update the map. Data passes, but I'm not able to remove or update the data yet.
In theory, is this an acceptable way to tackle this? If so, how would I go about removing the existing markers and placing the updated markers from 'newMarkers' and 'newInfoWindowContent'.
If there is a better way to be doing this, please...I'm all ears! I started to create a fiddle, but wanted to first get feedback about the procedure as I feel it is bloated and can be simplified.
Thank you to all in advance!
= = = = =
jQuery(function($) {
// Asynchronously Load the map API
var script = document.createElement('script');
script.src = "//maps.googleapis.com/maps/api/js?key=AIzaSyAqb3fT3SbMSDMggMEK7fJOIkvamccLrjA&callback=initialize";
document.body.appendChild(script);
});
function applyFilterMap (cabins) {
// Loop through old markers and set map to null for each.
// This is not working.
setMapOnAll(null);
markers = []
//console.log(markers)
// Build the array of new markers from filtered results.
newMarkers = '';
newMarkers += '[';
$.each(cabins, function(i, cabin) {
newMarkers += '[\''+ cabin.name + '\', ' + cabin.latitude + ', ' + cabin.longitude +'],'
});
newMarkers = newMarkers.slice(0, -1);
newMarkers += ']';
// Build the array of new infoWindowContent from filtered results.
newInfoWindowContent = '';
newInfoWindowContent += '[';
$.each(cabins, function(i, cabin) {
newInfoWindowContent += '[\'<div class="property clearfix"><div class="image"><div class="content"><i class="fa fa-external-link"></i><img src="' + cabin.image_url + '" alt="' + cabin.name + '" class="img-responsive" onload="ga(\'send\', \'event\', \'Impression-MapPin\', \'' + cabin.property.destination.slug + '\', \'' + cabin.cabinid + '\', 1);"><span class="label-sleeps"><i class="fa fa-group"></i> ' + cabin.maxguests + '</span> <span class="label-price">$'+ cabin.minrate + '</span></div></div><div class="property-detail"><h5 class="title">' + cabin.name + '</h5><h5>' + cabin.property.org.name + '</h5></div></div>\'],'
});
newInfoWindowContent = newInfoWindowContent.slice(0, -1);
newInfoWindowContent += ']';
// console.log(newMarkers);
// console.log(newInfoWindowContent);
initialize(newMarkers, newInfoWindowContent);
// Display the Map after it has been filtered and updated.
// $('#destinationMap_wrapper').html('<h3>New Map Here</h3>');
$('#sizeMap').fadeIn('fast');
$('#destinationMap_wrapper').fadeIn('fast');
} // END applyFilterMap() Function.
/// Initialize Map for initial load.
function initialize(newMarkers, newInfoWindowContent) {
var map;
var bounds = new google.maps.LatLngBounds();
var mapOptions = {
mapTypeId: 'roadmap',
};
// Create Markers
if(newMarkers) {
markers = newMarkers;
} else {
markers = [
['The Encantado', 40.38917970, -105.46607810],
['Valhalla', 40.35821830, -105.56307860],
['Mountain Side', 40.39301450, -105.43687520],
];
}
// Info Window Content
if(newInfoWindowContent) {
infoWindowContent = newInfoWindowContent;
} else {
infoWindowContent = [
['<h3>The Encantado Info</h3>'],
['<h3>Valhalla Info</h3>'],
['<h3>Mountain Side Info</h3>']
];
}
// Display map on the page
map = new google.maps.Map(document.getElementById("destinationMap_canvas"), mapOptions);
// Display markers on map
var infoWindow = new google.maps.InfoWindow(), marker, i;
// Loop through our array of markers & place each one on the map
for( i = 0; i < markers.length; i++ ) {
var position = new google.maps.LatLng(markers[i][1], markers[i][2]);
bounds.extend(position);
marker = new google.maps.Marker({
position: position,
map: map,
title: markers[i][0]
});
// Create info window for each marker
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infoWindow.setContent(infoWindowContent[i][0]);
// map.setCenter(marker.getPosition());
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.
var boundsListener = google.maps.event.addListener((map), 'bounds_changed', function(event) {
google.maps.event.removeListener(boundsListener);
});
}
function setMapOnAll(map1) {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(map1);
}
}
The issue is in your applyFilterMap you are defining the newMarkers as an string that have the representation of an array (so its not an array) and in your initilize method you are waiting for an array to loop. Its the same issue for the newInfoWindowContent. You can try a code like this
newMarkers = [];
$.each(cabins, function(i, cabin) {
newMarkers.push([ ''+cabin.name , cabin.latitude , cabin.longitude])
});
And apply the same thing for the newInfoWindowContent. but the code will all that div is a real mess try testing with simple text if it works apply your html with some cleaning
UPDATE
here is a possible version of your method
function applyFilterMap (cabins) {
// Loop through old markers and set map to null for each.
// This is not working.
//setMapOnAll(null);
markers = []
//console.log(markers)
// Build the array of new markers from filtered results.
newMarkers = [];
$.each(cabins, function(i, cabin) {
newMarkers.push([ ''+cabin.name , cabin.latitude , cabin.longitude])
});
// Build the array of new infoWindowContent from filtered results.
newInfoWindowContent = []
$.each(cabins, function(i, cabin) {
var oneArray = ['<h3>'+cabin.name+'</h3>'];
newInfoWindowContent.push(oneArray);
});
// console.log(newMarkers);
// console.log(newInfoWindowContent);
initialize(newMarkers, newInfoWindowContent);
// Display the Map after it has been filtered and updated.
// $('#destinationMap_wrapper').html('<h3>New Map Here</h3>');
$('#sizeMap').fadeIn('fast');
$('#destinationMap_wrapper').fadeIn('fast');
}
Introduction
I am working with google maps, displaying markers having different infoWindow. I am making an ajax call to update the map markers with related info windows. After successful ajax call, map render function called and map updated 'rightly'.
Problem
After ajax call, map updated but the problem is that each marker has the same duplicate infowindow. In other words, infowindow is not binding with markers respectively.
Javascript Code
I am sure problem is on clickEventListener. Comments are for info.
//map rendering start
function renderMap(dd) {
console.log('after ', dd);
for (var a = 0; a < dd; a++) {
console.log('after ', dd);
}
var dataArr = [];
var mapProp = {
center: abc,
zoom: 12,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("googleMap"), mapProp);
for (var a = 0; a < dd.length; a++) {
dataArr.push({ location: new google.maps.LatLng(dd.location.coordinates[1], dd.location.coordinates[0]), weight: 2 });
var contentString = dd;
var infowindow = new google.maps.InfoWindow({
content: contentString
});
var marker = new google.maps.Marker({
position: { lat: dd.location.coordinates[1], lng: dd.location.coordinates[0] },
label: "B",
map: map
});
console.log("before event listener", contentString);//Correctly displayed
google.maps.event.addListener(marker, 'click', function () {
//when click on marker, console is logged
console.log("after event listener", contentString);//Wrongly log same contentString
infowindow.open(map.get('map'), marker);
});
// Add circle overlay and bind to marker
var circle = new google.maps.Circle({
map: map,
radius: 5000, // 10 miles in metres
fillColor: '#4682b4'
});
circle.bindTo('center', marker, 'position');
//console.log(e.location] + ',' + e.location.coordinates[0]);
//start of inner for
}
var heatmap = new google.maps.visualization.HeatmapLayer({
data: dataArr
});
}
//map rendering end
function ajaxHeatMapHandler() {
var dataEl = $('#heatmapFilterArea');
var data = {};
//make ajax resquest
$.ajax({
type: "POST",
url: "/",
data: data,
success: function (response, status) {
heatmapTitle.text(responselength + ' entries');
renderMap(response);
},
});
}
I am trying to figure out what has gone wrong and now turned to SO, if anyone have idea or knowledge for this problem, please do help. Thanks for your time.
Check the great answer by Leigh here
The problem is the way how you create info window, not the event handler I think.
I have an array like this deviceId = [005305230001JIZZZZ, 085835360001NBGJZZ, 085835360002NBGJZZ].
The info window should show the deviceId and be displayed based on which marker is clicked. I started looking at JavaScript only a few days back and can't understand how the functions work and dont have the time right now to learn becauseI have to get this done. I saw a few implementations on this, but I think they have done the adding multiple markers differently using functions, I think. I couldn't understand it so I used for loop.
The latArray and lngArray have something like this [12.1456,12.5256,11.566] and [72.145,72.4557,75.23535]
I cant figure out how to add info windows for corresponding markers.
This is the code for map:
function initMap() {
var bounds = new google.maps.LatLngBounds();
var mapDiv = document.getElementById('map');
var map = new google.maps.Map(mapDiv);
map.setCenter(new google.maps.LatLng(latArray[0],lngArray[0]));
map.setZoom(18);
for(i=0;i<latArray.length;i++)
{
marker = new google.maps.Marker({
position: new google.maps.LatLng(latArray[i],lngArray[i]),
map: map,
title:"This is the place.",
// icon:"phone4.png"
});
//bounds.extend(marker.getPosition());
console.log(latArray);
console.log(lngArray);
}
//map.fitBounds(bounds);
var infoWindow = new google.maps.InfoWindow({
content: contentString
});
marker.addListener('click', function() {
infoWindow.open(map, marker);
});
}
How to show info window of corresponding markers.
This is content for marker:
contentString = '<div id = "content>'
+'<p style = "color:#000000">DeviceID<p>' +
'<p>'+ deviceId[i] + '<br></p>' //deviceId is the array with content
+ '</div>'
I read something about closures but didn't understand. Please help
Edit: I just tried this. I'm getting js?callback=initMap:34 InvalidValueError: setPosition: not a LatLng or LatLngLiteral: not an Object
What i tried:
var markerArray=[];
for(i=0;i<latArray.length;i++)
{
markerArray.push("new google.maps.LatLng("+ latArray[i]+","+lngArray[i]+")");
console.log(markerArray[i]);
}
console.log(markerArray[0]);
for(i=0;i<latArray.length;i++)
{
marker = new google.maps.Marker({
position: markerArray[i],
map: map,
title:"This is the place.",
// icon:"phone4.png"
});
var infoWindow = new google.maps.InfoWindow({
content: contentString[i]
});
marker.addListener('click', function(marker,contentString) {
infoWindow.open(map, marker);
});
}
So I will not bother you with the explanation how closures work (as you are saying your not interested in it now), I just supply you the solution:
// Your arrays with geo informations
var latArray = [-25.363, -26.263, -25.163];
var lngArray = [131.044, 131.144, 132.044];
// Your array with device information
var deviceIdArray = ["AAA", "BBB", "CCC"];
// Just create map according to the first geo info
var map = new google.maps.Map(document.getElementById("map"), {
center: {lat: latArray[0], lng: lngArray[0]},
zoom: 6
});
// Loop throuhg all geo info
latArray.forEach(function(lat, i) {
// For each one create info window
var infoWindow = new google.maps.InfoWindow({
content: '<div id="content>'
+ '<p style="color:#000000">DeviceID<p>'
+ '<p>'+ deviceIdArray[i] + '</p>'
+'</div>'
});
// For each one create marker
var marker = new google.maps.Marker({
map: map,
position: {lat: latArray[i], lng: lngArray[i]}
});
// Click on the currently created marker will show the right info window
marker.addListener("click", function() {
infoWindow.open(map, marker);
});
});
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3"></script>
<div id="map"></div>
Take a look at my function with map. It takes json object with some data from PHP and 'translate' it into array and then adds content to multiple markers (it is not dynamic in real time - you have to reload page). In addition it has a search box (which opens certain info window). If you don't understand do not hestitate to ask :).
//check if document is fully loaded, seetting a container for ajax call results
$(document).ready(function() {
var tablica = [];
// ajax call for action preparing set of names, descriptions, coords and slugs needed to render deatiled markers on map
$.ajax({
url: 'map/json_prepare',
dataType: 'json',
success: function(response) {
var obj = JSON && JSON.parse(response) || $.parseJSON(response);
obj.forEach(function(item, index, array)
{
tablica.push(item);
});
//call a function rendering a map itself
var map;
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 50.06561980, lng: 19.946850},
zoom: 12
});
////////////////////////////////////////////////////////////////////////////////////////////////////
// LOOP ADDING MARKERS FROM DB WITH PROPER INFO WINDOWS (DESCRIPTION AND LINKS)
// Add a markers reference
var markers = [];
$.each(tablica, function( key, value ) {
//markers
var myLatLng = {lat: value[1], lng: value[2]};
var marker = new google.maps.Marker({
position: myLatLng,
map: map,
title: value[0],
clickable: true,
animation: google.maps.Animation.DROP,
adress: value[5]
});
//infowindows
marker.info = new google.maps.InfoWindow ({
content: '<h1>'+ value[0] + '</h1>' + '<br>' + '<br>' + value[3] + '<br>' + value[5] +'<br>' + '<br>' + '' + 'Details' + '<br/>' +
'' + 'Take part in' + '<br>'
});
//eventlistener - after click infowindow opens
google.maps.event.addListener(marker, 'click', function() {
marker.info.open(map, marker);
});
//event listener - after dblclick zoom on certain event is set
google.maps.event.addListener(marker, 'dblclick', function() {
map.setZoom(18);
map.setCenter(marker.getPosition());
});
markers.push(marker);
});
// End of loop adding markers from db.
///////////////////////////////////////////////////////////////////////////////////////////////////////////
///additional event listener - rightclick to get back default zoom
google.maps.event.addListener(map, 'rightclick', function() {
map.setZoom(12);
map.setCenter(map.getPosition());
});
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CENTRING MAP AS ALL OF MARKERS IS VISIBLE//
//create empty LatLngBounds object
var bounds = new google.maps.LatLngBounds();
var infowindow = new google.maps.InfoWindow();
for (i = 0; i < tablica.length; i++) {
var marker = new google.maps.Marker({
position: new google.maps.LatLng(tablica[i][1], tablica[i][2]),
map: map
});
//extend the bounds to include each marker's position
bounds.extend(marker.position);
}
//now fit the map to the newly inclusive bounds
map.fitBounds(bounds);
/////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
///SEARCH_BOX////////
///Here comes part of script adding search box
// Create the search box and link it to the UI element.
// Anchor search box and search button to the map.
var input = document.getElementById('pac-input');
var searchBox = new google.maps.places.SearchBox(input);
var button = document.getElementById('submitSearch');
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
map.controls[google.maps.ControlPosition.TOP_LEFT].push(button);
//replacing polish characters on order to search without necessity typing them
function cleanUpSpecialChars(str)
{
str = str.replace(/[Ą]/g,"A");
str = str.replace(/[ą]/g,"a");
str = str.replace(/[Ę]/g,"E");
str = str.replace(/[ę]/g,"e");
str = str.replace(/[Ć]/g,"C");
str = str.replace(/[ć]/g,"c");
str = str.replace(/[Ł]/g,"L");
str = str.replace(/[ł]/g,"l");
str = str.replace(/[Ń]/g,"N");
str = str.replace(/[ń]/g,"n");
str = str.replace(/[Ó]/g,"O");
str = str.replace(/[ó]/g,"o");
str = str.replace(/[Ś]/g,"S");
str = str.replace(/[ś]/g,"s");
str = str.replace(/[Ź]/g,"Z");
str = str.replace(/[ź]/g,"z");
str = str.replace(/[Ż]/g,"Z");
str = str.replace(/[ż]/g,"z");
return str;
}
//Function, that search in array of markers, one which fits the key word written in searchbox.
$('#submitSearch').click(function() {
//Catching searched word and preparing its value for search process
var toSearch = $(input).val().trim();
toSearch = cleanUpSpecialChars(toSearch);
toSearch = toSearch.toLowerCase();
console.log('Szukana fraza -> ' + toSearch);
var results = [];
if (toSearch.length >=3) {
// Iterate through the array
$.each(markers, function (i, marker) {
//preparing certain elemnts of marker objects for search process
markers[i].title = cleanUpSpecialChars(markers[i].title);
markers[i].adress = cleanUpSpecialChars(markers[i].adress);
markers[i].title = markers[i].title.toLowerCase();
markers[i].adress = markers[i].adress.toLowerCase();
if (markers[i].title.indexOf(toSearch) > -1 || markers[i].adress.indexOf(toSearch) > -1) {
results.push(markers[i]);
}
});
if (results.length < 1) {
console.log ('nic');
$('#message2').slideDown(500, function () {
setTimeout(function () {
$('#message2').slideUp(500);
}, 5000);
});
}
// Close all the infoWindows, before rendering Search results.
markers.forEach(function (marker) {
marker.info.close(map, marker);
});
//Opens infWindows for multiple markers found and set bounds so that all markers found are visible
results.forEach(function (result) {
result.info.open(map, result);
bounds.extend(result.position);
});
map.fitBounds(bounds);
}
else{
//what if user has typed less than three characters in searchbox -> render flash mess.
$("#message").slideDown(500, function(){
setTimeout(function(){
$("#message").slideUp(500);
},5000);
});
}
});
//Enabling key Enter for triggering a search action.
$(input).keypress(function(e){
if(e.which == 13){//Enter key pressed
$('#submitSearch').click();//Trigger search button click event
}
});
},
//////////////////////////////////////////////////////////////////////////////////////////
//obsługa błędu, jeśli nie zostanie wyświetlona mapa
error: function (xhr, ajaxOptions, thrownError) {
console.log(xhr.status);
console.log(thrownError);
console.log(ajaxOptions);
alert('Map is broken. Please try again later.')
}
});
});
It will not qork here because it doesn't contain data from php.
I have a forloop that has a call to a function inside of it. Within that function, I'm pushing values to an array called markers.
Is there a way to access the values of the markers array outside of the forloop?
Here's the code:
<script type="text/javascript">
// arrays to hold copies of the markers and html used by the side_bar
// because the function closure trick doesnt work there
var map = null;
geocoder = new google.maps.Geocoder();
var side_bar_html = "";
var icon = '';
var markers = [];
function codeAddress(this_address,index,callback) {
geocoder.geocode( { 'address': this_address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
callback.call(window,index,results[0].geometry.location)
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
function initialize() {
// create the map
var myOptions = {
zoom: 3,
center: new google.maps.LatLng(46.90, -121.00),
mapTypeControl: true,
mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU},
navigationControl: true,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
google.maps.event.addListener(map, 'click', function() {
infowindow.close();
});
for (var i = 0; i < businesses.length; i++) {
codeAddress(businesses[i].address,i,function(i,point){
var description = businesses[i].description;
if(businesses[i].business_type == "Wine"){
//http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=A|00CC99|000000
icon = 'http://google-maps-icons.googlecode.com/files/wineyard.png';
}else if(businesses[i].business_type == "Golf"){
icon = 'http://google-maps-icons.googlecode.com/files/golf.png';
}else{
icon = 'http://google-maps-icons.googlecode.com/files/festival.png';
}
var marker = createMarker(point,businesses[i].name,description,icon);
// put the assembled side_bar_html contents into the side_bar div
document.getElementById("side_bar").innerHTML = side_bar_html;
});//End codeAddress-function
}//End for-loop
console.log(markers);
var markerCluster = new MarkerClusterer(map, markers);
}
// A function to create the marker and set up the event window function
function createMarker(latlng, name, html,icon) {
var contentString = html;
var marker = new google.maps.Marker({
position: latlng,
map: map,
icon: icon,
zIndex: Math.round(latlng.lat()*-100000)<<5
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(contentString);
infowindow.open(map,marker);
});
// save the info we need to use later for the side_bar
markers.push(marker);
// add a line to the side_bar html
side_bar_html += '<a href="javascript:myclick(' + (markers.length-1) + ')">' + name + '<\/a><br />'+html+'<br />';
}
var infowindow = new google.maps.InfoWindow({
size: new google.maps.Size(150,50)
});
// This function picks up the click and opens the corresponding info window
function myclick(i) {
google.maps.event.trigger(markers[i], "click");
}
</script>
As you can see, the last line says "var markerCluster = new MarkerClusterer(map, markers);" This is where I want to be able to access the information from.
Thanks!
The problem is you're not accounting for the asynchronous nature of the call to codeAddress. You're calling that function in a loop, which is triggering a series of calls to the Google Maps API.
You are running this line:
var markerCluster = new MarkerClusterer(map, markers);
...even before the callbacks have been triggered.
To fix, maintain a counter. Each time the callback is triggered increase that counter by 1. Once it is equal to businesses.length you know all the addresses have been geo-coded, and all markers have been added to the array. Now you can create the MarkerCluster.
Yes, Declare it before the for loop.
var markers
for(....
Bring the definition of the marker outside of the for loop ...
var markers = new Array ();
for (var i = 0; i < businesses.length; i++) {
markers[i] = ...