<template>
<div id="chart" style="width: 100%; height: 100%"></div>
</template>
<script>
// "echarts": "^5.3.2",
import * as echarts from "echarts";
// node_modules/echart/js下拉出来
import "./china";
// vue-admin项目中抓取的
import resize from "@/utils/mixins/resize";
const _ = require("lodash");
export default {
name: "chinaEchart",
mixins: [resize],
props: {
data: {
type: Array,
default: () => [],
},
},
data() {
return {
chart: null,
dataList: [],
chinaJson: [], //引入的地图数据
};
},
watch: {
data(val) {
this.setOptions();
this.renderEachArea(val);
},
},
mounted() {
this.chinaJson = echarts.getMap("china")?.geoJSON?.features;
this.$nextTick(() => {
this.initChart();
this.renderEachArea(this.data);
// 窗口变化监听,不用防抖的话有问题
//需要销毁时候取消监听,window为全局数据
window.addEventListener("resize", this.debounce);
});
},
beforeDestroy() {
if (!this.chart) {
return;
}
this.chart.dispose();
this.chart = null;
// 销毁window['resize']。
window.removeEventListener("resize", this.debounce);
},
methods: {
// 必须封装函数
debounce: _.debounce(function () {
this.renderEachArea(this.data);
}, 300),
initChart() {
this.chart = echarts.init(this.$el);
this.setOptions(this.data);
},
setOptions() {
let option = {
geo: {
map: "china",
roam: false, //不开启缩放和平移
zoom: 1.23, //视角缩放比例
label: {
normal: {
show: false,
fontSize: "10",
color: "rgba(0,0,0,0.7)",
},
},
itemStyle: {
normal: {
borderColor: "rgba(0, 0, 0, .6)",
areaColor: "#fff", //地图块颜色
},
emphasis: {
areaColor: "#ff4536", //鼠标选择区域颜色
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowBlur: 20,
borderWidth: 0,
shadowColor: "rgba(0, 0, 0, 0.5)",
},
},
emphasis: {
// 不弄成放上去就变颜色的那种
disabled: true,
focus: "self",
},
// 在地图中对特定的区域配置样式。
},
// series: [
// {
// name: "信息量",
// type: "map",
// geoIndex: 0,
// data: this.dataList,
// },
// ],
};
this.chart.setOption(option);
this.chart.on("click", (param) => {
console.log(param);
});
// 监听地图的拖拽与移动
// 防抖!
this.chart.on(
"geoRoam",
_.debounce((param) => {
this.renderEachArea();
}),
300
);
},
renderEachArea(data = []) {
// 测试echartsInstance. convertToPixel方法
// https://echarts.apache.org/zh/api.html#echartsInstance.convertToPixel
// let a = this.chart.convertToPixel("geo", [128.3324, 89.5344]);
// console.log(a);
// 不是很严谨
// userCount,schoolCount
let arr = [];
let schoolArr = [];
data.forEach((item) => {
arr.push(item.userCount, item.schoolCount);
schoolArr.push(item.schoolCount);
});
// 获取所有数据最大值
let maxData = Math.max(...arr);
// 获取学院最大值
let maxSchoolData = Math.max(...schoolArr);
const areaOption = {
xAxis: [],
yAxis: [],
grid: [],
series: [],
legend: {
icon: "circle",
width: "80",
right: "0%",
bottom: "30%",
textStyle: {
color: "#727E8F",
},
data: [{ name: "院校数" }, { name: "用户数" }],
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
formatter: (params, ticket) => {
let str = "";
params.forEach((item, index) => {
if (index % 4 == 0) {
str += `${item.axisValueLabel}</br>`;
}
if (
item.seriesName != "占位数字" &&
item.seriesName != "学院最大值"
) {
str += `<div style="font-size: 14px;color: #727E8F;line-height: 26px;">${item.marker}${item.seriesName}:${item.value}</div>`;
}
});
return str;
},
},
color: ["#ff4565", "#56844f"],
};
data.forEach((item, idx) => {
let city = this.chinaJson.find((val) => val?.id == item.provinceId);
// console.log(city);
// 依据城市地图坐标(经纬度)获取在echart图上的偏移量(定位)
let EcPxy = null;
if (this.chart) {
EcPxy = this.chart.convertToPixel("geo", city?.properties?.cp || []);
}
// console.log(EcPxy);
//基础echart同时绘制多个数据配置
areaOption.xAxis.push({
id: idx, // 组件id,在配置中引用标识
gridIndex: idx, // x轴所在的grid的索引
type: "category", // 坐标轴类型
nameLocation: "middle",
data: [item.province],
nameGap: 3, // 坐标轴名称与轴线之间的距离
splitLine: {
// 坐标轴在 grid 区域中的分隔线
show: false,
},
axisTick: {
// 坐标轴刻度
show: false,
},
axisLabel: {
// 坐标轴刻度标签
show: false,
},
axisLine: {
// 坐标轴轴线
onZero: false,
lineStyle: {
color: "#666",
},
},
z: 100,
});
areaOption.yAxis.push({
id: idx, // 组件id,在配置中引用标识
gridIndex: idx, // x轴所在的grid的索引
splitLine: {
// 坐标轴在 grid 区域中的分隔线
show: false,
},
axisTick: {
// 坐标轴刻度
show: false,
},
axisLabel: {
// 坐标轴刻度标签
show: false,
},
axisLine: {
// 坐标轴轴线
show: false,
lineStyle: {
color: "#1C70B6",
},
},
z: 100,
});
areaOption.grid.push({
id: idx, // 组件id,在配置中引用标识
width: 30, // 组件的宽度
height: 40, // 组件的高度
left: EcPxy[0] - 15, // 离容器左侧的距离
top: EcPxy[1] - 40, // 离容器上侧的距离
z: 100,
});
areaOption.series.push(
{
name: "院校数",
type: "bar", // 柱状图
xAxisId: idx, // 使用的x轴的id
yAxisId: idx, // 使用的y轴的id
barGap: 0, // 柱间距离
barCategoryGap: 0, // 同一系列的柱间距离
data: [item.schoolCount], // 柱子数据
// 渐变色
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "#3B76E1" },
{ offset: 1, color: "#7BB6F3" },
]),
borderRadius: [20, 20, 0, 0],
},
z: 100,
},
{
name: "占位数字",
type: "bar", // 柱状图
xAxisId: idx, // 使用的x轴的id
yAxisId: idx, // 使用的y轴的id
barGap: "0", // 柱间距离
barCategoryGap: 0, // 同一系列的柱间距离
data: [maxData], // 柱子数据
barWidth: 1,
// // 渐变色
itemStyle: {
opacity: 0,
borderRadius: [20, 20, 0, 0],
},
z: 100,
},
{
name: "学院最大值",
type: "bar", // 柱状图
xAxisId: idx, // 使用的x轴的id
yAxisId: idx, // 使用的y轴的id
barGap: "0", // 柱间距离
barCategoryGap: 0, // 同一系列的柱间距离
data: [maxSchoolData], // 柱子数据
barWidth: 1,
// // 渐变色
itemStyle: {
opacity: 0,
borderRadius: [20, 20, 0, 0],
},
z: 100,
},
{
name: "用户数",
type: "bar", // 柱状图
xAxisId: idx, // 使用的x轴的id
yAxisId: idx, // 使用的y轴的id
barGap: 0, // 柱间距离
barCategoryGap: 0, // 同一系列的柱间距离
data: [item.userCount], // 柱子数据
// 渐变色
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "#F56E6E" },
{ offset: 1, color: "#FDADA9" },
]),
borderRadius: [20, 20, 0, 0],
},
z: 100,
}
);
});
// console.log(areaOption);
// 应用配置
this.chart.setOption(areaOption);
this.chart.on("legendselectchanged", (params) => {
// console.log(params);
// 取消用户数
if (!params.selected["用户数"]) {
// console.log("取消用户数");
this.chart.dispatchAction({
type: "legendUnSelect",
name: "占位数字",
});
} else {
// 选定用户数
// console.log("选定用户数");
this.chart.dispatchAction({
type: "legendSelect",
name: "占位数字",
});
}
});
},
},
};
</script>