UNPKG

iovmap

Version:
419 lines (344 loc) 10.4 kB
import L from 'leaflet' import './Leaflet.CustomLayer.js' import AMapLoader from '@amap/amap-jsapi-loader' const AMAP_STYLES = { normal: 'amap://styles/normal', dark: 'amap://styles/dark', light: 'amap://styles/light', whitesmoke: 'amap://styles/whitesmoke', fresh: 'amap://styles/fresh', grey: 'amap://styles/grey', graffiti: 'amap://styles/graffiti', macaron: 'amap://styles/macaron', blue: 'amap://styles/blue', darkblue: 'amap://styles/darkblue', wine: 'amap://styles/wine', } const DEFAULT_CONFIG = { minZoom: 3, maxZoom: 20, padding: 0, opacity: 1, visible: true, zIndex: 100, corrdType: 'gcj02', viewMode: '2D', mapType: 'roadmap', mapStyle: 'normal', apiKey: '1fac5a5127fbe35e0219f295a506309b', securityConfig: { securityJsCode: '171de1c8624b802ac3c9e53c691721a9', }, amapConfig: { zoomEnable: true, dragEnable: true, resizeEnable: false, animateEnable: false, jogEnable: false, doubleClickZoom: false, keyboardEnable: false, scrollWheel: true, }, } let amapSdkPromise = null function mergeOptions(options) { const merged = Object.assign({}, DEFAULT_CONFIG, options) merged.securityConfig = Object.assign({}, DEFAULT_CONFIG.securityConfig, options && options.securityConfig) merged.amapConfig = Object.assign({}, DEFAULT_CONFIG.amapConfig, options && options.amapConfig) merged.mapStyle = (options && options.mapStyle) || merged.amapConfig.mapStyle || DEFAULT_CONFIG.mapStyle delete merged.amapConfig.mapStyle return merged } function convertMapStyleName(style) { return style in AMAP_STYLES ? AMAP_STYLES[style] : style } function convertCenter(latlng, corrdType) { if (!latlng || !L.coordConver) { return latlng } if (corrdType === 'gcj02') { const center = L.coordConver().gps84_To_gcj02(latlng.lng, latlng.lat) return L.latLng(center.lat, center.lng) } if (corrdType === 'bd09') { const center = L.coordConver().gps84_To_bd09(latlng.lng, latlng.lat) return L.latLng(center.lat, center.lng) } return latlng } function normalizeZoomRange(minZoom, maxZoom) { const min = Number(minZoom) const max = Number(maxZoom) const normalizedMin = Number.isFinite(min) ? min : DEFAULT_CONFIG.minZoom const normalizedMax = Number.isFinite(max) ? max : DEFAULT_CONFIG.maxZoom if (normalizedMin > normalizedMax) { return [normalizedMax, normalizedMin] } return [normalizedMin, normalizedMax] } const AmapLayer = L.CustomLayer.extend({ options: DEFAULT_CONFIG, initialize(options) { const mergedOptions = mergeOptions(options) const container = document.createElement('div') const host = document.createElement('div') container.className = 'leaflet-amap-layer' container.style.position = 'absolute' container.style.pointerEvents = 'auto' container.style.background = 'transparent' container.style.overflow = 'hidden' host.className = 'leaflet-amap-layer-host' host.style.position = 'absolute' host.style.left = '0' host.style.top = '0' host.style.width = '100%' host.style.height = '100%' host.style.pointerEvents = 'auto' host.style.background = 'transparent' container.appendChild(host) this._amap = null this._amapHost = host this._isLoaded = false this._loadPromise = null this._mapStyle = mergedOptions.mapStyle this._amapCenter = null this._previousMapMinZoom = null this._previousMapMaxZoom = null L.CustomLayer.prototype.initialize.call( this, Object.assign({}, mergedOptions, { container, }), ) this.on('layer-render', this._handleLayerRender, this) this.on('layer-mounted', this._handleLayerMounted, this) }, onAdd(map) { L.CustomLayer.prototype.onAdd.call(this, map) this._applyLeafletZoomRange(map) this._loadAndCreateMap() }, onRemove(map) { this._destroyAmap() this._restoreLeafletZoomRange(map) L.CustomLayer.prototype.onRemove.call(this, map) }, setVisible(visible) { this.options.visible = visible if (visible) { this.show() } else { this.hide() } return this }, show() { L.CustomLayer.prototype.show.call(this) if (this._amap) { this._handleLayerRender() } return this }, hide() { L.CustomLayer.prototype.hide.call(this) return this }, setMapStyle(style) { this._mapStyle = style this.options.mapStyle = style if (this._amap && this.options.mapType === 'roadmap') { this._amap.setMapStyle(convertMapStyleName(style)) } return this }, getMapStyle() { return this._mapStyle }, getAvailableStyles() { return AMAP_STYLES }, getAmapInstance() { return this._amap }, getCustomLayer() { return this }, destroy() { if (this._map) { this.remove() } else { this._destroyAmap() if (this._container) { L.DomUtil.remove(this._container) this._container = null } } return this }, isLayerLoaded() { return this._isLoaded }, _convertCenter(center) { return convertCenter(center, this.options.corrdType) }, _updateTransform(_center, zoom) { L.CustomLayer.prototype._updateTransform.call(this, _center, zoom) }, __update() { L.CustomLayer.prototype.__update.call(this) this._amapCenter = this._convertCenter(this._center) }, _loadAndCreateMap() { if (this._loadPromise) { return this._loadPromise } this._loadPromise = this._loadAmapSDK().then(() => { if (!this._container || !this._amapHost || !this._map || this._amap) { return } const amapConfig = Object.assign({}, this.options.amapConfig) if (this.options.mapType === 'roadmap' && this.options.mapStyle) { amapConfig.mapStyle = convertMapStyleName(this.options.mapStyle) } const zooms = normalizeZoomRange(this.options.minZoom, this.options.maxZoom) const center = this._convertCenter(this._map.getCenter()) const mapOptions = Object.assign({}, amapConfig, { viewMode: this.options.viewMode, zoom: this._limitZoom(this._map.getZoom()), zooms, center: [center.lng, center.lat], zoomEnable: true, dragEnable: true, resizeEnable: false, animateEnable: false, jogEnable: false, doubleClickZoom: false, keyboardEnable: false, scrollWheel: true, }) const layers = this._createAmapLayers(window.AMap) if (layers.length) { mapOptions.layers = layers } this._syncContainerSize() this._amap = new window.AMap.Map(this._amapHost, mapOptions) this._amap.setStatus({ zoomEnable: true, dragEnable: true, animateEnable: false, jogEnable: false, doubleClickZoom: false, keyboardEnable: false, scrollWheel: true, }) this._isLoaded = true this._handleLayerRender() }) return this._loadPromise }, _loadAmapSDK() { if (window.AMap) { return Promise.resolve(window.AMap) } if (!amapSdkPromise) { window._AMapSecurityConfig = this.options.securityConfig || {} amapSdkPromise = AMapLoader.load({ key: this.options.apiKey, version: '2.0', plugins: [], }) } return amapSdkPromise }, _createAmapLayers(AMap) { switch (this.options.mapType) { case 'satellite': return [new AMap.TileLayer.Satellite()] case 'roadnet': return [new AMap.TileLayer.RoadNet()] case 'hybrid': return [new AMap.TileLayer.Satellite(), new AMap.TileLayer.RoadNet()] default: return [] } }, _handleLayerMounted() { this._syncContainerSize() }, _handleLayerRender() { if (!this._amap || !this._zoomVisible) { return } this._syncContainerSize() const zoom = this._zoom != null ? this._zoom : this._map.getZoom() const center = this._amapCenter || this._convertCenter(this._center || this._map.getCenter()) this._amap.resize() this._amap.setZoomAndCenter(this._limitZoom(zoom), [center.lng, center.lat], true) }, _limitZoom(zoom) { const zooms = normalizeZoomRange(this.options.minZoom, this.options.maxZoom) return Math.max(zooms[0], Math.min(zooms[1], zoom)) }, _applyLeafletZoomRange(map) { if (!map) { return } const zooms = normalizeZoomRange(this.options.minZoom, this.options.maxZoom) this._previousMapMinZoom = map.options.minZoom this._previousMapMaxZoom = map.options.maxZoom if (map.setMinZoom) { map.setMinZoom(zooms[0]) } else { map.options.minZoom = zooms[0] } if (map.setMaxZoom) { map.setMaxZoom(zooms[1]) } else { map.options.maxZoom = zooms[1] } if (map.getZoom() < zooms[0] || map.getZoom() > zooms[1]) { map.setZoom(this._limitZoom(map.getZoom())) } }, _restoreLeafletZoomRange(map) { if (!map) { return } if (map.setMinZoom) { map.setMinZoom(this._previousMapMinZoom) } else { map.options.minZoom = this._previousMapMinZoom } if (map.setMaxZoom) { map.setMaxZoom(this._previousMapMaxZoom) } else { map.options.maxZoom = this._previousMapMaxZoom } this._previousMapMinZoom = null this._previousMapMaxZoom = null }, _syncContainerSize() { if (!this._map || !this._container || !this._amapHost) { return } const size = this._map.getSize() this._container.style.width = `${size.x}px` this._container.style.height = `${size.y}px` this._container.style.padding = '0' this._amapHost.style.width = `${size.x}px` this._amapHost.style.height = `${size.y}px` }, _destroyAmap() { if (this._amap) { this._amap.destroy() this._amap = null } this._amapCenter = null this._isLoaded = false this._loadPromise = null }, }) function createAmapLayer(options) { return new AmapLayer(options) } export { AmapLayer, createAmapLayer, AMAP_STYLES }