-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
310 lines (282 loc) · 14.1 KB
/
index.html
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
<! --
F1 Bingo Card Generator: https://github.com/jonahhb/F1-Bingo-Card-Generator
6 March 2023
Authors:
Jonah Hood Blaxill: https://github.com/jonahhb
Eric Andrechek: https://github.com/EricAndrechek
-->
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="styles.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
<title>F1 Bingo Card Generator</title>
</head>
<body>
<script type="text/javascript" src="https://cdn.jsdelivr.net/pyodide/v0.22.1/full/pyodide.js"></script>
<script type="text/javascript">
function downloadPDF(pdf) {
const linkSource = `data:application/pdf;base64,${pdf}`;
const downloadLink = document.createElement("a");
const fileName = "abc.pdf";
downloadLink.href = linkSource;
downloadLink.download = fileName;
downloadLink.click();
}
async function main() {
let pyodide = await loadPyodide();
let resources_url = 'https://raw.githubusercontent.com/jonahhb/F1-Bingo-Card-Generator/main/resources.zip';
let zipResponse = await fetch(resources_url);
let zipBinary = await zipResponse.arrayBuffer();
pyodide.unpackArchive(zipBinary, "zip");
await pyodide.loadPackage("micropip");
const micropip = pyodide.pyimport("micropip");
await micropip.install("https://raw.githubusercontent.com/jonahhb/F1-Bingo-Card-Generator/main/fpdf-1.7.2-py2.py3-none-any.whl");
globalThis.username = document.getElementById("name").value;
let encoded_string = pyodide.runPython(`
from fpdf import FPDF
import random
import os
import base64
from js import username
# base dir /home/pyodide/
name = username
#create the pdf
pdf = FPDF(orientation = 'P', unit = 'in', format='Letter')
pdf.add_page()
#Place the template image to take the size of the page and center it
pdf.image('/home/pyodide/template.png', x = 0.25, y = 0.25, w = 8, h = 10.5, type = '', link = '')
# list of all the possible bingo squares locations and size of the square
# access is by LOCATIONS[square#][0] for x and LOCATIONS[square#][1] for y
# the square# is 0-24 for the 25 squares working left to right, top to bottom
LOCATIONS = [(0.32,2.45),(1.92,2.45),(3.51,2.45),(5.10,2.45),(6.69,2.45),
(0.32,4.1),(1.92,4.1),(3.51,4.1),(5.10,4.1),(6.69,4.1),
(0.32,5.75),(1.92,5.75),(3.51,5.75),(5.10,5.75),(6.69,5.75),
(0.32,7.45),(1.92,7.45),(3.51,7.45),(5.10,7.45),(6.69,7.45),
(0.32,9.1),(1.92,9.1),(3.51,9.1),(5.10,9.1),(6.69,9.1)]
SQUARE_SIZE = 1.5
# List of which squares are taken so we don't place two images in the same square
# access is by taken[square#] where square# is 0-24 for the 25 squares
# working left to right, top to bottom
taken = [False, False, False, False, False,
False, False, False, False, False,
False, False, False, False, False,
False, False, False, False, False,
False, False, False, False, False]
#Add name in the top left corner
pdf.set_font('helvetica', 'B', 12)
pdf.set_text_color(0,0,0)
pdf.text(0.32, 0.2, name)
#place the racestarts image in the center block
pdf.image('/home/pyodide/imgs/racestarts.png', x = LOCATIONS[12][0], y = LOCATIONS[12][1], w = SQUARE_SIZE, h = SQUARE_SIZE, type = '', link = '')
taken[12] = True
#place the redflag, safetycar, vsc, images in random open locations
required = ['/home/pyodide/imgs/redflag.png', '/home/pyodide/imgs/safetycar.png', '/home/pyodide/imgs/vsc.png']
for imgLoc in required:
#pick a random square
square = random.randint(0,24)
#keep picking random squares until we find one that is not taken
while taken[square]:
square = random.randint(0,24)
#place the image in the square
pdf.image(imgLoc, x = LOCATIONS[square][0], y = LOCATIONS[square][1], w = SQUARE_SIZE, h = SQUARE_SIZE, type = '', link = '')
#mark the square as taken
taken[square] = True
#get a list of all the images in the imgs directory
imgs = os.listdir('/home/pyodide/imgs')
#remove the images we have already placed
imgs.remove('racestarts.png')
imgs.remove('redflag.png')
imgs.remove('safetycar.png')
imgs.remove('vsc.png')
#place 21 random images in random open locations without duplicates
for i in range(21):
#pick a random image
img = random.choice(imgs)
#pick a random square
square = random.randint(0,24)
#keep picking random squares until we find one that is not taken
while taken[square]:
square = random.randint(0,24)
#place the image in the square
pdf.image('/home/pyodide/imgs/' + img, x = LOCATIONS[square][0], y = LOCATIONS[square][1], w = SQUARE_SIZE, h = SQUARE_SIZE, type = '', link = '')
#mark the square as taken
taken[square] = True
#remove the image from the list so we don't place it again
imgs.remove(img)
#output the bingo card to the current directory
pdf.output('/home/pyodide/bingo_card.pdf', 'F')
#read the pdf into a string
with open('/home/pyodide/bingo_card.pdf', 'rb') as f:
pdf = f.read()
#encode the pdf as base64
encoded_string = base64.b64encode(pdf)
#return the encoded string
encoded_string.decode('utf-8')
`);
let decoded_string = atob(encoded_string);
let bytes = new Uint8Array(decoded_string.length);
for (let i = 0; i < decoded_string.length; i++) {
bytes[i] = decoded_string.charCodeAt(i);
}
let blob = new Blob([bytes], {type: "application/pdf"});
let link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "bingo_card.pdf";
link.click();
reshowGenerateButton();
}
window.onload = function() {
document.getElementById("generate").addEventListener("click", generateCard);
}
//add event listener to the generate button so we can see that it is working
function generateCard() {
console.log("generate button clicked");
//move text box and button out of the way
document.getElementById("name").style.display = "none";
document.getElementById("generate").style.display = "none";
//show text saying the card is being generated
document.getElementById("generating").style.display = "block";
//generate the Card
main();
}
function reshowGenerateButton() {
//move text box and button back into place
document.getElementById("name").style.display = "block";
document.getElementById("generate").style.display = "block";
//hide text saying the card is being generated
document.getElementById("generating").style.display = "none";
}
</script>
<div id="main">
<h1 id="title">F1 Bingo Card Generator</h1>
<div id="aboutSec">
<h2 id="about">About</h2>
<hr>
<p id="aboutText">
This F1 Bingo Card Generator is a simple web app that generates a bingo card for the 2023 F1 season. This bingo card is made up of a random assortment of
bingo squares that are related to the 2023 F1 season (see below: Possible Squares). The bingo card is generated using Python and the FPDF library
(see below: About the Generator). Your name is only used to put it in the top left corner of the bingo card, so make it whatever you want.
</p>
</div>
<div id="generatorSec">
<input class="gen" type="text" id="name" placeholder="Enter your name">
<button class="gen" id="generate">Generate</button>
<p id="generating">Generating...</p>
</div>
<p>Note: The name field is not required but will put a name at the top left of the bingo card.</p>
<div id="rulesSection">
<h2>Intended Rules</h2>
<hr>
The intention with the bingo squares with the small circles and red numbers is that the event in the square has to happen at least that many times in
the season before that event can be checked off. For example, with the "Red Flag" square, the red flag has to be shown at least 4 times in the season.
Every time there was a red flag you would cross off one of the numbers in the circle. Once all the numbers are crossed off, you can check off the square.
<br><br>
Other than the above mentioned regular bingo rules apply.
<br><br>
At the end of the day it's all just for fun, so play it however you want!
<h2>Possible Squares</h2>
<hr>
<div class="squares">
<img class="squImg" src="imgs/1.png" alt="Max Won the World Drivers Championship">
<p class="squInfoTitle">Max Won the World Drivers Championship</p>
<p class="squInfo">This square is intended to be crossed off after Max (inevitably) wins the 2023 WDC</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/2.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/3.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/4.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/5.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/6.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/7.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/8.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/9.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/10.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/11.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/12.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/13.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/14.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/15.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/16.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/17.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/18.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<div class="squares">
<img class="squImg" src="imgs/19.png" alt="message here">
<p class="squInfoTitle">message here</p>
<p class="squInfo">message here</p>
</div>
<h2>About the Generator</h2>
<hr>
</div>
</div>
</body>
</html>