-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.js
146 lines (116 loc) · 3.73 KB
/
main.js
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
window.addEventListener("beforeunload", function (e){
window.sessionStorage.tabId = window.tabId;
});
window.addEventListener("load", function (){
if (window.sessionStorage.tabId){
window.tabId = window.sessionStorage.tabId;
window.sessionStorage.removeItem("tabId");
} else {
window.tabId = `n${Math.floor(Math.random() * 1000000)}`
}
window.requestAnimationFrame(redraw)
});
const canvas = document.getElementById("canvas");
canvas.width = window.screen.availWidth;
canvas.height = window.screen.availHeight;
const ctx = canvas.getContext("2d");
function dot(x, y) {
return {
x: x,
y: y,
last: Date.now()
}
}
function fetchAndUpdateLocalStorage(offsetX, offsetY) {
// size of the actual webpage
const sWidth = window.innerWidth;
const sHeight = window.innerHeight;
// out dot will always be in the middle of the screen
const x = sWidth / 2;
const y = sHeight / 2;
// get the saved points
let points = JSON.parse(localStorage.getItem("points")) ?? {}
// add the new position to the points
points[window.tabId] = dot(x+offsetX, y+offsetY)
const now = Date.now()
points = Object.fromEntries(Object.entries(points).filter(([_, value]) => now - value.last <= 500))
// persist changes
localStorage.setItem("points", JSON.stringify(points))
return points
}
function redraw() {
// clear the canvas for redrawing...
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// offset from the top left of the screen
const offsetX = window.screenX;
const offsetY = window.screenY;
const points = fetchAndUpdateLocalStorage(offsetX, offsetY)
// go over all points and copy them over to `pts` array
const pts = []
for (let k in points) {
pts.push({
x: points[k].x,
y: points[k].y
})
}
// find the convex hull of the polygon
const outlinePoints = findConvexHullPoints(pts);
ctx.beginPath()
for (let i = 0; i < outlinePoints.length; i++) {
let p = outlinePoints[i];
if (i == 0) {
ctx.moveTo(p.x-offsetX, p.y-offsetY)
} else {
ctx.lineTo(p.x-offsetX, p.y-offsetY)
}
// close the loop
if (i == outlinePoints.length - 1) {
p = outlinePoints[0]
ctx.lineTo(p.x-offsetX, p.y-offsetY)
}
}
ctx.strokeStyle = "black";
ctx.stroke()
// draw the dots
for (let p of pts) {
ctx.beginPath();
ctx.arc(p.x-offsetX, p.y-offsetY, 10, 0, 2 * Math.PI);
ctx.fillstyle = 'black'
ctx.fill();
}
// redraw
window.requestAnimationFrame(redraw)
}
// reference: https://stackoverflow.com/a/3461533/9985287
function isToLeftOf(st, end, point) {
return (end.x - st.x)*(point.y - st.y) - (end.y - st.y)*(point.x - st.x) > 0;
}
// reference: https://en.wikipedia.org/wiki/Gift_wrapping_algorithm
function findConvexHullPoints(allPoints) {
let leftmost = allPoints[0]
for (let p of allPoints) {
if (p.x < leftmost.x) {
leftmost = p
}
}
let pointOnHull = leftmost
let i = 0
const convexHullPoints = []
while (true) {
convexHullPoints.push(pointOnHull)
let endpoint = allPoints[0]
for (let j=0;j<allPoints.length;j++) {
let condition = endpoint == pointOnHull
condition = condition || isToLeftOf(convexHullPoints[i], endpoint, allPoints[j])
if (condition) {
endpoint = allPoints[j]
}
}
i += 1
pointOnHull = endpoint
if (endpoint == convexHullPoints[0] || i > allPoints.length) {
break
}
};
return convexHullPoints;
}