Konva 实战篇(二)-- Transformer托拉拽

1,862 阅读1分钟

Transformer是基于Group创建的一个组件,主要负责拖拽、缩放、旋转,只需要自己把形状放到这个组里面进行操作。[官方文档]

接下来我们需要以下几步操作:点选形状、多选形状、取消选中、框选、全选、缩放、旋转。
1、点选形状:点击形状添加到group中
2、多选形状:可以通过shift + 点击 把形状添加group中
3、取消选中:如果已经添加到group中 就把他移出group
4、框选:可以用鼠标左键把框选的形状添加到group中
5、全选:可以通过ctrl + a 把所有的形状添加到group中

我们接着上一篇的代码的基础上加代码

1、创建Transformer

private _transformer: Konva.Transformer | undefined;

public get transformer(): Konva.Transformer {
    if (this._transformer === undefined) {
      this._transformer = new Konva.Transformer();
    }
    return this._transformer;
}

public set transformer(v: Konva.Transformer) {
    this._transformer = v;
}

2、 添加点击选中和框选

setStage(){
    // 1、在舞台添加监听点击事件
    this.stage.on("click tap",(e)=>{
        // 2、判断点击的是否是匹配的对象
        if(e.target === this.stage){
            // 如果是舞台就清空
            this.transformer.nodes([]);
            return;
        }
        if (this.transformer.children?.indexOf(e.target) !== -1) {
          // 不能点击自身
          return;
        }
        // 3、判断是否是多选
        if (e.evt.shiftKey){
          let nodes = this.transformer.nodes();
          let index = nodes.indexOf(e.target);
          // 判断是否添加到group中,用于取消选中
          if (index != -1) {
            let ns = nodes.filter((n) => n != e.target);
            this.transformer.nodes(ns);
          } else {
            let ns = nodes.concat([e.target]);
            this.transformer.nodes(ns);
          }
        }else{
          this.transformer.nodes([e.target]);
        }
    })
    
    // 5、框选
    rect:{x:number,y:number,width:number,height:number} = {x:0,y:0,width:0,height:0}
    this.stage.on("mousemove mousedown mouseup",(e)=>{
        let offset = this.byOffset(e.evt.offsetX, e.evt.offsetY);
        if (e.type === "mousedown") {
          rect.x = offset.x
          rect.y = offset.y
        } else if (e.type === "mouseup") {
          rect.width = offset.x - start.x
          rect.height = offset.y - start.y
          if (this.layer.children != undefined) {
          let ns: any = [];
          ns = this.layer.children.filter(
            (n) => this.isRectOn(rect, n.getClientRect())
          );
          this.transformer.nodes(ns);
        }
        }
    })
    // 判断矩阵相交
    isRectOn(rect1,rect2): boolean{
        return !(
          rect2.x + rect2.width < rect1.x ||
          rect2.x > rect1.x + rect1.width ||
          rect2.y + rect2.height < rect1.y ||
          rect2.y > rect1.y + rect1.height
        );
    }
    // 计算偏移量后的位置
    byOffset(
        x: number,
        y: number
      ): {
        x: number;
        y: number;
      } {
        x = (x - this.stage.x()) / this.stage.scaleX();
        y = (y - this.stage.y()) / this.stage.scaleY();
        return { x, y };
      }
}

3、添加全选功能

init(){
    // 4、全选 
    document.onkeydown = (e) => {
        if(e.key === "a" && (e.metaKey || e.ctrlKey)){
            if (this.layer.children === undefined) {
              return;
            }
            let all = this.layer.children.filter(
              (e) => true
            );
            this.transformer.nodes(all);
            this.transformer.moveToTop();
        }
    };
}

5、开始使用

this.layer.add(this.transformer)

上一章 目录 下一章

有用到konvajs的小伙伴可以点赞收藏❤️