여러 HTML5 캔버스 개체를 차례로 애니메이션하는 방법은 무엇입니까?

마티아스 리델

HTML5 캔버스와 JavaScript를 사용하여 애니메이션을 만들고 싶습니다. 아이디어는 다음과 같이 다른 객체에 대한 클래스를 작성하는 것입니다.

    class Line {
      constructor(x1, y1, x2, y2) {
        this.x1 = x1;
        this.y1 = y2;
        ...
      }

      draw() {
        }
    }

    class Circle {
      constructor(x, y, radius) {
        this.x = x;
        ...
      }

      draw() {}
    }

    ...

그런 다음 기본 코드에서해야 할 일은 중간에 일시 중지를 사용하여 모양을 차례로 그리는 것입니다.

let line1 = new Line(x1, y1, x2, y2);
let circle = new Circle(x, y, r);
let line2 = new Line(x1, y1, x2, y2);

line1.draw()
pause()
circle.draw()
pause()
line2.draw()

...

예를 들어 일부 라이브러리를 사용하여 약속 및 중첩 된 콜백 함수를 처리 할 필요가없는 쉬운 방법이 있습니까?

블라인드 맨 67

키 프레임

키 프레임을 사용하여 거의 모든 것에 애니메이션 효과를 줄 수 있습니다.

아래의 예 (더 많은 글을 쓰려고했지만 너무 늦어서 대답을 수락했습니다)는 매우 기본적인 키 프레임 유틸리티가 애니메이션을 만드는 방법을 보여줍니다.

키 프레임은 단지 인 timevalue

값에 이름을 부여하는 트랙에 키 프레임이 추가됩니다.

따라서 이름 x(위치) 및 키 {time : 0, value : 100}, {time : 1000, value : 900}은 0 ~ 1 초 동안 x속성을에서 100변경합니다.900

예를 들어 원

const circle = {
    x: 0,
    y: 0,
    r: 10,
    col : "",
    draw() { 
        ctx.fillStyle = this.col;
        ctx.beginPath(); 
        ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2); 
        ctx.fill() 
    }
};

시간이 지남에 따라 속성이 변경 될 수 있습니다.

먼저 트랙 객체를 만들고 키를 정의합니다.

const circleTracks = createTracks();

// properties to animate
circleTracks.addTrack("x");
circleTracks.addTrack("y");
circleTracks.addTrack("r");
circleTracks.addTrack("col");

그런 다음 특정 타임 스탬프에 키 프레임을 추가합니다.

circleTracks.addKeysAtTime(0, {x: 220, y :85, r: 20, col: "#F00"});
circleTracks.addKeysAtTime(1000, {x: 220, y :50, r: 50, col: "#0F0"});
circleTracks.addKeysAtTime(2000, {x: 420, y :100, r: 20, col: "#00F"});
circleTracks.addKeysAtTime(3000, {x: 180, y :160, r: 10, col: "#444"});
circleTracks.addKeysAtTime(4000, {x: 20, y :100, r: 20});
circleTracks.addKeysAtTime(5000, {x: 220, y :85, r: 10, col: "#888"});
circleTracks.addKeysAtTime(5500, {r: 10, col: "#08F"});
circleTracks.addKeysAtTime(6000, {r: 340, col: "#00F"});

준비가되면 키를 정리하십시오 (시간 순서없이 추가 할 수 있음).

circleTracks.clean();

시작을 추구

circleTracks.seek(0);

그리고 개체를 업데이트

circleTracks.update(circle);

애니메이션을 적용하려면 눈금 및 업데이트 함수를 호출하고 원을 그립니다.

circleTracks.tick();
circleTracks.update(circle);
circle.draw();

애니메이션을 시작하려면 클릭하십시오. 끝났 으면 다음을 사용하여 애니메이션을 스크럽 할 수 있습니다.tracks.seek(time)

가장 기본적인 키 프레임 애니메이션입니다.

