background-size:cover 的解决方案
我正在尝试为您提供解决方案(或作为一个想法考虑)。您可以查看工作演示here。调整窗口大小以查看结果。
首先,我不明白您为什么使用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时,您可以参考this URL了解更多关于图像尺寸计算的知识。
得到图像的尺寸后,我们需要绘制从实际图像到新图像尺寸的热点坐标。
为了使图像适合视口,图像将被剪裁在图像的顶部和底部/左侧和右侧。所以我们应该在绘制热点时将这个剪裁的图像大小视为偏移量。
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
为了使图像适合视口,将在图像的顶部和底部/左侧和右侧添加额外的空间。所以我们应该在绘制热点时将此空间视为偏移量。
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>
解决背景尺寸:100% 100%
如果有人正在寻找 background-size:100% 100%,请查看工作演示 here,这就是解决方案。调整窗口大小以查看结果。
这里我们不需要计算图像尺寸,因为图像总是适合 div。所以我们可以使用viewport和actualimage的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 热点。
这种方法的一个优点是我们不必在调整窗口大小时重新计算热点坐标,因为热点是在图像本身中绘制的。
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>