2017-10-09 12 views
5

Cette question est similaire à celui-ci: Zoom in on a point (using scale and translate) ou même celui-ci: Image zoom centered on mouse position mais je ne veux pas le faire sur une toile, mais une image normale (ou plutôt le conteneur div de l'image). Donc, le zoom devrait être aussi google maps. Je suis en fait Hacking/amélioration de zoom iDangerous Chipeur (http://idangero.us/swiper/), et qui est mon point de départ, ce qui est ce que je suis arrivé à ce jour: https://jsfiddle.net/xta2ccdt/3/Zoom sur un point de mousewheel (en utilisant l'échelle et de traduire)

Zoom uniquement avec la molette de la souris. La première fois que vous zoomez, il zoome parfaitement, mais je n'arrive pas à comprendre comment calculer chaque zoom après le premier.

Voici mon code: JS:

$(document).ready(function(){ 
    $("#slideContainer").on("mousewheel DOMMouseScroll", function (e) { 
    e.preventDefault(); 
    var delta = e.delta || e.originalEvent.wheelDelta; 
    var zoomOut; 
    if (delta === undefined) { 
     //we are on firefox 
     delta = e.originalEvent.detail; 
     zoomOut = delta ? delta < 0 : e.originalEvent.deltaY > 0; 
     zoomOut = !zoomOut; 
    } else { 
     zoomOut = delta ? delta < 0 : e.originalEvent.deltaY > 0; 
    } 
    var touchX = e.type === 'touchend' ? e.changedTouches[0].pageX : e.pageX; 
    var touchY = e.type === 'touchend' ? e.changedTouches[0].pageY : e.pageY; 
    var scale = 1, translateX, translateY; 
    if(zoomOut){ 
     //we are zooming out 
     //not interested in this yet 
    }else{ 
     //we are zooming in 
     scale = scale + 0.5; 
     var dimensionMultiplier = scale - 0.5;//when image is scaled up offsetWidth/offsetHeight doesn't take this into account so we must multiply by scale to get the correct width/height 
     var slideWidth = $("#slide")[0].offsetWidth * dimensionMultiplier; 
     var slideHeight = $("#slide")[0].offsetHeight * dimensionMultiplier; 

     var offsetX = $("#slide").offset().left;//distance from the left of the viewport to the slide 
     var offsetY = $("#slide").offset().top;//distance from the top of the viewport to the slide 
     var diffX = offsetX + slideWidth/2 - touchX;//this is distance from the mouse to the center of the image 
     var diffY = offsetY + slideHeight/2 - touchY;//this is distance from the mouse to the center of the image 

     //how much to translate by x and y so that poin on image is alway under the mouse 
     //we must multiply by 0.5 because the difference between previous and current scale is always 0.5 
     translateX = ((diffX) * (0.5)); 
     translateY = ((diffY) * (0.5));  
    } 
    $("#slide").css("transform", 'translate3d(' + translateX + 'px, ' + translateY + 'px,0) scale(' + scale + ')').css('transition-duration', '300ms'); 
    }); 


}); 

HTML:

<div id="slideContainer"> 
    <div id="slide"> 
    <img src="http://content.worldcarfans.co/2008/6/medium/9080606.002.1M.jpg"></img> 
    </div> 
</div> 

CSS:

#slideContainer{ 
    width:500px; 
    height:500px; 
    overflow:hidden; 
} 
#slide{ 
    width:100%; 
    height:100%; 
} 
img{ 
    width:auto; 
    height:auto; 
    max-width:100%; 
} 

Je me suis aussi si je soustrais translateX précédente et les valeurs translateY de la ceux en cours, je peux zoomer sur le même point autant que je veux et il va zoomer p mais si j'effectue un zoom sur un point, puis change la position de la souris et effectue un zoom avant, il ne sera plus zoomer comme il est censé le faire. Exemple: https://jsfiddle.net/xta2ccdt/4/

