├── .eslintignore ├── src ├── plugins │ ├── picker │ │ ├── README.md │ │ ├── picker.js │ │ └── package.json │ ├── fmover-slide-x │ │ ├── README.md │ │ ├── package.json │ │ └── dist │ │ │ └── fmover-slide-x.min.js │ ├── fmover-slide-y │ │ ├── README.md │ │ ├── package.json │ │ ├── dist │ │ │ └── fmover-slide-y.min.js │ │ └── fmover-slide-y.js │ ├── simulation-scroll-x │ │ ├── README.md │ │ ├── package.json │ │ ├── dist │ │ │ ├── simulation-scroll-x.min.js │ │ │ └── simulation-scroll-x.js │ │ └── simulation-scroll-x.js │ └── simulation-scroll-y │ │ ├── README.md │ │ ├── package.json │ │ └── dist │ │ └── simulation-scroll-y.min.js ├── moved │ ├── README.md │ ├── tw.js │ ├── package.json │ ├── animationframe.js │ ├── moved.js │ └── dist │ │ ├── moved.min.js │ │ └── moved.js ├── fingerd │ ├── README.md │ ├── package.json │ ├── dist │ │ ├── fingerd.min.js │ │ └── fingerd.js │ ├── fingerd.js │ └── tevent.js ├── vue-component │ └── simulation-scroll-y.vue ├── index.js └── shared │ └── util.js ├── .gitignore ├── .babelrc ├── circle.yml ├── test ├── index.unit.js └── unit │ ├── index.spec.js │ ├── util.spec.js │ └── moved.spec.js ├── demo ├── vue-component │ └── simulation-scroll-y │ │ ├── main.js │ │ ├── index.html │ │ └── app.vue ├── mover-easy-demo.html ├── fingerd-demo.html ├── simulation-y-demo.html ├── simulation-x-demo.html ├── 2d-scroll-demo.html ├── scroll-to-y.html ├── fingerd-scale-demo.html ├── scroll-to-x.html ├── fingerd-number.html ├── simulation-event-demo.html ├── load-more-demo.html ├── simulation-y-demo-vue.html ├── pull-down-demo.html ├── mover-demo.html ├── slide-with-scroll.html ├── contacts.html ├── fmover-slide-y.html ├── fmover-slide-x.html └── index.html ├── .eslintrc.js ├── package.json ├── README.md └── dist └── finger-mover.min.js /.eslintignore: -------------------------------------------------------------------------------- 1 | css* 2 | build 3 | dist -------------------------------------------------------------------------------- /src/plugins/picker/README.md: -------------------------------------------------------------------------------- 1 | ## fmover-slide-y 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | *.log 4 | .history 5 | coverage -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"], 3 | "ignore": [ 4 | "dist/**/*.js" 5 | ] 6 | } -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | node: 3 | version: 6 4 | 5 | test: 6 | override: 7 | - bash build/ci.sh 8 | -------------------------------------------------------------------------------- /test/index.unit.js: -------------------------------------------------------------------------------- 1 | const testsContext = require.context('./', true, /\.spec$/) 2 | testsContext.keys().forEach(testsContext) -------------------------------------------------------------------------------- /src/moved/README.md: -------------------------------------------------------------------------------- 1 | ## Moved 2 | 3 | Document address: [https://fmover.hcysun.me/#/zh-cn/package/moved](https://fmover.hcysun.me/#/zh-cn/package/moved) -------------------------------------------------------------------------------- /src/fingerd/README.md: -------------------------------------------------------------------------------- 1 | ## Fingerd 2 | 3 | Document address: [https://fmover.hcysun.me/#/zh-cn/package/fingerd](https://fmover.hcysun.me/#/zh-cn/package/fingerd) -------------------------------------------------------------------------------- /src/plugins/fmover-slide-x/README.md: -------------------------------------------------------------------------------- 1 | ## fmover-slide-x 2 | 3 | Document address: [https://fmover.hcysun.me/#/zh-cn/plugins/fmover-slide-x](https://fmover.hcysun.me/#/zh-cn/plugins/fmover-slide-x) -------------------------------------------------------------------------------- /src/plugins/fmover-slide-y/README.md: -------------------------------------------------------------------------------- 1 | ## fmover-slide-y 2 | 3 | Document address: [https://fmover.hcysun.me/#/zh-cn/plugins/fmover-slide-y](https://fmover.hcysun.me/#/zh-cn/plugins/fmover-slide-y) -------------------------------------------------------------------------------- /src/plugins/simulation-scroll-x/README.md: -------------------------------------------------------------------------------- 1 | ## simulation-scroll-x 2 | 3 | Document address: [https://fmover.hcysun.me/#/zh-cn/plugins/simulation-scroll-x](https://fmover.hcysun.me/#/zh-cn/plugins/simulation-scroll-x) -------------------------------------------------------------------------------- /src/plugins/simulation-scroll-y/README.md: -------------------------------------------------------------------------------- 1 | ## simulation-scroll-y 2 | 3 | Document address: [https://fmover.hcysun.me/#/zh-cn/plugins/simulation-scroll-y](https://fmover.hcysun.me/#/zh-cn/plugins/simulation-scroll-y) -------------------------------------------------------------------------------- /demo/vue-component/simulation-scroll-y/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from 'demo/simulation-scroll-y/app' 3 | 4 | Vue.config.productionTip = false 5 | 6 | new Vue({ 7 | el: '#main', 8 | template: '', 9 | components: { 10 | App 11 | } 12 | }) -------------------------------------------------------------------------------- /src/moved/tw.js: -------------------------------------------------------------------------------- 1 | const TW = { 2 | easeOutStrong: function (t, b, c, d) { 3 | return -c * ((t = t / d - 1) * t * t * t - 1) + b 4 | }, 5 | backOut: function (t, b, c, d, s) { 6 | if (typeof s === 'undefined') { 7 | s = 0.7 8 | } 9 | return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b 10 | } 11 | } 12 | 13 | export default TW -------------------------------------------------------------------------------- /demo/vue-component/simulation-scroll-y/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | simulation-scroll-y & Vue component 8 | 9 | 10 | 11 | 12 |
13 | 14 |
15 | 16 | -------------------------------------------------------------------------------- /src/moved/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moved", 3 | "version": "1.4.3", 4 | "description": "Miniature motion solutions", 5 | "main": "dist/moved.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/HcySunYang/finger-mover.git" 9 | }, 10 | "keywords": [ 11 | "move", 12 | "moved", 13 | "Animation" 14 | ], 15 | "author": "HcySunYang", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/HcySunYang/finger-mover/issues" 19 | }, 20 | "homepage": "https://github.com/HcySunYang/finger-mover/blob/master/src/moved/README.md" 21 | } 22 | -------------------------------------------------------------------------------- /src/plugins/picker/picker.js: -------------------------------------------------------------------------------- 1 | export default function (options) { 2 | 3 | return function (Fmover) { 4 | const { 5 | Moved 6 | } = Fmover 7 | 8 | return { 9 | init (fmover) { 10 | 11 | }, 12 | start (fingerd) { 13 | 14 | }, 15 | move (fingerd) { 16 | 17 | }, 18 | end (fingerd) { 19 | 20 | }, 21 | cancel (fingerd) { 22 | 23 | } 24 | 25 | } 26 | 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /src/plugins/picker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "picker", 3 | "version": "1.0.1", 4 | "description": "javascript picker inspired by ios UIPickerView", 5 | "main": "dist/picker.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/HcySunYang/finger-mover.git" 9 | }, 10 | "keywords": [ 11 | "plugin", 12 | "picker", 13 | "finger-mover" 14 | ], 15 | "author": "HcySunYang", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/HcySunYang/finger-mover/issues" 19 | }, 20 | "homepage": "https://github.com/HcySunYang/finger-mover/blob/master/src/plugins/picker/README.md" 21 | } 22 | -------------------------------------------------------------------------------- /src/fingerd/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fingerd", 3 | "version": "1.4.3", 4 | "description": "A development kit for finger unit event management in mobile development", 5 | "main": "dist/fingerd.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/HcySunYang/finger-mover.git" 9 | }, 10 | "keywords": [ 11 | "event", 12 | "finger", 13 | "fingerd" 14 | ], 15 | "author": "HcySunYang", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/HcySunYang/finger-mover/issues" 19 | }, 20 | "homepage": "https://github.com/HcySunYang/finger-mover/blob/master/src/fingerd/README.md" 21 | } 22 | -------------------------------------------------------------------------------- /src/plugins/fmover-slide-x/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fmover-slide-x", 3 | "version": "1.4.3", 4 | "description": "finger-mover horizontal slideshow plugin", 5 | "main": "dist/fmover-slide-x.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/HcySunYang/finger-mover.git" 9 | }, 10 | "keywords": [ 11 | "plugin", 12 | "slide", 13 | "swiper", 14 | "finger-mover" 15 | ], 16 | "author": "HcySunYang", 17 | "license": "MIT", 18 | "bugs": { 19 | "url": "https://github.com/HcySunYang/finger-mover/issues" 20 | }, 21 | "homepage": "https://github.com/HcySunYang/finger-mover/blob/master/src/plugins/fmover-slide-x/README.md" 22 | } 23 | -------------------------------------------------------------------------------- /src/plugins/fmover-slide-y/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fmover-slide-y", 3 | "version": "1.4.3", 4 | "description": "finger-mover vertical slideshow plugin", 5 | "main": "dist/fmover-slide-y.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/HcySunYang/finger-mover.git" 9 | }, 10 | "keywords": [ 11 | "plugin", 12 | "slide", 13 | "swiper", 14 | "finger-mover" 15 | ], 16 | "author": "HcySunYang", 17 | "license": "MIT", 18 | "bugs": { 19 | "url": "https://github.com/HcySunYang/finger-mover/issues" 20 | }, 21 | "homepage": "https://github.com/HcySunYang/finger-mover/blob/master/src/plugins/fmover-slide-y/README.md" 22 | } 23 | -------------------------------------------------------------------------------- /src/plugins/simulation-scroll-x/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simulation-scroll-x", 3 | "version": "1.4.3", 4 | "description": "Horizontal scroll simulation solution on mobile device.", 5 | "main": "dist/simulation-scroll-x.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/HcySunYang/finger-mover.git" 9 | }, 10 | "keywords": [ 11 | "scroll", 12 | "simulation", 13 | "finger-mover" 14 | ], 15 | "author": "HcySunYang", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/HcySunYang/finger-mover/issues" 19 | }, 20 | "homepage": "https://github.com/HcySunYang/finger-mover/blob/master/src/plugins/simulation-scroll-x/README.md" 21 | } 22 | -------------------------------------------------------------------------------- /src/plugins/simulation-scroll-y/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simulation-scroll-y", 3 | "version": "1.4.3", 4 | "description": "Vertical scroll simulation solution on mobile device.", 5 | "main": "dist/simulation-scroll-y.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/HcySunYang/finger-mover.git" 9 | }, 10 | "keywords": [ 11 | "scroll", 12 | "simulation", 13 | "finger-mover" 14 | ], 15 | "author": "HcySunYang", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/HcySunYang/finger-mover/issues" 19 | }, 20 | "homepage": "https://github.com/HcySunYang/finger-mover/blob/master/src/plugins/simulation-scroll-y/README.md" 21 | } 22 | -------------------------------------------------------------------------------- /src/moved/animationframe.js: -------------------------------------------------------------------------------- 1 | import { 2 | requestAnim, 3 | cancelAnim, 4 | now 5 | } from '../shared/util' 6 | 7 | export default class Animationframe { 8 | constructor (handle) { 9 | this.handle = handle 10 | this.id = 0 11 | this._init() 12 | } 13 | 14 | _init () { 15 | this.start = now() 16 | this.request() 17 | } 18 | 19 | _fakeHandle () { 20 | let times = now() - this.start 21 | 22 | this.handle(times) 23 | } 24 | 25 | _requestAnimFn (handle) { 26 | if (requestAnim) { 27 | return requestAnim(handle) 28 | } else { 29 | return setTimeout(handle, 1000 / 60) 30 | } 31 | } 32 | 33 | _cancelAnimFn (id) { 34 | if (cancelAnim) { 35 | cancelAnim(id) 36 | } else { 37 | clearTimeout(id) 38 | } 39 | } 40 | 41 | request () { 42 | this.id = this._requestAnimFn(this._fakeHandle.bind(this)) 43 | } 44 | 45 | cancel () { 46 | this._cancelAnimFn(this.id) 47 | } 48 | } -------------------------------------------------------------------------------- /demo/mover-easy-demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | Moved Demo 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /demo/vue-component/simulation-scroll-y/app.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 51 | 52 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /demo/fingerd-demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | Finger Demo 8 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | // required to lint *.vue files 5 | plugins: [ 6 | 'html' 7 | ], 8 | "env": { 9 | "browser": true, 10 | "es6": true 11 | }, 12 | "parserOptions": { 13 | "sourceType": "module" 14 | }, 15 | "rules": { 16 | "indent": [ 17 | "error", 18 | 4, 19 | { 20 | "SwitchCase": 1 21 | } 22 | ], 23 | "quotes": [ 24 | "error", 25 | "single" 26 | ], 27 | "semi": [ 28 | "error", 29 | "never" 30 | ], 31 | "no-dupe-args": "error", 32 | "no-extra-semi": "error", 33 | "no-multi-spaces": "error", 34 | "no-redeclare": "error", 35 | "comma-spacing": [ 36 | "error", 37 | { 38 | "before": false, 39 | "after": true 40 | } 41 | ], 42 | "func-call-spacing": "error", 43 | "key-spacing": [ 44 | "error", 45 | { 46 | "beforeColon": false, 47 | "afterColon": true, 48 | "mode": "strict" 49 | } 50 | ], 51 | "keyword-spacing": [ 52 | "error", 53 | ], 54 | "space-before-blocks": "error", 55 | "space-before-function-paren": [ 56 | "error", 57 | { 58 | "anonymous": "always", 59 | "named": "always", 60 | "asyncArrow": "always" 61 | } 62 | ], 63 | "space-infix-ops": "error", 64 | "space-unary-ops": [ 65 | "error", 66 | { 67 | "words": true, 68 | "nonwords": false 69 | } 70 | ], 71 | "arrow-spacing": "error", 72 | "constructor-super": "error", 73 | "no-const-assign": "error", 74 | "no-this-before-super": "error", 75 | "no-var": "error" 76 | } 77 | } -------------------------------------------------------------------------------- /demo/simulation-y-demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | simulation-scroll-y demo 8 | 33 | 34 | 35 | 36 | 37 | 38 |
39 |
40 |
41 |
42 |
43 | 44 | 45 | 46 | 63 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /demo/simulation-x-demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | simulation-scroll-x demo 8 | 34 | 35 | 36 | 37 | 38 | 39 |
40 |
41 |
42 |
43 |
44 | 45 | 46 | 47 | 64 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /demo/2d-scroll-demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 2D scroll demo 8 | 34 | 35 | 36 | 37 | 38 | 39 |
40 |
41 |
42 |
43 |
44 | 45 | 46 | 47 | 48 | 65 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /demo/scroll-to-y.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | scroll-to-y demo 8 | 33 | 34 | 35 | 36 | 37 | 38 |
39 |
40 |
41 |
42 |
43 | 44 | 45 | 46 | 64 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /demo/fingerd-scale-demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | Scale Demo 8 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 |
43 | Zoom gestures in the blue area
44 | (译:在蓝色区域进行缩放手势操作) 45 |
46 | 47 | 48 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /demo/scroll-to-x.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | scroll-to-x demo 8 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 |
48 |
49 |
50 | 51 | 52 | 53 | 71 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /demo/fingerd-number.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | fingerNumber Demo 8 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | Touch and slide out of the blue area, observe the difference between native event.touches.length and fingerNumber
36 | (译:手持触摸蓝色区域,并划出蓝色区域,观察原生 event.touches.length 与 fingerNumber 的区别) 37 |

38 |

39 |
40 | 41 | 42 | 43 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /test/unit/index.spec.js: -------------------------------------------------------------------------------- 1 | import Fmover from 'Fmover' 2 | 3 | describe('Initialization', () => { 4 | describe('Whether to use new', () => { 5 | it('Do not use new', () => { 6 | let isWarned = false 7 | try { 8 | Fmover() 9 | } catch (e) { 10 | if (e.toString() === 'TypeError: Cannot call a class as a function') { 11 | isWarned = true 12 | } 13 | } 14 | expect(isWarned).toBe(true) 15 | }) 16 | describe('Use new', () => { 17 | describe('parameter:opt.el', () => { 18 | it('The opt.el parameter is not passed', () => { 19 | let isWarned = false 20 | try { 21 | new Fmover() 22 | } catch (e) { 23 | if (e.toString() === 'TypeError: This is an invalid selector: undefined') { 24 | isWarned = true 25 | } 26 | } 27 | expect(isWarned).toBe(true) 28 | }) 29 | 30 | it('Pass the opt.el parameter', () => { 31 | let isWarned = false 32 | let dom = document.createElement('div') 33 | dom.id = 'test' 34 | document.body.appendChild(dom) 35 | try { 36 | new Fmover({ 37 | el: '#test' 38 | }) 39 | } catch (e) { 40 | isWarned = true 41 | } 42 | expect(isWarned).toBe(false) 43 | }) 44 | }) 45 | 46 | describe('parameter:opt.plugins', () => { 47 | it('Pass the opt.plugins parameter', () => { 48 | let testPlugin = function () { 49 | return function () { 50 | return { 51 | init: function (fmover) { 52 | expect(fmover instanceof Fmover).toBe(true) 53 | } 54 | } 55 | } 56 | } 57 | let isWarned = false 58 | let dom = document.createElement('div') 59 | dom.id = 'test2' 60 | document.body.appendChild(dom) 61 | 62 | new Fmover({ 63 | el: '#test2', 64 | plugins: [ 65 | testPlugin() 66 | ] 67 | }) 68 | 69 | }) 70 | 71 | }) 72 | }) 73 | }) 74 | 75 | }) -------------------------------------------------------------------------------- /demo/simulation-event-demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | event demo 8 | 33 | 34 | 35 | 36 | 37 | 38 |
39 |
40 |
41 |
42 |
43 | 44 | 45 | 46 | 63 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /test/unit/util.spec.js: -------------------------------------------------------------------------------- 1 | import * as util from 'util' 2 | let dom = null 3 | describe('Detection tool function', () => { 4 | 5 | beforeEach(() => { 6 | dom = document.createElement('div') 7 | document.body.appendChild(dom) 8 | }) 9 | 10 | afterEach(() => { 11 | dom.parentNode.removeChild(dom) 12 | }) 13 | 14 | describe('toArray', () => { 15 | it('If the argument is a array-like then the return value should also be an array', () => { 16 | let fakeArray = { 17 | 0: 'a', 18 | 1: 'b', 19 | 2: 'c', 20 | length: 3 21 | } 22 | let val = util.toArray(fakeArray) 23 | expect(Array.isArray(val)).toBe(true) 24 | }) 25 | 26 | it('If the argument is an array, the array is returned directly', () => { 27 | let arr = [1, 2, 3] 28 | let val = util.toArray(arr) 29 | expect(Array.isArray(val)).toBe(true) 30 | }) 31 | }) 32 | 33 | describe('parentNode', () => { 34 | it('Gets the parent of the element', () => { 35 | let val = util.parentNode(dom) 36 | expect((dom === null || dom instanceof Element)).toBe(true) 37 | }) 38 | }) 39 | 40 | describe('getAbsMaxFromArray', () => { 41 | it('Gets the maximum value in the array', () => { 42 | let arr = [1, 2, 3, 4, 5] 43 | let val = util.getAbsMaxFromArray(arr) 44 | expect(val).toBe(5) 45 | }) 46 | }) 47 | 48 | describe('is3DMatrix', () => { 49 | it('Determines whether the element applies the 3d transform', () => { 50 | let val 51 | 52 | dom.style.webkitTransform = 'rotateX(30deg)' 53 | val = util.is3DMatrix(dom) 54 | expect(val).toBe(true) 55 | 56 | dom.style.webkitTransform = 'rotateZ(30deg)' 57 | val = util.is3DMatrix(dom) 58 | expect(val).toBe(false) 59 | }) 60 | }) 61 | 62 | describe('getRelativeRect', () => { 63 | it('The distance from the element to the positioning parent should match the expectation', () => { 64 | dom.style.cssText = 'margin: 100px; width: 50px; height: 50px;' 65 | document.body.style.cssText = 'position: absolute;' 66 | let val = util.getRelativeRect(document.body, dom) 67 | expect(val.top).toBe(100) 68 | expect(val.left).toBe(100) 69 | }) 70 | }) 71 | 72 | describe('isInElement', () => { 73 | it('The positional relationship between elements should be in line with expectations', () => { 74 | let val 75 | 76 | val = util.isInElement(document.body, dom) 77 | expect(val).toBe(true) 78 | val = util.isInElement(dom, document.body) 79 | expect(val).toBe(false) 80 | }) 81 | }) 82 | }) -------------------------------------------------------------------------------- /demo/load-more-demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | Load more demo 8 | 39 | 40 | 41 | 42 | 43 | 44 |
45 |
46 |
47 | 48 |
Load more
49 |
50 |
51 | 52 | 53 | 54 | 71 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /src/vue-component/simulation-scroll-y.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 100 | -------------------------------------------------------------------------------- /src/moved/moved.js: -------------------------------------------------------------------------------- 1 | import TW from './tw' 2 | import { 3 | getStyle, 4 | transform, 5 | getPropFromMatrix 6 | } from '../shared/util' 7 | import Animationframe from './animationframe' 8 | 9 | const MOVE_STATUS = { 10 | start: 'start', 11 | stop: 'stop' 12 | } 13 | 14 | let cid = 0 15 | export default class Moved { 16 | constructor () { 17 | this.moveStatus = MOVE_STATUS.stop 18 | this.isArrivals = false 19 | /* istanbul ignore if */ 20 | if (!(this instanceof Moved)) { 21 | throwError('Moved is a constructor and should be called with the `new` keyword') 22 | } 23 | } 24 | 25 | start (options) { 26 | if (this.moveStatus === MOVE_STATUS.start) { 27 | return 28 | } 29 | options = options ? options : {} 30 | let {el, target, type, time, endCallBack, inCallBack, s} = options 31 | this.isArrivals = false 32 | this.id = cid++ 33 | this.el = el 34 | this.target = target 35 | this.type = type || 'easeOutStrong' 36 | this.time = time <= 1 ? 1 : time 37 | this.endCallBack = endCallBack 38 | this.inCallBack = inCallBack 39 | this.currentPos = {} 40 | this.moveStatus = MOVE_STATUS.start 41 | 42 | this.b = {} 43 | this.c = {} 44 | this.d = this.time 45 | this.s = s 46 | for (let attr in this.target) { 47 | this.b[attr] = getPropFromMatrix(this.el)[attr] 48 | this.c[attr] = this.target[attr] - this.b[attr] 49 | if (this.c[attr] === 0) { 50 | this.isArrivals = true 51 | } 52 | } 53 | if (this.isArrivals) { 54 | this.endCallBack && this.endCallBack(this.b) 55 | this.moveStatus = MOVE_STATUS.stop 56 | return false 57 | } 58 | 59 | this.anim = new Animationframe(this._moveHandle.bind(this)) 60 | } 61 | 62 | stop (callback) { 63 | if (this.moveStatus === MOVE_STATUS.stop || !this.anim) { 64 | return this 65 | } 66 | this.moveStatus = MOVE_STATUS.stop 67 | this.anim.cancel() 68 | for (let attr in this.target) { 69 | transform(this.el, attr, this.currentPos[attr]) 70 | } 71 | callback && callback(this.currentPos) 72 | return this 73 | } 74 | 75 | transform (el, attr, val) { 76 | transform(el, attr, val) 77 | } 78 | 79 | getPropFromMatrix (el) { 80 | return getPropFromMatrix(el) 81 | } 82 | 83 | _moveHandle (t) { 84 | t = t >= this.d ? this.d : t 85 | for (let attr in this.target) { 86 | this.currentPos[attr] = Moved.Tween[this.type](t, this.b[attr], this.c[attr], this.d, this.s) 87 | transform(this.el, attr, this.currentPos[attr]) 88 | } 89 | this.moveStatus = MOVE_STATUS.start 90 | this.inCallBack && this.inCallBack.call(this, this.currentPos) 91 | 92 | if (t >= this.d) { 93 | this.stop(this.endCallBack) 94 | } else { 95 | this.anim.request() 96 | } 97 | } 98 | } 99 | 100 | Moved.Tween = TW 101 | -------------------------------------------------------------------------------- /demo/simulation-y-demo-vue.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vue & simulation-scroll-y demo 7 | 32 | 33 | 34 | 35 | 36 | 37 |
38 |
39 |
40 |

{{obj.txt}}

41 |
42 |
43 |
44 | 45 | 46 | 47 | 48 | 67 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /src/plugins/simulation-scroll-x/dist/simulation-scroll-x.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * simulation-scroll-x.min.js v1.4.2 3 | * (c) 2018 HcySunYang 4 | * Released under the MIT License. 5 | */!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):n.simulationScrollX=t()}(this,function(){"use strict";return function(n){return function(t){function e(n,t){if(b)return void s(b,"width: "+t+"px;");b=document.createElement("span"),s(b,"\n position: absolute;\n z-index: 10000000;\n left:0;\n bottom: 3px;\n height: 3px; \n width: "+t+"px; \n background-color: #000;\n opacity: 0;\n border-radius: 1.5px;\n transition: opacity .2s;\n -webkit-transition: opacity .2s;\n "),"static"===a(n,"position")&&s(n,"position: relative;"),n.appendChild(b)}function o(n){var t=n,e=0;tM-S&&(e=M-S),t=X):t>T&&(e=4*(t-T),e>M-S&&(e=M-S),t=T+e);var o=M-e;b.style.width=o+"px",w.transform(b,"translateX",t)}var r=t.Moved,a=t.getStyle,i=t.extend,s=t.cssText,c=t.getRelativeRect,l=t.isInElement,u=t.throwError,f=function(){},p=i({scrollBar:!0,bounce:!0,onTouchMove:f,onTransMove:f,onTransMoveEnd:f,onMotionStop:f},n),d=null,m=null,h=0,v=0,g=0,b=null,M=0,S=7,x=0,y=0,X=0,T=0,w=new r,k=0,B=0,E=0,O="easeOutStrong",I=0,z=!1,C=!1;return{init:function(n){d=n.el,m=d.parentNode,"static"===a(d,"position")&&s(d,"position: relative; z-index: 10;"),this.refreshSize()},start:function(n){n.fingers[0];O="easeOutStrong",z=!1,C=!1,w.stop(function(n){k=n.translateX,p.onMotionStop(k)})},move:function(n){if("start"===w.moveStatus)return!1;var t=n.fingers[0],e=t.fingerInElement;if(B=k+t.distanceX,!e)return C||(C=!0,this.makeMove(t)),!1;B>x||y>0?B=p.bounce?.5*B:x:B2e3&&(o=2e3),o}var e;I=n.transTime,k=B,E=k+n.transDistanceX,k>x||y>0?(E=x,O="easeOutStrong",I=p.bounce?500:n.transTime,z=!0):kx&&(p.bounce?(E=x,O="backOut",I=t(x)):O="easeOutStrong"),Math.abs(n.transDistanceX)>100||z?this.wrapMove(E,I,O,e):p.scrollBar&&s(b,"opacity: 0;")},wrapMove:function(n,t,e,r){w.start({el:d,target:{translateX:n},type:e,time:t,s:r,inCallBack:function(n){k=n.translateX,p.bounce||(k>=x&&w.stop(function(n){k=x,w.transform(d,"translateX",k)}),k<=y&&w.stop(function(n){k=y,w.transform(d,"translateX",y)})),p.scrollBar&&o(-n.translateX*g),p.onTransMove.call(this,k)},endCallBack:function(n){k=n.translateX,p.onTransMoveEnd.call(this,k),p.onMotionStop(k),p.scrollBar&&s(b,"opacity: 0;")}})},scrollTo:function(n,t,e){var o;"string"==typeof n?o=document.querySelector(n):n instanceof Element&&(o=n),o&&(l(d,o)||u("ScrollTo function argument error, `child` must be a child of `parent`"),n=-c(d,o).left),e&&n>=x?n=x:e&&y<0&&n=0&&(n=x),k=n,this.wrapMove(n,t,"easeOutStrong")},refreshSize:function(){h=parseFloat(a(d,"width")),v=m.clientWidth,y=v-h,x=0,y>0&&(p.scrollBar=!1),p.scrollBar&&(g=v/h,M=v*g,S=M6;return n.translateX=i?r[12]:r[4],n.translateY=i?r[13]:r[5],n.translateZ=i?r[14]:0,n.scaleX=void 0!==e.transform.scaleX?e.transform.scaleX:1,n.scaleY=void 0!==e.transform.scaleY?e.transform.scaleY:1,n.scaleZ=void 0!==e.transform.scaleZ?e.transform.scaleZ:1,n.rotateX=void 0!==e.transform.rotateX?e.transform.rotateX:0,n.rotateY=void 0!==e.transform.rotateY?e.transform.rotateY:0,n.rotateZ=void 0!==e.transform.rotateZ?e.transform.rotateZ:0,n.skewX=void 0!==e.transform.skewX?e.transform.skewX:0,n.skewY=void 0!==e.transform.skewY?e.transform.skewY:0,n}var n={easeOutStrong:function(t,e,r,s){return-r*((t=t/s-1)*t*t*t-1)+e},backOut:function(t,e,r,s,a){return void 0===a&&(a=.7),r*((t=t/s-1)*t*((a+1)*t+a)+1)+e}},i=requestAnimationFrame||webkitRequestAnimationFrame,o=cancelAnimationFrame||webkitCancelAnimationFrame,c=function(t){this.handle=t,this.id=0,this._init()};c.prototype._init=function(){this.start=e(),this.request()},c.prototype._fakeHandle=function(){var t=e()-this.start;this.handle(t)},c.prototype._requestAnimFn=function(t){return i?i(t):setTimeout(t,1e3/60)},c.prototype._cancelAnimFn=function(t){o?o(t):clearTimeout(t)},c.prototype.request=function(){this.id=this._requestAnimFn(this._fakeHandle.bind(this))},c.prototype.cancel=function(){this._cancelAnimFn(this.id)};var l={start:"start",stop:"stop"},u=0,f=function t(){this.moveStatus=l.stop,this.isArrivals=!1,this instanceof t||throwError("Moved is a constructor and should be called with the `new` keyword")};return f.prototype.start=function(t){var e=this;if(this.moveStatus!==l.start){t=t||{};var r=t.el,s=t.target,n=t.type,i=t.time,o=t.endCallBack,f=t.inCallBack,h=t.s;this.isArrivals=!1,this.id=u++,this.el=r,this.target=s,this.type=n||"easeOutStrong",this.time=i<=1?1:i,this.endCallBack=o,this.inCallBack=f,this.currentPos={},this.moveStatus=l.start,this.b={},this.c={},this.d=this.time,this.s=h;for(var m in e.target)e.b[m]=a(e.el)[m],e.c[m]=e.target[m]-e.b[m],0===e.c[m]&&(e.isArrivals=!0);if(this.isArrivals)return this.endCallBack&&this.endCallBack(this.b),this.moveStatus=l.stop,!1;this.anim=new c(this._moveHandle.bind(this))}},f.prototype.stop=function(t){var e=this;if(this.moveStatus===l.stop||!this.anim)return this;this.moveStatus=l.stop,this.anim.cancel();for(var r in e.target)s(e.el,r,e.currentPos[r]);return t&&t(this.currentPos),this},f.prototype.transform=function(t,e,r){s(t,e,r)},f.prototype.getPropFromMatrix=function(t){return a(t)},f.prototype._moveHandle=function(t){var e=this;t=t>=this.d?this.d:t;for(var r in e.target)e.currentPos[r]=f.Tween[e.type](t,e.b[r],e.c[r],e.d,e.s),s(e.el,r,e.currentPos[r]);this.moveStatus=l.start,this.inCallBack&&this.inCallBack.call(this,this.currentPos),t>=this.d?this.stop(this.endCallBack):this.anim.request()},f.Tween=n,f}); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 |

5 | 6 | 7 | 8 | 9 | 10 |

11 | 12 | ## Intro 13 | 14 | `finger-mover` is a motion effect library that integrates 15 | [Fingerd (a development kit for finger unit event management in mobile development)](https://fmover.hcysun.me/#/package/fingerd) 16 | and 17 | [Moved (a micro movement framework)](https://fmover.hcysun.me/#/package/moved). `finger-mover` provides many useful plugins, such as [Vertical scroll simulation (simulation-scroll-y.js)](https://fmover.hcysun.me/#/plugins/simulation-scroll-y), [Horizontal scroll simulation (simulation-scroll-x.js)](https://fmover.hcysun.me/#/plugins/simulation-scroll-x) and so on. 18 | 19 | ## Docs 20 | 21 | [English](https://fmover.hcysun.me/#/home) • [中文文档](https://fmover.hcysun.me/#/zh-cn/) 22 | 23 | ## Features 24 | 25 | * Just 11.12KB after compression 26 | 27 | * Plugin support, motion components are available as plug-ins, thsi is a plug-in list: 28 | * [Vertical scroll simulation](https://fmover.hcysun.me/#/plugins/simulation-scroll-y) 29 | * [Horizontal scroll simulation](https://fmover.hcysun.me/#/plugins/simulation-scroll-x) 30 | * [2D scrolling](https://fmover.hcysun.me/#/plugins/2d-scroll) 31 | * [Horizontal slide show](https://fmover.hcysun.me/#/plugins/fmover-slide-x) 32 | * [Vertical slide show](https://fmover.hcysun.me/#/plugins/fmover-slide-y) 33 | 34 | ## Install 35 | 36 | #### NPM 37 | 38 | ``` 39 | npm install --save finger-mover 40 | ``` 41 | 42 | #### yarn 43 | 44 | ``` 45 | yarn add finger-mover 46 | ``` 47 | 48 | `finger-mover` released as a `umd` module. You can use it in any way for your favorite. You can get global variable `Fmover` by serving as ` 45 | 46 | 47 | 48 |
49 |
50 |
Pull down to refresh
51 | 52 |
53 |
54 |
55 | 56 | 57 | 58 | 75 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /src/plugins/fmover-slide-y/dist/fmover-slide-y.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * fmover-slide-y.min.js v1.4.2 3 | * (c) 2018 HcySunYang 4 | * Released under the MIT License. 5 | */!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.fmoverSlideY=e()}(this,function(){"use strict";return function(t){return function(e){var n=e.Moved,i=e.getStyle,o=e.extend,r=e.cssText,a=(e.getRelativeRect,e.isInElement,e.throwError,e.toArray),s={top:"top",bottom:"bottom"},l=null,h=null,d=null,c=0,u=0,f=0,x=0,p=0,v=0,m=new n,g=0,I=!1,y=null,b=!1,C=!1,S=function(){},Y=o({startSlide:1,autoplay:0,autoplayDir:s.top,loop:!0,times:500,bounce:!0,touchable:!0,onInit:S,onTouchStart:S,onTouchMove:S,onTouchEnd:S,onTransStart:S,onTransMove:S,onTransEnd:S,onChangeStart:S,onChange:S,onChangeEnd:S,onRefresh:S},t);return{index:1,get slideIndex(){return this.redressIndex(this.index)},get slideNumber(){return c},init:function(t){l=t.el,h=l.parentNode,this.refreshWrap(!0),Y.onInit.call(this)},start:function(t){if(0!==t.changeFingerIndex||!Y.touchable)return!1;I=!1,C=!1,clearInterval(y),m.stop(function(t){p=t.translateY}),Y.autoplay&&clearInterval(y),this.index>c?(p+=c*f,this.index=1):0===this.index&&(this.index=c,p-=c*f),m.transform(l,"translateY",p),Y.onTouchStart.call(this,p)},move:function(t){var e=t.fingers[0];return!!Y.touchable&&(e.fingerInElement?(v=p+e.distanceY,Y.loop||(v>0?v=Y.bounce?.5*v:0:vc&&(this.index=1),this.onChangeStart(this.redressIndex(this.index),s.bottom),this.makeMove()},slideTo:function(t,e){if(b||this.slideIndex===t)return!1;if(b=!0,this.index!==t){var n=this.index>t?s.bottom:s.top;this.index=this.limitIndex(t),this.onChangeStart(this.redressIndex(this.index),n),this.makeMove(e)}},initAutoplay:function(){var t=this;y=setInterval(function(){Y.autoplayDir===s.top?t.next():t.prev()},Y.autoplay)},wrapMove:function(t){var e=Y.loop||!Y.loop&&this.index!==c,n=Y.loop||!Y.loop&&1!==this.index;e&&t.direction.top&&Math.abs(t.yv)>.5&&t.distanceY<0||e&&t.distanceY<-f/2?(this.index++,this.onChangeStart(this.redressIndex(this.index),s.top)):(n&&t.direction.bottom&&Math.abs(t.yv)>.5&&t.distanceY>0||n&&t.distanceY>f/2)&&(this.index--,this.onChangeStart(this.redressIndex(this.index),s.bottom)),this.makeMove()},makeMove:function(t){var e=this;Y.onTransStart.call(this,p),Y.loop?(this.index<0?this.index=0:this.index>c+1&&(this.index=c+1),p=-this.index*f):(this.index<1?this.index=1:this.index>c&&(this.index=c),p=-(this.index-1)*f),m.start({el:l,target:{translateY:p},inCallBack:function(t){Y.onTransMove.call(e,t.translateY),C&&Y.onChange.call(e,t.translateY)},endCallBack:function(t){b=!1,Y.loop&&e.index>c?(p+=c*f,m.transform(l,"translateY",p),e.index=1):Y.loop&&0===e.index&&(e.index=c,p-=c*f,m.transform(l,"translateY",p)),Y.onTransEnd.call(e,t.translateY),C&&Y.onChangeEnd.call(e,t.translateY)},time:void 0===t?Y.times:t})},onChangeStart:function(t,e){C=!0,Y.onChangeStart.call(this,t,e)},redressIndex:function(t){return 0===t?c:t>c?1:t},limitIndex:function(t){return t>c?c:t<1?1:t},destroy:function(){clearInterval(y)}}}}}); -------------------------------------------------------------------------------- /src/plugins/fmover-slide-x/dist/fmover-slide-x.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * fmover-slide-x.min.js v1.4.2 3 | * (c) 2018 HcySunYang 4 | * Released under the MIT License. 5 | */!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.fmoverSlideX=e()}(this,function(){"use strict";return function(t){return function(e){var n=e.Moved,i=e.getStyle,o=e.extend,r=e.cssText,a=(e.getRelativeRect,e.isInElement,e.throwError,e.toArray),s={left:"left",right:"right"},l=null,h=null,d=null,c=0,u=0,f=0,x=0,p=0,v=0,g=new n,m=0,I=!1,y=null,b=!1,C=!1,S=function(){},X=o({startSlide:1,autoplay:0,autoplayDir:s.left,loop:!0,times:500,bounce:!0,touchable:!0,onInit:S,onTouchStart:S,onTouchMove:S,onTouchEnd:S,onTransStart:S,onTransMove:S,onTransEnd:S,onChangeStart:S,onChange:S,onChangeEnd:S,onRefresh:S},t);return{index:1,get slideIndex(){return this.redressIndex(this.index)},get slideNumber(){return c},init:function(t){l=t.el,h=l.parentNode,this.refreshWrap(!0),X.onInit.call(this)},start:function(t){if(0!==t.changeFingerIndex||!X.touchable)return!1;I=!1,C=!1,clearInterval(y),g.stop(function(t){p=t.translateX}),X.autoplay&&clearInterval(y),this.index>c?(p+=c*f,this.index=1):0===this.index&&(this.index=c,p-=c*f),g.transform(l,"translateX",p),X.onTouchStart.call(this,p)},move:function(t){var e=t.fingers[0];return!!X.touchable&&(e.fingerInElement?(v=p+e.distanceX,X.loop||(v>0?v=X.bounce?.5*v:0:vc&&(this.index=1),this.onChangeStart(this.redressIndex(this.index),s.right),this.makeMove()},slideTo:function(t,e){if(b||this.slideIndex===t)return!1;if(b=!0,this.index!==t){var n=this.index>t?s.right:s.left;this.index=this.limitIndex(t),this.onChangeStart(this.redressIndex(this.index),n),this.makeMove(e)}},initAutoplay:function(){var t=this;y=setInterval(function(){X.autoplayDir===s.left?t.next():t.prev()},X.autoplay)},wrapMove:function(t){var e=X.loop||!X.loop&&this.index!==c,n=X.loop||!X.loop&&1!==this.index;e&&t.direction.left&&Math.abs(t.xv)>.5&&t.distanceX<0||e&&t.distanceX<-f/2?(this.index++,this.onChangeStart(this.redressIndex(this.index),s.left)):(n&&t.direction.right&&Math.abs(t.xv)>.5&&t.distanceX>0||n&&t.distanceX>f/2)&&(this.index--,this.onChangeStart(this.redressIndex(this.index),s.right)),this.makeMove()},makeMove:function(t){var e=this;X.onTransStart.call(this,p),X.loop?(this.index<0?this.index=0:this.index>c+1&&(this.index=c+1),p=-this.index*f):(this.index<1?this.index=1:this.index>c&&(this.index=c),p=-(this.index-1)*f),g.start({el:l,target:{translateX:p},inCallBack:function(t){X.onTransMove.call(e,t.translateX,f,e.slideNumber),C&&X.onChange.call(e,t.translateX)},endCallBack:function(t){b=!1,X.loop&&e.index>c?(p+=c*f,g.transform(l,"translateX",p),e.index=1):X.loop&&0===e.index&&(e.index=c,p-=c*f,g.transform(l,"translateX",p)),X.onTransEnd.call(e,t.translateX),C&&X.onChangeEnd.call(e,t.translateX)},time:void 0===t?X.times:t})},onChangeStart:function(t,e){C=!0,X.onChangeStart.call(this,t,e)},redressIndex:function(t){return 0===t?c:t>c?1:t},limitIndex:function(t){return t>c?c:t<1?1:t},destroy:function(){clearInterval(y)}}}}}); -------------------------------------------------------------------------------- /demo/mover-demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | Moved Demo 8 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | Start 42 | Stop 43 | Reset 44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | 54 | 55 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | throwError, 3 | getStyle, 4 | now as timeNow, 5 | extend, 6 | is3DMatrix, 7 | cssText, 8 | getRelativeRect, 9 | isInElement, 10 | transform, 11 | getPropFromMatrix, 12 | toArray 13 | } from './shared/util' 14 | import Moved from './moved/moved' 15 | import Animationframe from './moved/animationframe' 16 | import TW from './moved/tw' 17 | import Fingerd from './fingerd/fingerd' 18 | 19 | export default class Fmover { 20 | constructor (options) { 21 | options = options ? options : {} 22 | /* istanbul ignore if */ 23 | if (!(this instanceof Fmover)) { 24 | throwError('Fmover is a constructor and should be called with the `new` keyword') 25 | } 26 | this._init(options) 27 | } 28 | 29 | _init (options) { 30 | this.el = typeof options.el === 'string' ? document.querySelector(options.el) : options.el 31 | if (!this.el) { 32 | throwError(`This is an invalid selector: ${options.el}`) 33 | } 34 | 35 | this.fingerd = new Fingerd({ 36 | element: this.el 37 | }) 38 | this.plugins = options.plugins || [] 39 | this.pluginsStorage = [] 40 | 41 | this._initPlugins() 42 | this._initStyle() 43 | this._initEvents() 44 | } 45 | 46 | _initPlugins () { 47 | let pluginLen = this.plugins.length 48 | for (let i = 0; i < pluginLen; i++) { 49 | this[i] = this.plugins[i](Fmover) 50 | this.pluginsStorage.push(this[i]) 51 | } 52 | 53 | let pluginStorLen = this.pluginsStorage.length 54 | for (let i = 0; i < pluginStorLen; i++) { 55 | this.pluginsStorage[i].init && this.pluginsStorage[i].init(this) 56 | } 57 | } 58 | 59 | _initStyle () { 60 | if (!is3DMatrix(this.el)) { 61 | transform(this.el, 'translateZ', 0.01) 62 | } 63 | } 64 | 65 | _initEvents () { 66 | const el = this.el 67 | 68 | el.addEventListener('touchstart', this._start.bind(this), false) 69 | el.addEventListener('touchmove', this._move.bind(this), false) 70 | el.addEventListener('touchend', this._end.bind(this), false) 71 | el.addEventListener('touchcancel', this._cancel.bind(this), false) 72 | } 73 | /* istanbul ignore next */ 74 | _start (event) { 75 | const F = this.fingerd.injectEvent(event) 76 | let fingerLen = F.fingers.length 77 | for (let i = 0; i < fingerLen; i++) { 78 | F.fingers[i].el = this.el 79 | } 80 | 81 | let pluginLen = this.pluginsStorage.length 82 | for (let i = 0; i < pluginLen; i++) { 83 | this.pluginsStorage[i].start && this.pluginsStorage[i].start(F) 84 | } 85 | } 86 | /* istanbul ignore next */ 87 | _move (event) { 88 | const F = this.fingerd.injectEvent(event) 89 | let returnVal 90 | let pluginStorLen = this.pluginsStorage.length 91 | for (let i = 0; i < pluginStorLen; i++) { 92 | returnVal = this.pluginsStorage[i].move && this.pluginsStorage[i].move(F) 93 | } 94 | 95 | if (typeof returnVal !== 'undefined' && !returnVal) { 96 | event.stopPropagation() 97 | } 98 | event.preventDefault() 99 | } 100 | /* istanbul ignore next */ 101 | _end (event) { 102 | const F = this.fingerd.injectEvent(event) 103 | 104 | let pluginStorLen = this.pluginsStorage.length 105 | for (let i = 0; i < pluginStorLen; i++) { 106 | this.pluginsStorage[i].end && this.pluginsStorage[i].end(F) 107 | } 108 | } 109 | /* istanbul ignore next */ 110 | _cancel (event) { 111 | const F = this.fingerd.injectEvent(event) 112 | 113 | let pluginStorLen = this.pluginsStorage.length 114 | for (let i = 0; i < pluginStorLen; i++) { 115 | this.pluginsStorage[i].cancel && this.pluginsStorage[i].cancel(F) 116 | } 117 | 118 | event.preventDefault() 119 | } 120 | 121 | } 122 | 123 | installGlobal(Fmover) 124 | 125 | function installGlobal (Fmover) { 126 | Fmover.Moved = Moved 127 | Fmover.Fingerd = Fingerd 128 | Fmover.extend = extend 129 | Fmover.now = timeNow 130 | Fmover.getStyle = getStyle 131 | Fmover.cssText = cssText 132 | Fmover.getPropFromMatrix = getPropFromMatrix 133 | Fmover.getRelativeRect = getRelativeRect 134 | Fmover.isInElement = isInElement 135 | Fmover.throwError = throwError 136 | Fmover.toArray = toArray 137 | } -------------------------------------------------------------------------------- /demo/slide-with-scroll.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | slide with scroll demo 8 | 70 | 71 | 72 | 73 | 74 |
75 |
Food
76 |
Movie
77 |
Hotel
78 | 79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
Movie
88 |
Hotel
89 |
90 | 93 |
94 | 95 | 96 | 97 | 98 | 99 | 116 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /demo/contacts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | contacts demo 8 | 57 | 58 | 59 | 60 | 61 | 62 |
63 |
64 |
65 | 75 |
76 |
77 | 80 |
81 | 82 | 83 | 84 | 114 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /src/plugins/simulation-scroll-y/dist/simulation-scroll-y.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * simulation-scroll-y.min.js v1.4.2 3 | * (c) 2018 HcySunYang 4 | * Released under the MIT License. 5 | */!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):t.simulationScrollY=n()}(this,function(){"use strict";return function(t){return function(n){function e(t,n){if(S)return void s(S,"height: "+n+"px;");S=document.createElement("span"),s(S,"\n position: absolute;\n z-index: 10000000;\n top:0;\n right: 3px;\n width: 3px; \n height: "+n+"px; \n background-color: #000;\n border-radius: 1.5px;\n transition: opacity .2s;\n -webkit-transition: opacity .2s;\n transform: translateZ(0.01px);\n opacity: 0;\n "),t.appendChild(S)}function o(t){var n=t,e=0;nb-w&&(e=b-w),n=E):n>y&&(e=4*(n-y),e>b-w&&(e=b-w),n=y+e);var o=b-e;S.style.height=o+"px",B.transform(S,"translateY",n),B.transform(S,"translateZ",.01)}var r=n.Moved,a=(n.transform,n.getStyle),i=n.extend,s=n.cssText,l=n.getPropFromMatrix,c=n.getRelativeRect,u=n.isInElement,f=n.throwError,d=function(){},p=i({scrollBar:!0,bounce:!0,unidirectional:!1,pullDown:{use:!1,distance:50,onBegin:d,onActive:d,onAfter:d},loadMore:{distance:0,onLoadMore:d},onTouchStart:d,onTouchMove:d,onTouchEnd:d,onTransMove:d,onTransMoveEnd:d,onMotionStop:d},t),h=null,m=null,v=0,g=0,M=0,S=null,b=0,w=7,T=0,Y=0,D=0,x=0,E=0,y=0,B=new r,k=0,O=0,z="easeOutStrong",I=0,A=!1,F=!1,C=!1,L=!1,N=0,R=!1,X=!1,Z=!1,j=!1,q=!1,H=!1,P=d,G=d,J={},K=!1,Q=!1,U=p.scrollBar;return{init:function(t){h=t.el,m=h.parentNode,"static"===a(h,"position")&&s(h,"position: relative; z-index: 10;"),"static"===a(m,"position")&&s(m,"position: relative;"),this.refreshSize()},start:function(t){t.fingers[0];z="easeOutStrong",F=!1,j="stop"!==B.moveStatus,C=!1,L=!1,K=!1,Q=!1,J={},k>T&&(k/=.5),j||p.onTouchStart(j),B.stop(function(t){Z=!1,N=k=t.translateY,p.onTouchStart(!0),p.onMotionStop(N)})},move:function(t){if("start"===B.moveStatus)return!1;Z=!0;var n=t.fingers[0];if(!n.fingerInElement)return F||(F=!0,this.makeMove(n)),!1;if(J=n.direction,(J.top||J.bottom)&&!K&&Math.abs(n.distanceY)>=10&&(Q=!0),(J.left||J.right)&&!Q&&Math.abs(n.distanceX)>=10&&(K=!0),Math.abs(n.distanceY)<10&&Math.abs(n.distanceX)<10)return!1;if(Q||!p.unidirectional){var e=n.distanceY>0?n.distanceY-10:n.distanceY+10;N=k+e,N>T||D>0?N=p.bounce?T+.5*(N-T):T:N0&&!R&&p.pullDown.onBegin&&p.pullDown.onBegin.call(this,N),p.onTouchMove.call(this,N)}return!(Q&&p.unidirectional||j)&&void 0},end:function(t){if(K&&!A)return p.onTouchEnd(B.moveStatus),!1;var n=t.fingers[0],e=t.changeFingerIndex,o=t.fingerNumber,r=n.fingerInElement;Z=!1,0===e&&0===o&&r&&this.makeMove(n),p.onTouchEnd("start"===B.moveStatus)},cancel:function(t){var n=t.fingers[0],e=t.changeFingerIndex,o=t.fingerNumber,r=n.fingerInElement;0===e&&0===o&&r&&(k+=n.distanceY)},makeMove:function(t){function n(n){var o=Math.abs(n-k)/Math.abs(t.transDistanceY)*t.transTime;return o<500?(o=500,e=2):o>2e3&&(o=2e3),o}var e;if(I=t.transTime,k=N,O=k+t.transDistanceY,p.pullDown&&p.pullDown.use&&k>=p.pullDown.distance&&!R)return R=!0,p.pullDown.onActive&&p.pullDown.onActive.call(this),T+=p.pullDown.distance,void this.scrollTo(p.pullDown.distance,300);p.pullDown&&p.pullDown.use&&k>T&&(L=!0),k>T||D>0?(O=T,z="easeOutStrong",I=p.bounce?500:t.transTime,A=!0):kT&&(p.bounce?(O=T,z="backOut",I=n(T)):z="easeOutStrong"),Math.abs(t.transDistanceY)>100||A?this.wrapMove(O,I,z,e):(p.scrollBar&&"start"!==B.moveStatus&&s(S,"opacity: 0;"),q&&this.refresh(),H&&this.loadEnd())},wrapMove:function(t,n,e,r){var a=this;B.start({el:h,target:{translateY:t},type:e,time:n,s:r||.7,inCallBack:function(t){k=t.translateY,p.bounce||(k>=T&&B.stop(function(t){k=T,B.transform(h,"translateY",k)}),k<=D&&B.stop(function(t){k=D,B.transform(h,"translateY",D)})),k<=x&&!X&&J.top&&(X=!0,p.loadMore.onLoadMore.call(a)),L&&p.pullDown.onAfter(t.translateY),p.scrollBar&&o(-t.translateY*M),p.onTransMove.call(this,k)},endCallBack:function(t){k=t.translateY,q&&a.refresh(),H&&a.loadEnd(),p.scrollBar&&s(S,"opacity: 0;"),p.onTransMoveEnd.call(this,k),j=!1,A=!1,p.onMotionStop(k)}})},scrollTo:function(t,n,e){var o;"string"==typeof t?o=document.querySelector(t):t instanceof Element&&(o=t),o&&(u(h,o)||f("ScrollTo function argument error, `child` must be a child of `parent`"),t=-c(h,o).top),e&&(t>T||D>0)?t=T:e&&tT&&(L=!0,this.scrollTo(T,500))},refreshSize:function(){v=parseFloat(a(h,"height")),g=m.clientHeight,D=g-v,Y=T=0,x=D<0?D+p.loadMore.distance:0,p.scrollBar=!(D>=0)&&U,p.scrollBar&&(M=g/v,b=g*M,w=b { 29 | for (let attr in f) { 30 | to[attr] = f[attr] 31 | } 32 | }) 33 | 34 | return to 35 | } 36 | export function cssText (el, cssText) { 37 | el.style.cssText = el.style.cssText + ' ' + cssText 38 | } 39 | 40 | export function getRelativeRect (parent, child) { 41 | let pos = { 42 | top: 0, 43 | left: 0 44 | } 45 | while (child !== parent) { 46 | pos.top += child.offsetTop 47 | pos.left += child.offsetLeft 48 | child = child.offsetParent 49 | } 50 | return pos 51 | } 52 | 53 | export function isInElement (parent, child) { 54 | let num = parent.compareDocumentPosition(child) 55 | 56 | if (num === 0 || num === 20) { 57 | return true 58 | } 59 | return false 60 | } 61 | 62 | export function is3DMatrix (el) { 63 | let matrix = getStyle(el, 'WebkitTransform') 64 | if (!matrix || matrix === 'none') { 65 | return false 66 | } 67 | let matrixArray = matrix.match(/[+-]?\d*[.]?\d+(?=,|\))/g) 68 | if (matrixArray.length > 6) { 69 | return true 70 | } 71 | return false 72 | } 73 | 74 | export function transform (el, attr, val) { 75 | let transString = '' 76 | 77 | el.transform = el.transform ? el.transform : Object.create(null) 78 | el.transform[attr] = val 79 | 80 | for (let a in el.transform) { 81 | switch (a) { 82 | case 'translateX': 83 | case 'translateY': 84 | case 'translateZ': 85 | transString += `${a}(${el.transform[a]}px) ` 86 | break 87 | case 'scaleX': 88 | case 'scaleY': 89 | case 'scaleZ': 90 | transString += `${a}(${el.transform[a]}) ` 91 | break 92 | case 'rotateX': 93 | case 'rotateY': 94 | case 'rotateZ': 95 | case 'skewX': 96 | case 'skewY': 97 | transString += `${a}(${el.transform[a]}deg) ` 98 | break 99 | } 100 | } 101 | cssText(el, `transform: ${transString}; -webkit-transform: ${transString};`) 102 | } 103 | 104 | export function getPropFromMatrix (el) { 105 | let matrix = getStyle(el, 'WebkitTransform') 106 | 107 | if (!matrix || matrix === 'none') { 108 | transform(el, 'translateZ', 0.01) 109 | } 110 | /* The element's dispaly attribute value is none */ 111 | if (matrix === 'none') { 112 | return {} 113 | } 114 | try { 115 | matrix = getStyle(el, 'WebkitTransform') 116 | .match(/[+-]?\d*[.]?\d+(?=,|\))/g) 117 | .map((o) => { 118 | return parseInt(o) 119 | }) 120 | } catch (e) {} 121 | 122 | let matrixLen = matrix.length 123 | let matrixObject = {} 124 | let is3D = matrixLen > 6 125 | 126 | matrixObject.translateX = is3D ? matrix[12] : matrix[4] 127 | matrixObject.translateY = is3D ? matrix[13] : matrix[5] 128 | matrixObject.translateZ = is3D ? matrix[14] : 0 129 | 130 | matrixObject.scaleX = typeof el.transform['scaleX'] !== 'undefined' 131 | ? el.transform['scaleX'] 132 | : 1 133 | matrixObject.scaleY = typeof el.transform['scaleY'] !== 'undefined' 134 | ? el.transform['scaleY'] 135 | : 1 136 | matrixObject.scaleZ = typeof el.transform['scaleZ'] !== 'undefined' 137 | ? el.transform['scaleZ'] 138 | : 1 139 | 140 | matrixObject.rotateX = typeof el.transform['rotateX'] !== 'undefined' 141 | ? el.transform['rotateX'] : 0 142 | matrixObject.rotateY = typeof el.transform['rotateY'] !== 'undefined' 143 | ? el.transform['rotateY'] : 0 144 | matrixObject.rotateZ = typeof el.transform['rotateZ'] !== 'undefined' 145 | ? el.transform['rotateZ'] : 0 146 | 147 | matrixObject.skewX = typeof el.transform['skewX'] !== 'undefined' 148 | ? el.transform['skewX'] : 0 149 | matrixObject.skewY = typeof el.transform['skewY'] !== 'undefined' 150 | ? el.transform['skewY'] : 0 151 | 152 | return matrixObject 153 | } 154 | 155 | export function getAbsMaxFromArray (arr) { 156 | let tempArr = arr.map((o) => { 157 | return Math.abs(o) 158 | }) 159 | let maxIndex = tempArr.indexOf(Math.max.apply(null, tempArr)) 160 | return arr[maxIndex] 161 | } -------------------------------------------------------------------------------- /demo/fmover-slide-y.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | slide-y demo 8 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
one
43 |
two
44 |
three
45 |
46 |
47 | 48 |
49 |
Prev
50 |
Next
51 |
52 | 53 |
54 |
Slide to 3
55 |
Switch to 3
56 |
57 | 58 |
59 |
Current index
60 |
Slide number
61 |
62 | 63 |
64 |
Refresh
65 |
Refresh force
66 |
67 | 68 | 69 | 70 | 71 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /src/fingerd/dist/fingerd.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * fingerd.min.js v1.4.2 3 | * (c) 2018 HcySunYang 4 | * Released under the MIT License. 5 | */!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define(i):t.Fingerd=i()}(this,function(){"use strict";function t(t){return Array.isArray(t)?t:Array.prototype.slice.call(t)}function i(){return Date.now()}function e(t){for(var i=[],e=arguments.length-1;e-- >0;)i[e]=arguments[e+1];return i.forEach(function(i){for(var e in i)t[e]=i[e]}),t}function n(t,i){var e=t.compareDocumentPosition(i);return 0===e||20===e}function s(t){var i=t.map(function(t){return Math.abs(t)});return t[i.indexOf(Math.max.apply(null,i))]}function r(t,i,e){var s=document.elementFromPoint(i,e);return!!s&&n(t,s)}function h(t,i){return 0===i?0:-i/t*4}function o(t,i){return 0===i?0:i*i/(-2*t)}function c(t,i){var e=t.x-i.x,n=t.y-i.y;return Math.sqrt(e*e+n*n)}function a(i,e){return void 0!==e?i.touches[e]||{}:t(i.touches)}function u(i,e){return void 0!==e?i.changedTouches[e]||{}:t(i.changedTouches)}var f=0,l=function(t){this.id=f++,this._init(t)};l.prototype._init=function(t){var i=e({element:null,transTime:3e3},t);this.element=i.element,this.native=null,this.startTime=this.startX=this.startY=this.distanceX=this.distanceY=this.lastX=this.lastY=this.lastTime=this.xv=this.yv=this.xs=this.ys=this.xt=this.yt=this.xa=this.ya=this.transDistanceX=this.transDistanceY=0,this.transTime=i.transTime,this.direction={top:!1,bottom:!1,left:!1,right:!1,topLeft:!1,topRight:!1,bottomLeft:!1,bottomRight:!1},this.fingerInElement=!1,this.isMoveOut=!1,this.velocityQueueX=[],this.velocityQueueY=[]},l.prototype.start=function(t){this.element&&(this.fingerInElement=r(this.element,t.clientX,t.clientY)),this.native=t,this.isMoveOut=!1,this.lastX=this.startX=t.pageX,this.lastY=this.startY=t.pageY,this.startTime=this.lastTime=i()},l.prototype.move=function(t){if(this.element&&(this.fingerInElement=r(this.element,t.clientX,t.clientY),!this.fingerInElement))return this.isMoveOut||(this.end(t),this.isMoveOut=!0),!1;this.native=t,this.distanceX=t.pageX-this.startX,this.distanceY=t.pageY-this.startY,this.xs=t.pageX-this.lastX,this.lastX=t.pageX,this.ys=t.pageY-this.lastY,this.lastY=t.pageY,this.checkDirection();var e=i();this.xt=this.yt=e-this.lastTime||15,this.lastTime=e,this.xv=this.xs/this.xt,this.yv=this.ys/this.yt,this.velocityBufferQueue(),this.xv=s(this.velocityQueueX),this.yv=s(this.velocityQueueY),this.xa=h(this.transTime,this.xv),this.ya=h(this.transTime,this.yv)},l.prototype.end=function(t){this.element&&(this.fingerInElement=r(this.element,t.clientX,t.clientY)),this.native=t,this.transDistanceX=o(this.xa,this.xv),this.transDistanceY=o(this.ya,this.yv)},l.prototype.velocityBufferQueue=function(){this.velocityQueueX.length>1&&this.velocityQueueX.shift(),this.velocityQueueY.length>1&&this.velocityQueueY.shift(),this.velocityQueueX.push(this.xv),this.velocityQueueY.push(this.yv)},l.prototype.checkDirection=function(){this.xs<0&&(this.direction.left=!0,this.direction.right=!1),0===this.xs&&(this.direction.left=!1,this.direction.right=!1),this.xs>0&&(this.direction.left=!1,this.direction.right=!0),this.ys<0&&(this.direction.top=!0,this.direction.bottom=!1),0===this.ys&&(this.direction.top=!1,this.direction.bottom=!1),this.ys>0&&(this.direction.top=!1,this.direction.bottom=!0),this.direction.topLeft=this.direction.top&&this.direction.left,this.direction.topRight=this.direction.top&&this.direction.right,this.direction.bottomLeft=this.direction.bottom&&this.direction.left,this.direction.bottomRight=this.direction.bottom&&this.direction.right},l.prototype.takeover=function(t){var e=t;this.distanceX=e.distanceX,this.distanceY=e.distanceY,this.startX=this.lastX-this.distanceX,this.startY=this.lastY-this.distanceY,this.lastTime=i()};var g={touchstart:"touchstart",touchmove:"touchmove",touchend:"touchend",touchcancel:"touchcancel"},v=function(t){this.options=e({element:null,transTime:3e3},t),this.fingers=[],this.changeFingerIndex=0,this.fingerNumber=0};return v.prototype.injectEvent=function(t){var i=this,e=t.type,n=(a(t),u(t));if(e===g.touchstart)for(var s=n.length,r=0;r=5&&e===g.touchcancel)return this.fingerNumber=0,this.fingers.length=0,this;for(var X=n.length,Y=0;Y 2 | 3 | 4 | 5 | 7 | slide-x demo 8 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
one
43 |
two
44 |
three
45 |
46 |
47 | 48 |
49 |
Prev
50 |
Next
51 |
52 | 53 |
54 |
Slide to 3
55 |
Switch to 3
56 |
57 | 58 |
59 |
Current index
60 |
Slide number
61 |
62 | 63 |
64 |
Refresh
65 |
Refresh force
66 |
67 | 68 |
69 |
Destroy
70 |
71 | 72 | 73 | 74 | 75 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | Demo 8 | 40 | 41 | 59 | 60 | 61 | 62 | 63 |

64 |
65 |
66 |
Pull down to refresh
67 | 68 |
69 | 70 |
Load more
71 |
72 |
73 | 74 | 75 | 76 | 77 | 78 | 95 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /src/fingerd/fingerd.js: -------------------------------------------------------------------------------- 1 | import { 2 | toArray, 3 | extend 4 | } from '../shared/util' 5 | import Tevent from './tevent' 6 | 7 | const EVENT_TYPE = { 8 | touchstart: 'touchstart', 9 | touchmove: 'touchmove', 10 | touchend: 'touchend', 11 | touchcancel: 'touchcancel' 12 | } 13 | 14 | export default class Fingerd { 15 | constructor (options) { 16 | this.options = extend({ 17 | element: null, 18 | transTime: 3000 19 | }, options) 20 | this.fingers = [] 21 | this.changeFingerIndex = 0 22 | this.fingerNumber = 0 23 | } 24 | 25 | injectEvent (event) { 26 | let eventType = event.type 27 | let fingers = getTouches(event) 28 | let changeFingers = getChangedTouches(event) 29 | 30 | if (eventType === EVENT_TYPE.touchstart) { 31 | let changeFingerLen = changeFingers.length 32 | for (let i = 0; i < changeFingerLen; i++) { 33 | let id = changeFingers[i].identifier, 34 | tevent = new Tevent(this.options) 35 | 36 | tevent.start(changeFingers[i]) 37 | 38 | if (this.fingerNumber === 0) { 39 | this.fingers.length = 0 40 | } 41 | this.fingers.push(tevent) 42 | 43 | let fingerFromId = this.getFingerById(this.fingers, id), 44 | f = fingerFromId.finger, 45 | pos = fingerFromId.pos 46 | 47 | this.fingerNumber = this.fingers.length 48 | this.changeFingerIndex = pos 49 | } 50 | } 51 | 52 | if (eventType === EVENT_TYPE.touchmove) { 53 | let changeFingerLen = changeFingers.length 54 | for (let i = 0; i < changeFingerLen; i++) { 55 | let id = changeFingers[i].identifier, 56 | fingerFromId = this.getFingerById(this.fingers, id), 57 | f = fingerFromId.finger, 58 | pos = fingerFromId.pos 59 | 60 | if (!f.fingerInElement) { 61 | return this 62 | } 63 | this.fingerNumber = this.fingers.length 64 | this.changeFingerIndex = pos 65 | f.move(changeFingers[i]) 66 | 67 | if (!f.fingerInElement) { 68 | this.forceRemove(fingerFromId, changeFingers[i]) 69 | } 70 | } 71 | } 72 | 73 | if (eventType === EVENT_TYPE.touchend || eventType === EVENT_TYPE.touchcancel) { 74 | // The mobile end limits up to 5 fingers at the same time touch the screen 75 | if (this.fingerNumber >= 5 && eventType === EVENT_TYPE.touchcancel) { 76 | this.fingerNumber = 0 77 | this.fingers.length = 0 78 | return this 79 | } 80 | let changeFingerLen = changeFingers.length 81 | for (let i = 0; i < changeFingerLen; i++) { 82 | let id = changeFingers[i].identifier, 83 | fingerFromId = this.getFingerById(this.fingers, id), 84 | f = fingerFromId.finger 85 | 86 | if (!f.fingerInElement) { 87 | return this 88 | } 89 | this.forceRemove(fingerFromId, changeFingers[i]) 90 | } 91 | } 92 | 93 | return this 94 | 95 | } 96 | 97 | getFingerPicth (f1, f2) { 98 | let p1 = { 99 | x: f1.native.clientX, 100 | y: f1.native.clientY 101 | } 102 | let p2 = { 103 | x: f2.native.clientX, 104 | y: f2.native.clientY 105 | } 106 | 107 | return getTowPointsDis(p1, p2) 108 | } 109 | 110 | getScale (f1, f2) { 111 | let startP1 = { 112 | x: f1.startX, 113 | y: f1.startY 114 | } 115 | let startP2 = { 116 | x: f2.startX, 117 | y: f2.startY 118 | } 119 | let startDis = getTowPointsDis(startP1, startP2) 120 | let currentDis = this.getFingerPicth(f1, f2) 121 | 122 | return (currentDis / startDis) 123 | } 124 | 125 | getFingerById (fingers, id) { 126 | let finger = null, 127 | pos = 0, 128 | fingersLen = fingers.length 129 | 130 | for (let i = 0; i < fingersLen; i++) { 131 | if (fingers[i].native.identifier === id) { 132 | finger = fingers[i] 133 | pos = i 134 | break 135 | } 136 | } 137 | return { 138 | finger: finger, 139 | pos: pos 140 | } 141 | } 142 | 143 | forceRemove (fingerFromId, nativeEvent) { 144 | let f = fingerFromId.finger, 145 | pos = fingerFromId.pos, 146 | next = this.fingers[pos + 1], 147 | prev = this.fingers[pos - 1] 148 | 149 | this.changeFingerIndex = pos 150 | f.end(nativeEvent) 151 | if (next) { 152 | next.takeover(f) 153 | this.fingers.splice(pos, 1) 154 | this.fingerNumber = this.fingers.length 155 | } else if (prev) { 156 | this.fingers.splice(pos, 1) 157 | this.fingerNumber = this.fingers.length 158 | } else { 159 | this.fingerNumber-- 160 | } 161 | } 162 | } 163 | 164 | function radTodeg (rad) { 165 | return 180 / Math.PI * rad 166 | } 167 | 168 | function getTowPointsDis (p1, p2) { 169 | let x = p1.x - p2.x, 170 | y = p1.y - p2.y 171 | return Math.sqrt(x * x + y * y) 172 | } 173 | 174 | function getTouches (event, pos) { 175 | if (typeof pos !== 'undefined') { 176 | return event.touches[pos] || {} 177 | } 178 | return toArray(event.touches) 179 | } 180 | 181 | function getChangedTouches (event, pos) { 182 | if (typeof pos !== 'undefined') { 183 | return event.changedTouches[pos] || {} 184 | } 185 | return toArray(event.changedTouches) 186 | } -------------------------------------------------------------------------------- /src/fingerd/tevent.js: -------------------------------------------------------------------------------- 1 | import { 2 | now, 3 | getAbsMaxFromArray, 4 | extend, 5 | isInElement 6 | } from '../shared/util' 7 | 8 | const MIN_INSTANT_TIME = 15 9 | let eventCid = 0 10 | const A = 0.001 11 | 12 | export function getTransTime (v, a) { 13 | let acceleration = a || A 14 | return v == 0 ? 0 : (Math.abs(v / acceleration) * 2.5) 15 | } 16 | export function fingerInElement (el, x, y) { 17 | let node = document.elementFromPoint(x, y) 18 | if (!node) { 19 | return false 20 | } 21 | return isInElement(el, node) 22 | } 23 | export function computeAcceleration (t, v) { 24 | return v === 0 ? 0 : (-v / t) * 4 25 | } 26 | export function computeTransDistance (a, v) { 27 | let acceleration = a || A 28 | return v === 0 ? 0 : (v * v / -(2 * a)) 29 | } 30 | 31 | export default class Tevent { 32 | constructor (options) { 33 | this.id = eventCid++ 34 | this._init(options) 35 | } 36 | 37 | _init (options) { 38 | let opa = extend({ 39 | element: null, 40 | transTime: 3000 41 | }, options) 42 | this.element = opa.element 43 | this.native = null 44 | this.startTime = 45 | this.startX = 46 | this.startY = 47 | this.distanceX = 48 | this.distanceY = 49 | this.lastX = 50 | this.lastY = 51 | this.lastTime = 52 | this.xv = 53 | this.yv = 54 | this.xs = 55 | this.ys = 56 | this.xt = 57 | this.yt = 58 | this.xa = 59 | this.ya = 60 | this.transDistanceX = 61 | this.transDistanceY = 0 62 | this.transTime = opa.transTime 63 | 64 | this.direction = { 65 | top: false, 66 | bottom: false, 67 | left: false, 68 | right: false, 69 | topLeft: false, 70 | topRight: false, 71 | bottomLeft: false, 72 | bottomRight: false 73 | } 74 | 75 | this.fingerInElement = false 76 | this.isMoveOut = false 77 | 78 | this.velocityQueueX = [] 79 | this.velocityQueueY = [] 80 | } 81 | 82 | start (event) { 83 | if (this.element) { 84 | this.fingerInElement = fingerInElement(this.element, event.clientX, event.clientY) 85 | } 86 | this.native = event 87 | this.isMoveOut = false 88 | this.lastX = this.startX = event.pageX 89 | this.lastY = this.startY = event.pageY 90 | this.startTime = this.lastTime = now() 91 | } 92 | 93 | move (event) { 94 | if (this.element) { 95 | this.fingerInElement = fingerInElement(this.element, event.clientX, event.clientY) 96 | if (!this.fingerInElement) { 97 | if (!this.isMoveOut) { 98 | this.end(event) 99 | this.isMoveOut = true 100 | } 101 | return false 102 | } 103 | } 104 | this.native = event 105 | this.distanceX = event.pageX - this.startX 106 | this.distanceY = event.pageY - this.startY 107 | this.xs = event.pageX - this.lastX 108 | this.lastX = event.pageX 109 | this.ys = event.pageY - this.lastY 110 | this.lastY = event.pageY 111 | 112 | this.checkDirection() 113 | 114 | let timeNow = now() 115 | this.xt = this.yt = (timeNow - this.lastTime) || MIN_INSTANT_TIME 116 | this.lastTime = timeNow 117 | 118 | this.xv = this.xs / this.xt 119 | this.yv = this.ys / this.yt 120 | 121 | this.velocityBufferQueue() 122 | 123 | this.xv = getAbsMaxFromArray(this.velocityQueueX) 124 | this.yv = getAbsMaxFromArray(this.velocityQueueY) 125 | 126 | this.xa = computeAcceleration(this.transTime, this.xv) 127 | this.ya = computeAcceleration(this.transTime, this.yv) 128 | } 129 | 130 | end (event) { 131 | if (this.element) { 132 | this.fingerInElement = fingerInElement(this.element, event.clientX, event.clientY) 133 | } 134 | this.native = event 135 | this.transDistanceX = computeTransDistance(this.xa, this.xv) 136 | this.transDistanceY = computeTransDistance(this.ya, this.yv) 137 | } 138 | 139 | velocityBufferQueue () { 140 | if (this.velocityQueueX.length > 1) { 141 | this.velocityQueueX.shift() 142 | } 143 | if (this.velocityQueueY.length > 1) { 144 | this.velocityQueueY.shift() 145 | } 146 | this.velocityQueueX.push(this.xv) 147 | this.velocityQueueY.push(this.yv) 148 | } 149 | 150 | checkDirection () { 151 | if (this.xs < 0) { 152 | this.direction.left = true 153 | this.direction.right = false 154 | } 155 | if (this.xs === 0) { 156 | this.direction.left = false 157 | this.direction.right = false 158 | } 159 | if (this.xs > 0) { 160 | this.direction.left = false 161 | this.direction.right = true 162 | } 163 | if (this.ys < 0) { 164 | this.direction.top = true 165 | this.direction.bottom = false 166 | } 167 | if (this.ys === 0) { 168 | this.direction.top = false 169 | this.direction.bottom = false 170 | } 171 | if (this.ys > 0) { 172 | this.direction.top = false 173 | this.direction.bottom = true 174 | } 175 | this.direction.topLeft = this.direction.top && this.direction.left 176 | this.direction.topRight = this.direction.top && this.direction.right 177 | this.direction.bottomLeft = this.direction.bottom && this.direction.left 178 | this.direction.bottomRight = this.direction.bottom && this.direction.right 179 | } 180 | 181 | takeover (prev) { 182 | let event = prev 183 | this.distanceX = event.distanceX 184 | this.distanceY = event.distanceY 185 | this.startX = this.lastX - this.distanceX 186 | this.startY = this.lastY - this.distanceY 187 | 188 | this.lastTime = now() 189 | } 190 | } -------------------------------------------------------------------------------- /test/unit/moved.spec.js: -------------------------------------------------------------------------------- 1 | import Moved from 'Moved' 2 | let moved 3 | let dom 4 | describe('Initialization Moved', () => { 5 | 6 | beforeEach(() => { 7 | moved = new Moved() 8 | dom = document.createElement('div') 9 | dom.id = 'moved-test' 10 | document.body.appendChild(dom) 11 | }) 12 | 13 | afterEach(() => { 14 | dom.parentNode.removeChild(dom) 15 | }) 16 | 17 | describe('Whether to use new', () => { 18 | it('Do not use new', () => { 19 | let isWarned = false 20 | try { 21 | Moved() 22 | } catch (e) { 23 | isWarned = true 24 | } 25 | expect(isWarned).toBe(true) 26 | }) 27 | 28 | it('Use new', () => { 29 | moved = new Moved() 30 | expect(moved instanceof Moved).toBe(true) 31 | }) 32 | }) 33 | 34 | describe('Start moving(Tween = easeOutStrong)', () => { 35 | it('When moving to the end, the position should be in line with expectations', (done) => { 36 | moved.start({ 37 | el: dom, 38 | target: { 39 | translateX: 100, 40 | translateY: 100, 41 | rotateX: 10, 42 | rotateY: 10, 43 | rotateZ: 10, 44 | scaleX: 10, 45 | scaleY: 10, 46 | scaleZ: 10, 47 | skewX: 10, 48 | skewY: 10 49 | }, 50 | endCallBack: function (currentPos) { 51 | console.log(currentPos) 52 | expect(currentPos.translateX).toBe(100) 53 | expect(currentPos.translateY).toBe(100) 54 | expect(currentPos.rotateX).toBe(10) 55 | expect(currentPos.rotateY).toBe(10) 56 | expect(currentPos.rotateZ).toBe(10) 57 | expect(currentPos.scaleX).toBe(10) 58 | expect(currentPos.scaleY).toBe(10) 59 | expect(currentPos.scaleZ).toBe(10) 60 | expect(currentPos.skewX).toBe(10) 61 | expect(currentPos.skewY).toBe(10) 62 | done() 63 | }, 64 | time: 1000 65 | }) 66 | }) 67 | }) 68 | 69 | describe('Start moving(Tween = backOut)', () => { 70 | it('When moving to the end, the position should be in line with expectations', (done) => { 71 | moved.start({ 72 | el: dom, 73 | type: 'backOut', 74 | target: { 75 | translateX: 100 76 | }, 77 | endCallBack: function (currentPos) { 78 | expect(currentPos.translateX).toBe(100) 79 | done() 80 | }, 81 | time: 1000 82 | }) 83 | }) 84 | }) 85 | 86 | describe('Stop motion', () => { 87 | it('The movement has stopped', (done) => { 88 | dom.style.cssText = 'width: 100px; height: 100px; background-color: red;' 89 | moved.start({ 90 | el: dom, 91 | target: { 92 | translateY: 100 93 | }, 94 | time: 1000 95 | }) 96 | 97 | setTimeout(() => { 98 | moved.stop(function () { 99 | expect(moved.moveStatus).toBe('stop') 100 | done() 101 | }) 102 | }, 200) 103 | }) 104 | }) 105 | 106 | describe('Call stop before starting to run', () => { 107 | it('If the element has not started to move, then return directly', () => { 108 | let isCall = false 109 | moved.stop(function () { 110 | isCall = true 111 | }) 112 | expect(isCall).toBe(false) 113 | }) 114 | }) 115 | 116 | describe('Call the transform method to manipulate the element', () => { 117 | it('The element should be rotated', () => { 118 | moved.transform(dom, 'rotateZ', 100) 119 | let attr = getComputedStyle(dom)['webkitTransform'] 120 | expect(attr).toMatch(/matrix/) 121 | }) 122 | }) 123 | 124 | describe('Call the getPropFromMatrix method to get the value of the transform property of the element', () => { 125 | it('Before the element transforms, the attribute value should match the expected', () => { 126 | let transformAttr = moved.getPropFromMatrix(dom) 127 | expect(transformAttr.translateX).toBe(0) 128 | expect(transformAttr.translateY).toBe(0) 129 | expect(transformAttr.translateZ).toBe(0) 130 | expect(transformAttr.scaleX).toBe(1) 131 | expect(transformAttr.scaleY).toBe(1) 132 | expect(transformAttr.scaleZ).toBe(1) 133 | expect(transformAttr.rotateX).toBe(0) 134 | expect(transformAttr.rotateY).toBe(0) 135 | expect(transformAttr.rotateZ).toBe(0) 136 | expect(transformAttr.skewX).toBe(0) 137 | expect(transformAttr.skewY).toBe(0) 138 | }) 139 | 140 | it('After the element is transformed, the attribute value should match the expectation', () => { 141 | moved.transform(dom, 'translateX', 100) 142 | moved.transform(dom, 'translateY', 100) 143 | moved.transform(dom, 'translateZ', 100) 144 | moved.transform(dom, 'scaleX', 100) 145 | moved.transform(dom, 'scaleY', 100) 146 | moved.transform(dom, 'scaleZ', 100) 147 | moved.transform(dom, 'rotateX', 100) 148 | moved.transform(dom, 'rotateY', 100) 149 | moved.transform(dom, 'rotateZ', 100) 150 | moved.transform(dom, 'skewX', 100) 151 | moved.transform(dom, 'skewY', 100) 152 | let transformAttr = moved.getPropFromMatrix(dom) 153 | expect(transformAttr.translateX).toBe(100) 154 | expect(transformAttr.translateY).toBe(100) 155 | expect(transformAttr.translateZ).toBe(100) 156 | expect(transformAttr.scaleX).toBe(100) 157 | expect(transformAttr.scaleY).toBe(100) 158 | expect(transformAttr.scaleZ).toBe(100) 159 | expect(transformAttr.rotateX).toBe(100) 160 | expect(transformAttr.rotateY).toBe(100) 161 | expect(transformAttr.rotateZ).toBe(100) 162 | expect(transformAttr.skewX).toBe(100) 163 | expect(transformAttr.skewY).toBe(100) 164 | }) 165 | }) 166 | 167 | }) -------------------------------------------------------------------------------- /src/moved/dist/moved.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * moved.js v1.4.2 3 | * (c) 2018 HcySunYang 4 | * Released under the MIT License. 5 | */ 6 | (function (global, factory) { 7 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 8 | typeof define === 'function' && define.amd ? define(factory) : 9 | (global.Moved = factory()); 10 | }(this, (function () { 'use strict'; 11 | 12 | var TW = { 13 | easeOutStrong: function (t, b, c, d) { 14 | return -c * ((t = t / d - 1) * t * t * t - 1) + b 15 | }, 16 | backOut: function (t, b, c, d, s) { 17 | if (typeof s === 'undefined') { 18 | s = 0.7; 19 | } 20 | return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b 21 | } 22 | }; 23 | 24 | var requestAnim = requestAnimationFrame || webkitRequestAnimationFrame; 25 | var cancelAnim = cancelAnimationFrame || webkitCancelAnimationFrame; 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | function getStyle (el, prototype) { 34 | return document.defaultView.getComputedStyle(el, null)[prototype] 35 | } 36 | 37 | function now () { 38 | return Date.now() 39 | } 40 | 41 | 42 | function cssText (el, cssText) { 43 | el.style.cssText = el.style.cssText + ' ' + cssText; 44 | } 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | function transform (el, attr, val) { 53 | var transString = ''; 54 | 55 | el.transform = el.transform ? el.transform : Object.create(null); 56 | el.transform[attr] = val; 57 | 58 | for (var a in el.transform) { 59 | switch (a) { 60 | case 'translateX': 61 | case 'translateY': 62 | case 'translateZ': 63 | transString += a + "(" + (el.transform[a]) + "px) "; 64 | break 65 | case 'scaleX': 66 | case 'scaleY': 67 | case 'scaleZ': 68 | transString += a + "(" + (el.transform[a]) + ") "; 69 | break 70 | case 'rotateX': 71 | case 'rotateY': 72 | case 'rotateZ': 73 | case 'skewX': 74 | case 'skewY': 75 | transString += a + "(" + (el.transform[a]) + "deg) "; 76 | break 77 | } 78 | } 79 | cssText(el, ("transform: " + transString + "; -webkit-transform: " + transString + ";")); 80 | } 81 | 82 | function getPropFromMatrix (el) { 83 | var matrix = getStyle(el, 'WebkitTransform'); 84 | 85 | if (!matrix || matrix === 'none') { 86 | transform(el, 'translateZ', 0.01); 87 | } 88 | /* The element's dispaly attribute value is none */ 89 | if (matrix === 'none') { 90 | return {} 91 | } 92 | try { 93 | matrix = getStyle(el, 'WebkitTransform') 94 | .match(/[+-]?\d*[.]?\d+(?=,|\))/g) 95 | .map(function (o) { 96 | return parseInt(o) 97 | }); 98 | } catch (e) {} 99 | 100 | var matrixLen = matrix.length; 101 | var matrixObject = {}; 102 | var is3D = matrixLen > 6; 103 | 104 | matrixObject.translateX = is3D ? matrix[12] : matrix[4]; 105 | matrixObject.translateY = is3D ? matrix[13] : matrix[5]; 106 | matrixObject.translateZ = is3D ? matrix[14] : 0; 107 | 108 | matrixObject.scaleX = typeof el.transform['scaleX'] !== 'undefined' 109 | ? el.transform['scaleX'] 110 | : 1; 111 | matrixObject.scaleY = typeof el.transform['scaleY'] !== 'undefined' 112 | ? el.transform['scaleY'] 113 | : 1; 114 | matrixObject.scaleZ = typeof el.transform['scaleZ'] !== 'undefined' 115 | ? el.transform['scaleZ'] 116 | : 1; 117 | 118 | matrixObject.rotateX = typeof el.transform['rotateX'] !== 'undefined' 119 | ? el.transform['rotateX'] : 0; 120 | matrixObject.rotateY = typeof el.transform['rotateY'] !== 'undefined' 121 | ? el.transform['rotateY'] : 0; 122 | matrixObject.rotateZ = typeof el.transform['rotateZ'] !== 'undefined' 123 | ? el.transform['rotateZ'] : 0; 124 | 125 | matrixObject.skewX = typeof el.transform['skewX'] !== 'undefined' 126 | ? el.transform['skewX'] : 0; 127 | matrixObject.skewY = typeof el.transform['skewY'] !== 'undefined' 128 | ? el.transform['skewY'] : 0; 129 | 130 | return matrixObject 131 | } 132 | 133 | var Animationframe = function Animationframe (handle) { 134 | this.handle = handle; 135 | this.id = 0; 136 | this._init(); 137 | }; 138 | 139 | Animationframe.prototype._init = function _init () { 140 | this.start = now(); 141 | this.request(); 142 | }; 143 | 144 | Animationframe.prototype._fakeHandle = function _fakeHandle () { 145 | var times = now() - this.start; 146 | 147 | this.handle(times); 148 | }; 149 | 150 | Animationframe.prototype._requestAnimFn = function _requestAnimFn (handle) { 151 | if (requestAnim) { 152 | return requestAnim(handle) 153 | } else { 154 | return setTimeout(handle, 1000 / 60) 155 | } 156 | }; 157 | 158 | Animationframe.prototype._cancelAnimFn = function _cancelAnimFn (id) { 159 | if (cancelAnim) { 160 | cancelAnim(id); 161 | } else { 162 | clearTimeout(id); 163 | } 164 | }; 165 | 166 | Animationframe.prototype.request = function request () { 167 | this.id = this._requestAnimFn(this._fakeHandle.bind(this)); 168 | }; 169 | 170 | Animationframe.prototype.cancel = function cancel () { 171 | this._cancelAnimFn(this.id); 172 | }; 173 | 174 | var MOVE_STATUS = { 175 | start: 'start', 176 | stop: 'stop' 177 | }; 178 | 179 | var cid = 0; 180 | var Moved = function Moved () { 181 | this.moveStatus = MOVE_STATUS.stop; 182 | this.isArrivals = false; 183 | /* istanbul ignore if */ 184 | if (!(this instanceof Moved)) { 185 | throwError('Moved is a constructor and should be called with the `new` keyword'); 186 | } 187 | }; 188 | 189 | Moved.prototype.start = function start (options) { 190 | var this$1 = this; 191 | 192 | if (this.moveStatus === MOVE_STATUS.start) { 193 | return 194 | } 195 | options = options ? options : {}; 196 | var el = options.el; 197 | var target = options.target; 198 | var type = options.type; 199 | var time = options.time; 200 | var endCallBack = options.endCallBack; 201 | var inCallBack = options.inCallBack; 202 | var s = options.s; 203 | this.isArrivals = false; 204 | this.id = cid++; 205 | this.el = el; 206 | this.target = target; 207 | this.type = type || 'easeOutStrong'; 208 | this.time = time <= 1 ? 1 : time; 209 | this.endCallBack = endCallBack; 210 | this.inCallBack = inCallBack; 211 | this.currentPos = {}; 212 | this.moveStatus = MOVE_STATUS.start; 213 | 214 | this.b = {}; 215 | this.c = {}; 216 | this.d = this.time; 217 | this.s = s; 218 | for (var attr in this$1.target) { 219 | this$1.b[attr] = getPropFromMatrix(this$1.el)[attr]; 220 | this$1.c[attr] = this$1.target[attr] - this$1.b[attr]; 221 | if (this$1.c[attr] === 0) { 222 | this$1.isArrivals = true; 223 | } 224 | } 225 | if (this.isArrivals) { 226 | this.endCallBack && this.endCallBack(this.b); 227 | this.moveStatus = MOVE_STATUS.stop; 228 | return false 229 | } 230 | 231 | this.anim = new Animationframe(this._moveHandle.bind(this)); 232 | }; 233 | 234 | Moved.prototype.stop = function stop (callback) { 235 | var this$1 = this; 236 | 237 | if (this.moveStatus === MOVE_STATUS.stop || !this.anim) { 238 | return this 239 | } 240 | this.moveStatus = MOVE_STATUS.stop; 241 | this.anim.cancel(); 242 | for (var attr in this$1.target) { 243 | transform(this$1.el, attr, this$1.currentPos[attr]); 244 | } 245 | callback && callback(this.currentPos); 246 | return this 247 | }; 248 | 249 | Moved.prototype.transform = function transform$1 (el, attr, val) { 250 | transform(el, attr, val); 251 | }; 252 | 253 | Moved.prototype.getPropFromMatrix = function getPropFromMatrix$1 (el) { 254 | return getPropFromMatrix(el) 255 | }; 256 | 257 | Moved.prototype._moveHandle = function _moveHandle (t) { 258 | var this$1 = this; 259 | 260 | t = t >= this.d ? this.d : t; 261 | for (var attr in this$1.target) { 262 | this$1.currentPos[attr] = Moved.Tween[this$1.type](t, this$1.b[attr], this$1.c[attr], this$1.d, this$1.s); 263 | transform(this$1.el, attr, this$1.currentPos[attr]); 264 | } 265 | this.moveStatus = MOVE_STATUS.start; 266 | this.inCallBack && this.inCallBack.call(this, this.currentPos); 267 | 268 | if (t >= this.d) { 269 | this.stop(this.endCallBack); 270 | } else { 271 | this.anim.request(); 272 | } 273 | }; 274 | 275 | Moved.Tween = TW; 276 | 277 | return Moved; 278 | 279 | }))); 280 | -------------------------------------------------------------------------------- /dist/finger-mover.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * finger-mover.min.js v1.4.2 3 | * (c) 2018 HcySunYang 4 | * Released under the MIT License. 5 | */!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.Fmover=e()}(this,function(){"use strict";function t(t){throw new TypeError(t)}function e(t){return Array.isArray(t)?t:Array.prototype.slice.call(t)}function i(t,e){return document.defaultView.getComputedStyle(t,null)[e]}function n(){return Date.now()}function s(t){for(var e=[],i=arguments.length-1;i-- >0;)e[i]=arguments[i+1];return e.forEach(function(e){for(var i in e)t[i]=e[i]}),t}function r(t,e){t.style.cssText=t.style.cssText+" "+e}function o(t,e){for(var i={top:0,left:0};e!==t;)i.top+=e.offsetTop,i.left+=e.offsetLeft,e=e.offsetParent;return i}function a(t,e){var i=t.compareDocumentPosition(e);return 0===i||20===i}function h(t){var e=i(t,"WebkitTransform");return!(!e||"none"===e)&&e.match(/[+-]?\d*[.]?\d+(?=,|\))/g).length>6}function c(t,e,i){var n="";t.transform=t.transform?t.transform:Object.create(null),t.transform[e]=i;for(var s in t.transform)switch(s){case"translateX":case"translateY":case"translateZ":n+=s+"("+t.transform[s]+"px) ";break;case"scaleX":case"scaleY":case"scaleZ":n+=s+"("+t.transform[s]+") ";break;case"rotateX":case"rotateY":case"rotateZ":case"skewX":case"skewY":n+=s+"("+t.transform[s]+"deg) "}r(t,"transform: "+n+"; -webkit-transform: "+n+";")}function l(t){var e=i(t,"WebkitTransform");if(e&&"none"!==e||c(t,"translateZ",.01),"none"===e)return{};try{e=i(t,"WebkitTransform").match(/[+-]?\d*[.]?\d+(?=,|\))/g).map(function(t){return parseInt(t)})}catch(t){}var n=e.length,s={},r=n>6;return s.translateX=r?e[12]:e[4],s.translateY=r?e[13]:e[5],s.translateZ=r?e[14]:0,s.scaleX=void 0!==t.transform.scaleX?t.transform.scaleX:1,s.scaleY=void 0!==t.transform.scaleY?t.transform.scaleY:1,s.scaleZ=void 0!==t.transform.scaleZ?t.transform.scaleZ:1,s.rotateX=void 0!==t.transform.rotateX?t.transform.rotateX:0,s.rotateY=void 0!==t.transform.rotateY?t.transform.rotateY:0,s.rotateZ=void 0!==t.transform.rotateZ?t.transform.rotateZ:0,s.skewX=void 0!==t.transform.skewX?t.transform.skewX:0,s.skewY=void 0!==t.transform.skewY?t.transform.skewY:0,s}function u(t){var e=t.map(function(t){return Math.abs(t)});return t[e.indexOf(Math.max.apply(null,e))]}function f(t,e,i){var n=document.elementFromPoint(e,i);return!!n&&a(t,n)}function g(t,e){return 0===e?0:-e/t*4}function p(t,e){return 0===e?0:e*e/(-2*t)}function m(t,e){var i=t.x-e.x,n=t.y-e.y;return Math.sqrt(i*i+n*n)}function d(t,i){return void 0!==i?t.touches[i]||{}:e(t.touches)}function v(t,i){return void 0!==i?t.changedTouches[i]||{}:e(t.changedTouches)}var y=requestAnimationFrame||webkitRequestAnimationFrame,X=cancelAnimationFrame||webkitCancelAnimationFrame,Y={easeOutStrong:function(t,e,i,n){return-i*((t=t/n-1)*t*t*t-1)+e},backOut:function(t,e,i,n,s){return void 0===s&&(s=.7),i*((t=t/n-1)*t*((s+1)*t+s)+1)+e}},b=function(t){this.handle=t,this.id=0,this._init()};b.prototype._init=function(){this.start=n(),this.request()},b.prototype._fakeHandle=function(){var t=n()-this.start;this.handle(t)},b.prototype._requestAnimFn=function(t){return y?y(t):setTimeout(t,1e3/60)},b.prototype._cancelAnimFn=function(t){X?X(t):clearTimeout(t)},b.prototype.request=function(){this.id=this._requestAnimFn(this._fakeHandle.bind(this))},b.prototype.cancel=function(){this._cancelAnimFn(this.id)};var x={start:"start",stop:"stop"},k=0,S=function t(){this.moveStatus=x.stop,this.isArrivals=!1,this instanceof t||throwError("Moved is a constructor and should be called with the `new` keyword")};S.prototype.start=function(t){var e=this;if(this.moveStatus!==x.start){t=t||{};var i=t.el,n=t.target,s=t.type,r=t.time,o=t.endCallBack,a=t.inCallBack,h=t.s;this.isArrivals=!1,this.id=k++,this.el=i,this.target=n,this.type=s||"easeOutStrong",this.time=r<=1?1:r,this.endCallBack=o,this.inCallBack=a,this.currentPos={},this.moveStatus=x.start,this.b={},this.c={},this.d=this.time,this.s=h;for(var c in e.target)e.b[c]=l(e.el)[c],e.c[c]=e.target[c]-e.b[c],0===e.c[c]&&(e.isArrivals=!0);if(this.isArrivals)return this.endCallBack&&this.endCallBack(this.b),this.moveStatus=x.stop,!1;this.anim=new b(this._moveHandle.bind(this))}},S.prototype.stop=function(t){var e=this;if(this.moveStatus===x.stop||!this.anim)return this;this.moveStatus=x.stop,this.anim.cancel();for(var i in e.target)c(e.el,i,e.currentPos[i]);return t&&t(this.currentPos),this},S.prototype.transform=function(t,e,i){c(t,e,i)},S.prototype.getPropFromMatrix=function(t){return l(t)},S.prototype._moveHandle=function(t){var e=this;t=t>=this.d?this.d:t;for(var i in e.target)e.currentPos[i]=S.Tween[e.type](t,e.b[i],e.c[i],e.d,e.s),c(e.el,i,e.currentPos[i]);this.moveStatus=x.start,this.inCallBack&&this.inCallBack.call(this,this.currentPos),t>=this.d?this.stop(this.endCallBack):this.anim.request()},S.Tween=Y;var w=0,T=function(t){this.id=w++,this._init(t)};T.prototype._init=function(t){var e=s({element:null,transTime:3e3},t);this.element=e.element,this.native=null,this.startTime=this.startX=this.startY=this.distanceX=this.distanceY=this.lastX=this.lastY=this.lastTime=this.xv=this.yv=this.xs=this.ys=this.xt=this.yt=this.xa=this.ya=this.transDistanceX=this.transDistanceY=0,this.transTime=e.transTime,this.direction={top:!1,bottom:!1,left:!1,right:!1,topLeft:!1,topRight:!1,bottomLeft:!1,bottomRight:!1},this.fingerInElement=!1,this.isMoveOut=!1,this.velocityQueueX=[],this.velocityQueueY=[]},T.prototype.start=function(t){this.element&&(this.fingerInElement=f(this.element,t.clientX,t.clientY)),this.native=t,this.isMoveOut=!1,this.lastX=this.startX=t.pageX,this.lastY=this.startY=t.pageY,this.startTime=this.lastTime=n()},T.prototype.move=function(t){if(this.element&&(this.fingerInElement=f(this.element,t.clientX,t.clientY),!this.fingerInElement))return this.isMoveOut||(this.end(t),this.isMoveOut=!0),!1;this.native=t,this.distanceX=t.pageX-this.startX,this.distanceY=t.pageY-this.startY,this.xs=t.pageX-this.lastX,this.lastX=t.pageX,this.ys=t.pageY-this.lastY,this.lastY=t.pageY,this.checkDirection();var e=n();this.xt=this.yt=e-this.lastTime||15,this.lastTime=e,this.xv=this.xs/this.xt,this.yv=this.ys/this.yt,this.velocityBufferQueue(),this.xv=u(this.velocityQueueX),this.yv=u(this.velocityQueueY),this.xa=g(this.transTime,this.xv),this.ya=g(this.transTime,this.yv)},T.prototype.end=function(t){this.element&&(this.fingerInElement=f(this.element,t.clientX,t.clientY)),this.native=t,this.transDistanceX=p(this.xa,this.xv),this.transDistanceY=p(this.ya,this.yv)},T.prototype.velocityBufferQueue=function(){this.velocityQueueX.length>1&&this.velocityQueueX.shift(),this.velocityQueueY.length>1&&this.velocityQueueY.shift(),this.velocityQueueX.push(this.xv),this.velocityQueueY.push(this.yv)},T.prototype.checkDirection=function(){this.xs<0&&(this.direction.left=!0,this.direction.right=!1),0===this.xs&&(this.direction.left=!1,this.direction.right=!1),this.xs>0&&(this.direction.left=!1,this.direction.right=!0),this.ys<0&&(this.direction.top=!0,this.direction.bottom=!1),0===this.ys&&(this.direction.top=!1,this.direction.bottom=!1),this.ys>0&&(this.direction.top=!1,this.direction.bottom=!0),this.direction.topLeft=this.direction.top&&this.direction.left,this.direction.topRight=this.direction.top&&this.direction.right,this.direction.bottomLeft=this.direction.bottom&&this.direction.left,this.direction.bottomRight=this.direction.bottom&&this.direction.right},T.prototype.takeover=function(t){var e=t;this.distanceX=e.distanceX,this.distanceY=e.distanceY,this.startX=this.lastX-this.distanceX,this.startY=this.lastY-this.distanceY,this.lastTime=n()};var _={touchstart:"touchstart",touchmove:"touchmove",touchend:"touchend",touchcancel:"touchcancel"},E=function(t){this.options=s({element:null,transTime:3e3},t),this.fingers=[],this.changeFingerIndex=0,this.fingerNumber=0};E.prototype.injectEvent=function(t){var e=this,i=t.type,n=(d(t),v(t));if(i===_.touchstart)for(var s=n.length,r=0;r=5&&i===_.touchcancel)return this.fingerNumber=0,this.fingers.length=0,this;for(var y=n.length,X=0;X 0 ) from[ len ] = arguments[ len + 1 ]; 30 | 31 | from.forEach(function (f) { 32 | for (var attr in f) { 33 | to[attr] = f[attr]; 34 | } 35 | }); 36 | 37 | return to 38 | } 39 | 40 | 41 | 42 | 43 | function isInElement (parent, child) { 44 | var num = parent.compareDocumentPosition(child); 45 | 46 | if (num === 0 || num === 20) { 47 | return true 48 | } 49 | return false 50 | } 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | function getAbsMaxFromArray (arr) { 59 | var tempArr = arr.map(function (o) { 60 | return Math.abs(o) 61 | }); 62 | var maxIndex = tempArr.indexOf(Math.max.apply(null, tempArr)); 63 | return arr[maxIndex] 64 | } 65 | 66 | var MIN_INSTANT_TIME = 15; 67 | var eventCid = 0; 68 | var A = 0.001; 69 | 70 | 71 | function fingerInElement (el, x, y) { 72 | var node = document.elementFromPoint(x, y); 73 | if (!node) { 74 | return false 75 | } 76 | return isInElement(el, node) 77 | } 78 | function computeAcceleration (t, v) { 79 | return v === 0 ? 0 : (-v / t) * 4 80 | } 81 | function computeTransDistance (a, v) { 82 | var acceleration = a || A; 83 | return v === 0 ? 0 : (v * v / -(2 * a)) 84 | } 85 | 86 | var Tevent = function Tevent (options) { 87 | this.id = eventCid++; 88 | this._init(options); 89 | }; 90 | 91 | Tevent.prototype._init = function _init (options) { 92 | var opa = extend({ 93 | element: null, 94 | transTime: 3000 95 | }, options); 96 | this.element = opa.element; 97 | this.native = null; 98 | this.startTime = 99 | this.startX = 100 | this.startY = 101 | this.distanceX = 102 | this.distanceY = 103 | this.lastX = 104 | this.lastY = 105 | this.lastTime = 106 | this.xv = 107 | this.yv = 108 | this.xs = 109 | this.ys = 110 | this.xt = 111 | this.yt = 112 | this.xa = 113 | this.ya = 114 | this.transDistanceX = 115 | this.transDistanceY = 0; 116 | this.transTime = opa.transTime; 117 | 118 | this.direction = { 119 | top: false, 120 | bottom: false, 121 | left: false, 122 | right: false, 123 | topLeft: false, 124 | topRight: false, 125 | bottomLeft: false, 126 | bottomRight: false 127 | }; 128 | 129 | this.fingerInElement = false; 130 | this.isMoveOut = false; 131 | 132 | this.velocityQueueX = []; 133 | this.velocityQueueY = []; 134 | }; 135 | 136 | Tevent.prototype.start = function start (event) { 137 | if (this.element) { 138 | this.fingerInElement = fingerInElement(this.element, event.clientX, event.clientY); 139 | } 140 | this.native = event; 141 | this.isMoveOut = false; 142 | this.lastX = this.startX = event.pageX; 143 | this.lastY = this.startY = event.pageY; 144 | this.startTime = this.lastTime = now(); 145 | }; 146 | 147 | Tevent.prototype.move = function move (event) { 148 | if (this.element) { 149 | this.fingerInElement = fingerInElement(this.element, event.clientX, event.clientY); 150 | if (!this.fingerInElement) { 151 | if (!this.isMoveOut) { 152 | this.end(event); 153 | this.isMoveOut = true; 154 | } 155 | return false 156 | } 157 | } 158 | this.native = event; 159 | this.distanceX = event.pageX - this.startX; 160 | this.distanceY = event.pageY - this.startY; 161 | this.xs = event.pageX - this.lastX; 162 | this.lastX = event.pageX; 163 | this.ys = event.pageY - this.lastY; 164 | this.lastY = event.pageY; 165 | 166 | this.checkDirection(); 167 | 168 | var timeNow = now(); 169 | this.xt = this.yt = (timeNow - this.lastTime) || MIN_INSTANT_TIME; 170 | this.lastTime = timeNow; 171 | 172 | this.xv = this.xs / this.xt; 173 | this.yv = this.ys / this.yt; 174 | 175 | this.velocityBufferQueue(); 176 | 177 | this.xv = getAbsMaxFromArray(this.velocityQueueX); 178 | this.yv = getAbsMaxFromArray(this.velocityQueueY); 179 | 180 | this.xa = computeAcceleration(this.transTime, this.xv); 181 | this.ya = computeAcceleration(this.transTime, this.yv); 182 | }; 183 | 184 | Tevent.prototype.end = function end (event) { 185 | if (this.element) { 186 | this.fingerInElement = fingerInElement(this.element, event.clientX, event.clientY); 187 | } 188 | this.native = event; 189 | this.transDistanceX = computeTransDistance(this.xa, this.xv); 190 | this.transDistanceY = computeTransDistance(this.ya, this.yv); 191 | }; 192 | 193 | Tevent.prototype.velocityBufferQueue = function velocityBufferQueue () { 194 | if (this.velocityQueueX.length > 1) { 195 | this.velocityQueueX.shift(); 196 | } 197 | if (this.velocityQueueY.length > 1) { 198 | this.velocityQueueY.shift(); 199 | } 200 | this.velocityQueueX.push(this.xv); 201 | this.velocityQueueY.push(this.yv); 202 | }; 203 | 204 | Tevent.prototype.checkDirection = function checkDirection () { 205 | if (this.xs < 0) { 206 | this.direction.left = true; 207 | this.direction.right = false; 208 | } 209 | if (this.xs === 0) { 210 | this.direction.left = false; 211 | this.direction.right = false; 212 | } 213 | if (this.xs > 0) { 214 | this.direction.left = false; 215 | this.direction.right = true; 216 | } 217 | if (this.ys < 0) { 218 | this.direction.top = true; 219 | this.direction.bottom = false; 220 | } 221 | if (this.ys === 0) { 222 | this.direction.top = false; 223 | this.direction.bottom = false; 224 | } 225 | if (this.ys > 0) { 226 | this.direction.top = false; 227 | this.direction.bottom = true; 228 | } 229 | this.direction.topLeft = this.direction.top && this.direction.left; 230 | this.direction.topRight = this.direction.top && this.direction.right; 231 | this.direction.bottomLeft = this.direction.bottom && this.direction.left; 232 | this.direction.bottomRight = this.direction.bottom && this.direction.right; 233 | }; 234 | 235 | Tevent.prototype.takeover = function takeover (prev) { 236 | var event = prev; 237 | this.distanceX = event.distanceX; 238 | this.distanceY = event.distanceY; 239 | this.startX = this.lastX - this.distanceX; 240 | this.startY = this.lastY - this.distanceY; 241 | 242 | this.lastTime = now(); 243 | }; 244 | 245 | var EVENT_TYPE = { 246 | touchstart: 'touchstart', 247 | touchmove: 'touchmove', 248 | touchend: 'touchend', 249 | touchcancel: 'touchcancel' 250 | }; 251 | 252 | var Fingerd = function Fingerd (options) { 253 | this.options = extend({ 254 | element: null, 255 | transTime: 3000 256 | }, options); 257 | this.fingers = []; 258 | this.changeFingerIndex = 0; 259 | this.fingerNumber = 0; 260 | }; 261 | 262 | Fingerd.prototype.injectEvent = function injectEvent (event) { 263 | var this$1 = this; 264 | 265 | var eventType = event.type; 266 | var fingers = getTouches(event); 267 | var changeFingers = getChangedTouches(event); 268 | 269 | if (eventType === EVENT_TYPE.touchstart) { 270 | var changeFingerLen = changeFingers.length; 271 | for (var i = 0; i < changeFingerLen; i++) { 272 | var id = changeFingers[i].identifier, 273 | tevent = new Tevent(this$1.options); 274 | 275 | tevent.start(changeFingers[i]); 276 | 277 | if (this$1.fingerNumber === 0) { 278 | this$1.fingers.length = 0; 279 | } 280 | this$1.fingers.push(tevent); 281 | 282 | var fingerFromId = this$1.getFingerById(this$1.fingers, id), 283 | f = fingerFromId.finger, 284 | pos = fingerFromId.pos; 285 | 286 | this$1.fingerNumber = this$1.fingers.length; 287 | this$1.changeFingerIndex = pos; 288 | } 289 | } 290 | 291 | if (eventType === EVENT_TYPE.touchmove) { 292 | var changeFingerLen$1 = changeFingers.length; 293 | for (var i$1 = 0; i$1 < changeFingerLen$1; i$1++) { 294 | var id$1 = changeFingers[i$1].identifier, 295 | fingerFromId$1 = this$1.getFingerById(this$1.fingers, id$1), 296 | f$1 = fingerFromId$1.finger, 297 | pos$1 = fingerFromId$1.pos; 298 | 299 | if (!f$1.fingerInElement) { 300 | return this$1 301 | } 302 | this$1.fingerNumber = this$1.fingers.length; 303 | this$1.changeFingerIndex = pos$1; 304 | f$1.move(changeFingers[i$1]); 305 | 306 | if (!f$1.fingerInElement) { 307 | this$1.forceRemove(fingerFromId$1, changeFingers[i$1]); 308 | } 309 | } 310 | } 311 | 312 | if (eventType === EVENT_TYPE.touchend || eventType === EVENT_TYPE.touchcancel) { 313 | // The mobile end limits up to 5 fingers at the same time touch the screen 314 | if (this.fingerNumber >= 5 && eventType === EVENT_TYPE.touchcancel) { 315 | this.fingerNumber = 0; 316 | this.fingers.length = 0; 317 | return this 318 | } 319 | var changeFingerLen$2 = changeFingers.length; 320 | for (var i$2 = 0; i$2 < changeFingerLen$2; i$2++) { 321 | var id$2 = changeFingers[i$2].identifier, 322 | fingerFromId$2 = this$1.getFingerById(this$1.fingers, id$2), 323 | f$2 = fingerFromId$2.finger; 324 | 325 | if (!f$2.fingerInElement) { 326 | return this$1 327 | } 328 | this$1.forceRemove(fingerFromId$2, changeFingers[i$2]); 329 | } 330 | } 331 | 332 | return this 333 | 334 | }; 335 | 336 | Fingerd.prototype.getFingerPicth = function getFingerPicth (f1, f2) { 337 | var p1 = { 338 | x: f1.native.clientX, 339 | y: f1.native.clientY 340 | }; 341 | var p2 = { 342 | x: f2.native.clientX, 343 | y: f2.native.clientY 344 | }; 345 | 346 | return getTowPointsDis(p1, p2) 347 | }; 348 | 349 | Fingerd.prototype.getScale = function getScale (f1, f2) { 350 | var startP1 = { 351 | x: f1.startX, 352 | y: f1.startY 353 | }; 354 | var startP2 = { 355 | x: f2.startX, 356 | y: f2.startY 357 | }; 358 | var startDis = getTowPointsDis(startP1, startP2); 359 | var currentDis = this.getFingerPicth(f1, f2); 360 | 361 | return (currentDis / startDis) 362 | }; 363 | 364 | Fingerd.prototype.getFingerById = function getFingerById (fingers, id) { 365 | var finger = null, 366 | pos = 0, 367 | fingersLen = fingers.length; 368 | 369 | for (var i = 0; i < fingersLen; i++) { 370 | if (fingers[i].native.identifier === id) { 371 | finger = fingers[i]; 372 | pos = i; 373 | break 374 | } 375 | } 376 | return { 377 | finger: finger, 378 | pos: pos 379 | } 380 | }; 381 | 382 | Fingerd.prototype.forceRemove = function forceRemove (fingerFromId, nativeEvent) { 383 | var f = fingerFromId.finger, 384 | pos = fingerFromId.pos, 385 | next = this.fingers[pos + 1], 386 | prev = this.fingers[pos - 1]; 387 | 388 | this.changeFingerIndex = pos; 389 | f.end(nativeEvent); 390 | if (next) { 391 | next.takeover(f); 392 | this.fingers.splice(pos, 1); 393 | this.fingerNumber = this.fingers.length; 394 | } else if (prev) { 395 | this.fingers.splice(pos, 1); 396 | this.fingerNumber = this.fingers.length; 397 | } else { 398 | this.fingerNumber--; 399 | } 400 | }; 401 | 402 | function getTowPointsDis (p1, p2) { 403 | var x = p1.x - p2.x, 404 | y = p1.y - p2.y; 405 | return Math.sqrt(x * x + y * y) 406 | } 407 | 408 | function getTouches (event, pos) { 409 | if (typeof pos !== 'undefined') { 410 | return event.touches[pos] || {} 411 | } 412 | return toArray(event.touches) 413 | } 414 | 415 | function getChangedTouches (event, pos) { 416 | if (typeof pos !== 'undefined') { 417 | return event.changedTouches[pos] || {} 418 | } 419 | return toArray(event.changedTouches) 420 | } 421 | 422 | return Fingerd; 423 | 424 | }))); 425 | -------------------------------------------------------------------------------- /src/plugins/simulation-scroll-x/simulation-scroll-x.js: -------------------------------------------------------------------------------- 1 | export default function (options) { 2 | 3 | return function (Fmover) { 4 | const { 5 | Moved, 6 | getStyle, 7 | extend, 8 | cssText, 9 | getRelativeRect, 10 | isInElement, 11 | throwError 12 | } = Fmover 13 | let noop = function () {} 14 | 15 | let opa = extend({ 16 | scrollBar: true, 17 | bounce: true, 18 | onTouchMove: noop, 19 | onTransMove: noop, 20 | onTransMoveEnd: noop, 21 | onMotionStop: noop 22 | }, options) 23 | 24 | const MIN_DISTANCE = 100 25 | 26 | let el = null, 27 | wrapEl = null, 28 | elSize = 0, 29 | wrapSize = 0, 30 | proportion = 0, 31 | scrollBarDom = null, 32 | scrollBarSize = 0, 33 | barMinWidth = 7, 34 | leftLimit = 0, 35 | rightLimit = 0, 36 | barLeftLimit = 0, 37 | barRightLimit = 0, 38 | moved = new Moved(), 39 | currentX = 0, 40 | moveTarget = 0, 41 | transTargetX = 0, 42 | moveType = 'easeOutStrong', 43 | moveTime = 0, 44 | borderBounce = false, 45 | isMoveOut = false 46 | 47 | function createScrollBar (parent, width) { 48 | if (scrollBarDom) { 49 | cssText(scrollBarDom, `width: ${width}px;`) 50 | return 51 | } 52 | scrollBarDom = document.createElement('span') 53 | cssText(scrollBarDom, ` 54 | position: absolute; 55 | z-index: 10000000; 56 | left:0; 57 | bottom: 3px; 58 | height: 3px; 59 | width: ${width}px; 60 | background-color: #000; 61 | opacity: 0; 62 | border-radius: 1.5px; 63 | transition: opacity .2s; 64 | -webkit-transition: opacity .2s; 65 | `) 66 | let parentPosition = getStyle(parent, 'position') 67 | if (parentPosition === 'static') { 68 | cssText(parent, 'position: relative;') 69 | } 70 | parent.appendChild(scrollBarDom) 71 | } 72 | function moveScrollBar (target) { 73 | let scrollBarTarget = target 74 | let gain = 4 75 | let shorten = 0 76 | 77 | if (scrollBarTarget < barLeftLimit) { 78 | shorten = (barLeftLimit - scrollBarTarget) * gain 79 | if (shorten > scrollBarSize - barMinWidth) { 80 | shorten = scrollBarSize - barMinWidth 81 | } 82 | scrollBarTarget = barLeftLimit 83 | } else if (scrollBarTarget > barRightLimit) { 84 | shorten = (scrollBarTarget - barRightLimit) * gain 85 | if (shorten > scrollBarSize - barMinWidth) { 86 | shorten = scrollBarSize - barMinWidth 87 | } 88 | scrollBarTarget = barRightLimit + shorten 89 | } 90 | 91 | let barRealWidth = scrollBarSize - shorten 92 | scrollBarDom.style.width = `${barRealWidth}px` 93 | moved.transform(scrollBarDom, 'translateX', scrollBarTarget) 94 | } 95 | 96 | return { 97 | init (fmover) { 98 | el = fmover.el 99 | wrapEl = el.parentNode 100 | let elPosition = getStyle(el, 'position') 101 | if (elPosition === 'static') { 102 | cssText(el, 'position: relative; z-index: 10;') 103 | } 104 | this.refreshSize() 105 | 106 | }, 107 | start (fingerd) { 108 | let tev = fingerd.fingers[0] 109 | moveType = 'easeOutStrong' 110 | borderBounce = false 111 | isMoveOut = false 112 | 113 | moved.stop((currentPos) => { 114 | currentX = currentPos.translateX 115 | opa.onMotionStop(currentX) 116 | }) 117 | }, 118 | move (fingerd) { 119 | if (moved.moveStatus === 'start') { 120 | return false 121 | } 122 | let tev = fingerd.fingers[0], 123 | fingerInElement = tev.fingerInElement 124 | 125 | moveTarget = currentX + tev.distanceX 126 | 127 | if (!fingerInElement) { 128 | if (!isMoveOut) { 129 | isMoveOut = true 130 | this.makeMove(tev) 131 | } 132 | return false 133 | } 134 | if (moveTarget > leftLimit || rightLimit > 0) { 135 | moveTarget = opa.bounce ? moveTarget * 0.5 : leftLimit 136 | } else if (moveTarget < rightLimit) { 137 | moveTarget = opa.bounce ? (rightLimit + (moveTarget - rightLimit) * 0.5) : rightLimit 138 | } 139 | 140 | moved.transform(tev.el, 'translateX', moveTarget) 141 | if (opa.scrollBar) { 142 | cssText(scrollBarDom, 'opacity: .4;') 143 | moveScrollBar(-(moveTarget * proportion)) 144 | } 145 | opa.onTouchMove.call(this, fingerd) 146 | 147 | }, 148 | end (fingerd) { 149 | let tev = fingerd.fingers[0], 150 | changeFingerIndex = fingerd.changeFingerIndex, 151 | fingerNumber = fingerd.fingerNumber, 152 | fingerInElement = tev.fingerInElement 153 | 154 | if (changeFingerIndex === 0 && fingerNumber === 0 && fingerInElement) { 155 | this.makeMove(tev) 156 | } 157 | 158 | }, 159 | 160 | cancel (fingerd) { 161 | let tev = fingerd.fingers[0], 162 | changeFingerIndex = fingerd.changeFingerIndex, 163 | fingerNumber = fingerd.fingerNumber, 164 | fingerInElement = tev.fingerInElement 165 | 166 | if (changeFingerIndex === 0 && fingerNumber === 0 && fingerInElement) { 167 | currentX = currentX + tev.distanceX 168 | } 169 | }, 170 | 171 | makeMove (tev) { 172 | let tweenS 173 | 174 | moveTime = tev.transTime 175 | currentX = moveTarget 176 | transTargetX = currentX + tev.transDistanceX 177 | 178 | if (currentX > leftLimit || rightLimit > 0) { 179 | transTargetX = leftLimit 180 | moveType = 'easeOutStrong' 181 | moveTime = opa.bounce ? 500 : tev.transTime 182 | borderBounce = true 183 | } else if (currentX < rightLimit) { 184 | transTargetX = rightLimit 185 | moveType = 'easeOutStrong' 186 | moveTime = opa.bounce ? 500 : tev.transTime 187 | borderBounce = true 188 | } else if (transTargetX < rightLimit) { 189 | if (opa.bounce) { 190 | transTargetX = rightLimit 191 | moveType = 'backOut' 192 | moveTime = wearTime(rightLimit) 193 | } else { 194 | moveType = 'easeOutStrong' 195 | } 196 | } else if (transTargetX > leftLimit) { 197 | if (opa.bounce) { 198 | transTargetX = leftLimit 199 | moveType = 'backOut' 200 | moveTime = wearTime(leftLimit) 201 | } else { 202 | moveType = 'easeOutStrong' 203 | } 204 | } 205 | 206 | if (Math.abs(tev.transDistanceX) > MIN_DISTANCE || borderBounce) { 207 | this.wrapMove(transTargetX, moveTime, moveType, tweenS) 208 | } else { 209 | if (opa.scrollBar) { 210 | cssText(scrollBarDom, 'opacity: 0;') 211 | } 212 | } 213 | 214 | function wearTime (target) { 215 | let weartime = (Math.abs(target - currentX) / Math.abs(tev.transDistanceY) * tev.transTime) 216 | if (weartime < 500) { 217 | weartime = 500 218 | tweenS = 2 219 | } else if (weartime > 2000) { 220 | weartime = 2000 221 | } 222 | return weartime 223 | } 224 | }, 225 | 226 | wrapMove (transTargetX, moveTime, moveType, tweenS) { 227 | moved.start({ 228 | el: el, 229 | target: { 230 | translateX: transTargetX 231 | }, 232 | type: moveType, 233 | time: moveTime, 234 | s: tweenS, 235 | inCallBack: function (currentPos) { 236 | currentX = currentPos.translateX 237 | if (!opa.bounce) { 238 | if (currentX >= leftLimit) { 239 | moved.stop((currentPos) => { 240 | currentX = leftLimit 241 | moved.transform(el, 'translateX', currentX) 242 | }) 243 | } 244 | if (currentX <= rightLimit) { 245 | moved.stop((currentPos) => { 246 | currentX = rightLimit 247 | moved.transform(el, 'translateX', rightLimit) 248 | }) 249 | } 250 | } 251 | 252 | if (opa.scrollBar) { 253 | moveScrollBar(-(currentPos.translateX * proportion)) 254 | } 255 | opa.onTransMove.call(this, currentX) 256 | }, 257 | endCallBack: function (currentPos) { 258 | currentX = currentPos.translateX 259 | opa.onTransMoveEnd.call(this, currentX) 260 | opa.onMotionStop(currentX) 261 | if (opa.scrollBar) { 262 | cssText(scrollBarDom, 'opacity: 0;') 263 | } 264 | } 265 | }) 266 | }, 267 | 268 | scrollTo (target, time, limit) { 269 | let child, 270 | selector 271 | if (typeof target === 'string') { 272 | child = document.querySelector(target) 273 | } else if (target instanceof Element) { 274 | child = target 275 | } 276 | if (child) { 277 | if (!isInElement(el, child)) { 278 | throwError('ScrollTo function argument error, `child` must be a child of `parent`') 279 | } 280 | target = -getRelativeRect(el, child).left 281 | } 282 | if (limit && target >= leftLimit) { 283 | target = leftLimit 284 | } else if (limit && rightLimit < 0 && target < rightLimit) { 285 | target = rightLimit 286 | } else if (limit && rightLimit >= 0) { 287 | target = leftLimit 288 | } 289 | 290 | currentX = target 291 | this.wrapMove(target, time, 'easeOutStrong') 292 | }, 293 | 294 | refreshSize () { 295 | elSize = parseFloat(getStyle(el, 'width')) 296 | wrapSize = wrapEl.clientWidth 297 | rightLimit = wrapSize - elSize 298 | leftLimit = 0 299 | if (rightLimit > 0) { 300 | opa.scrollBar = false 301 | } 302 | if (opa.scrollBar) { 303 | proportion = wrapSize / elSize 304 | scrollBarSize = wrapSize * proportion 305 | barMinWidth = scrollBarSize < barMinWidth ? scrollBarSize : barMinWidth 306 | barLeftLimit = -leftLimit * proportion 307 | barRightLimit = -rightLimit * proportion 308 | createScrollBar(wrapEl, scrollBarSize) 309 | } 310 | } 311 | 312 | } 313 | 314 | } 315 | 316 | } -------------------------------------------------------------------------------- /src/plugins/simulation-scroll-x/dist/simulation-scroll-x.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * simulation-scroll-x.js v1.4.2 3 | * (c) 2018 HcySunYang 4 | * Released under the MIT License. 5 | */ 6 | (function (global, factory) { 7 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 8 | typeof define === 'function' && define.amd ? define(factory) : 9 | (global.simulationScrollX = factory()); 10 | }(this, (function () { 'use strict'; 11 | 12 | var simulationScrollX = function (options) { 13 | 14 | return function (Fmover) { 15 | var Moved = Fmover.Moved; 16 | var getStyle = Fmover.getStyle; 17 | var extend = Fmover.extend; 18 | var cssText = Fmover.cssText; 19 | var getRelativeRect = Fmover.getRelativeRect; 20 | var isInElement = Fmover.isInElement; 21 | var throwError = Fmover.throwError; 22 | var noop = function () {}; 23 | 24 | var opa = extend({ 25 | scrollBar: true, 26 | bounce: true, 27 | onTouchMove: noop, 28 | onTransMove: noop, 29 | onTransMoveEnd: noop, 30 | onMotionStop: noop 31 | }, options); 32 | 33 | var MIN_DISTANCE = 100; 34 | 35 | var el = null, 36 | wrapEl = null, 37 | elSize = 0, 38 | wrapSize = 0, 39 | proportion = 0, 40 | scrollBarDom = null, 41 | scrollBarSize = 0, 42 | barMinWidth = 7, 43 | leftLimit = 0, 44 | rightLimit = 0, 45 | barLeftLimit = 0, 46 | barRightLimit = 0, 47 | moved = new Moved(), 48 | currentX = 0, 49 | moveTarget = 0, 50 | transTargetX = 0, 51 | moveType = 'easeOutStrong', 52 | moveTime = 0, 53 | borderBounce = false, 54 | isMoveOut = false; 55 | 56 | function createScrollBar (parent, width) { 57 | if (scrollBarDom) { 58 | cssText(scrollBarDom, ("width: " + width + "px;")); 59 | return 60 | } 61 | scrollBarDom = document.createElement('span'); 62 | cssText(scrollBarDom, ("\n position: absolute;\n z-index: 10000000;\n left:0;\n bottom: 3px;\n height: 3px; \n width: " + width + "px; \n background-color: #000;\n opacity: 0;\n border-radius: 1.5px;\n transition: opacity .2s;\n -webkit-transition: opacity .2s;\n ")); 63 | var parentPosition = getStyle(parent, 'position'); 64 | if (parentPosition === 'static') { 65 | cssText(parent, 'position: relative;'); 66 | } 67 | parent.appendChild(scrollBarDom); 68 | } 69 | function moveScrollBar (target) { 70 | var scrollBarTarget = target; 71 | var gain = 4; 72 | var shorten = 0; 73 | 74 | if (scrollBarTarget < barLeftLimit) { 75 | shorten = (barLeftLimit - scrollBarTarget) * gain; 76 | if (shorten > scrollBarSize - barMinWidth) { 77 | shorten = scrollBarSize - barMinWidth; 78 | } 79 | scrollBarTarget = barLeftLimit; 80 | } else if (scrollBarTarget > barRightLimit) { 81 | shorten = (scrollBarTarget - barRightLimit) * gain; 82 | if (shorten > scrollBarSize - barMinWidth) { 83 | shorten = scrollBarSize - barMinWidth; 84 | } 85 | scrollBarTarget = barRightLimit + shorten; 86 | } 87 | 88 | var barRealWidth = scrollBarSize - shorten; 89 | scrollBarDom.style.width = barRealWidth + "px"; 90 | moved.transform(scrollBarDom, 'translateX', scrollBarTarget); 91 | } 92 | 93 | return { 94 | init: function init (fmover) { 95 | el = fmover.el; 96 | wrapEl = el.parentNode; 97 | var elPosition = getStyle(el, 'position'); 98 | if (elPosition === 'static') { 99 | cssText(el, 'position: relative; z-index: 10;'); 100 | } 101 | this.refreshSize(); 102 | 103 | }, 104 | start: function start (fingerd) { 105 | var tev = fingerd.fingers[0]; 106 | moveType = 'easeOutStrong'; 107 | borderBounce = false; 108 | isMoveOut = false; 109 | 110 | moved.stop(function (currentPos) { 111 | currentX = currentPos.translateX; 112 | opa.onMotionStop(currentX); 113 | }); 114 | }, 115 | move: function move (fingerd) { 116 | if (moved.moveStatus === 'start') { 117 | return false 118 | } 119 | var tev = fingerd.fingers[0], 120 | fingerInElement = tev.fingerInElement; 121 | 122 | moveTarget = currentX + tev.distanceX; 123 | 124 | if (!fingerInElement) { 125 | if (!isMoveOut) { 126 | isMoveOut = true; 127 | this.makeMove(tev); 128 | } 129 | return false 130 | } 131 | if (moveTarget > leftLimit || rightLimit > 0) { 132 | moveTarget = opa.bounce ? moveTarget * 0.5 : leftLimit; 133 | } else if (moveTarget < rightLimit) { 134 | moveTarget = opa.bounce ? (rightLimit + (moveTarget - rightLimit) * 0.5) : rightLimit; 135 | } 136 | 137 | moved.transform(tev.el, 'translateX', moveTarget); 138 | if (opa.scrollBar) { 139 | cssText(scrollBarDom, 'opacity: .4;'); 140 | moveScrollBar(-(moveTarget * proportion)); 141 | } 142 | opa.onTouchMove.call(this, fingerd); 143 | 144 | }, 145 | end: function end (fingerd) { 146 | var tev = fingerd.fingers[0], 147 | changeFingerIndex = fingerd.changeFingerIndex, 148 | fingerNumber = fingerd.fingerNumber, 149 | fingerInElement = tev.fingerInElement; 150 | 151 | if (changeFingerIndex === 0 && fingerNumber === 0 && fingerInElement) { 152 | this.makeMove(tev); 153 | } 154 | 155 | }, 156 | 157 | cancel: function cancel (fingerd) { 158 | var tev = fingerd.fingers[0], 159 | changeFingerIndex = fingerd.changeFingerIndex, 160 | fingerNumber = fingerd.fingerNumber, 161 | fingerInElement = tev.fingerInElement; 162 | 163 | if (changeFingerIndex === 0 && fingerNumber === 0 && fingerInElement) { 164 | currentX = currentX + tev.distanceX; 165 | } 166 | }, 167 | 168 | makeMove: function makeMove (tev) { 169 | var tweenS; 170 | 171 | moveTime = tev.transTime; 172 | currentX = moveTarget; 173 | transTargetX = currentX + tev.transDistanceX; 174 | 175 | if (currentX > leftLimit || rightLimit > 0) { 176 | transTargetX = leftLimit; 177 | moveType = 'easeOutStrong'; 178 | moveTime = opa.bounce ? 500 : tev.transTime; 179 | borderBounce = true; 180 | } else if (currentX < rightLimit) { 181 | transTargetX = rightLimit; 182 | moveType = 'easeOutStrong'; 183 | moveTime = opa.bounce ? 500 : tev.transTime; 184 | borderBounce = true; 185 | } else if (transTargetX < rightLimit) { 186 | if (opa.bounce) { 187 | transTargetX = rightLimit; 188 | moveType = 'backOut'; 189 | moveTime = wearTime(rightLimit); 190 | } else { 191 | moveType = 'easeOutStrong'; 192 | } 193 | } else if (transTargetX > leftLimit) { 194 | if (opa.bounce) { 195 | transTargetX = leftLimit; 196 | moveType = 'backOut'; 197 | moveTime = wearTime(leftLimit); 198 | } else { 199 | moveType = 'easeOutStrong'; 200 | } 201 | } 202 | 203 | if (Math.abs(tev.transDistanceX) > MIN_DISTANCE || borderBounce) { 204 | this.wrapMove(transTargetX, moveTime, moveType, tweenS); 205 | } else { 206 | if (opa.scrollBar) { 207 | cssText(scrollBarDom, 'opacity: 0;'); 208 | } 209 | } 210 | 211 | function wearTime (target) { 212 | var weartime = (Math.abs(target - currentX) / Math.abs(tev.transDistanceY) * tev.transTime); 213 | if (weartime < 500) { 214 | weartime = 500; 215 | tweenS = 2; 216 | } else if (weartime > 2000) { 217 | weartime = 2000; 218 | } 219 | return weartime 220 | } 221 | }, 222 | 223 | wrapMove: function wrapMove (transTargetX, moveTime, moveType, tweenS) { 224 | moved.start({ 225 | el: el, 226 | target: { 227 | translateX: transTargetX 228 | }, 229 | type: moveType, 230 | time: moveTime, 231 | s: tweenS, 232 | inCallBack: function (currentPos) { 233 | currentX = currentPos.translateX; 234 | if (!opa.bounce) { 235 | if (currentX >= leftLimit) { 236 | moved.stop(function (currentPos) { 237 | currentX = leftLimit; 238 | moved.transform(el, 'translateX', currentX); 239 | }); 240 | } 241 | if (currentX <= rightLimit) { 242 | moved.stop(function (currentPos) { 243 | currentX = rightLimit; 244 | moved.transform(el, 'translateX', rightLimit); 245 | }); 246 | } 247 | } 248 | 249 | if (opa.scrollBar) { 250 | moveScrollBar(-(currentPos.translateX * proportion)); 251 | } 252 | opa.onTransMove.call(this, currentX); 253 | }, 254 | endCallBack: function (currentPos) { 255 | currentX = currentPos.translateX; 256 | opa.onTransMoveEnd.call(this, currentX); 257 | opa.onMotionStop(currentX); 258 | if (opa.scrollBar) { 259 | cssText(scrollBarDom, 'opacity: 0;'); 260 | } 261 | } 262 | }); 263 | }, 264 | 265 | scrollTo: function scrollTo (target, time, limit) { 266 | var child, 267 | selector; 268 | if (typeof target === 'string') { 269 | child = document.querySelector(target); 270 | } else if (target instanceof Element) { 271 | child = target; 272 | } 273 | if (child) { 274 | if (!isInElement(el, child)) { 275 | throwError('ScrollTo function argument error, `child` must be a child of `parent`'); 276 | } 277 | target = -getRelativeRect(el, child).left; 278 | } 279 | if (limit && target >= leftLimit) { 280 | target = leftLimit; 281 | } else if (limit && rightLimit < 0 && target < rightLimit) { 282 | target = rightLimit; 283 | } else if (limit && rightLimit >= 0) { 284 | target = leftLimit; 285 | } 286 | 287 | currentX = target; 288 | this.wrapMove(target, time, 'easeOutStrong'); 289 | }, 290 | 291 | refreshSize: function refreshSize () { 292 | elSize = parseFloat(getStyle(el, 'width')); 293 | wrapSize = wrapEl.clientWidth; 294 | rightLimit = wrapSize - elSize; 295 | leftLimit = 0; 296 | if (rightLimit > 0) { 297 | opa.scrollBar = false; 298 | } 299 | if (opa.scrollBar) { 300 | proportion = wrapSize / elSize; 301 | scrollBarSize = wrapSize * proportion; 302 | barMinWidth = scrollBarSize < barMinWidth ? scrollBarSize : barMinWidth; 303 | barLeftLimit = -leftLimit * proportion; 304 | barRightLimit = -rightLimit * proportion; 305 | createScrollBar(wrapEl, scrollBarSize); 306 | } 307 | } 308 | 309 | } 310 | 311 | } 312 | 313 | }; 314 | 315 | return simulationScrollX; 316 | 317 | }))); 318 | -------------------------------------------------------------------------------- /src/plugins/fmover-slide-y/fmover-slide-y.js: -------------------------------------------------------------------------------- 1 | export default function (options) { 2 | 3 | return function (Fmover) { 4 | const { 5 | Moved, 6 | getStyle, 7 | extend, 8 | cssText, 9 | getRelativeRect, 10 | isInElement, 11 | throwError, 12 | toArray 13 | } = Fmover 14 | const SPEED = 0.5 15 | const AUTOPLAY_DIR = { 16 | top: 'top', 17 | bottom: 'bottom' 18 | } 19 | let el = null, 20 | parentEl = null, 21 | slideEls = null, 22 | slideNumber = 0, 23 | realSlideNumber = 0, 24 | slideHeight = 0, 25 | elHeight = 0, 26 | current = 0, 27 | target = 0, 28 | moved = new Moved(), 29 | topLimit = 0, 30 | bottomLimit = 0, 31 | isMoveOut = false, 32 | timer = null, 33 | lock = false, 34 | isChange = false 35 | 36 | let noop = function () {} 37 | let opa = extend({ 38 | startSlide: 1, 39 | autoplay: 0, 40 | autoplayDir: AUTOPLAY_DIR.top, 41 | loop: true, 42 | times: 500, 43 | bounce: true, 44 | touchable: true, 45 | onInit: noop, 46 | onTouchStart: noop, 47 | onTouchMove: noop, 48 | onTouchEnd: noop, 49 | onTransStart: noop, 50 | onTransMove: noop, 51 | onTransEnd: noop, 52 | onChangeStart: noop, 53 | onChange: noop, 54 | onChangeEnd: noop, 55 | onRefresh: noop 56 | }, options) 57 | 58 | return { 59 | index: 1, 60 | get slideIndex () { 61 | return this.redressIndex(this.index) 62 | }, 63 | get slideNumber () { 64 | return slideNumber 65 | }, 66 | init (fmover) { 67 | el = fmover.el 68 | parentEl = el.parentNode 69 | this.refreshWrap(true) 70 | opa.onInit.call(this) 71 | }, 72 | start (fingerd) { 73 | if (fingerd.changeFingerIndex !== 0 || !opa.touchable) { 74 | return false 75 | } 76 | isMoveOut = false 77 | isChange = false 78 | clearInterval(timer) 79 | moved.stop(function (currentPos) { 80 | current = currentPos.translateY 81 | }) 82 | if (opa.autoplay) { 83 | clearInterval(timer) 84 | } 85 | if (this.index > slideNumber) { 86 | current = current + slideNumber * slideHeight 87 | this.index = 1 88 | } else if (this.index === 0) { 89 | this.index = slideNumber 90 | current = current - slideNumber * slideHeight 91 | } 92 | moved.transform(el, 'translateY', current) 93 | opa.onTouchStart.call(this, current) 94 | }, 95 | move (fingerd) { 96 | let fg = fingerd.fingers[0] 97 | if (!opa.touchable) { 98 | return false 99 | } 100 | if (!fg.fingerInElement) { 101 | if (!isMoveOut) { 102 | isMoveOut = true 103 | this.wrapMove(fg) 104 | if (opa.autoplay) { 105 | clearInterval(timer) 106 | this.initAutoplay() 107 | } 108 | opa.onTouchEnd.call(this) 109 | } 110 | return false 111 | } 112 | target = current + fg.distanceY 113 | if (!opa.loop) { 114 | if (target > topLimit) { 115 | target = opa.bounce ? target * 0.5 : topLimit 116 | } else if (target < bottomLimit) { 117 | target = opa.bounce ? (bottomLimit + (target - bottomLimit) * 0.5) : bottomLimit 118 | } 119 | } 120 | 121 | moved.transform(el, 'translateY', target) 122 | opa.onTouchMove.call(this, target) 123 | }, 124 | end (fingerd) { 125 | let fg = fingerd.fingers[0] 126 | if (!fg.fingerInElement || 127 | fingerd.changeFingerIndex !== 0 || 128 | fingerd.fingerNumber !== 0 || 129 | !opa.touchable) { 130 | return false 131 | } 132 | current = target 133 | this.wrapMove(fg) 134 | if (opa.autoplay) { 135 | clearInterval(timer) 136 | this.initAutoplay() 137 | } 138 | opa.onTouchEnd.call(this) 139 | }, 140 | cancel (fingerd) { 141 | if (!opa.touchable) { 142 | return false 143 | } 144 | if (opa.autoplay) { 145 | clearInterval(timer) 146 | this.initAutoplay() 147 | } 148 | this.makeMove() 149 | }, 150 | refresh (force) { 151 | this.refreshWrap(force) 152 | opa.onRefresh.call(this, slideNumber) 153 | }, 154 | refreshWrap (force) { 155 | force && moved && moved.stop(() => { 156 | lock = false 157 | }) 158 | let cloneNodes = toArray(el.querySelectorAll('[clone=true]')) 159 | cloneNodes.forEach((o) => { 160 | o.parentNode.removeChild(o) 161 | }) 162 | slideEls = Array.prototype.slice.call(el.children) 163 | slideNumber = slideEls.length 164 | slideHeight = parseInt(getStyle(parentEl, 'height')) 165 | this.index = force 166 | ? this.limitIndex(opa.startSlide) 167 | : this.limitIndex(this.index) 168 | if (opa.loop) { 169 | let firstSlideEl = slideEls[0] 170 | let lastSlideEl = slideEls[slideNumber - 1] 171 | let cloneFirst = firstSlideEl.cloneNode(true) 172 | cloneFirst.setAttribute('clone', true) 173 | let cloneLast = lastSlideEl.cloneNode(true) 174 | cloneLast.setAttribute('clone', true) 175 | el.appendChild(cloneFirst) 176 | el.insertBefore(cloneLast, el.firstElementChild) 177 | slideEls.push(cloneFirst) 178 | slideEls.unshift(cloneLast) 179 | current = -this.index * slideHeight 180 | } else { 181 | current = -(this.index - 1) * slideHeight 182 | } 183 | 184 | realSlideNumber = slideEls.length 185 | elHeight = slideHeight * realSlideNumber 186 | if (!opa.loop) { 187 | bottomLimit = -(elHeight - slideHeight) 188 | } 189 | cssText(parentEl, 'overflow: hidden;') 190 | cssText(el, `height: ${elHeight}px; width: 100%; overflow: hidden;`) 191 | moved.transform(el, 'translateY', current) 192 | slideEls.forEach((o, i, a) => { 193 | cssText(o, `width: 100%; height: ${slideHeight}px;`) 194 | }) 195 | 196 | if (opa.autoplay) { 197 | clearInterval(timer) 198 | this.initAutoplay() 199 | } 200 | }, 201 | prev () { 202 | if (lock) { 203 | return false 204 | } 205 | lock = true 206 | this.index-- 207 | if (!opa.loop && this.index === 0) { 208 | this.index = slideNumber 209 | } 210 | this.onChangeStart(this.redressIndex(this.index), AUTOPLAY_DIR.top) 211 | this.makeMove() 212 | }, 213 | next () { 214 | if (lock) { 215 | return false 216 | } 217 | lock = true 218 | this.index++ 219 | if (!opa.loop && this.index > slideNumber) { 220 | this.index = 1 221 | } 222 | this.onChangeStart(this.redressIndex(this.index), AUTOPLAY_DIR.bottom) 223 | this.makeMove() 224 | }, 225 | slideTo (index, times) { 226 | if (lock || this.slideIndex === index) { 227 | return false 228 | } 229 | lock = true 230 | if (this.index !== index) { 231 | let dir = this.index > index ? AUTOPLAY_DIR.bottom : AUTOPLAY_DIR.top 232 | this.index = this.limitIndex(index) 233 | this.onChangeStart(this.redressIndex(this.index), dir) 234 | this.makeMove(times) 235 | } 236 | }, 237 | initAutoplay () { 238 | timer = setInterval(() => { 239 | if (opa.autoplayDir === AUTOPLAY_DIR.top) { 240 | this.next() 241 | } else { 242 | this.prev() 243 | } 244 | }, opa.autoplay) 245 | }, 246 | wrapMove (fg) { 247 | let forceStopTop = opa.loop || (!opa.loop && this.index !== slideNumber) 248 | let forceStopBottom = opa.loop || (!opa.loop && this.index !== 1) 249 | 250 | if (forceStopTop && 251 | (fg.direction.top && Math.abs(fg.yv) > SPEED && fg.distanceY < 0) || 252 | (forceStopTop && fg.distanceY < -slideHeight / 2)) { 253 | this.index++ 254 | this.onChangeStart(this.redressIndex(this.index), AUTOPLAY_DIR.top) 255 | } else if (forceStopBottom && 256 | (fg.direction.bottom && Math.abs(fg.yv) > SPEED && fg.distanceY > 0) || 257 | (forceStopBottom && fg.distanceY > slideHeight / 2)) { 258 | this.index-- 259 | this.onChangeStart(this.redressIndex(this.index), AUTOPLAY_DIR.bottom) 260 | } 261 | this.makeMove() 262 | }, 263 | 264 | makeMove (times) { 265 | let that = this 266 | opa.onTransStart.call(this, current) 267 | if (opa.loop) { 268 | if (this.index < 0) { 269 | this.index = 0 270 | } else if (this.index > slideNumber + 1) { 271 | this.index = slideNumber + 1 272 | } 273 | current = -this.index * slideHeight 274 | } else { 275 | if (this.index < 1) { 276 | this.index = 1 277 | } else if (this.index > slideNumber) { 278 | this.index = slideNumber 279 | } 280 | current = -(this.index - 1) * slideHeight 281 | } 282 | moved.start({ 283 | el: el, 284 | target: { 285 | translateY: current 286 | }, 287 | inCallBack: function (currentPos) { 288 | opa.onTransMove.call(that, currentPos.translateY) 289 | if (isChange) { 290 | opa.onChange.call(that, currentPos.translateY) 291 | } 292 | }, 293 | endCallBack: function (currentPos) { 294 | lock = false 295 | if (opa.loop && that.index > slideNumber) { 296 | current = current + slideNumber * slideHeight 297 | moved.transform(el, 'translateY', current) 298 | that.index = 1 299 | } else if (opa.loop && that.index === 0) { 300 | that.index = slideNumber 301 | current = current - slideNumber * slideHeight 302 | moved.transform(el, 'translateY', current) 303 | } 304 | opa.onTransEnd.call(that, currentPos.translateY) 305 | if (isChange) { 306 | opa.onChangeEnd.call(that, currentPos.translateY) 307 | } 308 | }, 309 | time: typeof times === 'undefined' ? opa.times : times 310 | }) 311 | }, 312 | 313 | onChangeStart (index, dir) { 314 | isChange = true 315 | opa.onChangeStart.call(this, index, dir) 316 | }, 317 | 318 | redressIndex (index) { 319 | if (index === 0) { 320 | return slideNumber 321 | } 322 | if (index > slideNumber) { 323 | return 1 324 | } 325 | return index 326 | }, 327 | 328 | limitIndex (index) { 329 | return index > slideNumber 330 | ? slideNumber 331 | : index < 1 332 | ? 1 333 | : index 334 | }, 335 | destroy () { 336 | clearInterval(timer) 337 | } 338 | 339 | } 340 | 341 | } 342 | 343 | } --------------------------------------------------------------------------------