<div class="loading"> <div class="loading-container"> <p class="counter"></p> <div class="line"></div> </div> </div> <div class="body-container"> <div class="box"> <h1>Gallery Example</h1> </div> </div> @import url("https://fonts.googleapis.com/css?family=Montserrat:400,400i,700"); *, ::before, ::after { box-sizing: border-box; border-style: solid; border-width: 0; } html { background: #01012a; color: #33def4; } html, body { -ms-scroll-chaining: none; overscroll-behavior: none; font-family: Montserrat, sans-serif; overflow: hidden; } .box { padding: 32px; } h1 { font-size: 2.4rem; padding-bottom: 16px; } .loading { z-index: 9999; background: #01012a; color: #33def4; text-align: center; position: fixed; width: 100%; min-height: 100vh; min-height: calc(var(--vh, 1vh) * 100); overflow: hidden; display: flex; justify-content: center; align-items: center; opacity: 1; visibility: visible; transition: opacity 0.8s 0.8s cubic-bezier(0.755, 0.05, 0.855, 0.06), visibility 0.8s 0.8s cubic-bezier(0.755, 0.05, 0.855, 0.06); } .loading.loaded { opacity: 0; visibility: hidden; } .loading .loading-container { position: relative; width: 40%; overflow: hidden; } .loading .loading-container .counter { padding: 0.8rem; transform: traslate(0, 0); } .loading .loading-container .counter.loaded { -webkit-animation: counter-animation 0.8s cubic-bezier(0.755, 0.05, 0.855, 0.06) 0.8s 1 normal forwards running; animation: counter-animation 0.8s cubic-bezier(0.755, 0.05, 0.855, 0.06) 0.8s 1 normal forwards running; } .loading .loading-container .line { position: absolute; background: #03e2e7; left: 0; bottom: 0; width: 0; height: 2px; } .loading .loading-container .line.loaded { -webkit-animation: line-animation 0.8s cubic-bezier(0.755, 0.05, 0.855, 0.06) 0s 1 normal forwards running; animation: line-animation 0.8s cubic-bezier(0.755, 0.05, 0.855, 0.06) 0s 1 normal forwards running; } @-webkit-keyframes counter-animation { 0% { transform: translate(0, 0); } 100% { transform: translate(0, 10%); } } @keyframes counter-animation { 0% { transform: translate(0, 0); } 100% { transform: translate(0, 10%); } } @-webkit-keyframes line-animation { 0% { left: 0; } 100% { left: 100%; } } @keyframes line-animation { 0% { left: 0; } 100% { left: 100%; } } const imagePaths = [ 'https://images.unsplash.com/photo-1608687087357-845abfade367?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2Njc1NTk3NzE&ixlib=rb-4.0.3&q=80&w=400', 'https://images.unsplash.com/photo-1604818640599-71bda0165d53?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2Njc1NTk3NzE&ixlib=rb-4.0.3&q=80&w=400', 'https://images.unsplash.com/photo-1574357278720-2809ce8065db?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2Njc1NTk3NzE&ixlib=rb-4.0.3&q=80&w=400', 'https://images.unsplash.com/photo-1602136773736-34d445b989cb?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2Njc1NTk3NzE&ixlib=rb-4.0.3&q=80&w=400', 'https://images.unsplash.com/photo-1501769752-a59efa2298ce?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2Njc1NTk3NzE&ixlib=rb-4.0.3&q=80&w=400', 'https://images.unsplash.com/photo-1558961166-9c584702dcb0?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2Njc1NTk3NzE&ixlib=rb-4.0.3&q=80&w=400', 'https://images.unsplash.com/photo-1571182160015-2169f6e1aa5f?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2Njc1NTk3NzE&ixlib=rb-4.0.3&q=80&w=400', 'https://images.unsplash.com/photo-1555852224-2a3e675fc47e?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2Njc1NTk3NzE&ixlib=rb-4.0.3&q=80&w=400', 'https://images.unsplash.com/photo-1620215175664-cb9a6f5b6103?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2Njc1NTk4NzE&ixlib=rb-4.0.3&q=80&w=400', 'https://images.unsplash.com/photo-1539606328118-80c679838702?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2Njc1NTk4NzE&ixlib=rb-4.0.3&q=80&w=400', 'https://images.unsplash.com/photo-1574357278720-2809ce8065db?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2Njc1NTk4NzE&ixlib=rb-4.0.3&q=80&w=400', 'https://images.unsplash.com/photo-1574357265250-10c88f63ebfd?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2Njc1NTk4NzE&ixlib=rb-4.0.3&q=80&w=400', 'https://images.unsplash.com/photo-1536901766856-5d45744cd180?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2Njc1NTk5MjA&ixlib=rb-4.0.3&q=80&w=400']; class Utilities { static norm(value, min, max) { return (value - min) / (max - min); } static lerp(norm, min, max) { return (max - min) * norm + min; } static map(value, sourceMin, sourceMax, destMin, destMax) { return this.lerp(this.norm(value, sourceMin, sourceMax), destMin, destMax); } static clamp(value, min, max) { return Math.min(Math.max(value, min), max); } static distance(x0, y0, x1, y1) { const dx = x1 - x0; const dy = y1 - y0; return Math.sqrt(dx * dx + dy * dy); } static randomRange(min, max) { return min + Math.random() * (max - min); } static randomInt(min, max) { return Math.floor(min + Math.random() * (max - min + 1)); } static randomDist(min, max, iterations) { let total = 0; for (let i = 0; i < iterations; i++) { total += this.randomRange(min, max); } return total / iterations; } static degreesToRads(degrees) { return degrees / 180 * Math.PI; } static radsToDegrees(radians) { return radians * 180 / Math.PI; } static roundToPlaces(value, places) { const mult = Math.pow(10, places); return Math.round(value * mult) / mult; } static roundNearest(value, nearest) { return Math.round(value / nearest) * nearest; }} class Loading { constructor() { this.load = document.getElementsByClassName('loading')[0]; this.line = document.getElementsByClassName('line')[0]; this.counter = document.getElementsByClassName('counter')[0]; this.imagePaths = imagePaths; this.loadedNumber = 1; this.percentage = 0; this.num = 0; } initialize() { return new Promise((resolve, reject) => { this.loadImages(resolve, reject); }); } loadImages(resolve, reject) { for (let i = 0; i < this.imagePaths.length; i++) { const path = this.imagePaths[i]; const image = new Image(); image.src = path; image.crossOrigin = "anonymous"; image.addEventListener('load', () => { this.percentage = this.getPercentage(this.loadedNumber++); }); } this.drawPercentage(resolve, reject); } getPercentage(num) { return Math.floor(num / this.imagePaths.length * 100); } drawPercentage(resolve, reject) { if (this.num < this.percentage) { this.num++; } this.line.style.width = this.num + '%'; this.counter.textContent = this.num + '%'; if (this.num === 100) { this.cancelDrawLoopCounterNumber(resolve, reject); return; } this.animationID = requestAnimationFrame(this.drawPercentage.bind(this, resolve, reject)); } cancelDrawLoopCounterNumber(resolve, reject) { cancelAnimationFrame(this.animationID); this.addClass(resolve, reject); } addClass(resolve, reject) { this.delay(400). then(() => { this.load.classList.add('loaded'); this.line.classList.add('loaded'); this.counter.classList.add('loaded'); resolve(); }); } delay(time) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(); }, time); }); }} class FullScreen { constructor() { this.setupEvents(); this.initialize(); } initialize() { const vh = window.innerHeight * 0.01; document.documentElement.style.setProperty('--vh', `${vh}px`); } setupEvents() { window.addEventListener('resize', this.onResize.bind(this), false); } onResize() { this.initialize(); }} class DrawMainImage { constructor(ctx, width, height) { this.ctx = ctx; this.width = width; this.height = height; this.initialize(); } initialize() { this.canvas = document.createElement('canvas'); this.ctx2 = this.canvas.getContext('2d'); this.image = null; this.stopWatch = new Stopwatch(); this.dataArr = []; } drawImage(src) { this.isLoaded = false; this.image = new Image(); this.image.src = src; this.image.crossOrigin = "anonymous"; this.image.addEventListener('load', () => { this.stopWatch.initialize(); let imageWidth, ratio, imageHeight; if (this.image.width >= this.image.height) { imageWidth = Math.min(this.width * 0.9, this.image.width); ratio = this.image.width / this.image.height; imageHeight = imageWidth / ratio; } else { imageHeight = Math.min(this.height * 0.9, this.image.height); ratio = this.image.height / this.image.width; imageWidth = imageHeight / ratio; if (imageWidth >= this.width * 0.9) { imageWidth = Math.min(this.width * 0.9, this.image.width); ratio = this.image.width / this.image.height; imageHeight = imageWidth / ratio; } } this.canvas.width = imageWidth; this.canvas.height = imageHeight; this.ctx2.clearRect(0, 0, imageWidth, imageHeight); this.ctx2.drawImage(this.image, 0, 0, imageWidth, imageHeight); this.getImageData(); this.isLoaded = true; }); } getImageData() { this.dataArr = []; let preHeight = 0,addHeight = 0; for (let i = 0; i < this.canvas.height; i += addHeight) { const obj = {}; addHeight = Utilities.randomInt(5, 20); if (preHeight + addHeight > this.canvas.height) { addHeight = Math.floor(this.canvas.height - preHeight); } if (addHeight === 0) return; const image = this.ctx2.getImageData( 0, preHeight, this.canvas.width, addHeight); obj.image = image; obj.height = preHeight; obj.width = Math.random() * this.width * 0.5 - this.width * 0.25; this.dataArr.push(obj); preHeight += addHeight; } } addImage(t) { if (!this.isLoaded) return; for (let i = 0; i < this.dataArr.length; i++) { this.ctx.putImageData( this.dataArr[i].image, this.width / 2 - this.canvas.width / 2 + this.dataArr[i].width, this.height / 2 - this.canvas.height / 2 + this.dataArr[i].height); } this.moveImage(); } moveImage() { this.stopWatch.calculateTime(); const t = 1.0 - Math.min(this.stopWatch.getElapsedTime() * 0.0002, 1.0); this.e = this.ease(t); for (let i = 0; i < this.dataArr.length; i++) { this.dataArr[i].width *= this.e; } } deleteImage(t) { if (!this.isLoaded) return; for (let i = 0; i < this.dataArr.length; i++) { this.ctx.putImageData( this.dataArr[i].image, this.width / 2 - this.canvas.width / 2 + this.dataArr[i].width + Math.tan(t * 0.01 + this.dataArr[i].height / Math.PI) * 100, this.height / 2 - this.canvas.height / 2 + this.dataArr[i].height); } } ease(x) { return 1 - Math.sqrt(1 - Math.pow(x, 2)); }} class Sketch { constructor() { this.setupCanvas(); this.setupEvents(); this.initialize(); } setupCanvas() { this.canvas = document.createElement('canvas'); this.ctx = this.canvas.getContext('2d'); this.canvas.ariaLabel = 'This is images gallery.'; this.canvas.role = 'img'; this.canvas.style.position = 'fixed'; this.canvas.style.top = '0'; this.canvas.style.left = '0'; this.canvas.style.width = '100%'; this.canvas.style.minHeight = '100vh'; this.canvas.style.minHeight = 'calc(var(--vh, 1vh) * 100)'; this.canvas.style.display = 'block'; this.canvas.style.background = '#01012A'; this.canvas.style.zIndex = '-1'; document.body.appendChild(this.canvas); } setupEvents() { window.addEventListener('resize', this.onResize.bind(this), false); window.addEventListener('wheel', this.onWheel.bind(this), false); document.body.addEventListener('click', this.onClick.bind(this), false); document.body.addEventListener('mousemove', this.onMousemove.bind(this), false); document.body.addEventListener('touchstart', this.onTouchstart.bind(this), false); document.body.addEventListener('touchmove', this.onTouchmove.bind(this), false); } onMousemove(e) { this.touchInfos.mouse.x = e.clientX / this.width * this.width - this.width / 2; this.touchInfos.mouse.y = e.clientY / this.height * this.height - this.height / 2; } onTouchstart(e) { const t = e.targetTouches[0]; this.touchInfos.fing.start.x = t.pageX; this.touchInfos.fing.start.y = t.pageY; } onTouchmove(e) { const t = e.targetTouches[0]; this.touchInfos.mouse.x = t.pageX / this.width * this.width - this.width / 2; this.touchInfos.mouse.y = t.pageY / this.height * this.height - this.height / 2; this.touchInfos.fing.move.x = t.pageX; this.touchInfos.fing.move.y = t.pageY; this.touchInfos.fing.end.x = this.touchInfos.fing.start.x - this.touchInfos.fing.move.x; this.touchInfos.fing.end.y = this.touchInfos.fing.start.y - this.touchInfos.fing.move.y; this.touchInfos.delta.x += this.touchInfos.fing.end.x * 0.0003; this.touchInfos.delta.y += this.touchInfos.fing.end.y * 0.0003; } onResize() { if (this.preWidth === window.innerWidth) { this.height = this.canvas.height = window.innerHeight; return; } this.initialize(); } onWheel(e) { this.touchInfos.delta.x += e.deltaX * 0.0005; this.touchInfos.delta.y += e.deltaY * 0.0005; } onClick(e) { if (this.isDisplayed) { this.isDeleating = true; setTimeout(() => { this.isDeleating = false; this.isDisplayed = false; }, 160); return; } else { this.isDisplayed = false; } const x = this.touchInfos.mouse.x = e.clientX / this.width * this.width - this.width / 2; const y = this.touchInfos.mouse.y = e.clientY / this.height * this.height - this.height / 2; for (let i = 0; i < this.shapes.length; i++) { const s = this.shapes[i]; if (this.isHovered(s, x, y)) { this.isDisplayed = true; this.M.drawImage(s.image.src); return; } } } initialize() { if (this.animationId) { cancelAnimationFrame(this.animationId); } this.paths = imagePaths; this.isDisplayed = false; this.hasHover = window.matchMedia('(hover: hover)').matches; this.setupSizes(); this.setupShapes(); this.focus = { x: 0, y: 0, s: this.size }; this.touchInfos = { mouse: { x: 0, y: 0 }, delta: { x: 0, y: 0 }, fing: { start: { x: null, y: null }, move: { x: null, y: null }, end: { x: null, y: null } } }; this.G = new Glitch(this.ctx, this.width, this.height, 50, 200); this.M = new DrawMainImage(this.ctx, this.width, this.height); this.render(0); } setupSizes() { this.width = this.preWidth = this.canvas.width = window.innerWidth; this.height = this.canvas.height = window.innerHeight; } setupShapes() { const edge = Math.max(this.width, this.height); //const edge = Math.sqrt(this.width * this.width + this.height * this.height); this.radius = edge / 2; this.numberOfShape = 16; this.size = this.radius / (this.numberOfShape / 6); this.shapes = []; let index = 0; for (let x = 0; x < this.numberOfShape; x++) { for (let y = 0; y < this.numberOfShape; y++) { const params = { x: x, y: y, i: index++, c: this.ctx, s: this.size, r: this.radius, n: this.numberOfShape, p: this.paths[Math.floor(Math.random() * (this.paths.length - 1))] }; const s = new Shape(params); this.shapes.push(s); } } } drawFocus(s, hover) { if (hover === false) { this.focus.s += (0 - this.focus.s) * 0.16; this.focus.x += (this.touchInfos.mouse.x - this.focus.x) * 0.16; this.focus.y += (this.touchInfos.mouse.y - this.focus.y) * 0.16; this.ctx.save(); this.ctx.strokeStyle = '#FE296D'; this.ctx.lineWidth = 1; this.ctx.strokeRect(this.focus.x - this.focus.s / 2, this.focus.y - this.focus.s / 2, this.focus.s, this.focus.s); this.ctx.restore(); } else { this.focus.s += (this.size * s.ratio - this.focus.s) * 0.16; this.focus.x += (s.x - this.focus.x) * 0.16; this.focus.y += (s.y - this.focus.y) * 0.16; this.ctx.save(); this.ctx.strokeStyle = '#FE296D'; //this.ctx.globalCompositeOperation = 'lighter'; this.ctx.lineWidth = 5 * s.ratio; this.ctx.strokeRect(this.focus.x - this.focus.s / 2, this.focus.y - this.focus.s / 2, this.focus.s, this.focus.s); this.ctx.restore(); }; } isHovered(shape, x, y) { if ( shape.displayed === true && x > shape.x - this.size / 2 * shape.ratio && x < shape.x + this.size / 2 * shape.ratio && y > shape.y - this.size / 2 * shape.ratio && y < shape.y + this.size / 2 * shape.ratio) { return true; } } resetParams() { this.hover = false; document.body.style.cursor = 'initial'; } render(t) { this.resetParams(); this.ctx.clearRect(0, 0, this.width, this.height); this.ctx.save(); this.ctx.translate(this.width / 2, this.height / 2); let hoveredIndex; for (let i = 0; i < this.shapes.length; i++) { const s = this.shapes[i]; this.shapes[i].draw(this.touchInfos); if (this.isHovered(s, this.touchInfos.mouse.x, this.touchInfos.mouse.y)) { document.body.style.cursor = 'zoom-in'; this.hover = true; hoveredIndex = i; } } this.drawFocus(this.shapes[hoveredIndex], this.hover); if (Math.random() < 0.01) { this.G.draw(t); } if (this.isDisplayed && this.isDeleating !== true) { this.ctx.globalAlpha = 0.8; this.ctx.fillRect(-this.width / 2, -this.height / 2, this.width, this.height); this.M.addImage(t); } if (this.isDeleating) { this.M.deleteImage(t); } this.ctx.restore(); this.animationId = requestAnimationFrame(this.render.bind(this)); }} class Shape { constructor(params) { this.ctx = params.c; this.xIndex = params.x; this.yIndex = params.y; this.index = params.i; this.radius = params.r; this.numberOfShape = params.n; this.size = params.s; this.image = new Image(); this.image.crossOrigin = "anonymous"; this.image.src = params.p; this.ratio = 0; this.displayed = true; this.initialize(); } initialize() { this.xRadian = Math.PI * 2 / this.numberOfShape * this.xIndex; this.yRadian = Math.PI * 2 / this.numberOfShape * this.yIndex; } updateParams(infos) { this.x = Math.sin(this.xRadian + infos.delta.x) * this.radius; this.y = Math.cos(this.yRadian + infos.delta.y) * this.radius; this.ratio = this.getNormalizedDist(infos); } getNormalizedDist(infos) { let tmp; tmp = Math.sqrt(this.x * this.x + this.y * this.y) / this.radius; tmp = this.ease(tmp); tmp = 1 - Math.min(tmp, 1); return tmp; } ease(t) { return t * t * t; } draw(infos) { this.updateParams(infos); if (Math.sin(this.yRadian + infos.delta.y) > 0 || Math.cos(this.xRadian + infos.delta.x) > 0) { this.displayed = false; return; } this.displayed = true; this.ctx.save(); this.ctx.translate(this.x, this.y); this.ctx.scale(this.ratio, this.ratio); this.ctx.translate(-this.x, -this.y); this.ctx.globalAlpha = this.ratio; this.ctx.drawImage( this.image, this.image.width / 2 - this.size / 2, this.image.height / 2 - this.size / 2, this.size, this.size, this.x - this.size / 2, this.y - this.size / 2, this.size, this.size); this.ctx.restore(); }} class Glitch { constructor(ctx, width, height, min, max) { this.ctx = ctx; this.width = width; this.height = height; this.min = min; this.max = max; this.dataArr = []; } getImageData() { let preHeight = 0,addHeight = 0; for (let i = 0; i < this.height; i += addHeight) { const obj = {}; addHeight = Utilities.randomInt(this.min, this.max); if (preHeight + addHeight > this.height) { addHeight = Math.floor(this.height - preHeight); } if (addHeight === 0) { return; } const image = this.ctx.getImageData(0, preHeight, this.width, preHeight + addHeight); obj.image = image; obj.height = preHeight; this.dataArr.push(obj); preHeight += addHeight; } } addImage(t) { for (let i = 0; i < this.dataArr.length; i++) { if (Math.random() > 0.01) { this.ctx.putImageData( this.dataArr[i].image, Math.tan(this.dataArr[i].height * 0.1 + t) * 10 * Math.random(), this.dataArr[i].height); } else { this.ctx.putImageData( this.dataArr[Math.floor(this.dataArr.length * Math.random())].image, this.width * Math.random() - this.width / 2, this.dataArr[i].height); } } } draw(t) { this.dataArr = []; this.getImageData(); this.addImage(t); }} class Stopwatch { constructor() { this.initialize(); } initialize() { const time = Date.now(); this.startTime = time; this.lastTime = time; } calculateTime() { const time = Date.now(); this.elapsedTime = time - this.startTime; this.lastTime = time; } getElapsedTime() { return this.elapsedTime; }} window.addEventListener('load', () => { const F = new FullScreen(); const L = new Loading(); L.initialize(). then(() => { const S = new Sketch(); }); }); Навигация по записям Todo subitem Price slider