Подтвердить что ты не робот

Как объединить объекты в библиотеке JavaScript Raphael?

Извините за длинный вопрос, но здесь идет. Я пытаюсь изменить формы перетаскивания вокруг демонстрации здесь:

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

и внесли корректировки в другое место, чтобы он работал, но затем он просто перемещает текст и фигуры, но форма и текст никогда не видны в целом. Я могу перемещать текст отдельно от формы и наоборот. Мне нужно, чтобы они были одним объектом. поэтому они движутся вместе. Как я могу это сделать? Спасибо за любую помощь.

EDIT:

Я пробовал это:

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

Но текст и форма не оставались вместе, когда я двигал форму. Текст только что остался.

EDIT: я не могу получить демо-версию акции http://raphaeljs.com/graffle.html для работы с Chrome. IE работает.

4b9b3361

Ответ 1

Помогло ли большое редактирование элементам более элегантно.


Установки хороши для группировки объектов 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(), вам необходимо убедиться, что вы имеете дело как с элементом clicked on, так и с его ассоциированным элементом.

Например, здесь находится соответствующая часть функции 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 object
// 1 : Raphael object
// items : Raphael object,Raphael object
// length : 2
// type : set

Ответ 3

Да, для чего предназначен объект 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))
         ];

Вам также придется изменить свой dragger и перемещать функции, поскольку формы больше не имеют тип '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.

Ответ 4

Не проще ли было бы изменять атрибуты парного объекта вместе с атрибутами, которые меняются при перетаскивании основного объекта?

Что-то вроде этого:

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




    };