查看示例效果:

一、功能介绍

图片预览主要有以下几个功能点组成:监听图片点击事件,进入图片预览模式

自定义手势事件, (双指缩放,滑动,双击。。。)

监听图片手势事件,通过 transform-matrix 实现图片的各种变换;

二、实现方法

1、图片预览模式

图片预览即点击图片在页面中插入一个黑色全屏背景框并将图片居中显示。封装时,为了只对指定图片添加功能,可通过监听指定类名或添加某种属性的img标签监听;另外需在对背景框绑定点击事件,退出预览模式。一下是一个简单示例代码://点击图片进入预览

var $Dom = document.querySelector(".preview");

$Dom. = function() {

var temp = this.src;

var objE = document.createElement("div");

objE.innerHTML = '

' +

'' +

'

';

document.body.appendChild(objE.children[0]);

//退出图片预览事件

var $bg = document.querySelector(".bgM");

$bg. = function() {

var dm = document.querySelector(".bgM");

document.body.removeChild(dm);

}

//阻止事件冒泡

var $img = document.querySelector(".img-custom-img2");

$img. = function(event) {

event.stopPropagation();

}

}

css样式参考.bgM{

width: 100%;

height: 100%;

position: absolute;

top: 0;left: 0;right: 0;bottom: 0;

z-index: 1000;

background-color: rgba(0,0,0,0.85);

overflow: hidden;

}

.bgM img{

width: 100%;

max-height:100%;

position: absolute;

top: 0;left: 0;right: 0;bottom: 0;

z-index: 1001;

margin: auto;

}

2、自定义手势事件

这里通过监听移动端touch事件实现自定义双指缩放,单指滑动,双击事件,并通过事件属性传递相关参数,如缩放比例,滑动距离等,详细实现方式参考这篇博客:请参考此博文:https://www.cnblogs.com/pangys/p/9119845.html 这里只大概说明;当触发touch事件的时候,会生成一个TouchEvent对象,我们可通过其属性e.touches.length来判断是否多点触控,通过e.touches[index].pageX,e.touches[index].pageY获取去触点坐标,通过e.target获取dom节点;

这里为了方便,直接监听document事件然后对目标元素触发事件,实际也可以直接对img监听事件,然后分别处理;

(1)手势事件监听touchstart事件,若e.touches.length>=2,为双指事件,获取触点坐标(触点坐标-目标元素.offsetLeft/Top)计算两个点中点 添加到事件属性中,改变相关状态,触发gesturestart事件;

监听touchmove事件,若e.touches.length>=2,获当前取触点坐标和gesturestart坐标,计算出缩放比例及角度,触发gesturechange事件;

监听touchend事件,根据前面事件记录的状态触发结束gestureend事件;

(2)滑动事件监听touchstart事件,若e.touches.length<2,为单指事件,获取触点坐标(触点坐标-目标元素.offsetLeft/Top)添加到事件属性中,记录事件状态;

监听touchmove事件,若e.touches.length<2,获当前取触点坐标和上一步坐标,计算出移动距离添加到事件属性中,触发swipeMove事件;

(3)双击事件

监听touchstart事件,若e.touches.length<2,为单指事件,获取触点坐标(触点坐标-目标元素.offsetLeft/Top)添加到事件属性中,获取当前时间挫记录到相关变量中,计算本次时间戳与上次事件时间戳之差,若时间差范围在指定范围(0~250)则触发doubleTouch事件;

(4)单击事件

监听touchstart事件,使用延时器450ms触发单击事件,若在450ms无其他事件则触发单击事件

参考代码:var isTouch = false;

var isDoubleTouch = false; //是否为多触点

var start = []; //存放触点坐标

var now, delta; //当前时间,两次触发事件时间差

var timer = null; //计时器,触发单击事件

var startPosition, movePosition, endPosition; //滑动起点,移动,结束点坐标

//事件声明

var gesturestart = new CustomEvent('gesturestart');

var gesturechange = new CustomEvent('gesturechange');

var gestureend = new CustomEvent('gestureend');

var swipeMove = new CustomEvent('swipeMove');

var doubleTouch = new CustomEvent("doubleTouch");

var oneTouch = new CustomEvent("oneTouch");作者:pangyongsheng链接:https://juejin.im/post/5bcc528a6fb9a05d2f36e6c0来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

//监听touchstart事件

document.addEventListener('touchstart', function(e) {        if (e.touches.length >= 2) { //判断是否有两个点在屏幕上

isDoubleTouch = true;

start = e.touches; //得到第一组两个点

var screenMinPoint = getMidpoint(start[0], start[1]); //获取两个触点中心坐标

gesturestart.midPoint = [screenMinPoint[0] - e.target.offsetLeft, screenMinPoint[1] - e.target.offsetTop]; //获取中心点坐标相对目标元素坐标

e.target.dispatchEvent(gesturestart);

} else {

delta = Date.now() - now; //计算两次点击时间差

now = Date.now();

startPosition = [e.touches[0].pageX, e.touches[0].pageY];            if (delta > 0 && delta <= 250) { //双击事件

clearTimeout(timer);

doubleTouch.position = [e.touches[0].pageX - e.target.offsetLeft, e.touches[0].pageY - e.target.offsetTop];

e.target.dispatchEvent(doubleTouch);

} else { //滑动事件

timer = setTimeout(function(){

e.target.dispatchEvent(oneTouch);//单击事件

},450)

}

isTouch = true;

}

}, false);

//监听touchmove事件

document.addEventListener('touchmove', function(e) {

clearTimeout(timer);        if (e.touches.length >= 2 && isDoubleTouch) { //手势事件

var now = e.touches; //得到第二组两个点

var scale = getDistance(now[0], now[1]) / getDistance(start[0], start[1]); //得到缩放比例

var rotation = getAngle(now[0], now[1]) - getAngle(start[0], start[1]); //得到旋转角度差

gesturechange.scale = scale.toFixed(2);

gesturechange.rotation = rotation.toFixed(2);

e.target.dispatchEvent(gesturechange);

} else if (isTouch) {

movePosition = [e.touches[0].pageX, e.touches[0].pageY];

endPosition = movePosition;

movePosition = [movePosition[0] - startPosition[0], movePosition[1] - startPosition[1]];

startPosition = [e.touches[0].pageX, e.touches[0].pageY];

swipeMove.distance =[movePosition[0].toFixed(2) , movePosition[1].toFixed(2)];

e.target.dispatchEvent(swipeMove);

}

}, false);

//监听touchend事件

document.addEventListener('touchend', function(e) {        if (isDoubleTouch) {

isDoubleTouch = false;

gestureend.position = endPosition;

e.target.dispatchEvent(gestureend);

};

}, false);

/*

* 两点的距离

*/    function getDistance(p1, p2) {

var x = p2.pageX - p1.pageX,

y = p2.pageY - p1.pageY;        return Math.sqrt((x * x) + (y * y));

};

/*

* 两点的夹角

*/    function getAngle(p1, p2) {

var x = p1.pageX - p2.pageX,

y = p1.pageY - p2.pageY;        return Math.atan2(y, x) * 180 / Math.PI;

};

/*

* 获取中点

*/    function getMidpoint(p1, p2) {

var x = (p1.pageX + p2.pageX) / 2,

y = (p1.pageY + p2.pageY) / 2;        return [x, y];

}

三、图片的变换

对于图片的每次操作都需在上一次操作的基础上进行叠加,如果直接使用width,top,left或scale,translate等css样式需要每次都记录当前图片状态的全部参数,而且计算较多,这里考虑使用transform-matrix实现图片的基本变换,这样只需创建一个数组作为变换矩阵,每次操作直接在当前变换矩阵上修改相关参数即可实现图像的变换:transform-matrix :可配置[a,b,c,d,e,f]6个参数,如下图所示,x和y是初始的坐标,x’ 和y’则是通过矩阵变换后得到新的坐标。变换矩阵,对原先的坐标施加变换,就能得到新的坐标了。依据矩阵变换规则即可得到: x’=ax+cy+e y’=bx+dy+f。

变换x方向y方向缩放ad

移动ef

(1) 获取目标元素及相关参数,绑定事件var $imgs = document.querySelector("#img_scan");

var clientWidth = document.body.clientWidth; //窗口宽

var clientHeight = document.body.clientHeight; //窗口高

var imgWidth = parseInt(window.getComputedStyle($imgs).width); //图片宽

