6.8 创建图像放大器
本节,我们将创建一个十分优雅的图像放大器。创建方法是,根据鼠标的坐标,把大图的一部分裁剪出来,并显示在小图之上。
操作步骤
按照以下步骤,创建一条图像放大器,当用户把鼠标移动到图像上,该放大镜渲染被放大的图像的一部分:
1. 链接到Events类:
<script src="events.js">
</script>
2. 创建一个图像加载函数,来加载小图和大图,图像加载完成后,调用回调函数:
<script>
/* 加载图像,并在图像加载完成后,把这些图像作为入参调用回调函数 */
function loadImages(sources, callback){
var loadedImages = 0;
var numImages = 0;
var images = {};
//获取图像的数目
for (var src in sources) {
numImages++;
}
//加载图像
for (var src in sources) {
images[src] = new Image();
images[src].onload = function(){
//图像加载完成后,调用回调函数
if (++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
3. 定义drawMagnifier()函数,该函数绘制被放大的图像:
function drawMagnifier(config){
var context = config.context;
var images = config.images;
var mousePos = config.mousePos;
var imageX = config.imageX;
var imageY = config.imageY;
var magWidth = config.magWidth;
var magHeight = config.magHeight;
var smallWidth = config.smallWidth;
var smallHeight = config.smallHeight;
var largeWidth = config.largeWidth;
var largeHeight = config.largeHeight;
/* sourceX和sourceY假定我们裁剪的矩形区域在大图的内部是存在的。
* 在放大器超过大图边缘的情况下,我们将不得不进行调整。
*/
var sourceX = ((mousePos.x - imageX) * largeWidth / smallWidth) - magWidth / 2;
var sourceY = ((mousePos.y - imageY) * largeHeight / smallHeight) - magHeight / 2;
var destX = mousePos.x - magWidth / 2;
var destY = mousePos.y - magHeight / 2;
var viewWidth = magWidth;
var viewHeight = magHeight;
var viewX = destX;
var viewY = destY;
var drawMagImage = true;
// 在放大器超过大图边缘的情况下,我们将进行边界检查和调整
if (sourceX < 0) {
if (sourceX > -1 * magWidth) {
var diffX = -1 * sourceX;
viewX += diffX;
viewWidth -= diffX; sourceX = 0;
}
else {
drawMagImage = false;
}
}
if (sourceX > largeWidth - magWidth) {
if (sourceX < largeWidth) {
viewWidth = largeWidth - sourceX;
}
else {
drawMagImage = false;
}
}
if (sourceY < 0) {
if (sourceY > -1 * magHeight) {
var diffY = -1 * sourceY;
viewY += diffY;
viewHeight -= diffY; sourceY = 0;
}
else {
drawMagImage = false;
}
}
if (sourceY > largeHeight - magHeight) {
if (sourceY < largeHeight) {
viewHeight = largeHeight - sourceY;
}
else {
drawMagImage = false;
}
}
//绘制白色放大器背景
context.beginPath();
context.fillStyle = "white";
context.fillRect(destX, destY, magWidth, magHeight);
// 绘制图像
if (drawMagImage) {
context.beginPath();
context.drawImage(images.cobraLargeImg, sourceX,
sourceY, viewWidth, viewHeight, viewX, viewY, viewWidth, viewHeight);
}
//绘制边框
context.beginPath();
context.lineWidth = 2;
context.strokeStyle = "black";
context.strokeRect(destX, destY, magWidth, magHeight);
}
4. 定义drawImages()函数,该函数实例化一个Events对象,并定义放大镜的属性:
function drawImages(images){
var events = new Events("myCanvas");
var canvas = events.getCanvas();
var context = events.getContext();
// 定义放大镜所依赖的图像
var imageX = canvas.width / 2 - images.cobraSmallImg.width / 2;
var imageY = canvas.height / 2 - images.cobraSmallImg. height / 2;
var magWidth = 200;
var magHeight = 150;
var smallWidth = images.cobraSmallImg.width;
var smallHeight = images.cobraSmallImg.height;
var largeWidth = images.cobraLargeImg.width;
var largeHeight = images.cobraLargeImg.height;
5. 设置stage()函数,该函数绘制小图,然后调用drawMagnifier()函数绘制被放大的图像:
events.setStage(function(){
var mousePos = events.getMousePos(); this.clear();
context.drawImage(images.cobraSmallImg, imageX,
imageY, smallWidth, smallHeight);
// 绘制图像四周的边框
context.beginPath();
context.lineWidth = 2;
context.strokeStyle = "black";
context.strokeRect(imageX, imageY, smallWidth,
smallHeight);
context.closePath();
if (mousePos !== null) {
drawMagnifier({
context: context, images: images,
mousePos: mousePos,
imageX: imageX,
imageY: imageY,
magWidth: magWidth,
magHeight: magHeight,
smallWidth: smallWidth,
smallHeight: smallHeight,
largeWidth: largeWidth,
largeHeight: largeHeight
});
}
});
6. 为画布元素增加事件监听器,当用户鼠标移出画布时,该监听器会重绘整个画布,以便删除被放大的图像:
canvas.addEventListener("mouseout", function(){
events.stage();
}, false);
}
7. 页面加载完成后,创建一组图像,并以它们为入参,调用loadImages()函数:
window.onload = function(){
var sources = {
cobraSmallImg: "cobra_280x210.jpg",
cobraLargeImg: "cobra_800x600.jpg"
};
loadImages(sources, drawImages);
};
</script>
8. 在HTML文档的body部分嵌入canvas标签:
<canvas id="myCanvas" width="600" height="250" style="border:1px solid black;">
</canvas>
工作原理
要创建一个图像放大器,我们需要两幅图像,一副小图和一副大图。小图在画布上永远可见,大图将被用作绘制放大镜的缓存图像。页面加载完成后,两幅图像都被加载,我们可以实例化一个Events对象,并开始定义stage()函数。
在画布中央绘制完小图后,我们可以绘制被放大的图像。绘制方法是,计算drawImage()方法的参数sourceX, sourceY, destX, 和 destY,该方法会呈现大图被放大的部分,再把结果显示在小图上。
为了得到sourceX 和 sourceY的值,我们先计算出鼠标相对于小图的坐标(即鼠标位置和小图左上角位置的差值),再乘以放大系数(即大图的宽度除以小图的宽度),得到大图的坐标,再减去放大后的窗口尺寸的一半:
var sourceX = ((mousePos.x - imageX) * largeWidth / smallWidth) - magWidth / 2;
var sourceY = ((mousePos.y - imageY) * largeHeight / smallHeight) - magHeight / 2;
为了让放大的图像在鼠标光标的中央,我们可以让destX等于鼠标的x值减去放大后图像宽度的一半,让destY等于鼠标的y值减去放大后图像高度的一半:
var destX = mousePos.x - magWidth / 2;
var destY = mousePos.y - magHeight / 2;
相关参考
- 第3章 绘制图像
- 第3章 裁剪图像