web-dev-qa-db-ja.com

Raphael JavaScriptライブラリでオブジェクトを組み合わせるにはどうすればよいですか?

長い質問で申し訳ありませんが、ここに行きます。私はここでデモの周りのドラッグ形状を変更しようとしています:

http://raphaeljs.com/graffle.html

デモは正常に動作します。私がやりたいのは、単語を図形の中に入れ、図形とテキストを単一の複合オブジェクトとして移動することです。

オブジェクトを作成するためのコードは次のとおりです。

window.onload = function () {
    var dragger = function () {
        this.ox = this.type == "rect" ? this.attr("x") : this.attr("cx");
        this.oy = this.type == "rect" ? this.attr("y") : this.attr("cy");
        this.animate({"fill-opacity": .2}, 500);
    },
        move = function (dx, dy) {
            var att = this.type == "rect" ? {x: this.ox + dx, y: this.oy + dy} : {cx: this.ox + dx, cy: this.oy + dy};
            this.attr(att);
            for (var i = connections.length; i--;) {
                r.connection(connections[i]);
            }
            r.safari();
        },
        up = function () {
            this.animate({"fill-opacity": 0}, 500);
        },
        r = Raphael("holder", 640, 480),
        connections = [],
        shapes = [  r.ellipse(190, 100, 30, 20),
                    r.rect(290, 80, 60, 40, 10),
                    r.rect(290, 180, 60, 40, 2),
                    r.ellipse(450, 100, 20, 20)
                ];
    for (var i = 0, ii = shapes.length; i < ii; i++) {
        var color = Raphael.getColor();
        shapes[i].attr({fill: color, stroke: color, "fill-opacity": 0, "stroke-width": 2, cursor: "move"});
        shapes[i].drag(move, dragger, up);
    }
    connections.Push(r.connection(shapes[0], shapes[1], "#fff"));
    connections.Push(r.connection(shapes[1], shapes[2], "#fff", "#fff|5"));
    connections.Push(r.connection(shapes[1], shapes[3], "#000", "#fff"));
};

私はこのようなものを試しました:

 myWords = [ r.text(190, 100,  "Hello"),
      r.text(480,100, "Good Bye")
    ];

それが機能するように他の場所で調整を行いましたが、テキストと形状を移動するだけで、形状とテキストが全体として表示されることはありません。テキストを図形から分離したり、その逆を行ったりできます。それらを1つのオブジェクトにする必要があります。一緒に移動します。どうやってやるの?助けてくれてありがとう.

編集:

私はこれを試しました:

  st.Push(r.text (190, 100, "node1"), r.ellipse(190, 100, 30, 20)),
  st.Push(r.text (290, 80, "Center"), r.rect(290, 80, 60, 40, 10)),
  st.Push(r.text (290, 180, "node2"), r.rect(290, 180, 60, 40, 2)),
  st.Push(r.text (450, 100, "node3"), r.ellipse(450, 100, 20, 20))

ただし、図形を移動すると、テキストと図形が一緒に表示されません。テキストはそのまま残りました。

編集: http://raphaeljs.com/graffle.html でストックデモを取得できず、Chromeで動作しません。 IE動作します。

43
johnny

大幅に編集して、要素をよりエレガントな方法で関連付けました。


SetsはRaphaelオブジェクトをグループ化するのに適していますが、セットは独自の要素を作成しないため、ドラッグできませんそして、セットをドロップします。キャンバスをクリックすると、形状またはテキストのいずれかを選択しますが、セットは選択しません(セット要素がないため)。

これは、セットのプロパティを示す簡単なjsFiddleです。セットにはxまたはyプロパティ。

Raphaelのドキュメントから:

[セットc]は、配列のようなオブジェクトを作成して、いくつかの要素を同時に保持および操作します。 警告:ページ内にそれ自体の要素は作成されません。


