2017-10-09 101 views
5

这个问题是类似这样的:Zoom in on a point (using scale and translate) 甚至这一个:Image zoom centered on mouse position ,但我不想做一个画布,但一个正常的图像(或而不是图像的容器div)。 所以缩放应该是谷歌地图。 我其实黑客/增强iDangerous组队,探索变焦(http://idangero.us/swiper/),这是我的出发点,这是是我走到这一步: https://jsfiddle.net/xta2ccdt/3/放大一个鼠标滚轮点(使用规模和翻译)

变焦只可使用鼠标滚轮。第一次放大时,它会完美放大,但我无法弄清楚如何在第一次放大后计算每个缩放。

这里是我的代码: 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%; 
} 

我也想通了,如果我减去先前的平移X和translateY值当前的,我可以尽可能多地放大同一点,并且会缩小p但是如果我放大一个点然后改变鼠标位置并再次放大,它将不再按照它应该放大的那样缩放。例如:https://jsfiddle.net/xta2ccdt/4/

如果我改变鼠标位置,并计算新旧鼠标位置之间的X和Y差异,并将其添加到差异计算中,它将第二次正确缩放。但第三次看起来差异仍然从总计算中减去,这将导致翻译再次移动图像,之后,如果我们将鼠标放在相同的位置,它将再次正确地缩放。 所以我想我会在每次计算新的“差异”时添加旧的和新的鼠标位置之间的差异,并且这种作品不再像当我停止添加鼠标位置差异时那样跳跃,但它仍然没有放大到相同的位置,每次新的缩放都会移动(偏移)图像一小部分。我认为这是因为每次都有一个新的缩放值,但偏移量不是线性的,它每次都小于零,我无法弄清楚如何抵消偏移量。 这里是新的例子:https://jsfiddle.net/xta2ccdt/5/ 在例如新形象:一个老不再可用:https://jsfiddle.net/xta2ccdt/14/

+0

相依但没有按没有结束标签。它应该自我关闭我也不得不使用像占位符b/c之类的其他图像被阻止。出于某种原因,我无法缩小。 –

+0

我发现这个插件,似乎做你想做的:http://www.jqueryscript.net/demo/jQuery-Plugin-for-Image-Zoom-In-Out-With-Mousewheel-imgViewer/ – Isma

+0

btw。我最终放弃了这一点,并使用panzoom代替:https://github.com/timmywil/jquery.panzoom –

回答

1

你接近它,但它是更好地存储x,y和规模分别计算和基于这些值转换。这让事情变得容易得多+节约资源(不需要一遍遍查找的DOM属性),

我已经把代码放到一个不错的模块:通过调用

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+')') 
    } 
} 

使用它

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

的参数是:

  1. 容器:该元件的包装器被缩小。该脚本将 寻找容器的第一个孩子,并将变换 应用于它。
  2. max_scale:最大规模(4 = 400%的缩放)
  3. 因子:变焦速度(每只小鼠轮蜱1 = + 100%缩放)

JSFiddle here

+0

这似乎工作。你为什么将转换原点设置为0,0。由于它是默认的 –

+0

,因此我想将其保留为50%.50%,该逻辑基于x:0,y:0处的转换原点。但你可以修改它。 –

1

我认为这将让你更接近你想达到什么一点。

主要变更

  1. 我把规模回调之外;我不认为你想在每次赛事中重置你的比例。
  2. 除了手动计算翻译的话,尝试设置transform-origin鼠标上为中心的(除非你想保留它为中心这是默认的)

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

我仍然存在的问题。如果您放大例如在左上角的某处,然后放大右下角,图像跳转。 –

0

代码我使用放大鼠标位置在下面。它不使用transform/translate3d,但重新调整图像在div内的位置并调整其heightwidth

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

我与翻译卡住,因为试图增强iDangerous swiper缩放,并且他们使用翻译。 –

0

有关使用translate3dperspective,处理3D的转换,而不是使用scale什么?此外,从翻译中去除缩放使得它更简单。

$(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

我被卡住的规模,因为我试图加强iDangerous swiper缩放,他们使用规模 –