AngularJS 仿微信图片手势缩放的实例


Posted in Javascript onSeptember 28, 2017

AngularJS 仿微信图片手势缩放的实例

前言:

AngularJS 仿微信图片手势缩放的实例

最近,公司做一个混合应用项目,涉及到一个图片缩放功能,类似微信那样支持touch事件。

亲测,实现方案很不错,所以放出来,和大家分享一下,希望有人能用得到。

核心思想就是用到了CSS3的transform属性, 不多说,我们看代码:

'use strict';

/**
 * @ngInject
 */
module.exports = function () {
  var _directive = {
    restrict : 'A',
    scope  : false,
    link   : _link
  };

  function _link(scope, element, attrs) {
    var elWidth, elHeight;

    // mode : 'pinch' or 'swipe'
    var mode = '';

    // distance between two touche points (mode : 'pinch')
    var distance = 0;
    var initialDistance = 0;

    // image scaling
    var scale = 1;
    var relativeScale = 1;
    var initialScale = 1;
    var maxScale = parseInt(attrs.maxScale, 10);
    if (isNaN(maxScale) || maxScale <= 1) {
      maxScale = 3;
    }

    // position of the upper left corner of the element
    var positionX = 0;
    var positionY = 0;

    var initialPositionX = 0;
    var initialPositionY = 0;

    // central origin (mode : 'pinch')
    var originX = 0;
    var originY = 0;

    // start coordinate and amount of movement (mode : 'swipe')
    var startX = 0;
    var startY = 0;
    var moveX = 0;
    var moveY = 0;

    var image = new Image();
    image.onload = function() {
      elWidth = element[0].clientWidth;
      elHeight = element[0].clientHeight;

      element.css({
        '-webkit-transform-origin' : '0 0',
        'transform-origin'     : '0 0'
      });

      element.on('touchstart', touchstartHandler);
      element.on('touchmove', touchmoveHandler);
      element.on('touchend', touchendHandler);
    };

    if (attrs.ngSrc) {
      image.src = attrs.ngSrc;
    } else {
      image.src = attrs.src;
    }

    /**
     * @param {object} evt
     */
    function touchstartHandler(evt) {
      var touches = evt.originalEvent ? evt.originalEvent.touches : evt.touches;

      startX = touches[0].clientX;
      startY = touches[0].clientY;
      initialPositionX = positionX;
      initialPositionY = positionY;
      moveX = 0;
      moveY = 0;
    }

    /**
     * @param {object} evt
     */
    function touchmoveHandler(evt) {
      var touches = evt.originalEvent ? evt.originalEvent.touches : evt.touches;

      if (mode === '') {
        if (touches.length === 1 && scale > 1) {

          mode = 'swipe';

        } else if (touches.length === 2) {

          mode = 'pinch';

          initialScale = scale;
          initialDistance = getDistance(touches);
          originX = touches[0].clientX -
            parseInt((touches[0].clientX - touches[1].clientX) / 2, 10) -
            element[0].offsetLeft - initialPositionX;
          originY = touches[0].clientY -
            parseInt((touches[0].clientY - touches[1].clientY) / 2, 10) -
            element[0].offsetTop - initialPositionY;

        }
      }

      if (mode === 'swipe') {
        evt.preventDefault();

        moveX = touches[0].clientX - startX;
        moveY = touches[0].clientY - startY;

        positionX = initialPositionX + moveX;
        positionY = initialPositionY + moveY;

        transformElement();

      } else if (mode === 'pinch') {
        evt.preventDefault();

        distance = getDistance(touches);
        relativeScale = distance / initialDistance;
        scale = relativeScale * initialScale;

        positionX = originX * (1 - relativeScale) + initialPositionX + moveX;
        positionY = originY * (1 - relativeScale) + initialPositionY + moveY;

        transformElement();

      }
    }

    /**
     * @param {object} evt
     */
    function touchendHandler(evt) {
      var touches = evt.originalEvent ? evt.originalEvent.touches : evt.touches;

      if (mode === '' || touches.length > 0) {
        return;
      }

      if (scale < 1) {

        scale = 1;
        positionX = 0;
        positionY = 0;

      } else if (scale > maxScale) {

        scale = maxScale;
        relativeScale = scale / initialScale;
        positionX = originX * (1 - relativeScale) + initialPositionX + moveX;
        positionY = originY * (1 - relativeScale) + initialPositionY + moveY;

      } else {

        if (positionX > 0) {
          positionX = 0;
        } else if (positionX < elWidth * (1 - scale)) {
          positionX = elWidth * (1 - scale);
        }
        if (positionY > 0) {
          positionY = 0;
        } else if (positionY < elHeight * (1 - scale)) {
          positionY = elHeight * (1 - scale);
        }

      }

      transformElement(0.1);
      mode = '';
    }

    /**
     * @param {Array} touches
     * @return {number}
     */
    function getDistance(touches) {
      var d = Math.sqrt(Math.pow(touches[0].clientX - touches[1].clientX, 2) +
        Math.pow(touches[0].clientY - touches[1].clientY, 2));
      return parseInt(d, 10);
    }

    /**
     * @param {number} [duration]
     */
    function transformElement(duration) {
      var transition = duration ? 'all cubic-bezier(0,0,.5,1) ' + duration + 's' : '';
      var matrixArray = [scale, 0, 0, scale, positionX, positionY];
      var matrix   = 'matrix(' + matrixArray.join(',') + ')';

      element.css({
        '-webkit-transition' : transition,
        transition      : transition,
        '-webkit-transform' : matrix + ' translate3d(0,0,0)',
        transform      : matrix
      });
    }
  }

  return _directive;
};

