canvas动画 (三)

874 阅读2分钟

箭头跟随动效,这个很有意思的动效,看起来无从下手,实则还真有点难度,难在如下几个知识点

  • 怎么确认箭头方向
  • 怎么画确定方向的箭头
  • 怎么让箭头跟随鼠标方向移动

1、 怎么确认箭头方向?

一个点在另一个点那个方向这个在Math对象有个Math.atan2(y,x)函数可以做到,其定义:Math.atan2 返回从原点(0,0)到(x,y)点的线段与x轴正方向之间的平面角度(弧度值),也就是Math.atan2(y,x);

Math.atan2( -0, -0 )    // -3.141592653589793
Math.atan2( 0, -0 )    // +3.141592653589793

Math.atan2 通过x和y可以得到唯一的弧度值,Math.sin、Math.sin、Math.atan等是无法做到这一效果,因通过相应三角函数值转成弧度值(角度),时可以有两个弧度值可以得到相应三角函数值,所以不好确定

2、 怎么画确定方向的箭头?

这里可能下意识想着上一次箭头方向和现在箭头方向的角度是多少,这样想下去,基本无解,canvas动画和上次的状态是无关的,只要画出现在想要的样子就可以了,每一个当前状态连在一起变成了动画,所以先画出静态的箭头,最简单应该是角度为0的箭头,很快画应该就画完成,再画一个随机角度的箭头,动手起来要点时间,通过sin,cos,tan,和相关箭头的各个点位进行一翻计算后也能画出来,可能如下: 但这样的方式有点繁琐,所以有了这种方式:画一个为角度0的箭头,再旋转对应的角度

注意:canvas画东西要先给状态,后在的画的才有其状态,所以要先旋转画布,再画角度为0的箭头

3、 怎么让箭头跟随鼠标方向移动?

可以理解为怎么让一个箭头沿着一个方向移动,首先这个速度肯定是自定的,所以箭头移动的速度是知道,并且还知道方向(箭头方向),这样就可以直接将速度分解成水平和垂直两个速度,sin、cos很容易就可以得到

x += v * Math.cos(angle)
y += v * Math.sin(angle)

4、完整实现

<template>
	<div id="app">
		<canvas id="canvas"></canvas>
	</div>
</template>
<script>
	class Arrow {
  constructor(x, y, color, angle) {
    //箭头中心x坐标,默认值为0
    this.x = x || 0;
    //箭头中心y坐标,默认值为0
    this.y = y || 0;
    //颜色,默认值为“#FF0099”
    this.color = color || "blue";
    //旋转角度,默认值为0
    this.angle = angle || 0;
  }
  stroke(cxt) {
    cxt.save();
    // 将画布的左上角移至箭头的中心点 从而可旋转使自己不会偏移位置
    cxt.translate(this.x, this.y);
    cxt.rotate(this.angle);
    cxt.strokeStyle = this.color;
    cxt.beginPath();
    cxt.moveTo(-20, -10);
    cxt.lineTo(0, -10);
    cxt.lineTo(0, -20);
    cxt.lineTo(20, 0);
    cxt.lineTo(0, 20);
    cxt.lineTo(0, 10);
    cxt.lineTo(-20, 10);
    cxt.closePath();
    cxt.stroke();
    cxt.restore();
  }
}
export default {
  name: "App",
  mounted() {
    const eleCvas = document.getElementById("canvas");
    const mouse = { x: 0, y: 0 };
    const arrow = new Arrow(150, 75);
    eleCvas.addEventListener("mousemove", event => {
      mouse.x = event.pageX - canvas.offsetLeft;
      mouse.y = event.pageY - canvas.offsetTop;
    });
    const cxt = eleCvas.getContext("2d");
    cxt.fillStyle = "red";
    let v = 2;
    let mousex = 0;
    let mousey = 0;
    (function drawFrame() {
      cxt.clearRect(0, 0, eleCvas.width, eleCvas.height);
      window.requestAnimationFrame(drawFrame);
      if (mouse.x !== mousex || mouse.y !== mousey) {
        mousex = mouse.x;
        mousey = mouse.y;
        arrow.angle = Math.atan2(mouse.y - arrow.y, mouse.x - arrow.x);
      }
      const vx = Math.cos(arrow.angle) * v;
      const vy = Math.sin(arrow.angle) * v;
      arrow.x += vx;
      arrow.y += vy;
      arrow.stroke(cxt);
    })();
  }
};
</script>
<style>
	#app {
		text-align: center;
	}

	canvas {
		border: 1px solid red;
	}
</style>

代码地址

每个点门路清,实现起来就简单了,这是一个很基础的动效,当动手去实现时,你会发现很多细小的知识点;其它跟随动效基本就有思路了,那双球跟随动效怎么做了? 相关