简体   繁体   English

如何在Raphael javascript库中组合对象?

[英]How can I combine objects in the Raphael javascript library?

Sorry for a long question but here goes. 抱歉,这是一个很长的问题。 I am trying to modify the drag shapes around demo here: 我想在这里修改demo的拖动形状:

http://raphaeljs.com/graffle.html http://raphaeljs.com/graffle.html

The demo works fine. 该演示工作正常。 What I want to do is put words inside the shapes and move the shape and text around as a composite single object. 我想要做的是将单词放在形状中,并将形状和文本作为复合单个对象移动。

Here is the code for creating the objects: 以下是创建对象的代码:

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

I tried something like this: 我试过这样的事情:

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

and made adjustments elsewhere so that it would work, but then it just moves text and shapes but the shape and text are never seen as a whole. 并在其他地方进行调整,以便它可以工作,但它只是移动文本和形状,但形状和文字永远不会被视为一个整体。 I can move the text separate from the shape and vice versa. 我可以将文本与形状分开移动,反之亦然。 I need them to be one object. 我需要他们成为一个对象。 so they move together. 所以他们一起移动 How can I do that? 我怎样才能做到这一点? Thank you for any help. 感谢您的任何帮助。

EDIT: 编辑:

I tried this: 我试过这个:

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

But the text and shape did not stay together when I moved the shape. 但是当我移动形状时,文字和形状并没有保持在一起。 The text just stayed still. 文字保持不动。

EDIT: I cannot get the stock demo at http://raphaeljs.com/graffle.html to work with Chrome. 编辑:我无法在http://raphaeljs.com/graffle.html上获得与Chrome合作的股票演示。 IE it works. IE它的工作原理。

Did major edit to associate elements in a more elegant way. 主要编辑以更优雅的方式关联元素。


Sets are good for grouping Raphael objects, but sets do not create their own elements, so you cannot drag and drop a set, since when you click on the canvas you either select the shape or the text, but never the set (since there is no set element). 集合适用于分组Raphael对象,但集合不会创建自己的元素,因此您无法拖放集合,因为当您单击画布时,您可以选择形状或文本,但不要选择集合(因为有没有设定元素)。

Here is a simple jsFiddle showing the properties of a set. 这是一个简单的jsFiddle,显示了一个集合的属性。 Note that a set has no x or y properties. 请注意,集合没有xy属性。

From the Raphael documentation : 来自Raphael的文档

[A set c]reates array-like object to keep and operate couple of elements at once. [set c]创建类似于数组的对象,以便一次保持和操作几个元素。 Warning: it doesn't create any elements for itself in the page. 警告:它不会在页面中为自己创建任何元素。


The simple work around is to make both the text and shape separately draggable. 简单的解决方法是使文本和形状分别可拖动。 Then move the associated text along with the shape... and the associated shape along with the text. 然后将关联的文本与形状...以及相关的形状以及文本一起移动。

Associating objects like this is simple... create a property. 关联这样的对象很简单......创建一个属性。 In this case each shape and each text has a property called .pair which is a reference to the associated element. 在这种情况下,每个形状和每个文本都有一个名为.pair的属性,它是对相关元素的引用。

Here's how it's done: 以下是它的完成方式:

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

And then in the drag and drop code, which is the move() , dragger() , and up() functions you have to make sure to deal with both the clicked on element and its associated element. 然后在拖放代码中,即move()dragger()up()函数,您必须确保处理clicked元素及其相关元素。

For example here is the pertinent part of the move() function. 例如,这里是move()函数的相关部分。 Note that text can be dealt with in the same way as rectangle (by changing attributes x and y ), so the false condition in each of the Javascript conditional operators below handles both the case for rectangle and for text 请注意, text可以与rectangle相同的方式处理(通过更改属性xy ),因此下面每个Javascript条件运算符中的false条件都处理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);
    ...
}


And below is the full working code: 以下是完整的工作代码:

Working jsFiddle example of draggable text and shapes 使用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"));
};​

For completeness here is the code for the linked to jsFiddle for showing the properties of a 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

Or, try this "group" plugin for Raphael which lets you create a proper SVG group element. 或者,试试Raphael的这个“组”插件,它可以让你创建一个合适的SVG组元素。

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

Yes, that's what the set object is for: 是的,这就是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);

Additional answer: 补充答案:

OK, I see that you've tried using set but you are using it wrong. 好的,我看到你已经尝试过使用set但是你错了。 A set creates a group of things. 集合创建了一组东西。 Just like if you were to group shapes and text in Adobe Illustrator or Inkscape or Microsoft Word or Open Office. 就像您要在Adobe Illustrator或Inkscape或Microsoft Word或Open Office中对形状和文本进行分组一样。 If I understand you correctly what you want is this: 如果我理解你想要的是这个:

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

You'll also have to modify your dragger and move functions since the shapes are no longer of type 'rect' but are of type 'set': 您还必须修改拖动器和移动函数,因为形状不再是'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();
};

All sets have x and y attributes. 所有集都有xy属性。

Wouldn't it be easier just to change the attributes of the paired object along with the attributes which are changing when the main object is dragged? 仅仅更改配对对象的属性以及拖动主对象时正在更改的属性是不是更容易?

Something like this: 像这样的东西:

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




    };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM