Skip to content

Instantly share code, notes, and snippets.

@patrickatwsrn
Forked from CodeMyUI/image-masking.markdown
Created January 25, 2021 15:56
Show Gist options
  • Save patrickatwsrn/837ea38e16ef88ac4dab3ab97cd399a2 to your computer and use it in GitHub Desktop.
Save patrickatwsrn/837ea38e16ef88ac4dab3ab97cd399a2 to your computer and use it in GitHub Desktop.
Image Masking
<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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment