解决background-size:cover的问题
我尝试给您提供一个解决方案(或者说是想法)。您可以在这里检查工作演示。调整窗口大小以查看结果。
首先,我不明白为什么您要使用transform
,top: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;
在窗口大小调整处理程序中,计算视口的纵横比
r
。
接下来的诀窍是找到当我们调整窗口大小时图像的尺寸。但是,视口将剪裁图像以保持其纵横比。因此,为了计算图像尺寸,我们需要一些公式。
使用
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
您可以参考
此链接,了解使用
background-size:cover
时图像尺寸计算的更多信息。
在获取图像的尺寸后,我们需要将热点坐标从实际图像绘制到新图像尺寸上。
为了使图像适应视口,图像将被裁剪在顶部和底部/左侧和右侧。因此,在绘制热点时,我们应该考虑这个裁剪图像大小作为偏移量。
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>
背景大小为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
为了适应视口,将在图像的顶部和底部/左侧和右侧添加额外的空间。因此,在绘制热点时,我们应该将这个空间视为偏移量。
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%
的方法,请查看此处的工作演示。调整窗口大小以查看结果。
在这里,我们不需要计算图像尺寸,因为图像将始终适合div中。因此,我们可以使用视口和实际图像的height
和width
来计算热点的新坐标。
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>
画布解决方案
根据@JayMee的评论,创建一个与实际图像具有相同尺寸的canvas
,并在画布上将热点用rectangles
绘制。
One advantage in this approach is we don't have to recalculate the hotspot coordinates on resizing window as the hotspot are drawn in image itself.
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>