Skip to content

Instantly share code, notes, and snippets.

@harunpehlivan
Created May 30, 2021 13:39
Show Gist options
  • Select an option

  • Save harunpehlivan/af5fe03a2754f0e9d38fef376e9687ec to your computer and use it in GitHub Desktop.

Select an option

Save harunpehlivan/af5fe03a2754f0e9d38fef376e9687ec to your computer and use it in GitHub Desktop.
Travelling Salesman Sketches: Hamiltonian Range
<header>
<input type="range" min="1" max="500" step="10" value="20" />
<button>Refresh</button>
</header>
<main>
<div>
<canvas height="1200" width="1200"></canvas>
</div>
</main>
console.clear();
// TODO: group points in threes at a certain zoom level
class Point {
constructor({ x, y }) {
this.x = x;
this.y = y;
this.zones = {};
// how deep we zooming?
let scale = this.scales[5];
for (let i = 1; i >= scale; i /= 2)
this.zones[i.toFixed(5)] = this.plotter(i);
}
get scales() {
return [
1.00000, 0.50000, 0.25000,
0.12500, 0.06250, 0.03125
];
}
plotter(whole) {
// real float distance of center being the closest point
let centerProx = 0.3535533905932738;
let half = whole / 2;
let relx = (this.x % whole) / whole;
let rely = (this.y % whole) / whole;
let xoff = Math.floor(this.x / whole);
let yoff = Math.floor(this.y / whole);
let proxC = this.safeFloat(Math.hypot(0.5 - relx, 0.5 - rely));
let isCenter = proxC <= centerProx;
let origin;
// top left
if (relx < 0.5 && rely < 0.5) {
origin = 'nw';
// top right
} else if (relx >= 0.5 && rely < 0.5) {
origin = 'ne';
// bottom right
} else if (relx < 0.5 && rely >= 0.5) {
origin = 'sw';
// bottom left
} else {
origin = 'se';
}
relx = this.safeFloat(relx);
rely = this.safeFloat(rely);
return { relx, rely, xoff, yoff, proxC, isCenter, origin };
}
safeFloat(float) {
let res = 1000000000000000;
return Math.round(float * res) / res;
}
}
class App {
constructor() {
this.initializeCanvas();
}
run(pointCount) {
this.generatePoints(pointCount);
this.draw();
}
initializeCanvas() {
this.$cvs = document.querySelector('canvas');
this.$ctx = this.$cvs.getContext('2d');
this.g = 8;
this.w = this.$cvs.width - this.g * 2;
this.h = this.$cvs.height - this.g * 2;
this.di = 6;
this.rad = this.di / 2;
}
generatePoints(pointCount) {
this.points = [];
for (let i = 0; i < pointCount; i++) {
let point = new Point({ x: Math.random(), y: Math.random() });
this.points.push(point);
}
}
draw() {
this.drawnZones = {};
this.$ctx.clearRect(0, 0, this.$cvs.width, this.$cvs.height);
this.points.forEach((point) => {
this.drawPoint(point);
});
}
drawPoint(point) {
for (let key in point.zones) {
let zone = point.zones[key];
let size = parseFloat(key);
let color = `hsl(${size * 240}, 100%, 50%)`;
let id = `${zone.xoff}-${zone.yoff}-${size}`;
// we only want to draw the zone once
if (!this.drawnZones[id]) {
this.drawnZones[id] = true;
this.$ctx.fillStyle = color;
this.$ctx.fillRect(
zone.xoff * (size * this.w) + this.g + (this.w * size / 2) - this.rad,
zone.yoff * (size * this.h) + this.g + (this.h * size / 2) - this.rad,
this.di,
this.di
);
this.$ctx.strokeStyle = color;
this.$ctx.strokeRect(
zone.xoff * (size * this.w) + this.g,
zone.yoff * (size * this.h) + this.g,
this.w * size,
this.h * size
);
}
}
this.$ctx.fillStyle = '#fff';
this.$ctx.beginPath();
this.$ctx.arc(
(point.x * this.w) + this.g,
(point.y * this.h) + this.g,
this.rad, 0, 2 * Math.PI, false
);
this.$ctx.fill();
}
}
let app = new App();
let count = parseInt(document.querySelector('input').value);
app.run(count);
document.querySelector('button').addEventListener('click', () => {
app.run(count);
});
document.querySelector('input').addEventListener('input', (e) => {
count = parseInt(e.target.value);
app.run(count)
});
html,body {
height: 100%;
}
body {
background: #121212;
}
header, main {
text-align: center;
width: 95%;
max-width: 1200px;
margin: 0 auto;
padding: 2rem 0;
}
button, select {
border-radius: 4px;
padding: 0.5rem 0.75rem;
appearance: none;
background: black;
color: white;
border: 2px solid #444;
&:hover {
border-color: white;
}
cursor: pointer;
}
main {
user-select: none;
margin: 0 auto;
width: 95%;
max-width: 600px;
div {
position: relative;
width: 100%;
}
}
canvas {
display: block;
height: auto;
width: 100%;
background: black;
}

Travelling Salesman Sketches: Hamiltonian Range

Locating points to their nearest corner or center at different scales. The goal is to group them accordingly.

A Pen by HARUN PEHLİVAN on CodePen.

License.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment