Tinklaraščio įrašas
19/6/2025

SVG path elemento iškodavimas: kreivių ir lankų komandos

Tęsdama savo misiją išmokyti jus koduoti vektorius rankiniu būdu, Myriam Frisano antroji path elemento gilinimosi dalis nagrinėja sudėtingiausius galingiausio SVG elemento aspektus. Ji padės jums suprasti pagrindines taisykles ir funkcijas, kaip konstruojamos kreivės ir lankai. Baigę šį straipsnį, jūsų įrankių rinkinys bus pasirengęs visų tipų užduotims, reikalingoms piešti kodu – net jei kai kurios linijos vingiuoja ir sukasi.

Pirmojoje SVG path iškodavimo dalyje daugiausia nagrinėjome, kaip konvertuoti dalykus iš semantinių žymių (line, polyline, polygon) į path komandų sintaksę, tačiau path elementas iš tiesų nepasiūlė mums jokių naujų formų parinkčių. Šiame straipsnyje tai pasikeis, nes mokysimės piešti kreives ir lankus, kurie yra tiesiog elipsės dalys.

Trumpa ankstesnių straipsnių apžvalga

Jei tai jūsų pirmas susitikimas su šia serija, rekomenduojame susipažinti su SVG kodavimo ranka pagrindais, taip pat su tuo, kaip veikia <marker>, ir turėti pagrindinį supratimą apie animate, nes šiame vadove tai neaiškinama. Taip pat rekomenduojame žinoti apie M/m komandą <path> d atribute (parašėme minėtą straipsnį apie path linijų komandas, kad padėtume).

Pastaba: Šis straipsnis skirtas tik kreivių ir lankų komandų sintaksei ir nesiūlo įvado į path kaip elementą.

Prieš pradedant, norime greitai apžvelgti, kaip koduojame SVG – naudojant „JavaScript“. Nemėgstame dirbti su skaičiais ir matematika, o skaitydami SVG kodą, kuriame kiekvienas atributas užpildytas skaičiais, prarandame bet kokį supratimą. Suteikdami koordinatėms pavadinimus ir turėdami lengvai skaitomą bei išrašytą matematiką, mums daug geriau sekasi su tokio tipo kodu, ir manome, kad ir jums seksis.

Kadangi šio straipsnio tikslas yra suprasti path sintaksę, o ne išdėstymą ar kaip panaudoti ciklus ir kitus paprastesnius dalykus, nenagrinėsime visos kiekvieno pavyzdžio sąrankos. Pasidalinsime kodo fragmentais, tačiau atkreipkite dėmesį, kad jis gali būti šiek tiek pakoreguotas nuo „CodePen“ arba supaprastintas, kad straipsnį būtų lengviau skaityti. Tačiau, jei kyla konkrečių klausimų apie kodą, kurio nėra tekste, bet yra „CodePen“ demonstracinėse versijose – komentarų skiltis, kaip visada, yra atvira.

Kad viskas būtų nepriklausoma nuo karkaso, kodas parašytas grynu „JavaScript“, nors praktikoje dirbant su sudėtingais vaizdais labai rekomenduojamas „TypeScript“.

Bézier kreivių piešimas

Gebėjimas piešti linijas, daugiakampius, laužtes ir jų sudėtines versijas yra smagu ir naudinga, tačiau path gali nuveikti daugiau nei tik pasiūlyti kriptiškesnes pagrindinių semantinių SVG žymių implementacijas.

Vienas iš tų papildomų tipų yra Bézier kreivės.

Yra keletas skirtingų kreivių komandų. Ir čia atsiranda taškų ir valdymo taškų idėja.

Bézier matematinis braižymas nepatenka į šio straipsnio apimtį.

Tačiau yra vizualiai nuostabus Freya Holmér vaizdo įrašas pavadinimu „Bézier kreivių grožis“, kuriame gilinamasi į kubinių ir kvadratinių Bézier kreivių konstravimą su gražia animacija, o matematika tampa daug lengviau virškinama.