Si je change la position de la souris et que je calcule la différence X et Y entre l'ancienne et la nouvelle position de la souris et que j'ajoute cela dans le calcul de la différence, elle effectuera un zoom correct la deuxième fois. Mais la troisième fois, on dirait que cette différence est encore soustraite du calcul total et cela amènera le traducteur à déplacer l'image de nouveau, après quoi si nous maintenons la souris dans la même position, elle effectuera un zoom correct à nouveau. Alors j'ai pensé que je vais juste ajouter la différence entre l'ancienne et la nouvelle position de la souris chaque fois que je calcule le nouveau "diff", et ce genre de travail, il n'y a plus de saut comme si , mais il ne fait toujours pas de zoom sur la même position, avec chaque nouveau zoom il déplace (décale) l'image d'une petite quantité. Je pense que c'est parce qu'il y a une nouvelle valeur de zoom à chaque fois, mais le décalage n'est pas linéaire, il est de plus en plus petit, et je n'arrive pas à comprendre comment compenser le décalage. Voici le nouvel exemple: https://jsfiddle.net/xta2ccdt/5/ Nouvelle image dans l'exemple: ancien est plus disponible: https://jsfiddle.net/xta2ccdt/14/

+0

non apparentés mais doesn Pas de tag de fin. Il devrait se fermer automatiquement J'ai aussi dû utiliser quelque chose comme un espace réservé b/c l'autre image a été bloquée. Je ne pouvais pas faire un zoom arrière pour une raison quelconque. –

+0

J'ai trouvé cette prise qui semble faire ce que vous voulez: http://www.jqueryscript.net/demo/jQuery-Plugin-for-Image-Zoom-In-Out-With-Mousewheel-imgViewer/ – Isma

+0

btw. J'ai fini par abandonner ceci et ai utilisé le panzoom à la place: https://github.com/timmywil/jquery.panzoom –

Répondre

1

Vous étiez près de lui, mais il est préférable de stocker x, y et échelle séparément et calculer les transformées en fonction de ces valeurs. Cela rend les choses beaucoup de ressources permet d'économiser plus facile + (pas besoin de rechercher les propriétés dom à plusieurs reprises),

J'ai mis le code dans un module agréable:

function ScrollZoom(container,max_scale,factor){ 
    var target = container.children().first() 
    var size = {w:target.width(),h:target.height()} 
    var pos = {x:0,y:0} 
    var zoom_target = {x:0,y:0} 
    var zoom_point = {x:0,y:0} 
    var scale = 1 
    target.css('transform-origin','0 0') 
    target.on("mousewheel DOMMouseScroll",scrolled) 

    function scrolled(e){ 
     var offset = container.offset() 
     zoom_point.x = e.pageX - offset.left 
     zoom_point.y = e.pageY - offset.top 

     e.preventDefault(); 
     var delta = e.delta || e.originalEvent.wheelDelta; 
     if (delta === undefined) { 
      //we are on firefox 
      delta = e.originalEvent.detail; 
     } 
     delta = Math.max(-1,Math.min(1,delta)) // cap the delta to [-1,1] for cross browser consistency 

     // determine the point on where the slide is zoomed in 
     zoom_target.x = (zoom_point.x - pos.x)/scale 
     zoom_target.y = (zoom_point.y - pos.y)/scale 

     // apply zoom 
     scale += delta*factor * scale 
     scale = Math.max(1,Math.min(max_scale,scale)) 

     // calculate x and y based on zoom 
     pos.x = -zoom_target.x * scale + zoom_point.x 
     pos.y = -zoom_target.y * scale + zoom_point.y 


     // Make sure the slide stays in its container area when zooming out 
     if(pos.x>0) 
      pos.x = 0 
     if(pos.x+size.w*scale<size.w) 
      pos.x = -size.w*(scale-1) 
     if(pos.y>0) 
      pos.y = 0 
     if(pos.y+size.h*scale<size.h) 
      pos.y = -size.h*(scale-1) 

     update() 
    } 

    function update(){ 
     target.css('transform','translate('+(pos.x)+'px,'+(pos.y)+'px) scale('+scale+','+scale+')') 
    } 
} 

utiliser en appelant

new ScrollZoom($('#container'),4,0.5) 

les paramètres sont les suivants:

  1. récipient: l'enveloppe de l'élément à être agrandie. Le script recherchera le premier enfant du conteneur et appliquera les transformations à celui-ci.
  2. max_scale: L'échelle maximale (4 = 400%)
  3. facteur: le zoom rapide (1 = + 100% zoom par tique de la roue de la souris)

