aboutsummaryrefslogtreecommitdiff
path: root/js/fyr.js
blob: 7e7d94ba678e5d9c965539100a02fab12eb7148f (plain)
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
109
110
111
112
113
var color = document.querySelector('.color'),
    light = document.querySelector('.light'),
    timeline = document.querySelector('.timeline'),
    clear = document.querySelector('.clear'),
    colors = [],
    selecting = 0,
    recording = 0,
    animationTime = 0,
    lastFrame = 0,
    t = null,
    h = 0,
    s = 100,
    l = 50,
    {round, min, max} = Math;

function render() {
  color.style.backgroundColor = `hsl(${h} ${s}% ${l}%)`;
  light.style.transform = `translateY(-${l*2.2}px)`;
}

function renderTimeline() {
  var background = 'linear-gradient(90deg,',
      last = 0;
  for (var {h, s, l, t: now} of colors) {
    background += `hsl(${h} ${s}% ${l}%) ${round(100*last/3000)}%,`;
    background += `hsl(${h} ${s}% ${l}%) ${round(100*(last+now)/3000)}%,`;
    last += now;
  }
  background += `black ${round(100*last/3000)}%, black 101%)`;
  timeline.style.background = background;
}

function length() {
  return colors.map((c) => c.t).reduce((s, t) => s + t, 0);
}

function addColor() {
  t = Date.now();
  colors.push({h, s, l, t: 0});
}

function record() {
  if (recording) setTimeout(record, 100);
  var c = colors[colors.length - 1],
      l = length();
  if (c.h !== h || c.s !== s || c.l !== l) {
    c.t = min(3000, Date.now() - t);
    addColor();
    c = colors[colors.length - 1];
  }
  if (l >= 3000) return;
  c.t = min(3000, Date.now() - t);
  renderTimeline();
}

function preview(current) {
  if (selecting || recording) return; 
  window.requestAnimationFrame(preview);
  var dt = current - lastFrame,
      last = 0;
  if (dt > 32) {
    animationTime = (animationTime + dt) % 3000
    color.style.background = `hsl(0 0% 0%)`;
    for (var {h, s, l, t: now} of colors) {
      if (animationTime >= last && animationTime < last+now) {
        color.style.background = `hsl(${h} ${s}% ${l}%)`;
        break;
      }
      last += now;
    }
    lastFrame = current;
  }
}

color.addEventListener('mousemove', ({offsetX: x, offsetY: y}) => {
  h = round(360 * x / 200);
  s = round(100 * (200 - y) / 200);
  render();
});

color.addEventListener('wheel', ({deltaY: y}) => {
  selecting = 1;
  l = min(max(0, l + y/4), 100)
  render();
});

color.addEventListener('mousedown', () => {
  addColor();
  recording = 1;
  setTimeout(record, 100);
});

color.addEventListener('mouseup', () => {
  recording = 0;
});

color.addEventListener('mouseenter', () => {
  selecting = 1;
});

color.addEventListener('mouseout', () => {
  recording = 0;
  selecting = 0;
  window.requestAnimationFrame(preview);
});

clear.addEventListener('click', () => {
  colors = [];
  renderTimeline();
});

render();
renderTimeline();