I have a google maps api function place markers which I'm using from the tutorial found here:Google Maps API with JQuery
By any means, I had to modify the javascript to account for my application. I'm pulling markers from an XML file like before, though this time I'm getting multiple requests, and multiple standard deviation, time to serve, and means for these requests. I've set up the XML to have these with a counter appended to the tag, but it looks like it's not rendering into an array correctly.
To note, I've never used Javascript, and am mostly flying by the seat of my pants on this, so if it's an atrocity of Javascript, feel free to let me know, the entire generation of the XML is in Python.
Sample of the XML: (I apologize, I don't know how to show < or > on stack overflow without it simply hiding it as a tag. Around each "markers" "marker" "name" "requestX" "timetoserveX" etc. is the < and > for tags in XML.
markers
marker
name Simpletown, CA /name
request0 /resource/ /request0
timetoserve0 .001 Seconds to serve request /timetoserve0
mean0 .5309 Mean in seconds /mean0
std_dev0 .552 Standard Deviation in Seconds /std_dev0
request1 /resource2/ /request1
timetoserve1 0.015626 Seconds to serve request /timetoserve1
mean1 0.0011 Mean in seconds /mean1
std_dev1 0.004465 Standard Deviation in Seconds /std_dev1
/marker
/markers
MYMAP.placeMarkers = function(filename) {
$.get(filename, function(xml){
$(xml).find("marker").each(function(){
var name = $(this).find('name').text();
var count = 0;
var requeststring = 'request' + Integer.toString(count)
var request = new Array();
var timetoserve = new Array();
var mean = new Array();
var std_dev = new Array();
var timetoservestring = 'timetoserve' + Integer.toString(count);
var meanstring = 'mean' + Integer.toString(count);
var std_devstring = 'std_dev' + Integer.toString(count);
while ($(this).find(requeststring).text()){
timetoservestring = 'timetoserve' + Integer.toString(count);
meanstring = 'mean' + Integer.toString(count);
std_devstring = 'std_dev' + Integer.toString(count);
request[count] = $(this).find(requeststring).text();
timetoserve[count] = $(this).find(timetoservestring).text();
mean[count] = $(this).find(meanstring).text();
std_dev[count] = $(this).find(std_devstring).text();
count++;
requeststring = 'request' + Integer.toString(count)
}
// create a new LatLng point for the marker
var lat = $(this).find('lat').text();
var lng = $(this).find('lng').text();
var point = new google.maps.LatLng(parseFloat(lat),parseFloat(lng));
// extend the bounds to include the new point
MYMAP.bounds.extend(point);
var marker = new google.maps.Marker({
position: point,
map: MYMAP.map
});
var infoWindow = new google.maps.InfoWindow();
var html = ""
for (i=0;i<count;i++){
html=html+'<strong>'+name+'</strong.><br />'+request[i]+'<br />'+timetoserve[i]+'<br />'+mean[i]+'<br />'+std_dev[i]+<br />;
//var html='<strong>'+name+'</strong.><br />'+request+'</strong.><br />'+timetoserve+'</strong.><br />'+mean+'</strong.><br />'+std_dev;
}
google.maps.event.addListener(marker, 'click', function() {
infoWindow.setContent(html);
infoWindow.open(MYMAP.map, marker);
});
MYMAP.map.fitBounds(MYMAP.bounds);
});
});
}
With the updates, it's not longer having the array issues it looks like, even though I am getting the map to render at this point. The "Show Markers" button is not populating the map with markers. Running FireBug with this seems to only spew endless amounts of "Break on error" hits and warnings for jQuery.
var request[count] = $(this).find(requeststring).text();
var timetoserve[count] = $(this).find(timetoservestring).text();
var mean[count] = $(this).find(meanstring).text();
var std_dev[count] = $(this).find(std_devstring).text();
to
request[count] = $(this).find(requeststring).text();
timetoserve[count] = $(this).find(timetoservestring).text();
mean[count] = $(this).find(meanstring).text();
std_dev[count] = $(this).find(std_devstring).text();
-assuming these are the arrays that are not working correctly for you.
If I may make a suggestion (RE your comment this morning):
while ($(this).find(requeststring).text()){
//...omitted
}
if you were to rename all your tags to the same thing and give them an id attribute (which is valid in xml) you can do this:
var requests = $(this).find('request');
var timetoserves = $(this).find('timetoserve');
// etc...
for (var i=0; i<requests.length; i++) {
request[i] = requests.eq(i).text();
timetoserve[count] = timetoserves.eq(i).text();
//etc...
}
which would probably provide better performance.
Related
I am trying to get the distance between two locations in google using google Maps direction API through the script.
However, following YouTube video and researching on my own in google API documentation.
I am not able to resolve errors in my following code.
Error
"Cannot read property 'legs' of undefined"
function GT() {
var app = SpreadsheetApp;
var ss1 = app.getActiveSpreadsheet();
var mapsheet = ss1.getActiveSheet();
var start = mapsheet.getRange('B1').getValue;
var end = mapsheet.getRange('B2').getValue();
var directions = Maps.newDirectionFinder()
.setOrigin(start)
.setDestination(end)
.setMode(Maps.DirectionFinder.Mode.DRIVING)
.getDirections();
var routes = directions.routes[0]
mapsheet.getRange('A6:D10').clear();
var nextrow = mapsheet.getLastRow() +1 ;
const ro = directions.routes[0];
for (var i = 0; i < 2; i++)
{
var ea = ro.legs[1].end_address;
var sa = ro.legs[1].start_address;
var distance = ro.legs[1].distance.text;
var duration = ro.legs[1].duration.text;
mapsheet.getRange(nextrow,1).setValue(sa);
mapsheet.getRange(nextrow,1).setValue(ea);
mapsheet.getRange(nextrow,1).setValue(distance);
mapsheet.getRange(nextrow,1).setValue(duration);
}
Issue:
You forgot the () when retrieving the value for start:
var start = mapsheet.getRange('B1').getValue;
Therefore, your are retrieving the method getValue(), and not the cell value.
Because of this, ro is undefined (the origin has to be a string corresponding to an address) and, therefore, you cannot retrieve its legs property.
Solution:
Add the () for getValue():
var start = mapsheet.getRange('B1').getValue();
This should fix your issue, assuming that cells B1 and B2 contain proper addresses.
i have a little problem, need seperates two values from a LngLat Mapbox object. Im creating a marker on double click in the map. Works fine. The problem is that i need to store the value of longtitude and latitude in my database. And i have a problem with getting this values from lnglat object. I was looking in mapbox doc, but there is no any method for that object that could help. Is there any solution for this?
map.on('dblclick', (e) => {
const popupForm = document.querySelector('#marker-popup-form');
const popupText = popupForm['marker-infoo'].value;
// create the popup
var popup = new mapboxgl.Popup().setText(popupText);
popupForm.reset();
// create DOM element for the marker
var el = document.createElement('div');
el.id = 'marker';
// create the marker
new mapboxgl.Marker(el)
.setLngLat(e.lngLat)
.setPopup(popup)
.addTo(map);});
Ok, i found a solution by making and array and then extract the value
// Here array.values() function is called.
var iterator = el.values();
// All the elements of the array the array
// is being printed.
var myLng = iterator.next().value;
var myLat = iterator.next().value;
console.log('Lng = ' + myLng);
console.log('Lat = ' + myLat);
});
Console looks like this:
Lng = 18.263916015625682
Lat = 50.436719121999545
I'm writing a code that will plot multiple locations on a map using google's api. The coordinates, name and MMSI number is stored on an XML file and is imported in a javascript.
This is the part of code I'm talking about:
for(i=0; i<x; i++)
{
var locations = [
['MMSI', 50.26835, 50.45563, 1],
['MMSI', 50.29435, 50.44523, 2],
['MMSI', 50.09399, 50.40548, 3]
}
What I would like to do is add i to the end of 'MMSI' and turn it into a variable which is predefined above.
So what is written above the first code is:
var MMSI1 = 163474;
var MMSI2 = 209483;
var MMSI3 = 705245;
etc, etc...
and need the map markers to display those numbers instead of simply MMSI.
But I don't know how to achieve this as the program won't run every time I try it and google's api will only work with quotes, not variables.
I'm pretty sure there is a simple answer to this question and I am sorry for having to ask such a stupid question but I can't seem to find an answer anywhere or figure it out on my own.
Thanks in advance for any help.
Also I'm sorry if I used any terms wrong I'm still learning this language and I don't always know if I'm saying things correctly.
Ok this seems to work, I removed your ajax call to load the XML and pasted the XML in the fiddle itself. Also, I'm not an XML guru so there might be an easier method for the first part.
http://jsfiddle.net/gt8vK/4/
var x= "<Vessels><Ship><MMSI>431000527</MMSI><CALLSIGN>SLBM</CALLSIGN><LATITUDE>35.4150</LATITUDE><LONGITUDE>139.725</LONGITUDE><DESTINATION>JP SGM</DESTINATION></Ship><Ship><MMSI>244660180</MMSI><CALLSIGN>PD8027</CALLSIGN><LATITUDE>52.4066</LATITUDE><LONGITUDE>4.82345</LONGITUDE><DESTINATION>lalallal</DESTINATION></Ship></Vessels>";
var xmlDoc = new DOMParser().parseFromString(x,'text/xml');
var allShips = xmlDoc.getElementsByTagName("Ship");
console.log(xmlDoc.getElementsByTagName("Ship")[0].getElementsByTagName("MMSI")[0].childNodes[0].text)
var ships = [];
for (var i = 0, l = allShips.length; i < l; i++) {
ships.push({
name: 'MMSI' + (i + 1).toString(),
originalName: allShips[i].getElementsByTagName("MMSI")[0].childNodes[0].nodeValue,
latitude: allShips[i].getElementsByTagName("LATITUDE")[0].childNodes[0].nodeValue,
longitude: allShips[i].getElementsByTagName("LONGITUDE")[0].childNodes[0].nodeValue
})
}
var map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 2 ,
center: new google.maps.LatLng(0, 0),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var infowindow = new google.maps.InfoWindow();
var marker, i;
for (i = 0; i < ships.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(ships[i].latitude, ships[i].longitude),
map: map
});
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(ships[i].name);
infowindow.open(map, marker);
}
})(marker, i));
}
Basically I placed all the ships in an object, instead of creating a new variable for each one, this will keep everything cleaner and you can still access each one of them, just use ships['number'] instead of shipNumber.
I've got a 3 pane google map integration in our VB.net software. For the most part it works brilliantly. Today I'm trying to get these 3 seperate objects to paint different polygons depending on the lat/lngs they're sent for each day.
First map control works all of the time. 2nd and 3rd however are being troublesome. I've attempted to screenshot what's going on.
As you can see, the polys are being drawn, but for some reason an entirely new map is being drawn on top of my original. Obviously this isn't right. I've got code all over the place too:
Here's the JS initialize that is called upon DocumentComplete firing:
function Initialize(zoomLevel,lat,lng,type, bCanEdit, bCanDrag){
//Get the type of map to start.
//Need to convert the GoogleMapType enum
//to an actual Google Map Type
var MapType;
switch (type)
{
case 1:
MapType = google.maps.MapTypeId.ROADMAP;
break;
case 2:
MapType = google.maps.MapTypeId.TERRAIN;
break;
case 3:
MapType = google.maps.MapTypeId.HYBRID;
break;
case 4:
MapType = google.maps.MapTypeId.SATELLITE;
break;
default:
MapType = google.maps.MapTypeId.ROADMAP;
};
//Create an instance of the map with the lat, lng, zoom, and
//type passed in
myLatlng = new google.maps.LatLng(lat,lng);
var myOptions = {zoom: zoomLevel,center: myLatlng,mapTypeId: MapType};
var MarkerSize = new google.maps.Size(48,48);
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
google.maps.event.addListener(map, 'click', Map_Click);
google.maps.event.addListener(map, 'mousemove', Map_MouseMove);
google.maps.event.addListener(map, 'idle',Map_Idle);
overlayLayer = new Array();
overlayCount = 0;
driverRouteLayers = new Array();
driverRouteCount = 0;
canEdit = bCanEdit;
canDrag = bCanDrag;
}
The VB.net that invokes the script to draw the overlay areas:
Public Sub DrawAreaOverlays(ByVal area As DeliveryArea)
Dim gc As New GComArray()
For Each p As DeliveryAreaPoint In area.Points
Dim ll As New GLatLong(p.Latitude, p.Longitude)
gc.Add(ll)
Next
WebBrowser1.Document.InvokeScript("DrawAreaOverlay", {gc, Utility.Pens.GetHexColor(area.Colour)})
End Sub
And the initial DocumentComplete hook-in in vb.net:
Private Sub WebBrowser1_DocumentCompleted(ByVal sender As Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs)
'Initialize the google map with the initial settings.
'The Initialize script function takes four parameters.
'zoom, lat, lng, maptype. Call the script passing the
'parameters in.
WebBrowser1.Document.InvokeScript("Initialize", New Object() {InitialZoom, InitialLatitude, InitialLongitude, CInt(InitialMapType),
allowEditing, allowDragging})
RaiseEvent PopulateInitialRoutes()
End Sub
These are the only methods that are called to start with, the rest are just hooks into the javascript methods to display various things, but nothing is called (like this) prior to this point. And on this specific form, I'm only displaying, not allowing end-users to manipulate the data in any way.
The DrawAreaOverlay method (JS) is responsible for the poly drawing (please excuse the state of the code, I've been ripping it apart trying to figure this out!):
function DrawAreaOverlay(area, col)
{
if(area.Count <= 0)
{
CreateNewArea(0, 0);
return;
}
var coordsString = "";
var areaCoords = [];
overlayLayer[overlayCount] = new Array();
for(var j=0; j<area.Count; j++)
{
areaCoords.push(new google.maps.LatLng(area.Item(j).lat, area.Item(j).lng));
}
var poly = new google.maps.Polygon({
paths: areaCoords,
strokeColor: '#'+col,
strokOpacity: 0.35,
strokeWeight: 2,
fillColor: '#'+col,
fillOpacity: 0.25,
geodesic: false,
editable: canEdit,
draggable: canDrag,
map: map
});
poly.getPaths().forEach(function(path, index){
google.maps.event.addListener(path, 'set_at', function(){
var arrayOfPoints = new Array();
arrayOfPoints = poly.getPath();
coordsString = "";
for(var i=0; i<arrayOfPoints.length; i++)
{
coordsString += poly.getPath().getAt(i).lat() + ", " + poly.getPath().getAt(i).lng() + "|";
}
window.external.AreaPointMoved(coordsString.substring(0, coordsString.length -1));
});
});
// INSERTION OF NEW VERTICES ALONG THE POLYGON EDGES //
poly.getPaths().forEach(function(path, index){
google.maps.event.addListener(path, 'insert_at', function(){
var arrayOfPoints = new Array();
arrayOfPoints = poly.getPath();
coordsString = "";
for(var i=0; i<arrayOfPoints.length; i++)
{
coordsString += poly.getPath().getAt(i).lat() + ", " + poly.getPath().getAt(i).lng() + "|";
}
window.external.AreaPointMoved(coordsString.substring(0, coordsString.length -1));
});
});
debugger;
//if(map == null)
//{
// makeMeANotNullMap(zoomLevel, latitude, longitude);
// overlayLayer[overlayCount] = new Array();
//}
poly.setMap(map);
overlayLayer[overlayCount].push(poly);
overlayCount++;
//alert("I'll work now, but why?");
//window.external.DoNothing();
}
Now the REALLY weird part. If I uncomment the alert box in JS (the: I'll work now, but why? alert) each map renders wonderfully. So something clearly happens to the map once the alert box has been dismissed. It's this missing link I'm after. But I can't fathom it.
Without the alert box, interestingly, the 2nd and 3rd initialisations of the map controls, map is sometimes null. I know this, because I've setup VS to debug the script. So you can drag each one (vigorously) and get the attached image above outcome, where the poly has drawn, but you can't see it.
Any help is greatly appreciated. I don't have a clue why this is happening.
Today I am trying to make a store locator using google maps' api.
The store locator is to be set up like so:
two areas, one with a map containing all the stores in a given area (measured in a selectable radius from a center point), and one area with a list of all the stores on the map, their information, and of course a link to their website. When a person clicks on the name of the store on the store list, it centers upon the store in the map, and opens an infoWindow above the store marker.
I have a javascript variable to which I have taken pains to assign some json data from a php script (which is selecting this data on the fly from a database)
locations = [{"siteurl":"http:\/\/localhost.localdomain\/5","address":"260 Test St","city":"Brooklyn","state":"New York","zip_code":"11206"},{"siteurl":"http:\/\/localhost.localdomain\/4","address":"3709 Testing St.","city":"Austin","state":"Texas","zip_code":"78705"}];
Now, I know there are 5 different functions I need to run, listed below with their apparent use:
geocoder.getLocations : Used to
convert address data (from the json
object) into latitude and longitude
data object
addElementToList :
Used to add address information to
the list of stores, and bind the
centerOnStore function to onclick
centerOnStore when a store list item is clicked in the list area, this function center's upon the store that has been clicked on in the map area. This function also opens an infoWindow above the centered upon store.
placeMarker the function to place a marker on the map, called once the geocoder returns latitudeLongitude objects
eventListener this is tied up somehow in the clicking of a list item and it's further centering the map upon the store in question
Well, i am out of my league it would appear. I am just now learning about javascript closures, and I think these may be necessary, but I can't quite understand them. I need to figure out some way to get all these functions into a working order, passing information back and forth to each other, and create a store locator
.
Here is what I've got so far, but there is something very wrong with it.
var map = null;
var geocoder = null;
var locations = null;
var center_on = null;
var zoom_level = null;
var markerList = [];
function initialize()
{
if(GBrowserIsCompatible())
{
// Assign vars
map = new GMap2(document.getElementById("map_canvas"));
geocoder = new GClientGeocoder();
locations = <?php echo(json_encode($my_vars['locations'])); ?>;
center_on = "<?php echo($my_vars['center_on']); ?>";
zoom_level = <?php echo($my_vars['zoom_level']); ?>;
var currentLocation = 0;
geocoder.getLatLng(center_on, function(myPoint)
{
map.setCenter(myPoint, zoom_level);
});
map.setUIToDefault();
var list = document.getElementById('center_list');
for(var i = 0; i < locations.length; i++)
{
var address = locations[i]['address'] + ', ' + locations[i]['city'] + ' ' + locations[i]['state'] + ', ' + locations[i]['zip_code'];
geocoder.getLocations(address, addAddressToMap);
}
}
function addAddressToMap(response) {
if (!response || response.Status.code != 200) {
currentLocation++;
} else {
var place = response.Placemark[0];
var point = new GLatLng(place.Point.coordinates[1],
place.Point.coordinates[0]);
marker = new GMarker(point);
GEvent.addListener(marker, 'click', function(){
this.openInfoWindowHtml("<strong>" + place.address + "</strong><br /><a href='" + locations[currentLocation]['siteurl'] + "'>" + locations[currentLocation]['siteurl'] + "</a>");
});
map.setCenter(point, 13);
markerList.push(marker);
map.addOverlay(marker);
li = document.createElement('li');
li.innerHTML = "<strong>" + place.address + "</strong>";
li.setAttribute('onclick', 'center_on_center(' + place.Point.coordinates[1] + ',' + place.Point.coordinates[0] + ')');
li.setAttribute('id', 'center_');
li.style.fontSize = '1.4em';
document.getElementById('center_list').appendChild(li);
// alert(currentLocation) here says 0,0,0,0
currentLocation++;
// alert(currentLocation) here says 1,2,3,4
}
}
}
I am sorry for the wall of code. I can't think anymore. I had no idea this would be so difficult. No idea at all.
if I alert currentLocation in the line before I increment it, it's always 0. but If I alert it in the line after I increment it, it's '1,2,3,4' etc. This goes against everything I know about computers.
Forget about closures for a moment. You can dive into those once you get a working app. I think you're goal at this point to should be to just get something that accomplishes what you want.
To me, it seems like the only piece you're missing is the idea of a callback function. For instance, addElementToList would be passed as the callback argument to geocoder.getLocaitons. The way it works is that when getLocations() finishes, it calls addElementToList and supplies the result from getLocations() as an argument to addElementToList. The code for addElementToList will then add your store location to the map as a marker and add a new element to your html list with the store's name or address or whatever.
Take a look at this blog post for a simple example using a callback: Introducing Google's Geocoding Service.
The last part, centering on a specific store, can be done (as you suggested) with event listeners. You can set up a listener for clicks on the markers and also for clicks on your list. When you add a marker, you can also add an event listener on it. It'd be nice if you could set one listener for all markers on the map but I'm not familiar enough with google's API to know if this is possible.
What is your source for that information? placeMarker certainly doesn't ring a bell. The Google Maps API reference (complete with examples!) is available at http://code.google.com/apis/maps/documentation/reference.html
Based on your comment to #Rushyo's answer- it seems like you know enough about Javascript and the Google Maps API to construct those functions. I'm a little confused as to what you're looking for.
I would suggest however, that you add lat/lon coordinates to your database in the first place. You shouldn't have to geocode the addresses every time the map is loaded.
Update: In response to your comment below, here is the code you referenced - along with the addAddressToMap() function called by the Geocoder. It creates a marker for each address and adds it to the array markerList. You can then access the markers in that array later, since we initialized it outside the scope of the addAddressToMap() function.
for(var i = 0; i < locations.length; i++) {
var address = locations[i]['address'] + ', ' + locations[i]['city'] + ' ' + locations[i]['state'] + ', ' + locations[i]['zip_code'];
geocoder.getLocations(address, addAddressToMap);
}
var markerList = new array();
function addAddressToMap(response) {
if (!response || response.Status.code != 200) {
alert("\"" + address + "\" not found");
} else {
place = response.Placemark[0];
point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
marker = new GMarker(point);
markerList.push(marker);
map.addOverlay(marker);
}
}
Update 2: In response to the code you posted in your question above, you're probably getting random numbers in currentLocation because of the asynchronous nature of the Geocoder. Remember that your getLocations() function will send requests for every location in the array before it gets any responses back.
I'm creating a new answer, since my other answer is getting messy.
In order to get proper closure, you'll need to create a separate function to make the geocoder request. The following code will allow you to assign the desired infoWindow text to each marker.
for(var i = 0; i < locations.length; i++) {
var address = locations[i]['address'] + ', ' + locations[i]['city'] + ' ' + locations[i]['state'] + ', ' + locations[i]['zip_code'];
var text = locations[i]['address']; // or whatever you want the text to be
getLocation(address, text);
}
...
function getLocation(address, text) {
geocoder.getLocations(address, function(response) {
var place = response.Placemark[0];
var point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
marker = new GMarker(point);
marker.bindInfoWindowHtml(text); // note that if you want to use GEvent.addListener() instead - you'll need to create another function to get proper closure
map.addOverlay(marker);
});
}
For more info on closure in Google maps, see these questions:
One
Two
Three