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