文章目录
一、技术框架及相关资源
当前项目的WebGIS开发主要用到leaflet.js和esri-leaflet.js,这两个工具类库文档简单易读且开源,各自的Plugins版块也都有很多开源好用的插件。
-
leaflet.js 1.7.1
一个现代的、开源的、友好的互动地图JavaScript 库,虽然只有几十kb但能够支持pc和移动设备开发。 -
esri-leaflet.js
用于将ArcGIS服务和Leaflet一起使用的轻量级js工具类库。
v3.0.8地址 -
其他常用插件
- turf.js 一个地理空间分析库,用于处理各种地图算法。
- leaflet-contextmenu 右键菜单
- leaflet-easyprint 地图打印
- leaflet-editable 图形编辑
- leaflet-fullscreen 全屏组件
- leaflet-mouse-position 显示鼠标位置组件
- proj4、proj4leaflet 坐标系、空间参考转换
以上插件均支持npm方式安装引入。
扩展: vue2-leaflet 一套基于leaflet.js经vue组件化的地图组件库,安装引入到项目中后可以通过组件堆叠的方式进行WebGIS开发,可自行了解,本文不多作介绍。
二、在vue项目中引入leaflet.js并创建地图
1.安装leaflet
最新版本为1.8.0,当前使用1.7.1稳定版本
npm i leaflet@1.7.1
或
yarn add leaflet@1.7.1
2.在main.js中全局引入
import L from 'leaflet'
import 'leaflet/dist/leaflet.css'
3.vue页面初始化地图
<template>
<div id="mapContainer"></div>
</template>
<script>
export default {
data () {
return {
map: null
}
},
mounted () {
this.initMap()
},
methods: {
initMap () {
// 创建地图并初始化中心点、层级
this.map = L.map('mapContainer').setView([32.03064, 118.79517], 9)
// 添加底图
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(this.map)
}
}
}
</script>
<style lang="less" scoped>
#mapContainer {
width: 100%;
height: 100%;
}
</style>
三、添加基础点线面要素
上一步已经完成了地图的初始化,我们已经创建了一个地图容器,现在我们要尝试在容器上添加点线面要素。
1.添加要素
添加点、线、面要素,点位格式对应[纬度,经度]
ps: 经纬度皆为Number类型
// 点
const pointLatlng = [32.05511, 118.78454]
const marker = L.marker(latlng).addTo(this.map)
// 线
const polylineLatlngs = [
[32.05209, 118.78218],
[32.05174, 118.78437],
[32.05401, 118.78496],
[32.05374, 118.78705]
]
const polyline = L.polyline(latlngs).addTo(this.map)
// 面
const polygonLatlngs = [
[32.05425, 118.77905],
[32.05426, 118.78212],
[32.05612, 118.78206],
[32.05599, 118.77904]
]
const polygon = L.polygon(latlngs).addTo(this.map)
2.删除要素
添加了需要基础要素后,现在想要删除某些已创建的要素,执行:
marker.remove()
polyline.remove()
polygon.remove()
但是我们创建了很多要素时就不太好管理,此时我们可以使用图层组对要素进行管理,更多方法参考api文档
// 创建featureGroup并通过addTo()方法添加到地图上
const featureGroup = L.featureGroup([]).addTo(this.map)
// 向featureGroup中添加要素
featureGroup.addLayer(marker)
featureGroup.addLayer(polyline)
featureGroup.addLayer(polygon)
// 清除图层组中的全部要素
featureGroup.clearLayers()
3.挂载属性和创建弹窗
给要素挂载属性并绑定popup弹窗,应用于需要查看要素属性的场景,以marker标记为例,线、面要素同。
1)使用非geojson数据创建要素时可以通过添加额外属性的方式给要素挂载属性信息,这些属性信息默认会挂载到要素的options对象。
// 需要挂载的属性信息
const pointData = { tbbh: '001', name: '新街口', type: 'point' }
// 创建要素时将属性信息作为第二个参数传入
const marker = L.marker([32.05511, 118.78454], { data: pointData })
console.log(marker.options.data) // { id: '001', name: '新街口', type: 'point' }
2)要素挂载属性后就可以和其进行一些交互
通过bindPopup()绑定气泡弹窗,默认点击要素时触发
// 场景一:声明简单弹窗HTMLString并绑定要素
const popupHtml = `<div>marker标记弹窗</div>`
marker.bindPopup(popupHtml)
// 场景二:结合传入的属性信息生成弹窗
marker.bindPopup(layer => {
return `<div>图斑编号:${layer.options.data.tbbh}</div>`
})
扩展:
在vue项目中通常会使用一套或多套UI组件库,而这些组件标签在通过HTMLString和dom函数创建的弹窗中是不能被正确识别和渲染的,这时可以选择结合vue的extend构造器创建一个组件实例作为弹窗dom渲染。
1.创建PopupComp.vue
<template>
<div>
<div>tbbh{{ detailInfo.tbbh }}</div>
<a-button @click="viewDetail">查看详情</a-button>
</div>
</template>
<script>
export default {
name: 'PopupComp',
data () {
return {
detailInfo: {}
}
},
methods: {
viewDetail () {
this.$message.info(JSON.stringify(this.detailInfo))
}
}
}
</script>
2.引入组件并使用组件实例
// 引入组件
import PopupComp from './PopupComp.vue'
// 构造器创建实例
getPopupHtml (data = {}) {
const Comp = Vue.extend(PopupComp)
const vm = new Comp({})
vm.$mount()
vm.detailInfo = data
return vm.$el
}
// 使用组件实例渲染弹窗
marker.bindPopup(layer => this.getPopupHtml(layer.options.data))
或
marker.bindPopup(this.getPopupHtml(options.data))
4.自定义要素点击事件
自定义点击事件执行自定义操作,以marker标记为例,线、面要素同。
// 创建marker标记
const marker = L.marker([32.05511, 118.78454], { data: { key: '001', name: '新街口' } })
// 添加点击事件监听
marker.on(this.markerClick)
// marker标记点击事件
markerClick (e) {
// 此处执行自定义操作,图层数据可以在e.sourceTarget中获取
console.log(e)
}
// 移除监听
marker.off(this.markerClick)
四、结合ArcGIS Server服务开发
leaflet.js不同于ArcGIS for js,想要结合ArcGIS Server进行开发需要引入esri-leaflet.js插件支持。
安装
npm i -save esri-leaflet
页面引入
esri-leaflet的引入和其他插件引入方式有所不同,直接通过import方式引入不生效。
const esri = require(esri-leaflet)
关于ArcGIS Server相关的内容这里不作赘述,我们通常使用的服务url格式为:
http://<hostname>/arcgis/rest/services/<service-name>/MapServer
1.query查询
常应用于需要根据某个属性值或Geometry(点、线、面) 从图层服务中查询获取要素数据的场景。
注意:
1.单次只支持查询一个图层;
2.where参数常用条件为key=‘xxx’、key like '%xxx%'等,多条件可用and、or连接;
通过esri.query()
方法创建query任务,调取指定Server的query API,传入参数执行查询获取结果。
// 创建查询任务
const layerId = '0'
const query = esri.query({
url: `http://xxx/arcgis/rest/services/xxx/MapServer/${layerId}`
})
// 设置where参数作为查询条件
query
.where('objectid=1')
// 执行查询
.run(function (error, featureCollection, response) {
if (error) {
console.log(error)
return
}
console.log('query' + featureCollection, response)
})
2.find查询
常应用于需要从多个图层以某个属性值为依据匹配某些属性字段查询获取数据的场景。
注意:
1.layers参数可传入多个图层id,支持同时查询多个图层
2.fields参数可传入多个属性,支持同时匹配多个属性
2.contains参数为true时表示模糊匹配,false为完全匹配
通过esri.find()
方法创建find任务,调取指定Server的find API,传入参数执行查询获取结果。
const find = esri.find({
url: 'http://xxx/arcgis/rest/services/xxx/MapServer'
})
find
.layers('0, 1')
.text('xxx')
.fields('id, name, key')
.run(function (error, featureCollection, response) {
if (error) {
console.log(error)
return
}
console.log('find' + featureCollection, response)
})
3.identify识别
常用于查询包含已知Geometry(点、线、面)的图层要素数据或点击地图获取包含该点位图层要素数据的场景。通过esri.identifyFeatures()
方法创建identify任务,调取指定Server的identify API,传入参数执行查询获取结果。常用于实现地图识别操作,即点哪查哪。
const identify = esri.identifyFeatures({
url: 'http://xxx/arcgis/rest/services/xxx/MapServer'
})
identify
.on(this.map)
.at([lat, lng])
.layers('0, 1')
.run(function (error, featureCollection, response) {
if (error) {
console.log(error)
return
}
console.log('identify' + featureCollection, response)
})
4.ArcGIS Server查询结果处理
通过以上任意方式获取到数据后,通常还需要将结果绘制到地图上作为反馈,第二节已经介绍了三种方法绘制点L.marker()
、线L.polyline()
、面L.polygon()
,我们拿到的查询结果都是包含geometry点位信息和属性信息的,这些绘制方法都适用。但是仔细观察数据会发现实际返回的结果结构为:
// 以下为featureCollection.features中元素结构
geometry: {
coordinates: [[lat1, lng1], [lat2, lng2] ... ],
type: "Polygon"
}
id: 1
properties: {…}
type: "Feature"
这种类型的数据为GeoJSON数据,我们可以使用L.geoJSON()
将这些结果处理成图层并绘制到地图上:
const featureGroup = L.featureGroup([]).addTo(this.map)
featureCollection.features.forEach(geojson => {
const geoFeature = L.geoJSON(geojson, {
// 这里可以定义一些样式
style: function (feature) {
color: 'red',
fillColor: 'green',
fillOpacity: 0.8
}
})
featureGroup.addLayer(geoFeature)
})
用L.geoJSON()
创建的要素和基础方式创建的要素一样,也可以进行自定义颜色和挂载弹窗以及自定义点击事件等操作。
5.ArcGIS Server结合Echarts开发
Echarts支持geo类型图表和echarts-gl,在一些大屏项目中应用也比较广泛,官方支持的数据类型就是GeoJSON,通过ArcGIS Server获取到的数据就能直接用来渲染图表。
ps:写在结尾
WebGIS开发在项目业务中常用的功能多半是和数据进行交互实现,无非是实现对空间数据的增删改查再额外添加一些样式渲染。如果是你当前参与项目所使用的技术框架刚好为Leaflet.js + ArcGIS Server那么本文应该可以帮助你入门,但是想要更深入的了解WebGIS开发还需要了解或掌握更多知识。一些基础概念如图层、要素、瓦片、矢量、栅格、坐标参考、坐标系等等都要继续了解并在实践中加深认知。除此之外,随着经验的积累你可能还需要了解另一款优秀的开源作品GeoServer(处理发布服务),或者国产化的超图SuperMap,或者Esri的ArcGIS API for JavaScript等等。