Question

I'm trying to customize the metaballs example from Paperjs (http://paperjs.org/examples/meta-balls/). Problem is, that even copy-pasting it, it won't work. It does not draw/display the "bridges" between the balls.

Here's a jsFiddle: http://jsfiddle.net/AK47p/

And here's the code:

$(document).ready(function () {

    // Get a reference to the canvas object
    var canvas = document.getElementById('canvas');
    // Create an empty project and a view for the canvas:
    paper.setup(canvas);
    // Create a simple drawing tool:
    var tool = new paper.Tool();

    // Ported from original Metaball script by SATO Hiroyuki
    // http://park12.wakwak.com/~shp/lc/et/en_aics_script.html
    paper.project.currentStyle = {
        fillColor: 'black'
    };

    var ballPositions = [[255, 129], [610, 73], [486, 163],
        [117, 259], [484, 326], [843, 306], [789, 215], [949, 82],
        [292, 128], [917, 233], [352, 86], [92, 98]];

    var handle_len_rate = 2.4;
    var circlePaths = [];
    var radius = 50;
    for (var i = 0, l = ballPositions.length; i < l; i++) {
        var circlePath = new paper.Path.Circle({
            center: ballPositions[i],
            radius: 50
        });
        circlePaths.push(circlePath);
    }

    var largeCircle = new paper.Path.Circle({
        center: paper.view.center,
        radius: 100,
        fillColor: 'green'
    });
    circlePaths.push(largeCircle);

    tool.onMouseMove = function(event) {
        largeCircle.position = event.point;
        generateConnections(circlePaths);
    }

    var connections = new paper.Group(); var thePath;
    function generateConnections(paths) {
        // Remove the last connection paths:
        connections.children = [];

        for (var i = 0, l = paths.length; i < l; i++) {
            for (var j = i - 1; j >= 0; j--) {
                var path = metaball(paths[i], paths[j], 0.5, handle_len_rate, 300);thePath = path;
                if (path) {
                    connections.appendTop(path);
                    path.removeOnMove();
                }
            }
        }
    }

    generateConnections(circlePaths);

    // ---------------------------------------------
    function metaball(ball1, ball2, v, handle_len_rate, maxDistance) {
        var center1 = ball1.position;
        var center2 = ball2.position;
        var radius1 = ball1.bounds.width / 2;
        var radius2 = ball2.bounds.width / 2;
        var pi2 = Math.PI / 2;
        var d = center1.getDistance(center2);
        var u1, u2;

        if (radius1 == 0 || radius2 == 0)
            return;

        if (d > maxDistance || d <= Math.abs(radius1 - radius2)) {
            return;
        } else if (d < radius1 + radius2) { // case circles are overlapping
            u1 = Math.acos((radius1 * radius1 + d * d - radius2 * radius2) /
                    (2 * radius1 * d));
            u2 = Math.acos((radius2 * radius2 + d * d - radius1 * radius1) /
                    (2 * radius2 * d));
        } else {
            u1 = 0;
            u2 = 0;
        }

        var angle1 = center2.subtract(center1).getAngleInRadians();
        var angle2 = Math.acos((radius1 - radius2) / d);
        var angle1a = angle1 + u1 + (angle2 - u1) * v;
        var angle1b = angle1 - u1 - (angle2 - u1) * v;
        var angle2a = angle1 + Math.PI - u2 - (Math.PI - u2 - angle2) * v;
        var angle2b = angle1 - Math.PI + u2 + (Math.PI - u2 - angle2) * v;
        var p1a = center1 + getVector(angle1a, radius1);
        var p1b = center1 + getVector(angle1b, radius1);
        var p2a = center2 + getVector(angle2a, radius2);
        var p2b = center2 + getVector(angle2b, radius2);

        // define handle length by the distance between
        // both ends of the curve to draw
        var totalRadius = (radius1 + radius2);
        var d2 = Math.min(v * handle_len_rate, (p1a - p2a).length / totalRadius);

        // case circles are overlapping:
        d2 *= Math.min(1, d * 2 / (radius1 + radius2));

        radius1 *= d2;
        radius2 *= d2;

        var path = new paper.Path({
            segments: [p1a, p2a, p2b, p1b],
            style: ball1.style,
            closed: true
        });
        var segments = path.segments;
        segments[0].handleOut = getVector(angle1a - pi2, radius1);
        segments[1].handleIn = getVector(angle2a + pi2, radius2);
        segments[2].handleOut = getVector(angle2b - pi2, radius2);
        segments[3].handleIn = getVector(angle1b + pi2, radius1);
        return path;
    }

    // ------------------------------------------------
    function getVector(radians, length) {
        return new paper.Point({
            // Convert radians to degrees:
            angle: radians * 180 / Math.PI,
            length: length
        });
    }
});

As you can see I wrapped the code in a domReady function, as that is going to be part of a slideshow. I followed the instructions here (http://paperjs.org/tutorials/getting-started/using-javascript-directly/) to do this. Any idea what is wrong? I checked over and over, I must be missing something...

Thank you

Was it helpful?

Solution

Found out what was missing. It is not very well documented on Paperjs, anyway if you use it like regular javascript make sure all operations on paper objects (Point, Path etc.) are expressed as methods, instead of as operators.

wrong

var d2 = Math.min(v * handle_len_rate, (point1a - point2a).length / totalRadius);

right

var d2 = Math.min(v * handle_len_rate, point1a.subtract(point2a).length / totalRadius);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top