iovmap
Version:
a map sdk base on leaflet
923 lines (913 loc) • 29.7 kB
JavaScript
/*
* 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<ype=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 © <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)
}
}