vue3 使用echarts和百度地图
vue3.0 使用echarts和百度地图进行地图展示,自定义标注和自定义信息窗口,infoBox,infoWindow
文章目录
前言
前端开发经常会在各种场合需要用到地图展示,网上很多实现都是基于vue2的,这里记录一下vue3实现地图展示和数据标注的几种方法。同时也会比较一下几种方法的优缺点。如果有新的发现的话也会随时更新到本章中。
提示:以下是本篇文章正文内容
一、使用echarts
1. 安装echarts
在项目中引入 Apache ECharts 参照官方文档进行安装和引入
npm install echarts --save
不建议使用vue-echarts, 因为echarts本身已经比较简单了,而且官方很多示例代码,用vue-echarts增加学习成本
2. echarts中使用百度地图
百度地图API3.0文档
这个方法的优点是简单快捷,将echarts和百度地图结合起来,缺点是百度地图不能单纯展示一个地区,如我只需要展示广东省的地图,这就不行。
2.1 引入百度地图
在public/index.html中引入,根据官网教程,注册百度地图,获取应用ak。
//public/index.html
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
<script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=你的ak"></script>
</head>
2.2 全部代码
以下是全部代码,其中涉及到echarts的配置问题可以查看echarts的官方文档
//EchartsBaiduMap.vue
<template>
<div ref="mapEcharts" class="baidu-map-echart"></div>
</template>
<script>
import * as echarts from 'echarts'
import 'echarts/extension/bmap/bmap' // bmap用来处理百度地图
import { ref, onMounted, reactive } from 'vue'
export default {
setup() {
//标点的数据格式,其中value是必须的[经度,纬度,值]
const state = reactive({
datas: [
{
name: '海门',
value: [121.15, 31.89, 100],
},
{
name: '鄂尔多斯',
value: [109.781327, 39.608266, 154],
},
{
name: '舟山',
value: [122.207216, 29.985295, 80],
},
{
name: '金昌',
value: [102.188043, 38.520089, 130],
},
{
name: '乳山',
value: [121.52, 36.89, 200],
},
],
})
//模板引用,引用上面的dom节点
const mapEcharts = ref(null)
//初始化echarts
function initEcharts() {
console.log(mapEcharts)
const myMap = echarts.init(mapEcharts.value)
const option = {
title: {
text: 'echart百度地图示例',
left: 'center',
},
// 使用echarts配置地图
bmap: {
center: [104.114129, 37.550339],
zoom: 5,
roam: true, // scale允许缩放,move允许移动,true允许两者
},
tooltip: {
trigger: 'item',
},
series: [
{
name: 'assets',
type: 'effectScatter',
coordinateSystem: 'bmap',
data: state.datas,
symbolSize: function (val) {
return val[2] / 5
},
encode: {
value: 2,
},
label: {
position: 'top',
},
itemStyle: {
color: '#ddb926',
},
emphasis: {
label: {
show: true,
},
},
},
],
}
myMap.setOption(option)
myMap.on('click', (params) => {
console.log('click', params)
})
// 使用百度api来配置
let bmap = myMap.getModel().getComponent('bmap').getBMap()
bmap.disableDoubleClickZoom() //阻止双击放大
}
onMounted(() => {
initEcharts()
})
return {
mapEcharts,
}
},
}
</script>
<style scoped>
.baidu-map-echart {
height: 100%;
}
</style>
2.3 结果
3 echarts使用geomap进行地图展示
这个方法的优点是可以单独展示某个地区的地图轮廓,缺点是轮廓图缺少地图的细节,如路线等等
3.1地图轮廓geojson获取
各个地区省份的地图轮廓json数据可以在这里获取DataV数据可视化平台
可以将需要的json数据下载到本地,然后将其进行修改如下,在json文件的开头加上变量,然后导出,然后将文件名改为js,这样就可以直接引用了。也可以用ajax直接获取json。
//china.js
export let data={"type":"FeatureCollection","fe..."
3.2 全部代码
//EchartsGeomap.vue
<template>
<div ref="mapEcharts" class="map-echart"></div>
</template>
<script>
import * as echarts from 'echarts'
import { data as guangdong } from './guangdong'
import { ref, nextTick, onMounted } from 'vue'
export default {
setup() {
const mapEcharts = ref(null)
function initEcharts() {
echarts.registerMap('guangdong', guangdong)
nextTick(() => {
const map = echarts.init(mapEcharts.value, null, {
renderer: 'canvas',
})
const option = {
title: {
text: '广东地图',
left: 'center',
},
// 悬浮窗
tooltip: {
trigger: 'item',
},
geo: {
map: 'guangdong',
zoom: 1,
roam: 'move',
label: {
show: true,
color: 'black',
position: 'inside',
distance: 0,
fontSize: 10,
rotate: 45,
},
// 所有地图的区域颜色
itemStyle: {
areaColor: '#eee',
borderColor: '#02c0ff',
},
emphasis: {
itemStyle: {
areaColor: '#aaa',
shadowColor: 'rgba(0,0,0,0.8)',
},
},
},
series: [
{
type: 'scatter',
coordinateSystem: 'geo',
data: [
{ name: '肇庆市', value: [112.48461, 23.05196, 20] },
{ name: '佛山市', value: [113.130234, 23.018978, 30] },
{ name: '广州', value: [113.261081, 23.139856, 10] },
],
symbolSize: (val) => {
return val[2]
},
encode: {
value: 2,
},
itemStyle: {
color: '#ddb926',
},
emphasis: {
label: {
show: true,
},
},
},
],
}
map.setOption(option)
})
}
onMounted(() => {
initEcharts()
})
return {
mapEcharts,
}
},
}
</script>
<style scoped>
.map-echart {
height: 600px;
width: 900px;
}
</style>
3.3 结果
二、直接使用百度地图
echarts 的优点是它可以很快的帮助我们将数据标注在地图上,如果仅仅是基础的数据展示来说,基本上已经够用了。但是当要实现地图复杂功能的展示的时候,就不够用了,比如说下面这种情况。
这个信息框展示的东西很多,还有按钮,这种效果echarts就做不了。直接用百度地图来做是比较好的
1. 引入百度地图
这个和2.1节是一样的.
不建议使用vue-baidu-map 这个库,一个原因是这个库已经很久没有维护了,还是使用的vue2.0版本,另一个原因是原生的百度地图更加灵活好用。
2. 全部代码
代码涉及一些参数配置,这些都可以参照百度地图官方文档
//baidumap.vue
<template >
<div class="contain">
<div id="baiduMap" ref="baiduMapRef" class="baidu-map"></div>
<div ref="infoBoxRef" class="info-box" v-if="resource">
<header>
<div class="name">
{{ resource.name }}
</div>
<button @click="onCloseInfoBox">close</button>
</header>
<main>这里是内容</main>
</div>
</div>
</template>
<script>
import { onMounted, ref, reactive, toRefs } from 'vue'
//自定义信息窗口
import MyInfoBox from './libs/myInfoBox'
//自定义标注
import CircleOverlay from './libs/circleOverlay'
export default {
setup() {
const state = reactive({
resource: {},
resources: [
{
name: 'name1',
coordiate: {
type: 'Point',
coordinates: [113.261081, 23.139856],
},
},
{
name: 'name2',
coordiate: {
type: 'Point',
coordinates: [116.703144, 39.540888],
},
},
],
})
const infoBoxRef = ref(null)
const baiduMapRef = ref(null)
let myInfoBox
onMounted(() => {
const map = new BMap.Map('baiduMap', {
minZoom: 10,
maxZoom: 18,
enableMapClick: false,
})
map.centerAndZoom(new BMap.Point(113.261081, 23.139856), 10)
map.disableDoubleClickZoom() //阻止双击放大
//设置自定义地图样式
map.setMapStyleV2({
styleId: 'dbc55f135f1d3ce3ead90de962ed0a8e',
})
//新建自定义信息窗口
myInfoBox = new MyInfoBox(infoBoxRef.value) //将我们上面自定义的dom结构传入
map.addOverlay(myInfoBox)
myInfoBox.hide() //先隐藏,当点击标注的时候再显示
//渲染标注
state.resources.forEach((val) => {
const point = new BMap.Point(...val.coordiate.coordinates)
//新建自定义标注
const circleMarker = new CircleOverlay(point, 40, '#ffe866ce')
map.addOverlay(circleMarker)
circleMarker.addEventListener('click', () => {
state.resource = val
myInfoBox.open(point) //显示自定义信息窗口
})
})
// infoBox.open(map.getCenter())
})
function onCloseInfoBox() {
myInfoBox.hide()
}
return {
infoBoxRef,
baiduMapRef,
...toRefs(state),
onCloseInfoBox,
}
},
}
</script>
<style lang="less" scoped>
.contain {
height: 100%;
}
.contain .baidu-map {
height: 100%;
}
.info-box {
background-color: #fff;
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.2);
position: absolute;
border-radius: 6px;
width: 230px;
padding: 16px 20px;
box-sizing: border-box;
color: #333;
}
.info-box header {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 18px;
}
.border {
height: 1px;
background-color: #eee;
margin: 10px 0 !important;
}
</style>
你可能已经注意到了,两个自定义文件,不慌,下面会详细讲到
3. 运行效果
4. 自定义标注以及自定义信息窗口
4.1 自定义标注
这个可以参考这个文档 自定义标注
效果就是上面的黄色圆形
//CircleOverlay.js
// 自定义实现圆形的标注
// 定义自定义覆盖物的构造函数
export default function CircleOverlay(center, length = 10, color) {
this._center = center
this._radius = length
this._color = color
}
// 继承API的BMap.Overlay
CircleOverlay.prototype = new BMap.Overlay()
CircleOverlay.prototype.initialize = function (map) {
// 保存map对象实例
this._map = map
// 创建div元素,作为自定义覆盖物的容器
var div = document.createElement('div')
div.style.position = 'absolute'
// 可以根据参数设置元素外观
div.style.borderRadius = '50%'
div.style.width = this._radius + 'px'
div.style.height = this._radius + 'px'
div.style.cursor = 'pointer'
div.style.background = this._color
// 将div添加到覆盖物容器中
map.getPanes().markerPane.appendChild(div)
// 保存div实例
this._div = div
// 需要将div元素作为方法的返回值,当调用该覆盖物的show、
// hide方法,或者对覆盖物进行移除时,API都将操作此元素。
return div
}
// 实现绘制方法
CircleOverlay.prototype.draw = function () {
// 根据地理坐标转换为像素坐标,并设置给容器
var position = this._map.pointToOverlayPixel(this._center)
this._div.style.left = position.x - this._radius / 2 + 'px'
this._div.style.top = position.y - this._radius / 2 + 'px'
}
CircleOverlay.prototype.addEventListener = function (type, fn) {
if (typeof type !== 'string' || typeof fn !== 'function') return
this._div.addEventListener(type, fn)
}
4.2 自定义信息窗口
官方文档中自定义信息窗口 是使用 infoWindow
来实现自定义的,但是这有一些限制,如不能自定义边框,不能自定义关闭按钮等。而且样式也不怎么好看
文档中还提到了可以使用BMapLib.infoBox
来实现更自由的信息窗口,但BMapLib.infoBox
需要另外在index.html
引入InfoBox.js ,而且个人觉得它还不够自由。
信息窗口也是覆盖物的一种,所以我们可以像自定义标注那样进行自定义信息窗口,同样只需要继承BMap.Overlay
就好。
//myInfoBox.js
export default function MyInfoBox(content) {
this._content = content
}
MyInfoBox.prototype = new BMap.Overlay()
MyInfoBox.prototype.initialize = function (map) {
this._map = map
this._loc = map.getCenter()
map.getPanes().floatPane.appendChild(this._content)
return this._content
}
MyInfoBox.prototype.draw = function () {
var position = this._map.pointToOverlayPixel(this._loc)
console.log()
this._content.style.left = position.x - this._content.clientWidth / 2 + 'px'
this._content.style.top = position.y - this._content.clientHeight - 10 + 'px'
// this._content.style.left = position.x + 'px'
// this._content.style.top = position.y + 'px'
}
MyInfoBox.prototype.open = function (point) {
this._loc = point
this.draw()
this.show()
}
总结
记录一下学习的过程
更多推荐
所有评论(0)