在此d3.drag示例中,保留本地偏移量是什么? [英] What's preserving local offset in this d3.drag example?

查看:68
本文介绍了在此d3.drag示例中,保留本地偏移量是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

会阻止圆的中心捕捉到鼠标?

When dragging any circle in this d3 example, what prevents the circle's center from snapping to the mouse?

换句话说:当您通过单击圆的外部边缘附近的某个地方 来启动圆拖动时,代码中的内容将保留拖动开始时隐含的偏移(相对于圆的中心) ?

In other words: when you initiate a circle drag by clicking somewhere near the outer edges of the circle, what in the code preserves the offset (relative to the circle's center) that's implied at drag start?

我看到了这些.attr()呼叫:

.attr("cx", d.x = d3.event.x)
.attr("cy", d.y = d3.event.y)

但是我希望d3.event.x(和.y)是鼠标的坐标-不考虑偏移量-因此,我认为圆的中心(从UX的角度来看是不正确的) )最终在鼠标下方.

But I expect d3.event.x (and .y) to be the coordinates of the mouse — without accounting for the offset — and therefore I would think that the circle's center would (incorrectly, from a UX point-of-view) end up right under the mouse.

推荐答案

我相信d3拖动主题方法会发生这种情况:

I believe this happens with the d3 drag subject method:

如果指定了主题,则将主题访问器设置为指定的 对象或函数并返回拖动行为.如果主题不是 指定,返回当前的主题访问器,默认为:

If subject is specified, sets the subject accessor to the specified object or function and returns the drag behavior. If subject is not specified, returns the current subject accessor, which defaults to:

function subject(d) { return d == null ? {x: d3.event.x, y: d3.event.y} : d; }

function subject(d) { return d == null ? {x: d3.event.x, y: d3.event.y} : d; }

