1、实现效果
第一次进入该页面,默认一个小弹窗展示全省的数据,中间地图展示广东省全省各地市的数据,右下角展示广东省板块表示省公司,同时左上角还提供筛选按钮,实现对各地市和省公司的数据进行筛选,筛选后对应地市会被点亮,同时展示小弹窗数据。
2、实现步骤
以广东省全地市来讲述一下代码的主要实现步骤
(1)下载+引入:
echarts使用和其他开源插件一样,先下载,然后再项目中引入就可以使用了,具体实现可以参考官方文档。
echarts官方文档地址:快速上手 - 使用手册 - Apache ECharts
查看官方文档实例,找到符合自己需求的实例,然后就可以引入对应的组件进行改造使用。我本次使用地图坐标组件的 香港人口密度组件
(2)数据准备:
查看文档,在使用该地图组件前首先需要获取 地图JSON数据,在网上找了很多资料,找到一个可用的网页能够按需导出需要的地图JSON数据。导出地图JSON数据网址:简数科技
打开网址后根据需要筛选省份,选择GeoJSON格式数据(echarts-map组件需要使用该格式数据,另一种数据不生效),下面有对应链接,打开该链接然后右键将JSON文件保存下来就可以引入到代码里。
(3)代码实现:
HTML部分:
实现里面包含两部分,一部分是广东省所有地市数据的地图,另一部分是广东省地图。这块其实是引用了两个地图组件,然后通过样式调整,将省公司地图组件缩小放到右下角。
<!-- 地图数据 -->
<div class="chartBox">
<van-empty v-if="cityData.length === 0" :image="require('@/assets/images/projectManage/empty.png')" description="暂无数据"/>
<div id="mapChart" :style="{ width: '100%', height: '100%' }" class="city-map"></div>
<div id="proMapChart" :style="{ width: '30%', height: '30%' }" class="pro-map"></div>
</div>
JS部分(查询出数据后进行地图组件渲染):
渲染地图组件代码中包含地图组件自带的工具箱、弹出层、数据定义等配置项(官方文档还有很多配置项没用上,具体可参考官方文档配置项:Examples - Apache ECharts)。
import JSON from "./map.json";
import proJSON from "./china.json";
// 地市地图组件初始化
initECharts() {
this.$echarts.registerMap("广东", JSON);
let myChart = this.$echarts.init(document.getElementById("mapChart"));
let option = {
tooltip: {
trigger: "item", //提示框的触发方式
enterable: true, //允许鼠标进入提示悬浮层中
confine:true, // 弹窗只允许出现在地图范围内
backgroundColor: 'rgb(255 255 255 / 89%)', // 设置背景颜色
formatter: (data)=>{ // 提示框的格式化函数,用于自定义提示框的内容
this.closeProToolTip(); // 关闭省公司弹窗取消高亮展示
this.closeCityToolTip(); // 关闭其他地市高亮选择
// 设置选中的高亮(如果取消过一次高亮后需要重新设置高亮,否则不显示)
myChart.dispatchAction({
type: "highlight",
name: data.data.name,
});
let dataItem = this.cityData.filter(item =>item.REGION_CODE === data.data.value);
this.mapClick = true;
this.mapRegionCode = data.data.value;
this.$emit('getMapRegion',data.data.value); // 将点击地图获取的地市编码传出去
this.screenForm = {
name: data.data.name,
PCNT: dataItem.length >0 ? dataItem[0].PCNT : 0,
SHOULD_DELIVERY_CNT: dataItem.length >0 ? dataItem[0].SHOULD_DELIVERY_CNT : 0,
UNDELAY_CNT: dataItem.length >0 ? dataItem[0].UNDELAY_CNT : 0,
DELAY_CNT: dataItem.length >0 ? dataItem[0].DELAY_CNT : 0,
STOP_CNT: dataItem.length >0 ? dataItem[0].STOP_CNT : 0,
TER_CNT: dataItem.length >0 ? dataItem[0].TER_CNT : 0,
ON_MAINTENANCE_CNT: dataItem.length >0 ? dataItem[0].ON_MAINTENANCE_CNT : 0,
TERMINATION_CNT: dataItem.length >0 ? dataItem[0].TERMINATION_CNT : 0,
};
return (
this.projectStage === '1002' ?
`<div id="toolTipChild" style="display:flex;justify-content:space-between;"><h4 style="color:#409EFF">${data.data.name}</h4><button style="background:#409eff" onclick="openBox(this,'button')">展开</button></div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">项目数量:${dataItem.length >0 ? dataItem[0].PCNT : 0} 个</div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">应交付项目:${dataItem.length >0 ? dataItem[0].SHOULD_DELIVERY_CNT : 0} 个</div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">进度正常项目数:${dataItem.length >0 ? dataItem[0].UNDELAY_CNT : 0} 个</div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">进度异常项目数:${dataItem.length >0 ? dataItem[0].DELAY_CNT : 0} 个</div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">停工项目数:${dataItem.length >0 ? dataItem[0].STOP_CNT : 0} 个</div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">非正常结项数:${dataItem.length >0 ? dataItem[0].TER_CNT : 0} 个</div>`
:
`<div id="toolTipChild" style="display:flex;justify-content:space-between;"><h4 style="color:#409EFF">${data.data.name}</h4><button style="background:#409eff" onclick="openBox(this,'button')">展开</button></div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">项目数量:${dataItem.length >0 ? dataItem[0].PCNT : 0} 个</div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">在维项目数:${dataItem.length >0 ? dataItem[0].ON_MAINTENANCE_CNT : 0} 个</div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">结项项目数:${dataItem.length >0 ? dataItem[0].TERMINATION_CNT : 0} 个</div>`
)
},
},
visualMap: {
show: false,
inRange: {
color: ['#cee6ff']
}
},
//工具箱
toolbox: {
show: true, //是否显示工具箱
orient: "vertical", //工具箱的布局方向,可以设置为"horizontal"表示水平布局,或"vertical"表示垂直布局
left: "right", //工具箱的水平位置,可以设置为具体的像素值或百分比,或使用预定义的值如"left"、"center"、"right"等
top: "top", //工具箱的垂直位置,可以设置为具体的像素值或百分比,或使用预定义的值如"top"、"middle"、"bottom"等
feature: { //工具箱中的功能按钮,可以通过设置不同的属性来定义不同的功能按钮
restore: {}, //重置按钮
},
},
series: [
{
map: "广东", //地图的名称,可以是预定义的地图名称,也可以是自定义的地图名称
zoom: 1, //当前视角的缩放比例
roam: true, //是否开启平游或缩放
scaleLimit: { //滚轮缩放的极限控制
min: 0.5,
max: 2,
},
name: "广东省市图", //系列名称
type: "map", //系列类型,用于指定图表的类型
mapType: "广东", // 自定义扩展图表类型
label: {
show: true, // 地图文字标签设置
},
layoutCenter: ["50%", "50%"], //图表布局的中心位置
layoutSize: "100%", //图表布局的大小
itemStyle: {
normal: {
borderWidth: '1px', // 边框宽度
shadowColor: '#409EFF',
shadowBlur: 1,
shadowOffsetY: 4,
},
emphasis: {//鼠标移入高亮显颜色
areaColor: '#409EFF'
},
},
data: this.CITY_CODE_LIST,
},
],
};
myChart.setOption(option);
// 下拉框选择的实现地图高亮展示(同时关闭省公司高亮)
if(!this.mapClick){
this.closeProToolTip();
if(this.regionCode && this.regionCode !== '999'){
myChart.dispatchAction({
type: "highlight",
name: this.CITY_CODE_LIST.find(item =>item.value === this.regionCode).name,
});
myChart.dispatchAction({
type: 'showTip', //显示提示框
seriesIndex: 0,
name: this.CITY_CODE_LIST.find(item =>item.value === this.regionCode).name,
})
}
}
window.addEventListener("resize", function () {
myChart.resize();
});
window.openBox = (e,flag)=>{
this.screen = true;
if(flag === 'button'){
e.parentNode.parentNode.style.display = 'none'; // 找到按钮元素父元素的父元素,设置display为none即可实现手动关闭(为了tooltip展开后关闭tooltip)
}else{
e.parentNode.style.display = 'none'; // 找到按钮元素父元素的父元素,设置display为none即可实现手动关闭(为了tooltip展开后关闭tooltip)
}
}
},
// 查询省、市地图数据信息
queryProjectCount(){
const params = {
QRY_TYPE: '1',
REGION_CODE: '',
PROJECT_STAGE: '1002',
...this.queryInfo,
};
// 接口请求
this.$post(this.api.sale.project.queryProjectCount, {
...params
}).then((r) => {
const data = r.data.ROOT.BODY || {};
if (data.RETURN_CODE !== '0') {
this.$toast.fail('查询失败!' + r.data.ROOT.BODY.RETURN_MSG);
return;
}
this.cityData = data.OUT_DATA;
this.initECharts();
this.initProECharts();
});
},
3、TipOne
(1)实现效果:弹窗层里面点击展开或者某一行数据,tooltip消失,底部弹出弹出层展示数据。
(2)主要实现代码(JS渲染地图组件方法里):
tooltip: {
trigger: "item", //提示框的触发方式
enterable: true, //允许鼠标进入提示悬浮层中
confine:true, // 弹窗只允许出现在地图范围内
backgroundColor: 'rgb(255 255 255 / 89%)', // 设置背景颜色
formatter: (data)=>{ // 提示框的格式化函数,用于自定义提示框的内容
this.closeProToolTip(); // 关闭省公司弹窗取消高亮展示
this.closeCityToolTip(); // 关闭其他地市高亮选择
// 设置选中的高亮(如果取消过一次高亮后需要重新设置高亮,否则不显示)
myChart.dispatchAction({
type: "highlight",
name: data.data.name,
});
let dataItem = this.cityData.filter(item =>item.REGION_CODE === data.data.value);
this.mapClick = true;
this.mapRegionCode = data.data.value;
this.$emit('getMapRegion',data.data.value); // 将点击地图获取的地市编码传出去
this.screenForm = {
name: data.data.name,
PCNT: dataItem.length >0 ? dataItem[0].PCNT : 0,
SHOULD_DELIVERY_CNT: dataItem.length >0 ? dataItem[0].SHOULD_DELIVERY_CNT : 0,
UNDELAY_CNT: dataItem.length >0 ? dataItem[0].UNDELAY_CNT : 0,
DELAY_CNT: dataItem.length >0 ? dataItem[0].DELAY_CNT : 0,
STOP_CNT: dataItem.length >0 ? dataItem[0].STOP_CNT : 0,
TER_CNT: dataItem.length >0 ? dataItem[0].TER_CNT : 0,
ON_MAINTENANCE_CNT: dataItem.length >0 ? dataItem[0].ON_MAINTENANCE_CNT : 0,
TERMINATION_CNT: dataItem.length >0 ? dataItem[0].TERMINATION_CNT : 0,
};
return (
this.projectStage === '1002' ?
`<div id="toolTipChild" style="display:flex;justify-content:space-between;"><h4 style="color:#409EFF">${data.data.name}</h4><button style="background:#409eff" onclick="openBox(this,'button')">展开</button></div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">项目数量:${dataItem.length >0 ? dataItem[0].PCNT : 0} 个</div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">应交付项目:${dataItem.length >0 ? dataItem[0].SHOULD_DELIVERY_CNT : 0} 个</div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">进度正常项目数:${dataItem.length >0 ? dataItem[0].UNDELAY_CNT : 0} 个</div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">进度异常项目数:${dataItem.length >0 ? dataItem[0].DELAY_CNT : 0} 个</div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">停工项目数:${dataItem.length >0 ? dataItem[0].STOP_CNT : 0} 个</div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">非正常结项数:${dataItem.length >0 ? dataItem[0].TER_CNT : 0} 个</div>`
:
`<div id="toolTipChild" style="display:flex;justify-content:space-between;"><h4 style="color:#409EFF">${data.data.name}</h4><button style="background:#409eff" onclick="openBox(this,'button')">展开</button></div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">项目数量:${dataItem.length >0 ? dataItem[0].PCNT : 0} 个</div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">在维项目数:${dataItem.length >0 ? dataItem[0].ON_MAINTENANCE_CNT : 0} 个</div>`
+ `<div style="color:#409EFF" onclick="openBox(this)">结项项目数:${dataItem.length >0 ? dataItem[0].TERMINATION_CNT : 0} 个</div>`
)
},
},
window.openBox = (e,flag)=>{
this.screen = true;
if(flag === 'button'){
e.parentNode.parentNode.style.display = 'none'; // 找到按钮元素父元素的父元素,设置display为none即可实现手动关闭(为了tooltip展开后关闭tooltip)
}else{
e.parentNode.style.display = 'none'; // 找到按钮元素父元素的父元素,设置display为none即可实现手动关闭(为了tooltip展开后关闭tooltip)
}
}
4、TipTwo
(1)实现效果:点击左上角下拉框,选择某个地市数据后地图上该地市板块被点亮并且弹出tooltip展示数据。
- 主要实现代码:
定义一个字段,用于判断是否点击地图组件,默认为false,当点击地图组件会触发tooltip中formatter方法,此时设置mapClick为true。如果是通过下拉框选的话,重新渲染地图组件,此时mapClick为false就会进入到高亮地图和弹出tooltip弹出层的方法中。
注意:dispatchAction中name对应地图上的名称,highlight标识高亮,showTip标识展示弹出层。
mapClick:false,
// 下拉框选择的实现地图高亮展示(同时关闭省公司高亮)
if(!this.mapClick){
this.closeProToolTip();
if(this.regionCode && this.regionCode !== '999'){
myChart.dispatchAction({
type: "highlight",
name: this.CITY_CODE_LIST.find(item =>item.value === this.regionCode).name,
});
myChart.dispatchAction({
type: 'showTip', //显示提示框
seriesIndex: 0,
name: this.CITY_CODE_LIST.find(item =>item.value === this.regionCode).name,
})
}
}
5、TipThree
(1)问题展示:由于全广东省地市地图和省公司地图是两个地图,因此会出现点击省公司模块后再点击地市出现两个高亮展示。
(2)实现效果:点击省公司关闭其他地市高亮和弹窗;点击其他地市取消省公司高亮和弹窗。
(3)主要实现代码:
dispatchAction设置type为downplay取消高亮展示。
当点击地图组件的时候,在tooltip的formatter方法中调用对应取消高亮的方法(点击地市调用取消省公司高亮方法,点击省公司调用取消地市高亮方法)
// 项目管理视图点击筛选关闭toolTip
closeTooltip(){
if(document.getElementById("toolTipChild")){
document.getElementById("toolTipChild").parentNode.style.display = 'none';
}
if(document.getElementById("toolTipChildPro")){
document.getElementById("toolTipChildPro").parentNode.style.display = 'none';
}
},
// 关闭所选市弹窗并取消高亮展示
closeCityToolTip(){
let myChart = this.$echarts.init(document.getElementById("mapChart"));
if(document.getElementById("toolTipChild")){
document.getElementById("toolTipChild").parentNode.style.display = 'none';
myChart.dispatchAction({
type: "downplay",
});
}
},
// 关闭所选省弹窗并取消高亮展示
closeProToolTip(){
let myProChart = this.$echarts.init(document.getElementById('proMapChart'));
if(document.getElementById("toolTipChildPro")){
document.getElementById("toolTipChildPro").parentNode.style.display = 'none';
myProChart.dispatchAction({
type: "downplay",
name: '省公司',
});
}
},
6、TipFour
(1)问题展示:JSON文件展示的地图数据中汕尾会出现字体偏移。
(2)实现效果:将汕尾市字体移到汕尾板块地图中心位置。
(3)主要实现代码:
修改对应地市中引入的地图JSON数据即可
7、TipFive
(1)实现效果:首次进入页面默认展示全省数据弹窗。
(2)主要实现代码:
HTML部分:
单独一个弹窗用于展示全省数据,在下拉框选择全省数据是,展示该弹窗并取消其他地市和省公司的高亮和弹出层。
<!-- 全省项目概况 -->
<div class="allStyle" v-if="allInfoShow">
<div id="toolTipChildPro" style="display:flex;justify-content:space-between;">
<h4 style="color:#409EFF">全省</h4>
<button style="background:#409eff" onclick="openBox(this,'button')">展开</button>
</div>
<div v-if="this.projectStage === '1002'" style="color:#409EFF" onclick="openBox(this)">项目数量:{{ screenForm.PCNT }}个</div>
<div v-if="this.projectStage === '1002'" style="color:#409EFF" onclick="openBox(this)">应交付项目:{{ screenForm.SHOULD_DELIVERY_CNT }} 个</div>
<div v-if="this.projectStage === '1002'" style="color:#409EFF" onclick="openBox(this)">进度正常项目数:{{ screenForm.UNDELAY_CNT }} 个</div>
<div v-if="this.projectStage === '1002'" style="color:#409EFF" onclick="openBox(this)">进度异常项目数:{{ screenForm.DELAY_CNT }} 个</div>
<div v-if="this.projectStage === '1002'" style="color:#409EFF" onclick="openBox(this)">停工项目数:{{ screenForm.STOP_CNT }} 个</div>
<div v-if="this.projectStage === '1002'" style="color:#409EFF" onclick="openBox(this)">非正常结项数:{{ screenForm.TER_CNT }} 个</div>
<div v-if="this.projectStage === '1003'" style="color:#409EFF" onclick="openBox(this)">项目数量:{{ screenForm.PCNT }} 个</div>
<div v-if="this.projectStage === '1003'" style="color:#409EFF" onclick="openBox(this)">在维项目数:{{ screenForm.ON_MAINTENANCE_CNT }} 个</div>
<div v-if="this.projectStage === '1003'" style="color:#409EFF" onclick="openBox(this)">结项项目数:{{ screenForm.TERMINATION_CNT }} 个</div>
</div>
JS部分
// 下拉框选择的实现地图高亮展示
if(!this.mapClick){
this.closeCityToolTip();
if(this.regionCode === '999'){
myChart.dispatchAction({
type: "highlight",
name: '省公司',
});
myChart.dispatchAction({
type: 'showTip', //显示提示框
seriesIndex: 0,
name: "省公司",
})
}else if(!this.regionCode){ // 弹出全省项目概况
this.allInfoShow = true;
let PCNT = 0;
let SHOULD_DELIVERY_CNT = 0;
let UNDELAY_CNT = 0;
let DELAY_CNT = 0;
let STOP_CNT = 0;
let TER_CNT = 0;
let ON_MAINTENANCE_CNT = 0;
let TERMINATION_CNT = 0;
if(this.cityData.length > 0){
this.cityData.forEach(item =>{
PCNT = PCNT + (item.PCNT || 0);
SHOULD_DELIVERY_CNT = SHOULD_DELIVERY_CNT + (item.SHOULD_DELIVERY_CNT || 0);
UNDELAY_CNT = UNDELAY_CNT + (item.UNDELAY_CNT || 0);
DELAY_CNT = DELAY_CNT + (item.DELAY_CNT || 0);
STOP_CNT = STOP_CNT + (item.STOP_CNT || 0);
TER_CNT = TER_CNT + (item.TER_CNT || 0);
ON_MAINTENANCE_CNT = ON_MAINTENANCE_CNT + (item.ON_MAINTENANCE_CNT || 0);
TERMINATION_CNT = TERMINATION_CNT + (item.TERMINATION_CNT || 0);
})
}
this.screenForm = {
name: '全省',
PCNT: PCNT,
SHOULD_DELIVERY_CNT: SHOULD_DELIVERY_CNT,
UNDELAY_CNT: UNDELAY_CNT,
DELAY_CNT: DELAY_CNT,
STOP_CNT: STOP_CNT,
TER_CNT: TER_CNT,
ON_MAINTENANCE_CNT: ON_MAINTENANCE_CNT,
TERMINATION_CNT: TERMINATION_CNT,
};
}
}
style部分
.allStyle {
position: absolute;
display: block;
border-style: solid;
white-space: nowrap;
z-index: 9999999;
transition: left 0.4s cubic-bezier(0.23, 1, 0.32, 1) 0s, top 0.4s cubic-bezier(0.23, 1, 0.32, 1) 0s;
background-color: rgba(255, 255, 255, 0.89);
border-width: 0px;
border-color: rgb(51, 51, 51);
border-radius: 4px;
color: rgb(255, 255, 255);
font: 14px / 21px;
padding: 5px;
left: 30%;
top: 20%;
pointer-events: auto;
}