JSFiddle here

+0

Cela semble fonctionner. Pourquoi définissez-vous l'origine de la transformation à 0,0. Je voudrais le laisser à 50% .50% car il est par défaut –

+0

la logique est basée sur l'origine de transformation étant à x: 0, y: 0. Mais vous pourriez bien sûr modifier cela. –

1

Je pense que cela va vous obtenir un peu plus près de ce que vous essayez d'atteindre.

clés Changements

  1. J'ai tiré échelle en dehors de la fonction de rappel; Je ne pense pas que vous voulez réinitialiser votre échelle sur chaque événement de roue.
  2. Au lieu de calculer la traduction, essayez manuellement le réglage de la transform-origin être centrée sur votre souris (sauf si vous voulez le garder centré qui est la valeur par défaut)

var scale = 1; 
 

 
$(document).ready(function(){ 
 
    $("#slideContainer").on("mousewheel DOMMouseScroll", function (e) { 
 
    e.preventDefault(); 
 
    var delta = e.delta || e.originalEvent.wheelDelta; 
 
    var zoomOut; 
 
    if (delta === undefined) { 
 
     //we are on firefox 
 
     delta = e.originalEvent.detail; 
 
     zoomOut = delta ? delta < 0 : e.originalEvent.deltaY > 0; 
 
     zoomOut = !zoomOut; 
 
    } else { 
 
     zoomOut = delta ? delta < 0 : e.originalEvent.deltaY > 0; 
 
    } 
 
    var touchX = e.type === 'touchend' ? e.changedTouches[0].pageX : e.pageX; 
 
    var touchY = e.type === 'touchend' ? e.changedTouches[0].pageY : e.pageY; 
 
    var translateX, translateY; 
 
    if(zoomOut){ 
 
     // we are zooming out 
 
     scale = scale - 0.01; 
 
     
 
     var offsetWidth = $("#slide")[0].offsetWidth; 
 
     var offsetHeight = $("#slide")[0].offsetHeight; 
 

 
     $("#slide") 
 
     .css("transform-origin", touchX + 'px ' + touchY + 'px') 
 
     .css("transform", 'scale(' + scale + ')'); 
 
     
 
    }else{ 
 
     // we are zooming in 
 
     scale = scale + 0.01; 
 
     
 
     var offsetWidth = $("#slide")[0].offsetWidth; 
 
     var offsetHeight = $("#slide")[0].offsetHeight; 
 

 
     $("#slide") 
 
     .css("transform-origin", touchX + 'px ' + touchY + 'px') 
 
     .css("transform", 'scale(' + scale + ')'); 
 
    } 
 
    
 
    }); 
 

 

 
});
#slideContainer{ 
 
    width:200px; 
 
    height:200px; 
 
    overflow:hidden; 
 
} 
 
#slide{ 
 
    width:100%; 
 
    height:100%; 
 
} 
 
