-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathGMapsService.py
158 lines (137 loc) · 8.11 KB
/
GMapsService.py
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
import os, googlemaps, datetime, json, pprint
from models import Universal, Logger
from dotenv import load_dotenv
load_dotenv()
class GoogleMapsService:
servicesEnabled = False
contextChecked = False
gmapsAPIKey = None
gmapsClient = None
@staticmethod
def checkContext():
if "GoogleMapsEnabled" in os.environ and os.environ["GoogleMapsEnabled"] == "True":
GoogleMapsService.gmapsClient = googlemaps.Client(key=os.environ["GoogleMapsAPIKey"])
GoogleMapsService.gmapsAPIKey = os.environ["GoogleMapsAPIKey"]
GoogleMapsService.servicesEnabled = True
GoogleMapsService.contextChecked = True
@staticmethod
def generateMapEmbedHTML(mapMode, mapType, zoom="default", classlist="", id="", width="600", height="450", placeQuery=None, directionsOrigin=None, directionsDestination=None, directionsMode=None, viewCenterCoordinates=None):
'''Returns a string of `iframe` HTML that has a fully-embedded Google Map.
## Parameters:
- `mapMode`: String --> `place`, `directions`, `view`
- `place` to show the map of a specific place with a marker on the place's location
- Requires `placeQuery`.
- `directions` shows a map with a route plotted between a start and end destination.
- Requires `directionsOrigin`, `directionsDestination`, and `directionsMode`
- `view` displays a map around specific center co-ordinates.
- Requires `viewCenterCoordinates`.
- `mapType`: String --> `roadmap`, `satellite`
- `zoom`: String (optional, default: automatic) --> Integer in a string. Ranges from 0 (the whole world) to 21 (individual buildings).
- `classlist`: String (optional) --> Will set the classlist you provide in the `iframe`'s HTML. Could be used to apply CSS rules to the `iframe` embed.
- `id`: String (optional) --> Will set the ID you provide in the `iframe`'s HTML. Could be used to apply CSS rules to the `iframe` embed or otherwise.
- `width`: String (optional, default: 600) --> Sets the width of the `iframe`. All normal HTML and CSS width sizes can be applied (e.g `10%`).
- `height`: String (optional, default: 450) --> Sets the height of the `iframe`. All normal HTML and CSS width sizes can be applied (e.g `10%`).
- `placeQuery`: String (optional) --> Query a specific place on Google Maps. Example value: `Marina Bay Sands`.
- `directionsOrigin`: String (optional) --> A query for the origin of a directions route plot. Example value: `Marina Bay Sands`.
- `directionsDestination`: String (optional) --> A query for the destination of a directions route plot. Example value: `Jewel Changi Airport`.
- `directionsMode`: String (optional) --> The mode of transit for a directions route plot. Valid values: `driving`, `walking`, `bicycling`, `transit`, `flying`
- `viewCenterCoordinates`: String (optional) --> Comma-separated latitude and longitude coordinates. Example value: `37.4218,-122.0840`.
## Sample usage
In a Python file:
```python
GoogleMapsService.checkContext()
@app.route("/map")
def showMap():
mapEmbed = GoogleMapsService.generateMapEmbedHTML(mapMode="place", mapType="satellite", classlist="maps", id="googleMap", placeQuery="Marina Bay Sands")
return render_template("Map.html", map=mapEmbed)
```
In an HTML template `Map.html`:
```html
<html>
<head>
<style>
.maps {
text-align: center;
}
</style>
</head>
<body>
{{ map|safe }}
</body>
</html>
```
NOTE: To use `GoogleMapsService`, a Google Maps Platform API Key must be set as `GoogleMapsAPIKey` and `GoogleMapsEnabled` must be set to `True` in the .env file.
'''
# Check permission
if not GoogleMapsService.servicesEnabled:
return "ERROR: Google Maps services are not enabled."
# Validate inputs
if mapMode not in ["place", "directions", "view"]:
return "ERROR: Invalid map mode."
if mapType not in ["roadmap", "satellite"]:
return "ERROR: Invalid map type."
## Mode-based data validation
if mapMode == "place" and placeQuery == None:
return "ERROR: Place query not provided for place map mode."
if mapMode == "directions":
if directionsOrigin == None or directionsDestination == None or directionsMode == None:
return "ERROR: Directions origin, destination and commute mode not provided for directions map mode."
elif directionsMode not in ["driving", "walking", "bicycling", "transit", "flying"]:
return "ERROR: Invalid directions mode."
if mapMode == "view" and viewCenterCoordinates == None:
return "ERROR: View center coordinates not provided for view map mode."
# Formulate request parameters
parameters = ["key={}".format(GoogleMapsService.gmapsAPIKey)]
if mapMode == "place":
parameters += [
"q={}".format(placeQuery),
"maptype={}".format(mapType)
]
elif mapMode == "directions":
parameters += [
"origin={}".format(directionsOrigin),
"destination={}".format(directionsDestination),
"mode={}".format(directionsMode),
"units=metric",
"maptype={}".format(mapType)
]
elif mapMode == "view":
parameters += [
"center={}".format(viewCenterCoordinates),
"maptype={}".format(mapType)
]
if zoom != "default":
parameters.append("zoom={}".format(zoom))
if mapMode != "view" and viewCenterCoordinates != None:
parameters.append("center={}".format(viewCenterCoordinates))
# Formulate HTML
embedHTML = "<iframe class='{}' id='{}' width='{}' height='{}' frameborder='0' style='border:0' src='https://www.google.com/maps/embed/v1/{}?{}' allowfullscreen></iframe>".format(classlist, id, width, height, mapMode, "&".join(parameters))
return embedHTML
@staticmethod
def generateRoute(startLocation: str, endLocation: str, mode: str, departureTime: datetime.datetime):
# Check permission
if not GoogleMapsService.servicesEnabled:
return "ERROR: Google Maps services are not enabled."
if (not isinstance(startLocation, str)) or (not isinstance(endLocation, str)) or (not isinstance(mode, str)) or (not isinstance(departureTime, datetime.datetime)):
return "ERROR: Invalid start location, end location, commute mode or departure time provided. Start location, end location and commute mode must be of type String while departureTime must be a Python datetime object."
elif mode not in ["driving", "walking", "bicycling", "transit", "flying"]:
return "ERROR: Invalid directions mode."
# Obtain directions data from Google Maps
try:
directionsData = GoogleMapsService.gmapsClient.directions(startLocation, endLocation, mode=mode, departure_time=departureTime)
directionsData = directionsData[0]
except Exception as e:
return "ERROR: Failed to obtain directions data from Google Maps; error: {}".format(e)
# Extract and process relevant data
response = {}
response["copyright"] = directionsData["copyrights"]
response["warnings"] = directionsData["warnings"]
leg = directionsData["legs"][0]
response["distance"] = leg["distance"]["text"]
response["duration"] = leg["duration"]["text"]
response["startAddress"] = leg["start_address"]
response["endAddress"] = leg["end_address"]
response["startLocation"] = leg["start_location"]
response["endLocation"] = leg["end_location"]
response["steps"] = leg["steps"]
return response