Skip to content

Instantly share code, notes, and snippets.

@pgmoir
Last active March 9, 2023 09:23
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pgmoir/7e2eb61974d4d11cbd510c761d51626d to your computer and use it in GitHub Desktop.
Save pgmoir/7e2eb61974d4d11cbd510c761d51626d to your computer and use it in GitHub Desktop.
Responsive resize of canvas to match inserted image and plot/tag points that stay in location during resize
import React, { useRef, useEffect } from 'react';
const scaleWidth = 500;
const scaleHeight = 500;
/*
topImage is an object
{
image: String, // name of image
imageUrl: String, // full url of remote hosted image
metadata: [
{
category: String, // text desription of point selected
shape: String, // e.g. 34,75 currently x,y percentage position of point from top left
}
],
}
*/
function draw(topImage, canvas, scaleX, scaleY) {
const ctx = canvas.getContext('2d');
ctx.scale(scaleX, scaleY);
ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight);
const image = new Image();
image.src = topImage.imageUrl;
image.onload = () => {
var width = parseInt(image.width);
var height = parseInt(image.height);
canvas.height = height;
canvas.width = width;
ctx.drawImage(image, 0, 0, width, height);
if (topImage.metadata) {
topImage.metadata.forEach((m) => {
ctx.beginPath();
const [x, y] = m.shape.split(',');
const xcoord = width * (x / 100);
const ycoord = height * (y / 100);
ctx.arc(xcoord, ycoord, 10, 0, Math.PI * 2, true);
ctx.lineWidth = 3;
ctx.strokeStyle = 'yellow';
ctx.stroke();
ctx.font = '30px serif';
ctx.textAlign = x < 50 ? 'left' : 'right';
const xadj = x < 50 ? 20 : -20;
ctx.fillStyle = 'yellow';
ctx.fillText(m.category, xcoord + xadj, ycoord + 7);
ctx.closePath();
});
}
};
}
const PreviewImage = ({ image }) => {
const [scale, setScale] = React.useState({ x: 1, y: 1 });
const canvas = useRef(null);
const calculateScaleX = () =>
!canvas.current ? 0 : canvas.current.clientWidth / scaleWidth;
const calculateScaleY = () =>
!canvas.current ? 0 : canvas.current.clientHeight / scaleHeight;
const resized = () => {
canvas.current.width = canvas.current.clientWidth;
canvas.current.height = canvas.current.clientHeight;
setScale({ x: calculateScaleX(), y: calculateScaleY() });
};
useEffect(() => resized(), []);
useEffect(() => {
const currentCanvas = canvas.current;
currentCanvas.addEventListener('resize', resized);
return () => currentCanvas.removeEventListener('resize', resized);
});
useEffect(() => {
draw(image, canvas.current, scale.x, scale.y);
}, [image, scale]);
if (!image || !image.imageUrl) {
image = {
imageUrl: '/images/default.png',
};
}
return (
<>
<canvas ref={canvas} className="w-100 mb-3"></canvas>
</>
);
};
export { PreviewImage };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment