JSFiddle - React, Tailwind, and code Playground
CSS
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: grid;
place-items: center;
min-height: 100vh;
}
JavaScript
function vectorize(path) {
const vectors = []
if (path.length <= 1) return vectors
for (let i = 0, j = 1; j < path.length; i++, j++) {
const end = path[j]
const start = path[i]
const vector = {
x: end.x - start.x,
y: end.y - start.y,
}
vectors.push(vector)
}
return vectors
}
function make_line(path) {
const vectors = vectorize(path)
return vectors.reduce(
(thing, current) => {
const mag = Math.sqrt(current.x ** 2 + current.y ** 2)
thing.points.push(thing.length + mag)
thing.length += mag
return thing
},
{
points: [0],
length: 0,
},
).points
}
function get_dir(current, next, size) {
const dir = {
x: next.x - current.x,
y: next.y - current.y,
}
const mag = Math.sqrt(dir.x ** 2 + dir.y ** 2)
dir.x *= size / (mag || 1)
dir.y *= size / (mag || 1)
return dir
}
function make_path(path, size) {
const line = make_line(path)
const endPoints = []
if (path.length < 2) return endPoints
let nextIndex, currentPoint, currentLength
nextIndex = line.findIndex((n) => n > size)
currentPoint = path[0]
currentLength = size
while (nextIndex !== -1 && nextIndex < line.length) {
const nextPoint = path[nextIndex]
const dir = get_dir(currentPoint, nextPoint, size)
endPoints.push(currentPoint)
currentLength += size
currentPoint = {
x: currentPoint.x + dir.x,
y: currentPoint.y + dir.y,
}
nextIndex = line.findIndex((n) => n > currentLength)
if (nextIndex === -1) endPoints.push(currentPoint)
}
return endPoints
}
function is_not_closer_than(minDist, a, b) {
const sq2 = (a.x - b.x) ** 2 + (a.y - b.y) ** 2
const d2 = minDist ** 2
return sq2 >= d2
}
function stroke_path(context, path, lineWidth, strokeStyle) {
context.beginPath()
context.lineWidth = lineWidth
context.strokeStyle = strokeStyle
context.moveTo(path[0].x, path[0].y)
for (let i = 1; i < path.length; i++)...