키 프레임의 가장 좋은 점은 애니메이션을 코드에서 분리하여 애니메이션을 간단한 데이터 구조로 가져오고 내보낼 수 있다는 것입니다.

const ctx = canvas.getContext("2d");

requestAnimationFrame(mainLoop);

const allTracks = [];
function addKeyframedObject(tracks, object) {
    tracks.clean();
    tracks.seek(0);
    tracks.update(object);
    allTracks.push({tracks, object});
}
const FRAMES_PER_SEC = 60, TICK = 1000 / FRAMES_PER_SEC; //
const key = (time, value) => ({time, value});
var playing = false;
var showScrubber = false;
var currentTime = 0;
function mainLoop() {
    ctx.clearRect(0 ,0 ,ctx.canvas.width, ctx.canvas.height);
    if(playing) {
        for (const animated of allTracks) {
            animated.tracks.tick();
            animated.tracks.update(animated.object);
        }
    }
    for (const animated of allTracks) {
        animated.object.draw();
    }

    
    if(showScrubber) {
    
        slide.update();
        slide.draw();
        if(slide.value !== currentTime) {
            currentTime = slide.value;
            for (const animated of allTracks) {
                animated.tracks.seek(currentTime);
                animated.tracks.update(animated.object);
            }
        }
        
    } else {
        if(mouse.button) { playing = true }
    }
    if(allTracks[0].tracks.time > 6300) { 
        showScrubber = true 
        playing = false;
    }
    
    requestAnimationFrame(mainLoop);
}





const text = {
    x: canvas.width / 2,
    y: canvas.height / 2,
    alpha: 1,
    text: "",
    draw() { 
        ctx.font = "24px arial";
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.fillStyle = "#000";
        ctx.globalAlpha = this.alpha;
        ctx.fillText(this.text, this.x, this.y);
        ctx.globalAlpha = 1;
    }
}
const circle = {
    x: 0,
    y: 0,
    r: 10,
    col : "",
    draw() { 
        ctx.fillStyle = this.col;
        ctx.beginPath(); 
        ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2); 
        ctx.fill() 
    }
}




const circleTracks = createTracks();
circleTracks.addTrack("x");
circleTracks.addTrack("y");
circleTracks.addTrack("r");
circleTracks.addTrack("col");

circleTracks.addKeysAtTime(0, {x: 220, y :85, r: 20, col: "#F00"});
circleTracks.addKeysAtTime(1000, {x: 220, y :50, r: 50, col: "#0F0"});
circleTracks.addKeysAtTime(2000, {x: 420, y :100, r: 20, col: "#00F"});
circleTracks.addKeysAtTime(3000, {x: 180, y :160, r: 10, col: "#444"});
circleTracks.addKeysAtTime(4000, {x: 20, y :100, r: 20});
circleTracks.addKeysAtTime(5000, {x: 220, y :85, r: 10, col: "#888"});
circleTracks.addKeysAtTime(5500, {r: 10, col: "#08F"});
circleTracks.addKeysAtTime(6000, {r: 340, col: "#00F"});

addKeyframedObject(circleTracks, circle);


const textTracks = createTracks();
textTracks.addTrack("alpha");
textTracks.addTrack("text");
textTracks.addKeysAtTime(0, {alpha: 1, text: "Click to start"});
textTracks.addKeysAtTime(1, {alpha: 0});
textTracks.addKeysAtTime(20, {alpha: 0, text: "Simple keyframed animation"});
textTracks.addKeysAtTime(1000, {alpha: 1});
textTracks.addKeysAtTime(2000, {alpha: 0});
textTracks.addKeysAtTime(3500, {alpha: 0, text: "The END!" });
textTracks.addKeysAtTime(3500, {alpha: 1});
textTracks.addKeysAtTime(5500, {alpha: 1});
textTracks.addKeysAtTime(6000, {alpha: 0, text: "Use slider to scrub"});
textTracks.addKeysAtTime(6300, {alpha: 1});
addKeyframedObject(textTracks, text);



