let overlayLoaded = false; let baseLoaded = false; let radius = 200; document.addEventListener("DOMContentLoaded", e => { const overlayImg = document.querySelector("#overlay-img"); const baseImg = document.querySelector("#base-img"); overlayImg.addEventListener("load", e => { console.log("The overlay is loaded"); overlayLoaded = true; if (overlayLoaded && baseLoaded) { setup(); } }) baseImg.addEventListener("load", e => { console.log("The base is loaded"); baseLoaded = true; if (overlayLoaded && baseLoaded) { setup(); } }) }); function setup() { const overlay = document.querySelector("#overlay"); const base = document.querySelector("#base"); const overlayImg = document.querySelector("#overlay-img"); const baseImg = document.querySelector("#base-img"); /** @type {CanvasRenderingContext2D} */ const overlayCtx = overlay.getContext("2d"); /** @type {CanvasRenderingContext2D} */ const baseCtx = base.getContext("2d"); baseCtx.canvas.width = baseImg.width; baseCtx.canvas.height = baseImg.height; baseCtx.drawImage(baseImg, 0, 0); overlayCtx.canvas.width = overlayImg.width; overlayCtx.canvas.height = overlayImg.height; overlayCtx.drawImage(overlayImg, 0, 0); overlay.addEventListener("mousemove", e => { let x = e.clientX - e.target.getBoundingClientRect().x; let y = e.clientY - e.target.getBoundingClientRect().y; updateOverlay([[x,y]]); }); overlay.addEventListener("touchmove", e => { let offsetX = e.target.getBoundingClientRect().x; let offsetY = e.target.getBoundingClientRect().y; let touches = []; for (let i=0; i < e.touches.length; i++) { let x = e.touches[i].clientX - offsetX; let y = e.touches[i].clientY - offsetY; touches.push([x,y]); } updateOverlay(touches); }); console.log("Done"); } function updateOverlay(points) { console.log("MOVE") /** @type {CanvasRenderingContext2D} */ const overlayCtx = overlay.getContext("2d"); const overlayImg = document.querySelector("#overlay-img"); const w = overlayCtx.canvas.width; const h = overlayCtx.canvas.height; overlayCtx.save(); overlayCtx.globalCompositeOperation = "source-over"; overlayCtx.clearRect(0, 0, w, h); points.forEach(point => { const [x,y] = point; overlayCtx.beginPath(); overlayCtx.ellipse(x, y, radius, radius, 0, 0, 2 * Math.PI); const gradient = overlayCtx.createRadialGradient(x, y, 0, x, y, radius); gradient.addColorStop(0.75, '#000000FF'); gradient.addColorStop(1, '#00000000'); overlayCtx.fillStyle = gradient; overlayCtx.fill(); }) overlayCtx.globalCompositeOperation = "source-in"; overlayCtx.drawImage(overlayImg, 0, 0); overlayCtx.restore(); }