From a17e36c0c9e8b88902a361ac1ff88ec6fb3d04b1 Mon Sep 17 00:00:00 2001 From: libccy Date: Wed, 5 Apr 2017 12:21:25 +0800 Subject: [PATCH] pressure --- game/game.js | 97 ++++---- game/pressure.js | 576 +++++++++++++++++++++++++++++++++++++++++++++++ game/source.js | 1 + game/update.js | 4 +- 4 files changed, 621 insertions(+), 57 deletions(-) create mode 100644 game/pressure.js diff --git a/game/game.js b/game/game.js index 8d48ef169..3ee4bb1dd 100644 --- a/game/game.js +++ b/game/game.js @@ -159,6 +159,13 @@ unfrequent:true, intro:'开启后可使触屏设备反应更快,但无法使用鼠标操作', }, + threedtouch:{ + name:'压感操作', + init:true, + restart:true, + unfrequent:true, + intro:'开启后按压可显示菜单或暂停', + }, swipe:{ name:'滑动手势', init:true, @@ -5066,7 +5073,18 @@ node.oncontextmenu=ui.click.rightplayer; } } - node._customintro=func; + lib.setPressure(node,ui.click.rightpressure); + if(func){ + node._customintro=func; + } + }, + setPressure:function(node,func){ + if(lib.config.threedtouch&&window.Pressure){ + window.Pressure.set(node,{change: func}, { + only: lib.config.touchscreen?'touch':'mouse', + polyfill: false + }); + } }, setPopped:function(node,func,width,height,forceclick,paused2){ node._poppedfunc=func; @@ -5952,6 +5970,9 @@ lib.init.js(lib.assetURL+'card',lib.config.all.cards,packLoaded,packLoaded); lib.init.js(lib.assetURL+'character',lib.config.all.characters,packLoaded,packLoaded); lib.init.js(lib.assetURL+'character','rank',packLoaded,packLoaded); + if(lib.config.threedtouch){ + lib.init.js(lib.assetURL+'game','pressure'); + } }; if(extensionlist.length){ window.game=game; @@ -12050,17 +12071,7 @@ this.hujia=0; this.node.intro.innerHTML=lib.config.intro; this.node.name.dataset.nature=get.groupnature(this.group); - if(lib.config.touchscreen){ - lib.setLongPress(this,ui.click.intro); - } - else{ - if(lib.config.hover_all){ - lib.setHover(this,ui.click.hoverplayer); - } - if(lib.config.right_info){ - this.oncontextmenu=ui.click.rightplayer; - } - } + lib.setIntro(this); // var name=get.translation(character); this.node.name.innerHTML=get.slimName(character); if(this.classList.contains('minskin')&&this.node.name.querySelectorAll('br').length>=4){ @@ -24853,17 +24864,7 @@ event.avatars[i].animate('start'); event.nodes[event.avatars[i].index].style.display='none'; event.avatars[i].nodename.dataset.nature=get.groupnature(lib.character[name][1]); - if(lib.config.touchscreen){ - lib.setLongPress(event.avatars[i],ui.click.intro); - } - else{ - if(lib.config.hover_all){ - lib.setHover(event.avatars[i],ui.click.hoverplayer); - } - if(lib.config.right_info){ - event.avatars[i].oncontextmenu=ui.click.rightplayer; - } - } + lib.setIntro(event.avatars[i]); } event.resize(); for(var i=0;i'; @@ -34768,17 +34749,7 @@ } node.node.intro.innerHTML=lib.config.intro; if(!noclick){ - if(lib.config.touchscreen){ - lib.setLongPress(node,ui.click.intro); - } - else{ - if(lib.config.hover_all){ - lib.setHover(node,ui.click.hoverplayer); - } - if(lib.config.right_info){ - node.oncontextmenu=ui.click.rightplayer; - } - } + lib.setIntro(node); } node.storage={uncheck:[]}; if(info!='noclick'){ @@ -37646,6 +37617,20 @@ ui.click.touchpop(); e.stopPropagation(); }, + rightpressure(force, event){ + if(force>=0.5){ + if(_status.mousedragging){ + _status.mousedragging=null; + _status.mouseleft=false; + _status.mousedragorigin=null; + _status.dragstatuschanged=false; + game.uncheck(); + game.check(); + } + ui.click.rightplayer.call(this,event); + _status.clickedplayer=false; + } + }, rightplayer:function(e){ if(this._nopup) return false; if(_status.clickedplayer){ diff --git a/game/pressure.js b/game/pressure.js new file mode 100644 index 000000000..dbf205895 --- /dev/null +++ b/game/pressure.js @@ -0,0 +1,576 @@ +// Pressure v2.1.1 | Created By Stuart Yamartino | MIT License | 2015 - 2017 +;(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define([], factory); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else { + root.Pressure = factory(); + } +}(this, function() { +'use strict'; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +//--------------------- Public API Section ---------------------// +// this is the Pressure Object, this is the only object that is accessible to the end user +// only the methods in this object can be called, making it the "public api" + +var Pressure = { + + // targets any device with Force or 3D Touch + set: function set(selector, closure, options) { + loopPressureElements(selector, closure, options); + }, + + + // set configuration options for global config + config: function config(options) { + Config.set(options); + }, + + + // the map method allows for interpolating a value from one range of values to another + // example from the Arduino documentation: https://www.arduino.cc/en/Reference/Map + map: function map(x, in_min, in_max, out_min, out_max) { + return _map.apply(null, arguments); + } +}; + +var Element = function () { + function Element(el, block, options) { + _classCallCheck(this, Element); + + this.routeEvents(el, block, options); + this.preventSelect(el, options); + } + + _createClass(Element, [{ + key: 'routeEvents', + value: function routeEvents(el, block, options) { + var type = Config.get('only', options); + // for devices that support pointer events + if (supportsPointer && (type === 'pointer' || type === null)) { + this.adapter = new AdapterPointer(el, block, options).bindEvents(); + } + // for devices that support 3D Touch + else if (supportsTouch && (type === 'touch' || type === null)) { + this.adapter = new Adapter3DTouch(el, block, options).bindEvents(); + } + // for devices that support Force Touch + else if (supportsMouse && (type === 'mouse' || type === null)) { + this.adapter = new AdapterForceTouch(el, block, options).bindEvents(); + } + // unsupported if it is requesting a type and your browser is of other type + else { + this.adapter = new Adapter(el, block).bindUnsupportedEvent(); + } + } + + // prevent the default action of text selection, "peak & pop", and force touch special feature + + }, { + key: 'preventSelect', + value: function preventSelect(el, options) { + if (Config.get('preventSelect', options)) { + el.style.webkitTouchCallout = "none"; + el.style.webkitUserSelect = "none"; + el.style.khtmlUserSelect = "none"; + el.style.MozUserSelect = "none"; + el.style.msUserSelect = "none"; + el.style.userSelect = "none"; + } + } + }]); + + return Element; +}(); + +/* +This is the base adapter from which all the other adapters extend. +*/ + +var Adapter = function () { + function Adapter(el, block, options) { + _classCallCheck(this, Adapter); + + this.el = el; + this.block = block; + this.options = options; + this.pressed = false; + this.deepPressed = false; + this.nativeSupport = false; + this.runningPolyfill = false; + this.runKey = Math.random(); + } + + _createClass(Adapter, [{ + key: 'setPressed', + value: function setPressed(boolean) { + this.pressed = boolean; + } + }, { + key: 'setDeepPressed', + value: function setDeepPressed(boolean) { + this.deepPressed = boolean; + } + }, { + key: 'isPressed', + value: function isPressed() { + return this.pressed; + } + }, { + key: 'isDeepPressed', + value: function isDeepPressed() { + return this.deepPressed; + } + }, { + key: 'add', + value: function add(event, set) { + this.el.addEventListener(event, set, false); + } + }, { + key: 'runClosure', + value: function runClosure(method) { + if (method in this.block) { + // call the closure method and apply nth arguments if they exist + this.block[method].apply(this.el, Array.prototype.slice.call(arguments, 1)); + } + } + }, { + key: 'fail', + value: function fail(event, runKey) { + if (Config.get('polyfill', this.options)) { + if (this.runKey === runKey) { + this.runPolyfill(event); + } + } else { + this.runClosure('unsupported', event); + } + } + }, { + key: 'bindUnsupportedEvent', + value: function bindUnsupportedEvent() { + var _this = this; + + this.add(supportsTouch ? 'touchstart' : 'mousedown', function (event) { + return _this.runClosure('unsupported', event); + }); + } + }, { + key: '_startPress', + value: function _startPress(event) { + if (this.isPressed() === false) { + this.runningPolyfill = false; + this.setPressed(true); + this.runClosure('start', event); + } + } + }, { + key: '_startDeepPress', + value: function _startDeepPress(event) { + if (this.isPressed() && this.isDeepPressed() === false) { + this.setDeepPressed(true); + this.runClosure('startDeepPress', event); + } + } + }, { + key: '_changePress', + value: function _changePress(force, event) { + this.nativeSupport = true; + this.runClosure('change', force, event); + } + }, { + key: '_endDeepPress', + value: function _endDeepPress() { + if (this.isPressed() && this.isDeepPressed()) { + this.setDeepPressed(false); + this.runClosure('endDeepPress'); + } + } + }, { + key: '_endPress', + value: function _endPress() { + if (this.runningPolyfill === false) { + if (this.isPressed()) { + this._endDeepPress(); + this.setPressed(false); + this.runClosure('end'); + } + this.runKey = Math.random(); + this.nativeSupport = false; + } else { + this.setPressed(false); + } + } + }, { + key: 'deepPress', + value: function deepPress(force, event) { + force >= 0.5 ? this._startDeepPress(event) : this._endDeepPress(); + } + }, { + key: 'runPolyfill', + value: function runPolyfill(event) { + this.increment = Config.get('polyfillSpeedUp', this.options) === 0 ? 1 : 10 / Config.get('polyfillSpeedUp', this.options); + this.decrement = Config.get('polyfillSpeedDown', this.options) === 0 ? 1 : 10 / Config.get('polyfillSpeedDown', this.options); + this.setPressed(true); + this.runClosure('start', event); + if (this.runningPolyfill === false) { + this.loopPolyfillForce(0, event); + } + } + }, { + key: 'loopPolyfillForce', + value: function loopPolyfillForce(force, event) { + if (this.nativeSupport === false) { + if (this.isPressed()) { + this.runningPolyfill = true; + force = force + this.increment > 1 ? 1 : force + this.increment; + this.runClosure('change', force, event); + this.deepPress(force, event); + setTimeout(this.loopPolyfillForce.bind(this, force, event), 10); + } else { + force = force - this.decrement < 0 ? 0 : force - this.decrement; + if (force < 0.5 && this.isDeepPressed()) { + this.setDeepPressed(false); + this.runClosure('endDeepPress'); + } + if (force === 0) { + this.runningPolyfill = false; + this.setPressed(true); + this._endPress(); + } else { + this.runClosure('change', force, event); + this.deepPress(force, event); + setTimeout(this.loopPolyfillForce.bind(this, force, event), 10); + } + } + } + } + }]); + + return Adapter; +}(); + +/* +This adapter is for Macs with Force Touch trackpads. +*/ + +var AdapterForceTouch = function (_Adapter) { + _inherits(AdapterForceTouch, _Adapter); + + function AdapterForceTouch(el, block, options) { + _classCallCheck(this, AdapterForceTouch); + + return _possibleConstructorReturn(this, (AdapterForceTouch.__proto__ || Object.getPrototypeOf(AdapterForceTouch)).call(this, el, block, options)); + } + + _createClass(AdapterForceTouch, [{ + key: 'bindEvents', + value: function bindEvents() { + this.add('webkitmouseforcewillbegin', this._startPress.bind(this)); + this.add('mousedown', this.support.bind(this)); + this.add('webkitmouseforcechanged', this.change.bind(this)); + this.add('webkitmouseforcedown', this._startDeepPress.bind(this)); + this.add('webkitmouseforceup', this._endDeepPress.bind(this)); + this.add('mouseleave', this._endPress.bind(this)); + this.add('mouseup', this._endPress.bind(this)); + } + }, { + key: 'support', + value: function support(event) { + if (this.isPressed() === false) { + this.fail(event, this.runKey); + } + } + }, { + key: 'change', + value: function change(event) { + if (this.isPressed() && event.webkitForce > 0) { + this._changePress(this.normalizeForce(event.webkitForce), event); + } + } + + // make the force the standard 0 to 1 scale and not the 1 to 3 scale + + }, { + key: 'normalizeForce', + value: function normalizeForce(force) { + return this.reachOne(_map(force, 1, 3, 0, 1)); + } + + // if the force value is above 0.995 set the force to 1 + + }, { + key: 'reachOne', + value: function reachOne(force) { + return force > 0.995 ? 1 : force; + } + }]); + + return AdapterForceTouch; +}(Adapter); + +/* +This adapter is more mobile devices that support 3D Touch. +*/ + +var Adapter3DTouch = function (_Adapter2) { + _inherits(Adapter3DTouch, _Adapter2); + + function Adapter3DTouch(el, block, options) { + _classCallCheck(this, Adapter3DTouch); + + return _possibleConstructorReturn(this, (Adapter3DTouch.__proto__ || Object.getPrototypeOf(Adapter3DTouch)).call(this, el, block, options)); + } + + _createClass(Adapter3DTouch, [{ + key: 'bindEvents', + value: function bindEvents() { + if (supportsTouchForceChange) { + this.add('touchforcechange', this.start.bind(this)); + this.add('touchstart', this.support.bind(this, 0)); + this.add('touchend', this._endPress.bind(this)); + } else { + this.add('touchstart', this.startLegacy.bind(this)); + this.add('touchend', this._endPress.bind(this)); + } + } + }, { + key: 'start', + value: function start(event) { + if (event.touches.length > 0) { + this._startPress(event); + this.touch = this.selectTouch(event); + if (this.touch) { + this._changePress(this.touch.force, event); + } + } + } + }, { + key: 'support', + value: function support(iter, event) { + var runKey = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.runKey; + + if (this.isPressed() === false) { + if (iter <= 6) { + iter++; + setTimeout(this.support.bind(this, iter, event, runKey), 10); + } else { + this.fail(event, runKey); + } + } + } + }, { + key: 'startLegacy', + value: function startLegacy(event) { + this.initialForce = event.touches[0].force; + this.supportLegacy(0, event, this.runKey, this.initialForce); + } + + // this checks up to 6 times on a touch to see if the touch can read a force value + // if the force value has changed it means the device supports pressure + // more info from this issue https://github.com/yamartino/pressure/issues/15 + + }, { + key: 'supportLegacy', + value: function supportLegacy(iter, event, runKey, force) { + if (force !== this.initialForce) { + this._startPress(event); + this.loopForce(event); + } else if (iter <= 6) { + iter++; + setTimeout(this.supportLegacy.bind(this, iter, event, runKey, force), 10); + } else { + this.fail(event, runKey); + } + } + }, { + key: 'loopForce', + value: function loopForce(event) { + if (this.isPressed()) { + this.touch = this.selectTouch(event); + setTimeout(this.loopForce.bind(this, event), 10); + this._changePress(this.touch.force, event); + } + } + + // link up the touch point to the correct element, this is to support multitouch + + }, { + key: 'selectTouch', + value: function selectTouch(event) { + if (event.touches.length === 1) { + return this.returnTouch(event.touches[0], event); + } else { + for (var i = 0; i < event.touches.length; i++) { + // if the target press is on this element + if (event.touches[i].target === this.el || this.el.contains(event.touches[i].target)) { + return this.returnTouch(event.touches[i], event); + } + } + } + } + + // return the touch and run a start or end for deep press + + }, { + key: 'returnTouch', + value: function returnTouch(touch, event) { + this.deepPress(touch.force, event); + return touch; + } + }]); + + return Adapter3DTouch; +}(Adapter); + +/* +This adapter is for devices that support pointer events. +*/ + +var AdapterPointer = function (_Adapter3) { + _inherits(AdapterPointer, _Adapter3); + + function AdapterPointer(el, block, options) { + _classCallCheck(this, AdapterPointer); + + return _possibleConstructorReturn(this, (AdapterPointer.__proto__ || Object.getPrototypeOf(AdapterPointer)).call(this, el, block, options)); + } + + _createClass(AdapterPointer, [{ + key: 'bindEvents', + value: function bindEvents() { + this.add('pointerdown', this.support.bind(this)); + this.add('pointermove', this.change.bind(this)); + this.add('pointerup', this._endPress.bind(this)); + this.add('pointerleave', this._endPress.bind(this)); + } + }, { + key: 'support', + value: function support(event) { + if (this.isPressed() === false) { + if (event.pressure === 0 || event.pressure === 0.5) { + this.fail(event, this.runKey); + } else { + this._startPress(event); + this._changePress(event.pressure, event); + } + } + } + }, { + key: 'change', + value: function change(event) { + if (this.isPressed() && event.pressure > 0 && event.pressure !== 0.5) { + this._changePress(event.pressure, event); + this.deepPress(event.pressure, event); + } + } + }]); + + return AdapterPointer; +}(Adapter); + +// This class holds the states of the the Pressure config + + +var Config = { + + // 'false' will make polyfill not run when pressure is not supported and the 'unsupported' method will be called + polyfill: true, + + // milliseconds it takes to go from 0 to 1 for the polyfill + polyfillSpeedUp: 1000, + + // milliseconds it takes to go from 1 to 0 for the polyfill + polyfillSpeedDown: 0, + + // 'true' prevents the selecting of text and images via css properties + preventSelect: true, + + // 'touch', 'mouse', or 'pointer' will make it run only on that type of device + only: null, + + // this will get the correct config / option settings for the current pressure check + get: function get(option, options) { + return options.hasOwnProperty(option) ? options[option] : this[option]; + }, + + + // this will set the global configs + set: function set(options) { + for (var k in options) { + if (options.hasOwnProperty(k) && this.hasOwnProperty(k) && k != 'get' && k != 'set') { + this[k] = options[k]; + } + } + } +}; + +//------------------- Helpers -------------------// + +// accepts jQuery object, node list, string selector, then called a setup for each element +var loopPressureElements = function loopPressureElements(selector, closure) { + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + // if a string is passed in as an element + if (typeof selector === 'string' || selector instanceof String) { + var elements = document.querySelectorAll(selector); + for (var i = 0; i < elements.length; i++) { + new Element(elements[i], closure, options); + } + // if a single element object is passed in + } else if (isElement(selector)) { + new Element(selector, closure, options); + // if a node list is passed in ex. jQuery $() object + } else { + for (var i = 0; i < selector.length; i++) { + new Element(selector[i], closure, options); + } + } +}; + +//Returns true if it is a DOM element +var isElement = function isElement(o) { + return (typeof HTMLElement === 'undefined' ? 'undefined' : _typeof(HTMLElement)) === "object" ? o instanceof HTMLElement : //DOM2 + o && (typeof o === 'undefined' ? 'undefined' : _typeof(o)) === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName === "string"; +}; + +// the map method allows for interpolating a value from one range of values to another +// example from the Arduino documentation: https://www.arduino.cc/en/Reference/Map +var _map = function _map(x, in_min, in_max, out_min, out_max) { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +}; + +var supportsMouse = false; +var supportsTouch = false; +var supportsPointer = false; +var supportsTouchForce = false; +var supportsTouchForceChange = false; + +if (typeof window !== 'undefined') { + // only attempt to assign these in a browser environment. + // on the server, this is a no-op, like the rest of the library + if (typeof Touch !== 'undefined') { + // In Android, new Touch requires arguments. + try { + if (Touch.prototype.hasOwnProperty('force') || 'force' in new Touch()) { + supportsTouchForce = true; + } + } catch (e) {} + } + supportsTouch = 'ontouchstart' in window.document && supportsTouchForce; + supportsMouse = 'onmousemove' in window.document && !supportsTouch; + supportsPointer = 'onpointermove' in window.document; + supportsTouchForceChange = 'ontouchforcechange' in window.document; +} +return Pressure; +})); diff --git a/game/source.js b/game/source.js index 531ae514f..8325d39d1 100644 --- a/game/source.js +++ b/game/source.js @@ -32,6 +32,7 @@ window.noname_source_list=[ 'game/jszip.js', 'game/package.js', 'game/phantom.js', + 'game/pressure.js', 'game/server.js', 'game/source.js', 'game/update.js', diff --git a/game/update.js b/game/update.js index e8ef55e7d..edeb71c01 100644 --- a/game/update.js +++ b/game/update.js @@ -3,12 +3,14 @@ window.noname_update={ update:'1.9.20.1', changeLog:[ 'bug修复', + '压感操作' ], files:[ 'game/game.js', // 'game/package.js', 'game/config.js', - // 'game/source.js', + 'game/source.js', + 'game/pressure.js', // 'game/asset.js', // 'card/*', // 'card/sp.js',