D3 鼠标同时在两个图形上移动

D3 Mouse Move on Two Graphs at once

如何同时捕获鼠标悬停在两个图形上的事件。我需要做如下图所示的事情:

任何人都可以指导我如何处理这个问题吗?。到目前为止,我能够让简单的鼠标悬停在单个图形上工作。

这取决于您如何创建图表。

如果您使用嵌套输入模式(绑定数据,输入 svgs,然后从嵌套数据输入每个图表),那么它与您有两个单独创建的图表时略有不同。

但一般来说,请查看 at this example 示例。

您将首先创建未显示的文本和圆形叠加层:

var focus = svg.append("g")
      .attr("class", "focus")
      .style("display", "none");

  focus.append("circle")
      .attr("r", 4.5);

  focus.append("text")
      .attr("x", 9)
      .attr("dy", ".35em");

根据您的情况,为每个图表创建它们。

然后设置叠加层并捕获鼠标悬停:

svg.append("rect")
      .attr("class", "overlay")
      .attr("width", width)
      .attr("height", height)
      .on("mouseover", function() { focus.style("display", null); })
      .on("mouseout", function() { focus.style("display", "none"); })
      .on("mousemove", mousemove);

  function mousemove() {
    var x0 = x.invert(d3.mouse(this)[0]),
        i = bisectDate(data, x0, 1),
        d0 = data[i - 1],
        d1 = data[i],
        d = x0 - d0.date > d1.date - x0 ? d1 : d0;
    focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
    focus.select("text").text(formatCurrency(d.close));
  }

在您的情况下,由于您的图表具有相同的宽度,您可以对每个图表使用来自 x(d.date) 比例 return 的相同 x 转换。

y 值有点诡异。

如果你使用不同的数据集,你可能会有类似的东西。如果要嵌套单个数据集,则需要以不同方式使用键索引:

function mousemove() {
        var x0 = x.invert(d3.mouse(this)[0]),
            i = bisectDate(data, x0, 1),
            d0 = data[i - 1],
            d1 = data[i],
            d = x0 - d0.date > d1.date - x0 ? d1 : d0;

          var d02 = data2[i - 1],
            d12 = data2[i],
            d2 = x0 - d02.date > d12.date - x0 ? d12 : d0;
        focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
        focus.select("text").text(formatCurrency(d.close));
focuslowerchart.attr("transform", "translate(" + x(d.date) + "," +      (yLower(d2.close) + ")");
        focuslowerchart.select("text").text(formatCurrencyLower(d.close));
      }

以上假设图表之间的 i 索引相同。如果数据集的顺序不同,您需要以不同的方式对分。

我是 function-plot 的作者,它能够将事件分派到多个图,其中之一是 mouseover,例如

var width = 300
var height = 180
var a = functionPlot({
  target: '#a',
  height: height,
  width: width,
  data: [{ fn: 'x^2' }]
})
var b = functionPlot({
  target: '#b',
  height: height,
  width: width,
  data: [{ fn: 'x' }]
})
a.addLink(b)
b.addLink(a)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/function-plot/1.16.5/function-plot.js"></script>

<span id="a" />
<span id="b" />

解决方案涉及让每个图形在触发特定事件时执行某些操作,例如 d3 调度事件的方式是

 // create a dispatcher with the events you will fire in the future
 var dispatch = d3.dispatch('mycustomevent');
 // add some callbacks (note the namespace)
 dispatcher.on('mycustomevent.graph1, function (str) {
    // when called str === 'hello world'
 })
 dispatcher.on('mycustomevent.graph2, function (str) {
    // when called str === 'hello world'
 })
 // fire the event from the dispatcher
 // the two callbacks attached are called in the same order
 dispatch.mycustomevent('hello world')

实际上,每当您在图表上进行鼠标悬停而不是立即执行操作时,您会触发一个自定义事件并让每个图表在鼠标悬停时做任何它需要做的事情

 // create a dispatcher
 var dispatch = d3.dispatch('mymouseover');

 function graphWrapper(graph) {
    return function (xCoord) {
       // do something with `xCoord` in `graph`
    }
 }
 dispatcher.on('mymouseover.graph1, graphWrapper(graph1))
 dispatcher.on('mymouseover.graph2, graphWrapper(graph2))

 // graph1 and graph2 need to fire the custom event
 function dispatchMouseOver() {
   var xCoord = x.invert(d3.mouse(this)[0])
   dispatch.mymouseover(xCoord)
 }
 graph1.on('mousemove', dispatchMouseOver)
 graph2.on('mousemove', dispatchMouseOver)

对于实现,我修改了@In code veritas 引用的an example made by d3's author 和一个可重用的图表

a reusable graph with independent mouseover

如你所见,每个图都是相互独立的,在实施发布-订阅模式后,它看起来像这样

linked graphs

附带说明一下,我使用节点的事件模块在函数图中实现了这个功能,主要是因为在 d3 中,您在同一命名空间下使用不同的名称添加了一个回调,例如mymouseover.1mymouseover.2 等等,但在节点的事件模块中,您只需多次执行 graph.on('event', callback)

关于这个话题有用articles/demos