上面代码中我们新建了一个directive,方便多个地方重用。

当我们建立好directive时候,该如何使用呢?

<img style="width:100%;" src="assets/images/floorplan.jpeg" ng-pinch-zoom>

我们只需要在img文件上设定一个属性即可,是不是很简单呢?

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

Javascript 相关文章推荐
javascript 写类方式之八
Jul 05 Javascript
jqeury eval将字符串转换json的方法
Jan 20 Javascript
jQuery插件windowScroll实现单屏滚动特效
Jul 14 Javascript
JQuery解析XML数据的几个简单实例
May 18 Javascript
JS组件Bootstrap Table使用实例分享
May 30 Javascript
带你快速理解javascript中的事件模型
Aug 14 Javascript
JS实现简易换图时钟功能分析
Jan 04 Javascript
JS中利用FileReader实现上传图片前本地预览功能
Mar 02 Javascript
layer的prompt弹出框,点击回车,触发确定事件的方法
Sep 06 Javascript
卸载vue2.0并升级vue_cli3.0的实例讲解
Feb 16 Javascript
解决在Vue中使用axios POST请求变成OPTIONS的问题
Aug 14 Javascript
Javascript文本框脚本实现方法解析
Oct 30 Javascript
AngularJS路由删除#符号解决的办法
Sep 28 #Javascript
深入理解React高阶组件
Sep 28 #Javascript
基于webpack 实用配置方法总结
Sep 28 #Javascript
XMLHttpRequest对象_Ajax异步请求重点(推荐)
Sep 28 #Javascript
JQuery 选择器、DOM节点操作练习实例
Sep 28 #jQuery
浅谈JavaScript find 方法不支持IE的问题
Sep 28 #Javascript
VueJS事件处理器v-on的使用方法
Sep 27 #Javascript
You might like
PHP中的流(streams)浅析
2015/07/02 PHP
关于Laravel参数验证的一些疑与惑
2019/11/19 PHP
JavaScript限定复选框的选择个数示例代码
2013/08/25 Javascript
枚举的实现求得1-1000所有出现1的数字并计算出现1的个数
2013/09/10 Javascript
jQuery实现自动与手动切换的滚动新闻特效代码分享
2015/08/27 Javascript
使用jQuery判断Div是否在可视区域的方法 判断div是否可见
2016/02/17 Javascript
Bootstrap每天必学之折叠(Collapse)插件
2016/04/25 Javascript
js正则表达式注册页面表单验证
2016/10/11 Javascript
很棒的一组js图片轮播特效
2017/01/12 Javascript
原生js实现随机点名
2020/07/05 Javascript
js实现带积分弹球小游戏
2020/07/21 Javascript
[04:52]2015国际邀请赛LGD战队晋级之路
2015/08/14 DOTA
[50:50]完美世界DOTA2联赛PWL S3 INK ICE vs DLG 第一场 12.20
2020/12/23 DOTA
Python虚拟环境项目实例
2017/11/20 Python
python实现媒体播放器功能
2018/02/11 Python
Python高斯消除矩阵
2019/01/02 Python
Django组件之cookie与session的使用方法
2019/01/10 Python
Django自定义模板过滤器和标签的实现方法
2019/08/21 Python
Django 导出项目依赖库到 requirements.txt过程解析
2019/08/23 Python
在vscode中配置python环境过程解析
2019/09/28 Python
Django框架反向解析操作详解
2019/11/28 Python
Python pip install如何修改默认下载路径
2020/04/29 Python
解决python中0x80072ee2错误的方法
2020/07/19 Python
python的launcher用法知识点总结
2020/08/07 Python
纯CSS3发光分享按钮的实现教程
2014/09/06 HTML / CSS
html5 拖拽及用 js 实现拖拽功能的示例代码
2020/10/23 HTML / CSS
Footshop法国:购买运动鞋
2020/01/19 全球购物
当当网软件测试笔试题
2015/11/24 面试题
应聘教师自荐信
2013/10/12 职场文书
生日寿宴答谢词
2014/01/19 职场文书
2014升学宴答谢词
2014/01/26 职场文书
公务员政审单位鉴定材料
2014/05/16 职场文书
投标服务承诺书
2014/05/28 职场文书
2014年四风个人对照检查及整改措施
2014/10/28 职场文书
2015年护理工作总结范文
2015/04/03 职场文书
python之json文件转xml文件案例讲解
2021/08/07 Python