Descompunerea cercului SVG în căi
Publicat: 2022-03-10Acest articol începe cu o mărturisire: Îmi place să codific manual SVG. Nu este întotdeauna cazul, dar destul de des ar putea părea specific oamenilor care nu împărtășesc predilecția mea. Există un număr mare de beneficii în a putea scrie SVG manual, cum ar fi optimizarea SVG-urilor în moduri pe care un instrument nu le poate face (transformarea unei căi într-o cale sau o formă mai simplă) sau pur și simplu prin înțelegerea modului în care funcționează bibliotecile precum D3 sau Greensock. .
Acestea fiind spuse, aș dori să privesc mai îndeaproape formele circulare în SVG și lucrurile pe care le putem face cu ele când trecem de un cerc de bază. De ce cercuri? Ei bine, îmi plac cercurile. Sunt forma mea preferată.
În primul rând (sper că ați mai văzut un cerc de bază în SVG), iată un stilou care arată unul:
Se pot face o mulțime de lucruri cu un cerc: poate fi animat și poate avea diferite culori aplicate. Totuși, există două lucruri foarte drăguțe pe care nu le poți face pe un cerc în SVG 1.1: nu poți face ca un alt element grafic să se miște de-a lungul traseului cercului (folosind elementul animateMotion
) și nu poți forma un text de-a lungul căii unui cerc (acest lucru va să fie permis numai după lansarea SVG 2.0).
Transformând cercul nostru într-o cale
Există un mic instrument online care vă poate ajuta să creați căi din cercuri (puteți încerca aici), dar vom crea totul de la zero, astfel încât să putem afla ce se întâmplă cu adevărat în culise.
Pentru a face o cale circulară, vom face de fapt două arce, adică semicercuri care completează cercul într-o singură cale. După cum probabil ați observat în SVG de mai sus, atributele CX
, CY
și respectiv R
definesc locul în care este desenat cercul de-a lungul axei X și Y, în timp ce R
definește raza cercului. CX
și CY
creează centrul cercului, astfel încât cercul este desenat în jurul acelui punct.
Replicarea acelui cerc ar putea arăta astfel:
<path d=" M (CX - R), CY a R,R 0 1,0 (R * 2),0 a R,R 0 1,0 -(R * 2),0 " />
Rețineți că CX
este același cu atributul cx
al cercului; același lucru este valabil și pentru CY
și atributul cy
al cercului, precum și pentru R
și atributul r
al cercului. Caracterul mic este folosit pentru a defini a
segment de arc eliptic. Puteți folosi un Z
opțional (sau z
) pentru a închide calea.
Litera mică a
denotă începutul unui arc eliptic desenat relativ la poziția curentă - sau în cazul nostru specific:
<path d=" M 25, 50 a 25,25 0 1,1 50,0 a 25,25 0 1,1 -50,0 " />
Puteți vedea magia care se întâmplă în acest stilou:
Ascuns sub potecă este un cerc cu umplutură roșie. Pe măsură ce vă jucați cu valorile căii, veți vedea acel cerc atâta timp cât calea acoperă în totalitate cercul (calea în sine este un cerc de aceeași dimensiune) și vom ști că facem lucrurile corect .
Un lucru pe care ar trebui să-l știți este că atâta timp cât desenați arcuri relative, nu trebuie să repetați comanda a
pentru fiecare arc pe care îl desenați. Când primele 7 intrări sunt efectuate pentru arcul dvs., celelalte 7 intrări vor fi luate pentru următorul arc.
Puteți încerca acest lucru cu stiloul de mai sus, eliminând al doilea a
din cale:
a 25,25 0 1,1 50,0 25,25 0 1,1 -50,0
Acest lucru poate arăta la fel, dar prefer să-l las până când sunt gata să termin un desen și acest lucru mă ajută, de asemenea, să țin evidența unde mă aflu.
Cum funcționează această cale
În primul rând, trecem la o coordonată X,Y
poziționată absolut în imagine. Nu atrage nimic acolo - doar se mișcă acolo. Amintiți-vă că pentru un element cerc CX
, CY
reprezintă centrul cercului; dar așa cum se întâmplă în arcul eliptic, adevăratele CX
și CY
ale arcului vor fi calculate din celelalte proprietăți ale arcului respectiv.
Cu alte cuvinte, dacă vrem ca CX
-ul nostru să fie la 50
și raza noastră este 25
, atunci trebuie să trecem la 50 - 25
(dacă desenăm de la stânga la dreapta, desigur). Aceasta înseamnă că primul nostru arc este desenat din 25 X, 50 Y
ceea ce rezultă că primul nostru arc este 25,25 0 1,0 50,0
.
Să descompunem ce înseamnă de fapt valoarea 25,25 0 1,0 50,0
a arcului nostru:
-
25
: Raza X relativă a arcului; -
25
: Raza Y relativă a arcului; -
0 1,0
: nu voi vorbi despre cele trei valori medii (rotație, steagul arc mare și proprietățile steagului de baleiaj) pentru că nu sunt foarte importante în contextul exemplului curent atâta timp cât acestea sunt aceleași pentru ambele arce; -
50
: Coordonata X finală (relativă) a arcului; -
0
: Coordonata Y finală (relativă) a arcului.
Al doilea arc este un 25,25 0 1,0 -50,0
. Rețineți că acest arc va începe să deseneze de oriunde s-a oprit desenul ultimului arc. Desigur, raza X și Y sunt aceleași ( 25
), dar coordonata X finală este -50
față de cea curentă.
Evident, acest cerc ar fi putut fi desenat în multe moduri diferite. Acest proces de transformare a unui cerc într-o cale este cunoscut sub numele de descompunere. În specificațiile SVG 2, descompunerea unui cerc se va face cu 4 arce, cu toate acestea, metoda pe care o recomandă nu este încă posibilă, deoarece depinde în prezent de o caracteristică numită calea de completare a segmentului, care nu a fost încă specificată.
Pentru a vă arăta că putem desena cercul în multe feluri, am pregătit un mic stilou cu diverse exemple:
Dacă aruncați o privire mai atentă, veți vedea cercul nostru original împreună cu cinci exemple diferite despre cum să desenați trasee deasupra acelui cerc. Fiecare cale are un element de desc
copil care descrie utilizarea valorilor CX
, CY
și R
pentru a construi cercul. Primul exemplu este cel pe care l-am discutat aici, în timp ce alți trei folosesc variații care ar trebui să fie înțelese din citirea codului; Ultimele exemple utilizează patru arce semicirculare în loc de două, replicând oarecum procesul descris în specificațiile SVG 2 de mai sus.
Cercurile sunt stratificate unul peste altul folosind indexarea z naturală a SVG de plasare a elementelor care apar mai târziu în marcaj peste cele care vin mai devreme.
Dacă faceți clic pe traseele circulare din creion, primul clic va imprima modul în care este structurată calea către consolă și se va adăuga o clasă la element, astfel încât să vedeți culoarea conturului a modului în care este desenat cercul (puteți vedea că primul cerc este desenat cu o pană de pornire din cursă). Al doilea clic va elimina cercul, astfel încât să aveți posibilitatea de a interacționa cu cercul de mai jos.
Fiecare cerc are o culoare de umplere diferită; elementul cerc real este galben și va spune „Ați făcut clic pe cerc” pe consolă de fiecare dată când se face clic pe acesta. De asemenea, puteți, desigur, să citiți pur și simplu codul, deoarece elementele de desc
sunt destul de simple.
Mergând de la o cale la un cerc
Presupun că ați observat că, deși există multe moduri diferite de a desena cercul, căile folosite încă arată destul de asemănătoare. Adesea - în special în SVG-urile rezultate dintr-un program de desen - cercurile vor fi reprezentate de căi. Acest lucru se datorează probabil optimizării codului programului de grafică; odată ce ai codul pentru a desena o cale, poți desena orice, așa că folosește-l. Acest lucru poate duce la SVG-uri oarecum umflate, care sunt greu de raționat.
Lectură recomandată : „ Sfaturi pentru crearea și exportul de SVG-uri mai bune pentru web” de Sara Soueidan
Să luăm ca exemplu următorul SVG de la Wikipedia. Când te uiți la codul acelui fișier, vei vedea că are o mulțime de elemente de redactare după ce l-ai rulat prin SVGOMG al lui Jake Archibald! (despre care puteți citi mai multe aici), veți ajunge cu ceva de genul următor fișier care a fost destul de optimizat, dar cercurile din document sunt încă redate ca căi:
Deci, să vedem dacă ne putem da seama care ar trebui să fie acele cercuri dacă ar fi elemente reale ale cercului, având în vedere ceea ce știm despre cum funcționează căile. Prima cale din document nu este, evident, un cerc, în timp ce următoarele două sunt (afișând doar atributul 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
Așa că amintindu-ne că al doilea a
poate fi omis, să le rescriem pentru a avea puțin mai mult sens. (Prima cale este cercul mare.)
M39 20 a19 19 0 1 1-38 0 a19 19 0 1 1 38 0z
Aceste arcuri sunt atunci, evident, următoarele:
aR R 0 1 1 - (R * 2) 0 aR R 0 1 1 (R * 2) 0
Aceasta înseamnă că raza cercului nostru este 19
, dar care sunt valorile noastre CX
și CY
? Cred că M39
-ul nostru este de fapt CX + R
, ceea ce înseamnă că CX
este 20
și CY
este de asemenea 20
.
Să presupunem că adăugați într-un cerc după toate căile astfel:
<circle fill="none" stroke-width="1.99975" stroke="red" r="19" cx="20" cy="20" />
Veți vedea că este corect și că cercul roșu acoperă exact cercul mare. Al doilea cerc reformulat arată astfel:
M25 20 a5 5 0 1 1-10 0 5 5 0 1 1 10 0z
Evident, raza este 5
și pun pariu că valorile noastre CX
și CY
sunt aceleași ca înainte: - 20
.
Notă : Dacă CX = 20
, atunci CX + R = 25
. Cercul se află în interiorul celui mai mare din centru, așa că evident ar trebui să aibă aceleași valori CX
și CY
.
Adăugați următorul cerc la sfârșitul căilor:
<circle fill="yellow" r="5" cx="20" cy="20" />
Acum puteți vedea că acest lucru este corect aruncând o privire la următorul stilou:
Acum că știm care ar trebui să fie cercurile, putem elimina acele căi inutile și putem crea efectiv cercurile - așa cum puteți vedea aici:
Folosind calea noastră circulară pentru împachetarea textului
Deci, acum că avem cercurile noastre în căi, putem împacheta textul pe acele căi. Mai jos este un stilou cu aceleași căi ca și stiloul nostru anterior „Toate cercurile”, dar cu text înfășurat pe cale. Ori de câte ori dați clic pe o cale, acea cale va fi ștearsă și textul va fi împachetat pe următoarea cale disponibilă, astfel:
Privind diferitele căi, veți vedea mici diferențe între fiecare (mai multe despre asta într-un pic), dar mai întâi există o mică incompatibilitate între browsere de văzut - mai ales vizibilă în prima cale:
Dezvoltator Firefox | |
Crom | |
Microsoft Edge |
Motivul pentru care „S” de început al „Smashing” se află în acel unghi amuzant în soluția Firefox este că acolo am început de fapt să ne desenăm calea (datorită comenzii vR pe care am folosit-o). Acest lucru este mai evident în versiunea Chrome, unde puteți vedea clar prima pană în formă de plăcintă a cercului nostru pe care l-am desenat:
Chrome nu urmărește toate pene, așa că acesta este rezultatul când schimbați textul în „Smashing Magazine”. |
Motivul este că Chrome are o eroare cu privire la moștenirea atributului textLength
declarat pe elementul text
părinte. Dacă doriți ca ambele să arate la fel, puneți atributul textLength
pe elementul textPath
, precum și textul. De ce? Pentru că se dovedește că Firefox Developer are același bug dacă nu este specificat atributul textLength
pe elementul text
(așa este de câțiva ani încoace).
Microsoft Edge are o eroare total diferită; nu poate gestiona spațiul alb între Text
și elementul TextPath
copil. Odată ce ați eliminat spațiile albe și ați pus atributul textLength
atât pe elementele text
, cât și pe textPath
, toate vor arăta relativ la fel (cu mici variații din cauza diferențelor fonturilor implicite și așa mai departe). Deci, trei erori diferite pe trei browsere diferite - de aceea oamenii preferă adesea să lucreze cu biblioteci!
Următorul stilou arată cum pot fi rezolvate problemele:
Am eliminat, de asemenea, diferitele culori de umplere, deoarece face mai ușor să vedeți împachetarea textului. Eliminarea culorilor de umplere înseamnă că mica mea funcție de a vă permite să parcurgeți căile și să vedeți cum arată ele nu va funcționa decât dacă adaug un atribut pointer-events="all"
, așa că le-am adăugat și pe acestea.
Notă : puteți citi mai multe despre motivele acestui lucru în „Gestionarea interacțiunii SVG cu proprietatea Events Pointer”, explicată de Tiffany B. Brown.
Am discutat deja despre împachetarea căii multiarc, așa că haideți să ne uităm acum la celelalte. Deoarece avem o singură cale pe care ne înfășurăm, textul se va mișca întotdeauna în aceeași direcție.
Imagine | cale | Explicaţie |
---|---|---|
M CX, CY a R, R 0 1,0 -(R * 2), 0 a R, R 0 1,0 R * 2, 0 și folosește funcția de translate pentru a muta +R pe axa X. | Poziția de pornire pentru textPath (deoarece nu am specificat-o în niciun fel) este determinată de primul nostru arc final -(R * 2) , având în vedere raza pe care o are arcul însuși. | |
M (CX + R), CY a R,R 0 1,0 -(R * 2),0 a R,R 0 1,0 (R * 2),0 | Același lucru este valabil ca și calea anterioară. | |
M CX CY m -R, 0 a R,R 0 1,0 (R * 2),0 a R,R 0 1,0 -(R * 2),0 | Deoarece ne terminăm la (R * 2 ) în primul nostru arc, evident că vom începe din poziția opusă. Cu alte cuvinte, aceasta începe acolo unde s-au încheiat cele două căi anterioare. | |
M (CX - R), CY a R,R 0 1, (R * 2),0 1 a R,R 0 1, 1 -(R * 2),0 | Acesta începe în aceeași poziție ca și ultimul din cauza (R * 2) , dar rulează în sensul acelor de ceasornic deoarece am setat proprietatea sweep-flag (marcată cu galben) la 1 . |
Am văzut cum să împachetăm textul pe o singură cale într-un cerc. Să aruncăm o privire acum la modul în care putem împărți această cale în două căi și la beneficiile pe care le puteți obține din aceasta.
Spărgându-ne drumurile în părți
Există o mulțime de lucruri pe care le puteți face cu textul din calea dvs., adică obținerea de efecte stilistice cu elemente tspan
, setarea offset-ului textului sau animarea textului. Practic, orice vei face va fi constrâns de calea în sine. Dar, împărțind căile noastre multiarc în căi cu un singur arc, ne putem juca cu direcția textului nostru, indexarea z a diferitelor părți ale textului nostru și realizarea de animații mai complexe.
În primul rând, vom dori să folosim o altă imagine SVG pentru a arăta unele dintre efecte. Voi folosi diamantul din articolul despre evenimentele pointer pe care l-am menționat mai devreme. Mai întâi, să arătăm cum va arăta cu un text circular cu o singură cale așezat deasupra acestuia.
Să presupunem că cercul nostru este CX 295, CY 200, R 175
. Acum, urmând metoda cale circulară, vedem acum următoarele:
M (CX - R), CY a R,R 0 1,1 (R * 2),0 a R,R 0 1,1 -(R * 2),0
Nu voi vorbi despre calea sau dimensiunea textului, culoarea umplerii sau a conturului. Cu toții ar trebui să înțelegem asta până acum și să putem face ca acesta să fie orice ne dorim să fie. Dar, privind textul, putem vedea imediat câteva dezavantaje sau limitări:
- Tot textul rulează într-o singură direcție;
- Ar putea fi frumos ca o parte din text să treacă în spatele ametistului, mai ales acolo unde scrie REVISTA. Pentru a face „M” și „E” să se alinieze pe cerc, „A” trebuie să fie în punctul inferior lateral al ametistului, care se simte oarecum dezechilibrat într-un alt mod. (Simt că „A” ar trebui să fie poziționat cu precizie și îndreptat în jos în acel punct.)
Dacă vrem să remediem aceste probleme, trebuie să ne împărțim singura cale în două. În următorul stilou, am separat calea în două căi (și le-am plasat în zona de defs
a SVG-ului pentru ca textPath
-urile noastre să facă referire):
Din nou, presupunând că CX
-ul nostru este 295, CY 200, R 175
, atunci cele două căi sunt în formatul următor (pentru calea semicirculară de sus):
M (CX - R), CY a R,R 0 1,1 (R * 2),0
Și următoarele pentru partea de jos:
M (CX + R), CY a R,R 0 1,1 -(R * 2),0
Cu toate acestea, mai avem text circular care se mișcă toate în aceeași direcție. Pentru a remedia asta pentru orice, cu excepția Edge, tot ce trebuie să faceți este să adăugați atributul side="right"
la elementul text
care conține textPath
„MAGAZINE”.
Făcând textul să meargă în altă direcție
Dacă vrem să acceptăm cât mai multe browsere, trebuie să modificăm calea și să nu ne bazăm pe atributul side
care nu este pe deplin acceptat. Ceea ce putem face este să copiem calea semicercului de sus, dar să schimbăm matura de la 1
la 0
:
Inainte de:
M 120, 200 a 175,175 0 1,
M 120, 200 a 175,175 0 1,
1
350,0
350,0
După:
M 120, 200 a 175,175 0 1,
M 120, 200 a 175,175 0 1,
0
350,0
350,0
Dar textul nostru este acum desenat pe cercul interior definit de matură și nu va arăta atât de frumos în diferite browsere. Aceasta înseamnă că va trebui să mutăm poziția căii noastre pentru a ne alinia cu „S” din „Smashing”, să facem sfârșitul X al căii mai mare și să setăm o anumită compensare textului. După cum puteți vedea, există și o mică diferență de text între Firefox și celelalte, pe care o putem îmbunătăți prin creșterea atributului textLength
pe elementul text
, precum și prin eliminarea spațiului alb din textPath
(deoarece Firefox consideră evident că spațiul alb este semnificativ).
Soluția:
Schimbați indexul Z al unei părți a textului nostru circular
În cele din urmă, vrem să facem textul nostru să meargă atât în față, cât și în spatele ametistului. Ei bine, e ușor. Vă amintiți că indexarea z a elementului SVG se bazează pe locul în care se află în marcaj? Deci, dacă avem două elemente, elementul 1
va fi desenat în spatele elementului 2
. În continuare, tot ce trebuie să facem este să mutăm un element de text
în sus în marcajul nostru SVG, astfel încât să fie desenat înaintea ametistului.
Rezultatul îl puteți vedea mai jos în care părți din cuvântul „REVISTA” sunt ascunse de punctul inferior al ametistului.
Dacă aruncați o privire la marcaj, puteți vedea că semicercul inferior al textului a fost mutat pentru a fi înaintea căii care trage ametistul.
Animarea părților cercului nostru
Așadar, acum avem capacitatea de a face text circular controlând complet direcționalitatea părților textului nostru, punând textul în două semicercuri. Acest lucru poate fi, desigur, exploatat și pentru a face animații ale textului. Realizarea de animații SVG între browsere este într-adevăr subiectul unui alt articol (sau mult mai multe articole). Aceste exemple vor funcționa numai în Chrome și Firefox datorită utilizării sintaxei animațiilor SMIL în loc de cadre cheie CSS sau instrumente precum Greensock. Dar oferă un bun indicator al efectelor pe care le puteți obține prin animarea cercului descompus.
Luați următorul stilou injector:
Vă rugăm să apăsați butonul „Rerun” de pe codepen pentru a vedea animația în acțiune. Cele două părți ale textului nostru circular încep să se anime în același timp, dar au o durată diferită, așa că se termină în momente diferite. Deoarece textLength
atributul textLength, am pus două directive animate
sub fiecare text - una pentru elementul text
(deci va funcționa Firefox) și una pentru elementul textpath
(deci Chrome va funcționa).
Concluzie
În acest articol, am văzut cum să transformăm un cerc într-o cale și înapoi din nou, pentru a înțelege mai bine când trebuie să optimizăm o cale și când nu. Am văzut cum transformarea cercului într-o cale ne eliberează să plasăm textul pe calea circulară, dar și cum să împărțim în continuare calea circulară în semicercuri și să obținem un control mai deplin asupra direcționalității și animației părților componente ale textului nostru circular. .
Citiți suplimentare despre SmashingMag:
- Regândirea SVG-ului receptiv
- Animarea fișierelor SVG cu SVGator
- Stilizarea și animarea SVG-urilor cu CSS
- Gestionarea interacțiunii SVG cu proprietatea Pointer Events