react-konva实践:使用konva画可拖拽可变形可删除的框

·  阅读 56

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情

实现示例

Aug-12-2022 14-54-12.gif

实现

主要用到Konva 组件:

  • Rect
<Rect
    x={20}
    y={50}
    width={100}
    height={100}
    fill="red"
    shadowBlur={10}

/>
复制代码

Rect设置draggable = true , 监听拖拽事件:onDragEnd、onDragStart、onDragMove等一系列事件,获得当前Rect的属性;监听形变相关事件:onTransform、onTransformEnd、onTransformStart,获得变化后Rect数据;

  • Transformer 将当前需要变形的Rect的node赋值给Transformer组件

Transformer一些组件参数:

  • keepRatio={false} // 拖动四角不保存比例
  • rotateEnabled={false} // 禁止旋转

关键代码

rect组件代码

import React, { useState } from 'react';
import { Rect, Transformer } from 'react-konva';
import { Html } from 'react-konva-utils';

const Rectangle = ({
  shapeProps,
  canCancle = false,
  isSelected, onSelect,
  onDel = (v) => { },
  onChange,
  draggable = true, onDragStart = () => { }, onDragEnd = () => { }, onDragMove = () => { } }) => {
  const shapeRef = React.useRef();
  const trRef = React.useRef();
  const [cancelPosition, setCancelPosition] = useState(shapeProps);

  React.useEffect(() => {
    if (isSelected) {
      console.log('shwoProps',shapeProps);
      trRef?.current?.nodes([shapeRef.current]);
      trRef?.current?.getLayer().batchDraw();
    }
  }, [isSelected]);


  return (
    <React.Fragment>
      {
      {/* 删除按钮 */}
        canCancle  && <Html
          divProps={{
            style: {
              position: 'absolute',
              top: cancelPosition.y - 12,
              color: 'red',
              width: '16px',
              height: '16px',
              left: cancelPosition.x + cancelPosition.width + 6,
            },
          }}
        >
        <div className="cancelIcon"></div>
        </Html>
      }

      <Rect
        onDblClick={(e) => {
          onSelect(e);
        }} //  双击选中
        onClick={(e) => {
          onSelect(e);
        }}
        onTap={(e) => {
          onSelect(e);
        }}
        onDragStart={(e) => {
          onDragStart(e);
        }}
        onTransformStart={(e) => {
          onDragStart(e);
        }}
        ref={shapeRef}
        {...shapeProps}
        draggable={draggable}
        onDragMove={(e) => {
          onDragMove();
          onChange({
            ...shapeProps,
            x: e.target.x(),
            y: e.target.y(),
          });
        }}
        onDragEnd={(e) => {
          onDragEnd();
          onChange({
            ...shapeProps,
            x: e.target.x(),
            y: e.target.y(),
          });
        }}
        onTransform={(e) => {
          const node = shapeRef.current;
          const scaleX = node.scaleX();
          const scaleY = node.scaleY();
          node.scaleX(1);
          node.scaleY(1);
          onChange({
            ...shapeProps,
            x: node.x(),
            y: node.y(),
            // set minimal value
            width: Math.max(5, node.width() * scaleX),
            height: Math.max(node.height() * scaleY),
          });
        }}
        onTransformEnd={(e) => {
          const node = shapeRef.current;
          const scaleX = node.scaleX();
          const scaleY = node.scaleY();
          node.scaleX(1);
          node.scaleY(1);
          onChange({
            ...shapeProps,
            x: node.x(),
            y: node.y(),
            // set minimal value
            width: Math.max(5, node.width() * scaleX),
            height: Math.max(node.height() * scaleY),
          });
        }}
      />
      {/* 变形控制 */}
      {isSelected  && (
        <Transformer
          keepRatio={false} //  拖动四角不保存比例
          ref={trRef}
          rotateEnabled={false} //  禁止旋转
          boundBoxFunc={(oldBox, newBox) => {
            // limit resize
            if (newBox.width < 5 || newBox.height < 5) {
              return oldBox;
            }
            return newBox;
          }}
        />
      )}
    </React.Fragment>
  );
};

export default Rectangle;
复制代码
父组件调用
<Rectangle
              key={i}
              shapeProps={{
                ...rect,
                stroke: 'blue',
                strokeWidth: rect?.id === selectedId ? 3 : 1,
                fill: 'transparent'
              }}
              isSelected={rect?.id === selectedId}
              canCancle={rect?.id === selectedId}
              onDel={handleDelRect}
              onSelect={() => {
                onConfirm();
              }}
              onDragStart={() => {
                setIsDragging(true);
              }}
              onDragMove={() => {
                setSelectedRect(rect);
                setSelectedId(rect.id);
              }}
              onDragEnd={() => {
                setSelectedRect(rect);
                setSelectedId(rect.id);
                setIsDragging(false);
              }}
              onChange={(newAttrs) => {
                setRectangles(rects);
                setSelectedRect(rect);
              }}
            />
复制代码
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改