import React from "react";
import * as echarts from "echarts";
import worldJson from "../world.json";
import topIcon from "../../../../assets/bigscreen/map-bar-head.svg";
class WorldMap2D extends React.Component {
constructor(props) {
super(props);
this.chartRef = React.createRef();
this.chartInstance = null;
this.pulseTimer = null;
}
componentDidMount() {
echarts.registerMap("world", worldJson);
this.initChart();
window.addEventListener("resize", this.resizeChart);
this.startPulseAnimation();
}
componentWillUnmount() {
if (this.chartInstance) this.chartInstance.dispose();
if (this.pulseTimer) clearInterval(this.pulseTimer);
window.removeEventListener("resize", this.resizeChart);
}
componentDidUpdate() {
this.initChart();
}
resizeChart = () => {
if (this.chartInstance) this.chartInstance.resize();
};
initChart() {
if (!this.chartRef.current) return;
this.chartInstance = echarts.init(this.chartRef.current);
// 顶部图标数据
this.topIconData = this.props.data.map((d) => ({
name: d.name,
value: [d.value[0], d.value[1], d.value[2]],
symbolOffset: [0, (-d.value[2] / 2) * 50],
}));
// 底部光圈初始化
this.pulseData = this.props.data.map((d) => ({
name: d.name,
value: [d.value[0], d.value[1], 0],
}));
// 初始图表
const option = this.getChartOption();
this.chartInstance.setOption(option);
}
// 获取图表配置
getChartOption(currentPulseIndex = -1) {
// 当前显示光圈的柱子
const pulseSeriesData =
currentPulseIndex >= 0 ? [this.pulseData[currentPulseIndex]] : [];
return {
tooltip: {
// formatter: (params) => `${params.name}
${params.value[2]}`,
textStyle: { fontSize: 30, fontWeight: "bold" },
},
geo: {
map: "world",
roam: true,
zoom: 1.1,
itemStyle: {
areaColor: "rgba(126, 206, 244, 0.1)",
borderColor: "#2EA7E0",
borderWidth: 2,
},
label: { show: false },
emphasis: {
itemStyle: {
areaColor: "rgba(41, 241, 250, 0.6)",
borderWidth: 1,
borderColor: "rgba(41, 241, 250, 1)",
shadowColor: "rgba(41, 241, 250, 1)",
shadowBlur: 2,
shadowOffsetX: 10,
shadowOffsetY: -10,
},
label: { show: false },
},
},
series: [
// 主柱子
{
type: "scatter",
coordinateSystem: "geo",
symbol: "rect",
symbolSize: (val) => [28, val[2] * 50],
itemStyle: {
color: {
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: "#EC903A" },
{ offset: 1, color: "rgba(18,92,178,0)" },
],
},
shadowColor: "#4fd2dd",
shadowBlur: 10,
borderRadius: [8, 8, 0, 0],
},
encode: { tooltip: 2 },
data: this.props.data,
},
// 顶部图标
{
type: "scatter",
coordinateSystem: "geo",
symbol: `image://${topIcon}`,
symbolSize: [33, 33],
data: this.topIconData,
},
// 底部光圈
{
type: "effectScatter",
coordinateSystem: "geo",
rippleEffect: {
period: 5, // 波纹扩散周期
scale: 800, // 扩散倍数
brushType: "stroke", // 只描边
},
symbol: "circle",
symbolSize: 1, // 小中心点
itemStyle: {
color: "rgba(76,216,255,0.8)", // 中心点颜色
shadowBlur: 0, // 去掉阴影
shadowColor: "transparent",
},
data: pulseSeriesData,
},
],
};
}
// 启动依次扩散动画
startPulseAnimation() {
const { data } = this.props;
clearInterval(this.pulseTimer);
this.currentIndex = 0;
this.pulseTimer = setInterval(() => {
if (!this.chartInstance) return;
const pulseData = [data[this.currentIndex]]; // 当前光圈数据
// 更新 effectScatter
this.chartInstance.setOption({
series: [{}, {}, { data: pulseData }],
});
// 自动显示 tooltip
this.chartInstance.dispatchAction({
type: "showTip",
seriesIndex: 0, // 主柱子 series
dataIndex: this.currentIndex,
});
this.currentIndex = (this.currentIndex + 1) % data.length;
}, 2000);
}
render() {
return (