使用 DC.js Canvas 分散悬停信息更新另一个图表
Use DC.js Canvas Scatter Hover Information to Update Another Chart
我想将鼠标悬停在 DC.js canvas 图表上,并使用悬停点将更改应用于另一个图表(即在另一个图表中显示有关该点的信息)。
并发症:
- 这是一个canvas情节,我会徘徊
- 整个事情需要在虚拟 DOM
的上下文中完成
我猜它会是像 这样的 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);
});
});
renderlet 是进行初始化的好地方。我还发现在绘制图表之前没有定义 x 和 y 比例尺。
从组中获取数据,而不是维度,以便它观察其他维度上的过滤器。
当一个点被“过滤掉”时,仍然会有一个条目,但它的 value
是 0,所以删除那些。将鼠标悬停在隐藏点上应该 select 最近的可见点。
组的键是一个以 x,y 为第一个元素的数组,因为您将维度键定义为
const dimension = ndx.dimension(d => [
d.changePointTime,
d.photonCountsMean,
d.transitionDirection === -1 ? "BG" : "Signal"
]);
像以前一样初始化四叉树。
现在 mousemove 事件处理程序真的很简单,只做查找。应该很高效!
我发现它对 CPU 的使用没有帮助(仍然固定一个处理器),但浏览器控制台中的数字飞得更快。如果您想进一步提高性能,可以限制 mousemove 事件。 (浏览器每秒可以产生数百个。)
我想将鼠标悬停在 DC.js canvas 图表上,并使用悬停点将更改应用于另一个图表(即在另一个图表中显示有关该点的信息)。
并发症:
- 这是一个canvas情节,我会徘徊
- 整个事情需要在虚拟 DOM 的上下文中完成
我猜它会是像
我假设 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);
});
});
renderlet 是进行初始化的好地方。我还发现在绘制图表之前没有定义 x 和 y 比例尺。
从组中获取数据,而不是维度,以便它观察其他维度上的过滤器。
当一个点被“过滤掉”时,仍然会有一个条目,但它的
value
是 0,所以删除那些。将鼠标悬停在隐藏点上应该 select 最近的可见点。组的键是一个以 x,y 为第一个元素的数组,因为您将维度键定义为
const dimension = ndx.dimension(d => [ d.changePointTime, d.photonCountsMean, d.transitionDirection === -1 ? "BG" : "Signal" ]);
像以前一样初始化四叉树。
现在 mousemove 事件处理程序真的很简单,只做查找。应该很高效!
我发现它对 CPU 的使用没有帮助(仍然固定一个处理器),但浏览器控制台中的数字飞得更快。如果您想进一步提高性能,可以限制 mousemove 事件。 (浏览器每秒可以产生数百个。)