Parallax Canvas Gallery

Size
12,954 Kb
Views
32,384

How do I make an parallax canvas gallery?

Inspired by iOS photos app subtle parallax effect. Find the code on github. Grab icon by Felix Westphal, Keyboard icon by Jardson Almeida.. What is a parallax canvas gallery? How do you make a parallax canvas gallery? This script and codes were developed by Rosh Jutherford on 04 September 2022, Sunday.

Parallax Canvas Gallery Previews

Parallax Canvas Gallery - Script Codes HTML Codes

<!DOCTYPE html>
<html >
<head> <meta charset="UTF-8"> <title>Parallax Canvas Gallery</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css"> <style> /* NOTE: The styles were added inline because Prefixfree needs access to your styles and they must be inlined if they are on local disk! */ html { background: white; font-family: system, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif; text-rendering: optimizeLegibility; font-smoothing: antialiased; font-size: 62.5%;
}
.gallery { max-width: 600px; margin: 0 auto; position: relative;
}
.gallery canvas { cursor: pointer;
}
.gallery__item { display: none;
}
.instructions { text-align: center; color: #999999; margin: 40px 0 20px;
}
.instructions__title { text-transform: uppercase; margin-bottom: 10px; font-size: 2.4rem; font-weight: 300;
}
.instructions__icon { width: 50px; height: 50px; vertical-align: middle; fill: #999999;
}
.instructions__text { margin-right: 10px; font-weight: 400; font-size: 1.4rem;
}
/*svg*/
.swipe { width: 50px; height: 50px; display: block; margin: 100px auto 30px; opacity: 0.4;
} </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
</head>
<body> <div class="instructions">	<h1 class="instructions__title">Parallax Canvas Gallery</h1>	<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 100 125" class="instructions__icon icon--swipe">	<path d="M67.3,43.4c-0.8,0-1.5,0.1-2.3,0.4c-0.3-1.3-0.8-2.5-1.5-3.4c-1.1-1.3-2.6-2-4.3-2c-1.1,0-2.2,0.3-3.2,1 c-0.3-0.5-0.7-1-1-1.3c-1.2-1.2-2.8-1.9-4.5-1.9c-0.9,0-1.8,0.2-2.7,0.6v-12c0-2.7-1.1-4.4-2-5.3c-1.2-1.2-2.8-1.9-4.5-1.9 c-3.2,0-6.7,2.5-6.7,7.2V42c-3.5,1.2-8.2,4.3-8.2,10.3v12.2v0.1c0,0.1,0,0.1,0,0.2s0,0.1,0,0.2s0,0.1,0.1,0.2c0,0.1,0.1,0.1,0.1,0.2 s0.1,0.1,0.1,0.2s0.1,0.1,0.1,0.2c0,0,0,0.1,0.1,0.1l7.8,8.6v15.6c0,1.1,0.9,2,2,2h30.9c1.1,0,2-0.9,2-2V74.3l3.5-7.6 c0.1-0.3,0.2-0.5,0.2-0.8v-16C73.4,45.6,70.3,43.4,67.3,43.4z M69.4,65.4L65.9,73c-0.1,0.3-0.2,0.5-0.2,0.8v14.1H38.9v-5.2h20.8 c1.1,0,2-0.9,2-2s-0.9-2-2-2H38.9v-5.2c0-0.5-0.2-1-0.5-1.3l-7.8-8.6V52.2c0-3.3,2.3-5,4.2-5.9v11.6c0,1.1,0.9,2,2,2s2-0.9,2-2V43.5 l0,0V24.9c0-3.2,3-3.8,4.3-2.5c0.5,0.6,0.8,1.4,0.8,2.5v23.5c0,1.1,0.9,2,2,2s2-0.9,2-2v-4.9l0,0c0-3.3,3-3.8,4.3-2.5 c0.5,0.6,0.8,1.4,0.8,2.5v5.4c0,1.1,0.9,2,2,2s2-0.9,2-2v-3.1c0-2.2,1.1-3.2,2.2-3.2c0.3,0,0.8,0.1,1.2,0.6c0.5,0.6,0.7,1.5,0.7,2.6 V50c0,1.1,0.9,2,2,2c1.1,0,2-0.9,2-2l0,0c0-1.9,1.1-2.5,2.1-2.5s2.1,0.7,2.1,2.5L69.4,65.4L69.4,65.4z M18.8,26h9.1 c0.2,1.8,0.8,3.6,1.8,5.2c0.6,0.9,1.8,1.3,2.7,0.7c0.9-0.6,1.3-1.8,0.7-2.7c-0.9-1.5-1.3-3.1-1.3-4.8c0-5.2,4.3-9.5,9.5-9.5 s9.5,4.3,9.5,9.5c0,1.7-0.5,3.4-1.3,4.8c-0.6,0.9-0.3,2.2,0.7,2.7c0.3,0.2,0.7,0.3,1,0.3c0.7,0,1.3-0.3,1.7-1c1-1.6,1.6-3.4,1.8-5.2 h8.8l-2.6,2.6c-0.8,0.8-0.8,2,0,2.8c0.4,0.4,0.9,0.6,1.4,0.6s1-0.2,1.4-0.6l6-6c0.8-0.8,0.8-2,0-2.8l-6-6c-0.8-0.8-2-0.8-2.8,0 c-0.8,0.8-0.8,2,0,2.8l2.6,2.6h-8.9c-1.1-6.3-6.6-11.2-13.3-11.2S29.2,15.7,28,22h-9.2l2.6-2.6c0.8-0.8,0.8-2,0-2.8 c-0.8-0.8-2-0.8-2.8,0l-6,6c-0.8,0.8-0.8,2,0,2.8l6,6C19,31.8,19.5,32,20,32s1-0.2,1.4-0.6c0.8-0.8,0.8-2,0-2.8L18.8,26z"/>	</svg>	<span class="instructions__text">or</span>	<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="-132.1 184.4 66.1 32.3" class="instructions__icon icon--arrows">	<path d="M-68.2,216.6H-96c-1.2,0-2.3-1-2.3-2.3v-27.8c0-1.2,1-2.3,2.3-2.3h27.8c1.2,0,2.3,1,2.3,2.3v27.8	C-65.9,215.6-66.9,216.6-68.2,216.6z M-96,185.9c-0.4,0-0.8,0.3-0.8,0.8v27.8c0,0.4,0.3,0.8,0.8,0.8h27.8c0.4,0,0.8-0.3,0.8-0.8	v-27.8c0-0.4-0.3-0.8-0.8-0.8H-96z M-86,209c-0.2,0-0.4-0.1-0.5-0.2c-0.3-0.3-0.3-0.8,0-1.1l7.2-7.2l-7.2-7.2	c-0.3-0.3-0.3-0.8,0-1.1c0.3-0.3,0.8-0.3,1.1,0l7.8,7.8c0.3,0.3,0.3,0.8,0,1.1l-7.8,7.8C-85.6,208.9-85.8,209-86,209z M-102,216.6 h-27.8c-1.2,0-2.3-1-2.3-2.3v-27.8c0-1.2,1-2.3,2.3-2.3h27.8c1.2,0,2.3,1,2.3,2.3v27.8C-99.8,215.6-100.8,216.6-102,216.6z M-129.8,185.9c-0.4,0-0.8,0.3-0.8,0.8v27.8c0,0.4,0.3,0.8,0.8,0.8h27.8c0.4,0,0.8-0.3,0.8-0.8v-27.8c0-0.4-0.3-0.8-0.8-0.8H-129.8z M-112,209c-0.2,0-0.4-0.1-0.5-0.2l-7.8-7.8c-0.3-0.3-0.3-0.8,0-1.1l7.8-7.8c0.3-0.3,0.8-0.3,1.1,0c0.3,0.3,0.3,0.8,0,1.1l-7.2,7.2 l7.2,7.2c0.3,0.3,0.3,0.8,0,1.1C-111.7,208.9-111.9,209-112,209z"/>	</svg>
</div>
<div class="gallery" id="gallery">	<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/25381/2_copy.jpg" alt="" class="gallery__item">	<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/25381/3_copy.jpg" alt="" class="gallery__item">	<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/25381/4_copy.jpg" alt="" class="gallery__item">	<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/25381/5.jpg" alt="" class="gallery__item">	<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/25381/6.jpg" alt="" class="gallery__item">	<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/25381/7.jpg" alt="" class="gallery__item">
</div> <script src='https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.6/hammer.min.js'></script> <script src="js/index.js"></script>
</body>
</html>

