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 相关文章推荐
{}与function(){}选用空对象{}来存放keyValue
May 23 Javascript
JS 控件事件小结
Oct 31 Javascript
JQueryiframe页面操作父页面中的元素与方法(实例讲解)
Nov 19 Javascript
JavaScript结合AJAX_stream实现流式显示
Jan 08 Javascript
一波JavaScript日期判断脚本分享
Mar 06 Javascript
AngularJS入门教程之表格实例详解
Jul 27 Javascript
layer弹出层中H5播放器全屏出错的解决方法
Feb 21 Javascript
JSONP跨域请求
Mar 02 Javascript
详解基于vue-cli配置移动端自适应
Jan 13 Javascript
node.js博客项目开发手记
Mar 16 Javascript
在vue中使用jsx语法的使用方法
Sep 30 Javascript
微信小程序实现多选框全选与反全选及购物车中删除选中的商品功能
Dec 17 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懒人函数 自动添加数据
2011/06/28 PHP
Yii框架实现图片上传的方法详解
2017/05/20 PHP
Laravel如何自定义command命令浅析
2019/03/23 PHP
PHP中常用的三种设计模式详解【单例模式、工厂模式、观察者模式】
2019/06/14 PHP
jquery鼠标滑过提示title具体实现代码
2013/08/06 Javascript
jquery获得keycode的示例代码
2013/12/30 Javascript
JavaScript中变量声明有var和没var的区别示例介绍
2014/09/15 Javascript
JS实现超简单的仿QQ折叠菜单效果
2015/09/21 Javascript
JS+HTML5手机开发之滚动和惯性缓动实现方法分析
2016/06/12 Javascript
jquery的checkbox,radio,select等方法小结
2016/08/30 Javascript
详解开发react应用最好用的脚手架 create-react-app
2018/04/24 Javascript
LayUi中接口传数据成功,表格不显示数据的解决方法
2018/08/19 Javascript
vue 中 命名视图的用法实例详解
2019/08/14 Javascript
解决layui轮播图有数据不显示的情况
2019/09/16 Javascript
vue实现数字滚动效果
2020/06/29 Javascript
vue 中this.$set 动态绑定数据的案例讲解
2021/01/29 Vue.js
利用Python和OpenCV库将URL转换为OpenCV格式的方法
2015/03/27 Python
python魔法方法-自定义序列详解
2016/07/21 Python
Python中列表list以及list与数组array的相互转换实现方法
2017/09/22 Python
python的exec、eval使用分析
2017/12/11 Python
Python分析彩票记录并预测中奖号码过程详解
2019/07/09 Python
基于YUV 数据格式详解及python实现方式
2019/12/09 Python
python中sklearn的pipeline模块实例详解
2020/05/21 Python
Python filter过滤器原理及实例应用
2020/08/18 Python
如何用Python绘制3D柱形图
2020/09/16 Python
Django自带的用户验证系统实现
2020/12/18 Python
KIKO比利时官网:意大利彩妆品牌
2017/07/23 全球购物
Holland & Barrett爱尔兰:英国领先的健康零售商
2019/03/31 全球购物
公司总经理工作职责管理办法
2014/02/28 职场文书
空中乘务员岗位职责
2014/03/08 职场文书
总经理工作职责范文
2014/03/14 职场文书
护士辞职信怎么写
2015/02/27 职场文书
刑事撤诉申请书
2015/05/18 职场文书
辣妈辣妹观后感
2015/06/10 职场文书
教师岗位说明书
2015/09/30 职场文书
mysql 获取时间方式
2022/03/20 MySQL