diff --git a/frontend/index-old.html b/frontend/index-old.html
new file mode 100644
index 0000000..23ac777
--- /dev/null
+++ b/frontend/index-old.html
@@ -0,0 +1,90 @@
+
+
+
+
+ Dodgeball Tracker
+
+
+
+
+
+
+
+
+
+ Dodgeball Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/index.html b/frontend/index.html
index 15b27cc..1cefe89 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -2,29 +2,17 @@
- Animation
+ Dodgeball Tracker
+
- Hello, world!
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/frontend/main-old.js b/frontend/main-old.js
new file mode 100644
index 0000000..f031426
--- /dev/null
+++ b/frontend/main-old.js
@@ -0,0 +1,118 @@
+import anime from "https://esm.sh/animejs@3.2.2";
+import m from "https://esm.sh/mithril@2.2.2"
+import colormap from "https://esm.sh/colormap@2.3.2"
+
+
+const second = 1000;
+
+const canvasWidth = Number.parseFloat(document.querySelector("svg").getAttribute("width"));
+const canvasHeight = Number.parseFloat(document.querySelector("svg").getAttribute("height"));
+
+function gaussianRandom(mean=0, stdev=1) {
+ const u = 1 - Math.random(); // Converting [0,1) to (0,1]
+ const v = Math.random();
+ const z = Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v );
+ // Transform to the desired mean and standard deviation:
+ return z * stdev + mean;
+}
+
+function* brownian(n){
+ let x = 0;
+ for(let i = 0; i < n; i ++){
+ x += gaussianRandom(0, 10);
+ console.log(x);
+ yield x;
+ }
+}
+
+function* pseudoBrownian(n, limit){
+ let x = 0;
+ for(let i = 0; i < n; i ++){
+ let delta = gaussianRandom(0, 10);
+ if(Math.abs(x + delta) > limit){
+ delta = -1 * delta
+ }
+ x += delta;
+ yield x;
+ }
+}
+
+function* keyFrames(duration, framePerSeconds){
+ const deltaX = canvasWidth / (duration * framePerSeconds);
+ const limit = 0.75 * (canvasHeight / 2);
+ for(const deltaY of pseudoBrownian(duration * framePerSeconds, limit)){
+ yield {translateX: `+=${deltaX}`, translateY: deltaY};
+ }
+}
+
+const duration = 60;
+const timeline = anime.timeline({
+ duration: duration * second,
+ autoplay: false,
+ easing: 'linear'});
+
+for(let i = 1; i <= 12; i++){
+ timeline.add({
+ targets: `#rect-${i}`,
+ keyframes: Array.from(keyFrames(duration, 30)),
+ }, 0)
+}
+
+
+document.querySelector('#play').onclick = timeline.play;
+document.querySelector('#pause').onclick = timeline.pause;
+document.querySelector('#seek').onclick = function(){
+ const seekVal = Number.parseFloat(second * document.querySelector('#seek-value').value);
+ timeline.pause();
+ timeline.seek(seekVal);
+}
+
+
+function generatePoints(points, frames){
+ const lst = [];
+ const colors = colormap({
+ colormap: 'viridis',
+ nshades: new Set(points.map(p => p.objectId)).size,
+ format: 'hex',
+ alpha: 1
+ });
+ for(const point of points){
+ if(frames.indexOf(point.frameIndex) !== -1){
+ lst.push(m("text", {x: point.y, y: point.x, fill: colors[point.objectId]}, point.objectId));
+ }
+ }
+ return m("g", lst);
+}
+
+function getTimeStamp(points, frameId){
+ for(const point of points){
+ if(point.frameIndex === frameId){
+ return `${point.frameTimestamp / 1000} seconds`;
+ }
+ }
+}
+
+const url = "/dodgeball-tracker/outputs/output-lmbn_n_cuhk03_d.json";
+const resp = await fetch(url);
+const points = await resp.json();
+
+function range(min, max){
+ const ret = [];
+ while(min < max){
+ ret.push(min);
+ min ++;
+ }
+ return ret
+}
+
+function getCourtLines(){
+ return [
+ m("line", {x1: 450, x2: 450, y1: 0, y2: 450, class: "court-border"}),
+ m("line", {x1: 300, x2: 300, y1: 0, y2: 450, class: "return-line"}),
+ m("line", {x1: 600, x2: 600, y1: 0, y2: 450, class: "return-line"})
+ ]
+}
+
+
+m.render(document.getElementById("first"), generatePoints(points.points, range(-10, 400)));
+m.render(document.getElementById("first-ts"), m("span", getTimeStamp(points.points, 80)));
\ No newline at end of file
diff --git a/frontend/main.js b/frontend/main.js
index 9638bf2..0eeec6e 100644
--- a/frontend/main.js
+++ b/frontend/main.js
@@ -2,6 +2,72 @@ import m from "https://esm.sh/mithril@2.2.2"
import colormap from "https://esm.sh/colormap@2.3.2"
import {range} from "./util.js";
+
+// const second = 1000;
+
+// const canvasWidth = Number.parseFloat(document.querySelector("svg").getAttribute("width"));
+// const canvasHeight = Number.parseFloat(document.querySelector("svg").getAttribute("height"));
+
+function gaussianRandom(mean=0, stdev=1) {
+ const u = 1 - Math.random(); // Converting [0,1) to (0,1]
+ const v = Math.random();
+ const z = Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v );
+ // Transform to the desired mean and standard deviation:
+ return z * stdev + mean;
+}
+
+function* brownian(n){
+ let x = 0;
+ for(let i = 0; i < n; i ++){
+ x += gaussianRandom(0, 10);
+ console.log(x);
+ yield x;
+ }
+}
+
+function* pseudoBrownian(n, limit){
+ let x = 0;
+ for(let i = 0; i < n; i ++){
+ let delta = gaussianRandom(0, 10);
+ if(Math.abs(x + delta) > limit){
+ delta = -1 * delta
+ }
+ x += delta;
+ yield x;
+ }
+}
+
+function* keyFrames(duration, framePerSeconds){
+ const deltaX = canvasWidth / (duration * framePerSeconds);
+ const limit = 0.75 * (canvasHeight / 2);
+ for(const deltaY of pseudoBrownian(duration * framePerSeconds, limit)){
+ yield {translateX: `+=${deltaX}`, translateY: deltaY};
+ }
+}
+
+// const duration = 60;
+// const timeline = anime.timeline({
+// duration: duration * second,
+// autoplay: false,
+// easing: 'linear'});
+//
+// for(let i = 1; i <= 12; i++){
+// timeline.add({
+// targets: `#rect-${i}`,
+// keyframes: Array.from(keyFrames(duration, 30)),
+// }, 0)
+// }
+
+
+// document.querySelector('#play').onclick = timeline.play;
+// document.querySelector('#pause').onclick = timeline.pause;
+// document.querySelector('#seek').onclick = function(){
+// const seekVal = Number.parseFloat(second * document.querySelector('#seek-value').value);
+// timeline.pause();
+// timeline.seek(seekVal);
+// }
+
+
function generatePoints(points, frames){
const lst = [];
const colors = colormap({
@@ -26,11 +92,74 @@ function getTimeStamp(points, frameId){
}
}
-const url = "/dodgeball-tracker/outputs/output-lmbn_n_cuhk03_d.json";
-const resp = await fetch(url);
-const points = await resp.json();
+// const url = "/dodgeball-tracker/outputs/output-lmbn_n_cuhk03_d.json";
+// const resp = await fetch(url);
+// const points = await resp.json();
-m.render(document.getElementById("first"), generatePoints(points.points, range(-10, 400)));
-m.render(document.getElementById("first-ts"), m("span", getTimeStamp(points.points, 80)));
\ No newline at end of file
+function getCourtLines(){
+ return [
+ m("line", {x1: 450, x2: 450, y1: 0, y2: 450, class: "court-border"}),
+ m("line", {x1: 300, x2: 300, y1: 0, y2: 450, class: "return-line"}),
+ m("line", {x1: 600, x2: 600, y1: 0, y2: 450, class: "return-line"})
+ ]
+}
+class WorkingTabs{
+
+ tabs(){
+ return m("div.tabs",
+ m("ul",
+ m("li.is-active", m("a", "Info")),
+ m("li", m("a", "Video Player"))));
+ }
+
+ info(){
+ const options = [
+ m("option", "one"),
+ m("option", "two"),
+ ]
+ return m("div.field",
+ m("label.label", "Dataset"),
+ m("div.control",
+ m("div.select",
+ m("select", options))));
+ }
+ view(){
+ return m("div",
+ this.tabs(),
+ this.info())
+ }
+}
+
+const Court = {
+ view: function(){
+ const margin = 50
+ return m("svg.court-side", { width: 900 + 2 * margin, height: 450 + 2 * margin}, [
+ m("g.court-border#court", {transform: `translate(${margin} ${margin})`}, [
+ m("rect", {width: 900, height: 450, style: 'background-color: pink;'}),
+ getCourtLines()
+ ])
+ ])
+ }
+
+}
+
+// m.render(document.getElementById("new"), drawCourt());
+
+// m.render(document.getElementById("first"), generatePoints(points.points, range(-10, 400)));
+// m.render(document.getElementById("first-ts"), m("span", getTimeStamp(points.points, 80)));
+
+const Main = {
+ view: function(){
+ return m("div", [
+ m("h1.title.is-1", "DodgeBall Tracker"),
+ m("div.columns.is-centered",
+ m("m.column.is-three-quarters",
+ m(Court),
+ m(WorkingTabs)))
+ ])
+ }
+}
+
+m.mount(document.body, Main);
\ No newline at end of file
diff --git a/frontend/style.css b/frontend/style.css
index d7a1533..68bcd18 100644
--- a/frontend/style.css
+++ b/frontend/style.css
@@ -5,6 +5,10 @@
fill: gray;
}
+.court-side {
+ background-color: pink;
+}
+
.return-line {
stroke: blue;
stroke-width: 2px;