Google Maps: Find all zip codes along route - google-maps

Given two locations you can calculate a route in Google Maps.
Is it possible to find all zip codes along the route?
Given a zip code, can I expand the area easily with a 10 km radius and find all zip codes in that area?
What methods should I use to get this information? Tutorials are welcome. I don't need a complete working solution, although if one is available that would be really nice.

You need a data source containing the zipcode (ZCTA) polygons. One possible source is this FusionTable.
proof of concept
proof of concept showing ZCTA polygons
Note: since it queries for the zip code at every point along the route, it will take longer to finish the longer the route is.
code that performs the query (using the Google Visualization API):
function queryForZip(latlng) {
//set the query using the current latlng
var queryStr = "SELECT geometry, ZIP, latitude, longitude FROM "+ tableid + " WHERE ST_INTERSECTS(geometry, CIRCLE(LATLNG"+latlng+",1))";
var queryText = encodeURIComponent(queryStr);
var query = new google.visualization.Query('http://www.google.com/fusiontables/gvizdata?tq=' + queryText);
//set the callback function
query.send(addZipCode);
}
function addZipCode(response) {
if (!response) {
alert('no response');
return;
}
if (response.isError()) {
document.getElementById('status').innerHTML += 'Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage()+"<br>";
return;
}
FTresponse = response;
//for more information on the response object, see the documentation
//http://code.google.com/apis/visualization/documentation/reference.html#QueryResponse
numRows = response.getDataTable().getNumberOfRows();
numCols = response.getDataTable().getNumberOfColumns();
for(i = 0; i < numRows; i++) {
var zip = response.getDataTable().getValue(i, 1);
var zipStr = zip.toString()
if (!zipcodes[zipStr]) {
zipcodes[zipStr] = zipStr;
document.getElementById('zipcodes').innerHTML += zipStr+"<br>";
}
}
}

Related

Autodesk Forge Viewer How to get coordinates of line start/stop

I am trying to do room highlighting in forge viewer.
In revit I have created lines that represent the borders of a room. After conversion to svf I know the dbids of those lines. Now I want to know the start and stop points (vertices) of those lines so that I can create a Three.Shape() of the room borders.
[EDIT] I get the fragId from dbId
function getFragIdFromDbId(viewer, dbid){
var returnValue;
var it = viewer.model.getData().instanceTree;
it.enumNodeFragments(dbid, function(fragId) {
console.log("dbId: " + dbid + " FragId : " + fragId);
returnValue = fragId;
}, false);
return returnValue;
}
Question:
Once I know the fragId is there a way to see its start and stop points(vertices)? Also will those vertices be world space or local space?
This is what I ended up doing. Note make sure the model is finished loading before calling instanceTree. Also in my case the dbid and fragid where one to one, not sure if this will always be the case in the instance tree.
function getFragIdFromDbId(viewer, dbid) {
var returnValue;
var it = viewer.model.getData().instanceTree;
it.enumNodeFragments(dbid, function (fragId) {
console.log("dbId: " + dbid + " FragId : " + fragId);
returnValue = fragId;
}, false);
return returnValue;
}
...
// only need the start vertex
var floatArray = [];
for (var i = 0; i < dbidArray.length; i++) {
var fragId = getFragIdFromDbId(viewer, dbidArray[i]);
var mesh = viewer.impl.getRenderProxy(viewer.model, fragId);
var matrixWorld = mesh.matrixWorld;
var lmvBufferGeometry = mesh.geometry;
var lmvFloatArray = lmvBufferGeometry.vb; //this will have an array of 6 values 0,1,2 are start vertext , 3,4,5 are end vertex
floatArray.push(lmvFloatArray[0]);
floatArray.push(lmvFloatArray[1]);
floatArray.push(lmvFloatArray[2]);
}
//use matrixWorld to convert array to worldSpace

Why can't Google Sheets find reverseGeocode method from Maps API?

