D3.zoom以编程方式缩放后使用鼠标滚轮时会跳转 [英] D3.zoom jumps when using mouse wheel after programmatically zoom

查看:98
本文介绍了D3.zoom以编程方式缩放后使用鼠标滚轮时会跳转的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我通过单击鼠标放大到特定位置然后尝试平移时,或者当我使用鼠标滚轮时,缩放行为会跳跃.好像我的缩放级别正在恢复,就像单击鼠标之前一样.

When I zoom to a specific location on a mouse click and then try to pan or when I'm using the mouse wheel, the zoom behavior jumps. It seems that my zoom level is being restored like it was before the mouse click.

这是我的事件处理程序:

Here is my event handler:

function click(d) {
    var x, y, k;

    if (d && centered !== d) {
       var centroid = path.centroid(d);
       x = centroid[0];
       y = centroid[1];
       k = 4;
       centered = d;
     } else {
       x = width / 2;
       y = height / 2;
       k = 1;
       centered = null;
    }


    svgContainer.transition()
       .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(" + k + ")translate(" + -x + "," + -y + ")");
}

这就是我激活"缩放和平移功能的方式.

And this is how I "activate" my zoom and pan functionalities.

var svgContainer = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
    .call(d3.zoom().on("zoom", function () {
         svgContainer.attr("transform", d3.event.transform)
    }))
    .append("g")
    ...

svgContainer.selectAll(null)
    .data(feat.features)
    .enter()
    .append("path")
    .on("click", click)
     ...

推荐答案

背景

您正在操纵单击功能中应用于元素的变换,但没有更新缩放状态以反映这一点. d3.zoom完全不跟踪元素的变换.因此,当您独立于d3.zoom修改元素的变换属性时,d3.zoom不再知道"该元素的变换是什么-它保持不变. D3.zoom可以在内部且独立于任何元素的transform属性来跟踪缩放状态.

You are manipulating the transform applied to your elements in the click function but not updating the zoom state to reflect this. d3.zoom does not track an element's transform at all. So when you modify the transform attribute of an element independently of d3.zoom, d3.zoom no longer "knows" what the transform is of that element - it remains unchanged. D3.zoom does track zoom state - internally and independently of any element's transform attribute.

d3.zoom不能跟踪元素的变换似乎很奇怪,但是有充分的理由.并非总是使用d3.zoom来操纵元素的变换,它可能会更改元素宽度或比例之类的内容,而该元素的变换保持不变.这是我的 bl.ock ,其中d3.zoom在这里仅操纵圆的半径画布.

It might seem odd that d3.zoom doesn't track an element's transform, but there is good reason. d3.zoom isn't always used to manipulate the transform of an element, it may alter something like element width or a scale while that element's transform remains unchanged. Here's a bl.ock of mine where d3.zoom here manipulates only the radius of circles on canvas.

问题

由于您没有在click事件中更新缩放状态,因此d3.zoom会在应用新的缩放事件时选择其最后离开的位置,这说明了您的症状:看来我的缩放级别已恢复为原来的状态在鼠标单击之前."

As you don't update the zoom state in your click event, d3.zoom picks up where it was last left when applying a new zoom event, which explains your symptom: "It seems that my zoom level being restored like it was before the mouse click."

解决方案

那么,您需要做什么?您需要将缩放变换传递给d3.zoom并触发缩放事件.这样,将当前缩放状态通知给d3.zoom.幸运的是,有一种方法可以解决这个问题.我们采用d3.zoomIdentity(k = 1,x = 0,y = 0)并进行适当的翻译和缩放,我们也可以翻译,缩放然后再翻译:

So, what do you need to do? You need to pass your zoom transform to d3.zoom and trigger a zoom event. This way d3.zoom is apprised of the current zoom state. Luckily there is a method for this. We take a d3.zoomIdentity (k=1,x=0,y=0) and translate and scale as appropriate, we can translate, scale, and then translate again as you have done too:

   // Create a zoom transform from d3.zoomIdentity
   var transform = d3.zoomIdentity
    .translate(250,150)
    .scale(k)
    .translate(-x,-y);

