【问题标题】:Zoom on an image on mouse move: reaching all corners鼠标移动时放大图像:到达所有角落
【发布时间】:2016-08-13 01:28:42
【问题描述】:

我正在开发缩放功能。此缩放是一个固定框,具有 100% 的窗口大小,并且在一个具有固定框宽度的 200% 的图像内。

这个缩放需要像这样工作:

  • 当光标在窗口中心时,图像应该在中心。
  • 当光标在右上角时,图像应该停留在窗口的右上角(这样才能到达有角的图像)
  • 当光标在中下角时,图像应该水平居中并到达总底部,这样我们就可以看到图像的中底部分。
  • 等等。

我接近了,但我无法完美地到达角落。这是我的 sn-p(参见 onmousemove 函数中的 cmets):

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)在最高值不工作时完美工作?

【问题讨论】:

  • 如果我没有遗漏什么,因为视口不是正方形,您可能需要计算其纵横比。另外,translate 不是更好用吗?
  • 我尝试在第一个实例中进行翻译,但经过一些更改,我的最终代码看起来像这样!哈哈
  • 好吧,我再次将其更改为translate(),但显然这不是问题所在。 @LGSon 我如何在这里实现纵横比?
  • 我稍后再看看,现在没有时间......完成后告诉你
  • 没问题,我不急这个任务,只是卡住了。谢谢;)

标签: javascript jquery css aspect-ratio zooming


【解决方案1】:

你真的很亲密。获取垂直百分比时只需要计算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,我更改了 sn-p 中的图像,看起来还不错。似乎是什么问题?
  • 在sn-p中一切都很完美,在我的实现中(我完全复制你的计算)右侧没有完全到达,我与你分享的图像右侧很宽,所以它是用户无法到达图像的右侧非常烦人。到家后我会再次测试,可能这就是赏金的答案。也许我的代码正在产生冲突。再次感谢您!
  • 如果您可以分享有问题的测试代码,我可以查看它以尝试查看问题所在。代码中的宽度计算并不像它可能的那样具体,它被简化了,因为图像的宽度总是被假定为窗口宽度的两倍。
  • 是的,这个前提是正确的,图像总是会是父宽度的200%,所以变量unknown size就是高度。现在我不能和你分享 URL,也许一两个小时后我可以给你 URL 来测试它。再次感谢您。
【解决方案2】:

我认为你可以通过 CSS 修改来实现你想要的。如果您尝试在 onmousemove 事件中同时使用剪​​辑、变换平移和变换缩放,则可以按照问题中的指定移动图像。请让我知道,如果这是所需的行为,谢谢。

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>

【讨论】:

  • 哼,似乎是个好主意,但它不能正常工作,至少在这个带有触摸设备的小提琴jsfiddle.net/wznpL539 中。顶部,左侧和底部工作正常,而右侧不是。谢谢你。我给你一个赞成票,因为你这样做的绝妙方式。
  • 请尝试像我在问题中那样使用stacksn-ps,您必须单击编辑器顶部的代码sn-p图标。您可以添加 javascript、css 和 html 代码拆分在三个窗口中,第四个窗口用于预览。没问题后,保存到帖子中,我们都可以重现代码。
  • 我会尝试更新我的答案,谢谢你告诉我,我是新来的:)。同时,请查看jsfiddle.net/wznpL539/1
  • 我认为现在它可以按您的意愿工作。现在唯一的问题是div和图片的纵横比不同导致图片变形。
  • 如果您可以看到,在视口的低分辨率下,图像不会超过自身的一半。在高分辨率下工作正常,但我的代码以相同的方式工作,我的代码在高分辨率下工作,但在低分辨率下的高度不好。
猜你喜欢
  • 1970-01-01
  • 2013-01-04
  • 1970-01-01
  • 2011-12-28
  • 2014-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-04
相关资源
最近更新 更多