javascript - 使用 jQuery 缩放与背景覆盖成比例的元素

标签 javascript jquery html css screen-resolution

我有一个棘手的问题: 我在我正在工作的网站上有一个全尺寸的背景。 现在我想将一个 div 附加到图像上的某个位置,并且 div 的缩放方式与我的背景图像具有“background-size:cover”属性的方式相同。 所以在这个例子中,我有一张城市的图片,它覆盖了浏览器窗口,我希望我的 div 覆盖一个特定的建筑物,无论窗口大小如何。

我已经设法让 div 固定在一个位置,但无法正确调整大小。到目前为止我做了什么:

http://codepen.io/EmmieBln/pen/YqWaYZ

var imageWidth = 1920,
    imageHeight = 1368,
    imageAspectRatio = imageWidth / imageHeight,
    $window = $(window);

var hotSpots = [{
    'x': -160,
    'y': -20,
    'height': 400,
    'width': 300
}];

function appendHotSpots() {
    for (var i = 0; i < hotSpots.length; i++) {
        var $hotSpot = $('<div>').addClass('hot-spot');
        $('.container').append($hotSpot);
    }
    positionHotSpots();
}

function positionHotSpots() {
    var windowWidth = $window.width(),
        windowHeight = $window.height(),
        windowAspectRatio = windowWidth / windowHeight,
        $hotSpot = $('.hot-spot');

    $hotSpot.each(function(index) {
        var xPos = hotSpots[index]['x'],
            yPos = hotSpots[index]['y'],
            xSize = hotSpots[index]['width'],
            ySize = hotSpots[index]['height'],
            desiredLeft = 0,
            desiredTop = 0;

        if (windowAspectRatio > imageAspectRatio) {
            yPos = (yPos / imageHeight) * 100;
            xPos = (xPos / imageWidth) * 100;
            xSize = (xSize / imageWidth) * 1000;
            ySize = (ySize / imageHeight) * 1000;
        } else {
            yPos = ((yPos / (windowAspectRatio / imageAspectRatio)) / imageHeight) * 100;
            xPos = ((xPos / (windowAspectRatio / imageAspectRatio)) / imageWidth) * 100;
        }

        $(this).css({
            'margin-top': yPos + '%',
            'margin-left': xPos + '%',
            'width': xSize + 'px',
            'height': ySize + 'px'
        });

    });
}

appendHotSpots();
$(window).resize(positionHotSpots);

我的想法是: 如果 (imageWidth/windowWidth) < 1 然后设置 Value for var Scale = (windowWidth/imageWidth) else var Scale ( windowHeight/imageHeight ) 并使用 var Scale 进行转换:scale (Scale,Scale) 但我无法完成这项工作……

也许你们可以帮助我……

最佳答案

background-size:cover的解决方案

我正在尝试为您提供解决方案(或考虑作为一个想法)。您可以查看工作演示 here .调整窗口大小以查看结果。

首先,我不明白您为什么要使用transformtop:50%left:50% 作为热点。因此,我尝试使用最少的用例来解决这个问题,并为方便起见调整了您的标记和 CSS。

这里的rImage是原图的纵横比。

 var imageWidth = 1920;
 var imageHeight = 1368;
 var h = {
   x: imageWidth / 2,
   y: imageHeight / 2,
   height: 100,
   width: 50
 };
 var rImage= imageWidth / imageHeight;

在窗口调整大小处理程序中,计算视口(viewport)r 的纵横比。 接下来,诀窍是在我们调整窗口大小时找到图像的尺寸。但是,视口(viewport)会裁剪图像以保持纵横比。因此,要计算图像尺寸,我们需要一些公式。

当使用background-size:cover 计算图像尺寸时,使用以下公式。

if(actual_image_aspectratio <= viewport_aspectratio)
    image_width = width_of_viewport
    image_height = width_ofviewport / actual_image_aspectratio 

if(actual_image_aspectratio > viewport_aspectratio)
    image_width = height_of_viewport * actual_image_aspectratio 
    image_height = height_of_viewport

可以引用this URL了解使用 background-size:cover 时图像尺寸的计算。

得到图像的尺寸后,我们需要绘制从实际图像到新图像尺寸的热点坐标。

