/
_UseActionsPannable.ts
76 lines (68 loc) · 1.94 KB
/
_UseActionsPannable.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import TinyGesture from 'tinygesture';
import { tweened } from 'svelte/motion';
import { cubicInOut } from 'svelte/easing';
export default function Pannable(node: HTMLElement) {
const gesture = new TinyGesture(node);
let animationFrame: number | null = null;
const preventDefault = (event: Event) => {
event.preventDefault();
};
const left = tweened(0, {
duration: 300,
easing: cubicInOut,
});
const top = tweened(0, {
duration: 300,
easing: cubicInOut,
});
const leftUnsub = left.subscribe((value) => {
node.style.left = value + 'px';
});
const topUnsub = top.subscribe((value) => {
node.style.top = value + 'px';
});
node.style.transition =
(node.style.transition ? node.style.transition + ', ' : '') +
'opacity .3s ease';
node.addEventListener('touchstart', preventDefault, { passive: false });
gesture.on('panmove', () => {
if (animationFrame) {
return;
}
animationFrame = window.requestAnimationFrame(() => {
if (!gesture.swipingDirection.startsWith('pre-')) {
node.style.opacity = '0.7';
} else {
node.style.opacity = '1';
}
node.style.transform =
'rotate(' + (gesture.touchMoveX / 8 + gesture.touchMoveY / 8) + 'deg)';
left.set(gesture.touchMoveX, { duration: 0 });
top.set(gesture.touchMoveY, { duration: 0 });
animationFrame = null;
});
});
gesture.on('panend', () => {
if (animationFrame != null) {
window.cancelAnimationFrame(animationFrame);
}
animationFrame = null;
node.style.transform = '';
left.set(0);
top.set(0);
node.style.opacity = '1';
});
return {
destroy() {
node.removeEventListener('touchstart', preventDefault, {
passive: false,
} as EventListenerOptions);
if (animationFrame != null) {
window.cancelAnimationFrame(animationFrame);
}
leftUnsub();
topUnsub();
gesture.destroy();
},
};
}