generated from dellevin/template
724 lines
25 KiB
JavaScript
724 lines
25 KiB
JavaScript
/**
|
||
* ECharts 地图足迹模块 (支持钻取功能 - 点击省份查看下一级, 点击按钮返回)
|
||
*/
|
||
const MapFootprintModule = (() => {
|
||
let myChart = null; // ECharts 实例
|
||
let currentMapLevel = "country"; // 当前地图层级 ('country', 'province')
|
||
let currentProvinceCode = null; // 当前显示的省份编码 (如果有的话)
|
||
|
||
// --- 配置 ---
|
||
const COUNTRY_MAP_NAME = "china_custom";
|
||
const COUNTRY_GEOJSON_PATH = "./static/js/echarts/china.geojson";
|
||
const PROVINCE_GEOJSON_BASE_PATH = "./static/js/echarts/province/"; // 假设省份 GeoJSON 存放在这个目录
|
||
|
||
// --- 数据 ---
|
||
// 注意:这里的坐标可能需要根据你实际访问的城市进行微调
|
||
const visitedPlaces = [
|
||
{
|
||
name: "济南市",
|
||
province: "山东省",
|
||
value: [117.024961, 36.682788],
|
||
desc:'正在这里努力打工!',
|
||
imgList: [
|
||
"./static/img/location/jinan/1.jpg",
|
||
"./static/img/location/jinan/2.jpg",
|
||
"./static/img/location/jinan/3.jpg",
|
||
"./static/img/location/jinan/4.jpg",
|
||
],
|
||
},
|
||
{
|
||
name: "青岛市",
|
||
value: [120.384423, 36.065918],
|
||
province: "山东省" ,
|
||
desc:'这是我人生第一次看见海,我永远不会忘记。同样的还有你们。',
|
||
imgList: [
|
||
"./static/img/location/qingdao/1.jpg",
|
||
"./static/img/location/qingdao/2.jpg",
|
||
"./static/img/location/qingdao/3.jpg",
|
||
],
|
||
},
|
||
{
|
||
name: "淄博市",
|
||
desc:'也算是吃上淄博烧烤了。',
|
||
value: [118.055915, 36.813547],
|
||
province: "山东省"
|
||
},
|
||
{
|
||
name: "潍坊市",
|
||
desc:'风筝节!不错不错!',
|
||
value: [119.162775, 36.705759],
|
||
province: "山东省"
|
||
},
|
||
|
||
{
|
||
name: "保定市",
|
||
desc:'大学四年,那是最自由的时候。',
|
||
value: [115.482331, 38.867657],
|
||
province: "河北省"
|
||
},
|
||
{ name: "衡水市",
|
||
desc: '生我养我的地方,也是埋葬我的地方',
|
||
value: [115.665996, 37.739574], province: "河北省" },
|
||
{ name: "沧州市",
|
||
desc: 'hei !你一定要幸福啊!带着我们几个的祝福,走下去啊!',
|
||
value: [116.838581, 38.308094], province: "河北省" },
|
||
{
|
||
name: "廊坊市",
|
||
value: [116.704374, 39.523949],
|
||
province: "河北省" ,
|
||
desc:'五一寻友,一起夜间烧烤,宿醉到天明',
|
||
imgList: [
|
||
"./static/img/location/langfang/1.jpg",
|
||
"./static/img/location/langfang/2.jpg",
|
||
"./static/img/location/langfang/3.jpg",
|
||
],
|
||
},
|
||
{ name: "石家庄市",
|
||
desc: '我曾经来过。',
|
||
value: [114.514891, 38.042309], province: "河北省" },
|
||
{ name: "张家口市",
|
||
desc: '三个准大学生,傻傻的做七八个小时的绿皮火车来到这里,只为某人一份未知的爱情。',
|
||
value: [114.886714, 40.811943], province: "河北省" },
|
||
|
||
{ name: "洛阳市",
|
||
province: "河南省",
|
||
value: [112.454174, 34.618139],
|
||
desc:'群山巍峨,银装素裹,不虚此行',
|
||
imgList: [
|
||
"./static/img/location/luoyang/1.jpg",
|
||
"./static/img/location/luoyang/2.jpg",
|
||
"./static/img/location/luoyang/3.jpg",
|
||
],
|
||
},
|
||
|
||
{ name: "昌平区", value: [116.235904, 40.218086], province: "北京市" },
|
||
|
||
{ name: "杭州市",
|
||
desc: '细雨朦胧的西湖才是最美的。',
|
||
value: [120.153576, 30.287459], province: "浙江省" },
|
||
|
||
{ name: "苏州市", value: [120.585316, 31.298886], province: "江苏省" },
|
||
{ name: "扬州市", value: [119.421003, 32.393159], province: "江苏省" },
|
||
{ name: "镇江市", value: [119.452753, 32.204402], province: "江苏省" },
|
||
{ name: "南京市", value: [118.796877, 32.060255], province: "江苏省" },
|
||
{ name: "无锡市", value: [120.311987, 31.49092], province: "江苏省" },
|
||
];
|
||
|
||
// 省份名称到其 GeoJSON 文件名的映射 (需要根据你的文件名调整)
|
||
const provinceNameToGeoFile = {
|
||
北京市: "北京市.geojson",
|
||
山东省: "山东省.geojson",
|
||
河北省: "河北省.geojson",
|
||
河南省: "河南省.geojson",
|
||
浙江省: "浙江省.geojson",
|
||
江苏省: "江苏省.geojson",
|
||
};
|
||
|
||
// --- 工具函数 ---
|
||
|
||
/**
|
||
* 根据省份中文名获取其对应的 GeoJSON 文件完整路径
|
||
* @param {string} provinceName - 省份中文名
|
||
* @returns {string|null} - 文件路径或 null
|
||
*/
|
||
const getProvinceGeoPath = (provinceName) => {
|
||
const fileName = provinceNameToGeoFile[provinceName];
|
||
if (fileName) {
|
||
return ` ${PROVINCE_GEOJSON_BASE_PATH}${fileName}`;
|
||
}
|
||
console.warn(`未找到省份 " ${provinceName}" 对应的 GeoJSON 文件。`);
|
||
return null;
|
||
};
|
||
|
||
/**
|
||
* 根据地图层级和可选的省份编码生成 ECharts 配置
|
||
* @param {string} level - 地图层级 ('country' or 'province')
|
||
* @param {string} [provinceCode] - 省份编码 (当 level='province' 时使用)
|
||
* @returns {Object} - ECharts 配置对象
|
||
*/
|
||
const getEChartsOption = (level, provinceCode = null) => {
|
||
let geoMapName, roamSetting, zoomLevel, centerCoord, titleText;
|
||
let filteredVisitedPlaces = []; // 用于过滤足迹点
|
||
let seriesConfig = []; // 存储所有 series
|
||
let visualMapConfig = null; // 存储 visualMap 配置 (仅省份需要)
|
||
|
||
if (level === "country") {
|
||
geoMapName = COUNTRY_MAP_NAME;
|
||
roamSetting = false; // 启用缩放和平移
|
||
zoomLevel = 1.1;
|
||
centerCoord = [104.06, 32]; // 中国中心
|
||
titleText = "";
|
||
filteredVisitedPlaces = visitedPlaces; // 显示所有足迹
|
||
|
||
// 国家地图:保持原有的 geo 和 scatter 配置
|
||
seriesConfig = [
|
||
{
|
||
name: "足迹",
|
||
type: "scatter",
|
||
coordinateSystem: "geo",
|
||
data: filteredVisitedPlaces,
|
||
symbol: "pin",
|
||
symbolSize: 18,
|
||
itemStyle: {
|
||
color: "#FF6B6B",
|
||
borderColor: "#fff",
|
||
borderWidth: 1,
|
||
},
|
||
emphasis: {
|
||
itemStyle: {
|
||
color: "#dd4444",
|
||
},
|
||
},
|
||
tooltip: {
|
||
// --- 核心修改:Formatter 函数 ---
|
||
formatter: function (params) {
|
||
// 确保 params.data 存在
|
||
if (!params.data) {
|
||
return params.name || "未知地点"; // 如果没有数据,至少显示名称或默认文字
|
||
}
|
||
|
||
// 获取地点名称和坐标
|
||
const name = params.data.name || "未知地点";
|
||
const longitude =
|
||
params.data.value && params.data.value[0]
|
||
? params.data.value[0].toFixed(4)
|
||
: "N/A";
|
||
const latitude =
|
||
params.data.value && params.data.value[1]
|
||
? params.data.value[1].toFixed(4)
|
||
: "N/A";
|
||
|
||
// 初始化 tooltip 内容字符串
|
||
let tooltipHtml = `${name}<br/>坐标: [${longitude}, ${latitude}]<br/>`; // 添加一些换行和分割
|
||
// 如果还需要显示其他描述信息(例如可以从 params.data 中获取),可以在此处添加
|
||
const description = params.data.desc || "博主也不知道说啥了。。。";
|
||
if (description) {
|
||
tooltipHtml += `<strong>描述: </strong>${description}<br/>`;
|
||
}
|
||
// 获取图片列表
|
||
const imageList = params.data.imgList; // 直接从数据对象获取 imgList
|
||
|
||
// 检查是否有图片列表且不为空
|
||
if (Array.isArray(imageList) && imageList.length > 0) {
|
||
// 添加标题
|
||
tooltipHtml += "<strong>照片: </strong><br/>";
|
||
// 遍历图片列表,生成 HTML 图像标签
|
||
imageList.forEach((imgSrc) => {
|
||
tooltipHtml += `<img src="${imgSrc}" alt="${name} 图片" style="max-width: 150px; max-height: 100px; margin: 5px; border-radius: 4px;" onerror="this.style.display='none';"/>`;
|
||
});
|
||
} else {
|
||
// 如果没有图片或 imgList 不存在/为空,则显示提示
|
||
tooltipHtml += "<strong>照片: </strong>看来博主不是很爱拍照~";
|
||
}
|
||
|
||
return tooltipHtml; // 返回构建好的 HTML 字符串
|
||
},
|
||
},
|
||
},
|
||
];
|
||
} else if (level === "province" && provinceCode) {
|
||
geoMapName = `province_ ${provinceCode}`; // 为省份地图创建唯一名称
|
||
roamSetting = false; // 省份地图也启用缩放平移
|
||
zoomLevel = 1.0; // 可以根据需要调整
|
||
// 可以根据省份动态设置中心点,这里暂时固定
|
||
// centerCoord = [118.5, 36.5]; // 示例:山东中心
|
||
// 从 visitedPlaces 中找一个城市作为中心点,如果没有,则使用默认
|
||
const firstPlaceInProvince = visitedPlaces.find(
|
||
(place) => place.province === provinceCode,
|
||
);
|
||
centerCoord = firstPlaceInProvince
|
||
? firstPlaceInProvince.value
|
||
: [118.5, 36.5];
|
||
|
||
if (provinceCode == "山东省") {
|
||
centerCoord = [118.5, 36.5];
|
||
} else if (provinceCode == "河北省") {
|
||
centerCoord = [115.482331, 40];
|
||
} else if (provinceCode == "浙江省") {
|
||
centerCoord = [120.153576, 29.4];
|
||
} else if (provinceCode == "江苏省") {
|
||
centerCoord = [119, 32.9];
|
||
} else if (provinceCode == "河南省") {
|
||
centerCoord = [114, 34];
|
||
} else if (provinceCode == "北京市") {
|
||
centerCoord = [116.407395, 40.3];
|
||
}
|
||
|
||
titleText = ` ${provinceCode} - “印迹”`;
|
||
// 过滤出属于当前省份的足迹点
|
||
filteredVisitedPlaces = visitedPlaces.filter(
|
||
(place) => place.province === provinceCode,
|
||
);
|
||
// 构造 map 系列的数据,访问过的城市 value 设为 1,未访问的可以设为 0
|
||
// 为了实现高亮,我们只需要列出访问过的城市即可,未访问的城市会使用默认颜色
|
||
const provinceMapData = filteredVisitedPlaces.map((city) => ({
|
||
name: city.name,
|
||
desc: city.desc || "",
|
||
imgList: city.imgList || [],
|
||
value: 1, // 值为 1 表示访问过,用于 visualMap 区分
|
||
}));
|
||
|
||
// --- 配置 visualMap ---
|
||
visualMapConfig = {
|
||
show: false, // 通常不显示 visualMap 组件条
|
||
min: 0, // 最小值
|
||
max: 1, // 最大值
|
||
inRange: {
|
||
color: ["#FF6B6B"], // 高亮颜色 (访问过的城市)
|
||
},
|
||
calculable: true,
|
||
};
|
||
|
||
// --- 创建省份地图系列 (用于高亮城市) ---
|
||
const provinceMapSeries = {
|
||
// name: "访问过的城市",
|
||
type: "map",
|
||
map: geoMapName, // 指向当前省份的 GeoJSON
|
||
roam: roamSetting,
|
||
zoom: zoomLevel,
|
||
center: centerCoord,
|
||
silent: false, // 设置为 false,允许响应鼠标事件以显示 tooltip
|
||
label: {
|
||
show: true, // 可以选择是否显示城市名称标签
|
||
color: "#000", // 标签颜色
|
||
fontSize: 10,
|
||
},
|
||
emphasis: {
|
||
label: {
|
||
// 悬停时标签效果
|
||
show: true,
|
||
fontWeight: "bold",
|
||
},
|
||
itemStyle: {
|
||
// 悬停时区域效果
|
||
opacity: 0.8, // 降低透明度
|
||
// areaColor: '#ffcccc', // 也可以设置悬停颜色,但会受 visualMap 影响
|
||
},
|
||
},
|
||
|
||
// 数据驱动颜色
|
||
data: provinceMapData,
|
||
// 默认样式(未在 data 中定义的区域将使用此样式)
|
||
itemStyle: {
|
||
areaColor: "#eef2ff", // 未访问区域的默认颜色
|
||
borderColor: "#333",
|
||
borderWidth: 0.5,
|
||
},
|
||
// 添加 tooltip 配置到 series 级别
|
||
tooltip: {
|
||
trigger: 'item',
|
||
formatter: function(params) {
|
||
// 检查是否有数据
|
||
if (!params.data) {
|
||
return params.name || "未知城市";
|
||
}
|
||
|
||
const cityName = params.data.name || params.name || "未知城市";
|
||
let tooltipHtml = `<div style="font-weight: bold; font-size: 14px; margin-bottom: 8px;">${cityName}</div>`;
|
||
|
||
// 如果这个城市在 visitedPlaces 中有记录
|
||
const placeData = visitedPlaces.find(p => p.name === cityName && p.province === provinceCode);
|
||
if (placeData) {
|
||
// 显示描述
|
||
const description = placeData.desc || "暂无描述";
|
||
tooltipHtml += `<div style="margin-bottom: 8px; color: #666; font-size: 12px;">${description}</div>`;
|
||
|
||
// 显示图片
|
||
if (placeData.imgList && placeData.imgList.length > 0) {
|
||
tooltipHtml += `<div style="display: flex; gap: 5px; flex-wrap: wrap; margin-top: 5px;">`;
|
||
placeData.imgList.forEach((imgSrc) => {
|
||
tooltipHtml += `
|
||
<img src="${imgSrc}"
|
||
alt="${cityName}"
|
||
style="width: 60px; height: 60px; object-fit: cover;
|
||
border-radius: 4px; border: 1px solid #ddd;" />
|
||
`;
|
||
});
|
||
tooltipHtml += `</div>`;
|
||
}
|
||
}
|
||
|
||
return tooltipHtml;
|
||
}
|
||
}
|
||
};
|
||
|
||
// 将省份地图系列和 geo 组件添加到配置中
|
||
seriesConfig = [provinceMapSeries];
|
||
// geo 配置也需要包含省份 geo
|
||
// 注意:在返回全国地图时,需要重新设置 geo 为国家地图
|
||
// 这个 geo 组件会覆盖全局的 geo 配置
|
||
// 我们需要将 geo 配置移动到外面处理
|
||
} else {
|
||
console.error("无效的地图层级或省份代码");
|
||
return {}; // 返回空配置
|
||
}
|
||
|
||
// 构建最终的 option
|
||
const option = {
|
||
title: {
|
||
text: titleText,
|
||
subtext: "读万卷书,不如行万里路。见多才会识广~",
|
||
left: "center",
|
||
textStyle: {
|
||
fontSize: 18,
|
||
},
|
||
subtextStyle: {
|
||
fontSize: 12,
|
||
},
|
||
},
|
||
tooltip: {
|
||
trigger: 'item',
|
||
backgroundColor: 'rgba(255, 255, 255, 0.95)',
|
||
borderColor: '#ddd',
|
||
borderWidth: 1,
|
||
textStyle: {
|
||
color: '#333'
|
||
},
|
||
extraCssText: 'box-shadow: 0 2px 8px rgba(0,0,0,0.15); border-radius: 6px;'
|
||
},
|
||
// geo 组件配置
|
||
geo:
|
||
level === "country"
|
||
? {
|
||
map: geoMapName,
|
||
roam: roamSetting,
|
||
zoom: zoomLevel,
|
||
center: centerCoord,
|
||
emphasis: {
|
||
itemStyle: {
|
||
areaColor: "#f0f0f0", // geo 强调样式,当没有 series 时生效
|
||
borderColor: "#409EFF",
|
||
borderWidth: 1,
|
||
},
|
||
},
|
||
itemStyle: {
|
||
areaColor: "#eef2ff", // geo 默认样式,当没有 series 时生效
|
||
borderColor: "#333",
|
||
},
|
||
}
|
||
: {
|
||
// 省份地图的 geo 配置
|
||
id: "province_geo_for_clicks", // 给 geo 组件一个 ID 便于识别
|
||
map: geoMapName,
|
||
roam: roamSetting,
|
||
zoom: zoomLevel,
|
||
center: centerCoord,
|
||
silent: false, // 设置为 false,允许 geo 组件响应点击
|
||
// 隐藏 geo 组件的视觉表现,因为高亮由 series 控制
|
||
itemStyle: {
|
||
areaColor: "transparent", // 透明填充
|
||
borderColor: "transparent", // 透明边框
|
||
},
|
||
emphasis: {
|
||
itemStyle: {
|
||
areaColor: "rgba(64, 158, 255, 0.2)", // 可选:点击时的视觉反馈
|
||
borderColor: "transparent",
|
||
},
|
||
},
|
||
},
|
||
series: seriesConfig, // 使用构建好的 series 配置
|
||
};
|
||
|
||
// 如果当前是省份地图,添加 visualMap 配置
|
||
if (visualMapConfig) {
|
||
option.visualMap = visualMapConfig;
|
||
}
|
||
|
||
return option;
|
||
};
|
||
|
||
/**
|
||
* 加载并注册指定路径的 GeoJSON 地图数据
|
||
* @param {string} path - GeoJSON 文件路径
|
||
* @param {string} mapName - 注册到 ECharts 的地图名称
|
||
* @returns {Promise<boolean>} - 成功或失败
|
||
*/
|
||
const loadAndRegisterSingleMap = async (path, mapName) => {
|
||
try {
|
||
console.log(`正在加载 GeoJSON: ${path}`);
|
||
const response = await fetch(path);
|
||
if (!response.ok) {
|
||
throw new Error(
|
||
`加载 GeoJSON 失败: ${response.status} ${response.statusText}`,
|
||
);
|
||
}
|
||
const geoJsonData = await response.json();
|
||
|
||
// 注册地图
|
||
echarts.registerMap(mapName, geoJsonData);
|
||
console.log(`GeoJSON 地图数据 ${mapName} 加载并注册成功。`);
|
||
return true;
|
||
} catch (error) {
|
||
console.error("加载或注册 GeoJSON 地图时出错:", error);
|
||
return false;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 切换到指定的地图层级和区域
|
||
* @param {string} targetLevel - 目标层级 ('country' or 'province')
|
||
* @param {string} [targetProvinceCode] - 目标省份编码 (当 targetLevel='province' 时使用)
|
||
*/
|
||
const switchMap = async (targetLevel, targetProvinceCode = null) => {
|
||
if (!myChart) {
|
||
console.error("ECharts 实例不存在,无法切换地图。");
|
||
return;
|
||
}
|
||
|
||
let mapNameToUse, geoPathToLoad;
|
||
|
||
if (targetLevel === "country") {
|
||
mapNameToUse = COUNTRY_MAP_NAME;
|
||
geoPathToLoad = COUNTRY_GEOJSON_PATH;
|
||
currentMapLevel = "country";
|
||
currentProvinceCode = null;
|
||
} else if (targetLevel === "province" && targetProvinceCode) {
|
||
mapNameToUse = `province_ ${targetProvinceCode}`;
|
||
const path = getProvinceGeoPath(targetProvinceCode);
|
||
if (!path) {
|
||
console.error(
|
||
`无法切换到省份 ${targetProvinceCode}: 找不到对应的 GeoJSON 文件。`,
|
||
);
|
||
return;
|
||
}
|
||
geoPathToLoad = path;
|
||
currentMapLevel = "province";
|
||
currentProvinceCode = targetProvinceCode;
|
||
} else {
|
||
console.error("无效的目标层级或省份代码。");
|
||
return;
|
||
}
|
||
|
||
// 尝试加载并注册目标地图数据
|
||
const loadSuccess = await loadAndRegisterSingleMap(
|
||
geoPathToLoad,
|
||
mapNameToUse,
|
||
);
|
||
if (!loadSuccess) {
|
||
console.error(`切换地图失败:无法加载 ${geoPathToLoad}`);
|
||
return;
|
||
}
|
||
|
||
// 生成新配置并应用
|
||
const newOption = getEChartsOption(targetLevel, targetProvinceCode);
|
||
myChart.setOption(newOption, true); // 使用 notMerge=true 确保完全替换
|
||
|
||
// 更新返回按钮的可见性
|
||
updateBackButtonVisibility();
|
||
};
|
||
|
||
// --- 新增函数:管理返回按钮 ---
|
||
|
||
/**
|
||
* 获取返回按钮的DOM元素
|
||
* @returns {HTMLElement|null}
|
||
*/
|
||
const getBackButtonElement = () => {
|
||
// 假设按钮ID是固定的,可以根据需要调整
|
||
return document.getElementById("map-back-button");
|
||
};
|
||
|
||
/**
|
||
* 创建返回按钮并将其添加到图表容器中
|
||
* @param {HTMLElement} chartContainer - ECharts 图表容器
|
||
*/
|
||
const createBackButton = (chartContainer) => {
|
||
const button = document.createElement("button");
|
||
button.id = "map-back-button";
|
||
button.textContent = "⬅返回全国地图";
|
||
button.style.position = "absolute";
|
||
button.style.top = "50px";
|
||
button.style.left = "10px";
|
||
button.style.zIndex = 1000; // 确保按钮在图表之上
|
||
button.style.padding = "2px 5px"; // 减少内边距以更接近纯文本
|
||
button.style.fontSize = "14px"; // 根据需要调整字体大小
|
||
button.style.cursor = "pointer";
|
||
button.style.border = "none"; // 去掉边框
|
||
button.style.backgroundColor = "transparent"; // 设置背景透明
|
||
button.style.display = "none"; // 初始隐藏
|
||
|
||
button.onclick = () => {
|
||
console.log("点击了返回按钮。");
|
||
switchMap("country");
|
||
};
|
||
|
||
chartContainer.appendChild(button);
|
||
};
|
||
|
||
/**
|
||
* 根据当前地图层级更新返回按钮的可见性
|
||
*/
|
||
const updateBackButtonVisibility = () => {
|
||
const button = getBackButtonElement();
|
||
if (!button) {
|
||
console.warn("返回按钮 DOM 元素未找到,无法更新其可见性。");
|
||
return;
|
||
}
|
||
// 当前在省份地图时显示按钮,否则隐藏
|
||
button.style.display = currentMapLevel === "province" ? "block" : "none";
|
||
};
|
||
|
||
// --- /新增函数 ---
|
||
/**
|
||
* 初始化 ECharts 地图 (初始加载国家地图)
|
||
* @param {HTMLElement} container - 图表容器DOM元素
|
||
*/
|
||
const initEChartsMap = async (container) => {
|
||
if (!container) {
|
||
console.error("地图容器未找到");
|
||
return;
|
||
}
|
||
|
||
// 初始化 ECharts 实例
|
||
myChart = echarts.init(container);
|
||
|
||
// 创建并添加返回按钮
|
||
createBackButton(container);
|
||
|
||
// 首先加载并注册国家地图
|
||
const countryLoadSuccess = await loadAndRegisterSingleMap(
|
||
COUNTRY_GEOJSON_PATH,
|
||
COUNTRY_MAP_NAME,
|
||
);
|
||
if (!countryLoadSuccess) {
|
||
console.error("初始化失败:无法加载国家 GeoJSON。");
|
||
return; // 或者显示错误信息给用户
|
||
}
|
||
|
||
// 应用初始配置 (国家地图)
|
||
const initialOption = getEChartsOption("country");
|
||
myChart.setOption(initialOption);
|
||
|
||
// --- 添加事件监听 ---
|
||
|
||
// 监听 geo 组件的点击事件
|
||
// 关键修改:现在 geo 组件在省份地图时也存在,并且不静默
|
||
myChart.on("click", "geo", function (params) {
|
||
console.log("Geo component clicked:", params.componentId, params.name); // Debug log
|
||
if (currentMapLevel === "country") {
|
||
// 当前是国家地图,点击省份则进入
|
||
const clickedProvinceName = params.name;
|
||
console.log(`点击了省份: ${clickedProvinceName}`);
|
||
|
||
// 尝试获取省份对应的 GeoJSON 文件名
|
||
const fileName = Object.keys(provinceNameToGeoFile).find(
|
||
(key) => key === clickedProvinceName,
|
||
);
|
||
console.log(fileName);
|
||
if (fileName) {
|
||
const provinceCode = fileName; // 这里假设文件名就是省份简称
|
||
// console.log(`即将切换到省份: ${provinceCode}`);
|
||
switchMap("province", provinceCode);
|
||
} else {
|
||
showModal();
|
||
console.log(`未配置省份 " ${clickedProvinceName}" 的详细地图。`);
|
||
}
|
||
} else if (
|
||
currentMapLevel === "province" &&
|
||
params.componentId === "province_geo_for_clicks"
|
||
) {
|
||
// 当前是省份地图,且点击的是省份 geo 组件,则返回全国地图
|
||
console.log("点击省份 geo 组件,返回全国地图");
|
||
switchMap("country");
|
||
}
|
||
// 如果在省份地图上点击,但不是省份 geo 组件(理论上不会发生,因为 series 是 silent 的),可以有其他逻辑,比如不处理
|
||
});
|
||
|
||
// 监听窗口大小变化,自动适配
|
||
window.addEventListener("resize", function () {
|
||
if (myChart) {
|
||
myChart.resize();
|
||
}
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 获取地图容器ID
|
||
* @returns {string}
|
||
*/
|
||
const getMapContainerId = () => {
|
||
return "echarts-map-container";
|
||
};
|
||
|
||
/**
|
||
* 渲染 ECharts 地图内容到指定容器
|
||
* @param {HTMLElement} contentDiv - 标签页的内容容器
|
||
*/
|
||
const renderMap = (contentDiv) => {
|
||
// 清空内容区域
|
||
// contentDiv.innerHTML = '';
|
||
// 创建地图容器
|
||
const mapDiv = document.createElement("div");
|
||
mapDiv.id = getMapContainerId();
|
||
mapDiv.style.width = "100%";
|
||
mapDiv.style.height = "90vh";
|
||
mapDiv.style.marginTop = "20px";
|
||
mapDiv.style.position = "relative";
|
||
contentDiv.appendChild(mapDiv);
|
||
|
||
// 加载 GeoJSON 并初始化地图
|
||
setTimeout(async () => {
|
||
const container = document.getElementById(getMapContainerId());
|
||
if (container) {
|
||
await initEChartsMap(container); // 使用 await 确保初始化完成
|
||
} else {
|
||
console.error("地图容器 DOM 元素未找到,无法初始化图表。");
|
||
}
|
||
}, 100);
|
||
};
|
||
|
||
/**
|
||
* 销毁 ECharts 实例 (可选,用于性能优化或切换时清理)
|
||
*/
|
||
const destroyMap = () => {
|
||
if (myChart) {
|
||
myChart.dispose();
|
||
myChart = null;
|
||
console.log("ECharts 地图已销毁");
|
||
// 可以考虑移除返回按钮
|
||
const button = getBackButtonElement();
|
||
if (button && button.parentNode) {
|
||
button.parentNode.removeChild(button);
|
||
}
|
||
}
|
||
};
|
||
|
||
// 返回公共方法
|
||
return {
|
||
renderMap,
|
||
destroyMap,
|
||
};
|
||
})();
|
||
|
||
function showModal() {
|
||
document.getElementById("modalOverlay").style.display = "block";
|
||
}
|
||
|
||
const closeModal = () => {
|
||
document.getElementById("modalOverlay").style.display = "none";
|
||
};
|
||
// --- 页面加载完成后执行 ---
|
||
document.addEventListener("DOMContentLoaded", function () {
|
||
// 获取遮罩层和内容区域元素
|
||
const modalOverlay = document.getElementById("modalOverlay");
|
||
const modalContent = document.getElementById("modalContent");
|
||
|
||
// 定义点击遮罩层的处理函数
|
||
function handleOverlayClick(event) {
|
||
// 检查点击的目标是否是遮罩层本身(而不是它的子元素,比如里面的 p 或 button)
|
||
if (event.target === modalOverlay) {
|
||
closeModal(); // 如果是,就关闭弹窗
|
||
}
|
||
}
|
||
|
||
// 为遮罩层添加点击事件监听器
|
||
modalOverlay.addEventListener("click", handleOverlayClick);
|
||
|
||
// --- 示例:如何显示弹窗 (供参考) ---
|
||
// window.showModal = function() {
|
||
// modalOverlay.style.display = 'block';
|
||
// // 注意:如果每次都显示,事件监听器只需要添加一次,或者在这里检查是否已存在
|
||
// }
|
||
});
|