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 相关文章推荐
jquery load()在firefox(火狐)下显示不正常的解决方法
Apr 05 Javascript
Extjs优化(一)删除冗余代码提高运行速度
Apr 15 Javascript
ExtJS4如何自动生成控制grid的列显示、隐藏的checkbox
May 02 Javascript
JS控制表格实现一条光线流动分割行的方法
Mar 09 Javascript
JavaScript里 ==与===区别详解
Aug 16 Javascript
JS原型链 详解及示例代码
Sep 06 Javascript
KnockoutJS 3.X API 第四章之数据控制流component绑定
Oct 10 Javascript
js鼠标跟随运动效果
Mar 11 Javascript
JS模拟超市简易收银台小程序代码解析
Aug 18 Javascript
vue轻量级框架无法获取到vue对象解决方法
May 12 Javascript
JS 获取文件后缀,判断文件类型(比如是否为图片格式)
May 09 Javascript
Angular利用HTTP POST下载流文件的步骤记录
Jul 26 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
Zend Studio (eclipse)使用速度优化方法
2011/03/23 PHP
php curl模拟post请求小实例
2013/11/13 PHP
php使用curl存储cookie的示例
2014/03/31 PHP
Yii Framework框架获取分类下面的所有子类方法
2014/06/20 PHP
javascript生成img标签的3种实现方法(对象、方法、html)
2015/12/25 Javascript
JS实现隐藏同级元素后只显示JS文件内容的方法
2016/09/04 Javascript
AngularJS 模块化详解及实例代码
2016/09/14 Javascript
JS动态给对象添加属性和值的实现方法
2016/10/21 Javascript
JavaScript仿支付宝6位数字密码输入框
2016/12/29 Javascript
微信小程序开发之animation循环动画实现的让云朵飘效果
2017/07/14 Javascript
vue+springboot前后端分离实现单点登录跨域问题解决方法
2018/01/30 Javascript
vue-swiper的使用教程
2018/08/30 Javascript
一次Webpack配置文件的分离实战记录
2018/11/30 Javascript
Node.js Buffer模块功能及常用方法实例分析
2019/01/05 Javascript
vue prop属性传值与传引用示例
2019/11/13 Javascript
基于JavaScript的数据结构队列动画实现示例解析
2020/08/06 Javascript
[36:20]KG vs SECRET 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/19 DOTA
Python如何快速实现分布式任务
2017/07/06 Python
python+selenium实现163邮箱自动登陆的方法
2017/12/31 Python
简单的python协同过滤程序实例代码
2018/01/31 Python
基于Python实现的微信好友数据分析
2018/02/26 Python
Django页面数据的缓存与使用的具体方法
2019/04/23 Python
python增加图像对比度的方法
2019/07/12 Python
如何在Cloud Studio上执行Python代码?
2019/08/09 Python
python控制台实现tab补全和清屏的例子
2019/08/20 Python
基于Python+Appium实现京东双十一自动领金币功能
2019/10/31 Python
PyTorch 解决Dataset和Dataloader遇到的问题
2020/01/08 Python
Emma Bridgewater官网:英国餐具制造商
2019/11/24 全球购物
英国100%防污和防水的靴子:Muck Boot Company
2020/09/08 全球购物
日本AOKI官方商城:AOKI西装
2020/06/11 全球购物
财务部副经理岗位职责范本
2014/06/17 职场文书
先进个人事迹材料
2014/12/29 职场文书
运动会班级前导词
2015/07/20 职场文书
Nginx四层负载均衡的配置指南
2021/06/11 Servers
Apache Hudi 加速传统的批处理模式
2022/04/24 Servers
nginx lua 操作 mysql
2022/05/15 Servers