Question

I have a project I am trying to get an animated <canvas> working with Paper JS. What I am curious about is if there is anything built into PaperJS that allows the ability to detect interactivity between items (i.e. if a item is X distance from any other item on the layer). Here is what I have so far:

HTML

<canvas id="myCanvas" resize></canvas>

CSS

html, body{margin:0; padding: 0;}
#myCanvas{width: 100%; height: 100%;}

JS

$(function(){
    var canvas = $('#myCanvas')[0];
    paper.setup(canvas);
    var viewSize = paper.view.size;
    var itemCount = 20;

    var theBall = new paper.Path.Rectangle({
        point : [0,0],
        size : 10,
        fillColor : '#00a950',
    });
    var theBallSymbol = new paper.Symbol(theBall);

    // Create and place symbol on view
    for (var i = 1; i <= itemCount; i++) {
        var center = paper.Point.random().multiply(viewSize);
        var placedSymbol = theBallSymbol.place(center);
        placedSymbol.scale(i / itemCount);
        placedSymbol.data = {
            origin : center,
            direction : (Math.round(Math.random())) ? 'right' : 'left',
        }
        placedSymbol.onFrame = function(e){
            var pathWidth = this.bounds.width * 20;
            var center = this.data.origin;
            var moveValue = this.bounds.width / 20;

            if(this.data.direction == 'right'){
                if(this.position.x < center.x + pathWidth){
                    this.position.x += moveValue;
                } else{
                    this.position.x -= moveValue;
                    this.data.direction = 'left';                       
                }
            } else {
                if(this.position.x > center.x - pathWidth){
                    this.position.x -= moveValue;
                } else {
                    this.position.x += moveValue;
                    this.data.direction = 'right';                      
                }
            }       
        }
    }

    paper.view.onFrame = function (e){
        // For entire view
        for (var i = 0; i < itemCount; i++) {
            var item = paper.project.activeLayer.children[i];

            // I imagine I would need to do something here
            // I tried a hitTest already, but I'm not sure
            // that will give me the information I would need
        }
    }
});

JSFiddle

That part so far is working well. What I am curious about how I can do the following:

Whenever any given item (the squares) come within a distance of X between each other, create a line (path) between them

The idea is very similar to this page: http://panasonic.jp/shaver/lamdash/dna/

Any ideas would be greatly appreciated. Thanks!

Was it helpful?

Solution

Paper.js does not keep track of the inter-point distance between an item's center and all other items. The only way to gather that information is to manually loop through them.

In your case, I think it would be easiest to:

  1. Create an array of lines
  2. Only keep lines that might become shorter than the threshold value
  3. Loop through the lines array on each onFrame() and adjust the opacity.

By only choosing lines that will come within a threshold value, you can avoid creating unnecessary paths that would slow the framerate. Without this, you'd be checking ~5 times as many items.

Here's a quick example:

$(function(){
    var canvas = $('#myCanvas')[0];
    paper.setup(canvas);
    var viewSize = paper.view.size;
    var itemCount = 60;

    //setup arrays to change line segments
    var ballArray = [];
    var lineArray = [];

    //threshold distance for lines
    var threshold = Math.sqrt(paper.view.size.width*paper.view.size.height)/5;

    var theBall = new paper.Path.Rectangle({
        point : [0,0],
        size : 10,
        fillColor : '#00a950',
    });
    var theBallSymbol = new paper.Symbol(theBall);

    // Create and place symbol on view
    for (var i = 1; i <= itemCount; i++) {
        var center = paper.Point.random().multiply(viewSize);
        var placedSymbol = theBallSymbol.place(center);
        placedSymbol.scale(i / itemCount);
        placedSymbol.data = {
            origin : center,
            direction : (Math.round(Math.random())) ? 'right' : 'left',
        }

        // Keep each placedSymbol in an array
        ballArray.push( placedSymbol );

        placedSymbol.onFrame = function(e){
            var pathWidth = this.bounds.width * 20;
            var center = this.data.origin;
            var moveValue = this.bounds.width / 20;

            if(this.data.direction == 'right'){
                if(this.position.x < center.x + pathWidth){
                    this.position.x += moveValue;
                } else{
                    this.position.x -= moveValue;
                    this.data.direction = 'left';                       
                }
            } else {
                if(this.position.x > center.x - pathWidth){
                    this.position.x -= moveValue;
                } else {
                    this.position.x += moveValue;
                    this.data.direction = 'right';                      
                }
            }       
        }
    }

    // Run through every possible line
    // Only keep lines whose length might become less than threshold
    for (var i = 0; i < itemCount; i++) {

        for (j = i + 1, point1 = ballArray[i].data.origin; j < itemCount; j++) {

            if ( Math.abs(point1.y - ballArray[j].bounds.center.y) < threshold && Math.abs(point1.x - ballArray[j].data.origin.x) < 4 * threshold) {

                var line = new paper.Path.Line( point1, ballArray[j].bounds.center ) ;
                line.strokeColor = 'black';
                line.strokeWidth = .5;

                //note the index of the line's segments
                line.point1 = i;
                line.point2 = j;

                if (line.length > 1.4 * threshold && ballArray[j].data.direction == ballArray[i].data.direction) {
                    line.remove();
                }
                else {
                    lineArray.push(line);
                }
            }
        }
    }

    paper.view.onFrame = function (e){

        // Update the segments of each line
        // Change each line's opacity with respect to distance

        for (var i = 0, l = lineArray.length; i < l; i++) {
                    var line = lineArray[i];
                    line.segments[0].point = ballArray[line.point1].bounds.center;
                    line.segments[1].point = ballArray[line.point2].bounds.center;
                    if(line.length < threshold) {
                        line.opacity = (threshold - line.length) / threshold;
                    }
                    else line.opacity = 0;
                }
            }


});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top