js实现移动端图片预览:手势缩放, 手势拖动,双击放大...-阿里云开发者社区

开发者社区> 杰克.陈> 正文

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

简介: 原文:js实现移动端图片预览:手势缩放, 手势拖动,双击放大... 前言本文将介绍如何通过js实现移动端图片预览,包括图片的 预览模式,手势缩放,手势拖动,双击放大等基本功能; 扫码查看示例效果: 代码地址http://pangyongsheng.github.io/imgPreview/ 一、功能介绍   图片预览主要有以下几个功能点组成: 监听图片点击事件,进入图片预览模式 自定义手势事件, (双指缩放,滑动,双击。
+关注继续查看
原文:js实现移动端图片预览:手势缩放, 手势拖动,双击放大...

前言
本文将介绍如何通过js实现移动端图片预览,包括图片的 预览模式,手势缩放,手势拖动,双击放大等基本功能;

扫码查看示例效果:

代码地址http://pangyongsheng.github.io/imgPreview/

一、功能介绍

  图片预览主要有以下几个功能点组成:

  • 监听图片点击事件,进入图片预览模式
  • 自定义手势事件, (双指缩放,滑动,双击。。。)
  • 监听图片手势事件,通过 transform-matrix 实现图片的各种变换;

 

二、实现方法

1、图片预览模式

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

 //点击图片进入预览
    var $Dom = document.querySelector(".preview");
    $Dom.onclick = function() {
        var temp = this.src;
        var objE = document.createElement("div");
        objE.innerHTML = '<div class="bgM" >' +
                '<img src="'+temp+'"  id="img_scan" class="img-custom-img2"/>' +
            '</div>';
        document.body.appendChild(objE.children[0]);
        //退出图片预览事件
        var $bg = document.querySelector(".bgM");
        $bg.onclick = function() {
            var dm = document.querySelector(".bgM");
            document.body.removeChild(dm);
        }
        //阻止事件冒泡
        var $img = document.querySelector(".img-custom-img2");
        $img.onclick = function(event{
           event.stopPropagation();
        }
    }

css样式参考

.bgM{
    width100%;
    height100%;
    position: absolute;
    top0;left0;right0;bottom0;
    z-index1000;
    background-colorrgba(0,0,0,0.85);
    overflow: hidden;
}
.bgM img{
    width100%;
    max-height:100%;
    position: absolute;
    top0;left0;right0;bottom0;
    z-index1001;
    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事件;

参考代码:

    var isTouch = false;
    var isDoubleTouch = false//是否为多触点   
    var start = []; //存放触点坐标
    var now, delta; //当前时间,两次触发事件时间差
    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");
    //监听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) { //双击事件
                doubleTouch.position = [e.touches[0].pageX - e.target.offsetLeft, e.touches[0].pageY - e.target.offsetTop];
                e.target.dispatchEvent(doubleTouch);
            } else { //滑动事件
                isTouch = true;
            }
        }
    }, false);
    //监听touchmove事件
    document.addEventListener('touchmove'function(e{
        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方向
缩放 a d
移动 e f

(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);

    var tMatrix = [100100]; //x缩放,无,无,y缩放,x平移,y平移
    var originLast, maxSwipeLeft, maxSwipeRight, maxSwipeTop, maxSwipeBottom; //上下左右可拖动距离

(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 < 3 ? tMatrix[0] + sc - 1 : tMatrix[0];
     tMatrix[3] = tMatrix[3] + sc - 1 > 0.5 && tMatrix[3] + sc - 1 < 3 ? tMatrix[3] + sc - 1 : tMatrix[3];
     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 < tMatrix[4]) return;
     if (event.distance[0] < 0 && maxSwipeRight < -tMatrix[4]) return;
     if (event.distance[1] > 0 && maxSwipeTop < tMatrix[5]) return;
     if (event.distance[1] < 0 && maxSwipeBottom < -tMatrix[5]) return;

     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;

至此一个图片预览的基本功能即可实现 ,  也可以通过手势做旋转及上下一张的功能;

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
silverlight:DeepZoom版的图片局部放大效果
先上演示地址: http://images.24city.com/jimmy/DeepZoom/  步骤:1.先启动PhotoShop,利用自动等分切片功能把图片等分成若干小图片,并导出,参考下图: 2.
699 0
React.js 入门与实战之开发适配PC端及移动端新闻头条平台课程上线了
作者:Parry 出处:http://www.cnblogs.com/parry/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
860 0
ArchSummit2016移动端架构相关技术一些思考
  有幸参加ArchSummit2016全球架构师峰会,作为一名移动端开发人员,比较关注移动端架构相关主题,可惜的是此次会议关于移动端主题太少了,很多都停留在技术表面泛泛而谈,不够深入。除了移动端主题外,还关注了一下新技术方向主题:微服务架构,移动直播,区块链。
3008 0
巧用CSS3滤镜实现图片不同渲染效果
本站在首页文章封面图从无色转变为有色,以及页面切换、发布留言等信息提示的背景模糊都利用到了css3的filter滤镜。 CSS3 Filter是W3C CSS filter Effect 1.0中定义的滤镜,一个使用CSS来改变图片和HTML的模糊度、亮度、对比度、饱和度等等效果的过滤器。
1022 0
手风琴图片和钢琴导航栏JQ滑动特效
手风琴JQ滑动特效 1.效果预览: 556.gif 2.相关代码: Title * { margin: 0; padding: 0; } .
900 0
这款神秘的移动端OCR引擎,如何做到“所见即所得”?
随着深度学习,尤其是CNN和RNN等技术的飞速发展,文字识别技术(OCR)近几年得到了迅速的提升。
3353 0
小程序实现图片上传,预览以及图片base64位处理
小程序实现图片上传,预览以及图片base64位处理
30 0
+关注
杰克.陈
一个安静的程序猿~
9798
文章
2
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载