Here is my problem. I want to set different image to standard markers given by fusion tables. I extract data from the column that contains my points "(coord,coord)" BUT when I associate this coordinates to a marker, this one is not showed! I think that the solution is soooo easy but I can't get it :(. Please read in the section "HERE IS THE PROBLEM" in the middle of this code to have a clear idea. Thanks!!!!
function initialize() {
geocoder = new google.maps.Geocoder();
map = new google.maps.Map(document.getElementById('map_canvas'), {
center: new google.maps.LatLng(46.06454, 13.23561), //the center lat and long
zoom: 9, //zoom
mapTypeId: google.maps.MapTypeId.ROADMAP //the map style
});
//make gviz request
setData();
}
/* GVIZ - get data from Fusion Tables */
function setData() {
//create a viz query to send to Fusion Tables
var query = new google.visualization.Query('http://www.google.com/fusiontables/gvizdata?tq=' + encodeURIComponent("SELECT dove FROM 781907"));
//set the callback function that will be called when the query returns
query.send(getData);
}
function getData(response) {
numRows = response.getDataTable().getNumberOfRows();
for (i = 0; i < numRows; i++) {
var row = response.getDataTable().getValue(i,0);
codeAddress(row);
}
}
var geocoder;
function codeAddress(latlng) {
// HERE IS THE PROBLEM!!!!
// Test show correctly "(lat,lng)" BUT no marker showed on the map!
document.getElementById("test").innerHTML = latlng;
geocoder.geocode( { 'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var marker = new google.maps.Marker({
map: map,
position: latlng
//icon: new google.maps.MarkerImage("http://www.google.com/images/icons/product/fusion_tables-32.png")
});
}
});
}
UPDATE: Based on #Trott's answer, maybe something like this? But still not running. Any advice?
function getData(response) {
numRows = response.getDataTable().getNumberOfRows();
//create an array of row values
for (i = 0; i < numRows; i++) {
rowtext = response.getDataTable().getValue(i,0);
var strArr[] = rowtext.split(",");
document.getElementById("via").innerHTML = rowtext;
row = new google.maps.LatLng(strArr[0],strArr[1]);
codeAddress(row);
}
}
geocoder.geocode() requires a LatLng object. Your variable latlng is simply text. You'll need to find a way to convert it to a LatLng object. Most obvious way is probably to parse it with a regex or some other way and pass the lat and lng to new google.maps.LatLng(). There may be a more elegant solution, but that will work.
If it helps, here's some quick hacking I did to your code to confirm what I wrote above. I just hardcoded your first pair of coordinates. You'll still need to write something to parse the data.
function codeAddress(latlng) {
//Whoops, latlng is a string. We need it to be an object. Let's just hardcode one for demo purposes.
latlng=new google.maps.LatLng(46.0724339, 13.249490000000037);
geocoder.geocode( { 'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var marker = new google.maps.Marker({
map: map,
position: latlng,
icon: new google.maps.MarkerImage("http://www.google.com/images/icons/product/fusion_tables-32.png")
});
}
});
}
UPDATE: If you (#Massimo) want to do it the way you have it in your update, then you need to remove the parentheses and possibly white space. Try something more like this:
function getData(response) {
numRows = response.getDataTable().getNumberOfRows();
//create an array of row values
for (i = 0; i < numRows; i++) {
var rowtext = response.getDataTable().getValue(i,0);
var sanitizedText = rowtext.replace(/[\(\)\s]/g, "");
var strArr = sanitizedText.split(",");
document.getElementById("via").innerHTML = rowtext;
row = new google.maps.LatLng(strArr[0],strArr[1]);
codeAddress(row);
}
}
Related
I have a function that loads my map to keep my map static.
<script>
var delArray = new Array();
var gm;
var map;
var iw;
var oms;
window.onload = function(){
gm = google.maps;
map = new gm.Map(document.getElementById('map_canvas'), {
mapTypeId: gm.MapTypeId.TERRAIN,
center: new gm.LatLng(-29.335205, 24.793563),
scrollwheel: false,
zoom: 6
});
iw = new gm.InfoWindow();
oms = new OverlappingMarkerSpiderfier(map,
{markersWontMove: true, markersWontHide: true});
}
</script>
I then use another function to construct my spiderfier data.
<script>
function spider(mapData){
var usualColor = 'eebb22';
var spiderfiedColor = 'ffee22';
var iconWithColor = function(color) {
return 'http://chart.googleapis.com/chart?chst=d_map_xpin_letter&chld=pin|+|' +
color + '|000000|ffff00';
}
var shadow = new gm.MarkerImage(
'https://www.google.com/intl/en_ALL/mapfiles/shadow50.png',
new gm.Size(37, 34), // size - for sprite clipping
new gm.Point(0, 0), // origin - ditto
new gm.Point(10, 34) // anchor - where to meet map location
);
oms.addListener('click', function(marker) {
iw.setContent(marker.desc);
iw.open(map, marker);
});
oms.addListener('spiderfy', function(markers) {
for(var i = 0; i < markers.length; i ++) {
markers[i].setIcon(iconWithColor(spiderfiedColor));
markers[i].setShadow(null);
}
iw.close();
});
oms.addListener('unspiderfy', function(markers) {
for(var i = 0; i < markers.length; i ++) {
markers[i].setIcon(iconWithColor(usualColor));
markers[i].setShadow(shadow);
}
});
var bounds = new gm.LatLngBounds();
for (var i = 0; i < mapData.length; i ++) {
var datum = mapData[i];
var loc = new gm.LatLng(datum[0], datum[1]);
bounds.extend(loc);
var marker = new gm.Marker({
position: loc,
title: datum[2],
animation: google.maps.Animation.DROP,
map: map,
icon: iconWithColor(usualColor),
shadow: shadow
});
marker.desc = datum[3];
oms.addMarker(marker);
delArray.push(marker);
}
map.fitBounds(bounds);
// for debugging/exploratory use in console
window.map = map;
window.oms = oms;
}
</script>
And Another to remove markers from the map:
<script>
function delMe(){
if(delArray){
for(i =0; i <= delArray.length; i++){
delArray[i].setMap(null);
}
this.delArray = new Array();
}
}
</script>
My map data (mapData) comes from a php script and passed on via Jason. And that's also where I call my delete function right before I call my spider (map) function. This I do to clear the map before I pass the new data.
$( document ).ready(function() {
delMe();
var pdata = $js_array;
spider(pdata);
});
Now, my problem is that all data is displaying perfectly but after calling the delMe() function it clears the markers 100% but then my map become unresponsive it's not loading new data when calling the spider() function with new data.
I can overcome this problem by reloading/creating the map again, but I want to avoid that and only use a static map. And if I don't delete markers it just fill the map with 100's of markers mixing the old and new.
I am a bit of a noob when it comes to javascript/jquery, any help will be much appreciated!.
It looks like you're missing an OMS removeMarker call in your delMe function, which should go something like this:
function delMe(){
if (delArray){
for (i =0; i <= delArray.length; i++){
oms.removeMarker(delArray[i]);
delArray[i].setMap(null);
}
this.delArray = [];
}
}
(It's possible you have other problems too, but here's a start).
It's not clear from what you write, but are you using the JS developer console? Google '[your browser] developer console' for more info — it lets you see if errors are causing your map to become unresponsive.
I'm an amateur programmer and working on a project I have in mind using the google maps API. Long story short, I'm trying to create a variable with the average longitude and latitude of n number of points. I'm to the point that I have an array of the lng/lat coordinates, but I'm struggling to convert them into a format that I can use as input for a google maps LatLng method.
I've referenced this SO question, Find the average (center) of lats/lngs, and numerous other websites for a month now, but I haven't been able to understand or implement a solution. I feel like I'm missing the simple stuff, but I've been banging my head against this for a month, and not getting anywhere. Any advice or help with this would be appreciated.
//GOOGLE MAPS API SCRIPTS
var streetarray = document.getElementsByName("street");
var cityarray = document.getElementsByName("city");
var geocoder;
var map;
var results;
var mapArray = new Array();
var avgLat;
var avgLng;
function initialize() {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(-34.397, 150.644);
var mapOptions = {
zoom: 8,
//centered on Carrollton, Texas -- Change lat,long values to change initial map area
center:
new google.maps.LatLng(32.999173, -96.897413)
}
//change Id reference to the div/container that contains the google map
map = new google.maps.Map(document.getElementById('map'), mapOptions);
}
function codeAddress() {
//Loop through and concate street and city values to find long,lat values for all fields
for (var cName = 0; cName < namearray.length; cName++){
var address = streetarray[cName].value + cityarray[cName].value;
//start geocode copy & paste text from API reference
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var results = results[0].geometry.location;
map.setCenter(results);
var marker = new google.maps.Marker({
map: map,
position: results,
});
//Push lng/lat locations to the mapArray
mapArray.push(results);
//Loop through mapArray to add Lat/Lng values, and then divide by j (number of locations) to find the average
for (var i in mapArray) {
var avgLat = 0;
var avgLng = 0;
var j = 0;
var avgLat = (avgLat + mapArray[i][1]);
var avgLng = (avgLng + mapArray[i][2]);
console.log(mapArray, avgLat, avgLng);
j++;
}
avgLat = avgLat / j;
avgLng = avgLng / j;
var markerCircle = new google.maps.Circle({
center: results,
radius: 15000,
strokeColor:"#0000FF",
strokeOpacity:0.8,
strokeWeight:2,
fillColor:"#0000FF",
fillOpacity:0.4
})
markerCircle.setMap(map);
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
}}
2 issues:
results[0].geometry.location is not an array, it's an object(a google.maps.LatLng). Use the methods lat() and lng() to retrieve latitude and longitude
var avgLat = 0;
var avgLng = 0;
var j = 0;.
You must move this to outside of the loop, otherwise the variables will be cleared on each loop.
please help me with this issue. I have the following code with working address variable. I tryed to add titles to the Infowindow so when a user clicks on a marker on the map to see some content in popup. Unfortunately, for all popups I can see the same title. I tested, it is a correct js array, but shows only the first titles that comes from the array.. Please help to solve this issue.. Thank you in advance guys !
<script type="text/javascript" charset="utf-8">
var map;
var address = < ? php echo json_encode($adr); ? > ;
var titles = < ? php echo json_encode($ttl); ? > ;
var x = 0;
var nbAddresses = address.length;
var geocoder;
var mark;
var contentString = titles[x];
function init() {
var moptions = {
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map"), moptions);
geocoder = new google.maps.Geocoder();
for (var i = 0; i < nbAddresses; i++) {
geocoder.geocode({
'address': address[i]
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
mark = new google.maps.Marker({
position: results[0].geometry.location,
map: map,
title: titles[x]
});
map.setCenter(results[0].geometry.location);
x++;
setInfoWindow();
}
});
}
function setInfoWindow() {
google.maps.event.addListener(mark, 'click', function(event) {
var iwindow = new google.maps.InfoWindow();
iwindow.setContent(contentString);
iwindow.open(map, this);
});
}
}
window.onload = init;
</script>
changing
x++;
setInfoWindow(); to
setInfoWindow();
x++;
sets the problem !
At the start of your program you set the contentString to the first element in the title array
var contentString = titles[x];
Then you use this variable inside the setInfoWindow function unchanged.
What if you changed the setInfoWindow to accept a contentString parameter like so
function setInfoWindow(contentString) {...
When you call setInfoWindow, pass in the title.
setInfoWindow(title[x]);
Make sure you increment x after you call this function, so move x++ below setInfoWindow call.
EDIT You will also notice a strange problem from time to time where some titles may appear on the wrong markers. This is because you are doing multiple geocodes at once, and you may get a response out of order.
The following modification would fix that.
for (var i = 0; i < nbAddresses; i++) {
geocoder.geocode({
'address': address[i]
}, return function(x) { // we define a function and call it straight away. The function returns another function which is our callback.
function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
mark = new google.maps.Marker({
position: results[0].geometry.location,
map: map,
title: titles[x]
});
map.setCenter(results[0].geometry.location);
setInfoWindow();
}
}
}(i)); // (i) after the function declaration calls the function and passes in the current value of i
}
So basically what we did here was define a function and run it straight away with the current value of 'i' passed in. The function would then return another function. This function will be run once the goecoding has finished. But now we have a reference to 'i' as it was when the function was defined. So you no longer need to keep a record of x outside this function as x will be equal to i which corresponds with the address passed into geocoder.
This is called a closure.
How do JavaScript closures work?
I have a list of schools that I want to plot on a Google Map. I'm using Google's Geocoding Service to lookup the lng/lat for a given postcode, upon successfully retrieving this information I want to drop a marker, together with adding the appropriate event listener that opens an infobox when a given marker is clicked.
When I make a request to the geocoder it's in the context of a school, when I receive a callback I lose this context. You'll see from code below that I've come up with a clunky solution to this, although it fails occasionally when the geocoder results truncate the postcode.
Should I be using something like jQuery's Deferred Object to solve this issue?
var geocoder;
var map;
var infowindow
var iterator = 0;
geosearch = new Array();
function drop() {
for (var i = 0; i < schools.length; i++) {
setTimeout(function() { // delay added to prevent being throttled
addMarker();
iterator++;
}, i * 1000);
}
}
function addMarker() {
address = schools[iterator].addresses[0].address.zip;
geosearch[address] = schools[iterator]; // this is how I'm keeping track of initial request
geocoder.geocode( { 'address': address }, function(results, status) {
var school = geosearch[results[0].address_components[0].short_name]; // loading the school associated with the initial request, which only works if the postcode completely matches up - clunky!
if (status == google.maps.GeocoderStatus.OK) {
// each school has tags, I want to set a marker if certain tags exist
if ($.inArray('D', school.tags) > 0) {
var image = 'map_markers/brown_MarkerD.png';
} else if ($.inArray('C', school.tags) > 0) {
var image = 'map_markers/red_MarkerC.png';
} else if ($.inArray('B', school.tags) > 0) {
var image = 'map_markers/yellow_MarkerB.png';
} else if ($.inArray('A', school.tags) > 0) {
var image = 'map_markers/green_MarkerA.png';
} else {
var image = 'map_markers/blue_MarkerZ.png';
}
// add the marker to the map, using result
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location,
draggable: false,
icon: image,
shadow: 'http://www.google.com/mapfiles/arrowshadow.png',
animation: google.maps.Animation.DROP
});
// adds listening on marker so that popup box appears when clicked
google.maps.event.addListener(marker, 'click', (function(marker, school) {
return function() {
infowindow.setContent(
''+school.name+''
+'<address>'
+school.addresses[0].address.street+'<br />'
+school.addresses[0].address.city+'<br />'
+school.addresses[0].address.state+'<br />'
+school.addresses[0].address.zip+'<br />'
+school.addresses[0].address.country+'<br />'
+'</address>');
infowindow.open(map, marker);
}
})(marker, school));
} else {
console.log("* NOT found: " + status);
}
});
}
function initialise() {
geocoder = new google.maps.Geocoder();
infowindow = new google.maps.InfoWindow();
var latlng = new google.maps.LatLng(54.82659788452641,-3.417279296874991);
var mapOptions = {
zoom: 6,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
drop(); // loops through schools to add marker
}
I would suggest geocoding the addresses offline and storing the coordinates in your database (or wherever you are storing the addresses). Then use the coordinates to display the markers.
I would also suggest reviewing this article on geocoding strategies from the documentation
To answer your question, I would suggest using javascript function closures to associate the address with the callback function.
The problem I was experiencing here was just a questions of scope, and in particular the way that I was referencing the school within the addMarker() function. Rather than referencing the school within the schools array using the global iterator variable, I instead pass in this school, this way the correct school is always referenced on the callback that is created within this scope.
var geocoder;
var map;
var infowindow
var iterator = 0;
function drop() {
for (var i = 0; i < schools.length; i++) {
setTimeout(function() {
addMarker(schools[iterator]); // pass in the school as an argument
iterator++;
$('#current_school').text(iterator); // taken this out of addMarker()
}, i * 1000);
}
}
function addMarker(school) {
geocoder.geocode( { 'address': school.addresses[0].address.zip }, function(results, status) {
... // the inners from here remain the same
});
}
I've got this problem when removing a Marker from an array. I click on the map and place markers where i have clicked, the markers are then saved in an array. When removing them it only works in the order i have placed them but backwards, that means i place 1 2 3 but have to remove them like 3 2 1.
If i try to remove the markers in random order, the first one is removed, but then the others just stop working, the listener still works, but it seems like the forloop doesnt find the other markers in the array.
Any ideas? I'm completely lost.
Here is the code:
var map;
var tempLatLng;
var zoomLevel;
var markers = [];
var zoomLevels = [];
var count = -1;
var nullLatlng = new google.maps.LatLng(84.52,45.16);
var nullMarker = new google.maps.Marker({
position: nullLatLng,
});
function initialize() {
var myLatlng = new google.maps.LatLng(55.605629745598904,13.000441789627075);
var myOptions = {
zoom: 17,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel:false
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
//Puts a listener on the map, when clicking on the map, it places a marker.
google.maps.event.addListener(map, 'click', function(event) {
zoomLevel = map.getZoom();
document.getElementById("zoom").value = zoomLevel;
tempLatLng = event.latLng;
setTimeout("placeMarker(tempLatLng)", 800); //placeMarker is called with a duration so that //doubleclicking doesn't bother the placement.
});
}
//Function to place markers.
function placeMarker(location) {
if(zoomLevel == map.getZoom()){
if(true){
var marker1 = new google.maps.Marker({
position: location,
map: map,
draggable:true
});
count = count + 1;
markers[count] = marker1;
document.getElementById("count").value = count;
google.maps.event.addListener(marker1,'rightclick', function(event){
document.getElementById("test2").value = "funkar";
for(var i = 0 ;i < markers.length ;i++){
if(markers[i].getTitle() == marker1.getTitle()){
marker1.setMap(null);
document.getElementById("markerpos").value = markers[i].getTitle();
document.getElementById("test1").value = markers[i].getTitle();
count = count - 1;
document.getElementById("count").value = count;
markers[i] = nullMarker;
}
}
});
marker1.setTitle(location.toString());
}
map.setCenter(location);
}
}
Here is the JSFiddle Demo:
Basically, you were using var count to keep track of the number of markers. You can do markers.length for that. Instead of using markers[count] you can use native array's push method to add element into the array. To remove use splice(i, 1); where i is the element's position and remove 1 element from that position. Also, to check if two markers are equal or the "same" instead using getTitle() use === which does:
is exactly equal to (value and type)
The problem is if you create two or more markers on the same position it would remove both markers but in reality you only remove one of the two "clones" and thus leaving a marker un-removable. This is caused by using getTitle which returns lat lng and if you have two markers w/ same lat lng you have an issue. Also, i changed, within your onclick function, marker1 to this which are referring to the same object for readability.
//Function to place markers.
function placeMarker(location) {
if (zoomLevel == map.getZoom()) {
if (true) {
var marker1 = new google.maps.Marker({
position: location,
map: map,
draggable: true
});
count = count + 1;
markers.push(marker1);
document.getElementById("count").value = markers.length;
google.maps.event.addListener(marker1, 'rightclick', function(event) {
document.getElementById("test2").value = "funkar";
for (var i = 0; i < markers.length; i++) {
if (markers[i] === this) {
this.setMap(null);
document.getElementById("markerpos").value = markers[i].getTitle();
document.getElementById("test1").value = markers[i].getTitle();
markers.splice(i, 1);
document.getElementById("count").value = markers.length;
}
}
});
marker1.setTitle(location.toString());
}
map.setCenter(location);
}
}