如何正确使用d3.js拖动?
How to use d3.js drag properly?
我正在使用 d3.js 和 Vue js 创建平面图。我想添加一个功能,用户单击一个按钮创建一个矩形(门口),用户可以更改比例和 X、Y 位置。我对 vue js 和 d3.js 很陌生,所以我使用 this 作为参考。该按钮起作用并为 X 次按下添加 X 次矩形。但是,当我添加第一个门口并尝试拖动矩形时,它完全偏离了用户的鼠标坐标。此外,当我添加第二个、第三个、第四个等矩形时,我无法更改它们的位置,只能更改第一个矩形。我认为这是因为我在拖动功能中只选择了一个矩形。但是,我更关心如何在矩形上正确拖动。有人能给我指出正确的方向吗?
<template>
<div id = "app">
<header>
<Navbar />
</header>
<div class = "floor">
<div id = "tooltip"></div>
<svg width = "850" height = "800">
</svg>
</div>
<div class = "buttons">
<button v-on:click="addRec()"> Add Doorway </button>
</div>
</div>
</template>
addRec(){
console.log("Doorway Added")
var doorGroup = d3.selectAll("svg")
.append("g")
//setting attributes for doorway
var doorway = doorGroup.append("rect")
.attr("width",100)
.attr("height", 25)
.attr("x", 150)
.attr("y", 200)
//setting style attributes for doorway
.attr("fill","#F5F5F5")
.attr("stroke", "black")
.attr("stroke-width", 2.5)
.attr("cursor", "move")
//binding drag method onto rectangle
.call(d3.drag()
.on('start', dragStart)
.on('drag', dragging)
.on('end', dragEnd)
)
},
//this is to be called once used has clicked on the doorway
dragStart(d,i,nodes){
d3.select(nodes[i])
.style("stroke", "red")
},
/*
this is to be called once used has started dragging the doorway
dragging(d) upadtes the position of the doorway, from the mouse X,Y Coors
*/
dragging(d,i,nodes){
var width = 850
var height = 800
var xCoor = d3.pointer(event)[0]
var yCoor = d3.pointer(event)[1]
// d3.select(nodes[i])
// .attr("transform", "translate(" + (xCoor - 200) + "," + (yCoor - 300) + ")")
d3.select(nodes[i])
.attr("x", xCoor)
.attr("y", yCoor)
},
//this is to be called once user has clicked off the doorway
dragEnd(d,i,nodes){
d3.select(nodes[i])
.style("stroke", "black")
},
您的代码中有两个问题:
- 你只能select同一个矩形:
你所有的拖动函数都使用:
d3.select("rect")
这将 select 第一个匹配元素 DOM。这将始终是相同的矩形,它与被拖动的矩形不对应。相反,您可以通过以下方式访问正确的矩形:
function dragFunction() {
d3.select(this);
}
在 d3v5 及更早版本中,如果 this
不可用,您可以使用:
dragFunction(d,i,nodes) => d3.select(nodes[i])
如果您在 d3v6 中无法访问 this
,则没有获取矩形的好方法 - migration guide 显示了一种“旧”获取方式this
涉及为基准匹配过滤元素。我从未见过 d3v5 或更早版本中使用的方法,如果 this
不可用,d3.select(nodes[i])
总是回退。因此,理想情况下,您可以访问 this
- 不要对侦听器使用箭头函数
- 您通过 x,y 应用变换和定位。
最初附加您按 x,y 定位的矩形时。拖动时应用平移,但不要删除初始的 x,y 定位。这导致 x,y 坐标被应用两次,一次使用它们的原始值,一次使用它们相对于原点(而不是它们的起始位置)的拖动值。您应该为初始放置和拖动修改相同的 属性 - x、y 属性或变换,但不要将两者都用于放置。
D3v5
除了使用 d3.event.x 和 d3.event.y(d3.pointer 已添加到 d3v6 中),我还进行了上述更改,相信我已经创建了下面的预期效果。
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 300);
d3.select("button")
.on("click", function() {
svg.append("rect")
.attr("width",10)
.attr("height", 25)
.attr("x", 150)
.attr("y", 100)
.attr("fill","#1b1c3b")
.attr("opacity", ".5")
.attr("stroke", "black")
.attr("stroke-width", "2")
.attr("cursor", "move")
.call(d3.drag()
.on('start', dragStart)
.on('drag', dragging)
.on('end', dragEnd)
)
function dragStart(d,i,nodes){
d3.select(nodes[i])
.style("stroke", "red")
}
function dragging(d,i,nodes){
var xCoor = d3.event.x;
var yCoor = d3.event.y;
d3.select(nodes[i])
.attr("x", xCoor)
.attr("y", yCoor);
}
function dragEnd(d,i,nodes){
d3.select(nodes[i])
.style("stroke", "black")
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<button>Add Rect</button>
D3v6
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 300);
d3.select("button")
.on("click", function() {
svg.append("rect")
.attr("width",10)
.attr("height", 25)
.attr("x", 150)
.attr("y", 100)
.attr("fill","#1b1c3b")
.attr("opacity", ".5")
.attr("stroke", "black")
.attr("stroke-width", "2")
.attr("cursor", "move")
.call(d3.drag()
.on('start', dragStart)
.on('drag', dragging)
.on('end', dragEnd)
)
function dragStart(event,d){
d3.select(this)
.style("stroke", "")
}
function dragging(event,d){
var xCoor = event.x;
var yCoor = event.y;
d3.select(this)
.attr("x", xCoor)
.attr("y", yCoor);
}
function dragEnd(event,d){
d3.select(this)
.style("stroke", "black")
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.1.0/d3.min.js"></script>
<button>Add Rect</button>
我正在使用 d3.js 和 Vue js 创建平面图。我想添加一个功能,用户单击一个按钮创建一个矩形(门口),用户可以更改比例和 X、Y 位置。我对 vue js 和 d3.js 很陌生,所以我使用 this 作为参考。该按钮起作用并为 X 次按下添加 X 次矩形。但是,当我添加第一个门口并尝试拖动矩形时,它完全偏离了用户的鼠标坐标。此外,当我添加第二个、第三个、第四个等矩形时,我无法更改它们的位置,只能更改第一个矩形。我认为这是因为我在拖动功能中只选择了一个矩形。但是,我更关心如何在矩形上正确拖动。有人能给我指出正确的方向吗?
<template>
<div id = "app">
<header>
<Navbar />
</header>
<div class = "floor">
<div id = "tooltip"></div>
<svg width = "850" height = "800">
</svg>
</div>
<div class = "buttons">
<button v-on:click="addRec()"> Add Doorway </button>
</div>
</div>
</template>
addRec(){
console.log("Doorway Added")
var doorGroup = d3.selectAll("svg")
.append("g")
//setting attributes for doorway
var doorway = doorGroup.append("rect")
.attr("width",100)
.attr("height", 25)
.attr("x", 150)
.attr("y", 200)
//setting style attributes for doorway
.attr("fill","#F5F5F5")
.attr("stroke", "black")
.attr("stroke-width", 2.5)
.attr("cursor", "move")
//binding drag method onto rectangle
.call(d3.drag()
.on('start', dragStart)
.on('drag', dragging)
.on('end', dragEnd)
)
},
//this is to be called once used has clicked on the doorway
dragStart(d,i,nodes){
d3.select(nodes[i])
.style("stroke", "red")
},
/*
this is to be called once used has started dragging the doorway
dragging(d) upadtes the position of the doorway, from the mouse X,Y Coors
*/
dragging(d,i,nodes){
var width = 850
var height = 800
var xCoor = d3.pointer(event)[0]
var yCoor = d3.pointer(event)[1]
// d3.select(nodes[i])
// .attr("transform", "translate(" + (xCoor - 200) + "," + (yCoor - 300) + ")")
d3.select(nodes[i])
.attr("x", xCoor)
.attr("y", yCoor)
},
//this is to be called once user has clicked off the doorway
dragEnd(d,i,nodes){
d3.select(nodes[i])
.style("stroke", "black")
},
您的代码中有两个问题:
- 你只能select同一个矩形:
你所有的拖动函数都使用:
d3.select("rect")
这将 select 第一个匹配元素 DOM。这将始终是相同的矩形,它与被拖动的矩形不对应。相反,您可以通过以下方式访问正确的矩形:
function dragFunction() {
d3.select(this);
}
在 d3v5 及更早版本中,如果 this
不可用,您可以使用:
dragFunction(d,i,nodes) => d3.select(nodes[i])
如果您在 d3v6 中无法访问 this
,则没有获取矩形的好方法 - migration guide 显示了一种“旧”获取方式this
涉及为基准匹配过滤元素。我从未见过 d3v5 或更早版本中使用的方法,如果 this
不可用,d3.select(nodes[i])
总是回退。因此,理想情况下,您可以访问 this
- 不要对侦听器使用箭头函数
- 您通过 x,y 应用变换和定位。
最初附加您按 x,y 定位的矩形时。拖动时应用平移,但不要删除初始的 x,y 定位。这导致 x,y 坐标被应用两次,一次使用它们的原始值,一次使用它们相对于原点(而不是它们的起始位置)的拖动值。您应该为初始放置和拖动修改相同的 属性 - x、y 属性或变换,但不要将两者都用于放置。
D3v5
除了使用 d3.event.x 和 d3.event.y(d3.pointer 已添加到 d3v6 中),我还进行了上述更改,相信我已经创建了下面的预期效果。
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 300);
d3.select("button")
.on("click", function() {
svg.append("rect")
.attr("width",10)
.attr("height", 25)
.attr("x", 150)
.attr("y", 100)
.attr("fill","#1b1c3b")
.attr("opacity", ".5")
.attr("stroke", "black")
.attr("stroke-width", "2")
.attr("cursor", "move")
.call(d3.drag()
.on('start', dragStart)
.on('drag', dragging)
.on('end', dragEnd)
)
function dragStart(d,i,nodes){
d3.select(nodes[i])
.style("stroke", "red")
}
function dragging(d,i,nodes){
var xCoor = d3.event.x;
var yCoor = d3.event.y;
d3.select(nodes[i])
.attr("x", xCoor)
.attr("y", yCoor);
}
function dragEnd(d,i,nodes){
d3.select(nodes[i])
.style("stroke", "black")
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<button>Add Rect</button>
D3v6
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 300);
d3.select("button")
.on("click", function() {
svg.append("rect")
.attr("width",10)
.attr("height", 25)
.attr("x", 150)
.attr("y", 100)
.attr("fill","#1b1c3b")
.attr("opacity", ".5")
.attr("stroke", "black")
.attr("stroke-width", "2")
.attr("cursor", "move")
.call(d3.drag()
.on('start', dragStart)
.on('drag', dragging)
.on('end', dragEnd)
)
function dragStart(event,d){
d3.select(this)
.style("stroke", "")
}
function dragging(event,d){
var xCoor = event.x;
var yCoor = event.y;
d3.select(this)
.attr("x", xCoor)
.attr("y", yCoor);
}
function dragEnd(event,d){
d3.select(this)
.style("stroke", "black")
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.1.0/d3.min.js"></script>
<button>Add Rect</button>