Diese Frage ist ähnlich wie diese: Vergrößern Sie einen Punkt (mithilfe von Skalierung und Verschiebung) Oder sogar diesen: Bildzoom auf Mausposition zentriert Aber ich möchte nicht Um dies auf einer Leinwand zu tun, sondern um ein normales Bild (oder eher das Container-Div des Bildes) zu machen, sollte das Zoomen so sein wie bei Google Maps. Ich bin eigentlich hacking/verbessere den iDangerous Swiper-Zoom ( http://idangero.us/swiper/ ), und das ist mein Ausgangspunkt, und das ist, was ich bisher bekommen habe: https://jsfiddle.net/xta2ccdt/3/
Zoomen Sie nur mit dem Mausrad. Beim ersten Zoom zoomen Sie perfekt, aber ich kann nicht herausfinden, wie ich jeden Zoom nach dem ersten Zoom berechnen soll.
Hier ist mein 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%;
}
Ich habe auch herausgefunden, ob ich die vorherigen Werte von translateX subtrahiere und die aktuellen Werte von translateY subtrahiere. Ich kann an demselben Punkt so viel zoomen, wie ich möchte, und er wird perfekt zoomen. Wenn ich jedoch nur einen Punkt zoome, dann ändern Sie die Mausposition und den Zoom wieder wird es nicht mehr so zoomen, wie es soll. Beispiel: https://jsfiddle.net/xta2ccdt/4/
Wenn ich die Mausposition ändere und die X- und Y-Differenz zwischen der alten und der neuen Mausposition berechne und diese in die Differenzberechnung einsetze, wird sie beim zweiten Mal korrekt vergrößert. Das dritte Mal sieht jedoch so aus, als ob diese Differenz immer noch von der Gesamtberechnung abgezogen wird. Dies führt dazu, dass das Bild das Bild wieder wegbewegt, und wenn wir die Maus in derselben Position halten, zoomt das Bild wieder korrekt Ich werde einfach den Unterschied zwischen der alten und der neuen Mausposition hinzufügen, wenn ich den neuen "diff" berechne, und so funktioniert es, es gibt keinen Sprung mehr wie damals, als ich die Mauspositionsdifferenz nicht mehr hinzugefügt habe zoomt immer noch nicht an derselben Position, mit jedem neuen Zoom wird das Bild um einen kleinen Betrag verschoben (versetzt). Ich denke, dies ist, weil es jedes Mal einen neuen Zoom-Wert gibt, aber der Versatz ist nicht linear, er ist immer kleiner, wenn er sich Null nähert, und ich kann nicht herausfinden, wie ich den Versatz korrigieren kann .. Hier ist das neue Beispiel: https://jsfiddle.net/xta2ccdt/5/ Neues Bild im Beispiel: Das alte ist nicht mehr verfügbar: https://jsfiddle.net/xta2ccdt/14/
Sie waren nah dran, es ist jedoch besser, X, Y und Skalierung separat zu speichern und die Transformationen basierend auf diesen Werten zu berechnen. Es macht die Dinge viel einfacher + spart Ressourcen (keine Notwendigkeit, die Dom-Eigenschaften immer wieder nachzuschlagen),
Ich habe den Code in ein Nice-Modul eingefügt:
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+')')
}
}
Verwenden Sie es, indem Sie anrufen
new ScrollZoom($('#container'),4,0.5)
Die Parameter sind:
Ich denke, das bringt Sie näher an das, was Sie erreichen wollen.
Wichtige Änderungen
transform-Origin
so, dass er auf Ihrer Maus zentriert ist (es sei denn, Sie möchten, dass die Übersetzung zentriert bleibt, was der Standard ist).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>
Der Code, den ich zum Vergrößern der Mausposition verwende, befindet sich unten. Es verwendet nicht transform
/translate3d
, sondern passt die Position des Bildes im div an und passt seine height
und width
an.
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
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;
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>
Wie wäre es mit translate3d
und perspective
, um die 3D-Transformationen zu handhaben, anstatt scale
zu verwenden? Durch das Entkoppeln des Zooms von der Übersetzung wird es einfacher.
$(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>