devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
400 lines (399 loc) • 15.5 kB
JavaScript
/**
* DevExtreme (esm/ui/map/provider.dynamic.google.js)
* Version: 21.1.4
* Build date: Mon Jun 21 2021
*
* Copyright (c) 2012 - 2021 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
import $ from "../../core/renderer";
import {
getWindow
} from "../../core/utils/window";
var window = getWindow();
import {
noop
} from "../../core/utils/common";
import devices from "../../core/devices";
import Promise from "../../core/polyfills/promise";
import {
extend
} from "../../core/utils/extend";
import {
map
} from "../../core/utils/iterator";
import DynamicProvider from "./provider.dynamic";
import errors from "../widget/ui.errors";
import Color from "../../color";
import ajax from "../../core/utils/ajax";
import {
isDefined
} from "../../core/utils/type";
var GOOGLE_MAP_READY = "_googleScriptReady";
var GOOGLE_URL = "https://maps.googleapis.com/maps/api/js?callback=" + GOOGLE_MAP_READY;
var INFO_WINDOW_CLASS = "gm-style-iw";
var CustomMarker;
var initCustomMarkerClass = function() {
CustomMarker = function(options) {
this._position = options.position;
this._offset = options.offset;
this._$overlayContainer = $("<div>").css({
position: "absolute",
display: "none",
cursor: "pointer"
}).append(options.html);
this.setMap(options.map)
};
CustomMarker.prototype = new google.maps.OverlayView;
CustomMarker.prototype.onAdd = function() {
var $pane = $(this.getPanes().overlayMouseTarget);
$pane.append(this._$overlayContainer);
this._clickListener = google.maps.event.addDomListener(this._$overlayContainer.get(0), "click", function(e) {
google.maps.event.trigger(this, "click");
e.preventDefault()
}.bind(this));
this.draw()
};
CustomMarker.prototype.onRemove = function() {
google.maps.event.removeListener(this._clickListener);
this._$overlayContainer.remove()
};
CustomMarker.prototype.draw = function() {
var position = this.getProjection().fromLatLngToDivPixel(this._position);
this._$overlayContainer.css({
left: position.x + this._offset.left,
top: position.y + this._offset.top,
display: "block"
})
}
};
var googleMapsLoaded = function() {
return window.google && window.google.maps
};
var googleMapsLoader;
var GoogleProvider = DynamicProvider.inherit({
_mapType: function(type) {
var mapTypes = {
hybrid: google.maps.MapTypeId.HYBRID,
roadmap: google.maps.MapTypeId.ROADMAP,
satellite: google.maps.MapTypeId.SATELLITE
};
return mapTypes[type] || mapTypes.hybrid
},
_movementMode: function(type) {
var movementTypes = {
driving: google.maps.TravelMode.DRIVING,
walking: google.maps.TravelMode.WALKING
};
return movementTypes[type] || movementTypes.driving
},
_resolveLocation: function(location) {
return new Promise(function(resolve) {
var latLng = this._getLatLng(location);
if (latLng) {
resolve(new google.maps.LatLng(latLng.lat, latLng.lng))
} else {
this._geocodeLocation(location).then((function(geocodedLocation) {
resolve(geocodedLocation)
}))
}
}.bind(this))
},
_geocodedLocations: {},
_geocodeLocationImpl: function(location) {
return new Promise((function(resolve) {
if (!isDefined(location)) {
resolve(new google.maps.LatLng(0, 0));
return
}
var geocoder = new google.maps.Geocoder;
geocoder.geocode({
address: location
}, (function(results, status) {
if (status === google.maps.GeocoderStatus.OK) {
resolve(results[0].geometry.location)
} else {
errors.log("W1006", status);
resolve(new google.maps.LatLng(0, 0))
}
}))
}))
},
_normalizeLocation: function(location) {
return {
lat: location.lat(),
lng: location.lng()
}
},
_normalizeLocationRect: function(locationRect) {
return {
northEast: this._normalizeLocation(locationRect.getNorthEast()),
southWest: this._normalizeLocation(locationRect.getSouthWest())
}
},
_loadImpl: function() {
return new Promise(function(resolve) {
if (googleMapsLoaded()) {
resolve()
} else {
if (!googleMapsLoader) {
googleMapsLoader = this._loadMapScript()
}
googleMapsLoader.then(function() {
if (googleMapsLoaded()) {
resolve();
return
}
this._loadMapScript().then(resolve)
}.bind(this))
}
}.bind(this)).then((function() {
initCustomMarkerClass()
}))
},
_loadMapScript: function() {
return new Promise(function(resolve) {
var key = this._keyOption("google");
window[GOOGLE_MAP_READY] = resolve;
ajax.sendRequest({
url: GOOGLE_URL + (key ? "&key=" + key : ""),
dataType: "script"
})
}.bind(this)).then((function() {
try {
delete window[GOOGLE_MAP_READY]
} catch (e) {
window[GOOGLE_MAP_READY] = void 0
}
}))
},
_init: function() {
return new Promise(function(resolve) {
this._resolveLocation(this._option("center")).then(function(center) {
var showDefaultUI = this._option("controls");
this._map = new google.maps.Map(this._$container[0], {
zoom: this._option("zoom"),
center: center,
disableDefaultUI: !showDefaultUI
});
var listener = google.maps.event.addListener(this._map, "idle", (function() {
resolve(listener)
}))
}.bind(this))
}.bind(this)).then((function(listener) {
google.maps.event.removeListener(listener)
}))
},
_attachHandlers: function() {
this._boundsChangeListener = google.maps.event.addListener(this._map, "bounds_changed", this._boundsChangeHandler.bind(this));
this._clickListener = google.maps.event.addListener(this._map, "click", this._clickActionHandler.bind(this))
},
_boundsChangeHandler: function() {
var bounds = this._map.getBounds();
this._option("bounds", this._normalizeLocationRect(bounds));
var center = this._map.getCenter();
this._option("center", this._normalizeLocation(center));
if (!this._preventZoomChangeEvent) {
this._option("zoom", this._map.getZoom())
}
},
_clickActionHandler: function(e) {
this._fireClickAction({
location: this._normalizeLocation(e.latLng)
})
},
updateDimensions: function() {
var center = this._option("center");
google.maps.event.trigger(this._map, "resize");
this._option("center", center);
return this.updateCenter()
},
updateMapType: function() {
this._map.setMapTypeId(this._mapType(this._option("type")));
return Promise.resolve()
},
updateBounds: function() {
return Promise.all([this._resolveLocation(this._option("bounds.northEast")), this._resolveLocation(this._option("bounds.southWest"))]).then(function(result) {
var bounds = new google.maps.LatLngBounds;
bounds.extend(result[0]);
bounds.extend(result[1]);
this._map.fitBounds(bounds)
}.bind(this))
},
updateCenter: function() {
return this._resolveLocation(this._option("center")).then(function(center) {
this._map.setCenter(center);
this._option("center", this._normalizeLocation(center))
}.bind(this))
},
updateZoom: function() {
this._map.setZoom(this._option("zoom"));
return Promise.resolve()
},
updateControls: function() {
var showDefaultUI = this._option("controls");
this._map.setOptions({
disableDefaultUI: !showDefaultUI
});
return Promise.resolve()
},
isEventsCanceled: function(e) {
var gestureHandling = this._map && this._map.get("gestureHandling");
var isInfoWindowContent = $(e.target).closest(".".concat(INFO_WINDOW_CLASS)).length > 0;
if (isInfoWindowContent || "desktop" !== devices.real().deviceType && "cooperative" === gestureHandling) {
return false
}
return this.callBase()
},
_renderMarker: function(options) {
return this._resolveLocation(options.location).then(function(location) {
var marker;
if (options.html) {
marker = new CustomMarker({
map: this._map,
position: location,
html: options.html,
offset: extend({
top: 0,
left: 0
}, options.htmlOffset)
})
} else {
marker = new google.maps.Marker({
position: location,
map: this._map,
icon: options.iconSrc || this._option("markerIconSrc")
})
}
var infoWindow = this._renderTooltip(marker, options.tooltip);
var listener;
if (options.onClick || options.tooltip) {
var markerClickAction = this._mapWidget._createAction(options.onClick || noop);
var markerNormalizedLocation = this._normalizeLocation(location);
listener = google.maps.event.addListener(marker, "click", function() {
markerClickAction({
location: markerNormalizedLocation
});
if (infoWindow) {
infoWindow.open(this._map, marker)
}
}.bind(this))
}
return {
location: location,
marker: marker,
listener: listener
}
}.bind(this))
},
_renderTooltip: function(marker, options) {
if (!options) {
return
}
options = this._parseTooltipOptions(options);
var infoWindow = new google.maps.InfoWindow({
content: options.text
});
if (options.visible) {
infoWindow.open(this._map, marker)
}
return infoWindow
},
_destroyMarker: function(marker) {
marker.marker.setMap(null);
if (marker.listener) {
google.maps.event.removeListener(marker.listener)
}
},
_renderRoute: function(options) {
return Promise.all(map(options.locations, function(point) {
return this._resolveLocation(point)
}.bind(this))).then(function(locations) {
return new Promise(function(resolve) {
var origin = locations.shift();
var destination = locations.pop();
var waypoints = map(locations, (function(location) {
return {
location: location,
stopover: true
}
}));
var request = {
origin: origin,
destination: destination,
waypoints: waypoints,
optimizeWaypoints: true,
travelMode: this._movementMode(options.mode)
};
(new google.maps.DirectionsService).route(request, function(response, status) {
if (status === google.maps.DirectionsStatus.OK) {
var color = new Color(options.color || this._defaultRouteColor()).toHex();
var directionOptions = {
directions: response,
map: this._map,
suppressMarkers: true,
preserveViewport: true,
polylineOptions: {
strokeWeight: options.weight || this._defaultRouteWeight(),
strokeOpacity: options.opacity || this._defaultRouteOpacity(),
strokeColor: color
}
};
var route = new google.maps.DirectionsRenderer(directionOptions);
var bounds = response.routes[0].bounds;
resolve({
instance: route,
northEast: bounds.getNorthEast(),
southWest: bounds.getSouthWest()
})
} else {
errors.log("W1006", status);
resolve({
instance: new google.maps.DirectionsRenderer({})
})
}
}.bind(this))
}.bind(this))
}.bind(this))
},
_destroyRoute: function(routeObject) {
routeObject.instance.setMap(null)
},
_fitBounds: function() {
this._updateBounds();
if (this._bounds && this._option("autoAdjust")) {
var zoomBeforeFitting = this._map.getZoom();
this._preventZoomChangeEvent = true;
this._map.fitBounds(this._bounds);
this._boundsChangeHandler();
var zoomAfterFitting = this._map.getZoom();
if (zoomBeforeFitting < zoomAfterFitting) {
this._map.setZoom(zoomBeforeFitting)
} else {
this._option("zoom", zoomAfterFitting)
}
delete this._preventZoomChangeEvent
}
return Promise.resolve()
},
_extendBounds: function(location) {
if (this._bounds) {
this._bounds.extend(location)
} else {
this._bounds = new google.maps.LatLngBounds;
this._bounds.extend(location)
}
},
clean: function() {
if (this._map) {
google.maps.event.removeListener(this._boundsChangeListener);
google.maps.event.removeListener(this._clickListener);
this._clearMarkers();
this._clearRoutes();
delete this._map;
this._$container.empty()
}
return Promise.resolve()
}
});
export default GoogleProvider;