My Problem
I'm attempting to create a metaball effect using Paper.js. While there's a metaball effect example on the Paper.js site (Metaball demo), it focuses on round shapes. My shapes, however, are irregular. I'm not sure how to achieve this effect with these shapes or if it's even feasible. I am not good enough in math that I could write a logical function that calculates the shape between objects.
While I'm aware I could use SVG filters for the desired result, this would rasterize the effect, and exporting as SVG would no longer be an option. The main reason for trying to create the meta-ball effect without effects is that the exported SVG should then work in every vector program Figma / Adobe Illustrator...
Here's a CodePen demo I've created. In this demo, you can move the shapes, and when the threshold is met, they connect with a straight line.
The primary function of interest is drawConnections, which establishes connections between two segment points. The Paper.js documentation for segments is available here. Some of these methods and properties might be useful for achieving the metaball effect.
The structure of the demo is like this:
init()Sets up the Paper.js and imports the SVG onto the canvas.onSvgLoad(item)This function performs initial setup tasks when an SVG is loaded such as scaling, adding to canvas, segment extraction, and setting up event listenersdrawLine(points, size): Creates and returns a simple path (line) using provided points.drawConnections(segments, threshold): Checks for nearby segments and draws connections between them based on a threshold distance.extractSegments(item, includeCounterClockwise): Extracts segments (points) from the provided SVG item. It can also be configured to exclude segments of paths that are counter-clockwise.getAllObjects(item): Retrieves all SVG objects (like paths, compound paths) from the provided item.addSegmentsToPath(item, add, includeCounterClockwise): Increases the number of segments in a given path or compound path based on the specified number (add).onDragStart(item, event): Determines which child path of the SVG was clicked on.onDrag(item, event): Moves the selected path based on drag events and redraws the connections.onDragEnd(item, event): Finalizes the drag operation, deselects the path, and updates the view.
Here is the main function drawConnections this function is called in the onDrag function:
....
function drawConnections(segments, threshold = 40) {
for (const segment of segments) {
for (const otherSegment of segments) {
if (segment === otherSegment) continue;
for (const seg of segment) {
for (const otherSeg of otherSegment) {
if (seg.point.getDistance(otherSeg.point) < threshold) {
const path = drawLine([seg.point, otherSeg.point], 4);
path.sendToBack();
path.removeOn({ drag: true, up: true });
}
}
}
}
}
}
....
Some extra demos I have created:
- In this demo each segment can only have one connection Demo.
- The meta-ball effect is created with an SVG filter Demo.
I am thankful for all the help I get.
Disclaimer: I'm no expert in paper.js at all, so there might be an even simpler solution.
What makes you think you can't use SVG filters with SVG? That's literally what they've been made for.
Since your filter is added through CSS over the canvas it's not surprising that paper.js can't export it, but you can very well just add it yourself to the exported
<svg>: