react-konva实践:实现画布放大缩小功能

·  阅读 43

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

示例

实现功能: 点击放大/缩小按钮实现画布内图片/其他shape跟随比例放大缩小

Aug-12-2022 11-27-30.gif

Aug-12-2022 11-33-16.gif

思路

  • 其他实现思路 通过konva的scale相关api实现

  • 我的方案: (因为有一些其他复杂shape等操作,所以采用该方案)

  1. 封装Stage组件,内含Image、shape等
  2. Stage组件外层容器,控制容器缩放比例
  3. Stage组件内部拿容器的ClientHeight、ClientWidth计算缩放比例
  4. 根据缩放比例对应处理相关shape的attr等属性值

关键代码

组件容器代码
<div className="image-priview"
                  ref={imgScrollBoxRef}
                  style={{ display: 'block', overflow: 'auto' }}
                >
                  <div className="image-box" style={{ width: `${sizes.width}%`, height: `${sizes.height}%`, transform: `rotate(${sizes.deg}deg)`, margin: 'auto' }} ref={imageBoxRef}>
                    <div className="stage-view" id="stage-view" >
                          <ImageStage
                            ImageUrl={selectImgItem.image}
                            ImageWidth={selectImgItem.width}
                            ImageHeight={selectImgItem.height}
                            imageBox={imageBoxRef}
                            sizes={sizes}
                            ref={ImageStageRef}
                          />
                    </div>
                  </div>
                </div>
复制代码
组件代码
useEffect(() => {
// 尺寸变化后重新计算坐标值
      setWidth(ImageBox.current.clientWidth  * sizes.width / lastSize.width);
      setHeight(ImageBox.current.clientHeight * sizes.height / lastSize.height );
      if (rectangles.length > 0) {
        setShapeProps({
          ...shapeProps,
          x: (shapeProps.x * sizes.width / lastSize.width),
          y: (shapeProps.y * sizes.height / lastSize.height),
          width: (shapeProps.width * sizes.width / lastSize.width),
          height: (shapeProps.height * sizes.height / lastSize.height),
        });
      }
      setLastSize(sizes);
    }, [sizes]);
 <Stage
        ref={StageRef}
        onMouseUp={onMouseUp}
        onMousemove={onMousemove}
        onMouseDown={onMouseDown}
        rotation={0}
        width={width}
        height={height}
      >
        <Layer
          width={width}
          height={height}
        >
         {/* 图片底图图层 */}
        <Image
            width={width}
            height={height}
            ref={ImageRef}
            image={image} />
            <Rect
        onClick={(e) => {
        }}
        onTap={(e) => {
        }}
        onDragStart={(e) => {
        }}
        onTransformStart={(e) => {
        }}
        {...shapeProps}
        draggable={draggable}
        onDragMove={(e) => {
        }}
        onDragEnd={(e) => {
        }}
        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;
          }}
        />
        }
        </Layer>
 </Stage
复制代码
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改