Commit | Line | Data |
---|---|---|
98344134 JC |
1 | const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); |
2 | ||
483ef61b JC |
3 | const getGenres = (lStorage) => { |
4 | return new Promise((resolve) => { | |
5 | const genres = JSON.parse(lStorage.getItem("genres")) | |
6 | if (genres === null) { | |
7 | fetch("http://api.brackets.jacobcasper.com/genre") | |
8 | .then((response) => response.text()) | |
9 | .then((text) => { | |
10 | lStorage.setItem("genres", text); | |
11 | resolve(JSON.parse(text)); | |
12 | }) | |
13 | } else { | |
14 | resolve(genres); | |
15 | } | |
16 | }); | |
17 | } | |
18 | ||
01952c94 JC |
19 | /** |
20 | * Safari iOS pls | |
21 | */ | |
22 | const formSubmitPolyfill = (form, callback) => { | |
23 | if (form.requestSubmit) { | |
24 | form.requestSubmit(); | |
25 | } else { | |
26 | callback(); | |
27 | } | |
28 | } | |
29 | ||
98344134 JC |
30 | const createGenreListWithClickEvent = (genreList, genres, callback) => { |
31 | genreList.append(...genres.map((genre) => { | |
32 | const name = genre["name"]; | |
74f7e922 JC |
33 | const option = document.createElement("option"); |
34 | option.setAttribute("data-name", name); | |
35 | option.addEventListener("click", callback); | |
36 | option.appendChild(document.createTextNode(name)); | |
37 | return option; | |
98344134 JC |
38 | })); |
39 | } | |
40 | ||
41 | const relativeToCtx = (x1, x2, y1, y2, ctx) => { | |
42 | const newX = x1 + x2; | |
43 | const newY = y1 + y2; | |
44 | ctx.lineTo(newX, newY); | |
45 | return [newX, newY]; | |
46 | } | |
47 | ||
1ffe1db0 JC |
48 | /** |
49 | * Return (x,y) of canvas | |
50 | */ | |
51 | const getDimensions = (canvas) => [canvas.width, canvas.height]; | |
52 | ||
53 | /** | |
54 | * Return (x,y) midpoint of canvas | |
55 | */ | |
56 | const getCenter = (canvas) => getDimensions(canvas).map((dim) => dim / 2); | |
57 | ||
dce15b01 JC |
58 | const getRectangleDimensionsUnbound = (canvas, xScale, yScale) => { |
59 | [width, height] = getDimensions(canvas); | |
60 | return [width * xScale, height * yScale]; | |
61 | } | |
62 | ||
63 | const getRectangleDimensions = (canvas) => getRectangleDimensionsUnbound(canvas, .5, .1); | |
64 | ||
1ffe1db0 JC |
65 | /** |
66 | * Draw champion box and clear background. | |
67 | */ | |
68 | const drawWinner = (canvas) => { | |
98344134 | 69 | const ctx = canvas.getContext("2d"); |
1ffe1db0 JC |
70 | const [width, height] = getDimensions(canvas); |
71 | const [mid_x, mid_y] = getCenter(canvas); | |
dce15b01 | 72 | const [rect_width, rect_height] = getRectangleDimensions(canvas); |
98344134 JC |
73 | ctx.strokeRect(mid_x - rect_width / 2, mid_y - rect_height / 2, rect_width, rect_height); |
74 | ctx.clearRect(mid_x - rect_width / 2, mid_y - rect_height / 2, rect_width, rect_height); | |
1ffe1db0 JC |
75 | } |
76 | ||
77 | /** | |
78 | * Draws a path in context from the current location to a point xDist * left, yDist * up away from it. | |
79 | * @param ctx RenderingContext | |
80 | * @param x, y float current location | |
81 | * @param x, y float distance away | |
82 | * @param up, left (-1|1) directions | |
83 | * @return [newNodeX, newNodeY] | |
84 | */ | |
85 | const drawBranchFrom = (ctx, x, y, xDist, yDist, left, up) => { | |
86 | const newX = x + (xDist * left) | |
87 | const newY = y + (yDist * up) | |
88 | ctx.lineTo(x, newY); | |
89 | ctx.lineTo(newX, newY); | |
692ff642 | 90 | ctx.stroke(); |
1ffe1db0 JC |
91 | return [newX, newY]; |
92 | } | |
93 | ||
692ff642 | 94 | const drawArtistOnCtx = (ctx, artistName, x, y) => { |
59a851b3 | 95 | ctx.font = "20px sans serif"; |
692ff642 JC |
96 | ctx.strokeText(artistName, x, y); |
97 | } | |
1ffe1db0 JC |
98 | |
99 | /** | |
100 | * Draws paths to the terminal nodes of a round | |
101 | * @param x, y the point representation of the start of the branch | |
692ff642 | 102 | * @param baseCallback a callback that needs the terminal x,y context |
1ffe1db0 | 103 | */ |
692ff642 JC |
104 | const drawMatchup = (canvas, x, y, iter, maxIter, left, artists, baseCallback) => { |
105 | if (iter === maxIter) { | |
106 | return baseCallback(x, y); | |
107 | } | |
1ffe1db0 | 108 | const ctx = canvas.getContext("2d"); |
0230aa11 | 109 | ctx.direction = left === -1 ? "ltr" : "rtl"; |
1ffe1db0 JC |
110 | const [width, height] = getDimensions(canvas); |
111 | ||
692ff642 JC |
112 | const drawBranchUp = (xDist, yDist) => drawBranchFrom(ctx, x, y, xDist, yDist, left, -1); |
113 | const drawBranchDown = (xDist, yDist) => drawBranchFrom(ctx, x, y, xDist, yDist, left, 1); | |
1ffe1db0 | 114 | const drawArtist = (artistName, x, y) => drawArtistOnCtx(ctx, artistName, x, y); |
4b4b1eff JC |
115 | const drawArtist1 = (x, y) => { |
116 | const artist1 = artists.shift(); | |
117 | if (!artist1) { | |
118 | return; | |
119 | } | |
120 | drawArtist(artist1["name"], x, y); | |
121 | } | |
122 | ||
123 | const drawArtist2 = (x, y) => { | |
124 | const artist2 = artists.pop(); | |
125 | if (!artist2) { | |
126 | return; | |
127 | } | |
128 | drawArtist(artist2["name"], x, y); | |
129 | } | |
98344134 | 130 | |
98344134 | 131 | ctx.beginPath(); |
1ffe1db0 | 132 | ctx.moveTo(x, y); |
692ff642 JC |
133 | const branchDistances = [width / (5 * (iter + 1)), height / (9 * (iter + 1))]; |
134 | drawMatchup( | |
135 | canvas, | |
136 | ...drawBranchUp(...branchDistances), | |
137 | iter + 1, | |
138 | maxIter, | |
139 | left, | |
140 | artists, | |
141 | drawArtist1, | |
1ffe1db0 | 142 | ); |
692ff642 | 143 | |
1ffe1db0 | 144 | ctx.moveTo(x, y); |
692ff642 JC |
145 | drawMatchup( |
146 | canvas, | |
147 | ...drawBranchDown(...branchDistances), | |
148 | iter + 1, | |
149 | maxIter, | |
150 | left, | |
151 | artists, | |
152 | drawArtist2, | |
1ffe1db0 | 153 | ); |
98344134 JC |
154 | } |
155 | ||
a6490680 JC |
156 | const drawBracket = (canvas, artists, genre) => { |
157 | const context = canvas.getContext("2d"); | |
158 | context.clearRect(0, 0, canvas.width, canvas.height); | |
1ffe1db0 JC |
159 | drawWinner(canvas); |
160 | const [mid_x, mid_y] = getCenter(canvas); | |
a6490680 | 161 | context.font = '28px sans serif' |
f512a462 JC |
162 | context.textAlign = "center"; |
163 | context.strokeText(genre.toUpperCase(), mid_x, 40); | |
164 | context.textAlign = "start"; | |
dce15b01 | 165 | const [rect_width, rect_height] = getRectangleDimensions(canvas); |
581e4442 | 166 | const groups = 4; |
e4763c42 JC |
167 | const rounds = Math.max( |
168 | Math.floor(Math.log2(artists.length / groups)), | |
169 | 1 | |
170 | ); | |
581e4442 | 171 | for (let group = 1; group <= groups; group++) { |
4b4b1eff JC |
172 | if (artists.length === 0) { |
173 | break; | |
174 | } | |
692ff642 JC |
175 | drawMatchup( |
176 | canvas, | |
59a851b3 JC |
177 | mid_x + (Math.pow(-1, group) * (rect_width / 6)), |
178 | mid_y + (Math.pow(-1, Math.floor(group / 2)) * (rect_height * 2.5)), | |
692ff642 JC |
179 | 0, |
180 | rounds, | |
181 | Math.pow(-1, group), | |
182 | artists, | |
183 | (x, y) => console.log("hello") | |
184 | ); | |
581e4442 | 185 | } |
1ffe1db0 JC |
186 | } |
187 | ||
98344134 JC |
188 | window.onload = () => { |
189 | const lStorage = window.localStorage; | |
190 | const genreList = document.getElementById("genre-list"); | |
191 | const genreInput = document.getElementById("genre-input"); | |
192 | const genreForm = document.getElementById("genre-form"); | |
193 | const canvas = document.getElementById("bracket"); | |
194 | ||
74f7e922 JC |
195 | const genreFormSubmitPolyfill = () => formSubmitPolyfill(genreList, formSubmitAction) |
196 | ||
98344134 JC |
197 | const createGenreList = (genreList, genres) => { |
198 | return createGenreListWithClickEvent(genreList, genres, (e) => { | |
199 | genreInput.value = e.target.innerText; | |
74f7e922 | 200 | genreFormSubmitPolyfill() |
98344134 JC |
201 | }) |
202 | } | |
483ef61b JC |
203 | |
204 | const genres = getGenres(lStorage) | |
205 | .then((genres) => createGenreList(genreList, genres)); | |
206 | ||
207 | const formSubmitAction = () => { | |
208 | fetch(encodeURI(`http://api.brackets.jacobcasper.com/artist/genre?genre_name=${genreInput.value}`)) | |
209 | .then((response) => response.json()) | |
210 | .then((data) => drawBracket(canvas, data.slice(0, 33), genreInput.value)); | |
98344134 JC |
211 | } |
212 | ||
213 | genreForm.addEventListener("submit", (e) => { | |
214 | e.preventDefault(); | |
01952c94 | 215 | formSubmitAction() |
98344134 JC |
216 | }); |
217 | ||
74f7e922 JC |
218 | genreInput.addEventListener("change", (e) => { |
219 | genreFormSubmitPolyfill() | |
98344134 JC |
220 | }); |
221 | ||
222 | ||
223 | canvas.width = window.innerWidth; | |
224 | canvas.height = window.innerHeight; | |
4b4b1eff | 225 | drawBracket(canvas, [], ""); |
98344134 JC |
226 | |
227 | const bgImg = new Image(); | |
228 | bgImg.onload = () => { | |
229 | const ctx = canvas.getContext("2d"); | |
98344134 JC |
230 | ctx.drawImage( |
231 | bgImg, | |
232 | 0, | |
233 | 0, | |
234 | (canvas.width / bgImg.width) * bgImg.width, | |
235 | (canvas.height / bgImg.height) * bgImg.height | |
236 | ); | |
237 | } | |
238 | ||
239 | const upload = document.getElementById("image-upload"); | |
240 | upload.addEventListener("change", (e) => { | |
241 | bgImg.src = URL.createObjectURL(e.target.files[0]); | |
242 | }); | |
243 | } |