<!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.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/echarts/map/js/china.js"></script> <style> * {margin: 0;padding:0} html,body {height:100%;background:#060e20;overflow:hidden} #tourMap {width:100vw;height:100vh;} </style> </head> <body> <div id="tourMap"></div> <script> const chartDom = document.getElementById('tourMap'); const myChart = echarts.init(chartDom); // ========== 全国完整城市库(34个行政区中心城市) ========== const cityCoordinate = { // 直辖市 "北京": [116.40, 39.90], "天津": [117.20, 39.08], "上海": [121.47, 31.23], "重庆": [106.55, 29.57], // 23个省 省会 "石家庄": [114.48, 38.04], "太原": [112.55, 37.87], "沈阳": [123.43, 41.80], "长春": [125.33, 43.88], "哈尔滨": [126.63, 45.75], "南京": [118.78, 32.04], "杭州": [120.15, 30.28], "合肥": [117.27, 31.86], "福州": [119.30, 26.08], "南昌": [115.86, 28.68], "济南": [117.00, 36.67], "郑州": [113.62, 34.76], "武汉": [114.31, 30.59], "长沙": [112.93, 28.23], "广州": [113.27, 23.13], "海口": [110.35, 20.02], "成都": [104.07, 30.67], "贵阳": [106.63, 26.65], "昆明": [102.71, 25.04], "西安": [108.95, 34.27], "兰州": [103.83, 36.06], "西宁": [101.78, 36.62], "银川": [106.27, 38.48], "乌鲁木齐": [87.62, 43.82], // 自治区 "呼和浩特": [111.75, 40.82], "南宁": [108.32, 22.82], "拉萨": [91.00, 29.64], // 港澳台 "香港": [114.17, 22.28], "澳门": [113.55, 22.20] }; const cityList = Object.keys(cityCoordinate); // 随机数字工具 function random(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } // 生成旅游数据:城市流入游客、流出游客、城市间旅游飞线 function buildTourData() { let scatterData = []; let flowLines = []; cityList.forEach(cityName => { // 随机:本市居民出游(流出)、外地游客到访(流入) const tourOut = random(1000, 15000); const tourIn = random(800, 13000); const totalTour = tourOut + tourIn; // 城市脉冲圆点数据 scatterData.push({ name: cityName, value: [...cityCoordinate[cityName], totalTour, tourOut, tourIn] }) // 每个城市随机生成 3 条去往其他城市的旅游动线 const otherCities = cityList.filter(c => c !== cityName); for (let i = 0; i < 3; i++) { const target = otherCities[random(0, otherCities.length - 1)]; const peopleNum = random(300, tourOut / 2); flowLines.push({ source: cityName, target: target, value: peopleNum }) } }) return { scatterData, flowLines }; } // 渲染地图配置 function renderMap() { const { scatterData, flowLines } = buildTourData(); const option = { backgroundColor: "#060e20", tooltip: { trigger: "item", formatter(params) { // 悬浮在飞线上 if (params.data.coords) { return `旅游线路:${params.data.sourceName} → ${params.data.targetName}<br>出行人数:${params.data.value} 人` } // 悬浮在城市点位 const v = params.data.value; return `【${params.name}】 总旅游客流量:${v[2]} 人 本地出游流出:${v[3]} 人 外来游客流入:${v[4]} 人` } }, geo: { map: "china", roam: true, zoom: 1.15, label: { show: false }, itemStyle: { areaColor: "#0b2248", borderColor: "#2466b3" }, emphasis: { itemStyle: { areaColor: "#173b78" } } }, series: [ // 城市脉冲光圈(客流越大光圈越大) { type: "effectScatter", coordinateSystem: "geo", data: scatterData, rippleEffect: { brushType: "stroke", scale: 4, period: 4 }, symbolSize: val => val[2] / 600, itemStyle: { color: "#36e4ff" } }, // 城市之间流动光线 { type: "lines", coordinateSystem: "geo", zlevel: 2, data: flowLines.map(item => ({ coords: [cityCoordinate[item.source], cityCoordinate[item.target]], sourceName: item.source, targetName: item.target, value: item.value })), lineStyle: { width: 1.2, color: "#ffd343", curveness: 0.2 }, effect: { show: true, trailLength: 0.6, symbolSize: 5, color: "#fff" } } ] }; myChart.setOption(option); } // 初始化渲染 renderMap(); // 10分钟刷新一次 = 10 * 60 * 1000 = 600000毫秒 setInterval(renderMap, 600000); // 窗口缩放自适应 window.addEventListener("resize", () => myChart.resize()) </script> </body> </html>
![]()