Last active
March 9, 2023 09:23
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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