function createTracks() {
    return {
        tracks: {},
        addTrack(name, keys = [], value) {  
            this.tracks[name] = {name, keys, idx: -1, value}
        },
        addKeysAtTime(time, keys) {
            for(const name of Object.keys(keys)) {
                this.tracks[name].keys.push(key(time, keys[name]));
            }
        },
        clean() {
            for(const track of Object.values(this.tracks)) {
                track.keys.sort((a,b) => a.time - b.time);
            }
        },
        seek(time) { // seek to random time
            this.time = time;
            for(const track of Object.values(this.tracks)) {
                if (track.keys[0].time > time) {
                    track.idx = -1; // befor first key
                }else {
                    let idx = 1;
                    while(idx < track.keys.length) {
                        if(track.keys[idx].time > time && track.keys[idx-1].time <= time) {
                            track.idx = idx - 1;
                            break;
                        }
                        idx += 1;
                    }
                }
            }
            this.tick(0);
        }, 
        tick(timeStep = TICK) { 
            const time = this.time += timeStep;
            for(const track of Object.values(this.tracks)) {
                if(track.keys[track.idx + 1] && track.keys[track.idx + 1].time <= time) {
                    track.idx += 1;
                }
                if(track.idx === -1) {
                    track.value = track.keys[0].value;
                } else {
                    const k1 = track.keys[track.idx];
                    const k2 = track.keys[track.idx + 1];
                    if (typeof k1.value !== "number" || !k2) {
                        track.value = k1.value;
                    } else if (k2) {
                        const unitTime = (time - k1.time) / (k2.time - k1.time);
                        track.value = (k2.value - k1.value) * unitTime + k1.value;
                    } 
                }
                
            }
        },
        update(obj) {
            for(const track of Object.values(this.tracks)) {
                obj[track.name] = track.value;
            }
        }   
    };
};














const slide = {
    min: 0,
    max: 6300,
    value: 6300,
    top: 160,
    left: 1,
    height: 9,
    width: 438,
    slide: 10,
    slideX: 0,
    draw() {
        
        
        ctx.fillStyle = "#000";
        ctx.fillRect(this.left-1, this.top-1, this.width+ 2, this.height+ 2);
        ctx.fillStyle = "#888";
        ctx.fillRect(this.left, this.top, this.width, this.height);
        ctx.fillStyle = "#DDD";
        this.slideX = (this.value - this.min) / (this.max - this.min) * (this.width - this.slide)  + this.left;
        ctx.fillRect(this.slideX, this.top + 1, this.slide, this.height - 2);
    },
    
    update() {

         if(mouse.x > this.left && mouse.x < this.left + this.width && 
            mouse.y > this.top && mouse.y < this.top + this.height) {
            
            if (mouse.button && !this.captured) {
                this.captured = true;
            } else {
                canvas.style.cursor = "ew-resize";
            }
         }
         if (this.captured) {
            if (!mouse.button) {
               this.captured = false;
               canvas.style.cursor = "default";
            } else {
               this.value = ((mouse.x - this.left) / this.width) * (this.max - this.min) + this.min;
               canvas.style.cursor = "none";
               this.value = this.value < this.min ? this.min : this.value > this.max ? this.max : this.value;
               
            }
         } 
     }
 };
        
        
        
const mouse  = {x : 0, y : 0, button : false};
function mouseEvents(e){
     const bounds = canvas.getBoundingClientRect();
	   mouse.x = e.pageX - bounds.left - scrollX;
	   mouse.y = e.pageY - bounds.top - scrollY;
  	 mouse.button = e.type === "mousedown" ? true : e.type === "mouseup" ? false : mouse.button;
}
["down","up","move"].forEach(name => document.addEventListener("mouse"+name,mouseEvents));
canvas { border: 1px solid black; }
<canvas id="canvas" width="440" height="170"><canvas>

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

