サーチ…


応答性の高い全面キャンバスを作成する

javascriptを使用してサイズ変更イベントに応答するフルページキャンバスを作成して削除するための初心者コード。

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によって呼び出されるメインループ関数を介してすべてのフレームを実行し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は私は T S imple S tupid) 愚かで年前。それの考えを持っていないために私を指し (Kの EEP)ほとんどのプログラマが知っておくべきものであり、それは最善の解決策は、すべての最も簡単ですが判明します。

メインのアニメーションループ内からキャンバスのサイズを変更するだけです。それはディスプレイ装置と同期したままであり、不必要なレンダリングはなく、フルフレームレートを維持しながらリソース管理は可能な限り最小限である。また、ウィンドウに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);
}


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow