Pada artikel ini saya ingin menyoroti seluk-beluk bekerja dengan grafik SVG, animasi SVG (termasuk jalur), masalah dan metode untuk menyelesaikannya, serta berbagai perangkap, yang ada banyak SVG. Saya memposisikan artikel ini sebagai panduan terperinci.

Tidak akan ada plugin, perpustakaan, dll., Kami hanya akan berbicara tentang SVG murni.
Satu-satunya alat yang akan saya gunakan adalah Adobe Illustrator.
Kata Pengantar
Semuanya dimulai dengan kuliah yang membosankan dan dengan harapan dapat menghibur diri sendiri dengan setidaknya sesuatu, saya memutuskan untuk mempelajari grafis SVG, yaitu animasi. Yang mengejutkan saya, ada sangat sedikit informasi di Internet. Di mana-mana ada informasi duplikat yang menjelaskan dasar-dasarnya, tetapi tentang animasi secara umum dari kekuatan 2-3 tautan dengan informasi yang benar-benar identik, yang merupakan terjemahan dari artikel A Guide to SVG Animations (SMIL) oleh Sarah Suydan.
Artikelnya berbicara tentang segalanya, tetapi secara dangkal. Meskipun demikian, saya sangat menyarankan agar Anda membiasakan diri dengannya. * Tautan ke terjemahan *Beberapa minggu berikutnya saya habiskan mengumpulkan informasi sepotong demi sepotong dari berbagai sumber. Hasil pencarian ini adalah artikel ini.
Ekspor SVG yang tepat dari Illustrator
Bagian ini berfokus pada fitur dan masalah Adobe Illustrator, jadi jika Anda tidak menggunakan Illustrator, Anda dapat melewati bagian ini.
Mempersiapkan dokumen untuk animasi adalah tahap yang sangat penting, pengabaian yang dapat mengakibatkan konsekuensi yang sangat tidak menyenangkan. Untuk mengajari Anda cara menggambar yang lebih baik di Illustrator, saya tidak akan. Satu-satunya hal yang akan saya katakan adalah bahwa ketika menggambar bentuk, Anda harus melacak nilai-nilai, diinginkan bahwa mereka hanya memiliki satu angka setelah titik desimal, dan lebih baik menjadi bilangan bulat. Mengikuti aturan ini tidak perlu, tetapi akan mengurangi ukuran file, menyederhanakan animasi lebih lanjut dan mengurangi jumlah informasi secara visual. Lihatlah
<path d="M 17.7 29 C 28.2 12.9 47 5.6 62.8 10.4 c 28.2 8.5 30 50.5 24.8 53.1 c -2.6 1.3 -10.4 -6.1 -29.2 -34.6"/> <path d="M 17.651 28.956 c 10.56 -16.04 29.351 -23.359 45.12 -18.589 c 28.151 8.516 29.957 50.5 24.841 53.063 c -2.631 1.318 -10.381 -6.148 -29.235 -34.643"/>
Dalam contoh, kurva yang sama, tetapi dalam kasus pertama, satu digit setelah titik desimal, dan dalam tiga yang kedua. Kurva ini hanya memiliki 4 poin, dan contoh kedua adalah sepertiga lebih panjang dari yang pertama. Bayangkan berapa banyak ruang yang dibutuhkan kurva 20-titik.
Setelah gambar rangka dibuat, Anda perlu menyimpan gambar sebagai file SVG. Ada dua cara untuk melakukan ini - Simpan Sebagai atau Ekspor Sebagai. Tapi cara mana yang harus dipilih? Jika Anda mempercayai saya, lebih baik gunakan "save as." Jika Anda ingin tahu alasannya, gunakan spoiler.
Jadi mengapa?Sekilas, tidak ada bedanya, karena pada akhirnya kita mendapatkan file a.svg dengan gambar kita. Namun, perbedaannya dimulai pada tahap pengaturan ekspor.
Saya tidak melihat titik dalam menjelaskan semua parameter secara rinci, Illustrator melakukannya dengan sangat baik di bagian "Deskripsi".Seperti yang Anda lihat, "simpan" memiliki lebih banyak pengaturan daripada "ekspor", dan bagi sebagian orang itu akan menjadi alasan yang baik untuk menolak mengekspor, tetapi kami akan melanjutkan.
Jika kami membuka file yang disimpan dalam dua cara di browser, kami tidak akan melihat perbedaannya. Namun, saat ini kami lebih tertarik bukan pada penampilan, tetapi mengisi, jadi kami akan melakukan hal yang sama, tetapi melalui editor teks. Di sini perbedaan akan menjadi lebih jelas. Saya menyarankan agar Anda sendiri melihat dan menarik kesimpulan, saya tidak mengubah apa pun di file, saya hanya menyalin keseluruhan seperti apa adanya.
Ekspor <svg id="_1" data-name=" 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 51 51"> <defs> <style> .cls-1 { fill: none; stroke: #4ec931; stroke-miterlimit: 10; } .cls-2 { fill: #4ec931; } .cls-3 { fill: #fff; } </style> </defs> <title>my_icon_E</title> <circle class="cls-1" cx="25.5" cy="25.5" r="20"/> <circle class="cls-1" cx="25.5" cy="25.5" r="25"/> <g id="_2" data-name=" 2"> <circle class="cls-2" cx="25.5" cy="25.5" r="15"/> <polygon class="cls-3" points="25.5 34.8 34 20.3 17 20.3 25.5 34.8"/> </g> </svg>
Simpan <?xml version="1.0" encoding="utf-8"?> <svg version="1.1" id="_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve"> <style type="text/css"> .st0{fill:none;stroke:#4EC931;stroke-miterlimit:10;} .st1{fill:#4EC931;} .st2{fill:#FFFFFF;} </style> <circle class="st0" cx="50" cy="50" r="20"/> <circle class="st0" cx="50" cy="50" r="25"/> <g id="_2"> <circle class="st1" cx="50" cy="50" r="15"/> <polygon class="st2" points="50,59.3 58.5,44.8 41.5,44.8 "/> </g> </svg>
Selain perbedaan dalam penamaan kelas CSS dan desain secara umum, yang mungkin dianggap enak, ada masalah lain. Saat "mengekspor" seluruh gambar dikurangi 2 kali. Anda bisa menilai ini berdasarkan ukuran bentuk dan atribut
viewBox . Karena ini adalah grafik vektor, itu tidak menjadi lebih buruk, tetapi masih tidak menyenangkan. "Menyimpan" meninggalkan dimensi yang saya tentukan di Illustrator.
Tetapi semua ini adalah bunga dibandingkan dengan jenis "ekspor" babi yang dapat dimasukkan. Secara khusus, contoh-contoh ini tidak memiliki masalah ini, mungkin karena gambarnya sangat sederhana. Namun, saya menabraknya ketika mengekspor karya saya yang lain. Ini screenshotnya

Ukuran file cukup besar, jadi saya hanya akan memberikan bagian masalahnya
<g id="-21" data-name=""> <path class="cls-9" d="M477.94,456.75a1.83,1.83,0,0,1-.9,1.36l-4.91,3.1a7.29,7.29,0,0,1-7.5,0l-16.29-9.72a1.85,1.85,0,0,1-.92-1.56v-3.68a1.85,1.85,0,0,0,.92,1.56l.38.23,15.91,9.49a7.29,7.29,0,0,0,7.5,0l4.53-2.86.38-.23a1.87,1.87,0,0,0,.9-1.36Z" transform="translate(-5.5 -5.5)"/> <path class="cls-10" d="M477,451.19l-16.38-9.5a7.28,7.28,0,0,0-7.32,0l-5,2.9a1.88,1.88,0,0,0-.94,1.51v.17a1.85,1.85,0,0,0,.92,1.56l.38.23,15.91,9.49a7.29,7.29,0,0,0,7.5,0l4.53-2.86.38-.23a1.87,1.87,0,0,0,.9-1.36v-.51A1.88,1.88,0,0,0,477,451.19Z" transform="translate(-5.5 -5.5)"/> </g> <g id="-22" data-name=""> <path class="cls-9" d="M525.37,557.86a1.85,1.85,0,0,1-.9,1.36l-33.22,19.64a7.29,7.29,0,0,1-7.5,0l-16.29-9.72a1.85,1.85,0,0,1-.92-1.56v-3.68a1.85,1.85,0,0,0,.92,1.56l.38.23,15.91,9.49a7.29,7.29,0,0,0,7.5,0l32.84-19.41.38-.23a1.83,1.83,0,0,0,.9-1.36Z" transform="translate(-5.5 -5.5)"/> <path class="cls-10" d="M524.45,552.3l-16.38-9.51a7.31,7.31,0,0,0-7.32,0l-33.27,19.44a1.89,1.89,0,0,0-.94,1.51v.17a1.85,1.85,0,0,0,.92,1.56l.38.23,15.91,9.49a7.29,7.29,0,0,0,7.5,0l32.84-19.41.38-.23a1.83,1.83,0,0,0,.9-1.36v-.5A1.86,1.86,0,0,0,524.45,552.3Z" transform="translate(-5.5 -5.5)"/> </g>
Melihat sesuatu yang tidak biasa? Jika Anda melihat atribut
transformasi , maka Anda benar. Dialah yang merusak seluruh raspberry. Saat Anda "mengekspor" gambar, Illustrator menetapkannya untuk SEMUA elemen
<path> . Namun, masalah seperti itu tidak diamati dengan "konservasi".
Jika Anda masih tidak memahami kemarahan saya, maka saya akan menjelaskan: jika Anda ingin menggerakkan gerakan elemen seperti itu, maka itu akan bergeser ke samping. Dalam hal ini, 5,5 pada kedua sumbu. Ini disebabkan oleh fakta bahwa animasi gerakan
mengubah atribut
transform , mengatur ulang semua nilai masa lalu. Tentu saja, ini dapat dielakkan, tetapi apakah tidak lebih baik untuk menghindari masalah daripada memperbaiki konsekuensinya nanti ...
Saat ini, saya hanya memperhatikan masalah ini, tetapi ini tidak berarti bahwa itu adalah satu-satunya. Jika Anda menilai situasinya dengan masuk akal, ternyata "simpan sebagai" menang dalam segalanya. Itu sebabnya saya menyarankan Anda untuk menggunakannya.
Cara mengimpor dokumen SVG ke HTML
Sebelum saya mulai langsung dengan animasi, saya ingin berbicara tentang cara menanamkan SVG pada halaman. Setiap metode memiliki "fitur" sendiri yang memiliki dampak langsung pada animasi. Dan jika Anda tidak membicarakannya, maka artikel tersebut tidak akan lengkap.
Misalkan Anda sudah memiliki SVG yang sudah jadi dengan animasi interaktif dan tetap menyematkan dokumen ini di situs. Bagaimana cara melakukannya?
Opsi nomor satu adalah untuk mengingat bahwa SVG juga merupakan gambar dan dapat diimpor menggunakan alat HTML standar. Anda dapat membuat
tag <img> dengan tautan ke dokumen
<img src="Hello_SVG.svg" />
Atau atur SVG sebagai gambar latar
#box { background-image: url("Hello_again.svg"); }
Kerugian utama dari metode ini adalah isolasi gambar. SVG sebagai pameran di museum - Anda dapat menonton, tanpa sentuhan. Animasi di dalamnya akan berfungsi, tetapi tidak ada pembicaraan tentang interaktivitas apa pun. Jika, misalnya, animasi dipicu oleh klik pengguna, atau ada kebutuhan untuk mengubah konten dokumen SVG secara dinamis, maka metode ini bukan untuk Anda.
Opsi nomor dua adalah membuat objek dari SVG menggunakan
tag <object> atau
<embed> . Dimungkinkan juga untuk menggunakan
<iframe> untuk membuat bingkai, tetapi saya tidak merekomendasikan menggunakan metode ini, karena diperlukan
kruk untuk semua browser sehingga opsi ini ditampilkan dengan benar
<object data="My_SVG.svg" type="image/svg+xml"></object> <embed src="My_SVG.svg" type="image/svg+xml" /> <iframe src="My_SVG.svg"></iframe>
Di sini segalanya lebih baik. Animasi mendapatkan kesempatan untuk menjadi interaktif, tetapi hanya jika mereka dinyatakan dalam dokumen SVG, dan konten tersedia untuk JavaScript eksternal. Masih
<object> dan
<iframe> dapat menampilkan rintisan jika tiba-tiba gambar tidak dimuat.
Opsi nomor tiga adalah dengan hanya menempelkan isi dokumen SVG langsung ke HTML. Ya kamu bisa. Dukungan SVG muncul dalam
standar HTML5 . Karena SVG pada dasarnya adalah bagian dari halaman itu sendiri, akses ke sana adalah di mana-mana. Animasi dan gaya elemen dapat dideklarasikan di dalam SVG dan di file eksternal. Kelemahannya adalah bahwa gambar seperti itu tidak disimpan secara terpisah dari halaman
<body> ... <svg> </svg> </body>
Animasi SVG
Ada dua cara utama untuk menghidupkan elemen SVG:
- Animasi CSS
- Animasi SMIL dibangun menjadi SVG (sebenarnya, ini adalah animasi SVG yang didasarkan pada SMIL dan memperluas fungsinya)
Secara pribadi, saya memisahkan mereka sebagai animasi "eksternal" dan "internal". Divisi ini bersyarat, tetapi mereka masih memiliki perbedaan fungsional. Jika kita berbicara tentang perbedaan secara umum: CSS - memiliki dukungan yang lebih baik untuk browser; SMIL - memiliki fungsionalitas hebat. Sulit untuk mengatakan mana yang lebih baik untuk digunakan karena mereka sangat mirip. Pilihannya tergantung pada tugas, jadi saya hanya akan mengatakan alasan utama untuk menggunakan SMIL daripada CSS
SMIL - saat dibutuhkan:
- Apa yang tidak dapat dilakukan CSS (menghidupkan atribut yang tidak didukung, dll.)
- Memiliki kontrol yang lebih tepat atas animasi.
- Buat path morphing (animasi atribut d pada path tag)
- Sinkronkan animasi
- Buat animasi interaktif
Jika saya menulis bahwa SMIL harus digunakan untuk animasi interaktif, ini tidak berarti bahwa hal yang sama tidak dapat dilakukan dengan CSS. Cukup SMIL adalah alat yang lebih fungsional dan canggih. Dan itulah mengapa itu harus digunakan hanya jika diperlukan. Jika animasinya sederhana dan CSS dapat ditiadakan, maka ini harus dilakukan.
Animasi CSS
Tidak ada yang baru di sini. Kami dapat menghidupkan elemen SVG dengan cara yang sama seperti yang kami lakukan dengan HTML. Semua animasi dibuat menggunakan
bingkai kunci @ . Karena animasi CSS adalah topik lain, saya tidak akan membahas hal ini secara rinci, jaringan penuh dengan dokumentasi dan panduan tentang topik ini. Semua yang dijelaskan di sini berlaku untuk SVG, tetapi saya hanya akan memberikan beberapa contoh.
Dokumen SVG memiliki stylesheet internal, jadi kami akan menulis animasi di dalamnya
<svg> <style> </style> </svg>
Animasi atribut SVG sesederhana atribut CSS
@keyframes reduce_radius { from { r: 10; } to { r: 3; } } @keyframes change_fill { 0% { fill: #49549E; } 75% { fill: #1bceb1; } 100% { fill: #1bce4f; } }
Anda dapat menentukan nilai sebagai persentase, dan dari-ke konstruksiKemudian tinggal menerapkan animasi yang dibuat ke elemen yang diinginkan
.circle { animation: change_fill 1s, popup 2s; }
Semua yang saya jelaskan di atas adalah animasi statis, tidak ada bau interaktivitas di sana. Tetapi bagaimana jika Anda benar-benar menginginkannya? Ya, sesuatu masih bisa dilakukan secara interaktif dan dalam CSS. Misalnya, jika Anda menggunakan
transisi dalam kombinasi dengan
kelas pseudo
hover .circle { fill: #49549E; transition: .3s; } .circle:hover { fill: #1bceb1; }
Saat Anda mengarahkan kursor ke suatu item, item itu akan berubah warna dari biru menjadi biru selama 300 msAnimasi atribut dan sepotong kecil interaktivitas - di sinilah fitur akhir animasi CSS. Tetapi fungsi ini sudah cukup, karena sebagian besar tugas datang untuk menjiwai beberapa atribut. Hampir semua atribut SVG dapat dianimasikan. Dan ketika saya menulis "hampir semua", maksud saya bahwa jika Anda memilih atribut acak dan ternyata tidak berubah, maka Anda SANGAT beruntung.
Animasi SMIL
Layak dikatakan bahwa animasi SMIL setua dunia dan sedang sekarat, dukungan browser layak, tetapi masih kurang dari Animasi CSS, tetapi ada alasan mengapa SMIL masih menarik - itu bisa karena CSS tidak bisa.
Saya akan berbicara lebih banyak tentang SMIL, karena ada banyak jebakan yang jarang mereka tulis. Dan topik ini kurang populer daripada CSS. Tag utama untuk animasi adalah
<animate> ,
<set> ,
<animateTransform> ,
<animateMotion> .
<animate>
Mari kita mulai dengan artileri berat.
<animate> - digunakan untuk menghidupkan atribut apa pun dan merupakan alat utama. Tag yang tersisa sangat terspesialisasi, tetapi hal pertama yang pertama.
Bagaimana cara menerapkan animasi ke suatu elemen?Ada dua cara untuk menentukan elemen yang akan diterapkan animasi.
- Letakkan tag di dalam elemen. Metode ini memungkinkan Anda untuk merangkum animasi di dalam objek, yang membuatnya lebih mudah untuk membaca kode
<circle ...> <animate .../> </circle>
Dalam hal ini, animasi akan diterapkan ke elemen lingkaran . - Lewati tautan ke item. Berguna jika Anda ingin semua animasi dikumpulkan di satu tempat
<svg xmlns:xlink="http://www.w3.org/1999/xlink"> <circle id="blue" .../> ... <animate xlink:href="#blue" .../> </svg>
Atribut xlink: href digunakan di sini, di mana kami menentukan id elemen yang harus diterapkan animasi. Agar metode ini berfungsi, Anda harus mendefinisikan namespace xlink . Ini dilakukan dalam tag <svg>.
Dengan SVG 2, atribut
xlink: href sudah usang, spesifikasi merekomendasikan menggunakan
href , yang tidak memerlukan namespace
xlink .
<circle id="blue" .../> ... <animate href="#blue" .../>
Tapi di sini, tidak semuanya lancar -
href tidak didukung oleh Safari. Ternyata situasi jalan buntu, satu atribut sudah usang, yang lain sebagian tidak didukung. Jadi metode apa yang digunakan, semua orang memutuskan untuk dirinya sendiri.
Bagi mereka yang telah memperhatikan kesamaan dengan pemilih CSS: Maaf mengecewakan, saya tidak akan dapat mengakses elemen berdasarkan kelas
<circle class="blue_circle" .../> <animate href=".blue_circle" .../>
Ini tidak bekerja!Bagaimana cara menentukan atribut untuk animasi?Ada
atributName untuk ini. Nilainya adalah nama dari atribut yang akan kita hidupkan.
<circle r="25" ...> <animate attributeName="r" ... /> </circle>
Dengan menentukan r di atributName , kami melaporkan bahwa kami akan menganimasikan jari-jari lingkaranApa itu attributeType dan mengapa Anda tidak membutuhkannya?Karena dia tidak bergunaSecara teori, sesaat mungkin muncul ketika nama atribut dalam CSS dan XML cocok, yang dapat menyebabkan masalah. Dan untuk menyelesaikan konflik ini, Anda harus secara eksplisit menentukan namespace. Ada dua
kursi cara: tentukan awalan atau gunakan
atributType . Mari kita mulai dengan awalan.
Di mana-mana mereka menulis sesuatu seperti berikut:
Anda bisa menentukan awalan XMLNS untuk atribut untuk secara eksplisit menentukan namespace-nya
Metode ini disebutkan secara sepintas dan tanpa contoh. Jadi saya tidak akan mengubah tradisi. (Saya menyarankan Anda untuk berhenti di sini, lupakan awalan sebagai mimpi buruk dan pergi ke
atributType , saya memperingatkan Anda)
"Aku seorang masokis"Isi spoiler ini agak menghibur dan eksploratif. Tidak ada informasi yang berguna, selain fakta bahwa awalan tidak berfungsi, Anda tidak akan menemukannya di siniPertama, Anda perlu menemukan definisi yang lebih akurat, dan, seperti yang Anda tahu, definisi paling akurat dalam spesifikasi dan standar.
Panduan singkat tentang cara menyerah pada kehidupan- Kami membuka spesifikasi untuk animasi SVG untuk 14 Maret 2019
- Di bagian attributeName , kita melihat bahwa ia mewarisi standar Animasi SMIL untuk (oh horor) 2001
- Baca definisi attributeName
- Untung!
Terjemahan definisi tersebut berbunyi sebagai berikut:
“Menentukan nama atribut target. Awalan XMLNS dapat digunakan untuk menentukan XML namespace untuk atribut. Awalan akan ditafsirkan dalam lingkup elemen animasi. "
Hmm, itu tidak mudah. Apa yang terlintas dalam pikiran seseorang yang tidak tahu XML setelah membaca definisi seperti itu? Benar Sama seperti saya.
Saya menerimanya secara harfiah dan berpikir itu akan terlihat seperti ini
<animate attributeName="xmlns:* *"/>
Saya berpikir dan dengan aman melupakan metode ini sebelum menulis artikel ini. Masalahnya dimulai ketika saya memutuskan untuk mengujinya dalam praktik. Saya pikir saya tidak akan mengejutkan siapa pun jika saya mengatakan bahwa ini tidak berhasil. Setelah beberapa jam pencarian gagal, saya googled "awalan xmlns" dan, saya terkejut, saya melihat bahwa xmlns bukanlah awalan itu sendiri, tetapi
(berkonsentrasi, itu akan sulit sekarang) desain namespace dengan awalan .
Ini terlihat sebagai berikut:
<** xmlns:**="* url *" ...>
Lalu saya menyadari bahwa saya tidak mengerti apa-apa ... pada awalnya ... dan sekarang, pada prinsipnya, jugaSetelah beberapa jam, saya akhirnya menemukan apa yang saya cari di
Namespaces dalam XML . Ini adalah contoh asli:
<x xmlns:n1="http://www.w3.org" xmlns="http://www.w3.org" > <good a="1" n1:a="2" /> </x>
Tapi tahukah Anda apa hal yang paling lucu? Itu masih tidak berhasil. Meski semuanya dilakukan sesuai buku
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:n1="http://www.w3.org/2000/svg"> <circle id="www" n1:r="10" .../> <animate href="#www" attributeName="n1:r" .../> </svg>
Tidak ada kesalahan dan tidak boleh, karena semuanya dilakukan sesuai aturan, tetapi masalahnya adalah kita mendapatkan lingkaran tanpa jari-jari. Hasil yang sama akan terjadi jika Anda tidak menulis atribut
r .
Epilog : SVG mengabaikan atribut awalan. Akibatnya, bahkan jika SMIL benar-benar menjiwai atribut dengan awalan, Anda tidak akan melihat hasil dari animasi ini.
Dalam pembelaan saya, saya akan mengatakan bahwa saya hanya berurusan dengan SVG, yaitu dengan animasinya, sehingga guru XML akan mengesampingkan obor dan garpu rumput. Jika Anda tahu cara membuat metode ini berfungsi, selamat datang komentar Untuk secara eksplisit menunjukkan apa yang dimiliki atribut animasi, atributType digunakan. Dibutuhkan 3 nilai:
CSS ,
XML ,
otomatis . Kecuali
atribut atribut ditentukan secara eksplisit,
otomatis akan digunakan. Dalam hal ini, properti CSS diperiksa terlebih dahulu, dan jika tidak ada kecocokan, maka atribut elemen target diperiksa. Dalam contoh, kami menunjukkan bahwa kami akan menghidupkan properti CSS dengan tepat
<animate attributeType="CSS" attributeName="opacity" .../>
AtributType memungkinkan Anda dengan mudah dan tanpa kruk untuk menunjukkan apa yang dimiliki atribut animasi, sehingga memecahkan "masalah", yang bahkan tidak ada.
Tanpa diduga, kan? Seperti yang saya katakan di awal bab ini, SMIL sedang sekarat dan ini disebabkan oleh kenyataan bahwa animasi tersebut diterjemahkan ke dalam rel CSS. Sebagian besar atribut duplikat benar-benar identik satu sama lain, yaitu tidak masalah jika atribut CSS atau SMIL termasuk - hasilnya akan sama. Dan dalam kombinasi dengan nilai
otomatis default, kebutuhan untuk secara eksplisit mendefinisikan
atributType tidak lagi diperlukan.
Beberapa fakta menarik: attributeType tidak didukung oleh SVG. Dari mana dia berasal saat itu? Dia datang kepada kami dari SMIL Animation, yang menjadi dasar animasi SVG. Dan juga attributeType dihapus setelah SVG 1.1 Second Edition. Semua bukti di siniBagaimana cara menentukan nilai animasi?Menentukan atribut untuk animasi tidak cukup, Anda harus menentukan nilainya. Di sini datang
dari ,
ke ,
oleh ,
nilai-nilai .
Mari kita mulai dengan pasangan yang selalu bersama:
dari dan
ke . Makna dari keberadaan mereka jelas,
dari menunjukkan awal,
hingga akhir
<circle r="25" ...> <animate attributeName="r" from="10" to="45" .../> </circle>
Hasil dari animasi akan menjadi perubahan yang halus pada jari-jari lingkaran dari 10 menjadi 45Meskipun saya mengatakan bahwa mereka selalu bersama,
untuk dapat juga digunakan tanpa secara eksplisit menyatakan
dari . Dalam hal ini,
dari akan mengambil nilai yang ditentukan dalam elemen target. Untuk contoh di atas, animasi akan dimulai pada 25.
Jika ada kebutuhan untuk menentukan satu set beberapa nilai, nilai digunakan. Nilai terdaftar dengan tanda titik koma.
<circle r="25" ...> <animate attributeName="r" values="15;50;25" .../> </circle>
Nilai jari-jari berkurang menjadi 15, kemudian meningkat menjadi 50 dan kemudian kembali ke posisi semula.Terakhir sejalan. Dia tidak peduli "di mana" dan "di mana", semua yang menarik baginya adalah "seberapa banyak". Dengan kata lain, alih-alih nilai absolut, ia bekerja dengan relatif
<circle r="25" ...> <animate attributeName="r" by="15" .../> </circle>
Sebagai hasil dari animasi, jari-jari akan meningkat sebesar 15, yaitu, dapatkan 25 + 15 = 40Legenda mengitari bentangan manual yang
" oleh dapat digunakan untuk menunjukkan jumlah animasi yang harus ditingkatkan .
" Saya memahaminya seperti ini: jika
dari = 20 ,
ke = 50 , dan diberikan
oleh = 10 , maka jalan ini harus diatasi dengan "melompat" dengan 10, yaitu. 20, 30, 40, 50. Tetapi tidak peduli bagaimana saya mencoba, dengan dan tanpa, animasi tidak berubah sedikit pun. Juga, saya tidak menemukan konfirmasi dalam spesifikasi. Sepertinya itu hanya kesalahan.
Nilai memiliki prioritas tertinggi, lalu
dari -
ke , terakhir
oleh . Prioritas terendah
dengan menjelaskan mengapa "legenda" tidak dapat bekerja secara prinsip. Namun,
dengan bekerja bersama dengan
dari , dalam hal ini,
dari hanya mengesampingkan posisi elemen saat ini
<circle cy="50" ...> <animate attributeName="cy" from="70" by="30" .../> </circle>
Di sini animasi bukannya 50 dimulai pada 70 dan berakhir pada 100Lebih lanjut tentang animasi relatifAnda dapat membuat atribut lain berfungsi sama
dengan Ini dilakukan dengan menggunakan atribut
aditif , yang memiliki dua posisi -
ganti dan
jumlah .
Yang pertama adalah default, jadi kami tertarik pada yang kedua. Dengan nilai penjumlahan, semua atribut akan ditambahkan ke nilai saat ini dari elemen target, mis. ketika menjiwai radius 20 dengan nilai bentuk = 5 dan ke = 15 , animasi akan dari 20 + 5 hingga 20 + 15 <circle r="20" ...> <animate attributeName="r" from="5" to="15" additive="sum" .../> </circle>
Saat melakukan animasi, akan ada lompatan tajam ke posisi 25, yang tidak baik (kecuali, tentu saja, ini dimaksudkan). Ini dapat dihindari dengan bentuk = 0 , tetapi kemudian arti dari menggunakan jumlah hilang , karena efek yang sama dapat diperoleh tanpa tambahan menggunakan oleh <animate attributeName="r" from="0" to="15" additive="sum" .../> <animate attributeName="r" by="15" .../>
Bagi saya, metode kedua jauh lebih mudah dimengerti dan nyaman.Di mana menentukan durasi animasi?Atribut yang diperlukan terakhir dibiarkan untuk membuat animasi berfungsi - dan ini dur . Nilai atribut menentukan durasi animasi, yang dapat ditentukan dalam detik dan dalam milidetik <animate dur="0.5s" .../> <animate dur="500ms" .../> <animate dur="00:00:00.5" .../>
Dari baris terakhir Anda dapat menebak bahwa ada sesuatu yang lain ...Anda juga dapat menunjukkan nilai dalam hitungan menit dan bahkan jam <animate dur="1.2min" .../> <animate dur="0.02h" .../>
Brengsek tahu, mengapa Anda mengatur untuk menunjukkan nilai dalam hitungan jam, tapi saya tidak masuk ke urusan orang lain, jika Anda mau, itu berarti mengapa ...Untuk atribut lain, nilai sementara diatur dalam bentuk yang sama.Apa yang dapat saya lakukan untuk mencegah animasi kembali ke awal?Atribut fill (jangan bingung atribut ini dengan namanya) bertanggung jawab atas perilaku elemen setelah akhir animasi. Ada dua opsi:- hapus (nilai default) - segera setelah animasi mencapai akhir, semua transformasi diatur ulang dan elemen mengambil keadaan seperti sebelum animasi
- membekukan - elemen membeku di posisi akhir animasi
Apakah mungkin untuk mengulang animasi?Jawabannya adalah ya. Untuk melakukan ini, atribut repeatCount menentukan nilai yang tidak terbatas . Atribut menentukan jumlah pengulangan animasi dan default ke 1, tetapi Anda dapat menentukan nomor apa pun <animate repeatCount="indefinite" .../> <animate repeatCount="3" .../>
Yang pertama akan berulang tanpa henti, yang kedua akan berfungsi 3 kali.Sekarang animasi tanpa akhir membuatku kesal, bisakah aku mematikannya setelah beberapa saat?Untuk orang-orang menjengkelkan seperti itu mengulangi . Atribut ini menghentikan animasi setelah waktu tertentu dari awal animasi! Sederhananya, repeatDur membatasi durasi animasi. Perbedaan utama dari repeatCount adalah bahwa animasi dapat dihentikan di tengah <animate dur="2s" repeatCount="indefinite" repeatDur="3s" .../>
Animasi akan pecah di tengah iterasi kedua.Dan bagaimana jika saya ingin animasi tidak segera dimulai?Maka untuk Anda, teman saya, atribut begin disediakan. Dia bertanggung jawab ketika animasi dimulai. Atribut ini sangat berguna karena juga digunakan untuk menyinkronkan beberapa animasi, tetapi lebih lanjut tentang itu nanti.Jika Anda perlu menentukan penundaan peluncuran yang biasa, maka kami menulis periode animasi yang harus dimulai setelah membuka dokumen <animate begin="1.5s" .../>
Putar ulang dimulai setelah 1,5 detik.Anda juga dapat menentukan nilai negatif. Maka animasi akan dimulai bukan dari awal, tetapi di tempat di mana itu akan setelah jangka waktu tertentu <animate begin="-2s" dur="4s" .../>
Animasi akan dimulai dengan pembukaan dokumen, tetapi akan diputar dari tengah.Kami membuat animasi yang interaktif.Ketika nilai dimulai, Anda dapat menentukan acara di mana animasi akan dimulai, tetapi tanpa awalan "on". Misalnya, jika Anda ingin membuat animasi klik-tayang, alih-alih “onclick” kami menulis klik <circle ...> <animate begin="click" .../> </circle>
Pada contoh di atas, animasi dimulai ketika Anda mengklik pada elemen di mana animasi diterapkan. Jika Anda ingin memulai animasi pada suatu acara dari elemen lain, maka Anda perlu menentukan id -nya <circle id="button" .../> ... <animate begin="button.click" .../>
Anda juga dapat menentukan beberapa kondisi untuk memulai animasi. Untuk melakukan ini, daftarkan mereka dipisahkan dengan titik koma. <animate begin="click; 0s" .../>
Animasi akan dimulai ketika dokumen dimuat dan dengan mengklik. Tidak semua acara didukung, tetapi sebagian besar acara yang berhubungan dengan mouse berfungsi. Saya tidak akan mencantumkan semuanya, peristiwa yang tersedia dapat ditemukan di suatu tempat di sini . Juga, tidak ada yang membatalkan metode menusuk ilmiah.Animasi dimulai ulang tanpa mencapai akhir, bagaimana saya bisa memperbaikinya?Saya akan memberikan contoh sederhana. Di sini animasi dimulai dengan klik. Jika pengguna masih tidak menekan, maka mulai otomatis disediakan dalam 3 detik <animate begin="click; 3s" dur="7s" .../>
Tetapi ada masalah: jika pengguna menekan sebelum timer otomatis, maka ketika 3 detik berlalu, animasi akan restart, dan tidak pernah mencapai akhir. Atribut restart dalam nilai whenNotActive akan datang untuk menyelamatkan . Secara total, ia memiliki tiga dari mereka- selalu merupakan default - memungkinkan Anda untuk memulai ulang animasi kapan saja
- whenNotActive - animasi dapat dimulai jika belum diputar
- tidak pernah - melarang memulai kembali animasi
<animate begin="click; 3s" dur="7s" restart="whenNotActive" .../>
Masalahnya teratasi, meskipun dalam kebanyakan kasus Anda dapat melakukannya tanpa atribut ini hanya dengan membangun dependensi secara kompeten.Sinkronisasi animasiSelain acara standar, sebagai klik, ada peristiwa awal, akhir, dan pengulangan animasi. Untuk mengikat suatu acara, Anda harus menentukan id animasi dan melalui titik mulai , akhir , ulangi, masing-masing <animate id="pop" begin="click" .../> <animate begin="pop.begin" .../> <animate begin="pop.end" .../>
Jika dengan dua yang pertama semuanya jelas, maka dengan mengulang semuanya tidak begitu jelas. Jumlah pengulangan ditulis dalam tanda kurung, setelah itu Anda harus memulai animasi (nomor ini tidak bisa menjadi pengulangan terakhir) <animate id="flip" repeatCount="5" .../> <animate begin="flip.repeat(2)" .../>
Animasi akan dimulai setelah dua pengulangan, dan tidak setiap pengulangan 2.Anda juga dapat menentukan penundaan relatif terhadap acara tersebut. Misalnya, jika saya ingin memutar animasi 2 detik setelah dimulainya yang lain <animate id="another" .../> <animate begin="another.begin + 2s" .../>
Atau mulai animasi sedetik sebelum akhir yang lain <animate begin="another.end - 1s" .../>
Apa lagi yang bisa dimulai ...Saya ingin memanggil bagian ini, tetapi lebih tepat menyebutnya "Apa yang bisa dia lakukan, tetapi tidak bisa?". Menurut spesifikasi favorit saya , mulai harus memiliki dua nilai lagi yang harus diambil. Yang pertama adalah accessKey , yang memulai animasi dengan menekan tombol yang ditentukan dalam format Unicode. Yang kedua adalah jam dinding , yang menentukan awal animasi secara real time. Dan di sana Anda dapat menentukan tidak hanya jam, tetapi bahkan bulan dan tahun, secara umum, satu set lengkap.Sayangnya, tidak satu pun dari mereka yang mau bekerja. Meski kerugiannya tidak besar, karena kebutuhan mereka masih meragukan <animate begin="accessKey(\u0077)" .../> <animate begin="wallclock(2019-04-09T19:56:00.0Z);" .../>
Saya tidak tahu apa masalahnya, mungkin browser saya tidak mendukung mereka, atau mungkin sesuatu yang lain ...Bisakah saya mengganggu animasinya?Ini bisa dilakukan dengan atribut end . Dalam penggunaannya, identik untuk memulai , Anda juga dapat menentukan waktu, peristiwa, dll. Seperti yang Anda lihat, ini bukan cara pertama (dan bukan yang terakhir) untuk mengganggu animasi, karena ada repeatDur , di mana Anda juga dapat memperbaiki durasi animasi. Dansementara Anda juga dapat menentukan waktu secara langsungpada akhirnya , fitur-fiturnya yang khas adalah pengikatan acara dan kemampuan untuk menentukan daftar nilai.Misalkan kita memiliki elemen yang memiliki keadaan istirahat dan aktivitas. Yang kedua diaktifkan ketika diklik. Dan kami ingin mengganggu animasi sisanya dengan dimulainya aktivitas. Anda dapat menerapkan ide serupa seperti ini <animate id="idle" end="action.begin" begin="0s" repeatCount="indefinite" .../> <animate id="action" begin="click" .../>
Animasi sisanya dimulai secara default. Ketika Anda mengklik suatu elemen, animasi aktivitas dimulai dan mengganggu animasi sisanya.Menggabungkan atribut berakhir dan mulaiSeperti yang sudah Anda ketahui, keduanya mulai dan berakhir dapat mengambil daftar nilai, tetapi masih tidak jelas bagaimana animasi akan berperilaku jika Anda menentukan daftar di kedua atribut. Dan itu akan menghasilkan pengulangan dengan durasi dan interval yang dapat dikonfigurasi di antara mereka ... apakah itu tidak jelas? Saya akan menjelaskan semuanya sekarang.Hal pertama yang perlu diketahui adalah bahwa jumlah nilai dalam daftar harus cocok. Setiap pasangan nilai awal - akhirmendefinisikan satu "pengulangan". Dan waktu antara akhir dari satu "pengulangan" dan awal berikutnya menentukan penundaan. Saya menyebutnya "pengulangan" karena suatu alasan, animasi tidak berhenti dan melanjutkan, tetapi terganggu dan mulai dari awal. Ternyata kita dapat secara terpisah menyesuaikan durasi setiap pengulangan dan mengatur penundaan yang berbeda setelah setiap pengulangan <animate dur="3s" begin="1s; 5s; 9s" end = "2s; 8s; 11s" .../>
Dalam contoh ini, animasi memiliki 3 "pengulangan". Yang pertama akan dimulai satu detik setelah memuat dokumen dan hanya akan berlangsung satu detik dari tiga. Kemudian penundaan 3 detik, dan setelah itu animasi lengkap 3 detik. Sekali lagi, penundaan, tetapi dalam 1 detik. Pengulangan terakhir akan terganggu setelah dua detik animasi.Bisakah Anda masih mengganggu animasi?Beberapa atribut yang tidak berguna untuk celenganKeeneeee, ada dua atribut lainnya - min dan maks . Seperti namanya, min mendefinisikan minimum, dan max menentukandurasi maksimum. Pertama, durasi animasi dihitung menggunakan nilai dur , repeatCount , repeatDur ,akhir . Dan setelah itu, durasi yang diperoleh disesuaikan dengan frame yang ditentukan oleh min dan maks . Semuanya indah di atas kertas, mari kita lihat cara kerjanya dalam praktik.Dengan max, semuanya sederhana, ini adalah atribut lain yang mendefinisikan batas atas. Jika durasi yang dihitung kurang dari maks , maka diabaikan, dan jika lebih lama, maka durasi animasi menjadi sama dengan maks <animate dur="10s" repeatDur="7s" end="5s" max="4s" .../>
Ini akan terganggu selama 4 detik,tetapi min kurang beruntung. Jika durasi animasi yang dihitung lebih panjang dari min , maka diabaikan, yang logis. Namun, jika durasi yang dihitung kurang dari min , maka ... terkadang diabaikan, dan kadang tidak.Kenapa kenapa?! Momen ini sangat mudah membingungkan, jadi bacalah dengan cermat.Kami memiliki dua opsi saat durasi yang dihitung kurang dari min :- Karena animasi itu sendiri sudah berakhir, mis. dur * repeatCount < min
<animate dur="2s" repeatCount="2" min="5s" .../>
Dalam opsi ini, atribut min diabaikan, animasi akan berhenti pada detik keempat - repeatDur end .
Karena banyaknya atribut yang mengganggu animasi, ada banyak kebingungan. Akibatnya, tidak ada arti besar dalam max dan min , karena animasi yang ditulis dengan baik menghilangkan kebutuhan mereka.Bagaimana mengelola bingkai kunci dan di mana menunjukkan fungsi waktu?Untuk melakukan ini, Anda perlu mengetahui atribut keyTimes , keySplines , calcMode . Setelah menentukan daftar dalam nilai , kami mendeklarasikan bingkai kunci, tetapi mereka didistribusikan secara merata. Berkat atribut keyTimeskita dapat mempercepat atau memperlambat transisi dari satu kondisi ke kondisi lainnya. Di dalamnya, juga dalam bentuk daftar, nilai-nilai untuk setiap frame ditunjukkan. Nilai-nilai mewakili posisi keyframe pada sumbu waktu sebagai persentase, relatif terhadap durasi seluruh animasi (0 - 0%; 0,5 - 50%; 1 - 100%).Ada beberapa aturan: setiap nilai mewakili angka titik-mengambang dari 0 hingga 1, jumlah nilai dalam daftar harus cocok, nilai pertama harus 0, dan 1 terakhir, setiap nilai berikutnya harus lebih besar dari yang sebelumnya. Saya pikir Anda mengerti bahwa menggunakan keyTimes tanpa nilai tidak masuk akal . Dan sekarang menjadi contoh <animate values="15; 10; 45; 55; 50" keyTimes="0; 0.1; 0.6; 0.9; 1" .../>
Secara default, semua konversi terjadi secara linear, untuk mengubahnya, Anda perlu menentukan mode yang berbeda di calcMode . Dan tidak banyak pilihan:- linier - nilai standar, tidak perlu penjelasan
- Interval waktu mondar - mandir dihitung sehingga kecepatan antara frame kunci adalah konstan
- discrete - animasi beralih di antara frame kunci dalam lompatan, tanpa interpolasi
- spline - kita dapat mengatakan bahwa ini adalah mode kontrol manual (tentangnya nanti)
Sayangnya, ini semua adalah fungsi bawaan, di sini Anda tidak akan menemukan kemudahan masuk seperti dalam CSS. Jadi kebutuhan ini harus memuaskan rezim, yang saya sebut "manual".Yang paling sulit dimengerti - itu mondar-mandir , sehingga akan menjelaskan lebih rinci. Untuk memulai, lihat bagaimana animasi bekerja dalam mode standar. Animasi ini berlangsung 2 detik dan kami memiliki 3 bingkai kunci - awal, menengah, akhir <animate dur="2s" values="100; 200; 150" .../>
Jika Anda menonton animasi, akan menjadi jelas bahwa perpindahan antar bingkai kunci terjadi secara berkala. Jarak antara yang pertama dan kedua adalah 100, dan antara yang kedua dan ketiga adalah 50, yaitu setengah dari cara pertama. Dengan perhitungan sederhana, menjadi jelas bahwa elemen akan melalui segmen kedua dua kali lebih lambat dari yang pertama. Sekarang tambahkan calcMode = "mondar-mandir" dan lihat apa yang telah berubah. <animate dur="2s" values="100; 200; 150" calcMode="paced" .../>
Dan kecepatan elemen telah berubah. Sekarang ia dirancang sedemikian rupa untuk menutupi seluruh jarak dengan kecepatan yang sama, dengan kata lain, elemen akan menggerakkan kedua segmen secara merata.Sekarang mari kita lihat mode spline dan atribut keySplines . Mereka memiliki beberapa kesamaan ... hmm ...Jika spline mendefinisikan mode manual, maka atribut keySplines menentukan nilai untuk mode ini. Jelas, yang satu tidak bekerja tanpa yang lain. Nilai-nilai di keySplines ditetapkan oleh daftar di mana koordinat dua titik untuk Bezier kubik ditunjukkan.Lebih lanjut tentang Fungsi Kubik Bezier, . 4 0 1 : cubic-bezier(x1, y1, x2, y2). , .

cubic-bezier .
, .
Jumlah nilai di keySplines harus 1 kurang dari nilai . Ini disebabkan oleh fakta bahwa kami menunjukkan nilai bukan untuk bingkai kunci, tetapi untuk interval di antara mereka. <animate values="100; 200; 150" keySplines=".25 .1 .25 1; 0 0 .58 1" calcMode="spline" .../>
Koordinat titik fungsi Bezier dipisahkan oleh spasi atau koma, dan nilai daftar dipisahkan oleh titik komaminus pertama dan paling tidak menyenangkan adalah bahwa Anda tidak dapat mengatur fungsi waktu umum untuk semua frame kunci, Anda harus menduplikasi fungsi untuk setiap frame.Kedua - jika Anda ingin mengatur fungsi waktu untuk atribut dari - ke atau oleh , Anda memerlukan kruk: Anda harus mengatur keyTimes dengan nilai "0; 1" <animate from="10" to="50" keyTimes="0; 1" keySplines=".25 .1 .25 1;" calcMode="spline" .../>
Jika, bukan dari - ke menggunakan nilai-nilai dari dua nilai, maka masalah ini tidak akanBagaimana untuk mewujudkan penghematan animasi?Pertama, sedikit teori - pengulangan selanjutnya dari animasi kumulatif akan berlanjut di mana yang sebelumnya berakhir. Itu akan keren, tapi tidak terlalu ... Fakta bahwa animasi kumulatif hanya bekerja dalam pengulangan itu mengecewakan.Sekarang tentang cara membuat kumulatif animasi: Anda perlu mengatur atribut akumulasi (yang tidak ada secara default) untuk dijumlahkan <animate by="100" repeatCount="3" accumulate="sum".../>
Harus diingat bahwa jika Anda menggunakan nilai atau dari - ke , maka semua pengulangan, kecuali yang pertama, mereka akan berperilaku seolah-olah aditif = "jumlah" . Dan akumulasi diabaikan jika hanya satu yang ditentukan .Kami memahami morphing dari konturSekarang setelah saya menjelaskan dasar-dasarnya, sekarang saatnya untuk beralih ke hal-hal yang benar-benar keren dan kompleks. Saya yakin seseorang membuka artikel ini hanya untuk bagian ini.Path morphing adalah animasi atribut d dari tag path , yang memungkinkan Anda untuk membuat efek mengubah bentuk bentuk dengan mulus. Saat ini, dengan alat bawaan, ini hanya dapat dilakukan menggunakan SMIL. Masuknilai menunjukkan daftar nilai untuk atribut d melalui mana elemen melewati. Anda juga dapat menggunakan dari - ke . Secara umum, garis morf terlihat seperti ini <animate attributeName="d" values=" 1; 2; ..." .../>
Dan sekarang mari kita beralih ke seluk-beluk proses ini:Bagi mereka yang ada di dalam tangki, atribut d berisi sekumpulan titik yang selanjutnya dihubungkan pada gilirannya untuk membentuk sebuah angka. Pandangan yang lebih dekat mengungkapkan bahwa daftar nilai mirip dengan serangkaian instruksi untuk mesin CNC (atau "robot" dalam pelajaran ilmu komputer). Ada banyak tim, beberapa bertanggung jawab untuk "memindahkan kursor", yang lain untuk "menggambar", beberapa untuk berapa banyak kurva akan menjadi garis, dll. ( semua tim ada di sini ).Agar morphing berfungsi, jumlah perintah harus cocok , dan harus dari jenis yang sama . Jika Anda mengabaikan kondisi ini, maka tidak akan ada interpolasi - animasinya akan melompat dari satu kondisi ke kondisi lainnyacalcMode = "diskrit" . Pada pandangan pertama, tidak ada yang rumit, dan ini adalah jika Anda akan menghidupkan bentuk tanpa kurva. Jika tidak, maka kesulitan akan dimulai.Saat membuat grafik yang kompleks, semua orang menggunakan editor vektor, dan mereka memiliki kebiasaan mengoptimalkan "kode" sebanyak mungkin. Ini biasanya merupakan nilai tambah, tetapi tidak dalam kasus kami. Pada output, kami mungkin memiliki daftar satu panjang, tetapi dengan tim dari berbagai jenis, dan ini merupakan pelanggaran terhadap salah satu aturan. Saya menggunakan Adobe Illustrator dan tidak menemukan opsi yang dapat memperbaiki keadaan. Terkadang, atas kehendak para dewa dizign, masalah ini tidak ada. Tapi serius, probabilitas masalah berbanding lurus dengan kompleksitas gambar dan morphing.Saat ini, satu-satunya solusi untuk masalah ini adalah konversi "kode bengkok" di aplikasi web Shape Shifter . Ini adalah opsi yang saya gunakan. Selain memperbaiki kode yang rusak, Shape Shifter memungkinkan Anda melihat hasilnya, secara opsional menambahkan jenis animasi lain dan mengekspor hasilnya dalam format yang nyaman.Berikutnya akan menjadi tutorial langkah demi langkah di mana saya akan memberi tahu Anda cara membuat animasi yang begitu indah
Ajari aku: SVG Adobe Illustrator, , Shape Shifter . CSS, SMIL .
. Illustrator. , . 200x200 .
, , . , , «». ,
. . « »
, . , , ,
. , , . , . SVG , . …
. , . SVG . ( Illustrator )
, , Illustrator
<path> ,
<circle> . , . , , . - (
SVGO ), . .
d , ) <?xml version="1.0" encoding="utf-8"?> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 200 200" style="enable-background:new 0 0 200 200;" xml:space="preserve"> <style type="text/css"> .st0{fill:#D38911;} .st1{fill:#87872B;} .st2{fill:#CEB629;} .st3{fill:none;stroke:#DD913E;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:12,200;} </style> <g id="Pulse"> <g> <path class="st0" d="M100,87c44.1,0,80,35.9,80,80s-35.9,80-80,80s-80-35.9-80-80S55.9,87,100,87 M100,82c-46.9,0-85,38.1-85,85 s38.1,85,85,85s85-38.1,85-85S146.9,82,100,82L100,82z"/> </g> </g> <g id="_x3F__1_"> <path id="side" class="st1" d=" "/> <path id="front" class="st2" d=" "/> </g> <g id="Particles"> <line class="st3" x1="80" y1="162.9" x2="42" y2="59.1"/> <line class="st3" x1="90.1" y1="148.8" x2="59.8" y2="28.8"/> <line class="st3" x1="107.9" y1="155.6" x2="124.9" y2="15.9"/> <line class="st3" x1="94.4" y1="160.4" x2="154.3" y2="7.2"/> <line class="st3" x1="119.3" y1="157" x2="159.2" y2="75.5"/> <line class="st3" x1="98" y1="169" x2="87.7" y2="10.7"/> <line class="st3" x1="80.4" y1="147.6" x2="63.2" y2="14.1"/> </g> </svg>
<?xml version="1.0" encoding="utf-8"?> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"> <style type="text/css"> #Pulse{fill: none; stroke: #D38911; stroke-width: 5;} #side{fill:#87872B;} #front{fill:#CEB629;} .particles{fill:none;stroke:#DD913E;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:12,200;} </style> <circle id="Pulse" cx="100" cy="167" r="85"/> <g id="Sign"> <path id="side" d=" "/> <path id="front" d=" "/> </g> <g id="Particles"> <line class="particles" x1="80" y1="162.9" x2="42" y2="59.1"/> <line class="particles" x1="90.1" y1="148.8" x2="59.8" y2="28.8"/> <line class="particles" x1="107.9" y1="155.6" x2="124.9" y2="15.9"/> <line class="particles" x1="94.4" y1="160.4" x2="154.3" y2="7.2"/> <line class="particles" x1="119.3" y1="157" x2="159.2" y2="75.5"/> <line class="particles" x1="98" y1="169" x2="87.7" y2="10.7"/> <line class="particles" x1="80.4" y1="147.6" x2="63.2" y2="14.1"/> </g> </svg>
, . , ,CSS , . . , . . CSS . :
#Pulse{fill: none; stroke: #D38911; stroke-width: 5; transform: rotateX(80deg);} ._transformer{transform-box: fill-box; transform-origin: center;}
,
_transformer , , . «»
<animateTransform> .
- :
, Illustrator? …– , . , . ,
<path> , .
, ! – , . , – .
circle , .
animate , 3
<circle id="Pulse" class="_transformer" cx="100" cy="167" r="0"> <animate id="doPulse" attributeName="r" values="0;85;" dur=".8s" begin="Sign.click" calcMode="spline" keySplines="0,0,.58,1"/> <animate attributeName="stroke-width" values="5;12;" dur=".8s" begin="doPulse.begin"/> <animate attributeName="opacity" values="0.5;1;1;0" keyTimes="0;0.2;0.5;1" dur=".8s" begin="doPulse.begin"/> </circle>
, CSS, . : , , . - :
. - , . ,
<linearGradient id="light-gradient"> <stop offset="0%" stop-color="#ffffff00"/> <stop offset="10%" stop-color="#FFF"/> <stop offset="90%" stop-color="#FFF"/> <stop offset="100%" stop-color="#ffffff00"/> </linearGradient> <mask id="light-mask"> <rect y="0" x="90" class="_transformer" width="20" height="220" fill="url(#light-gradient)" /> </mask>
, . , , . ,
<use> ,
<path> <defs> <defs> <path id="question" d=" "/> </defs> ... <use id="front" href="#question"/> <use id="light" href="#question" mask="url(#light-mask)"/>
, , . . ,
#light-mask rect{ animation: highlight 4s infinite; } @keyframes highlight { 0% { transform: translate(-100px,0) rotate(-50deg); } 30% { transform: translate(100px,0) rotate(-50deg); } 100% { transform: translate(100px,0) rotate(-50deg); } }
. . CSS , SMIL.
, . — , . ,
<g id="Sign" class="_transformer"> <path id="side" d=" "/> <use id="front" href="#question"/> <use id="light" href="#question" mask="url(#light-mask)"/> <animateTransform id="idle" attributeName="transform" type="translate" values="0,0;0,-5;0,0" dur="6s" begin="0s; jump.end" end="click" repeatCount="indefinite" /> <animateTransform id="jump" attributeName="transform" type="translate" calMode="spline" values="0,0;0,10;0,-35;0,5;0,0" keyTimes="0;0.1;0.35;0.6;1" keySpline="0,0,.58,1;0,0,.58,1;.42,0,1,1;0,0,.58,1" dur="1s" begin="idle.end" /> </g>
,, , . ,
additive="sum" <animateTransform attributeName="transform" type="scale" additive="sum" values="1,1;1.1,0.8;0.9,1.2;1.1,0.8;1,1" keyTimes="0;0.1;0.35;0.7;1" dur="1s" begin="idle.end" />
, , . Hasil:
.
? - , , .
stroke-dashoffset , . ,
- . ,
<g id="Particles"> ... </g> <g id="Sign" class="_transformer"> ... </g>
, ,
.particles{ opacity:.7; stroke-width:0; ... }
, . ,
@keyframes sparks { 0% { stroke-dasharray: 20,200; stroke-width: 5px; } 100% { stroke-dasharray: 4,200; stroke-width: 0px; stroke-dashoffset: -180; } }
, . , , «». : CSS , , . SMIL, 3 , , 7. , , …
– , - , . CSS, SMIL.
Particles_active ,
.Particles_active .particles{ animation: sparks .7s; }
<set> , , (
set )
<g id="Particles"> <line class="particles" x1="80" y1="162.9" x2="42" y2="59.1"/> ... <line class="particles" x1="80.4" y1="147.6" x2="63.2" y2="14.1"/> <set attributeName="class" to="Particles_active" dur=".7s" begin="jump.begin + .5s"/> </g>
:. , , . 3D , . , , .
Adobe Illustrator, . , . - , . ,
d .
, . Shape Shifter.
, , . , Shape Shifter, SVG . Shape Shifter , «» SVG. Illustrator. , . , pathData
, , toValue. . «»
. ,
, , Shape Shifter , , , , . , toValue fromValue .
. ,
<animate attributeName="d" calMode="spline" values=" 1; 2; 1" dur="5s" keySpline=".42,0,.58,1;.42,0,.58,1" repeatCount="indefinite" />
1 – , 2 –. Codepen.
, SVG – , . , ,
<set>
Tag yang ditetapkan adalah versi singkat dari animasi , kecuali bahwa tag tersebut tidak dapat diinterpolasi. Ini digunakan untuk mengubah atribut secara instan untuk periode waktu tertentu, mis. bekerja berdasarkan prinsip sakelar. Akibatnya, ia mengabaikan atribut yang terkait dengan interpolasi dan tidak mendukung animasi kumulatif atau relatif. Nilai diatur secara eksklusif menggunakan atribut to , nilai , dari , oleh atribut diabaikan. <set attributeName="cx" to="200" begin="click" dur="5s" .../>
Elemen berubah posisi dengan mengklik, setelah 5 detik ia kembali ke posisi semula.Jika Anda tidak menentukan atribut dur , elemen akan tetap dalam status ini sampai dokumen dimuat ulang. Kalau tidak, ini mirip dengan menghidupkan .<animateTransform>
Seperti namanya, ini digunakan untuk menerapkan berbagai transformasi pada suatu elemen. Semua jenis transformasi identik dengan transformasi CSS. Dengan penggunaan simultan transformasi CSS dan SMIL, mereka akan saling menimpa, jadi lebih baik menggunakan satu hal, atau menonton agar tidak tumpang tindih.Bagaimana cara mentransformasikannya?Atribut animasi adalah transformasi . Mode transformasi ditunjukkan dalam atribut type dan mengambil 4 jenis nilai - bergerak, berputar, penskalaan, bergeser sepanjang sumbu.terjemahkan - memindahkan elemen relatif ke posisi saat ini. Dibutuhkan offset dalam format [x, y] , di mana y adalah parameter opsional <animateTransform attributeName="transform" type="translate" from="0, -10" to="0, 10" .../>
Memindahkan elemen sepanjang sumbu Ymemutar - memutar elemen relatif ke pusat rotasi. Dibutuhkan sudut rotasi dan koordinat pusat rotasi [deg, x, y] sebagai nilai, koordinat tengah adalah opsional. Secara default, pusat rotasi ada di sudut kiri atas dokumen SVG <animateTransform attributeName="transform" type="rotate" from="0, 150, 150" to="45, 150, 150" .../>
Putar 45 derajat di sekitar titik dengan koordinat 150, 150Juga, pusat rotasi dapat diubah menggunakan properti CSS transformasi-asal , di mana selain koordinat, Anda dapat menentukan persentase. Secara default, persentase dihitung dengan ukuran seluruh dokumen, sehingga persentase dihitung relatif terhadap elemen, Anda perlu mengatur properti CSS transform-box dengan nilai kotak-isi .skala - skala item. Sebagai nilai, dibutuhkan angka titik-mengambang dalam format [skala] untuk kedua sumbu, atau secara terpisah untuk setiap sumbu [scaleX, scaleY] (1 sesuai dengan ukuran normal elemen). Jika Anda tidak mengubah kotak transformasiSeperti yang saya sebutkan di atas, elemen tersebut diskalakan relatif terhadap seluruh dokumen. Ruang kosong di sekitar elemen juga berubah dengannya, jadi secara visual tampaknya elemen tersebut bergeser ke samping <animateTransform attributeName="transform" type="scale" from="1, 1" to="2, 1" .../>
Meregangkan elemen di sepanjang sumbu X skewX atau skewY - menggeser elemen relatif ke sumbu. Nilai mengambil sudut kemiringan [deg] . Secara default, pusat shift adalah sudut kiri atas, sehingga lelucon yang sama dengan transform-box dan transform-origin bekerja di sini sepertipada transformasi lainnya <animateTransform attributeName="transform" type="skewX" from="0" to="45" .../> <animateTransform attributeName="transform" type="skewY" from="90" to="0" .../>
Satu bergeser sepanjang X, yang lain sepanjang YPenjumlahan dan redefinisi transformasiDi animateTransform , Anda masih dapat membuat animasi kumulatif dan relatif, namun di sini atribut aditif berperilaku berbeda. Dalam nilai ganti, transformasi menimpa semua yang sebelumnya. Dalam nilai penjumlahan ,transformasi dijumlahkan dengan nilai sebelumnya <rect transform="skewY(115)" ...> <animateTransform type="translate" from="-10" to="10" additive="replace" .../> <animateTransform type="rotate" from="0" to="90" additive="sum" .../> </rect>
Dalam contoh ini, pergeseran persegi panjang akan didefinisikan ulang untuk bergerak dan memutar<animateMotion>
Diperlukan untuk menghidupkan gerakan elemen di sepanjang jalan. animateMotion mendukung atribut bernyawa dan memiliki 3 sendiri - jalan , rotate yang , Poin penting .Opsi untuk menentukan lintasanAnda dapat menentukan lintasan gerak dengan beberapa cara - gunakan atribut yang familier dari , ke , oleh, atau nilai , atribut jalur baru, atau tag <mpath> anak . Saya telah membuat daftar cara untuk meningkatkan prioritas dan saya akan menjelaskannya dalam urutan yang sama.Untuk atribut dari , ke, Dengan ditentukan koordinat titik, nilai yang sama, tapi sudah dalam daftar <animateMotion from="0,0" to="50,100" .../> <animateMotion values="0,0; 0,100; 100,100; 0,0" .../>
Efek dari metode ini sebanding dengan transformasi perpindahan biasa. Sebuah elemen bergerak lurus dari satu titik ke titik lainnya. Dan di sini, seperti dalam animateTransform , koordinatnya relatif . Titik 0,0 tidak menunjukkan sudut kiri atas dokumen, tetapi posisi saat ini dari elemen target. Fitur ini hadir dalam metode lain untuk menentukan lintasan.Atribut path menentukan seperangkat perintah, seperti untuk atribut d . Jika dalam atribut d perintah ditafsirkan sebagai garis besar gambar, maka dalam atribut path mereka adalah garis di mana elemen akan bergerak. Koordinat titik juga relatif, sehingga jalur dimulai pada titik 0,0 <animateMotion path="M 0 0 c 3.4 -6.8 27.8 -54.2 56 -37.7 C 73.3 -27.5 89.6 -5.1 81.9 5.9 c -5.8 8.3 -24.7 8.7 -45.4 -0.4" .../>
Jalur ini menggambarkan kurva seperti ituCara terakhir adalah menggunakan elemen <path> pihak ketiga sebagai path . Untuk melakukan ini, Anda harus menentukan tautan ke elemen ini di tag <mpath> , dan tag itu sendiri harus ditempatkan di dalam <animateMotion> . Opsi ini memiliki fitur yang sama dengan koordinat relatif. Pada intinya, metode ini “menyalin” nilai atribut d dari elemen ke atribut <path> <path id="movement" .../> ... <animateMotion ...> <mpath href="#movement"/> </animateMotion>
Elemen yang mendefinisikan path bahkan mungkin tidak muncul di dokumen. Anda cukup mendefinisikannya di <defs>Putar elemen relatif ke lintasan.Dimungkinkan untuk membuat elemen memutar ke arah gerakan menggunakan atribut rotate . Ini menerima 3 jenis nilai: otomatis , mundur otomatis dan angka yang menunjukkan rotasi dalam derajat <animateMotion rotate="auto" .../>
Secara default, rotate adalah 0. Nilai numerik apa pun menangkap sudut sepanjang animasi. Mode otomatis otomatis dan mundur otomatis mengubah sudut rotasi elemen, masing-masing, bersinggungan dengan jalan. Dan mereka berbeda dalam arah tangen ini. Di otomatis, ini diarahkan ke depan, sedangkan di auto-mundur , itu diarahkan kembaliBagaimana cara mengontrol pergerakan di sepanjang jalan?Lintasan adalah kurva yang memiliki awal dan akhir, titik-titik ini dilambangkan dengan angka 0 dan 1, masing-masing. Setiap posisi pada kurva dapat ditentukan oleh angka dalam kisaran ini. Dengan mencantumkan poin di atribut keyPoints , Anda dapat menentukan segala jenis gerakan di sepanjang jalur. Tetapi ini tidak cukup untuk mengendalikan gerakan, untuk ini Anda memerlukan seluruh sistem atribut.Pertama, Anda perlu mengatur calcMode ke linear atau spline . Tidak seperti tag lain, animateMotion default untuk mondar - mandir (untuk beberapa alasan, animasi tidak ingin bekerja dalam mode ini). Anda juga harus menentukan atribut.keyTimes . Hanya dengan menyelesaikan langkah-langkah ini, animasi akan berfungsi sebagaimana mestinya <animateMotion keyPoints="0.5; 1; 0; 0.5" keyTimes="0; 0.25; 0.75; 1" calcMode="linear" .../>
Dalam contoh, animasi dimulai di tengah jalan, bergerak ke ujung, lalu ke awal, dan mengakhiri gerakan lagi di tengahPSBerhubungan dengan animateMotion , saya menemukan informasi bahwa hal yang sama dapat, seperti, dilakukan pada CSS. Tetapi pada akhir artikel ini, saya tidak memiliki kekuatan maupun keinginan untuk berurusan dengan ini. Untuk penggemar, saya hanya meninggalkan tautan ke dokumentasi.Terima kasih khusus
Bhudh atas kerja kerasnya memperbaiki artikel