HTML5 Canvas로 밤하늘 그리기

개발

HTML5 Canvas로 밤하늘 그리기
최종 수정일:

https://codesandbox.io/s/z68y1012yl 참고한 글
https://github.com/marshallku/canvas-night-sky 깃허브

여름도 왔고, 호텔 델루나 보다 보니 보름달이 뜬 밤하늘이 예뻐서 인터넷 뒤적이며 만들어 봤습니다.
어디에 써먹을지 고민을 좀 해봤는데, 막상 써먹을 데가 없는 게 아쉽네요. ㅠㅠ

HTML에 nightsky란 ID를 지닌 canvas 추가하시고 아래 스크립트만 붙여 넣으셔도 작동합니다.

const width = window.innerWidth,
    height = window.innerHeight,
    stars = createStars(width, height, 30),
    moon = {
        x: 0,
        y: height / 2,
        r: 45,
    },
    canvas = document.getElementById("nightsky"),
    ctx = canvas.getContext("2d");
let counter = 0,
    time = 0;
 
function random(max) {
    return Math.floor(Math.random() * max);
}
 
function createStars(width, height, spacing) {
    const stars = [];
 
    for (let x = 0; x < width; x += spacing) {
        for (let y = 0; y < height; y += spacing) {
            const star = {
                x: x + random(spacing),
                y: y + random(spacing),
                r: Math.random() * 1.5,
            };
            stars.push(star);
        }
    }
    return stars;
}
 
function fillCircle(ctx, x, y, r, fillStyle) {
    ctx.beginPath(), (ctx.fillStyle = fillStyle), ctx.arc(x, y, r, 0, Math.PI * 2), ctx.fill();
}
 
function getOpacity(factor) {
    const opacityIncrement = 0.6 * Math.abs(Math.sin(factor)),
        opacity = 0.1 + opacityIncrement;
    return opacity;
}
 
function render() {
    const gradient = ctx.createLinearGradient(0, 0, 0, height);
    let newX = time / 10 - 45;
    gradient.addColorStop(0, "#00111e");
    gradient.addColorStop(1, "#0a2342");
    //배경 그래디언트
    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, width, height);
    stars.forEach(function (star, i) {
        const factor = counter * i,
            x = star.x,
            y = star.y,
            opacity = getOpacity(factor),
            randomColor = Math.floor(Math.random() * 360 + 1);
 
        fillCircle(ctx, x, y, star.r, `hsla(${randomColor}, 30%, 80%, ${opacity})`); //별 그리기
    });
 
    newX <= width + 90 // window 너비에 달 지름 추가
        ? ((moon.x = newX), (moon.y = newY(newX)), (time += 5))
        : (time = 0),
        // 달에 애니메이션 추가
 
        fillCircle(ctx, moon.x, moon.y, moon.r, "#f5f3ce"); // 달 그리기
 
    counter++;
    requestAnimationFrame(render);
}
 
function newY(x) {
    return Math.pow(x - width / 2, 2) / 9000 + height / 2 + 1;
}
 
(canvas.width = width), (canvas.height = height), render();

살면서 2차 함수 그래프를 다시 그릴 날이 올 줄 누가 알았겠습니까…ㅋㅋㅋ
달 애니메이션엔 2차 함수 그래프가 제일 어울릴 것 같아 2차 함수 그래프 모양으로 움직이도록 해뒀습니다.

Report an issue
Marshall Ku