求助:D3.js旋转缩放地球实现背面点隐藏的问题
解决D3.js Orthographic地球投影中城市点背面隐藏问题
你遇到的问题其实D3的geoOrthographic投影已经内置了解决方案——当点处于地球不可见的半球时,投影函数会返回null,我们可以直接利用这个特性来控制城市点的显示/隐藏,不用手动计算旋转后的地球中心经纬度,简单又可靠。
下面是具体的修改步骤,直接替换你现有代码中的对应部分即可:
1. 初始加载城市点时处理可见性
修改你的CSV加载代码,在初始化时就判断每个点是否在可见半球:
d3.csv("us-cities2.csv", function(data) { map.selectAll("circle") .data(data) .enter() .append("circle") .attr("r", 2) .attr("class","city") .style("fill", "yellow") .style("stroke", "gray") .style("stroke-width", 0.25) .each(function(d) { // 获取投影后的坐标 var projectedCoords = projection([d.lon, d.lat]); if (projectedCoords) { // 点在正面:设置坐标并显示 d3.select(this) .attr("cx", projectedCoords[0]) .attr("cy", projectedCoords[1]) .style("opacity", 0.75); } else { // 点在背面:隐藏 d3.select(this).style("opacity", 0); } }); });
2. 拖拽旋转时更新点的可见性
修改dragged函数中的点更新逻辑,替换原来仅更新cx/cy的代码:
function dragged() { gpos1 = projection.invert(d3.mouse(this)); o0 = projection.rotate(); o1 = eulerAngles(gpos0, gpos1, o0); projection.rotate(o1); map.selectAll("path").attr("d", path); // 更新城市点的位置和可见性 map.selectAll('circle') .each(function(d) { var projectedCoords = projection([d.lon, d.lat]); if (projectedCoords) { d3.select(this) .attr("cx", projectedCoords[0]) .attr("cy", projectedCoords[1]) .style("opacity", 0.75); } else { d3.select(this).style("opacity", 0); } }); }
3. 缩放时更新点的可见性
同样修改zoomed函数中的点更新部分:
function zoomed() { projection.scale(d3.event.transform.translate(projection).k * scl); map.selectAll("path").attr("d", path); // 更新城市点的位置和可见性 map.selectAll('circle') .each(function(d) { var projectedCoords = projection([d.lon, d.lat]); if (projectedCoords) { d3.select(this) .attr("cx", projectedCoords[0]) .attr("cy", projectedCoords[1]) .style("opacity", 0.75); } else { d3.select(this).style("opacity", 0); } }); }
原理说明
D3的geoOrthographic投影内部会自动判断坐标是否位于当前视角的可见半球:
- 如果点在可见区域,返回正常的[x,y]屏幕坐标
- 如果点在地球背面,返回
null
我们只需要根据这个返回值切换点的透明度(或者用style("display", "none")完全隐藏),就能实现点随地球旋转自动显示/隐藏的效果,比手动计算经纬度距离要高效且准确得多。
如果你想要更彻底的隐藏,可以把style("opacity", 0)换成style("display", "none"),这样背面的点不会占据任何渲染资源;如果需要平滑过渡效果,也可以给opacity添加过渡动画,比如:
d3.select(this) .transition() .duration(100) .style("opacity", 0);
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

