Skip to content

Instantly share code, notes, and snippets.

@antoineMoPa
Created June 18, 2023 13:11
Show Gist options
  • Save antoineMoPa/a4c6a488ff0ee7eb445fd33f52e28a1c to your computer and use it in GitHub Desktop.
Save antoineMoPa/a4c6a488ff0ee7eb445fd33f52e28a1c to your computer and use it in GitHub Desktop.
index.html (cities)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body{
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<canvas class="cities-canvas"></canvas>
<script type="module">
const canvas = document.querySelectorAll('.cities-canvas')[0];
const drawRoads = (roads, ctx) => {
if (!roads.length) { return };
ctx.beginPath();
roads.forEach(road => {
ctx.moveTo(road.p0[0], road.p0[1]);
ctx.bezierCurveTo(road.c0[0], road.c0[1], road.c1[0], road.c1[1], road.p1[0], road.p1[1]);
});
ctx.stroke();
};
const drawState = (state, ctx) => {
ctx.fillStyle = "#efefef";
ctx.fillRect(0,0, ctx.canvas.width, ctx.canvas.height);
drawRoads(state.roads, ctx);
}
const initialState = () => {
return {
'roads': [],
'buildings': [
]
};
}
// Computes b - a
const subtractVec = (b, a) => {
return [b[0] - a[0], b[1] - a[1]];
}
// Computes a + b
const addVec = (a, b) => {
return [b[0] + a[0], b[1] + a[1]];
}
// Computes a * b
const multVec = (a, b) => {
return [b[0] * a[0], b[1] * a[1]];
}
// Mixes a and b
const mixVec = (a, b) => {
return [(a[0] + b[0]) * 0.5, (a[1] + a[1]) * 0.5];
}
class Cities {
state;
lastUpdate = null;
static init(canvas) {
const cities = new Cities();
const ctx = canvas.getContext('2d');
cities.canvas = canvas;
cities.ctx = ctx;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
cities.state = initialState();
window.requestAnimationFrame(function () {
cities.mainLoop();
});
let lastButtons = 0;
let index = 0;
window.addEventListener('mouseup', (e) => {
index = 0;
});
window.addEventListener('mousemove', (e) => {
const roads = cities.state.roads;
let start = [];
if (e.buttons !== lastButtons || roads.length === 0) {
start = [e.x, e.y];
index = 0;
} else {
start = roads[roads.length - 1].p1;
}
if (e.buttons == 1) {
const distance = Math.sqrt(
Math.pow(e.x - start[0], 2) + Math.pow(e.y - start[1], 2)
);
if (index == 0 || distance > 4) {
const p1 = [e.x, e.y];
cities.state.roads.push({
c0: start,
p0: start,
p1,
c1: p1,
index: index
});
index++;
}
}
lastButtons = e.buttons;
});
}
mainLoop() {
this.state = this.update(this.state);
drawState(this.state, this.ctx);
const cities = this;
window.requestAnimationFrame(function () {
cities.mainLoop();
});
}
update(state) {
// Find and update time delta
if (!this.lastUpdate) {
this.lastUpdate = new Date().getTime();
}
const time = new Date().getTime();
const delta = time - this.lastUpdate;
this.lastUpdate = time;
// smoothen roads
for (let i = 0; i < state.roads.length - 1; i++) {
const p0 = state.roads[i].p0;
const p1 = state.roads[i].p1;
// Smooth road by transforming indices 1 and 2 in control points.
if (state.roads.length > i + 3 &&
state.roads[i].index % 4 === 0 &&
state.roads[i + 1]?.index % 4 === 1 &&
state.roads[i + 2]?.index % 4 === 2 &&
state.roads[i + 3]?.index % 4 === 3) {
state.roads[i].c0 = state.roads[i + 1].p0;
state.roads[i].c1 = state.roads[i + 2].p0;
state.roads[i].p1 = state.roads[i + 3].p1;
state.roads[i].index = 1.5;
state.roads.splice(i+1, 3);
}
}
return state;
}
}
Cities.init(canvas)
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment