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

对不起,很长的问题,但这里。 我试图修改这里演示的拖动形状:

http://raphaeljs.com/graffle.html

演示工作正常。 我想要做的就是将单词放在形状中,并将形状和文字作为复合单个对象移动。

这里是创build对象的代码:

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

并在其他地方作了调整,以便它能起作用,但是它只是移动文本和形状,但形状和文本从来不被视为一个整体。 我可以将文字从形状中分离出来,反之亦然。 我需要他们成为一个对象。 所以他们一起移动。 我怎样才能做到这一点? 感谢您的任何帮助。

编辑:

我试过这个:

  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浏览器工作。

做了大量编辑,以更优雅的方式关联元素。


集合对Raphael对象进行分组很好,但集合不会创build自己的元素,所以您不能拖放集合,因为当您单击canvas时,您可以select形状或文本,但不会select集合(因为存在没有设置元素)。

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

拉斐尔文档

[一组c]控制类似数组的对象来保存和操作一对元素。 警告:它不会在页面中为它自己创build任何元素。

简单的解决方法是使文本和形状分别拖动。 然后将相关文本与形状一起移动…以及相关的形状与文本一起。

像这样关联对象很简单…创build一个属性。 在这种情况下,每个形状和每个文本都有一个名为.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()函数的拖放代码中,您必须确保处理clicked元素及其关联的元素。

例如这里是move()函数的相关部分。 请注意, 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); ... } 

以下是完整的工作代码:

工作js可拖动的文本和形状的例子

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

为了完整,这里是链接到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 

或者,试试这个Raphael的“group”插件,它可以让你创build一个合适的SVG组元素。

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

是的,这是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); 

附加答案:

好的,我看到你已经尝试过使用set,但是你用错了。 一组创build一组事物。 就像在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”types,而是“set”types:

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

所有集合都有xy属性。

如果仅仅改变配对对象的属性以及主对象被拖动时改变的属性,会不会更容易?

像这样的东西:

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