I am using react-konva to try and make a tool where users can visualize and plan their frame wall. The user can choose a background, then chooses a frame size and different posters. It kind of looks like this:
So far I have made a background image that scales correctly whenever the window size changes. I have also created an image that represents a poster that scales down/up the same way as the background image. The image that represents a poster is draggable. It can currently only de dragged inside of the background image. However, I want the position of the poster to be the same relative to the background image whenever the window is resized.
This is a demo - https://blue-print.vercel.app/ Select a background and a poster and resize the window. You will see that both the poster and the background shrinks/grows but the position of the poster will not be same relative to the background.
This is the relevant code of the Poster component:
//rest of component
const handleDragEnd = (e: Konva.KonvaEventObject<DragEvent>) => {
setElementPos({
x: e.target.x(),
y: e.target.y(),
});
};
const handleDrag = (pos: Konva.Vector2d) => {
//this makes the group only be draggable within the background image
const { width, height, x, y } = props.bg;
const newX = Math.max(x!, Math.min(pos.x, x! + width - scaledSizes.width!));
const newY = Math.max(
y!,
Math.min(pos.y, y! + height - scaledSizes.height!)
);
return {
x: newX,
y: newY,
};
};
return (
<Group
x={elementPos.x}
y={elementPos.y}
dragBoundFunc={handleDrag}
draggable
onDragEnd={handleDragEnd}
ref={groupRef}
onClick={() => handleSelectItem(props.item)}
onTap={() => handleSelectItem(props.item)}
>
// content of the group
Please let me know if you need any additional code / info. Thanks in advance! :)
For any future people reading this post:
So it turns out that all I had to do was to add a scaleX and scaleY attribute to a group containing all the elements that I wanted to scale. Them set a "virtual height/width" for the elements inside of the group.This would scale all of the elements instead of trying to do it myself with dynamic variables.
I did this simple calculation to determine the scale variable: Here the canvas.Background is the height and width of my background-image.
aspectRatio = canvasBackground!.width / canvasBackground!.height;
scaleX = dimensions.width / canvasBackground!.width;
scaleY = dimensions.height / canvasBackground!.height;
scale = aspectRatio < 1 ? Math.max(scaleX, scaleY) : Math.min(scaleX, scaleY);
Which resulted in the following code in the component:
<Container
sx={{ height: '100%', position: 'relative' }}
ref={stageCanvasRef}//ref is used to get the height and width of this container
>
<Stage
height={dimensions.height}//This is the same height as the above container
width={dimensions.width}//This is the same width as the above container
>
<Layer>
<Group scaleX={scale} scaleY={scale} x={x} y={y}>
<Image
height={canvasBackground.height}
width={canvasBackground.width}
alt="background"
image={canvasBackground}
/>
/**Rest of the Groups content*/