'How to scratch reveal an image with Javascript canvas element
I created a canvas element where I can draw paths. There, I draw transparent paths and I "scratch" reveal the foreground. It works on both mobile and desktop.
Solution 1:[1]
A working example
// Animation frame
window.requestAnimFrame = (function (callback) {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimaitonFrame ||
function (callback) {
window.setTimeout(callback, 1000/60);
};
})();
const body = document.getElementById('body');
// Draw
const color = "#f70d8a";
const stroke = 25;
// Canvas
const canvas = document.getElementById("canvas");
let canvasWidth = canvas.offsetWidth;
let canvasHeight = canvas.offsetHeight;
const context = canvas.getContext("2d");
context.fillRect(0, 0, canvasWidth, canvasHeight);
context.strokeStyle = color;
context.lineWidth = stroke;
document.getElementById('canvas-background').innerHTML = "Oh<br>yeah";
// Mouse events
var drawing = false;
var mousePos = { x:0, y:0 };
var lastPos = mousePos;
canvas.addEventListener("mousedown", function (e) {
drawing = true;
lastPos = getMousePos(canvas, e);
}, false);
canvas.addEventListener("mouseup", function (e) {
drawing = false;
}, false);
canvas.addEventListener("mousemove", function (e) {
mousePos = getMousePos(canvas, e);
}, false);
// Touch events
canvas.addEventListener("touchstart", function (e) {
mousePos = getTouchPos(canvas, e);
var touch = e.touches[0];
var mouseEvent = new MouseEvent("mousedown", {
clientX: touch.clientX,
clientY: touch.clientY
});
canvas.dispatchEvent(mouseEvent);
}, false);
canvas.addEventListener("touchend", function (e) {
var mouseEvent = new MouseEvent("mouseup", {});
canvas.dispatchEvent(mouseEvent);
}, false);
canvas.addEventListener("touchmove", function (e) {
var touch = e.touches[0];
var mouseEvent = new MouseEvent("mousemove", {
clientX: touch.clientX,
clientY: touch.clientY
});
canvas.dispatchEvent(mouseEvent);
}, false);
// Prevent default scrolling behavior on Touch events
document.body.addEventListener("touchstart", function (e) {
if (e.target == canvas) {
e.preventDefault();
}
}, {passive:false});
document.body.addEventListener("touchend", function (e) {
if (e.target == canvas) {
e.preventDefault();
}
}, {passive:false});
document.body.addEventListener("touchmove", function (e) {
if (e.target == canvas) {
e.preventDefault();
}
}, {passive:false});
// Mouse position
function getMousePos(canvasDom, mouseEvent) {
var rect = canvasDom.getBoundingClientRect();
return {
x: mouseEvent.clientX - rect.left,
y: mouseEvent.clientY - rect.top
};
}
// Touch position
function getTouchPos(canvasDom, touchEvent) {
var rect = canvasDom.getBoundingClientRect();
return {
x: touchEvent.touches[0].clientX - rect.left,
y: touchEvent.touches[0].clientY - rect.top
};
}
// Draw
function renderCanvas() {
if (drawing) {
context.moveTo(lastPos.x, lastPos.y);
context.lineTo(mousePos.x, mousePos.y);
context.globalCompositeOperation = "destination-out";
context.stroke();
lastPos = mousePos;
}
}
// Animation frame
(function drawLoop () {
requestAnimFrame(drawLoop);
renderCanvas();
})();
/*---- Global variables ----*/
:root {
--black: #222;
--yellow: #fff295;
--purple: #fa0afa;
--blue: #0daaf8;
--green: #0df882;
--red: #e64c4c;
--pink: #f70d8a;
--main-margin-top: 10vh;
--canvas-width: 320px;
--canvas-height: 320px;
}
/*---- Resetter ----*/
* {
margin: 0;
border: 0;
padding: 0;
}
/*---- Default classes ----*/
body {
background-color: var(--black);
color: #fff;
font-family: Futura, Arial, sans-serif;
font-size: 1rem;
line-height:1rem;
}
main {
margin: var(--main-margin-top) auto;
width: var(--canvas-width);
}
h1 {
font-size: 2rem;
font-weight: 400;
}
/*---- Generic classes ----*/
.center {
text-align: center;
}
/*---- Custom classes ----*/
#canvas {
z-index:9999;
position:absolute;
top:calc(var(--main-margin-top) + 2rem);
left:calc(50vw - var(--canvas-width)/2);
background-color: transparent;
}
#canvas-background {
z-index: 999;
position: absolute;
width: inherit;
line-height: 1em;
font-size: 5rem;
padding-top:calc(var(--canvas-height)/2 - 1em);
text-align: center;
color:var(--pink);
}
<body id="body">
<main class="center">
<h1 class="center">Scratch this bitch</h1>
<canvas id="canvas" width="320px" height="320px">
</canvas>
<p id="canvas-background"></p>
</main>
</body>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | jlanssie |