hammerjs_rails 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +33 -0
- data/Rakefile +2 -0
- data/app/assets/javascripts/hammer.js +2163 -0
- data/hammerjs_rails.gemspec +25 -0
- data/lib/hammerjs_rails.rb +8 -0
- data/lib/hammerjs_rails/version.rb +3 -0
- metadata +97 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 07e04e93367436529241e395b86d27136fd739ff
|
4
|
+
data.tar.gz: f8c7b6a4e8d8a0dec2a0178fd22e6669cdbe69ee
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 615c08b00653f78fb62551662205b784932efd2b1c5321f818a48619dc66162cd0ba5ce15594c930404d9924ea70bcadc1bb8f0bdc22fd2998e3c85cec9b6e49
|
7
|
+
data.tar.gz: 644b387e8ef92e1d6bc085be1452d7c1320b6f71b85e78604cd64b5f69a913a17f52ec7db4ea2caff70a84e43dc9b1d4b0ceb748c9652315054601e067799661
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Guy Israeli
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# HammerjsRails
|
2
|
+
|
3
|
+
Hammer.js for Ruby on Rails
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'hammerjs_rails'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install hammerjs_rails
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
add to manifest (application.js)
|
22
|
+
|
23
|
+
//= require hammer
|
24
|
+
|
25
|
+
and then lay down the hammer on https://github.com/EightMedia/hammer.js
|
26
|
+
|
27
|
+
## Contributing
|
28
|
+
|
29
|
+
1. Fork it ( https://github.com/[my-github-username]/hammerjs_rails/fork )
|
30
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
31
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
32
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
33
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,2163 @@
|
|
1
|
+
/*! Hammer.JS - v1.1.3 - 2014-05-22
|
2
|
+
* http://eightmedia.github.io/hammer.js
|
3
|
+
*
|
4
|
+
* Copyright (c) 2014 Jorik Tangelder <j.tangelder@gmail.com>;
|
5
|
+
* Licensed under the MIT license */
|
6
|
+
|
7
|
+
(function(window, undefined) {
|
8
|
+
'use strict';
|
9
|
+
|
10
|
+
/**
|
11
|
+
* @main
|
12
|
+
* @module hammer
|
13
|
+
*
|
14
|
+
* @class Hammer
|
15
|
+
* @static
|
16
|
+
*/
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Hammer, use this to create instances
|
20
|
+
* ````
|
21
|
+
* var hammertime = new Hammer(myElement);
|
22
|
+
* ````
|
23
|
+
*
|
24
|
+
* @method Hammer
|
25
|
+
* @param {HTMLElement} element
|
26
|
+
* @param {Object} [options={}]
|
27
|
+
* @return {Hammer.Instance}
|
28
|
+
*/
|
29
|
+
var Hammer = function Hammer(element, options) {
|
30
|
+
return new Hammer.Instance(element, options || {});
|
31
|
+
};
|
32
|
+
|
33
|
+
/**
|
34
|
+
* version, as defined in package.json
|
35
|
+
* the value will be set at each build
|
36
|
+
* @property VERSION
|
37
|
+
* @final
|
38
|
+
* @type {String}
|
39
|
+
*/
|
40
|
+
Hammer.VERSION = '1.1.3';
|
41
|
+
|
42
|
+
/**
|
43
|
+
* default settings.
|
44
|
+
* more settings are defined per gesture at `/gestures`. Each gesture can be disabled/enabled
|
45
|
+
* by setting it's name (like `swipe`) to false.
|
46
|
+
* You can set the defaults for all instances by changing this object before creating an instance.
|
47
|
+
* @example
|
48
|
+
* ````
|
49
|
+
* Hammer.defaults.drag = false;
|
50
|
+
* Hammer.defaults.behavior.touchAction = 'pan-y';
|
51
|
+
* delete Hammer.defaults.behavior.userSelect;
|
52
|
+
* ````
|
53
|
+
* @property defaults
|
54
|
+
* @type {Object}
|
55
|
+
*/
|
56
|
+
Hammer.defaults = {
|
57
|
+
/**
|
58
|
+
* this setting object adds styles and attributes to the element to prevent the browser from doing
|
59
|
+
* its native behavior. The css properties are auto prefixed for the browsers when needed.
|
60
|
+
* @property defaults.behavior
|
61
|
+
* @type {Object}
|
62
|
+
*/
|
63
|
+
behavior: {
|
64
|
+
/**
|
65
|
+
* Disables text selection to improve the dragging gesture. When the value is `none` it also sets
|
66
|
+
* `onselectstart=false` for IE on the element. Mainly for desktop browsers.
|
67
|
+
* @property defaults.behavior.userSelect
|
68
|
+
* @type {String}
|
69
|
+
* @default 'none'
|
70
|
+
*/
|
71
|
+
userSelect: 'none',
|
72
|
+
|
73
|
+
/**
|
74
|
+
* Specifies whether and how a given region can be manipulated by the user (for instance, by panning or zooming).
|
75
|
+
* Used by Chrome 35> and IE10>. By default this makes the element blocking any touch event.
|
76
|
+
* @property defaults.behavior.touchAction
|
77
|
+
* @type {String}
|
78
|
+
* @default: 'pan-y'
|
79
|
+
*/
|
80
|
+
touchAction: 'pan-y',
|
81
|
+
|
82
|
+
/**
|
83
|
+
* Disables the default callout shown when you touch and hold a touch target.
|
84
|
+
* On iOS, when you touch and hold a touch target such as a link, Safari displays
|
85
|
+
* a callout containing information about the link. This property allows you to disable that callout.
|
86
|
+
* @property defaults.behavior.touchCallout
|
87
|
+
* @type {String}
|
88
|
+
* @default 'none'
|
89
|
+
*/
|
90
|
+
touchCallout: 'none',
|
91
|
+
|
92
|
+
/**
|
93
|
+
* Specifies whether zooming is enabled. Used by IE10>
|
94
|
+
* @property defaults.behavior.contentZooming
|
95
|
+
* @type {String}
|
96
|
+
* @default 'none'
|
97
|
+
*/
|
98
|
+
contentZooming: 'none',
|
99
|
+
|
100
|
+
/**
|
101
|
+
* Specifies that an entire element should be draggable instead of its contents.
|
102
|
+
* Mainly for desktop browsers.
|
103
|
+
* @property defaults.behavior.userDrag
|
104
|
+
* @type {String}
|
105
|
+
* @default 'none'
|
106
|
+
*/
|
107
|
+
userDrag: 'none',
|
108
|
+
|
109
|
+
/**
|
110
|
+
* Overrides the highlight color shown when the user taps a link or a JavaScript
|
111
|
+
* clickable element in Safari on iPhone. This property obeys the alpha value, if specified.
|
112
|
+
*
|
113
|
+
* If you don't specify an alpha value, Safari on iPhone applies a default alpha value
|
114
|
+
* to the color. To disable tap highlighting, set the alpha value to 0 (invisible).
|
115
|
+
* If you set the alpha value to 1.0 (opaque), the element is not visible when tapped.
|
116
|
+
* @property defaults.behavior.tapHighlightColor
|
117
|
+
* @type {String}
|
118
|
+
* @default 'rgba(0,0,0,0)'
|
119
|
+
*/
|
120
|
+
tapHighlightColor: 'rgba(0,0,0,0)'
|
121
|
+
}
|
122
|
+
};
|
123
|
+
|
124
|
+
/**
|
125
|
+
* hammer document where the base events are added at
|
126
|
+
* @property DOCUMENT
|
127
|
+
* @type {HTMLElement}
|
128
|
+
* @default window.document
|
129
|
+
*/
|
130
|
+
Hammer.DOCUMENT = document;
|
131
|
+
|
132
|
+
/**
|
133
|
+
* detect support for pointer events
|
134
|
+
* @property HAS_POINTEREVENTS
|
135
|
+
* @type {Boolean}
|
136
|
+
*/
|
137
|
+
Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled;
|
138
|
+
|
139
|
+
/**
|
140
|
+
* detect support for touch events
|
141
|
+
* @property HAS_TOUCHEVENTS
|
142
|
+
* @type {Boolean}
|
143
|
+
*/
|
144
|
+
Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window);
|
145
|
+
|
146
|
+
/**
|
147
|
+
* detect mobile browsers
|
148
|
+
* @property IS_MOBILE
|
149
|
+
* @type {Boolean}
|
150
|
+
*/
|
151
|
+
Hammer.IS_MOBILE = /mobile|tablet|ip(ad|hone|od)|android|silk/i.test(navigator.userAgent);
|
152
|
+
|
153
|
+
/**
|
154
|
+
* detect if we want to support mouseevents at all
|
155
|
+
* @property NO_MOUSEEVENTS
|
156
|
+
* @type {Boolean}
|
157
|
+
*/
|
158
|
+
Hammer.NO_MOUSEEVENTS = (Hammer.HAS_TOUCHEVENTS && Hammer.IS_MOBILE) || Hammer.HAS_POINTEREVENTS;
|
159
|
+
|
160
|
+
/**
|
161
|
+
* interval in which Hammer recalculates current velocity/direction/angle in ms
|
162
|
+
* @property CALCULATE_INTERVAL
|
163
|
+
* @type {Number}
|
164
|
+
* @default 25
|
165
|
+
*/
|
166
|
+
Hammer.CALCULATE_INTERVAL = 25;
|
167
|
+
|
168
|
+
/**
|
169
|
+
* eventtypes per touchevent (start, move, end) are filled by `Event.determineEventTypes` on `setup`
|
170
|
+
* the object contains the DOM event names per type (`EVENT_START`, `EVENT_MOVE`, `EVENT_END`)
|
171
|
+
* @property EVENT_TYPES
|
172
|
+
* @private
|
173
|
+
* @writeOnce
|
174
|
+
* @type {Object}
|
175
|
+
*/
|
176
|
+
var EVENT_TYPES = {};
|
177
|
+
|
178
|
+
/**
|
179
|
+
* direction strings, for safe comparisons
|
180
|
+
* @property DIRECTION_DOWN|LEFT|UP|RIGHT
|
181
|
+
* @final
|
182
|
+
* @type {String}
|
183
|
+
* @default 'down' 'left' 'up' 'right'
|
184
|
+
*/
|
185
|
+
var DIRECTION_DOWN = Hammer.DIRECTION_DOWN = 'down';
|
186
|
+
var DIRECTION_LEFT = Hammer.DIRECTION_LEFT = 'left';
|
187
|
+
var DIRECTION_UP = Hammer.DIRECTION_UP = 'up';
|
188
|
+
var DIRECTION_RIGHT = Hammer.DIRECTION_RIGHT = 'right';
|
189
|
+
|
190
|
+
/**
|
191
|
+
* pointertype strings, for safe comparisons
|
192
|
+
* @property POINTER_MOUSE|TOUCH|PEN
|
193
|
+
* @final
|
194
|
+
* @type {String}
|
195
|
+
* @default 'mouse' 'touch' 'pen'
|
196
|
+
*/
|
197
|
+
var POINTER_MOUSE = Hammer.POINTER_MOUSE = 'mouse';
|
198
|
+
var POINTER_TOUCH = Hammer.POINTER_TOUCH = 'touch';
|
199
|
+
var POINTER_PEN = Hammer.POINTER_PEN = 'pen';
|
200
|
+
|
201
|
+
/**
|
202
|
+
* eventtypes
|
203
|
+
* @property EVENT_START|MOVE|END|RELEASE|TOUCH
|
204
|
+
* @final
|
205
|
+
* @type {String}
|
206
|
+
* @default 'start' 'change' 'move' 'end' 'release' 'touch'
|
207
|
+
*/
|
208
|
+
var EVENT_START = Hammer.EVENT_START = 'start';
|
209
|
+
var EVENT_MOVE = Hammer.EVENT_MOVE = 'move';
|
210
|
+
var EVENT_END = Hammer.EVENT_END = 'end';
|
211
|
+
var EVENT_RELEASE = Hammer.EVENT_RELEASE = 'release';
|
212
|
+
var EVENT_TOUCH = Hammer.EVENT_TOUCH = 'touch';
|
213
|
+
|
214
|
+
/**
|
215
|
+
* if the window events are set...
|
216
|
+
* @property READY
|
217
|
+
* @writeOnce
|
218
|
+
* @type {Boolean}
|
219
|
+
* @default false
|
220
|
+
*/
|
221
|
+
Hammer.READY = false;
|
222
|
+
|
223
|
+
/**
|
224
|
+
* plugins namespace
|
225
|
+
* @property plugins
|
226
|
+
* @type {Object}
|
227
|
+
*/
|
228
|
+
Hammer.plugins = Hammer.plugins || {};
|
229
|
+
|
230
|
+
/**
|
231
|
+
* gestures namespace
|
232
|
+
* see `/gestures` for the definitions
|
233
|
+
* @property gestures
|
234
|
+
* @type {Object}
|
235
|
+
*/
|
236
|
+
Hammer.gestures = Hammer.gestures || {};
|
237
|
+
|
238
|
+
/**
|
239
|
+
* setup events to detect gestures on the document
|
240
|
+
* this function is called when creating an new instance
|
241
|
+
* @private
|
242
|
+
*/
|
243
|
+
function setup() {
|
244
|
+
if(Hammer.READY) {
|
245
|
+
return;
|
246
|
+
}
|
247
|
+
|
248
|
+
// find what eventtypes we add listeners to
|
249
|
+
Event.determineEventTypes();
|
250
|
+
|
251
|
+
// Register all gestures inside Hammer.gestures
|
252
|
+
Utils.each(Hammer.gestures, function(gesture) {
|
253
|
+
Detection.register(gesture);
|
254
|
+
});
|
255
|
+
|
256
|
+
// Add touch events on the document
|
257
|
+
Event.onTouch(Hammer.DOCUMENT, EVENT_MOVE, Detection.detect);
|
258
|
+
Event.onTouch(Hammer.DOCUMENT, EVENT_END, Detection.detect);
|
259
|
+
|
260
|
+
// Hammer is ready...!
|
261
|
+
Hammer.READY = true;
|
262
|
+
}
|
263
|
+
|
264
|
+
/**
|
265
|
+
* @module hammer
|
266
|
+
*
|
267
|
+
* @class Utils
|
268
|
+
* @static
|
269
|
+
*/
|
270
|
+
var Utils = Hammer.utils = {
|
271
|
+
/**
|
272
|
+
* extend method, could also be used for cloning when `dest` is an empty object.
|
273
|
+
* changes the dest object
|
274
|
+
* @method extend
|
275
|
+
* @param {Object} dest
|
276
|
+
* @param {Object} src
|
277
|
+
* @param {Boolean} [merge=false] do a merge
|
278
|
+
* @return {Object} dest
|
279
|
+
*/
|
280
|
+
extend: function extend(dest, src, merge) {
|
281
|
+
for(var key in src) {
|
282
|
+
if(!src.hasOwnProperty(key) || (dest[key] !== undefined && merge)) {
|
283
|
+
continue;
|
284
|
+
}
|
285
|
+
dest[key] = src[key];
|
286
|
+
}
|
287
|
+
return dest;
|
288
|
+
},
|
289
|
+
|
290
|
+
/**
|
291
|
+
* simple addEventListener wrapper
|
292
|
+
* @method on
|
293
|
+
* @param {HTMLElement} element
|
294
|
+
* @param {String} type
|
295
|
+
* @param {Function} handler
|
296
|
+
*/
|
297
|
+
on: function on(element, type, handler) {
|
298
|
+
element.addEventListener(type, handler, false);
|
299
|
+
},
|
300
|
+
|
301
|
+
/**
|
302
|
+
* simple removeEventListener wrapper
|
303
|
+
* @method off
|
304
|
+
* @param {HTMLElement} element
|
305
|
+
* @param {String} type
|
306
|
+
* @param {Function} handler
|
307
|
+
*/
|
308
|
+
off: function off(element, type, handler) {
|
309
|
+
element.removeEventListener(type, handler, false);
|
310
|
+
},
|
311
|
+
|
312
|
+
/**
|
313
|
+
* forEach over arrays and objects
|
314
|
+
* @method each
|
315
|
+
* @param {Object|Array} obj
|
316
|
+
* @param {Function} iterator
|
317
|
+
* @param {any} iterator.item
|
318
|
+
* @param {Number} iterator.index
|
319
|
+
* @param {Object|Array} iterator.obj the source object
|
320
|
+
* @param {Object} context value to use as `this` in the iterator
|
321
|
+
*/
|
322
|
+
each: function each(obj, iterator, context) {
|
323
|
+
var i, len;
|
324
|
+
|
325
|
+
// native forEach on arrays
|
326
|
+
if('forEach' in obj) {
|
327
|
+
obj.forEach(iterator, context);
|
328
|
+
// arrays
|
329
|
+
} else if(obj.length !== undefined) {
|
330
|
+
for(i = 0, len = obj.length; i < len; i++) {
|
331
|
+
if(iterator.call(context, obj[i], i, obj) === false) {
|
332
|
+
return;
|
333
|
+
}
|
334
|
+
}
|
335
|
+
// objects
|
336
|
+
} else {
|
337
|
+
for(i in obj) {
|
338
|
+
if(obj.hasOwnProperty(i) &&
|
339
|
+
iterator.call(context, obj[i], i, obj) === false) {
|
340
|
+
return;
|
341
|
+
}
|
342
|
+
}
|
343
|
+
}
|
344
|
+
},
|
345
|
+
|
346
|
+
/**
|
347
|
+
* find if a string contains the string using indexOf
|
348
|
+
* @method inStr
|
349
|
+
* @param {String} src
|
350
|
+
* @param {String} find
|
351
|
+
* @return {Boolean} found
|
352
|
+
*/
|
353
|
+
inStr: function inStr(src, find) {
|
354
|
+
return src.indexOf(find) > -1;
|
355
|
+
},
|
356
|
+
|
357
|
+
/**
|
358
|
+
* find if a array contains the object using indexOf or a simple polyfill
|
359
|
+
* @method inArray
|
360
|
+
* @param {String} src
|
361
|
+
* @param {String} find
|
362
|
+
* @return {Boolean|Number} false when not found, or the index
|
363
|
+
*/
|
364
|
+
inArray: function inArray(src, find) {
|
365
|
+
if(src.indexOf) {
|
366
|
+
var index = src.indexOf(find);
|
367
|
+
return (index === -1) ? false : index;
|
368
|
+
} else {
|
369
|
+
for(var i = 0, len = src.length; i < len; i++) {
|
370
|
+
if(src[i] === find) {
|
371
|
+
return i;
|
372
|
+
}
|
373
|
+
}
|
374
|
+
return false;
|
375
|
+
}
|
376
|
+
},
|
377
|
+
|
378
|
+
/**
|
379
|
+
* convert an array-like object (`arguments`, `touchlist`) to an array
|
380
|
+
* @method toArray
|
381
|
+
* @param {Object} obj
|
382
|
+
* @return {Array}
|
383
|
+
*/
|
384
|
+
toArray: function toArray(obj) {
|
385
|
+
return Array.prototype.slice.call(obj, 0);
|
386
|
+
},
|
387
|
+
|
388
|
+
/**
|
389
|
+
* find if a node is in the given parent
|
390
|
+
* @method hasParent
|
391
|
+
* @param {HTMLElement} node
|
392
|
+
* @param {HTMLElement} parent
|
393
|
+
* @return {Boolean} found
|
394
|
+
*/
|
395
|
+
hasParent: function hasParent(node, parent) {
|
396
|
+
while(node) {
|
397
|
+
if(node == parent) {
|
398
|
+
return true;
|
399
|
+
}
|
400
|
+
node = node.parentNode;
|
401
|
+
}
|
402
|
+
return false;
|
403
|
+
},
|
404
|
+
|
405
|
+
/**
|
406
|
+
* get the center of all the touches
|
407
|
+
* @method getCenter
|
408
|
+
* @param {Array} touches
|
409
|
+
* @return {Object} center contains `pageX`, `pageY`, `clientX` and `clientY` properties
|
410
|
+
*/
|
411
|
+
getCenter: function getCenter(touches) {
|
412
|
+
var pageX = [],
|
413
|
+
pageY = [],
|
414
|
+
clientX = [],
|
415
|
+
clientY = [],
|
416
|
+
min = Math.min,
|
417
|
+
max = Math.max;
|
418
|
+
|
419
|
+
// no need to loop when only one touch
|
420
|
+
if(touches.length === 1) {
|
421
|
+
return {
|
422
|
+
pageX: touches[0].pageX,
|
423
|
+
pageY: touches[0].pageY,
|
424
|
+
clientX: touches[0].clientX,
|
425
|
+
clientY: touches[0].clientY
|
426
|
+
};
|
427
|
+
}
|
428
|
+
|
429
|
+
Utils.each(touches, function(touch) {
|
430
|
+
pageX.push(touch.pageX);
|
431
|
+
pageY.push(touch.pageY);
|
432
|
+
clientX.push(touch.clientX);
|
433
|
+
clientY.push(touch.clientY);
|
434
|
+
});
|
435
|
+
|
436
|
+
return {
|
437
|
+
pageX: (min.apply(Math, pageX) + max.apply(Math, pageX)) / 2,
|
438
|
+
pageY: (min.apply(Math, pageY) + max.apply(Math, pageY)) / 2,
|
439
|
+
clientX: (min.apply(Math, clientX) + max.apply(Math, clientX)) / 2,
|
440
|
+
clientY: (min.apply(Math, clientY) + max.apply(Math, clientY)) / 2
|
441
|
+
};
|
442
|
+
},
|
443
|
+
|
444
|
+
/**
|
445
|
+
* calculate the velocity between two points. unit is in px per ms.
|
446
|
+
* @method getVelocity
|
447
|
+
* @param {Number} deltaTime
|
448
|
+
* @param {Number} deltaX
|
449
|
+
* @param {Number} deltaY
|
450
|
+
* @return {Object} velocity `x` and `y`
|
451
|
+
*/
|
452
|
+
getVelocity: function getVelocity(deltaTime, deltaX, deltaY) {
|
453
|
+
return {
|
454
|
+
x: Math.abs(deltaX / deltaTime) || 0,
|
455
|
+
y: Math.abs(deltaY / deltaTime) || 0
|
456
|
+
};
|
457
|
+
},
|
458
|
+
|
459
|
+
/**
|
460
|
+
* calculate the angle between two coordinates
|
461
|
+
* @method getAngle
|
462
|
+
* @param {Touch} touch1
|
463
|
+
* @param {Touch} touch2
|
464
|
+
* @return {Number} angle
|
465
|
+
*/
|
466
|
+
getAngle: function getAngle(touch1, touch2) {
|
467
|
+
var x = touch2.clientX - touch1.clientX,
|
468
|
+
y = touch2.clientY - touch1.clientY;
|
469
|
+
|
470
|
+
return Math.atan2(y, x) * 180 / Math.PI;
|
471
|
+
},
|
472
|
+
|
473
|
+
/**
|
474
|
+
* do a small comparision to get the direction between two touches.
|
475
|
+
* @method getDirection
|
476
|
+
* @param {Touch} touch1
|
477
|
+
* @param {Touch} touch2
|
478
|
+
* @return {String} direction matches `DIRECTION_LEFT|RIGHT|UP|DOWN`
|
479
|
+
*/
|
480
|
+
getDirection: function getDirection(touch1, touch2) {
|
481
|
+
var x = Math.abs(touch1.clientX - touch2.clientX),
|
482
|
+
y = Math.abs(touch1.clientY - touch2.clientY);
|
483
|
+
|
484
|
+
if(x >= y) {
|
485
|
+
return touch1.clientX - touch2.clientX > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
|
486
|
+
}
|
487
|
+
return touch1.clientY - touch2.clientY > 0 ? DIRECTION_UP : DIRECTION_DOWN;
|
488
|
+
},
|
489
|
+
|
490
|
+
/**
|
491
|
+
* calculate the distance between two touches
|
492
|
+
* @method getDistance
|
493
|
+
* @param {Touch}touch1
|
494
|
+
* @param {Touch} touch2
|
495
|
+
* @return {Number} distance
|
496
|
+
*/
|
497
|
+
getDistance: function getDistance(touch1, touch2) {
|
498
|
+
var x = touch2.clientX - touch1.clientX,
|
499
|
+
y = touch2.clientY - touch1.clientY;
|
500
|
+
|
501
|
+
return Math.sqrt((x * x) + (y * y));
|
502
|
+
},
|
503
|
+
|
504
|
+
/**
|
505
|
+
* calculate the scale factor between two touchLists
|
506
|
+
* no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
|
507
|
+
* @method getScale
|
508
|
+
* @param {Array} start array of touches
|
509
|
+
* @param {Array} end array of touches
|
510
|
+
* @return {Number} scale
|
511
|
+
*/
|
512
|
+
getScale: function getScale(start, end) {
|
513
|
+
// need two fingers...
|
514
|
+
if(start.length >= 2 && end.length >= 2) {
|
515
|
+
return this.getDistance(end[0], end[1]) / this.getDistance(start[0], start[1]);
|
516
|
+
}
|
517
|
+
return 1;
|
518
|
+
},
|
519
|
+
|
520
|
+
/**
|
521
|
+
* calculate the rotation degrees between two touchLists
|
522
|
+
* @method getRotation
|
523
|
+
* @param {Array} start array of touches
|
524
|
+
* @param {Array} end array of touches
|
525
|
+
* @return {Number} rotation
|
526
|
+
*/
|
527
|
+
getRotation: function getRotation(start, end) {
|
528
|
+
// need two fingers
|
529
|
+
if(start.length >= 2 && end.length >= 2) {
|
530
|
+
return this.getAngle(end[1], end[0]) - this.getAngle(start[1], start[0]);
|
531
|
+
}
|
532
|
+
return 0;
|
533
|
+
},
|
534
|
+
|
535
|
+
/**
|
536
|
+
* find out if the direction is vertical *
|
537
|
+
* @method isVertical
|
538
|
+
* @param {String} direction matches `DIRECTION_UP|DOWN`
|
539
|
+
* @return {Boolean} is_vertical
|
540
|
+
*/
|
541
|
+
isVertical: function isVertical(direction) {
|
542
|
+
return direction == DIRECTION_UP || direction == DIRECTION_DOWN;
|
543
|
+
},
|
544
|
+
|
545
|
+
/**
|
546
|
+
* set css properties with their prefixes
|
547
|
+
* @param {HTMLElement} element
|
548
|
+
* @param {String} prop
|
549
|
+
* @param {String} value
|
550
|
+
* @param {Boolean} [toggle=true]
|
551
|
+
* @return {Boolean}
|
552
|
+
*/
|
553
|
+
setPrefixedCss: function setPrefixedCss(element, prop, value, toggle) {
|
554
|
+
var prefixes = ['', 'Webkit', 'Moz', 'O', 'ms'];
|
555
|
+
prop = Utils.toCamelCase(prop);
|
556
|
+
|
557
|
+
for(var i = 0; i < prefixes.length; i++) {
|
558
|
+
var p = prop;
|
559
|
+
// prefixes
|
560
|
+
if(prefixes[i]) {
|
561
|
+
p = prefixes[i] + p.slice(0, 1).toUpperCase() + p.slice(1);
|
562
|
+
}
|
563
|
+
|
564
|
+
// test the style
|
565
|
+
if(p in element.style) {
|
566
|
+
element.style[p] = (toggle == null || toggle) && value || '';
|
567
|
+
break;
|
568
|
+
}
|
569
|
+
}
|
570
|
+
},
|
571
|
+
|
572
|
+
/**
|
573
|
+
* toggle browser default behavior by setting css properties.
|
574
|
+
* `userSelect='none'` also sets `element.onselectstart` to false
|
575
|
+
* `userDrag='none'` also sets `element.ondragstart` to false
|
576
|
+
*
|
577
|
+
* @method toggleBehavior
|
578
|
+
* @param {HtmlElement} element
|
579
|
+
* @param {Object} props
|
580
|
+
* @param {Boolean} [toggle=true]
|
581
|
+
*/
|
582
|
+
toggleBehavior: function toggleBehavior(element, props, toggle) {
|
583
|
+
if(!props || !element || !element.style) {
|
584
|
+
return;
|
585
|
+
}
|
586
|
+
|
587
|
+
// set the css properties
|
588
|
+
Utils.each(props, function(value, prop) {
|
589
|
+
Utils.setPrefixedCss(element, prop, value, toggle);
|
590
|
+
});
|
591
|
+
|
592
|
+
var falseFn = toggle && function() {
|
593
|
+
return false;
|
594
|
+
};
|
595
|
+
|
596
|
+
// also the disable onselectstart
|
597
|
+
if(props.userSelect == 'none') {
|
598
|
+
element.onselectstart = falseFn;
|
599
|
+
}
|
600
|
+
// and disable ondragstart
|
601
|
+
if(props.userDrag == 'none') {
|
602
|
+
element.ondragstart = falseFn;
|
603
|
+
}
|
604
|
+
},
|
605
|
+
|
606
|
+
/**
|
607
|
+
* convert a string with underscores to camelCase
|
608
|
+
* so prevent_default becomes preventDefault
|
609
|
+
* @param {String} str
|
610
|
+
* @return {String} camelCaseStr
|
611
|
+
*/
|
612
|
+
toCamelCase: function toCamelCase(str) {
|
613
|
+
return str.replace(/[_-]([a-z])/g, function(s) {
|
614
|
+
return s[1].toUpperCase();
|
615
|
+
});
|
616
|
+
}
|
617
|
+
};
|
618
|
+
|
619
|
+
|
620
|
+
/**
|
621
|
+
* @module hammer
|
622
|
+
*/
|
623
|
+
/**
|
624
|
+
* @class Event
|
625
|
+
* @static
|
626
|
+
*/
|
627
|
+
var Event = Hammer.event = {
|
628
|
+
/**
|
629
|
+
* when touch events have been fired, this is true
|
630
|
+
* this is used to stop mouse events
|
631
|
+
* @property prevent_mouseevents
|
632
|
+
* @private
|
633
|
+
* @type {Boolean}
|
634
|
+
*/
|
635
|
+
preventMouseEvents: false,
|
636
|
+
|
637
|
+
/**
|
638
|
+
* if EVENT_START has been fired
|
639
|
+
* @property started
|
640
|
+
* @private
|
641
|
+
* @type {Boolean}
|
642
|
+
*/
|
643
|
+
started: false,
|
644
|
+
|
645
|
+
/**
|
646
|
+
* when the mouse is hold down, this is true
|
647
|
+
* @property should_detect
|
648
|
+
* @private
|
649
|
+
* @type {Boolean}
|
650
|
+
*/
|
651
|
+
shouldDetect: false,
|
652
|
+
|
653
|
+
/**
|
654
|
+
* simple event binder with a hook and support for multiple types
|
655
|
+
* @method on
|
656
|
+
* @param {HTMLElement} element
|
657
|
+
* @param {String} type
|
658
|
+
* @param {Function} handler
|
659
|
+
* @param {Function} [hook]
|
660
|
+
* @param {Object} hook.type
|
661
|
+
*/
|
662
|
+
on: function on(element, type, handler, hook) {
|
663
|
+
var types = type.split(' ');
|
664
|
+
Utils.each(types, function(type) {
|
665
|
+
Utils.on(element, type, handler);
|
666
|
+
hook && hook(type);
|
667
|
+
});
|
668
|
+
},
|
669
|
+
|
670
|
+
/**
|
671
|
+
* simple event unbinder with a hook and support for multiple types
|
672
|
+
* @method off
|
673
|
+
* @param {HTMLElement} element
|
674
|
+
* @param {String} type
|
675
|
+
* @param {Function} handler
|
676
|
+
* @param {Function} [hook]
|
677
|
+
* @param {Object} hook.type
|
678
|
+
*/
|
679
|
+
off: function off(element, type, handler, hook) {
|
680
|
+
var types = type.split(' ');
|
681
|
+
Utils.each(types, function(type) {
|
682
|
+
Utils.off(element, type, handler);
|
683
|
+
hook && hook(type);
|
684
|
+
});
|
685
|
+
},
|
686
|
+
|
687
|
+
/**
|
688
|
+
* the core touch event handler.
|
689
|
+
* this finds out if we should to detect gestures
|
690
|
+
* @method onTouch
|
691
|
+
* @param {HTMLElement} element
|
692
|
+
* @param {String} eventType matches `EVENT_START|MOVE|END`
|
693
|
+
* @param {Function} handler
|
694
|
+
* @return onTouchHandler {Function} the core event handler
|
695
|
+
*/
|
696
|
+
onTouch: function onTouch(element, eventType, handler) {
|
697
|
+
var self = this;
|
698
|
+
|
699
|
+
var onTouchHandler = function onTouchHandler(ev) {
|
700
|
+
var srcType = ev.type.toLowerCase(),
|
701
|
+
isPointer = Hammer.HAS_POINTEREVENTS,
|
702
|
+
isMouse = Utils.inStr(srcType, 'mouse'),
|
703
|
+
triggerType;
|
704
|
+
|
705
|
+
// if we are in a mouseevent, but there has been a touchevent triggered in this session
|
706
|
+
// we want to do nothing. simply break out of the event.
|
707
|
+
if(isMouse && self.preventMouseEvents) {
|
708
|
+
return;
|
709
|
+
|
710
|
+
// mousebutton must be down
|
711
|
+
} else if(isMouse && eventType == EVENT_START && ev.button === 0) {
|
712
|
+
self.preventMouseEvents = false;
|
713
|
+
self.shouldDetect = true;
|
714
|
+
} else if(isPointer && eventType == EVENT_START) {
|
715
|
+
self.shouldDetect = (ev.buttons === 1 || PointerEvent.matchType(POINTER_TOUCH, ev));
|
716
|
+
// just a valid start event, but no mouse
|
717
|
+
} else if(!isMouse && eventType == EVENT_START) {
|
718
|
+
self.preventMouseEvents = true;
|
719
|
+
self.shouldDetect = true;
|
720
|
+
}
|
721
|
+
|
722
|
+
// update the pointer event before entering the detection
|
723
|
+
if(isPointer && eventType != EVENT_END) {
|
724
|
+
PointerEvent.updatePointer(eventType, ev);
|
725
|
+
}
|
726
|
+
|
727
|
+
// we are in a touch/down state, so allowed detection of gestures
|
728
|
+
if(self.shouldDetect) {
|
729
|
+
triggerType = self.doDetect.call(self, ev, eventType, element, handler);
|
730
|
+
}
|
731
|
+
|
732
|
+
// ...and we are done with the detection
|
733
|
+
// so reset everything to start each detection totally fresh
|
734
|
+
if(triggerType == EVENT_END) {
|
735
|
+
self.preventMouseEvents = false;
|
736
|
+
self.shouldDetect = false;
|
737
|
+
PointerEvent.reset();
|
738
|
+
// update the pointerevent object after the detection
|
739
|
+
}
|
740
|
+
|
741
|
+
if(isPointer && eventType == EVENT_END) {
|
742
|
+
PointerEvent.updatePointer(eventType, ev);
|
743
|
+
}
|
744
|
+
};
|
745
|
+
|
746
|
+
this.on(element, EVENT_TYPES[eventType], onTouchHandler);
|
747
|
+
return onTouchHandler;
|
748
|
+
},
|
749
|
+
|
750
|
+
/**
|
751
|
+
* the core detection method
|
752
|
+
* this finds out what hammer-touch-events to trigger
|
753
|
+
* @method doDetect
|
754
|
+
* @param {Object} ev
|
755
|
+
* @param {String} eventType matches `EVENT_START|MOVE|END`
|
756
|
+
* @param {HTMLElement} element
|
757
|
+
* @param {Function} handler
|
758
|
+
* @return {String} triggerType matches `EVENT_START|MOVE|END`
|
759
|
+
*/
|
760
|
+
doDetect: function doDetect(ev, eventType, element, handler) {
|
761
|
+
var touchList = this.getTouchList(ev, eventType);
|
762
|
+
var touchListLength = touchList.length;
|
763
|
+
var triggerType = eventType;
|
764
|
+
var triggerChange = touchList.trigger; // used by fakeMultitouch plugin
|
765
|
+
var changedLength = touchListLength;
|
766
|
+
|
767
|
+
// at each touchstart-like event we want also want to trigger a TOUCH event...
|
768
|
+
if(eventType == EVENT_START) {
|
769
|
+
triggerChange = EVENT_TOUCH;
|
770
|
+
// ...the same for a touchend-like event
|
771
|
+
} else if(eventType == EVENT_END) {
|
772
|
+
triggerChange = EVENT_RELEASE;
|
773
|
+
|
774
|
+
// keep track of how many touches have been removed
|
775
|
+
changedLength = touchList.length - ((ev.changedTouches) ? ev.changedTouches.length : 1);
|
776
|
+
}
|
777
|
+
|
778
|
+
// after there are still touches on the screen,
|
779
|
+
// we just want to trigger a MOVE event. so change the START or END to a MOVE
|
780
|
+
// but only after detection has been started, the first time we actualy want a START
|
781
|
+
if(changedLength > 0 && this.started) {
|
782
|
+
triggerType = EVENT_MOVE;
|
783
|
+
}
|
784
|
+
|
785
|
+
// detection has been started, we keep track of this, see above
|
786
|
+
this.started = true;
|
787
|
+
|
788
|
+
// generate some event data, some basic information
|
789
|
+
var evData = this.collectEventData(element, triggerType, touchList, ev);
|
790
|
+
|
791
|
+
// trigger the triggerType event before the change (TOUCH, RELEASE) events
|
792
|
+
// but the END event should be at last
|
793
|
+
if(eventType != EVENT_END) {
|
794
|
+
handler.call(Detection, evData);
|
795
|
+
}
|
796
|
+
|
797
|
+
// trigger a change (TOUCH, RELEASE) event, this means the length of the touches changed
|
798
|
+
if(triggerChange) {
|
799
|
+
evData.changedLength = changedLength;
|
800
|
+
evData.eventType = triggerChange;
|
801
|
+
|
802
|
+
handler.call(Detection, evData);
|
803
|
+
|
804
|
+
evData.eventType = triggerType;
|
805
|
+
delete evData.changedLength;
|
806
|
+
}
|
807
|
+
|
808
|
+
// trigger the END event
|
809
|
+
if(triggerType == EVENT_END) {
|
810
|
+
handler.call(Detection, evData);
|
811
|
+
|
812
|
+
// ...and we are done with the detection
|
813
|
+
// so reset everything to start each detection totally fresh
|
814
|
+
this.started = false;
|
815
|
+
}
|
816
|
+
|
817
|
+
return triggerType;
|
818
|
+
},
|
819
|
+
|
820
|
+
/**
|
821
|
+
* we have different events for each device/browser
|
822
|
+
* determine what we need and set them in the EVENT_TYPES constant
|
823
|
+
* the `onTouch` method is bind to these properties.
|
824
|
+
* @method determineEventTypes
|
825
|
+
* @return {Object} events
|
826
|
+
*/
|
827
|
+
determineEventTypes: function determineEventTypes() {
|
828
|
+
var types;
|
829
|
+
if(Hammer.HAS_POINTEREVENTS) {
|
830
|
+
if(window.PointerEvent) {
|
831
|
+
types = [
|
832
|
+
'pointerdown',
|
833
|
+
'pointermove',
|
834
|
+
'pointerup pointercancel lostpointercapture'
|
835
|
+
];
|
836
|
+
} else {
|
837
|
+
types = [
|
838
|
+
'MSPointerDown',
|
839
|
+
'MSPointerMove',
|
840
|
+
'MSPointerUp MSPointerCancel MSLostPointerCapture'
|
841
|
+
];
|
842
|
+
}
|
843
|
+
} else if(Hammer.NO_MOUSEEVENTS) {
|
844
|
+
types = [
|
845
|
+
'touchstart',
|
846
|
+
'touchmove',
|
847
|
+
'touchend touchcancel'
|
848
|
+
];
|
849
|
+
} else {
|
850
|
+
types = [
|
851
|
+
'touchstart mousedown',
|
852
|
+
'touchmove mousemove',
|
853
|
+
'touchend touchcancel mouseup'
|
854
|
+
];
|
855
|
+
}
|
856
|
+
|
857
|
+
EVENT_TYPES[EVENT_START] = types[0];
|
858
|
+
EVENT_TYPES[EVENT_MOVE] = types[1];
|
859
|
+
EVENT_TYPES[EVENT_END] = types[2];
|
860
|
+
return EVENT_TYPES;
|
861
|
+
},
|
862
|
+
|
863
|
+
/**
|
864
|
+
* create touchList depending on the event
|
865
|
+
* @method getTouchList
|
866
|
+
* @param {Object} ev
|
867
|
+
* @param {String} eventType
|
868
|
+
* @return {Array} touches
|
869
|
+
*/
|
870
|
+
getTouchList: function getTouchList(ev, eventType) {
|
871
|
+
// get the fake pointerEvent touchlist
|
872
|
+
if(Hammer.HAS_POINTEREVENTS) {
|
873
|
+
return PointerEvent.getTouchList();
|
874
|
+
}
|
875
|
+
|
876
|
+
// get the touchlist
|
877
|
+
if(ev.touches) {
|
878
|
+
if(eventType == EVENT_MOVE) {
|
879
|
+
return ev.touches;
|
880
|
+
}
|
881
|
+
|
882
|
+
var identifiers = [];
|
883
|
+
var concat = [].concat(Utils.toArray(ev.touches), Utils.toArray(ev.changedTouches));
|
884
|
+
var touchList = [];
|
885
|
+
|
886
|
+
Utils.each(concat, function(touch) {
|
887
|
+
if(Utils.inArray(identifiers, touch.identifier) === false) {
|
888
|
+
touchList.push(touch);
|
889
|
+
}
|
890
|
+
identifiers.push(touch.identifier);
|
891
|
+
});
|
892
|
+
|
893
|
+
return touchList;
|
894
|
+
}
|
895
|
+
|
896
|
+
// make fake touchList from mouse position
|
897
|
+
ev.identifier = 1;
|
898
|
+
return [ev];
|
899
|
+
},
|
900
|
+
|
901
|
+
/**
|
902
|
+
* collect basic event data
|
903
|
+
* @method collectEventData
|
904
|
+
* @param {HTMLElement} element
|
905
|
+
* @param {String} eventType matches `EVENT_START|MOVE|END`
|
906
|
+
* @param {Array} touches
|
907
|
+
* @param {Object} ev
|
908
|
+
* @return {Object} ev
|
909
|
+
*/
|
910
|
+
collectEventData: function collectEventData(element, eventType, touches, ev) {
|
911
|
+
// find out pointerType
|
912
|
+
var pointerType = POINTER_TOUCH;
|
913
|
+
if(Utils.inStr(ev.type, 'mouse') || PointerEvent.matchType(POINTER_MOUSE, ev)) {
|
914
|
+
pointerType = POINTER_MOUSE;
|
915
|
+
} else if(PointerEvent.matchType(POINTER_PEN, ev)) {
|
916
|
+
pointerType = POINTER_PEN;
|
917
|
+
}
|
918
|
+
|
919
|
+
return {
|
920
|
+
center: Utils.getCenter(touches),
|
921
|
+
timeStamp: Date.now(),
|
922
|
+
target: ev.target,
|
923
|
+
touches: touches,
|
924
|
+
eventType: eventType,
|
925
|
+
pointerType: pointerType,
|
926
|
+
srcEvent: ev,
|
927
|
+
|
928
|
+
/**
|
929
|
+
* prevent the browser default actions
|
930
|
+
* mostly used to disable scrolling of the browser
|
931
|
+
*/
|
932
|
+
preventDefault: function() {
|
933
|
+
var srcEvent = this.srcEvent;
|
934
|
+
srcEvent.preventManipulation && srcEvent.preventManipulation();
|
935
|
+
srcEvent.preventDefault && srcEvent.preventDefault();
|
936
|
+
},
|
937
|
+
|
938
|
+
/**
|
939
|
+
* stop bubbling the event up to its parents
|
940
|
+
*/
|
941
|
+
stopPropagation: function() {
|
942
|
+
this.srcEvent.stopPropagation();
|
943
|
+
},
|
944
|
+
|
945
|
+
/**
|
946
|
+
* immediately stop gesture detection
|
947
|
+
* might be useful after a swipe was detected
|
948
|
+
* @return {*}
|
949
|
+
*/
|
950
|
+
stopDetect: function() {
|
951
|
+
return Detection.stopDetect();
|
952
|
+
}
|
953
|
+
};
|
954
|
+
}
|
955
|
+
};
|
956
|
+
|
957
|
+
|
958
|
+
/**
|
959
|
+
* @module hammer
|
960
|
+
*
|
961
|
+
* @class PointerEvent
|
962
|
+
* @static
|
963
|
+
*/
|
964
|
+
var PointerEvent = Hammer.PointerEvent = {
|
965
|
+
/**
|
966
|
+
* holds all pointers, by `identifier`
|
967
|
+
* @property pointers
|
968
|
+
* @type {Object}
|
969
|
+
*/
|
970
|
+
pointers: {},
|
971
|
+
|
972
|
+
/**
|
973
|
+
* get the pointers as an array
|
974
|
+
* @method getTouchList
|
975
|
+
* @return {Array} touchlist
|
976
|
+
*/
|
977
|
+
getTouchList: function getTouchList() {
|
978
|
+
var touchlist = [];
|
979
|
+
// we can use forEach since pointerEvents only is in IE10
|
980
|
+
Utils.each(this.pointers, function(pointer) {
|
981
|
+
touchlist.push(pointer);
|
982
|
+
});
|
983
|
+
|
984
|
+
return touchlist;
|
985
|
+
},
|
986
|
+
|
987
|
+
/**
|
988
|
+
* update the position of a pointer
|
989
|
+
* @method updatePointer
|
990
|
+
* @param {String} eventType matches `EVENT_START|MOVE|END`
|
991
|
+
* @param {Object} pointerEvent
|
992
|
+
*/
|
993
|
+
updatePointer: function updatePointer(eventType, pointerEvent) {
|
994
|
+
if(eventType == EVENT_END) {
|
995
|
+
delete this.pointers[pointerEvent.pointerId];
|
996
|
+
} else {
|
997
|
+
pointerEvent.identifier = pointerEvent.pointerId;
|
998
|
+
this.pointers[pointerEvent.pointerId] = pointerEvent;
|
999
|
+
}
|
1000
|
+
},
|
1001
|
+
|
1002
|
+
/**
|
1003
|
+
* check if ev matches pointertype
|
1004
|
+
* @method matchType
|
1005
|
+
* @param {String} pointerType matches `POINTER_MOUSE|TOUCH|PEN`
|
1006
|
+
* @param {PointerEvent} ev
|
1007
|
+
*/
|
1008
|
+
matchType: function matchType(pointerType, ev) {
|
1009
|
+
if(!ev.pointerType) {
|
1010
|
+
return false;
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
var pt = ev.pointerType,
|
1014
|
+
types = {};
|
1015
|
+
|
1016
|
+
types[POINTER_MOUSE] = (pt === (ev.MSPOINTER_TYPE_MOUSE || POINTER_MOUSE));
|
1017
|
+
types[POINTER_TOUCH] = (pt === (ev.MSPOINTER_TYPE_TOUCH || POINTER_TOUCH));
|
1018
|
+
types[POINTER_PEN] = (pt === (ev.MSPOINTER_TYPE_PEN || POINTER_PEN));
|
1019
|
+
return types[pointerType];
|
1020
|
+
},
|
1021
|
+
|
1022
|
+
/**
|
1023
|
+
* reset the stored pointers
|
1024
|
+
* @method reset
|
1025
|
+
*/
|
1026
|
+
reset: function resetList() {
|
1027
|
+
this.pointers = {};
|
1028
|
+
}
|
1029
|
+
};
|
1030
|
+
|
1031
|
+
|
1032
|
+
/**
|
1033
|
+
* @module hammer
|
1034
|
+
*
|
1035
|
+
* @class Detection
|
1036
|
+
* @static
|
1037
|
+
*/
|
1038
|
+
var Detection = Hammer.detection = {
|
1039
|
+
// contains all registred Hammer.gestures in the correct order
|
1040
|
+
gestures: [],
|
1041
|
+
|
1042
|
+
// data of the current Hammer.gesture detection session
|
1043
|
+
current: null,
|
1044
|
+
|
1045
|
+
// the previous Hammer.gesture session data
|
1046
|
+
// is a full clone of the previous gesture.current object
|
1047
|
+
previous: null,
|
1048
|
+
|
1049
|
+
// when this becomes true, no gestures are fired
|
1050
|
+
stopped: false,
|
1051
|
+
|
1052
|
+
/**
|
1053
|
+
* start Hammer.gesture detection
|
1054
|
+
* @method startDetect
|
1055
|
+
* @param {Hammer.Instance} inst
|
1056
|
+
* @param {Object} eventData
|
1057
|
+
*/
|
1058
|
+
startDetect: function startDetect(inst, eventData) {
|
1059
|
+
// already busy with a Hammer.gesture detection on an element
|
1060
|
+
if(this.current) {
|
1061
|
+
return;
|
1062
|
+
}
|
1063
|
+
|
1064
|
+
this.stopped = false;
|
1065
|
+
|
1066
|
+
// holds current session
|
1067
|
+
this.current = {
|
1068
|
+
inst: inst, // reference to HammerInstance we're working for
|
1069
|
+
startEvent: Utils.extend({}, eventData), // start eventData for distances, timing etc
|
1070
|
+
lastEvent: false, // last eventData
|
1071
|
+
lastCalcEvent: false, // last eventData for calculations.
|
1072
|
+
futureCalcEvent: false, // last eventData for calculations.
|
1073
|
+
lastCalcData: {}, // last lastCalcData
|
1074
|
+
name: '' // current gesture we're in/detected, can be 'tap', 'hold' etc
|
1075
|
+
};
|
1076
|
+
|
1077
|
+
this.detect(eventData);
|
1078
|
+
},
|
1079
|
+
|
1080
|
+
/**
|
1081
|
+
* Hammer.gesture detection
|
1082
|
+
* @method detect
|
1083
|
+
* @param {Object} eventData
|
1084
|
+
* @return {any}
|
1085
|
+
*/
|
1086
|
+
detect: function detect(eventData) {
|
1087
|
+
if(!this.current || this.stopped) {
|
1088
|
+
return;
|
1089
|
+
}
|
1090
|
+
|
1091
|
+
// extend event data with calculations about scale, distance etc
|
1092
|
+
eventData = this.extendEventData(eventData);
|
1093
|
+
|
1094
|
+
// hammer instance and instance options
|
1095
|
+
var inst = this.current.inst,
|
1096
|
+
instOptions = inst.options;
|
1097
|
+
|
1098
|
+
// call Hammer.gesture handlers
|
1099
|
+
Utils.each(this.gestures, function triggerGesture(gesture) {
|
1100
|
+
// only when the instance options have enabled this gesture
|
1101
|
+
if(!this.stopped && inst.enabled && instOptions[gesture.name]) {
|
1102
|
+
gesture.handler.call(gesture, eventData, inst);
|
1103
|
+
}
|
1104
|
+
}, this);
|
1105
|
+
|
1106
|
+
// store as previous event event
|
1107
|
+
if(this.current) {
|
1108
|
+
this.current.lastEvent = eventData;
|
1109
|
+
}
|
1110
|
+
|
1111
|
+
if(eventData.eventType == EVENT_END) {
|
1112
|
+
this.stopDetect();
|
1113
|
+
}
|
1114
|
+
|
1115
|
+
return eventData;
|
1116
|
+
},
|
1117
|
+
|
1118
|
+
/**
|
1119
|
+
* clear the Hammer.gesture vars
|
1120
|
+
* this is called on endDetect, but can also be used when a final Hammer.gesture has been detected
|
1121
|
+
* to stop other Hammer.gestures from being fired
|
1122
|
+
* @method stopDetect
|
1123
|
+
*/
|
1124
|
+
stopDetect: function stopDetect() {
|
1125
|
+
// clone current data to the store as the previous gesture
|
1126
|
+
// used for the double tap gesture, since this is an other gesture detect session
|
1127
|
+
this.previous = Utils.extend({}, this.current);
|
1128
|
+
|
1129
|
+
// reset the current
|
1130
|
+
this.current = null;
|
1131
|
+
this.stopped = true;
|
1132
|
+
},
|
1133
|
+
|
1134
|
+
/**
|
1135
|
+
* calculate velocity, angle and direction
|
1136
|
+
* @method getVelocityData
|
1137
|
+
* @param {Object} ev
|
1138
|
+
* @param {Object} center
|
1139
|
+
* @param {Number} deltaTime
|
1140
|
+
* @param {Number} deltaX
|
1141
|
+
* @param {Number} deltaY
|
1142
|
+
*/
|
1143
|
+
getCalculatedData: function getCalculatedData(ev, center, deltaTime, deltaX, deltaY) {
|
1144
|
+
var cur = this.current,
|
1145
|
+
recalc = false,
|
1146
|
+
calcEv = cur.lastCalcEvent,
|
1147
|
+
calcData = cur.lastCalcData;
|
1148
|
+
|
1149
|
+
if(calcEv && ev.timeStamp - calcEv.timeStamp > Hammer.CALCULATE_INTERVAL) {
|
1150
|
+
center = calcEv.center;
|
1151
|
+
deltaTime = ev.timeStamp - calcEv.timeStamp;
|
1152
|
+
deltaX = ev.center.clientX - calcEv.center.clientX;
|
1153
|
+
deltaY = ev.center.clientY - calcEv.center.clientY;
|
1154
|
+
recalc = true;
|
1155
|
+
}
|
1156
|
+
|
1157
|
+
if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) {
|
1158
|
+
cur.futureCalcEvent = ev;
|
1159
|
+
}
|
1160
|
+
|
1161
|
+
if(!cur.lastCalcEvent || recalc) {
|
1162
|
+
calcData.velocity = Utils.getVelocity(deltaTime, deltaX, deltaY);
|
1163
|
+
calcData.angle = Utils.getAngle(center, ev.center);
|
1164
|
+
calcData.direction = Utils.getDirection(center, ev.center);
|
1165
|
+
|
1166
|
+
cur.lastCalcEvent = cur.futureCalcEvent || ev;
|
1167
|
+
cur.futureCalcEvent = ev;
|
1168
|
+
}
|
1169
|
+
|
1170
|
+
ev.velocityX = calcData.velocity.x;
|
1171
|
+
ev.velocityY = calcData.velocity.y;
|
1172
|
+
ev.interimAngle = calcData.angle;
|
1173
|
+
ev.interimDirection = calcData.direction;
|
1174
|
+
},
|
1175
|
+
|
1176
|
+
/**
|
1177
|
+
* extend eventData for Hammer.gestures
|
1178
|
+
* @method extendEventData
|
1179
|
+
* @param {Object} ev
|
1180
|
+
* @return {Object} ev
|
1181
|
+
*/
|
1182
|
+
extendEventData: function extendEventData(ev) {
|
1183
|
+
var cur = this.current,
|
1184
|
+
startEv = cur.startEvent,
|
1185
|
+
lastEv = cur.lastEvent || startEv;
|
1186
|
+
|
1187
|
+
// update the start touchlist to calculate the scale/rotation
|
1188
|
+
if(ev.eventType == EVENT_TOUCH || ev.eventType == EVENT_RELEASE) {
|
1189
|
+
startEv.touches = [];
|
1190
|
+
Utils.each(ev.touches, function(touch) {
|
1191
|
+
startEv.touches.push({
|
1192
|
+
clientX: touch.clientX,
|
1193
|
+
clientY: touch.clientY
|
1194
|
+
});
|
1195
|
+
});
|
1196
|
+
}
|
1197
|
+
|
1198
|
+
var deltaTime = ev.timeStamp - startEv.timeStamp,
|
1199
|
+
deltaX = ev.center.clientX - startEv.center.clientX,
|
1200
|
+
deltaY = ev.center.clientY - startEv.center.clientY;
|
1201
|
+
|
1202
|
+
this.getCalculatedData(ev, lastEv.center, deltaTime, deltaX, deltaY);
|
1203
|
+
|
1204
|
+
Utils.extend(ev, {
|
1205
|
+
startEvent: startEv,
|
1206
|
+
|
1207
|
+
deltaTime: deltaTime,
|
1208
|
+
deltaX: deltaX,
|
1209
|
+
deltaY: deltaY,
|
1210
|
+
|
1211
|
+
distance: Utils.getDistance(startEv.center, ev.center),
|
1212
|
+
angle: Utils.getAngle(startEv.center, ev.center),
|
1213
|
+
direction: Utils.getDirection(startEv.center, ev.center),
|
1214
|
+
scale: Utils.getScale(startEv.touches, ev.touches),
|
1215
|
+
rotation: Utils.getRotation(startEv.touches, ev.touches)
|
1216
|
+
});
|
1217
|
+
|
1218
|
+
return ev;
|
1219
|
+
},
|
1220
|
+
|
1221
|
+
/**
|
1222
|
+
* register new gesture
|
1223
|
+
* @method register
|
1224
|
+
* @param {Object} gesture object, see `gestures/` for documentation
|
1225
|
+
* @return {Array} gestures
|
1226
|
+
*/
|
1227
|
+
register: function register(gesture) {
|
1228
|
+
// add an enable gesture options if there is no given
|
1229
|
+
var options = gesture.defaults || {};
|
1230
|
+
if(options[gesture.name] === undefined) {
|
1231
|
+
options[gesture.name] = true;
|
1232
|
+
}
|
1233
|
+
|
1234
|
+
// extend Hammer default options with the Hammer.gesture options
|
1235
|
+
Utils.extend(Hammer.defaults, options, true);
|
1236
|
+
|
1237
|
+
// set its index
|
1238
|
+
gesture.index = gesture.index || 1000;
|
1239
|
+
|
1240
|
+
// add Hammer.gesture to the list
|
1241
|
+
this.gestures.push(gesture);
|
1242
|
+
|
1243
|
+
// sort the list by index
|
1244
|
+
this.gestures.sort(function(a, b) {
|
1245
|
+
if(a.index < b.index) {
|
1246
|
+
return -1;
|
1247
|
+
}
|
1248
|
+
if(a.index > b.index) {
|
1249
|
+
return 1;
|
1250
|
+
}
|
1251
|
+
return 0;
|
1252
|
+
});
|
1253
|
+
|
1254
|
+
return this.gestures;
|
1255
|
+
}
|
1256
|
+
};
|
1257
|
+
|
1258
|
+
|
1259
|
+
/**
|
1260
|
+
* @module hammer
|
1261
|
+
*/
|
1262
|
+
|
1263
|
+
/**
|
1264
|
+
* create new hammer instance
|
1265
|
+
* all methods should return the instance itself, so it is chainable.
|
1266
|
+
*
|
1267
|
+
* @class Instance
|
1268
|
+
* @constructor
|
1269
|
+
* @param {HTMLElement} element
|
1270
|
+
* @param {Object} [options={}] options are merged with `Hammer.defaults`
|
1271
|
+
* @return {Hammer.Instance}
|
1272
|
+
*/
|
1273
|
+
Hammer.Instance = function(element, options) {
|
1274
|
+
var self = this;
|
1275
|
+
|
1276
|
+
// setup HammerJS window events and register all gestures
|
1277
|
+
// this also sets up the default options
|
1278
|
+
setup();
|
1279
|
+
|
1280
|
+
/**
|
1281
|
+
* @property element
|
1282
|
+
* @type {HTMLElement}
|
1283
|
+
*/
|
1284
|
+
this.element = element;
|
1285
|
+
|
1286
|
+
/**
|
1287
|
+
* @property enabled
|
1288
|
+
* @type {Boolean}
|
1289
|
+
* @protected
|
1290
|
+
*/
|
1291
|
+
this.enabled = true;
|
1292
|
+
|
1293
|
+
/**
|
1294
|
+
* options, merged with the defaults
|
1295
|
+
* options with an _ are converted to camelCase
|
1296
|
+
* @property options
|
1297
|
+
* @type {Object}
|
1298
|
+
*/
|
1299
|
+
Utils.each(options, function(value, name) {
|
1300
|
+
delete options[name];
|
1301
|
+
options[Utils.toCamelCase(name)] = value;
|
1302
|
+
});
|
1303
|
+
|
1304
|
+
this.options = Utils.extend(Utils.extend({}, Hammer.defaults), options || {});
|
1305
|
+
|
1306
|
+
// add some css to the element to prevent the browser from doing its native behavoir
|
1307
|
+
if(this.options.behavior) {
|
1308
|
+
Utils.toggleBehavior(this.element, this.options.behavior, true);
|
1309
|
+
}
|
1310
|
+
|
1311
|
+
/**
|
1312
|
+
* event start handler on the element to start the detection
|
1313
|
+
* @property eventStartHandler
|
1314
|
+
* @type {Object}
|
1315
|
+
*/
|
1316
|
+
this.eventStartHandler = Event.onTouch(element, EVENT_START, function(ev) {
|
1317
|
+
if(self.enabled && ev.eventType == EVENT_START) {
|
1318
|
+
Detection.startDetect(self, ev);
|
1319
|
+
} else if(ev.eventType == EVENT_TOUCH) {
|
1320
|
+
Detection.detect(ev);
|
1321
|
+
}
|
1322
|
+
});
|
1323
|
+
|
1324
|
+
/**
|
1325
|
+
* keep a list of user event handlers which needs to be removed when calling 'dispose'
|
1326
|
+
* @property eventHandlers
|
1327
|
+
* @type {Array}
|
1328
|
+
*/
|
1329
|
+
this.eventHandlers = [];
|
1330
|
+
};
|
1331
|
+
|
1332
|
+
Hammer.Instance.prototype = {
|
1333
|
+
/**
|
1334
|
+
* bind events to the instance
|
1335
|
+
* @method on
|
1336
|
+
* @chainable
|
1337
|
+
* @param {String} gestures multiple gestures by splitting with a space
|
1338
|
+
* @param {Function} handler
|
1339
|
+
* @param {Object} handler.ev event object
|
1340
|
+
*/
|
1341
|
+
on: function onEvent(gestures, handler) {
|
1342
|
+
var self = this;
|
1343
|
+
Event.on(self.element, gestures, handler, function(type) {
|
1344
|
+
self.eventHandlers.push({ gesture: type, handler: handler });
|
1345
|
+
});
|
1346
|
+
return self;
|
1347
|
+
},
|
1348
|
+
|
1349
|
+
/**
|
1350
|
+
* unbind events to the instance
|
1351
|
+
* @method off
|
1352
|
+
* @chainable
|
1353
|
+
* @param {String} gestures
|
1354
|
+
* @param {Function} handler
|
1355
|
+
*/
|
1356
|
+
off: function offEvent(gestures, handler) {
|
1357
|
+
var self = this;
|
1358
|
+
|
1359
|
+
Event.off(self.element, gestures, handler, function(type) {
|
1360
|
+
var index = Utils.inArray({ gesture: type, handler: handler });
|
1361
|
+
if(index !== false) {
|
1362
|
+
self.eventHandlers.splice(index, 1);
|
1363
|
+
}
|
1364
|
+
});
|
1365
|
+
return self;
|
1366
|
+
},
|
1367
|
+
|
1368
|
+
/**
|
1369
|
+
* trigger gesture event
|
1370
|
+
* @method trigger
|
1371
|
+
* @chainable
|
1372
|
+
* @param {String} gesture
|
1373
|
+
* @param {Object} [eventData]
|
1374
|
+
*/
|
1375
|
+
trigger: function triggerEvent(gesture, eventData) {
|
1376
|
+
// optional
|
1377
|
+
if(!eventData) {
|
1378
|
+
eventData = {};
|
1379
|
+
}
|
1380
|
+
|
1381
|
+
// create DOM event
|
1382
|
+
var event = Hammer.DOCUMENT.createEvent('Event');
|
1383
|
+
event.initEvent(gesture, true, true);
|
1384
|
+
event.gesture = eventData;
|
1385
|
+
|
1386
|
+
// trigger on the target if it is in the instance element,
|
1387
|
+
// this is for event delegation tricks
|
1388
|
+
var element = this.element;
|
1389
|
+
if(Utils.hasParent(eventData.target, element)) {
|
1390
|
+
element = eventData.target;
|
1391
|
+
}
|
1392
|
+
|
1393
|
+
element.dispatchEvent(event);
|
1394
|
+
return this;
|
1395
|
+
},
|
1396
|
+
|
1397
|
+
/**
|
1398
|
+
* enable of disable hammer.js detection
|
1399
|
+
* @method enable
|
1400
|
+
* @chainable
|
1401
|
+
* @param {Boolean} state
|
1402
|
+
*/
|
1403
|
+
enable: function enable(state) {
|
1404
|
+
this.enabled = state;
|
1405
|
+
return this;
|
1406
|
+
},
|
1407
|
+
|
1408
|
+
/**
|
1409
|
+
* dispose this hammer instance
|
1410
|
+
* @method dispose
|
1411
|
+
* @return {Null}
|
1412
|
+
*/
|
1413
|
+
dispose: function dispose() {
|
1414
|
+
var i, eh;
|
1415
|
+
|
1416
|
+
// undo all changes made by stop_browser_behavior
|
1417
|
+
Utils.toggleBehavior(this.element, this.options.behavior, false);
|
1418
|
+
|
1419
|
+
// unbind all custom event handlers
|
1420
|
+
for(i = -1; (eh = this.eventHandlers[++i]);) {
|
1421
|
+
Utils.off(this.element, eh.gesture, eh.handler);
|
1422
|
+
}
|
1423
|
+
|
1424
|
+
this.eventHandlers = [];
|
1425
|
+
|
1426
|
+
// unbind the start event listener
|
1427
|
+
Event.off(this.element, EVENT_TYPES[EVENT_START], this.eventStartHandler);
|
1428
|
+
|
1429
|
+
return null;
|
1430
|
+
}
|
1431
|
+
};
|
1432
|
+
|
1433
|
+
|
1434
|
+
/**
|
1435
|
+
* @module gestures
|
1436
|
+
*/
|
1437
|
+
/**
|
1438
|
+
* Move with x fingers (default 1) around on the page.
|
1439
|
+
* Preventing the default browser behavior is a good way to improve feel and working.
|
1440
|
+
* ````
|
1441
|
+
* hammertime.on("drag", function(ev) {
|
1442
|
+
* console.log(ev);
|
1443
|
+
* ev.gesture.preventDefault();
|
1444
|
+
* });
|
1445
|
+
* ````
|
1446
|
+
*
|
1447
|
+
* @class Drag
|
1448
|
+
* @static
|
1449
|
+
*/
|
1450
|
+
/**
|
1451
|
+
* @event drag
|
1452
|
+
* @param {Object} ev
|
1453
|
+
*/
|
1454
|
+
/**
|
1455
|
+
* @event dragstart
|
1456
|
+
* @param {Object} ev
|
1457
|
+
*/
|
1458
|
+
/**
|
1459
|
+
* @event dragend
|
1460
|
+
* @param {Object} ev
|
1461
|
+
*/
|
1462
|
+
/**
|
1463
|
+
* @event drapleft
|
1464
|
+
* @param {Object} ev
|
1465
|
+
*/
|
1466
|
+
/**
|
1467
|
+
* @event dragright
|
1468
|
+
* @param {Object} ev
|
1469
|
+
*/
|
1470
|
+
/**
|
1471
|
+
* @event dragup
|
1472
|
+
* @param {Object} ev
|
1473
|
+
*/
|
1474
|
+
/**
|
1475
|
+
* @event dragdown
|
1476
|
+
* @param {Object} ev
|
1477
|
+
*/
|
1478
|
+
|
1479
|
+
/**
|
1480
|
+
* @param {String} name
|
1481
|
+
*/
|
1482
|
+
(function(name) {
|
1483
|
+
var triggered = false;
|
1484
|
+
|
1485
|
+
function dragGesture(ev, inst) {
|
1486
|
+
var cur = Detection.current;
|
1487
|
+
|
1488
|
+
// max touches
|
1489
|
+
if(inst.options.dragMaxTouches > 0 &&
|
1490
|
+
ev.touches.length > inst.options.dragMaxTouches) {
|
1491
|
+
return;
|
1492
|
+
}
|
1493
|
+
|
1494
|
+
switch(ev.eventType) {
|
1495
|
+
case EVENT_START:
|
1496
|
+
triggered = false;
|
1497
|
+
break;
|
1498
|
+
|
1499
|
+
case EVENT_MOVE:
|
1500
|
+
// when the distance we moved is too small we skip this gesture
|
1501
|
+
// or we can be already in dragging
|
1502
|
+
if(ev.distance < inst.options.dragMinDistance &&
|
1503
|
+
cur.name != name) {
|
1504
|
+
return;
|
1505
|
+
}
|
1506
|
+
|
1507
|
+
var startCenter = cur.startEvent.center;
|
1508
|
+
|
1509
|
+
// we are dragging!
|
1510
|
+
if(cur.name != name) {
|
1511
|
+
cur.name = name;
|
1512
|
+
if(inst.options.dragDistanceCorrection && ev.distance > 0) {
|
1513
|
+
// When a drag is triggered, set the event center to dragMinDistance pixels from the original event center.
|
1514
|
+
// Without this correction, the dragged distance would jumpstart at dragMinDistance pixels instead of at 0.
|
1515
|
+
// It might be useful to save the original start point somewhere
|
1516
|
+
var factor = Math.abs(inst.options.dragMinDistance / ev.distance);
|
1517
|
+
startCenter.pageX += ev.deltaX * factor;
|
1518
|
+
startCenter.pageY += ev.deltaY * factor;
|
1519
|
+
startCenter.clientX += ev.deltaX * factor;
|
1520
|
+
startCenter.clientY += ev.deltaY * factor;
|
1521
|
+
|
1522
|
+
// recalculate event data using new start point
|
1523
|
+
ev = Detection.extendEventData(ev);
|
1524
|
+
}
|
1525
|
+
}
|
1526
|
+
|
1527
|
+
// lock drag to axis?
|
1528
|
+
if(cur.lastEvent.dragLockToAxis ||
|
1529
|
+
( inst.options.dragLockToAxis &&
|
1530
|
+
inst.options.dragLockMinDistance <= ev.distance
|
1531
|
+
)) {
|
1532
|
+
ev.dragLockToAxis = true;
|
1533
|
+
}
|
1534
|
+
|
1535
|
+
// keep direction on the axis that the drag gesture started on
|
1536
|
+
var lastDirection = cur.lastEvent.direction;
|
1537
|
+
if(ev.dragLockToAxis && lastDirection !== ev.direction) {
|
1538
|
+
if(Utils.isVertical(lastDirection)) {
|
1539
|
+
ev.direction = (ev.deltaY < 0) ? DIRECTION_UP : DIRECTION_DOWN;
|
1540
|
+
} else {
|
1541
|
+
ev.direction = (ev.deltaX < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT;
|
1542
|
+
}
|
1543
|
+
}
|
1544
|
+
|
1545
|
+
// first time, trigger dragstart event
|
1546
|
+
if(!triggered) {
|
1547
|
+
inst.trigger(name + 'start', ev);
|
1548
|
+
triggered = true;
|
1549
|
+
}
|
1550
|
+
|
1551
|
+
// trigger events
|
1552
|
+
inst.trigger(name, ev);
|
1553
|
+
inst.trigger(name + ev.direction, ev);
|
1554
|
+
|
1555
|
+
var isVertical = Utils.isVertical(ev.direction);
|
1556
|
+
|
1557
|
+
// block the browser events
|
1558
|
+
if((inst.options.dragBlockVertical && isVertical) ||
|
1559
|
+
(inst.options.dragBlockHorizontal && !isVertical)) {
|
1560
|
+
ev.preventDefault();
|
1561
|
+
}
|
1562
|
+
break;
|
1563
|
+
|
1564
|
+
case EVENT_RELEASE:
|
1565
|
+
if(triggered && ev.changedLength <= inst.options.dragMaxTouches) {
|
1566
|
+
inst.trigger(name + 'end', ev);
|
1567
|
+
triggered = false;
|
1568
|
+
}
|
1569
|
+
break;
|
1570
|
+
|
1571
|
+
case EVENT_END:
|
1572
|
+
triggered = false;
|
1573
|
+
break;
|
1574
|
+
}
|
1575
|
+
}
|
1576
|
+
|
1577
|
+
Hammer.gestures.Drag = {
|
1578
|
+
name: name,
|
1579
|
+
index: 50,
|
1580
|
+
handler: dragGesture,
|
1581
|
+
defaults: {
|
1582
|
+
/**
|
1583
|
+
* minimal movement that have to be made before the drag event gets triggered
|
1584
|
+
* @property dragMinDistance
|
1585
|
+
* @type {Number}
|
1586
|
+
* @default 10
|
1587
|
+
*/
|
1588
|
+
dragMinDistance: 10,
|
1589
|
+
|
1590
|
+
/**
|
1591
|
+
* Set dragDistanceCorrection to true to make the starting point of the drag
|
1592
|
+
* be calculated from where the drag was triggered, not from where the touch started.
|
1593
|
+
* Useful to avoid a jerk-starting drag, which can make fine-adjustments
|
1594
|
+
* through dragging difficult, and be visually unappealing.
|
1595
|
+
* @property dragDistanceCorrection
|
1596
|
+
* @type {Boolean}
|
1597
|
+
* @default true
|
1598
|
+
*/
|
1599
|
+
dragDistanceCorrection: true,
|
1600
|
+
|
1601
|
+
/**
|
1602
|
+
* set 0 for unlimited, but this can conflict with transform
|
1603
|
+
* @property dragMaxTouches
|
1604
|
+
* @type {Number}
|
1605
|
+
* @default 1
|
1606
|
+
*/
|
1607
|
+
dragMaxTouches: 1,
|
1608
|
+
|
1609
|
+
/**
|
1610
|
+
* prevent default browser behavior when dragging occurs
|
1611
|
+
* be careful with it, it makes the element a blocking element
|
1612
|
+
* when you are using the drag gesture, it is a good practice to set this true
|
1613
|
+
* @property dragBlockHorizontal
|
1614
|
+
* @type {Boolean}
|
1615
|
+
* @default false
|
1616
|
+
*/
|
1617
|
+
dragBlockHorizontal: false,
|
1618
|
+
|
1619
|
+
/**
|
1620
|
+
* same as `dragBlockHorizontal`, but for vertical movement
|
1621
|
+
* @property dragBlockVertical
|
1622
|
+
* @type {Boolean}
|
1623
|
+
* @default false
|
1624
|
+
*/
|
1625
|
+
dragBlockVertical: false,
|
1626
|
+
|
1627
|
+
/**
|
1628
|
+
* dragLockToAxis keeps the drag gesture on the axis that it started on,
|
1629
|
+
* It disallows vertical directions if the initial direction was horizontal, and vice versa.
|
1630
|
+
* @property dragLockToAxis
|
1631
|
+
* @type {Boolean}
|
1632
|
+
* @default false
|
1633
|
+
*/
|
1634
|
+
dragLockToAxis: false,
|
1635
|
+
|
1636
|
+
/**
|
1637
|
+
* drag lock only kicks in when distance > dragLockMinDistance
|
1638
|
+
* This way, locking occurs only when the distance has become large enough to reliably determine the direction
|
1639
|
+
* @property dragLockMinDistance
|
1640
|
+
* @type {Number}
|
1641
|
+
* @default 25
|
1642
|
+
*/
|
1643
|
+
dragLockMinDistance: 25
|
1644
|
+
}
|
1645
|
+
};
|
1646
|
+
})('drag');
|
1647
|
+
|
1648
|
+
/**
|
1649
|
+
* @module gestures
|
1650
|
+
*/
|
1651
|
+
/**
|
1652
|
+
* trigger a simple gesture event, so you can do anything in your handler.
|
1653
|
+
* only usable if you know what your doing...
|
1654
|
+
*
|
1655
|
+
* @class Gesture
|
1656
|
+
* @static
|
1657
|
+
*/
|
1658
|
+
/**
|
1659
|
+
* @event gesture
|
1660
|
+
* @param {Object} ev
|
1661
|
+
*/
|
1662
|
+
Hammer.gestures.Gesture = {
|
1663
|
+
name: 'gesture',
|
1664
|
+
index: 1337,
|
1665
|
+
handler: function releaseGesture(ev, inst) {
|
1666
|
+
inst.trigger(this.name, ev);
|
1667
|
+
}
|
1668
|
+
};
|
1669
|
+
|
1670
|
+
/**
|
1671
|
+
* @module gestures
|
1672
|
+
*/
|
1673
|
+
/**
|
1674
|
+
* Touch stays at the same place for x time
|
1675
|
+
*
|
1676
|
+
* @class Hold
|
1677
|
+
* @static
|
1678
|
+
*/
|
1679
|
+
/**
|
1680
|
+
* @event hold
|
1681
|
+
* @param {Object} ev
|
1682
|
+
*/
|
1683
|
+
|
1684
|
+
/**
|
1685
|
+
* @param {String} name
|
1686
|
+
*/
|
1687
|
+
(function(name) {
|
1688
|
+
var timer;
|
1689
|
+
|
1690
|
+
function holdGesture(ev, inst) {
|
1691
|
+
var options = inst.options,
|
1692
|
+
current = Detection.current;
|
1693
|
+
|
1694
|
+
switch(ev.eventType) {
|
1695
|
+
case EVENT_START:
|
1696
|
+
clearTimeout(timer);
|
1697
|
+
|
1698
|
+
// set the gesture so we can check in the timeout if it still is
|
1699
|
+
current.name = name;
|
1700
|
+
|
1701
|
+
// set timer and if after the timeout it still is hold,
|
1702
|
+
// we trigger the hold event
|
1703
|
+
timer = setTimeout(function() {
|
1704
|
+
if(current && current.name == name) {
|
1705
|
+
inst.trigger(name, ev);
|
1706
|
+
}
|
1707
|
+
}, options.holdTimeout);
|
1708
|
+
break;
|
1709
|
+
|
1710
|
+
case EVENT_MOVE:
|
1711
|
+
if(ev.distance > options.holdThreshold) {
|
1712
|
+
clearTimeout(timer);
|
1713
|
+
}
|
1714
|
+
break;
|
1715
|
+
|
1716
|
+
case EVENT_RELEASE:
|
1717
|
+
clearTimeout(timer);
|
1718
|
+
break;
|
1719
|
+
}
|
1720
|
+
}
|
1721
|
+
|
1722
|
+
Hammer.gestures.Hold = {
|
1723
|
+
name: name,
|
1724
|
+
index: 10,
|
1725
|
+
defaults: {
|
1726
|
+
/**
|
1727
|
+
* @property holdTimeout
|
1728
|
+
* @type {Number}
|
1729
|
+
* @default 500
|
1730
|
+
*/
|
1731
|
+
holdTimeout: 500,
|
1732
|
+
|
1733
|
+
/**
|
1734
|
+
* movement allowed while holding
|
1735
|
+
* @property holdThreshold
|
1736
|
+
* @type {Number}
|
1737
|
+
* @default 2
|
1738
|
+
*/
|
1739
|
+
holdThreshold: 2
|
1740
|
+
},
|
1741
|
+
handler: holdGesture
|
1742
|
+
};
|
1743
|
+
})('hold');
|
1744
|
+
|
1745
|
+
/**
|
1746
|
+
* @module gestures
|
1747
|
+
*/
|
1748
|
+
/**
|
1749
|
+
* when a touch is being released from the page
|
1750
|
+
*
|
1751
|
+
* @class Release
|
1752
|
+
* @static
|
1753
|
+
*/
|
1754
|
+
/**
|
1755
|
+
* @event release
|
1756
|
+
* @param {Object} ev
|
1757
|
+
*/
|
1758
|
+
Hammer.gestures.Release = {
|
1759
|
+
name: 'release',
|
1760
|
+
index: Infinity,
|
1761
|
+
handler: function releaseGesture(ev, inst) {
|
1762
|
+
if(ev.eventType == EVENT_RELEASE) {
|
1763
|
+
inst.trigger(this.name, ev);
|
1764
|
+
}
|
1765
|
+
}
|
1766
|
+
};
|
1767
|
+
|
1768
|
+
/**
|
1769
|
+
* @module gestures
|
1770
|
+
*/
|
1771
|
+
/**
|
1772
|
+
* triggers swipe events when the end velocity is above the threshold
|
1773
|
+
* for best usage, set `preventDefault` (on the drag gesture) to `true`
|
1774
|
+
* ````
|
1775
|
+
* hammertime.on("dragleft swipeleft", function(ev) {
|
1776
|
+
* console.log(ev);
|
1777
|
+
* ev.gesture.preventDefault();
|
1778
|
+
* });
|
1779
|
+
* ````
|
1780
|
+
*
|
1781
|
+
* @class Swipe
|
1782
|
+
* @static
|
1783
|
+
*/
|
1784
|
+
/**
|
1785
|
+
* @event swipe
|
1786
|
+
* @param {Object} ev
|
1787
|
+
*/
|
1788
|
+
/**
|
1789
|
+
* @event swipeleft
|
1790
|
+
* @param {Object} ev
|
1791
|
+
*/
|
1792
|
+
/**
|
1793
|
+
* @event swiperight
|
1794
|
+
* @param {Object} ev
|
1795
|
+
*/
|
1796
|
+
/**
|
1797
|
+
* @event swipeup
|
1798
|
+
* @param {Object} ev
|
1799
|
+
*/
|
1800
|
+
/**
|
1801
|
+
* @event swipedown
|
1802
|
+
* @param {Object} ev
|
1803
|
+
*/
|
1804
|
+
Hammer.gestures.Swipe = {
|
1805
|
+
name: 'swipe',
|
1806
|
+
index: 40,
|
1807
|
+
defaults: {
|
1808
|
+
/**
|
1809
|
+
* @property swipeMinTouches
|
1810
|
+
* @type {Number}
|
1811
|
+
* @default 1
|
1812
|
+
*/
|
1813
|
+
swipeMinTouches: 1,
|
1814
|
+
|
1815
|
+
/**
|
1816
|
+
* @property swipeMaxTouches
|
1817
|
+
* @type {Number}
|
1818
|
+
* @default 1
|
1819
|
+
*/
|
1820
|
+
swipeMaxTouches: 1,
|
1821
|
+
|
1822
|
+
/**
|
1823
|
+
* horizontal swipe velocity
|
1824
|
+
* @property swipeVelocityX
|
1825
|
+
* @type {Number}
|
1826
|
+
* @default 0.6
|
1827
|
+
*/
|
1828
|
+
swipeVelocityX: 0.6,
|
1829
|
+
|
1830
|
+
/**
|
1831
|
+
* vertical swipe velocity
|
1832
|
+
* @property swipeVelocityY
|
1833
|
+
* @type {Number}
|
1834
|
+
* @default 0.6
|
1835
|
+
*/
|
1836
|
+
swipeVelocityY: 0.6
|
1837
|
+
},
|
1838
|
+
|
1839
|
+
handler: function swipeGesture(ev, inst) {
|
1840
|
+
if(ev.eventType == EVENT_RELEASE) {
|
1841
|
+
var touches = ev.touches.length,
|
1842
|
+
options = inst.options;
|
1843
|
+
|
1844
|
+
// max touches
|
1845
|
+
if(touches < options.swipeMinTouches ||
|
1846
|
+
touches > options.swipeMaxTouches) {
|
1847
|
+
return;
|
1848
|
+
}
|
1849
|
+
|
1850
|
+
// when the distance we moved is too small we skip this gesture
|
1851
|
+
// or we can be already in dragging
|
1852
|
+
if(ev.velocityX > options.swipeVelocityX ||
|
1853
|
+
ev.velocityY > options.swipeVelocityY) {
|
1854
|
+
// trigger swipe events
|
1855
|
+
inst.trigger(this.name, ev);
|
1856
|
+
inst.trigger(this.name + ev.direction, ev);
|
1857
|
+
}
|
1858
|
+
}
|
1859
|
+
}
|
1860
|
+
};
|
1861
|
+
|
1862
|
+
/**
|
1863
|
+
* @module gestures
|
1864
|
+
*/
|
1865
|
+
/**
|
1866
|
+
* Single tap and a double tap on a place
|
1867
|
+
*
|
1868
|
+
* @class Tap
|
1869
|
+
* @static
|
1870
|
+
*/
|
1871
|
+
/**
|
1872
|
+
* @event tap
|
1873
|
+
* @param {Object} ev
|
1874
|
+
*/
|
1875
|
+
/**
|
1876
|
+
* @event doubletap
|
1877
|
+
* @param {Object} ev
|
1878
|
+
*/
|
1879
|
+
|
1880
|
+
/**
|
1881
|
+
* @param {String} name
|
1882
|
+
*/
|
1883
|
+
(function(name) {
|
1884
|
+
var hasMoved = false;
|
1885
|
+
|
1886
|
+
function tapGesture(ev, inst) {
|
1887
|
+
var options = inst.options,
|
1888
|
+
current = Detection.current,
|
1889
|
+
prev = Detection.previous,
|
1890
|
+
sincePrev,
|
1891
|
+
didDoubleTap;
|
1892
|
+
|
1893
|
+
switch(ev.eventType) {
|
1894
|
+
case EVENT_START:
|
1895
|
+
hasMoved = false;
|
1896
|
+
break;
|
1897
|
+
|
1898
|
+
case EVENT_MOVE:
|
1899
|
+
hasMoved = hasMoved || (ev.distance > options.tapMaxDistance);
|
1900
|
+
break;
|
1901
|
+
|
1902
|
+
case EVENT_END:
|
1903
|
+
if(!Utils.inStr(ev.srcEvent.type, 'cancel') && ev.deltaTime < options.tapMaxTime && !hasMoved) {
|
1904
|
+
// previous gesture, for the double tap since these are two different gesture detections
|
1905
|
+
sincePrev = prev && prev.lastEvent && ev.timeStamp - prev.lastEvent.timeStamp;
|
1906
|
+
didDoubleTap = false;
|
1907
|
+
|
1908
|
+
// check if double tap
|
1909
|
+
if(prev && prev.name == name &&
|
1910
|
+
(sincePrev && sincePrev < options.doubleTapInterval) &&
|
1911
|
+
ev.distance < options.doubleTapDistance) {
|
1912
|
+
inst.trigger('doubletap', ev);
|
1913
|
+
didDoubleTap = true;
|
1914
|
+
}
|
1915
|
+
|
1916
|
+
// do a single tap
|
1917
|
+
if(!didDoubleTap || options.tapAlways) {
|
1918
|
+
current.name = name;
|
1919
|
+
inst.trigger(current.name, ev);
|
1920
|
+
}
|
1921
|
+
}
|
1922
|
+
break;
|
1923
|
+
}
|
1924
|
+
}
|
1925
|
+
|
1926
|
+
Hammer.gestures.Tap = {
|
1927
|
+
name: name,
|
1928
|
+
index: 100,
|
1929
|
+
handler: tapGesture,
|
1930
|
+
defaults: {
|
1931
|
+
/**
|
1932
|
+
* max time of a tap, this is for the slow tappers
|
1933
|
+
* @property tapMaxTime
|
1934
|
+
* @type {Number}
|
1935
|
+
* @default 250
|
1936
|
+
*/
|
1937
|
+
tapMaxTime: 250,
|
1938
|
+
|
1939
|
+
/**
|
1940
|
+
* max distance of movement of a tap, this is for the slow tappers
|
1941
|
+
* @property tapMaxDistance
|
1942
|
+
* @type {Number}
|
1943
|
+
* @default 10
|
1944
|
+
*/
|
1945
|
+
tapMaxDistance: 10,
|
1946
|
+
|
1947
|
+
/**
|
1948
|
+
* always trigger the `tap` event, even while double-tapping
|
1949
|
+
* @property tapAlways
|
1950
|
+
* @type {Boolean}
|
1951
|
+
* @default true
|
1952
|
+
*/
|
1953
|
+
tapAlways: true,
|
1954
|
+
|
1955
|
+
/**
|
1956
|
+
* max distance between two taps
|
1957
|
+
* @property doubleTapDistance
|
1958
|
+
* @type {Number}
|
1959
|
+
* @default 20
|
1960
|
+
*/
|
1961
|
+
doubleTapDistance: 20,
|
1962
|
+
|
1963
|
+
/**
|
1964
|
+
* max time between two taps
|
1965
|
+
* @property doubleTapInterval
|
1966
|
+
* @type {Number}
|
1967
|
+
* @default 300
|
1968
|
+
*/
|
1969
|
+
doubleTapInterval: 300
|
1970
|
+
}
|
1971
|
+
};
|
1972
|
+
})('tap');
|
1973
|
+
|
1974
|
+
/**
|
1975
|
+
* @module gestures
|
1976
|
+
*/
|
1977
|
+
/**
|
1978
|
+
* when a touch is being touched at the page
|
1979
|
+
*
|
1980
|
+
* @class Touch
|
1981
|
+
* @static
|
1982
|
+
*/
|
1983
|
+
/**
|
1984
|
+
* @event touch
|
1985
|
+
* @param {Object} ev
|
1986
|
+
*/
|
1987
|
+
Hammer.gestures.Touch = {
|
1988
|
+
name: 'touch',
|
1989
|
+
index: -Infinity,
|
1990
|
+
defaults: {
|
1991
|
+
/**
|
1992
|
+
* call preventDefault at touchstart, and makes the element blocking by disabling the scrolling of the page,
|
1993
|
+
* but it improves gestures like transforming and dragging.
|
1994
|
+
* be careful with using this, it can be very annoying for users to be stuck on the page
|
1995
|
+
* @property preventDefault
|
1996
|
+
* @type {Boolean}
|
1997
|
+
* @default false
|
1998
|
+
*/
|
1999
|
+
preventDefault: false,
|
2000
|
+
|
2001
|
+
/**
|
2002
|
+
* disable mouse events, so only touch (or pen!) input triggers events
|
2003
|
+
* @property preventMouse
|
2004
|
+
* @type {Boolean}
|
2005
|
+
* @default false
|
2006
|
+
*/
|
2007
|
+
preventMouse: false
|
2008
|
+
},
|
2009
|
+
handler: function touchGesture(ev, inst) {
|
2010
|
+
if(inst.options.preventMouse && ev.pointerType == POINTER_MOUSE) {
|
2011
|
+
ev.stopDetect();
|
2012
|
+
return;
|
2013
|
+
}
|
2014
|
+
|
2015
|
+
if(inst.options.preventDefault) {
|
2016
|
+
ev.preventDefault();
|
2017
|
+
}
|
2018
|
+
|
2019
|
+
if(ev.eventType == EVENT_TOUCH) {
|
2020
|
+
inst.trigger('touch', ev);
|
2021
|
+
}
|
2022
|
+
}
|
2023
|
+
};
|
2024
|
+
|
2025
|
+
/**
|
2026
|
+
* @module gestures
|
2027
|
+
*/
|
2028
|
+
/**
|
2029
|
+
* User want to scale or rotate with 2 fingers
|
2030
|
+
* Preventing the default browser behavior is a good way to improve feel and working. This can be done with the
|
2031
|
+
* `preventDefault` option.
|
2032
|
+
*
|
2033
|
+
* @class Transform
|
2034
|
+
* @static
|
2035
|
+
*/
|
2036
|
+
/**
|
2037
|
+
* @event transform
|
2038
|
+
* @param {Object} ev
|
2039
|
+
*/
|
2040
|
+
/**
|
2041
|
+
* @event transformstart
|
2042
|
+
* @param {Object} ev
|
2043
|
+
*/
|
2044
|
+
/**
|
2045
|
+
* @event transformend
|
2046
|
+
* @param {Object} ev
|
2047
|
+
*/
|
2048
|
+
/**
|
2049
|
+
* @event pinchin
|
2050
|
+
* @param {Object} ev
|
2051
|
+
*/
|
2052
|
+
/**
|
2053
|
+
* @event pinchout
|
2054
|
+
* @param {Object} ev
|
2055
|
+
*/
|
2056
|
+
/**
|
2057
|
+
* @event rotate
|
2058
|
+
* @param {Object} ev
|
2059
|
+
*/
|
2060
|
+
|
2061
|
+
/**
|
2062
|
+
* @param {String} name
|
2063
|
+
*/
|
2064
|
+
(function(name) {
|
2065
|
+
var triggered = false;
|
2066
|
+
|
2067
|
+
function transformGesture(ev, inst) {
|
2068
|
+
switch(ev.eventType) {
|
2069
|
+
case EVENT_START:
|
2070
|
+
triggered = false;
|
2071
|
+
break;
|
2072
|
+
|
2073
|
+
case EVENT_MOVE:
|
2074
|
+
// at least multitouch
|
2075
|
+
if(ev.touches.length < 2) {
|
2076
|
+
return;
|
2077
|
+
}
|
2078
|
+
|
2079
|
+
var scaleThreshold = Math.abs(1 - ev.scale);
|
2080
|
+
var rotationThreshold = Math.abs(ev.rotation);
|
2081
|
+
|
2082
|
+
// when the distance we moved is too small we skip this gesture
|
2083
|
+
// or we can be already in dragging
|
2084
|
+
if(scaleThreshold < inst.options.transformMinScale &&
|
2085
|
+
rotationThreshold < inst.options.transformMinRotation) {
|
2086
|
+
return;
|
2087
|
+
}
|
2088
|
+
|
2089
|
+
// we are transforming!
|
2090
|
+
Detection.current.name = name;
|
2091
|
+
|
2092
|
+
// first time, trigger dragstart event
|
2093
|
+
if(!triggered) {
|
2094
|
+
inst.trigger(name + 'start', ev);
|
2095
|
+
triggered = true;
|
2096
|
+
}
|
2097
|
+
|
2098
|
+
inst.trigger(name, ev); // basic transform event
|
2099
|
+
|
2100
|
+
// trigger rotate event
|
2101
|
+
if(rotationThreshold > inst.options.transformMinRotation) {
|
2102
|
+
inst.trigger('rotate', ev);
|
2103
|
+
}
|
2104
|
+
|
2105
|
+
// trigger pinch event
|
2106
|
+
if(scaleThreshold > inst.options.transformMinScale) {
|
2107
|
+
inst.trigger('pinch', ev);
|
2108
|
+
inst.trigger('pinch' + (ev.scale < 1 ? 'in' : 'out'), ev);
|
2109
|
+
}
|
2110
|
+
break;
|
2111
|
+
|
2112
|
+
case EVENT_RELEASE:
|
2113
|
+
if(triggered && ev.changedLength < 2) {
|
2114
|
+
inst.trigger(name + 'end', ev);
|
2115
|
+
triggered = false;
|
2116
|
+
}
|
2117
|
+
break;
|
2118
|
+
}
|
2119
|
+
}
|
2120
|
+
|
2121
|
+
Hammer.gestures.Transform = {
|
2122
|
+
name: name,
|
2123
|
+
index: 45,
|
2124
|
+
defaults: {
|
2125
|
+
/**
|
2126
|
+
* minimal scale factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1
|
2127
|
+
* @property transformMinScale
|
2128
|
+
* @type {Number}
|
2129
|
+
* @default 0.01
|
2130
|
+
*/
|
2131
|
+
transformMinScale: 0.01,
|
2132
|
+
|
2133
|
+
/**
|
2134
|
+
* rotation in degrees
|
2135
|
+
* @property transformMinRotation
|
2136
|
+
* @type {Number}
|
2137
|
+
* @default 1
|
2138
|
+
*/
|
2139
|
+
transformMinRotation: 1
|
2140
|
+
},
|
2141
|
+
|
2142
|
+
handler: transformGesture
|
2143
|
+
};
|
2144
|
+
})('transform');
|
2145
|
+
|
2146
|
+
/**
|
2147
|
+
* @module hammer
|
2148
|
+
*/
|
2149
|
+
|
2150
|
+
// AMD export
|
2151
|
+
if(typeof define == 'function' && define.amd) {
|
2152
|
+
define(function() {
|
2153
|
+
return Hammer;
|
2154
|
+
});
|
2155
|
+
// commonjs export
|
2156
|
+
} else if(typeof module !== 'undefined' && module.exports) {
|
2157
|
+
module.exports = Hammer;
|
2158
|
+
// browser export
|
2159
|
+
} else {
|
2160
|
+
window.Hammer = Hammer;
|
2161
|
+
}
|
2162
|
+
|
2163
|
+
})(window);
|