如果你正在做可视化地图相关的业务或者功能的话,希望本篇文章能够给你提供帮助
1. leaflet的介绍
取自官网的介绍(leafletjs.cn/):Leaflet 是一个开源并且对移动端友好的交互式地图 JavaScript 库。 它大小仅仅只有 42 KB of JS, 并且拥有绝大部分开发者所需要的所有地图特性 。
Leaflet 简单、高效并且易用。 它可以高效的运行在桌面和移动平台, 拥有着大量的 扩展插件、 优秀的文档、简单易用的 API 和完善的案例, 以及可读性较好的 源码 。
功能很强大,不管是PC端还是移动端,都有他的用武之地
2. leaflet在vue3项目中的简单使用
- 首先引入leaflet包
npm install leaflet
- 初始化一个地图画面
// 结构
<template>
<div class="portal">
<div class="map-content" id="mapId"></div>
</div>
</template>
// js代码
var map = L.map('map').setView([51.505, -0.09], 13); L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png',
{ attribution: '©
<a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' }).addTo(map);
L.marker([51.5, -0.09]).addTo(map) .bindPopup('A pretty CSS3 popup.<br> Easily customizable.') .openPopup();
以上是按照官网实现的一个简单的地图功能,我们平常开发中一般都需要自己去寻找瓦片,然后根据自己的业务来实现地图
leaflet在真实项目中的使用
- 首先我们先创建一个文件夹lib,存储leaflet自定义的一些文件
- 然后将自定义的文件leaflet.ChineseTmsProviders和Leaflet.chartLayer创建一下
// leaflet.ChineseTmsProviders文件
// this L.CRS.Baidu from https://github.com/muyao1987/leaflet-tileLayer-baidugaode/blob/master/src/tileLayer.baidu.js
if (L.Proj) {
L.CRS.Baidu = new L.Proj.CRS(
'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 () {
var level = 19
var res = []
res[0] = Math.pow(2, 18)
for (var 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]),
}
)
}
L.TileLayer.ChinaProvider = L.TileLayer.extend({
initialize: function (type, options) {
// (type, Object)
var providers = L.TileLayer.ChinaProvider.providers
options = options || {}
var parts = type.split('.')
var providerName = parts[0]
var mapName = parts[1]
var mapType = parts[2]
var url = providers[providerName][mapName][mapType]
options.subdomains = providers[providerName].Subdomains
options.key = options.key || providers[providerName].key
if ('tms' in providers[providerName]) {
options.tms = providers[providerName]['tms']
}
L.TileLayer.prototype.initialize.call(this, url, options)
},
})
L.TileLayer.ChinaProvider.providers = {
TianDiTu: {
Normal: {
Map: '//t{s}.tianditu.gov.cn/DataServer?T=vec_w&X={x}&Y={y}&L={z}&tk={key}',
Annotion:
'//t{s}.tianditu.gov.cn/DataServer?T=cva_w&X={x}&Y={y}&L={z}&tk={key}',
},
Satellite: {
Map: '//t{s}.tianditu.gov.cn/DataServer?T=img_w&X={x}&Y={y}&L={z}&tk={key}',
Annotion:
'//t{s}.tianditu.gov.cn/DataServer?T=cia_w&X={x}&Y={y}&L={z}&tk={key}',
},
Terrain: {
Map: '//t{s}.tianditu.gov.cn/DataServer?T=ter_w&X={x}&Y={y}&L={z}&tk={key}',
Annotion:
'//t{s}.tianditu.gov.cn/DataServer?T=cta_w&X={x}&Y={y}&L={z}&tk={key}',
},
Subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
key: 'b0c36010bb50280fd8cff2311c58e689',
},
GaoDe: {
Normal: {
Map: '//webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
},
Satellite: {
Map: '//webst0{s}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
Annotion:
'//webst0{s}.is.autonavi.com/appmaptile?style=8&x={x}&y={y}&z={z}',
},
Subdomains: ['1', '2', '3', '4'],
},
Google: {
Normal: {
Map: '//www.google.cn/maps/vt?lyrs=m@189&gl=cn&x={x}&y={y}&z={z}',
},
Satellite: {
Map: '//www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}',
Annotion: '//www.google.cn/maps/vt?lyrs=y@189&gl=cn&x={x}&y={y}&z={z}',
},
Subdomains: [],
},
Geoq: {
Normal: {
Map: '//map.geoq.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x}',
PurplishBlue:
'//map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}',
Gray: '//map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetGray/MapServer/tile/{z}/{y}/{x}',
Warm: '//map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetWarm/MapServer/tile/{z}/{y}/{x}',
},
Theme: {
Hydro:
'//thematic.geoq.cn/arcgis/rest/services/ThematicMaps/WorldHydroMap/MapServer/tile/{z}/{y}/{x}',
},
Subdomains: [],
},
OSM: {
Normal: {
Map: '//{s}.tile.osm.org/{z}/{x}/{y}.png',
},
Subdomains: ['a', 'b', 'c'],
},
SHIPFORMULA: {
OSM: {
Map: 'https://maps.shipformula.com/wmts/osm/webmercator/{z}/{x}/{y}.png',
},
DT: {
Map: 'https://maps.shipformula.com/wmts/dtmap/webmercator/{z}/{x}/{y}.png',
},
Satellite: {
Map: 'https://maps.shipformula.com/wmts/satellite/webmercator/{z}/{x}/{y}.png',
},
ZHSatellite: {
Map: 'https://maps.shipformula.com/wmts/zhsatellite/webmercator/{z}/{x}/{y}.png',
},
Subdomains: [],
},
Baidu: {
Normal: {
Map: '//online{s}.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=pl&scaler=1&p=1',
},
Satellite: {
Map: '//shangetu{s}.map.bdimg.com/it/u=x={x};y={y};z={z};v=009;type=sate&fm=46',
Annotion:
'//online{s}.map.bdimg.com/tile/?qt=tile&x={x}&y={y}&z={z}&styles=sl&v=020',
},
Subdomains: '0123456789',
tms: true,
},
SHIPXY: {
Normal: {
Map: 'http://m12.shipxy.com/tile.c?l=Na&m=o&x={x}&y={y}&z={z}',
},
Subdomains: [],
},
SF: {
Normal: {
Map: 'http://map.shipformula.com/styles/klokantech-basic/{z}/{x}/{y}.png',
Bright: 'http://map.shipformula.com/styles/osm-bright/{z}/{x}/{y}.png',
Dark: 'http://map.shipformula.com/styles/dark-matter/{z}/{x}/{y}.png',
Positron: 'http://map.shipformula.com/styles/positron/{z}/{x}/{y}.png',
},
Satellite: {
Map: 'http://map.shipformula.com/styles/satellite/{z}/{x}/{y}.png',
Hybrid: 'http://map.shipformula.com/styles/hybrid/{z}/{x}/{y}.png',
},
Subdomains: [],
},
Local: {
Normal: {
Map: 'http://192.168.30.229:8083/styles/klokantech-basic/{z}/{x}/{y}.png',
Bright: 'http://192.168.30.229:8083/styles/osm-bright/{z}/{x}/{y}.png',
Dark: 'http://192.168.30.229:8083/styles/dark-matter/{z}/{x}/{y}.png',
Positron: 'http://192.168.30.229:8083/styles/positron/{z}/{x}/{y}.png',
},
Satellite: {
Map: 'http://192.168.30.229:8083/styles/satellite/{z}/{x}/{y}.png',
Hybrid: 'http://192.168.30.229:8083/styles/hybrid/{z}/{x}/{y}.png',
},
Subdomains: [],
},
}
L.tileLayer.chinaProvider = function (type, options) {
return new L.TileLayer.ChinaProvider(type, options)
}
···
```js
// Leaflet.chartLayer
// import Constants from '../config/Constants';
// const CHART_URL = ['http://shipdt-emap.shipdt.com/emap_36/']
// const CHART_URL = ['http://emap.n.shipdt.com/emap_6/']
const CHART_URL = ['https://www.shipformula.com/emap_6/']
const CHART_ERROR = 'https://mobile.shipformula.com/static/images/error.png'
/**
* 海图Layer 继承自TileLayer
*
* @param {Object}
* tomcat中映射该切片目录url
* @param {Object}
* options
* http://enc-cmap2.myships.com/ChartMap/L02/R00000001/C00000003.png
*/
L.TileLayer.ChartLayer = L.TileLayer.extend({
initialize(url, options) {
options = L.setOptions(this, options)
options.errorTileUrl = CHART_ERROR
const tempurl = CHART_URL[Math.floor(Math.random() * CHART_URL.length)]
this.url = `${tempurl}{s}/{x}.png`
L.TileLayer.prototype.initialize.call(this, this.url, options)
},
})
/**
* 重写TileLayer中获取切片url方法
*
* @param {Object}
* tilePoint
*/
L.TileLayer.ChartLayer.prototype.getTileUrl = function (tilePoint) {
return L.Util.template(
this._url,
L.extend({
s() {
const zl = tilePoint.z
const ty = tilePoint.y
let dir = ''
let levDir = ''
let rowDir = ''
if (zl < 2) {
levDir = `LN${zl.toString()}`
} else if (zl < 12) {
levDir = `L0${(zl - 2).toString()}`
} else {
levDir = `L${(zl - 2).toString()}`
}
rowDir = `R${L.tileLayer.getHexString(ty)}`
dir = `${levDir}/${rowDir}`
return dir
},
x: `C${L.tileLayer.getHexString(tilePoint.x)}`,
})
)
}
L.tileLayer.getHexString = function (value) {
let strHex = value.toString(16)
switch (strHex.length) {
case 1:
strHex = `0000000${strHex}`
break
case 2:
strHex = `000000${strHex}`
break
case 3:
strHex = `00000${strHex}`
break
case 4:
strHex = `0000${strHex}`
break
case 5:
strHex = `000${strHex}`
break
case 6:
strHex = `00${strHex}`
break
case 7:
strHex = `0${strHex}`
break
default:
}
return strHex
}
let chartLyaer = null
const ChartLayer = function (url, options) {
if (!chartLyaer) {
chartLyaer = new L.TileLayer.ChartLayer(url, options)
}
return chartLyaer
}
export default {
ChartLayer,
}
- 接下来我们在vue项目里引入创建的两个js文件
<!-- 工作台 -->
<template>
<div class="portal">
<div class="map">
<div class="map-content" id="mapId"></div>
</div>
</div>
</template>
<script setup>
import 'leaflet/dist/leaflet.css'
import L from 'leaflet'
import '@/lib/leaflet.ChineseTmsProviders'
import 'leaflet-providers'
import SeaMap from '@/lib/Leaflet.chartLayer'
import 'leaflet.markercluster'
import 'leaflet.markercluster.placementstrategies'
onMounted(() => {
initMap()
})
// 地图相关数据
const state = reactive({
glbmap: null,
})
const initMap = async () => {
const osm = L.tileLayer.chinaProvider('GaoDe.Normal.Map', {
preferCanvas: true,
maxZoom: 18,
minZoom: 3,
name: 'osm',
})
const google = L.tileLayer.chinaProvider('GaoDe.Satellite.Map', {
preferCanvas: true,
maxZoom: 18,
minZoom: 3,
name: 'google',
})
const googletdt = L.tileLayer.chinaProvider('GaoDe.Satellite.Annotion', {
preferCanvas: true,
maxZoom: 18,
minZoom: 3,
name: 'googletdt',
})
const seaMap = SeaMap.ChartLayer('', {
preferCanvas: true,
name: 'seaMap',
})
const baseLayers = {
默认图: osm,
卫星图: L.layerGroup([google, googletdt]),
海图: seaMap,
}
state.glbmap = L.map('mapId', {
preferCanvas: true,
attributionControl: false,
renderer: L.canvas(),
center: [34.22088, 121.14048],
zoom: 6,
layers: [osm],
zoomControl: false,
worldCopyJump: true,
zoomSnap: 1,
zoomDelta: 1,
wheelPxPerZoomLevel: 120,
crs: L.CRS.EPSG3857,
})
let mapControl = L.control.layers(baseLayers).addTo(state.glbmap)
mapControl.setPosition('topright')
}
</script>
<style lang="scss" scoped>
.portal {
width: 100%;
height: calc(100vh - 91px);
box-sizing: border-box;
position: relative;
}
.map {
width: 100%;
height: 100%;
.map-content {
width: 100%;
height: 100%;
}
}
</style>
接下来我们就可以看到地图效果了
后续篇章我们就在地图做一些交互效果