TUTORIAL

react-konva 基于物体(矩形)上左右进行放大缩小

react-konva 基于物体(矩形)上左右进行放大缩小

前言

项目有用到 react-konva,当看到这么一个需求,似乎又得手写拖拽而不能用自带的 Transformer(没看到能自定义四个点的 api),内心:“又不是不能用!”。
1.png

创建拖拽组件

首先创建内容和四个点,这里就用圆点代替拖拽图片,方块代替内容,如何绘制对应的位置。

//物体信息
const position = {
  x: 115,
  y: 43,
  width: 1056,
  height: 31
}

const circleStyle = {
  stroke: '#666',
  fill: '#ddd',
  strokeWidth: 2,
  radius: 8,
  draggable: true,
  dragOnTop: false
}

//计算点的位置
const circleMap = [
  {
    name: 'top',
    x: position => position.x + position.width / 2,
    y: position => position.y
  },
  {
    name: 'right',
    x: position => position.x + position.width,
    y: position => position.y + position.height / 2
  },
  {
    name: 'bottom',
    x: position => position.x + position.width / 2,
    y: position => position.y + position.height
  },
  {
    name: 'left',
    x: position => position.x,
    y: position => position.y + position.height / 2
  }
]

function TransformApp({position, handleDragStart, onDragMove, handleDragEnd}) {

  const _onDragMove = e => {
   // ...
  }

  return (
    <Group>
      <Rect {...position} fill="red" shadowBlur={10}/>
      {circleMap.map((circle, key) => (
        <Circle
          key={key}
          name={circle.name}
          defaultXY={{x: circle.x(position), y: circle.y(position)}}
          x={circle.x(position)}
          y={circle.y(position)}
          onDragStart={handleDragStart}
          onDragMove={_onDragMove}
          onDragEnd={handleDragEnd}
          {...circleStyle}
        />
      ))}
    </Group>
  )
}

function App() {

  const [state, setState] = useState(position)

  const handleDragStart = e => {
    e.target.setAttrs({
      scaleX: 1.2,
      scaleY: 1.2
    })
  }

  const handleDragEnd = e => {
    e.target.to({
      duration: 0.5,
      easing: Konva.Easings.ElasticEaseOut,
      scaleX: 1,
      scaleY: 1,
      shadowOffsetX: 5,
      shadowOffsetY: 5
    })
  }

  return (
    <Stage width={window.innerWidth} height={window.innerHeight}>
      <Layer>
        <TransformApp
          position={state}
          handleDragStart={handleDragStart}
          onDragMove={state => setState(state)}
          handleDragEnd={handleDragEnd}/>
      </Layer>
    </Stage>
  )
}
ReactDOM.render(<App />, document.getElementById('root'))

计算位置

将四个点设置为可移动,并阻止对应方向的拖动,然后的时候改变物体的的信息就可以了,而不需要计算其他三点的位置。

const _onDragMove = e => {
    const {name, x, y, defaultXY} = e.target.attrs
    switch (name) {
      case 'top':
        e.target.setAttrs({
          x: defaultXY.x,
          y
        })
        onDragMove(
          {
            ...position,
            height:
              y < defaultXY.y
                ? position.height + (defaultXY.y - y)
                : position.height - (y - defaultXY.y),
            y:
              y < defaultXY.y
                ? defaultXY.y - (defaultXY.y - y)
                : defaultXY.y + (y - defaultXY.y)
          }
        )
        break
      case 'bottom':
        e.target.setAttrs({
          x: defaultXY.x,
          y
        })
        onDragMove({
          ...position,
          height:
            y > defaultXY.y
              ? y - defaultXY.y + position.height
              : position.height - defaultXY.y + y
        })
        break
      case 'left':
        e.target.setAttrs({
          y: defaultXY.y,
          x
        })
        onDragMove({
          ...position,
          width:
            x > defaultXY.x
              ? position.width - (x - defaultXY.x)
              : position.width + (defaultXY.x - x),
          x:
            x > defaultXY.x
              ? position.x + (x - defaultXY.x)
              : position.x - (defaultXY.x - x)
        })
        break
      case 'right':
        e.target.setAttrs({
          y: defaultXY.y,
          x
        })
        onDragMove({
          ...position,
          width:
            x > defaultXY.x
              ? position.width + (x - defaultXY.x)
              : position.width - (defaultXY.x - x)
        })
        break
      default:
        break
    }
  }

回复

This is just a placeholder img.