img{ 
 
    width:auto; 
 
    height:auto; 
 
    max-width:100%; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div id="slideContainer"> 
 
    <div id="slide"> 
 
    <img src="https://via.placeholder.com/200x200"></img> 
 
    </div> 
 
</div>

+0

Le problème que j'ai est toujours là. Si vous effectuez un zoom par ex. quelque part dans le coin supérieur gauche, puis zoom dans le coin en bas à droite, l'image saute. –

0

Le code J'utilise pour zoomer à la position de la souris est ci-dessous.Il n'utilise pas transform/translate3d mais réajuste la position de l'image dans le div et ajuste ses height et width.

var zoom = 1; 
 
var img, div; 
 
window.onload = function() { 
 
    window.addEventListener('DOMMouseScroll', wheel, false) 
 
    img = document.getElementById("img"); 
 
    div = document.getElementById("div"); 
 
} 
 

 
function wheel(event) { 
 
    event.preventDefault(); 
 
    var delta = 0; 
 
    if (!event) /* For IE. */ 
 
    event = window.event; 
 
    if (event.wheelDelta) { /* IE/Opera. */ 
 
    delta = event.wheelDelta/120; 
 
    } else if (event.detail) { /** Mozilla case. */ 
 
    /** In Mozilla, sign of delta is different than in IE. 
 
    * Also, delta is multiple of 3. 
 
    */ 
 
    delta = -event.detail/3; 
 
    } 
 
    /** If delta is nonzero, handle it. 
 
    * Positive Delta = wheel scrolled up, 
 
    * Negative Delte = wheel scrolled down. 
 
    */ 
 
    if (delta) { 
 
    // will pass 1 to zoom in and -1 to zoom out \t  
 
    delta = delta/Math.abs(delta) 
 
    zoomImage(delta == 1, event); 
 
    } 
 
} 
 

 
function zoomImage(zoomIn, e) { 
 
    var oldZoom = zoom; 
 
    var direction = 1 * (zoomIn ? 1 : -1); 
 
    zoom += direction * .2; 
 
    // range = 50% => 600% 
 
    zoom = round(Math.min(6, Math.max(.5, zoom)), 1); 
 
    
 
    if (zoom == 1) { 
 
    // For a zoom = 1, we reset 
 
    resetZoom(div, img); 
 
    return; 
 
    } 
 

 
    // make the position of the mouse the center, 
 
    // or as close as can with keeping maximum image viewable 
 
    // e == div[this.slide] 
 
    // gets the top and left of the div 
 
    var divOffset = getOffset(div); 
 
    var imgStyles = getComputedStyle(img); 
 
    var divStyles = getComputedStyle(div); 
 
    var imgOffset = { 
 
    x: parseInt(imgStyles.left), 
 
    y: parseInt(imgStyles.top) 
 
    }; 
 

 
    // where clicked relative in div 
 
    var yTravel = e.pageY - divOffset.y; 
 
    var xTravel = e.pageX - divOffset.x; 
 

 
    // where clicked 
 
    var xOldImg = -imgOffset.x + xTravel; 
 
    var yOldImg = -imgOffset.y + yTravel; 
 

 
    // the clicked position relative to the image 0,0 
 
    // clicked position will remain at the cursor position while image zoom changes 
 

 
    // calc the same position at the new zoom level 
 
    var ratio = zoom/oldZoom; 
 
    var xNewImg = xOldImg * ratio; 
 
    var yNewImg = yOldImg * ratio; 
 

 
    // calc new top/left 
 
    var xStart = -(xNewImg - xTravel); 
 
    var yStart = -(yNewImg - yTravel); 
 

 
    img.style.height = parseInt(divStyles.height) * (zoom) + "px"; 
 
    img.style.width = parseInt(divStyles.width) * (zoom) + "px"; 
 

 
    img.style.top = yStart + "px"; 
 
    img.style.left = xStart + "px"; 
 
    img.style.cursor = "grab"; 
 
} 
 

 
function resetZoom(div, img) { 
 
    img.style.top = "0px"; 
 
    img.style.left = "0px"; 
 
    img.style.height = div.style.height; 
 
    img.style.width = div.style.width; 
 
    img.style.cursor = "default"; 
 
    zoom = 1; 
 
} 
 

 
function getOffset(element) { 
 
    var rect = element.getBoundingClientRect(); 
 
    var posX = rect.left + window.pageXOffset; // alias for window.scrollX; 
 
    var posY = rect.top + window.pageYOffset; // alias for window.scrollY; \t 
 

 
    return { 
 
    x: posX, 
 
    y: posY, 
 
    left: posX, 
 
    top: posY, 
 
    width: rect.width, 
 
    height: rect.height 
 
    }; 
 
} 
 

 
function round(number, precision) { 
 
    precision = precision ? +precision : 0; 
 

 
    var sNumber = number + '', 
 
    periodIndex = sNumber.indexOf('.'), 
 
    factor = Math.pow(10, precision); 
 

 
    if (periodIndex === -1 || precision < 0) { 
 
    return Math.round(number * factor)/factor; 
 
    } 
 

 
    number = +number; 
 

 
    // sNumber[periodIndex + precision + 1] is the last digit 
 
    if (sNumber[periodIndex + precision + 1] >= 5) { 
 
    // Correcting float error 
 
    // factor * 10 to use one decimal place beyond the precision 
 
    number += (number < 0 ? -1 : 1)/(factor * 10); 
 
    } 
 

 
    return +number.toFixed(precision); 
 
}
#div { 
 
    width: 350px; 
 
    height: 262px; 
 
    border: 1px solid black; 
 
    overflow: hidden; 
 
} 
 

 
#img { 
 
    width: 350px; 
 
    height: 262px; 
 
    position: relative; 
 
}
<div id='div'> 
 
    <img id='img' src="https://www.design.mseifert.com/git-slideshow/img-demo/images01.jpg"> 
 
