| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 | (function(window, document, exportName, undefined) {    "use strict";    var isMultiTouch = false;    var multiTouchStartPos;    var eventTarget;    var touchElements = {};    // polyfills    if(!document.createTouch) {        document.createTouch = function(view, target, identifier, pageX, pageY, screenX, screenY, clientX, clientY) {            // auto set            if(clientX == undefined || clientY == undefined) {                clientX = pageX - window.pageXOffset;                clientY = pageY - window.pageYOffset;            }            return new Touch(target, identifier, {                pageX: pageX,                pageY: pageY,                screenX: screenX,                screenY: screenY,                clientX: clientX,                clientY: clientY            });        };    }    if(!document.createTouchList) {        document.createTouchList = function() {            var touchList = new TouchList();            for (var i = 0; i < arguments.length; i++) {                touchList[i] = arguments[i];            }            touchList.length = arguments.length;            return touchList;        };    }    /**     * create an touch point     * @constructor     * @param target     * @param identifier     * @param pos     * @param deltaX     * @param deltaY     * @returns {Object} touchPoint     */    function Touch(target, identifier, pos, deltaX, deltaY) {        deltaX = deltaX || 0;        deltaY = deltaY || 0;        this.identifier = identifier;        this.target = target;        this.clientX = pos.clientX + deltaX;        this.clientY = pos.clientY + deltaY;        this.screenX = pos.screenX + deltaX;        this.screenY = pos.screenY + deltaY;        this.pageX = pos.pageX + deltaX;        this.pageY = pos.pageY + deltaY;    }    /**     * create empty touchlist with the methods     * @constructor     * @returns touchList     */    function TouchList() {        var touchList = [];        touchList.item = function(index) {            return this[index] || null;        };        // specified by Mozilla        touchList.identifiedTouch = function(id) {            return this[id + 1] || null;        };        return touchList;    }    /**     * Simple trick to fake touch event support     * this is enough for most libraries like Modernizr and Hammer     */    function fakeTouchSupport() {        var objs = [window, document.documentElement];        var props = ['ontouchstart', 'ontouchmove', 'ontouchcancel', 'ontouchend'];        for(var o=0; o<objs.length; o++) {            for(var p=0; p<props.length; p++) {                if(objs[o] && objs[o][props[p]] == undefined) {                    objs[o][props[p]] = null;                }            }        }    }    /**     * we don't have to emulate on a touch device     * @returns {boolean}     */    function hasTouchSupport() {        return ("ontouchstart" in window) || // touch events               (window.Modernizr && window.Modernizr.touch) || // modernizr               (navigator.msMaxTouchPoints || navigator.maxTouchPoints) > 2; // pointer events    }    /**     * disable mouseevents on the page     * @param ev     */    function preventMouseEvents(ev) {		// 注释启用默认事件        // ev.preventDefault();        // ev.stopPropagation();    }    /**     * only trigger touches when the left mousebutton has been pressed     * @param touchType     * @returns {Function}     */    function onMouse(touchType) {        return function(ev) {            // prevent mouse events            preventMouseEvents(ev);            if (ev.which !== 1) {                return;            }            // The EventTarget on which the touch point started when it was first placed on the surface,            // even if the touch point has since moved outside the interactive area of that element.            // also, when the target doesnt exist anymore, we update it            if (ev.type == 'mousedown' || !eventTarget || (eventTarget && !eventTarget.dispatchEvent)) {                eventTarget = ev.target;            }            // shiftKey has been lost, so trigger a touchend            if (isMultiTouch && !ev.shiftKey) {                triggerTouch('touchend', ev);                isMultiTouch = false;            }            triggerTouch(touchType, ev);            // we're entering the multi-touch mode!            if (!isMultiTouch && ev.shiftKey) {                isMultiTouch = true;                multiTouchStartPos = {                    pageX: ev.pageX,                    pageY: ev.pageY,                    clientX: ev.clientX,                    clientY: ev.clientY,                    screenX: ev.screenX,                    screenY: ev.screenY                };                triggerTouch('touchstart', ev);            }            // reset            if (ev.type == 'mouseup') {                multiTouchStartPos = null;                isMultiTouch = false;                eventTarget = null;            }        }    }    /**     * trigger a touch event     * @param eventName     * @param mouseEv     */    function triggerTouch(eventName, mouseEv) {        var touchEvent = document.createEvent('Event');        touchEvent.initEvent(eventName, true, true);        touchEvent.altKey = mouseEv.altKey;        touchEvent.ctrlKey = mouseEv.ctrlKey;        touchEvent.metaKey = mouseEv.metaKey;        touchEvent.shiftKey = mouseEv.shiftKey;        touchEvent.touches = getActiveTouches(mouseEv, eventName);        touchEvent.targetTouches = getActiveTouches(mouseEv, eventName);        touchEvent.changedTouches = getChangedTouches(mouseEv, eventName);        eventTarget.dispatchEvent(touchEvent);    }    /**     * create a touchList based on the mouse event     * @param mouseEv     * @returns {TouchList}     */    function createTouchList(mouseEv) {        var touchList = new TouchList();        if (isMultiTouch) {            var f = TouchEmulator.multiTouchOffset;            var deltaX = multiTouchStartPos.pageX - mouseEv.pageX;            var deltaY = multiTouchStartPos.pageY - mouseEv.pageY;            touchList.push(new Touch(eventTarget, 1, multiTouchStartPos, (deltaX*-1) - f, (deltaY*-1) + f));            touchList.push(new Touch(eventTarget, 2, multiTouchStartPos, deltaX+f, deltaY-f));        } else {            touchList.push(new Touch(eventTarget, 1, mouseEv, 0, 0));        }        return touchList;    }    /**     * receive all active touches     * @param mouseEv     * @returns {TouchList}     */    function getActiveTouches(mouseEv, eventName) {        // empty list        if (mouseEv.type == 'mouseup') {            return new TouchList();        }        var touchList = createTouchList(mouseEv);        if(isMultiTouch && mouseEv.type != 'mouseup' && eventName == 'touchend') {            touchList.splice(1, 1);        }        return touchList;    }    /**     * receive a filtered set of touches with only the changed pointers     * @param mouseEv     * @param eventName     * @returns {TouchList}     */    function getChangedTouches(mouseEv, eventName) {        var touchList = createTouchList(mouseEv);        // we only want to return the added/removed item on multitouch        // which is the second pointer, so remove the first pointer from the touchList        //        // but when the mouseEv.type is mouseup, we want to send all touches because then        // no new input will be possible        if(isMultiTouch && mouseEv.type != 'mouseup' &&            (eventName == 'touchstart' || eventName == 'touchend')) {            touchList.splice(0, 1);        }        return touchList;    }    /**     * show the touchpoints on the screen     */    function showTouches(ev) {        var touch, i, el, styles;        // first all visible touches        for(i = 0; i < ev.touches.length; i++) {            touch = ev.touches[i];            el = touchElements[touch.identifier];            if(!el) {                el = touchElements[touch.identifier] = document.createElement("div");                document.body.appendChild(el);            }            styles = TouchEmulator.template(touch);            for(var prop in styles) {                el.style[prop] = styles[prop];            }        }        // remove all ended touches        if(ev.type == 'touchend' || ev.type == 'touchcancel') {            for(i = 0; i < ev.changedTouches.length; i++) {                touch = ev.changedTouches[i];                el = touchElements[touch.identifier];                if(el) {                    el.parentNode.removeChild(el);                    delete touchElements[touch.identifier];                }            }        }    }    /**     * TouchEmulator initializer     */    function TouchEmulator() {        if (hasTouchSupport()) {            return;        }        fakeTouchSupport();        window.addEventListener("mousedown", onMouse('touchstart'), true);        window.addEventListener("mousemove", onMouse('touchmove'), true);        window.addEventListener("mouseup", onMouse('touchend'), true);        window.addEventListener("mouseenter", preventMouseEvents, true);        window.addEventListener("mouseleave", preventMouseEvents, true);        window.addEventListener("mouseout", preventMouseEvents, true);        window.addEventListener("mouseover", preventMouseEvents, true);        // it uses itself!        window.addEventListener("touchstart", showTouches, true);        window.addEventListener("touchmove", showTouches, true);        window.addEventListener("touchend", showTouches, true);        window.addEventListener("touchcancel", showTouches, true);    }    // start distance when entering the multitouch mode    TouchEmulator.multiTouchOffset = 75;    /**     * css template for the touch rendering     * @param touch     * @returns object     */    TouchEmulator.template = function(touch) {        var size = 0;        var transform = 'translate('+ (touch.clientX-(size/2)) +'px, '+ (touch.clientY-(size/2)) +'px)';        return {            position: 'fixed',            left: 0,            top: 0,            background: '#fff',            border: 'solid 1px #999',            opacity: .6,            borderRadius: '100%',            height: size + 'px',            width: size + 'px',            padding: 0,            margin: 0,            display: 'block',            overflow: 'hidden',            pointerEvents: 'none',            webkitUserSelect: 'none',            mozUserSelect: 'none',            userSelect: 'none',            webkitTransform: transform,            mozTransform: transform,            transform: transform,            zIndex: 100        }    };    // export    if (typeof define == "function" && define.amd) {        define(function() {            return TouchEmulator;        });    } else if (typeof module != "undefined" && module.exports) {        module.exports = TouchEmulator;    } else {        window[exportName] = TouchEmulator;    }})(window, document, "TouchEmulator");
 |