핸들러를 사용하여 Android에서 스태킹 뷰를 차례로 올바르게 애니메이션하는 방법은 무엇입니까?

분류에서Dev

HTML5 캔버스를 사용하여 다단계 원형 차트를 그리는 방법은 무엇입니까?

분류에서Dev

HTML5 캔버스를 사용하여 오프셋으로 최종 점 좌표를 계산하는 방법은 무엇입니까?

분류에서Dev

캔버스로 애니메이션 막대 그래프를 만드는 방법은 무엇입니까?

분류에서Dev

화살표 키를 눌러 캔버스 HTML5에서 이미지를 이동하는 방법은 무엇입니까?

분류에서Dev

캔버스 HTML5에서 ontouch 이벤트를 사용하는 방법은 무엇입니까?

분류에서Dev

javascript / jquery를 사용하여 3 개의 캔버스 HTML 요소를 하나의 이미지 파일로 결합하는 방법은 무엇입니까?

분류에서Dev

Base64 String 형식으로 JSON에서 전달 된 HTML5 캔버스에 이미지를 표시하는 방법은 무엇입니까?

분류에서Dev

html5 캔버스를 배경으로 사용하여 CSS를 사용하여 YouTube 삽입을 그 위에 배치하여 해상도에 독립적이되도록하는 방법은 무엇입니까?

분류에서Dev

HTML5 캔버스를 사용하여 원의 어느 부분을 클릭했는지 확인하는 방법은 무엇입니까?

분류에서Dev

HTML5 캔버스 컨텍스트를 기본값으로 재설정하는 방법은 무엇입니까?

분류에서Dev

테두리가있는 상자에 HTML5 캔버스를 만드는 방법은 무엇입니까?

분류에서Dev

JavaScript를 사용하여 캔버스 끝을 칠 때 개체를 중지하는 방법은 무엇입니까?

분류에서Dev

cp2 포인트로 HTML5 캔버스에서 베 지어 곡선 크기를 얻는 방법은 무엇입니까?

분류에서Dev

HTML5 캔버스를 사용하여 도로 선을 만드는 방법

분류에서Dev

애니메이션 중 캔버스 크기를 조정하는 방법은 무엇입니까?

분류에서Dev

2 개의 SVG 경로를 스택하고 애니메이션하는 방법은 무엇입니까?

분류에서Dev

캔버스 애니메이션 배율을 만드는 방법 (HTML5)

분류에서Dev

Javascript / HTML5를 사용하여 한 줄에 무작위로 개체를 생성하는 방법은 무엇입니까?

분류에서Dev

javascript 또는 jquery를 사용하여 버튼 클릭으로 여러 mp3 파일을 차례로 재생하는 방법은 무엇입니까?

분류에서Dev

자바 스크립트를 사용하여 애니메이션이 완료된 후 개체를 회전하는 방법은 무엇입니까?

분류에서Dev

CSS를 사용하여 HTML5 캔버스에 색상을 지정하는 방법이 있습니까?

분류에서Dev

itext pdf를 사용하여 PDF 캔버스에 경로를 그리는 방법은 무엇입니까?

분류에서Dev

HTML에서 버튼을 사용하여 애니메이션을 재생하는 방법은 무엇입니까?

분류에서Dev

캔버스에 여러 이미지를 표시하는 방법은 무엇입니까?

분류에서Dev

Windows 10에서 여러 페이지를 하나의 PDF로 스캔하는 방법은 무엇입니까?

분류에서Dev

CSS를 사용하여 javafx에서 텍스트를 애니메이션하는 방법은 무엇입니까?

분류에서Dev

jquery를 사용하여 클릭시 클래스를 애니메이션하는 방법은 무엇입니까?

분류에서Dev

CSS 및 Javascript를 사용하여 HTML DOM 개체에 애니메이션을 추가하는 올바른 방법은 무엇입니까?

