konvajs使用

konvajs提供了一系列接口,快捷便利得生成canvas图形,大大缩短了手搓canvas的开发工作量。

中文官网指路:文档 | Konva 中文文档 中文API

官网指路:

https://konvajs.org/api/Konva.Stage.html

安装

npm install konva

Konva 的对象是以一颗树的形式保存的,Konva.Stage 是树的根节点,Stage 子节点是用户创建的图层 (Konva.Layer)。

每一个 layer 有两个 <canvas> 渲染器: 场景渲染器 和 图像命中检测渲染器。场景渲染器输出你所看见的内容,图像命中渲染器在隐藏的 canvas 里用于高性能的检测事件。

图层可以包含图形、嵌套图形的组、嵌套组的组。Stage(舞台),layers(图层),groups(组),和 shapes(图形) 都是虚拟节点,类似于 HTML 的 DOM 节点。

stage创建

let stage = new konva.Stage({

      container: "container",//dom id

});

Layer创建

const mapLayer = useRef<konva.Layer>(); //定义

mapLayer.current = new konva.Layer();//创建实例

stageRef.current.add(mapLayer.current);//加入stage

外部Image引入 

//roubotIconRef:承载图片的图层

 konva.Image.fromURL(‘图片地址’, (image: konva.Image) => {

      image.setAttrs({

        width: 30,

        height: 30,

      });

      if (roubotIconRef.current) {

        roubotIconRef.current.add(image);

      }

    }); 

一些常用方法 

1.调整元素参数:setAttrs

对于layer上的元素,可以通过setAttrs调整对应参数

通过该函数可以在元素初始化后操作元素

部分参数:

draggable

是否可拖动
x元素对应stage左上角的横坐标
y元素对应stage左上角的纵坐标

scale

{x:0.5,y:0.6}--x:横向缩放;y:纵向缩放

width

元素宽
height元素高

offset

{x:12,y:14}  相对于当前位置的横纵偏移量

rotation

旋转角度

strokeWidth

线的宽度

fill

填充颜色

stroke

线的颜色

closed

线条是否为封闭
...

可修改的参数为当时创建实例时的参数,不同实例有部分参数不同,可参考官网开发 

例子:

 robotImg.current.setAttrs({

        x: 300,

        y: 400,

        scale: {

          x: 0.5 / (stageRef?.current?.scaleX() || 1),

          y: 0.5 / (stageRef?.current?.scaleX() || 1),

        },

        width: 35,

        height: 35,

        offset: { x: 12, y: 14 },

        rotation: (90 / Math.PI) * 180,

 });

2. 清空图层 destroyChildren

该函数可清空图层上的一切元素

roubotIconRef.current.destroyChildren();

 3.向layer上增加元素add

可单添加也可批量加,后加入的层级高

add(元素1,元素2,元素3......)

roubotIconRef.current.add(image)

4.获取图层上的全部元素 getChildren

返回结果是一个元素数组,我们可以对每个元素进行指定操作

 lineLayerRef.current.getChildren().forEach((item: any) => {

      item.setAttrs({

        strokeWidth: 1 / (stageRef?.current?.scaleX() || 1),

      });

 });

5.克隆已有实例clone 

有时候会重复使用相同的实例,不必每次都去new一个新的,使用clone就可以克隆已有实例

使用场景:

  • 重复使用一张图片,可初始就使用konva.Image.fromURL将图片加载好
  • 同时生成大量实例,且大部分参数相同

 let clone = image.clone({

      x: 300,

      y: 400,

 });

6. imageSmoothingEnabled设置图片缓存

.imageSmoothingEnabled 是 Canvas 2D API 用来设置图片是否平滑的属性,true表示图片平滑(默认值),false表示图片不平滑。当我们获取 imageSmoothingEnabled属性值时, 它会返回最新设置的值。

以缩放画布为例,这个属性对像素为主的游戏很有用。默认的改变大小的算法会造成图片模糊并且破坏图片原有的像素。 如果那样的话,设置属性值为false。