Laimei, SVG leidžia mums piešti kvadratines kreives su vienu valdymo tašku ir kubines kreives su dviem valdymo taškais, neatliekant jokios papildomos matematikos.

Taigi, kas yra valdymo taškas? Valdymo taškas yra rankenėlės, kuri valdo kreivę, padėtis. Tai nėra taškas, kuris yra nupiešiamas.

Atradome, kad geriausias būdas suprasti šias path komandas yra atvaizduoti jas kaip grafinę vartotojo sąsają (GUI), kaip tai darytų „Affinity“ ir „Illustrator“. Tada nupiešti „rankenėles“ ir keletą atsitiktinių kreivių su skirtingomis savybėmis ir pamatyti, kaip jos veikia kreivę. Matant tą animaciją taip pat labai padeda suprasti šių komandų mechaniką.

Būtent tam naudosime žymeklius ir animaciją tolesnėse vizualizacijose. Pastebėsite, kad naudojami žymekliai yra stačiakampiai ir apskritimai, ir kadangi jie yra sujungti su linijomis, galime pasinaudoti marker ir sutaupyti daug animacijos laiko, nes šie papildomi elementai yra prijungti prie sistemos. (O animuojant vieną d komandą vietoj atskirų x ir y atributų, SVG kodas taip pat tampa daug trumpesnis.)

Kvadratinės Bézier kreivės: Q ir T komandos

Q komanda naudojama piešti kvadratines Bézier kreives. Ji priima du argumentus: valdymo tašką ir galutinį tašką.

Taigi, paprastai kreivei, pradėtume nuo M, kad pereitume į pradžios tašką, tada Q, kad nupieštume kreivę.

const path = `M${start.x} ${start.y} Q${control.x} ${control.y} ${end.x} ${end.y}`;

Kadangi turime valdymo tašką, pradžios tašką ir galutinį tašką, iš tiesų gana paprasta atvaizduoti vienos rankenėlės taką, kaip tai darytų grafikos programa.

Juokingiausia, kad tikriausiai niekada nesąveikavote su kvadratine Bézier kreive taip, kaip su kubine daugumoje įprastų GUI! Dauguma populiarių programų konvertuos šią kreivę į kubinę kreivę su dviem rankenėlėmis ir valdymo taškais, kai tik norėsite su ja pažaisti.

Piešimui sukūrėme kelis žymeklius ir piešiame rankenėlę raudonai, kad ji geriau išsiskirtų.

Taip pat apibrėžėme pagrindinį path su gradientu ir suteikėme jam kryžminio brūkšniavimo rašto užpildą. (Apie pattern kalbėjome pirmajame straipsnyje, linearGradient yra gana panašus. Abu yra def elementai, į kuriuos galite kreiptis per id.) Mums patinka matyti užpildą, bet jei jums tai trukdo, galite modifikuoti jo kintamąjį.

Raginame jus pažiūrėti pavyzdį su ir be rankenėlės atvaizdavimo, kad pamatytumėte kai kuriuos niuansus, kurie atsiranda aplink taškus, kai valdymo taškai prie jų artėja.

See the Pen SVG Path Quadratic Bézier Curve Visual by Smashing Magazine (@smashingmag) on CodePen.

(Žr. CodePen SVG Path Quadratic Bézier Curve Visual)

Kvadratinės Bézier kreivės yra „mažiau lenktos“.Šios kreivės visada išlieka šiek tiek panašios į „u“ ar „n“ formas ir negali būti iškraipytos. Tačiau jos gali būti suspaustos.

Sujungtos Bézier kreivės vadinamos „splainais“. Ir yra papildoma komanda, jungianti kelias kvadratines kreives – tai T komanda.

T komanda naudojama piešti kreivę, kuri yra sujungta su ankstesne kreive, todėl ji visada turi sekti po Q komandos (arba kitos T komandos). Ji priima tik vieną argumentą, kuris yra kreivės galutinis taškas.

const path = `M${p1.x} ${p1.y} Q${cP.x} ${cP.y} ${p2.x} ${p2.y} T${p3.x} ${p3.y}`

