Skip to content

Commit

Permalink
Init project.
Browse files Browse the repository at this point in the history
  • Loading branch information
tomzidani committed Apr 22, 2024
0 parents commit 4a114c6
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 0 deletions.
Binary file added img.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Fractal Glass Effect</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<div data-component="fractal-glass" class="media">
<div data-element="glass"></div>

<img src="img.png" class="img" data-element="image" />
</div>
</div>

<script src="script.js" async></script>
</body>
</html>
138 changes: 138 additions & 0 deletions script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
document.addEventListener('DOMContentLoaded', () => {
const fractalGlassComponent = document.querySelectorAll('[data-component="fractal-glass"]')
fractalGlassComponent.forEach((c) => new FractalGlass(c))
})

class FractalGlass {
el
imageEl
glassEl

imageWidth
imageHeight
imageSourceWidth
imageSourceHeight

canvas
ctx

columnsNumber = 30
columnsWidth

distortion = 3

resizeTick = null

constructor(el) {
this.el = el
this.imageEl = el.querySelector('[data-element="image"]')
this.glassEl = el.querySelector('[data-element="glass"]')

this.init()
}

init() {
this.initCanvas()
this.getImageDimensions()
this.getColumnsWidth()
this.initColumns()
this.bindEvents()
}

initCanvas() {
this.canvas = document.createElement('canvas')
this.ctx = this.canvas.getContext('2d')
}

getImageDimensions() {
this.imageWidth = this.imageEl.width
this.imageHeight = this.imageEl.height
this.imageSourceWidth = this.imageEl.naturalWidth
this.imageSourceHeight = this.imageEl.naturalHeight
}

getColumnsWidth() {
this.columnsWidth = 100 / this.columnsNumber
}

initColumns() {
const columns = []

for (let i = 0; i < this.columnsNumber; i++) {
const c = document.createElement('div')

this.setColumnProperties(c, i)

this.glassEl.appendChild(c)
columns.push(c)
}

this.columns = columns
}

setColumnProperties(c, i) {
const startXPercent = this.columnsWidth * i
const endXPercent = this.columnsWidth + startXPercent

const imagePortion = this.getImagePortion(startXPercent, endXPercent)

c.style.backgroundImage = `url('${imagePortion}')`
c.style.width = `${this.canvas.width / this.distortion}px`
c.style.height = `${this.canvas.height}px`
c.style.left = `${(this.canvas.width / this.distortion) * i}px`
}

getImagePortion(startXPercent, endXPercent) {
let startX = this.imageWidth * (startXPercent / 100)
let startSourceX = this.imageSourceWidth * (startXPercent / 100)

const endX = this.imageWidth * (endXPercent / 100)
const endSourceX = this.imageSourceWidth * (endXPercent / 100)

const portionWidth = (endX - startX) * this.distortion
const portionSourceWidth = (endSourceX - startSourceX) * this.distortion

const isPortionWidthGreaterThanImageWidth = startX + portionWidth > this.imageWidth
const isPortionSourceWidthGreaterThanImageSourceWidth = startSourceX + portionSourceWidth > this.imageSourceWidth

if (isPortionWidthGreaterThanImageWidth) startX = this.imageWidth - portionWidth
if (isPortionSourceWidthGreaterThanImageSourceWidth) startSourceX = this.imageSourceWidth - portionSourceWidth

this.canvas.width = portionWidth
this.canvas.height = this.imageHeight

this.ctx.drawImage(this.imageEl, startSourceX, 0, portionSourceWidth / 2, this.imageSourceHeight, portionWidth / 2, 0, portionWidth / 2, this.imageHeight)
this.ctx.scale(-1, 1)
this.ctx.drawImage(this.imageEl, startSourceX, 0, portionSourceWidth / 2, this.imageSourceHeight, -(portionWidth / 2), 0, portionWidth / 2, this.imageHeight)
this.ctx.setTransform(1, 0, 0, 1, 0, 0)

return this.canvas.toDataURL()
}

handleResize() {
this.getImageDimensions()

this.columns.forEach((c, i) => {
this.setColumnProperties(c, i)
})
}

debounce(func, delay) {
let timeout

return () => {
clearTimeout(timeout)

timeout = setTimeout(() => {
func.apply(this, arguments)
}, delay)
}
}

bindEvents() {
this.handleResize = this.handleResize.bind(this)
this.resizeTick = this.debounce(this.handleResize, 200)

window.addEventListener('resize', this.resizeTick)
}
}
66 changes: 66 additions & 0 deletions style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
* {
box-sizing: border-box;
}

body {
padding: 0;
margin: 0;
}

img {
max-width: 100%;
height: auto;

opacity: 0;
}

.container {
display: grid;
position: relative;
max-height: 80vh;

place-content: center;

overflow: hidden;
}

[data-component='fractal-glass'] {
display: inline-block;
position: relative;

overflow: hidden;
}

[data-element='glass'] {
position: absolute;
inset: 0;
width: 100%;
height: 100%;

z-index: 2;
}

[data-element='glass'] > div {
position: absolute;
top: 0;
bottom: 0;
height: 100%;
max-height: 100%;

background-size: 100% 100%;
background-repeat: round;

opacity: 1;
backdrop-filter: blur(1px);
}

[data-element='glass'] > div::before {
position: absolute;
content: '';
inset: 0;
width: 100%;
height: 100%;

background: linear-gradient(90deg, rgba(0, 0, 0, 0.1) 10%, rgba(4, 9, 20, 0) 70%, rgba(0, 0, 0, 0.1) 110%);
backdrop-filter: blur();
}

0 comments on commit 4a114c6

Please sign in to comment.