UNPKG

iovmap

Version:
923 lines (913 loc) 29.7 kB
/* * Copyright (C) 2017 dehai.site All Rights Reserved. * * @author level <dehai168@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict' import L from 'leaflet' import proj4leaflet from 'proj4leaflet' import MiniMap from 'leaflet-minimap' import { Config } from '../config' import mapCorrection from '../plugin/leaflet.mapCorrection' import '../plugin/Leaflet.GoogleMutant' import { AmapLayer } from '../plugin/leaflet.AmapLayer' import { MercatorTileLayer } from '../plugin/leaflet.MercatorTileLayer' //引入样式 import 'leaflet-minimap/dist/Control.MiniMap.min.css' export class Map { /** * 初始化地图 * @param {String} domid 标签元素id * @param {Object} options 地图参数 */ constructor(domid, options) { let zoom = options.zoom || 5 let center = options.center || [34.161818, 106.523438] this.config = new Config() // 保存初始化选项,供 openFlyEye 等方法创建新图层时使用(如 Google Maps 需要 key) this._mapOptions = options const option = { zoomControl: false, attributionControl: false, zoom, center, } this.map = new L.map(domid, option) this._initMap(options) if (options.type === 'BMap') { this.map.setView(center, zoom) } this.map.addControl(L.control.zoom({ position: 'topright' })) this.map.addControl(L.control.scale()) } _initMap(options) { let crs = L.CRS.EPSG3857 // 默认使用3857 if (options.type.indexOf('BMap') > -1) { crs = this._getCRS('BMap') } this.type = options.type this.map.options.crs = crs this.hideRoadGrid() const savedTile = this._customTileConfig this._removeCustomLayerOnly() if (this.mapLayer) { // 如果有地图图层,先移除旧的图层 this.map.removeLayer(this.mapLayer) } this.mapLayer = this._getLayer(options.type, options) this.map.addLayer(this.mapLayer) // 切换 CRS 后强制刷新像素原点,否则叠加层可能算错位置 try { const c = this.map.getCenter() const z = this.map.getZoom() if (typeof this.map._resetView === 'function') { this.map._resetView(c, z) } } catch (e) { /* ignore */ } // 切换底图后按新坐标系重新挂载自定义瓦片 if (savedTile) { this._customTileConfig = savedTile this._mountTileLayer(savedTile.url, savedTile.options) } } /** * 是否使用百度自定义 CRS(与 EPSG:3857 切片方案不兼容,需走内部兼容层) */ _isBaiduCrs() { return !!(this.type && this.type.indexOf('BMap') > -1) } _getLayer(type, options) { let mapLayer = null switch (type) { case 'BMap': mapLayer = new L.tileLayer( 'https://ss{s}.bdstatic.com/8bo_dTSlR1gBo1vgoIiO_jowehsv/tile/?qt=vtile&x={x}&y={y}&z={z}&styles=pl&udt=20190125&scaler=1', { maxZoom: 18, minZoom: 5, subdomains: [0, 1, 2, 3], attribution: 'ⓒ Baidu', tms: true, }, ) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'bd09' break case 'BMap_Road_Grid': mapLayer = new L.tileLayer( 'https://ss{s}.bdstatic.com/8bo_dTSlR1gBo1vgoIiO_jowehsv/tile/?qt=vtile&x={x}&y={y}&z={z}&styles=sl&showtext=1&udt=20250807&v=083', { maxZoom: 17, minZoom: 5, subdomains: [0, 1, 2, 3], attribution: 'ⓒ Baidu', tms: true, }, ) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'bd09' break case 'BMap_Sate': mapLayer = new L.tileLayer( 'https://ss{s}.bdstatic.com/8bo_dTSlR1gBo1vgoIiO_jowehsv/starpic/?qt=satepc&u=x={x};y={y};z={z};v=009;type=sate&fm=46&app=webearth2&v=009&udt=20190305', { maxZoom: 17, minZoom: 5, subdomains: [0, 1, 2, 3], attribution: 'ⓒ Baidu', tms: true, }, ) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'bd09' break case 'BMap_Custom_midnight': //light,redalert,googlelite,grassgreen,pink,darkgreen,bluish,grayscale,hardedge mapLayer = new L.tileLayer( 'http://api{s}.map.bdimg.com/customimage/tile?&x={x}&y={y}&z={z}&udt=20190305&scale=1&customid=midnight', { maxZoom: 18, minZoom: 5, subdomains: [0, 1, 2], attribution: 'ⓒ Baidu', tms: true, }, ) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'bd09' break case 'BMap_Custom_dark': mapLayer = new L.tileLayer( 'http://api{s}.map.bdimg.com/customimage/tile?&x={x}&y={y}&z={z}&udt=20190305&scale=1&customid=dark', { maxZoom: 18, minZoom: 5, subdomains: [0, 1, 2], attribution: 'ⓒ Baidu', tms: true, }, ) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'bd09' break case 'BMap_Custom_grayscale': mapLayer = new L.tileLayer( 'http://api{s}.map.bdimg.com/customimage/tile?&x={x}&y={y}&z={z}&udt=20190305&scale=1&customid=grayscale', { maxZoom: 18, minZoom: 5, subdomains: [0, 1, 2], attribution: 'ⓒ Baidu', tms: true, }, ) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'bd09' break case 'GMap_CN': mapLayer = new L.tileLayer( 'http://mt{s}.google.cn/vt/lyrs=m@160000000&hl=zh-CN&gl=CN&src=app&y={y}&x={x}&z={z}&s=Ga', { subdomains: [0, 1, 2, 3], attribution: '© <a href="http://www.google.cn/maps">GoogleMap</a> contributors', }, ) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'gcj02' break case 'GMap_Sate_CN': mapLayer = new L.tileLayer('http://mt{s}.google.cn/vt/lyrs=s@821&gl=cn&x={x}&y={y}&z={z}', { subdomains: [0, 1, 2, 3], attribution: '© <a href="http://www.google.cn/maps">GoogleMap</a> contributors', }) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'gcj02' break case 'GMap': // 目前国内地图部分坐标有偏移,海外正常。不做调整 this._insertGoogleMapApiScript(options.key || '') mapLayer = L.gridLayer.googleMutant({ maxZoom: 24, type: 'roadmap', styles: [{ featureType: 'poi', elementType: 'labels', stylers: [{ visibility: options.poiLabels || 'on' }] }], }) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'wgs84' break case 'GMap_Sate': this._insertGoogleMapApiScript(options.key || '') this.key = options.key || '' mapLayer = L.gridLayer.googleMutant({ maxZoom: 24, type: 'satellite', }) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'wgs84' break case 'GMap_Road_Grid': // 卫星地图+路网 this._insertGoogleMapApiScript(this.key || '') mapLayer = L.gridLayer.googleMutant({ maxZoom: 24, type: 'hybrid', }) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'wgs84' break case 'SSMap': mapLayer = new L.tileLayer('http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0', { tms: true, maxZoom: 18, minZoom: 3, subdomains: [0, 1, 2, 3], attribution: '© <a href="http://map.soso.com">SoSoMap</a> contributors', }) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'gcj02' break case 'AMap': // 前者lang可以通过zh_cn设置中文,en设置英文, // size基本无作用, // scl尺寸控制,1=256,2=512 // style地图类型控制,6卫星(st),7简图(st rd),8详图(不透明rd,透明图st) // ltype 线性控制,增加后,只对地图要素进行控制,没有文字注记,要素多少,是否透明:11路网 12 标记 14 路网+标记 // https://www.cnblogs.com/lucio110/p/17310054.html mapLayer = new L.tileLayer('http://webrd0{s}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&style=8', { maxZoom: 18, minZoom: 3, subdomains: [1, 2, 3, 4], attribution: '© <a href="http://www.amap.cn">AMap</a> contributors', }) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'gcj02' break case 'AMap_Sate': mapLayer = new L.tileLayer( 'https://webst0{s}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&style=6', { maxZoom: 16, minZoom: 3, subdomains: [1, 2, 3, 4], attribution: '© <a href="http://www.amap.cn">AMap</a> contributors', }, ) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'gcj02' break case 'AMap_Road_Grid': // 透明路网 mapLayer = new L.tileLayer( 'https://webst0{s}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&style=8&ltype=14', { zIndex: 2, maxZoom: 16, minZoom: 3, subdomains: [1, 2, 3, 4], attribution: '© <a href="http://www.amap.cn">AMap</a> contributors', }, ) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'gcj02' break case 'AMap+BEKD': const mapLayer1 = new L.tileLayer( 'http://webrd0{s}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8', { maxZoom: 18, minZoom: 3, subdomains: [1, 2, 3, 4], attribution: '© <a href="http://www.amap.cn">AMap</a> contributors', }, ) const mapLayer2 = L.tileLayer.wms('http://47.108.171.223:8080/geoserver/bedmk84/wms', { layers: 'bedmk84:0_LineString', format: 'image/png', transparent: true, }) mapLayer = L.layerGroup([mapLayer1, mapLayer2], { corrdType: 'gcj02', }) break case 'AMap_Sate+BEKD': const mapLayer3 = new L.tileLayer('https://webst0{s}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}', { maxZoom: 18, minZoom: 3, subdomains: [1, 2, 3, 4], attribution: '© <a href="http://www.amap.cn">AMap</a> contributors', }) const mapLayer4 = L.tileLayer.wms('http://47.108.171.223:8080/geoserver/bedmk84/wms', { layers: 'bedmk84:0_LineString', format: 'image/png', transparent: true, }) mapLayer = L.layerGroup([mapLayer3, mapLayer4], { corrdType: 'gcj02', }) break case 'LAMap_Road': // 本地高德路网地图 mapLayer = new L.tileLayer(`${options.tileServer}/AMap/Road/{z}/{x}/{y}/tile.png`, { maxZoom: 16, minZoom: 3, attribution: '© <a href="http://www.amap.cn">AMap</a> contributors', }) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'gcj02' break case 'AMap2': // 通过高德地图API获取的地图图层,支持更多参数配置 mapLayer = new AmapLayer({ minZoom: 3, maxZoom: 20, corrdType: 'gcj02', viewMode: '2D', mapType: 'roadmap', mapStyle: options.mapStyle || 'normal', apiKey: options.key, securityConfig: { securityJsCode: options.sk, }, }) break case 'AMap2_State': this.key = options.key || '' this.sk = options.sk || '' mapLayer = new AmapLayer({ minZoom: 3, maxZoom: 20, corrdType: 'gcj02', viewMode: '2D', mapType: 'satellite', apiKey: options.key, securityConfig: { securityJsCode: options.sk, }, }) break case 'AMap2_Road_Grid': mapLayer = new AmapLayer({ minZoom: 3, maxZoom: 20, corrdType: 'gcj02', viewMode: '2D', mapType: 'roadnet', apiKey: this.key, securityConfig: { securityJsCode: this.sk, }, }) break default: mapLayer = new L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18, minZoom: 3, attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, ', id: 'mapbox.streets', }) mapLayer.options = mapLayer.options || {} mapLayer.options.corrdType = 'wgs84' break } return mapLayer } _getCRS(type) { let crs = null switch (type) { case 'BMap': crs = new L.Proj.CRS( //"EPSG:3395", //"+proj=merc +lon_0=0 +k=1 +x_0=140 +y_0=-250 +datum=WGS84 +units=m +no_defs", 'EPSG:900913', '+proj=merc +a=6378206 +b=6356584.314245179 +lat_ts=0.0 +lon_0=0.0 +x_0=0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs', { resolutions: (function () { let level = 19 let res = [] res[0] = Math.pow(2, 18) for (let i = 1; i < level; i++) { res[i] = Math.pow(2, 18 - i) } return res })(), origin: [0, 0], bounds: L.bounds([20037508.342789244, 0], [0, 20037508.342789244]), }, ) break default: break } return crs } // 百度坐标系转火星坐标系(BD09 → GCJ02) _bd09ToGcj02(bd_lat, bd_lon) { var x = bd_lon - 0.0065 var y = bd_lat - 0.006 var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin((y * Math.PI * 3000.0) / 180.0) var theta = Math.atan2(y, x) - 0.000003 * Math.cos((x * Math.PI * 3000.0) / 180.0) var gg_lng = z * Math.cos(theta) var gg_lat = z * Math.sin(theta) return [gg_lat, gg_lng] } // 火星坐标系转百度坐标系(GCJ02 → BD09) _gcj02ToBd09(gcj_lat, gcj_lon) { var x = gcj_lon var y = gcj_lat var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin((y * Math.PI * 3000.0) / 180.0) var theta = Math.atan2(y, x) + 0.000003 * Math.cos((x * Math.PI * 3000.0) / 180.0) var bd_lon = z * Math.cos(theta) + 0.0065 var bd_lat = z * Math.sin(theta) + 0.006 return [bd_lat, bd_lon] } /** * 修改地图缩放等级 * @param {Number} zoom */ setZoom(zoom) { if (typeof zoom === 'string') { zoom = parseInt(zoom) } this.map.setZoom(zoom) } /** * 设定地图给定的地点和缩放 * @param {*} point 经纬度 * @param {*} zoom 缩放等级 */ setView(point, zoom) { if (typeof point === 'object') { if (typeof zoom === 'string') { zoom = parseInt(zoom) } this.map.setView(point, zoom) } } /** * 获取地图当前的视图缩放 * @returns lat,lng,zoom */ getView() { const latlng = this.map.getCenter() const zoom = this.map.getZoom() return latlng.lat + ',' + latlng.lng + ',' + zoom } /** * 全图 */ minZoom() { const zoom = this.map.getMinZoom() this.map.setZoom(zoom) } /** * 最大 */ maxZoom() { const zoom = this.map.getMaxZoom() this.map.setZoom(zoom) } /** * 放大 */ zoomIn() { this.map.zoomIn() } /** * 缩小 */ zoomOut() { this.map.zoomOut() } /** * 打开鹰眼 */ openFlyEye() { // 传入 _mapOptions 以支持 GMap 等需要 key 的图层类型 const mapLayer = this._getLayer(this.type, this._mapOptions) //这里要注意,鹰眼图的layer不能和地图上共用一个 Note that you cannot use the same layer object again, as that will confuse the two map controls //使用鹰眼图,添加到地图上 this.flyEyeViewLayer = new MiniMap(mapLayer, { toggleDisplay: true, }).addTo(this.map) } /** * 关闭鹰眼 */ closeFlyEye() { if (this.flyEyeViewLayer) { this.map.removeControl(this.flyEyeViewLayer) } } /** * 定位 */ locate() { this.map.locate({ setView: true, maxZoom: 16, }) } /** * 停止定位 */ stopLocate() { this.map.stopLocate() } /** * 计算面积 */ area() {} /** * 拉框选区公共逻辑(boxIn/boxOut 共用),避免代码重复 * @param {Function} completeCallback 框选完成后的操作,接收 L.LatLngBounds 参数 */ _setupBoxSelect(completeCallback) { let that = this let latlngs = [] let rectangle = null let mousemoveEvent = function (e) { if (rectangle !== null) { if (latlngs.length === 1) { latlngs.push(e.latlng) } else { latlngs[1] = e.latlng } rectangle.setBounds(latlngs) } } let clickEvent = function (e) { if (rectangle === null) { latlngs.push(e.latlng) rectangle = L.rectangle(latlngs, { color: 'blue' }) rectangle.addTo(that.map) } else { const bounds = L.latLngBounds(latlngs[0], latlngs[1]) completeCallback(bounds) rectangle.remove() that.map.off('click', clickEvent) that.map.off('mousemove', mousemoveEvent) } } this.map.on('click', clickEvent) this.map.on('mousemove', mousemoveEvent) } /** * 拉框缩小 */ boxIn() { this._setupBoxSelect((bounds) => { this.map.panInsideBounds(bounds) setTimeout(() => { this.map.zoomOut() }, 500) }) } /** * 拉框放大 */ boxOut() { this._setupBoxSelect((bounds) => { this.map.fitBounds(bounds, { maxZoom: this.map.getMaxZoom() -2}) }) } /** * 测量距离 */ distance() { let that = this let polyline = null let latlngs = [] let markerList = [] let distance = 0 let clickEvent = function (e) { latlngs.push(e.latlng) let marker = L.marker(e.latlng, { icon: that.config.POINT_ICON }).addTo(that.map) if (polyline === null) { polyline = L.polyline(latlngs, { color: 'blue' }) polyline.addTo(that.map) } else { polyline.setLatLngs(latlngs) let first = latlngs[latlngs.length - 2] let last = latlngs[latlngs.length - 1] distance += that.map.distance(first, last) marker .bindTooltip(distance > 1000 ? (distance / 1000).toFixed(2) + 'km' : distance.toFixed(2) + 'm') .openTooltip() } markerList.push(marker) } let markerClickEvent = function (e) { polyline.remove() markerList.forEach((element) => { element.remove() }) } let dblclickEvent = function (e) { let cancelMarker = L.marker(e.latlng, { icon: that.config.CANCEL_ICON }).addTo(that.map) cancelMarker.on('click', markerClickEvent) markerList.push(cancelMarker) that.map.off('click', clickEvent) that.map.off('dblclick', dblclickEvent) } this.map.on('click', clickEvent) this.map.on('dblclick', dblclickEvent) } /** * 移动地图到坐标 * @param {array} point [lng,lat] */ flyTo(point) { if (typeof point === 'object') { this.map.flyTo(point) } } /** * 移动地图到坐标 * @param {*} point */ panTo(point) { if (typeof point === 'object') { this.map.panTo(point) } } /** * 移动地图到视野 * @param {array} pointNW [lng,lat] * @param {array} pointSE [lng,lat] */ flyToBounds(pointNW, pointSE) { if (typeof pointNW === 'object' && typeof pointSE === 'object') { this.map.flyToBounds([pointNW, pointSE]) } } /** * * @param {*} pointNW * @param {*} pointSE */ fitBounds(pointNW, pointSE) { if (typeof pointNW === 'object' && typeof pointSE === 'object') { this.map.fitBounds([pointNW, pointSE]) } } /** * 切换地图 * @param {String} type? BMap/GMap/AMap */ changeMap(type, option) { const options = option || {} options.type = type // 获取当前地图中心点(在当前坐标系中) const currentCenter = this.map.getCenter() const currentZoom = this.map.getZoom() // 如果需要,进行坐标转换 let newCenter = currentCenter if (this.type.includes('AMap') && type.includes('BMap')) { // 从高德坐标系(gcj02)转换到百度坐标系(bd09) newCenter = this._gcj02ToBd09(currentCenter.lat, currentCenter.lng) } else if (this.type.includes('BMap') && type.includes('AMap')) { // 从百度坐标系(bd09)转换到高德坐标系(gcj02) newCenter = this._bd09ToGcj02(currentCenter.lat, currentCenter.lng) } this._initMap(options) // 设置新的中心点 this.map.setView(newCenter, currentZoom) } /** * 显示路网,主要是卫星图 * @param {*} type * @param {*} option */ showRoadGrid(type, option) { this.hideRoadGrid() this.roadLayer = this._getLayer(type + '_Road_Grid') this.map.addLayer(this.roadLayer) } /** * 隐藏路网 */ hideRoadGrid() { if (this.roadLayer) { this.map.removeLayer(this.roadLayer) this.roadLayer = null } } /** * 添加自定义瓦片图层(XYZ/TMS,如 nginx 静态切片) * 业务侧只需传地址相关参数;坐标系按 SDK 统一 WGS84,内部根据当前底图自动适配(高德/OSM/百度等)。 * @param {String} url 瓦片地址模板,如 http://host/tiles/{z}/{x}/{y}.png * @param {Object} [options] * @param {Boolean} [options.tms=false] 源切片为 TMS(Y 轴反向)时设为 true;上下颠倒也可改这个 * @param {Number} [options.maxZoom=18] * @param {Number} [options.maxNativeZoom] * @param {Number} [options.minZoom] * @param {Number} [options.opacity=1] 透明度 0-1 * @param {Number} [options.zIndex] 图层层级 * @returns {L.Layer} * @example * iovMap.addTileLayer('http://127.0.0.1/tiles/cai-chang/{z}/{x}/{y}.png', { * tms: true, * maxZoom: 18, * maxNativeZoom: 18 * }) */ addTileLayer(url, options) { const opts = Object.assign( { maxZoom: 18, tms: false, opacity: 1, }, options || {}, ) // 对外不暴露坐标系;SDK 内统一按 WGS84 处理 delete opts.coordType delete opts.corrdType this._customTileConfig = { url: url, options: opts } return this._mountTileLayer(url, opts) } /** * 移除自定义瓦片图层 */ removeTileLayer() { this._removeCustomLayerOnly() this._customTileConfig = null } /** * 设置自定义瓦片图层透明度 * @param {Number} opacity 0-1 */ setTileLayerOpacity(opacity) { if (this.customLayer) { this.customLayer.setOpacity(opacity) } } _mountTileLayer(url, opts) { this._removeCustomLayerOnly() if (this._isBaiduCrs()) { // 百度自定义 CRS:内部用兼容层,业务无感知 const mercatorOpts = { sourceTms: !!opts.tms, maxZoom: opts.maxZoom != null ? opts.maxZoom : 18, opacity: opts.opacity != null ? opts.opacity : 1, zIndex: opts.zIndex != null ? opts.zIndex : 450, pane: 'overlayPane', } if (opts.minZoom != null) { mercatorOpts.minZoom = opts.minZoom } if (opts.maxNativeZoom != null) { mercatorOpts.maxNativeZoom = opts.maxNativeZoom } this.customLayer = new MercatorTileLayer(url, mercatorOpts) } else { // 高德/OSM 等 EPSG:3857:标准瓦片层;底图纠偏由 SDK 统一处理,自定义层按 WGS84 叠加 const tileOpts = { tms: !!opts.tms, maxZoom: opts.maxZoom != null ? opts.maxZoom : 18, opacity: opts.opacity != null ? opts.opacity : 1, } if (opts.minZoom != null) { tileOpts.minZoom = opts.minZoom } if (opts.maxNativeZoom != null) { tileOpts.maxNativeZoom = opts.maxNativeZoom } this.customLayer = L.tileLayer(url, tileOpts) if (opts.zIndex != null) { this.customLayer.setZIndex(opts.zIndex) } } this.map.addLayer(this.customLayer) return this.customLayer } _removeCustomLayerOnly() { if (this.customLayer) { this.map.removeLayer(this.customLayer) this.customLayer = null } } /** * @deprecated 请使用 removeTileLayer */ removeCustomLayer() { this.removeTileLayer() } /** * @deprecated 请使用 setTileLayerOpacity */ setCustomLayerOpacity(opacity) { this.setTileLayerOpacity(opacity) } /** * @deprecated 请使用 removeTileLayer */ removeWmsLayer() { this.removeTileLayer() } /** * @deprecated 请使用 setTileLayerOpacity */ setWmsLayerOpacity(opacity) { this.setTileLayerOpacity(opacity) } /** * 创建自定义Canvas面板 */ createCanvasPane() { let canvas = L.DomUtil.create('canvas') let pane = this.map.createPane('customCanvas') let size = this.map.getSize() let that = this this.customCanvasPaneResizeEvent = function (e) { size = that.map.getSize() canvas.width = size.x canvas.height = size.y } this.customCanvasPaneMoveendEvent = function (e) { let topLeft = that.map.containerPointToLayerPoint([0, 0]) L.DomUtil.setPosition(canvas, topLeft) } this.map.on('resize', this.customCanvasPaneResizeEvent) this.map.on('moveend', this.customCanvasPaneMoveendEvent) canvas.width = size.x canvas.height = size.y pane.style['z-index'] = 300 pane.appendChild(canvas) return canvas } /** * 移除自定义Canvas面板 */ removeCanvasPane() { let pane = this.map.getPane('customCanvas') pane.parentNode.removeChild(pane) this.map.off('resize', this.customCanvasPaneResizeEvent) this.map.off('moveend', this.customCanvasPaneMoveendEvent) } /** * 查询包含在列表内的点 * @param {*} list 定位列表 * @param {*} latlngs 区域 */ findExist(list, latlngs) { const result = [] const bounds = L.latLngBounds(latlngs[0], latlngs[1]) list.forEach((element) => { if (bounds.contains([element.lat, element.lng])) { result.push({ id: element.id, text: element.text }) } }) return result } /** * 计算里程 * @param {Array} latlngs * @returns */ computerMileage(latlngs) { let result = 0 for (let index = 0; index < latlngs.length; index++) { if (index !== latlngs.length - 1) { const first = latlngs[index] const last = latlngs[index + 1] result += this.map.distance(first, last) } } return result } /** * 插入一个google map api key的js文件 * @param {*} key */ _insertGoogleMapApiScript(key) { // 创建一个 script 元素 let script = document.createElement('script') let src = 'https://maps.googleapis.com/maps/api/js?key=' + key script.src = src script.async = true script.defer = true // 判断该脚本是否已存在 let existingScript = document.querySelector('script[src="' + src + '"]') // 如果不存在,则将脚本插入到 head 中 if (!existingScript) { document.head.appendChild(script) } } polylineCenter(latlngs) { const lineUtil = L.LineUtil return lineUtil.polylineCenter(latlngs, this.map.options.crs) } polygonCenter(latlngs) { const polyUtil = L.PolyUtil return polyUtil.polygonCenter(latlngs, this.map.options.crs) } }