T komanda iš tiesų naudos informaciją apie mūsų valdymo tašką cP Q komandoje.

Norėdami pamatyti, kaip sukūrėme šį pavyzdį, atkreipkite dėmesį, kad numanomos rankenėlės nupieštos žaliai, o mūsų nurodyti valdikliai vis dar atvaizduojami raudonai.

See the Pen SVG Path Quadratic Curve T Command by Smashing Magazine (@smashingmag) on CodePen.

(Žr. CodePen SVG Path Quadratic Curve T Command)

Gerai, taigi viršutinė kreivė naudoja dvi Q komandas, o tai reiškia, kad iš viso yra trys valdymo taškai. Naudoti atskirą valdymo tašką išlenkimui sukurti yra prasminga, tačiau trečiasis valdymo taškas yra tiesiog antrojo valdymo taško atspindys per ankstesnį tašką.

Būtent tai daro T komanda. Ji numato valdymo taškus, atspindėdama juos per ankstesnės Q (arba T) komandos galutinį tašką. Galite pamatyti, kaip sistema susijungia žemiau esančioje animacijoje, kur manipuliavome tik pagrindinių taškų ir pirmųjų valdymo taškų padėtimi. Numanomi valdymo taškai seka paskui.

(Žr. CodePen SVG Path Quadratic Bézier Spline T Command Visual)

Taip pat egzistuoja q ir t komandos, kurios naudos santykines koordinates.

Prieš tęsiant, jei norite sąveikauti su kubine kreive, SVG Path Editor leidžia labai gražiai redaguoti visas path komandas.

Kubinės Bézier kreivės: C ir S

Kubinės Bézier kreivės veikia iš esmės kaip kvadratinės, tačiau vietoj vieno valdymo taško jos turi du. Tai tikriausiai yra kreivė, su kuria esate labiausiai susipažinę.

Tvarka yra tokia, kad pradedate nuo pirmojo valdymo taško, tada antrojo, ir galiausiai galutinio taško.

const path = `M${p1.x} ${p1.y} C${cP1.x} ${cP1.y} ${cP2.x} ${cP2.y} ${p2.x} ${p2.y}`;

Pažvelkime į vizualizaciją, kad pamatytume ją veiksme.

See the Pen SVG Path Cubic Bézier Curve Animation by Smashing Magazine (@smashingmag) on CodePen.

(Žr. CodePen SVG Path Cubic Bézier Curve Animation)

Kubinės Bézier kreivės yra lankstumo meistrės.Skirtingai nuo kvadratinės kreivės, ši gali susisukti, sudaryti kilpas ir įgauti visiškai kitokias formas nei bet kuris kitas SVG elementas. Ji gali padalinti užpildytą sritį į dvi dalis, o kvadratinė kreivė – ne.

Kaip ir su T komanda, kubinėms kreivėms yra prieinama atspindėjimo komanda – S.

Ją naudojant, pirmąjį valdymo tašką gauname per atspindį, o naują galutinį valdymo tašką ir galutinį tašką galime apibrėžti patys. Kaip ir anksčiau, tam reikia splaino, taigi, bent vienos ankstesnės C (arba S) komandos.


const path = `
	M ${p0.x} ${p0.y}
    C ${c0.x} ${c0.y} ${c1.x} ${c1.y} ${p1.x} ${p1.y}
    S ${c2.x} ${c2.y} ${p2.x} ${p2.y}`;

Sukūrėme ir gyvą vizualizaciją tam.

(Žr. CodePen SVG Path Cubic Bézier Spline S Command Visual)

Kada naudoti T ir S:Didelis šių grandininių atspindėjimo komandų privalumas yra tai, jei norite piešti bangas arba tiesiog absoliučiai užtikrinti, kad jūsų splaino jungtis būtų lygi.

Jei negalite naudoti atspindžio, bet norite turėti gražią, lygią jungtį, įsitikinkite, kad jūsų valdymo taškai sudaro tiesią liniją. Jei rankenėlėse yra lūžis, jūsų splainas taip pat jį turės.

Lankai: A komanda

