效果图
在线预览 如果跟上图不一致请按 Ctrl
+ F5
,或在评论区反馈。
前言
看过本专栏前3篇童鞋的应该知道,将所有功能整合在一起代码量是很大的,并且可能地图上需要绘制很多线和点,项目中可能有几十处需要应用到 ArcGis地图。本篇是将另外3篇实现的功能结合在一起封装成 Vue组件,力求使用极简的 Api 实现 绘制线条、绘制自定义图标、获取Graphic的数据、底图切换、添加小部件 等功能,使代码得到充分的复用。
ArcGisMap组件
<template>
<div id="map" class="map-container"></div>
</template>
<script>
import {
loadModules } from 'esri-loader'
import {
manyGraphics } from '@/utils/arcgisUtils'
export default {
name: 'ArcGisMap',
props: {
// 选择加载地图自定义部件 ['switch-map', 'full-screen']
tools: {
type: Array,
default: () => []
},
// 图形数据
graphicsData: {
type: Array,
default: () => []
},
// 地图初始中心点
centerPoint: {
type: Array,
default: () => [0, 0]
},
// 初始底图
defaultBaseMap: {
type: String,
default: 'osm'
},
// 初始缩放级别
zoom: {
type: Number,
default: 12
}
},
data () {
return {
view: null,
// 用于切换底图ID的数组
baseMaps: ['osm', 'satellite', 'terrain']
}
},
mounted () {
const {
defaultBaseMap, centerPoint, zoom, graphicsData } = this
loadModules(
['esri/Map', 'esri/views/MapView', 'esri/Graphic'],
{
css: true }
)
.then(
([ArcGISMap, MapView, Graphic]) => {
const map = new ArcGISMap({
basemap: defaultBaseMap
})
this.view = new MapView({
container: document.getElementById('map'),
map: map,
center: centerPoint,
zoom: zoom
})
// 将图形添加到视图的图形层
graphicsData.length && this.view.graphics.addMany(manyGraphics(Graphic, graphicsData))
// 绑定点击事件
this.view.on('click', e => {
this.view.hitTest(e)
.then(res => {
// 获取每个图形上的ID
res.results.length && this.$emit('clickGraphic', res.results[0].graphic.attributes)
})
})
// 添加自定义控件
this.tools.includes('switch-map') && this.view.ui.add(this.switchMapBtn(map), 'top-left')
this.tools.includes('full-screen') && this.view.ui.add(this.fullScreenBtn(), 'top-left')
}
)
},
methods: {
// 地图切换按钮
switchMapBtn (map) {
const btn = document.createElement('img')
btn.src = require('./icons/switch-map.jpg')
btn.style.width = '32px'
btn.style.height = '32px'
btn.style.cursor = 'pointer'
btn.onclick = () => {
let index = this.baseMaps.indexOf(map.basemap.id)
map.basemap = index < this.baseMaps.length - 1 ? this.baseMaps[++index] : this.baseMaps[0]
}
return btn
},
// 地图全屏按钮
fullScreenBtn () {
const btn = document.createElement('div')
btn.id = 'full-screen-btn'
btn.style.width = '32px'
btn.style.height = '32px'
btn.style.cursor = 'pointer'
btn.onclick = function () {
const mapContainer = document.getElementById('map')
const _body = document.body
this.classList.toggle('full-screen')
mapContainer.classList.toggle('full-screen')
mapContainer.classList.contains('full-screen') ? (_body.style.overflow = 'hidden') : (_body.style.overflow = '')
}
return btn
}
},
beforeDestroy () {
this.view && (this.view.container = null)
}
}
</script>
<style scoped lang="less">
.map-container {
width: 100%;
height: 100%;
background: #f5f5f5;
&.full-screen {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: 1;
}
/deep/ #full-screen-btn {
background: #fff url('./icons/full-screen.svg') no-repeat center center / 100% 100%;
&.full-screen {
background-image: url('./icons/normal-screen.svg');
}
}
}
</style>
arcgisUtils.js
/**
* 创建线
* @param Graphic 实例对象
* @param paths 路径经纬度数组
* @param color 路径的颜色
* @param borderWidth 路径的宽度
* @param id 该图形的 ID,用于判断点击的图形
* @returns {*}
*/
export function createLineGraphic (Graphic, paths, color, borderWidth, id) {
return new Graphic({
geometry: {
type: 'polyline',
paths: paths
},
symbol: {
type: 'simple-line',
color: color, // 颜色 rgb or rgba [255, 0, 0, 0.5] or 16进制
width: borderWidth
},
attributes: {
id: id
}
})
}
/**
* 创建点
* @param Graphic
* @param lng 点的位置
* @param lat
* @param markerUrl 图片的 url
* @param width 点的大小
* @param height
* @param id
* @returns {*}
*/
export function createPointGraphic (Graphic, lng, lat, markerUrl, width, height, id) {
return new Graphic({
geometry: {
type: 'point',
longitude: lng,
latitude: lat
},
symbol: {
type: 'picture-marker',
url: markerUrl,
width: width,
height: height
},
attributes: {
id: id
}
})
}
/**
* 生成 'Graphic实例' 数组
* @param Graphic Graphic类
* @param graphicsData 生成 Graphic 实例的数据
* @returns {[]}
*/
export function manyGraphics (Graphic, graphicsData) {
const graphics = []
graphicsData.forEach(item => {
if (item.paths) {
graphics.push(createLineGraphic(Graphic, ...Object.values(item)))
} else if (item.lng) {
graphics.push(createPointGraphic(Graphic, ...Object.values(item)))
}
})
return graphics
}
父组件
<template>
<div class="arcgis-map-wrapper">
<arc-gis-map
:tools="['switch-map', 'full-screen']"
:graphicsData="graphicsData"
:centerPoint="[117.17144639449873, 31.83296921125205]"
@clickGraphic="getParams"
/>
</div>
</template>
<script>
import ArcGisMap from '@/components/ArcgisMap/ArcgisMap'
export default {
components: {
ArcGisMap },
data () {
return {
// 图形数据
graphicsData: [
{
paths: [
[117.129359, 31.839979],
[117.128810, 31.839979],
[117.128810, 31.832240],
[117.227610, 31.833600]
],
color: '#1e80ff',
width: 5,
id: 'Hello world'
},
{
lng: 117.129359,
lat: 31.839979,
markerUrl: require('@/assets/img/view-start.png'),
width: '32px',
height: '48px',
id: 'Foo'
},
{
lng: 117.227610,
lat: 31.833600,
markerUrl: require('@/assets/img/view-end.png'),
width: '32px',
height: '48px',
id: 'Bar'
}
]
}
},
methods: {
getParams (e) {
this.$message.info(JSON.stringify(e))
}
}
}
</script>
<style lang="less" scoped>
.arcgis-map-wrapper {
width: 100%;
height: 100%;
}
</style>
结束语
呼~~又贴了这么多又臭又长的代码,其实我看博文第一看有没有demo图片,第二看是不是高亮代码,不然很难深入看下去,贴这么多代码是为了需要的人能第一时间看到想要的东西。
为什么开 ArcGisJS系列 专栏?主要是入坑完 ArcGisJS 后,感觉要记录一下,万一以后的项目又用到 ArcGisJS 怎么办,这东西半年不用就忘。虽然本专栏内文章都是基于 ArcGisJS 的粗浅使用,但是忘了七七八八后再折腾一下也得花不少时间。而记录下来,不仅加深了理解,也能帮助初次接触的人少走更多弯路。