鼠标移动时放大图片:覆盖所有角落

3
我正在开发一个缩放功能。这个缩放是一个100%窗口大小的固定框,里面有一个200%宽度的图像。
这个缩放需要按照以下方式工作:
- 当鼠标指针在窗口中心时,图像应该在中心。 - 当鼠标指针在右上角时,图像应该停留在窗口的右上角(所以到达图像与角落)。 - 当鼠标指针在中间底部角落时,图像应该水平居中并到达底部,这样我们就可以看到图像的中间底部部分。 - 依此类推。
我已经尝试了一种方法,但无法完美地到达角落。这是我的代码片段(请参见onmousemove函数中的注释):

var Zoom = function(imageZoom) {
  this.urlImage = imageZoom;
  this.img = undefined;
  this.$img = undefined;

  this.init = function() {
    this.loaders("on");
    this.calcs();
  };
  this.calcs = function() {
    var self = this;
    this.img = new Image();
    this.img.onload = function() {
      self.build();
    };
    this.img.src = this.urlImage;
  };
  this.loaders = function(status) {
    switch(status) {
      case "on":
        $('#loader').fadeIn(200);
        break;
      case "off":
        $('#loader').fadeOut(200);
        break;
    }
  };
  this.build = function() {
    var self = this;
    this.$img = $(self.img);
    
    $('#zoom').fadeIn(200).append(this.$img);
    
    this.$img.on('mousedown', function(e) {
      e.preventDefault();
    });
    
    // this is the problematic function
    $('body').on('mousemove', function(e) {
      e.preventDefault();
      // calc the percents of the window where
      var px = 100 * e.pageX / $(window).width(); 
      var py = 100 * e.pageY / $(window).height();

      // calc of the percent pixel of the image
      var fx = self.$img.width() * px / 100;
      var fy = self.$img.height() * py / 100;

      // render it left / 2 and top / 1.5 (the 1.5 value is imaginary!!)
      self.$img.css({'transform': 'translate('+ -(fx/2) +'px, '+ -(fy/1.5)+'px)'});
    });
    self.loaders("off");
  };
};

var zoom = new Zoom("http://dummyimage.com/2000x1230/000/fff");
zoom.init();
#zoom {
 position: fixed;;
 top: 0;
 left: 0;
 width: 100%;
 height: 100%;
 z-index: 1000000;
 display: none;
}
#zoom img {
 width: 200%;
 height: auto;
 position: absolute;
 cursor: crosshair;
 -webkit-touch-callout: none;
 -webkit-user-select: none;
 -khtml-user-select: none;
 -moz-user-select: none;
 -ms-user-select: none;
 user-select: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="loader">Loading</div>
<div id="zoom"></div>

问题在于我使用了fx/1.5,因为fx/2不起作用。但水平值却完美地运行。
我应该如何配置才能到达所有角落?为什么左边的值(像素除以2)可以完美工作,而上方的值却不能?

我尝试在第一次翻译时进行翻译,但是随着一些更改,我的最终代码看起来像这样!哈哈 - Marcos Pérez Gude
好的,我再次将其更改为translate(),但显然那不是问题所在。 @LGSon,我如何在这里实现宽高比? - Marcos Pérez Gude
我稍后会看一下,现在没时间...做完后会通知你。 - Asons
没问题,我对这个任务没有着急的时间限制,只是卡住了。谢谢 ;) - Marcos Pérez Gude
我在尝试调整图片的宽高比,但效果不佳。感谢您的帮助。我们可以假设图像的比例为1:1(例如1000×1000),但最好不要对图像尺寸做任何假设。谢谢。 - Marcos Pérez Gude
显示剩余5条评论
2个回答

4
你非常接近了。在获取垂直百分比时,你只需要计算image.height - window.height
由于考虑到图像高度进行计算,因此这也适用于不同的图像长宽比。由于宽度始终是窗口宽度的两倍,因此宽度不是问题。

var Zoom = function(imageZoom) {
  this.urlImage = imageZoom;
  this.img = undefined;
  this.$img = undefined;

  this.init = function() {
    this.loaders("on");
    this.calcs();
  };
  this.calcs = function() {
    var self = this;
    this.img = new Image();
    this.img.onload = function() {
      self.build();
    };
    this.img.src = this.urlImage;
  };
  this.loaders = function(status) {
    switch (status) {
      case "on":
        $('#loader').fadeIn(200);
        break;
      case "off":
        $('#loader').fadeOut(200);
        break;
    }
  };
  this.build = function() {
    var self = this;
    this.$img = $(self.img);

    $('#zoom').fadeIn(200).append(this.$img);

    this.$img.on('mousedown', function(e) {
      e.preventDefault();
    });

    // this is the problematic function
    $('body').on('mousemove', function(e) {
      e.preventDefault();

      var wx = $(window).width();
      var wy = $(window).height();
      var iy = self.$img.height();

      var px = e.pageX;
      var py = e.pageY;

      var tx = -1 * (px / wx) * wx;
      var ty = -1 * (py / wy) * (iy - wy);

      self.$img.css({
        'transform': 'translate(' + tx + 'px, ' + ty + 'px)'
      });
    });
    self.loaders("off");
  };
};

var zoom = new Zoom("http://dummyimage.com/2000x1200/000/fff");
zoom.init();
#zoom {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1000000;
  display: none;
}
#zoom img {
  width: 200%;
  height: 100%;
  height: auto;
  position: absolute;
  cursor: crosshair;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
