SVG
Scripting
Ricerca…
Osservazioni
Scripting SVG utilizzando le interfacce DOM native è attualmente (2016) in uno stato di lieve cambiamento. L'attuale standard SVG (1.1) è ben implementato dalla maggior parte dei browser Web principali. Tuttavia, poiché lo standard SVG 2.0 è in fase di sviluppo, alcuni browser hanno iniziato a rimuovere le funzionalità SVG 1.1 che saranno obsolete in 2.0. Puoi vedere un elenco completo delle modifiche proposte da SVG 1.1 a SVG 2.0 nell'Appendice L di SVG 2.0 .
Sostituzione di pathSegList
e altro utilizzo di SVGPathSeg
In SVG 1.1 gli elementi <path>
sono definiti per avere una proprietà pathSegList
che dà accesso a una rappresentazione nativa di tutti i comandi di percorso . Google Chrome v48 ha rimosso questa proprietà alla fine del 2015, in preparazione di una proposta di sostituzione in SVG 2.0 . Fino a quando non viene aggiunto il supporto SVG 2.0, è necessario utilizzare un polyfill per ripristinare la funzionalità 1.1 o per implementare l'API 2.0 proposta .
Sostituire getTransformToElement()
Anche Chrome v48 ha rimosso il metodo SVGGraphicsElement.getTransformToElement()
. Esiste un semplice polyfill per implementare il vecchio metodo .
Creare un elemento
Il modo più semplice per comprendere la creazione e la modifica degli elementi SVG è di operare sugli elementi usando le interfacce DOM Level 2 Core , come faresti con HTML o XML.
È imperativo che gli elementi creati da JavaScript siano creati nello stesso spazio dei nomi dichiarato nell'elemento SVG - in questo esempio: " http://www.w3.org/2000/svg ". Tuttavia, quasi tutti gli attributi degli elementi SVG non sono in alcun spazio dei nomi. Non li necessario inserire nel namespace SVG.
Qui mostriamo SVG ospitato all'interno di HTML, poiché si tratta di un caso comune:
<!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>
Ci sono alcuni attributi che devono essere creati in un particolare spazio dei nomi. Sono quelli elencati con i due punti nei loro nomi nell'indice degli attributi SVG . Nello specifico, sono: xlink:actuate
xlink:arcrole
, xlink:arcrole
, xlink:href
, xlink:role
, xlink:show
, xlink:title
, xlink:type
, xml:base
, xml:lang
e xml:space
. Imposta questi attributi usando 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' );
Se crei spesso elementi, in particolare con molti attributi, una funzione di supporto come la seguente può farti risparmiare digitazione, evitare errori e rendere il tuo codice più facile da leggere:
<!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>
Lettura / Scrittura attributi
È possibile utilizzare i metodi DOM Level 2 Core getAttribute()
, getAttributeNS()
, setAttribute()
e setAttributeNS()
per leggere e scrivere valori dagli elementi SVG oppure utilizzare proprietà e metodi personalizzati specificati nell'IDL SVG 1.1 (interfaccia Linguaggio di definizione).
Semplici attributi numerici
Ad esempio, se si dispone di un elemento cerchio SVG:
<circle id="circ" cx="10" cy="20" r="15" />
puoi utilizzare i metodi DOM per leggere e scrivere gli attributi:
var circ = document.querySelector('#circ');
var x = circ.getAttribute('cx') * 1; // Use *1 to convert from string to number value
circ.setAttribute('cy', 25);
... oppure è possibile utilizzare le proprietà personalizzate cx
, cy
e r
definite per SVGCircleElement
. Si noti che questi non sono numeri diretti, ma invece, come con molti accessori in SVG 1.1, consentono l'accesso ai valori animati. Queste proprietà sono di tipo SVGAnimatedLength
. Ignorando le animazioni e le unità di lunghezza, puoi usare attributi come:
var x = circ.cx.baseVal.value; // this is a number, not a string
circ.cy.baseVal.value = 25;
trasformazioni
I gruppi SVG possono essere utilizzati per spostare, ruotare, ridimensionare e in altro modo trasformare più elementi grafici nel loro complesso. (Per i dettagli sulle traduzioni SVG, consultare il Capitolo 7 ). Ecco un gruppo che fa una faccina che è possibile regolare la dimensione, la rotazione e la posizione di regolando 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>
L'uso dello script per regolare la scala di questo tramite i metodi DOM richiede la manipolazione dell'intero attributo transform
come stringa:
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 SVG DOM è possibile attraversare le trasformazioni specifiche dell'elenco, trovare quello desiderato e modificare i valori:
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;
}
}
- Per attraversare e manipolare il numero di trasformazioni, vedere
SVGTransformList
. - Per manipolare le singole trasformazioni, vedere
SVGTransform
.
Trascinando elementi SVG
Usare il mouse per trascinare un elemento SVG (o un gruppo di elementi) può essere ottenuto da:
- L'aggiunta di
mousedown
gestore per inizio la resistenza: l'aggiunta di una traduzione sul elemento da utilizzare durante il trascinamento (se necessario), il monitoraggiomousemove
eventi, e l'aggiunta di unmouseup
gestore di porre fine alla resistenza. - Durante il
mousemove
, trasforma la posizione del mouse dalle coordinate dello schermo nelle coordinate locali dell'oggetto che stai trascinando e aggiorna la traduzione di conseguenza. - Durante il
mouseup
, rimuovendo i gestori dimousemove
emouseup
.
// 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());
}
}