provider.dynamic.bing.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /**
  2. * DevExtreme (ui/map/provider.dynamic.bing.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var noop = require("../../core/utils/common").noop;
  11. var window = require("../../core/utils/window").getWindow();
  12. var Promise = require("../../core/polyfills/promise");
  13. var extend = require("../../core/utils/extend").extend;
  14. var errors = require("../widget/ui.errors");
  15. var iteratorUtils = require("../../core/utils/iterator");
  16. var DynamicProvider = require("./provider.dynamic");
  17. var Color = require("../../color");
  18. var ajax = require("../../core/utils/ajax");
  19. var isDefined = require("../../core/utils/type").isDefined;
  20. var BING_MAP_READY = "_bingScriptReady";
  21. var BING_URL_V8 = "https://www.bing.com/api/maps/mapcontrol?callback=" + BING_MAP_READY;
  22. var INFOBOX_V_OFFSET_V8 = 13;
  23. var BING_CREDENTIALS = "AhuxC0dQ1DBTNo8L-H9ToVMQStmizZzBJdraTSgCzDSWPsA1Qd8uIvFSflzxdaLH";
  24. var MIN_LOCATION_RECT_LENGTH = 1e-16;
  25. var msMapsLoaded = function() {
  26. return window.Microsoft && window.Microsoft.Maps
  27. };
  28. var msMapsLoader;
  29. var BingProvider = DynamicProvider.inherit({
  30. _mapType: function(type) {
  31. var mapTypes = {
  32. roadmap: Microsoft.Maps.MapTypeId.road,
  33. hybrid: Microsoft.Maps.MapTypeId.aerial,
  34. satellite: Microsoft.Maps.MapTypeId.aerial
  35. };
  36. return mapTypes[type] || mapTypes.road
  37. },
  38. _movementMode: function(type) {
  39. var movementTypes = {
  40. driving: Microsoft.Maps.Directions.RouteMode.driving,
  41. walking: Microsoft.Maps.Directions.RouteMode.walking
  42. };
  43. return movementTypes[type] || movementTypes.driving
  44. },
  45. _resolveLocation: function(location) {
  46. return new Promise(function(resolve) {
  47. var latLng = this._getLatLng(location);
  48. if (latLng) {
  49. resolve(new Microsoft.Maps.Location(latLng.lat, latLng.lng))
  50. } else {
  51. this._geocodeLocation(location).then(function(geocodedLocation) {
  52. resolve(geocodedLocation)
  53. })
  54. }
  55. }.bind(this))
  56. },
  57. _geocodedLocations: {},
  58. _geocodeLocationImpl: function(location) {
  59. return new Promise(function(resolve) {
  60. if (!isDefined(location)) {
  61. resolve(new Microsoft.Maps.Location(0, 0));
  62. return
  63. }
  64. var searchManager = new Microsoft.Maps.Search.SearchManager(this._map);
  65. var searchRequest = {
  66. where: location,
  67. count: 1,
  68. callback: function(searchResponse) {
  69. var result = searchResponse.results[0];
  70. if (result) {
  71. var boundsBox = searchResponse.results[0].location;
  72. resolve(new Microsoft.Maps.Location(boundsBox.latitude, boundsBox.longitude))
  73. } else {
  74. resolve(new Microsoft.Maps.Location(0, 0))
  75. }
  76. }
  77. };
  78. searchManager.geocode(searchRequest)
  79. }.bind(this))
  80. },
  81. _normalizeLocation: function(location) {
  82. return {
  83. lat: location.latitude,
  84. lng: location.longitude
  85. }
  86. },
  87. _normalizeLocationRect: function(locationRect) {
  88. var northWest = this._normalizeLocation(locationRect.getNorthwest());
  89. var southEast = this._normalizeLocation(locationRect.getSoutheast());
  90. return {
  91. northEast: {
  92. lat: northWest.lat,
  93. lng: southEast.lng
  94. },
  95. southWest: {
  96. lat: southEast.lat,
  97. lng: northWest.lng
  98. }
  99. }
  100. },
  101. _loadImpl: function() {
  102. return new Promise(function(resolve) {
  103. if (msMapsLoaded()) {
  104. resolve()
  105. } else {
  106. if (!msMapsLoader) {
  107. msMapsLoader = this._loadMapScript()
  108. }
  109. msMapsLoader.then(function() {
  110. if (msMapsLoaded()) {
  111. resolve();
  112. return
  113. }
  114. this._loadMapScript().then(resolve)
  115. }.bind(this))
  116. }
  117. }.bind(this)).then(function() {
  118. return Promise.all([new Promise(function(resolve) {
  119. Microsoft.Maps.loadModule("Microsoft.Maps.Search", {
  120. callback: resolve
  121. })
  122. }), new Promise(function(resolve) {
  123. Microsoft.Maps.loadModule("Microsoft.Maps.Directions", {
  124. callback: resolve
  125. })
  126. })])
  127. })
  128. },
  129. _loadMapScript: function() {
  130. return new Promise(function(resolve) {
  131. window[BING_MAP_READY] = resolve;
  132. ajax.sendRequest({
  133. url: BING_URL_V8,
  134. dataType: "script"
  135. })
  136. }).then(function() {
  137. try {
  138. delete window[BING_MAP_READY]
  139. } catch (e) {
  140. window[BING_MAP_READY] = void 0
  141. }
  142. })
  143. },
  144. _init: function() {
  145. this._createMap();
  146. return Promise.resolve()
  147. },
  148. _createMap: function() {
  149. var controls = this._option("controls");
  150. this._map = new Microsoft.Maps.Map(this._$container[0], {
  151. credentials: this._keyOption("bing") || BING_CREDENTIALS,
  152. zoom: this._option("zoom"),
  153. showDashboard: controls,
  154. showMapTypeSelector: controls,
  155. showScalebar: controls
  156. })
  157. },
  158. _attachHandlers: function() {
  159. this._providerViewChangeHandler = Microsoft.Maps.Events.addHandler(this._map, "viewchange", this._viewChangeHandler.bind(this));
  160. this._providerClickHandler = Microsoft.Maps.Events.addHandler(this._map, "click", this._clickActionHandler.bind(this))
  161. },
  162. _viewChangeHandler: function() {
  163. var bounds = this._map.getBounds();
  164. this._option("bounds", this._normalizeLocationRect(bounds));
  165. var center = this._map.getCenter();
  166. this._option("center", this._normalizeLocation(center));
  167. if (!this._preventZoomChangeEvent) {
  168. this._option("zoom", this._map.getZoom())
  169. }
  170. },
  171. _clickActionHandler: function(e) {
  172. if ("map" === e.targetType) {
  173. this._fireClickAction({
  174. location: this._normalizeLocation(e.location)
  175. })
  176. }
  177. },
  178. updateDimensions: function() {
  179. var $container = this._$container;
  180. this._map.setOptions({
  181. width: $container.width(),
  182. height: $container.height()
  183. });
  184. return Promise.resolve()
  185. },
  186. updateMapType: function() {
  187. var type = this._option("type");
  188. var labelOverlay = Microsoft.Maps.LabelOverlay;
  189. this._map.setView({
  190. animate: false,
  191. mapTypeId: this._mapType(type),
  192. labelOverlay: "satellite" === type ? labelOverlay.hidden : labelOverlay.visible
  193. });
  194. return Promise.resolve()
  195. },
  196. updateBounds: function() {
  197. return Promise.all([this._resolveLocation(this._option("bounds.northEast")), this._resolveLocation(this._option("bounds.southWest"))]).then(function(result) {
  198. var bounds = new Microsoft.Maps.LocationRect.fromLocations(result[0], result[1]);
  199. this._map.setView({
  200. animate: false,
  201. bounds: bounds
  202. })
  203. }.bind(this))
  204. },
  205. updateCenter: function() {
  206. return this._resolveLocation(this._option("center")).then(function(center) {
  207. this._map.setView({
  208. animate: false,
  209. center: center
  210. })
  211. }.bind(this))
  212. },
  213. updateZoom: function() {
  214. this._map.setView({
  215. animate: false,
  216. zoom: this._option("zoom")
  217. });
  218. return Promise.resolve()
  219. },
  220. updateControls: function() {
  221. this.clean();
  222. return this.render.apply(this, arguments)
  223. },
  224. _renderMarker: function(options) {
  225. return this._resolveLocation(options.location).then(function(location) {
  226. var pushpinOptions = {
  227. icon: options.iconSrc || this._option("markerIconSrc")
  228. };
  229. if (options.html) {
  230. extend(pushpinOptions, {
  231. htmlContent: options.html,
  232. width: null,
  233. height: null
  234. });
  235. var htmlOffset = options.htmlOffset;
  236. if (htmlOffset) {
  237. pushpinOptions.anchor = new Microsoft.Maps.Point((-htmlOffset.left), (-htmlOffset.top))
  238. }
  239. }
  240. var pushpin = new Microsoft.Maps.Pushpin(location, pushpinOptions);
  241. this._map.entities.push(pushpin);
  242. var infobox = this._renderTooltip(location, options.tooltip);
  243. var handler;
  244. if (options.onClick || options.tooltip) {
  245. var markerClickAction = this._mapWidget._createAction(options.onClick || noop);
  246. var markerNormalizedLocation = this._normalizeLocation(location);
  247. handler = Microsoft.Maps.Events.addHandler(pushpin, "click", function() {
  248. markerClickAction({
  249. location: markerNormalizedLocation
  250. });
  251. if (infobox) {
  252. infobox.setOptions({
  253. visible: true
  254. })
  255. }
  256. })
  257. }
  258. return {
  259. location: location,
  260. marker: pushpin,
  261. infobox: infobox,
  262. handler: handler
  263. }
  264. }.bind(this))
  265. },
  266. _renderTooltip: function(location, options) {
  267. if (!options) {
  268. return
  269. }
  270. options = this._parseTooltipOptions(options);
  271. var infobox = new Microsoft.Maps.Infobox(location, {
  272. description: options.text,
  273. offset: new Microsoft.Maps.Point(0, INFOBOX_V_OFFSET_V8),
  274. visible: options.visible
  275. });
  276. infobox.setMap(this._map);
  277. return infobox
  278. },
  279. _destroyMarker: function(marker) {
  280. this._map.entities.remove(marker.marker);
  281. if (marker.infobox) {
  282. marker.infobox.setMap(null)
  283. }
  284. if (marker.handler) {
  285. Microsoft.Maps.Events.removeHandler(marker.handler)
  286. }
  287. },
  288. _renderRoute: function(options) {
  289. return Promise.all(iteratorUtils.map(options.locations, function(point) {
  290. return this._resolveLocation(point)
  291. }.bind(this))).then(function(locations) {
  292. return new Promise(function(resolve) {
  293. var direction = new Microsoft.Maps.Directions.DirectionsManager(this._map);
  294. var color = new Color(options.color || this._defaultRouteColor()).toHex();
  295. var routeColor = new Microsoft.Maps.Color.fromHex(color);
  296. routeColor.a = 255 * (options.opacity || this._defaultRouteOpacity());
  297. direction.setRenderOptions({
  298. autoUpdateMapView: false,
  299. displayRouteSelector: false,
  300. waypointPushpinOptions: {
  301. visible: false
  302. },
  303. drivingPolylineOptions: {
  304. strokeColor: routeColor,
  305. strokeThickness: options.weight || this._defaultRouteWeight()
  306. },
  307. walkingPolylineOptions: {
  308. strokeColor: routeColor,
  309. strokeThickness: options.weight || this._defaultRouteWeight()
  310. }
  311. });
  312. direction.setRequestOptions({
  313. routeMode: this._movementMode(options.mode),
  314. routeDraggable: false
  315. });
  316. iteratorUtils.each(locations, function(_, location) {
  317. var waypoint = new Microsoft.Maps.Directions.Waypoint({
  318. location: location
  319. });
  320. direction.addWaypoint(waypoint)
  321. });
  322. var directionHandlers = [];
  323. directionHandlers.push(Microsoft.Maps.Events.addHandler(direction, "directionsUpdated", function(args) {
  324. while (directionHandlers.length) {
  325. Microsoft.Maps.Events.removeHandler(directionHandlers.pop())
  326. }
  327. var routeSummary = args.routeSummary[0];
  328. resolve({
  329. instance: direction,
  330. northEast: routeSummary.northEast,
  331. southWest: routeSummary.southWest
  332. })
  333. }));
  334. directionHandlers.push(Microsoft.Maps.Events.addHandler(direction, "directionsError", function(args) {
  335. while (directionHandlers.length) {
  336. Microsoft.Maps.Events.removeHandler(directionHandlers.pop())
  337. }
  338. var status = "RouteResponseCode: " + args.responseCode + " - " + args.message;
  339. errors.log("W1006", status);
  340. resolve({
  341. instance: direction
  342. })
  343. }));
  344. direction.calculateDirections()
  345. }.bind(this))
  346. }.bind(this))
  347. },
  348. _destroyRoute: function(routeObject) {
  349. routeObject.instance.dispose()
  350. },
  351. _fitBounds: function() {
  352. this._updateBounds();
  353. if (this._bounds && this._option("autoAdjust")) {
  354. var zoomBeforeFitting = this._map.getZoom();
  355. this._preventZoomChangeEvent = true;
  356. var bounds = this._bounds.clone();
  357. bounds.height = 1.1 * bounds.height;
  358. bounds.width = 1.1 * bounds.width;
  359. this._map.setView({
  360. animate: false,
  361. bounds: bounds,
  362. zoom: zoomBeforeFitting
  363. });
  364. var zoomAfterFitting = this._map.getZoom();
  365. if (zoomBeforeFitting < zoomAfterFitting) {
  366. this._map.setView({
  367. animate: false,
  368. zoom: zoomBeforeFitting
  369. })
  370. } else {
  371. this._option("zoom", zoomAfterFitting)
  372. }
  373. delete this._preventZoomChangeEvent
  374. }
  375. return Promise.resolve()
  376. },
  377. _extendBounds: function(location) {
  378. if (this._bounds) {
  379. this._bounds = new Microsoft.Maps.LocationRect.fromLocations(this._bounds.getNorthwest(), this._bounds.getSoutheast(), location)
  380. } else {
  381. this._bounds = new Microsoft.Maps.LocationRect(location, MIN_LOCATION_RECT_LENGTH, MIN_LOCATION_RECT_LENGTH)
  382. }
  383. },
  384. clean: function() {
  385. if (this._map) {
  386. Microsoft.Maps.Events.removeHandler(this._providerViewChangeHandler);
  387. Microsoft.Maps.Events.removeHandler(this._providerClickHandler);
  388. this._clearMarkers();
  389. this._clearRoutes();
  390. this._map.dispose()
  391. }
  392. return Promise.resolve()
  393. }
  394. });
  395. module.exports = BingProvider;