web-dev-qa-db-fra.com

Draggables et Resizables en SVG

Je veux qu'un élément svg (chemin, rect ou cercle) puisse être déplacé et lui donner des poignées de redimensionnement.

Mais contrairement au HTML DOM, tous les éléments ne possèdent pas une coordonnée x, y en haut à gauche, et une largeur et une hauteur pour une zone entourant le contenu. Cela fait qu'il est peu pratique de faire une procédure générique de redimensionnement ou de glisser.

Est-ce une bonne idée que chaque chemin ou cercle soit tracé à l'intérieur de son propre objet svg pour me donner une boîte avec laquelle jouer?

Comment est-ce que draggable/resizable est typiquement implémenté dans SVG?

29
Boris Yeltz

Remarque: que vous souhaitiez faire glisser ou redimensionner, vous devrez créer des observations distinctes pour certains types d'éléments. Jetez un coup d'oeil dansl'exemple que je fournis plus tardqui gère le glissement des ellipses et des rectangles dans le même ensemble de fonctions.


Pour rendre un élément déplaçable, utilisez:

element.drag(move, start, up);

Les trois arguments sont des références aux fonctions qui gèrent le déplacement (glisser), le démarrage (souris vers le bas) et l’arrêt (mouseup).

Par exemple, pour créer un cercle déplaçable (à partir de la documentation):

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

Exemple jsFiddle


Dans l'exemple ci-dessus, les propriétés ox et oy sont ajoutées à l'élément pour garder une trace de son emplacement, et ces propriétés associées à dx et dy sont utilisées pour modifier l'emplacement de l'élément pendant son déplacement.

Un glisser-déposer plus compliquépour répondrecette question.

Pour rendre un objet redimensionnable, vous créez simplement un deuxième ensemble de méthodes de glisser-déposer pour le redimensionneur et vous ajustez simplement les éléments cibles height et width en fonction du glissement du resizer.

Voici une boîte pleine d'un glisser-déposer et redimensionnable que j'ai écrit:

Exemple jsFiddle de glisser-déposer et de boîte redimensionnable

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

Les gestionnaires d’événements inclus (vous pouvez en utiliser plus en association avec.node()) et la description du glisser-déposer se trouvent au bas de la pagedans la documentation.

Vous feriez simplement une toile Raphael et chaque élément serait un élément différent. Assignez-les simplement à des variables pour pouvoir les gérer, comme dans l'exemple ci-dessus (c a été utilisé pour faire référence à l'élément de cercle créé).

En réponse aux commentaires, voici un simple glisser-déposer + cercle redimensionné. L'astuce est que les cercles utilisent les attributs cx et cy pour le positionnement et r pour la taille. La mécanique est à peu près la même… une ellipse serait un peu plus compliquée, mais encore une fois, il s’agit simplement de travailler avec les bons attributs.

Exemple jsFiddle de glisser-déposer et de cercle redimensionnable

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

Regardez Raphael.FreeTransform qui semble faire ce que vous cherchez.

4
Elbert Alias

Essayez Graphiti voici le lien: Draw2d et Graphiti

Il est basé sur Raphael et très facile à utiliser.

3
JS Rocker

Il y a aussi ce plugin pour SVG.js.

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

0
Paul LeBeau