放大镜在网页中运用广泛,在淘宝京东上面的商品图中就用到了,还有在空间上面展示图片的地方也有用到。现在这种jquery的插件也有很多,但是也要明白其中原理就可以自己做各种各样的放大镜效果了。
现在就来好好分析一下放大镜的原理和实现的过程:
简单的实现
成果图:
图像 1.png
放大镜的原理
使用两个图片,一个是小图——全部展现在页面中的,一个是大图——局部展示放大的效果。所以由此可以看出突破点,就是网页中一共有两张图,根据他们的移动的距离,可以实现放大镜的效果。
网页结构
下面就来写以下网页的结构
<!--css样式--> <style> * { margin: 0; padding: 0; } /*放大镜的大盒子*/ .box { width: 350px; height: 350px; margin: 100px; border: 1px solid #ccc; position: relative; } /*大图片外面的盒子*/ .big { width: 400px; height: 400px; position: absolute; top: 0; left: 360px; border: 1px solid #ccc; overflow: hidden; display: none; } /*遮挡层*/ .mask { width: 175px; height: 175px; background: rgba(255, 255, 0, 0.4); position: absolute; top: 0px; left: 0px; cursor: move; display: none; } /*小图片外面的大盒子*/ .small { position: relative; } </style><!--html结构--><body> <!--放大镜的整体--> <div class="box" id="box"> <!--小图的模块--> <div class="small"> <!--小图--> ![](images/small.png) <!--遮挡层--> <div class="mask"></div> </div> <!--大图的模块--> <div class="big"> <!--大图--> ![](images/big.jpg) </div> </div></body>
如果上面的骨架搭好了,下面就来分析以下放大镜的功能步骤:
1.鼠标移动的时候遮罩层中的框也跟着一起移动
2.在遮罩层移动的时候右边的大图也一起移动
3.遮罩层的移动和大图的移动是相反的,也是按照一定比例进行移动的
4.遮罩层是不能离开小图的框的
实现步骤
下面上步骤:
第一步 获取元素
因为这里面的元素都有可能用到
//获取最外面的div var box = document.getElementById("box"); //获取显示小图的div var small = box.children[0]; //获取小图中的遮挡的div var mask = small.children[1]; //获取显示大图的div var big = box.children[1]; //获取大div中的大图 var imgObj = big.children[0];
第二步 注册鼠标进入离开事件
在鼠标进入的时候,显示遮挡层和大图的图层
在鼠标离开的时候,隐藏遮挡层和大图的图层
//鼠标进入事件 box.onmouseover = function(){ mask.style.display = "block"; big.style.display = "block"; } //鼠标离开事件 box.onmouseout = function(){ mask.style.display = "none"; big.style.display = "none"; }
第三步 注册鼠标移动事件(确定遮罩层的定位)
给鼠标注册移动事件,在小图上移动的时候,遮罩层也跟着移动
要拿到可视区域的横纵坐标——clientX,clientY(不考虑兼容性)
设置遮罩层的left和top值
那么怎么通过鼠标的横纵坐标来设置遮罩层的left和top的值呢?
一张图来说明白:
mask.png
上图中的第三步,分析为什么会出现这样的问题
因为在鼠标进入的时候,在鼠标和小图的框中加了一个遮罩层,这个遮罩层让鼠标和小图的框进行了分离。所以当鼠标进行移动的时候,移动到了小图的框的外面,但是检测不到鼠标到底有没有离开小图的范围,所以遮罩层就跟着鼠标一起可以在可视区域中进行移动。
要想要进行范围的限定,就类似于一辆车在两堵墙之间的移动的最大距离一样。最大的移动距离无非就是小图框本身的宽度 - 遮罩层本身的宽度
下面上代码:
small.onmousemove = function (e) { var left = e.clientX - mask.offsetWidth / 2;//横坐标 var top = e.clientY - mask.offsetHeight / 2;//纵坐标 //设置遮挡层的left和top var x = left - 100;//margin var y = top - 100;//margin //为遮挡层设置范围 x=x<0?0:x;//如果横坐标小于0就设置为0 y=y<0?0:y;//如果纵坐标小于0就设置为0 //如果横坐标大于横向最大移动距离就设置为横向最大移动距离 x=x>small.offsetWidth-mask.offsetWidth?small.offsetWidth-mask.offsetWidth:x; //如果纵坐标大于纵向最大移动距离就设置为纵向最大移动距离 y=y>small.offsetHeight-mask.offsetHeight?small.offsetHeight-mask.offsetHeight:y; //设置mask的定位 mask.style.left = x + "px"; mask.style.top = y + "px"; };
最后一步 大图跟着鼠标移动
如果图片是有比例的,那么移动的时候也成比例就可以
如果图片是不成比例的,那么就要有一个普遍的算法
先来个原理图:
max.png
上图说的是宽度,其实高度可以以此类推。
由此可以得出:
**大图的移动距离 = 遮挡层的移动距离 * 大图的最大移动距离 / 遮挡层的最大移动距离 **
//大图的最大的移动距离 var imgMaxMove=imgObj.offsetWidth-big.offsetWidth; //遮挡层的最大的移动距离 var maskMaxMove=small.offsetWidth-mask.offsetWidth; //大图的横向移动的距离 var imgMoveLeft=x*imgMaxMove/maskMaxMove; //大图的纵向移动的距离 var imgMoveTop=y*imgMaxMove/maskMaxMove; //设置大图的left和top---移动的是margin-left和margin-top imgObj.style.marginLeft=-imgMoveLeft+"px"; imgObj.style.marginTop=-imgMoveTop+"px";
整理一下全部的js代码
<script> //获取元素 var box = document.getElementById("box"); //获取显示小图的div var small = box.children[0]; //获取小图中的遮挡的div var mask = small.children[1]; //获取显示大图的div var big = box.children[1]; //获取大div中的大图 var imgObj = big.children[0]; //显示遮挡层和显示大图的的层 //鼠标进入事件 box.onmouseover = function () { mask.style.display = "block"; big.style.display = "block"; }; //鼠标离开事件 box.onmouseout = function () { mask.style.display = "none"; big.style.display = "none"; }; //为小层注册鼠标移动的事件 small.onmousemove = function (e) { var left = e.clientX - mask.offsetWidth / 2;//横坐标 var top = e.clientY - mask.offsetHeight / 2;//纵坐标 //设置遮挡层的left和top var x = left - 100;//margin var y = top - 100;//margin x=x<0?0:x;//如果横坐标小于0就设置为0 y=y<0?0:y;//如果纵坐标小于0就设置为0 x=x>small.offsetWidth-mask.offsetWidth?small.offsetWidth-mask.offsetWidth:x; y=y>small.offsetHeight-mask.offsetHeight?small.offsetHeight-mask.offsetHeight:y; //设置遮挡层的定位值 mask.style.left = x + "px"; mask.style.top = y + "px"; //设置大图的移动距离 //大图的最大的移动距离 var imgMaxMove=imgObj.offsetWidth-big.offsetWidth; //遮挡层的最大的移动距离 var maskMaxMove=small.offsetWidth-mask.offsetWidth; //大图的横向移动的距离 var imgMoveLeft=x*imgMaxMove/maskMaxMove; //大图的纵向移动的距离 var imgMoveTop=y*imgMaxMove/maskMaxMove; //设置大图的left和top---移动的是margin-left和margin-top imgObj.style.marginLeft=-imgMoveLeft+"px"; imgObj.style.marginTop=-imgMoveTop+"px"; };</script>
放大镜进阶
最近要做的这个放大镜的功能需求是这样的
截取屏幕可视区域的图片然后进行放大。
为了可以看到动态的效果,所以我在上面加了随机的添加图标的功能,这样就可以看到实时的改变。
功能分析
设置按钮,点击按钮的时候显示遮挡层和大图框
设置添加图标按钮,点击在屏幕的随机位置生成一个图标
在文本框中输入文字
截取可视区域的屏幕并生成图片
将可视区域的图片进行放大放入到大图框中
鼠标移动的时候大图框中的也同样移动
效果图
tb.png
截屏插件 html2canvas
这个插件是让你整体截屏或者部分截屏的功能,截屏直接在浏览器上使用。这个插件是基于dom操作,但是不是百分百准确的,因为它并不是生成一个图片,而是基于页面上的信息截图。(说白了就是截下来一部分的信息然后直接绘制到另一个地方,并不是保存成了图片文件)
注意事项
这个插件有一定的限制
第一个就是文档不是很全,过于简单
第二个是其工作原理不是真正生成一个截图,而是遍历所有的dom元素构建页面,所以很多css属性无法使用
第三个是要求图像同源且没有代理,这个脚本不渲染flash\applet\iframe等内容
可用参数
这些参考API和中文的简书,写的很清楚
demo
先引入js文件
<script type="text/javascript" src="html2canvas.js"></script>
写html结构
<body id="bd"> <div id="view" style="background:url('./test.png') no-repeat;background-size: contain; width: 700px; height: 500px;"> <input type="button" value="截图" ="takeScreenshot()"> </div></body>
写js代码
<script type="text/javascript"> function takeScreenshot() { html2canvas(document.getElementById('bd'), { onrendered: function(canvas) { document.body.appendChild(canvas); } }); } </script>
下面还是回归正题,开始写放大镜的结构:
放大镜的html结构
<style> *{ margin:0; padding:0; } body{ background-image: url('./hua.jpg'); background-repeat: no-repeat; position: absolute; width: 100%; height: 100%; } #dv{ position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); display: none; } #btn{ position:absolute; top: 20px; left: 20px; } #mask{ width: 175px; height:175px; position: absolute; top: 0; left: 0; background-color: rgba(255,150,0,.5); cursor: move; } #look{ width: 200px; height:200px; position: absolute; top: 30px; right: 30px; border: 1px solid #f40; cursor: move; overflow: hidden; } #box{ width: 100%; height:100%; }</style><body id="bd"> hello world!! <input type="button" value="放大镜" id="btn"/> <div id="dv"><!--遮罩层--> <div id='box'></div><!--相当于小图--> <div id="mask"></div><!--跟着鼠标的层--> <div id="look"><!--显示的区域--> <div id="move"></div><!--移动的地方--> </div> </div></body>
使用jquery进行代码实现
第一步 获取元素
//获取id var btn = $('#btn'); var dv = $('#dv'); var box = $('#box'); var mask = $('#mask'); var look = $('#look'); var move = $('#move'); //定义图片的最大移动距离和跟着鼠标层的最大移动距离的变量 var imgMaxMove; var maskMaxMove;
第二步 注册按钮点击事件
点击按钮的时候显示遮罩层,同时也显示出来随着鼠标移动的框框,显示出来图片显示的位置。
显示遮罩层的时候截图
点击遮罩层的时候遮罩层消失
//给按钮注册点击事件 btn.on('click',function(){ //截屏功能 takeScreenshot(); //遮罩层显示 dv.css('display','block'); }); //点击屏幕的时候就消除 dv.on('click',function(){ $(this).css('display','none'); })
第三步 截屏功能
function takeScreenshot() { //根据body进行截屏 html2canvas(bd, { allowTaint: true, //允许跨域 taintTest: false, //渲染图片不用测试图片 //渲染图片 onrendered: function(canvas) { //将canvas标签转化为img标签 canvas.id = 'cv'; var dataUrl = canvas.toDataURL(); var newImg = document.createElement("img"); newImg.src = dataUrl; //设置图片的长和宽 newImg.width = 4 * bd.width(); newImg.height = 4* bd.height(); //把图片的长宽赋值给外面的盒子 move.width(newImg.width); move.height(newImg.height); //把图片加到盒子上 move.append(newImg); }, }); }
第四步 注册鼠标移动事件
不考虑兼容的问题,使用clientX
确定不要让跟着鼠标的小块出了屏幕,给它设定范围
比例这个东西啊,因为之前截屏的时候,长度就进行了扩大,所以比例也不好掌握,后面自己慢慢的调。。。总会差不多的。(给自己留的bug)
//给鼠标注册移动事件dv.on('mousemove',function(e){ var left = e.clientX - mask.width() / 2;//横坐标 var top = e.clientY - mask.height() / 2;//纵坐标 //设置遮挡层的left和top var x = left; var y = top; x=x<0?0:x;//如果横坐标小于0就设置为0 y=y<0?0:y;//如果纵坐标小于0就设置为0 x=x>box.width()-mask.width()?box.width()-mask.width():x; y=y>box.height()-mask.height()?box.height()-mask.height():y; //确定跟着鼠标动的小块的定位值 mask.offset({"left":x,"top":y}); //大图的最大的移动距离 imgMaxMove=newImg.width-look.width(); //遮挡层的最大的移动距离 maskMaxMove=box.width()-mask.width(); //大图的横向移动的距离 var imgMoveLeft=x*maskMaxMove/imgMaxMove*9; //大图的纵向移动的距离 var imgMoveTop=y*maskMaxMove/imgMaxMove*9; // 给大图设定移动位置 move.css("marginLeft",-imgMoveLeft); move.css("marginTop",-imgMoveTop); })
第五步 给屏幕上动态的添加元素
点击添加图标的时候,在屏幕上随机的添加一个图标
可以在文本框中输入文字信息
$('#jb').on('click',function(){ var img = document.createElement('img'); img.src = 'images/jb.jpg'; img.width = 100; img.height = 100; var leftRandom = Math.random()*1366; //随机生成横坐标 var topRandom = Math.random()*768; //随机生成纵坐标 img.style.position = 'absolute'; img.style.left = leftRandom + 'px'; img.style.top = topRandom + 'px'; $('#show').append(img); })
完整代码
css文件glass.css
*{ margin:0; padding:0; }body{ background-image: url('../images/hua.jpg'); background-repeat: no-repeat; position: absolute; width: 100%; height: 100%; }#dv{ position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); display: none; }#btn{ position:absolute; top: 100px; left: 100px; width: 100px; height:50px; background-color:rgba(0,0,0,.9); border-radius: 8px; line-height: 50px; text-align: center; color: #fff; cursor: pointer; font-size: 16px; }#mask{ width: 200px; height:200px; position: absolute; top: 0; left: 0; background-color: rgba(255,150,0,.5); cursor: move; }#look{ width: 300px; height:300px; position: absolute; bottom: 30px; right: 30px; border: 1px solid #f40; cursor: move; overflow: hidden; }#box{ width: 100%; height:100%; }#jb{ position:absolute; left: 100px; top:200px; width: 100px; height: 50px; background-color: rgba(0,0,0,.9); border-radius: 8px; line-height: 50px; text-align: center; color: #fff; cursor: pointer; font-size: 16px; }#txt{ position: absolute; left: 100px; top: 300px; width: 100px; height: 50px; }
index.html
<link rel="stylesheet" href="css/glass.css"/><script type="text/javascript" src="libs/jquery.min.js"></script><script type="text/javascript" src="libs/html2canvas.js"></script><script type="text/javascript" src="js/glass.js"></script><body id="bd">hello world!!<div id="jb">显示图标</div><input type="text" id="txt"/><div id="show"></div><div id='btn'>放大镜</div><div id="dv"><!--遮罩层--> <div id='box'></div><!--相当于小图--> <div id="mask"></div><!--跟着鼠标的区域--> <div id="look"> <div id="move"></div><!--移动的地方--> </div><!--显示的区域--></div><script> $(function(){ $('#dv').glass(); $('#jb').on('click',function(){ var img = document.createElement('img'); img.src = 'images/jb.jpg'; img.width = 100; img.height = 100; var leftRandom = Math.random()*1366; var topRandom = Math.random()*768; img.style.position = 'absolute'; img.style.left = leftRandom + 'px'; img.style.top = topRandom + 'px'; $('#show').append(img); }) });</script></body>
js文件 glass.js
(function($){ $.fn.glass = function(){ var mask = $('#mask'); var box = $('#box'); var look = $('#look'); var move = $('#move'); var btn = $('#btn'); var imgMaxMove; var maskMaxMove; var _this = $(this); //点击按钮 btn.on('click',function(){ move.html(''); takeScreenshot(); _this.css('display','block'); }); //点击屏幕的时候就消除 _this.on('click',function(){ _this.css('display','none'); }) //获取屏幕截图 function takeScreenshot() { alert('1'); html2canvas($('#bd'), { allowTaint: true, taintTest: false, onrendered: function(canvas) { canvas.id = 'cv'; var dataUrl = canvas.toDataURL(); var newImg = document.createElement("img"); newImg.src = dataUrl; newImg.width = 4 * $('#bd').width(); newImg.height = 4* $('#bd').height(); move.width(newImg.width); move.height(newImg.height); move.append(newImg); _this.on('mousemove',function(e){ var left = e.clientX - mask.width() / 2;//横坐标 var top = e.clientY - mask.height() / 2;//纵坐标 //console.log(mask.width()); //设置遮挡层的left和top var x = left;//margin var y = top;//margin x=x<0?0:x;//如果横坐标小于0就设置为0 y=y<0?0:y;//如果纵坐标小于0就设置为0 x=x>box.width()-mask.width()?box.width()-mask.width():x; y=y>box.height()-mask.height()?box.height()-mask.height():y; mask.offset({"left":x,"top":y}); //大图的最大的移动距离 imgMaxMove=newImg.width-look.width(); console.log(imgMaxMove); //遮挡层的最大的移动距离 maskMaxMove=box.width()-mask.width(); console.log(maskMaxMove); //大图的横向移动的距离 var imgMoveLeft=x*maskMaxMove/imgMaxMove*9; //大图的纵向移动的距离 var imgMoveTop=y*maskMaxMove/imgMaxMove*9; move.css("marginLeft",-imgMoveLeft); move.css("marginTop",-imgMoveTop); }) }, }); } } })(jQuery);
补充
关于图片的比例问题
也可以这样做:
大图的宽 / 小图的宽 = 大图的移动距离 / 小图的移动距离
这样就将id = move的标签进行设置
css:
#move{ position:absolute; top:0; left: 0; }
js:
x = newImg.width / $('#bd').width() * x / 2; y = newImg.width / $('#bd').width() * y / 2; $('#move').css('left',-x); $('#move').css('top',-y);
还是那句话,比例自己调正。。。
作者:顽皮的雪狐七七
链接:https://www.jianshu.com/p/662f77e95b63