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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
import * as sfw from 'sfw';
const { Div, Canvas } = sfw.element.native;
import { Image } from 'widgets';
const css = await sfw.css(import.meta.url, './index.css');
export default class ShuffleView extends sfw.element.Container {
#front_image
#back_image
#front_image_index
#back_image_index
#images
#date
#drag_start_position
#drag_strength
constructor() {
super({ css });
this.#front_image_index = null;
this.#back_image_index = null;
this.body.append(
this.#date = Div.new({ id: 'date' }),
this.#front_image = Image.new({
id: 'front',
disabled: true,
ontouchstart: (e) => {
if (e.touches.length != 1) return;
this.#drag_start_position = [e.touches[0].pageX, e.touches[0].pageY];
},
ontouchmove: (e) => {
if (e.touches.length != 1) return;
const position = [e.touches[0].pageX, e.touches[0].pageY];
const delta = [
position[0] - this.#drag_start_position[0],
position[1] - this.#drag_start_position[1]
];
const strength = Math.min(1, Math.max((delta[0]**2 + delta[1]**2) / (40 ** 2), 0) / 100);
this.#drag_strength = strength;
const angle_x = position[0] - window.screen.width / 2;
const angle_y = position[1] - window.screen.height * 1.2;
let angle = (Math.atan((angle_y) / (angle_x)) * 180 / Math.PI + 90);
if (angle_x < 0) {
angle -= 180;
}
this.#front_image.style.transform = `
translate(-50%, calc(-50% - 50px))
translate(${delta[0]}px, ${delta[1]}px)
rotate(${angle}deg)
`;
this.#back_image.style.filter = `blur(${(1 - strength) * 50}px)`;
},
ontouchend: (e) => {
if (this.#drag_strength > 0.3) {
this.next();
}
this.#front_image.style.transform = '';
this.#back_image.style.filter = '';
},
}),
this.#back_image = Image.new({ id: 'back', disabled: true }),
)
this.onclick = () => this.next();
}
set images(images) {
this.#images = images;
}
open() {
this.next();
this.next();
}
next() {
this.#front_image_index = this.#back_image_index;
this.#back_image_index = Math.floor(Math.random() * this.#images.length);
if (this.#front_image_index !== null) {
this.#front_image.metadata = this.#images[this.#front_image_index];
this.#front_image.load();
const date = this.#images[this.#front_image_index].date
this.#date.innerText = date.toLocaleString('default', {
month: 'long',
year: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
}); ;
}
this.#back_image.metadata = this.#images[this.#back_image_index];
this.#back_image.load();
}
}
|