然后我们根据文档调用zoom.transform来应用缩放

And then we apply the zoom by calling zoom.transform which according to the docs:

将所选元素的当前缩放变换设置为 指定的变换,立即发出开始,缩放和结束 事件.如果选择是过渡,则定义到之间的缩放"补间 使用d3.interpolateZoom指定的转换,发出开始事件 过渡开始时,针对 转换,然后是转换结束时的结束事件(或 中断). (链接)

sets the current zoom transform of the selected elements to the specified transform, instantaneously emitting start, zoom and end events. If selection is a transition, defines a "zoom" tween to the specified transform using d3.interpolateZoom, emitting a start event when the transition starts, zoom events for each tick of the transition, and then an end event when the transition ends (or is interrupted). (link)

我们可以使用以下命令调用zoom.transform:

We can call zoom.transform with:

   // Apply the zoom and trigger a zoom event with a provided zoom transform:
   svg.call(zoom.transform, transform);

因此,如果这与您拥有的内容无关:

So if this is analagous to what you have:

var zoom = d3.zoom()
  .scaleExtent([1,8])
  .translateExtent([[0,0],[500,300]])
  .on("zoom",zoomed);

var svg = d3.select("div")
  .append("svg")
  .attr("width",500)
  .attr("height",300)
  .call(zoom);
  
var g = svg.append("g");
  
var rects = g.selectAll(null)
  .data(d3.range(750))
  .enter()
  .append("rect")
  .attr("width",17)
  .attr("height",17)
  .attr("fill","#eee")
  .attr("y", function(d) { return Math.floor(d/50) * 20; })
  .attr("x", function(d) { return d%50 * 20; })
  .on("click", click);

function zoomed() {
  g.attr("transform", d3.event.transform);
}

function click(d) {
   rects.attr("fill","#eee");  
   
   var clicked = d3.select(this);
   clicked.attr("fill","orange");
   
   var x = +clicked.attr("x")+10;
   var y = +clicked.attr("y")+10;
   var k = 5;
   
   var transform = "translate(" + 250 + "," + 150 + ")scale(" + k + ")translate(" + -x + "," + -y + ")";
   
   g.transition()
     .attr("transform",transform)
     .duration(1000);
}

rect {
  stroke-width: 1px;
  stroke: #ccc;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div>

这可能与您的解决方案类似:

This can be analagous to your solution:

var zoom = d3.zoom()
  .scaleExtent([1,8])
  .translateExtent([[0,0],[500,300]])
  .on("zoom",zoomed);

var svg = d3.select("div")
  .append("svg")
  .attr("width",500)
  .attr("height",300)
  .call(zoom);
  
var g = svg.append("g");
  
var rects = g.selectAll(null)
  .data(d3.range(750))
  .enter()
  .append("rect")
  .attr("width",17)
  .attr("height",17)
  .attr("fill","#eee")
  .attr("y", function(d) { return Math.floor(d/50) * 20; })
  .attr("x", function(d) { return d%50 * 20; })
  .on("click", click);

function zoomed() {
  g.attr("transform", d3.event.transform);
}

function click(d) {
   rects.attr("fill","#eee");  
   
   var clicked = d3.select(this);
   clicked.attr("fill","orange");
   
   var x = +clicked.attr("x")+10;
   var y = +clicked.attr("y")+10;
   var k = 5;

   // Create a zoom transform from d3.zoomIdentity
   var transform = d3.zoomIdentity
    .translate(250,150)
    .scale(k)
    .translate(-x,-y);
   
   // Apply the zoom and trigger a zoom event:
   svg.call(zoom.transform, transform);

}

rect {
  stroke-width: 1px;
  stroke: #ccc;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div>

这篇关于D3.zoom以编程方式缩放后使用鼠标滚轮时会跳转的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