수색…
반응이 빠른 전체 페이지 캔버스 만들기
자바 스크립트를 통해 크기 조정 이벤트에 응답하는 전체 페이지 캔버스를 만들고 삭제하는 초보자 용 코드입니다.
var canvas; // Global canvas reference
var ctx; // Global 2D context reference
// Creates a canvas
function createCanvas () {
const canvas = document.createElement("canvas");
canvas.style.position = "absolute"; // Set the style
canvas.style.left = "0px"; // Position in top left
canvas.style.top = "0px";
canvas.style.zIndex = 1;
document.body.appendChild(canvas); // Add to document
return canvas;
}
// Resizes canvas. Will create a canvas if it does not exist
function sizeCanvas () {
if (canvas === undefined) { // Check for global canvas reference
canvas = createCanvas(); // Create a new canvas element
ctx = canvas.getContext("2d"); // Get the 2D context
}
canvas.width = innerWidth; // Set the canvas resolution to fill the page
canvas.height = innerHeight;
}
// Removes the canvas
function removeCanvas () {
if (canvas !== undefined) { // Make sure there is something to remove
removeEventListener("resize", sizeCanvas); // Remove resize event
document.body.removeChild(canvas); // Remove the canvas from the DOM
ctx = undefined; // Dereference the context
canvas = undefined; // Dereference the canvas
}
}
// Add the resize listener
addEventListener("resize", sizeCanvas);
// Call sizeCanvas to create and set the canvas resolution
sizeCanvas();
// ctx and canvas are now available for use.
캔버스가 더 이상 필요없는 경우 removeCanvas()
를 호출하여 캔버스를 제거 할 수 있습니다.
jsfiddle에서의이 예제의 데모
크기 조정 (또는 스크롤) 후 마우스 좌표
캔버스 응용 프로그램은 마우스와의 사용자 상호 작용에 의존하는 경우가 많지만 크기를 조절할 때 캔버스가 사용하는 마우스 이벤트 좌표는 크기가 변경되어 캔버스가 윈도우와 관련된 다른 위치에서 오프셋되기 때문에 변경 될 가능성이 큽니다. 따라서 반응 형 디자인에서는 창 크기를 조정할 때 캔버스 간격 띄우기 위치를 다시 계산해야하며 창을 스크롤 할 때 다시 계산해야합니다.
이 코드는 윈도우 크기 조정 이벤트를 수신하고 마우스 이벤트 핸들러에 사용 된 오프셋을 다시 계산합니다.
// variables holding the current canvas offset position
// relative to the window
var offsetX,offsetY;
// a function to recalculate the canvas offsets
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
// listen for window resizing (and scrolling) events
// and then recalculate the canvas offsets
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }
// example usage of the offsets in a mouse handler
function handleMouseUp(e){
// use offsetX & offsetY to get the correct mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// ...
}
리사이즈 이벤트없이 반응하는 캔버스 애니메이션.
창 크기 조정 이벤트는 사용자 입력 장치의 움직임에 따라 실행될 수 있습니다. 캔버스의 크기를 조정하면 자동으로 지워지고 내용을 다시 렌더링해야합니다. 애니메이션의 경우 requestAnimationFrame
의해 호출되는 메인 루프 함수를 통해 모든 프레임을 처리하므로 렌더링을 디스플레이 하드웨어와 동기화 된 상태로 유지하는 것이 가장 좋습니다.
크기 조정 이벤트의 문제점은 마우스를 사용하여 창 크기를 조정할 때 이벤트가 브라우저의 표준 60fps 속도보다 몇 배 더 빠르게 트리거 될 수 있다는 것입니다. resize 이벤트가 종료되면 캔버스 백 버퍼가 디스플레이 장치와 동기화되지 않은 상태로 DOM에 제공되어 전단 및 기타 부정적인 영향을 미칠 수 있습니다. GC가 나중에 시간을 정리할 때 애니메이션에 더 많은 영향을 미칠 수있는 불필요한 메모리 할당과 릴리즈가 많이 있습니다.
디 바운싱 된 크기 조정 이벤트
resize 이벤트의 높은 실행 속도를 처리하는 일반적인 방법은 resize 이벤트를 디버깅하는 것입니다.
// Assume canvas is in scope
addEventListener.("resize", debouncedResize );
// debounce timeout handle
var debounceTimeoutHandle;
// The debounce time in ms (1/1000th second)
const DEBOUNCE_TIME = 100;
// Resize function
function debouncedResize () {
clearTimeout(debounceTimeoutHandle); // Clears any pending debounce events
// Schedule a canvas resize
debounceTimeoutHandle = setTimeout(resizeCanvas, DEBOUNCE_TIME);
}
// canvas resize function
function resizeCanvas () { ... resize and redraw ... }
위의 예제는 resize 이벤트 후 100ms가 될 때까지 캔버스의 크기 조정을 지연합니다. 그 시간에 추가 크기 조정 이벤트가 트리거되면 기존 크기 조정 시간 초과가 취소되고 새 크기 조정이 예약됩니다. 이는 대부분의 크기 조정 이벤트를 효과적으로 소비합니다.
여전히 몇 가지 문제가 있습니다. 가장 주목할만한 것은 크기가 조정 된 캔버스를 보는 것과 크기를 조정하는 것 사이의 지연입니다. 디 바운스 시간을 줄이면 성능이 향상되지만 크기는 디스플레이 장치와 여전히 일치하지 않습니다. 또한 애니메이션 메인 루프 렌더링이 잘못된 피사체 캔버스에 여전히 있습니다.
더 많은 코드가 문제를 줄일 수 있습니다! 더 많은 코드는 새로운 문제를 만듭니다.
단순하고 최상의 크기 조정
불합리하게 복잡한 것부터 문제를 무시하는 것에 이르기까지 캔버스의 크기를 부드럽게하는 많은 다른 방법을 시도해 보았습니다. 누가 상관합니까? 저는 믿을 수있는 친구에게 넘어졌습니다.
KISS 는 대부분의 프로그래머가 알아야 할 것입니다 (( K eep I t S imple S tupid) 바보는 몇 년 전 생각하지 못했기 때문에 저를 말합니다. ) 그리고 가장 좋은 해결책은 가장 단순한 것으로 밝혀졌습니다.
메인 애니메이션 루프 내에서 캔버스의 크기를 조절하면됩니다. 디스플레이 장치와 동기화되어있어 불필요한 렌더링이 필요 없으며 전체 프레임 속도를 유지하면서 자원 관리가 가능한 최소한으로 유지됩니다. 또한 윈도우에 resize 이벤트를 추가하거나 추가 크기 조정 함수를 추가 할 필요도 없습니다.
캔바스 크기가 창 크기와 일치하는지 확인하여 일반적으로 캔버스를 지우는 위치에서 크기 조정을 추가합니다. 크기를 조정하지 않은 경우
// Assumes canvas element is in scope as canvas
// Standard main loop function callback from requestAnimationFrame
function mainLoop(time) {
// Check if the canvas size matches the window size
if (canvas.width !== innerWidth || canvas.height !== innerHeight) {
canvas.width = innerWidth; // resize canvas
canvas.height = innerHeight; // also clears the canvas
} else {
ctx.clearRect(0, 0, canvas.width, canvas.height); // clear if not resized
}
// Animation code as normal.
requestAnimationFrame(mainLoop);
}