在两个不同的图层上使用d3进行缩放和鼠标悬停/鼠标移除事件之间的冲突

时间:2015-08-28 21:30:53

标签: javascript events d3.js svg

当鼠标进入条形图时,我正在处理一个带有基本缩放和工具提示显示的简单条形图。 我在d3代码的不同层上触发的两个事件之间存在冲突。我有一个svg:rect,其目的是捕获d3缩放事件,我有一个兄弟节点,一个名为layer1的svg,其中包含条形图的条形图。这些条中的每一个都是简单的svg:rect,它们是我的layer1 svg的子节点。我在每个栏上附加了mouseover和mouseout事件以显示工具提示(我使用https://github.com/Caged/d3-tip/)。

我的问题如下:

如果我尝试使用鼠标滚轮进行缩放,当鼠标位于绘图上但位于条形图外时,它可以正常工作。但是,当鼠标在条形图上时,显示d3-tip但我不能再放大/缩小,鼠标滚轮只会使整个页面向上或向下滚动。

我已经尝试过以下链接中描述的方法但没有成功:

Handling Mouse Events in Overlapping SVG Layers

我还希望通过将它附加到我的主svg后附加layer1来直接处理evt_catcher层的鼠标悬停和鼠标输出,但问题是函数tip.show和tip.hide实际上计算了工具提示的位置event.target/d3.event.target,这里将与evt_catcher层相关联,而不再与bar相关联。

所以为了使这个方法成功,我需要从鼠标的坐标获得与一个条相关联的svg节点,我不知道该怎么做。 Document.elementFromPoint()似乎很有希望,但只提供最顶层的元素,这将再次出现在evt_catcher中......

以下是一些相关代码:

// appending evt_catcher layer
this.evt_catcher = this.svg.append('rect')
   .attr('class', 'overlay')
   .attr('width', this.width)
   .attr('height', this.height);

// appending layer1 layer (will contain the bars)
this.layer1 = this.svg.append('svg')
   .attr('height', this.height)
   .attr('width', this.width);

// creating the d3-tip
this.tip = d3.tip()
   .attr('class', 'd3-tip')
   .offset([-10, 0])
   .html(function(d) {
      return d[1].toFixed(2);
   });

// attaching the d3-tip to the main svg
this.svg.call(this.tip);

// defining the d3.behavior.zoom function
this.zoom = d3.behavior.zoom()
   .x(this.x)
   .scaleExtent([1, 32])
   .on('zoom', function() {
      d3.event.sourceEvent.stopPropagation();
      d3.event.sourceEvent.preventDefault();
      /* my zoom code */
      });
});

// creating the bars representing the data
var bars = this.layer1.selectAll('.bar').data(data.series.values);
bars.transition()
   .attr('x', function(d) {return that.x(d[0]);})
   .attr('width', that.range_band * that.zoom.scale())
   .attr('y', function(d) { return d[1] < 0 ? that.y(0): that.y(d[1]); })
   .attr('height', function(d) {
      return Math.abs(that.y(d[1]) - that.y(0));
   });

bars.enter().append('rect')
   .attr('class', 'bar')
   .attr('x', function(d) {return that.x(d[0]);})
   .attr('fill', 'steelblue')
   .attr('width', that.range_band * that.zoom.scale())
   .attr('y', function(d) { return d[1] < 0 ? that.y(0): that.y(d[1]); })
   .attr('height', 0)
   .on('mouseover', that.tip.show) // attaching mouseover event to trigger the display of the tooltip
   .on('mouseout', that.tip.hide) //attaching mouseout event to hide the the tooltip
 .transition()
   .attr('height', function(d) {
      return Math.abs(that.y(d[1]) - that.y(0));
   });

bars.exit().transition()
   .attr('height', 0)
   .remove();

// attaching the zoom event to the evt_catcher layer
this.evt_catcher.call(this.zoom);

有什么想法吗?

0 个答案:

没有答案