react-konva实践:绘制可拖拽、放大缩小操作的矩形

·  阅读 17

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

konva绘制基础矩形

我们需要传入 (x, y) 设置矩形的左上角,并用 width 和 height 设置其的宽高。

import { Rect } from 'react-konva';

<Rect

x={20}

y={50}

width={100}

height={100}

fill="red"

shadowBlur={10}

/>

复制代码

通过设置draggable允许矩形可拖拽,监听onDragMove,onDragEnd,onDragStart等拖拽事件,处理相关逻辑。

<Rect
        onDblClick={onSelect} //  双击选中
        onClick={onSelect}
        onTap={onSelect}
        onDragStart={(e) => {
          onDragStart(e);
        }}
        onTransformStart={(e) => {
        }}
        draggable
        onDragMove={(e) => {
          onDragMove();
        }}
        onDragEnd={(e) => {
          onDragEnd();
        }}
        onTransform={(e) => {
          console.log('onTransform')
          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),
          });
        }}
      />
复制代码

变形组件Transform

基础用法

<Transformer
          ref={trRef}
          rotateEnabled={false} //  禁止旋转
          boundBoxFunc={(oldBox, newBox) => {
            // limit resize
            if (newBox.width < 5 || newBox.height < 5) {
              return oldBox;
            }
            return newBox;
          }}
        />

复制代码

配置参数

  • rotateEnabled 是否允许旋转(false则没有头部的旋转操作标示)

完整示例

import React from 'react';

import { createRoot } from 'react-dom/client';

import { Stage, Layer, Rect, Transformer } from 'react-konva';




const Rectangle = ({ shapeProps, isSelected, onSelect, onChange }) => {

const shapeRef = React.useRef();

const trRef = React.useRef();




React.useEffect(() => {

if (isSelected) {

// we need to attach transformer manually

trRef.current.nodes([shapeRef.current]);

trRef.current.getLayer().batchDraw();

}

}, [isSelected]);



return (

<React.Fragment>

<Rect

onClick={onSelect}

onTap={onSelect}

ref={shapeRef}

{...shapeProps}

draggable

onDragEnd={(e) => {

onChange({

...shapeProps,

x: e.target.x(),

y: e.target.y(),

});

}}

onTransformEnd={(e) => {

// transformer is changing scale of the node

// and NOT its width or height

// but in the store we have only width and height

// to match the data better we will reset scale on transform end

const node = shapeRef.current;

const scaleX = node.scaleX();

const scaleY = node.scaleY();


// we will reset it back

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

ref={trRef}

boundBoxFunc={(oldBox, newBox) => {

// limit resize

if (newBox.width < 5 || newBox.height < 5) {

return oldBox;

}

return newBox;

}}

/>

)}

</React.Fragment>

);

};



const initialRectangles = [

{

x: 10,

y: 10,

width: 100,

height: 100,

fill: 'red',

id: 'rect1',

},

{

x: 150,

y: 150,

width: 100,

height: 100,

fill: 'green',

id: 'rect2',

},

];




const App = () => {

const [rectangles, setRectangles] = React.useState(initialRectangles);

const [selectedId, selectShape] = React.useState(null);




const checkDeselect = (e) => {


const clickedOnEmpty = e.target === e.target.getStage();

if (clickedOnEmpty) {

selectShape(null);

}

};



return (

<Stage

width={window.innerWidth}

height={window.innerHeight}

onMouseDown={checkDeselect}

onTouchStart={checkDeselect}

>

<Layer>

{rectangles.map((rect, i) => {

return (

<Rectangle

key={i}

shapeProps={rect}

isSelected={rect.id === selectedId}

onSelect={() => {

selectShape(rect.id);

}}

onChange={(newAttrs) => {

const rects = rectangles.slice();

rects[i] = newAttrs;

setRectangles(rects);

}}

/>

);

})}

</Layer>

</Stage>

);

};



const container = document.getElementById('root');

const root = createRoot(container);

root.render(<App />);


复制代码

konva实践系列

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改