我正在努力更新变压器的高度以匹配内部文本的总高度,当我减小变压器宽度时,文本会分成几行,导致它们超出变压器高度,使其无法看到,然后我必须手动增加变压器(我猜也是文本对象)以使下面的线可见
有办法让它自动化吗?
这是我的文本组件
import React, { useState } from 'react';
import { useRef, useEffect } from 'react';
import { Text as TextObject, Transformer } from 'react-konva';
import { Html } from 'react-konva-utils';
import { BsFillCheckSquareFill } from 'react-icons/bs';
import { usePropertiesContext } from '@/hooks/PropertiesContent';
interface TextProps {
x: number;
y: number;
fontSize: number;
fill: string;
fontVariant: string;
align: undefined;
fontFamily: string;
opacity: number;
rotation: number;
isSelected: boolean;
boundingBoxWidth: number;
boundingBoxHeight: number;
onSelect: () => void;
onChange: ({ x, y }: { x: number; y: number }) => void;
}
const Text: React.FC<TextProps> = ({
x,
y,
fontSize,
fill,
fontVariant,
align,
fontFamily,
opacity,
rotation,
isSelected,
boundingBoxWidth,
boundingBoxHeight,
onSelect,
onChange,
}) => {
const { settextRotation } = usePropertiesContext();
const [textHeight, setTextHeight] = useState(20);
const [text, setText] = useState('Your Text');
const [edit, setEdit] = useState(false);
const [textWidth, setTextWidth] = useState(120);
const [realHeight, setRealHeight] = useState(20);
const [rotationAngle, setRotationAngle] = useState(rotation); // Store the rotation angle
const [transformerHeight, setTransformerHeight] = useState(textHeight);
const shapeRef = useRef() as any;
const trRef = useRef<Transformer>() as any;
useEffect(() => {
if (!edit && isSelected) {
trRef.current?.nodes([shapeRef.current]);
trRef.current.getLayer().batchDraw();
}
}, [edit, isSelected]);
useEffect(() => {
// Access the Konva.Text instance
const textNode = shapeRef.current;
if (textNode) {
const newTextHeight = textNode.height();
console.log(`Height of Text element: ${newTextHeight}`);
setRealHeight(newTextHeight);
}
// Update the rotation angle in state
setRotationAngle(rotation);
}, [rotation]);
// Function to update the size and position of the TextObject and Transformer
const updateSizeAndPosition = (
newTextWidth: number,
newTextHeight: number
) => {
setTextWidth(newTextWidth);
setTextHeight(newTextHeight);
shapeRef.current?.width(newTextWidth);
shapeRef.current?.height(newTextHeight);
// Update Transformer size and position
trRef.current?.boundBoxFunc(trRef.current.getClientRect(), {
x: x,
y: y,
width: newTextWidth,
height: newTextHeight,
});
setTransformerHeight(newTextHeight); // Update the transformer height here
trRef.current?.getLayer().batchDraw();
};
return (
<React.Fragment>
<Html
divProps={{
style: {
position: 'absolute',
top: y + 'px',
left: x + 'px',
transform: `rotate(${rotationAngle}deg)`, // Apply rotation to the textarea
},
}}
>
{edit ? (
<div className="flex items-start gap-x-2">
<textarea
value={text}
onChange={(e) => {
setText(e.target.value);
const newHeight = e.target.scrollHeight;
const newWidth = e.target.scrollWidth;
updateSizeAndPosition(newWidth, newHeight);
}}
style={{
width: textWidth + 'px',
height: textHeight + 'px',
backgroundColor: 'transparent',
color: fill,
textAlign: align,
fontSize: fontSize,
fontFamily: fontFamily,
fontVariant: fontVariant,
opacity: opacity,
lineHeight: 1,
appearance: 'none',
overflow: 'hidden' /* Hide the scrollbar */,
resize: 'none' /* Disable resizing */,
border: 'none',
outline: 'none',
}}
/>
<button onClick={() => setEdit(false)}>
<BsFillCheckSquareFill className="text-blue-500 hover:text-blue-600 text-lg shadow-sm" />
</button>
</div>
) : (
<></>
)}
</Html>
{!edit ? (
<TextObject
onClick={onSelect}
onTap={onSelect}
onDblClick={() => setEdit(true)}
onDblTap={() => setEdit(true)}
text={text}
ref={shapeRef}
fontSize={fontSize}
fill={fill}
x={x}
y={y}
opacity={opacity}
width={textWidth}
fontFamily={fontFamily}
fontVariant={fontVariant}
align={align}
rotation={rotation}
height={textHeight}
draggable
onDragEnd={(e) => {
onChange({
x: e.target.x(),
y: e.target.y(),
});
}}
onDragMove={(e) => {
// Do not let the object move outside of the pdf page
if (e.target.x() - 10 < 0) e.target.x(10);
if (e.target.y() - 10 < 0) e.target.y(10);
if (e.target.x() + e.target.width() + 10 > boundingBoxWidth)
e.target.x(boundingBoxWidth - e.target.width() - 10);
if (e.target.y() + e.target.height() + 10 > boundingBoxHeight)
e.target.y(boundingBoxHeight - e.target.height() - 10);
}}
/>
) : (
<></>
)}
{isSelected && !edit && (
<Transformer
x={x}
y={y}
width={textWidth}
height={transformerHeight}
rotateAnchorOffset={30}
anchorCornerRadius={90}
padding={5}
ref={trRef}
boundBoxFunc={(oldBox, newBox) => {
if (newBox.width < 5 || newBox.height < 5) {
return oldBox;
}
return newBox;
}}
onTransform={(e) => {
const node = e.target;
const newRotation = Math.round(node.rotation()); // Get the new rotation
settextRotation(newRotation); // Update the rotation angle in state
node.setAttrs({
width: Math.max(node.width() * node.scaleX(), 20),
height: Math.max(node.height() * node.scaleY(), 20),
scaleX: 1,
scaleY: 1,
});
setTextWidth(node.width() * node.scaleX());
setTextHeight(node.height() * node.scaleY());
onChange({
x: e.target.x(),
y: e.target.y(),
});
}}
/>
)}
</React.Fragment>
);
};
export default Text;
如果您明确设置文本的高度,Konva 将始终遵循它。如果文本超出定义的高度,那么 Konva 将剪切它并仅渲染可见线。
有两种方法可以解决此问题。
您可以从
height
组件中删除 <Text />
属性。所以默认情况下它将是“自动”。您仍然可以将其保留在该状态以用于其他目的。
当你用更新后的文本高度更新状态时,你可以先将其重置为
undefined
,然后再获取,而不是直接从文本实例中读取。重置后,Konva 将返回所有线条所需的高度。
// reset height
node.height(undefined);
// then read real value
setTextHeight(node.height() * node.scaleY());