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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3679436/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 05:41:26  来源:igfitidea点击:

How can I combine objects in the Raphael javascript library?

javascriptraphael

提问by johnny

Sorry for a long question but here goes. I am trying to modify the drag shapes around demo here:

抱歉问了一个很长的问题,但这里是。我试图在这里修改演示周围的拖动形状:

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.htmlto work with Chrome. IE it works.

编辑:我无法在http://raphaeljs.com/graffle.html 上获得与 Chrome 一起使用的股票演示。IE它的工作原理。

回答by Peter Ajtai

Did major edit to associate elements in a more elegant way.

进行了重大编辑,以更优雅的方式关联元素。



Setsare 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.Note that a set has no xor yproperties.

这是一个简单的 jsFiddle,显示了集合的属性。请注意,集合没有xy属性。

From the Raphael documentation:

拉斐尔文档

[A set c]reates array-like object to keep and operate couple of elements at once. Warning: it doesn't create any elements for itself in the page.

[A set c]创建类数组对象以同时保留和操作几个元素。警告:它不会在页面中为自己创建任何元素。



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 .pairwhich 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()功能,您必须确保同时处理的点击的元素及其相关元素上。

For example here is the pertinent part of the move()function. Note that textcan be dealt with in the same way as rectangle(by changing attributes xand y), so the falsecondition in each of the Javascript conditional operators below handles both the case for rectangleand for text

例如这里是move()函数的相关部分。请注意,text可以以与rectangle(通过更改属性xy)相同的方式处理,因此false下面每个 Javascript 条件运算符中的条件处理 forrectangle和 for的情况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);
    ...
}



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

回答by Ben Bederson

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

回答by slebetman

Yes, that's what the setobject 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. 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. If I understand you correctly what you want is this:

好的,我看到您尝试使用 set 但您使用错误。一组创建一组事物。就像您要在 Adob​​e 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))
         ];

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 xand yattributes.

所有集合都有xy属性。

回答by Adam Moszczyński

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




    };