Перетаскивание фигуры в kinetic js также перемещает несвязанную фигуру

У меня есть линия, идущая от одной точки к другой. Я добавляю круги на концах линии, что позволяет перемещать линию.

Однако, когда я перемещаю круг и линия обновляется, другая линия каким-то образом обновляет свои собственные точки.

Раньше (движение должно происходить только в правой части экрана): before

После: после

Вот скрипка: http://jsfiddle.net/Robodude/s86xc/1/

(По какой-то причине линии не отображаются надежно в chrome на js fiddle ... он отлично работает локально, но в Интернете я могу показать их только на FF)

Основные инструкции: в левой сетке щелкните кружок. Щелкните второй кружок. Между точками должна быть проведена линия. Нажмите кнопку «Копировать Q в A», и линия должна быть нарисована в правом кадре с конечными точками круга, которые можно перемещать.

Справа вот что происходит:

1) Линии рисуются в правой группе.

2) На концах линий рисуются кружки.

3) Кружкам даются ссылки на все линии, которые начинаются / заканчиваются в их центре.

4) При перетаскивании кружки обновляют линии, на которые они ссылаются.

Насколько я могу судить, кружки не имеют ссылок на линии на левой боковой панели.

Левые боковые линии имеют имя "линия", а правые боковые линии (на которые есть ссылки в кружке) имеют имя "линия2".

Вот как я даю кружкам ссылки на линии. Если круг в координатах x, y уже существует, переместите линию к его свойству connectedLines.

var circleTest = circleGroup.get("." + point.x + ", " + point.y)[0];
if (circleTest == null) {
    var circle = new Kinetic.Circle({
        name: (point.x) + ", " + (point.y),
        x: point.x,
        y: point.y,
        radius: answer ? 15 : 10,
        stroke: "rgba(0,0,0,1)",
        strokeWidth: "3",
        fill: "rgba(255, 255, 255, 1)",
        connectedLines: [line],
        draggable: answer ? false: true,
        oldX: point.x,
        oldY: point.y,
        dragBoundFunc: answer ? null : function (pos) {
            var x = pos.x;
            var y = pos.y;

            var newPos = { x: x - offset.x, y: y - offset.y };

            updateAttachedLines(newPos, this);

            return {
                x: x,
                y: y
            }
        }
    });

    circle.on("click", function () {
        console.log(this.attrs.connectedLines);
    });

    circleGroup.add(circle);
}
else {
    circleTest.attrs.connectedLines.push(line);
}

Вот как выглядит updateAttachedLines:

function updateAttachedLines(pos, circle)
{
    var x = pos.x;
    var y = pos.y;
    var ox = circle.attrs.oldX;
    var oy = circle.attrs.oldY;

    var cls = circle.attrs.connectedLines;

    for (var i = 0; i < cls.length; i++) {
        var cl = cls[i];
        console.log(cl.attrs.name);
        var points = cl.getPoints();

        var newPoints = [];
        for (var n = 0; n < points.length; n++) {
            var point = points[n];

            if ((point.x == ox) && (point.y == oy)) {
                point.x = x;
                point.y = y;
            }

            newPoints.push(point);
        }

        cl.setPoints(newPoints);
    }

    circle.parent.parent.draw();

    circle.attrs.oldX = x;
    circle.attrs.oldY = y;
}

Так почему же движение в правой боковой линии влияет на левую боковую линию?


person RoboKozo    schedule 23.05.2013    source источник


Ответы (1)


Даже если вы создаете новый Kinetic.Line объект, когда buildLines для answerGroup, вы не копируете точки исходной линии, а скорее передаете ссылку.

Это означает, что при изменении точек линии в answerGroup вы в конечном итоге также измените точки исходной линии в lineGroup.

Теперь, следуя этой интуиции, общая идея состоит в том, чтобы скопировать массив точек с помощью line.points.slice() при создании нового Kinetic.Line в buildLines. Это действительно сработало бы, если бы line.points всегда был массивом чисел, но он может быть трех типов:

points: [Number, Number, Number, ...]
or
points: [Array, Array, Array, ...]
or
points: [Object, Object, Object, ...]

Итак, теперь необходимо убедиться, что при создании новой строки для группы ответов все точки, которые она получает из исходной строки, являются копиями, а не ссылками. Один из способов добиться этого - использовать map на line.points.

Пусть обратный вызов будет:

var _copyPts = function(e, i, a) {
    if(e instanceof Array) {
        return e.slice();
    }
    else if(e instanceof Object) {
        var r = {};
        for(var k in e) {
            if(e.hasOwnProperty(k)) r[k] = e[k];
        }
        return r;
    }

    return e;
};

И изменение buildLines будет:

...
var lineShape = new Kinetic.Line({
    id: "l" + i,
    name: "line2",
    stroke: answer ? "rgba(000,000,000,1)" : line.color,
    strokeWidth: answer ? 8 : 5,
    points: line.points.map(_copyPts),     //<--- change here
    dashArray: answer ? [10, 5] : null
});
...

Вот рабочая версия.

person Misguided    schedule 24.05.2013
comment
+1 Хороший улов! Напоминает мне старые добрые / плохие старые времена программирования на Silverlight, когда в некоторых коллекциях ключей неожиданно не было метода клонирования. - person markE; 24.05.2013
comment
Большое спасибо - отлично работает. Я не слишком хорошо знаком с .map, поэтому займусь этим позже сегодня :) - person RoboKozo; 24.05.2013