I have been playing with Google maps I had it working but when I tried to change the Icons to Blue I lost some of the information in my pop up windows.
The first windows that opens is all correct but the second click on windows opens but the only thing the is correct is the point information the Lat & Lng if I remove the couston Icon back to the default it all works. i found the information on a site and tried to copy it into my script. I am just learning javascript and I am not sure where I when wrong.
The datetime alt speed and course are all ok on the frist window but fail on the click on window, the icons are now blue, if I remove the customIcons[call] from the statement var marker = createMarker(point,customIcons[call]); and replace it with datetime is seems to work. I thank all for having a look if there is anything that you think may help please advise.
My Script.....
function load() {
if (GBrowserIsCompatible()) {
// Get map (Version 2)
var map = new GMap2(document.getElementById("map"));
map.setUIToDefault();
// Default user interface
var icon = new GIcon();
icon.image = 'http://labs.google.com/ridefinder/images/mm_20_blue.png';
icon.shadow = 'http://labs.google.com/ridefinder/images/mm_20_shadow.png';
icon.iconSize = new GSize(12, 20);
icon.shadowSize = new GSize(22, 20);
icon.iconAnchor = new GPoint(6, 20);
icon.infoWindowAnchor = new GPoint(5, 1);
var customIcons = [];
customIcons["VE9SC-9"] = icon;
// Get course
GDownloadUrl("http://guardian.no-ip.org/track/phpsqlajax_genxml_track_25.php",
function(data) {
var xml = GXml.parse(data);
var markers =
xml.documentElement.getElementsByTagName("marker");
var points = new Array(0);
// For polyline
// Loop through the markers
for (var i = 0; i < markers.length; i++) {
var datetime = markers[i].getAttribute("datetime");
var speed = markers[i].getAttribute("speed");
var course = markers[i].getAttribute("course");
var alt = markers[i].getAttribute("alt");
var call = markers[i].getAttribute("call");
var point =
new GLatLng(parseFloat(markers[i].getAttribute("lat")),
parseFloat(markers[i].getAttribute("lng")));
points[i] =
new GLatLng(parseFloat(markers[i].getAttribute("lat")),
parseFloat(markers[i].getAttribute("lng")));
var marker = createMarker(point, customIcons[call]);
map.addOverlay(marker);
}
// End loop
// Polyline
var polyline = new GPolyline(points, "#0066cc", 2);
map.addOverlay(polyline);
// Set map centre (to last point), zoom level
map.setCenter(point, 13);
// InfoWindow HTML (last marker)
var html = "";
html += "<div id=\"infobox\">";
html += "VE9SC-9";
html += "<br />This is my last position on";
html += "<br />" + datetime;
html += " UTC";
html += "<br />" + point;
html += "<br />Aluitude ";
html += +alt;
html += " Feet ";
html += "<br />" + speed;
html += " MPH Last Recorded Speed";
html += "<br />" + course;
html += " deg Last Recorded Course";
html += "<br />ve9sc#rogers.com";
html += "<br />ve9sc.no-ip.org</div>";
html += "<br />Updated Via MySql PHP.";
html += "</div>";
map.openInfoWindowHtml(point, html);
});
}
}
// General markers
function createMarker(point, datetime) {
var marker = new GMarker(point, datetime);
var html = "";
html += "<div id=\"infobox\">";
html += "VE9SC-9";
html += "<br />This is my position on";
html += "<br />" + datetime;
html += " UTC";
html += "<br />" + point;
html += "<br />Aluitude ";
html += +alt;
html += " Feet ";
html += "<br />" + speed;
html += " MPH Last Recorded Speed";
html += "<br />" + course;
html += " deg Last Recorded Course";
html += "<br />ve9sc#rogers.com";
html += "<br />ve9sc.no-ip.org</div>";
html += "<br />Updated Via MySql PHP.";
html += "</div>";
GEvent.addListener(marker, 'click',
function() {
marker.openInfoWindowHtml(html);
});
return marker;
}
It looks like you are using V2 of Google Map API (which kind of old). In this version the 2nd argument that you try to pass to GMarker should be an GMarkerOptions not an GIcon (assume API Version 2.5+)
From your code I think you are trying to pass GIcon object from customIcons[] in which is incorrect. I think you should inspect the datetime object here to make sure it's an GmarkerOptions not GIcon
var marker = new GMarker(point, datetime);
http://code.google.com/apis/maps/documentation/javascript/v2/reference.html#GMarker
Related
I have written a script which has a trigger to run every hour, it searches my emails and extracts the data, turns it to a PDF and locates it in a folder if the subject equals "xxxx", it overwrites data in the folder if it already exists.. I would like to add in a new if function where it will only pick up emails for the current day and not history (to save efficiency of the script and data)
function saveGmailAsPDF2() {
var gmailLabels = 'xxxxx';
var driveFolder = DriveApp.getFolderById("folder url");
var threads = GmailApp.search("subject:" + gmailLabels,0,20);
if (threads.length > 0) {
/* Google Drive folder where the Files would be saved */
var folders = DriveApp.getFoldersByName(driveFolder);
var folder = folders.hasNext() ?
folders.next() : DriveApp.createFolder(driveFolder);
/* Gmail Label that contains the queue */
var label = GmailApp.getUserLabelByName(gmailLabels) ?
GmailApp.getUserLabelByName(gmailLabels) : GmailApp.createLabel(driveFolder);
for (var t=0; t<threads.length; t++) {
threads[t].removeLabel(label);
var msgs = threads[t].getMessages();
var html = "";
var subject = threads[t].getFirstMessageSubject();
var previousdoc = driveFolder.getFilesByName(subject + ".pdf"); //gets name of csv, if exists in drive then move to trash before creating new file
if (previousdoc.hasNext()) {
previousdoc.next().setTrashed(true);}
/* Append all the threads in a message in an HTML document */
for (var m=0; m<msgs.length; m++) {
var msg = msgs[m];
html += "From: " + msg.getFrom() + "<br />";
html += "To: " + msg.getTo() + "<br />";
html += "Date: " + msg.getDate() + "<br />";
html += "Subject: " + msg.getSubject() + "<br />";
html += "<hr />";
html += msg.getBody().replace(/<img[^>]*>/g,"");
html += "<hr />";}
/* Convert the Email Thread into a PDF File */
var tempFile = DriveApp.createFile("temp.html", html, "text/html");
folder.createFile(tempFile.getAs("application/pdf")).setName(subject + ".pdf");
tempFile.setTrashed(true);}}}
Explanation:
There is a function getLastMessageDate() that gives the date of a thread's most recent message. You can compare that against the date of today and if they match execute the rest of the code.
Since you use a for loop: for (var t=0; t<threads.length; t++)
I think the condition if (threads.length > 0) is redundant because for loop won't run anyway if threads.length equals 0.
Because of the latter, I transferred the folder creation part of your code into the loop itself and execute it only when the last day of the thread is equal to today. But I leave this part for you to decide.
I can't test your code but this should work:
function saveGmailAsPDF2() {
var gmailLabels = 'xxxxx';
var driveFolder = DriveApp.getFolderById("folder url");
var threads = GmailApp.search("subject:" + gmailLabels,0,20);
// new code
const today = new Date();
const ss = SpreadsheetApp.getActive();
const timezone = ss.getSpreadsheetTimeZone();
const today_dt = Utilities.formatDate(today, timezone, 'yyyy-MM-dd');
///////////
for (var t=0; t<threads.length; t++) {
// new code
var lastMessageDate = threads[t].getLastMessageDate();
var thread_dt = Utilities.formatDate(lastMessageDate, timezone, 'yyyy-MM-dd');
if(today_dt==thread_dt){
///////////
/* Google Drive folder where the Files would be saved */
var folders = DriveApp.getFoldersByName(driveFolder);
var folder = folders.hasNext() ?
folders.next() : DriveApp.createFolder(driveFolder);
/* Gmail Label that contains the queue */
var label = GmailApp.getUserLabelByName(gmailLabels) ?
GmailApp.getUserLabelByName(gmailLabels) : GmailApp.createLabel(driveFolder);
threads[t].removeLabel(label);
var msgs = threads[t].getMessages();
var html = "";
var subject = threads[t].getFirstMessageSubject();
var previousdoc = driveFolder.getFilesByName(subject + ".pdf"); //gets name of csv, if exists in drive then move to trash before creating new file
if (previousdoc.hasNext()) {
previousdoc.next().setTrashed(true);}
/* Append all the threads in a message in an HTML document */
for (var m=0; m<msgs.length; m++) {
var msg = msgs[m];
html += "From: " + msg.getFrom() + "<br />";
html += "To: " + msg.getTo() + "<br />";
html += "Date: " + msg.getDate() + "<br />";
html += "Subject: " + msg.getSubject() + "<br />";
html += "<hr />";
html += msg.getBody().replace(/<img[^>]*>/g,"");
html += "<hr />";}
/* Convert the Email Thread into a PDF File */
var tempFile = DriveApp.createFile("temp.html", html, "text/html");
folder.createFile(tempFile.getAs("application/pdf")).setName(subject + ".pdf");
tempFile.setTrashed(true);}}}
Working with the Google maps and places API, I am rendering infowindows for each marker that gets generated by a function generateInfoWindow(location).
In there I create a string HTML that will be passed to the Google maps markers content attribute.
Function
function generateInfoWindow(location) {
var html = "<div class = 'infowindowContainer'>" +
"<span class = 'infoWindowHeader'>" + location.name + "</span>" +
"<div class = 'row'>" +
"<span class = 'col-xs-12'> ... : " + getInfoWindowDetails(location).adress + "</span>" +
"<span class = 'col-xs-12'> ... : " + getInfoWindowDetails(location).open_hours + "</span>";
if (location.offers.length > 0) {
html +=
"<span class = 'col-xs-12 iwOffers'> ... </span>" +
"</div>" + //ends row
"<div class = 'infoWindowCircleContainer'>";
for (var i = 0; i < location.offers.length; i++) {
html += "<span class = 'infoWindowCircle'>" + location.offers[i].offer_text + "</span>";
}
html += "</div>" //CircleContainer
}
html += "<span class = 'showMore' onclick = 'processWin(" + location + ")'>Show more</span>";
html += "</div>"; //InfoWindowContainer the parent to all
return html;
}
function processWin(location) {
var winMarker;
var winnerMap;
var mapOptions = {
zoom: 15,
center: location.geometry.location,
mapTypeId: google.maps.MapTypeId.ROADMAP,
styles: googleMapsStyles
};
var locationId = location.place_id;
var request = {
placeId: locationId
};
places.getDetails(request, getWinnerDetails); //Where getWinnerDetails is the callback
//since the location that we are passing in the callback function is the one we get as a JSON from the detailed search we are going to have to use our modified vars associated with the location here such as .keyword
$("#foodType").text("Typ av mat : " + location.keyword);
winnerMap = new google.maps.Map(document.getElementById('displayWinnerMap'), mapOptions);
for (var i = 0; i < markers.length; i++) {
if (markers[i].placeId == location.place_id) {
winMarker = markers[i];
break;
}
}
//setOfferCircles(location);
winMarker.setMap(winnerMap);
$("#displayWinPage").css("display", "block");
doScroll("#displayWinPage");
}
Where I append the span with the class showMore I wish to append an onclick event that will call a method processWin(location) where I pass the location variable. (Will be multiple markers).
I can't seem to be able to pass the object location in the onclick event and
I don't understand why. Please do enlighten me.
An object converted to a string becomes [object object] and that is what you are passing as the parameter and not the object itself. Here is example code showing the wrong output
var location = {x : 100, y : 100};
var html = "<span class = 'showMore' onclick = 'processWin(" + location + ")'>Show more</span>";
console.log(html);
Output: <span class = 'showMore' onclick = 'processWin([object Object])'>Show more</span>
Using JSON.stringify(location) you get the object output correctly as shown below.
var location = {x : 100, y : 100};
var html = "<span class = 'showMore' onclick = 'processWin(" + JSON.stringify(location) + ")'>Show more</span>";
console.log(html);
Output:<span class = 'showMore' onclick = 'processWin({"x":100,"y":100})'>Show more</span>
Basically I am trying to zoom to certain route segment when getting direction on OneMap. Here is the JavaScript codes where I trying to plot a route and zoom to certain route segment:
function getDirections() {
var routeData = new Route;
var from = document.getElementById('txtFrom').value
var to = document.getElementById('txtTo').value
//Draw out the line from the cordinate to another cordinate
routeData.routeStops = from + ";" + to;
//What type of mode will it do
routeData.routeMode = "DRIVE";
//can draw out untill the following coordiante
routeData.barriers = '36908.388637,35897.420831';
{
if (document.getElementById('CbAvoid').checked) {
routeData.avoidERP = "1";
}
else
routeData.avoidERP = "0";
}
routeData.GetRoute(showRouteData)
}
function showRouteData(routeResults) {
if (routeResults.results == "No results") {
alert("No Route found, please try other location.")
return
}
$('#divComputedDirection').show();
directions = routeResults.results.directions[0];
directionFeatures = directions.features;
var routeSymbol = new esri.symbol.SimpleLineSymbol().setColor(new dojo.Color([0, 0, 255, 0.5])).setWidth(4);
var mergedGeometry = new esri.geometry.Polyline()
mergedGeometry.addPath(routeResults.results.routes.features[0].geometry.paths[0])
OneMap.map.graphics.add(new esri.Graphic(mergedGeometry, routeSymbol));
//Display the total time and distance of the route
var htmlStr = "";
htmlStr += "<img class='close-image' onclick='closeDirectionResultDIV();' alt='close' src='img/closeDirectionResult.png' />";
htmlStr += "<span style='font-weight:bold;'><br /> Total distance: " + Math.round(directions.summary.totalLength) + "km" + "<br /> Total time: " + Math.round(directions.summary.totalTime) + "mins <br/></span>";
document.getElementById("divComputedDirection").innerHTML = htmlStr;
//List the directions and create hyperlinks for each route segment
for (var i = 0; i < directions.features.length; i++) {
var feature = directions.features[i]
document.getElementById("divComputedDirection").innerHTML += '<br>' + parseInt(parseInt(i) + 1) + ". " + feature.attributes.text + " (" + formatDistance(feature.attributes.length, "miles") + ", " + formatTime(feature.attributes.time) + ") " + '';
}
}
//Zoom to the appropriate segment when the user clicks a hyperlink in the directions list
function zoomToSegment(index) {
var segment = directionFeatures[index];
map.setExtent(segment.geometry.getExtent(), true);
if (!segmentGraphic) {
segmentGraphic = map.graphics.add(new esri.Graphic(segment.geometry, segmentSymbol));
}
else {
segmentGraphic.setGeometry(segment.geometry);
}
}
It did plot the route and show all the directions. But when I click on certain direction and zoom to segement, it throws me an error message which is Uncaught TypeError: Cannot call method 'getExtent' of undefined.
I wonder why is it so. Thanks in advance.
The root cause of your error is that you're trying to get the extent of a .geometry property that doesn't exist - that part is relatively easy. The problem, I think, is that you're looking for the geometry of each segment of the journey, and the return from OneMap's RouteTask doesn't give you that directly.
The geometry from the entire route is in
routeResults.results.routes.features[0].geometry.paths[0]
and the individual segments are in one of ESRI's fun compressed formats in the value:
routeResults.results.directions[x].features[y].compressedGeometry
There's some documentation and C# code for this compressed format here:
http://resources.esri.com/help/9.3/arcgisengine/ArcObjects/esrinetworkanalyst/INACompactStreetDirection_CompressedGeometry.htm
It should be relatively easy to port that C# code to JS if you really need the geometry of individual segments.
OneMap have a full working example here which shows how to process the results from the RouteTask, but unfortunately they don't attempt to extract the compressedGeometry field.
Edit: More sample code from ESRI here, with examples in C#/Java/Python.
I have a dropdown menu that I want to put inside a google maps infowindow. The menu is populated with contents from an array. When I position the menu outside the info window it works fine but when I try and put it inside the infowindow it breaks. The end goal is to get a form inside the info window so when I submit the form I can process the form data and return the directions to the marker. I have attached the code below and the problematic line is denoted by ** and thanks in advance for all your help.
Infowindow code:
google.maps.event.addListener(marker, 'click', function () {
service.getDetails(request, function (place, status) {
var locationofplace = place.geometry.location;
var markerlocation = marker.getPosition();
var markerlat = markerlocation.lat();
var markerlng = markerlocation.lng();
if (status == google.maps.places.PlacesServiceStatus.OK) {
var contentStr = '<h5>' + place.name + '</h5><p>' + place.formatted_address;
if (!!place.formatted_phone_number) contentStr += '<br>' + place.formatted_phone_number;
if (!!place.website) contentStr += '<br><a target="_blank" href="' + place.website + '">' + place.website + '</a>'; * * contentStr += '<form><select id="selectNumber"><option>Change Address</option></select></form>'; * *
contentStr += '<br>Get Directions';
contentStr += '<br>' + place.types + '</p>';
infowindow.setContent(contentStr);
infowindow.open(map, marker);
} else {
var contentStr = "<h5>No Result, status=" + status + "</h5>";
infowindow.setContent(contentStr);
infowindow.open(map, marker);
}
});
});
add data to menu code:
window.addEvent('load', function () {
var select = document.getElementById("selectNumber");
for (var i = 0; i < addresses.length; i++) {
var opt = addresses[i];
var el = document.createElement("option");
el.textContent = opt;
el.value = opt;
select.appendChild(el);
}
});
use the domready-event of the infowindow instead of the load-event of the window to manipulate the dropdown(the dropdown hasn't been injected into the document before the domready-event)
I'm working on a dynamic mapping application that receives a series of data as JSON and then converts the data to a map point with a pop up in Leaflet.
The JSON data looks like this:
{
"unit":"90",
"latitude":36.120915,
"longitude":-97.0633733,
"velocity":0.022,
"heading":102.9,
"timestamp":"Wed, 23 Nov 2011 20:00:28 GMT"
}
I have a listener setup to receive this data from a push server which calls the below function to draw the unit's location on the map.
function drawUnit(unit)
{
//removeUnitMarkers();
var popupContent = "<h3>" + unit.number + "</h3>";
popupContent = popupContent + "<p><strong>Direction: </strong>" + unit.heading + "<br />";
popupContent = popupContent + "<strong>Speed: </strong>" + unit.velocity + "<br />";
popupContent = popupContent + "<strong>Last Update:</strong> " + unit.timestamp + "<br /></p>";
var markerLocation = new L.LatLng(unit.latitude,unit.longitude);
var marker = new L.Marker(markerLocation);
var unitNumber = unit.number;
var unitTest = 'test';
console.log(unitData);
unitLayerGroup.addLayer(marker);
marker.bindPopup(popupContent);
//unitMarkerCache.push(marker);
//map.panTo(markerLocation);
}
This works for a single unit but I need it to work for 2 or more units.
I'm struggling to think about what to do to draw the units on the map and be able to call a unique marker to destroy it and then redraw it. I've thought about defining an array or object to hold the data but I can't get it to work with a unit's number as part of the variable name.
var marker[unit.number] = {"unit":unit.number, "latitude":unit.latitude};
Doing something like the above var marker[unit.number] doesn't work; Firebug always throws an error:
missing ; before statement
http://10.10.1.10:86/map2.php
Line 161
This is line 161: var marker[unit.number] = new L.Marker(markerLocation);
I don't know how your eventlistener is setup, and how many unique units you have. but If you only have one unit = "90" and want to plot its location by listening to data sent from that unit, this code will work.
pointMarkers = [];
var listener = new EventSource("your event source");
listener.addEventListener('your call', function(e){
points = JSON.parse(e.data);
if(points.unit = '90') {
for (var i =0; i < pointMarkers.length; i++) {
mymap.removeLayer(pointMarkers[i]);
}
marker = L.marker([points.latitude, points.longitude]).addTo(mymap);
pointMarkers.push(marker);
}
}, false);