Parallax Canvas Gallery - Script Codes CSS Codes

html { background: white; font-family: system, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif; text-rendering: optimizeLegibility; font-smoothing: antialiased; font-size: 62.5%;
}
.gallery { max-width: 600px; margin: 0 auto; position: relative;
}
.gallery canvas { cursor: pointer;
}
.gallery__item { display: none;
}
.instructions { text-align: center; color: #999999; margin: 40px 0 20px;
}
.instructions__title { text-transform: uppercase; margin-bottom: 10px; font-size: 2.4rem; font-weight: 300;
}
.instructions__icon { width: 50px; height: 50px; vertical-align: middle; fill: #999999;
}
.instructions__text { margin-right: 10px; font-weight: 400; font-size: 1.4rem;
}
/*svg*/
.swipe { width: 50px; height: 50px; display: block; margin: 100px auto 30px; opacity: 0.4;
}

Parallax Canvas Gallery - Script Codes JS Codes

'use strict';
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Emitter = function () { function Emitter() { _classCallCheck(this, Emitter); this._events = {}; } Emitter.prototype._hasEvent = function _hasEvent(eventName) { return this._events.hasOwnProperty(eventName); }; Emitter.prototype.on = function on(eventName, callback) { this._events[eventName] = this._events[eventName] || []; this._events[eventName].push(callback); }; Emitter.prototype.off = function off(eventName, callback) { if (!this._hasEvent(eventName)) { return; } var index = this._events[eventName].indexOf(callback); if (index > -1) { this._events[eventName].splice(index, 1); } }; Emitter.prototype.trigger = function trigger(eventName, data) { if (this._events.hasOwnProperty(eventName)) { this._events[eventName].forEach(function (callback) { if (typeof data !== 'undefined') { callback(data); } else { callback(); } }); } }; Emitter.prototype.destroy = function destroy() { this._events = null; }; return Emitter;
}();
;
var Gallery = function (_Emitter) { _inherits(Gallery, _Emitter); /** * Constructor. * @param { DOM node } el - the DOM node to gallerify */ function Gallery(el) { _classCallCheck(this, Gallery); var _this = _possibleConstructorReturn(this, _Emitter.call(this)); _this._el = el; _this._width = _this._el.getBoundingClientRect().width; _this._maxHeight = 500; _this._margin = 40; _this.currentSlide = 0; _this._lastPos = 0; _this.pos = 0; _this._ready = false; _this._transitioning = false; _this._transitionStart = false; _this._drag = 0; _this._direction = false; _this._ticking = false; _this._getSlides(_this._el, function (slides) { _this._slideImages = slides; var slideDimensions = _this._getSlideDimensions(slides); _this._height = slideDimensions.tallest; _this._createCanvasLayers(el); _this._slides = []; slides.forEach(function (slide, idx) { _this._slides.push(new Item(_this._ctx, slide, idx, _this._width, _this._height, _this._margin, slideDimensions[idx].width, slideDimensions[idx].height)); }); _this.currentPosition = _this._slides[_this.currentSlide].leftOffset; _this._numSlides = slides.length; _this._fullWidth = (_this._width + _this._margin) * (_this._numSlides - 1); _this._bindEvents(); _this._ready = true; _this._draw(); _this._slides[_this.currentSlide]._onDraw(_this.pos); _this.trigger('ready'); }); return _this; } /** * Fetches images from the DOM and creates Items. * @param { DOM node } gallery * @param { function } cb - the callback to be executed when the promises resolve. Receives an array of items as the only parameter. */ Gallery.prototype._getSlides = function _getSlides(gallery, cb) { var promises = []; var slides = Array.from(gallery.querySelectorAll('.gallery__item')); slides.forEach(function (slide, idx) { var src = slide.src; var img = document.createElement('img'); var width = undefined, height = undefined; var promise = new Promise(function (resolve, reject) { img.onload = function () { resolve(img); }; img.onerror = function () { reject('image could not load'); }; }); promises.push(promise); img.src = src; }); return Promise.all(promises).then(cb); }; /** * Takes an array of slides and returnes the scaled values for each, as well as the height of the tallest scaled slide. * @param { array } slides * @return { object } dimensions */ Gallery.prototype._getSlideDimensions = function _getSlideDimensions(slides) { var _this2 = this; var tallest = 0; var info = {}; slides.forEach(function (slide, idx) { var dimensions = _this2._scaleImageDimensions(slide.width, slide.height, _this2._width, _this2._maxHeight); tallest = dimensions.height > tallest ? dimensions.height : tallest; info[idx] = dimensions; }); info.tallest = tallest; return info; }; /** * Takes an images dimensions, and returns the scaled values to fit into the gallery. * @param { number} width * @param { number} height * @param { number} galleryMaxWidth * @param { number} galleryMaxHeight */ Gallery.prototype._scaleImageDimensions = function _scaleImageDimensions(width, height, galleryMaxWidth, galleryMaxHeight) { var itemRatio = width / height; var galleryRatio = galleryMaxWidth / galleryMaxHeight; var willScaleXAxis = itemRatio >= galleryRatio; var newWidth = Math.round(willScaleXAxis ? galleryMaxWidth : width * galleryMaxHeight / height); var newHeight = Math.round(willScaleXAxis ? height * galleryMaxWidth / width : galleryMaxHeight); return { width: newWidth, height: newHeight }; }; /** * Creates the <canvas> element. * @param { DOM node } gallery */ Gallery.prototype._createCanvasLayers = function _createCanvasLayers(gallery) { this._canvas = document.createElement('canvas'); this._canvas.width = this._width; this._canvas.height = this._height; this._ctx = this._canvas.getContext('2d'); // Put it out: gallery.appendChild(this._canvas); }; /** * Attaches key listeners. */ Gallery.prototype._bindKeyEvents = function _bindKeyEvents() { var _this3 = this; document.addEventListener('keydown', function (e) { if (_this3._transitioning || e.altKey || e.ctrlKey || e.shiftKey) { return; } if (e.keyCode === 37) { e.preventDefault(); _this3._goToSlide(_this3.currentSlide - 1, 500); } else if (e.keyCode === 39) { e.preventDefault(); _this3._goToSlide(_this3.currentSlide + 1, 500); } }); }; /** * Attaches touch listeners. */ Gallery.prototype._bindTouchEvents = function _bindTouchEvents() { var _this4 = this; this._hammer = new Hammer(this._canvas); this._hammer.on('pan', function (e) { _this4._direction = e.direction === 4 || e.direction === 2 ? e.direction : _this4._direction; _this4._drag = Math.round(e.deltaX); var tentativePos = _this4.currentPosition + _this4._drag * -1; if (tentativePos <= 0 || tentativePos >= _this4._fullWidth) { tentativePos = _this4.currentPosition + _this4._drag * -0.5; } _this4.pos = tentativePos; if (e.isFinal && Math.abs(_this4._drag) >= _this4._width / 3 && !_this4._isTerminal()) { var which = _this4._drag < 0 ? _this4.currentSlide + 1 : _this4.currentSlide - 1; _this4._goToSlide(which); } else if (e.isFinal) { _this4._transition(_this4.pos, _this4.currentPosition); } }); }; /** * * */ Gallery.prototype._bindResizeEvent = function _bindResizeEvent() { var _this5 = this; var resizeHandler = function resizeHandler(timestamp) { _this5._width = _this5._el.getBoundingClientRect().width; var slideDimensions = _this5._getSlideDimensions(_this5._slideImages); _this5._canvas.width = _this5._width; _this5._canvas.height = slideDimensions.tallest; _this5._slides.forEach(function (slide, idx) { slide.refresh(slideDimensions[idx].width, slideDimensions[idx].height, _this5._width, _this5._maxHeight); }); _this5.off('draw', resizeHandler); _this5._clear(); _this5._lastPos = false; _this5.pos = _this5._slides[_this5.currentSlide].leftOffset; _this5._ticking = false; }; window.addEventListener('resize', function () { if (_this5._ticking) { return; } _this5._ticking = true; _this5.on('draw', resizeHandler); }); }; /** * * */ Gallery.prototype._bindEvents = function _bindEvents() { this._bindKeyEvents(); this._bindTouchEvents(); this._bindResizeEvent(); }; /** * Detects if the current slide can move in the current direction. * @return { boolean } */ Gallery.prototype._isTerminal = function _isTerminal() { return this.currentSlide === 0 && this._direction === 4 || this.currentSlide === this._numSlides - 1 && this._direction === 2; }; /** * Creates a transition from one position to another. * @param { number } from * @param { number } to * @param { number = 250 } duration */ Gallery.prototype._transition = function _transition(from, to) { var duration = arguments.length <= 2 || arguments[2] === undefined ? 250 : arguments[2]; this._transitioning = true; this._transitionDuration = duration; this._transitionFrom = from; this._transitionTo = to; }; /** * Advances to the next/previous slide. */ Gallery.prototype._setCurrentPosition = function _setCurrentPosition() { var duration = arguments.length <= 0 || arguments[0] === undefined ? 250 : arguments[0]; var dest = this._slides[this.currentSlide].leftOffset; this.currentPosition = dest; this._transition(this.pos, dest, duration); }; /** * Goes to the specified slide. * @param { number } slideNo */ Gallery.prototype._goToSlide = function _goToSlide(slideNo) { var duration = arguments.length <= 1 || arguments[1] === undefined ? 250 : arguments[1]; if (slideNo < 0 || slideNo > this._numSlides - 1) { return; } this.currentSlide = slideNo; this._setCurrentPosition(duration); this.trigger('update'); }; /** * Returns the currently visible slides. * @param { number } pos - the current position * @return { array } slides */ Gallery.prototype._getSlidesInView = function _getSlidesInView(pos) { var inView = []; this._slides.forEach(function (slide, idx) { if (pos >= slide.leftBound && pos <= slide.rightBound) { inView.push(idx); } }); return inView; }; /** * Clears the <canvas> for next paint. */ Gallery.prototype._clear = function _clear() { return this._ctx.clearRect(0, 0, this._width, this._height); }; /** * Callback executed at each animationFrame. * @param { number } timestamp */ Gallery.prototype._draw = function _draw(timestamp) { var _this6 = this; this.trigger('draw', timestamp); if (typeof timestamp === 'undefined' || this.pos === this._lastPos && !this._transitioning || !this._ready) { this._raf = requestAnimationFrame(this._draw.bind(this)); return; } if (this._transitioning) { if (this._transitionStart === false) { this._transitionStart = timestamp; } var delta = Math.min((timestamp - this._transitionStart) / this._transitionDuration, 1); this.pos = (this._transitionTo - this._transitionFrom) * delta * delta + this._transitionFrom; if (delta === 1) { this._transitioning = false; this._transitionStart = false; } } this._clear(); this._getSlidesInView(this.pos).forEach(function (idx) { _this6._slides[idx].trigger('draw', _this6.pos); }); this._lastPos = this.pos; this._raf = requestAnimationFrame(this._draw.bind(this)); }; return Gallery;
}(Emitter);
;
var Item = function (_Emitter2) { _inherits(Item, _Emitter2); /** * Constructor. See _getProps for parameters. */ function Item() { _classCallCheck(this, Item); var _this7 = _possibleConstructorReturn(this, _Emitter2.call(this)); _this7._getProps.apply(_this7, arguments); _this7._boundOnDraw = _this7._onDraw.bind(_this7); _this7.on('draw', _this7._boundOnDraw); return _this7; } /** * Callback executed when 'draw' event is triggered. * @param { number } pos */ Item.prototype._onDraw = function _onDraw(pos) { var sx = 0; var sy = 0; var sWidth = this.width; var sHeight = this.height; var dx = this.leftOffset - pos + this.xOffset; var dy = 0 + this.yOffset; var dWidth = this.slideWidth; var dHeight = this.slideHeight; this._parallax(dx); this.output.drawImage(this.canvas, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); }; /** * Handles parallax effect. * @param { number } dx - the difference between the current position and the Item center. */ Item.prototype._parallax = function _parallax(dx) { var multiplier = Math.round((dx - this.xOffset) * -0.25); this.ctx.clearRect(0, 0, this.width, this.height); this.ctx.drawImage(this.img, multiplier, 0, this.width, this.height); }; /** * Extracts parameters needed for setup. * @param { DOM node } output - the <canvas> to draw to _onDraw. * @param { DOM node } img - the <img> element that this slide is based on. * @param { number } idx - the index of this slide in relation to its' siblings. * @param { number } parentWidth - the width of the parent Gallery * @param { number } parentHeight - the height of the parent Gallery. * @param { number } margin - the amount of margin between each slide. * @param { number } slideWidth - the scaled width of the slide. * @param { number } slideHeight - the scaled height of the slide. */ Item.prototype._getProps = function _getProps(output, img) { var idx = arguments.length <= 2 || arguments[2] === undefined ? 0 : arguments[2]; var parentWidth = arguments.length <= 3 || arguments[3] === undefined ? 400 : arguments[3]; var parentHeight = arguments.length <= 4 || arguments[4] === undefined ? 400 : arguments[4]; var margin = arguments.length <= 5 || arguments[5] === undefined ? 40 : arguments[5]; var slideWidth = arguments[6]; var slideHeight = arguments[7]; this.idx = idx; this.margin = margin; this.refresh(slideWidth, slideHeight, parentWidth, parentHeight); this.output = output; this.img = img; this.width = this.img.width; this.height = this.img.height; this.canvas = document.createElement('canvas'); this.ctx = this.canvas.getContext('2d'); this.canvas.width = this.width; this.canvas.height = this.height; this.ctx.drawImage(this.img, 0, 0, this.width, this.height); }; /** * Calculates positioning and offsets. * @param { number } slideWidth - the scaled width of the slide. * @param { number } slideHeight - the scaled height of the slide. * @param { number } parentWidth - the width of the parent Gallery * @param { number } parentHeight - the height of the parent Gallery. */ Item.prototype.refresh = function refresh(slideWidth, slideHeight, parentWidth, parentHeight) { this.slideWidth = slideWidth; this.slideHeight = slideHeight; this.parentWidth = parentWidth; this.parentHeight = parentHeight; this.xOffset = (parentWidth - slideWidth) / 2; this.yOffset = (parentHeight - slideHeight) / 2; this.leftBound = (this.idx - 1) * this.parentWidth + this.idx * this.margin; this.rightBound = (this.idx + 1) * this.parentWidth + this.idx * this.margin; this.leftOffset = this.idx * this.parentWidth + this.idx * this.margin; }; return Item;
}(Emitter);
;
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
//
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
//
// MIT license
(function () { var lastTime = 0; var vendors = ['ms', 'moz', 'webkit', 'o']; for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame']; } if (!window.requestAnimationFrame) { window.requestAnimationFrame = function (callback, element) { var currTime = new Date().getTime(); var timeToCall = Math.max(0, 16 - (currTime - lastTime)); var id = window.setTimeout(function () { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; } if (!window.cancelAnimationFrame) { window.cancelAnimationFrame = function (id) { clearTimeout(id); }; }
})();
var gallery = new Gallery(document.getElementById('gallery'));
Parallax Canvas Gallery - Script Codes
Parallax Canvas Gallery - Script Codes
Home Page Home
Developer Rosh Jutherford
Username the_ruther4d
Uploaded September 04, 2022
Rating 4.5
Size 12,954 Kb
Views 32,384
Do you need developer help for Parallax Canvas Gallery?

Find the perfect freelance services for your business! Fiverr's mission is to change how the world works together. Fiverr connects businesses with freelancers offering digital services in 500+ categories. Find Developer!

Rosh Jutherford (the_ruther4d) Script Codes
Create amazing marketing copy with AI!

Jasper is the AI Content Generator that helps you and your team break through creative blocks to create amazing, original content 10X faster. Discover all the ways the Jasper AI Content Platform can help streamline your creative workflows. Start For Free!