I’m having some trouble getting d3.drag to work while using canvas in a react application. My data nodes are simply objects with coordinates, f.e. {x: 3, y:5}
existing in my redux state.
The nodes does not seem to be moving during drag event though I have found the correct subject. I have used this example as an inspiration
It would be really nice with an example on the D3 page with a zoomable and draggable stateful application using React.
My drag functionality
// Drag
const dragSubject = (e: DragEvent) => {
const x = zoomedXScale.invert(e.x);
const y = zoomedYScale.invert(e.y);
let dx, dy;
const temp = data.find((node) => {
const tempNode = node;
dx = x - tempNode.x;
dy = y - tempNode.y;
if (dx * dx + dy * dy < 5 * 5) {
tempNode.x = x;
tempNode.y = y;
return tempNode;
}
});
return temp;
};
const dragStarted = (e) => {
const { x }: { x: number } = e;
const { y }: { y: number } = e;
e.subject.fx = zoomedXScale.invert(x);
e.subject.fy = zoomedYScale.invert(y);
};
const dragged = (e) => {
console.log('dragged');
const { x }: { x: number } = e;
const { y }: { y: number } = e;
e.subject.fx = zoomedXScale.invert(x);
e.subject.fy = zoomedYScale.invert(y);
};
const dragEnded = (e) => {
console.log(e.subject);
console.log('drag is ended');
};
And my code using the Canvas and d3 svg looks like this
const drag = d3
.drag()
.subject(dragSubject)
.on('start', dragStarted)
.on('drag', dragged)
.on('end', dragEnded);
// UseEffects
useEffect(() => {
if (canvasRef.current) {
const canvasObj: HTMLCanvasElement = canvasRef.current;
setContext(canvasObj.getContext('2d'));
}
});
// UseEffect for zoom - Calls zoomed on canvasRef on d3.ZoomEvent
useEffect(() => {
d3.select(canvasRef.current).call(drag).call(zoomed).call(draw);
}, [zoomed, drag]);
My drawing function for the canvas to draw my points
const draw = () => {
if (context) {
context.save();
context.clearRect(0, 0, chartWidth, chartHeight);
context.beginPath();
data.forEach((point) => {
drawPoint(point);
});
context.fill();
context.restore();
}
};