0

ある点から別の点に引かれた線があります。線の端に円を追加して、線を移動できるようにします。

ただし、円を移動して線が更新されると、別の線が何らかの形で独自のポイントを更新しています。

前 (動きは画面の右側でのみ発生する必要があります): 前

後: 後

これがフィドルです: http://jsfiddle.net/Robodude/s86xc/1/

(何らかの理由で、jsフィドルのクロムで線が確実に描画されていません...ローカルでは正常に動作しますが、オンラインではFFでしか表示できません)

基本的な手順: 左のグリッドで、円をクリックします。2 番目の円をクリックします。ポイント間に線を引く必要があります。[Q を A にコピー] ボタンをクリックすると、右側のフレームに線が描画され、円の終点がドラッグできるようになります。

右側では、これは何が起こっているのかです:

1) 線は右側のグループに描画されます。

2) 線の端に円が描画されます。

3) 円には、その中心で開始/終了するすべての線への参照が与えられます

4) ドラッグすると、円は参照先の線を更新します。

私が知る限り、円には左側のパネルの行への参照がありません。

左側の線には「line」という名前が付けられ、右側の線 (円が参照している) には「line2」という名前が付けられます。

これが、円に線への参照を与える方法です。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;
}

では、なぜ右側の線の動きが左側の線に影響を与えるのでしょうか?

4

1 に答える 1

2

の場合は新しいKinetic.Lineオブジェクトを作成しますbuildLinesが、元の線のポイントをコピーanswerGroupせず、参照を渡します。

つまり、 でラインのポイントをanswerGroup変更すると、 で元のラインのポイントも変更されることになりlineGroupます。

さて、この直感に従うと、一般的な考え方は、で新しいを作成するときにポイントの配列をコピーすることline.points.slice()です。が常に数値の配列である場合、これは実際には機能しますが、次の 3 つのタイプにすることができます。Kinetic.LinebuildLinesline.points

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

したがって、回答グループに対して新しい行が作成されたときに、元の行から取得したポイントはすべてコピーであり、参照ではないことを確認する必要があります。これを実現する 1 つの方法は、maponを使用すること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
});
...

ここに作業バージョンがあります。

于 2013-05-24T05:09:39.093 に答える