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

Draggables и Resizables в SVG

Я хочу, чтобы элемент svg (путь, прямоугольник или круг) мог быть перетаскиваемым и давать ему изменения размера.

Но, в отличие от HTML DOM, не все элементы имеют верхний левый угол x, y координаты и ширину и высоту для поля, окружающего контент. Это делает неудобным создание общей процедуры изменения размера или перетаскивания.

Это хорошая идея, чтобы каждый путь или круг был нарисован внутри собственного объекта svg, чтобы дать мне поле для игры с?

Как перетаскиваемый/изменяемый размер обычно реализуется в SVG?

4b9b3361

Ответ 1

Примечание. Для перетаскивания и изменения размера вам придется делать отдельные случаи для некоторых разных типов элементов. Посмотрите пример, который я предоставляю позже, который обрабатывает перетаскивание как эллипсов, так и прямоугольников в одном наборе функций.


Чтобы создать элемент, можно использовать:

element.drag(move, start, up);

Три аргумента - это ссылки на функции, которые обрабатывают перемещение (перетаскивание), запуск (мышь вниз) и остановку (mouseup).

Например, чтобы сделать перетаскиваемый круг (из документации):

window.onload = function() {
var R = Raphael("canvas", 500, 500);    
var c = R.circle(100, 100, 50).attr({
    fill: "hsb(.8, 1, 1)",
    stroke: "none",
    opacity: .5
});
var start = function () {
    // storing original coordinates
    this.ox = this.attr("cx");
    this.oy = this.attr("cy");
    this.attr({opacity: 1});
},
move = function (dx, dy) {
    // move will be called with dx and dy
    this.attr({cx: this.ox + dx, cy: this.oy + dy});
},
up = function () {
    // restoring state
    this.attr({opacity: .5});
};
c.drag(move, start, up);    
};​

Пример jsFiddle


В приведенном выше примере свойства ox и oy привязаны к элементу, чтобы отслеживать его местоположение, и эти свойства в сочетании с dx и dy используются для изменения местоположения элемент при его перетаскивании.

Более сложное перетаскивание, чтобы ответить этот вопрос.

Чтобы сделать объект изменчивым, вы просто создадите второй набор методов перетаскивания для resizer и просто настройте целевые элементы height и width на основе перетаскивания resizer.

Здесь вы найдете полный перетаскиваемый и изменяемый размер ящик:

Пример jsFiddle окна перетаскивания и изменения размера

window.onload = function() {
var R = Raphael("canvas", 500, 500),
    c = R.rect(100, 100, 100, 100).attr({
            fill: "hsb(.8, 1, 1)",
            stroke: "none",
            opacity: .5,
            cursor: "move"
        }),
    s = R.rect(180, 180, 20, 20).attr({
            fill: "hsb(.8, .5, .5)",
            stroke: "none",
            opacity: .5
        }),
    // start, move, and up are the drag functions
    start = function () {
        // storing original coordinates
        this.ox = this.attr("x");
        this.oy = this.attr("y");
        this.attr({opacity: 1});

        this.sizer.ox = this.sizer.attr("x");
        this.sizer.oy = this.sizer.attr("y");
        this.sizer.attr({opacity: 1});
    },
    move = function (dx, dy) {
        // move will be called with dx and dy
        this.attr({x: this.ox + dx, y: this.oy + dy});
        this.sizer.attr({x: this.sizer.ox + dx, y: this.sizer.oy + dy});        
    },
    up = function () {
        // restoring state
        this.attr({opacity: .5});
        this.sizer.attr({opacity: .5});        
    },
    rstart = function () {
        // storing original coordinates
        this.ox = this.attr("x");
        this.oy = this.attr("y");

        this.box.ow = this.box.attr("width");
        this.box.oh = this.box.attr("height");        
    },
    rmove = function (dx, dy) {
        // move will be called with dx and dy
        this.attr({x: this.ox + dx, y: this.oy + dy});
        this.box.attr({width: this.box.ow + dx, height: this.box.oh + dy});
    };   
    // rstart and rmove are the resize functions;
    c.drag(move, start, up);
    c.sizer = s;
    s.drag(rmove, rstart);
    s.box = c;
};​

Включенные обработчики событий (вы можете использовать больше, конечно, в сочетании с .node()) и описание перетаскивания находится в нижней части страницы в документации.

Вы просто сделали бы один холст Рафаэля, и тогда каждый элемент был бы другим элементом. Просто назначьте их переменным, чтобы вы могли их обрабатывать, как в приведенном выше примере (c использовался для ссылки на созданный элемент окружения).

В ответ на комментарии здесь можно просто перетащить и изменить размер круга. Фокус в том, что круги используют атрибуты cx и cy для позиционирования и r для размера. Механика почти такая же... эллипс будет немного усложняться, но опять же это вопрос работы с правильными атрибутами.

jsFiddle пример перетаскивания и масштабируемого круга

window.onload = function() {
    var R = Raphael("canvas", 500, 500),
        c = R.circle(100, 100, 50).attr({
            fill: "hsb(.8, 1, 1)",
            stroke: "none",
            opacity: .5
        }),
        s = R.circle(125, 125, 15).attr({
            fill: "hsb(.8, .5, .5)",
            stroke: "none",
            opacity: .5
        });
    var start = function () {
        // storing original coordinates
        this.ox = this.attr("cx");    
        this.oy = this.attr("cy");

        this.sizer.ox = this.sizer.attr("cx");    
        this.sizer.oy = this.sizer.attr("cy")

        this.attr({opacity: 1});
        this.sizer.attr({opacity: 1});
    },
    move = function (dx, dy) {
        // move will be called with dx and dy
        this.attr({cx: this.ox + dx, cy: this.oy + dy});
        this.sizer.attr({cx: this.sizer.ox + dx, cy: this.sizer.oy + dy});
    },
    up = function () {
        // restoring state
        this.attr({opacity: .5});
        this.sizer.attr({opacity: .5});
    },
    rstart = function() {
        // storing original coordinates
        this.ox = this.attr("cx");
        this.oy = this.attr("cy");        

        this.big.or = this.big.attr("r");
    },
    rmove = function (dx, dy) {
        // move will be called with dx and dy
        this.attr({cx: this.ox + dy, cy: this.oy + dy});
        this.big.attr({r: this.big.or + Math.sqrt(2*dy*dy)});
    };
    c.drag(move, start, up);    
    c.sizer = s;
    s.drag(rmove, rstart);
    s.big = c;
};

Ответ 2

Посмотрите Raphael.FreeTransform, который, кажется, делает то, что вам нужно.

Ответ 3

Попробуйте Graphiti вот ссылка: Draw2d и Graphiti

Он основан на Рафаэле и очень прост в использовании.