vue 里怎么使用 echarts 实现地图自动轮播功能、自定义 tooltip 悬浮位置提示、自定义 label 标签位置样式?
要实现的功能代码实现1、安装依赖npm i echarts -s
要实现的功能
比如:我们要实现白云地图24镇街的常住人口统计展示,然后需要我们实现 1s 自动轮播一次地区,自定义标签样式,自定义悬浮样式。
准备工作
1、安装依赖
npm i echarts -s
2、准备 24 镇街的 geoJson 数据
关于怎么获取 24 镇街的 geoJson 数据,请参考我之前的一篇博客:怎么获取echarts需要的geoJson数据去渲染地图:以广州市白云区24镇街为例
3、准备一份配置 24 镇街的文件
我们新建文件 440111.config.js
,在里面添加一些配置参数用于数据展示的方便,比如我配置了几个:
/**
* 1)4个镇:江高镇、人和镇、太和镇、钟落潭镇;
* 2)20个街:龙归街、大源街、三元里街、松洲街、景泰街、同德街、黄石街、棠景街、新市街、同和街、京溪街、永平街、嘉禾街、均禾街、石井街、金沙街、云城街、鹤龙街、白云湖街、石门街;
* */
export const BAIYUN_CONFIG = [
'江高镇',
'人和镇',
'太和镇',
'钟落潭镇',
'龙归街',
'大源街',
'三元里街',
'松洲街',
'景泰街',
'同德街',
'黄石街',
'棠景街',
'新市街',
'同和街',
'京溪街',
'永平街',
'嘉禾街',
'均禾街',
'石井街',
'金沙街',
'云城街',
'鹤龙街',
'白云湖街',
'石门街'
];
/**
* SUCCESS_STYLE:绿色样式:'江高镇','太和镇','景泰街','黄石街','棠景街','京溪街','永平街','均禾街','石井街','金沙街';
* WARNING_STYLE:橙色样式:'人和镇','嘉禾街','三元里街','石门街','新市街','大源街','松洲街';
* ERROR_STYLE:红色样式:'钟落潭镇','同德街','云城街','鹤龙街','白云湖街','龙归街','同和街';
* */
export const SUCCESS_STYLE = ['江高镇','太和镇','景泰街','黄石街','棠景街','京溪街','永平街','均禾街','石井街','金沙街'];
export const WARNING_STYLE = ['人和镇','嘉禾街','三元里街','石门街','新市街','大源街','松洲街'];
export const ERROR_STYLE = ['钟落潭镇','同德街','云城街','鹤龙街','白云湖街','龙归街','同和街'];
// 测试数据
export const MapData = [
{
id: "jianggao",
name: "江高镇",
value: 883945
},{
id: "renhe",
name: "人和镇",
value: 4567992
},{
id: "taihe",
name: "太和镇",
value: 4567323
},{
id: "zhongluotan",
name: "钟落潭镇",
value: 497863
},{
id: "longgui",
name: "龙归街",
value: 3486257
},{
id: "dayuan",
name: "大源街",
value: 897435
},{
id: "sanyuanli",
name: "三元里街",
value: 46809544
},{
id: "songzhou",
name: "松洲街",
value: 123403
},{
id: "jingtai",
name: "景泰街",
value: 342256677
},{
id: "tongde",
name: "同德街",
value: 234677
},{
id: "huangshi",
name: "黄石街",
value: 976542
},{
id: "tangjing",
name: "棠景街",
value: 33456
},{
id: "xinshi",
name: "新市街",
value: 3455602
},{
id: "tonghe",
name: "同和街",
value: 487654
},{
id: "jingxi",
name: "京溪街",
value: 3876735
},{
id: "yongping",
name: "永平街",
value: 6677544
},{
id: "jiahe",
name: "嘉禾街",
value: 34526784
},{
id: "junhe",
name: "均禾街",
value: 8756534
},{
id: "shijing",
name: "石井街",
value: 220232
},{
id: "jinsha",
name: "金沙街",
value: 3352256
},{
id: "yuncheng",
name: "云城街",
value: 335677
},{
id: "helong",
name: "鹤龙街",
value: 334225
},{
id: "baiyunhu",
name: "白云湖街",
value: 34556
},{
id: "shimen",
name: "石门街",
value: 1354667
}
];
4、准备工具方法添加千分位
新建文件 utils.js
,添加千分位函数:
// 数字加千位分隔符
export function numToThsSprtr (num) {
let res = num.toString().replace(/\d+/, function (n) { // 先提取整数部分
return n.replace(/(\d)(?=(\d{3})+$)/g, function ($1) {
return $1 + ',';
});
})
return res;
}
代码实现
1、自定义标签
我们配置标签的相应样式,我们利用 formatter,以及 rich 去处理,具体可以参考:https://echarts.apache.org/zh/option.html#series-map.label.formatter,backgroundColor 可以使用背景图片。
label: {
show: true,
color: "#fff",
textAlign: "center",
// {a}:系列名。{b}:数据名。{c}:数据值。
formatter: (params) => {
let richName = "";
if (SUCCESS_STYLE.includes(params.name)) {
richName = "success";
} else if (WARNING_STYLE.includes(params.name)) {
richName = "warning";
} else if (ERROR_STYLE.includes(params.name)) {
richName = "error";
}
return `{${richName}|${params.name}}`;
},
rich: {
success: {
fontSize: "0.0729rem",
padding: [4, 7],
borderWidth: 2, // 图形描边的宽度。
borderColor: "#fff", // 边框颜色
backgroundColor: 'green', // 背景色
},
warning: {
fontSize: "0.0729rem",
padding: [4, 7],
borderWidth: 2, // 图形描边的宽度。
borderColor: "#fff", // 边框颜色
backgroundColor: 'orange', // 背景色
},
error: {
fontSize: "0.0729rem",
padding: [4, 7],
borderWidth: 2, // 图形描边的宽度。
borderColor: "#fff", // 边框颜色
backgroundColor: 'red', // 背景色
},
},
},
怎么处理标签名重叠问题?
如果大家出现下面这种标签名重叠的问题,那应该怎么去处理?
这里我们可以参考 github 上面 echarts 的问题 4379 进行相应的处理:中国地图,省份名称重叠 #4379
问题的描述:
两种方式处理重叠
第一种:在 geoJson 数据中添加 cp 属性数据。
"properties": {
"name": "白云湖街",
"cp": [113.23196411132812, 23.24386977767157]
}
第二种:echarts.getMap(‘china’) 后修改已经加载的地图的数据。
var chinaMapInfoObj = document.getElementById(‘mianid‘’);
var chinaMap = echarts.init(chinaMapInfoObj);
var chinaEchartsObj = echarts.getMap('china');
var geoJSONChina = chinaEchartsObj.geoJson;
var allDefProvince = geoJSONChina.features;
for(var i=0,len=allDefProvince.length; i<len; i++){
var sglProvinceProperties = allDefProvince[i].properties;
var sglProvinceName = sglProvinceProperties.name;
switch(sglProvinceName){
case '新疆':
sglProvinceProperties.cp[0]=87.617733;
sglProvinceProperties.cp[1]=41.792818;
break;
case '青海'://def:101.778916,36.623178
sglProvinceProperties.cp[0]=97.617733;
sglProvinceProperties.cp[1]=36.623178;
break;
case '江苏'://def:118.767413,32.041544
sglProvinceProperties.cp[0]=119.767413;
sglProvinceProperties.cp[1]=33.041544;
break;
}
}
option.echarts.registerMap('china', geoJSONChina, {});
怎么确定中心点的坐标
可以去查看这个我写的这一篇博客里的确定边界汇聚点
部分,里面有介绍怎么处理。怎么获取 echarts 需要的 geoJson 数据去渲染地图:以广州市白云区24镇街为例
大致就是把矩形左上方的点放到新的位置中心,就可以得到大概的坐标。
得到坐标之后,可能有点不太精确,可以自己合适的调整数据,达到自己想要的位置就行。
比如:现在 松洲街
被 同德街
,挡住了,需要把它进行移动,
这里我们采用第一种方式,修改 geojson 数据,我们给松洲街添加 cp 坐标数据,我们发现就不会被遮住了,其他也是同样的原理
"properties": {
"name": "松洲街",
"cp": [113.21036999511719, 23.15851026498019]
}
2、自定义悬浮提示
这里我们主要需要处理的就是 position 跟样式 formatter。这里的位置需要计算一下 (point:鼠标位置) 跟(contentSize:dom 的尺寸),找到合适的显示位置。具体的可以参考:
tooltip: {
show: true,
trigger: "item",
// point:鼠标位置 contentSize:dom 的尺寸
position: (point, params, dom, rect, size) => {
return [point[0] - 20, point[1] - size.contentSize[1] - 15];
},
extraCssText: "box-shadow: none", // 额外样式
formatter: (param) => {
let data = `
<div class="map-tooltips">
<div class="name">${param.name}常住人口</div>
<div class="value">
<span class="num">${numToThsSprtr(param.value || 0)}</span>
<span class="unit">人</span>
</div>
</div>
`;
return data;
},
},
3、自动轮播功能
我们可以通过 dispatchAction 实现轮播高亮提示效果。这里需要注意的就是轮播到最后一个时的状态处理。这里就不具体展开逻辑,看完整代码就行,有注释。
具体的配置参考:https://echarts.apache.org/zh/api.html#action
高亮指定的数据图形。
// 如果要高亮系列:
dispatchAction({
type: 'highlight',
// 用 index 或 id 或 name 来指定系列。
// 可以使用数组指定多个系列。
seriesIndex?: number | number[],
seriesId?: string | string[],
seriesName?: string | string[],
// 数据项的 index,如果不指定也可以通过 name 属性根据名称指定数据项
dataIndex?: number | number[],
// 可选,数据项名称,在有 dataIndex 的时候忽略
name?: string | string[],
});
取消高亮指定的数据图形。
// 如果要取消高亮系列:
dispatchAction({
type: 'downplay',
// 用 index 或 id 或 name 来指定系列。
// 可以使用数组指定多个系列。
seriesIndex?: number | number[],
seriesId?: string | string[],
seriesName?: string | string[],
// 数据项的 index,如果不指定也可以通过 name 属性根据名称指定数据项
dataIndex?: number | number[],
// 可选,数据项名称,在有 dataIndex 的时候忽略
name?: string | string[],
})
指定系列中的数据图形,根据 tooltip 的配置项显示提示框。
dispatchAction({
type: 'showTip',
// 系列的 index,在 tooltip 的 trigger 为 axis 的时候可选。
seriesIndex?: number,
// 数据项的 index,如果不指定也可以通过 name 属性根据名称指定数据项
dataIndex?: number,
// 可选,数据项名称,在有 dataIndex 的时候忽略
name?: string,,
// 本次显示 tooltip 的位置。只在本次 action 中生效。
// 缺省则使用 option 中定义的 tooltip 位置。
position: number[] | string | Function,
})
隐藏提示框。
dispatchAction({
type: 'hideTip'
})
4、大屏自适应方案
这个可以参考我的另外一篇:使用 sass + rem + flexible.js 实现大屏自适应
完整代码
<template>
<div ref="geoTwoDimensionalMapChart" class="geo-two-dimensional-map-chart"></div>
</template>
<script>
import * as echarts from "echarts";
// 白云区 geojson 数据
import baiyunGeoJson from "@/assets/mapData/440111.json";
// 24 镇街数据
import {
BAIYUN_CONFIG,
SUCCESS_STYLE,
WARNING_STYLE,
ERROR_STYLE,
MapData
} from "@/assets/mapData/440111.config.js";
// 工具方法
import {
numToThsSprtr
} from "@/utils/utils.js";
export default {
name: "geoTwoDimensionalMapChart",
data() {
return {
myChart: null,
interval: 1000, // 时间间隔毫秒数
index: 0, // 播放所在下标
timer: null,
option: {
series: [{
type: "map",
map: "白云区",
data: [],
layoutCenter: ["50%", "50%"], // 属性定义地图中心在屏幕中的位置
layoutSize: "99%", // 定义地图的大小
label: {
show: true,
color: "#fff",
textAlign: "center",
// {a}:系列名。{b}:数据名。{c}:数据值。
formatter: (params) => {
let richName = "";
if (SUCCESS_STYLE.includes(params.name)) {
richName = "success";
} else if (WARNING_STYLE.includes(params.name)) {
richName = "warning";
} else if (ERROR_STYLE.includes(params.name)) {
richName = "error";
}
return `{${richName}|${params.name}}`;
},
rich: {
success: {
fontSize: "0.0729rem",
padding: [4, 7],
borderWidth: 2, // 图形描边的宽度。
borderColor: "#fff", // 边框颜色
backgroundColor: 'green', // 背景色
},
warning: {
fontSize: "0.0729rem",
padding: [4, 7],
borderWidth: 2, // 图形描边的宽度。
borderColor: "#fff", // 边框颜色
backgroundColor: 'orange', // 背景色
},
error: {
fontSize: "0.0729rem",
padding: [4, 7],
borderWidth: 2, // 图形描边的宽度。
borderColor: "#fff", // 边框颜色
backgroundColor: 'red', // 背景色
},
},
},
itemStyle: {
borderWidth: 2, // 图形描边的宽度。
borderColor: "#ddd", // 图形描边的颜色。
areaColor: '#ccc',
shadowColor: '#eee',
shadowBlur: 10,
shadowOffsetX: 0,
shadowOffsetY: 2
},
// 点击选择样式
select: {
label: {
color: "#fff",
},
itemStyle: {
borderWidth: 2, // 图形描边的宽度。
borderColor: "#ddd", // 图形描边的颜色。
areaColor: '#ccc',
}
},
emphasis: {
// 当鼠标放上
label: {
color: "#fff",
},
itemStyle: {
borderWidth: 2,
borderColor: "#000",
areaColor: 'blue',
},
},
}],
tooltip: {
show: true,
trigger: "item",
// point:鼠标位置 contentSize:dom 的尺寸
position: (point, params, dom, rect, size) => {
return [point[0] - 20, point[1] - size.contentSize[1] - 15];
},
extraCssText: "box-shadow: none", // 额外样式
formatter: (param) => {
let data = `
<div class="map-tooltips">
<div class="name">${param.name}常住人口</div>
<div class="value">
<span class="num">${numToThsSprtr(param.value || 0)}</span>
<span class="unit">人</span>
</div>
</div>
`;
return data;
},
},
},
};
},
mounted() {
// 初始化渲染
this.initRender();
// 设置轮播
this.setIntervalMyChart();
// resize 事件监听
window.addEventListener("resize", this.handleResize);
},
destroyed() {
clearInterval(this.timer);
window.removeEventListener("resize", this.handleResize);
},
methods: {
// 初始化渲染
initRender() {
// 注册地图名字和数据
echarts.registerMap("白云区", baiyunGeoJson);
let chartDom = this.$refs.geoTwoDimensionalMapChart;
this.myChart = echarts.init(chartDom);
this.option.series[0].data = MapData;
this.myChart.setOption(this.option);
// 激活高亮跟提示
console.log('initRender', this.index);
this.dispatchActionChart("highlight", this.index);
this.dispatchActionChart("showTip", this.index);
// 鼠标划入
this.mouseEvents();
},
// 鼠标划入
mouseEvents() {
this.myChart.on("mouseover", () => {
// 停止定时器,清除之前的高亮
clearInterval(this.timer);
this.dispatchActionChart("downplay", this.index);
});
// 鼠标划出重新定时器开始
this.myChart.on("mouseout", () => {
clearInterval(this.timer);
// 启动轮播
this.setIntervalMyChart();
});
},
// 设置轮播
setIntervalMyChart() {
const dataLength = BAIYUN_CONFIG.length;
// 每隔 interval 进行一次切换
this.timer = setInterval(() => {
// 清除高亮跟提示
this.dispatchActionChart("downplay", this.index);
this.dispatchActionChart("hideTip", this.index);
// 索引增加
this.index++;
// 激活高亮跟提示
this.dispatchActionChart("highlight", this.index);
this.dispatchActionChart("showTip", this.index);
if (this.index === dataLength - 1) {
// 需要对最后一个进行清除,对第一个进行激活
let tempTimer = setTimeout(() => {
this.dispatchActionChart("downplay", dataLength - 1);
this.dispatchActionChart("highlight", this.index);
clearTimeout(tempTimer);
}, this.interval);
this.index = -1;
}
}, this.interval);
},
/**
* @description 控制高亮跟提示
* @param {String} type (highlight:高亮(反:downplay);showTip:显示提示(反:hideTip))
* @param {Number} dataIndex 数据项的 index
* */
dispatchActionChart(type, dataIndex) {
this.myChart.dispatchAction({
type: type,
seriesIndex: 0,
dataIndex: dataIndex,
});
},
// resize 事件
handleResize() {
this.myChart.resize();
},
},
};
</script>
<style lang="scss" scoped>
@import "@/assets/scss/utils.scss";
.geo-two-dimensional-map-chart {
width: 100%;
height: p2r(730);
::v-deep .map-tooltips {
min-width: p2r(160);
position: relative;
text-align: center;
padding-top: p2r(10);
.name {
font-size: p2r(16);
font-weight: 400;
color: green;
line-height: p2r(22);
margin-bottom: p2r(8);
}
.value {
color: green;
.num {
font-size: p2r(26);
font-weight: bold;
line-height: p2r(26);
}
.unit {
font-size: p2r(14);
}
}
}
}
</style>
参考资料
更多推荐
所有评论(0)