Published
Edited
Mar 19, 2020
Importers
1 star
Insert cell
Insert cell
Insert cell
// Simple abstraction for cartesian points
class Point {
constructor(x, y) {
this.x = x
this.y = y
}
static random({ xMin = 0, xMax = 100, yMin = 0, yMax = 100 } = {}) {
return new Point(
randomFloat(xMin, xMax),
randomFloat(yMin, yMax)
)
}
}
Insert cell
/*
An SVG circle encapsulated in a class.
The default values assume a viewBox of "0 0 100 56.25" which is a 16x9 aspect ratio.
Since this is arbitrary and up to the user, the values are easily overwritten.

Example:

svg`
<svg width="${width}" height="${height}">
${array(100).map(() =>
Circle.random({
xMin: 20,
xMax: w - 200,
yMin: 10,
yMax: h - 10,
attrs: {
fill: p[randomInt(0, p.length - 1)],
opacity: randomFloat(0.3, 1)
}
}).draw()
).join('')}
</svg>
`

where
width = default "width" value provided by Observable
height = some number
p = array of color strings
*/
class Circle {
constructor(cx, cy, r, attrs = {}) {
// technically cx, cy, and r could be added to "attrs" but keeping them as first class arguments
// makes it clear that they are important structural properties for the circle
this.cx = cx
this.cy = cy
this.r = r
const defaultAttrs = {
"stroke-width": "0.2px",
"stroke": "#000",
"fill": "none"
}
this.attrs = Object.assign({}, defaultAttrs, attrs)
}
draw() {
return `
<circle cx="${this.cx}" cy="${this.cy}" r="${this.r}"
${Object.entries(this.attrs).map(([key, value]) => `${key}="${value}"`).join(" ")}
/>
`
}
hasIntersection(other, padding = 0) {
return distance(this.cx, other.cx, this.cy, other.cy) < this.r + other.r + padding
}
static random({ xMin = 0, xMax = 100, yMin = 0, yMax = 56, rMin = 0.25, rMax = 5, attrs = {}} = {}) {
const cx = randomFloat(xMin, xMax)
const cy = randomFloat(yMin, yMax)
const r = randomFloat(rMin, rMax)
return new Circle(cx, cy, r, attrs)
}
}
Insert cell
Insert cell
randomFloat = (start = 0, end = 1) => Math.random() * (start - end) + end
Insert cell
randomInt = (start = 0, end = 10) => Math.round(randomFloat(start, end))
Insert cell
// credit: https://github.com/ramda/ramda/blob/c52096be3a2703ca2116e26771d00a880192c615/source/any.js
any = (fn, list) => {
var idx = 0;
while (idx < list.length) {
if (fn(list[idx])) {
return true;
}
idx += 1;
}
return false;
}
Insert cell
// two dimensional euclidean distance
// ref: https://en.wikipedia.org/wiki/Euclidean_distance
distance = (x1, x2, y1, y2) => Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
Insert cell
// default aspect ratio for viewBoxed SVGs
// reference: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio
aspectRatio = "xMidYMid meet"
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