</div>

+0

Je suis bloqué avec translate parce que j'essayais d'améliorer le zoom du swiper iDangerous, et ils utilisent translate. –

0

Qu'en est-il en utilisant translate3d et perspective, pour gérer les transformations 3D, au lieu d'utiliser scale? De plus, le découplage du zoom de la traduction simplifie les choses.

$(document).ready(function() { 
 

 
    var translateX = 0, 
 
    translateY = 0, 
 
    translateZ = 0, 
 
    stepZ = 10, 
 
    initial_obj_X = 0, 
 
    initial_obj_Y = 0, 
 
    initial_mouse_X = 0, 
 
    initial_mouse_Y = 0; 
 

 
    function apply_coords() { 
 
    $("#slide").css("transform", 'perspective(100px) translate3d(' + translateX + 'px, ' + translateY + 'px, ' + translateZ + 'px)'); 
 
    } 
 

 

 
    $("#slideContainer").on("mousewheel DOMMouseScroll", function(e) { 
 

 
    e.preventDefault(); 
 
    var delta = e.delta || e.originalEvent.wheelDelta; 
 
    var zoomOut; 
 
    if (delta === undefined) { 
 
     delta = e.originalEvent.detail; 
 
     zoomOut = delta ? delta < 0 : e.originalEvent.deltaY > 0; 
 
     zoomOut = !zoomOut; 
 
    } else { 
 
     zoomOut = delta ? delta < 0 : e.originalEvent.deltaY > 0; 
 
    } 
 
    if (zoomOut) { 
 
     translateZ = translateZ - stepZ; 
 
    } else { 
 
     translateZ = translateZ + stepZ; 
 
    } 
 
    apply_coords(); 
 

 
    }); 
 

 

 
    var is_dragging = false; 
 
    $("#slideContainer") 
 
    .mousedown(function(e) { 
 
     is_dragging = true; 
 
    }) 
 
    .mousemove(function(e) { 
 
     if (is_dragging) { 
 
     e.preventDefault(); 
 
     var currentX = e.type === 'touchend' ? e.changedTouches[0].pageX : e.pageX; 
 
     var currentY = e.type === 'touchend' ? e.changedTouches[0].pageY : e.pageY; 
 
     translateX = initial_obj_X + (currentX - initial_mouse_X); 
 
     translateY = initial_obj_Y + (currentY - initial_mouse_Y); 
 
     apply_coords(); 
 
     } else { 
 
     initial_mouse_X = e.type === 'touchend' ? e.changedTouches[0].pageX : e.pageX; 
 
     initial_mouse_Y = e.type === 'touchend' ? e.changedTouches[0].pageY : e.pageY; 
 
     initial_obj_X = translateX; 
 
     initial_obj_Y = translateY; 
 
     } 
 
    }) 
 
    .mouseup(function() { 
 
     is_dragging = false; 
 
    }); 
 

 

 
});
#slideContainer { 
 
    width: 200px; 
 
    height: 200px; 
 
    overflow: hidden; 
 
    position: relative; 
 
} 
 

 
#slide { 
 
    width: 100%; 
 
    height: 100%; 
 
    background: red; 
 
} 
 

 
img { 
 
    width: auto; 
 
    height: auto; 
 
    max-width: 100%; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div id="slideContainer"> 
 
    <div id="slide"> 
 
    </div> 
 
</div>

+0

Je suis coincé avec l'échelle parce que j'essayais d'améliorer iDangerous swiper zoom et ils utilisent l'échelle –