I have the following code:
const data = [
{ text: "Forage" },
{ text: "Fourndollar" },
// { text: 'Interiorndesign' },
// { text: 'Salviannormcore' },
// { text: 'Typewriter' },
// { text: 'Bicyclenrights' },
// { text: 'Try-hardnenamel' },
// { text: 'Grailed' },
// { text: 'Fingerstache' },
];
const canvas = document.getElementById("metaballs__canvas");
let circles = [];
let blob = null;
const random = (min, max) => Math.random() * (max - min) + min;
const orbitRadius = random(8, 16);
const orbitSpeed = random(0.001, 0.005);
paper.setup(canvas);
paper.view.autoUpdate = true;
blob = new paper.CompoundPath({
children: [],
strokeColor: "white"
});
const createCircles = (content, position) => {
const text = new paper.PointText({
point: position,
content: content,
fontFamily: "Instrument Sans",
fontWeight: "400",
fontSize: 24,
justification: "center",
fillColor: "white"
});
const circle = new paper.Path.Circle({
center: position,
radius: text.bounds.width / 2 + 48,
fillColor: "transparent"
});
const group = new paper.Group([text, circle]);
group.onMouseDrag = (event) => {
group.position = group.position.add(event.delta);
};
circles.push({
group: group,
circle: circle,
text: text,
angle: random(0, 360),
center: position,
orbitRadius: orbitRadius,
orbitSpeed: orbitSpeed
});
};
const createBlob = () => {
blob.removeChildren();
const unitedPath = circles.reduce((acc, {
circle
}) => {
if (acc) return acc.unite(circle);
else return circle;
}, null);
if (unitedPath) blob.addChild(unitedPath);
};
const animateCircles = () => {
circles.forEach(
({
group,
circle,
text,
angle,
center,
orbitRadius,
orbitSpeed
},
index
) => {
angle += orbitSpeed;
const x = center.x + orbitRadius * Math.cos(angle);
const y = center.y + orbitRadius * Math.sin(angle);
circle.position = new paper.Point(x, y);
text.position = new paper.Point(x, y);
group.position = new paper.Point(x, y);
circles[index].angle = angle;
}
);
};
data.forEach((item) => {
createCircles(
item.text,
new paper.Point(
random(0, paper.view.bounds.width),
random(0, paper.view.bounds.height)
)
);
});
paper.view.onFrame = (event) => {
createBlob();
// animateCircles();
};
paper.view.update();
@import url("https://fonts.googleapis.com/css2?family=Instrument+Sans:ital,wght@0,400..700;1,400..700&display=swap");
#metaballs {
padding: 32px;
}
#metaballs__canvas {
position: relative;
border-radius: 8px;
width: 640px;
aspect-ratio: 16 / 9;
overflow: hidden;
background-color: hsla(0, 0%, 0%, 1);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.18/paper-full.min.js"></script>
<div id="metaballs">
<canvas id="metaballs__canvas"></canvas>
</div>
With 2 items, it works fine. However, whenever I uncomment more items, I encounter performance issues, probably caused by the compound path creation on every frame. Is there a more sophisticated solution for this?
I also want to smooth out the connections of the circles. I found a plugin called paperjs-round-corners
, but it’s really buggy when applied to the segments. An example of what I’m aiming for is the option in Adobe Illustrator where you unite two circles, select the path, and apply a corner radius operation.