Как я могу объединить объекты в библиотеке 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")
];
и внесли изменения в другом месте, чтобы он работал, но затем он просто перемещает текст и фигуры, но фигура и текст никогда не видятся в целом. Я могу переместить текст отдельно от фигуры и наоборот. Мне нужно, чтобы они были одним объектом. поэтому они двигаются вместе. Как я могу это сделать? Спасибо за любую помощь.
РЕДАКТИРОВАТЬ:
Я попробовал это:
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 это работает.
4 ответа
Сделал серьезное редактирование, чтобы связать элементы более элегантным способом.
Наборы хороши для группировки объектов Raphael, но наборы не создают свои собственные элементы, поэтому вы не можете перетаскивать набор, поскольку при нажатии на холст вы выбираете либо форму, либо текст, но не набор (поскольку без заданного элемента).
Вот простой jsFiddle, показывающий свойства набора. Обратите внимание, что набор не имеет x
или же y
свойства.
[Набор 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()
функция. Обратите внимание, что text
можно рассматривать так же, как rectangle
(путем изменения атрибутов x
а также y
), Итак false
условие в каждом из условных операторов Javascript ниже обрабатывает оба случая для rectangle
и для 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);
...
}
И ниже полный рабочий код:
Рабочий пример 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"));
};
Для полноты здесь приведен код для ссылки на 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, который позволяет вам создать правильный элемент SVG group.
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, но вы используете его неправильно. Набор создает группу вещей. Точно так же, как если бы вам нужно было группировать фигуры и текст в 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
атрибутов.
Не проще ли изменить атрибуты парного объекта вместе с атрибутами, которые меняются при перетаскивании основного объекта?
Что-то вроде этого:
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);
};