Related 관련 기사

  1. 1

    핸들러를 사용하여 Android에서 스태킹 뷰를 차례로 올바르게 애니메이션하는 방법은 무엇입니까?

  2. 2

    HTML5 캔버스를 사용하여 다단계 원형 차트를 그리는 방법은 무엇입니까?

  3. 3

    HTML5 캔버스를 사용하여 오프셋으로 최종 점 좌표를 계산하는 방법은 무엇입니까?

  4. 4

    캔버스로 애니메이션 막대 그래프를 만드는 방법은 무엇입니까?

  5. 5

    화살표 키를 눌러 캔버스 HTML5에서 이미지를 이동하는 방법은 무엇입니까?

  6. 6

    캔버스 HTML5에서 ontouch 이벤트를 사용하는 방법은 무엇입니까?

  7. 7

    javascript / jquery를 사용하여 3 개의 캔버스 HTML 요소를 하나의 이미지 파일로 결합하는 방법은 무엇입니까?

  8. 8

    Base64 String 형식으로 JSON에서 전달 된 HTML5 캔버스에 이미지를 표시하는 방법은 무엇입니까?

  9. 9

    html5 캔버스를 배경으로 사용하여 CSS를 사용하여 YouTube 삽입을 그 위에 배치하여 해상도에 독립적이되도록하는 방법은 무엇입니까?

  10. 10

    HTML5 캔버스를 사용하여 원의 어느 부분을 클릭했는지 확인하는 방법은 무엇입니까?

  11. 11

    HTML5 캔버스 컨텍스트를 기본값으로 재설정하는 방법은 무엇입니까?

  12. 12

    테두리가있는 상자에 HTML5 캔버스를 만드는 방법은 무엇입니까?

  13. 13

    JavaScript를 사용하여 캔버스 끝을 칠 때 개체를 중지하는 방법은 무엇입니까?

  14. 14

    cp2 포인트로 HTML5 캔버스에서 베 지어 곡선 크기를 얻는 방법은 무엇입니까?

  15. 15

    HTML5 캔버스를 사용하여 도로 선을 만드는 방법

  16. 16

    애니메이션 중 캔버스 크기를 조정하는 방법은 무엇입니까?

  17. 17

    2 개의 SVG 경로를 스택하고 애니메이션하는 방법은 무엇입니까?

  18. 18

    캔버스 애니메이션 배율을 만드는 방법 (HTML5)

  19. 19

    Javascript / HTML5를 사용하여 한 줄에 무작위로 개체를 생성하는 방법은 무엇입니까?

  20. 20

    javascript 또는 jquery를 사용하여 버튼 클릭으로 여러 mp3 파일을 차례로 재생하는 방법은 무엇입니까?

  21. 21

    자바 스크립트를 사용하여 애니메이션이 완료된 후 개체를 회전하는 방법은 무엇입니까?

  22. 22

    CSS를 사용하여 HTML5 캔버스에 색상을 지정하는 방법이 있습니까?

  23. 23

    itext pdf를 사용하여 PDF 캔버스에 경로를 그리는 방법은 무엇입니까?

  24. 24

    HTML에서 버튼을 사용하여 애니메이션을 재생하는 방법은 무엇입니까?

  25. 25

    캔버스에 여러 이미지를 표시하는 방법은 무엇입니까?

  26. 26

    Windows 10에서 여러 페이지를 하나의 PDF로 스캔하는 방법은 무엇입니까?

  27. 27

    CSS를 사용하여 javafx에서 텍스트를 애니메이션하는 방법은 무엇입니까?

  28. 28

    jquery를 사용하여 클릭시 클래스를 애니메이션하는 방법은 무엇입니까?

  29. 29

    CSS 및 Javascript를 사용하여 HTML DOM 개체에 애니메이션을 추가하는 올바른 방법은 무엇입니까?

뜨겁다태그

보관