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

D3.js V6按钮控制缩放平移(Zoom/Pan)功能失效问题

D3.js V6 缩放平移功能修复方案

原代码存在的问题

  • 拼写错误:d3.bheviour.zoom 应为 d3.zoom(D3 v6已移除behaviour命名空间)
  • HTML语法错误:</butto/*n> 是注释残留,需修正为 </button>
  • 重复ID:两个按钮使用相同id="pan_top",分别改为pan_down和pan_up
  • 缩放事件处理不当:zoomed函数需使用D3 v6的event.transform直接设置变换,而非手动拼接字符串
  • 插值缩放逻辑错误:未通过zoom.transform()更新zoom状态,导致变换不生效
  • 未实现平移按钮逻辑:原代码仅处理缩放按钮,需补充平移功能

修正后的完整代码

<!DOCTYPE html>
<meta charset="utf-8">
<title>Zoom + Pan</title>
<script src="https://d3js.org/d3.v6.min.js"></script>
<style>
.overlay {
  fill: none;
  pointer-events: all;
}
button {
  padding: 10px 20px;
  margin: 0 5px;
}
</style>
<body>
<div id="buttons">
<button class="zooming" id="zoom_in">+</button>
<button class="zooming" id="zoom_out">-</button>
<button class="panning" id="pan_right">&rarr;</button>
<button class="panning" id="pan_left">&larr;</button>
<button class="panning" id="pan_down">&darr;</button>
<button class="panning" id="pan_up">&uarr;</button>
</div>
<script>
var width = 960,
    height = 500;

var randomX = d3.randomNormal(width / 2, 80),
    randomY = d3.randomNormal(height / 2, 80);

var data = d3.range(2000).map(function() {
    return [randomX(), randomY() ];
});

// 修正拼写错误,使用d3.zoom()
var zoom = d3.zoom()
    .scaleExtent([1, 8])
    .translateExtent([[-1000, -500], [1000, 500]])
    .on("zoom", zoomed);

// 分离zoom容器和内容容器,确保变换作用于内容g
var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

var zoomContainer = svg.append("g")
    .call(zoom);

var contentContainer = zoomContainer.append("g");

contentContainer.append("rect")
    .attr("class", "overlay")
    .attr("width", width)
    .attr("height", height);

contentContainer.selectAll("circle")
    .data(data)
  .enter().append("circle")
    .attr("r", 2.5)
    .attr("transform", function(d) { return "translate(" + d + ")"; });

// 修正zoomed函数,使用event.transform直接设置
function zoomed(event) {
    contentContainer.attr("transform", event.transform);
}

// 修正插值缩放函数,使用zoom.transform更新状态
function interpolateZoom(targetTransform) {
    d3.transition().duration(350)
        .tween("zoom", function() {
            var currentTransform = d3.zoomTransform(zoomContainer.node());
            var interpolator = d3.interpolate(currentTransform, targetTransform);
            return function(t) {
                zoom.transform(zoomContainer, interpolator(t));
            };
        });
}

// 完善按钮点击事件,区分缩放和平移
function handleButtonClick(event) {
    var buttonId = this.id;
    var currentTransform = d3.zoomTransform(zoomContainer.node());
    var scale = currentTransform.k;
    var translate = [currentTransform.x, currentTransform.y];
    var panStep = 50 / scale; // 根据缩放比例调整平移步长

    if (buttonId === "zoom_in" || buttonId === "zoom_out") {
        // 缩放逻辑
        var factor = buttonId === "zoom_in" ? 1.2 : 0.8;
        var targetScale = Math.max(zoom.scaleExtent()[0], Math.min(zoom.scaleExtent()[1], scale * factor));
        // 计算以中心为基准的缩放变换
        var targetTransform = currentTransform.scale(targetScale);
        interpolateZoom(targetTransform);
    } else {
        // 平移逻辑
        var newTranslate = [...translate];
        switch(buttonId) {
            case "pan_right": newTranslate[0] += panStep; break;
            case "pan_left": newTranslate[0] -= panStep; break;
            case "pan_down": newTranslate[1] += panStep; break;
            case "pan_up": newTranslate[1] -= panStep; break;
        }
        // 应用平移变换
        var targetTransform = d3.zoomIdentity.translate(newTranslate[0], newTranslate[1]).scale(scale);
        zoom.transform(zoomContainer, targetTransform);
    }
}

d3.selectAll('button').on('click', handleButtonClick);
</script>
</body>
</html>

关键修正说明

  1. 分离容器:将zoom监听的容器和内容容器分开,确保变换只作用于内容元素
  2. 正确使用D3 v6 API:使用event.transform获取当前变换,通过zoom.transform()更新状态
  3. 完善平移逻辑:根据当前缩放比例调整平移步长,保证体验一致
  4. 修复语法错误:修正拼写、HTML标签和重复ID问题

内容的提问来源于stack exchange,提问作者B L Praveen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 02:17:21