body {
  margin: 0;
}
* {
  box-sizing: border-box;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="loader">Loading</div>
<div id="zoom"></div>

作为额外加分: 如果您想要消除图像纵横比高时留下的空白区域(jsfiddle),您可以确保图像高度至少等于窗口高度(jsfiddle)。但是,在这种情况下,您需要设置width: auto,以便图像不总是比窗口宽两倍。

@MarcosPérezGude,我在代码片段中更改了图像,看起来没问题。有什么问题吗? - Ozan
在这段代码中一切都很完美,在我的实现中(我完全复制了你的计算),右侧没有完全到达,而且我与你分享的图片有一个宽阔的右侧,所以用户无法完全看到图片的右侧非常令人恼火。当我回家后我会再次测试,很可能这就是解决问题的答案。也许我的代码存在冲突。再次感谢你! - Marcos Pérez Gude
如果您能分享带问题的测试代码,我可以看一下并尝试找出问题所在。代码中的宽度计算不够具体,因为假定图像的宽度始终是窗口宽度的两倍,所以进行了简化。 - Ozan
不客气。我猜想:如果您的实例中有其他元素(我假设您有,因为代码片段中不存在问题),那么问题可能是由于box-sizing和/或padding/margin值设置在其他元素上影响图像位置造成的。 - Ozan
不,所有页面的盒模型尺寸都设置为border-box :( - Marcos Pérez Gude
显示剩余3条评论

1

我认为你可以通过CSS修改来实现你想要的效果。如果你尝试在onmousemove事件中同时使用clip、transform translate和transform scale,你就可以按照你问题中指定的方式移动图片。如果这是你想要的行为,请告诉我,谢谢。

var divPos = {left:0,top:0};
var offset = $("#loader").offset();
$(document).mousemove(function(e){
  divPos = {
    left: e.pageX - offset.left,
    top: e.pageY - offset.top
  };

  console.log("x:" + divPos.left + " y: " + divPos.top);
});

var Zoom = function(imageZoom) {
  this.urlImage = imageZoom;
  this.img = undefined;
  this.$img = undefined;

  this.init = function() {
    this.loaders("on");
    this.calcs();
  };
  
  this.calcs = function() {
    var self = this;
    this.img = new Image();
    this.img.onload = function() {
      self.build();
    };
  
    this.img.src = this.urlImage;
  };
  this.loaders = function(status) {
    switch(status) {
      case "on":
        $('#loader').fadeIn(200);
        break;
      case "off":
        $('#loader').fadeOut(200);
        break;
    }
  };
  this.build = function() {
    var self = this;
    this.$img = $(self.img);
                
    $('#zoom').fadeIn(200).append(this.$img);
                
    this.$img.on('mousedown', function(e) {
      e.preventDefault();
    });

                
    // this is the problematic function
    $('body').on('mousemove', function(e) {
      e.preventDefault();

      var width = $(self.img).width();
      var height = $(self.img).height();
      // img center calculation
      var imgCenterX = width/2;
      var imgCenterY = height/2;
      // translate calculation
      var tx = imgCenterX-divPos.left;
      var ty = imgCenterY-divPos.top;

      // clip calculation
      var c0 = divPos.top/2;
      var c1 = divPos.left/2 + width/2;
      var c2 = divPos.top/2 + height/2;
      var c3 = divPos.left/2;

      console.log(c0 + ',' + c1 + ',' + c2 + ',' + c3);

      var t = 'translate('+ tx +'px, '+ ty +'px)';
      var c = 'rect('+ c0 +'px,'+ c1 +'px,'+ c2 +'px,'+ c3 +'px)';
      self.$img.css({'transform': t + ' scale(2,2)'});
      self.$img.css({'clip': c});
    });
    self.loaders("off");
  };
};

var zoom = new Zoom("http://dummyimage.com/2000x1230/000/fff");
zoom.init();
#zoom {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: 1000000;
            display: none;
}
#zoom img {
            width: 100%;
            height: 100%;
            position: absolute;
            cursor: crosshair;
            -webkit-touch-callout: none;
            -webkit-user-select: none;
            -khtml-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="loader">Loading</div>
<div id="zoom"></div>


嗯,看起来是个好主意,但在这个链接 https://jsfiddle.net/wznpL539/ 上使用触摸设备时并不能正常工作。顶部、左侧和底部都可以正常工作,但右侧不行。谢谢你的帮助,我会给你点赞的,因为你的方法真的很棒。 - Marcos Pérez Gude
1
请尝试像我在问题中所做的那样使用stacksnippets,您必须点击编辑器顶部的代码片段图标。您可以将JavaScript、CSS和HTML代码分割到三个窗口中,并在第四个窗口中进行预览。当一切就绪后,请保存帖子,我们所有人都能够复制代码。 - Marcos Pérez Gude
我会尝试更新我的答案,谢谢你告诉我,我是新来的:)。与此同时,请查看https://jsfiddle.net/wznpL539/1/。 - peebee
我认为现在它像你想要的那样工作了。现在唯一的问题是由于div和图像的不同宽高比而导致图像变形。 - peebee
如果您能看到,当视口的分辨率较低时,图像不会超过其一半。在高分辨率下工作正常,但我的代码也是这样,我的代码在高分辨率下工作良好,但在低分辨率下高度表现不佳。 - Marcos Pérez Gude
图片高度需要设置为“自动”,以避免变形。 - Marcos Pérez Gude

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接