코딩 연습장/Javascript

자바스크립트를 이용한 개인 프로젝트 - 4(코코coco 화면)

Do아 2021. 6. 13. 21:41
728x90

2021/04/01(목)

 

 

 

 

자바스크립트를 활용하여 영상처리 프로젝트 : 세번째 메인 화면 구현(세번째 슬라이드)

 

 

 

 

메인화면의 구성같은 경우 그 전에 첫번째 메인화면 구성과 같다

https://cordingdoah.tistory.com/85

 

자바스크립트를 이용한 개인 프로젝트 - 2(인어 공주 화면)

2021/04/01(목) 자바스크립트를 활용하여 영상처리 프로젝트 : 첫 메인 화면 구현(첫 슬라이드) <메인화면의 구성> index.html이라는 메인html 위에 물결이 치는 모습을 구현한 module을 크기에 맞게 띄우

cordingdoah.tistory.com

 

 

 

 

<코드 구현>

<app3.js>

import {BounceString} from './bouncestring.js';

class App3{
    constructor (){
    
    	//캔버스 설정
        this.canvas = document.createElement('canvas');
        document.body.appendChild(this.canvas);
        this.ctx = this.canvas.getContext('2d');
      
	// 현재 표시 장치의 물리적 픽셀과 CSS 픽셀의 비율을 반환
        this.pixelRatio = window.devicePixelRatio > 1 ? 2:1;

        this.strings = [];
        this.moveX = -5000;
        this.moveY = -5000;
        this.isDown = false;
        
	//리사이즈될 때 이벤트
        window.addEventListener('resize', this.resize.bind(this), false);
        this.resize();

	//클릭했을 때 이벤트 구현
        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);

        const xGap = 40;
        const yGap = 40;
        const x1 = xGap;
        const x2 = this.stageWidth - xGap;
        const total = Math.floor((this.stageHeight - yGap)/ yGap);

        this.strings = [];

        for(let i = 0; i< total; i++){
            this.strings[i] = new BounceString(
                {
                    x1: x1,
                    y1: i * yGap + yGap,
                    x2: x2,
                    y2: i * yGap + yGap,
                },
                '#FF9436'
            )
        }
    }

    animate(){
        window.requestAnimationFrame(this.animate.bind(this));
        this.ctx.clearRect(0,0, this.stageWidth, this.stageHeight);

        if(this.strings.length>0){
            for(let i=0; i<this.strings.length; i++){
                this.strings[i].animate(this.ctx, this.moveX, this.moveY);
            }
        }
    }

    onDown(e) {
        this.isDown = true;
        this.moveX = e.clientX;
        this.moveY = e.clientY;
    }

    onMove(e){
        if(this.isDown){
            this.moveX = e.clientX;
            this.moveY = e.clientY;
        }
    }

    onUp(e){
        this.isDown = false;
        this.moveX =-5000;
        this.moveY =-5000;
    }
}

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

 

 

 

 

<bouncestring.js>

import { lineCircle } from "./utils.js";

const BOUNCE = 0.92;

export class BounceString {
    constructor(pos, color){
        
        const middleX = ((pos.x2 - pos.x1)/2) + pos.x1;
        const middleY = ((pos.y2 - pos.y1)/2) + pos.y1;

        this.points = [
        {
            x: pos.x1,
            y: pos.y1,
            ox: pos.x1,
            oy: pos.y1,
            vx: 0,
            vy: 0,
        },
        {
            x: middleX,
            y: middleY,
            ox: middleX,
            oy: middleY,
            vx:0,
            vy:0,
        },
        {
            x: pos.x2,
            y: pos.y2,
            ox: pos.x2,
            oy: pos.y2,
            vx:0,
            vy:0,
        },
        ];

        this.detect = 10;

        this.color = color;
    }

    animate(ctx, moveX, moveY){

        ctx.beginPath();
        ctx.fillStyle = '#FFFFFF';
        
        //20은 줄 갯수
        ctx.arc(moveX, moveY, 20, 0, Math.PI * 2, false);
        ctx.fill();

        ctx.beginPath();
        ctx.strokeStyle = this.color;
        ctx.lineWidth = 4;

        if(lineCircle(
            this.points[0].x,
            this.points[0].y,
            this.points[2].x,
            this.points[2].y,
            moveX,
            moveY,
            this.detect,
        )){
            //줄 흔들림 조절
            this.detect = 300;
            let tx = (this.points[1].ox + moveX) / 2;
            let ty = moveY;
            this.points[1].vx = tx - this.points[1].x;
            this.points[1].vy = ty - this.points[1].y;
        }else{
            this.detect = 10;
            let tx = this.points[1].ox;
            let ty = this.points[1].oy;
            this.points[1].vx += tx - this.points[1].x;
            this.points[1].vx *= BOUNCE;
            this.points[1].vy +=ty - this.points[1].y;
            this.points[1].vy *=BOUNCE;
        }

        this.points[1].x += this.points[1].vx;
        this.points[1].y += this.points[1].vy;

        let prevX = this.points[0].x;
        let prevY = this.points[0].y;
        
        ctx.moveTo(prevX, prevY);

        for(let i =1; i< this.points.length; i++){
            const cx = (prevX + this.points[i].x) / 2;
            const cy = (prevY + this.points[i].y) / 2;

            ctx.quadraticCurveTo(prevX,prevY, cx, cy);

            prevX = this.points[i].x;
            prevY = this.points[i].y;
        }

        ctx.lineTo(prevX, prevY);
        ctx.stroke();
    }

}

 

 

 

 

<utils.js>

export function distance(x1, y1, x2, y2){
    const x = x2 - x1;
    const y = y2 - y1;
    return Math.sqrt(x * x + y * y);
}

export function lineCircle(x1, y1, x2, y2, cx, cy, r){
    const lineLength = distance(x1, y1, x2, y2);
    const point = (((cx - x1) * (x2 - x1)) + 
    ((cy - y1) * (y2 - y1))) / 
    Math.pow(lineLength, 2);
    const pw = x1 + (point * (x2 - x1));
    const py = y1 + (point * (y2 - y1));

    if(distance(pw, py, cx, cy) < r) {
        return true;
    } 
    else{
        return false;
    }

}

 

 

 

참고: 인터렉티브 디벨로퍼

https://www.youtube.com/user/cmiscm

 

Interactive Developer

코드로 만드는 애니메이션, 영감, 실리콘밸리의 생활과 해외취업에 대해 이야기 합니다. https://blog.cmiscm.com/

www.youtube.com

 

728x90