UNPKG

4.77 kBJavaScriptView Raw
1const actions = require('./base');
2const utils = require('../utils');
3const InteractEvent = require('../InteractEvent');
4const Interactable = require('../Interactable');
5const Interaction = require('../Interaction');
6const defaultOptions = require('../defaultOptions');
7
8const gesture = {
9 defaults: {
10 enabled : false,
11 origin : null,
12 restrict: null,
13 },
14
15 checker: function (pointer, event, interactable, element, interaction) {
16 if (interaction.pointerIds.length >= 2) {
17 return { name: 'gesture' };
18 }
19
20 return null;
21 },
22
23 getCursor: function () {
24 return '';
25 },
26};
27
28InteractEvent.signals.on('new', function ({ iEvent, interaction }) {
29 if (iEvent.type !== 'gesturestart') { return; }
30 iEvent.ds = 0;
31
32 interaction.gesture.startDistance = interaction.gesture.prevDistance = iEvent.distance;
33 interaction.gesture.startAngle = interaction.gesture.prevAngle = iEvent.angle;
34 interaction.gesture.scale = 1;
35});
36
37InteractEvent.signals.on('new', function ({ iEvent, interaction }) {
38 if (iEvent.type !== 'gesturemove') { return; }
39
40 iEvent.ds = iEvent.scale - interaction.gesture.scale;
41
42 interaction.target.fire(iEvent);
43
44 interaction.gesture.prevAngle = iEvent.angle;
45 interaction.gesture.prevDistance = iEvent.distance;
46
47 if (iEvent.scale !== Infinity
48 && iEvent.scale !== null
49 && iEvent.scale !== undefined
50 && !isNaN(iEvent.scale)) {
51
52 interaction.gesture.scale = iEvent.scale;
53 }
54});
55
56/**
57 * ```js
58 * interact(element).gesturable({
59 * onstart: function (event) {},
60 * onmove : function (event) {},
61 * onend : function (event) {},
62 *
63 * // limit multiple gestures.
64 * // See the explanation in {@link Interactable.draggable} example
65 * max: Infinity,
66 * maxPerElement: 1,
67 * });
68 *
69 * var isGestureable = interact(element).gesturable();
70 * ```
71 *
72 * Gets or sets whether multitouch gestures can be performed on the target
73 *
74 * @param {boolean | object} [options] true/false or An object with event
75 * listeners to be fired on gesture events (makes the Interactable gesturable)
76 * @return {boolean | Interactable} A boolean indicating if this can be the
77 * target of gesture events, or this Interactable
78 */
79Interactable.prototype.gesturable = function (options) {
80 if (utils.is.object(options)) {
81 this.options.gesture.enabled = options.enabled === false? false: true;
82 this.setPerAction('gesture', options);
83 this.setOnEvents('gesture', options);
84
85 return this;
86 }
87
88 if (utils.is.bool(options)) {
89 this.options.gesture.enabled = options;
90
91 if (!options) {
92 this.ongesturestart = this.ongesturestart = this.ongestureend = null;
93 }
94
95 return this;
96 }
97
98 return this.options.gesture;
99};
100
101InteractEvent.signals.on('set-delta', function ({ interaction, iEvent, action, event, starting, ending, deltaSource }) {
102 if (action !== 'gesture') { return; }
103
104 const pointers = interaction.pointers;
105
106 iEvent.touches = [pointers[0], pointers[1]];
107
108 if (starting) {
109 iEvent.distance = utils.touchDistance(pointers, deltaSource);
110 iEvent.box = utils.touchBBox(pointers);
111 iEvent.scale = 1;
112 iEvent.ds = 0;
113 iEvent.angle = utils.touchAngle(pointers, undefined, deltaSource);
114 iEvent.da = 0;
115 }
116 else if (ending || event instanceof InteractEvent) {
117 iEvent.distance = interaction.prevEvent.distance;
118 iEvent.box = interaction.prevEvent.box;
119 iEvent.scale = interaction.prevEvent.scale;
120 iEvent.ds = iEvent.scale - 1;
121 iEvent.angle = interaction.prevEvent.angle;
122 iEvent.da = iEvent.angle - interaction.gesture.startAngle;
123 }
124 else {
125 iEvent.distance = utils.touchDistance(pointers, deltaSource);
126 iEvent.box = utils.touchBBox(pointers);
127 iEvent.scale = iEvent.distance / interaction.gesture.startDistance;
128 iEvent.angle = utils.touchAngle(pointers, interaction.gesture.prevAngle, deltaSource);
129
130 iEvent.ds = iEvent.scale - interaction.gesture.prevScale;
131 iEvent.da = iEvent.angle - interaction.gesture.prevAngle;
132 }
133});
134
135Interaction.signals.on('new', function (interaction) {
136 interaction.gesture = {
137 start: { x: 0, y: 0 },
138
139 startDistance: 0, // distance between two touches of touchStart
140 prevDistance : 0,
141 distance : 0,
142
143 scale: 1, // gesture.distance / gesture.startDistance
144
145 startAngle: 0, // angle of line joining two touches
146 prevAngle : 0, // angle of the previous gesture event
147 };
148});
149
150actions.gesture = gesture;
151actions.names.push('gesture');
152utils.merge(Interactable.eventTypes, [
153 'gesturestart',
154 'gesturemove',
155 'gestureend',
156]);
157actions.methodDict.gesture = 'gesturable';
158
159defaultOptions.gesture = gesture.defaults;
160
161module.exports = gesture;