为什么d3.event在拖动回调中与数据坐标有某种关系
Why d3.event in dragging callback is somehow related to data coordinate
我正在玩 d3.js,我注意到拖动时有一种奇怪的行为。
如果我使用数据和 scaleX/scaleY 添加一个圆,当我拖动它时 d3.event.y 值是相对于 "data" 数组内的 xy 坐标,而不是左上角...
这是代码和一个jsFiddle:如果你打开控制台,如果你拖动第一个圆圈,参考是左上角,如果你拖动第二个圆圈,参考是与{相关的东西x: 3, y: 2}
var circle2 = svgGraph
.selectAll('.circle2')
.data([{ x: 3, y: 2 }])
.enter()
.append('circle') // Uses the enter().append() method
.attr('cx', scaleX(100))
.attr('cy', scaleY(100))
.attr('r', 15)
.call(d3.drag()
.on('start', (d) => { })
.on('drag', onHandlerDrag())
.on('end', (d) => { }));
function onHandlerDrag() {
return (d) => {
console.log(d3.event.y);
}
}
该行为是故意的吗?你对此有任何参考吗?
谢谢
是的,这是预期的行为。事实上,我们通常在拖动事件中使用 x
和 y
属性来避免元素 在容器周围跳跃 (当一个人懒得指定正确的主题)。
既然你要求参考,看看drag.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 default subject is the datum of the element in the originating selection (see drag) that received the initiating input event; if this datum is undefined, an object representing the coordinates of the pointer is created. When dragging circle elements in SVG, the default subject is thus the datum of the circle being dragged. (emphasis mine)
最后:
The returned subject should be an object that exposes x
and y
properties, so that the relative position of the subject and the pointer can be preserved during the drag gesture.
因此,如果您不希望 drag
使用数据中的 x
和 y
,只需在主题中设置不同的对象即可:
.subject(function() {
return {
foo: d3.event.x,
bar: d3.event.y
};
})
这里是你的代码有那个变化:
function onHandlerDrag() {
return (d) => {
console.log(d3.event.y);
}
}
var scaleX = d3
.scaleLinear()
.domain([0, 500])
.range([0, 500]);
var scaleY = d3
.scaleLinear()
.domain([0, 500])
.range([0, 500]);
var svgGraph = d3
.select('.area')
.attr('width', 500)
.attr('height', 500);
var circle1 = svgGraph
.append('circle')
.attr('cx', scaleX(20))
.attr('cy', scaleY(20))
.attr('r', 15)
.call(d3.drag()
.on('start', (d) => {})
.on('drag', onHandlerDrag())
.on('end', (d) => {}));
var circle2 = svgGraph
.selectAll('.circle2')
.data([{
x: 3,
y: 2
}])
.enter()
.append('circle') // Uses the enter().append() method
.attr('cx', scaleX(100))
.attr('cy', scaleY(100))
.attr('r', 15)
.call(d3.drag()
.subject(function() {
return {
foo: d3.event.x,
bar: d3.event.y
};
})
.on('start', (d) => {})
.on('drag', onHandlerDrag())
.on('end', (d) => {}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg class='area'></svg>
我正在玩 d3.js,我注意到拖动时有一种奇怪的行为。 如果我使用数据和 scaleX/scaleY 添加一个圆,当我拖动它时 d3.event.y 值是相对于 "data" 数组内的 xy 坐标,而不是左上角...
这是代码和一个jsFiddle:如果你打开控制台,如果你拖动第一个圆圈,参考是左上角,如果你拖动第二个圆圈,参考是与{相关的东西x: 3, y: 2}
var circle2 = svgGraph
.selectAll('.circle2')
.data([{ x: 3, y: 2 }])
.enter()
.append('circle') // Uses the enter().append() method
.attr('cx', scaleX(100))
.attr('cy', scaleY(100))
.attr('r', 15)
.call(d3.drag()
.on('start', (d) => { })
.on('drag', onHandlerDrag())
.on('end', (d) => { }));
function onHandlerDrag() {
return (d) => {
console.log(d3.event.y);
}
}
该行为是故意的吗?你对此有任何参考吗?
谢谢
是的,这是预期的行为。事实上,我们通常在拖动事件中使用 x
和 y
属性来避免元素 在容器周围跳跃 (当一个人懒得指定正确的主题)。
既然你要求参考,看看drag.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 default subject is the datum of the element in the originating selection (see drag) that received the initiating input event; if this datum is undefined, an object representing the coordinates of the pointer is created. When dragging circle elements in SVG, the default subject is thus the datum of the circle being dragged. (emphasis mine)
最后:
The returned subject should be an object that exposes
x
andy
properties, so that the relative position of the subject and the pointer can be preserved during the drag gesture.
因此,如果您不希望 drag
使用数据中的 x
和 y
,只需在主题中设置不同的对象即可:
.subject(function() {
return {
foo: d3.event.x,
bar: d3.event.y
};
})
这里是你的代码有那个变化:
function onHandlerDrag() {
return (d) => {
console.log(d3.event.y);
}
}
var scaleX = d3
.scaleLinear()
.domain([0, 500])
.range([0, 500]);
var scaleY = d3
.scaleLinear()
.domain([0, 500])
.range([0, 500]);
var svgGraph = d3
.select('.area')
.attr('width', 500)
.attr('height', 500);
var circle1 = svgGraph
.append('circle')
.attr('cx', scaleX(20))
.attr('cy', scaleY(20))
.attr('r', 15)
.call(d3.drag()
.on('start', (d) => {})
.on('drag', onHandlerDrag())
.on('end', (d) => {}));
var circle2 = svgGraph
.selectAll('.circle2')
.data([{
x: 3,
y: 2
}])
.enter()
.append('circle') // Uses the enter().append() method
.attr('cx', scaleX(100))
.attr('cy', scaleY(100))
.attr('r', 15)
.call(d3.drag()
.subject(function() {
return {
foo: d3.event.x,
bar: d3.event.y
};
})
.on('start', (d) => {})
.on('drag', onHandlerDrag())
.on('end', (d) => {}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg class='area'></svg>