PaperJS — Как соединить все элементы, которые находятся на расстоянии X от любого заданного элемента? (Интерактивность элемента)

У меня есть проект, в котором я пытаюсь заставить анимированный <canvas> работать с Paper JS. Что мне интересно, так это то, есть ли что-то встроенное в PaperJS, которое позволяет обнаруживать интерактивность между элементами (т.е. если элемент находится на расстоянии X от любого другого элемента на слое). Вот что у меня есть до сих пор:

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

Эта часть пока работает хорошо. Что мне интересно, как я могу сделать следующее:

Всякий раз, когда любой заданный элемент (квадраты) находится на расстоянии X друг от друга, создайте линию (путь) между ними

Идея очень похожа на эту страницу: http://panasonic.jp/shaver/lamdash/dna/< /а>

Любые идеи очень приветствуются. Спасибо!


person Fillip Peyton    schedule 16.08.2013    source источник


Ответы (1)


Paper.js не отслеживает межточечное расстояние между центром элемента и всеми остальными элементами. Единственный способ собрать эту информацию — просмотреть их вручную.

В вашем случае, я думаю, было бы проще:

  1. Создайте массив строк
  2. Сохраняйте только те строки, которые могут стать короче порогового значения.
  3. Прокрутите массив строк на каждом onFrame() и отрегулируйте непрозрачность.

Выбирая только линии, которые будут находиться в пределах порогового значения, вы можете избежать создания ненужных путей, которые замедлят частоту кадров. Без этого вы бы проверяли примерно в 5 раз больше элементов.

Вот краткий пример:

$(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;
                }
            }


});
person Alex Blackwood    schedule 16.08.2013
comment
Отличные предложения! Спасибо! - person Fillip Peyton; 17.08.2013