글 작성자: 택시 운전사
반응형

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>test</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <script type="module" src="app.js"></script>
</body>
</html>

app.js

import { Polygon } from "./polygon.js"

class App {
    constructor() {
        this.canvas = document.createElement('canvas');
        document.body.appendChild(this.canvas);
        this.ctx = this.canvas.getContext('2d');

        this.pixelRatio = window.devicePixelRatio > 1 ? 2 : 1;

        window.addEventListener('resize', this.resize.bind(this), false);
        this.resize()

        this.isDown = false;
        this.moveX = 0;
        this.offsetX = 0;

        document.addEventListener('pointerdown', this.onDown.bind(this), false);
        document.addEventListener('pointermove', this.onMove.bind(this), false);
        document.addEventListener('pointerup', this.onUp.bind(this), false);

        window.requestAnimationFrame(this.animate.bind(this));
    }

    resize() {
        this.stageWidth = document.body.clientWidth;
        this.stageHeight = document.body.clientHeight;

        this.canvas.width = this.stageWidth * this.pixelRatio;
        this.canvas.height = this.stageHeight * this.pixelRatio;

        this.ctx.scale(this.pixelRatio, this.pixelRatio)

        this.polygon = new Polygon(
            this.stageWidth / 2,
            this.stageHeight + (this.stageHeight/2),
            this.stageHeight / 1.5,
            15
        )
    }
    animate(ctx, moveX) {
        window.requestAnimationFrame(this.animate.bind(this));

        this.ctx.clearRect(0,0, this.stageWidth, this.stageHeight);

        this.moveX *= 0.9;

        this.polygon.animate(this.ctx, this.moveX)
    }

    onDown(e) {
        this.isDown = true
        this.moveX = 0;
        this.offsetX = e.clientX;
    }
    onMove(e) {
        if(this.isDown){
            this.moveX = e.clientX - this.offsetX;
            this.offsetX = e.clientX
        }
    }
    onUp(e) {
        this.isDown = false
    }

}

window.onload = () => {
    new App();
}

polygon.js

const PI2 = Math.PI * 2;

const COLORS = [
    '#ca00d5',
    '#ef3e2f',
    '#b05af2',
    '#e8c476',
    '#e8bcf4',
    '#615118',
    '#fca6dd',
    '#ddccbd',
    '#e6cbeb',
    '#81156a',
    '#eba118',
    '#7956ed',
]

export class Polygon {
    constructor(x, y, radius, sides, rotate){
        /** 도형 중앙 x좌표 */
        this.x = x;
        /** 도형 중앙 y좌표 */
        this.y = y;
        /** 반지름 */
        this.radius = radius;
        /** 각의 수 */
        this.sides = sides;
        /** 회전한 각도 */
        this.rotate = 0
    }

    animate(ctx, moveX) {
        ctx.save();

        /** 360도를 각의 수만큼 나눈 각도 */
        const angle = PI2 / this.sides;
        const angle2 = PI2 / 4;

        /** (x, y)만큼 기준점 이동 */
        ctx.translate(this.x, this.y);

        this.rotate -= moveX * 0.008;
        ctx.rotate(this.rotate);

        for(let i = 0 ; i < this.sides ; i++){
            /** 각도별 도형의 중앙 x좌표 */
            const x = this.radius * Math.cos(angle * i);
            /** 각도별 도형의 중앙 y좌표 */
            const y = this.radius * Math.sin(angle * i);

            ctx.save();

            ctx.fillStyle = COLORS[i]
            /** 전체 polygon의 중심에서 (x,y)만큼 기준점 이동  */
            ctx.translate(x,y)
            /** 각도에 따라 자식 도형의 회전각도도 달라져야한다. */
            ctx.rotate(((360/this.sides) * i+45) * Math.PI / 180);

            ctx.beginPath();
            for(let j = 0;j<4;j++){
                const x2 = 160 * Math.cos(angle2 * j);
                const y2 = 160 * Math.sin(angle2 * j);
                /** 자식 정사각형 그리기 */
                (j == 0) ? ctx.moveTo(x2, y2) : ctx.lineTo(x2,y2);
            }
            ctx.fill();
            ctx.closePath();
            ctx.restore();
        }

        ctx.restore();
    }
}

결과물

반응형