Published
Edited
Apr 25, 2020
3 forks
5 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
seed = Date.now()
Insert cell
noiseScale = 4500
Insert cell
n = 1000
Insert cell
p = getRandomPalette()
Insert cell
palette = shuffle(p)
Insert cell
Insert cell
svg`<svg width="${w}" height="${h}">
<defs>
<mask id="Mask">
<rect x="0" y="0" width="${w}" height="${h}" fill="white" />
<rect x="${margin}" y="${margin}" width="${w - margin * 2}" height="${h - margin * 2}" fill="black" />
</mask>
</defs>

<rect x="0" y="0" width="${w}" height="${h}" fill="${palette[0]}" />

<g>
${(() => {
const segments = [
new Segment(PVector(margin, margin), PVector(w-margin, margin)),
new Segment(PVector(w-margin, margin), PVector(w-margin, h-margin)),
new Segment(PVector(w-margin, h-margin), PVector(margin, h-margin)),
new Segment(PVector(margin, h-margin), PVector(margin, margin))
]

array(n).forEach(i => {
const pos = PVector.random(PVector(margin, margin), PVector(w - margin, h - margin))

// const angle = random(Math.PI)
// const angle = randInt(4) * Math.PI / 4
const angle = random() < .6 ? randInt(2) * Math.PI / 2 : random(Math.PI)
// const angle = sn.noise3D(pos.x / noiseScale, pos.y /noiseScale, seed) * TAU
const dir = PVector.fromAngle(angle).setMag(h+w)

const segment = new Segment(pos.clone().add(dir), pos.clone().sub(dir))

const intersections = []
for (const s of segments) {
const intersection = segSegIntersection(segment, s)
if (intersection !== null) intersections.push(intersection)
}

intersections.sort((a, b) => a.distSq(segment.center) > b.distSq(segment.center) ? 1 : -1)
const nearest = getNearestIntersections(segment, intersections)
if(nearest !== null) segments.push(new Segment(nearest[0], nearest[1]))
})

return segments.map(s => `<line
clip-path="url(#clip)"
opacity="0.9"
stroke="${palette[randInt(1, palette.length)]}"
stroke-width="${randInt(5, 50)}"
x1="${s.a.x}" y1="${s.a.y}"
x2="${s.b.x}" y2="${s.b.y}"
/>`).join('\n') +
`<rect
x="0"
y="0"
width="${w}"
height="${h}"
stroke="none"
fill="${palette[0]}"
mask="url(#Mask)"
/>\n` +
segments.map(s => `<line
stroke="${palette[0]}"
stroke-width="1.5"
x1="${s.a.x}" y1="${s.a.y}"
x2="${s.b.x}" y2="${s.b.y}"
/>
`).join('\n')
})()}
</g>
</svg>`
Insert cell
getNearestIntersections = (seg, intersections) => {
if(intersections.length === 2) return intersections
const closest = intersections[0]
const dir = seg.center.clone().sub(closest).invert().norm()
const second = intersections.find(d => PVector.sub(seg.center, d).norm().isEqualTo(dir, 0.01))

if(second) return [closest, second]
return null
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more