将鼠标单击处理程序分配给具有捕捉行为的 d3 中的行
Assign mouse click handler to line in d3 with snapping behaviour
我有一条只有一个像素宽的 d3 线。我想要一个点击
分配给这条线的处理程序。但是,在尝试 select 时,很难准确地排在最前面。是否有某些 "selection corridor" 功能可以让您改为指定 "distance to line"。 IE。如果鼠标指针距离线最大 8pt 的距离并且单击鼠标,则会触发 click 事件?
您可以攻击 svg/group 元素上的点击事件,并检查鼠标位置与路径上最近点的距离是否小于某个固定值,例如4. 可以使用Closest Point on Path example.
中的函数计算距离
点击事件:
var path = svg.append('path').datum(data).attr("d", line);
svg.on('click', function() {
var m = d3.mouse(this),
p = closestPoint(path.node(), m);
if (p.distance < 4) {
/* make action */
console.log('click', p.distance)
}
})
closestPoint()
取自上面的例子。
中的解决方案是一个很好的解决方案,也是一个有趣的解决方案。
不过,我更喜欢"traditional"的解决方案,就是画另一条线,比可见的细线透明且粗,只是为了捕捉点击事件。我更喜欢这个 "traditional" 解决方案(D3 编码器中最常见的解决方案)的原因是用户体验:让用户知道 she/he 可以单击该行是个好主意。
因此,在可见的细线上使用较粗的透明线的优点是您可以将光标设置为手...
.attr("cursor", "pointer")
...当用户将鼠标悬停在透明线上时。
这是一个简单的演示:
var svg = d3.select("svg");
var data = d3.range(30).map(function(d) {
return {
x: d * 10,
y: Math.random() * 150
}
});
var lineGenerator = d3.line()
.x(function(d) {
return d.x
})
.y(function(d) {
return d.y
});
var realLine = svg.append("path")
.attr("stroke", "teal")
.attr("fill", "none")
.attr("stroke-width", 1)
.attr("d", lineGenerator(data));
var transparentLine = svg.append("path")
.attr("stroke", "teal")
.attr("fill", "none")
.attr("stroke-width", 12)
.attr("opacity", 0)
.attr("cursor", "pointer")
.attr("d", lineGenerator(data));
transparentLine.on("click", function() {
console.log("clicked")
})
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
当然,这个 "traditional" 解决方案只有在该图表上有一条或几条线时才有意义。如果你有几十行或几百行,那将是一团糟。
我有一条只有一个像素宽的 d3 线。我想要一个点击 分配给这条线的处理程序。但是,在尝试 select 时,很难准确地排在最前面。是否有某些 "selection corridor" 功能可以让您改为指定 "distance to line"。 IE。如果鼠标指针距离线最大 8pt 的距离并且单击鼠标,则会触发 click 事件?
您可以攻击 svg/group 元素上的点击事件,并检查鼠标位置与路径上最近点的距离是否小于某个固定值,例如4. 可以使用Closest Point on Path example.
中的函数计算距离点击事件:
var path = svg.append('path').datum(data).attr("d", line);
svg.on('click', function() {
var m = d3.mouse(this),
p = closestPoint(path.node(), m);
if (p.distance < 4) {
/* make action */
console.log('click', p.distance)
}
})
closestPoint()
取自上面的例子。
不过,我更喜欢"traditional"的解决方案,就是画另一条线,比可见的细线透明且粗,只是为了捕捉点击事件。我更喜欢这个 "traditional" 解决方案(D3 编码器中最常见的解决方案)的原因是用户体验:让用户知道 she/he 可以单击该行是个好主意。
因此,在可见的细线上使用较粗的透明线的优点是您可以将光标设置为手...
.attr("cursor", "pointer")
...当用户将鼠标悬停在透明线上时。
这是一个简单的演示:
var svg = d3.select("svg");
var data = d3.range(30).map(function(d) {
return {
x: d * 10,
y: Math.random() * 150
}
});
var lineGenerator = d3.line()
.x(function(d) {
return d.x
})
.y(function(d) {
return d.y
});
var realLine = svg.append("path")
.attr("stroke", "teal")
.attr("fill", "none")
.attr("stroke-width", 1)
.attr("d", lineGenerator(data));
var transparentLine = svg.append("path")
.attr("stroke", "teal")
.attr("fill", "none")
.attr("stroke-width", 12)
.attr("opacity", 0)
.attr("cursor", "pointer")
.attr("d", lineGenerator(data));
transparentLine.on("click", function() {
console.log("clicked")
})
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
当然,这个 "traditional" 解决方案只有在该图表上有一条或几条线时才有意义。如果你有几十行或几百行,那将是一团糟。