Ένα από τα πράγματα που μας μπέρδεψαν όταν φτιάχναμε τη νέα μας ιστοσελίδα ήταν τα μορφοποιημένα κύματα που μπορείτε να δείτε σε διάφορα σημεία των σελίδων. Είχαμε πολλές ιδέες για το πώς να τα υλοποιήσουμε με τον σωστό τρόπο χωρίς μεγάλη προσπάθεια. Ωστόσο, οι περισσότερες λύσεις ήταν αργές και έπρεπε να φτιάξουμε από το μηδέν κάτι που θα ήταν ταχύτερο από τις ήδη υπάρχουσες βιβλιοθήκες.
Προτάσεις λύσης
Ξεκινήσαμε με ένα απλό αντικείμενο SVG το οποίο κινείται με διάφορες βιβλιοθήκες. Καθώς θέλαμε να έχουμε 3 αντικείμενα σε μια σελίδα, το αποτέλεσμα δεν ήταν τόσο ικανοποιητικό. Όλα τα κινούμενα σχέδια ήταν απλά αργά - όλες οι διαδρομές ενός και μόνο αντικειμένου SVG έπρεπε να ενημερώνονται σε πολύ μικρά χρονικά διαστήματα, γεγονός που έκανε ολόκληρη τη σελίδα αργή σαν σαλιγκάρι. Αναγκαστήκαμε να απορρίψουμε τη λύση με καθαρό SVG που εισάγεται σε ένα έγγραφο. Αυτό μας άφησε δύο άλλες λύσεις για να επιλέξουμε.
Το βίντεο
στοιχείο ήταν η δεύτερη επιλογή. Ξεκινήσαμε με δύο προβλήματα:
- διαφανές φόντο, το οποίο δεν μπορεί να εφαρμοστεί με τις πιο δημοφιλείς μορφές βίντεο, όπως .mp4 ή .webm,
- ανταπόκριση, το οποίο αποτελούσε πραγματικό πρόβλημα επειδή τα βίντεο δεν είναι κλιμακούμενα ως τέτοια.
Αποφασίσαμε να κρατήσουμε αυτή τη λύση σε δεύτερη μοίρα - "αν δεν βρούμε κάτι άλλο, θα επιλέξουμε αυτή".
Η τελευταία επιλογή ήταν η χρήση καμβάς
με WebGL
απόδοση. Ήταν μια τόσο ασυνήθιστη επιλογή επειδή έπρεπε να σχεδιάσουμε μόνοι μας όλους τους μηχανισμούς απόδοσης. Αυτό οφείλεται στο γεγονός ότι τα μορφικά κύματα που είχαμε ήταν προσαρμοσμένα - αυτό μας ανάγκασε να σχεδιάσουμε μια προσαρμοσμένη λύση Και αυτή ήταν η επιλογή που θέλαμε να ακολουθήσουμε και στην οποία θέλαμε πραγματικά να επικεντρωθούμε.
Αρχιτεκτονική της λύσης
Ας ξεκινήσουμε από το μηδέν. Ποιο ήταν το υλικό που έπρεπε να χρησιμοποιήσουμε για να φτιάξουμε αυτά τα κύματα; Η ιδέα ήταν ότι όλα τα κύματα ήταν ένα αρχείο SVG μεγέθους 1×1 και συγκεκριμένα μονοπάτια τοποθετημένα γύρω από αυτή την περιοχή. Η κίνηση αυτού του SVG χτίστηκε με κάποιες μορφές καταστάσεων σε αυτό το αρχείο. Έτσι, όλα τα κινούμενα σχέδια αναπαρίσταντο ως ένα σύνολο αρχείων που περιείχαν τα στάδια της μετακίνησης ενός σχήματος.
Ρίξτε μια βαθύτερη ματιά στο τι είναι οι καταστάσεις - όλα τα μονοπάτια είναι απλώς ένα είδος πίνακα με συγκεκριμένες τιμές τοποθετημένες σε συγκεκριμένη σειρά. Η αλλαγή αυτών των τιμών σε συγκεκριμένες θέσεις μέσα σε αυτόν τον πίνακα αλλάζει το σχήμα στα συγκεκριμένα μέρη του. Μπορούμε να το απλοποιήσουμε αυτό με το ακόλουθο παράδειγμα:
κατάσταση 1: [1, 50, 25, 40, 100]
κατάσταση 2: [0, 75, -20, 5, 120]
κατάσταση 3: [5, 0, -100, 80, 90]
Έτσι, μπορούμε να υποθέσουμε ότι το σχήμα που θέλουμε να αποδώσουμε αποτελείται από πίνακα με 5 στοιχεία που αλλάζουν με τη γραμμική χαλάρωση σε συγκεκριμένες χρονικές περιόδους. Όταν το animation τελειώσει το τελευταίο στάδιο, ξεκινάει ξανά με το πρώτο για να μας δώσει την εντύπωση ενός άπειρου animation.
Αλλά... περιμένετε - τι ακριβώς είναι η συστοιχία που παρουσιάζεται παραπάνω; Όπως ανέφερα, πρόκειται για μια διαδρομή που είναι υπεύθυνη για την εμφάνιση ενός συγκεκριμένου σχήματος. Όλη η μαγεία περιλαμβάνεται στο d
ιδιότητα της διαδρομής του SVG. Αυτή η ιδιότητα περιέχει ένα σύνολο "εντολών" για τη σχεδίαση ενός σχήματος και κάθε εντολή έχει ένα είδος ορίων. Ο πίνακας που αναφέρθηκε παραπάνω αποτελείται από όλες τις τιμές (ορίσματα) που συνδέονται με αυτές τις εντολές.
Η μόνη διαφορά μεταξύ αυτών των "αρχείων κατάστασης" ήταν οι τιμές συγκεκριμένων εντολών, καθώς η σειρά των εντολών ήταν η ίδια. Έτσι, όλη η μαγεία αφορούσε τη λήψη όλων των τιμών και την εμψύχωση τους.
Ο οδηγός που ονομάζεται Physics
Στην παραπάνω παράγραφο, ανέφερα ότι η μόνη μαγεία στην εμψύχωση ενός αντικειμένου είναι η δημιουργία μεταβάσεων μεταξύ όλων των σταδίων ενός σχήματος. Το ερώτημα είναι - πώς να το κάνετε αυτό με τον καμβά;
Η λειτουργία που όλοι όσοι εργάστηκαν με καμβάς
πρέπει να γνωρίζει είναι requestAnimationFrame. Αν το βλέπετε αυτό για πρώτη φορά, πιστεύω ειλικρινά ότι πρέπει να ξεκινήσετε διαβάζοντας αυτό. Έτσι, το πράγμα με αυτή τη συνάρτηση που μας ενδιαφέρει είναι το όρισμα - DOMHighResTimeStamp
. Φαίνεται πραγματικά τρομακτικό, αλλά στην πράξη δεν είναι τόσο δύσκολο να το καταλάβετε. Μπορούμε να πούμε ότι είναι μια χρονοσφραγίδα του χρόνου που έχει παρέλθει από την πρώτη απόδοση.
Εντάξει, αλλά τι μπορούμε να κάνουμε με αυτό; Καθώς η requestAnimationFrame
συνάρτηση πρέπει να καλείται αναδρομικά, μπορούμε να έχουμε πρόσβαση σε ένα χρονικό δέλτα μεταξύ των κλήσεών της. Και εδώ πάμε με την επιστήμη! ⚛️ (εντάξει, ίσως όχι επιστήμη πυραύλων... ακόμα )
Η φυσική μας διδάσκει ότι το δέλτα μιας απόστασης είναι ίσο με το δέλτα του χρόνου πολλαπλασιασμένο με την ταχύτητα. Στην περίπτωσή μας, η ταχύτητα είναι σταθερή επειδή θέλουμε να φτάσουμε στο τελικό σημείο σε συγκεκριμένο χρονικό διάστημα. Ας δούμε λοιπόν πώς μπορούμε να το αναπαραστήσουμε με τις παραπάνω καταστάσεις:
Ας πούμε ότι θέλουμε να μεταβούμε μεταξύ αυτών των καταστάσεων σε χίλια χιλιοστά του δευτερολέπτου, οπότε οι τιμές της ταχύτητας θα είναι οι εξής:
delta: [ -1, 25, -45, -35, 20]
ταχύτητα: [-1/1000, 25/1000, -45/1000, -35/1000, 20/1000]
Η παραπάνω ταχύτητα μας λέει: για κάθε χιλιοστό του δευτερολέπτου ας αυξήσουμε την τιμή κατά -1/1000. Και εδώ είναι το σημείο όπου μπορούμε να επιστρέψουμε στο requestAnimationFrame
και χρονικό δέλτα. Η τιμή μιας συγκεκριμένης θέσης κατά την οποία θέλουμε να αυξηθεί είναι το χρονικό δέλτα πολλαπλασιασμένο με την ταχύτητα της θέσης του. Κάτι ακόμα που θα το πετύχουμε χωρίς πρόβλημα είναι να περιορίσουμε την τιμή ώστε να μην ξεπεράσει την κατάσταση στην οποία πηγαίνει.
Όταν τελειώσει η μετάβαση, καλούμε μια άλλη και ούτω καθεξής. Και δεν φαίνεται να είναι τόσο δύσκολο να εφαρμοστεί, αλλά ένας από τους κύριους κανόνες στο ανάπτυξη λογισμικού είναι να μην ξοδεύουμε χρόνο σε πράγματα που έχουν ήδη εφαρμοστεί. Έτσι - διαλέξαμε ένα μικρή βιβλιοθήκη που μας επιτρέπει να δημιουργούμε αυτές τις μεταβάσεις με αβίαστο τρόπο.
Έτσι δημιουργήσαμε ένα κινούμενο κύμα που μοιάζει με ζωντανό πλάσμα.
Λίγα λόγια για την κλωνοποίηση σχημάτων
Όπως μπορείτε να δείτε, τα κύματα της μάρκας The Codest δεν είναι μια ενιαία κινούμενη φιγούρα. Αποτελούνται από πολλές φιγούρες με το ίδιο σχήμα αλλά διαφορετικό μέγεθος και θέση. Σε αυτό το βήμα, θα ρίξουμε μια γρήγορη ματιά στο πώς να αντιγράψουμε με τέτοιο τρόπο.
Έτσι, το πλαίσιο καμβά μας επιτρέπει να περιοχή σχεδίασης κλίμακας (κάτω από την κουκούλα - μπορούμε να πούμε ότι πολλαπλασιάζει όλες τις διαστάσεις που περνάνε στις μεθόδους drawable επί "k", όπου "k" είναι ένας παράγοντας κλιμάκωσης, που από προεπιλογή έχει οριστεί σε "1"), κάνει καμβά μεταφρασμένο, είναι σαν να αλλάζετε το σημείο αγκύρωσης μιας περιοχής σχεδίασης. Και μπορούμε επίσης να μεταπηδήσουμε μεταξύ αυτών των καταστάσεων με αυτές τις μεθόδους: save και αποκατάσταση.
Αυτές οι μέθοδοι μας επιτρέπουν να αποθηκεύσουμε την κατάσταση "μηδενικών τροποποιήσεων" και στη συνέχεια να αποδώσουμε συγκεκριμένο αριθμό κυμάτων στο βρόχο με σωστά κλιμακωμένο και μεταφρασμένο καμβά. Αμέσως μετά από αυτό, μπορούμε να επιστρέψουμε στην αποθηκευμένη κατάσταση. Αυτά είναι όλα σχετικά με την κλωνοποίηση σχήματος. Πολύ πιο εύκολο από το κλωνοποίηση προβάτων, έτσι δεν είναι;
Κεράσι στην κορυφή
Ανέφερα ότι απορρίψαμε μία από τις πιθανές λύσεις λόγω των επιδόσεων. Η επιλογή με τον καμβά είναι αρκετά γρήγορη, αλλά κανείς δεν είπε ότι δεν θα μπορούσε να βελτιστοποιηθεί ακόμη περισσότερο. Ας ξεκινήσουμε με το γεγονός ότι δεν μας ενδιαφέρει πραγματικά η μετάβαση των σχημάτων όταν βρίσκονται εκτός του πεδίου προβολής του προγράμματος περιήγησης.
Υπάρχει ένα άλλο API του προγράμματος περιήγησης που οι προγραμματιστές λάτρεψαν - IntersectionObserver. Μας επιτρέπει να ακολουθούμε συγκεκριμένα στοιχεία της σελίδας και να χειριζόμαστε γεγονότα που προκαλούνται όταν αυτά τα στοιχεία εμφανίζονται ή εξαφανίζονται από το παράθυρο προβολής. Αυτή τη στιγμή - έχουμε μια αρκετά εύκολη κατάσταση - ας δημιουργήσουμε την κατάσταση της ορατότητας, ας την αλλάξουμε λόγω των χειριστών συμβάντων IntersectionObserver και απλά ας ενεργοποιήσουμε/απενεργοποιήσουμε το σύστημα απόδοσης για συγκεκριμένα σχήματα. Και ... μπουμ, η απόδοση έχει βελτιωθεί πολύ! Αποδίδουμε τα μόνα πράγματα που είναι ορατά στο παράθυρο προβολής.
Περίληψη
Η επιλογή ενός τρόπου υλοποίησης είναι συχνά μια δύσκολη επιλογή, ειδικά όταν οι διαθέσιμες επιλογές φαίνεται να έχουν παρόμοια πλεονεκτήματα και μειονεκτήματα. Το κλειδί για να κάνουμε μια σωστή επιλογή είναι να αναλύσουμε καθεμία από αυτές και να αποκλείσουμε εκείνες που θεωρούμε λιγότερο επωφελείς. Δεν είναι όλα ξεκάθαρα - κάποια λύση απαιτεί περισσότερο χρόνο από τις άλλες, αλλά μπορεί να βελτιστοποιείται ευκολότερα ή να προσαρμόζεται περισσότερο.
Παρόλο που νέες βιβλιοθήκες JS εμφανίζονται σχεδόν κάθε λεπτό, υπάρχουν πράγματα που δεν μπορούν να επιλύσουν. Και αυτός είναι ο λόγος για τον οποίο κάθε front-end engineer (και όχι μόνο αυτός) θα πρέπει να γνωρίζει τα API του προγράμματος περιήγησης, να ενημερώνεται για τα τεχνικά νέα και μερικές φορές να σκέφτεται απλά "πώς θα ήταν η δική μου υλοποίηση αυτής της βιβλιοθήκης αν έπρεπε να κάνω αυτό;". Με περισσότερες γνώσεις σχετικά με τα προγράμματα περιήγησης, μπορούμε να κατασκευάσουμε πραγματικά φανταχτερά πράγματα, να πάρουμε σωστές αποφάσεις σχετικά με τα εργαλεία που χρησιμοποιούμε και να γίνουμε πιο σίγουροι για την κωδικός.
Διαβάστε περισσότερα:
– Ruby 3.0. Ruby και λιγότερο γνωστές μέθοδοι ελέγχου της ιδιωτικότητας
– Σκάσε και πάρε τα λεφτά σου #1: Κρυφό κόστος και πραγματική ευελιξία στη διαδικασία ανάπτυξης προϊόντων
– Προκλήσεις CTO - κλιμάκωση και ανάπτυξη προϊόντων λογισμικού