vue 数据大屏 项目开发中,需要使用echarts渲染地图效果,为了数据展示以及效果美观,一般都会在鼠标点击地图的时候,在点击的位置显示一个弹窗用来展示数据,但是因为鼠标点击距离边界比较近,而弹窗又比较大,会导致弹窗不能完整的展示出来,会有一部分弹窗溢出边界被遮挡,导致无法完整显示,这时候我们就需要做一些处理了。
解决思路
我们在鼠标点击的时候首先获取鼠标当前的坐标,并获取当前组件的宽和高,以及弹窗的宽和高,然后计算鼠标坐标加上弹窗的宽高是不是会超出div的边界,如果没有超出的话,就默认显示,如果超出了,就给一个预设的最大边界值。
关键代码
myChart.on('click', function (params) {
let data = myChart.convertFromPixel('geo', [params.event.event.offsetX, params.event.event.offsetY])
// 判断是否超出x轴边界
if (params.event.event.offsetX > (that.$refs.echartsBody.offsetWidth - 408)) {
that.left = that.$refs.echartsBody.offsetWidth - 408
} else {
that.left = params.event.event.offsetX
}
// 判断是否超出y轴边界
if (params.event.event.offsetY > (that.$refs.echartsBody.offsetHeight - 222)) {
that.top = that.$refs.echartsBody.offsetHeight - 222
} else {
that.top = params.event.event.offsetY
}
that.name = params.data.name
that.show = true
})
完整代码
<template>
<div class="item1" ref="echartsBody">
<div class="centerMap2">
<item :item="item" v-for="(item,index) in list" :key="index"></item>
</div>
<div class="centerMap" ref="centerMap">
</div>
<div class="map">
</div>
<div class="popWin" v-if="show" @click="show=false" :style="{left:left+'px',top:top+'px'}">
<div class="popWins">
<div class="titleInfos">
<p class="cityName">地区信息</p>
</div>
<div class="popLine">
</div>
<div class="infoBody">
<div class="infoItem">
<div class="infoItemTitle">
<img src="../assets/sudan.png" alt="">
<span>{{ name }}</span>
</div>
<div class="infoItemDesc">对应的国家</div>
</div>
<div class="infoItem">
<div class="infoItemTitle">3</div>
<div class="infoItemDesc">对应数量</div>
</div>
<div class="infoItem">
<div class="infoItemTitle">716</div>
<div class="infoItemDesc">注册企业数量</div>
</div>
<div class="infoItem">
<div class="infoItemTitle">植物源性食品、动物源...</div>
<div class="infoItemDesc">主要产品</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import data from '../assets/data.json'
import * as echarts from "echarts"
import icon1 from '../assets/quan.png'
export default {
name: "item1",
data() {
return {
data,
height: 0,
width: 0,
popShow: false,
left: 0,
top: 0,
show: false,
name: '',
num: 10,
iconData: [],
list: []
}
},
components: {},
watch: {},
mounted() {
var that = this;
const viewElem = document.body;
// 监听窗口变化,重绘echarts
const resizeObserver = new ResizeObserver(() => {
setTimeout(() => {
that.drawEcharts();
}, 300)
});
resizeObserver.observe(viewElem);
},
methods: {
drawEcharts() {
var that = this;
var chartDom = that.$refs.centerMap;
var myChart = echarts.init(chartDom);
myChart.clear()
myChart.resize()
var nameMap = '地图数据';
var geoCoordMap = {};
var mapData = [];
// 图标数据
echarts.registerMap(nameMap, this.data);
var mapFeatures = echarts.getMap(nameMap).geoJson.features;
myChart.hideLoading();
var mapName = ''
var serverdata = [{ // 地图块的相关信息
type: 'map',
name: '准入审核',
map: nameMap,
// zoom: 1.2,
aspectScale: 0.85,
z: 10,
layoutCenter: ["50%", "50%"],
layoutSize: '200%',
itemStyle: {
normal: {
borderColor: '#93b3ea',
borderWidth: 1,
areaColor: '#2f73d9'
},
emphasis: {
areaColor: '#416ef8',
borderWidth: 0,
label: {
show: true,
color: '#fff'
},
}
},
select: {
label: {
show: true,
color: '#fff',
normal: {
show: true,
textStyle: {
fontSize: 14,
fontWeight: 400,
color: '#fff'
}
},
emphasis: {
textStyle: {
fontSize: 14,
fontWeight: 400,
color: '#fff'
}
}
},
itemStyle: {
areaColor: '#416ef8',
borderWidth: 0,
}
},
label: {
show: false,
normal: {
show: false,
textStyle: {
fontSize: 14,
fontWeight: 400,
color: '#fff'
}
},
emphasis: {
show: false,
textStyle: {
fontSize: 14,
fontWeight: 400,
color: '#fff'
}
}
},
data: mapData
}]
mapFeatures.forEach(function (v, index) {
// 地区名称
mapData.push({
name: v.properties.name,
value: 10 * index
});
geoCoordMap[v.properties.name] = v.properties.center;
mapName = mapName + (mapName ? ',' : '') + v.properties.name
});
that.iconData.forEach((type, index) => {
var datamap = {
type: 'scatter',
tooltip: {
show: true,
formatter: function (params) {
return params.data.name;
}
},
name: type.name,
coordinateSystem: 'geo',
symbol: 'image://' + icon1,
symbolSize: [26, 26],
symbolOffset: [-0, -0],
hoverAnimation: true,
z: 101,
data: [type]
}
serverdata.push(datamap)
});
var optionMap = {
visualMap: [{
min: 0,
max: 100,
show: false,
right: 20,
bottom: 0,
realtime: true,
calculable: true,
seriesIndex: [0],
inRange: {
color: ['#e6edff', '#a8c3ff', '#12389b', '#2f73d9']
}
}],
geo: {
map: nameMap,
show: false,
aspectScale: 0.85,
layoutCenter: ["50%", "50%"],
layoutSize: '134%',
roam: false,
itemStyle: {
normal: {
areaColor: '#3391f8',
shadowColor: '#3391f8',
shadowBlur: 1,
shadowOffsetX: 0,
shadowOffsetY: 8,
}
},
z: 0,
label: {
normal: {
show: false
},
emphasis: {
show: false
}
}
},
series: serverdata
};
myChart.clear()
myChart.resize()
myChart.setOption(optionMap);
myChart.off('click')
myChart.on('click', function (params) {
let data = myChart.convertFromPixel('geo', [params.event.event.offsetX, params.event.event.offsetY])
// 判断是否超出x轴边界
if (params.event.event.offsetX > (that.$refs.echartsBody.offsetWidth - 408)) {
that.left = that.$refs.echartsBody.offsetWidth - 408
} else {
that.left = params.event.event.offsetX
}
// 判断是否超出y轴边界
if (params.event.event.offsetY > (that.$refs.echartsBody.offsetHeight - 222)) {
that.top = that.$refs.echartsBody.offsetHeight - 222
} else {
that.top = params.event.event.offsetY
}
that.name = params.data.name
that.show = true
})
}
},
}
</script>
<style lang="scss" scoped>
.item1 {
position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: nowrap;
flex-direction: row;
align-content: flex-start;
}
.map {
//background: url("../../../../../assets/centerMap.png") center center no-repeat;
//background-size: 1024px 783px;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: nowrap;
flex-direction: row;
align-content: flex-start;
margin: 0 auto;
position: absolute;
z-index: 0;
img {
height: 100%;
max-width: 100%;
max-height: 100%;
}
}
.centerMap {
width: 100%;
height: 100%;
position: relative;
z-index: 1;
top: 0;
}
.centerMap2 {
width: 100%;
height: 100%;
position: absolute;
z-index: 13;
top: 0;
pointer-events: none;
}
.popWin {
position: absolute;
left: 0;
top: 0;
background: url("../assets/popBg.png") no-repeat;
background-size: 100% 100%;
width: 408px;
height: 222px;
z-index: 100;
.popLine {
width: 340px;
height: 1px;
background: linear-gradient(90deg, #FFFFFF 0%, rgba(255, 255, 255, 0) 100%);
opacity: 0.3;
margin-left: 30px;
}
.titleInfos {
margin-left: 30px;
font-size: 22px;
font-family: YouSheBiaoTiHei;
font-weight: 400;
color: #00FDFE;
height: 50px;
display: flex;
justify-content: flex-start;
align-items: center;
flex-wrap: nowrap;
flex-direction: row;
align-content: flex-start;
}
}
.infoBody {
display: flex;
justify-content: flex-start;
align-items: flex-start;
flex-wrap: wrap;
flex-direction: row;
align-content: flex-start;
width: 100%;
.infoItem {
display: flex;
justify-content: flex-start;
align-items: flex-start;
flex-wrap: nowrap;
flex-direction: column;
align-content: flex-start;
margin-left: 30px;
width: 40%;
height: 80px;
.infoItemTitle {
display: flex;
justify-content: flex-start;
align-items: center;
flex-wrap: nowrap;
flex-direction: row;
margin-top: 20px;
align-content: flex-start;
font-size: 16px;
font-family: MicrosoftYaHei;
font-weight: bold;
color: #FFFFFF;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
img {
margin-right: 5px;
}
}
.infoItemDesc {
font-size: 14px;
font-family: MicrosoftYaHei;
font-weight: 400;
color: #FFFFFF;
opacity: 0.6;
}
}
}
</style>