devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
412 lines (410 loc) • 16.4 kB
JavaScript
/**
* DevExtreme (cjs/__internal/ui/map/m_provider.dynamic.google.js)
* Version: 24.2.6
* Build date: Mon Mar 17 2025
*
* Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _color = _interopRequireDefault(require("../../../color"));
var _devices = _interopRequireDefault(require("../../../core/devices"));
var _renderer = _interopRequireDefault(require("../../../core/renderer"));
var _ajax = _interopRequireDefault(require("../../../core/utils/ajax"));
var _common = require("../../../core/utils/common");
var _extend = require("../../../core/utils/extend");
var _iterator = require("../../../core/utils/iterator");
var _type = require("../../../core/utils/type");
var _window = require("../../../core/utils/window");
var _ui = _interopRequireDefault(require("../../../ui/widget/ui.errors"));
var _m_provider = _interopRequireDefault(require("./m_provider.dynamic"));
function _interopRequireDefault(e) {
return e && e.__esModule ? e : {
default: e
}
}
const window = (0, _window.getWindow)();
const GOOGLE_MAP_READY = "_googleScriptReady";
let GOOGLE_URL = `https://maps.googleapis.com/maps/api/js?callback=${GOOGLE_MAP_READY}&libraries=marker&loading=async`;
const INFO_WINDOW_CLASS = "gm-style-iw";
let CustomMarker;
const initCustomMarkerClass = function() {
CustomMarker = function(options) {
this._position = options.position;
this._offset = options.offset;
this._$overlayContainer = (0, _renderer.default)("<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() {
const $pane = (0, _renderer.default)(this.getPanes().overlayMouseTarget);
$pane.append(this._$overlayContainer);
this._clickListener = google.maps.event.addDomListener(this._$overlayContainer.get(0), "click", (e => {
google.maps.event.trigger(this, "click");
e.preventDefault()
}));
this.draw()
};
CustomMarker.prototype.onRemove = function() {
google.maps.event.removeListener(this._clickListener);
this._$overlayContainer.remove()
};
CustomMarker.prototype.draw = function() {
const position = this.getProjection().fromLatLngToDivPixel(this._position);
this._$overlayContainer.css({
left: position.x + this._offset.left,
top: position.y + this._offset.top,
display: "block"
})
}
};
const googleMapsLoaded = function() {
var _window$google;
return null === (_window$google = window.google) || void 0 === _window$google ? void 0 : _window$google.maps
};
let googleMapsLoader;
class GoogleProvider extends _m_provider.default {
_mapType(type) {
const mapTypes = {
hybrid: google.maps.MapTypeId.HYBRID,
roadmap: google.maps.MapTypeId.ROADMAP,
satellite: google.maps.MapTypeId.SATELLITE
};
return mapTypes[type] || mapTypes.hybrid
}
_movementMode(type) {
const movementTypes = {
driving: google.maps.TravelMode.DRIVING,
walking: google.maps.TravelMode.WALKING
};
return movementTypes[type] || movementTypes.driving
}
_resolveLocation(location) {
return new Promise((resolve => {
const latLng = this._getLatLng(location);
if (latLng) {
resolve(new google.maps.LatLng(latLng.lat, latLng.lng))
} else {
this._geocodeLocation(location).then((geocodedLocation => {
resolve(geocodedLocation)
}))
}
}))
}
_geocodeLocationImpl(location) {
return new Promise((resolve => {
if (!(0, _type.isDefined)(location)) {
resolve(new google.maps.LatLng(0, 0));
return
}
const geocoder = new google.maps.Geocoder;
geocoder.geocode({
address: location
}, ((results, status) => {
if (status === google.maps.GeocoderStatus.OK) {
resolve(results[0].geometry.location)
} else {
_ui.default.log("W1006", status);
resolve(new google.maps.LatLng(0, 0))
}
}))
}))
}
_normalizeLocation(location) {
return {
lat: location.lat(),
lng: location.lng()
}
}
_normalizeLocationRect(locationRect) {
return {
northEast: this._normalizeLocation(locationRect.getNorthEast()),
southWest: this._normalizeLocation(locationRect.getSouthWest())
}
}
_loadImpl() {
return new Promise((resolve => {
if (googleMapsLoaded()) {
resolve()
} else {
if (!googleMapsLoader) {
googleMapsLoader = this._loadMapScript()
}
googleMapsLoader.then((() => {
if (googleMapsLoaded()) {
resolve();
return
}
this._loadMapScript().then(resolve)
}))
}
})).then((() => {
initCustomMarkerClass()
}))
}
_loadMapScript() {
return new Promise((resolve => {
const key = this._keyOption("google");
window[GOOGLE_MAP_READY] = resolve;
_ajax.default.sendRequest({
url: GOOGLE_URL + (key ? `&key=${key}` : ""),
dataType: "script"
})
})).then((() => {
try {
delete window[GOOGLE_MAP_READY]
} catch (e) {
window[GOOGLE_MAP_READY] = void 0
}
}))
}
_init() {
return new Promise((resolve => {
this._resolveLocation(this._option("center")).then((center => {
const disableDefaultUI = !this._option("controls");
const providerConfig = this._option("providerConfig");
const mapId = (null === providerConfig || void 0 === providerConfig ? void 0 : providerConfig.mapId) ?? "";
this._map = new google.maps.Map(this._$container[0], {
center: center,
disableDefaultUI: disableDefaultUI,
mapId: mapId,
zoom: this._option("zoom")
});
const listener = google.maps.event.addListener(this._map, "idle", (() => {
resolve(listener)
}))
}))
})).then((listener => {
google.maps.event.removeListener(listener)
}))
}
_attachHandlers() {
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() {
const bounds = this._map.getBounds();
this._option("bounds", this._normalizeLocationRect(bounds));
const center = this._map.getCenter();
this._option("center", this._normalizeLocation(center));
if (!this._preventZoomChangeEvent) {
this._option("zoom", this._map.getZoom())
}
}
_clickActionHandler(e) {
this._fireClickAction({
location: this._normalizeLocation(e.latLng)
})
}
updateDimensions() {
const center = this._option("center");
google.maps.event.trigger(this._map, "resize");
this._option("center", center);
return this.updateCenter()
}
updateMapType() {
this._map.setMapTypeId(this._mapType(this._option("type")));
return Promise.resolve()
}
updateBounds() {
return Promise.all([this._resolveLocation(this._option("bounds.northEast")), this._resolveLocation(this._option("bounds.southWest"))]).then((result => {
const bounds = new google.maps.LatLngBounds;
bounds.extend(result[0]);
bounds.extend(result[1]);
this._map.fitBounds(bounds)
}))
}
updateCenter() {
return this._resolveLocation(this._option("center")).then((center => {
this._map.setCenter(center);
this._option("center", this._normalizeLocation(center))
}))
}
updateZoom() {
this._map.setZoom(this._option("zoom"));
return Promise.resolve()
}
updateControls() {
const showDefaultUI = this._option("controls");
this._map.setOptions({
disableDefaultUI: !showDefaultUI
});
return Promise.resolve()
}
isEventsCanceled(e) {
var _this$_map;
const gestureHandling = null === (_this$_map = this._map) || void 0 === _this$_map ? void 0 : _this$_map.get("gestureHandling");
const isInfoWindowContent = (0, _renderer.default)(e.target).closest(".gm-style-iw").length > 0;
if (isInfoWindowContent || "desktop" !== _devices.default.real().deviceType && "cooperative" === gestureHandling) {
return false
}
return super.isEventsCanceled(e)
}
_renderMarker(options) {
return this._resolveLocation(options.location).then((location => {
let marker;
if (options.html) {
marker = new CustomMarker({
map: this._map,
position: location,
html: options.html,
offset: (0, _extend.extend)({
top: 0,
left: 0
}, options.htmlOffset)
})
} else {
const providerConfig = this._option("providerConfig");
const useAdvancedMarkers = (null === providerConfig || void 0 === providerConfig ? void 0 : providerConfig.useAdvancedMarkers) ?? true;
const icon = options.iconSrc || this._option("markerIconSrc");
if (useAdvancedMarkers) {
const content = icon ? this._createIconTemplate(icon) : void 0;
marker = new google.maps.marker.AdvancedMarkerElement({
position: location,
map: this._map,
content: content
})
} else {
marker = new google.maps.Marker({
position: location,
map: this._map,
icon: icon
})
}
}
const infoWindow = this._renderTooltip(marker, options.tooltip);
let listener;
if (options.onClick || options.tooltip) {
const markerClickAction = this._mapWidget._createAction(options.onClick || _common.noop);
const markerNormalizedLocation = this._normalizeLocation(location);
listener = google.maps.event.addListener(marker, "click", (() => {
markerClickAction({
location: markerNormalizedLocation
});
if (infoWindow) {
infoWindow.open(this._map, marker)
}
}))
}
return {
location: location,
marker: marker,
listener: listener
}
}))
}
_renderTooltip(marker, options) {
if (!options) {
return
}
options = this._parseTooltipOptions(options);
const infoWindow = new google.maps.InfoWindow({
content: options.text
});
if (options.visible) {
infoWindow.open(this._map, marker)
}
return infoWindow
}
_destroyMarker(marker) {
marker.marker.setMap(null);
if (marker.listener) {
google.maps.event.removeListener(marker.listener)
}
}
_renderRoute(options) {
return Promise.all((0, _iterator.map)(options.locations, (point => this._resolveLocation(point)))).then((locations => new Promise((resolve => {
const origin = locations.shift();
const destination = locations.pop();
const waypoints = (0, _iterator.map)(locations, (location => ({
location: location,
stopover: true
})));
const request = {
origin: origin,
destination: destination,
waypoints: waypoints,
optimizeWaypoints: true,
travelMode: this._movementMode(options.mode)
};
(new google.maps.DirectionsService).route(request, ((response, status) => {
if (status === google.maps.DirectionsStatus.OK) {
const color = new _color.default(options.color || this._defaultRouteColor()).toHex();
const directionOptions = {
directions: response,
map: this._map,
suppressMarkers: true,
preserveViewport: true,
polylineOptions: {
strokeWeight: options.weight || this._defaultRouteWeight(),
strokeOpacity: options.opacity || this._defaultRouteOpacity(),
strokeColor: color
}
};
const route = new google.maps.DirectionsRenderer(directionOptions);
const {
bounds: bounds
} = response.routes[0];
resolve({
instance: route,
northEast: bounds.getNorthEast(),
southWest: bounds.getSouthWest()
})
} else {
_ui.default.log("W1006", status);
resolve({
instance: new google.maps.DirectionsRenderer({})
})
}
}))
}))))
}
_destroyRoute(routeObject) {
routeObject.instance.setMap(null)
}
_fitBounds() {
this._updateBounds();
if (this._bounds && this._option("autoAdjust")) {
const zoomBeforeFitting = this._map.getZoom();
this._preventZoomChangeEvent = true;
this._map.fitBounds(this._bounds);
this._boundsChangeHandler();
const zoomAfterFitting = this._map.getZoom();
if (zoomBeforeFitting < zoomAfterFitting) {
this._map.setZoom(zoomBeforeFitting)
} else {
this._option("zoom", zoomAfterFitting)
}
delete this._preventZoomChangeEvent
}
return Promise.resolve()
}
_extendBounds(location) {
if (this._bounds) {
this._bounds.extend(location)
} else {
this._bounds = new google.maps.LatLngBounds;
this._bounds.extend(location)
}
}
clean() {
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()
}
}
var _default = exports.default = GoogleProvider;