var imgHeight = parseInt(window.getComputedStyle($imgs).height); //图片高    $imgs.addEventListener('gesturestart', gesturef, false);    $imgs.addEventListener('gesturechange', gesturef, false);    $imgs.addEventListener('gestureend', gesturef, false);    $imgs.addEventListener('swipeMove', gesturef, false);    $imgs.addEventListener('doubleTouch', gesturef, false);    $imgs.addEventListener('oneTouch', gesturef, false);

var tMatrix = [1, 0, 0, 1, 0, 0]; //x缩放,无,无,y缩放,x平移,y平移

var originLast, maxSwipeLeft, maxSwipeRight, maxSwipeTop, maxSwipeBottom; //上下左右可拖动距离作者:pangyongsheng链接:https://juejin.im/post/5bcc528a6fb9a05d2f36e6c0来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

(2)监听 gesturestart 设置 变换中心case "gesturestart":

var x = event.midPoint[0];

var y = event.midPoint[1];

originLast = event.midPoint;

$imgs.style.transformOrigin = x + "px " + y + "px";

break;

(2)监听 gesturechange 进行缩放变换,这里设置了缩放范围为0.5 ~ 3;case "gesturechange":

var sc = parseFloat(event.scale);

tMatrix[0] = tMatrix[0] + sc - 1 > 0.5 && tMatrix[0] + sc - 1

tMatrix[3] = tMatrix[3] + sc - 1 > 0.5 && tMatrix[3] + sc - 1

var temp = tMatrix.join(",");

$imgs.style.transform = "matrix(" + temp + ")";

break;

(3)监听 gestureend 获取移动边界范围边界case "gestureend":

maxMove();

break;

可移动边界范围的计算

对于图片中的任意点可拖动范围都是相同的,那么以缩放中心点来计算,如下图所示,对于图片中的缩放中心点p,有缩放后距离边距的距离,可移动的范围均为 缩放后增加或减少的距离 - (缩放中心点距离图片边缘的距离),即 | 缩放比例 - 1 |  *  p点距离边缘的距离;

代码如下:function maxMove(){

//最大可拖动范围

var sca = tMatrix[0];

maxSwipeLeft = Math.abs(sca - 1) * originLast[0];

maxSwipeRight = Math.abs(sca - 1) * (imgWidth - originLast[0]);

maxSwipeTop = Math.abs(sca - 1) * originLast[1];

maxSwipeBottom = Math.abs(sca - 1) * (imgHeight - originLast[1]);

}

(4)监听 swipeMove 拖动图片,需考虑是否在可拖动范围if (!maxSwipeLeft || !maxSwipeRight || !maxSwipeTop || !maxSwipeBottom) return;

