canvas背景圆球移动

要展示的页面

import {useEffect,useRef} from "react";
import {BGAnimate} from "../../types/CanvasAnimation.ts";
function Home(){
    const bgAnimate = useRef<BGAnimate>(null)
    const bgCanvasRef = useRef<HTMLCanvasElement>(null)
    useEffect(() => {
        bgAnimate.current = new BGAnimate(bgCanvasRef.current!);
        // 创建50个小球
        for(let i=0;i<50;i++){
          bgAnimate.current.createCircle(10)
        }
        // 小球开启运动
        bgAnimate.current.start();
    }, []);

    return (
        <>
            <canvas ref={bgCanvasRef}></canvas>
        </>
    )

}

export  default Home;

主要代码

const CIRCLE_LEN = 16; // 两个小球多长距离内会连线

class Circle {
    x: number;
    y: number;
    r: number;
    sleepX: number;
    sleepY: number;
    color: string;
    width: number;
    height: number;
    isSelect:boolean;//是否选中

    constructor(x: number, y: number, r: number, width: number, height: number) {
        this.x = x;
        this.y = y;
        this.r = r;
        this.sleepX = this.getRandom();
        this.sleepY = this.getRandom();
        this.width = width;
        this.height = height;
        this.isSelect = false;
        this.color = this.getColor();
    }

    setSleep() {
        if (this.x < 0 || this.x > this.width) {
            this.sleepX = -this.sleepX;
        }
        if (this.y < 0 || this.y > this.height) {
            this.sleepY = -this.sleepY;
        }
    }

    move() {
        if(this.isSelect) return;

        this.setSleep()
        this.x += this.sleepX;
        this.y += this.sleepY;
    }
    getColor(){
        const r = Math.random()*255;
        const g = Math.random()*255;
        const b = Math.random()*255;
        return `rgb(${r},${g},${b}`;
    }
    // 生成随机数
    getRandom() {
        return Math.random() * 3 + 1;
    }
    // 两个球是否相近
    circleAichika(ctx:CanvasRenderingContext2D,circle:Circle){
        // if(this.x)
        // 当前点的坐标
        const w = Math.abs(this.x-circle.x);
        const h = Math.abs(this.y-circle.y);
        // 目标坐标
        const len = Math.sqrt(w+h);
        if(len<=CIRCLE_LEN){//画线
            this.drawLine(ctx,circle);
        }
    }

    drawLine(ctx:CanvasRenderingContext2D,circle:Circle){
        ctx.beginPath();
        ctx.lineWidth=0.5;
        ctx.strokeStyle="#535c68";
        ctx.moveTo(this.x,this.y);
        ctx.lineTo(circle.x,circle.y);
        ctx.stroke();
        ctx.closePath();
    }

}

export class BGAnimate {
    private canvas: HTMLCanvasElement;
    private ctx: CanvasRenderingContext2D;
    private circles: Circle[];
    private width: number;
    private height: number;

    constructor(canvas: HTMLCanvasElement) {
        const {clientWidth, clientHeight} = document.documentElement;
        this.canvas = canvas;
        this.width = clientWidth;
        this.height = clientHeight;
        this.init();

        this.ctx = canvas.getContext("2d")!;

        this.circles = [];
    }

    init() {
        this.canvas.width = this.width;
        this.canvas.height = this.height;
        this.canvas.style.position = "absolute";
        this.canvas.style.top = "0";
        this.canvas.style.left = "0";
        this.canvas.style.width = this.width + "px";
        this.canvas.style.height = this.height + "px";
        this.canvas.style.background = "#2c3e50";
        this.canvas.addEventListener("mousemove",e=>{
            // 得到当前坐标
            const {clientX:x,clientY:y} = e;
            this.circles.forEach(circle=>{
                if(circle.isSelect){
                    if(x>circle.x-circle.r&&x<circle.x+circle.r&&
                        y>circle.y-circle.r&&y<circle.y+circle.r){
                        circle.isSelect = true;
                        return;
                    }
                        circle.isSelect = false;

                }
                if(x>circle.x-circle.r&&x<circle.x+circle.r&&
                y>circle.y-circle.r&&y<circle.y+circle.r){
                    circle.isSelect = true;
                }
            })
        })
    }

    createCircle( r: number) {
        const circle = new Circle(Math.random()*this.width, Math.random()*this.height, r, this.width, this.height);
        this.circles.push(circle)
        this.draw(circle);
    }

    // 开始移动
    start() {
        this.move();
        requestAnimationFrame(() => {
            this.start();
        })
    }

    // 移动
    move() {
        this.ctx.clearRect(0, 0, this.width, this.height)
        this.circles.forEach(circle => {
            circle.move();
            this.circles.forEach(v=>{
                circle.circleAichika(this.ctx,v);
            })
            this.draw(circle)
        })
    }

    //绘画
    draw(circle: Circle) {
        this.ctx.beginPath();
        this.ctx.arc(circle.x, circle.y, circle.r, 0, Math.PI * 2);
        this.ctx.fillStyle = circle.color;
        this.ctx.fill();
        this.ctx.closePath();

    }


}

鼠标停留在某个小球上 可以让他暂停


 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值