我正在尝试让鼠标事件在散点图中的不同元素之间进行协作。 D3的 this.Configuration.LazyLoadingEnabled = false;
组件为被调用元素添加了一些侦听器(例如brush
)。我还希望显示绑定在SVG上的点,就像散点图一样,以及那些支持svg.call(brush)
事件的点(用于工具提示和其他交互)。
A previous solution建议在调用画笔之前绘制点,它支持在点上鼠标悬停,同时允许绘制画笔并修改范围。但是,如果画笔的拖动动作开始于一个点(我预计在非常密集的图形中),当画笔组件已经处于活动状态时(画笔的大小调整大小),画笔组件会出现异常。您可以在this example上进行试用,其中已实施上述建议的解决方案。
我已将问题范围缩小到如何在mouseover
组件内部的d3的brushstart()
函数中处理事件。这是刷子正确工作时相关变量的样子。
d3.svg.brush
这是目前的情况,使用上述解决方案:
this eventTarget dragging resizing
-------------- ------------------------------------- ---------- ----------
Translating extent brush parent rect.extent true 0
Resizing extent brush parent rect (invisible rects for resizing) false e.g. "e"
Redrawing brush parent rect.background false 0
真正的问题是:我如何捏造d3.event.target的来源以匹配第一个表?如果我能做到这一点,我就可以得到我想要的行为。谢谢你的帮助!
如果你错过了,这就是这个难题的重点:http://bl.ocks.org/yelper/d38ddf461a0175ebd927946d15140947
答案 0 :(得分:3)
这是一个快速破解纠正行为的行为:
.on('mousedown', function(d){
var e = brush.extent(),
m = d3.mouse(svg.node()), // pointer position with respect to g
p = [x.invert(m[0]), y.invert(m[1])]; // position in user space
if ( brush.empty() || // if there is no brush
(e[0][0] > d[0] || d[0] > e[1][0]
|| e[0][1] > d[1] || d[1] > e[1][1] ) // or our current circle is outside the bounds of the brush
) {
brush.extent([p,p]); // set brush to current position
} else {
d3.select(this).classed('extent', true); // else we are moving the brush, so fool d3 (I got this from looking at source code, it's how d3 determines a drag)
}
});
下面的工作代码,更新了阻止here。
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.hidden {
opacity: 0.3;
}
.extent {
fill: #000;
fill-opacity: .125;
stroke: #fff;
}
</style>
<body>
<script src="//d3js.org/d3.v3.js"></script>
<script>
var margin = {top: 20, right: 50, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 350 - margin.top - margin.bottom;
var x = d3.scale.linear()
.range([0, width])
.domain([0, 10]);
var y = d3.scale.linear()
.range([height, 0])
.domain([0, 10]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var curPt = d3.select('body')
.append('p')
.html("Current point: ")
.append('span')
.attr('id', 'curPt');
var svg = d3.select('body').insert('svg', 'p')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,'+height+')')
.call(xAxis);
svg.append('g')
.attr('class', 'y axis')
.call(yAxis);
var brush = d3.svg.brush()
.x(x)
.y(y)
.on("brush", function() {
var e = brush.extent(),
c = svg.selectAll('circle');
c.classed('extent', false);
c.classed('hidden', function(d) {
return e[0][0] > d[0] || d[0] > e[1][0]
|| e[0][1] > d[1] || d[1] > e[1][1];
}
);
})
.on("brushend", function() {
if (brush.empty()) svg.selectAll('circle').classed('hidden', false);
});
svg.call(brush);
var data = d3.range(50).map(function() { return [Math.random() * 10, Math.random() * 10]; });
svg.append('g')
.attr('class', 'points')
.selectAll('circle')
.data(data).enter()
.append('circle')
.attr('cx', function(d) { return x(d[0]); })
.attr('cy', function(d) { return y(d[1]); })
.attr('r', 10)
.style('fill', 'steelblue')
.on('mouseover', function(d) {
curPt.html("[" + d[0] + ", " + d[1] + "]");
})
.on('mouseout', function(d) {
curPt.html("");
})
.on('mousedown', function(d){
var e = brush.extent(),
m = d3.mouse(svg.node()),
p = [x.invert(m[0]), y.invert(m[1])];
if ( brush.empty() ||
(e[0][0] > d[0] || d[0] > e[1][0]
|| e[0][1] > d[1] || d[1] > e[1][1] )
) {
brush.extent([p,p]);
} else {
d3.select(this).classed('extent', true);
}
});
</script>
&#13;
答案 1 :(得分:0)
以下是工作示例: https://jsfiddle.net/paradite/rpqusqdc/2/
基本上,我使用drag
事件而不是brush
使用我之前编码的范围选择工具:http://bl.ocks.org/paradite/71869a0f30592ade5246
它不会干扰您的圈子。因此,您只需获取当前的rect
维度并相应地更新您的圈子:
// select your points here
var e = selectionRect.getCurrentAttributes();
svg.selectAll('circle').classed('hidden', function(d) {
return e.x1 > x(d[0]) || x(d[0]) > e.x2 || e.y1 > y(d[1]) || y(d[1]) > e.y2;
});
当然,你可以删除部分逻辑,因为你的情况不需要它。