Cross‑Window Real‑Time Rendering with Canvas, window.screenX/Y and localStorage
This article demonstrates how to create a multi‑window, real‑time interactive animation using pure JavaScript by drawing circles on a canvas, sharing each window's screen coordinates and colors through localStorage, and connecting them with lines across browsers.
The author describes a technique for building a cross‑window, real‑time interactive animation entirely with JavaScript, without third‑party libraries. Each browser window draws a circle at its center on a canvas, stores its screen coordinates ( window.screenX, window.screenY) and a color in localStorage, and reads other windows' data to render connecting lines.
Key APIs used : window.requestAnimationFrame – for the animation loop. const { screenX, screenY } = window – to obtain the window's position relative to the screen. const barHeight = window.outerHeight - window.innerHeight – to calculate the browser UI height. canvas – the drawing surface. localStorage – shared storage for all pages under the same origin.
Core drawing logic (simplified) :
const alert1 = document.getElementById('alert1');
const alert2 = document.getElementById('alert2');
const canvas1 = document.getElementById('canvas1');
const ctx = canvas1.getContext('2d');
function draw() {
const { clientWidth, clientHeight } = document.body;
const { screenX, screenY } = window;
const barHeight = window.outerHeight - window.innerHeight;
// log current window info
alert1.textContent = JSON.stringify({ clientWidth, clientHeight, screenX, screenY, barHeight }, null, 2);
canvas1.width = clientWidth;
canvas1.height = clientHeight;
const x = clientWidth / 2;
const y = clientHeight / 2;
// draw own circle
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(x, y, 15, 0, Math.PI * 2);
ctx.fill();
const position = { top: y + barHeight + screenY, left: x + screenX, color };
// draw other windows' circles and connecting lines
getOtherKeys().forEach(k => {
const position2 = JSON.parse(localStorage.getItem(k));
const w = position2.left - position.left;
const h = position2.top - position.top;
ctx.fillStyle = position2.color;
ctx.beginPath();
ctx.arc(x + w, y + h, 15, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = 'black';
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x + w, y + h);
ctx.stroke();
});
// update own position in storage
localStorage.setItem(key, JSON.stringify(position));
alert2.textContent = JSON.stringify(localStorage, null, 2);
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);Utility functions manage storage keys, assign a unique key to each window, and clean up on window.onunload:
function getOtherKeys() {
const keys = [];
for (let i = 0; i < localStorage.length; i++) {
const k = Number(localStorage.key(i));
if (!isNaN(k)) keys.push(k);
}
return keys.sort((a, b) => a - b);
}
window.onunload = function () {
localStorage.removeItem(key);
};The article concludes with the full source code, a summary of current limitations (e.g., missing connection lines when windows overlap), and links to the GitHub repository and live demo for further exploration.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
