포포 일상 블로그

javascript + canvas 마우스 효과 본문

dev/JS

javascript + canvas 마우스 효과

dev포포 2021. 1. 12. 04:02

우연히 마우스 효과를 보게 되어 만들어보고 싶다는 생각이 들어 만들게 되었다.

 

마우스를 따라다니는 원들의 집합인데 사진보다는 실제로 보면 훨씬 이쁘다.

 

바로 시작하겠다.

 

html을 설정한다.

<canvas id="canvas"></canvas>
<script src="app.js" type="module"></script>
<script type="module">
   import App from './app.js';

   new App();
</script>

이번에는 모듈로 사용해서 코드를 작성해봤다.

 

html을 설정은 이게 끝이다.

 

바로 js 모듈로 넘어간다..

 

app.js

import Circle from "./Circle.js";

export default class App {
    constructor() {
        this.canvas = document.getElementById('canvas');
        this.ctx = this.canvas.getContext('2d');
              
        this.width = window.innerWidth;
        this.height = window.innerHeight;

        this.mousePosition = {
            x: 0,
            y: 0
        }

        this.createCount = 5;
        this.circles = [];

        window.addEventListener('mousemove', (e) => {
            this.mousePosition.x = e.clientX;
            this.mousePosition.y = e.clientY;
            for (let i = 0; i < this.createCount; i++) {
                const circleA = new Circle({
                    x: this.mousePosition.x,
                    y: this.mousePosition.y
                });

                this.circles.push(circleA);
            }
        });

        this.resize();
        window.addEventListener('resize', () => {
            this.resize();
        });
        
        requestAnimationFrame(this.render)
    }

    update = () => {
        for (let i = 0; i < this.circles.length; i++) {
            this.circles[i].draw(this.ctx, this.circles);
        }
    }

    render = () => {
        this.ctx.clearRect(0, 0, this.width, this.height);
        this.update();
        requestAnimationFrame(this.render);
    }

    resize = () => {
        this.width = window.innerWidth;
        this.height = window.innerHeight;
        this.canvas.width = this.width;
        this.canvas.height = this.height;
    }
}

바로 직전에 올린 프로젝트 하다가 삘 꽂혀서 하나 더 만들고 나서 글을 올리는 거라 바로 코드를 올리고 설명하는 형태로 작성했다.

 

재밌는 포인트들은 많지만 여기서 중요한 포인트는 마우스가 움직일 때마다 Circle이라는 클래스 인스턴스를 생성하고 x:y를 전달해주고 있구나 정도인 거 같다.

 

Circle.js

import Utils from "./Utils.js";

export default class Circle {
    constructor({ x, y }) {
        this.x = x;
        this.y = y;
        this.dirX = Utils.getDirection();
        this.dirY = Utils.getDirection();
        this.radius = Math.floor(Math.random() * 5) + 5;
        this.step = 1;
        this.opacity = 1;
        this.color = Utils.randomColor();
    }

    draw = (ctx, circles) => {
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
        ctx.fillStyle = `rgba(${this.color},${this.opacity})`;
        ctx.fill();
        this.opacity -= 0.02;

        this.x += this.dirX;
        this.y += this.dirY;

        if (this.opacity <= 0) {
            circles.splice(circles.indexOf(this), 1);
        }
    }
}

작업하다가 원들을 퍼트리는 부분에서 좀 막혔었는데 방식을 찾는데 좀 많이 헤맸다...

우선 생성 시 마우스 좌표 기준으로 x, y가 생성되고 dirX, dirY는 나중에 추가한 개념이었는데 방향(direction)이다.

 

막혔던 부분이 마우스로 잘만 따라가는 데 멋지게 퍼트리고 싶은데 머리가 굳어서... 여러 레퍼런스 찾아보던 중에 여러 구절이 있었지만 그냥 랜덤 한 값을 써서 구분하면 되겠다 싶어서 넣게 되었다.

 

처음 생성될 때 방향이 정해 지므로 지워졌다 그려지면서 그 방향대로 나아가는 듯한 효과를 줄 수 있다.

 

그리고 투명도를 계속해서 줄이고 0 보다 작아지거나 같아지면 circles에서 없앤다. 이렇게 하면 생각보다 너무 쉽게 구현할 수 있다.

 

역시 그냥 보는 것보다 해보면 생각보다 쉬운 듯하다.

 

Utils.js

export default class Utils {
    static randomColor() {
        return `${Math.round(Utils.getRandomArbitrary(0, 255))},${Math.round(Utils.getRandomArbitrary(0, 255))},${Math.round(Utils.getRandomArbitrary(0, 255))}`
    }

    static getRandomArbitrary(min, max) {
        return Math.random() * (max - min) + min;
    }
    
    static getDirection () {
        return (Math.random() * 2) - 1;
    }
}

유틸 클래스는 생각보다 별게 없다 랜덤 값 정도?

 

순서대로 랜덤 컬러 RGB, 최소 ~ 최대 값 랜덤, 랜덤 방향( -1.9 ~ 1.9) 정도로 보면 될 듯?

 

여기까지 잘 따라왔다면

 

 

 

(심플하면서도 화려한) 마우스 이팩트를 보실 수 있습니다.

 

완성 코드 

codepen.io/sinhooking/pen/qBaMQKj

 

javascript + canvas mouse effect

...

codepen.io

근데 js를 모듈 자체로 올리는 법은 몰라서 클래스들을 모아서 올렸습니다..

 

리뷰 및 결론 

 - 하나하나 만들면서 배워가는 이 느낌이 너무 좋다.

 - 생각보다 하고 나면 쉽다?

 - 나중에 해당 기술들을 모아서 토이 프로젝트를 만들어보자.

 - 끄으으으으읕