美文网首页
顺滑的canvas带箭头线条生成

顺滑的canvas带箭头线条生成

作者: 李霖弢 | 来源:发表于2020-12-15 10:23 被阅读0次
  1. 定义一个点位数组并遍历画线
this.lastRoute = [{"left":399,"top":402},{"left":414,"top":393},{"left":430,"top":385},{"left":445,"top":376},{"left":460,"top":368},{"left":481,"top":363},{"left":501,"top":358},{"left":522,"top":354},{"left":541,"top":354},{"left":560,"top":354},{"left":579,"top":354},{"left":599,"top":354},{"left":614,"top":345},{"left":629,"top":336},{"left":645,"top":327},{"left":665,"top":331},{"left":685,"top":330},{"left":706,"top":329},{"left":726,"top":328},{"left":747,"top":328},{"left":767,"top":327},{"left":763,"top":349},{"left":760,"top":371},{"left":756,"top":393},{"left":752,"top":415}];
for (let index = 0; index < this.lastRoute.length - 1; index++) {
  await this.drawLastRoute(index);
}
  1. 通过二次贝塞尔曲线,将当前点作为控制点,当前点和前后两点的中点分别作为起始点和结束点
drawLastRoute(index) {
  return new Promise((resolve) => {
    setTimeout(() => {
      let e0 = {
          left:
            index == 0
              ? this.lastRoute[index].left
              : (this.lastRoute[index - 1].left +
                  this.lastRoute[index].left) /
                2,
          top:
            index == 0
              ? this.lastRoute[index].top
              : (this.lastRoute[index - 1].top +
                  this.lastRoute[index].top) /
                2,
        },
        e1 = {
          left:
            (this.lastRoute[index].left + this.lastRoute[index + 1].left) /
            2,
          top:
            (this.lastRoute[index].top + this.lastRoute[index + 1].top) / 2,
        };

//先画黑色底
      this.context.lineCap = "round";
      this.context.strokeStyle = "#027C4B";
      this.context.lineJoin = "round";

      this.context.lineWidth = 8;
      this.context.moveTo(e0.left, e0.top);

      this.context.quadraticCurveTo(
        this.lastRoute[index].left,
        this.lastRoute[index].top,
        e1.left,
        e1.top
      );
      this.context.stroke();

//再画绿色填充
      this.context.lineCap = "round";
      this.context.strokeStyle = "#01C47A";
      this.context.lineJoin = "round";

      this.context.lineWidth = 6;
      this.context.moveTo(e0.left, e0.top);

      this.context.quadraticCurveTo(
        this.lastRoute[index].left,
        this.lastRoute[index].top,
        e1.left,
        e1.top
      );
      this.context.stroke();

      this.drawArrow(index);

      resolve();
    }, this.moveInterval);
  });
},
  1. 绘制箭头
  • 因上一步中为了能使线条连贯,没有在每一次绘制中重新beginPath,因此每次画线会从头开始再画一遍,覆盖所有已画箭头,所以箭头每次也需要从头画多个
  • 因采用top,与常用数学坐标系y轴方向相反
  • arctan只能返回 -Math.PI/2 ~ Math.PI/2 之间的弧度,因此为下半弧时需增加Math.PI以获得真实的弧度
  • 通过translate设置旋转的圆心
var arrow = new Image();
arrow.src = require("@/assets/img/Nav/arrow.png");
drawArrow(index) {
  for (let i = 0; i < index; i++) {
    if (i % 2 == 0) continue;
    let x1 =
        i == 0
          ? this.lastRoute[i].left
          : (this.lastRoute[i - 1].left + this.lastRoute[i].left) / 2,
      y1 =
        i == 0
          ? this.lastRoute[i].top
          : (this.lastRoute[i - 1].top + this.lastRoute[i].top) / 2,
      x2 = (this.lastRoute[i].left + this.lastRoute[i + 1].left) / 2,
      y2 = (this.lastRoute[i].top + this.lastRoute[i + 1].top) / 2,
      deg = Math.atan((x2 - x1) / (y1 - y2));
    if (y2 > y1) {
      deg = Math.PI + deg;
    }
    this.context.translate(x1, y1);
    this.context.rotate(deg);
    this.context.drawImage(arrow, -3, -3, 6, 6);
    this.context.rotate(-deg);
    this.context.translate(-x1, -y1);
  }
},

也可以使用三次贝塞尔曲线
this.context.bezierCurveTo(cAx, cAy, cBx, cBy, nowX, nowY);
image.png
image.png
  • 边界值计算 : 起点和终点的控制点


相关文章

网友评论

      本文标题:顺滑的canvas带箭头线条生成

      本文链接:https://www.haomeiwen.com/subject/wgiigktx.html