如何根据行总高度增加变压器和文本?

问题描述 投票:0回答:1

我正在努力更新变压器的高度以匹配内部文本的总高度,当我减小变压器宽度时,文本会分成几行,导致它们超出变压器高度,使其无法看到,然后我必须手动增加变压器(我猜也是文本对象)以使下面的线可见

有办法让它自动化吗?

这是我的文本组件

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;
reactjs konvajs react-konva konva konvajs-reactjs
1个回答
0
投票

如果您明确设置文本的高度,Konva 将始终遵循它。如果文本超出定义的高度,那么 Konva 将剪切它并仅渲染可见线。

有两种方法可以解决此问题。

  1. 您可以从

    height
    组件中删除
    <Text />
    属性。所以默认情况下它将是“自动”。您仍然可以将其保留在该状态以用于其他目的。

  2. 当你用更新后的文本高度更新状态时,你可以先将其重置为

    undefined
    ,然后再获取,而不是直接从文本实例中读取。重置后,Konva 将返回所有线条所需的高度。

// reset height
node.height(undefined);
// then read real value
setTextHeight(node.height() * node.scaleY());
© www.soinside.com 2019 - 2024. All rights reserved.