美文网首页
【Canvas】使用Vue3+TS+Canvas实现星星连线

【Canvas】使用Vue3+TS+Canvas实现星星连线

作者: Ringo_ | 来源:发表于2022-08-07 11:29 被阅读0次

    1.效果预览

    动画.gif

    2.实现思路

    1.绘制一颗星星,让这颗星星在画布中运动
    2.在画布中绘制一组星星,每颗星星都在画布中运动
    3.当星星之间的距离小于某个数值时进行连线
    4.当鼠标点击画布时,新增5颗星星到画布中
    5.鼠标移入画布时,在鼠标处新建一颗星星,跟随鼠标移动

    3.实现代码

    1.画布设置

    • 新建画布
    <div class="star_content">
      <canvas id="star_canvas" ref="star_canvas"></canvas>
    </div>
    
    • 给画布设置背景,也可以选择图片背景
    #star_canvas {
      background-color: #333333;
    }
    
    • 设置画布大小,获取上下文对象
    const star_canvas = ref<HTMLCanvasElement>();
    star_canvas.value!.width = 1000;
    star_canvas.value!.height = 800;
    let ctx: CanvasRenderingContext2D;
    ctx = star_canvas.value!.getContext("2d") as CanvasRenderingContext2D;
    
    • 清空画布
    ctx.clearRect(0, 0, 1000, 800);
    
    • 设置画笔的边缘和填充颜色
    ctx.fillStyle = "white";
    ctx.strokeStyle = "white";
    

    2.绘制单个移动的星星

    • 每个星星的结构包含坐标、星星半径和移动速度
    interface Star {
      x: number;
      y: number;
      r: number;
      speedX: number;
      speedY: number;
    }
    
    • 星星的坐标、半径和移动速度都随机生成
    const randomSpeed = () => {
      return Math.random() * 3 * Math.pow(-1, Math.round(Math.random()));
    };
    
    • 生成一颗星星
    const generateStar = () => {
      const star: Star = {
        x: 0,
        y: 0,
        r: 0,
        speedX: 0,
        speedY: 0,
      };
      star.x = Math.random() * 1000;
      star.y = Math.random() * 800;
      star.r = Math.random() * 5;
      star.speedX = randomSpeed();
      star.speedY = randomSpeed();
      return star;
    };
    let star = generateStar();
    
    • 将星星绘制在画布上
    const Draw = (ctx: CanvasRenderingContext2D, star: Star) => {
      ctx.beginPath();
      ctx.arc(star.x, star.y, star.r, 0, Math.PI * 2);
      ctx.fill();
      ctx.closePath();
    };
    Draw(ctx, star);
    
    • 使星星移动,碰到画布边缘时,改变星星的移动方向
    const Move = (star: Star) => {
      star.x -= star.speedX;
      star.y -= star.speedY;
      if (star.x < 0 || star.x > 1000) {
        star.speedX *= -1;
      }
      if (star.y < 0 || star.y > 800) {
        star.speedY *= -1;
      }
    };
    let timer;
    timer = setInterval(() => {
      ctx.clearRect(0, 0, 1000, 800);
      Draw(ctx, star);
      Move(star);
    }, 50);
    

    3.绘制一组星星,在画布中移动

    let starArr: Star[] = [];
    for (let i = 0; i < 20; i++) {
    let star = generateStar();
      starArr.push(star);
    }
    timer = setInterval(() => {
      ctx.clearRect(0, 0, 1000, 800);
      starArr.forEach((star: Star) => {
        Draw(ctx, star);
        Move(star);
      });
    }, 50);
    

    4.判断星星之间的距离,进行连线

    • 两颗星星进行连线
    const DrawLine = (startX: number, startY: number, endX: number, endY: number, ctx: CanvasRenderingContext2D) => {
      ctx.beginPath();
      ctx.moveTo(startX, startY);
      ctx.lineTo(endX, endY);
      ctx.stroke();
      ctx.closePath();
    };
    
    • 判断距离
    starArr.forEach((star: Star, index: number) => {
      for (let i = index + 1; i < starArr.length; i++) {
        if (Math.abs(star.x - starArr[i].x) < 50 && Math.abs(star.y - starArr[i].y) < 50) {
          DrawLine(star.x, star.y, starArr[i].x, starArr[i].y, ctx);
        }
      }
    });
    

    5.点击添加星星和鼠标星星跟随

    • 点击添加星星
    star_canvas.value!.onclick = e => {
      for (let i = 0; i < 5; i++) {
        let star = generateStar();
        star.x = e.offsetX;
        star.y = e.offsetY;
        starArr.push(star);
      }
    };
    
    • 鼠标跟随
    const mouse_star = generateStar();
    mouse_star.speedX = 0;
    mouse_star.speedY = 0;
    star_canvas.value!.onmousemove = e => {
      mouse_star.x = e.offsetX;
      mouse_star.y = e.offsetY;
    };
    timer = setInterval(() => {
      ctx.clearRect(0, 0, 1000, 800);
      // 鼠标star移动
      Draw(ctx, mouse_star);
      // star移动
      starArr.forEach((star: Star) => {
        Draw(ctx, star);
        Move(star);
      });
    
      // 比较star和所有其他star的距离,小于50连线
      starArr.forEach((star: Star, index: number) => {
        for (let i = index + 1; i < starArr.length; i++) {
          if (Math.abs(star.x - starArr[i].x) < 50 && Math.abs(star.y - starArr[i].y) < 50) {
            DrawLine(star.x, star.y, starArr[i].x, starArr[i].y, ctx);
          }
        }
      });
      // 比较鼠标star和所有star的距离
      for (let i = 0; i < starArr.length; i++) {
        if (Math.abs(mouse_star.x - starArr[i].x) < 50 && 
      Math.abs(mouse_star.y - starArr[i].y) < 50) {
          DrawLine(mouse_star.x, mouse_star.y, starArr[i].x, 
      starArr[i].y, ctx);
        }
      }
    }, 50);
    
    • 离开页面前清除定时器
    onBeforeUnmount(() => {
      clearInterval(timer);
    });
    

    3.全部代码

    • index.vue
    <template>
      <div class="star_content">
        <canvas id="star_canvas" ref="star_canvas"></canvas>
      </div>
    </template>
    
    <script setup lang="ts">
    import { onBeforeUnmount, onMounted, ref } from "vue";
    import { Star, Move, Draw, DrawLine, generateStar } from "./index";
    
    const star_canvas = ref<HTMLCanvasElement>();
    let ctx: CanvasRenderingContext2D;
    
    let timer: any;
    
    const initStar = () => {
      ctx = star_canvas.value!.getContext("2d") as CanvasRenderingContext2D;
      ctx.fillStyle = "white";
      ctx.strokeStyle = "white";
      let starArr: Star[] = [];
      for (let i = 0; i < 20; i++) {
        let star = generateStar();
        starArr.push(star);
      }
    
      // 鼠标star
      const mouse_star = generateStar();
      mouse_star.speedX = 0;
      mouse_star.speedY = 0;
      // 鼠标star跟随移动
      star_canvas.value!.onmousemove = e => {
        mouse_star.x = e.offsetX;
        mouse_star.y = e.offsetY;
      };
    
      timer = setInterval(() => {
        ctx.clearRect(0, 0, 1000, 800);
        // 鼠标star移动
        Draw(ctx, mouse_star);
        // star移动
        starArr.forEach((star: Star) => {
          Draw(ctx, star);
          Move(star);
        });
    
        // 比较star和所有其他star的距离,小于50连线
        starArr.forEach((star: Star, index: number) => {
          for (let i = index + 1; i < starArr.length; i++) {
            if (Math.abs(star.x - starArr[i].x) < 50 && Math.abs(star.y - starArr[i].y) < 50) {
              DrawLine(star.x, star.y, starArr[i].x, starArr[i].y, ctx);
            }
          }
        });
        // 比较鼠标star和所有star的距离
        for (let i = 0; i < starArr.length; i++) {
          if (Math.abs(mouse_star.x - starArr[i].x) < 50 && Math.abs(mouse_star.y - starArr[i].y) < 50) {
            DrawLine(mouse_star.x, mouse_star.y, starArr[i].x, starArr[i].y, ctx);
          }
        }
      }, 50);
    
      // 点击添加star
      star_canvas.value!.onclick = e => {
        for (let i = 0; i < 5; i++) {
          let star = generateStar();
          star.x = e.offsetX;
          star.y = e.offsetY;
          starArr.push(star);
        }
      };
    };
    const initCanvas = () => {
      ctx = star_canvas.value?.getContext("2d") as CanvasRenderingContext2D;
      star_canvas.value!.width = 1000;
      star_canvas.value!.height = 800;
      initStar();
    };
    onMounted(() => {
      initCanvas();
    });
    onBeforeUnmount(() => {
      clearInterval(timer);
    });
    </script>
    
    <style lang="less" scoped>
    #star_canvas {
      background-color: #333333;
    }
    </style>
    
    • index.ts
    export interface Star {
      x: number;
      y: number;
      r: number;
      speedX: number;
      speedY: number;
    }
    
    export const generateStar = () => {
      const star: Star = {
        x: 0,
        y: 0,
        r: 0,
        speedX: 0,
        speedY: 0,
      };
      star.x = Math.random() * 1000;
      star.y = Math.random() * 800;
      star.r = Math.random() * 5;
      star.speedX = randomSpeed();
      star.speedY = randomSpeed();
      return star;
    };
    
    export const randomSpeed = () => {
      return Math.random() * 3 * Math.pow(-1, Math.round(Math.random()));
    };
    
    export const Draw = (ctx: CanvasRenderingContext2D, star: Star) => {
      ctx.beginPath();
      ctx.arc(star.x, star.y, star.r, 0, Math.PI * 2);
      ctx.fill();
      ctx.closePath();
    };
    
    export const Move = (star: Star) => {
      star.x -= star.speedX;
      star.y -= star.speedY;
      if (star.x < 0 || star.x > 1000) {
        star.speedX *= -1;
      }
      if (star.y < 0 || star.y > 800) {
        star.speedY *= -1;
      }
    };
    
    export const DrawLine = (startX: number, startY: number, endX: number, endY: number, ctx: CanvasRenderingContext2D) => {
      ctx.beginPath();
      ctx.moveTo(startX, startY);
      ctx.lineTo(endX, endY);
      ctx.stroke();
      ctx.closePath();
    };
    

    相关文章

      网友评论

          本文标题:【Canvas】使用Vue3+TS+Canvas实现星星连线

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