I'm using a Google Sheets function to reverse geocode a list lat/long coordinates. It looks like this:
function getAdd(lat, lng) {
if (lat == "") {
return "You have to provide latitudinal coordinates to the place"
} if (lng == ""){
return "You have to provide longitudinal coordinates to the place"
}
var response = Maps.newGeocoder().reverseGeocode(lat, lng);
for (var i = 0; i < response.results.length; i++) {
var result = response.results[i];
Utilities.sleep(1000);
return result.formatted_address;
}
};
Question 1: Why is Google Sheets giving me the following error: "Cannot find method reverseGeocode(object,(class))"?
Question 2: Once I fix that, how can fetch country names from the result array instead of the complete address from the results?
You're trying to return a result for each result in the response object. Instead you have to choose one:
function getAdd(lat, lng) {
if (lat == "") {
return "You have to provide latitudinal coordinates to the place"
} if (lng == ""){
return "You have to provide longitudinal coordinates to the place"
}
var response = Maps.newGeocoder().reverseGeocode(lat, lng);
return response.results[0].formatted_address;
};
If you're looking for just the country, the format of the result object is here:
https://developers.google.com/maps/documentation/geocoding/#ReverseGeocoding
In that case, you should iterate through the results[0] object and test to see if the types includes "Country". If it does, select the results[0].address_components[i].short_name where i is your iterator. Or use long_name instead.
Ok, figured it out. Here's how I eventually got country from lat/long:
function getAdd(lat, lng) {
if (lat == "") {
return "Insert latitude."
}
if (lng == ""){
return "Insert longitude."
}
var response = Maps.newGeocoder().reverseGeocode(lat,lng);
Utilities.sleep(1000); //in order not to exeed api calls per second
for (var i in response.results) {
var result = response.results[i];
}
for (var j in result.address_components) {
for (var k in result.address_components[j].types) {
if (result.address_components[j].types[k] == "country") {
return result.address_components[j].long_name;
}
}
}
};
Thank you for posting this it just helped me a lot with what I was trying to do. Just a quick note that your first loop simply returns the last record and not all data is in the last record but the country seems to always be there. If anyone (like me) is looking for locality names you can simply choose the first record and more data is available to you.
I just changed:
for (var i in response.results) {
var result = response.results[i];
}
to:
var result = response.results[0];
Full Code returns the locality and country:
function getAdd(lat, lng) {
var response = Maps.newGeocoder().reverseGeocode(lat,lng);
var country="";
var place="";
Utilities.sleep(1000); //in order not to exeed api calls per second
var result = response.results[0];
for (var j in result.address_components) {
for (var k in result.address_components[j].types) {
if (result.address_components[j].types[k] == "country") {
country = result.address_components[j].long_name;
}
if(result.address_components[j].types[k] == "locality") {
place = result.address_components[j].long_name;
}
}
}
return [place, country];
};

Google Maps and Fusion Tables

A map I created last year using Google Maps API V3 and Fusion Tables V1 has stopped functioning properly in the last week or so. I am not sure if I missed an update that has deprecated my code or if there's another explanation. In brief, the following code queries my fusion table and if a match is found it returns data for an info window. However, it is now returning false every time. The addInfoWindow() function is firing fine. The issue appears to be either in the query itself or the data that's returned. Additionally, the pin is dropping in the correct location on the map so the coordinates are not the issue.
This issue can be replicated by entering an address in the field. For demonstration purposes, 9132 Kingston Pike 37923 should return true. Clicking inside any polygon will return the intended results.
Thank you for any guidance you can provide.
// query
var script = document.createElement('script');
var url = ['https://www.googleapis.com/fusiontables/v1/query?'];
url.push('sql=');
var query = "SELECT * FROM " +
tableid + " WHERE ST_INTERSECTS(geometry, CIRCLE(LATLNG(" + coordinate.lat() + "," + coordinate.lng() + "), 0.001))";
var encodedQuery = encodeURIComponent(query);
url.push(encodedQuery);
url.push('&callback=addInfoWindow');
url.push('&key=' + apiKey);
script.src = url.join('');
var head = document.getElementsByTagName('head')[0];
head.appendChild(script);
// call back function
function addInfoWindow(data) {
infowindow.close();
initialize();
var rows = data['rows'];
if (rows)
{
console.log("inside if statement");
for (var i = 0; i < 1; i++)
{
console.log("inside for loop: " + rows[i][0]);
infowindow.setContent("<div style='width:250px;'><h2>"+ rows[i][1] + "</h2><p>The neighborhood contact in your area would love to hear from you! </p><p>Click <a href='https://cspctystn.infellowship.com/GroupSearch/ShowGroup/" + rows[i][0] + "' target='_blank'>here</a> to get their information.</p><p> </p><p>If you desire to communicate with Community Life staff, contact -- removed --.<p><br/><br/></div>");
//console.log(rows[i][1] + ": " + rows[i][0]);
infowindow.setPosition(coordinate);
map.setCenter(coordinate);
map.setZoom(15);
infowindow.open(map);
}
}
else
{
console.log("error");
infowindow.setContent("<div style='width:250px;'><h2>Oops!</h1><p> It seems we don't have a neighborhood contact in your area.</p><p>Please communicate with our <a href='http://www.cspc.net/communitylife' target= '_blank' >Community Life</a> staff for more information. -- removed --<p></div>");
infowindow.setPosition(coordinate);
map.setCenter(coordinate);
map.setZoom(15);
infowindow.open(map);
}
}

Why aren't my Fusion Table Layers and Styles working?

I am currently using a Google Maps Fusion Table for County information to display the county boundaries for Texas. There are over 200+ counties in Texas. I am looping through an array of values for each county and need to color-code the county based on the value in the array. There are 4 levels of colors for the county: Stop, Warning, Watch and Open. Everything seems to be working, except that the color is only being applied to 5 counties. The limit of styles is 5 and the limit of layers is also 5, but I am only using 1 layer and 4 styles.
Can someone tell me what I am dong wrong? Or is this just not possible via the API?
Below is a snippet of the code:
var styles = new Array();
var ftLayer = new google.maps.FusionTablesLayer();
function loadTexas() {
loadFusionLayer('TX');
ftLayer.setMap(map);
for (var i = 0; i < aryCounty.length; i++) {
styleLayer("'State Abbr.' = 'TX' AND 'County Name' = '" +
aryCounty[i].County + "'", 1000);
}
ftLayer.set('styles', styles);
}
function loadFusionLayer(state) {
if (state != null) {
where = "'State Abbr.' IN ('" + state + "')";
}
var select = "geometry, 'State Abbr.', 'County Name'";
ftLayer.setOptions({
query: {
select: select,
from: countyTableId,
where: where
}
});
}
function styleLayer(where, actualValue) {
var color = setPolygonColorBy(actualValue);
styles.push({
where: where,
polygonOptions: {
fillColor: color,
fillOpacity: 0.6
}
});
}
function setPolygonColorBy(actualValue, divisor) {
var status;
var stop = STATUS_LAYER_STYLES["Stop"].color;
var warning = STATUS_LAYER_STYLES["Warning"].color;
var watch = STATUS_LAYER_STYLES["Watch"].color;
var open = STATUS_LAYER_STYLES["Open"].color;
if (actualValue >= minValue && actualValue < midValue) {
status = watch;
}
else if (actualValue >=midValue && actualValue < maxValue) {
status = warning;
}
else if (actualValue >= maxValue) {
status = stop;
}
else {
status = open;
}
return status;
}
You really only have 4 styles. You need to get the dollar value for each county into your own Fusion Table. You could download the US Counties Fusion Table, perhaps only the TX counties and create a new FT. Then add you own dollar value column. (A simpler better approach would be to merge your actualValues with the Counties table, but I'm not famiiar with merging table. You need your actual Values and the State-County key values. The merge should create a new table owned by you)
Then you can create your 4 styles as described in the Maps FT Docs.
There may be syntax errors here.
ftLayer = new google.maps.FusionTablesLayer({
query: {
select: 'geometry',
from: countyTable_with_actualValues_Id },
styles: [{
// default color
where: "'State Abbr.' ='" + state + "'";
polygonOptions: {
fillColor: open
}
}, {
where: "'State Abbr.' ='" + state + "' AND actualValue >= " + maxValue;
polygonOptions: {
fillColor: stop
}
}, {
where: "'State Abbr.' ='" + state + "' AND actualValue >= " + minValue + "AND actualValue < " + midValue;
polygonOptions: {
fillColor: watch
},
// Final condition left as an exercise :-)
}]
});
ftLayer.setMap(map);
Answer Update:
If your company does not want to push the data out and you are writing an internal application that is only available to employees, then you don't want to use Fusion Tables. The data in Fusion Tables is generally available to the public and is published one of two ways:
Follow-up To Your May 25, 2012 Comment (if you decide to move forward with FusionTables):
With your comments, I understand better what you are doing. I believe the code you have in the loadTexas function that is calling the styleLayer function to create the FusionTablesStyle objects is correct.
The part that looks suspicious is the ordering of the code in the loadTexas function and the loadFusionLayer function. There is also a missing var where declaration in the loadFusionLayer function. I don't think it is causing a problem (at least not in the code you have shown), but it does inadvertently create a global, so corrected that problem in the code that follows. I suggest making the following changes:
Create a new var fusionTablesOptions in the global space and use fusionTablesOptions to set up all of the options for the ftLayer FusionTablesLayer.
Change the declaration of var ftLayer so that it is assigned to: null.
Iterate the aryCounty array, build the styles array, and assign it to the fusionTablesOptions.styles property.
Assign fusionTablesOptions.map to the existing instance of google.maps.Map named: map (and remove this line of code in the loadTexas function: ftLayer.setMap(map);).
Assign fusionTablesOptions.query to the object that is built in the loadFusionLayer function.
Now that all of the necessary fusionTablesOptions properties have been set, create a new instance of google.maps.FusionTablesLayer, passing fusionTablesOptions to the constructor function.
var styles = new Array();
//Step 1:
var fusionTablesOptions = {};
//Step 2:
var ftLayer = null;
function loadTexas() {
//Step 3:
for (var i = 0; i < aryCounty.length; i++) {
//Call to the styleLayer function not shown to reduce code size
}
fusionTablesOptions.styles = styles;
//Step 4:
fusionTablesOptions.map = map;
loadFusionLayer('TX');
}
function loadFusionLayer(state) {
var where = null; //Corrects the missing var keyword
if (state != null) {
where = "'State Abbr.' IN ('" + state + "')";
}
var select = "geometry, 'State Abbr.', 'County Name'";
//Step 5:
fusionTablesOptions.query : {
select: select,
from: countyTableId,
where: where
}
//Step 6:
ftLayer = new google.maps.FusionTablesLayer( fusionTablesOptions );
}
Apologies for the large answer, but I wanted to make sure I conveyed all of my suggestions clearly in a way thought would be easy to review or implement.

Hiding and showing markers won't appear after being dragged in google maps

The title kinda says it all, i have a google maps api v3 and everything works fine except for one annoying new feature which i cant seem to fix.
You can show and hide markers by a click of a button which calls togglePOI(), but when i drag a marker and click hide and show again. All the markers appear except for the ones i have been dragging around. So the dragging seems to throw things into chaos. I’ve been have headaches over this one so any help would be greatly appreciated.
I cannot paste all the code in here, but if you want to see some other aspect that you think is causing this just ask and ill put it in.
var latlngs = new google.maps.MVCArray();
Map init etc
Marker creation
google.maps.event.addListener(locationMarker, "drag", function()
{
var index = findMarkerIndex(locationMarker, 1);
if (index >= 0)
{
var nLatLng = locationMarker.getPosition();
latlngs.setAt(index, nLatLng);
var nLat = nLatLng.lat();
var nLng = nLatLng.lng();
var modifiedLocation = {
Latitude: nLat,
Longitude: nLng
};
//SEND OUTPUT TO SELECT BOX
locations[index] = modifiedLocation;
document.getElementById('locations').options[index] = new Option('Num: ' + index + ' Pois: ' + nLat + ' - ' + nLng, data[4] + ',' + nLat + ',' + nLng + ',' + data[5]);
}
});
//FUNCTION CALLED FROM HTML BUTTON
function togglePOI()
{
if(togglePOIBool)
{
for(var i=0;i<markers.length;i++)
{
if (markers[i].category == 1) //ONLY HIDE CAT 1
markers[i].setMap(null);
}
togglePOIBool = false;
$("#togglePOIButton").val('Aan');
}
else
{
for(var i=0;i<markers.length;i++)
{
if (markers[i].category == 1)//ONLY SHOW CAT 1
markers[i].setMap(map);
}
togglePOIBool = true;
$("#togglePOIButton").val('Uit');
}
}
// Returns the index of the marker in the polyline.
function findMarkerIndex(locationMarker, option)
{
var index = -1;
for (var i = 0; i < markers.length; ++i)
{
if (markers[i] == locationMarker)
{
index = i;
break;
}
}
return index;
}
If it's OK for your application, replace setMap's with setVisible(true/false). When I tried this, it solves your problem.
http://jsfiddle.net/F3XbV/
You are not saving that position into markers array, I think it could solve the problem, insert this inside drag event:
markers[index].setPosition(locationMarker.getPosition());