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 QueryString解析类代码
Jan 17 Javascript
json属性名为什么要双引号(个人猜测)
Jul 31 Javascript
jQuery网页选项卡插件rTabs用法实例分析
Aug 26 Javascript
js计算文本框输入的字符数
Oct 23 Javascript
基于javascript实现彩票随机数生成(升级版)
Apr 17 Javascript
JQuery Ajax WebService传递参数的简单实例
Nov 02 Javascript
JS实现的五级联动菜单效果完整实例
Feb 23 Javascript
js中DOM事件绑定分析
Mar 18 Javascript
vue中各种通信传值方式总结
Feb 14 Javascript
使用pm2部署node生产环境的方法步骤
Mar 09 Javascript
详解vue-cli3多页应用改造
Jun 04 Javascript
Node.js API详解之 net模块实例分析
May 18 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
在html文件中也可以执行php语句的方法
2015/04/09 PHP
PHP入门教程之表单与验证实例详解
2016/09/11 PHP
php面向对象基础详解【星际争霸游戏案例】
2020/01/23 PHP
PHP加MySQL消息队列深入理解
2021/02/27 PHP
JS实现图片放大镜效果的方法
2015/02/27 Javascript
angularjs学习笔记之三大模块(modal,controller,view)
2015/09/26 Javascript
js定义类的几种方法(推荐)
2016/06/08 Javascript
深入理解jQuery layui分页控件的使用
2016/08/17 Javascript
javascript和jQuery中的AJAX技术详解【包含AJAX各种跨域技术】
2016/12/15 Javascript
原生javascript实现分页效果
2017/04/21 Javascript
浅谈Vue组件及组件的注册方法
2018/08/24 Javascript
Vue SPA 初次进入加载动画实现代码
2019/11/14 Javascript
谈谈node.js中的模块系统
2020/09/01 Javascript
Python中__new__与__init__方法的区别详解
2015/05/04 Python
opencv python 图像去噪的实现方法
2018/08/31 Python
python multiprocessing多进程变量共享与加锁的实现
2019/10/02 Python
keras输出预测值和真实值方式
2020/06/27 Python
Python批量获取并保存手机号归属地和运营商的示例
2020/10/09 Python
新西兰珠宝品牌:Michael Hill
2017/09/16 全球购物
Bibloo荷兰:女士、男士和儿童的服装、鞋子和配饰
2019/02/25 全球购物
新西兰第一的行李箱网站:luggage.co.nz
2019/07/22 全球购物
与UNIX有关的几个名词
2015/09/17 面试题
厂长助理岗位职责
2013/12/27 职场文书
小学生暑假感言
2014/02/06 职场文书
创建学习型党组织实施方案
2014/03/29 职场文书
小学教师师德师风个人整改措施
2014/09/18 职场文书
网站出售协议书范文
2014/10/10 职场文书
离婚协议书怎样才有法律效力
2014/10/10 职场文书
2014年初一班主任工作总结
2014/11/08 职场文书
2014年督导工作总结
2014/11/19 职场文书
2014年财政所工作总结
2014/11/22 职场文书
2014年青年教师工作总结
2014/12/17 职场文书
2016父亲节感恩话语
2015/12/09 职场文书
团队拓展训练心得体会
2016/01/12 职场文书
入党转正申请书范文
2019/05/20 职场文书
Redis sentinel哨兵集群的实现步骤
2022/07/15 Redis