Fork me on GitHub
COLORFUL 一枚数字艺术家的自留地
2015 - 03 - 05

下面的配图仅供卖萌

很久没有写博客了,今天给大家带来一个小折腾。 虽然说是小折腾,但还是废了不少劲,某位大神的博客写得好: 前端工程师要想脱颖而出,就要拿出草稿纸,所以有了如下这个丑陋无比的配图:

Paper

此次折腾的相关信息如下:

cute-qq-redpoint

SVG + JS 实现新版手机 QQ 的手势消除红点消息的动画。 可以打开手机 QQ,在底部菜单消息一栏的红点上进行拖拽体验。 本插件欲实现的就是这个效果。

原理及部分代码

做的比较粗糙,但是基本效果已经实现了。 通过计算草稿中四个坐标位置,然后在 touchmove 中更新 path d 即可,两条二次贝塞尔曲线是关键。 二次贝塞尔曲线的参考坐标可以轻松得出: 两个圆心相连线的中心即为该参考点。 故得到代码如下:

(function () {
  "use strict";

  var initCircle = document.getElementById("initCircle");
  var finalCircle = document.getElementById("finalCircle");
  var aPath = document.getElementById("animationPath");

  var touchFingers; // 缓存 touches 队列

  // 初始圆坐标
  var x0 = parseInt(initCircle.getAttribute("cx"));
  var y0 = parseInt(initCircle.getAttribute("cy"));
  var r0 = parseInt(initCircle.getAttribute("r"));

  // 最终圆坐标
  var x1;
  var y1;
  var r1 = parseInt(finalCircle.getAttribute("r"));

  //setter
  Element.prototype._setter = function (options) {
    var attr;
    for (attr in options) {
      if (options.hasOwnProperty(attr)) {
        this.setAttribute(attr, options[attr]);
      }
    }
  };

  var updateF = function updateTouches(event) {
    touchFingers = event.touches[0];
  };

  var renderThing = function () {
    x1 = touchFingers.clientX;
    y1 = touchFingers.clientY;

    // 二次贝赛尔曲线参考点
    var pX = x0 - (x0 - x1) / 2;
    var pY = y0 - (y0 - y1) / 2;

    // 勾股 x, y
    var _gX = Math.abs(x0 - x1);
    var _gY = Math.abs(y0 - y1);

    // 勾股定理斜线长度长
    var longL = Math.sqrt(_gX * _gX + _gY * _gY);

    var sinX = _gY / longL;
    var cosX = _gX / longL;

    // 四个点的路径构建
    var fourPoints = [
      "M",
      x0 + r0 * sinX,
      y0 + r0 * cosX,
      "Q",
      pX,
      pY,
      x1 + r1 * sinX,
      y1 + r1 * cosX,
      "L",
      x1 - r1 * sinX,
      y1 - r1 * cosX,
      "Q",
      pX,
      pY,
      x0 - r0 * sinX,
      y0 - r0 * cosX,
      "Z",
    ];

    finalCircle._setter({
      cx: x1,
      cy: y1,
    });

    // 设置路径
    aPath._setter({
      d: fourPoints.join(" "),
    });
  };

  document.addEventListener("touchstart", function (e) {
    e.preventDefault();
    touchFingers = e.touches[0];
  });

  document.addEventListener("touchmove", function (e) {
    e.preventDefault(); // 屏蔽掉默认的滚动行为
    updateF(e);
    renderThing();
  });
})();

演示

用手机打开 codepen 在线 Demo

TODO

  1. 实现弹性系数 K,模拟拉断的情况,加入初始圆的半径缩小控制
  2. 插件化处理

Github

源码地址