为了使图像适合视口(viewport)图像将在图像的顶部和底部/左侧和右侧进行裁剪。因此,在绘制热点时,我们应该将这个裁剪后的图像大小视为一个偏移量。

offset_top=(image_height-viewport_height)/2
offset_left=(image_width-viewport_width)/2

将此偏移值添加到每个热点的 x,y 坐标

var imageWidth = 1920;
var imageHeight = 1368;
var hotspots = [{
  x: 100,
  y: 200,
  height: 100,
  width: 50
}, {
  x: 300,
  y: 500,
  height: 200,
  width: 100
}, {
  x: 600,
  y: 600,
  height: 150,
  width: 100
}, {
  x: 900,
  y: 550,
  height: 100,
  width: 25
}];
var aspectRatio = imageWidth / imageHeight;

$(window).resize(function() {
  positionHotSpots();
});
var positionHotSpots = function() {
  $('.hotspot').remove();
  var wi = 0,
    hi = 0;
  var r = $('#image').width() / $('#image').height();
  if (aspectRatio <= r) {
    wi = $('#image').width();
    hi = $('#image').width() / aspectRatio;
  } else {
    wi = $('#image').height() * aspectRatio;
    hi = $('#image').height();
  }
  var offsetTop = (hi - $('#image').height()) / 2;
  var offsetLeft = (wi - $('#image').width()) / 2;
  $.each(hotspots, function(i, h) {

    var x = (wi * h.x) / imageWidth;
    var y = (hi * h.y) / imageHeight;

    var ww = (wi * (h.width)) / imageWidth;
    var hh = (hi * (h.height)) / imageHeight;

    var hotspot = $('<div>').addClass('hotspot').css({
      top: y - offsetTop,
      left: x - offsetLeft,
      height: hh,
      width: ww
    });
    $('body').append(hotspot);
  });
};
positionHotSpots();
html,
body {
  height: 100%;
  padding: 0;
  margin: 0;
}
#image {
  height: 100%;
  width: 100%;
  background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg');
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
}
.hotspot {
  position: absolute;
  z-index: 1;
  background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='image'></div>

background-size:contain的解决方案

当使用background-size:contain计算图片的尺寸时,会用到下面的公式。

if(actual_image_aspectratio <= viewport_aspectratio)
    image_width = height_of_viewport * actual_image_aspectratio 
    image_height = height_of_viewport

if(actual_image_aspectratio > viewport_aspectratio)
    image_width = width_of_viewport
    image_height = width_ofviewport / actual_image_aspectratio

为了使图像适合视口(viewport),将在图像的顶部和底部/左侧和右侧添加额外的空间。因此,我们在绘制热点时应将此空间视为偏移量。

offset_top=(viewport_height-image_height)/2
offset_left=(viewport_width-image_width)/2

将此偏移值添加到每个热点的 x,y 坐标

 var imageWidth = 1920;
 var imageHeight = 1368;
 var hotspots = [{
   x: 100,
   y: 200,
   height: 100,
   width: 50
 }, {
   x: 300,
   y: 500,
   height: 200,
   width: 100
 }, {
   x: 600,
   y: 600,
   height: 150,
   width: 100
 }, {
   x: 900,
   y: 550,
   height: 100,
   width: 25
 }];
 var aspectRatio = imageWidth / imageHeight;

 $(window).resize(function() {
   positionHotSpots();
 });
 var positionHotSpots = function() {
   $('.hotspot').remove();
   var wi = 0,
     hi = 0;

   var r = $('#image').width() / $('#image').height();
   if (aspectRatio <= r) {
     wi = $('#image').height() * aspectRatio;
     hi = $('#image').height();

   } else {
     wi = $('#image').width();
     hi = $('#image').width() / aspectRatio;
   }
   var offsetTop = ($('#image').height() - hi) / 2;
   var offsetLeft = ($('#image').width() - wi) / 2;
   $.each(hotspots, function(i, h) {

     var x = (wi * h.x) / imageWidth;
     var y = (hi * h.y) / imageHeight;

     var ww = (wi * (h.width)) / imageWidth;
     var hh = (hi * (h.height)) / imageHeight;

     var hotspot = $('<div>').addClass('hotspot').css({
       top: y + offsetTop,
       left: x + offsetLeft,
       height: hh,
       width: ww
     });
     $('body').append(hotspot);
   });
 };
 positionHotSpots();
html,
body {
  height: 100%;
  padding: 0;
  margin: 0;
}
#image {
  height: 100%;
  width: 100%;
  background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}
