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 相关文章推荐
JS生成不重复随机数组的函数代码
Jun 10 Javascript
javascript与jquery中的this关键字用法实例分析
Dec 24 Javascript
Jquery对新插入的节点 绑定Click事件失效的解决方法
Jun 02 Javascript
D3.js实现折线图的方法详解
Sep 21 Javascript
js addDqmForPP给标签内属性值加上双引号的函数
Dec 24 Javascript
BootStrap 弹出层代码
Feb 09 Javascript
JS实现弹出下载对话框及常见文件类型的下载
Jul 13 Javascript
vue采用EventBus实现跨组件通信及注意事项小结
Jun 14 Javascript
JS打印彩色菱形的实例代码
Aug 15 Javascript
记一次用vue做的活动页的方法步骤
Apr 11 Javascript
关于Vue源码vm.$watch()内部原理详解
Apr 26 Javascript
react quill中图片上传由默认转成base64改成上传到服务器的方法
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
图书管理程序(一)
2006/10/09 PHP
windows下配置php5.5开发环境及开发扩展
2014/12/25 PHP
使用 PHPStorm 开发 Laravel
2015/03/24 PHP
PHP命名空间namespace的定义方法详解
2017/03/29 PHP
PHP实现RSA签名生成订单功能【支付宝示例】
2017/06/06 PHP
thinkphp5.1 文件引入路径问题及注意事项
2018/06/13 PHP
HTTP头隐藏PHP版本号实现过程解析
2020/12/09 PHP
jquery 实现两级导航菜单附效果图
2014/03/07 Javascript
jQuery中closest和parents的区别分析
2015/05/07 Javascript
更高效的使用JQuery 这里总结了8个小技巧
2016/04/13 Javascript
JQuery.validationEngine表单验证插件(推荐)
2016/12/10 Javascript
详解nodejs 文本操作模块-fs模块(三)
2016/12/22 NodeJs
vue 实现 tomato timer(蕃茄钟)实例讲解
2017/07/24 Javascript
原生JS实现 MUI导航栏透明渐变效果
2017/11/07 Javascript
使用nodejs分离html文件里的js和css详解
2019/04/12 NodeJs
Layui 解决表格异步调用后台分页的问题
2019/10/26 Javascript
VUE使用axios调用后台API接口的方法
2020/08/03 Javascript
Python、PyCharm安装及使用方法(Mac版)详解
2017/04/28 Python
python与C互相调用的方法详解
2017/07/14 Python
python中使用%与.format格式化文本方法解析
2017/12/27 Python
Python 安装第三方库 pip install 安装慢安装不上的解决办法
2019/06/18 Python
python实现tail -f 功能
2020/01/17 Python
python中urllib.request和requests的使用及区别详解
2020/05/05 Python
Django框架实现在线考试系统的示例代码
2020/11/30 Python
JACK & JONES英国官方网站:欧洲领先的男装生产商
2017/09/27 全球购物
国际书籍零售商:Wordery
2017/11/01 全球购物
阿迪达斯墨西哥官方网站:adidas墨西哥
2017/11/03 全球购物
华为C++笔试题
2014/08/05 面试题
省三好学生申请材料
2014/01/22 职场文书
周年庆典邀请函范文
2014/01/24 职场文书
董事长秘书职责
2014/01/31 职场文书
运动会入场式解说词
2014/02/18 职场文书
经济贸易专业自荐信
2014/06/11 职场文书
新文化运动的口号
2014/06/21 职场文书
因工资原因离职的辞职信范文
2015/05/12 职场文书
初中英语教学反思范文
2016/02/15 职场文书