我想用支持鼠标滚动缩放的D3制作大约100.000个项目的散点图。我设法在React中实现了这一点。不幸的是,缩放交互非常慢。有没有办法让缩放更平滑和即时?
我的useEffect如下所示
useEffect(() => {
//setting up container width and height
const w = width;
const h = height;
// create the result chart
const resultChart = d3.select(resultChartRef.current)
.attr('width', w)
.attr('height', h)
.style('margin-top', '10px');
// Create the latent chart
const latentChart = d3.select(latentChartRef.current)
.attr('width', w)
.attr('height', h)
.style('margin-top', '10px');
// d3.select(resultChartRef.current).selectAll().remove().exit()
// Compute the scales of the two charts
const resultScales = setScalesChart(dimRedData?.data?.result, w, h)
const latentScales = setScalesChart(dimRedData?.data?.latent_space, w, h)
if (currentZoomState) {
const newXScale = currentZoomState.rescaleX(resultScales[0])
const newYScale = currentZoomState.rescaleX(resultScales[1])
resultScales[0].domain(newXScale.domain())
resultScales[1].domain(newYScale.domain())
};
const xAxis = d3.axisBottom(resultScales[0]).ticks(10)
const yAxis = d3.axisLeft(resultScales[0]).ticks(10)
const gX = resultChart.append('g').call(xAxis).attr('transform', `translate(0, ${h})`);
const gY = resultChart.append('g').call(yAxis);
// TODO: styling properties http://www.d3noob.org/2014/02/styles-in-d3js.html
resultChart.selectAll('*').remove();
resultChart.selectAll('circle')
// select dataset
.data(filterData(dimRedData?.data?.result))
.enter()
// Assign data value
.append('circle')
.attr('cx', d => resultScales[0](d[0]))
.attr('cy', d => resultScales[1](d[1]))
.attr('r', 2)
// Add item colour
.style("fill", function(d, i) {
return dimRedData.data.colour[0][i]
})
// Set border width
.style("stroke-width", 0.5)
// Add border colour
.style("stroke", "black");
latentChart.selectAll()
// select dataset
.data(filterData(dimRedData?.data?.latent_space))
.enter()
// Assign data value
.append('circle')
.attr('cx', d => latentScales[0](d[0]))
.attr('cy', d => latentScales[1](d[1]))
.attr('r', 2)
// Add item colour
.style("fill", function(d, i) {
return dimRedData.data.colour[0][i]
})
// Set border width
.style("stroke-width", 0.5)
// Add border colour
.style("stroke", "black");
// Zoom of the chart
const zoomBehavior = d3.zoom()
.extent([[0, 0],[w, h]])
.scaleExtent([0.5, 5])
.translateExtent([[0,0], [w, h]])
.on("zoom", (e) => {
const zoomState = d3.zoomTransform(resultChart.node())
setCurrentZoomState(zoomState);
console.log("ZOOM!")
});
// Add zoom functionality to the result chart
resultChart.call(zoomBehavior)
}, [random, projectionFullScreen, currentZoomState]);
我想知道是否有可能加快速度,或者我应该换一种不同的方法。甚至可能是一种与D3不同的技术。
1条答案
按热度按时间rkttyhzu1#
可能的事情:
不是ReactMaven,但是缩放是否每次都调用useEffect函数呢?如果是这样,那就不好了,因为它至少要从零开始销毁和重新添加resultChart的所有100,000个对象。您可以将它们全部删除(resultChart.selectAll('*').remove();),然后通过enter()再次将它们全部添加进去。在D3方面,您应该只删除(通过exit())没有相应数据的现有对象,添加(通过enter())数据没有相应对象的对象,并更新数据和对象都存在的对象。要实现这一点,您需要一个关键函数作为.data(filterData(dimRedData?.data?.latent_space))调用的第二个参数,通常它引用数据对象的ID字段。
其次,即使这样做了,这是一个svg,这100,000个圆圈被添加到,所以它会很慢,因为通过缩放svg放大和缩小涉及浏览器重新绘制它包含的所有这100,000个对象(它可能有一些智能,而不是“绘制”那些在放大视图之外,但它仍然必须计算)
我以前做过一个基于d3的散点图,上面有很多点,我在缩放/平移时唯一的方法就是把这些点绘制到画布图像上,然后放大和缩小。但是这意味着你的圆看起来会有锯齿/模糊,这取决于抗锯齿。因此,如果您继续使用这条路线,可能需要切换到正方形“点”。我还需要编写自己的代码来与点进行交互
我想总结一下,除非这是为了你自己的教育或者你受到其他问题的限制,否则去谷歌一下react散点图库,看看是否有人已经解决了这个问题;- )