使用 DC.js Canvas 分散悬停信息更新另一个图表

Use DC.js Canvas Scatter Hover Information to Update Another Chart

我想将鼠标悬停在 DC.js canvas 图表上,并使用悬停点将更改应用于另一个图表(即在另一个图表中显示有关该点的信息)。

并发症:

我猜它会是像 这样的 renderlet,但它相当棘手,因为它是 canvas 情节。

我假设 canvas 需要我使用隐藏元素,例如 block

我放了一个 Stackblitz ,其中所需的行为将悬停在橙色和绿色的图上,另一个散点有一些(对于这个例子来说是任何)属性 改变了各组积分

我使用以下方法获得了四叉树点 ID:

const data = dimension
    .top(Infinity)
    .map(d => [d.changePointTime, d.photonCountsMean]);

eventScatterChart.on("renderlet", c => {
  c.select(".overlay").on("mousemove.eventID", event => {
    const cursorX = d3.pointer(event)[0];
    const cursorY = d3.pointer(event)[1];
    const overlay = c.select(".overlay");
    const xScale = eventScatterChart.x();
    const yScale = eventScatterChart.y();
    const overlayPos = overlay.node().getBBox();
    const tree = d3
      .quadtree()
      .extent([
        [xScale.invert(overlayPos.x), yScale.invert(overlayPos.y)],
        [xScale.invert(overlayPos.width), yScale.invert(overlayPos.height)]
      ])
      .addAll(data);

    const closestPoint = tree.find(
      xScale.invert(cursorX),
      yScale.invert(cursorY)
    );
    console.log(closestPoint);
  }); 
});

下次编辑其他图表更改...

酷!很高兴您明白了这一点并发布了您的答案。这将对其他人有所帮助。

您的直觉是正确的,不要在内循环中进行昂贵的初始化。

可以在 renderlet 处理程序中工作;当图表被渲染或重新绘制时,即数据发生变化时,它会被触发,所以它是有道理的。

但是,在 mousemove 侦听器 中计算四叉树等昂贵的计算并不是一个好主意,因为那是交互式的。

看起来速度完全没问题,但我有一台不错的iMac,在低端机器上性能可能会遇到麻烦。

我会这样构造代码:

  eventScatterChart.on("renderlet", c => {
    // 0
    const xScale = c.x();
    const yScale = c.y();
    const data = c.group().all() // 1
        .filter(({value}) => value) // 2
        .map(({key}) => key); // 3
    // 4
    const overlayPos = c.select('.overlay').node().getBBox();
    const tree = d3
      .quadtree()
      .extent([
        [xScale.invert(overlayPos.x), yScale.invert(overlayPos.y)],
        [xScale.invert(overlayPos.width), yScale.invert(overlayPos.height)]
      ])
      .addAll(data);

    c.select(".overlay").on("mousemove.eventID", function(event) {
      // 5
      const cursorX = d3.pointer(event)[0];
      const cursorY = d3.pointer(event)[1];

      const closestPoint = tree.find(
        xScale.invert(cursorX),
        yScale.invert(cursorY)
      );
      console.log(closestPoint);
    });
  });
  1. renderlet 是进行初始化的好地方。我还发现在绘制图表之前没有定义 x 和 y 比例尺。

  2. 从组中获取数据,而不是维度,以便它观察其他维度上的过滤器。

  3. 当一个点被“过滤掉”时,仍然会有一个条目,但它的 value 是 0,所以删除那些。将鼠标悬停在隐藏点上应该 select 最近的可见点。

  4. 组的键是一个以 x,y 为第一个元素的数组,因为您将维度键定义为

     const dimension = ndx.dimension(d => [
       d.changePointTime,
       d.photonCountsMean,
       d.transitionDirection === -1 ? "BG" : "Signal"
     ]);
    
  5. 像以前一样初始化四叉树。

  6. 现在 mousemove 事件处理程序真的很简单,只做查找。应该很高效!

我发现它对 CPU 的使用没有帮助(仍然固定一个处理器),但浏览器控制台中的数字飞得更快。如果您想进一步提高性能,可以限制 mousemove 事件。 (浏览器每秒可以产生数百个。)

Fork of your stackblitz.