1 year ago
#342804
wfinzer
Can d3 drag behavior be assigned to 10,000 points without taking a long time and using a lot of memory?
I've got a d3 application that draws a scatterplot with ~10,000 points. The user can click and drag on any point and drag it to a new location, thereby changing its data values. Bringing up the app on Chrome on my M1 Max takes over a minute. If I remove the assignment of the drag behavior to each of the points, it comes up in a few seconds, so I believe the assignment is, for some reason, quite expensive. I'm looking for a way to get the desired behavior without the inordinate time.
Here is my (elided) code:
useEffect(() => {
let dragID = -1
function onDragStart(event: any, d: any) {
...
}
function onDrag(event: { dx: number; dy: number; }, d: any) {
if (event.dx !== 0 || event.dy !== 0) {
const deltaX = props.dots.xScale.invert(event.dx) - props.dots.xScale.invert(0),
deltaY = props.dots.yScale.invert(event.dy) - props.dots.yScale.invert(0)
setData(data => {
return data.map((datum) =>
datum.caseID === dragID
? {...datum, x: datum.x += deltaX, y: datum.y += deltaY}
: {...datum}
)
}
)
}
}
function onDragEnd() {
...
}
const
dragBehavior = drag()
.on("start", onDragStart)
.on("drag", onDrag)
.on("end", onDragEnd)
select(ref.current)
.selectAll('circle')
.data(data, keyFunc)
.join(
(enter) => {
enter.append('circle')
.attr('class', 'dot')
.attr("r", defaultRadius)
.attr("cx", (d: { x: any; }) => props.dots.xScale(d.x))
.attr("cy", (d: { y: any; }) => props.dots.yScale(d.y))
.property('caseID', (d: any) => d.caseID)
.call(dragBehavior) // Commenting out this line eliminates the expensive startup
},
(update) => {
...
}
)
}, [data, props.dots, props.dots.xScale, props.dots.yScale])
Is it possible to assign the desired drag behavior dynamically, say on mouseover or mousedown? Or is there a different approach I should be taking?
performance
d3.js
drag
0 Answers
Your Answer