Arrastrar y soltar en SVG

facebook-svg gplus-svg twitter-svg

Arrastrar y soltar en SVG

Una de las cosas divertidas que podemos hacer en SVG es mover objetos. Empezamos con un ejemplo fácil: después de dibujar un rectángulo vamos a arrastrarlo y soltarlo por  ahí.

Algunas cosas necesarias

Primero necesitamos establecer algunas variables:

var SVG_NS, de hecho una constante, define el espacio de nombres en SVG. La necesitamos para crear un nuevo elemento SVG.
var svg: representa el elemento <svg>, el lienzo en el cual dibujamos.
var svgRaton: la posición del ratón relativo al lienzo SVG.
var rectRaton: la posición del ratón relativo al rectángulo.
var distInicial: la posición inicial del rectángulo.
var arrastrar: un booleano que por ahora es false, o sea no podemos arrastrar.

La función oMousePos()  detecta la posición del ratón encima de un determinado elemento del DOM, y devuelve un objeto con las coordinadas x e y de este.

Dibujar un rectángulo

Dibujar un rectángulo en SVG es muy fácil, peró ya que quiero moverlo por ahí, y quiero dibujarlo y actualizarlo una y otra vez, de manera dinámica, voy a escribir una función que crea un objeto  rectángulo: function Rect().

El objeto que queremos crear necesita varias propiedades ( es como llamamos las variables dentro de un objeto JavaScript ) y métodos ( o sea funciones ).

Propiedades del rectángulo

this.att: un rectángulo SVG tiene varios atributos ( x, y, width, height, . . . etc ), y por lo tanto el objeto rectángulo que queremos crear debe tener una propiedad, de hecho un objeto, que guarda el valor de estos atributos.

this.att = { /* por ahora un objeto vacío */ }

this.elemento:  representa el elemento (no el objeto) rectángulo que aparce en el DOM.

Métodos del rectángulo

this.dibujar: necesitamos un método para poder dibujar el rectángulo. Prácticamente creamos un nuevo elemento "rect"

this.dibujar = function(elementoPadre) {
      var elmt = document.createElementNS(SVG_NS, "rect");
      for (var name in this.att) {
        if (this.att.hasOwnProperty(name)) {
          elmt.setAttributeNS(null, name, this.att[name]);
        }
      }
      elementoPadre.appendChild(elmt);
      this.elemento = elmt;
}

y lo dotamos con los atributos necesarios

this.dibujar = function(elementoPadre) {
      var elmt = document.createElementNS(SVG_NS, "rect");
  for (var name in this.att) {
        if (this.att.hasOwnProperty(name)) {
          elmt.setAttributeNS(null, name, this.att[name]);
        }
  }
      elementoPadre.appendChild(elmt);
      this.elemento = elmt;
}

Al final, muy importante, adjuntamos ( con appendChild ) el rectángulo al elementoPadre y guardamos una referencia: this.elemento = elmt;

this.dibujar = function(elementoPadre) {
      var elmt = document.createElementNS(SVG_NS, "rect");
      for (var name in this.att) {
        if (this.att.hasOwnProperty(name)) {
          elmt.setAttributeNS(null, name, this.att[name]);
        }
      }
      elementoPadre.appendChild(elmt);
      this.elemento = elmt;
}

this.actualizar: es una función ( en realidad un método ) que translada el rectángulo en una nueva posición. De hecho actualiza el valor del atributo transform de acuerdo con la posición del ratón:

this.actualizar = function(x,y){
    this.elemento.setAttributeNS(null, "transform", "translate("+x+","+y+")");
}

Crear un nuevo rectángulo

Ahora que ya lo tenemos todo, crear un nuevo rectángulo es pan comido.

// crea un nuevo objeto rectángulo
var oRect = new Rect();
// establece los atributos del nuevo rectángulo
oRect.att = {x:80,y:94,width:80,height:50, transform:"translate(0,0)",fill:"gold"};
// dibuja el nuevo rectángulo y lo adjunta al svg ( el elemento padre )
oRect.dibujar(svg);

Eventos del ratón utilizados:

Para arrastrar y soltar necesitamos:

1. Presionar el botón del ratón, para "coger" el objeto. El evento del ratón involucrado en este caso es mousedown ( literalmente : ratón abajo ).
2. Mantener presionado y arrastrar el ratón a la ubicación deseada. El evento del ratón involucrado en este caso es mousemove (literalmente : ratón moviendose).
3. Soltar el objeto arrastrado, soltando el botón del ratón. El evento del ratón involucrado en este caso es mouseup. ( literalmente : ratón arriba ).
4. Si queremos podemos también tomar en consideración la salida del ratón del <canvas>: mouseout (literalmente : ratón fuera).

var num = 0; // un contador
rectangulo.addEventListener("mousedown", function(evt){
       num++;
       // detecta la posición del ratón en el lienzo SVG
       svgRaton = oMousePos(svg, evt);
       // detecta la posición del ratón en el rectángulo (this) 
       rectRaton = oMousePos(this, evt);
       
       if(num == 1){// calculado solo una vez, en el primer clic
       // recupera la posición inicial del rectángulo
       distInicial.x = svgRaton.x - rectRaton.x;
       distInicial.y = svgRaton.y - rectRaton.y;
       }
       // podemos arrastrar
       arrastrar = true;
     }, false);
        
rectangulo.addEventListener("mousemove", function(evt) {
       // si podemos arrastrar
       if (arrastrar) {
       // detecta la posición del ratón en el lienzo SVG
       svgRaton = oMousePos(svg, evt);
       // y actualiza la posición del rectángulo en función de la posición del ratón
       var x = svgRaton.x - rectRaton.x - distInicial.x;
       var y = svgRaton.y - rectRaton.y - distInicial.y;
       oRect.actualizar( x, y); 
       }
}, false);
  
rectangulo.addEventListener("mouseup", function(evt) {
        // al soltar el objeto arrastrado ya no podemos arrastrar
         arrastrar = false;
}, false);

rectangulo.addEventListener("mouseout", function(evt) {
         // al salir fuera ya no podemos arrastrar
         arrastrar = false;
}, false);

Vea este ejemplo en codepen.io

Arrastre el rectángulo amarillo.

See the Pen SVG drag shape translate by Gabi (@enxaneta) on CodePen.