Using canvas for image masking.
Image courtesy of Laura Aziz | Unsplash https://unsplash.com/photos/Zx5UKS3zC60
A Pen by Paul Mealy on CodePen.
Using canvas for image masking.
Image courtesy of Laura Aziz | Unsplash https://unsplash.com/photos/Zx5UKS3zC60
A Pen by Paul Mealy on CodePen.
<canvas id='stage'></canvas> | |
<h1>Mouse over image</h1> | |
<footer> | |
<a href="http://insidedown.com">Paul Mealy | InsideDown</a> | |
</footer> |
//*** SHIM *** | |
window.requestAnimFrame = (function() { | |
return window.requestAnimationFrame || | |
window.webkitRequestAnimationFrame || | |
window.mozRequestAnimationFrame || | |
window.oRequestAnimationFrame || | |
window.msRequestAnimationFrame || | |
function(callback) { | |
window.setTimeout(callback, 1000 / 60); | |
}; | |
})(); | |
(function() { | |
"use strict"; | |
//************ | |
//VARIABLES | |
//************ | |
var _Canvas; | |
let _frontImageSrc = 'http://insidedown.com/codepen/stock/mountain-tan.jpg'; | |
let _backImageSrc = 'http://insidedown.com/codepen/stock/mountain.jpg'; | |
let _frontImage; | |
let _backImage; | |
let _blackMask; | |
let _mouseX = 0; | |
let _mouseY = 0; | |
let _maskCount = 25; | |
let _tweenTime = 0.5; | |
let _pauseTime = 0.25; | |
let _delayTime = 0.08; | |
let _maskArray = []; | |
let _srcArray = ["http://insidedown.com/codepen/stock/newstain1.png", "http://insidedown.com/codepen/stock/newstain2.png", "http://insidedown.com/codepen/stock/newstain3.png"]; | |
//************ | |
//METHODS | |
//************ | |
function init() { | |
_Canvas = new Canvas({stage:document.getElementById('stage')}); | |
_backImage = new MaskedImage({src:_backImageSrc}); | |
_frontImage = new MaskedImage({src:_frontImageSrc}); | |
for(let i=0;i<_maskCount;i++){ | |
let ranSrc = _srcArray[Math.floor(Math.random() * _srcArray.length)]; | |
let mask = new MaskedImage({src:ranSrc, delay:i, width:300}); | |
_maskArray.push(mask); | |
} | |
addListeners(); | |
} | |
//************ | |
//EVENTS | |
//************ | |
function addListeners() { | |
_Canvas.el.addEventListener('mousemove', onCanvasMouseMove); | |
_Canvas.el.addEventListener('mouseout', onCanvasMouseOut); | |
} | |
function onCanvasMouseMove(event) { | |
_mouseX = event.pageX - $(this).offset().left; | |
_mouseY = event.pageY - $(this).offset().top; | |
} | |
function onCanvasMouseOut(event) { | |
} | |
function onEnterFrame() { | |
_Canvas.clearStage(); | |
drawStage(); | |
window.requestAnimFrame(onEnterFrame, 60); | |
} | |
function drawStage() { | |
_Canvas.context.save(); | |
for(let i=0;i<_maskCount;i++){ | |
let mask = _maskArray[i]; | |
mask.tweenDraw(); | |
} | |
//_blackMask.draw(_mouseX,_mouseY); | |
_Canvas.context.globalCompositeOperation = 'source-in'; | |
_backImage.draw(); | |
_Canvas.context.globalCompositeOperation = 'destination-over'; | |
_frontImage.draw(); | |
_Canvas.context.restore(); | |
} | |
//************ | |
//CLASSES | |
//************ | |
class MaskedImage { | |
constructor(options) { | |
this.hasImg = false; | |
this.img = new Image(); | |
this.empty = {scale:0, alpha:1, x:0, y:0}; | |
this.delay = options.delay; | |
this.rotation = Math.random() * 360; | |
this.width = options.width; | |
this.halfWidth = this.width/2; | |
this.img.src = options.src; | |
this.img.onload = function() { | |
this.hasImg = true; | |
if(this.delay){ | |
setTimeout(function() {this.scale();}.bind(this), this.delay*(_delayTime * 1000)); | |
} | |
this.draw(); | |
}.bind(this); | |
} | |
draw(x=0,y=0) { | |
if(this.hasImg) { | |
_Canvas.context.drawImage(this.img,x,y); | |
} | |
} | |
tweenDraw() { | |
if(this.hasImg) { | |
let curWidth = this.width * this.empty.scale; | |
_Canvas.context.save(); | |
_Canvas.context.globalAlpha = this.empty.alpha; | |
_Canvas.context.translate(this.empty.x, this.empty.y); | |
_Canvas.context.rotate(this.rotation * Math.PI / 180); | |
_Canvas.context.scale(1.5 * (curWidth/this.width), 1.5*(curWidth/this.width)); | |
_Canvas.context.translate(-this.empty.x, -this.empty.y); | |
_Canvas.context.drawImage(this.img,this.empty.x-this.halfWidth,this.empty.y-this.halfWidth); | |
_Canvas.context.globalAlpha = 1; | |
_Canvas.context.restore(); | |
} | |
} | |
scale() { | |
this.empty.x = _mouseX; | |
this.empty.y = _mouseY; | |
this.rotation = Math.random() * 360; | |
TweenMax.fromTo(this.empty, _tweenTime, {alpha:1, scale:0},{alpha:1, scale:1, onComplete:function(){ | |
setTimeout(this.fadeOut.bind(this), _pauseTime * 1000); | |
}.bind(this) | |
}); | |
} | |
fadeOut() { | |
TweenMax.to(this.empty, _tweenTime,{alpha:0, onComplete:this.scale.bind(this)}); | |
} | |
} | |
class Canvas { | |
constructor(options) { | |
this._stage = options.stage; | |
this._stageWidth = this._stage.width = window.innerWidth; | |
this._stageHeight = this._stage.height = window.innerHeight; | |
this._stageContext = this._stage.getContext('2d'); | |
} | |
// clear stage of current content | |
clearStage(options) { | |
if(typeof options === "undefined") { | |
this._stageContext.clearRect(0,0,this._stageWidth, this._stageHeight); | |
} | |
} | |
get width() { return this._stageWidth; } | |
get height() { return this._stageHeight; } | |
get el() {return this._stage; } | |
get context() {return this._stageContext; } | |
} //end Canvas class | |
init(); | |
onEnterFrame(); | |
})(); |
<script src="//cdnjs.cloudflare.com/ajax/libs/zepto/1.1.4/zepto.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.1/TweenMax.min.js"></script> |
@import url(https://fonts.googleapis.com/css?family=Lato:300,400,700, 400italic); | |
body { | |
background-color: #000; | |
height: 100%; | |
margin: 0; | |
overflow: hidden; | |
padding: 0; | |
width: 100%; | |
} | |
h1 { | |
color: #999; | |
font-family: 'Lato', helvetica, arial, sans-serif; | |
font-weight: normal; | |
font-size: 16px; | |
position: absolute; | |
text-align: center; | |
top: 0; | |
width: 100%; | |
} | |
canvas { | |
background-color: #111; | |
} | |
footer { | |
background: rgba(0,0,0,0.35); | |
border-radius: 0 10px 0px 0; | |
bottom: 0px; | |
color: #fff; | |
font-family: 'Lato', helvetica, arial, sans-serif; | |
font-size: 11px; | |
font-weight: 300; | |
padding: 8px 12px 8px 12px; | |
position: absolute; | |
text-shadow: -1px 1px #000000; | |
text-transform: uppercase; | |
z-index: 2; | |
} | |
footer a { | |
color: #fff; | |
text-decoration: none; | |
} | |
footer a:hover { | |
color: #ddd; | |
} |
@dt24tared
I had almost the same problem after using this same zip file, until I noticed that the html file wasn't complete; it's exactly as it appears on codePen. Just edit that and you should be fine. i.e here's my edit
From This;
<canvas id='stage'></canvas>
<h1>Mouse over image</h1>
<footer>
<a href="http://insidedown.com">Paul Mealy | InsideDown</a>
</footer>
To This;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Image Masking [local]</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<canvas id='stage'></canvas>
<h1>Mouse over image</h1>
<footer>
<a href="http://insidedown.com">Paul Mealy | InsideDown</a>
</footer>
<script src="https://cdnjs.cloudflare.com/ajax/libs/zepto/1.1.4/zepto.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.1/TweenMax.min.js"></script>
<script src="script.js"></script>
</body>
</html>
Worked well afterwards...cheers
how to set the height an width of the image....
I downloaded the zip file, because I was having issues when copying the code from Codepen, however the same problem arose from the zip files. The text shows up fine but the images aren't shown and it only shows the black background from the css. It doesn't work either with the precoded images or with images I included from file. It reads the Javascript file as being linked but doesn't seam to implement anything from it. I did very little to the code, and yet it doesn't work in any browser I've tried. Is there something I need to do?