1 year ago

#342804

test-img

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

Accepted video resources