Skip to content

Commit c674b1a

Browse files
Add Voronoi
1 parent ffb3a81 commit c674b1a

File tree

4 files changed

+186
-0
lines changed

4 files changed

+186
-0
lines changed

favicon.ico

14.7 KB
Binary file not shown.

games/Voronoi/index.html

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta name="description" content="In mathematics, a Voronoi diagram is a partition of a plane into regions close to each of a given set of objects. In the simplest case, these objects are just finitely many points in the plane (called seeds, sites, or generators). For each seed there is a corresponding region, called a Voronoi cell, consisting of all points of the plane closer to that seed than to any other. The Voronoi diagram of a set of points is dual to its Delaunay triangulation.">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
7+
<title>Voronoi by Nickolas Gupton</title>
8+
<!-- My CSS -->
9+
<link rel="stylesheet" href="./style.css">
10+
<link rel="apple-touch-icon" sizes="180x180" href="https://nickolas.gupton.xyz/favicons/apple-touch-icon.png">
11+
<link rel="icon" type="image/png" sizes="32x32" href="https://nickolas.gupton.xyz/favicons/favicon-32x32.png">
12+
<link rel="icon" type="image/png" sizes="194x194" href="https://nickolas.gupton.xyz/favicons/favicon-194x194.png">
13+
<link rel="icon" type="image/png" sizes="192x192" href="https://nickolas.gupton.xyz/favicons/android-chrome-192x192.png">
14+
<link rel="icon" type="image/png" sizes="16x16" href="https://nickolas.gupton.xyz/favicons/favicon-16x16.png">
15+
<link rel="manifest" href="https://nickolas.gupton.xyz/favicons/site.webmanifest">
16+
<link rel="mask-icon" href="https://nickolas.gupton.xyz/favicons/safari-pinned-tab.svg" color="#454d6a">
17+
<link rel="shortcut icon" href="https://nickolas.gupton.xyz/favicons/favicon.ico">
18+
<meta name="apple-mobile-web-app-title" content="Voronoi">
19+
<meta name="application-name" content="Voronoi">
20+
<meta name="msapplication-TileColor" content="#454d6a">
21+
<meta name="msapplication-TileImage" content="https://nickolas.gupton.xyz/favicons/mstile-144x144.png">
22+
<meta name="msapplication-config" content="https://nickolas.gupton.xyz/favicons/browserconfig.xml">
23+
<meta name="theme-color" content="#454d6a">
24+
<script src="./script.js" defer></script>
25+
<!-- Clarity code for https://nickolas.gupton.xyz/ -->
26+
<script>
27+
(function(c,l,a,r,i,t,y){
28+
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
29+
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
30+
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
31+
})(window, document, "clarity", "script", "4xpup7sywk");
32+
</script>
33+
</head>
34+
<body>
35+
<h1 style="display:none;">Voronoi by Nickolas Gupton</h1>
36+
37+
<fieldset>
38+
<legend id="title">Voronoi</legend>
39+
<canvas id="canvas"></canvas>
40+
</fieldset>
41+
42+
43+
</body>
44+
</html>