簡単な回避策は、テキストと図形の両方を個別にドラッグ可能にすることです。次に、関連付けられているテキストを図形と一緒に移動します...関連する図形をテキストと一緒に移動します。

このようなオブジェクトの関連付けは簡単です...プロパティを作成します。この場合、各図形と各テキストには、関連する要素への参照である_.pair_というプロパティがあります。

方法は次のとおりです。

_var i, ii, tempS, tempT
     shapes = [  ... ],
     texts = [  ... ];
for (i = 0, ii = shapes.length; i < ii; i++) {
    tempS = shapes[i].attr( ... );
    tempT = texts[i].attr( ...);

      // Make all the shapes and texts dragable
    shapes[i].drag(move, dragger, up);
    texts[i].drag(move, dragger, up);

      // Associate the elements
    tempS.pair = tempT;
    tempT.pair = tempS;
}
_

次に、ドラッグアンドドロップコードで、move()dragger()、およびup()関数を使用して、クリックされた要素の両方を処理する必要があります。とその関連要素。

たとえば、以下はmove()関数の関連部分です。 textrectangleと同じ方法で(属性xyを変更することで)処理できるため、false以下の各Javascript条件演算子の条件は、rectangletextの両方のケースを処理します

_move = function (dx, dy) {

      // Move main element
    var att = this.type == "ellipse" ? 
                           {cx: this.ox + dx, cy: this.oy + dy} : 
                           {x: this.ox + dx, y: this.oy + dy};
    this.attr(att);

      // Move paired element
    att = this.pair.type == "ellipse" ? 
                            {cx: this.pair.ox + dx, cy: this.pair.oy + dy} : 
                            {x: this.pair.ox + dx, y: this.pair.oy + dy};
    this.pair.attr(att);
    ...
}
_


そして、以下は完全に機能するコードです:

ドラッグ可能なテキストと形状のjsFiddleの例

_Raphael.fn.connection = function (obj1, obj2, line, bg) {
    if (obj1.line && obj1.from && obj1.to) {
        line = obj1;
        obj1 = line.from;
        obj2 = line.to;
    }
    var bb1 = obj1.getBBox(),
        bb2 = obj2.getBBox(),
        p = [{x: bb1.x + bb1.width / 2, y: bb1.y - 1},
        {x: bb1.x + bb1.width / 2, y: bb1.y + bb1.height + 1},
        {x: bb1.x - 1, y: bb1.y + bb1.height / 2},
        {x: bb1.x + bb1.width + 1, y: bb1.y + bb1.height / 2},
        {x: bb2.x + bb2.width / 2, y: bb2.y - 1},
        {x: bb2.x + bb2.width / 2, y: bb2.y + bb2.height + 1},
        {x: bb2.x - 1, y: bb2.y + bb2.height / 2},
        {x: bb2.x + bb2.width + 1, y: bb2.y + bb2.height / 2}],
        d = {}, dis = [];
    for (var i = 0; i < 4; i++) {
        for (var j = 4; j < 8; j++) {
            var dx = Math.abs(p[i].x - p[j].x),
                dy = Math.abs(p[i].y - p[j].y);
            if ((i == j - 4) || (((i != 3 && j != 6) || p[i].x < p[j].x) && ((i != 2 && j != 7) || p[i].x > p[j].x) && ((i != 0 && j != 5) || p[i].y > p[j].y) && ((i != 1 && j != 4) || p[i].y < p[j].y))) {
                dis.Push(dx + dy);
                d[dis[dis.length - 1]] = [i, j];
            }
        }
    }
    if (dis.length == 0) {
        var res = [0, 4];
    } else {
        res = d[Math.min.apply(Math, dis)];
    }
    var x1 = p[res[0]].x,
        y1 = p[res[0]].y,
        x4 = p[res[1]].x,
        y4 = p[res[1]].y;
    dx = Math.max(Math.abs(x1 - x4) / 2, 10);
    dy = Math.max(Math.abs(y1 - y4) / 2, 10);
    var x2 = [x1, x1, x1 - dx, x1 + dx][res[0]].toFixed(3),
        y2 = [y1 - dy, y1 + dy, y1, y1][res[0]].toFixed(3),
        x3 = [0, 0, 0, 0, x4, x4, x4 - dx, x4 + dx][res[1]].toFixed(3),
        y3 = [0, 0, 0, 0, y1 + dy, y1 - dy, y4, y4][res[1]].toFixed(3);
    var path = ["M", x1.toFixed(3), y1.toFixed(3), "C", x2, y2, x3, y3, x4.toFixed(3), y4.toFixed(3)].join(",");
    if (line && line.line) {
        line.bg && line.bg.attr({path: path});
        line.line.attr({path: path});
    } else {
        var color = typeof line == "string" ? line : "#000";
        return {
            bg: bg && bg.split && this.path(path).attr({stroke: bg.split("|")[0], fill: "none", "stroke-width": bg.split("|")[1] || 3}),
            line: this.path(path).attr({stroke: color, fill: "none"}),
            from: obj1,
            to: obj2
        };
    }
};

var el;
window.onload = function () {
    var color, i, ii, tempS, tempT,
        dragger = function () {
                // Original coords for main element
            this.ox = this.type == "ellipse" ? this.attr("cx") : this.attr("x");
            this.oy = this.type == "ellipse" ? this.attr("cy") : this.attr("y");
            if (this.type != "text") this.animate({"fill-opacity": .2}, 500);

                // Original coords for pair element
            this.pair.ox = this.pair.type == "ellipse" ? this.pair.attr("cx") : this.pair.attr("x");
            this.pair.oy = this.pair.type == "ellipse" ? this.pair.attr("cy") : this.pair.attr("y");
            if (this.pair.type != "text") this.pair.animate({"fill-opacity": .2}, 500);            
        },
        move = function (dx, dy) {
                // Move main element
            var att = this.type == "ellipse" ? {cx: this.ox + dx, cy: this.oy + dy} : 
                                               {x: this.ox + dx, y: this.oy + dy};
            this.attr(att);

                // Move paired element
            att = this.pair.type == "ellipse" ? {cx: this.pair.ox + dx, cy: this.pair.oy + dy} : 
                                               {x: this.pair.ox + dx, y: this.pair.oy + dy};
            this.pair.attr(att);            

                // Move connections
            for (i = connections.length; i--;) {
                r.connection(connections[i]);
            }
            r.safari();
        },
        up = function () {
                // Fade original element on mouse up
            if (this.type != "text") this.animate({"fill-opacity": 0}, 500);

                // Fade paired element on mouse up
            if (this.pair.type != "text") this.pair.animate({"fill-opacity": 0}, 500);            
        },
        r = Raphael("holder", 640, 480),
        connections = [],
        shapes = [  r.ellipse(190, 100, 30, 20),
                    r.rect(290, 80, 60, 40, 10),
                    r.rect(290, 180, 60, 40, 2),
                    r.ellipse(450, 100, 20, 20)
                ],
        texts = [   r.text(190, 100, "One"),
                    r.text(320, 100, "Two"),
                    r.text(320, 200, "Three"),
                    r.text(450, 100, "Four")
                ];
    for (i = 0, ii = shapes.length; i < ii; i++) {
        color = Raphael.getColor();
        tempS = shapes[i].attr({fill: color, stroke: color, "fill-opacity": 0, "stroke-width": 2, cursor: "move"});
        tempT = texts[i].attr({fill: color, stroke: "none", "font-size": 15, cursor: "move"});
        shapes[i].drag(move, dragger, up);
        texts[i].drag(move, dragger, up);

        // Associate the elements
        tempS.pair = tempT;
        tempT.pair = tempS;
    }
    connections.Push(r.connection(shapes[0], shapes[1], "#fff"));
    connections.Push(r.connection(shapes[1], shapes[2], "#fff", "#fff|5"));
    connections.Push(r.connection(shapes[1], shapes[3], "#000", "#fff"));
};​
_