.hotspot {
  position: absolute;
  z-index: 1;
  background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='image'></div>

background-size:100% 100%的解决方案

如果有人正在寻找 background-size:100% 100% 查看工作演示 here,这就是解决方案.调整窗口大小以查看结果。

这里我们不需要计算图像尺寸,因为图像总是适合 div。所以我们可以使用视口(viewport)和实际图像的 heightwidth 来计算热点的新坐标。

var imageWidth = 1920;
var imageHeight = 1368;
var hotspots = [{
  x: 100,
  y: 200,
  height: 100,
  width: 50
}, {
  x: 300,
  y: 500,
  height: 200,
  width: 100
}, {
  x: 600,
  y: 600,
  height: 150,
  width: 100
}, {
  x: 900,
  y: 550,
  height: 100,
  width: 25
}];

$(window).resize(function() {
  positionHotSpots();
});


var positionHotSpots = function() {
  $('.hotspot').remove();

  $.each(hotspots, function(i, h) {
    var x = ($('#image').width() * h.x) / imageWidth;
    var y = ($('#image').height() * h.y) / imageHeight;

    var ww = ($('#image').width() * (h.width)) / imageWidth;
    var hh = ($('#image').height() * (h.height)) / imageHeight;
    var hotspot = $('<div>').addClass('hotspot').css({
      top: y,
      left: x,
      height: hh,
      width: ww
    });
    $('body').append(hotspot);
  });

};
positionHotSpots();
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}
#image {
  height: 100%;
  width: 100%;
  background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg');
  background-size: 100% 100%;
}
.hotspot {
  position: absolute;
  z-index: 1;
  background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='image'></div>

Canvas 解决方案

根据@JayMee 的评论,创建一个与实际图像具有相同尺寸的 Canvas ,并在 Canvas 上绘制热点作为矩形

这种方法的一个优点是我们不必在调整窗口大小时重新计算热点坐标,因为热点是在图像本身中绘制的。

 var imageWidth = 1920;
 var imageHeight = 1368;
 var hotspots = [{
   x: 100,
   y: 200,
   height: 100,
   width: 50
 }, {
   x: 300,
   y: 500,
   height: 200,
   width: 100
 }, {
   x: 600,
   y: 600,
   height: 150,
   width: 100
 }, {
   x: 900,
   y: 550,
   height: 100,
   width: 25
 }];

 var positionHotSpots = function() {


   var canvas = document.createElement('canvas');
   canvas.height = imageHeight;
   canvas.width = imageWidth;
   var context = canvas.getContext('2d');
   var imageObj = new Image();
   imageObj.onload = function() {

     context.drawImage(imageObj, 0, 0);

     $.each(hotspots, function(i, h) {
       context.rect(h.x, h.y, h.width, h.height);
     });
     context.fillStyle = "red";
     context.fill();
     $('#image').css('background-image', 'url("' + canvas.toDataURL() + '")');
   };
   imageObj.setAttribute('crossOrigin', 'anonymous');
   imageObj.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg';

 };
 positionHotSpots();
html,
body {
  height: 100%;
  padding: 0;
  margin: 0;
}
#image {
  height: 100%;
  width: 100%;
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
}
<!DOCTYPE html>
<html>

<head>
  <script src="https://code.jquery.com/jquery-2.1.4.js"></script>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

<body>
  <div id='image'></div>
</body>

</html>

关于javascript - 使用 jQuery 缩放与背景覆盖成比例的元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35942014/

相关文章:

javascript - 对大值使用 setTimeout()

javascript - jQuery 有 AJAJ 方法吗?

jquery - 根据用户代理删除 jQuery 脚本

javascript - HTML 复选框的状态无法在浏览器中呈现

javascript - Chart.js 图例对齐

javascript - 我可以只用 HTML5 实现这个功能吗?

javascript - Google map api v3, "Object #<Object> has no method ' setValues“错误

javascript - 如何解决输入范围 slider 的跨浏览器兼容性问题?

javascript - jQuery 旋转器旋转不正确 - 太多递归

html - HTML 中数字的重音符号(如 ^ 大于 1)