我喜欢日本艺术家Yayoi Kusama的作品,并且很长一段时间都想制作她著名的点的互动海报。
尽管我父亲是一位退休的数学老师,但我只是 超简单的“圆包装”算法,所以我最终做了更简单的事情:
function kusamaDots(
numDots,
minRadius,
maxRadius,
width,
height
) {
const dots = [];
function createDot() {
const x = Math.floor(Math.random() * width);
const y = Math.floor(Math.random() * height);
const radius =
Math.random() * (maxRadius - minRadius) + minRadius;
const dot = { radius, x, y };
if (!dots.some((c) => intersects(dot, c))) {
return dot;
}
return null;
}
while (dots.length < numDots) {
const dot = createDot();
if (dot !== null) dots.push(dot);
}
return dots;
}
参数为:
-
numDots
。点总数。 -
minRadius
。点的最小半径。 -
maxRadius
。点的最大半径。 -
“ canvas”(SVG ViewBox)的
width
。 -
相同的
height
。
createDot
方法在viewBox
的边界内创建一个随机的x
和y
-position。它在minRadius
和maxRadius
的值之间设置一个随机半径。
它创建一个dot
-object,然后检查点是否与任何其他点(已经创建的点)相交。为此,我们需要一个小型帮助者:
function intersects(first, second) {
const dx = first.x - second.x;
const dy = first.y - second.y;
const distance = Math.sqrt(dx * dx + dy * dy);
const sumOfRadii = first.radius + second.radius;
return distance <= sumOfRadii;
}
如果DOT与任何其他点相交 ,则为return
。
之后,while
循环运行直到达到numDots
。
to output dots,我们只需在svg中创建<circle>
s:
const dots = kusamaDots(
e.target.valueAsNumber,
10,
150,
1000,
1000
);
svg.innerHTML = dots
.map(
(dot) =>
`<circle r="${dot.radius}" cx="${dot.x}" cy="${dot.y}"></circle>`
)
.join("")
CSS
CSS非常简单。框架和响应式文本类似于The Moon in 10241 Dots。
最重要的部分是用于点颜色的自定义属性(如fill
)!
但是,我决定做一个自定义的范围滑块和一个颜色挑剔的作为海报的一部分,从而使其成为交互式海报:
你能发现它们吗?!
拖拉滑块,然后单击颜色挑选以制作自己的海报:
演示