if (event.distance[0] > 0 && maxSwipeLeft

if (event.distance[0]

if (event.distance[1] > 0 && maxSwipeTop

if (event.distance[1]

tMatrix[4] = tMatrix[4] + parseInt(event.distance[0]);

tMatrix[5] = tMatrix[5] + parseInt(event.distance[1]);

var temp = tMatrix.join(",");

$imgs.style.transform = "matrix(" + temp + ")";

break;

(5)监听 doubleTouch 实现双击点缩放case "doubleTouch":

originLast = event.position;

$imgs.style.transformOrigin = event.position[0] + "px " + event.position[1] + "px";

tMatrix[0] = 2;

tMatrix[3] = 2;

var temp = tMatrix.join(",");

$imgs.style.transform = "matrix(" + temp + ")";

maxMove();

break;

(6)监听 oneTouch 实现退出预览case "oneTouch":

var $bg = document.querySelector(".bgM");

document.body.removeChild($bg);

break;

html5 双指缩放图片,js实现移动端图片预览:手势缩放, 手势拖动,双击放大......相关推荐

  1. html滑动验证图片,js实现移动端图片滑块验证功能

    之前写过一篇uniapp框架的滑块验证,今天抽个空用原生js实现这个功能,pc端暂时不做,因为pc端只要把touch事件改成mouse事件就能实现,这里就不再重复写了. (最新完美版本,js+canv ...

  2. js实现移动端图片预览:手势缩放, 手势拖动,双击放大...

    原文:js实现移动端图片预览:手势缩放, 手势拖动,双击放大... 前言 本文将介绍如何通过js实现移动端图片预览,包括图片的 预览模式,手势缩放,手势拖动,双击放大等基本功能: 扫码查看示例效果: ...

  3. pdfh5.js 基于pdf.js和jQuery,web/h5/移动端PDF预览手势缩放插件。

    pdfh5.js 基于pdf.js和jQuery,web/h5/移动端PDF预览手势缩放插件. 注意:本地绝对路径地址不能加载,跨域问题用代理或者服务端解决. svg模式渲染存在缺陷,只能渲染普通pd ...

  4. 手机端html5展示pdf,pdf.js移动端展示预览打开pdf-pdfh5.js

    pdf.js移动端展示预览打开pdf-pdfh5.js 本插件基于pdf.js和jQuery,可手势捏合缩放,支持懒加载(即分段加载). 2019.07.18更新:增加npm install pdfh ...

  5. html5图片自动翻转,纯js实现360度旋转预览图片特效

    这是一款纯js实现360度旋转预览图片特效.该js特效仅使用120行代码,即可实现通过滑块.或鼠标手动360度旋转图片,以及自动360度旋转图片的效果. 使用方法 HTML结构 import Roll ...

  6. js 获取图片url的Blob值并预览

    js 获取图片url的Blob值并预览 1)使用 XMLHttpRequest 对象获取图片url的Blob值 参考:https://www.cnblogs.com/tujia/p/6483255.h ...

  7. firefox js服务器上怎么显示图片的绝对路径,js兼容火狐显示上传图片预览效果的方法...

    本文实例讲述了js兼容火狐显示上传图片预览效果的方法.分享给大家供大家参考.具体实现方法如下: Image preview example div {width:100px;height:100px; ...

  8. vue移动端文件预览

    vue移动端文件预览 前言: 整体思路: 具体实现: 一.外壳(vViews.vue): 二.文件预览: 1.图片预览: 2.pdf文件预览: 3.docx文件预览: 4.excel表格预览(xls. ...

  9. 一个使用js做的一个PDF预览PDF标注(在线批注)工具

    一个使用js做的一个PDF预览&PDF标注工具 核心主要使用pdf.js以及操作canvas 目前支持web端,windows端,mac端,可npm包引入项目 目前支持的功能有大文件预览.缩略 ...

最新文章

  1. RabbitMQ指南(中)
  2. 百度搜索,你画了好大一张饼,你还打算欺骗多少人呢?有图为证
  3. android 使用compareTo比较大小
  4. 工作原理是什么_磁翻板液位计工作原理是什么?
  5. PAT 乙级 1001. 害死人不偿命的(3n+1)猜想 (15) Java版
  6. webpack教程——css的加载
  7. dbca:Exception in thread main java.lang.UnsatisfiedLinkError: get
  8. Mybatis参数Integer类型值为0 源码处理
  9. docker 镜像备份magento 2.2.3
  10. python全套视频免费教程_《python免费视频教程33》 请问谁有靠谱的Python全套视频教程,求推荐分享...
  11. 读林锐《软件工程思想》------讲述软件开发和做程序员的道理--语录
  12. 如何解决读写txt文件中文乱码问题
  13. stm32f107使用外部16MHz晶振
  14. 使用Python打印爱心图案
  15. Python selenium —— 将你的自动化脚本打包成一个exe
  16. TCP:利用Socket编程技术实现客户端向服务端上传一个图片。
  17. http://bigwhite.blogbus.com/logs/1347304.html
  18. 如何判断一个动作是深蹲还是硬拉?
  19. 随元素而来,随元素而去,变一变样式,深藏功与名——论伪元素
  20. 交通灯管理系统分析(张孝祥老师)

热门文章

  1. 在win10中,映射共享文件时,输入网络凭据总是报错
  2. html5中英文间自动空格,如何快速在文章中英文数字间自动添加空格
  3. AI-大型软件研发效能倍增的银弹
  4. react起步,冲冲冲
  5. I2P和TOR 有趣网络精灵
  6. MySQL报错1406_mysql报错:1406, Data too long for column
  7. Data truncation: Data too long for column 'xxx' at row 1
  8. 毕业论文查重软件如何论文查重?
  9. android 熄屏 socket断开,Android 休眠导致的问题Socket断开
  10. win10以太网dns服务器未响应,Win10系统dns服务器未响应如何修复?