Skip to content

canvas 动画

太阳系动画

注意这两个 API 的使用:

js
// 返回当前时间的秒数,范围 0 - 60
time.getSeconds()
// getMilliseconds() 方法返回一个 0 到 999 的整数。
time.getMilliseconds()
vue
<script setup lang="ts">
import { onMounted } from 'vue';
import { withBase } from 'vitepress'

onMounted(() => {
  // 第一个路径

  const sun = new Image();
  const moon = new Image();
  const earth = new Image();
  init();
  function init(){
    // 加载三张图片
    sun.src = withBase('https://lukecheng2.oss-cn-chengdu.aliyuncs.com/public/img/canvas_sun.png');
    moon.src = withBase('https://lukecheng2.oss-cn-chengdu.aliyuncs.com/public/img/canvas_moon.png');
    earth.src = withBase('https://lukecheng2.oss-cn-chengdu.aliyuncs.com/public/img/canvas_earth.png');
    // 开始绘画
    window.requestAnimationFrame(draw);
  }
  function draw() {
    // 获取画布
    const ctx = (document.getElementById('solar-system') as HTMLCanvasElement).getContext('2d')!
    // 设置合成属性为 destination-over
    ctx.globalCompositeOperation = 'destination-over';
    // 清空画布
    ctx.clearRect(0, 0, 300, 300);
    // 设置填充颜色为带点透明的黑色
    ctx.fillStyle = 'rgba(0, 0, 0, 0.4)';
    // 设置轮廓颜色
    ctx.strokeStyle = 'rgba(0, 153, 255, 0.4)';
    // 第一次保存
    ctx.save();
    // 把坐标系原点移到画布中间
    ctx.translate(150, 150);

    // 绘制地球
    const time = new Date();
    // 60 秒转一圈,也就是说,60 秒旋转的角度有 2 * Math.PI。
    // ((2 * Math.PI) / 60000) * time.getMilliseconds():精确到毫秒。
    // 
    ctx.rotate( ((2 * Math.PI) / 60) * time.getSeconds() + ((2 * Math.PI) / 60000) * time.getMilliseconds() );
    // 把坐标系移到相对于 (150, 150) 的 (105, 0) 处。
    ctx.translate(105, 0); // 不能和上面的 ctx.rotate 调整顺序,否则地球不转了。 
    // 绘制阴影
    ctx.fillRect(0, -12, 50, 24); // Shadow
    // 绘制地球
    ctx.drawImage(earth, -12, -12);

    // 绘制月亮
    // 第二次保存
    ctx.save();
    // 围绕地球旋转。6 秒转一圈,也就是说,6 秒旋转的角度有 2 * Math.PI。
    // 精度也达到毫秒级别。
    ctx.rotate( ((2 * Math.PI) / 6) * time.getSeconds() + ((2 * Math.PI) / 6000) * time.getMilliseconds() );
    // 有调整坐标系原点
    ctx.translate(0, 28.5);
    // 绘制月亮
    ctx.drawImage(moon, -3.5, -3.5);
    // 第一次恢复
    ctx.restore();
    // 第二次恢复
    ctx.restore();

    ctx.beginPath();
    // 绘制地球轨道
    ctx.arc(150, 150, 105, 0, Math.PI * 2, false);
    ctx.stroke();
    // 绘制太阳
    ctx.drawImage(sun, 0, 0, 300, 300);
    // 重复绘画(rotate 会在上一次旋转的基础上进行旋转)
    window.requestAnimationFrame(draw);
  }
})
</script>
<template>
  <div class="border-t-1 border-b-1 border-l-none border-r-none border-solid border-t-gray-700 border-b-gray-700 pa-4 my-4">
    <canvas id="solar-system" width="300" height="300" class="border border-solid border-red">
    </canvas>
  </div>
</template>

时钟

鼠标跟踪动画

c 如何实现 canvas 的拖尾效果?

这里的技巧在于,在重绘制下一帧前,不是调用 clearRect 清除掉上一帧的内容,而是在上一帧基础上加上一个半透明蒙层,然后继续画下一帧。画的帧数多了,也就有了拖尾效果,拖尾效果的长短,跟蒙层的透明度有关,透明度越小,拖尾越长。

https://www.cnblogs.com/imgss/p/10387222.html

Released under the MIT License.