gpt4 book ai didi

d3.js - 在这个 d3.drag 示例中保留本地偏移量是什么?

转载 作者:行者123 更新时间:2023-12-01 11:17:15 25 4
gpt4 key购买 nike

this d3 example 中拖动任何圆圈时,什么阻止圆的中心捕捉到鼠标?

换句话说:当您通过单击圆外边缘附近的某处来启动圆拖动时,代码中的什么保留了拖动开始时隐含的偏移量(相对于圆的中心)?

我看到这些 .attr()调用:

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

但我希望 d3.event.x (和 .y )是鼠标的坐标 - 不考虑偏移 - 因此我认为圆的中心会(错误地,从用户体验的角度来看)在鼠标正下方结束。

最佳答案

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

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; }

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 属性的数据,那么拖动事件将导致圆居中/捕捉到拖动起点:

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 属性作为每次拖动的起点(多次拖动以查看)重新居中:

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>


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

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 之间的差异:
  dx = s.x - p[0] || 0;
dy = s.y - p[1] || 0;

其中 p 是鼠标的起始位置。 s 是主语。

这就解释了为什么当没有提供 x 或 y 属性时,圆圈会捕捉到拖动开始的地方。在计算输出时,d3 将 x 和 y 值设置为:
p[0] + dx,
p[1] + dy

其中 p 是当前鼠标位置。

所以 d3.event.x/.y 不应该是鼠标的绝对位置,而是给定拖动指定位置的相对变化的圆的绝对位置。正是通过主题,鼠标位置的相对变化被转换为被拖动项目的绝对位置。

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

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.js - 在这个 d3.drag 示例中保留本地偏移量是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49179662/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com