D3实现可缩放平移choropleth分级统计图异常问题求助
D3分级统计图缩放平移问题修复方案
问题排查
- 地图未跟随缩放同步变化的核心原因
- 错误将变换属性绑定到
<svg>根元素,缩放变换应作用于svg内部承载地图内容的<g class="map">容器 - 墨卡托投影初始化语法错误,
scale配置未显式调用方法,投影参数未生效 - 存在冗余的
path变量重复定义问题
- 错误将变换属性绑定到
- 平移无边界问题的修复逻辑
- 在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
相关产品推荐
相关产品推荐

