I'm not used to writing JS, honestly, and to make matters worse I'm working with the Google Maps API which, while well-documented, is a bear. So, I've written a function that allows a users to zoom onto the map from a link. But the interpreter insists my function isn't defined when I call it. The function is "zoomTo" and it appears in the following monster script.
function load() {
if (GBrowserIsCompatible()) {
var gmarkers = [];
var htmls = [];
var i = 0;
// Read the data
//++++++++++++++++
GDownloadUrl("/assets/data/nolag.xml", function(data) {
var xml = GXml.parse(data);
var markers =
xml.documentElement.getElementsByTagName("marker");
// Draw icons
for (var i = 0; i < markers.length; i++) {
var locoName = markers[i].getAttribute("locoName");
var speed = markers[i].getAttribute("speed");
var ip = markers[i].getAttribute("ip");
var date = markers[i].getAttribute("captureTime");
var lat = markers[i].getAttribute("lat");
var lng = markers[i].getAttribute("lng");
var location = markers[i].getAttribute("location");
var heading = markers[i].getAttribute("heading");
var type = markers[i].getAttribute("type");
var point = new GLatLng(parseFloat(markers[i].getAttribute("lat")),
parseFloat(markers[i].getAttribute("lng")));
var marker = createMarker(point, locoName, speed, ip, date, lat, lng, location, heading, type);
map.addOverlay(marker);
}
});
// create the map
var map = new GMap2(document.getElementById("map"));
map.addControl(new GLargeMapControl3D());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(40.5500, -72.1700), 7);
map.enableScrollWheelZoom();
NEC = new GPolyline(NECRoute, "#0d004c", 3, 0.7);
map.addOverlay(NEC);
// A function to create the marker and set up the event window
//+++++++++++++++++
function createMarker(point, locoName, speed, ip, date, lat, lng, location, heading, type) {
var marker = new GMarker(point, customIcons[type]);
marker.tooltip = '<div class="tooltip"><h1>' + locoName + '</h1><h2>' + speed + '<br/>' + location + '</h2></div>';
marker.contextmenu = '<div class="contextmenu">Hello world</div>';
var satellite = "<img src=\"./images/icons/satellite.gif\">";
var gps = "<img src=\"./images/icons/gps.gif\">";
var cmu = "<img src=\"./images/icons/cmu.gif\">";
var ftp = "<img src=\"./images/icons/ftp.gif\">";
var me1k = "<img src=\"./images/icons/me1k.gif\">";
var html = "<div class=\"bubble\">";
html += "<h3>" + locoName + "<span class=\"small-data\"> Route 2150</span></h3>";;
html += "<div class=\"toolbar\">" + gps + satellite + cmu + ftp + me1k + "</div>";
html += "<h4>Heading " + heading + " # " + speed + " MPH</h4>"
html += "<h4>Lat: " + lat + "</h4><h4> Lng: " + lng + "</h4>";
html += "<h4>IP: " + ip + "</h4>";
html += "<h4><div class=\"sm-button\"><a style='color: #FFFFFF; decoration:none;' href='map_detail.php'>Details</a></div><div class=\"sm-button\">Zoom To</div></h4>";
html += "</div>";
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(html);
});
gmarkers[i] = marker;
htmls[i] = html;
i++;
// ====== The new marker "mouseover" and "mouseout" listeners ======
GEvent.addListener(marker,"mouseover", function() {
showTooltip(marker);
});
GEvent.addListener(marker,"mouseout", function() {
tooltip.style.visibility="hidden"
});
return marker;
}
// ====== This function displays the tooltip ======
//+++++++++++++++++++++++++++++++++++++++++++++++++++
function showTooltip(marker) {
tooltip.innerHTML = marker.tooltip;
var point=map.getCurrentMapType().getProjection().fromLatLngToPixel(map.getBounds().getSouthWest(),map.getZoom());
var offset=map.getCurrentMapType().getProjection().fromLatLngToPixel(marker.getPoint(),map.getZoom());
var anchor=marker.getIcon().iconAnchor;
var width=marker.getIcon().iconSize.width;
var pos = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(offset.x - point.x - anchor.x + width,- offset.y + point.y +anchor.y));
pos.apply(tooltip);
tooltip.style.visibility="visible";
}
// ===== This function is invoked when the mouse goes over an entry in the side_bar =====
function mymouseover(i) {
showTooltip(gmarkers[i])
}
// ===== This function is invoked when the mouse leaves an entry in the side_bar =====
function mymouseout() {
tooltip.style.visibility="hidden";
}
// This function picks up the side_bar click and opens the corresponding info window
function myclick(i) {
gmarkers[i].openInfoWindowHtml(htmls[i]);
}
// ====== set up marker mouseover tooltip div ======
var tooltip = document.createElement("div");
document.getElementById("map").appendChild(tooltip);
tooltip.style.visibility="hidden";
// === create the context menu div ===
var contextmenu = document.createElement("div");
contextmenu.style.visibility="hidden";
// === functions that perform the context menu options ===
function zoomTo( lat, lng, level) {
// perform the requested operation
map.setCenter( new GLatLng(lat,lng), level);
// hide the context menu now that it has been used
contextmenu.style.visibility="hidden";
}
contextmenu.innerHTML = '<div class="context"><ul>'
+ '<li class="sectionheading">Zoom Out</li>'
+ '<li class="sectionheading">Boston Area</li>'
+ '<li>South Station, Boston</li>'
+ '<li>South Hampton</li>'
+ '<li>New Haven</li>'
+ '<li class="sectionheading">New York Area</li>'
+ '<li>Sunny Side</li>'
+ '<li>NY, Penn Station</li>'
+ '<li>30th Street, Philadelphia</li>'
+ '<li>Wilmington Shops</li>'
+ '<li>Baltimore, Penn Station</li>'
+ '<li class="sectionheading">DC Area</li>'
+ '<li>DC, Ivy City</li>'
+ '<li>DC, Union Station</li>'
+ '</ul</div>';
map.getContainer().appendChild(contextmenu);
// === listen for singlerightclick ===
GEvent.addListener(map,"singlerightclick",function(pixel,tile) {
clickedPixel = pixel;
var x=pixel.x;
var y=pixel.y;
if (x > map.getSize().width - 120) { x = map.getSize().width - 120 }
if (y > map.getSize().height - 100) { y = map.getSize().height - 100 }
var pos = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(x,y));
pos.apply(contextmenu);
contextmenu.style.visibility = "visible";
});
// === If the user clicks on the map, close the context menu ===
GEvent.addListener(map, "click", function() {
contextmenu.style.visibility="hidden";
});
} else {
alert("Sorry, the Google Maps API is not compatible with this browser");
}
}
It appears that zoomTo is an annonymous function inside of the top-level function load() - therefore, it's not available to top-level calls.
Instead of
// === functions that perform the context menu options ===
function zoomTo( lat, lng, level) {
// perform the requested operation
map.setCenter( new GLatLng(lat,lng), level);
// hide the context menu now that it has been used
contextmenu.style.visibility="hidden";
}
put the function in the top level, and pass in the map and contextmenu variables:
// === functions that perform the context menu options ===
function zoomTo( lat, lng, level) {
// perform the requested operation
map.setCenter( new GLatLng(lat,lng), level);
// hide the context menu now that it has been used
contextmenu.style.visibility="hidden";
}
As it dont looks well in comment. posting the comment above here again
<html>
<head>
<script type="text/javascript">
function zoomTo(x,y,z) {
....
}
</script>
.....
</head>
......
</html>
Related
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;
}
I' m using google map api version 3 for this program. What I m trying to do is change the position of infoWindow which appears on mouseover. Currently it shows on the marker. I want to change the position to show it on top of the marker icon. When I replace
speedTest.infoWindow.setPosition(latlng);
speedTest.infoWindow.open(speedTest.map);
These two lines with following line,
speedTest.infoWindow.open(speedTest.map, this);
It shows correctly on top of the marker. but then infoWindow will not able popup when I trigger mouse event from side items.
speedTest.showMarkers = function() {
speedTest.markers = [];
var type = 1;
if ($('usegmm').checked) {
type = 0;
}
if (speedTest.markerClusterer) {
speedTest.markerClusterer.clearMarkers();
}
var panel = $('markerlist');
panel.innerHTML = '';
var numMarkers = $('nummarkers').value;
for (var i = 0; i < numMarkers; i++) {
var titleText = speedTest.pics[i].photo_title;
if (titleText == '') {
titleText = 'No title';
}
var item = document.createElement('DIV');
var title = document.createElement('A');
title.href = '#';
title.className = 'title';
title.innerHTML = titleText;
item.appendChild(title);
panel.appendChild(item);
var latLng = new google.maps.LatLng(speedTest.pics[i].latitude,
speedTest.pics[i].longitude);
var imageUrl = 'http://chart.apis.google.com/chart?cht=mm&chs=24x32&chco=' +
'FFFFFF,008CFF,000000&ext=.png';
var markerImage = new google.maps.MarkerImage(imageUrl,
new google.maps.Size(24, 32));
var marker = new google.maps.Marker({
'position': latLng,
'icon': markerImage
});
var fn = speedTest.markerClickFunction(speedTest.pics[i], latLng);
google.maps.event.addListener(marker, 'click', fn);
google.maps.event.addDomListener(title, 'click', fn);
speedTest.markers.push(marker);
}
window.setTimeout(speedTest.time, 0);
};
speedTest.markerClickFunction = function(pic, latlng) {
return function(e) {
e.cancelBubble = true;
e.returnValue = false;
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
var title = pic.photo_title;
var url = pic.photo_url;
var fileurl = pic.photo_file_url;
var infoHtml = '<div class="info"><h3>' + title +
'</h3><div class="info-body">' +
'<a href="' + url + '" target="_blank"><img src="' +
fileurl + '" class="info-img"/></a></div>' +
'<a href="http://www.panoramio.com/" target="_blank">' +
'<img src="http://maps.google.com/intl/en_ALL/mapfiles/' +
'iw_panoramio.png"/></a><br/>' +
'<a href="' + pic.owner_url + '" target="_blank">' + pic.owner_name +
'</a></div></div>';
speedTest.infoWindow.setContent(infoHtml);
speedTest.infoWindow.setPosition(latlng);
speedTest.infoWindow.open(speedTest.map);
};
};
Here is the full code I m currently using:
speed_test_example.html
speed_test.js
When you create your marker, you can specify where the InfoWindow should be anchored, like:
var marker = new google.maps.Marker({
'position': latLng,
'icon': markerImage,
'anchorPoint': new google.maps.Point(x, y)
});
where x and y are the x and y offset from the marker's position.
Note: google.maps.MarkerImage is no longer used. Use Icon instead.
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;
I am using ajax and php and I grabbing all of the points out of my database and plotting them on the map. Which works fine. However I want to change the icon of the marker depending on if status in the database is 100 or 200 or 300 for each record. I can't seem to get anything to work. Here is my code:
if (localStorage.getItem('type2') !== null) {
$(function ()
{
var radius2 = localStorage.getItem("radius2");
var lat2 = localStorage.getItem("lat2");
var long2 = localStorage.getItem("long2");
var type2 = localStorage.getItem("type2");
var city2 = localStorage.getItem("city2");
var rep2 = localStorage.getItem("rep2");
var size2 = localStorage.getItem("size2");
var status2 = localStorage.getItem("status2");
$.ajax({
url: 'http://example.com/Test/www/22233333.php',
data: "city2=" + city2 + "&rep2=" + rep2 + "&status2=" + status2 + "&size2=" + size2 + "&type2=" + type2 + "&long2=" + long2 + "&lat2=" + lat2 + "&radius2=" + radius2,
type: 'post',
dataType: 'json',
success: function (data) {
$.each(data, function (key, val) {
var lng = val['lng'];
var lat = val['lat'];
var id = val['id'];
var name = val['name'];
var address = val['address'];
var category = val['category'];
var city = val['city'];
var state = val['state'];
var rep = val['rep'];
var status = val['status'];
var size = val['size'];
$('div#google-map').gmap('addMarker', {
'position': new google.maps.LatLng(lat, lng),
'bounds': true,
'icon': 'images/hospital.png'
}).click(function () {
$('div#google-map').gmap('openInfoWindow', {
'backgroundColor': "rgb(32,32,32)",
'content': "<table><tr><td>Name:</td><td>" + name + "</td></tr><tr><td>Address:</td><td>" + address + ", " + city + " " + state + "</td></tr><tr><td>Category:</td><td>" + category + "</td></tr><tr><td>Rep:</td><td>" + rep + "</td></tr><tr><td>Status:</td><td>" + status + "</td></tr><tr><td>Size:</td><td>" + size + "</td></tr></table>"
}, this);
});
})
}
});
})
}
Looks like you are using jquery-ui-map?
I haven't used this abstraction
You can call the setIcon function - on a marker you can set it's icon this way for the main API
https://developers.google.com/maps/documentation/javascript/reference#Marker
So your addMarker method will return a marker instance by the look of it so once you have that run setIcon
Do something like this in your success function with in $.each.
Status is the database field
var size = val['size'];
var status = val['status'];
var icon = '';
if (status == 100){
icon = 'images/icon1.png'; //your icon1
}else if (status == 100){
icon = 'images/icon1.png'; //your icon2
}
...
$('div#google-map').gmap('addMarker', {
'position': new google.maps.LatLng(lat, lng),
'bounds': true,
'icon': icon //your dynamic icon
})
Hope this helps
I'm using a Google Maps plugin, and I want it to show up on the page load as well as all postbacks. It seems to only work on postbacks though. Any ideas? I have the body onload tag as "body background="#ccccff" onload="initialize()"", but the function is not defined the first time. Why? Here is the code:
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"> </script>
<script type="text/javascript">
var mostRecentInfo;
function initialize() {
var center = new google.maps.LatLng(0, 0);
var mapOptions = {
center: center,
zoom:1,
mapTypeId: google.maps.MapTypeId.SATELLITE
};
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
var posStr = <%=JSON%>;
if (posStr.toString() != "0") {
var test = posStr.toString().split(',');
var groundstation = <%=groundStation%>;
var dateTimeStr = <%=datetimesStr%>;
var AUStr = <%=auStr%>;
var spaceCraft = <%=spacecraft%>;
var dateTimes = dateTimeStr.toString().split(',');
var auIDs = AUStr.toString().split(',');
var latitude = new Array((test.length / 2));
var longitude = new Array(latitude.length);
var i = 0;
var markerArray = new Array();
for (var j = 0; j < (test.length - 1); j = j + 2) {
latitude[i] = eval(test[j+1]);
longitude[i] = eval(test[j]);
var position = new google.maps.LatLng(latitude[i], longitude[i]);
var marker = new google.maps.Marker({
map:map,
position:position
});
markerArray.push(marker);
i++;
}
var sumLat = 0;
var sumLong = 0;
for (i = 0; i < latitude.length; i++) {
sumLat += latitude[i];
sumLong += longitude[i];
}
var avgLat = sumLat / latitude.length;
var avgLong = sumLong / longitude.length;
center = new google.maps.LatLng(avgLat, avgLong);
map.panTo(center);
var circle;
var contentStr = new Array();
for (i = 0; i < markerArray.length; i++) {
position = markerArray[i].getPosition();
var circOptions = {
strokeColor:"#770000",
strokeOpacity:0.1,
fillColor:"#881111",
fillOpacity:0.4,
map:map,
center:position,
radius:2500000
};
circle = new google.maps.Circle(circOptions);
marker = markerArray[i];
contentStr[i] = '<div id="content">' +
'<b>Spacecraft: </b>' + spaceCraft.toString() + '<br />' +
'<b>Start Time (UTC): </b>' + dateTimes[i].toString() + '<br />' +
'<b>Position: </b>(' + latitude[i].toString() + ', ' + longitude[i].toString() + ')<br />' +
'<b>AU ID: </b>' + auIDs[i] + '<br />' +
'<b>Downlink Station: </b>' + groundstation.toString() + '<br />' +
'</div>';
addListener(map, marker, contentStr[i]);
}
}
}
function addListener(map, marker, content) {
var infowindow = new google.maps.InfoWindow({
content:content
});
google.maps.event.addListener(marker, 'mouseover', function() {
if (mostRecentInfo)
mostRecentInfo.close();
mostRecentInfo = infowindow;
infowindow.open(map, this);
});
}
etc.
It is likely a timing issue with the onload function being called before the initialize function is ready. This is the reason libraries like jQuery have a document.ready function. You can try removing the onload and place a call to initialize() at the bottom of your HTML, just prior to the closing body tag. This will probably work for you.
If you have the option, I'd use a library so you can assure that the function is there and your page is ready. If you haven't tried it, give jQuery a shot.