Map.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. /*
  2. * This file is part of OsmInEdit, released under ISC license (see LICENSE.md)
  3. *
  4. * Copyright (c) Adrien Pavie 2019
  5. * Copyright (c) Daimler AG 2019
  6. *
  7. * Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  10. *
  11. */
  12. import React, { Component } from 'react';
  13. import 'leaflet/dist/leaflet.css';
  14. import L from 'leaflet';
  15. import 'leaflet-hash';
  16. import { Map, TileLayer, AttributionControl, ScaleControl } from 'react-leaflet';
  17. import Spinner from 'react-bootstrap/Spinner';
  18. import PubSub from 'pubsub-js';
  19. import Body from './Body';
  20. import PACKAGE from '../../package.json';
  21. import Features from './layers/Features';
  22. import FloorImagery from './layers/FloorImagery';
  23. import MoveableObject from './layers/MoveableObject';
  24. import MapStyler from '../model/mapcss/MapStyler';
  25. import LevelSelector from './common/LevelSelector';
  26. import NorthPointer from './common/NorthPointer';
  27. import HistoryTrack from './layers/HistoryTrack';
  28. import POIObject from './layers/POIObject';
  29. import MapUtil from './utils/MapUtil';
  30. /*
  31. * Extend leaflet hash for handling level value
  32. */
  33. L.Hash.parseHash = function (hash) {
  34. if (hash.indexOf('#') === 0) {
  35. hash = hash.substr(1);
  36. }
  37. var args = hash.split("/");
  38. if (args.length >= 3 && args.length <= 4) {
  39. var zoom = parseInt(args[0], 10),
  40. lat = parseFloat(args[1]),
  41. lon = parseFloat(args[2]),
  42. level = args.length === 4 ? parseInt(args[3], 10) : 0;
  43. if (isNaN(zoom) || isNaN(lat) || isNaN(lon)) {
  44. return false;
  45. } else {
  46. return {
  47. center: new L.LatLng(lat, lon),
  48. zoom: zoom,
  49. level: isNaN(level) ? 0 : level
  50. };
  51. }
  52. } else {
  53. return false;
  54. }
  55. };
  56. L.Hash.prototype.parseHash = L.Hash.parseHash;
  57. L.Hash.formatHash = function (map) {
  58. var center = map.getCenter(),
  59. zoom = map.getZoom(),
  60. precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
  61. return "#" + [zoom,
  62. center.lat.toFixed(precision),
  63. center.lng.toFixed(precision),
  64. this._level || "0"
  65. ].join("/");
  66. };
  67. L.Hash.prototype.formatHash = L.Hash.formatHash;
  68. L.Hash.prototype.setLevel = function (lvl) {
  69. if (this._level !== lvl) {
  70. this._level = lvl;
  71. var hash = this.formatHash(this.map);
  72. window.location.replace(hash);
  73. this.lastHash = hash;
  74. }
  75. };
  76. L.Hash.prototype.update = function () {
  77. var hash = window.location.hash;
  78. if (hash === this.lastHash) {
  79. return;
  80. }
  81. var parsed = this.parseHash(hash);
  82. if (parsed) {
  83. this.movingMap = true;
  84. this.map.setView(parsed.center, parsed.zoom);
  85. this.movingMap = false;
  86. PubSub.publish("body.level.set", { level: parsed.level });
  87. } else {
  88. this.onMapMove(this.map);
  89. }
  90. };
  91. /**
  92. * Map component handles the whole map and associated widgets.
  93. */
  94. class MyMap extends Component {
  95. constructor() {
  96. super();
  97. this.state = {
  98. loading: false,
  99. dataready: false,
  100. initHisTrack: false,
  101. center: null,
  102. zoom: null,
  103. minZoom: null,
  104. maxZoom: null,
  105. maxBounds: null,
  106. };
  107. this.mapStyler = new MapStyler();
  108. this.loadedArea = null;
  109. }
  110. /**
  111. * Alert this component that its size has changed
  112. */
  113. invalidateSize() {
  114. if (this.elem && this.elem.leafletElement) {
  115. this.elem.leafletElement.invalidateSize();
  116. this.map = this.elem.leafletElement;
  117. // 设定初始化的值
  118. this.setState({
  119. center: this.props.center,
  120. zoom: this.props.zoom,
  121. minZoom: this.props.minZoom,
  122. maxZoom: this.props.maxZoom,
  123. maxBounds: this.props.maxBounds
  124. })
  125. // // 设置地图中心、缩放
  126. // if (this.props.center) {
  127. // this.setView(this.props.center, this.props.zoom);
  128. // } else {
  129. // this.setZoom(this.props.zoom);
  130. // }
  131. // // 设置缩放范围
  132. // this.setZoomRange(this.props.minZoom, this.props.maxZoom);
  133. // // 设置视图范围
  134. // if (this.props.maxBounds.length === 2) {
  135. // this.setMaxBounds(this.props.maxBounds)
  136. // }
  137. }
  138. }
  139. /**
  140. * Clean up map after changeset upload
  141. */
  142. cleanUp() {
  143. this.loadedArea = null;
  144. this.setState({ loading: false, dataready: false });
  145. }
  146. /**
  147. * 修改地图状态
  148. */
  149. setView(center, zoom) {
  150. if (this.elem && this.elem.leafletElement) {
  151. this.elem.leafletElement.setView(center, zoom);
  152. // this.setState({
  153. // center: latlng,
  154. // zoom: zoom
  155. // })
  156. } else {
  157. console.error('setView')
  158. }
  159. }
  160. setCenter(center) {
  161. if (this.elem && this.elem.leafletElement) {
  162. this.elem.leafletElement.pathTo(center);
  163. // this.setState({
  164. // center: latlng
  165. // })
  166. } else {
  167. console.error('setCenter')
  168. }
  169. }
  170. setZoom(zoom) {
  171. if (this.elem && this.elem.leafletElement) {
  172. this.elem.leafletElement.setZoom(zoom);
  173. // this.setState({
  174. // zoom: zoom
  175. // })
  176. } else {
  177. console.error('setZoom')
  178. }
  179. }
  180. setMinZoom(zoom) {
  181. if (this.elem && this.elem.leafletElement) {
  182. this.elem.leafletElement.setMinZoom(zoom);
  183. // this.setState({
  184. // minZoom: zoom
  185. // })
  186. } else {
  187. console.error('setMinZoom')
  188. }
  189. }
  190. setMaxZoom(zoom) {
  191. if (this.elem && this.elem.leafletElement) {
  192. this.elem.leafletElement.setMaxZoom(zoom);
  193. // this.setState({
  194. // maxZoom: zoom
  195. // })
  196. } else {
  197. console.error('setMaxZoom')
  198. }
  199. }
  200. setZoomRange(min, max) {
  201. if (this.elem && this.elem.leafletElement) {
  202. this.elem.leafletElement.setMinZoom(min);
  203. this.elem.leafletElement.setMaxZoom(max);
  204. // this.setState({
  205. // minZoom: min,
  206. // maxZoom: max
  207. // })
  208. } else {
  209. console.error('setZoomRange')
  210. }
  211. }
  212. setMaxBounds(corner) {
  213. let corner1 = L.latLng(corner[0]), corner2 = L.latLng(corner[1]);
  214. let bounds = L.latLngBounds(corner1, corner2)
  215. if (this.elem && this.elem.leafletElement) {
  216. this.elem.leafletElement.setMaxBounds(bounds)
  217. // this.setState({
  218. // maxBounds: bounds
  219. // })
  220. } else {
  221. console.error('setMaxBounds')
  222. }
  223. }
  224. /**
  225. * @param {Array} [10, 20] [-20, 10]
  226. */
  227. pathTo(center) {
  228. if (this.elem && this.elem.leafletElement) {
  229. this.elem.leafletElement.pathTo(center)
  230. } else {
  231. console.error('pathTo')
  232. }
  233. }
  234. /**
  235. * @param {Array/Object} center [10, 20] {lat: 10, lng: 10}
  236. * @param {Number} zoom 18
  237. */
  238. flyTo(center, zoom) {
  239. if (this.elem && this.elem.leafletElement) {
  240. this.elem.leafletElement.flyTo(center, zoom)
  241. } else {
  242. console.error('flyTo')
  243. }
  244. }
  245. /**
  246. * 获取地图状态
  247. */
  248. /**
  249. * Get the coordinates of map center
  250. * @return {LatLng} Coordinates of map center (or null if not ready)
  251. */
  252. getCenter() {
  253. return (this.elem && this.elem.leafletElement) ? this.elem.leafletElement.getCenter() : null;
  254. }
  255. getZoom() {
  256. return (this.elem && this.elem.leafletElement) ? this.elem.leafletElement.getZoom() : null;
  257. }
  258. getMinZoom() {
  259. return (this.elem && this.elem.leafletElement) ? this.elem.leafletElement.getMinZoom() : null;
  260. }
  261. getMaxZoom() {
  262. return (this.elem && this.elem.leafletElement) ? this.elem.leafletElement.getMaxZoom() : null;
  263. }
  264. getZoomRange() {
  265. return (this.elem && this.elem.leafletElement) ? [this.elem.leafletElement.getMinZoom(), this.elem.leafletElement.getMaxZoom()] : [];
  266. }
  267. getContainerSize() {
  268. return (this.elem && this.elem.leafletElement) ? this.elem.leafletElement.getSize() : null;
  269. }
  270. /**
  271. * Get the bounding box of currently shown area on map
  272. * @return {LatLngBounds} Bounding box of the map
  273. */
  274. getBounds() {
  275. return (this.elem && this.elem.leafletElement) ? this.elem.leafletElement.getBounds() : null;
  276. }
  277. /**
  278. * Is the map currently loading data ?
  279. * @return {boolean} True if loading
  280. */
  281. isLoading() {
  282. return this.state.loading;
  283. }
  284. /**
  285. * Event handler when map moves
  286. * @private
  287. */
  288. async _loadData(bounds) {
  289. // (this.props.datalocked || (window.CONFIG.always_authenticated && !window.editor_user))
  290. if (this.props.datalocked) {
  291. return new Promise(resolve => {
  292. setTimeout(() => resolve(this._loadData(bounds)), 100);
  293. });
  294. }
  295. else if (!this.props.draw && this.getBounds() && this.elem.leafletElement.getZoom() >= window.CONFIG.data_min_zoom) {
  296. let bbox = bounds || this.getBounds();
  297. // Only load data if bbox is valid and not in an already downloaded area
  298. if (
  299. bbox
  300. && bbox.getSouth() !== bbox.getNorth()
  301. && bbox.getWest() !== bbox.getEast()
  302. && (!this.loadedArea || !this.loadedArea.contains(bbox))
  303. ) {
  304. // Augment bbox size if too small (to avoid many data reloads)
  305. while (bbox.getSouthWest().distanceTo(bbox.getNorthEast()) < 400) {
  306. bbox = bbox.pad(0.1);
  307. }
  308. this.loadedArea = bbox;
  309. this.setState(
  310. { loading: true },
  311. async () => {
  312. try {
  313. const result = await window.vectorDataManager.loadOSMData(bbox);
  314. this.setState({ loading: false, dataready: result });
  315. }
  316. catch (e) {
  317. alert("Can't download data from OSM server. Please retry later.");
  318. this.setState({ loading: false, dataready: false });
  319. }
  320. }
  321. );
  322. }
  323. }
  324. }
  325. /**
  326. * Generate layer from given configuration
  327. * @private
  328. */
  329. _getLayer(min, max) {
  330. const url = "https://webrd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}";
  331. return <TileLayer
  332. attribution="&copy 高德地图"
  333. url={url}
  334. key={url} // 'amap'
  335. minZoom={min}
  336. maxZoom={max}
  337. maxNativeZoom={18} // 瓦片源即高德地图可用最大缩放数
  338. />;
  339. }
  340. /**
  341. * Converts floor imagery info into a Leaflet layer.
  342. * @private
  343. */
  344. _getFloorMapLayer(floormap) {
  345. if (!floormap || !floormap.topleft) {
  346. return null;
  347. }
  348. else {
  349. return <FloorImagery
  350. data={floormap}
  351. key={floormap.id}
  352. opacity={floormap.opacity !== undefined && !isNaN(parseFloat(floormap.opacity)) ? floormap.opacity : 1}
  353. ref={"floormap_" + floormap.id}
  354. level={this.props.level}
  355. mode={this.props.mode}
  356. tool={this.props.floorImageryMode}
  357. />;
  358. }
  359. }
  360. render() {
  361. // const floorImgs = window.imageryManager.getFloorImages();
  362. let levelsList = null;
  363. if (this.props.mode === Body.MODE_EXPLORE) {
  364. levelsList = window.vectorDataManager.getAllLevels(true);
  365. }
  366. else if (this.props.mode === Body.MODE_BUILDING) {
  367. if (this.props.building) {
  368. levelsList = this.props.building.properties.own.levels.slice(0);
  369. levelsList.sort();
  370. }
  371. else {
  372. levelsList = window.vectorDataManager.getAllLevels(false);
  373. }
  374. }
  375. else if ([Body.MODE_LEVELS, Body.MODE_FEATURES].includes(this.props.mode) && this.props.building) {
  376. levelsList = this.props.building.properties.own.levels.slice(0);
  377. levelsList.sort();
  378. }
  379. return <div className="app-map-container">
  380. {(this.props.mode === Body.MODE_CHANGESET || this.state.loading) &&
  381. <div style={{
  382. zIndex: 20000,
  383. background: "rgba(0,0,0,0.5)",
  384. position: "absolute",
  385. top: 0, right: 0, left: 0, bottom: 0,
  386. textAlign: "center", display: "flex", alignItems: "center"
  387. }}>
  388. {this.state.loading &&
  389. <Spinner
  390. animation="grow"
  391. variant="light"
  392. size="lg"
  393. style={{ margin: "auto", width: "5rem", height: "5rem" }}
  394. />
  395. }
  396. </div>
  397. }
  398. <Map
  399. center={this.props.center}
  400. zoom={this.props.zoom}
  401. minZoom={this.props.minZoom}
  402. maxZoom={this.props.maxZoom}
  403. maxBounds={this.props.maxBounds}
  404. className={"app-map" + (this.props.draw ? " leaflet-clickable" : "")}
  405. ref={elem => this.elem = elem}
  406. preferCanvas={false}
  407. editable={true}
  408. scrollWheelZoom={true}
  409. doubleClickZoom={this.props.mode === Body.MODE_EXPLORE}
  410. attributionControl={false}
  411. boxSelector={false}
  412. boxZoom={false}
  413. >
  414. <AttributionControl
  415. prefix={window.MAP_NAME + " v" + PACKAGE.version}
  416. />
  417. <ScaleControl
  418. position="bottomleft"
  419. imperial={false}
  420. />
  421. <NorthPointer
  422. position="bottomright"
  423. />
  424. {[Body.MODE_EXPLORE, Body.MODE_BUILDING, Body.MODE_LEVELS, Body.MODE_FEATURES].includes(this.props.mode) && !this.state.loading && this.state.dataready && levelsList &&
  425. <LevelSelector
  426. position="topright"
  427. levels={levelsList}
  428. level={this.props.level}
  429. />
  430. }
  431. {this._getLayer(this.props.minZoom, this.props.maxZoom)}
  432. {/* {this.props.selectedBaseImagery && this._getLayer(this.props.selectedBaseImagery, this.props.baseImageryOpacity)} */}
  433. {/* {this.props.selectedOverlaysImagery && this.props.selectedOverlaysImagery.map(ol => this._getLayer(ol, this.props.overlaysImageryOpacity))} */}
  434. {/* {this.props.mode !== Body.MODE_EXPLORE && floorImgs && floorImgs.map(fi => this._getFloorMapLayer(fi))} */}
  435. {/* {!this.state.loading && this.state.dataready && [Body.MODE_BUILDING, Body.MODE_FLOOR_IMAGERY].includes(this.props.mode) &&
  436. <Building
  437. styler={this.mapStyler}
  438. building={this.props.building}
  439. draw={this.props.draw}
  440. center={this.props.level}
  441. locked={this.props.mode === Body.MODE_FLOOR_IMAGERY}
  442. />
  443. } */}
  444. {/* {!this.state.loading && this.state.dataready && this.props.mode === Body.MODE_LEVELS && this.props.building &&
  445. <Levels
  446. styler={this.mapStyler}
  447. level={this.props.level}
  448. building={this.props.building}
  449. floor={this.props.floor}
  450. draw={this.props.draw}
  451. />
  452. } */}
  453. {!this.state.loading && this.state.dataready && (this.props.mode === Body.MODE_EXPLORE || (this.props.mode === Body.MODE_FEATURES && this.props.building)) &&
  454. <Features
  455. styler={this.mapStyler}
  456. level={this.props.level}
  457. building={this.props.building}
  458. feature={this.props.feature}
  459. draw={this.props.draw}
  460. locked={this.props.mode === Body.MODE_EXPLORE}
  461. />
  462. }
  463. {!this.state.loading && this.state.dataready &&
  464. <MoveableObject
  465. styler={this.mapStyler}
  466. level={this.props.level}
  467. floor={this.props.floor}
  468. />
  469. }
  470. {!this.state.loading && this.state.dataready &&
  471. <POIObject
  472. styler={this.mapStyler}
  473. level={this.props.level}
  474. floor={this.props.floor}
  475. />
  476. }
  477. {this.state.initHisTrack &&
  478. <HistoryTrack
  479. map={this.elem}
  480. />
  481. }
  482. </Map>
  483. </div>;
  484. }
  485. /**
  486. * @private
  487. */
  488. _followMouse(e) {
  489. this._mouseCoords = e.latlng;
  490. // console.log(e.latlng)
  491. }
  492. /**
  493. * @private
  494. */
  495. _MouseClick(e) {
  496. this._mouseCoords = e.latlng;
  497. // console.log(e.latlng)
  498. }
  499. componentDidMount() {
  500. setTimeout(() => {
  501. this.invalidateSize();
  502. this._loadData();
  503. }, 500);
  504. MapUtil.map = this.elem.leafletElement;
  505. // URL hash for map
  506. this._mapHash = new L.Hash(this.elem.leafletElement);
  507. // If no valid hash found, use default coordinates from config file or stored cookie
  508. if (!window.location.hash || !window.location.hash.match(/^#\d+\/-?\d+(.\d+)?\/-?\d+(.\d+)?(\/(-?\d+(.\d+)?)?)?$/)) {
  509. // Has cookie ?
  510. const cookieHash = document.cookie.replace(/(?:(?:^|.*;\s*)lasthash\s*=\s*([^;]*).*$)|^.*$/, "$1");
  511. let newHash;
  512. if (cookieHash && L.Hash.parseHash(cookieHash)) {
  513. newHash = cookieHash;
  514. }
  515. else {
  516. newHash = "#" + window.CONFIG.map_initial_zoom + "/" + window.CONFIG.map_initial_latlng.join("/");
  517. }
  518. window.history.pushState({}, "", window.location.href.split("#")[0] + newHash);
  519. }
  520. L.DomEvent.addListener(window, "hashchange", () => {
  521. document.cookie = "lasthash=" + window.location.hash;
  522. });
  523. this.elem.leafletElement.on("dblclick", e => {
  524. if (!this.props.draw && this.props.mode !== Body.MODE_EXPLORE) {
  525. PubSub.publish("body.unselect.feature");
  526. }
  527. });
  528. this.elem.leafletElement.on("zoomend moveend", () => {
  529. if (this.elem && this.elem.leafletElement) {
  530. this._loadData();
  531. const zoom = this.elem.leafletElement.getZoom();
  532. if (zoom < window.CONFIG.data_min_zoom && (!this._lastZoom || this._lastZoom >= window.CONFIG.data_min_zoom)) {
  533. this.elem.container.classList.add("app-map-novector");
  534. PubSub.publishSync("body.unselect.feature");
  535. // PubSub.publish("body.mode.set", { mode: Body.MODE_BUILDING });
  536. }
  537. else if (zoom >= window.CONFIG.data_min_zoom && (!this._lastZoom || this._lastZoom < window.CONFIG.data_min_zoom)) {
  538. this.elem.container.classList.remove("app-map-novector");
  539. }
  540. this._lastZoom = zoom;
  541. }
  542. });
  543. // Follow mouse position
  544. this.elem.leafletElement.on("mousemove", this._followMouse, this);
  545. // Mouse Click position
  546. this.elem.leafletElement.on("click", this._MouseClick, this);
  547. /**
  548. * Event for map zoom changes
  549. * @event map.zoom.changed
  550. * @memberof MyMap
  551. * @property {int} zoom The new zoom level
  552. */
  553. const alertZoom = () => {
  554. if (this.elem && this.elem.leafletElement) {
  555. PubSub.publish("map.zoom.changed", { zoom: this.elem.leafletElement.getZoom() });
  556. }
  557. };
  558. this.elem.leafletElement.on("zoomend", alertZoom);
  559. alertZoom();
  560. /**
  561. * Event for changing current map position
  562. * @event map.position.set
  563. * @memberof MyMap
  564. * @property {LatLng} coordinates The new position
  565. * @property {int} [zoom] The zoom level
  566. */
  567. PubSub.subscribe("map.position.set", (msg, data) => {
  568. if (data.bbox) {
  569. const [minlat, maxlat, minlon, maxlon] = data.bbox;
  570. this.elem.leafletElement.fitBounds([[minlat, minlon], [maxlat, maxlon]]);
  571. }
  572. else if (data.zoom) {
  573. this.elem.leafletElement.setView(data.coordinates, data.zoom);
  574. }
  575. else {
  576. this.elem.leafletElement.panTo(data.coordinates);
  577. }
  578. });
  579. PubSub.subscribe("map.his.init", (msg, data) => {
  580. this.setState({
  581. initHisTrack: true
  582. });
  583. });
  584. PubSub.subscribe("map.event.bind", (msg, data) => {
  585. if (data.eventName === 'contextmenu') {
  586. this.elem.leafletElement.addEventListener(data.eventName, data.callback);
  587. return;
  588. }
  589. this.elem.leafletElement.on(data.eventName, data.callback);
  590. });
  591. PubSub.subscribe("map.event.unbind", (msg, data) => {
  592. if (data.eventName === 'contextmenu') {
  593. this.elem.leafletElement.removeEventListener(data.eventName, data.callback);
  594. return;
  595. }
  596. if (!data.callback) {
  597. this.elem.leafletElement.off(data.eventName);
  598. return;
  599. }
  600. this.elem.leafletElement.off(data.eventName, data.callback);
  601. });
  602. }
  603. componentDidUpdate(fromProps) {
  604. if (this.props.level !== fromProps.level) {
  605. this._mapHash.setLevel(this.props.level);
  606. }
  607. // const floorImgs = window.imageryManager.getFloorImages();
  608. // Force update of floor imagery after mode change
  609. if (fromProps.mode !== this.props.mode) {
  610. this.invalidateSize();
  611. // floorImgs.forEach(img => {
  612. // // Check if we have a leaflet layer
  613. // if (this.refs["floormap_" + img.id]) {
  614. // this.refs["floormap_" + img.id].forceUpdate();
  615. // }
  616. // });
  617. }
  618. // Mouse Click position
  619. this.elem.leafletElement.off("click", this._MouseClick, this);
  620. this.elem.leafletElement.on("click", this._MouseClick, this);
  621. // Follow mouse position
  622. this.elem.leafletElement.off("mousemove", this._followMouse, this);
  623. this.elem.leafletElement.on("mousemove", this._followMouse, this);
  624. // Load wider area if necessary
  625. if (!this.props.draw && !this.state.loading && this.elem.leafletElement.getZoom() > 19) {
  626. this._loadData(this.getBounds().pad(0.5 * (this.elem.leafletElement.getZoom() - 19)));
  627. }
  628. }
  629. componentWillUnmount() {
  630. PubSub.unsubscribe("map");
  631. this.elem.leafletElement.off("click", this._MouseClick, this);
  632. this.elem.leafletElement.off("mousemove", this._followMouse, this);
  633. this.elem.leafletElement.off("load");
  634. this.elem.leafletElement.off("zoomend");
  635. this.elem.leafletElement.off("moveend");
  636. this.elem.leafletElement.off("dblclick");
  637. }
  638. }
  639. export default MyMap;