mapLayer.current.imageSmoothingEnabled(false);

事件监听 

Konva 支持的事件类型有 mouseovermouseoutmouseentermouseleavemousemovemousedownmouseupwheelclickdblclickdragstartdragmove,dragend

Konva 支持的移动端事件类型有 touchstarttouchmovetouchendtapdbltapdragstartdragmovedragend

加入事件:

两种写法

 factorLayerRef.current?.on("tap", function (evt) { });

 stageRef.current

      ?.getContent()

      .addEventListener("touchstart", function (evt: any) {

...

  });

移除事件

  factorLayerRef.current?.off("tap");

stageRef.current

      ?.getContent()

      .removeEventListener("touchstart")

双指缩放

  var lastDist = 0;
  var lastCenter: any = null;
    function getDistance(p1: any, p2: any) {
      return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
    }

    function getCenter(p1: any, p2: any) {
      return {
        x: (p1.x + p2.x) / 2,
        y: (p1.y + p2.y) / 2,
      };
    }

    stageRef.current
      ?.getContent()
      .addEventListener("touchmove", function (evt: any) {
        evt.preventDefault();
        var touch1 = evt.touches[0];
        var touch2 = evt.touches[1];
        if (touch1 && touch2) {
          // if the stageRef.current? was under Konva's drag&drop
          // we need to stop it, and implement our own pan logic with two pointers
          if (stageRef.current?.isDragging()) {
            stageRef.current?.stopDrag();
          }
          var p1 = {
            x: touch1.clientX,
            y: touch1.clientY,
          };
          var p2 = {
            x: touch2.clientX,
            y: touch2.clientY,
          };
          if (!lastCenter) {
            lastCenter = getCenter(p1, p2);
            return;
          }
          var newCenter = getCenter(p1, p2);
          var dist = getDistance(p1, p2);
          if (!lastDist) {
            lastDist = dist;
          }
          // local coordinates of center point
          var pointTo = {
            x:
              (newCenter.x - stageRef.current!.x()) /
              stageRef.current!.scaleX(),
            y:
              (newCenter.y - stageRef.current!.y()) /
              stageRef.current!.scaleX(),
          };
          var scale = stageRef.current!.scaleX() * (dist / lastDist);
          stageRef.current!.scaleX(scale);
          stageRef.current!.scaleY(scale);
          // calculate new position of the stageRef.current!
          var dx = newCenter.x - lastCenter.x;
          var dy = newCenter.y - lastCenter.y;
          var newPos = {
            x: newCenter.x - pointTo.x * scale + dx,
            y: newCenter.y - pointTo.y * scale + dy,
          };
          stageRef.current!.position(newPos);
          lastDist = dist;
          lastCenter = newCenter;
          changeStage();
        }
      });
 stageRef.current
      ?.getContent()
      .addEventListener("touchend", function (evt: any) {
        lastDist = 0;
        lastCenter = null;
      });

鼠标中心点缩放

  let StageScale = useRef(1);    

// 画布缩放
    stageRef.current?.on("wheel", (e: any) => {
      e.evt.preventDefault();
      const pointerPos = stageRef.current!.getPointerPosition();
      if (!pointerPos) return;
      const oldScale = StageScale.current;
      const delta = e.evt.deltaY > 0 ? -1 : 1;
      StageScale.current += delta * 0.1;
      StageScale.current = Math.max(0.1, Math.min(5, StageScale.current));
      const newPos = {
        x: (pointerPos.x - stageRef.current!.x()) / oldScale,
        y: (pointerPos.y - stageRef.current!.y()) / oldScale,
      };
      stageRef.current!.x(-(newPos.x * StageScale.current - pointerPos.x));
      stageRef.current!.y(-(newPos.y * StageScale.current - pointerPos.y));
      stageRef.current!.scale({ x: StageScale.current, y: StageScale.current });
      changeStage();
    });

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值