Scomposizione del cerchio SVG in percorsi
Pubblicato: 2022-03-10Questo articolo inizia con una confessione: mi piace codificare manualmente SVG. Non è sempre così, ma abbastanza spesso può sembrare strano a persone che non condividono la mia predilezione. Ci sono un buon numero di vantaggi nell'essere in grado di scrivere SVG a mano, come ottimizzare gli SVG in modi che uno strumento non può (trasformare un percorso in un percorso o una forma più semplice) o semplicemente capire come funzionano librerie come D3 o Greensock .
Detto questo, mi piacerebbe esaminare più da vicino le forme circolari in SVG e le cose che possiamo fare con esse quando ci spostiamo oltre un cerchio di base. Perché cerchi? Beh, io amo i cerchi. Sono la mia forma preferita.
Prima di tutto (si spera che tu abbia già visto un cerchio di base in SVG), ecco una penna che ne mostra uno:
Si possono fare molte cose con un cerchio: può essere animato e può avere diversi colori applicati. Tuttavia, ci sono due cose molto belle che non puoi fare in modo che un cerchio faccia in SVG 1.1: non puoi far muovere un altro elemento grafico lungo il percorso del cerchio (usando l'elemento animateMotion
) e non puoi dare forma a un testo lungo il percorso di un cerchio (questo essere consentito solo dopo il rilascio di SVG 2.0).
Trasformare il nostro cerchio in un percorso
C'è un piccolo strumento online che può aiutarti a creare percorsi fuori dai cerchi (puoi provarlo qui), ma creeremo tutto da zero in modo da poter scoprire cosa sta davvero succedendo dietro le quinte.
Per fare un percorso circolare, creeremo effettivamente due archi, cioè semicerchi che completano il cerchio in un percorso. Come probabilmente avrai notato nell'SVG sopra, gli attributi CX
, CY
e R
definiscono rispettivamente dove il cerchio viene disegnato lungo l'asse X e Y, mentre R
definisce il raggio del cerchio. CX
e CY
creano il centro del cerchio, quindi il cerchio viene disegnato attorno a quel punto.
Replicare quel cerchio potrebbe assomigliare a questo:
<path d=" M (CX - R), CY a R,R 0 1,0 (R * 2),0 a R,R 0 1,0 -(R * 2),0 " />
Nota che CX
è lo stesso dell'attributo cx
del cerchio; lo stesso vale per CY
e l'attributo cy
del cerchio, così come R
e l'attributo r
del cerchio. Il carattere piccolo a
viene utilizzato per definire un segmento di un arco ellittico. È possibile utilizzare una Z
(o z
) opzionale per chiudere il percorso.
La lettera minuscola a
denota l'inizio di un arco ellittico disegnato relativamente alla posizione attuale — o nel nostro caso specifico:
<path d=" M 25, 50 a 25,25 0 1,1 50,0 a 25,25 0 1,1 -50,0 " />
Puoi vedere la magia che accade in questa penna:
Nascosto sotto il percorso c'è un cerchio con un riempimento rosso. Mentre giochi con i valori del percorso, vedrai quel cerchio fintanto che il percorso copre completamente il cerchio (il percorso stesso è un cerchio della stessa dimensione) e sapremo che stiamo facendo le cose per bene .
Una cosa che dovresti anche sapere è che finché stai disegnando archi relativi, non è necessario ripetere il comando a
per ogni arco che disegna. Quando i primi 7 input sono terminati per il tuo arco, i secondi 7 input verranno presi per l'arco successivo.
Puoi provarlo con la penna sopra rimuovendo la seconda a
nel percorso:
a 25,25 0 1,1 50,0 25,25 0 1,1 -50,0
Potrebbe sembrare lo stesso, ma preferisco lasciarlo finché non sono pronto per finire un disegno, e questo mi aiuta anche a tenere traccia di dove mi trovo.
Come funziona questo percorso
Per prima cosa, ci spostiamo su una coordinata X,Y
assolutamente posizionata nell'immagine. Non disegna nulla lì, si sposta semplicemente lì. Ricorda che per un elemento circolare CX
, CY
denota il centro del cerchio; ma come accade nell'arco ellittico, il vero CX
e CY
dell'arco sarà calcolato dalle altre proprietà di quell'arco.
In altre parole, se vogliamo che il nostro CX
sia a 50
e il nostro raggio sia 25
, allora dobbiamo spostarci a 50 - 25
(se stiamo disegnando da sinistra a destra, ovviamente). Ciò significa che il nostro primo arco è tracciato da 25 X, 50 Y
che risulta che il nostro primo arco è 25,25 0 1,0 50,0
.
Analizziamo cosa significa effettivamente il valore 25,25 0 1,0 50,0
del nostro arco:
-
25
: Il raggio X relativo dell'arco; -
25
: Il raggio Y relativo dell'arco; -
0 1,0
: Non parlerò dei tre valori medi (rotazione, large-arc-flag e le proprietà sweep-flag) perché non sono molto importanti nel contesto dell'esempio corrente purché siano sono gli stessi per entrambi gli archi; -
50
: La coordinata X finale (relativa) dell'arco; -
0
: La coordinata Y finale (relativa) dell'arco.
Il secondo arco è un 25,25 0 1,0 -50,0
. Tieni presente che questo arco inizierà a disegnare da dove l'ultimo arco ha smesso di disegnare. Naturalmente, il raggio X e Y sono gli stessi ( 25
), ma la coordinata X finale è -50
di quella attuale.
Ovviamente questo cerchio avrebbe potuto essere disegnato in molti modi diversi. Questo processo di trasformare un cerchio in un percorso è noto come decomposizione. Nella specifica SVG 2 la scomposizione di un cerchio verrà eseguita con 4 archi, tuttavia, il metodo che consiglia non è ancora possibile utilizzare, poiché attualmente dipende da una funzionalità denominata percorso chiuso di completamento del segmento che non è stato ancora specificato.
Per mostrarti che possiamo disegnare il cerchio in molti modi, ho preparato una piccola penna con vari esempi:
Se dai un'occhiata più da vicino, vedrai il nostro cerchio originale insieme a cinque diversi esempi di come disegnare percorsi sopra quel cerchio. Ogni percorso ha un elemento desc
figlio che descrive l'uso dei valori CX
, CY
e R
per costruire il cerchio. Il primo esempio è quello di cui abbiamo discusso qui, mentre altri tre utilizzano variazioni che dovrebbero essere comprensibili dalla lettura del codice; gli ultimi esempi utilizzano quattro archi semicircolari invece di due, replicando in qualche modo il processo descritto nelle specifiche SVG 2 collegate sopra.
I cerchi sono sovrapposti l'uno sull'altro utilizzando l'indicizzazione z naturale di SVG per posizionare gli elementi che vengono dopo nel markup sopra quelli che vengono prima.
Se fai clic sui percorsi circolari nella penna, il primo clic stamperà come è strutturato il percorso sulla console e aggiungerà una classe all'elemento in modo da vedere il colore del tratto di come è disegnato il cerchio (puoi vedere che il primo cerchio sia disegnato con un cuneo di partenza dal tratto). Il secondo clic rimuoverà il cerchio in modo da avere la possibilità di interagire con il cerchio sottostante.
Ogni cerchio ha un colore di riempimento diverso; l'elemento del cerchio effettivo è giallo e dirà "Hai cliccato sul cerchio" alla console ogni volta che viene cliccato. Ovviamente puoi anche leggere semplicemente il codice poiché gli elementi desc
sono abbastanza semplici.
Andando da un percorso a un cerchio
Suppongo che tu abbia notato che mentre ci sono molti modi diversi per disegnare il cerchio, i percorsi usati sembrano ancora abbastanza simili. Spesso, specialmente nell'output SVG da un programma di disegno, i cerchi saranno rappresentati da percorsi. Ciò è probabilmente dovuto all'ottimizzazione del codice del programma grafico; una volta che hai il codice per disegnare un percorso puoi disegnare qualsiasi cosa, quindi usalo. Questo può portare a SVG un po' gonfi su cui è difficile ragionare.
Letture consigliate : " Suggerimenti per creare ed esportare SVG migliori per il Web" di Sara Soueidan
Prendiamo come esempio il seguente SVG da Wikipedia. Quando guardi il codice per quel file, vedrai che ha un sacco di modifiche dell'editor dopo averlo eseguito tramite SVGOMG di Jake Archibald! (di cui puoi leggere di più qui), ti ritroverai con qualcosa come il seguente file che è stato abbastanza ottimizzato ma i cerchi nel documento sono ancora visualizzati come percorsi:
Quindi, vediamo se riusciamo a capire quali dovrebbero essere quei cerchi se fossero elementi di cerchio reali, dato quello che sappiamo su come funzionano i percorsi. Il primo percorso nel documento non è ovviamente un cerchio mentre i due successivi lo sono (mostrando solo l'attributo d
):
M39 20a19 19 0 1 1-38 0 19 19 0 1 1 38 0z
M25 20a5 5 0 1 1-10 0 5 5 0 1 1 10 0z
Quindi, ricordando che la seconda a
può essere tralasciata, riscriviamoli per avere un po' più di senso. (Il primo percorso è il grande cerchio.)
M39 20 a19 19 0 1 1-38 0 a19 19 0 1 1 38 0z
Questi archi sono quindi ovviamente i seguenti:
aR R 0 1 1 - (R * 2) 0 aR R 0 1 1 (R * 2) 0
Ciò significa che il raggio del nostro cerchio è 19
, ma quali sono i nostri valori CX
e CY
? Penso che il nostro M39
sia in realtà CX + R
, il che significa che CX
è 20
e anche CY
è 20
.
Diciamo che aggiungi in un cerchio dopo tutti i percorsi come questo:
<circle fill="none" stroke-width="1.99975" stroke="red" r="19" cx="20" cy="20" />
Vedrai che è corretto e che il cerchio tratteggiato in rosso copre esattamente il cerchio grande. Il secondo percorso circolare riformulato si presenta così:
M25 20 a5 5 0 1 1-10 0 5 5 0 1 1 10 0z
Ovviamente, il raggio è 5
e scommetto che i nostri valori CX
e CY
sono gli stessi di prima: - 20
.
Nota : se CX = 20
, allora CX + R = 25
. Il cerchio si trova all'interno di quello più grande al centro, quindi ovviamente dovrebbe avere gli stessi valori CX
e CY
.
Aggiungi il seguente cerchio alla fine dei percorsi:
<circle fill="yellow" r="5" cx="20" cy="20" />
Ora puoi vedere che questo è corretto dando un'occhiata alla seguente penna:
Ora che sappiamo quali dovrebbero essere i cerchi, possiamo rimuovere quei percorsi non necessari e creare effettivamente i cerchi, come puoi vedere qui:
Usando il nostro percorso circolare per avvolgere il testo
Quindi ora che abbiamo i nostri cerchi nei percorsi, possiamo avvolgere il testo su quei percorsi. Di seguito è riportata una penna con gli stessi percorsi della nostra precedente penna "Tutti i cerchi", ma con il testo avvolto sul percorso. Ogni volta che fai clic su un percorso, quel percorso verrà eliminato e il testo verrà spostato sul successivo percorso disponibile, in questo modo:
Osservando i diversi percorsi, vedrai minuscole differenze tra ciascuno di essi (ne parleremo tra un po'), ma prima c'è una piccola incompatibilità tra browser da vedere, particolarmente evidente nel primo percorso:
Sviluppatore Firefox | |
Cromo | |
Microsoft Edge |
Il motivo per cui la "S" iniziale di "Smashing" si trova in quella strana angolazione nella soluzione di Firefox è che è lì che abbiamo effettivamente iniziato a tracciare il nostro percorso (a causa del comando vR che abbiamo usato). Questo è più ovvio nella versione Chrome dove puoi vedere chiaramente il primo cuneo a forma di torta del nostro cerchio che abbiamo disegnato:
Chrome non segue tutti i cunei, quindi questo è il risultato quando modifichi il testo in "Smashing Magazine". |
Il motivo è che Chrome ha un bug relativo all'ereditarietà dell'attributo textLength
dichiarato sull'elemento di text
padre. Se vuoi che entrambi abbiano lo stesso aspetto, inserisci l'attributo textLength
sull'elemento textPath
e sul testo. Come mai? Perché si scopre che Firefox Developer ha lo stesso bug se l'attributo textLength
non è specificato sull'elemento di text
(questo è il caso ormai da alcuni anni).
Microsoft Edge ha un bug completamente diverso; non può gestire gli spazi bianchi tra il Text
e l'elemento TextPath
figlio. Dopo aver rimosso gli spazi bianchi e inserito l'attributo textLength
su entrambi gli elementi text
e textPath
, sembreranno tutti relativamente uguali (con piccole variazioni dovute a differenze nei caratteri predefiniti e così via). Quindi, tre diversi bug su tre diversi browser: ecco perché le persone spesso preferiscono lavorare con le librerie!
La penna seguente mostra come risolvere i problemi:
Ho anche rimosso i vari colori di riempimento perché rende più facile vedere l'avvolgimento del testo. Rimuovere i colori di riempimento significa che la mia piccola funzione per consentirti di scorrere i percorsi e vedere come appaiono non funzionerà a meno che non aggiunga un attributo pointer-events="all"
, quindi ho aggiunto anche quelli.
Nota : puoi leggere ulteriori informazioni sui motivi in "Gestione dell'interazione SVG con la proprietà degli eventi Pointer" spiegato da Tiffany B. Brown.
Abbiamo già discusso del wrapping del percorso multiarco, quindi diamo un'occhiata agli altri. Poiché abbiamo un percorso su cui stiamo andando a capo, il testo si sposterà sempre nella stessa direzione.
Immagine | Sentiero | Spiegazione |
---|---|---|
M CX, CY a R, R 0 1,0 -(R * 2), 0 a R, R 0 1,0 R * 2, 0 e usa la funzione di translate per spostare +R sull'asse X. | La posizione iniziale per il nostro textPath (poiché non l'abbiamo specificata in alcun modo) è determinata dal nostro primo arco finale -(R * 2) , dato il raggio che ha l'arco stesso. | |
M (CX + R), CY a R,R 0 1,0 -(R * 2),0 a R,R 0 1,0 (R * 2),0 | Lo stesso vale per il percorso precedente. | |
M CX CY m -R, 0 a R,R 0 1,0 (R * 2),0 a R,R 0 1,0 -(R * 2),0 | Dal momento che stiamo finendo a (R * 2 ) nel nostro primo arco, inizieremo ovviamente nella posizione opposta. In altre parole, questo inizia dove sono finiti i nostri due percorsi precedenti. | |
M (CX - R), CY a R,R 0 1, 1 (R * 2),0 a R,R 0 1, 1 -(R * 2),0 | Questo inizia nella stessa posizione dell'ultimo a causa di (R * 2) , ma funziona in senso orario perché abbiamo impostato la proprietà sweep-flag (contrassegnata in giallo) su 1 . |
Abbiamo visto come avvolgere il testo su un unico percorso in un cerchio. Diamo ora un'occhiata a come possiamo dividere quel percorso in due percorsi e ai vantaggi che puoi trarne.
Spezzando i nostri percorsi in parti
Ci sono molte cose che puoi fare con il testo nel tuo percorso, ad esempio ottenere effetti stilistici con elementi tspan
, impostare l'offset del testo o animare il testo. Fondamentalmente, qualunque cosa tu faccia sarà vincolata dal percorso stesso. Ma suddividendo i nostri percorsi multiarco in percorsi ad arco singolo, possiamo giocare con la direzione del nostro testo, l'indicizzazione z di diverse parti del nostro testo e ottenere animazioni più complesse.
Innanzitutto, vorremo utilizzare un'altra immagine SVG per mostrare alcuni degli effetti. Userò il diamante dell'articolo sugli eventi del puntatore che ho menzionato in precedenza. Per prima cosa, mostriamo come apparirà con un testo circolare a tracciato singolo posizionato sopra di esso.
Assumiamo che il nostro cerchio sia CX 295, CY 200, R 175
. Ora, seguendo il metodo del percorso circolare, ora vediamo quanto segue:
M (CX - R), CY a R,R 0 1,1 (R * 2),0 a R,R 0 1,1 -(R * 2),0
Non parlerò del percorso o della dimensione del testo, del riempimento o del colore del tratto. Dovremmo capirlo tutti ormai ed essere in grado di farlo diventare ciò che vogliamo che sia. Ma guardando il testo, possiamo vedere subito alcuni aspetti negativi o limitazioni:
- Il testo va tutto in una direzione;
- Potrebbe essere bello che parte del testo vada dietro l'ametista, specialmente dove dice MAGAZINE. Per allineare la "M" e la "E" sul cerchio, la "A" deve trovarsi sul punto laterale inferiore dell'ametista, che sembra sbilanciato in un altro modo. (Sento che la "A" dovrebbe essere posizionata con precisione e puntata verso il basso in quel punto.)
Se vogliamo risolvere questi problemi, dobbiamo dividere il nostro unico percorso in due. Nella penna seguente, ho separato il percorso in due percorsi (e li ho inseriti nell'area defs
dell'SVG per fare riferimento al nostro textPath
s):
Di nuovo, supponendo che il nostro CX
sia 295, CY 200, R 175
, i due percorsi sono nel formato seguente (per il percorso semicircolare superiore):
M (CX - R), CY a R,R 0 1,1 (R * 2),0
E quanto segue per il fondo:
M (CX + R), CY a R,R 0 1,1 -(R * 2),0
Tuttavia, abbiamo ancora un testo circolare che si muove tutto nella stessa direzione. Per risolvere il problema per tutto tranne che per Edge, tutto ciò che devi fare è aggiungere l'attributo side="right"
all'elemento di text
che contiene textPath
'MAGAZINE'.
Far andare il testo in un'altra direzione
Se vogliamo supportare quanti più browser possibile, dobbiamo modificare il percorso e non fare affidamento sull'attributo side
che non è completamente supportato. Quello che possiamo fare è copiare il nostro percorso del semicerchio superiore, ma cambiare lo sweep da 1
a 0
:
Prima:
M 120, 200 a 175,175 0 1,
M 120, 200 a 175,175 0 1,
1
350,0
350,0
Dopo:
M 120, 200 a 175,175 0 1,
M 120, 200 a 175,175 0 1,
0
350,0
350,0
Ma il nostro testo è ora disegnato sul cerchio interno definito dallo sweep e non sembrerà così bello in diversi browser. Ciò significa che dovremo spostare la posizione del nostro percorso per allinearlo con la "S" di "Smashing", aumentare la X finale del percorso e impostare un po' di offset rispetto al testo. Come puoi vedere, c'è anche una piccola differenza di testo tra Firefox e gli altri che possiamo migliorare aumentando l'attributo textLength
sull'elemento di text
, oltre a rimuovere gli spazi bianchi da textPath
(poiché Firefox evidentemente pensa che gli spazi bianchi siano significativi).
La soluzione:
Cambia l'indice Z di parte del nostro testo circolare
Infine, vogliamo che il nostro testo vada sia davanti che dietro l'ametista. Bene, è facile. Ricorda che l'indicizzazione z degli elementi di SVG si basa su dove si trovano nel markup? Quindi, se abbiamo due elementi, l'elemento 1
verrà disegnato dietro l'elemento 2
. Successivamente, tutto ciò che dobbiamo fare è spostare un elemento di text
in alto nel nostro markup SVG in modo che venga disegnato prima dell'ametista.
Puoi vedere il risultato di seguito in cui parti della parola 'MAGAZINE' sono nascoste dal punto inferiore dell'ametista.
Se dai un'occhiata al markup, puoi vedere che il semicerchio inferiore del testo è stato spostato prima del percorso che disegna l'ametista.
Animare le parti del nostro cerchio
Quindi ora abbiamo la possibilità di creare un testo circolare controllando completamente la direzionalità delle parti del nostro testo mettendo il testo in due semicerchi. Questo può, ovviamente, essere sfruttato anche per realizzare animazioni del testo. La creazione di animazioni SVG cross-browser è davvero oggetto di un altro articolo (o molti più articoli). Questi esempi funzioneranno solo in Chrome e Firefox a causa dell'utilizzo della sintassi delle animazioni SMIL invece dei fotogrammi chiave CSS o di strumenti come Greensock. Ma fornisce un buon indicatore degli effetti che puoi ottenere animando il cerchio scomposto.
Prendi la seguente penna:
Premi il pulsante "Riesegui" sul codepen per vedere l'animazione in azione. Le due parti del nostro testo circolare iniziano ad animarsi contemporaneamente, ma hanno una durata diversa, quindi terminano in momenti diversi. Poiché stiamo animando l'attributo textLength
, abbiamo inserito due direttive animate
sotto ogni testo: una per l'elemento di text
(quindi Firefox funzionerà) e una per l'elemento textpath
(quindi Chrome funzionerà).
Conclusione
In questo articolo abbiamo visto come trasformare un cerchio in un percorso e viceversa, per capire meglio quando è necessario ottimizzare un percorso e quando no. Abbiamo visto come trasformare il cerchio in un percorso ci liberi di posizionare il testo sul percorso circolare, ma anche come suddividere ulteriormente il percorso circolare in semicerchi e ottenere un controllo più completo sulla direzionalità e sull'animazione delle parti componenti del nostro testo circolare .
Ulteriori letture su SmashingMag:
- Ripensare un SVG reattivo
- Animazione di file SVG con SVGator
- Styling e animazione di SVG con CSS
- Gestione dell'interazione SVG con la proprietà Pointer Events