# 使用 Konva.Tween 实现拖拽后的惯性动画

在现代 Web 应用中,为用户提供流畅自然的交互体验至关重要。通过为拖拽操作添加惯性效果,我们可以让应用感觉更加生动和自然。

# 准备工作

在开始之前,确保已安装 Konva.js 库。

npm install konva

或者说直接在 HTML 中直接引用

<script src="https://unpkg.com/konva@8.3.10/konva.min.js"></script>

# 创建场景和节点

  1. 创建一个场景和一个节点,并添加到场景中。
  2. 每次拖拽时都计算速度(与上次拖拽位置的差值)
  3. 创建一个 Tween 对象,并设置其属性为节点的位置和速度
<script src="https://unpkg.com/konva@8.3.10/konva.min.js"></script>
    <div id="container"></div>
    <script>
      // 创建舞台和图层
      const width = window.innerWidth;
      const height = window.innerHeight;
      const stage = new Konva.Stage({
        container: "container",
        width: width,
        height: height,
      });
      let layer = new Konva.Layer();
      stage.add(layer);
      let rect = new Konva.Rect({
        x: 50,
        y: 50,
        width: 100,
        height: 50,
        fill: "green",
        draggable: true,
      });
      layer.add(rect);
      layer.draw();
      let lastTime = 0;
      let lastPos = null;
      let lastVelocity = 0;
      let lastVelocitx = 0;
      function calculateVelocity() {
        if (lastTime) {
          const dt = (Date.now() - lastTime) ;
          const dx = rect.x() - lastPos.x;
          const dy = rect.y() - lastPos.y;
          if (dt === 0) {
            lastVelocitx = 0;
            lastVelocity = 0;
          } else {
            lastVelocitx = dx / dt;
            lastVelocity = dy / dt;
          }
          // console.log('Velocity:', lastVelocity);
        }
        lastTime = Date.now();
        lastPos = { x: rect.x(), y: rect.y() };
      }
      rect.on("dragstart", () => {
        lastTime = Date.now();
        lastPos = { x: rect.x(), y: rect.y() };
      });
      rect.on("dragmove", () => {
        calculateVelocity();
      });
      rect.on("dragend", () => {
        console.log(lastVelocitx, lastVelocity);
        const targetX = rect.x() + lastVelocitx * 100; // 根据速度预测终点
        const targetY = rect.y() + lastVelocity * 100;
        // 使用 Tween 创建惯性动画
        new Konva.Tween({
          node: rect,
          duration: 1, // 动画持续时间
          easing: Konva.Easings.EaseOut, // 缓动函数
          x: targetX,
          y: targetY,
        }).play();
      });
    </script>

# Tween 属性详解

# 核心属性说明

  1. node(必填)

    • 类型: Konva.Node
    • 作用:指定要应用动画的节点对象(如 rect circle 等)
    • 示例: node: rect
  2. duration(必填)

    • 类型: Number
    • 作用:动画持续时间(单位:秒)
    • 示例: duration: 1 表示 1 秒完成动画
    • 注意:结合 easing 函数可实现缓动效果
  3. easing

    • 类型: Function
    • 作用:控制动画的缓动曲线
    • 常用预设:
      • Konva.Easings.Linear 线性匀速
      • Konva.Easings.EaseIn 先慢后快
      • Konva.Easings.EaseOut 先快后慢(适合惯性效果)
      • Konva.Easings.EaseInOut 慢 - 快 - 慢
  4. 目标属性

    • 类型: Number
    • 作用:指定节点要动画到的目标属性值(可设置多个)
    • 示例: x: targetX, y: targetY, rotation: 360

# 高级配置

  1. onFinish

    • 类型: Function
    • 作用:动画结束时的回调函数
    • 示例:
      onFinish: function() {
        console.log('动画完成');
      }
  2. onUpdate

    • 类型: Function
    • 作用:动画每帧更新时的回调
    • 示例:
      onUpdate: function() {
        layer.draw(); // 手动重绘图层
      }
  3. repeat

    • 类型: Number
    • 作用:动画重复次数(0 表示不重复)
    • 示例: repeat: 2 动画将执行 3 次(初始 1 次 + 重复 2 次)
  4. yoyo

    • 类型: Boolean
    • 作用:是否开启往返动画(需要配合 repeat 使用)
    • 示例: yoyo: true 动画会正向播放后反向播放