Galiausiai, paskutinis path komandos tipas yra lankų kūrimas. Lankai yra apskritimų ar elipsių dalys.

Tai mūsų mažiausiai mėgstama komanda, nes joje yra tiek daug elementų. Bet tai yra paslaptis, kaip nupiešti tinkamą žiedinę diagramą, todėl esame su ja šiek tiek praleidę laiko.

Pažvelkime į ją.

Kaip ir su bet kuria kita path komanda, mažoji raidė reiškia santykines koordinates. Taigi, kaip yra A komanda, taip yra ir a.

Taigi, lanko takas atrodo taip:

const path = `M${start.x} ${start.y} A${radius.x} ${radius.y}
${xAxisRotation} ${largeArcFlag} ${sweepFlag} ${end.x} ${end.y}`;

Ir kas, po galais, yra xAxisRotation, largeArcFlag ir sweepFlag? Trumpai:

  • xAxisRotation yra pagrindinės elipsės ašių pasukimas laipsniais.
  • largeArcFlag yra loginė reikšmė (boolean), kuri nustato, ar lankas yra didesnis nei 180°.
  • sweepFlag taip pat yra loginė reikšmė ir nustato lanko kryptį, t. y., ar jis eina pagal laikrodžio rodyklę, ar prieš.

Norėdami geriau suprasti šias koncepcijas, sukūrėme šią vizualizaciją.

See the Pen SVG Path Arc Command Visuals by Smashing Magazine (@smashingmag) on CodePen.

(Žr. CodePen SVG Path Arc Command Visuals)

Spindulio dydis

Tame „CodePen“ pastebėsite, kad kiekvienai komandai nupieštos elipsės. Viršutinėje eilutėje jos persidengia, o apatinėje – sukrautos viena ant kitos. Abi eilutės iš tikrųjų naudoja tas pačias radius.x ir radius.y reikšmes savo lankų apibrėžimuose, o atstumas tarp pradžios ir pabaigos taškų antroje eilutėje didėja.

Sukrovimas vyksta todėl, kad spindulio dydis atsižvelgiamas tik tada, jei pradžios ir pabaigos taškai telpa į nurodytą elipsę. Toks elgesys mus nustebino, todėl pasigilinome į specifikacijas ir radome šią informaciją apie tai, kaip veikia lankas:

„Visiems elipsės lanko parametrams (išskyrus logines vėliavėles) leidžiamos bet kokios skaitinės reikšmės, tačiau vartotojo agentai, atvaizduodami kreives ar skaičiuodami jų geometriją, turi atlikti šiuos neteisingų reikšmių koregavimus:

  1. Jei segmento pabaigos taškas (x, y) yra identiškas dabartiniam taškui (pvz., ankstesnio segmento pabaigos taškui), tai prilygsta visišam elipsės lanko segmento praleidimui.
  2. Jei rx arba ry yra 0, šis lankas traktuojamas kaip tiesi linijos atkarpa (lineto), jungianti pabaigos taškus.
  3. Jei rx arba ry turi neigiamus ženklus, jie pašalinami; vietoj jų naudojama absoliuti vertė.
  4. Jei rx, ry ir x-axis-rotation yra tokie, kad sprendimo nėra (iš esmės, elipsė nėra pakankamai didelė, kad pasiektų nuo dabartinio taško iki naujo pabaigos taško), elipsė yra vienodai padidinama, kol atsiranda lygiai vienas sprendimas (kol elipsė tampa pakankamai didelė).

Žr. priedo skiltį Ne diapazone esančių spindulių korekcija, kurioje pateikta matematinė šio mastelio keitimo operacijos formulė.“

9.5.1 Ne diapazone esantys elipsės lanko parametrai

Taigi, iš tikrųjų, tas sukrovimas yra tik gražus ir sklandus klaidų valdymas, o ne tai, kaip buvo numatyta. Nes viršutinė eilutė yra tai, kaip lankai turėtų būti naudojami.

Įvedus logiškas reikšmes, pagrindinės elipsės ir du taškai mums suteikia keturias piešimo parinktis, kaip galėtume sujungti du taškus elipsės taku. Būtent tam ir skirtos loginės reikšmės.

