You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

D3实现可缩放平移choropleth分级统计图异常问题求助

D3分级统计图缩放平移问题修复方案

问题排查

  1. 地图未跟随缩放同步变化的核心原因
    • 错误将变换属性绑定到<svg>根元素,缩放变换应作用于svg内部承载地图内容的<g class="map">容器
    • 墨卡托投影初始化语法错误,scale配置未显式调用方法,投影参数未生效
    • 存在冗余的path变量重复定义问题
  2. 平移无边界问题的修复逻辑
    • 在zoom事件回调中增加坐标边界校验,根据当前缩放比例动态限制transform的x、y取值范围,避免地图完全移出可视区域

修复后完整代码

HTML+样式

<!DOCTYPE html>
<meta charset="utf-8">
<style>
    body {
      margin: 0
    }

    svg {
      background: #fff;
    }

    .sphere {
      fill: #fff;
    }

    .land {
      fill: #000;
    }

    .map {
      fill: none;
      stroke: #fff;
      stroke-linejoin: round;
      stroke-linecap: round;
      vector-effect: non-scaling-stroke;
    }
    .country:hover{
      stroke: #ddd;
      stroke-width: 4px;
    }
    .legend{
        margin: 1%;
        padding: 1%;
    }
    .legendCells{
        padding: 10px;
        margin: 10px;
    }
    div.tooltip {
      color: #222; 
      background: #fff; 
      padding: .5em; 
      text-shadow: #f5f5f5 0 1px 0;
      border-radius: 2px; 
      box-shadow: 0px 0px 2px 0px #a6a6a6; 
      opacity: 0.9; 
      position: absolute;
    }
    .country{
        fill: #000;
    }
</style>
<body>
<svg width="960" height="600"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://d3js.org/d3-geo-projection.v2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.js"></script>

JS逻辑

const svg = d3.select("svg");
const width = +svg.attr("width"),
      height = +svg.attr("height");
// 地图投影初始化,修正scale调用语法
const projection = d3.geoMercator()
    .scale(width / 2 / Math.PI)
    .translate([width / 2, height / 2])
const path = d3.geoPath().projection(projection);

const zoom = d3.zoom()
    .on('zoom', function(){
        const transform = d3.event.transform;
        const scale = transform.k;
        // 平移边界限制,可根据实际需求调整系数
        const maxOffsetX = (scale - 1) * width / 2;
        const maxOffsetY = (scale - 1) * height / 2;
        transform.x = Math.max(Math.min(transform.x, maxOffsetX), -maxOffsetX);
        transform.y = Math.max(Math.min(transform.y, maxOffsetY), -maxOffsetY);
        // 变换作用于地图容器,而非svg根元素
        d3.select('.map').attr('transform', transform);
    })
    .scaleExtent([1, 40]);

// 加载地图数据
d3.queue()
    .defer(d3.json, "http://enjalot.github.io/wwsd/data/world/world-110m.geojson")
    .await(ready);

function ready(error, topo) {
    if (error) throw error;
    drawmap(topo)
}

function drawmap(topo){
    const mapContainer = svg.append("g")
        .attr("class", "map");
    
    mapContainer.selectAll("path")
        .data(topo.features)
        .enter()
        .append("path")
        .attr("fill","#000")
        .attr("d", path)
        .attr("class","country")
    
    svg.call(zoom);
}

优化说明

  • 边界限制的系数可根据业务需求调整,如果需要允许地图边缘部分移出视野,可适当调大maxOffsetX和maxOffsetY的计算系数
  • vector-effect: non-scaling-stroke属性保证缩放过程中国家边界线宽不会随缩放比例变化,保持视觉一致性

内容的提问来源于stack exchange,提问作者LBes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 10:54:03