完全を期すために、のコードは、setのプロパティを表示するためにjsFiddleにリンクされています。

_window.onload = function () {
    var paper = Raphael("canvas", 320, 200),
        st = paper.set(), 
        propArr = [];

    st.Push(
        paper.circle(10, 10, 5),
        paper.circle(30, 10, 5)
    );

    st.attr({fill: "red"});

    for(var prop in st) {
        if (st.hasOwnProperty(prop)) {
            // handle prop as required
            propArr.Push(prop + " : " + st[prop]);
        }
    }
    alert(propArr.join("\n"));
};​

// Output:
// 0 : Raphael's object
// 1 : Raphael's object
// items : Raphael's object,Raphael's object
// length : 2
// type : set
_
55
Peter Ajtai

または、適切なSVGグループ要素を作成できるRaphaelのこの「グループ」プラグインを試してください。

https://github.com/rhyolight/Raphael-Plugins/blob/master/raphael.group.js

7
Ben Bederson

はい、それがsetオブジェクトの目的です。

var myWords = r.set();
myWords.Push(
    r.text(190, 100, "Hello"),
    r.text(480,100, "Good Bye"
);

// now you can treat the set as a single object:
myWords.rotate(90);

追加回答:

OK、私はあなたがsetを使用しようとしたが、それを間違って使用しているようです。セットは物事のグループを作成します。 Adobe Illustrator、Inkscape、Microsoft Word、またはOpen Officeで図形やテキストをグループ化する場合と同じです。私があなたを正しく理解しているなら、あなたが望むものはこれです:

shapes = [  r.set(r.text (190, 100, "node1"), r.ellipse(190, 100, 30, 20)),
            r.set(r.text (290, 80, "Center"), r.rect(290, 80, 60, 40, 10)),
            r.set(r.text (290, 180, "node2"), r.rect(290, 180, 60, 40, 2)),
            r.set(r.text (450, 100, "node3"), r.ellipse(450, 100, 20, 20))
         ];

また、形状は「rect」タイプではなく「set」タイプであるため、ドラッガと移動関数を変更する必要があります。

var dragger = function () {
    this.ox = this.attr("x");
    this.oy = this.attr("y");
    this.animate({"fill-opacity": .2}, 500);
};
var move = function (dx, dy) {
    var att = {x: this.ox + dx, y: this.oy + dy};
    this.attr(att);
    for (var i = connections.length; i--;) {
        r.connection(connections[i]);
    }
    r.safari();
};

すべてのセットにはxおよびy属性があります。

4
slebetman

メインオブジェクトがドラッグされたときに変化する属性に加えて、ペアのオブジェクトの属性を変更する方が簡単ではないでしょうか。

このようなもの:

window.onload = function () {
        var R = Raphael("holder"),
            circ = R.circle(100, 100, 50).attr({ "fill": "#d9d9d9", "stroke-width": 1 }),
        circ2 = R.circle(50, 50, 5),
            start = function () {
                this.ox = this.attr("cx"); //ox = original x value
                this.oy = this.attr("cy");
                this.animate({ "opacity": .5, "stroke-width": 15 }, 200);
            },
            move = function (dx, dy) {  //dx - delta x - diiference in movement between point a and b
                var cdx = circ2.attr("cx") - this.attr("cx"),
                    cdy = circ2.attr("cy") - this.attr("cy");
                this.attr({ "cx": this.ox + dx, "cy": this.oy + dy });
                group(this,circ2,cdx,cdy);
                R.safari();
            },
            up = function () {
                this.animate({ "opacity": 1, "stroke-width": 1 }, 200);
            },
            group = function (refObj,thisObj, dx, dy) {                    
                thisObj.attr({ "cx": refObj.attr("cx") + dx, "cy": refObj.attr("cy") + dy });
            };

            circ.drag(move, start, up);




    };
1