Highcharts正射投影地球仪地图相关技术问题咨询
现有代码
在线示例链接
HTML
<script src="https://code.highcharts.com/maps/highmaps.js"></script> <script src="https://code.highcharts.com/maps/modules/data.js"></script> <script src="https://code.highcharts.com/maps/modules/exporting.js"></script> <script src="https://code.highcharts.com/maps/modules/accessibility.js"></script> <div class="globe-container"> <div class="circle"></div> <div id="globe"></div> </div>
CSS
.globe-container { position: absolute; z-index: 0; overflow: hidden; width: 913px; height: 506px; } .circle { width: 873px; height: 873px; border-radius: 50%; position: absolute; top: 0; right: 0; background: linear-gradient( 118.16deg, #be84cf 6.43%, #56c0f5 61.63%, #52fbff 100% ); opacity: 0.2; z-index: 0; } #globe { border-radius: 50%; height: 750px; width: 750px; margin-top: 60px; margin-left: 100px; }
JavaScript
(完整数据见在线示例,以下为核心逻辑代码)
function initializeGlobe() { const self = this; const getGraticule = () => { const data = []; // Meridians for (let x = -180; x <= 180; x += 15) { data.push({ geometry: { type: "LineString", coordinates: x % 90 === 0 ? [ [x, -90], [x, 0], [x, 90] ] : [ [x, -80], [x, 80] ] } }); } // Latitudes for (let y = -90; y <= 90; y += 10) { const coordinates = []; for (let x = -180; x <= 180; x += 5) { coordinates.push([x, y]); } data.push({ geometry: { type: "LineString", coordinates }, lineWidth: y === 0 ? 2 : undefined }); } return data; }; this.chart = Highcharts.mapChart("globe", { chart: { map: topology, backgroundColor: "#dbf4fe", margin: 0, padding: 0, spacing: [0, 0, 0, 0] }, accessibility: { enabled: false }, credits: { enabled: false }, title: { text: null }, legend: { enabled: false }, mapNavigation: { enabled: true, enableDoubleClickZoomTo: false }, mapView: { maxZoom: 4, projection: { name: "Orthographic", rotation: [50, -20] }, animation: true, zoom: 3 }, tooltip: { enabled: false }, series: [ { name: "Graticule", id: "graticule", type: "mapline", data: getGraticule(), enableMouseTracking: false }, { data: countries, joinBy: "name", name: "", color: "#549ee2", borderColor: "#75aee1", cursor: "pointer", events: { click: (event) => { event.srcElement.point.select(); event.srcElement.point.zoomTo(); } }, states: { normal: { animation: false }, inactive: { color: "#75aee1", borderColor: "#75aee1", animation: { duration: 200 } }, select: { color: "#131660", borderColor: "#75aee1", enabled: true }, hover: { color: "#131660", borderColor: "#75aee1", animation: { duration: 200 } } }, dataLabels: { enabled: false } } ] }); const renderSea = () => { let verb = "animate"; if (!this.chart.sea) { this.chart.sea = this.chart.renderer .circle() .attr({ fill: { radialGradient: { cx: 0.4, cy: 0.4, r: 1 }, stops: [[0, "#dbf4fe"]] }, zIndex: 0 }) .add(this.chart.get("graticule").group); verb = "attr"; } const bounds = this.chart.get("graticule").bounds, p1 = this.chart.mapView.projectedUnitsToPixels({ x: bounds.x1, y: bounds.y1 }), p2 = this.chart.mapView.projectedUnitsToPixels({ x: bounds.x2, y: bounds.y2 }); this.chart.sea[verb]({ cx: (p1.x + p2.x) / 2, cy: (p1.y + p2.y) / 2, r: Math.min(p2.x - p1.x, p1.y - p2.y) / 2 }); }; renderSea(); Highcharts.addEvent(this.chart, "redraw", renderSea); this.rotateGlobe(this.chart); } function rotateGlobe(chart) { const interval = setInterval(() => { const rotation = chart.mapView.projection.options.rotation; rotation[0] += 5; if (rotation[0] === 355) { clearInterval(interval); } chart.update( { mapView: { projection: { rotation } } }, void 0, void 0, false ); }, 1); setTimeout(() => { clearInterval(interval); }, 10000); } initializeGlobe();
技术问题解答
1. 点击单个国家时旋转地球仪使其居中显示
修改国家系列的点击事件逻辑,通过计算国家中心经纬度调整投影旋转参数,实现平滑居中:
click: (event) => { const point = event.srcElement.point; point.select(); // 获取国家几何中心的经纬度 const center = point.geometry.getCenter(); // Orthographic投影的旋转参数是视角旋转,需对经纬度取反 const newRotation = [-center.lon, -center.lat, 0]; // 更新地图视图,开启动画实现平滑旋转 point.series.chart.update({ mapView: { projection: { rotation: newRotation } } }, true); }
无需调用zoomTo(),直接通过旋转视角让目标国家居中,更符合地球仪的交互逻辑。
2. 地图数据的简化方案
- 不是必须使用TopoJSON,Highcharts支持多种格式:
- GeoJSON:通用地理数据格式,可直接解析,Natural Earth等公开数据源均提供该格式文件。
- Highcharts预定义地图:直接使用官方提供的地图,比如
custom/world-highres,通过map: 'custom/world-highres'加载,无需自行引入外部数据。 - 自定义地图生成:通过官方地图编辑工具上传GeoJSON/TopoJSON,编辑后导出适配Highcharts的格式。
3. 选择多个国家组成的区域
- 基于当前数据可实现多选:
- 在国家系列中添加配置:
allowPointSelect: true, selectedMode: 'multiple',开启多点选中功能。 - 通过
chart.getSelectedPoints()获取所有选中的国家,自定义高亮或交互逻辑。
- 在国家系列中添加配置:
- 若需将多个国家视为统一区域:
- 使用Mapshaper等工具,将目标国家的GeoJSON合并为单个Feature。
- 加载合并后的地理数据作为新系列,或在现有数据中标记区域归属,通过筛选实现批量高亮。
4. 放大后平移跳帧的解决办法
- 调整地图视图动画配置,仅在初始化时启用动画:
mapView: { maxZoom: 4, projection: { name: "Orthographic", rotation: [50, -20] }, animation: { duration: 0, // 交互时关闭动画 defer: false }, zoom: 3 } - 关闭平滑平移功能:
mapNavigation: { enabled: true, enableDoubleClickZoomTo: false, enableSmoothPan: false } - 优化
renderSea函数的重绘逻辑,将后续更新改为直接属性赋值而非动画:this.chart.sea.attr({ // 替换animate为attr cx: (p1.x + p2.x) / 2, cy: (p1.y + p2.y) / 2, r: Math.min(p2.x - p1.x, p1.y - p2.y) / 2 });
内容的提问来源于stack exchange,提问作者tortoise
相关产品推荐
相关产品推荐

