mirror of https://gitee.com/xiaonuobase/snowy
370 lines
8.5 KiB
Vue
370 lines
8.5 KiB
Vue
<template>
|
||
<div class="gaodeMap" :style="{ height: `${height}px` }">
|
||
<div :id="`container-${mid}`" style="width: 100%; height: 100%">地图资源加载中...</div>
|
||
</div>
|
||
</template>
|
||
<!--AMap官网:https://lbs.amap.com/api/javascript-api-v2/summary-->
|
||
<script setup name="GaodeMap">
|
||
import { onMounted, onUnmounted, shallowRef } from 'vue'
|
||
import AMapLoader from '@amap/amap-jsapi-loader'
|
||
|
||
const props = defineProps({
|
||
mid: {
|
||
type: Number,
|
||
default: new Date().getTime()
|
||
},
|
||
height: {
|
||
type: Number,
|
||
default: 800
|
||
},
|
||
apiKey: {
|
||
type: String,
|
||
required: true
|
||
},
|
||
center: {
|
||
type: Array
|
||
},
|
||
plugins: {
|
||
type: Array,
|
||
// eslint-disable-next-line vue/require-valid-default-prop
|
||
default: ['AMap.ToolBar', 'AMap.Scale', 'AMap.HawkEye', 'AMap.MapType', 'AMap.Geolocation', 'AMap.MarkerCluster']
|
||
},
|
||
viewMode: {
|
||
type: String,
|
||
default: '3D',
|
||
validator(value) {
|
||
return ['2D', '3D'].includes(value)
|
||
}
|
||
},
|
||
zoom: {
|
||
type: Number,
|
||
default: 12
|
||
},
|
||
pitch: {
|
||
type: Number,
|
||
default: 50
|
||
},
|
||
mapStyle: {
|
||
type: String,
|
||
default: 'normal',
|
||
validator(value) {
|
||
return ['normal', 'macaron', 'dark', 'fresh', 'grey'].includes(value)
|
||
}
|
||
},
|
||
markerCluster: {
|
||
type: Boolean,
|
||
default: true
|
||
}
|
||
})
|
||
|
||
const emits = defineEmits(['complete', 'markerClick'])
|
||
|
||
const gaodeMap = shallowRef(null)
|
||
const gaodeMapMarkerArr = ref([])
|
||
const gaodeMapInfoWindowObj = ref({})
|
||
|
||
const init = () => {
|
||
AMapLoader.load({
|
||
key: props.apiKey,
|
||
version: '2.0',
|
||
plugins: props.plugins,
|
||
AMapUI: {
|
||
version: '1.1',
|
||
plugins: ['overlay/SimpleMarker', 'overlay/AwesomeMarker']
|
||
}
|
||
})
|
||
.then(() => {
|
||
initMap()
|
||
})
|
||
.catch((e) => {
|
||
console.error(e)
|
||
})
|
||
}
|
||
|
||
// 初始化 地图
|
||
const initMap = () => {
|
||
gaodeMap.value = new AMap.Map(`container-${props.mid}`, {
|
||
viewMode: props.viewMode,
|
||
zoom: props.zoom,
|
||
// 地图俯仰角度
|
||
pitch: props.pitch,
|
||
mapStyle: `amap://styles/${props.mapStyle}`
|
||
})
|
||
|
||
// 中心点
|
||
if (props.center) {
|
||
gaodeMap.value.setCenter(props.center)
|
||
}
|
||
|
||
// 控件
|
||
props.plugins.length > 0 && initControlPlugin()
|
||
|
||
// 地图初始化完成
|
||
gaodeMap.value.on('complete', () => {
|
||
emits('complete')
|
||
})
|
||
}
|
||
|
||
// 初始化 控制控件
|
||
const initControlPlugin = () => {
|
||
// 工具条,控制地图的缩放、平移等
|
||
props.plugins.includes('AMap.ToolBar') && gaodeMap.value.addControl(new AMap.ToolBar({}))
|
||
// 比例尺
|
||
props.plugins.includes('AMap.Scale') && gaodeMap.value.addControl(new AMap.Scale())
|
||
// 鹰眼,显示缩略图
|
||
props.plugins.includes('AMap.HawkEye') && gaodeMap.value.addControl(new AMap.HawkEye({ isOpen: true }))
|
||
// 图层切换
|
||
props.plugins.includes('AMap.MapType') && gaodeMap.value.addControl(new AMap.MapType({}))
|
||
// 定位
|
||
props.plugins.includes('AMap.Geolocation') && gaodeMap.value.addControl(new AMap.Geolocation({}))
|
||
}
|
||
|
||
// 渲染 点标记
|
||
const renderMarker = (dataArr) => {
|
||
dataArr.forEach((d) => {
|
||
const marker = new AMap.Marker({
|
||
map: gaodeMap.value,
|
||
position: d.position,
|
||
// 鼠标滑过点标记时的文字提示
|
||
title: d.title,
|
||
// 显示内容:content有效时,icon属性将被覆盖
|
||
content: d.content,
|
||
// 图标
|
||
icon: d.icon ? d.icon : null,
|
||
// 文本标注
|
||
label: d.label
|
||
})
|
||
marker.on('click', () => {
|
||
emits('markerClick', d.position)
|
||
})
|
||
gaodeMapMarkerArr.value.push(marker)
|
||
})
|
||
|
||
setFitView()
|
||
}
|
||
|
||
// 渲染 圆点标记
|
||
const renderCircleMarker = (dataArr) => {
|
||
dataArr.forEach((d) => {
|
||
const marker = new AMap.CircleMarker({
|
||
map: gaodeMap.value,
|
||
// 圆心位置
|
||
center: d.position,
|
||
// 圆点半径
|
||
radius: d.radius ? d.radius : 20,
|
||
// 线条颜色
|
||
strokeColor: d.strokeColor ? d.strokeColor : '#006600',
|
||
// 轮廓线透明度
|
||
strokeOpacity: 0.5,
|
||
// 轮廓线宽度
|
||
strokeWeight: 2,
|
||
// 填充颜色
|
||
fillColor: d.fillColor ? d.fillColor : '#006600',
|
||
// 填充透明度
|
||
fillOpacity: 0.5,
|
||
cursor: 'pointer'
|
||
})
|
||
marker.on('click', () => {
|
||
emits('markerClick', d.position)
|
||
})
|
||
gaodeMapMarkerArr.value.push(marker)
|
||
})
|
||
|
||
setFitView()
|
||
}
|
||
|
||
// 渲染 简单点标记
|
||
const renderSimpleMarker = (dataArr, theme = 'default') => {
|
||
dataArr.forEach((d) => {
|
||
const marker = new AMapUI.SimpleMarker({
|
||
map: gaodeMap.value,
|
||
position: d.position,
|
||
// 前景文字
|
||
iconLabel: {
|
||
// 文本
|
||
innerHTML: d.label,
|
||
// 字体的样式,比如颜色,大小等
|
||
style: d.labelStyle
|
||
? d.labelStyle
|
||
: {
|
||
color: '#333',
|
||
fontSize: '12px'
|
||
}
|
||
},
|
||
// 图标主题:default,fresh,numv1,numv2
|
||
iconTheme: theme,
|
||
// 背景图标样式
|
||
iconStyle: d.style
|
||
})
|
||
marker.on('click', () => {
|
||
emits('markerClick', d.position)
|
||
})
|
||
gaodeMapMarkerArr.value.push(marker)
|
||
})
|
||
|
||
setFitView()
|
||
}
|
||
|
||
// 渲染 字体点标记
|
||
const renderAwesomeMarker = (dataArr) => {
|
||
dataArr.forEach((d) => {
|
||
const marker = new AMapUI.AwesomeMarker({
|
||
map: gaodeMap.value,
|
||
position: d.position,
|
||
// 图标,参见:http://fontawesome.io/icons/
|
||
awesomeIcon: d.awesomeIcon,
|
||
// 字体的样式,比如颜色,大小等
|
||
iconLabel: {
|
||
style: d.labelStyle
|
||
? d.labelStyle
|
||
: {
|
||
color: '#333',
|
||
fontSize: '12px'
|
||
}
|
||
},
|
||
// 背景图标的样式
|
||
iconStyle: d.style
|
||
})
|
||
marker.on('click', () => {
|
||
emits('markerClick', d.position)
|
||
})
|
||
gaodeMapMarkerArr.value.push(marker)
|
||
})
|
||
|
||
setFitView()
|
||
}
|
||
|
||
// 设置 视图级别
|
||
const setFitView = () => {
|
||
// 点聚合
|
||
props.markerCluster && new AMap.MarkerCluster(gaodeMap.value, gaodeMapMarkerArr.value)
|
||
|
||
// 根据地图上添加的覆盖物分布情况,自动缩放地图到合适的视野级别
|
||
gaodeMap.value.setFitView(gaodeMapMarkerArr.value)
|
||
}
|
||
|
||
// 渲染 线
|
||
const renderPolyline = (dataArr, option = {}) => {
|
||
const path = []
|
||
dataArr.forEach((d) => {
|
||
path.push(new AMap.LngLat(d.position[0], d.position[1]))
|
||
})
|
||
|
||
const polyline = new AMap.Polyline({
|
||
path: path,
|
||
strokeColor: option.strokeColor || 'blue',
|
||
strokeWeight: option.strokeWeight || 2,
|
||
strokeOpacity: option.strokeOpacity || 0.5,
|
||
isOutline: option.isOutline || false,
|
||
borderWeight: option.borderWeight || 1,
|
||
// 折线拐点连接处样式
|
||
lineJoin: 'round'
|
||
})
|
||
gaodeMap.value.add(polyline)
|
||
|
||
gaodeMap.value.setFitView([polyline])
|
||
}
|
||
|
||
// 渲染 圆
|
||
const renderCircle = (position, radius, option) => {
|
||
const circle = new AMap.Circle({
|
||
center: new AMap.LngLat(position[0], position[1]),
|
||
radius: radius,
|
||
strokeColor: option.strokeColor || 'blue',
|
||
strokeWeight: option.strokeWeight || 2,
|
||
strokeOpacity: option.strokeOpacity || 0.5,
|
||
fillColor: option.fillColor || 'blue',
|
||
fillOpacity: option.fillOpacity || 0.5,
|
||
strokeStyle: 'solid'
|
||
})
|
||
gaodeMap.value.add(circle)
|
||
|
||
gaodeMap.value.setFitView([circle])
|
||
}
|
||
|
||
// 渲染 面
|
||
const renderPolygon = (dataArr, option = {}) => {
|
||
const path = []
|
||
dataArr.forEach((d) => {
|
||
path.push(new AMap.LngLat(d.position[0], d.position[1]))
|
||
})
|
||
|
||
const polygon = new AMap.Polygon({
|
||
path: path,
|
||
strokeColor: option.strokeColor || 'blue',
|
||
strokeWeight: option.strokeWeight || 2,
|
||
strokeOpacity: option.strokeOpacity || 0.5,
|
||
fillColor: option.fillColor || 'blue',
|
||
fillOpacity: option.fillOpacity || 0.5,
|
||
strokeStyle: 'solid'
|
||
})
|
||
gaodeMap.value.add(polygon)
|
||
|
||
gaodeMap.value.setFitView([polygon])
|
||
}
|
||
|
||
// 渲染 信息窗体
|
||
const renderInfoWindow = (dataArr) => {
|
||
dataArr.forEach((d) => {
|
||
gaodeMapInfoWindowObj.value[d.position] = new AMap.InfoWindow({
|
||
// 显示内容
|
||
content: d.content.join('<br>'),
|
||
// 位置偏移量
|
||
offset: new AMap.Pixel(0, -20),
|
||
// 点击地图后关闭信息窗体
|
||
closeWhenClickMap: true
|
||
})
|
||
})
|
||
}
|
||
|
||
// 打开 信息窗体
|
||
const openInfoWindow = (position) => {
|
||
const infoWindow = gaodeMapInfoWindowObj.value[position]
|
||
if (infoWindow) {
|
||
infoWindow.open(gaodeMap.value, position)
|
||
}
|
||
}
|
||
|
||
// 清理 覆盖物
|
||
const clearOverlay = () => {
|
||
gaodeMap.value.clearMap()
|
||
}
|
||
|
||
onMounted(() => {
|
||
init()
|
||
})
|
||
|
||
onUnmounted(() => {
|
||
gaodeMap.value && gaodeMap.value.destroy()
|
||
})
|
||
|
||
defineExpose({
|
||
renderMarker,
|
||
renderCircleMarker,
|
||
renderSimpleMarker,
|
||
renderAwesomeMarker,
|
||
renderPolyline,
|
||
renderCircle,
|
||
renderPolygon,
|
||
renderInfoWindow,
|
||
openInfoWindow,
|
||
clearOverlay
|
||
})
|
||
</script>
|
||
|
||
<style lang="less">
|
||
.gaodeMap {
|
||
padding: 0;
|
||
margin: 0;
|
||
width: 100%;
|
||
|
||
input[type='radio'] {
|
||
-webkit-appearance: radio;
|
||
}
|
||
|
||
input[type='checkbox'] {
|
||
-webkit-appearance: checkbox;
|
||
}
|
||
}
|
||
</style>
|