Поиск…


Создание гибкого полноформатного холста

Код запуска для создания и удаления полного холста страницы, который реагирует на изменение размера событий через 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

Координаты мыши после изменения размера (или прокрутки)

Приложения Canvas часто в значительной степени зависят от взаимодействия пользователя с мышью, но когда размер окна изменяется, координаты события мыши, на которые полагается холст, скорее всего, будут изменены, поскольку изменение размера приведет к смещению холста в другое положение относительно окна. Таким образом, отзывчивый дизайн требует, чтобы позиция смещения холста была пересчитана при изменении размера окна, а также пересчитана при прокрутке окна.

Этот код прослушивает события изменения размера окна и пересчитывает смещения, используемые в обработчиках событий мыши:

// 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 которая прилагает все усилия, чтобы поддерживать рендеринг в синхронизации с оборудованием дисплея.

Проблема с событием изменения размера заключается в том, что когда мышь используется для изменения размера окна, события могут запускаться во много раз быстрее, чем стандартная скорость 60 кадров в секунду браузера. Когда событие изменения размера выходит из обратного буфера холста, оно отображается в DOM из-за синхронизации с устройством отображения, что может привести к сдвигу и другим негативным эффектам. Существует также много ненужного выделения и освобождения памяти, которое может дополнительно повлиять на анимацию, когда GC очистит некоторое время после этого.


Событие с измененным размером

Обычный способ справиться с высокими скоростями стрельбы события изменения размера - это отмена события изменения размера.

 // 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 ... }

Вышеупомянутый пример задерживает изменение размера холста до 100 мс после события изменения размера. Если в это время будут инициированы события с последующим изменением размера, существующий тайм-аут изменения размера отменяется, а новый запланирован. Это эффективно поглощает большинство событий изменения размера.

У него все еще есть некоторые проблемы, наиболее заметным является задержка между изменением размера и просмотром измененного холста. Уменьшение времени отладки улучшает это, но изменение размера по-прежнему не синхронизируется с устройством отображения. У вас также есть анимация основного цикла анимации на плохо подходящем холсте.

Больше кода может уменьшить проблемы! Больше кода также создает свои собственные новые проблемы.


Простой и лучший размер

Попробовав много разных способов сгладить изменение размера холста, от абсурдно сложного, просто игнорируя проблему (кто заботится в любом случае?), Я вернулся к надежному другу.

KISS - это то, о чем большинство программистов должно знать (( K eep I t S imple S tupid) Глупо относится ко мне за то, что я не думал об этом много лет назад. ) И получается, что лучшим решением является самый простой из всех.

Просто измените размер холста из основного цикла анимации. Он остается синхронно с устройством отображения, нет ненужного рендеринга, и управление ресурсами минимально возможно при сохранении полной частоты кадров. Вам также не нужно добавлять событие изменения размера в окно или любые дополнительные функции изменения размера.

Вы добавляете размер, в котором вы обычно очищаете холст, проверяя, соответствует ли размер холста размеру окна. Если не изменить его размер.

// 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