Add 5 files
Browse files- README.md +5 -8
- app.js +62 -0
- index.html +39 -19
- main.js +31 -0
- style.css +1 -28
README.md
CHANGED
@@ -1,11 +1,8 @@
|
|
1 |
---
|
|
|
2 |
title: Basketball Shot Analysis
|
3 |
-
emoji: 🦀
|
4 |
-
colorFrom: green
|
5 |
-
colorTo: purple
|
6 |
sdk: static
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
1 |
---
|
2 |
+
license: apache-2.0
|
3 |
title: Basketball Shot Analysis
|
|
|
|
|
|
|
4 |
sdk: static
|
5 |
+
emoji: 🏀
|
6 |
+
colorFrom: yellow
|
7 |
+
colorTo: green
|
8 |
+
---
|
|
app.js
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// Components
|
2 |
+
float x1, y1, x2, y2, gradient;
|
3 |
+
int width = 860;
|
4 |
+
int height = 420;
|
5 |
+
|
6 |
+
void setup() {
|
7 |
+
// Alphine JS
|
8 |
+
let courtSelect = document.getElementById('court-select');
|
9 |
+
let playerSelect = document.getElementById('player-select');
|
10 |
+
let shotSelect = document.getElementById('shot-select');
|
11 |
+
let analysisSelect = document.getElementById('analysis-select');
|
12 |
+
|
13 |
+
courtSelect.addEventListener('change', (e) => {
|
14 |
+
courtSelected = e.target.value;
|
15 |
+
playerSelected = null;
|
16 |
+
playerSelect.value = null;
|
17 |
+
});
|
18 |
+
|
19 |
+
playerSelect.addEventListener('change', (e) => {
|
20 |
+
playerSelected = e.target.value;
|
21 |
+
});
|
22 |
+
|
23 |
+
shotSelect.addEventListener('change', (e) => {
|
24 |
+
shotSelected = e.target.value;
|
25 |
+
});
|
26 |
+
|
27 |
+
analysisSelect.addEventListener('change', (e) => {
|
28 |
+
analysisSelected = e.target.value;
|
29 |
+
});
|
30 |
+
}
|
31 |
+
|
32 |
+
void draw() {
|
33 |
+
background(255);
|
34 |
+
textSize(20);
|
35 |
+
fill(0, 0, 0);
|
36 |
+
text(`Players in this court: ${players.length}`, 30, height/2);
|
37 |
+
}
|
38 |
+
|
39 |
+
void mousePressed() {
|
40 |
+
for (let i = 0; i < players.length; i++) {
|
41 |
+
let player = players[i];
|
42 |
+
let dx = dist(mouseX, mouseY, player.x, player.y);
|
43 |
+
if (dx < player.size/2) {
|
44 |
+
player.ballCount++;
|
45 |
+
break;
|
46 |
+
}
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
void keyPressed() {
|
51 |
+
if (keyCode === ENTER) {
|
52 |
+
background(255);
|
53 |
+
|
54 |
+
fill(0, 0, 0);
|
55 |
+
textSize(20);
|
56 |
+
text('You found an easter egg!', 30, height/2);
|
57 |
+
|
58 |
+
noLoop();
|
59 |
+
return;
|
60 |
+
}
|
61 |
+
|
62 |
+
if (keyCode === PATH) {
|
index.html
CHANGED
@@ -1,19 +1,39 @@
|
|
1 |
-
|
2 |
-
<
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
</
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<html><head><link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/full.css" rel="stylesheet" type="text/css" /><script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script><script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"></script><script defer src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.156.1/three.min.js"></script><script type="module" src="main.js"></script><title>Basketball Shot Analysis</title></head><body><header class="max-w-3xl mx-auto"><h1>Basketball Shot Analysis AI</h1></header><main class="max-w-3xl mx-auto"> <!-- Alpine JS -->
|
2 |
+
<div class="grid grid-cols-1 gap-2 py-4 pl-2 ">
|
3 |
+
<div class="flex flex-col md:flex-row justify-between md:items-center">
|
4 |
+
<div class="flex flex-col md:flex-row mb-2">
|
5 |
+
<h2 class="text-xl font-bold">Select a Court:</h2>
|
6 |
+
<select id="court-select" class="mt-1 block w-full border-2 border-gray-300 rounded-md shadow-sm py-2 px-3 text-gray-700 md:mt-0" x-model="courtSelected">
|
7 |
+
<option hidden>-- Select a Court --</option>
|
8 |
+
<option value="1">Court 1</option>
|
9 |
+
<option value="2">Court 2</option>
|
10 |
+
<option value="3">Court 3</option>
|
11 |
+
</select>
|
12 |
+
</div>
|
13 |
+
<div class="flex flex-col md:flex-row mb-2">
|
14 |
+
<h2 class="text-xl font-bold">Select a Player:</h2>
|
15 |
+
<select id="player-select" class="mt-1 block w-full border-2 border-gray-300 rounded-md shadow-sm py-2 px-3 text-gray-700 md:mt-0" x-model="playerSelected">
|
16 |
+
<option hidden>-- Select a Player --</option>
|
17 |
+
<option value="1">Player 1</option>
|
18 |
+
<option value="2">Player 2</option>
|
19 |
+
<option value="3">Player 3</option>
|
20 |
+
</select>
|
21 |
+
</div>
|
22 |
+
</div>
|
23 |
+
<div class="grid grid-cols-2 md:grid-cols-3 w-full place-items-center">
|
24 |
+
<div x-show="courtSelected">
|
25 |
+
<h3 class="text-gray-700 mb-4 text-2xl">Court 1</h3>
|
26 |
+
<div class="grid grid-cols-1 grid-rows-1 gap-2 w-full" x-show="playerSelected">
|
27 |
+
<h3 class="text-gray-700 mb-4 text-2xl">Player 1</h3>
|
28 |
+
<div class="grid grid-cols-1 grid-rows-1 gap-2 w-full" x-show="shotSelected">
|
29 |
+
<h3 class="text-gray-700 mb-4 text-2xl">Shot 1</h3>
|
30 |
+
<div class="grid grid-cols-2 md:grid-cols-5 w-full" x-show="analysisSelected">
|
31 |
+
<span class="col-span-1">{{ shot. similarity }}</span>
|
32 |
+
<span class="col-span-1">{{ shot. count }}</span>
|
33 |
+
<span class="col-span-1">{{ shot. candidate }}</span>
|
34 |
+
</div>
|
35 |
+
</div>
|
36 |
+
</div>
|
37 |
+
</div>
|
38 |
+
</div>
|
39 |
+
</div>
|
main.js
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// Components
|
2 |
+
x-clock
|
3 |
+
x-interval
|
4 |
+
|
5 |
+
const app = new Vue({
|
6 |
+
el: '#app',
|
7 |
+
delimiters: ["<", ">"],
|
8 |
+
components: {
|
9 |
+
Aside
|
10 |
+
},
|
11 |
+
data: () => ({
|
12 |
+
msg: "Welcome to the world of Basketball!",
|
13 |
+
dots: "Returns the dot product from the vector broadcaster",
|
14 |
+
orientation: "Returns the orientation of the vector broadcaster",
|
15 |
+
rotation: "Returns the rotation matrix representing the vector broadcaster",
|
16 |
+
scale: "Returns the scale factor of the vector broadcaster",
|
17 |
+
velocity: "Returns the velocity of the vector broadcaster in global coordinates",
|
18 |
+
}),
|
19 |
+
methods: {
|
20 |
+
swap: function () {
|
21 |
+
[this.msg, this.velocity] = [this.velocity, this.msg];
|
22 |
+
},
|
23 |
+
},
|
24 |
+
});
|
25 |
+
|
26 |
+
// eslint-disable-next-line
|
27 |
+
Vue.config.productionTip = false;
|
28 |
+
|
29 |
+
new Vue({
|
30 |
+
render: (h) => h(HTML),
|
31 |
+
}).$mount("#app");
|
style.css
CHANGED
@@ -1,28 +1 @@
|
|
1 |
-
|
2 |
-
padding: 2rem;
|
3 |
-
font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
|
4 |
-
}
|
5 |
-
|
6 |
-
h1 {
|
7 |
-
font-size: 16px;
|
8 |
-
margin-top: 0;
|
9 |
-
}
|
10 |
-
|
11 |
-
p {
|
12 |
-
color: rgb(107, 114, 128);
|
13 |
-
font-size: 15px;
|
14 |
-
margin-bottom: 10px;
|
15 |
-
margin-top: 5px;
|
16 |
-
}
|
17 |
-
|
18 |
-
.card {
|
19 |
-
max-width: 620px;
|
20 |
-
margin: 0 auto;
|
21 |
-
padding: 16px;
|
22 |
-
border: 1px solid lightgray;
|
23 |
-
border-radius: 16px;
|
24 |
-
}
|
25 |
-
|
26 |
-
.card p:last-child {
|
27 |
-
margin-bottom: 0;
|
28 |
-
}
|
|
|
1 |
+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.css">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|