Files
data-index-report/tools/china_map.html
2026-05-18 13:52:47 +08:00

380 lines
16 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>全国采集数量分布地图生成器</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.3/echarts.min.js"></script>
<!-- 引入中国地图数据 -->
<script src="https://fastly.jsdelivr.net/npm/echarts@4.9.0/map/js/china.js"></script>
<style>
#map-container {
height: calc(100vh - 120px);
min-height: 500px;
}
.custom-card {
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
border-radius: 12px;
background: white;
}
</style>
</head>
<body class="bg-slate-50 text-slate-900 font-sans">
<header class="bg-blue-600 text-white p-4 shadow-md">
<div class="container mx-auto flex justify-between items-center">
<h1 class="text-xl font-bold flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
全国采集数量分布地图
</h1>
<p class="text-sm opacity-80">支持批量导入与独立导出</p>
</div>
</header>
<main class="container mx-auto p-4 lg:p-6 grid grid-cols-1 lg:grid-cols-4 gap-6">
<!-- 左侧控制面板 -->
<div class="lg:col-span-1 space-y-4">
<div class="custom-card p-4 flex flex-col h-full">
<h2 class="font-semibold mb-3 flex items-center gap-2 text-slate-700">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 1 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
数据管理
</h2>
<p class="text-xs text-slate-500 mb-2">每行格式:地区 数量</p>
<textarea
id="data-input"
class="w-full flex-grow p-3 border border-slate-200 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none resize-none font-mono mb-4"
placeholder="输入数据..."
></textarea>
<div class="space-y-3">
<div>
<label class="text-xs font-medium text-slate-500 mb-1 block">导出文件名</label>
<input
id="export-filename"
type="text"
class="w-full p-2 border border-slate-200 rounded-md text-sm outline-none focus:ring-2 focus:ring-blue-500"
placeholder="如1月采集分布图"
>
</div>
<div class="grid grid-cols-1 gap-2">
<button
onclick="updateChart()"
class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 rounded-lg transition-all shadow-sm active:scale-95 flex items-center justify-center gap-2"
>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 4v6h-6"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/></svg>
实时刷新
</button>
<button
onclick="exportHTML()"
class="w-full bg-emerald-600 hover:bg-emerald-700 text-white font-medium py-2 rounded-lg transition-all shadow-sm active:scale-95 flex items-center justify-center gap-2"
>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
导出纯净地图
</button>
</div>
</div>
</div>
<div class="custom-card p-4">
<h3 class="text-sm font-semibold mb-2 text-slate-700">数据统计</h3>
<div class="space-y-2">
<div class="flex justify-between text-sm">
<span class="text-slate-500">地区总数:</span>
<span id="stat-count" class="font-bold">0</span>
</div>
<div class="flex justify-between text-sm">
<span class="text-slate-500">采集总量:</span>
<span id="stat-total" class="font-bold text-blue-600">0</span>
</div>
</div>
</div>
</div>
<!-- 右侧地图展示 -->
<div class="lg:col-span-3">
<div class="custom-card p-4 relative overflow-hidden">
<div id="map-container" class="w-full"></div>
<div id="no-data" class="absolute inset-0 flex items-center justify-center bg-white/80 hidden z-10">
<p class="text-slate-400 italic">请在左侧输入有效数据以生成地图</p>
</div>
</div>
</div>
</main>
<script>
// 初始数据
const initialData = `大连市 158
湖南省 1777
新疆维吾尔 83
青海省 37
陕西省 1841
河北省 2714
青岛市 409
广东省 6726
福建省 1722
浙江省 3031
黑龙江省 500
云南省 934
深圳市 2332
江苏省 4712
甘肃省 786
江西省 1174
广西省 872
吉林省 399
内蒙古 701
厦门市 431
四川省 4560
河南省 2779
西藏 20
山西省 926
山东省 3229
安徽省 2307
海南省 384
宁夏 46
重庆市 838
上海市 1621
湖北省 1786
贵州省 1129
辽宁省 554
宁波市 567
天津市 452
北京市 1666`;
const cityToProvince = {
'大连市': '辽宁', '大连': '辽宁',
'青岛市': '山东', '青岛': '山东',
'深圳市': '广东', '深圳': '广东',
'厦门市': '福建', '厦门': '福建',
'宁波市': '浙江', '宁波': '浙江'
};
let myChart = null;
function init() {
document.getElementById('data-input').value = initialData;
myChart = echarts.init(document.getElementById('map-container'));
updateChart();
window.addEventListener('resize', () => {
myChart && myChart.resize();
});
}
function parseData(text) {
const lines = text.trim().split('\n');
const dataMap = {};
let total = 0;
lines.forEach(line => {
const parts = line.trim().split(/[\s\t,]+/);
if (parts.length >= 2) {
const rawName = parts[0];
const value = parseFloat(parts[1]);
if (isNaN(value)) return;
total += value;
let cleanName = rawName.replace(/(省|市|自治区|维吾尔|壮族|回族)/g, '');
if (cityToProvince[rawName]) {
cleanName = cityToProvince[rawName];
}
if (dataMap[cleanName]) {
dataMap[cleanName] += value;
} else {
dataMap[cleanName] = value;
}
}
});
return {
list: Object.keys(dataMap).map(name => ({ name, value: dataMap[name] })),
total: total,
count: Object.keys(dataMap).length
};
}
function updateChart() {
const inputText = document.getElementById('data-input').value;
const parsed = parseData(inputText);
if (parsed.list.length === 0) {
document.getElementById('no-data').classList.remove('hidden');
return;
} else {
document.getElementById('no-data').classList.add('hidden');
}
document.getElementById('stat-count').innerText = parsed.count;
document.getElementById('stat-total').innerText = parsed.total.toLocaleString();
const maxVal = Math.max(...parsed.list.map(i => i.value), 100);
const option = getChartOption(parsed, maxVal);
myChart.setOption(option);
}
function getChartOption(parsed, maxVal) {
return {
backgroundColor: '#ffffff',
title: {
text: '全国采集数量分布地图',
left: 'center',
top: 20,
textStyle: { color: '#1e293b', fontSize: 24, fontWeight: 'bold' }
},
tooltip: {
trigger: 'item',
formatter: function(params) {
if (isNaN(params.value)) return params.name + ': 无数据';
return `${params.name}<br/>采集数量: <span style="font-weight:bold;color:#2563eb">${params.value.toLocaleString()}</span>`;
},
backgroundColor: 'rgba(255, 255, 255, 0.95)',
borderRadius: 8,
padding: 10,
textStyle: { color: '#334155' }
},
visualMap: {
min: 0,
max: maxVal,
left: 40,
bottom: 40,
text: ['高', '低'],
calculable: true,
inRange: {
color: ['#f0f9ff', '#bae6fd', '#38bdf8', '#0284c7', '#075985']
}
},
geo: {
map: 'china',
roam: true,
zoom: 1.1,
label: {
show: true,
fontSize: 11,
lineHeight: 15,
color: '#334155',
fontWeight: 'bold',
textBorderColor: '#ffffff',
textBorderWidth: 2,
formatter: function(params) {
if (params.name === '香港' || params.name === '澳门') return '';
const item = parsed.list.find(i => i.name === params.name);
return item && item.value > 0 ? `${params.name}\n${item.value}` : params.name;
}
},
itemStyle: {
borderColor: 'rgba(255,255,255,0.6)',
borderWidth: 1,
areaColor: '#f8fafc'
},
emphasis: {
itemStyle: { areaColor: '#fbbf24' },
label: { color: '#000' }
},
regions: [
{ name: '香港', label: { show: false } },
{ name: '澳门', label: { show: false } }
]
},
series: [
{
type: 'map',
geoIndex: 0,
data: parsed.list
}
]
};
}
// 导出功能:生成仅含地图的纯净 HTML
function exportHTML() {
const currentDataText = document.getElementById('data-input').value;
const customFilename = document.getElementById('export-filename').value.trim();
const parsed = parseData(currentDataText);
const maxVal = Math.max(...parsed.list.map(i => i.value), 100);
// 构建纯净版模板
const cleanTemplate = `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>全国采集数量分布地图</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.3/echarts.min.js"><\/script>
<script src="https://fastly.jsdelivr.net/npm/echarts@4.9.0/map/js/china.js"><\/script>
<style>
body, html { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: #fff; }
#map { width: 100vw; height: 100vh; }
</style>
</head>
<body>
<div id="map"></div>
<script>
const parsedData = ${JSON.stringify(parsed)};
const maxVal = ${maxVal};
const myChart = echarts.init(document.getElementById('map'));
const option = {
backgroundColor: '#ffffff',
title: {
text: '全国采集数量分布地图',
left: 'center',
top: 30,
textStyle: { color: '#1e293b', fontSize: 26, fontWeight: 'bold' }
},
tooltip: {
trigger: 'item',
formatter: function(params) {
if (isNaN(params.value)) return params.name + ': 无数据';
return params.name + '<br/>采集数量: ' + params.value.toLocaleString();
}
},
visualMap: {
min: 0, max: maxVal, left: 50, bottom: 50, text: ['高', '低'], calculable: true,
inRange: { color: ['#f0f9ff', '#bae6fd', '#38bdf8', '#0284c7', '#075985'] }
},
geo: {
map: 'china', roam: true, zoom: 1.1,
label: {
show: true, fontSize: 12, lineHeight: 16, color: '#334155', fontWeight: 'bold',
textBorderColor: '#ffffff', textBorderWidth: 2,
formatter: function(params) {
if (params.name === '香港' || params.name === '澳门') return '';
const item = parsedData.list.find(i => i.name === params.name);
return item && item.value > 0 ? params.name + '\\n' + item.value : params.name;
}
},
itemStyle: { borderColor: 'rgba(255,255,255,0.6)', borderWidth: 1, areaColor: '#f8fafc' },
emphasis: { itemStyle: { areaColor: '#fbbf24' } },
regions: [{ name: '香港', label: { show: false } }, { name: '澳门', label: { show: false } }]
},
series: [{ type: 'map', geoIndex: 0, data: parsedData.list }]
};
myChart.setOption(option);
window.addEventListener('resize', () => myChart.resize());
<\/script>
</body>
</html>`;
const blob = new Blob([cleanTemplate], { type: 'text/html' });
const a = document.createElement('a');
const date = new Date().toISOString().slice(0,10);
// 使用自定义名称或默认名称
const finalFilename = customFilename ? `${customFilename}.html` : `全国采集地图_纯净版_${date}.html`;
a.href = URL.createObjectURL(blob);
a.download = finalFilename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
window.onload = init;
</script>
</body>
</html>