web-dev-qa-db-fra.com

Comment puis-je combiner des objets dans la bibliothèque javascript de Raphael?

Désolé pour une longue question, mais voilà. J'essaie de modifier les formes de glissement autour de la démo ici:

http://raphaeljs.com/graffle.html

La démo fonctionne bien. Ce que je veux faire, c'est mettre des mots à l'intérieur des formes et déplacer la forme et le texte comme un objet composite unique.

Voici le code pour créer les objets:

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"));
};

J'ai essayé quelque chose comme ça:

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

et fait des ajustements ailleurs pour que cela fonctionne, mais il déplace simplement le texte et les formes, mais la forme et le texte ne sont jamais vus dans leur ensemble. Je peux déplacer le texte séparément de la forme et vice versa. J'ai besoin qu'ils soient un seul objet. alors ils se déplacent ensemble. Comment puis je faire ça? Merci pour toute aide.

ÉDITER:

J'ai essayé ceci:

  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))

Mais le texte et la forme ne sont pas restés ensemble lorsque j'ai déplacé la forme. Le texte est juste resté immobile.

EDIT: je ne peux pas obtenir la démo de stock à http://raphaeljs.com/graffle.html pour travailler avec Chrome. IE ça marche.

43
johnny

A fait une modification majeure pour associer les éléments d'une manière plus élégante.


Ensembles sont bons pour regrouper des objets Raphael, mais les ensembles ne créent pas leurs propres éléments, vous ne pouvez donc pas faire glisser et déposer un ensemble , car lorsque vous cliquez sur le canevas, vous sélectionnez la forme ou le texte, mais jamais l'ensemble (car il n'y a pas d'élément d'ensemble).

Voici un simple jsFiddle montrant les propriétés d'un ensemble. Notez qu'un ensemble n'a pas de x ou y propriétés.

Depuis le documentation Raphael:

[Un ensemble c] crée un objet de type tableau pour conserver et faire fonctionner deux éléments à la fois. Avertissement: il ne crée aucun élément pour lui-même dans la page.


La solution simple consiste à faire glisser le texte et la forme séparément. Déplacez ensuite le texte associé avec la forme ... et la forme associée avec le texte.

L'association d'objets comme celui-ci est simple ... créez une propriété. Dans ce cas, chaque forme et chaque texte a une propriété appelée .pair Qui est une référence à l'élément associé.

Voici comment procéder:

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

Et puis dans le code glisser-déposer, qui est les fonctions move(), dragger() et up(), vous devez vous assurer de traiter à la fois l'élément cliqué sur et son élément associé.

Par exemple, voici la partie pertinente de la fonction move(). Notez que text peut être traité de la même manière que rectangle (en changeant les attributs x et y), donc le false dans chacun des opérateurs conditionnels Javascript ci-dessous gère à la fois la casse pour rectangle et pour text

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);
    ...
}


Et ci-dessous est le code de travail complet:

Exemple de travail jsFiddle de texte et de formes déplaçables

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"));
};​

Pour être complet, voici le code pour le lié à jsFiddle pour afficher les propriétés d'un ensemble:

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

Ou, essayez ce plugin "groupe" pour Raphael qui vous permet de créer un élément de groupe SVG approprié.

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

7
Ben Bederson

Oui, c'est à cela que sert l'objet 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);

Réponse supplémentaire:

OK, je vois que vous avez essayé d'utiliser set mais que vous l'utilisez mal. Un ensemble crée un groupe de choses. Tout comme si vous deviez grouper des formes et du texte dans Adobe Illustrator ou Inkscape ou Microsoft Word ou Open Office. Si je vous comprends bien, ce que vous voulez c'est:

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))
         ];

Vous devrez également modifier votre dragger et déplacer les fonctions car les formes ne sont plus de type 'rect' mais de type '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();
};

Tous les ensembles ont des attributs x et y.

4
slebetman

Ne serait-il pas plus facile de simplement changer les attributs de l'objet jumelé avec les attributs qui changent lorsque l'objet principal est déplacé?

Quelque chose comme ça:

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
Adam Moszczyński