結合 PHP 後端數據輸出、Raphael.js SVG 繪圖庫、jQuery 交互,實現省級數據的中國地圖熱力圖展示。本文提供完整前後端代碼架構。
project/
├── index.html # 頁面入口
├── json.php # 數據 API
├── raphael.js # Raphael 庫
├── chinamapPath.js # 省份路徑數據
└── jquery.js # jQuery 庫
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>中國地圖數據可視化</title>
<script src="jquery.js"></script>
<script src="raphael.js"></script>
<script src="chinamapPath.js"></script>
</head>
<body>
<div id="map" style="width: 600px; height: 500px;"></div>
</body>
</html>
<?php
// json.php
header('Content-Type: application/json; charset=utf-8');
$host = 'localhost';
$user = 'root';
$pass = '';
$dbname = 'demo';
$mysqli = new mysqli($host, $user, $pass, $dbname);
if ($mysqli->connect_errno) {
echo json_encode(['error' => 'DB連接失敗']);
exit;
}
$mysqli->set_charset('utf8mb4');
// 關鍵:查詢順序必須與 chinamapPath.js 省份順序一致
$sql = "SELECT active FROM mapdata ORDER BY id ASC";
$result = $mysqli->query($sql);
$data = [];
while ($row = $result->fetch_assoc()) {
$data[] = (int)$row['active'];
}
echo json_encode($data); // 輸出: [120, 45, 300, ...]
$mysqli->close();
?>
CREATE TABLE mapdata (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
province VARCHAR(20) NOT NULL COMMENT '省份名稱',
active INT UNSIGNED DEFAULT 0 COMMENT '活躍用戶數',
INDEX idx_province (province)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 插入數據 (順序對應 chinamapPath.js)
INSERT INTO mapdata (province, active) VALUES
('北京', 1200), ('天津', 800), ('河北', 1500), ...;
<script>
$(function() {
$.get('json.php', function(json) {
// 兼容字符串/數組
var data = typeof json === 'string' ? JSON.parse(json) : json;
// 1. 數值映射到 0-5 級
var levels = [];
for (var i = 0; i < data.length; i++) {
var d = data[i];
if (d < 100) level = 0;
else if (d < 500) level = 1;
else if (d < 2000) level = 2;
else if (d < 5000) level = 3;
else if (d < 10000) level = 4;
else level = 5;
levels.push(level);
}
// 2. 顏色定義 (淺到深)
var colors = [
'#d7eef8', '#97d6f5', '#3fbeef',
'#00a2e9', '#0084be', '#005c86'
];
// 3. 初始化 Raphael
var R = Raphael('map', 600, 500);
// 4. 繪制地圖 (假設 chinamapPath.js 定義 window.china 對象)
paintMap(R); // 此函數來自 chinamapPath.js 或自定義
// 5. 文字屬性
var textAttr = {
fill: '#000',
'font-size': '12px',
cursor: 'pointer'
};
// 6. 遍歷省份填充顏色、添加標籤、綁定交互
var i = 0;
for (var state in china) {
var st = china[state]['path'];
var name = china[state]['name'];
// 獲取中心坐標 (用於放置文字)
var bbox = st.getBBox();
var cx = bbox.x + bbox.width / 2;
var cy = bbox.y + bbox.height / 2;
// 微調特定省份文字位置
var offsets = {
'江蘇': [5, -10], '河北': [-10, 20], '天津': [10, 10],
'上海': [10, 0], '廣東': [0, -10], '澳門': [0, 10],
'香港': [20, 5], '甘肅': [-40, -30], '陝西': [5, 10],
'內蒙古': [-15, 65]
};
if (offsets[name]) {
cx += offsets[name][0];
cy += offsets[name][1];
}
// 創建文字標籤
china[state]['text'] = R.text(cx, cy, name).attr(textAttr);
// 填充顏色
var fillColor = colors[levels[i]];
st.attr({fill: fillColor, stroke: '#eee', 'stroke-width': 0.5});
// 懸停交互
st[0].onmouseover = function() {
this.animate({fill: '#fdd', stroke: '#eee'}, 300);
china[state]['text'].toFront();
};
st[0].onmouseout = function() {
this.animate({fill: fillColor, stroke: '#eee'}, 300);
china[state]['text'].toFront();
};
i++;
}
});
});
// 輔助:字符串轉數組 (舊版兼容)
function string2Array(str) {
return JSON.parse(str);
}
</script>
// 簡化示例,實際文件包含所有省份 SVG 路徑
var china = {
'北京': {
name: '北京',
path: R.path('M...Z'), // SVG 路徑字符串
text: null
},
'天津': { ... },
// ... 34 個省級行政區
};
完整路徑數據可從開源項目獲取:china-map-data
header('Cache-Control: max-age=300')scaleQuantize 或 scaleThreshold 替代硬編碼級別R.setViewBox(0, 0, 600, 500, true) 適配容器
此方案展示了經典「後端數據 + 前端 SVG 繪製」架構,理解原理後建議遷移至成熟圖表庫提升開發效率。