Szukaj…
Tworzenie responsywnego obszaru roboczego całej strony
Kod startowy do tworzenia i usuwania obszaru roboczego całej strony, który reaguje na zdarzenia zmiany rozmiaru za pomocą 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.
Jeśli nie potrzebujesz już płótna, możesz go usunąć, wywołując removeCanvas()
Demo tego przykładu w jsfiddle
Współrzędne myszy po zmianie rozmiaru (lub przewinięciu)
Aplikacje Canvas często polegają w dużej mierze na interakcji użytkownika z myszą, ale przy zmianie rozmiaru okna współrzędne zdarzenia myszy, na których opiera się canvas, prawdopodobnie ulegają zmianie, ponieważ zmiana rozmiaru powoduje przesunięcie płótna w innej pozycji względem okna. Zatem responsywne projektowanie wymaga ponownego obliczenia położenia przesunięcia obszaru roboczego przy zmianie rozmiaru okna - a także ponownego obliczenia po przewinięciu okna.
Ten kod nasłuchuje zdarzeń zmieniających rozmiar okna i ponownie oblicza przesunięcia używane w programach obsługi zdarzeń myszy:
// 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);
// ...
}
Elastyczne animacje na płótnie bez zdarzeń zmiany rozmiaru.
Zdarzenia zmiany rozmiaru okna mogą być uruchamiane w odpowiedzi na ruch urządzenia wejściowego użytkownika. Po zmianie rozmiaru płótna jest on automatycznie usuwany i użytkownik jest zmuszony do ponownego renderowania treści. W przypadku animacji robisz to co klatkę za pomocą funkcji głównej pętli wywoływanej przez requestAnimationFrame
która stara się zachować synchronizację renderowania ze sprzętem wyświetlającym.
Problem ze zdarzeniem zmiany rozmiaru polega na tym, że gdy mysz zmienia rozmiar okna, zdarzenia mogą być wyzwalane wiele razy szybciej niż standardowa szybkość 60 klatek na sekundę w przeglądarce. Po wyjściu ze zdarzenia zmiany rozmiaru bufor tylnego obszaru roboczego jest prezentowany DOM bez synchronizacji z urządzeniem wyświetlającym, co może powodować ścinanie i inne negatywne skutki. Istnieje również wiele niepotrzebnych przydziałów pamięci i zwolnień, które mogą mieć wpływ na animację, gdy GC oczyści trochę później.
Ogłoszono zdarzenie zmiany rozmiaru
Częstym sposobem radzenia sobie z wysokimi częstotliwościami wystrzeliwania zdarzenia zmiany rozmiaru jest ogłoszenie zdarzenia zmiany rozmiaru.
// 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 ... }
Powyższy przykład opóźnia zmianę rozmiaru obszaru roboczego do 100 ms po zdarzeniu zmiany rozmiaru. Jeśli w tym czasie zostaną uruchomione kolejne zdarzenia zmiany rozmiaru, istniejący limit czasu zostanie anulowany i zaplanowane zostanie nowe. To skutecznie zużywa większość zdarzeń zmiany rozmiaru.
Nadal występują pewne problemy, najbardziej zauważalne jest opóźnienie między zmianą rozmiaru a wyświetleniem obrazu o zmienionym rozmiarze. Skrócenie czasu odbicia poprawia to, ale zmiana rozmiaru nadal nie jest zsynchronizowana z urządzeniem wyświetlającym. Nadal masz również renderowanie głównej pętli animacji na źle dopasowanym płótnie.
Więcej kodów może zmniejszyć problemy! Więcej kodu stwarza również nowe problemy.
Prosty i najlepszy rozmiar
Po wypróbowaniu wielu różnych sposobów na wygładzenie rozmiaru płótna, od absurdalnie skomplikowanego, po ignorowanie problemu (kogo to obchodzi?) Wróciłem do zaufanego przyjaciela.
KISS jest czymś większość programistów powinien być świadomy ((K EEP I t S wyko S tupid) Głupi odnosi się do mnie nie myślał o nim rok temu.) I okazuje się, że najlepszym rozwiązaniem jest najprostszym ze wszystkich.
Po prostu zmień rozmiar płótna w głównej pętli animacji. Pozostaje zsynchronizowany z urządzeniem wyświetlającym, nie ma niepotrzebnego renderowania, a zarządzanie zasobami jest na minimalnym możliwym poziomie przy zachowaniu pełnej częstotliwości klatek. Nie trzeba też dodawać zdarzenia zmiany rozmiaru do okna ani żadnych dodatkowych funkcji zmiany rozmiaru.
Dodajesz zmianę rozmiaru w miejscu, w którym normalnie wyczyścisz płótno, sprawdzając, czy rozmiar płótna odpowiada rozmiarowi okna. Jeśli nie, zmień jego rozmiar.
// 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);
}