Simplify genre retrieval with promise
[brackets.git] / frontend / index.js
CommitLineData
98344134
JC
1const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
2
483ef61b
JC
3const 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 */
22const formSubmitPolyfill = (form, callback) => {
23 if (form.requestSubmit) {
24 form.requestSubmit();
25 } else {
26 callback();
27 }
28}
29
98344134
JC
30const 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
41const 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 */
51const getDimensions = (canvas) => [canvas.width, canvas.height];
52
53/**
54 * Return (x,y) midpoint of canvas
55 */
56const getCenter = (canvas) => getDimensions(canvas).map((dim) => dim / 2);
57
dce15b01
JC
58const getRectangleDimensionsUnbound = (canvas, xScale, yScale) => {
59 [width, height] = getDimensions(canvas);
60 return [width * xScale, height * yScale];
61}
62
63const getRectangleDimensions = (canvas) => getRectangleDimensionsUnbound(canvas, .5, .1);
64
1ffe1db0
JC
65/**
66 * Draw champion box and clear background.
67 */
68const 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 */
85const 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 94const 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
104const 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
156const 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
188window.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}