devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
439 lines (367 loc) • 15 kB
JavaScript
"use strict";
var noop = require("../../core/utils/common").noop,
window = require("../../core/utils/window").getWindow(),
Promise = require("../../core/polyfills/promise"),
extend = require("../../core/utils/extend").extend,
iteratorUtils = require("../../core/utils/iterator"),
DynamicProvider = require("./provider.dynamic"),
Color = require("../../color"),
ajax = require("../../core/utils/ajax"),
isDefined = require("../../core/utils/type").isDefined;
/* global Microsoft */
var BING_MAP_READY = "_bingScriptReady",
BING_URL_V8 = "https://www.bing.com/api/maps/mapcontrol?callback=" + BING_MAP_READY,
INFOBOX_V_OFFSET_V8 = 13,
BING_CREDENTIALS = "AhuxC0dQ1DBTNo8L-H9ToVMQStmizZzBJdraTSgCzDSWPsA1Qd8uIvFSflzxdaLH",
MIN_LOCATION_RECT_LENGTH = 0.0000000000000001;
var msMapsLoaded = function msMapsLoaded() {
return window.Microsoft && window.Microsoft.Maps;
};
var msMapsLoader;
var BingProvider = DynamicProvider.inherit({
_mapType: function _mapType(type) {
var mapTypes = {
roadmap: Microsoft.Maps.MapTypeId.road,
hybrid: Microsoft.Maps.MapTypeId.aerial,
satellite: Microsoft.Maps.MapTypeId.aerial
};
return mapTypes[type] || mapTypes.road;
},
_movementMode: function _movementMode(type) {
var movementTypes = {
driving: Microsoft.Maps.Directions.RouteMode.driving,
walking: Microsoft.Maps.Directions.RouteMode.walking
};
return movementTypes[type] || movementTypes.driving;
},
_resolveLocation: function _resolveLocation(location) {
return new Promise(function (resolve) {
var latLng = this._getLatLng(location);
if (latLng) {
resolve(new Microsoft.Maps.Location(latLng.lat, latLng.lng));
} else {
this._geocodeLocation(location).then(function (geocodedLocation) {
resolve(geocodedLocation);
});
}
}.bind(this));
},
_geocodedLocations: {},
_geocodeLocationImpl: function _geocodeLocationImpl(location) {
return new Promise(function (resolve) {
if (!isDefined(location)) {
resolve(new Microsoft.Maps.Location(0, 0));
return;
}
var searchManager = new Microsoft.Maps.Search.SearchManager(this._map);
var searchRequest = {
where: location,
count: 1,
callback: function callback(searchResponse) {
var result = searchResponse.results[0];
if (result) {
var boundsBox = searchResponse.results[0].location;
resolve(new Microsoft.Maps.Location(boundsBox.latitude, boundsBox.longitude));
} else {
resolve(new Microsoft.Maps.Location(0, 0));
}
}
};
searchManager.geocode(searchRequest);
}.bind(this));
},
_normalizeLocation: function _normalizeLocation(location) {
return {
lat: location.latitude,
lng: location.longitude
};
},
_normalizeLocationRect: function _normalizeLocationRect(locationRect) {
var northWest = this._normalizeLocation(locationRect.getNorthwest()),
southEast = this._normalizeLocation(locationRect.getSoutheast());
return {
northEast: {
lat: northWest.lat,
lng: southEast.lng
},
southWest: {
lat: southEast.lat,
lng: northWest.lng
}
};
},
_loadImpl: function _loadImpl() {
return new Promise(function (resolve) {
if (msMapsLoaded()) {
resolve();
} else {
if (!msMapsLoader) {
msMapsLoader = this._loadMapScript();
}
msMapsLoader.then(function () {
if (msMapsLoaded()) {
resolve();
return;
}
this._loadMapScript().then(resolve);
}.bind(this));
}
}.bind(this)).then(function () {
return Promise.all([new Promise(function (resolve) {
Microsoft.Maps.loadModule('Microsoft.Maps.Search', { callback: resolve });
}), new Promise(function (resolve) {
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', { callback: resolve });
})]);
});
},
_loadMapScript: function _loadMapScript() {
return new Promise(function (resolve) {
window[BING_MAP_READY] = resolve;
ajax.sendRequest({
url: BING_URL_V8,
dataType: "script"
});
}).then(function () {
try {
delete window[BING_MAP_READY];
} catch (e) {
window[BING_MAP_READY] = undefined;
}
});
},
_init: function _init() {
this._createMap();
return Promise.resolve();
},
_createMap: function _createMap() {
var controls = this._option("controls");
this._map = new Microsoft.Maps.Map(this._$container[0], {
credentials: this._keyOption("bing") || BING_CREDENTIALS,
zoom: this._option("zoom"),
showDashboard: controls,
showMapTypeSelector: controls,
showScalebar: controls
});
},
_attachHandlers: function _attachHandlers() {
this._providerViewChangeHandler = Microsoft.Maps.Events.addHandler(this._map, 'viewchange', this._viewChangeHandler.bind(this));
this._providerClickHandler = Microsoft.Maps.Events.addHandler(this._map, 'click', this._clickActionHandler.bind(this));
},
_viewChangeHandler: function _viewChangeHandler() {
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 _clickActionHandler(e) {
if (e.targetType === "map") {
this._fireClickAction({ location: this._normalizeLocation(e.location) });
}
},
updateDimensions: function updateDimensions() {
var $container = this._$container;
this._map.setOptions({
width: $container.width(),
height: $container.height()
});
return Promise.resolve();
},
updateMapType: function updateMapType() {
var type = this._option("type"),
labelOverlay = Microsoft.Maps.LabelOverlay;
this._map.setView({
animate: false,
mapTypeId: this._mapType(type),
labelOverlay: type === "satellite" ? labelOverlay.hidden : labelOverlay.visible
});
return Promise.resolve();
},
updateBounds: function updateBounds() {
return Promise.all([this._resolveLocation(this._option("bounds.northEast")), this._resolveLocation(this._option("bounds.southWest"))]).then(function (result) {
var bounds = new Microsoft.Maps.LocationRect.fromLocations(result[0], result[1]);
this._map.setView({
animate: false,
bounds: bounds
});
}.bind(this));
},
updateCenter: function updateCenter() {
return this._resolveLocation(this._option("center")).then(function (center) {
this._map.setView({
animate: false,
center: center
});
}.bind(this));
},
updateZoom: function updateZoom() {
this._map.setView({
animate: false,
zoom: this._option("zoom")
});
return Promise.resolve();
},
updateControls: function updateControls() {
this.clean();
return this.render.apply(this, arguments);
},
_renderMarker: function _renderMarker(options) {
return this._resolveLocation(options.location).then(function (location) {
var pushpinOptions = {
icon: options.iconSrc || this._option("markerIconSrc")
};
if (options.html) {
extend(pushpinOptions, {
htmlContent: options.html,
width: null,
height: null
});
var htmlOffset = options.htmlOffset;
if (htmlOffset) {
pushpinOptions.anchor = new Microsoft.Maps.Point(-htmlOffset.left, -htmlOffset.top);
}
}
var pushpin = new Microsoft.Maps.Pushpin(location, pushpinOptions);
this._map.entities.push(pushpin);
var infobox = this._renderTooltip(location, options.tooltip);
var handler;
if (options.onClick || options.tooltip) {
var markerClickAction = this._mapWidget._createAction(options.onClick || noop),
markerNormalizedLocation = this._normalizeLocation(location);
handler = Microsoft.Maps.Events.addHandler(pushpin, "click", function () {
markerClickAction({
location: markerNormalizedLocation
});
if (infobox) {
infobox.setOptions({ visible: true });
}
});
}
return {
location: location,
marker: pushpin,
infobox: infobox,
handler: handler
};
}.bind(this));
},
_renderTooltip: function _renderTooltip(location, options) {
if (!options) {
return;
}
options = this._parseTooltipOptions(options);
var infobox = new Microsoft.Maps.Infobox(location, {
description: options.text,
offset: new Microsoft.Maps.Point(0, INFOBOX_V_OFFSET_V8),
visible: options.visible
});
infobox.setMap(this._map);
return infobox;
},
_destroyMarker: function _destroyMarker(marker) {
this._map.entities.remove(marker.marker);
if (marker.infobox) {
this._map.entities.remove(marker.infobox);
}
if (marker.handler) {
Microsoft.Maps.Events.removeHandler(marker.handler);
}
},
_renderRoute: function _renderRoute(options) {
return Promise.all(iteratorUtils.map(options.locations, function (point) {
return this._resolveLocation(point);
}.bind(this))).then(function (locations) {
return new Promise(function (resolve) {
var direction = new Microsoft.Maps.Directions.DirectionsManager(this._map),
color = new Color(options.color || this._defaultRouteColor()).toHex(),
routeColor = new Microsoft.Maps.Color.fromHex(color);
routeColor.a = (options.opacity || this._defaultRouteOpacity()) * 255;
direction.setRenderOptions({
autoUpdateMapView: false,
displayRouteSelector: false,
waypointPushpinOptions: { visible: false },
drivingPolylineOptions: {
strokeColor: routeColor,
strokeThickness: options.weight || this._defaultRouteWeight()
},
walkingPolylineOptions: {
strokeColor: routeColor,
strokeThickness: options.weight || this._defaultRouteWeight()
}
});
direction.setRequestOptions({
routeMode: this._movementMode(options.mode),
routeDraggable: false
});
iteratorUtils.each(locations, function (_, location) {
var waypoint = new Microsoft.Maps.Directions.Waypoint({ location: location });
direction.addWaypoint(waypoint);
});
var handler = Microsoft.Maps.Events.addHandler(direction, 'directionsUpdated', function (args) {
Microsoft.Maps.Events.removeHandler(handler);
var routeSummary = args.routeSummary[0];
resolve({
instance: direction,
northEast: routeSummary.northEast,
southWest: routeSummary.southWest
});
});
direction.calculateDirections();
}.bind(this));
}.bind(this));
},
_destroyRoute: function _destroyRoute(routeObject) {
routeObject.instance.dispose();
},
_fitBounds: function _fitBounds() {
this._updateBounds();
if (this._bounds && this._option("autoAdjust")) {
var zoomBeforeFitting = this._map.getZoom();
this._preventZoomChangeEvent = true;
var bounds = this._bounds.clone();
bounds.height = bounds.height * 1.1;
bounds.width = bounds.width * 1.1;
this._map.setView({
animate: false,
bounds: bounds,
zoom: zoomBeforeFitting
});
var zoomAfterFitting = this._map.getZoom();
if (zoomBeforeFitting < zoomAfterFitting) {
this._map.setView({
animate: false,
zoom: zoomBeforeFitting
});
} else {
this._option("zoom", zoomAfterFitting);
}
delete this._preventZoomChangeEvent;
}
return Promise.resolve();
},
_extendBounds: function _extendBounds(location) {
if (this._bounds) {
this._bounds = new Microsoft.Maps.LocationRect.fromLocations(this._bounds.getNorthwest(), this._bounds.getSoutheast(), location);
} else {
this._bounds = new Microsoft.Maps.LocationRect(location, MIN_LOCATION_RECT_LENGTH, MIN_LOCATION_RECT_LENGTH);
}
},
clean: function clean() {
if (this._map) {
Microsoft.Maps.Events.removeHandler(this._providerViewChangeHandler);
Microsoft.Maps.Events.removeHandler(this._providerClickHandler);
this._clearMarkers();
this._clearRoutes();
this._map.dispose();
}
return Promise.resolve();
}
});
///#DEBUG
BingProvider.remapConstant = function (newValue) {
BING_URL_V8 = newValue;
};
///#ENDDEBUG
module.exports = BingProvider;