-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.js
153 lines (124 loc) · 3.91 KB
/
main.js
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
const el = document.getElementById.bind(document)
const ctx = el('canvas').getContext('2d')
const pic = el('picture').getContext('2d')
const wsp = el('workspace').getContext('2d')
const all_the_emoji = get_me_all_the_emoji()
const cw = 1000
const ch = 1000
const ratchet_top = 255
const ratchet_bottom = 10
const ratchet_chance = 0.26
const ratchet_bounce = 30
const ratchet_step = 1
const margin = 0.3
let tries = 0
let ticks = 0
let wins = 0
let stop = true
let image_path = location.hash.slice(1)
if(image_path) set() // things start here. unless they don't.
function set() {
const img = new Image()
img.src = image_path
img.crossOrigin = 'Anonymous' // CORS light
img.onload = ev => pic.drawImage(img, 0, 0),go() // abuse of notation
}
function go() {
let ratchet = ratchet_top
let size = ratchet
stop = false
requestAnimationFrame(draw)
function draw() {
let old_wins = wins
since(1)
ticks++
while(since() < 16) { // 60fps ftw
tries++
let x = rand(cw)
let y = rand(ch)
let e = drawrand(wsp, x, y, size)
let [mx, my, msize] = marginize(x, y, size, margin)
let [c, w, p] = get_image_data([ctx, wsp, pic], mx, my, msize)
if(test(w.data, c.data, p.data)) {
drawstr(ctx, e, x, y, size)
wins++
} else {
wsp.putImageData(c, mx, my)
}
}
if(wins === old_wins) {
size += rand(ratchet - size) + rand(ratchet_bounce*2+1) - ratchet_bounce
if(ratchet > ratchet_bottom)
if(Math.random() < ratchet_chance)
ratchet -= ratchet_step
}
if(size < ratchet_bottom)
size = ratchet_bottom + rand(ratchet_bounce*2+1)
if(size > ratchet_top)
size = ratchet_top - rand(ratchet_bounce*2+1)
if(!stop)
requestAnimationFrame(draw)
}
return draw
}
function marginize(x, y, size, margin) {
let m = size * margin // emoji are squirrely
let msize = size+m
let mx = x - m/2
let my = y - size - m/2
return [mx, my, msize]
}
function get_image_data(ctxs, x, y, size) {
return ctxs.map(ctx => ctx.getImageData(x, y, size, size))
}
function drawrand(ctx, x, y, size) {
let e = all_the_emoji[rand(all_the_emoji.length)]
drawstr(ctx, e, x, y, size)
return e
}
function drawstr(ctx, s, x, y, size) {
ctx.font = size + 'px serif'
ctx.fillText(s, x, y)
}
function test(a, b, z) { // is a closer to z than b?
return score(a, z) < score(b, z)
}
function score(a, b) { // taxicab metric
return a.reduce((acc, x, i) => acc += Math.abs(x - b[i]), 0)
}
function rand(n) {
return Math.floor(Math.random() * n)
}
function is_colour_boring(r, g, b) { // if the pixel is not black, white, or red,
let s = r + g + b // then it probably belongs to an emoji
return (!s || s === 765 || s === 255 && s === r)
}
function is_char_emoji(ctx, char) {
let size = ctx.measureText(char).width
if(!size) return false
ctx.clearRect(0, 0, size+3, size+3) // three is a lucky number
ctx.fillText(char, 0, size) // probably chops off the emoji edges
let data = ctx.getImageData(0, 0, size, size).data
for(var i = data.length-4; i >= 0; i -= 4) // step through the RBGA values
if(!is_colour_boring(data[i], data[i+1], data[i+2]))
return true
return false
}
function get_me_all_the_emoji() {
let testCanvas = document.createElement("canvas")
let miniCtx = testCanvas.getContext('2d')
let q = []
for(let i=0; i<2000; i++) {
let char = String.fromCodePoint(127514 + i) // MAGICK EMOJI NUMBER
if(is_char_emoji(miniCtx, char))
q.push(char)
}
return q
}
let since = (()=>{
let last = performance.now()
return (r) => {
let now = performance.now()
let delta = now-last
if(r) last = now
return delta}})()