Draggables и Resizables в SVG - PullRequest
       6

Draggables и Resizables в SVG

29 голосов
/ 01 сентября 2010

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

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

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

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

Ответы [ 4 ]

53 голосов
/ 07 октября 2010

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


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

element.drag(move, start, up);

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

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

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 используются для изменениярасположение элемента во время его перетаскивания.

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

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

Вот полный блок перетаскивания и изменяемого размера, который я написал:

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()), а описание перетаскивания находится внизу страницы в документации .

You wможно было бы просто сделать одно полотно Рафаэля, и тогда каждый предмет был бы отдельным элементом.Просто присвойте их переменным, чтобы вы могли обрабатывать их, как в примере выше (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;
};
4 голосов
/ 07 декабря 2011

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

3 голосов
/ 23 августа 2012

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

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

0 голосов
/ 11 декабря 2018

Существует также этот плагин для SVG.js.

https://github.com/svgdotjs/svg.resize.js

...