]>
Commit | Line | Data |
---|---|---|
3ec245a0 RBR |
1 | var color = document.querySelector('.color'), |
2 | light = document.querySelector('.light'), | |
3 | timeline = document.querySelector('.timeline'), | |
4 | clear = document.querySelector('.clear'), | |
5 | colors = [], | |
6 | selecting = false, | |
7 | recording = false, | |
8 | animationTime = 0, | |
9 | lastFrame = 0, | |
10 | t = null, | |
11 | h = 0, | |
12 | s = 100, | |
13 | l = 50; | |
14 | ||
15 | function render() { | |
16 | color.style.backgroundColor = `hsl(${h} ${s}% ${l}%)`; | |
17 | light.style.transform = `translateY(-${l*2.2}px)`; | |
18 | } | |
19 | ||
20 | function renderTimeline() { | |
21 | var background = 'linear-gradient(90deg,', | |
22 | last = 0; | |
23 | for (var {h, s, l, t: now} of colors) { | |
24 | background += `hsl(${h} ${s}% ${l}%) ${Math.round(100*last/3000)}%,`; | |
25 | background += `hsl(${h} ${s}% ${l}%) ${Math.round(100*(last+now)/3000)}%,`; | |
26 | last += now; | |
27 | } | |
28 | background += `black ${Math.round(100*last/3000)}%, black 101%)`; | |
29 | timeline.style.background = background; | |
30 | } | |
31 | ||
32 | function length() { | |
33 | return colors.map((c) => c.t).reduce((s, t) => s + t, 0); | |
34 | } | |
35 | ||
36 | function addColor() { | |
37 | t = Date.now(); | |
38 | colors.push({h, s, l, t: 0}); | |
39 | } | |
40 | ||
41 | function record() { | |
42 | if (recording) setTimeout(record, 100); | |
43 | var c = colors[colors.length - 1], | |
44 | l = length(); | |
45 | if (c.h !== h || c.s !== s || c.l !== l) { | |
46 | c.t = Math.min(3000, Date.now() - t); | |
47 | addColor(); | |
48 | c = colors[colors.length - 1]; | |
49 | } | |
50 | if (l >= 3000) return; | |
51 | c.t = Math.min(3000, Date.now() - t); | |
52 | renderTimeline(); | |
53 | } | |
54 | ||
55 | function preview(current) { | |
56 | if (selecting || recording) return; | |
57 | window.requestAnimationFrame(preview); | |
58 | var dt = current - lastFrame, | |
59 | last = 0; | |
60 | if (dt > 32) { | |
61 | animationTime = (animationTime + dt) % 3000 | |
62 | color.style.background = `hsl(0 0% 0%)`; | |
63 | for (var {h, s, l, t: now} of colors) { | |
64 | if (animationTime >= last && animationTime < last+now) { | |
65 | color.style.background = `hsl(${h} ${s}% ${l}%)`; | |
66 | break; | |
67 | } | |
68 | last += now; | |
69 | } | |
70 | lastFrame = current; | |
71 | } | |
72 | } | |
73 | ||
74 | color.addEventListener('mousemove', ({offsetX: x, offsetY: y}) => { | |
75 | h = Math.round(360 * x / 200); | |
76 | s = Math.round(100 * (200 - y) / 200); | |
77 | render(); | |
78 | }); | |
79 | ||
80 | color.addEventListener('wheel', ({deltaY: y}) => { | |
81 | selecting = true; | |
82 | l = Math.min(Math.max(0, l + y/4), 100) | |
83 | render(); | |
84 | }); | |
85 | ||
86 | color.addEventListener('mousedown', () => { | |
87 | addColor(); | |
88 | recording = true; | |
89 | setTimeout(record, 100); | |
90 | }); | |
91 | ||
92 | color.addEventListener('mouseup', () => { | |
93 | recording = false; | |
94 | }); | |
95 | ||
96 | color.addEventListener('mouseenter', () => { | |
97 | selecting = true; | |
98 | }); | |
99 | ||
100 | color.addEventListener('mouseout', () => { | |
101 | recording = false; | |
102 | selecting = false; | |
103 | window.requestAnimationFrame(preview); | |
104 | }); | |
105 | ||
106 | clear.addEventListener('click', () => { | |
107 | colors = []; | |
108 | renderTimeline(); | |
109 | }); | |
110 | ||
111 | render(); | |
112 | renderTimeline(); |