SVG
Scripting
Buscar..
Observaciones
Las secuencias de comandos SVG que utilizan las interfaces DOM nativas se encuentran actualmente (2016) en un estado de leve cambio. El estándar SVG actual (1.1) se implementa bien en la mayoría de los principales navegadores web. Sin embargo, como el estándar SVG 2.0 está en desarrollo, algunos navegadores han comenzado a eliminar las funciones SVG 1.1 que quedarán obsoletas en 2.0. Puede ver una lista completa de los cambios propuestos desde SVG 1.1 a SVG 2.0 en el Apéndice L de SVG 2.0 .
Reemplazo de pathSegList
y otro uso de SVGPathSeg
En SVG 1.1, los elementos <path>
están definidos para tener una propiedad pathSegList
que le da acceso a una representación nativa de todos los comandos de ruta . Google Chrome v48 eliminó esta propiedad a finales de 2015, en preparación para un reemplazo propuesto en SVG 2.0 . Hasta que se agregue la compatibilidad con SVG 2.0, debe usar un polyfill para recuperar la funcionalidad 1.1 o para implementar la API 2.0 propuesta .
Reemplazo de getTransformToElement()
Chrome v48 también eliminó el método SVGGraphicsElement.getTransformToElement()
. Existe un polyfill simple para implementar el método antiguo .
Creando un elemento
La forma más sencilla de comprender cómo crear y modificar elementos SVG es operar sobre los elementos utilizando las interfaces DOM Level 2 Core , como lo haría con HTML o XML.
Es imperativo que los elementos creados a partir de JavaScript se creen en el mismo espacio de nombres declarado en el elemento SVG, en este ejemplo: " http://www.w3.org/2000/svg ". Sin embargo, casi todos los atributos de los elementos SVG no están en ningún espacio de nombres. No se debe colocar en el espacio de nombres SVG.
Aquí mostramos SVG alojado dentro de HTML, ya que este es un caso común:
<!doctype HTML>
<html><title>Creating an Element</title>
<body>
<svg xmlns="http://www.w3.org/2000/svg"
width="100%" height="100%"
viewBox="0 0 400 300"></svg>
<script>
var svgNS = "http://www.w3.org/2000/svg";
// Create a circle element (not part of the DOM yet)
var circle = document.createElementNS(svgNS,'circle'); // Creates a <circle/>
circle.setAttribute('fill','red'); // Note: NOT setAttributeNS()
circle.setAttribute('cx',150); // setAttribute turns 150 into a string
circle.setAttribute('cy','80'); // using a string works, too
circle.setAttribute('r',35); // give the circle a radius so we can see it
// Now, add the circle to the SVG document so we can see it
var svg = document.querySelector('svg'); // the root <svg> element
svg.appendChild(circle);
</script>
</body></html>
Hay algunos atributos que deben crearse en un espacio de nombres particular. Son los que figuran con dos puntos en sus nombres en el Índice de Atributos SVG . Específicamente, son: xlink:actuate
xlink:arcrole
, xlink:arcrole
, xlink:href
, xlink:role
, xlink:show
, xlink:title
, xlink:type
, xml:base
, xml:lang
, y xml:space
. Establezca estos atributos utilizando setAttributeNS()
:
var svgNS = "http://www.w3.org/2000/svg";
var xlinkNS = "http://www.w3.org/1999/xlink";
var img = document.createElementNS( svgNS, 'image' );
img.setAttributeNS( xlinkNS, 'href', 'my.png' );
Si crea elementos con frecuencia, especialmente con muchos atributos, una función auxiliar como la siguiente puede ahorrarle la escritura, evitar errores y hacer que su código sea más fácil de leer:
<!doctype HTML>
<html><title>Creating an Element</title>
<body>
<svg xmlns="http://www.w3.org/2000/svg"></svg>
<script>
var svg = document.querySelector('svg');
var circle = createOn( svg, 'circle', {fill:'red', cx:150, cy:80, r:35} );
// Create an SVG element on another node with a set of attributes.
// Attributes with colons in the name (e.g. 'xlink:href') will automatically
// find the appropriate namespace URI from the SVG element.
// Optionally specify text to create as a child node, for example
// createOn(someGroup,'text',{x:100,'text-anchor':'middle'},"Hello World!");
function createOn(parentEl,name,attrs,text){
var doc=parentEl.ownerDocument, svg=parentEl;
while (svg && svg.tagName!='svg') svg=svg.parentNode;
var el = doc.createElementNS(svg.namespaceURI,name);
for (var a in attrs){
if (!attrs.hasOwnProperty(a)) continue;
var p = a.split(':');
if (p[1]) el.setAttributeNS(svg.getAttribute('xmlns:'+p[0]),p[1],attrs[a]);
else el.setAttribute(a,attrs[a]);
}
if (text) el.appendChild(doc.createTextNode(text));
return parentEl.appendChild(el);
}
</script>
</body></html>
Atributos de lectura / escritura
Puede usar los métodos de DOM Level 2 Core getAttribute()
, getAttributeNS()
, setAttribute()
y setAttributeNS()
para leer y escribir valores de elementos SVG, o puede usar las propiedades personalizadas y los métodos especificados en la IDL SVG 1.1 (Interfaz Lenguaje de definición).
Atributos Numéricos Simples
Por ejemplo, si tiene un elemento de círculo SVG:
<circle id="circ" cx="10" cy="20" r="15" />
puede usar métodos DOM para leer y escribir los atributos:
var circ = document.querySelector('#circ');
var x = circ.getAttribute('cx') * 1; // Use *1 to convert from string to number value
circ.setAttribute('cy', 25);
... o puede usar las propiedades cx
, cy
y r
definidas para SVGCircleElement
. Tenga en cuenta que estos no son números directos, sino que, como sucede con muchos accesores en SVG 1.1, permiten el acceso a valores animados. Estas propiedades son de tipo SVGAnimatedLength
. Sin tener en cuenta las unidades de animación y de longitud, puede utilizar atributos como:
var x = circ.cx.baseVal.value; // this is a number, not a string
circ.cy.baseVal.value = 25;
Transformaciones
Los grupos SVG se pueden usar para mover, rotar, escalar y, de lo contrario, transformar múltiples elementos gráficos en conjunto. (Para detalles sobre traducciones de SVG, vea el Capítulo 7 ). Aquí hay un grupo que hace una carita feliz en la que puede ajustar el tamaño, la rotación y la ubicación ajustando la transform
:
<g id="smiley" transform="translate(120,120) scale(5) rotate(30)">
<circle r="20" fill="yellow" stroke-width="2"/>
<path fill="none" d="M-10,5 a 5 3 0 0 0 20,0" stroke-width="2"/>
<circle cx="-6" cy="-5" r="2" fill="#000"/>
<circle cx="6" cy="-5" r="2" fill="#000"/>
</g>
El uso de scripts para ajustar la escala de esto a través de los métodos DOM requiere manipular todo el atributo de transform
como una cadena:
var face = document.querySelector('#smiley');
// Find the full string value of the attribute
var xform = face.getAttribute('transform');
// Use a Regular Expression to replace the existing scale with 'scale(3)'
xform = xform.replace( /scale\s*\([^)]+\)/, 'scale(3)' );
// Set the attribute to the new string.
face.setAttribute('transform',xform);
Con el SVG DOM se pueden recorrer las transformaciones específicas de la lista, encontrar la deseada y modificar los valores:
var face = document.querySelector('#smiley');
// Get the SVGTransformList, ignoring animation
var xforms = face.transform.baseVal;
// Find the scale transform (pretending we don't know its index)
for (var i=0; i<xforms.numberOfItems; ++i){
// Get this part as an SVGTransform
var xform = xforms.getItem(i);
if (xform.type == SVGTransform.SVG_TRANSFORM_SCALE){
// Set the scale; both X and Y scales are required
xform.setScale(3,3);
break;
}
}
- Para recorrer y manipular el número de transformaciones, consulte
SVGTransformList
. - Para manipular transformaciones individuales, vea
SVGTransform
.
Arrastrando elementos SVG
El uso del mouse para arrastrar un elemento SVG (o grupo de elementos) se puede lograr mediante:
- Agregar el controlador
mousedown
para iniciar el arrastre: agregar una traducción en el elemento para usar durante el arrastre (si es necesario), realizar un seguimiento de los eventos delmousemove
y agregar un controladormouseup
para finalizar el arrastre. - Durante el
mousemove
, transforme la posición del mouse de las coordenadas de la pantalla en las coordenadas locales para el objeto que está arrastrando y actualice la traducción según corresponda. - Durante
mouseup
, se eliminan losmousemove
ymouseup
.
// Makes an element in an SVG document draggable.
// Fires custom `dragstart`, `drag`, and `dragend` events on the
// element with the `detail` property of the event carrying XY
// coordinates for the location of the element.
function makeDraggable(el){
if (!el) return console.error('makeDraggable() needs an element');
var svg = el;
while (svg && svg.tagName!='svg') svg=svg.parentNode;
if (!svg) return console.error(el,'must be inside an SVG wrapper');
var pt=svg.createSVGPoint(), doc=svg.ownerDocument;
var root = doc.rootElement || doc.body || svg;
var xlate, txStartX, txStartY, mouseStart;
var xforms = el.transform.baseVal;
el.addEventListener('mousedown',startMove,false);
function startMove(evt){
// We listen for mousemove/up on the root-most
// element in case the mouse is not over el.
root.addEventListener('mousemove',handleMove,false);
root.addEventListener('mouseup', finishMove,false);
// Ensure that the first transform is a translate()
xlate = xforms.numberOfItems>0 && xforms.getItem(0);
if (!xlate || xlate.type != SVGTransform.SVG_TRANSFORM_TRANSLATE){
xlate = xforms.createSVGTransformFromMatrix( svg.createSVGMatrix() );
xforms.insertItemBefore( xlate, 0 );
}
txStartX=xlate.matrix.e;
txStartY=xlate.matrix.f;
mouseStart = inElementSpace(evt);
fireEvent('dragstart');
}
function handleMove(evt){
var point = inElementSpace(evt);
xlate.setTranslate(
txStartX + point.x - mouseStart.x,
txStartY + point.y - mouseStart.y
);
fireEvent('drag');
}
function finishMove(evt){
root.removeEventListener('mousemove',handleMove,false);
root.removeEventListener('mouseup', finishMove,false);
fireEvent('dragend');
}
function fireEvent(eventName){
var event = new Event(eventName);
event.detail = { x:xlate.matrix.e, y:xlate.matrix.f };
return el.dispatchEvent(event);
}
// Convert mouse position from screen space to coordinates of el
function inElementSpace(evt){
pt.x=evt.clientX; pt.y=evt.clientY;
return pt.matrixTransform(el.parentNode.getScreenCTM().inverse());
}
}