xAxisRotation

Prieš pereinant prie loginių reikšmių, kryžminis brūkšniavimas rodo xAxisrotation. Elipsė pasukama aplink savo centrą, o laipsnių reikšmė yra susijusi su SVG x kryptimi.Taigi, jei dirbate su apskrita elipse, pasukimas neturės jokio poveikio lankui (išskyrus, jei naudojate jį rašte, kaip mes ten padarėme).

Sweep Flag

Atkreipkite dėmesį į mažą rodyklės žymeklį, rodantį lanko piešimo kryptį. Jei reikšmė yra 0, lankas piešiamas pagal laikrodžio rodyklę. Jei reikšmė yra 1, lankas piešiamas prieš laikrodžio rodyklę.

Large Arc Flag

Large Arc Flag nurodo takui, ar norite mažesnio, ar didesnio lanko iš elipsės. Jei turime padidintą atvejį, gauname lygiai 180° mūsų elipsės.

Lankai paprastai reikalauja daug daugiau erzinančio apskritų skaičių tvarkymo, nei mums patinka daryti. (Kai tik atsiranda radianai, linkstame pasinerti į triušių urvus, kur tenka iš naujo mokytis per daug matematikos, kurią laimingai pamirštame.)Jie labiau priklauso nuo to, ar reikšmės yra susijusios viena su kita, kad rezultatas būtų toks, kaip tikėtasi, ir tiesiog tiek daug informacijos įeina.

Bet – ir tai didelis bet – lankai yra nuostabiai galingi!

Išvada

Gerai, tai buvo daug! Tačiau tikimės, kad pradedate matyti, kaip path komandos gali būti naudingos. Mums jos atrodo itin naudingos iliustruojant duomenis.

Kai žinote, kaip lengva sukurti tokius dalykus kaip tinkleliai, dėžutės ir kreivės, nereikia daug daugiau žingsnių, kad sukurtumėte vizualizacijas, kurios yra šiek tiek unikalesnės nei tai, ką siūlo standartinės duomenų vizualizacijos bibliotekos.

Su viskuo, ką išmokote šioje straipsnių serijoje, iš esmės esate visiškai pasirengę atvaizduoti visų tipų diagramas – ar kitokio tipo vizualizacijas.

Pavyzdžiui, kaip dėl pagrindinės kubinės Bézier kreivės vizualizavimo, tarkime, CSS transition-timing-function: ease;? Būtent tai sukūrėme, norėdami išsiaiškinti, kaip galėtume paversti tas transition-timing-function į kažką, ką supranta <animate> žymė.

(Žr. CodePen CSS Cubic Beziers as SVG Animations & CSS Transition Comparisons)

SVG yra smagus ir keistas, o path elementas gali būti labiausiai pribloškiančios simbolių eilutės, kurią kada nors matėte kodo inspekcijos metu, turėtojas. Tačiau, jei skirsite laiko suprasti pagrindinę logiką, visa tai virsta viena gražiai paprasta ir itin galinga sintakse.

Tikimės, kad šiais dviem path iškodavimo straipsniais pavyko atskleisti pagrindinę mechaniką, kaip veikia path braižymas. Jei norite dar daugiau išteklių, nereikalaujančių gilintis į specifikacijas, išbandykite MDN pamoką apie takus. Ji trumpa ir kompaktiška, ir buvo pagrindinis išteklius mums mokantis visa tai.

Tačiau, nuo tada, kai parašėme išsamią apžvalgą šia tema, atradome nuostabų svg-tutorial.com, kuris puikiai vizualizuoja SVG kodavimą apskritai, bet ypač pasižymi mūsų mėgstamiausia lanko vizualizacija Lanko redaktoriuje. Ir jei turite taką, kurį norėtumėte tinkamai iškoduoti, nesaugodami visos informacijos iš šių dviejų straipsnių, yra SVG Path Visualizer, kuris labai gražiai išskaido tako informaciją.

O dabar: pirmyn ir smagiai žaiskite matricoje.