viewof chartcanvas = render(() => {
const canvasRef = useRef(null);
const svgRef = useRef(null);
const [context, setContext] = useState(null);
const [currentZoomState, setCurrentZoomState] = useState(d3.zoomIdentity);
const margin = { top: 20, right: 15, bottom: 60, left: 70 };
const outerWidth = 600;
const outerHeight = 800;
const chartWidth = outerWidth - margin.left - margin.right;
const chartHeight = outerHeight - margin.top - margin.bottom;
const dataExample = [{x: 10, y: 20}, {x: 20, y: 30}];
const xScale = d3.scaleLinear()
.domain([0, d3.max(dataExample, (d) => d.x)])
.range([0, chartWidth])
.nice();
const yScale = d3.scaleLinear()
.domain([0, d3.max(dataExample, (d) => d.y)])
.range([chartHeight, 0])
.nice();
const xAxis = d3.axisBottom(xScale);
const yAxis = d3.axisLeft(yScale);
const zoomedXScale = useMemo(
() => currentZoomState.rescaleX(xScale),
[currentZoomState, xScale]
);
const zoomedYScale = useMemo(
() => currentZoomState.rescaleY(yScale),
[currentZoomState, yScale]
);
const drawPoint = (point) => {
context.beginPath();
context.fillStyle = '#0058a3';
const px = zoomedXScale(point.x);
const py = zoomedYScale(point.y);
context.arc(px, py, 5, 0, 2 * Math.PI, true);
context.fill();
};
const draw = () => {
if (context) {
console.log('i draw');
context.save();
context.clearRect(0, 0, chartWidth, chartHeight);
context.beginPath();
dataExample.forEach((point) => {
drawPoint(point);
});
context.fill();
context.restore();
}
};
const zoomed = d3
.zoom()
.extent([
[0, 0],
[width, chartHeight]
])
.translateExtent([
[0, 0],
[width, chartHeight]
])
.scaleExtent([1, 5])
.on('zoom', (e) => {
const zoomState = e.transform;
setCurrentZoomState(zoomState);
});
const dragSubject = (e) => {
const x = zoomedXScale.invert(e.x);
const y = zoomedYScale.invert(e.y);
let dx, dy;
const temp = dataExample.find((node) => {
const tempNode = node;
dx = x - tempNode.x;
dy = y - tempNode.y;
if (dx * dx + dy * dy < 2 * 2) {
tempNode.x = zoomedXScale(tempNode.x);
tempNode.y = zoomedYScale(tempNode.y);
return tempNode;
}
});
return temp;
};
const dragStarted = (e) => {
e.subject.x = zoomedXScale.invert(e.x);
e.subject.y = zoomedYScale.invert(e.y);
};
const dragged = (e) => {
e.subject.x = zoomedXScale.invert(e.x);
e.subject.y = zoomedYScale.invert(e.y);
};
const dragEnded = (e) => {
};
const drag = d3
.drag()
.subject(dragSubject)
.on('start', dragStarted)
.on('drag', dragged)
.on('end', dragEnded);
useEffect(() => {
if (canvasRef.current) {
const canvasObj = canvasRef.current;
setContext(canvasObj.getContext('2d'));
}
});
useEffect(() => {
d3.select(canvasRef.current).call(
drag.on('start.draw drag.draw end.draw', draw)
);
}, [drag]);
useEffect(() => {
d3.select(canvasRef.current).call(zoomed).call(draw);
}, [zoomed]);
useEffect(() => {
d3.select(svgRef).append('g')
.call(yAxis)
})
return jsx`
<div style=${{ margin: 'auto', width: outerWidth, height: outerHeight }}>
<svg
ref=${svgRef}
width=${outerWidth}
height=${outerHeight}
style=${{ position: 'absolute' }}
>
<g transform=${`translate(${margin.left}, ${margin.top})`} />
</svg>
<canvas
ref=${canvasRef}
width=${chartWidth}
height=${chartHeight}
style=${{
marginLeft: `${margin.left}px`,
marginTop: `${margin.top}px`,
position: 'absolute'
}}
/>
</div>`;
})