Making Words Not Crash Into Each Other
Sounded simple until I tried it. How can we place many words of different sizes without overlapping? They can't be randomly scattered as there will be collision. And we can't put them in a grid, that's boring.
I needed a method that would do all of this:
- Place bigger words first
- place smaller words around them
- Rotate a few of the words 90 degrees for fun!
- Make sure none would collide
Step 1. Sort by “weight”.
Each word is assigned a random weight, which defines how big they will be compared to the others. These will be placed first in the center by sorting the list of words by weight:
this.words.sort((a, b) => b.weight - a.weight);Step 2. Position the rest outward.
For each subsequent word, start at the center and spiral outward in a circular pattern, checking viable positions along the way.
for (let radius = 0; radius < maxRadius; radius += 1) {
for (let angle = 0; angle < 2 * Math.PI; angle += angleStep) {
const x = centerX + radius * Math.cos(angle);
const y = centerY + radius * Math.sin(angle);
// Check if there's no collision
if (!this.collision(bounds)) {
return { x, y, bounds }; // Found a spot
}
}
}Step 3. Collision detection
Before placing a word, we need to check if it would overlap with any existing word. Each word has an area, and their bounds shouldn't be trespassed.
intersect(a, b) {
return !(
a.right < b.left ||
a.left > b.right ||
a.bottom < b.top ||
a.top > b.bottom
);
}This is basic rectangle collision detection. If the rectangles don't intersect, the words won't overlap. Geometry to the rescue!
Step 4. Save as Image
The save feature converts the canvas to a PNG image you can download. No screenshots needed.