games/Voronoi/script.js

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
'use strict';
2+
3+
///// Globals /////
4+
let ManhattanDistance = false;
5+
let generatingPoints = [];
6+
let voronoiCanvas = document.querySelector('#canvas');
7+
let voronoiContext = voronoiCanvas && voronoiCanvas.getContext && voronoiCanvas.getContext('2d');
8+
9+
///// Main Functions /////
10+
function getPointFromEvent(ev) {
11+
let rect = voronoiCanvas.getBoundingClientRect();
12+
return {
13+
color: 'rgb(' + Math.floor(Math.random() * 256) + ', ' + Math.floor(Math.random() * 256) + ', ' + Math.floor(Math.random() * 256) + ')',
14+
x: ev.clientX - rect.left,
15+
y: ev.clientY - rect.top
16+
};
17+
}
18+
19+
function updateVoronoiDiagram() {
20+
voronoiCanvas.width = voronoiCanvas.clientWidth;
21+
voronoiCanvas.height = voronoiCanvas.clientHeight;
22+
23+
// If there are no points, no reason to redraw
24+
if (generatingPoints.length === 0) {
25+
voronoiContext.fillStyle = 'rgb(0, 0, 0)';
26+
voronoiContext.fillRect(0, 0, voronoiCanvas.width, voronoiCanvas.height);
27+
return;
28+
}
29+
30+
// Pick a color for each pixel based on the closest point
31+
for (let x = 0; x < voronoiCanvas.width; x += 1) {
32+
for (let y = 0; y < voronoiCanvas.height; y += 1) {
33+
let currentDistance = 0;
34+
let closestDistance = Infinity;
35+
36+
generatingPoints.forEach(function (currentPoint) {
37+
if (ManhattanDistance) {
38+
currentDistance = (Math.abs(x - currentPoint.x) + Math.abs(y - currentPoint.y));
39+
} else {
40+
currentDistance = Math.sqrt(Math.pow(x - currentPoint.x, 2) + Math.pow(y - currentPoint.y, 2));
41+
}
42+
43+
if (currentDistance < closestDistance) {
44+
closestDistance = currentDistance;
45+
voronoiContext.fillStyle = currentPoint.color;
46+
}
47+
});
48+
voronoiContext.fillRect(x, y, 1, 1);
49+
}
50+
}
51+
52+
// Draw the circle around the point
53+
generatingPoints.forEach(function (currentPoint) {
54+
// Black circle
55+
voronoiContext.beginPath();
56+
voronoiContext.arc(currentPoint.x, currentPoint.y, 7, 0, 2 * Math.PI, false);
57+
voronoiContext.fillStyle = 'black';
58+
voronoiContext.fill();
59+
60+
// White circle
61+
voronoiContext.beginPath();
62+
voronoiContext.arc(currentPoint.x, currentPoint.y, 5, 0, 2 * Math.PI, false);
63+
voronoiContext.fillStyle = 'white';
64+
voronoiContext.fill();
65+
66+
// Colored circle
67+
voronoiContext.beginPath();
68+
voronoiContext.arc(currentPoint.x, currentPoint.y, 3, 0, 2 * Math.PI, false);
69+
voronoiContext.fillStyle = currentPoint.color;
70+
voronoiContext.fill();
71+
});
72+
}
73+
74+
function addPoint(ev) {
75+
generatingPoints.push(getPointFromEvent(ev));
76+
updateVoronoiDiagram();
77+
}
78+
79+
function swapDistanceCalculation() {
80+
ManhattanDistance = !ManhattanDistance;
81+
if (ManhattanDistance) {
82+
document.body.style.backgroundColor = 'rgb(66, 7, 122)';
83+
} else {
84+
document.body.style.backgroundColor = 'rgb(22, 74, 119)';
85+
}
86+
87+
updateVoronoiDiagram();
88+
}
89+
90+
///// Event listeners /////
91+
voronoiCanvas.addEventListener('click', (ev) => addPoint(ev), false);
92+
document.querySelector('#title').addEventListener('click', swapDistanceCalculation, false);
93+
window.addEventListener('resize', updateVoronoiDiagram, false);
94+
95+
///// Run! /////
96+
// Finally draw for the first time
97+
updateVoronoiDiagram();

games/Voronoi/style.css

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
* {
2+
margin: 0;
3+
padding: 0;
4+
}
5+
6+
body {
7+
width: 100vw;
8+
height: 100vh;
9+
background-color: rgb(22, 74, 119);
10+
overflow: hidden;
11+
}
12+
13+
fieldset {
14+
width: 80vw;
15+
margin-left: 10vw;
16+
height: 80vh;
17+
margin-top: 10vh;
18+
box-shadow: 10px 10px black;
19+
background-color: white;
20+
border-color: white;
21+
border-radius: 10px;
22+
border-style: solid;
23+
border-width: 2px;
24+
}
25+
26+
legend {
27+
color: black;
28+
text-shadow: 1px 1px gray;
29+
font-family: Arial, Helvetica, sans-serif;
30+
background-color: white;
31+
border-color: white;
32+
padding: 0 5px 0 5px;
33+
font-size: xx-large;
34+
border-radius: 10px;
35+
border-style: solid;
36+
border-width: 2px;
37+
}
38+
39+
#canvas {
40+
padding: 0;
41+
width: calc(80vw - 20px);
42+
margin-left: 10px;
43+
height: calc(80vh - 60px);
44+
margin-top: 10px;
45+
}

0 commit comments

Comments
 (0)