Files
canvas-label/src/components/transformable-image.tsx
2023-11-29 14:39:05 +01:00

94 lines
2.3 KiB
TypeScript

import { type ImageConfig } from "konva/lib/shapes/Image";
import { useRef, useEffect, type ElementRef } from "react";
import { Transformer, Image } from "react-konva";
import useImage from "use-image";
type TransformableImageConfig = Omit<ImageConfig, "image"> & {
imageUrl: string;
};
export type TransformableImageProps = {
imageProps: TransformableImageConfig;
id: string;
isSelected: boolean;
onSelect: () => void;
onChange: (newAttrs: TransformableImageConfig) => void;
};
export const TransformableImage = ({
imageProps,
id,
isSelected,
onSelect,
onChange,
}: TransformableImageProps) => {
const imageRef = useRef<ElementRef<typeof Image>>(null);
const trRef = useRef<ElementRef<typeof Transformer>>(null);
const [image] = useImage(imageProps.imageUrl);
useEffect(() => {
if (!imageRef.current) return;
if (isSelected) {
// we need to attach transformer manually
trRef.current?.nodes([imageRef.current]);
trRef.current?.getLayer()?.batchDraw();
}
}, [isSelected]);
return (
<>
<Image
id={id}
alt={"canvas image"}
onClick={onSelect}
onTap={onSelect}
ref={imageRef}
{...imageProps}
image={image}
draggable
onDragEnd={(e) => {
onChange({
...imageProps,
image,
x: e.target.x(),
y: e.target.y(),
});
}}
onTransformEnd={() => {
const node = imageRef.current;
if (!node) return;
const scaleX = node.scaleX();
const scaleY = node.scaleY();
// we will reset it back
node.scaleX(1);
node.scaleY(1);
onChange({
...imageProps,
image,
x: node.x(),
y: node.y(),
// set minimal value
width: Math.max(5, node.width() * scaleX),
height: Math.max(node.height() * scaleY),
});
}}
/>
{isSelected && (
<Transformer
ref={trRef}
boundBoxFunc={(oldBox, newBox) => {
// limit resize
if (newBox.width < 5 || newBox.height < 5) {
return oldBox;
}
return newBox;
}}
/>
)}
</>
);
};