ti-enxame.com

Draggables e Resizables em SVG

Eu quero fazer um elemento svg (path, rect ou circle) poder ser arrastável e dar a ele as alças de redimensionamento.

Mas, diferentemente do HTML DOM, nem todos os elementos possuem um canto superior esquerdo x, y coordenada e uma largura e altura para uma caixa ao redor do conteúdo. Isso torna inconveniente para fazer um procedimento genérico de redimensionar ou arrastar.

É uma boa ideia ter cada caminho ou círculo desenhado dentro do seu próprio objeto svg para me dar uma caixa para brincar?

Como draggable/redimensionável normalmente implementado em SVG?

29
Boris Yeltz

Nota: Para arrastar e redimensionar, você terá que criar casos separados para determinados tipos diferentes de elementos. Dê uma olhada emo exemplo que forneço posteriormenteque lida com o arrastamento de elipses e retângulos no mesmo conjunto de funções.


Para tornar um elemento arrastável, use:

element.drag(move, start, up);

Os três argumentos são referências às funções que lidam com movimentação (arrastar), iniciar (mouse para baixo) e parar (mouseup).

Por exemplo, para fazer um círculo arrastável (da documentação):

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 example


No exemplo acima, as propriedades ox e oy são colocadas no elemento para manter o controle de sua localização, e essas propriedades em conjunto com dx e dy são usadas para alterar a localização do elemento conforme ele é arrastado.

Um arrastar e soltar mais complicadopara responderesta questão.

Para tornar um objeto redimensionável, basta criar um segundo conjunto de métodos de arrastar e soltar para o redimensionador e apenas ajustar os elementos de destino height e width com base no arrasto do redimensionador.

Aqui está uma caixa de arrastar e soltar e redimensionável que eu escrevi:

jsFiddle exemplo de arrastar e soltar e caixa redimensionável

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

Os manipuladores de eventos incluídos (você pode usar mais claro em conjunto com.node()) e a descrição de arrastar e soltar está na parte inferior da páginana documentação.

Você faria simplesmente uma tela de Rafael, e então cada item seria um elemento diferente. Apenas os atribua a variáveis ​​para que você possa manipulá-las, como no exemplo acima (c foi usado para se referir ao elemento circle criado).

Em resposta aos comentários, aqui está um simples arrastar e soltar + círculo redimensionável. O truque é que os círculos usam os atributos cx e cy para posicionamento e r para tamanho. A mecânica é praticamente a mesma ... uma elipse seria um pouco mais complicada, mas novamente é apenas uma questão de trabalhar com os atributos certos.

jsFiddle exemplo de arrastar e soltar e círculo redimensionável

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;
};
53
Peter Ajtai

Dê uma olhada em Raphael.FreeTransform que parece fazer o que você está procurando.

4
Elbert Alias

Tente Graphiti aqui é o link: Draw2d e Graphiti

É baseado em Raphael e muito fácil de usar.

3
JS Rocker

Há também este plugin para SVG.js.

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

0
Paul LeBeau