• 移动端图片缩放插件Pinchzoom.js


    1.哪里找?

        https://github.com/jias/pinchzoom
        https://www.jq22.com/jquery-info9795  

    2.有什么作用?

     提供了多点触摸手势,可以对任何 DOM 元素进行缩放和拖动 ,例如:  双击图片放大 , 双指放大缩小等

    3.如何做?

    示例:

    html

    <div class="page">
        <div class="pinch-zoom-container" style="overflow: hidden; position: relative; height: 333px;">
            <div class="pinch-zoom" style="transform-origin: 0% 0%; position: absolute; transform: scale(1, 1) translate(0px, 0px);">
                <img src="https://img.hbhcdn.com/zhuanti/20919/pazzle02.jpg" alt=""> 
            </div>
        </div>
    </div>

    css   1rem = 50px

    body, html {
        text-align:center;
        color:#fff
    }
    body {
        background-color:#333;
        font-family:Georgia
    }
    .page{
         width: 6.66rem;
         height:6.66rem;
         margin:5rem auto;
    }
    .pinch-zoom-container{
        overflow: inherit !important;
    }
    .pinch-zoom,
    .pinch-zoom img{
         width: 6.66rem;
         height:6.66rem;
        -webkit-user-drag: none;
        -moz-user-drag: none;
        -ms-user-drag: none;
        user-drag: none;
    }

    js

    $('div.pinch-zoom').each(function () {
            new RTP.PinchZoom($(this), {});
        });

    由源码可知 相关配置参数

    new RTP.PinchZoom($(this), {
        tapZoomFactor:     // 双击可缩放到的缩放因子。(默认值2)
        zoomOutFactor:     // 当缩放因子低于配置值时,调整为原始大小。(默认值1.3)
        animationDuration: // 动画持续时间(毫秒)。(默认300)
        maxZoom:          //  最大缩放因子。(默认值4)
        minZoom:          //  最小缩放因子。(默认值为0.5)
    });

    源码

    (function () {
        'use strict';
        var definePinchZoom = function ($) {
            var PinchZoom = function (el, options) {
                    this.el = $(el);
                    this.zoomFactor = 1;
                    this.lastScale = 1;
                    this.offset = {
                        x: 0,
                        y: 0
                    };
                    this.options = $.extend({}, this.defaults, options);
                    this.setupMarkup();
                    this.bindEvents();
                    this.update();
                    this.enable();
                },
                sum = function (a, b) {
                    return a + b;
                },
                isCloseTo = function (value, expected) {
                    return value > expected - 0.01 && value < expected + 0.01;
                };
            PinchZoom.prototype = {
                defaults: {
                    tapZoomFactor: 2,
                    zoomOutFactor: 1.3,
                    animationDuration: 300,
                    maxZoom: 4,
                    minZoom: 0.5,
                    lockDragAxis: false,
                    use2d: true,
                    zoomStartEventName: 'pz_zoomstart',
                    zoomEndEventName: 'pz_zoomend',
                    dragStartEventName: 'pz_dragstart',
                    dragEndEventName: 'pz_dragend',
                    doubleTapEventName: 'pz_doubletap'
                },
                handleDragStart: function (event) {
                    this.el.trigger(this.options.dragStartEventName);
                    this.stopAnimation();
                    this.lastDragPosition = false;
                    this.hasInteraction = true;
                    this.handleDrag(event);
                },
                handleDrag: function (event) {
                    if (this.zoomFactor > 1.0) {
                        var touch = this.getTouches(event)[0];
                        this.drag(touch, this.lastDragPosition);
                        this.offset = this.sanitizeOffset(this.offset);
                        this.lastDragPosition = touch;
                    }
                },
                handleDragEnd: function () {
                    this.el.trigger(this.options.dragEndEventName);
                    this.end();
                },
                handleZoomStart: function (event) {
                    this.el.trigger(this.options.zoomStartEventName);
                    this.stopAnimation();
                    this.lastScale = 1;
                    this.nthZoom = 0;
                    this.lastZoomCenter = false;
                    this.hasInteraction = true;
                },
                handleZoom: function (event, newScale) {
                    var touchCenter = this.getTouchCenter(this.getTouches(event)),
                        scale = newScale / this.lastScale;
                    this.lastScale = newScale;
                    this.nthZoom += 1;
                    if (this.nthZoom > 3) {
                        this.scale(scale, touchCenter);
                        this.drag(touchCenter, this.lastZoomCenter);
                    }
                    this.lastZoomCenter = touchCenter;
                },
                handleZoomEnd: function () {
                    this.el.trigger(this.options.zoomEndEventName);
                    this.end();
                },
                handleDoubleTap: function (event) {
                    var center = this.getTouches(event)[0],
                        zoomFactor = this.zoomFactor > 1 ? 1 : this.options.tapZoomFactor,
                        startZoomFactor = this.zoomFactor,
                        updateProgress = (function (progress) {
                            this.scaleTo(startZoomFactor + progress * (zoomFactor - startZoomFactor),
                                center);
                        }).bind(this);
                    if (this.hasInteraction) {
                        return;
                    }
                    if (startZoomFactor > zoomFactor) {
                        center = this.getCurrentZoomCenter();
                    }
                    this.animate(this.options.animationDuration, updateProgress, this.swing);
                    this.el.trigger(this.options.doubleTapEventName);
                },
                sanitizeOffset: function (offset) {
                    var maxX = (this.zoomFactor - 1) * this.getContainerX(),
                        maxY = (this.zoomFactor - 1) * this.getContainerY(),
                        maxOffsetX = Math.max(maxX, 0),
                        maxOffsetY = Math.max(maxY, 0),
                        minOffsetX = Math.min(maxX, 0),
                        minOffsetY = Math.min(maxY, 0);
                    return {
                        x: Math.min(Math.max(offset.x, minOffsetX), maxOffsetX),
                        y: Math.min(Math.max(offset.y, minOffsetY), maxOffsetY)
                    };
                },
                scaleTo: function (zoomFactor, center) {
                    this.scale(zoomFactor / this.zoomFactor, center);
                },
                scale: function (scale, center) {
                    scale = this.scaleZoomFactor(scale);
                    this.addOffset({
                        x: (scale - 1) * (center.x + this.offset.x),
                        y: (scale - 1) * (center.y + this.offset.y)
                    });
                },
                scaleZoomFactor: function (scale) {
                    var originalZoomFactor = this.zoomFactor;
                    this.zoomFactor *= scale;
                    this.zoomFactor = Math.min(this.options.maxZoom, Math.max(this.zoomFactor, this.options
                        .minZoom));
                    return this.zoomFactor / originalZoomFactor;
                },
                drag: function (center, lastCenter) {
                    if (lastCenter) {
                        if (this.options.lockDragAxis) {
                            if (Math.abs(center.x - lastCenter.x) > Math.abs(center.y - lastCenter.y)) {
                                this.addOffset({
                                    x: -(center.x - lastCenter.x),
                                    y: 0
                                });
                            } else {
                                this.addOffset({
                                    y: -(center.y - lastCenter.y),
                                    x: 0
                                });
                            }
                        } else {
                            this.addOffset({
                                y: -(center.y - lastCenter.y),
                                x: -(center.x - lastCenter.x)
                            });
                        }
                    }
                },
                getTouchCenter: function (touches) {
                    return this.getVectorAvg(touches);
                },
                getVectorAvg: function (vectors) {
                    return {
                        x: vectors.map(function (v) {
                            return v.x;
                        }).reduce(sum) / vectors.length,
                        y: vectors.map(function (v) {
                            return v.y;
                        }).reduce(sum) / vectors.length
                    };
                },
                addOffset: function (offset) {
                    this.offset = {
                        x: this.offset.x + offset.x,
                        y: this.offset.y + offset.y
                    };
                },
                sanitize: function () {
                    if (this.zoomFactor < this.options.zoomOutFactor) {
                        this.zoomOutAnimation();
                    } else if (this.isInsaneOffset(this.offset)) {
                        this.sanitizeOffsetAnimation();
                    }
                },
                isInsaneOffset: function (offset) {
                    var sanitizedOffset = this.sanitizeOffset(offset);
                    return sanitizedOffset.x !== offset.x || sanitizedOffset.y !== offset.y;
                },
                sanitizeOffsetAnimation: function () {
                    var targetOffset = this.sanitizeOffset(this.offset),
                        startOffset = {
                            x: this.offset.x,
                            y: this.offset.y
                        },
                        updateProgress = (function (progress) {
                            this.offset.x = startOffset.x + progress * (targetOffset.x - startOffset.x);
                            this.offset.y = startOffset.y + progress * (targetOffset.y - startOffset.y);
                            this.update();
                        }).bind(this);
                    this.animate(this.options.animationDuration, updateProgress, this.swing);
                },
                zoomOutAnimation: function () {
                    var startZoomFactor = this.zoomFactor,
                        zoomFactor = 1,
                        center = this.getCurrentZoomCenter(),
                        updateProgress = (function (progress) {
                            this.scaleTo(startZoomFactor + progress * (zoomFactor - startZoomFactor),
                                center);
                        }).bind(this);
                    this.animate(this.options.animationDuration, updateProgress, this.swing);
                },
                updateAspectRatio: function () {
                    this.setContainerY(this.getContainerX() / this.getAspectRatio());
                },
                getInitialZoomFactor: function () {
                    return this.container[0].offsetWidth / this.el[0].offsetWidth;
                },
                getAspectRatio: function () {
                    return this.el[0].offsetWidth / this.el[0].offsetHeight;
                },
                getCurrentZoomCenter: function () {
                    var length = this.container[0].offsetWidth * this.zoomFactor,
                        offsetLeft = this.offset.x,
                        offsetRight = length - offsetLeft - this.container[0].offsetWidth,
                        widthOffsetRatio = offsetLeft / offsetRight,
                        centerX = widthOffsetRatio * this.container[0].offsetWidth / (widthOffsetRatio + 1),
                        height = this.container[0].offsetHeight * this.zoomFactor,
                        offsetTop = this.offset.y,
                        offsetBottom = height - offsetTop - this.container[0].offsetHeight,
                        heightOffsetRatio = offsetTop / offsetBottom,
                        centerY = heightOffsetRatio * this.container[0].offsetHeight / (heightOffsetRatio +
                            1);
                    if (offsetRight === 0) {
                        centerX = this.container[0].offsetWidth;
                    }
                    if (offsetBottom === 0) {
                        centerY = this.container[0].offsetHeight;
                    }
                    return {
                        x: centerX,
                        y: centerY
                    };
                },
                canDrag: function () {
                    return !isCloseTo(this.zoomFactor, 1);
                },
                getTouches: function (event) {
                    var position = this.container.offset();
                    return Array.prototype.slice.call(event.touches).map(function (touch) {
                        return {
                            x: touch.pageX - position.left,
                            y: touch.pageY - position.top
                        };
                    });
                },
                animate: function (duration, framefn, timefn, callback) {
                    var startTime = new Date().getTime(),
                        renderFrame = (function () {
                            if (!this.inAnimation) {
                                return;
                            }
                            var frameTime = new Date().getTime() - startTime,
                                progress = frameTime / duration;
                            if (frameTime >= duration) {
                                framefn(1);
                                if (callback) {
                                    callback();
                                }
                                this.update();
                                this.stopAnimation();
                                this.update();
                            } else {
                                if (timefn) {
                                    progress = timefn(progress);
                                }
                                framefn(progress);
                                this.update();
                                requestAnimationFrame(renderFrame);
                            }
                        }).bind(this);
                    this.inAnimation = true;
                    requestAnimationFrame(renderFrame);
                },
                stopAnimation: function () {
                    this.inAnimation = false;
                },
                swing: function (p) {
                    return -Math.cos(p * Math.PI) / 2 + 0.5;
                },
                getContainerX: function () {
                    return this.container[0].offsetWidth;
                },
                getContainerY: function () {
                    return this.container[0].offsetHeight;
                },
                setContainerY: function (y) {
                    return this.container.height(y);
                },
                setupMarkup: function () {
                    this.container = $('<div class="pinch-zoom-container"></div>');
                    this.el.before(this.container);
                    this.container.append(this.el);
                    this.container.css({
                        'overflow': 'hidden',
                        'position': 'relative'
                    });
                    this.el.css({
                        '-webkit-transform-origin': '0% 0%',
                        '-moz-transform-origin': '0% 0%',
                        '-ms-transform-origin': '0% 0%',
                        '-o-transform-origin': '0% 0%',
                        'transform-origin': '0% 0%',
                        'position': 'absolute'
                    });
                },
                end: function () {
                    this.hasInteraction = false;
                    this.sanitize();
                    this.update();
                },
                bindEvents: function () {
                    detectGestures(this.container.get(0), this);
                    $(window).on('resize', this.update.bind(this));
                    $(this.el).find('img').on('load', this.update.bind(this));
                },
                update: function () {
                    if (this.updatePlaned) {
                        return;
                    }
                    this.updatePlaned = true;
                    setTimeout((function () {
                        this.updatePlaned = false;
                        this.updateAspectRatio();
                        var zoomFactor = this.getInitialZoomFactor() * this.zoomFactor,
                            offsetX = -this.offset.x / zoomFactor,
                            offsetY = -this.offset.y / zoomFactor,
                            transform3d = 'scale3d(' + zoomFactor + ', ' + zoomFactor + ',1) ' +
                            'translate3d(' + offsetX + 'px,' + offsetY + 'px,0px)',
                            transform2d = 'scale(' + zoomFactor + ', ' + zoomFactor + ') ' +
                            'translate(' + offsetX + 'px,' + offsetY + 'px)',
                            removeClone = (function () {
                                if (this.clone) {
                                    this.clone.remove();
                                    delete this.clone;
                                }
                            }).bind(this);
                        if (!this.options.use2d || this.hasInteraction || this.inAnimation) {
                            this.is3d = true;
                            removeClone();
                            this.el.css({
                                '-webkit-transform': transform3d,
                                '-o-transform': transform2d,
                                '-ms-transform': transform2d,
                                '-moz-transform': transform2d,
                                'transform': transform3d
                            });
                        } else {
                            if (this.is3d) {
                                this.clone = this.el.clone();
                                this.clone.css('pointer-events', 'none');
                                this.clone.appendTo(this.container);
                                setTimeout(removeClone, 200);
                            }
                            this.el.css({
                                '-webkit-transform': transform2d,
                                '-o-transform': transform2d,
                                '-ms-transform': transform2d,
                                '-moz-transform': transform2d,
                                'transform': transform2d
                            });
                            this.is3d = false;
                        }
                    }).bind(this), 0);
                },
                enable: function () {
                    this.enabled = true;
                },
                disable: function () {
                    this.enabled = false;
                }
            };
            var detectGestures = function (el, target) {
                var interaction = null,
                    fingers = 0,
                    lastTouchStart = null,
                    startTouches = null,
                    setInteraction = function (newInteraction, event) {
                        if (interaction !== newInteraction) {
                            if (interaction && !newInteraction) {
                                switch (interaction) {
                                    case "zoom":
                                        target.handleZoomEnd(event);
                                        break;
                                    case 'drag':
                                        target.handleDragEnd(event);
                                        break;
                                }
                            }
                            switch (newInteraction) {
                                case 'zoom':
                                    target.handleZoomStart(event);
                                    break;
                                case 'drag':
                                    target.handleDragStart(event);
                                    break;
                            }
                        }
                        interaction = newInteraction;
                    },
                    updateInteraction = function (event) {
                        if (fingers === 2) {
                            setInteraction('zoom');
                        } else if (fingers === 1 && target.canDrag()) {
                            setInteraction('drag', event);
                        } else {
                            setInteraction(null, event);
                        }
                    },
                    targetTouches = function (touches) {
                        return Array.prototype.slice.call(touches).map(function (touch) {
                            return {
                                x: touch.pageX,
                                y: touch.pageY
                            };
                        });
                    },
                    getDistance = function (a, b) {
                        var x, y;
                        x = a.x - b.x;
                        y = a.y - b.y;
                        return Math.sqrt(x * x + y * y);
                    },
                    calculateScale = function (startTouches, endTouches) {
                        var startDistance = getDistance(startTouches[0], startTouches[1]),
                            endDistance = getDistance(endTouches[0], endTouches[1]);
                        return endDistance / startDistance;
                    },
                    cancelEvent = function (event) {
                        event.stopPropagation();
                        event.preventDefault();
                    },
                    detectDoubleTap = function (event) {
                        var time = (new Date()).getTime();
                        if (fingers > 1) {
                            lastTouchStart = null;
                        }
                        if (time - lastTouchStart < 300) {
                            cancelEvent(event);
                            target.handleDoubleTap(event);
                            switch (interaction) {
                                case "zoom":
                                    target.handleZoomEnd(event);
                                    break;
                                case 'drag':
                                    target.handleDragEnd(event);
                                    break;
                            }
                        }
                        if (fingers === 1) {
                            lastTouchStart = time;
                        }
                    },
                    firstMove = true;
                el.addEventListener('touchstart', function (event) {
                    if (target.enabled) {
                        firstMove = true;
                        fingers = event.touches.length;
                        detectDoubleTap(event);
                    }
                });
                el.addEventListener('touchmove', function (event) {
                    if (target.enabled) {
                        if (firstMove) {
                            updateInteraction(event);
                            if (interaction) {
                                cancelEvent(event);
                            }
                            startTouches = targetTouches(event.touches);
                        } else {
                            switch (interaction) {
                                case 'zoom':
                                    target.handleZoom(event, calculateScale(startTouches, targetTouches(
                                        event.touches)));
                                    break;
                                case 'drag':
                                    target.handleDrag(event);
                                    break;
                            }
                            if (interaction) {
                                cancelEvent(event);
                                target.update();
                            }
                        }
                        firstMove = false;
                    }
                });
                el.addEventListener('touchend', function (event) {
                    if (target.enabled) {
                        fingers = event.touches.length;
                        updateInteraction(event);
                    }
                });
            };
            return PinchZoom;
        };
        if (typeof define !== 'undefined' && define.amd) {
            define(['jquery'], function ($) {
                return definePinchZoom($);
            });
        } else {
            window.RTP = window.RTP || {};
            window.RTP.PinchZoom = definePinchZoom(window.$);
        }
    }).call(this);

    ....

  • 相关阅读:
    复制带有random指针的单链表
    loadrunner常见问题
    【转】性能测试、负载测试、压力测试的区别
    文件存储结构inode与RAM结构建立联系
    inode表元数据,存储在物理存储体上
    debug宏起作用应用
    linux内核常用函数或宏
    file、inode在应用层和驱动层之间的联系_转
    内核交互--sysfs
    内核交互--procfs
  • 原文地址:https://www.cnblogs.com/wxyblog/p/14282351.html
Copyright © 2020-2023  润新知