D3鼠标一次移动两个图形

时间:2016-05-02 22:15:14

标签: javascript d3.js nvd3.js

如何一次捕获两个图形的事件上的鼠标。我需要做一些如下图所示的事情:

enter image description here

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

2 个答案:

答案 0 :(得分:3)

我是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

如您所见,每个图表彼此独立,在执行pub-sub模式后,它看起来像这样

linked graphs

作为旁注,我使用节点的事件模块在功能图中实现了这个特征,基本上是因为在d3中你在相同的命名空间下使用不同的名称添加回调,例如mymouseover.1mymouseover.2等等,但在节点的事件模块中,您只需多次执行graph.on('event', callback)

关于此主题的有用文章/演示

答案 1 :(得分:2)

这取决于您创建图表的方式。

如果您使用嵌套的输入模式(绑定数据,输入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)比例返回使用相同的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索引相同。如果数据集的排序方式不同,则需要进行不同的分割。