拖动手势的主题表示被拖动的物体.它 是在收到启动输入事件(例如 在拖动手势开始前立即按下鼠标或触摸开始. 然后将主题公开为event.subject在后续拖动事件中 对于这个手势. (链接)

The subject of a drag gesture represents the thing being dragged. It is computed when an initiating input event is received, such as a mousedown or touchstart, immediately before the drag gesture starts. The subject is then exposed as event.subject on subsequent drag events for this gesture. (link)

我们可以看到,如果我们不提供主题函数,也不提供具有x和y属性的基准,那么拖动事件将导致圆的居中/捕捉到拖动起点:

We can see that if we don't provide a subject function and we also don't provide a datum with x and y properties, then the drag events will result in a circle's centering/snapping to the drag start point:

var svg = d3.select("body")
  .append("svg")
  .attr("width",500)
  .attr("height",300);
  
var datum = {x:250,y:150}
  
var g = svg.append("g")
    
  g.append("rect")
  .attr("width",500)
  .attr("height",300)
  .attr("fill","#ddd");
  
  g.append("circle")
  .datum(datum)
  .attr("cx",function(d) { return d.x; })
  .attr("cy",function(d) { return d.y; })
  .attr("r",10);
    
g.call(d3.drag().on("drag", dragged))
  
function dragged(d) {
  d3.select(this)
    .select("circle")
    .attr("cx", d3.event.x)
    .attr("cy", d3.event.y);
}

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

以相同的示例为例,然后将数据分配给父级g元素,则拖动将可以访问主题的x和y属性(在上面的示例中不存在).在此,拖动相对于初始基准(保持不变),并且将使用在基准中指定的初始x和y属性作为每次拖动的起点来重新定心节点(拖动一次以上即可看到):

Taking the same example, and moving assigning the datum to the parent g element allows the drag to access the subject's x and y properties (which were not present in the above example). Here the drag is relative to the initial datum (which remains unmodified), and the node will be re-centered usingn the initial x and y properties specified in the datum as the starting point for each drag (drag more than once to see):

var svg = d3.select("body")
  .append("svg")
  .attr("width",500)
  .attr("height",300);
  
var datum = {x:250,y:150}
  
var g = svg.append("g")
  .datum(datum);
  
  g.append("rect")
  .attr("width",500)
  .attr("height",300)
  .attr("fill","#ddd");
  
  g.append("circle")
  .attr("cx",function(d) { return d.x; })
  .attr("cy",function(d) { return d.y; })
  .attr("r",10);
    
g.call(d3.drag().on("drag", dragged))
  
function dragged(d) {
  d3.select(this)
    .select("circle")
    .attr("cx", d3.event.x)
    .attr("cy", d3.event.y);
}

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

然后我们可以更新主题的基准,这使每个拖动事件都相对于圆的当前位置而不是初始位置:

Then we can update the datum of the subject, which makes each drag event relative to the circle's current position rather than the initial position:

var svg = d3.select("body")
  .append("svg")
  .attr("width",500)
  .attr("height",300);
  
var datum = {x:250,y:150}
  
var g = svg.append("g")
  .datum(datum);
  
  g.append("rect")
  .attr("width",500)
  .attr("height",300)
  .attr("fill","#ddd");
  
  g.append("circle")
  .attr("cx",function(d) { return d.x; })
  .attr("cy",function(d) { return d.y; })
  .attr("r",10);
    
g.call(d3.drag().on("drag", dragged))
  
function dragged(d) {
  d3.select(this)
    .select("circle")
    .attr("cx", d.x = d3.event.x)
    .attr("cy", d.y = d3.event.y);
}

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

稍微研究一下拖动代码,我们可以看到,开始拖动时,如果没有为主题方法提供任何功能,则可以计算出x,y start和主题x,y之间的差值:

Diving into the drag code a little bit we can see that when a drag is started and if no function has been provided to the subject method, the difference between the drag x,y start and the subject x,y is calculated:

  dx = s.x - p[0] || 0;
  dy = s.y - p[1] || 0;

其中p是鼠标的起始位置. s是主题.

Where p is the starting mouse position. And s is the subject.

这将解释为什么不提供x或y属性时,圆会捕捉到拖动开始的位置.在计算输出时,d3将x和y值设置为:

Which explains why when no x or y attributes are provided, the circle snaps to wherever the drag began. When calculating the output, d3 sets the x and y values as:

p[0] + dx,
p[1] + dy

其中p是当前鼠标位置.

where p is the current mouse position.

因此d3.event.x/.y不应是鼠标的绝对位置,而应是拖动指定的位置发生相对变化时圆的绝对位置.正是通过这个主题,鼠标位置的相对变化才被转换为要拖动的项目的绝对位置.

So d3.event.x/.y should not be the absolute position of the mouse, but rather the absolute position of the circle given a relative change in position specified by the drag. It is through the subject that the relative change in mouse position is translated into an absolute position for the item being dragged.

这是一个带有自定义主题的示例,其中拖动将相对于[100,100],并且圆圈将在每次拖动事件开始时捕捉到该位置:

Here's an example with a custom subject, where the drag will be relative to [100,100] and the circle will snap there at the beginning of each drag event:

var svg = d3.select("body")
  .append("svg")
  .attr("width",500)
  .attr("height",300);
  
var datum = {x:250,y:150}
  
var g = svg.append("g")
  .datum(datum);
  
  g.append("rect")
  .attr("width",500)
  .attr("height",300)
  .attr("fill","#ddd");
  
  g.append("circle")
  .attr("cx",function(d) { return d.x; })
  .attr("cy",function(d) { return d.y; })
  .attr("r",10);
    
g.call(d3.drag()
   .on("drag", dragged)
   .subject({x:100,y:100})
   )
  
function dragged(d) {
  d3.select(this)
    .select("circle")
    .attr("cx", d3.event.x)
    .attr("cy", d3.event.y);
}

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

这篇关于在此d3.drag示例中,保留本地偏移量是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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