2 * Map route planner based on Google Maps.
4 * @author Matthias Schmidt
5 * @copyright 2001-2019 WoltLab GmbH
6 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
7 * @module WoltLabSuite/Core/Controller/Map/Route/Planner
8 * @woltlabExcludeBundle all
10 define(["require", "exports", "tslib", "../../../Ajax/Status", "../../../Core", "../../../Dom/Util", "../../../Language", "../../../Ui/Dialog"], function (require
, exports
, tslib_1
, AjaxStatus
, Core
, Util_1
, Language
, Dialog_1
) {
12 AjaxStatus
= tslib_1
.__importStar(AjaxStatus
);
13 Core
= tslib_1
.__importStar(Core
);
14 Util_1
= tslib_1
.__importDefault(Util_1
);
15 Language
= tslib_1
.__importStar(Language
);
16 Dialog_1
= tslib_1
.__importDefault(Dialog_1
);
17 class ControllerMapRoutePlanner
{
18 constructor(buttonId
, destination
) {
19 this.didInitDialog
= false;
20 this.directionsRenderer
= undefined;
21 this.directionsService
= undefined;
22 this.googleLink
= undefined;
23 this.lastOrigin
= undefined;
25 this.originInput
= undefined;
26 this.travelMode
= undefined;
27 const button
= document
.getElementById(buttonId
);
28 if (button
=== null) {
29 throw new Error(`Unknown button with id '${buttonId}'`);
32 this.button
.addEventListener("click", (ev
) => this.openDialog(ev
));
33 this.destination
= destination
;
36 * Calculates the route based on the given result of a location search.
38 _calculateRoute(data
) {
39 const dialog
= Dialog_1
.default.getDialog(this).dialog
;
41 this.originInput
.value
= data
.label
;
43 if (this.map
=== undefined) {
44 const mapContainer
= dialog
.querySelector(".googleMap");
45 this.map
= new google
.maps
.Map(mapContainer
, {
46 disableDoubleClickZoom
: window
.WCF
.Location
.GoogleMaps
.Settings
.get("disableDoubleClickZoom"),
47 draggable
: window
.WCF
.Location
.GoogleMaps
.Settings
.get("draggable"),
48 mapTypeId
: google
.maps
.MapTypeId
.ROADMAP
,
49 scaleControl
: window
.WCF
.Location
.GoogleMaps
.Settings
.get("scaleControl"),
50 scrollwheel
: window
.WCF
.Location
.GoogleMaps
.Settings
.get("scrollwheel"),
52 this.directionsService
= new google
.maps
.DirectionsService();
53 this.directionsRenderer
= new google
.maps
.DirectionsRenderer();
54 this.directionsRenderer
.setMap(this.map
);
55 const directionsContainer
= dialog
.querySelector(".googleMapsDirections");
56 this.directionsRenderer
.setPanel(directionsContainer
);
57 this.googleLink
= dialog
.querySelector(".googleMapsDirectionsGoogleLink");
60 destination
: this.destination
,
61 origin
: data
.location
,
62 provideRouteAlternatives
: true,
63 travelMode
: google
.maps
.TravelMode
[this.travelMode
.value
.toUpperCase()],
66 // .route() returns a promise, but we rely on the callback API for compatibility reasons.
67 void this.directionsService
.route(request
, (result
, status
) => this.setRoute(result
, status
));
68 this.googleLink
.href
= this.getGoogleMapsLink(data
.location
, this.travelMode
.value
);
69 this.lastOrigin
= data
.location
;
72 * Returns the Google Maps link based on the given optional directions origin
73 * and optional travel mode.
75 getGoogleMapsLink(origin
, travelMode
) {
77 let link
= `https://www.google.com/maps/dir/?api=1&origin=${origin.lat()},${origin.lng()}&destination=${this.destination.lat()},${this.destination.lng()}`;
79 link
+= `&travelmode=${travelMode}`;
83 return `https://www.google.com/maps/search/?api=1&query=${this.destination.lat()},${this.destination.lng()}`;
86 * Initializes the route planning dialog.
89 if (!this.didInitDialog
) {
90 const dialog
= Dialog_1
.default.getDialog(this).dialog
;
91 // make input element a location search
92 this.originInput
= dialog
.querySelector('input[name="origin"]');
93 new window
.WCF
.Location
.GoogleMaps
.LocationSearch(this.originInput
, (data
) => this._calculateRoute(data
));
94 this.travelMode
= dialog
.querySelector('select[name="travelMode"]');
95 this.travelMode
.addEventListener("change", this.updateRoute
.bind(this));
96 this.didInitDialog
= true;
100 * Opens the route planning dialog.
103 event
.preventDefault();
104 Dialog_1
.default.open(this);
107 * Handles the response of the direction service.
109 setRoute(result
, status
) {
111 if (status
=== google
.maps
.DirectionsStatus
.OK
) {
112 Util_1
.default.show(this.map
.getDiv().parentElement
);
113 google
.maps
.event
.trigger(this.map
, "resize");
114 this.directionsRenderer
.setDirections(result
);
115 Util_1
.default.show(this.travelMode
.closest("dl"));
116 Util_1
.default.show(this.googleLink
);
117 Util_1
.default.innerError(this.originInput
, false);
120 // map irrelevant errors to not found error
121 if (status
!== google
.maps
.DirectionsStatus
.OVER_QUERY_LIMIT
&&
122 status
!== google
.maps
.DirectionsStatus
.REQUEST_DENIED
) {
123 status
= google
.maps
.DirectionsStatus
.NOT_FOUND
;
125 Util_1
.default.innerError(this.originInput
, Language
.get(`wcf.map.route.error.${status.toLowerCase()}`));
129 * Updates the route after the travel mode has been changed.
132 this._calculateRoute({
133 location
: this.lastOrigin
,
137 * Sets up the route planner dialog.
141 id
: this.button
.id
+ "Dialog",
143 onShow
: this.initDialog
.bind(this),
144 title
: Language
.get("wcf.map.route.planner"),
147 <div class="googleMapsDirectionsContainer" style="display: none;">
148 <div class="googleMap"></div>
149 <div class="googleMapsDirections"></div>
151 <small class="googleMapsDirectionsGoogleLinkContainer">
152 <a href="${this.getGoogleMapsLink()}" class="googleMapsDirectionsGoogleLink" target="_blank" style="display: none;">${Language.get("wcf.map.route.viewOnGoogleMaps")}</a>
155 <dt>${Language.get("wcf.map.route.origin")}</dt>
157 <input type="text" name="origin" class="long" autofocus>
160 <dl style="display: none;">
161 <dt>${Language.get("wcf.map.route.travelMode")}</dt>
163 <select name="travelMode">
164 <option value="driving">${Language.get("wcf.map.route.travelMode.driving")}</option>
165 <option value="walking">${Language.get("wcf.map.route.travelMode.walking")}</option>
166 <option value="bicycling">${Language.get("wcf.map.route.travelMode.bicycling")}</option>
167 <option value="transit">${Language.get("wcf.map.route.travelMode.transit")}</option>
174 Core
.enableLegacyInheritance(ControllerMapRoutePlanner
);
175 return ControllerMapRoutePlanner
;