【新增】百度地图组件 BMap

pull/147/MERGE
这么诚实 2023-07-28 14:24:53 +08:00 committed by 小诺
parent 7a3b988a44
commit f237abd040
3 changed files with 713 additions and 0 deletions

View File

@ -0,0 +1,181 @@
BMap
====
> 百度地图组件,常用于地图展示使用
该组件由 [小诺开源技术](https://www.xiaonuo.vip) 封装
### 使用方式
```vue
<template>
<a-map ref="map" api-key="******" @complete="handleComplete"
@marker-click="handleMarkerClick"></a-map>
</template>
<script setup name="exmAMap">
import AMap from '@/components/Map/bMap/index.vue'
const map = ref(null)
const handleComplete = () => {
// 渲染 点标记
map.value.renderMarker(
[
{
position: [116.39, 39.9],
title: 'TA',
content: 'CA',
label: {
content: 'LCA'
}
},
{
position: [116.33, 39.5],
title: 'TB',
icon: '//vdata.amap.com/icons/b18/1/2.png'
}
]
)
}
const handleMarkerClick = (position) => {
map.value.openInfoWindow(position)
}
</script>
```
### Prop属性
| 名称 | 说明 | 类型 | 默认值 |
|---------------|--------------|--------|------|
| mid | 容器ID | String | 时间戳 |
| apiKey | 地图Key | String | |
| center | 地图中心点 | String | 自动定位 |
| plugins | 地图控件 | Array | |
| viewMode | 效果2D3D | String | 3D |
| rotationAngle | 旋转角度 | Number | 60 |
| tiltAngle | 倾斜角度 | Number | 70 |
| zoom | 地图缩放比例 | Number | 12 |
| mapStyle | 地图样式:个性化地图 | String | |
#### 地图控件
- BMap.ScaleControl比例尺
- BMap.ZoomControl缩放
- BMap.LocationControl定位
- BMap.NavigationControl3D3D控件
### 事件
| 名称 | 说明 | 参数 | 参数类型 |
|-------------|---------------|----------|-------|
| complete | 当地图初始化完成时触发 | - | - |
| markerClick | 当点击了点覆盖物时触发 | position | Array |
### 方法
| 名称 | 说明 | 参数 | 参数类型 |
|----------------------|-----------|------------------------|-------------------|
| renderMarker | 渲染 点标记 | dataArr | Array |
| renderIconMarker | 渲染 图标标记 | dataArr | Array |
| render3DCircleMarker | 渲染 3D圆点标记 | dataArr | Array |
| render3DIconMarker | 渲染 3D图标标记 | dataArr | Array |
| renderPolyline | 渲染 线 | dataArr,option | Array,JSON |
| renderCircle | 渲染 圆 | position,radius,option | Array,Number,JSON |
| renderPolygon | 渲染 面 | dataArr,option | Array,JSON |
| renderInfoWindow | 渲染 信息窗体 | dataArr | Array |
| openInfoWindow | 打开 信息窗体 | position | Array |
| clearOverlay | 清理 覆盖物 | | |
### 方法参数```dataArr```结构
> 点标记
```json
[{
"position": "坐标数组",
"title": "鼠标滑过点标记时的文字提示"
}]
```
> 图标标记
```json
[{
"position": "坐标数组",
"title": "鼠标滑过点标记时的文字提示",
"img": "图片地址",
"imgWidth": "图片宽度默认40",
"imgHeight": "图片高度默认40"
}]
```
> 3D圆点标记
```json
[{
"position": "坐标数组",
"height": "高度默认8000",
"size": "大小默认50",
"fillColor": "填充颜色,默认#006600"
}]
```
> 3D图标标记
```json
[{
"position": "坐标数组",
"height": "高度默认8000",
"size": "大小默认50",
"img": "图片地址",
"imgWidth": "图片宽度默认40",
"imgHeight": "图片高度默认40"
}]
```
> 线、面
```json
[{
"position": "坐标数组"
}]
```
> 信息窗体
```json
[{
"position": "坐标数组",
"title": "标题",
"content": "内容,文本数组,会以换行进行连接",
"width": "窗体宽度",
"height": "窗体高度"
}]
```
### 方法参数```option```结构
> 线、圆
```json
{
"strokeColor": "边线颜色默认blue",
"strokeWeight": "边线宽度默认2",
"strokeOpacity": "边线透明度默认0.5"
}
```
> 面
```json
{
"strokeColor": "边线颜色默认blue",
"strokeWeight": "边线宽度默认2",
"strokeOpacity": "边线透明度默认0.5",
"fillColor": "填充颜色默认blue",
"fllOpacity": "填充透明度默认0.5"
}
```

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -0,0 +1,402 @@
<template>
<div class="bMap">
<div :id="`container-${mid}`" style="width: 100%;height: 100%;">
地图资源加载中...
</div>
</div>
</template>
<!--BMapGL官网https://lbsyun.baidu.com/index.php?title=jspopularGL-->
<script setup name="BMap">
import {onMounted, onUnmounted, shallowRef} from "vue"
const props = defineProps(
{
mid: {
type: Number,
default: new Date().getTime()
},
apiKey: {
type: String,
required: true
},
center: {
type: Array
},
plugins: {
type: Array,
default: [
'BMap.ScaleControl',
'BMap.ZoomControl',
'BMap.LocationControl',
'BMap.NavigationControl3D'
]
},
viewMode: {
type: String,
default: '3D',
validator(value) {
return ['2D', '3D'].includes(value)
}
},
rotationAngle: {
type: Number,
default: 60
},
tiltAngle: {
type: Number,
default: 70
},
zoom: {
type: Number,
default: 12
},
mapStyle: {
type: String
}
}
)
const emits = defineEmits(['complete', 'markerClick'])
const bMap = shallowRef(null)
const bMapPointArr = ref([])
const bMapInfoWindowObj = ref({})
const init = () => {
// script api
const script = document.createElement('script')
script.src = `https://api.map.baidu.com/api?v=1.0&&type=webgl&ak=${props.apiKey}&callback=initMap`
// head api
const head = document.getElementsByTagName('head')[0]
head.appendChild(script)
}
/**
* 初始化 地图
*/
window.initMap = () => {
bMap.value = new BMapGL.Map(`container-${props.mid}`)
//
bMap.value.enableScrollWheelZoom(true)
//
if (props.mapStyle) {
bMap.setMapStyleV2(props.mapStyle)
}
//
props.plugins.length > 0 && initControlPlugin()
//
if (props.center) {
setFitView(new BMapGL.Point(props.center[0], props.center[1]))
//
emits('complete')
} else {
//
new BMapGL.Geolocation().getCurrentPosition((r) => {
if (r) {
setFitView(new BMapGL.Point(r.longitude, r.latitude))
} else {
console.error('getCurrentPosition fail', r)
setFitView()
}
//
emits('complete')
})
}
}
/**
* 初始化 控制控件
*/
const initControlPlugin = () => {
//
props.plugins.includes('BMap.ScaleControl') && bMap.value.addControl(new BMapGL.ScaleControl())
//
props.plugins.includes('BMap.ZoomControl') && bMap.value.addControl(new BMapGL.ZoomControl())
//
props.plugins.includes('BMap.LocationControl') && bMap.value.addControl(new BMapGL.LocationControl())
// 3D
props.plugins.includes('BMap.NavigationControl3D') && bMap.value.addControl(new BMapGL.NavigationControl3D())
}
/**
* 渲染 点标记
* @param dataArr
*/
const renderMarker = (dataArr) => {
dataArr.forEach(d => {
const point = new BMapGL.Point(d.position[0], d.position[1])
const marker = new BMapGL.Marker(
//
point,
{
//
title: d.title
}
)
marker.addEventListener('click', () => {
emits('markerClick', d.position)
})
bMap.value.addOverlay(marker)
bMapPointArr.value.push(point)
})
setFitView()
}
/**
* 渲染 图标标记
* @param dataArr
*/
const renderIconMarker = (dataArr) => {
dataArr.forEach(d => {
const point = new BMapGL.Point(d.position[0], d.position[1])
const marker = new BMapGL.Marker(
//
point,
{
//
title: d.title,
//
icon: new BMapGL.Icon(d.img,
new BMapGL.Size(d.imgWidth ? d.imgWidth : 40, d.imgHeight ? d.imgHeight : 40)
)
}
)
marker.addEventListener('click', () => {
emits('markerClick', d.position)
})
bMap.value.addOverlay(marker)
bMapPointArr.value.push(point)
})
setFitView()
}
/**
* 渲染 3D圆点标记
* @param dataArr
*/
const render3DCircleMarker = (dataArr) => {
dataArr.forEach(d => {
const point = new BMapGL.Point(d.position[0], d.position[1])
const marker = new BMapGL.Marker3D(
//
point,
// 8000
d.height ? d.height : 8000,
//
{
// 50
size: d.size ? d.size : 50,
//
shape: 'BMAP_SHAPE_CIRCLE',
//
fillColor: d.fillColor ? d.fillColor : '#006600',
//
fillOpacity: 0.5
}
)
marker.addEventListener('click', () => {
emits('markerClick', d.position)
})
bMap.value.addOverlay(marker)
bMapPointArr.value.push(point)
})
setFitView()
}
/**
* 渲染 3D图标标记
* @param dataArr
*/
const render3DIconMarker = (dataArr) => {
dataArr.forEach(d => {
const point = new BMapGL.Point(d.position[0], d.position[1])
const marker = new BMapGL.Marker3D(
//
point,
// 8000
d.height ? d.height : 8000,
//
{
// 50
size: d.size ? d.size : 50,
//
icon: new BMapGL.Icon(d.img,
new BMapGL.Size(d.imgWidth ? d.imgWidth : 40, d.imgHeight ? d.imgHeight : 40)
)
}
)
marker.addEventListener('click', () => {
emits('markerClick', d.position)
})
bMap.value.addOverlay(marker)
bMapPointArr.value.push(point)
})
setFitView()
}
/**
* 渲染 线
* @param dataArr
* @param option
*/
const renderPolyline = (dataArr, option = {}) => {
dataArr.forEach(d => {
bMapPointArr.value.push(new BMapGL.Point(d.position[0], d.position[1]))
})
const polyline = new BMapGL.Polyline(bMapPointArr.value, {
stokeStyle: 'solid',
strokeColor: option.strokeColor || 'blue',
strokeWeight: option.strokeWeight || 2,
strokeOpacity: option.strokeOpacity || 0.5
})
bMap.value.addOverlay(polyline)
setFitView()
}
/**
* 渲染
* @param position
* @param radius
* @param option
*/
const renderCircle = (position, radius, option = {}) => {
const point = new BMapGL.Point(position[0], position[1])
bMapPointArr.value.push(point)
const circle = new BMapGL.Circle(
point,
radius ? radius : 500,
{
strokeColor: option.strokeColor || 'blue',
strokeWeight: option.strokeWeight || 2,
strokeOpacity: option.strokeOpacity || 0.5
})
bMap.value.addOverlay(circle)
setFitView()
}
/**
* 渲染
* @param dataArr
* @param option
*/
const renderPolygon = (dataArr, option = {}) => {
dataArr.forEach(d => {
bMapPointArr.value.push(new BMapGL.Point(d.position[0], d.position[1]))
})
const polygon = new BMapGL.Polygon(bMapPointArr.value, {
stokeStyle: 'solid',
strokeColor: option.strokeColor || 'blue',
strokeWeight: option.strokeWeight || 2,
strokeOpacity: option.strokeOpacity || 0.5,
fillColor: option.fillColor || 'blue',
fllOpacity: option.fllOpacity || 0.5
})
bMap.value.addOverlay(polygon)
setFitView()
}
/**
* 设置 视图级别
* @param point
*/
const setFitView = (point) => {
if (!point) {
const viewPort = bMap.value.getViewport(bMapPointArr.value)
point = new BMapGL.Point(viewPort.center.lng, viewPort.center.lat)
}
bMap.value.centerAndZoom(point, props.zoom)
// 3D
if (props.viewMode === '3D') {
//
bMap.value.setHeading(props.rotationAngle)
//
bMap.value.setTilt(props.tiltAngle)
}
}
/**
* 渲染 信息窗体
* @param dataArr
*/
const renderInfoWindow = (dataArr) => {
dataArr.forEach(d => {
bMapInfoWindowObj.value[d.position] = new BMapGL.InfoWindow(
d.content.join('<br>'),
{
title: d.title,
width: d.width ? d.width : 250,
height: d.height ? d.height : 100
}
)
})
}
/**
* 打开 信息窗体
* @param position
*/
const openInfoWindow = (position) => {
const infoWindow = bMapInfoWindowObj.value[position]
if (infoWindow) {
bMap.value.openInfoWindow(infoWindow, new BMapGL.Point(position[0], position[1]))
}
}
/**
* 清理 覆盖物
*/
const clearOverlay = () => {
bMap.value.clearOverlays()
}
onMounted(() => {
init()
})
onUnmounted(() => {
bMap.value && bMap.value.destroy()
})
defineExpose({
renderMarker,
renderIconMarker,
render3DCircleMarker,
render3DIconMarker,
renderPolyline,
renderCircle,
renderPolygon,
renderInfoWindow,
openInfoWindow,
clearOverlay
})
</script>
<style lang="less">
.bMap {
padding: 0;
margin: 0;
width: 100%;
height: 800px;
}
</style>

View File

@ -0,0 +1,130 @@
<template>
<b-map ref="map" api-key="NtTydKuftIVXAy526uWXZoHS86lg0KeW" @complete="handleComplete"
@marker-click="handleMarkerClick"></b-map>
</template>
<script setup name="exmBMap">
import BMap from '@/components/Map/bMap/index.vue'
const map = ref(null)
const handleComplete = () => {
console.log('complete')
//
map.value.renderMarker(
[
{
position: [116.39, 39.9],
title: 'BI'
},
{
position: [116.33, 39.5],
title: 'BI-2'
}
]
)
//
// map.value.renderIconMarker(
// [
// {
// position: [116.39, 39.9],
// title: 'BI',
// img: 'https://webmap0.bdimg.com/image/api/bg.png',
// imgWidth: 40,
// imgHeight: 40
// },
// {
// position: [116.33, 39.5],
// title: 'BI-2',
// img: 'https://webmap0.bdimg.com/image/api/bg.png'
// }
// ]
// )
// 3D
// map.value.render3DCircleMarker(
// [
// {
// position: [116.39, 39.9],
// height: 7000,
// size: 40
// },
// {
// position: [116.33, 39.5],
// height: 7000,
// size: 40
// }
// ]
// )
// 3D
// map.value.render3DIconMarker(
// [
// {
// position: [116.39, 39.9],
// height: 7000,
// size: 40,
// img: 'https://webmap0.bdimg.com/image/api/bg.png',
// imgWidth: 40,
// imgHeight: 40
// },
// {
// position: [116.33, 39.5],
// height: 7000,
// img: 'https://webmap0.bdimg.com/image/api/bg.png'
// }
// ]
// )
//
// map.value.renderPolygon(
// [
// {
// position: [116.39, 39.9]
// },
// {
// position: [116.47, 39.8]
// },
// {
// position: [116.46, 39.7]
// },
// {
// position: [116.35, 39.6]
// }
// ]
// )
//
map.value.renderInfoWindow(
[
{
position: [116.39, 39.9],
title: 'Snowy-小诺开源技术',
content: [
"<div style='padding:0'>",
"网站 : https://www.xiaonuo.vip",
"Snowy是一款国内首例国产密码算法加密框架采用Vue3.0+AntDesignVue3.0+SpringBoot2.8前后分离技术打造,技术框架与密码的结合,让前后分离‘密’不可分!</div>"
]
},
{
position: [116.33, 39.5],
title: 'Snowy-小诺开源技术',
content: [
"<div style='padding:0'>",
"网站 : https://www.xiaonuo.vip",
"Snowy是一款国内首例国产密码算法加密框架采用Vue3.0+AntDesignVue3.0+SpringBoot2.8前后分离技术打造,技术框架与密码的结合,让前后分离‘密’不可分!</div>"
],
width: 300,
height: 200
}
]
)
}
const handleMarkerClick = (position) => {
map.value.openInfoWindow(position)
console.log('marker click', position)
}
</script>
<style lang="less">
</style>