i saw this magnifying glass effect a while ago here on codepen and thought i'd do my own version with zoom. Sadly i can't find the original pen to credit it π
Created
November 13, 2019 06:26
-
-
Save CodeMyUI/e9b47ac289f24e8cf95aeb0546496cea to your computer and use it in GitHub Desktop.
magnifying image view with zoom π +touch support
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="image"> | |
<a href="" target="_blank"> | |
<img src="" alt=""> | |
</a> | |
</div> | |
<div class="zoom"> | |
<img class="zoom-image" src="" alt=""> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// use your mousewheel to zoom in π | |
console.clear(); | |
const image = document.querySelectorAll('.image')[0]; | |
const zoom = document.querySelectorAll('.zoom')[0]; | |
const zoomImage = document.querySelectorAll('.zoom-image')[0]; | |
let clearSrc; | |
let zoomLevel = 1; | |
const images = [ | |
{ | |
thumb: 'https://images.unsplash.com/photo-1480796927426-f609979314bd?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60', | |
hires: 'https://images.unsplash.com/photo-1480796927426-f609979314bd?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2560&q=80' | |
}, { | |
thumb: 'https://images.unsplash.com/photo-1503899036084-c55cdd92da26?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60', | |
hires: 'https://images.unsplash.com/photo-1503899036084-c55cdd92da26?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2560&q=80' | |
}, { | |
thumb: 'https://images.unsplash.com/photo-1490761668535-35497054764d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60', | |
hires: 'https://images.unsplash.com/photo-1490761668535-35497054764d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2560&q=80' | |
}, { | |
thumb: 'https://images.unsplash.com/photo-1565175508370-0fff04b6bb5a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60', | |
hires: 'https://images.unsplash.com/photo-1565175508370-0fff04b6bb5a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2560&q=80' | |
}, { | |
thumb: 'https://images.unsplash.com/photo-1522547902298-51566e4fb383?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60', | |
hires: 'https://images.unsplash.com/photo-1522547902298-51566e4fb383?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2560&q=80' | |
}, | |
] | |
// set to random image | |
let img = images[Math.floor(Math.random() * images.length)]; | |
image.getElementsByTagName('a')[0].setAttribute('href', img.hires); | |
image.getElementsByTagName('img')[0].setAttribute('src', img.thumb); | |
const preloadImage = url => { | |
let img = new Image(); | |
img.src = url; | |
} | |
preloadImage(img.hires); | |
const enterImage = function(e) { | |
zoom.classList.add('show', 'loading'); | |
clearTimeout(clearSrc); | |
let posX, posY, touch = false; | |
if (e.touches) { | |
posX = e.touches[0].clientX; | |
posY = e.touches[0].clientY; | |
touch = true; | |
} else { | |
posX = e.clientX; | |
posY = e.clientY; | |
} | |
touch | |
? zoom.style.top = `${posY - zoom.offsetHeight / 1.25}px` | |
: zoom.style.top = `${posY - zoom.offsetHeight / 2}px`; | |
zoom.style.left = `${posX - zoom.offsetWidth / 2}px`; | |
let originalImage = this.getElementsByTagName('a')[0].getAttribute('href'); | |
zoomImage.setAttribute('src', originalImage); | |
// remove the loading class | |
zoomImage.onload = function() { | |
console.log('hires image loaded!'); | |
setTimeout(() => { | |
zoom.classList.remove('loading'); | |
}, 500); | |
} | |
} | |
const leaveImage = function() { | |
// remove scaling to prevent non-transition | |
zoom.style.transform = null; | |
zoomLevel = 1; | |
zoom.classList.remove('show'); | |
clearSrc = setTimeout(() => { | |
zoomImage.setAttribute('src', ''); | |
}, 250); | |
} | |
const move = function(e) { | |
e.preventDefault(); | |
let posX, posY, touch = false; | |
if (e.touches) { | |
posX = e.touches[0].clientX; | |
posY = e.touches[0].clientY; | |
touch = true; | |
} else { | |
posX = e.clientX; | |
posY = e.clientY; | |
} | |
// move the zoom a little bit up on mobile (because of your fat fingers :<) | |
touch | |
? zoom.style.top = `${posY - zoom.offsetHeight / 1.25}px` | |
: zoom.style.top = `${posY - zoom.offsetHeight / 2}px`; | |
zoom.style.left = `${posX - zoom.offsetWidth / 2}px`; | |
let percX = (posX - this.offsetLeft) / this.offsetWidth, | |
percY = (posY - this.offsetTop) / this.offsetHeight; | |
let zoomLeft = -percX * zoomImage.offsetWidth + (zoom.offsetWidth / 2), | |
zoomTop = -percY * zoomImage.offsetHeight + (zoom.offsetHeight / 2); | |
zoomImage.style.left = `${zoomLeft}px`; | |
zoomImage.style.top = `${zoomTop}px`; | |
} | |
image.addEventListener('mouseover', enterImage); | |
image.addEventListener('touchstart', enterImage); | |
image.addEventListener('mouseout', leaveImage); | |
image.addEventListener('touchend', leaveImage); | |
image.addEventListener('mousemove', move); | |
image.addEventListener('touchmove', move); | |
image.addEventListener('wheel', e => { | |
e.preventDefault(); | |
e.deltaY > 0 ? zoomLevel-- : zoomLevel++; | |
if (zoomLevel < 1) zoomLevel = 1; | |
if (zoomLevel > 5) zoomLevel = 5; | |
console.log(`zoom level: ${zoomLevel}`); | |
zoom.style.transform = `scale(${zoomLevel})`; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
} | |
html { | |
width: 100%; | |
height: 100%; | |
font-size: 18px; | |
} | |
body { | |
width: 100%; | |
min-height: 100%; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
overflow: hidden; | |
} | |
.image { | |
max-width: 100%; | |
cursor: none; | |
a { | |
cursor: none; | |
} | |
img { | |
max-width: 100%; | |
vertical-align: middle; | |
z-index: 1; | |
} | |
} | |
.zoom { | |
width: 14rem; | |
height: 14rem; | |
background: #fff; | |
border-radius: 50%; | |
position: absolute; | |
// box-shadow: inset 0 0 0 1px #000; | |
pointer-events: none; | |
transition: transform .25s ease, opacity 0s linear .25s, background .25s ease; | |
opacity: 0; | |
transform: scale(0); | |
transform-origin: 50% 50%; | |
overflow: hidden; | |
&:before { | |
content: ''; | |
position: absolute; | |
margin: auto; | |
left: 0; | |
top: 0; | |
right: 0; | |
bottom: 0; | |
width: 100%; | |
height: 100%; | |
border-radius: 50%; | |
display: none; | |
} | |
&.show { | |
transform: scale(1); | |
opacity: 1; | |
transition: transform .25s ease, opacity 0s linear; | |
} | |
&.loading { | |
background: transparent; | |
&:before { | |
display: block; | |
animation: loading .5s ease infinite alternate; | |
} | |
@keyframes loading { | |
0% { | |
transform: scale(0.1); | |
box-shadow: inset 0 0 0 150px gold; | |
} | |
50% { | |
transform: scale(1); | |
box-shadow: inset 0 0 0 140px golf; | |
} | |
100% { | |
box-shadow: inset 0 0 0 0 gold; | |
} | |
} | |
.zoom-image { | |
opacity: 0; | |
} | |
} | |
.zoom-image { | |
position: absolute; | |
left: 0; | |
top: 0; | |
transition: opacity .25s ease; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment