Reputation: 1
I'm trying to make a zoomable image
on a modal and I'm using wheelzoom.js
It's almost perfect, but I need to resize the image Height
that is auto, by default, when the orientation of the img is Horizontal
. And resize the width when its vertical!
Also, the zoom must work with pinch move.
Here's my project on a freehost
My demo.html:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Wheelzoom</title>
<style>
body {
margin: 0;
padding: 0;
}
.containerzoom {
border: 1px dashed;
/* Borda visual para identificar o contêiner */
height: 98dvh;
/* Usando unidade 'dvh' para melhor responsividade em dispositivos móveis */
max-width: 100vw;
/* Garante que o contêiner não ultrapasse a largura da viewport */
display: flex;
justify-content: center;
/* Centraliza a imagem horizontalmente */
align-items: center;
/* Centraliza a imagem verticalmente */
position: relative;
/* Necessário para posicionar elementos dentro */
overflow: hidden;
/* Garante que o conteúdo que ultrapassa seja cortado */
top: 10px;
/* Desloca o contêiner para baixo */
}
.containerzoom img {
border: 2px solid;
/* Borda para a imagem se necessário */
max-width: 100%;
/* Limita a largura máxima da imagem */
max-height: 100%;
/* Limita a altura máxima da imagem */
width: auto;
/* Mantém a proporção correta */
height: auto;
/* Mantém a proporção correta */
object-fit: contain;
/* Ajusta a imagem dentro da div, mantendo a proporção */
transition: transform 0.3s ease;
/* Indica que a imagem pode ser ampliada */
}
/* .containerzoom img:active {
cursor: move;
} */
.zoom-button {
position: absolute;
top: 40px;
background: rgba(255, 255, 255, 0.7);
border: 1px solid #ccc;
border-radius: 5px;
padding: 10px;
cursor: pointer;
font-size: 16px;
margin-left: auto;
}
.zoom-in {
left: 10px;
}
.zoom-out {
left: 90px;
}
</style>
</head>
<body>
<div class="containerzoom">
<img class='zoom zoomedimage'
src='https://img.freepik.com/free-photo/panoramic-shot-erg-chebbi-dunes-sahara-desert-merzouga-morocco_181624-16129.jpg?t=st=1727474703~exp=1727478303~hmac=e729edeeaed62fafb9627aa20e68dd4d79a4fdc2c7daeda09c619101c99e9e63&w=1380'
alt='Daisy!' />
<!-- <img class='zoom zoomedimage' src='http://localhost/apis/gallery-box/img/image%20(112).jpeg' alt='Daisy!' /> -->
</div>
<button class="zoom-button zoom-in">Zoom In</button>
<button class="zoom-button zoom-out">Zoom Out</button>
<script src="wheelzoom.js"></script>
<script>
const img = document.querySelector('img.zoom');
wheelzoom(img);
const zoomInButton = document.querySelector('.zoom-in');
const zoomOutButton = document.querySelector('.zoom-out');
// Função para atualizar os estilos dos botões
function updateZoomButtons() {
const currentBgSize = img.style.backgroundSize.split(' ')[0] || '100%'; // Pega a largura atual ou padrão
const width = parseFloat(currentBgSize); // Converte para número
// Tamanho padrão
const defaultSize = img.clientWidth;
// Atualiza a opacidade e o cursor do botão de zoom out
if (width <= defaultSize) {
zoomOutButton.style.opacity = 0.5;
zoomOutButton.style.cursor = 'default';
zoomOutButton.disabled = true; // Desabilita o botão
} else {
zoomOutButton.style.opacity = 1;
zoomOutButton.style.cursor = 'pointer';
zoomOutButton.disabled = false; // Habilita o botão
}
// Usa o valor de width atual para verificar se o zoom máximo foi atingido
if (width >= defaultSize * 2.4) { // Defina o fator de zoom máximo desejado
console.log(`Desabilitando o botão Zoom In: width = ${width}, defaultSize = ${defaultSize}`);
zoomInButton.style.opacity = 0.5;
zoomInButton.style.cursor = 'default'; // Cursor padrão
zoomInButton.disabled = true; // Desabilita o botão
} else {
zoomInButton.style.opacity = 1;
zoomInButton.style.cursor = 'pointer'; // Cursor pointer
zoomInButton.disabled = false; // Habilita o botão
}
// Log do tamanho atual da imagem
console.log(`Tamanho atual da imagem: ${width}px`);
}
zoomInButton.addEventListener('click', () => {
const event = new WheelEvent('wheel', { deltaY: -50, bubbles: true, cancelable: true });
img.dispatchEvent(event);
updateZoomButtons();
});
zoomOutButton.addEventListener('click', () => {
const currentBgSize = img.style.backgroundSize.split(' ')[0] || '100%';
const width = parseFloat(currentBgSize);
if (width > img.clientWidth) {
const event = new WheelEvent('wheel', { deltaY: 50, bubbles: true, cancelable: true });
img.dispatchEvent(event);
updateZoomButtons();
}
});
updateZoomButtons(); // Chama inicialmente para configurar os botões
</script>
</body>
</html>
And my Wheelzoom.js:
window.wheelzoom = (function () {
var defaults = {
zoom: 0.20,
maxZoom: 5,
initialZoom: 1,
initialX: 0.5,
initialY: 0.5,
};
var main = function (img, options) {
if (!img || !img.nodeName || img.nodeName !== 'IMG') { return; }
var settings = {};
var width;
var height;
var bgWidth;
var bgHeight;
var bgPosX;
var bgPosY;
var previousEvent;
var transparentSpaceFiller;
function setSrcToBackground(img) {
img.style.backgroundRepeat = 'no-repeat';
img.style.backgroundImage = 'url("' + img.src + '")';
transparentSpaceFiller = 'data:image/svg+xml;base64,' + window.btoa('<svg xmlns="http://www.w3.org/2000/svg" width="' + img.naturalWidth + '" height="' + img.naturalHeight + '"></svg>');
img.src = transparentSpaceFiller;
}
function updateBgStyle() {
if (bgPosX > 0) {
bgPosX = 0;
} else if (bgPosX < width - bgWidth) {
bgPosX = width - bgWidth;
}
if (bgPosY > 0) {
bgPosY = 0;
} else if (bgPosY < height - bgHeight) {
bgPosY = height - bgHeight;
}
img.style.backgroundSize = bgWidth + 'px ' + bgHeight + 'px';
img.style.backgroundPosition = bgPosX + 'px ' + bgPosY + 'px';
}
function reset() {
bgWidth = width;
bgHeight = height;
bgPosX = bgPosY = 0;
updateBgStyle();
}
function onwheel(e) {
var deltaY = e.deltaY ? e.deltaY : -e.wheelDelta;
e.preventDefault();
var rect = img.getBoundingClientRect();
var offsetX = e.pageX - rect.left - window.pageXOffset;
var offsetY = e.pageY - rect.top - window.pageYOffset;
var bgCursorX = offsetX - bgPosX;
var bgCursorY = offsetY - bgPosY;
var bgRatioX = bgCursorX / bgWidth;
var bgRatioY = bgCursorY / bgHeight;
if (deltaY < 0) {
bgWidth += bgWidth * settings.zoom;
bgHeight += bgHeight * settings.zoom;
img.style.cursor = 'move';
} else {
bgWidth -= bgWidth * settings.zoom;
bgHeight -= bgHeight * settings.zoom;
img.style.cursor = 'default';
}
if (settings.maxZoom) {
bgWidth = Math.min(width * settings.maxZoom, bgWidth);
bgHeight = Math.min(height * settings.maxZoom, bgHeight);
}
bgPosX = offsetX - (bgWidth * bgRatioX);
bgPosY = offsetY - (bgHeight * bgRatioY);
if (bgWidth <= width || bgHeight <= height) {
reset();
} else {
updateBgStyle();
}
}
function drag(e) {
e.preventDefault();
bgPosX += (e.pageX - previousEvent.pageX);
bgPosY += (e.pageY - previousEvent.pageY);
previousEvent = e;
updateBgStyle();
}
function removeDrag() {
document.removeEventListener('mouseup', removeDrag);
document.removeEventListener('mousemove', drag);
}
function draggable(e) {
e.preventDefault();
previousEvent = e;
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', removeDrag);
}
function load() {
var initial = Math.max(settings.initialZoom, 1);
if (img.src === transparentSpaceFiller) return;
var computedStyle = window.getComputedStyle(img, null);
width = parseInt(computedStyle.width, 10);
height = parseInt(computedStyle.height, 10);
bgWidth = width * initial;
bgHeight = height * initial;
bgPosX = -(bgWidth - width) * settings.initialX;
bgPosY = -(bgHeight - height) * settings.initialY;
setSrcToBackground(img);
img.style.backgroundSize = bgWidth + 'px ' + bgHeight + 'px';
img.style.backgroundPosition = bgPosX + 'px ' + bgPosY + 'px';
img.addEventListener('wheelzoom.reset', reset);
img.addEventListener('wheel', onwheel, { passive: false });
img.addEventListener('mousedown', draggable);
}
function touchStart(e) {
e.preventDefault();
previousEvent = e.touches[0];
document.addEventListener('touchmove', touchMove);
document.addEventListener('touchend', touchEnd);
}
function touchMove(e) {
e.preventDefault();
bgPosX += (e.touches[0].pageX - previousEvent.pageX);
bgPosY += (e.touches[0].pageY - previousEvent.pageY);
previousEvent = e.touches[0];
updateBgStyle();
}
function touchEnd() {
document.removeEventListener('touchmove', touchMove);
document.removeEventListener('touchend', touchEnd);
}
var destroy = function (originalProperties) {
img.removeEventListener('wheelzoom.destroy', destroy);
img.removeEventListener('wheelzoom.reset', reset);
img.removeEventListener('load', load);
img.removeEventListener('mouseup', removeDrag);
img.removeEventListener('mousemove', drag);
img.removeEventListener('mousedown', draggable);
img.removeEventListener('wheel', onwheel);
img.removeEventListener('touchstart', touchStart);
img.removeEventListener('touchmove', touchMove);
img.removeEventListener('touchend', touchEnd);
img.style.backgroundImage = originalProperties.backgroundImage;
img.style.backgroundRepeat = originalProperties.backgroundRepeat;
img.src = originalProperties.src;
}.bind(null, {
backgroundImage: img.style.backgroundImage,
backgroundRepeat: img.style.backgroundRepeat,
src: img.src
});
img.addEventListener('wheelzoom.destroy', destroy);
options = options || {};
Object.keys(defaults).forEach(function (key) {
settings[key] = options[key] !== undefined ? options[key] : defaults[key];
});
if (img.complete) {
load();
}
img.addEventListener('load', load);
img.addEventListener('touchstart', touchStart, { passive: false });
};
if (typeof window.btoa !== 'function') {
return function (elements) {
return elements;
};
} else {
return function (elements, options) {
if (elements && elements.length) {
Array.prototype.forEach.call(elements, function (node) {
main(node, options);
});
} else if (elements && elements.nodeName) {
main(elements, options);
}
return elements;
};
}
}());
Upvotes: 0
Views: 50