-
Notifications
You must be signed in to change notification settings - Fork 4
/
Geocode.gs
176 lines (158 loc) · 5.96 KB
/
Geocode.gs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/**
* @OnlyCurrentDoc Limits the script to only accessing the current spreadsheet.
* Usage: Select a continuous column of address and select Add-Ons->Geocode Selected Cells
* Encoding will put the lat/lng in the columns labled Lat/Lng
* Based off of: https://vilimpoc.org/blog/2013/07/11/google-spreadsheet-geocoding-macro/
*/
/*
* Short: Use Google's geocoding to convert addresses to GPS coordinates in a Google spreadsheet.
* Tip: Select a continuous column of address and click "Add-Ons->Geocode Selected Cells". Encoding will puts the results in the columns labeled "Lat" and "Lng".
See Add-Ons->Instructions for more details.
*/
/**
* Adds a custom menu to the active spreadsheet, containing a single menu item.
*
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
*
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [
{
name: "Geocode Selected Cells",
functionName: "geocodeSelectedCells"
},
{
name: "Instructions",
functionName: "geocodeSelectedCellsHelp"
}
];
sheet.addMenu("Add-ons", entries);
}
function geocodeSelectedCellsHelp() {
// Display a modal dialog box with custom HtmlService content.
var htmlOutput = HtmlService
.createHtmlOutputFromFile("GeoHelpDialog")
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(425)
.setHeight(175);
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Geocode Instructions');
}
function showPrompt(missingColumn) {
var ui = SpreadsheetApp.getUi(); // Same variations.
var word = (missingColumn[missingColumn.length - 1] == 's') ? "them" : "it";
var result = ui.alert(
'Add Columns',
'You are missing ' + missingColumn + ' for results would you like me to create ' + word + ' for you?',
ui.ButtonSet.YES_NO);
// Process the user's response.
return result == ui.Button.YES;
}
function geocodeSelectedCells() {
var sheet = SpreadsheetApp.getActiveSheet();
var addresses = sheet.getActiveRange();
// We expect only the column to be encoded selected
if (addresses.getNumColumns() == 0) {
Browser.msgBox("Please select a address/location column to encode");
} else if (addresses.getNumColumns() != 1) {
Browser.msgBox("Please select only one address/location column to encode");
return;
}
// Find where to put results
var headerRange = sheet.getRange(1, 1, 1, sheet.getLastColumn());
var headerValues = headerRange.getValues();
var latColumn = -1;
var lngColumn = -1;
var row = null;
for (row in headerValues) {
for (var col in headerValues[row]) {
if (headerValues[row][col].toLowerCase() == "lat") {
latColumn = parseInt(col) + 1;
} else if (headerValues[row][col].toLowerCase() == "lng") {
lngColumn = parseInt(col) + 1;
}
}
}
if (latColumn == -1 && lngColumn == -1) {
if (!showPrompt("the Lat/Lng columns")) {
return;
}
latColumn = sheet.getLastColumn() + 1;
lngColumn = latColumn + 1;
sheet.insertColumnAfter(sheet.getLastColumn());
sheet.insertColumnAfter(latColumn);
setValue(sheet, 1, lngColumn, 'Lng');
setValue(sheet, 1, latColumn, 'Lat');
} else if (latColumn == -1) {
if (!showPrompt("a Lat column")) {
return;
}
sheet.insertColumnAfter(lngColumn);
latColumn = lngColumn + 1;
setValue(sheet, 1, latColumn, 'Lat');
} else if (lngColumn == -1) {
if (!showPrompt("a Lng column")) {
return;
}
sheet.insertColumnAfter(latColumn);
lngColumn = latColumn + 1;
setValue(sheet, 1, lngColumn, 'Lng');
setValue(sheet, 1, latColumn, 'Lat');
}
// Let's Encode
var geocoder = Maps.newGeocoder().setRegion('de');
row = 1;
// Skip header if selected
if (addresses.getRow() == 1) {
++row;
}
var cell = null;
for (var r = row; r <= addresses.getNumRows(); ++r) {
cell = addresses.getCell(r, 1);
if (!sheet.getRange(cell.getRow(), latColumn).isBlank() || !sheet.getRange(cell.getRow(), lngColumn).isBlank()) {
var ui = SpreadsheetApp.getUi();
var response = ui.alert('The results cells lat/lng are not empty. Do you wish to override?', ui.ButtonSet.YES_NO);
// Process the user's response.
if (response == ui.Button.YES) {
break;
} else {
return;
}
}
}
for (row; row <= addresses.getNumRows(); ++row) {
cell = addresses.getCell(row, 1);
var address = cell.getValue();
// Geocode the address and plug the lat, lng pair into the
if (address == "") {
continue;
}
var location = geocoder.geocode(address);
// Only change cells if geocoder seems to have gotten a
// valid response.
if (location.status == 'OK') {
lat = location["results"][0]["geometry"]["location"]["lat"];
lng = location["results"][0]["geometry"]["location"]["lng"];
setValue(sheet, cell.getRow(), latColumn, lat);
setValue(sheet, cell.getRow(), lngColumn, lng);
} else {
setValue(sheet, cell.getRow(), latColumn, location.status);
setValue(sheet, cell.getRow(), lngColumn, location.status);
}
}
}
function setValue(sheet, row, column, val) {
sheet.getRange(row, column).setValue(val);
}
/**
* Runs when the add-on is installed; calls onOpen() to ensure menu creation and
* any other initializion work is done immediately.
*
* @param {Object} e The event parameter for a simple onInstall trigger.
*/
function onInstall(e) {
onOpen(e);
}