什么是 Konva

Konva.js 是一个 H5 Canvas 的 JavaScript 框架,我们可以通过制作桌面端和移动端的 apps。

Konva 支持动画、转换、节点嵌套、图层、过滤、缓存、事件(桌面端和移动端)等。在 Konva 中,所有的图形都存在于 stage 中,即便是你的 app 使用了成百上千的 shapes(图形)也可以在 stage 中许多与图形对应的多个事件,以实现移动、缩放、旋转等功能。

Konva 的结构

              Stage
         +------+------+
         |             |
       Layer         Layer
         |             |
   +-----+-----+     Shape
   |           |
 Group       Group
   |           |
   +       +---+---+
   |       |       |
Shape   Group    Shape
         Shape

Stage(容器)

在 Konva 中,一切的开端始于 Konva.Stage 这个类,它包含了用户定义的 Konva.Layer,可以说 Stage 是 Konva 的容器,我们的图形都存在于这里面。

在 H5 中,Stage 表现为一个普通的 div 标签,例如,创建一个 Konva 容器:

file:[创建 Konva.Stage]
  <div id="container"></div>
  <script>
    // stage 是一个容器,装所有的 layer
    const stage = new Konva.Stage({
      container: "container", // id 选择器
      width: window.innerWidth,
      height: window.innerHeight
  </script>
</body>

Layer(图层)

如上结构所示,Stage 下面有许多 Layer(图层),图层在 PS、绘画中很容易出现,我们可以理解图层中包含了许多的 Shapes(图形)、组(Group)。

<div id="container"></div> <script> // stage 是一个容器,装所有的 layer const stage = new Konva.Stage({ container: "container", width: window.innerWidth, height: window.innerHeight // 创建图层1 const layer1 = new Konva.Layer(); // 创建 rect1 const rect1 = new Konva.Rect({ x: 20, y: 20, width: 100, height: 50, fill: "green", stroke: "black", strokeWidth: 2 // 把 rect1 添加到图层1中,一个图层有许多的图形、组。 layer1.add(rect1); const layer2 = new Konva.Layer(); const rect2 = new Konva.Rect({ x: 150, y: 40, width: 100, height: 50, fill: "red", shadowBlur: 10, cornerRadius: 10 layer2.add(rect2); const layer3 = new Konva.Layer(); const rect3 = new Konva.Rect({ x: 50, y: 120, width: 100, height: 100, fill: "blue", cornerRadius: [0, 10, 20, 30] const rect4 = new Konva.Rect({ x: 250, y: 150, width: 100, height: 100, fill: "#525288", cornerRadius: 5 layer3.add(rect3); layer3.add(rect4); // 把图层1、2、3添加到容器中 stage.add(layer1); stage.add(layer2); stage.add(layer3); </script> </body>

JS 代码解释

如上所示中,我创建了三个 Layer,每一个图层都有一个矩形(Shape),Layer 图层创建好了之后把它放入 Stage 中。

每一个图形都可以自定义样式,如圆角、填充颜色、宽度、高度等。

H5 结构解释

如上图所示,容器下面有三个 canvas 标签,正好对应了我们三个图层(Layer),图层中有自己的图形(Shape)。

我们可以很容易地使用 Konva 提供的输入事件:click(点击)、dblclick(双击)、mouseover(鼠标移入)、tap(移动端点击)、dbltap(移动端双击)、touchstart(点击开始)。

以及,属性点击事件:sacleXChange、FillChange;拖拽&松手事件:dragstart、dragmove、dragend。

const rect4 = new Konva.Rect({
  x: 250,
  y: 150,
  width: 100,
  height: 100,
  fill: "#525288",
  cornerRadius: 5
rect4.on("mouseout", e => {
  console.log(e);
rect4.draggable("true");

Konva.js 有两种方式创建动画,这里我演示其中一种:通过 Konva.Animation 类实现。另一种方式查看官方文档:Konva - Animation

const layer = new Konva.Layer();
const rect = new Konva.Rect({
  x: 250,
  y: 150,
  width: 100,
  height: 100,
  fill: "#525288",
  cornerRadius: 5
layer.add(rect);
const animation = new Konva.Animation(frame => {
  const B = frame.time / 2000;
  const radian = 2 * Math.PI;
  rect.x(200 * Math.sin(radian * B));
}, layer);
animation.start();

Konva.Animation 对象中传递一个回调函数以及第二个参数图层对象(Layer),在前面中说到,一个图层在 H5 中就是一个 canvas 标签(Canvas 对象)。我认为,一个图层拥有一个动画比较合理。

tip:[start]在使用 Konva.Animation 创建动画时,针对的是一个图层(Layer),也就是一个 Canvas 中对应一个动画,每过一个帧就会执行一次回调,所以在回调中改变某图层的图形 tip:[end]

分析回调代码

const animation = new Konva.Animation(frame => {
  const B = frame.time / 2000;
  const radian = 2 * Math.PI;
  rect.x(200 * Math.sin(radian * B));
}, layer);

一旦程序运行,Konva.Animation 就会每一帧执行一次回调函数并传递一个变量 frame,这个 frame 包含了从开始到现在距离的毫秒数(也就是从程序开始到目前已经过去了多少毫秒)。

在回调中,我修改 rect 图形的 x 轴,使其能够周期性地、规律地、连续地运动,我们可以通过 Math.sin(正弦函数)或者 Math.cos(余弦函数)来让它保持一个周期性地、规律地、连续地运动。cos 和 sin 都是连续的函数,tan 函数周期之间有断开,不适合做一个连续地运动。

frame.time 来自于 Animation 回调的变量,只需调节 2000 这个值的大小就可以改变这个图形动画运行的速度(快慢)。

sin 函数

\[y = A * sin(B * x)
  • 振幅 A 影响 sin 函数的谷峰和谷底之间的差距。意思是说,A 越大,两者距离越高,那么这个图形水平移动的距离就越长,反之越短。
  • 周期因子 B 决定了正弦函数图像重复自身的水平距离。意思是说,B 越大,一个周期就拉的越长,图形从一个周期开始到周期结束的水平距离就越长,那么这个图形在一个周期内走完所需要的时间就越长,反之越短。
  • 因此,B 才是影响动画快慢的变量。