D3 και καμβά σε 3 βήματα

Η δέσμευση, η ισοπαλία και η διαδραστικότητα

Ας πούμε ότι χτίζετε μια οπτικοποίηση δεδομένων χρησιμοποιώντας D3 και SVG. Μπορείτε να χτυπήσετε ένα ανώτατο όριο όταν προσπαθείτε να εμφανίσετε αρκετές χιλιάδες στοιχεία την ίδια στιγμή. Ο φυλλομετρητής σας μπορεί να αρχίσει να φουσκώνει κάτω από το βάρος όλων αυτών των στοιχείων DOM.

Λοιπόν εδώ έρχεται HTML5 καμβά για τη διάσωση! Είναι πολύ γρηγορότερο, ώστε να μπορεί να λύσει τα προβλήματα εμφάνισης του φυλλομετρητή σας.

Αλλά μπορεί γρήγορα να βρεθείτε απογοητευμένοι. Επειδή οι D3 και Canvas λειτουργούν λίγο διαφορετικά από το D3 και το SVG - ειδικά όταν πρόκειται για σχεδίαση και προσθήκη αλληλεπίδρασης.

Αλλά δεν φοβόμαστε - δεν είναι τόσο περίπλοκο. Οποιαδήποτε εμπειρία που είχατε με την κατασκευή οπτικών με D3 και SVG - ή πλησιάζοντας D3 με διαφορετικό renderer - θα σας βοηθήσει τρομερά.

Αυτό το σεμινάριο χτίστηκε στους ώμους των γιγάντων που έχουν ήδη καλύψει καμβά καλά. Έμαθα αυτά τα τρία μαθήματα από την καρδιά μου και σας συνιστώ να το κάνετε και εσείς:

  • Εργασία με το D3.js και τον καμβά: Πότε και πώς από την Irene Ros
  • Βελόνες, Haystacks και API Canvas από τον Yannick Assogba
  • Ενημέρωση από εξαρτημένο D3.js για την εκκίνηση με καμβά από τον Nadieh Bremer

Γιατί λοιπόν να συνεχίσουμε να διαβάζουμε αυτό; Λοιπόν, όταν θέλω να μάθω κάτι καινούργιο, με βοηθά πολύ να εξετάσω το ίδιο θέμα από ελαφρώς διαφορετικές γωνίες. Και αυτό το σεμινάριο είναι μια ελαφρώς διαφορετική γωνία.

Επίσης, αυτό το σεμινάριο καλύπτει τα τρία βασικά βήματα: δεσμευτικά δεδομένα, στοιχεία σχεδίασης και προσθήκη αλληλεπίδρασης - και το κάνει όλα αυτά με μια κίνηση, με ένα πρόσθετο εγχειρίδιο βήμα προς βήμα για να σας καθοδηγήσει.

Τι χτίζουμε;

Ένα πλέγμα όμορφα χρώματα

Ένα πλέγμα από (πολλά) τετράγωνα. Τα χρώματα τους δεν έχουν κανένα βαθύ νόημα, αλλά δεν φαίνονται όμορφα; Το σημαντικό κομμάτι είναι ότι μπορείτε να το ενημερώσετε (για να καλύψετε τα δεσμευτικά και την ενημέρωση των δεδομένων), να έχει πολλά στοιχεία (μέχρι 10.000 για να πληρώσει ο καμβάς) και ότι μπορείτε να τοποθετήσετε το δείκτη του ποντικιού πάνω από κάθε τετράγωνο για να εμφανίσετε ειδικές τετραγωνικές πληροφορίες (διαδραστικότητα). Μπορείτε να παίξετε μαζί του εδώ σε πλήρη οθόνη ή εδώ με όλο τον κώδικα

Το νοητικό μοντέλο

Πριν αρχίσουμε πραγματικά να βουτήξουμε, ας επιστρέψουμε γρήγορα και να κατανοήσουμε με εννοιολογικό τρόπο τι κάνουμε όταν δημιουργούμε στοιχεία με την D3 για να τα σχεδιάσουμε στην οθόνη. Περάστε αυτό, αν απλά θέλετε να κάνετε τα πράγματα.

Το πρώτο βήμα όταν χρησιμοποιείτε το D3 συνήθως δεν περιλαμβάνει σχεδίαση - περιλαμβάνει προετοιμασία όλων των στοιχείων που θέλετε να σχεδιάσετε. Είναι λίγο σαν να χτίζεις κάποιο LEGO. Μπορείτε να ανοίξετε το κιβώτιο και να ξεκινήσετε να κατασκευάζετε κάτι ή μπορείτε πρώτα να δείτε το εγχειρίδιο και να το κατασκευάσετε σύμφωνα με το σχέδιο. Το εγχειρίδιο είναι το νοητικό σας μοντέλο, ένα σχέδιο ή συνταγή του τι θέλετε να χτίσετε.

Ένα νοητικό μοντέλο μετατράπηκε σε υλικό (Mike, 2009 https://creativecommons.org/licenses/by/2.0/)

Τι είναι το μοντέλο της D3; Εκτός από τον μεγάλο αριθμό χρήσιμων λειτουργιών και μεθόδων που υπολογίζουν τις θέσεις, αναμορφώνουν τα σύνολα δεδομένων και δημιουργούν λειτουργίες που αντλούν, για παράδειγμα, διαδρομές για εμάς, το D3 έχει ένα μοντέλο για τον τρόπο με τον οποίο οι ζωές των στοιχείων θα πρέπει να εξελιχθούν στην οθόνη . Έχει έναν συγκεκριμένο τρόπο να σκεφτεί τον κύκλο ζωής κάθε στοιχείου.

Λιγότερο αιθερικό, εισάγετε τα δεδομένα σε ένα DOM που δεν υπάρχει ακόμα και το D3 δημιουργεί νέα στοιχεία της επιλογής σας σύμφωνα με τα δεδομένα που εισάγετε. Συνήθως ένα στοιχείο ανά datapoint. Εάν θέλετε να εισάγετε νέα δεδομένα στο DOM, μπορείτε να το κάνετε και το D3 προσδιορίζει ποια στοιχεία πρέπει να δημιουργηθούν πρόσφατα, ποια στοιχεία επιτρέπεται να παραμείνουν και ποια στοιχεία πρέπει να συσκευάζονται και να εγκαταλείπουν την οθόνη.

Το D3 συνήθως χρησιμοποιείται σε συνδυασμό με το SVG ή μερικές φορές με στοιχεία HTML. Σε αυτή την ορθόδοξη περίπτωση, μπορείτε να δείτε τα δεδομένα στο DOM όταν επιλέγετε να τα εξετάσετε μέσω της κονσόλας, για παράδειγμα. Μπορείτε να το πάρετε, μπορείτε να το μετακινήσετε επάνω ή κάτω από το DOM και μπορείτε - πολύ σημαντικό - να προσθέσετε αλληλεπίδραση σε κάθε στοιχείο που θέλετε να δείξετε, για παράδειγμα, μια επεξήγηση εργαλείων.

Αλλά - από την αρνητική πλευρά - δεν μπορείτε να δείξετε πολλά στοιχεία. Γιατί; Επειδή τα περισσότερα στοιχεία που πιέζετε στο DOM, τόσο πιο δύσκολο το πρόγραμμα περιήγησης πρέπει να λειτουργήσει για να τα εμφανίσει όλα. Αφήστε τους επίσης να μετακινηθούν και το πρόγραμμα περιήγησης πρέπει να τους υπολογίσει εκ νέου συνεχώς. Όσο πιο δύσκολο γίνεται το πρόγραμμα περιήγησης, τόσο χαμηλότερο είναι το ποσοστό καρέ σας ή το FPS (Frames Per Second), το οποίο μετρά πόσα πλαίσια το πρόγραμμα περιήγησης μπορεί να ζωγραφίσει κάθε δευτερόλεπτο. Ένας ρυθμός καρέ των 60 είναι καλός και επιτρέπει μια εμπειρία ρευστού εφ 'όσον δεν χάνονται καρέ - ένας ρυθμός πλαισίου οτιδήποτε κάτω από 30 μπορεί να ισοδυναμεί με μια ασταθής βόλτα. Έτσι, όταν θέλετε να δείτε περισσότερα στοιχεία, μπορείτε να επιστρέψετε σε καμβά.

Γιατί καμβά; Ο καμβάς είναι ένα στοιχείο HTML5 που έρχεται με το δικό του API για να ζωγραφίζει πάνω του. Όλα τα στοιχεία που σχεδιάζονται στο στοιχείο του καμβά δεν θα εκδηλωθούν στο DOM και θα σώσει πολλή δουλειά για το πρόγραμμα περιήγησης. Τραβούνται σε άμεση λειτουργία. Αυτό σημαίνει ότι τα παρασχεθέντα στοιχεία δεν θα αποθηκευτούν στο DOM, αλλά οι οδηγίες σας θα τα επιστήσουν απευθείας σε ένα συγκεκριμένο πλαίσιο. Το DOM γνωρίζει μόνο το στοιχείο ενός καμβά. όλα σε αυτό είναι μόνο στη μνήμη. Αν θέλετε να αλλάξετε τα στοιχεία του καμβά σας, πρέπει να επανασχεδιάσετε τη σκηνή για το επόμενο πλαίσιο.

Το πρόβλημα με αυτό είναι βέβαια ότι δεν μπορείτε να επικοινωνήσετε άμεσα με αυτά τα μη-υλικά στοιχεία που ζουν στη μνήμη. Πρέπει να βρούμε έναν τρόπο να τους μιλήσουμε έμμεσα. Αυτό είναι όπου έρχεται το μοντέλο D3 καθώς και προσαρμοσμένα ή «εικονικά» στοιχεία DOM. Αυτό που θα κάνετε κυρίως είναι:

  1. Συνδέστε τα δεδομένα σας σε προσαρμοσμένα στοιχεία DOM. Δεν ζουν στο DOM αλλά μόνο στη μνήμη (σε ένα «εικονικό» DOM) και περιγράφουν τον κύκλο ζωής αυτών των στοιχείων με έναν γνωστό τρόπο D3.
  2. Χρησιμοποιήστε καμβά για να σχεδιάσετε αυτά τα στοιχεία.
  3. Προσθέστε διαδραστικότητα με μια τεχνική που ονομάζεται 'picking'.

Ας το κάνουμε.

Τα δεδομένα

Πριν αρχίσουμε να κωδικοποιούμε, ας παράγουμε κάποια δεδομένα. Ας υποθέσουμε ότι θέλετε 5.000 datapoints. Ας δημιουργήσουμε έναν πίνακα με 5.000 στοιχεία, καθένα από τα οποία είναι ένα αντικείμενο με μια μόνο τιμή ιδιοκτησίας που φέρει το δείκτη του στοιχείου. Εδώ μπορείτε να το δημιουργήσετε με το d3.range (). Το d3.range () είναι μια συνάρτηση χρησιμότητας D3, η οποία δημιουργεί μια συστοιχία με βάση το επιχείρημά της:

var δεδομένα = [].
d3.order (5000) .forEach (συνάρτηση (el) {
  data.push ({value: el});
});

Δείτε πώς εμφανίζονται τα δεδομένα στην κονσόλα

Συγκίνηση!

Το δοχείο καμβά και τα εργαλεία του

Το στοιχείο καμβά είναι ένα στοιχείο HTML. Είναι εννοιολογικά πολύ σαν οποιοδήποτε γονικό στοιχείο SVG, το οποίο συνήθως προσθέτω συνήθως σε ένα απλό διαμέρισμα container όπως στο:

Έτσι, ας το προσθέσουμε στο κουτί σας με D3 όπως και στο ...

var πλάτος = 750, ύψος = 400;
var canvas = d3.select ('# container')
  .append ('καμβάς')
  .attr ('πλάτος', πλάτος)
  .attr ('ύψος', ύψος).
var πλαίσιο = canvas.node (). getContext ('2δ');

Πρέπει επίσης να προσθέσετε το πλαίσιο, το οποίο είναι η εργαλειοθήκη του καμβά. Η μεταβλητή περιβάλλοντος είναι από τώρα και στο αντικείμενο που μεταφέρει όλες τις ιδιότητες και τις μεθόδους, τις βούρτσες και τα χρώματα που πρέπει να σχεδιάσετε στον καμβά. Χωρίς το πλαίσιο, το στοιχείο καμβά θα παραμείνει άδειο και λευκό. Αυτό είναι το μόνο που χρειάζεται να ρυθμίσετε - έναν καμβά και τα εργαλεία του ...

Βάση από τον Stilfehler - δική του δουλειά, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=5899171; μπλε Lego από τον David Lofink, 2008 https://creativecommons.org/licenses/by/2.0/

Το HTML

... είναι απλή. Η κύρια δομή HTML του ιστότοπού σας θα είναι:


Χρωματισμένα πλέγματα



... παίρνει αριθμούς μεταξύ 1 και 10k

Η δομή του Javascript

Σε ανώτερο επίπεδο χρειάζεστε μόνο 2 λειτουργίες:

δεδομένα δεδομένων (δεδομένα) {
  // Δεσμεύστε δεδομένα σε προσαρμοσμένα στοιχεία.
}}
σχεδιάζω() {
  // Σχεδιάστε τα στοιχεία στον καμβά.
}}

Αρκετά ευθεία προς τα εμπρός μέχρι τώρα.

Συνδέστε τα στοιχεία

Για να συνδέσετε δεδομένα στα στοιχεία που δημιουργείτε πρώτα ένα στοιχείο βάσης για όλα τα προσαρμοσμένα στοιχεία που θα δημιουργήσετε και θα σχεδιάσετε. Εάν γνωρίζετε καλά το D3, σκεφτείτε το ως αντικατάσταση του στοιχείου SVG:

var customBase = document.createElement ('προσαρμοσμένο');
var custom = d3.select (customBase);
// Αυτή είναι η αντικατάσταση SVG και ο γονέας όλων των άλλων στοιχείων

Στη συνέχεια, προσθέτετε κάποιες ρυθμίσεις για το πλέγμα σας. Με λίγα λόγια, αυτές οι ρυθμίσεις σας επιτρέπουν να σχεδιάσετε ένα πλέγμα τετραγώνων. 100 τετράγωνα δημιουργούν ένα 'δέμα' και υπάρχει ένα σπάσιμο γραμμής μετά από δέκα δέματα (ή μετά από 1.000 τετράγωνα). Μπορείτε να ρυθμίσετε αυτό για διαφορετική 'κατανομή' των τετραγώνων ή διαφορετικών γραμμών. Ή απλώς μην ανησυχείτε γι 'αυτό. Προτείνω την τελευταία ...

// Ρυθμίσεις για ένα πλέγμα με 10 κελιά στη σειρά,
// 100 κύτταρα σε ένα μπλοκ και 1000 κύτταρα σε σειρά.
var groupSpacing = 4;
var cellSpacing = 2;
var offsetTop = ύψος / 5;
var cellSize = Math.floor ((πλάτος - 11 * groupSpacing) / 100) - cellSpacing;

Τώρα ας ξεκινήσουμε την αποστολή δεσμεύσεων δεδομένων. Ας πάρουμε πρώτα τα αναγκαιότητα και να δημιουργήσουμε μια κλίμακα χρώματος που θα εφαρμοστεί στα τετράγωνα σας λίγο αργότερα.

λειτουργία δεδομένων (δεδομένα) {
// Πάρτε μια κλίμακα για τα χρώματα - όχι απαραίτητη αλλά ωραία.
colourScale = d3.scaleSequential (d3.interpolateSpectral)
                .domain (d3.extent (δεδομένα, λειτουργία (d) {επιστροφή d;}));

Τώρα, ας ενώσουμε τα δεδομένα σας στο 'replace-SVG' που κάνατε πιο πάνω ως προσαρμοσμένο και προσθέστε ακόμα μη υπάρχοντα προσαρμοσμένα στοιχεία με την κλάση .rect

var join = custom.selectΌλα ('custom.rect')
  ημερομηνίες (δεδομένα).

Εισάγετε τα προσαρμοσμένα στοιχεία (θυμηθείτε ότι τίποτα δεν εισέρχεται στο DOM, αυτό είναι όλα στη μνήμη).

var enterSel = join.enter ()
  .append ('custom')
  .attr ('class', 'rect')
  .attr ("x", συνάρτηση (d, i) {
    var x0 = Math.floor (i / 100)% 10, χ1 = Math.floor (i% 10);
    επιστροφή ομάδαςΚαθαρισμός * x0 + (cellSpacing + cellSize) * (x1 + x0 * 10); })
  .attr ("y", συνάρτηση (d, i) {
  var y0 = Math.floor (i / 1000), y1 = Math.floor (i% 100/10).
  επιστροφή ομάδαςΚαθαρισμός * y0 + (cellSpacing + cellSize) * (y1 + y0 * 10); })
  .attr ('πλάτος', 0)
  .attr ('ύψος', 0).

Όταν ένα στοιχείο εισέρχεται στο μοντέλο σας, το δίνετε απλά μια θέση x και y καθώς και πλάτος και ύψος 0, τα οποία θα αλλάξετε στην επερχόμενη επιλογή ενημέρωσης ...

Μπορείτε να συγχωνεύσετε την επιλογή εισαγωγής στην επιλογή ενημέρωσης και να ορίσετε όλα τα χαρακτηριστικά για την ενημέρωση και να εισαγάγετε την επιλογή. Αυτό περιλαμβάνει μια τιμή πλάτους και ύψους καθώς και ένα χρώμα από την κλίμακα χρώματος που δημιουργήσατε νωρίτερα:

Συμμετοχή
  .merge (enterSel)
  .μετάβαση()
  .attr ('πλάτος', cellSize)
  .attr ('ύψος', cellSize)
  .attr ('fillStyle', συνάρτηση (d) {χρώμα επιστροφήςScale (d);});

Δύο πράγματα για την τελευταία γραμμή. Όταν εργάζεστε με το SVG αυτή η γραμμή θα είναι

.style ('χρώμα', συνάρτηση (d) {επιστροφή χρώματοςΚλίμακα (d),})

Αλλά με τον καμβά χρησιμοποιείτε το .attr (). Γιατί; Το κύριο ενδιαφέρον σας είναι να βρείτε έναν τρόπο χωρίς πόνο για να μεταφέρετε κάποιες πληροφορίες για συγκεκριμένα στοιχεία. Εδώ θέλετε να μεταφέρετε μια έγχρωμη συμβολοσειρά από τη βάση δεδομένων () στη λειτουργία draw (). Χρησιμοποιείτε το στοιχείο απλώς ως ένα σκάφος για τη μεταφορά των δεδομένων σας σε εκεί όπου αποδίδεται στον καμβά.

Αυτή είναι μια πολύ σημαντική διάκριση: όταν εργάζεστε με το SVG ή το HTML, μπορείτε να δεσμεύσετε δεδομένα σε στοιχεία και να σχεδιάσετε ή να εφαρμόσετε στυλ στα στοιχεία σε ένα βήμα. Στον καμβά χρειάζεστε δύο βήματα. Αρχικά δεσμεύετε τα δεδομένα και στη συνέχεια συντάσσετε τα δεδομένα. Δεν μπορείτε να διαμορφώσετε τα στοιχεία ενώ δεσμεύετε. Αυτά υπάρχουν μόνο στη μνήμη και ο καμβάς δεν μπορεί να στυλιστεί με ιδιότητες στυλ CSS, πράγμα που είναι ακριβώς αυτό που έχετε πρόσβαση όταν χρησιμοποιείτε το .style ().

Αρχικά, αυτό μπορεί να φαίνεται περιοριστικό, καθώς μπορείτε να κάνετε λιγότερα σε ένα βήμα, αλλά είναι εννοιολογικά σχεδόν καθαρότερο και σας δίνει επίσης κάποια ελευθερία. Το .attr () μας επιτρέπει να στέλνουμε ζεύγη κλειδιών-τιμών στο ταξίδι. Μπορείτε να χρησιμοποιήσετε άλλες μεθόδους όπως η ιδιότητα HTML .dataset για παράδειγμα, αλλά το .attr () θα κάνει καλά.

Παρατηρήστε ότι δεν λέμε χρώμα αλλά fillStyle. Για να είμαι ειλικρινής, θα μπορούσατε να χρησιμοποιήσετε το χρώμα ή θα μπορούσατε να χρησιμοποιήσετε το chooChooTrain εδώ. Θα χρειαστεί να το θυμάστε αυτό μόνο όταν φέρετε τις πληροφορίες αργότερα κατά τη διάρκεια του σχεδίου. Ωστόσο, καθώς ο καμβάς χρησιμοποιεί μια ιδιότητα που ονομάζεται fillStyle σε στοιχεία στυλ, φαίνεται πιο ενδεδειγμένη σε αυτή την περίπτωση.

Τέλος, καθορίζετε επίσης την επιλογή εξόδου, αποφασίζοντας τι πρέπει να συμβεί στα εξερχόμενα στοιχεία.

var exitSel = join.exit ()
  .μετάβαση()
  .attr ('πλάτος', 0)
  .attr ('ύψος', 0)
  .αφαιρώ();

Αυτό είναι! Μπορείτε να κλείσετε τη λειτουργία databind () και να συνεχίσετε ...

} // databind ()

Αυτό δεν είναι πραγματικά τρομακτικό που προέρχεται από το D3 καθώς είναι σχεδόν ακριβώς το ίδιο. Τώρα έχετε δημιουργήσει με επιτυχία το μοντέλο δεδομένων σας, τον τρόπο με τον οποίο η εφαρμογή θα σκεφτεί τα δεδομένα. Κάθε στοιχείο θα έχει τις ιδιότητες που χρειάζεται για να σχεδιαστεί μέσω των λειτουργιών .attr () και κάθε στοιχείο θα εκχωρηθεί σε μια κατάσταση κύκλου ζωής ανάλογα με τα δεδομένα που έχουν εγχυθεί. Το πρότυπο μοντέλο μας D3.

Σχεδίαση των στοιχείων

Από την Kristina Alexanderson, 2011 https://creativecommons.org/licenses/by-nc-nd/2.0/

Τώρα πρέπει να γράψετε τη λειτουργία κλήρωσης για να λάβετε τα στοιχεία στην οθόνη. Ας σημειώσουμε εδώ ότι τίποτα δεν έχει συμβεί ακόμα. Δεν έχετε καλέσει το databind () ακόμα επειδή πρέπει να βρείτε έναν τρόπο να το σύρετε στον καμβά πρώτα. Εδώ λοιπόν πάμε ... Η λειτουργία draw () δεν χρειάζεται να πάρει κανένα επιχείρημα στην περίπτωση αυτή:

() {

Όπως αναφέρθηκε προηγουμένως, πρέπει να φροντίσετε να καθαρίζετε τον καμβά κάθε φορά που σχεδιάζετε ξανά. Το DOM είναι υλικό, δεδομένου ότι όταν σχεδιάζετε ένα στοιχείο ορθής οθόνης σε αυτό και αλλάζετε την τιμή του x, θα κινείται προς την κατεύθυνση x και το DOM θα φροντίσει αυτομάτως αυτή τη μετακίνηση (ή τη νέα βαφή).

Αν μετακινήσετε ένα ορθογώνιο από x = 0 σε x = 1 σε ένα συγκεκριμένο χρονικό σημείο (μετά από ένα πάτημα ενός κουμπιού για παράδειγμα), το πρόγραμμα περιήγησης θα μετακινήσει το ορθογώνιο από 0 σε 1 μέσα σε ένα tick ή frame-paint (το οποίο έχει μήκος περίπου 16ms ). Αν το μετακινήσετε από 0 σε 10, θα το πράξει σε μια χρονική στιγμή, ανάλογα με τη διάρκεια που ζητήσατε να γίνει αυτή η μετάβαση, ίσως 1 εικονοστοιχείο ανά τσεπάκι ίσως 8 pixel ανά τσιμπούρι (για περισσότερες πληροφορίες διαβάστε αυτό το blog).

Αλλά θα πει το pixel στο 0 ότι το ορθογώνιο έχει εξαφανιστεί και το pixel στο 1 ότι υπάρχει ένα ορθογώνιο τώρα. Ο καμβάς δεν το κάνει αυτό. Πρέπει να πείτε στον καμβά τι να ζωγραφίσετε και εάν ζωγραφίσετε κάτι καινούργιο, πρέπει να του πείτε να αφαιρέσει το προηγούμενο χρώμα.

Ας αρχίσουμε λοιπόν να καθαρίζουμε οτιδήποτε μπορεί να είναι στον καμβά πριν σχεδιάσετε. Δείτε πώς:

context.clearRect (0, 0, πλάτος, ύψος); // Καθαρίστε τον καμβά.

Απλός.

Τώρα εσύ…

  1. ... πάρετε όλα τα στοιχεία για να
  2. βρόχο μέσω όλων των στοιχείων και
  3. πάρτε τις πληροφορίες που έχετε αποθηκεύσει στη λειτουργία databaseind ​​() για να σχεδιάσετε το στοιχείο:
// Σχεδιάστε κάθε μεμονωμένο προσαρμοσμένο στοιχείο με τις ιδιότητές του.
var στοιχεία = custom.selectΌλα ('custom.rect');
// Πιάσε όλα τα στοιχεία στα οποία δεσμεύονται δεδομένα στη λειτουργία databaseind ​​().
elements.each (συνάρτηση (d, i) {// Για κάθε εικονικό / προσαρμοσμένο στοιχείο ...
  var node = d3.σελέξ (αυτό);
  // Αυτό είναι κάθε ξεχωριστό στοιχείο στον βρόχο.
  
  context.fillStyle = node.attr ('fillStyle').
  // Εδώ μπορείτε να ανακτήσετε το χρώμα από τον μεμονωμένο κόμβο της μνήμης και να ορίσετε το fillStyle για το χρώμα του καμβά
  context.fillRect (node.attr ('x'), node.attr ('y'), node.attr ('πλάτος'), node.attr ('ύψος')).
  // Εδώ μπορείτε να ανακτήσετε τη θέση του κόμβου και να το εφαρμόσετε στη συνάρτηση contextRectRect που θα γεμίσει και θα βάψει το τετράγωνο.
}); // Βρόχος μέσα από κάθε στοιχείο.

Και αυτό είναι! Μπορείτε να κλείσετε τη λειτουργία κλήρωσης ()

} // σχεδιάζω()

Όταν άρχισα με τον καμβά μετά από λίγο που θέλω να βουτήξω σε αυτό, αυτή η απλότητα πραγματικά επάνω μου πνεύματα.

Ωστόσο, δεν έχει γίνει κάτι στο πρόγραμμα περιήγησης. Έχουμε τα εργαλεία στη βάση δεδομένων () και στη λειτουργία draw (), αλλά τίποτα δεν έχει συνταχθεί ακόμα. Πώς το κάνεις αυτό; Εάν απλά ήθελε να σχεδιάσει ένα στατικό οπτικό ή εικόνα, απλά τηλεφωνείτε:

δεδομένα δεδομένων (δεδομένα) ·
σχεδιάζω();

Αυτό θα συνδέσει τα δεδομένα με τα προσαρμοσμένα στοιχεία, τα οποία θα ζούσαν στη μνήμη και στη συνέχεια θα το εφάρμοζαν - μία φορά!

Αλλά έχετε μεταβάσεις. Θυμηθείτε παραπάνω: όταν γράψατε τη λειτουργία databaseind ​​(), μεταβάλατε το πλάτος κυψελών και το ύψος από το 0 στο μέγεθος τους καθώς και το χρώμα από το μαύρο (το προεπιλεγμένο) στο χρώμα του αντίστοιχου στοιχείου. Μια προεπιλεγμένη μετάβαση D3 διαρκεί 250 χιλιοστά του δευτερολέπτου, οπότε πρέπει να επανασχεδιάσετε τα τετράγωνα πολλές φορές σε αυτά τα 250 ms για να έχετε μια ομαλή μετάβαση. Πώς το κάνεις αυτό;

Είναι και πάλι απλή. Απλώς καλέσατε τη βάση δεδομένων (δεδομένα) για να δημιουργήσετε τα προσαρμοσμένα στοιχεία μας προτού να καλέσετε επανειλημμένα την κλήρωση () για όσο διάστημα χρειάζεται η μετάβαση για να τρέξει. Έτσι στην περίπτωσή μας τουλάχιστον 250 ms. Θα μπορούσατε να χρησιμοποιήσετε το setInterval () γι 'αυτό, αλλά πρέπει πραγματικά να χρησιμοποιήσουμε το requestAnimationFrame () για να είμαστε όσο το δυνατόν πιο αποδοτικοί (για περισσότερες πληροφορίες). Υπάρχουν μερικοί τρόποι για να το χρησιμοποιήσετε, αλλά διατηρώντας μέσα στο πνεύμα D3, σας προτείνω να χρησιμοποιήσετε το d3.timer () το οποίο υλοποιεί το requestAnimationFrame () καθώς και να είστε ευθεία προς χρήση. Τόσο εδώ:

// === Πρώτη κλήση === //
βάση δεδομένων (d3.περιφορά (τιμή)); // Δημιουργία των προσαρμοσμένων στοιχείων στη μνήμη.
var t = d3.timer (λειτουργία (παρήλθε) {
  σχεδιάζω();
  αν (παρελθόν> 300) t.stop ();
}); // Χρονοδιακόπτης που εκτελεί τη λειτουργία κλήρωσης επανειλημμένα για 300 ms.

Το d3.timer () καλεί επανειλημμένα την επανάκληση έως ότου παρέλθει (που είναι ο χρόνος που πέρασε σε χιλιοστά του δευτερολέπτου από την παράσταση) και μετά ο χρονιστής σταμάτησε. Σε αυτά τα 300 χιλιοστά του δευτερολέπτου, τρέχει το draw () σε κάθε τσιμπούρι (περίπου κάθε 16ms). draw (), τότε εξετάζει τα χαρακτηριστικά κάθε στοιχείου και τα σχεδιάζει αναλόγως.

Έτσι λειτουργεί η μετάβαση σε καμβά. Μπορείτε να καλέσετε τη λειτουργία σχεδίασης αμέσως μετά τη λειτουργία σύνδεσης πολλές φορές. Όποια και αν είναι το μοντέλο σας D3 που έχει ρυθμιστεί σε μετάβαση (θέσεις, χρώματα, μεγέθη), θα ανασυσταθεί πολλές φορές με μικρές σταδιακές αλλαγές για κάθε ισοπαλία

Σημειώστε ότι η κλήρωση () πρέπει να έρθει αμέσως μετά τη συνάρτηση δεδομένων (). Δεν θα μπορούσατε να ζητήσετε από το μηχάνημα να τρέξει το databaseind ​​(), στη συνέχεια κάντε κάτι άλλο για ένα δευτερόλεπτο και στη συνέχεια κλήση κλήρωση (). Επειδή μετά από 1 δευτερόλεπτο οι μεταβατικές καταστάσεις που υπολογίστηκαν από τη συνάρτηση databaseind ​​() έχουν όλα μετατραπεί ήδη. Έγινε, ξεσκονισμένο και ξεχασμένο.

Αυτό είναι! Έχετε δεσμεύσει δεδομένα σε προσαρμοσμένα στοιχεία και έχετε σχεδιάσει στον καμβά.

Αφήστε τον χρήστη να ενημερώσει τον αριθμό τετραγώνων

Για να δώσετε στον χρήστη την ευκαιρία να επαναλάβει αυτό το επίτευγμα με ένα προσαρμοσμένο αριθμό στοιχείων (ok, semi-custom με μέγιστο αριθμό 10.000), προσθέτετε τον ακόλουθο ακροατή και χειριστή στο πλαίσιο εισαγωγής κειμένου:

// === Ακροατές / χειριστές === //
d3.select ('# text-input') στην ('keydown', λειτουργία () {
εάν (d3.event.keyCode === 13) {
// Να κάνετε κάτι μόνο αν ο χρήστης χτυπήσει την επιστροφή (κωδικός 13).
  εάν (+ this.value <1 || + this.value> 10000) {
  // Εάν ο χρήστης πηγαίνει κάτω από 1 ή μεγαλύτερο από 10k ...
     
    d3.select ('# text-explain') ταξινομημένο ('alert', true);
    // ... επισημάνετε τη σημείωση σχετικά με την εμβέλεια και την επιστροφή.
    ΕΠΙΣΤΡΟΦΗ;
  } else {
  // Αν ο χρήστης πληκτρολογεί έναν λογικό αριθμό ...
    d3.select ('# text-explain') ταξινομημένο ('alert', false);
    // ... αφαιρέστε πιθανά χρώματα συναγερμού από τη σημείωση ...
    τιμή = + αυτή η τιμή. // ... ορίστε την τιμή ...
    βάση δεδομένων (d3.περιφορά (τιμή)); // ... και δεσμεύει τα δεδομένα.
    var t = d3.timer (λειτουργία (παρήλθε) {
      σχεδιάζω();
  
      αν (παρελθόν> 300) t.stop ();
    }); // Χρονοδιακόπτης που εκτελεί τη λειτουργία κλήρωσης επανειλημμένα για 300 ms.
  
  } // Αν ο χρήστης επιστρέψει.
}); // Ακρόαση / χειριστής εισαγωγής κειμένου

Εδώ είναι και πάλι, το πολύχρωμο πλέγμα πλακών του καμβά, έτοιμο να ενημερωθεί και να ανασυγκροτηθεί:

Διαδραστικότητα

Ο μεγαλύτερος «πόνος» με καμβά σε σύγκριση με το SVG ή το HTML είναι ότι δεν υπάρχουν υλικά στοιχεία που ζουν στο DOM. Αν υπήρχε θα μπορούσατε να εγγραφείτε ακροατές στα στοιχεία και να προσθέσετε χειριστές στους ακροατές. Για παράδειγμα, μπορείτε να ενεργοποιήσετε ένα ποντίκι σε ένα στοιχείο ορθής προβολής SVG και όποτε ενεργοποιείται ο ακροατής, μπορείτε να κάνετε κάτι στο ορθογώνιο. Όπως δείχνουν τις τιμές δεδομένων που είναι αποθηκευμένες με το ορθό σε μια επεξήγηση εργαλείου.

Με τον καμβά θα πρέπει να βρούμε έναν άλλο τρόπο να ακούσουμε ένα γεγονός στα στοιχεία του καμβά. Ευτυχώς υπάρχουν πολλοί έξυπνοι άνθρωποι που σκέφτονταν έναν έμμεσο αλλά λογικό τρόπο.

Έτσι τι διαδραστικότητα θέλουμε; Όπως αναφέρθηκε παραπάνω, ας πάμε για μια επεξήγηση εργαλείου και ας υποθέσουμε ότι θέλετε να δείξετε τον δείκτη του τετραγώνου σε μια επεξήγηση εργαλείου αμέσως μόλις περάσετε το δείκτη πάνω από το στοιχείο. Δεν είναι πολύ συναρπαστικό, αλλά το κλειδί είναι ότι μπορείτε να έχετε πρόσβαση στα δεδομένα που συνδέονται με το στοιχείο, κρατώντας το πάνω από αυτό.

Συλλογή

Υπάρχουν μερικά βήματα (όλα λογικά όμως). Αλλά με λίγα λόγια θα χτίσετε δύο καμβάδες για να το πετύχετε αυτό. Ένας κύριος καμβάς που παράγει τον οπτικό μας και έναν κρυφό καμβά (όπως δεν το βλέπουμε) που παράγει το ίδιο οπτικό. Το κλειδί εδώ είναι ότι όλα τα στοιχεία του δεύτερου καμβά θα βρίσκονται ακριβώς στην ίδια θέση σε σχέση με την προέλευση του καμβά σε σύγκριση με τον πρώτο καμβά. Έτσι, το τετράγωνο 1 ξεκινάει με 0,0 στον κύριο καμβά καθώς και στον κρυμμένο καμβά. Η πλατεία 2 ξεκινά στις 8,0 στον κύριο καμβά καθώς και στον κρυμμένο καμβά και ούτω καθεξής.

Υπάρχει μόνο μία σημαντική διαφορά. Κάθε στοιχείο στον κρυμμένο καμβά θα έχει ένα μοναδικό χρώμα. Θα δημιουργήσουμε ένα αντικείμενο (ή μάλλον έναν συσχετιστικό πίνακα ή χάρτη για συντομία) που συνδέει κάθε μοναδικό χρώμα με τα δεδομένα κάθε στοιχείου.

Γιατί; Επειδή στη συνέχεια προσαρμόζουμε έναν ακροατή με κίνηση του ποντικιού στον κύριο καμβά για να ανακτήσουμε ένα ρεύμα από θέσεις ποντικιού. Σε κάθε θέση του ποντικιού μπορούμε να χρησιμοποιήσουμε μια μέθοδο του καμβά για την "επιλογή" του χρώματος σε αυτή την ακριβή θέση. Στη συνέχεια, κοιτάμε μόνο το χρώμα στο συσσωματικό μας πεδίο και έχουμε τα δεδομένα! Και πετάμε ...

Από τον Kenny Louie, 2010 https://creativecommons.org/licenses/by/2.0/

Θα μπορούσατε να πείτε "καλά, οι πλατείες μου έχουν ήδη ένα μοναδικό χρώμα, μπορώ να τις χρησιμοποιήσω;" Και πράγματι, θα μπορούσατε να τις χρησιμοποιήσετε. Ωστόσο, η διαδραστικότητα σας θα βγαίνει από το παράθυρο μόλις αποφασίσετε να αποφύγετε τις πλατείες σας από τα χρώματα. Έτσι πρέπει να έχετε πάντα έναν καμβά - τον κρυμμένο καμβά - ο οποίος έχει ένα εγγυημένο σύνολο μοναδικών χρωμάτων για τα τετράγωνα.

Ας εφαρμόσουμε αυτήν την τεχνική βήμα προς βήμα. Ο κώδικας που δημιουργήσατε μέχρι στιγμής μπορεί να παραμείνει όπως είναι - απλώς προσθέτετε σε αυτό καθώς συνεχίζετε.

1. Προετοιμάστε τον κρυμμένο καμβά

Πρώτα ας δημιουργήσουμε τον κρυμμένο καμβά που θα φιλοξενήσει το οπτικό μας με ένα μοναδικό χρώμα ανά τετράγωνο.

1.1 Δημιουργία κρυμμένου στοιχείου καμβά και ορίστε το CSS σε {display: none. }.

// Μετονομάστε τον κύριο καμβά και προσθέστε μια κλάση 'mainCanvas' σε αυτό.
var mainCanvas = d3.select ('# κοντέινερ')
  .append ('καμβάς')
  .classed ('mainCanvas', true)
  .attr ('πλάτος', πλάτος) .attr ('ύψος', ύψος);
 
// νέος -----------------------------------
// Προσθέστε την κρυμμένη καμβά και να του δώσετε την κατηγορία «hiddenCanvas».
var hiddenCanvas = d3.select ('# κοντέινερ')
  .append ('καμβάς')
  .classed ('hiddenCanvas', true)
  .attr ('πλάτος', πλάτος)
  .attr ('ύψος', ύψος).

Στην πραγματικότητα, δεν θα θέσω τον καμβά να κρυφτεί σε αυτό το παράδειγμα για να δείξει τι συμβαίνει. Αλλά για να το κάνετε, απλά προσθέστε .hiddenCanvas {display: none; } στο CSS και η πράξη έχει ολοκληρωθεί.

1.2 Κατασκευάστε τη μεταβλητή περιβάλλοντος στη συνάρτηση draw () και περάστε δύο επιχειρήματα στη λειτουργία: ο καμβάς καθώς και ένα boolean που ονομάζεται 'hidden' που καθορίζει ποιο καμβά χτίζουμε (hidden = true || false) όπως στο:

λειτουργία κλήρωσης (καμβάς, κρυφή) {

1.3 Θα πρέπει τώρα να προσαρμοστούν όλες τις λειτουργίες κλήρωση για να συμπεριλάβει τα δύο νέα ισοπαλία () επιχειρήματα. Έτσι από εδώ και στο εξής, δεν καλείτε μόνο κλήρωση () που ονομάζετε είτε κλήρωση (mainCanvas, false) είτε κλήρωση (hiddenCanvas, true)

2. Εφαρμόστε μοναδικά χρώματα στα κρυμμένα στοιχεία και χαρτογραφήστε τα

Εδώ, αγαπητέ αναγνώστη, έρχεται το βασικό κομμάτι της λειτουργίας μας, η μηχανή του φορτηγού μας, το μπαχαρικό στη σούπα μας.

Από τον Andrew Becraft, 2007 https://creativecommons.org/licenses/by-nc-sa/2.0/

2.1 Συμπεριλάβετε μια συνάρτηση για να δημιουργήσετε ένα νέο μοναδικό χρώμα κάθε φορά που ονομάζεται (μέσω υπερχείλισης στοίβας)

// Λειτουργία για τη δημιουργία νέων χρωμάτων για τη συλλογή.
var nextCol = 1;
λειτουργία genColor () {
  
  var ret = [].
  εάν (nextCol <16777215) {
    
    ret.push (επόμενοCol & 0xff); // R
    ret.push ((επόμενηCol & 0xff00) >> 8); // G
    ret.push ((επόμενηCol & 0xff0000) >> 16); // B
    nextCol + = 1.
  
  }}
var col = "rgb (" + ret.join (',') + ")";
επιστροφή col;
}}

genColour () παράγει ένα χρώμα που ορίζει εγχόρδων υπό τη μορφή RGB (0,0,0). Κάθε φορά που ονομάζεται αυξάνεται η τιμή R κατά ένα. Μόλις φτάσει στο 255, αυξάνει την τιμή G κατά 1 και επαναφέρει την τιμή R στο 0. Μόλις φτάσει στο r (255,255,0) αυξάνει την τιμή Β κατά 1 επαναφέροντας το R και το G στο 0 κ.ο.κ.

Έτσι, συνολικά μπορείτε να έχετε 256 * 256 * 256 = 16.777.216 στοιχεία για να διατηρήσετε ένα μοναδικό χρώμα. Ωστόσο, μπορώ να σας διαβεβαιώσω ότι ο φυλλομετρητής σας θα πεθάνει εκ των προτέρων. Ακόμη και με καμβά (webGL tutorial για να ακολουθήσετε).

2.2 Δημιουργήστε το αντικείμενο χάρτη που θα παρακολουθεί ποιο προσαρμοσμένο στοιχείο έχει το μοναδικό χρώμα:

varcolourToNode = {}; // Χάρτης για την παρακολούθηση του χρώματος των κόμβων.

Μπορείτε να προσθέσετε τη λειτουργία genColour () οπουδήποτε θέλετε στη δέσμη ενεργειών σας, αρκεί να είναι εκτός του πλαισίου λειτουργίας του databind () και draw (). Ωστόσο, σημειώστε ότι η μεταβλητή του χάρτη σας πρέπει να δημιουργηθεί πριν και πέρα ​​από το πεδίο εφαρμογής της συνάρτησης δεδομένων ().

2.3 Προσθέστε ένα μοναδικό χρώμα σε κάθε προσαρμοσμένο στοιχείο όπως για παράδειγμα .attr ('fillStyleHidden') και
2.4 Δημιουργία του αντικειμένου χάρτη κατά τη δημιουργία στοιχείων

Εδώ θα χρησιμοποιήσετε το genColour () του color-canon στη λειτουργία μας databaseind ​​() όταν αναθέτουμε το fillStyle στα στοιχεία μας. Καθώς έχετε επίσης πρόσβαση σε κάθε datapoint ενώ δεσμεύεται σε κάθε στοιχείο, μπορείτε να φέρετε μαζί το χρώμα και τα δεδομένα στο χάρτη colourToNode.

Συμμετοχή
  .merge (enterSel)
  .μετάβαση()
  .attr ('πλάτος', cellSize)
  .attr ('ύψος', cellSize)
  .attr ('fillStyle', συνάρτηση (d) {
    επιστροφή σχήματος χρώματος (d.value);
  });
  // νέος ----------------------------------------------- ------
  
  .attr ('fillStyleHidden', συνάρτηση (d) {
    εάν (! d.hiddenCol) {
      d.hiddenCol = genColor ();
      colourToNode [d.hiddenCol] = d;
    }}
    // Εδώ (1) προσθέτετε ένα μοναδικό χρώμα ως ιδιότητα σε κάθε στοιχείο
    // και (2) χαρτώνει το χρώμα στον κόμβο στο colourToNode-map.
    επιστροφή d.hiddenCol;
});

2.5 Μπορείτε τώρα να χρωματίσετε τα στοιχεία σύμφωνα με τον καμβά. Η λειτουργία draw () αποδίδει. Προσθέτετε μια προϋπόθεση για το fillStyle στη λειτουργία draw () εφαρμόζοντας τα χρώματα για την οπτική μας στον κύριο καμβά και τα μοναδικά χρώματα στον κρυμμένο καμβά. Πρόκειται για ένα απλό μοτέρ:

context.fillStyle = κρυφό; node.attr ('fillStyleHidden'): node.attr ('fillStyle');
// Το χρώμα κόμβου εξαρτάται από τον καμβά που σχεδιάσατε.

Ο κύριος καμβάς εξακολουθεί να φαίνεται το ίδιο φυσικά:

Ας προσθέσουμε τελικά κάποια αλληλεπίδραση και αρχίστε με το σχέδιο του κρυμμένου καμβά κάθε φορά που μετακινεί το ποντίκι πάνω στον κύριο καμβά μας.

3. Σηκώστε τα χρώματα με το ποντίκι

3.1 Πρώτον, απλά εγγραφείτε έναν ακροατή στον κύριο καμβά, ακούγοντας τα γεγονότα που κινούνται με το ποντίκι.

d3.select ('. mainCanvas') στο ('mousemove', λειτουργία () {
});

Γιατί mousemove; Επειδή δεν μπορείτε να καταχωρήσετε τους ακροατές με μεμονωμένα τετράγωνα αλλά πρέπει να χρησιμοποιήσετε ολόκληρο τον καμβά, δεν θα μπορείτε να εργαστείτε με τα σπλάχνα ή τα γεγονότα -out, καθώς θα ενεργοποιούν μόνο όταν εισέρχονται στον καμβά όχι τα στοιχεία. Για να αποκτήσετε τη θέση του ποντικιού στον καμβά σας, μπορείτε να κάνετε mousemove ή να κάνετε κλικ / οριζοντίωση.

d3.select ('. mainCanvas') στο ('mousemove', λειτουργία () {
  κλήρωση (hiddenCanvas, true); // Σχεδιάστε τον κρυμμένο καμβά.
});

Με αυτόν τον τρόπο, το πρώτο πράγμα που ενεργοποιεί ο χρήστης όταν σφίγγει πάνω από τον κύριο καμβά είναι να δημιουργήσει εν αγνοία τους τον κρυμμένο καμβά. Όπως είπαμε, στην παραγωγή αυτός ο καμβάς θα ήταν κρυμμένος, αλλά για τους εκπαιδευτικούς μας σκοπούς θέλουμε να το δούμε και πράγματι, να πυροδοτήσουμε τον κρυμμένο καμβά που θα τραβήξει όταν το ποντίκι μετακινείται πάνω στον κύριο καμβά έτσι:

Τα χρώματα στον κύριο καμβά κυμαίνονται από μαύρο σε κόκκινο, από rgb (0,0,0) έως rgb (255,0,0) και στη συνέχεια φαίνεται ότι το ίδιο εύρος από το μαύρο στο κόκκινο επαναλαμβάνεται. Ωστόσο, τώρα το χρώμα κυμαίνεται από ελαφρώς πιο πράσινο μαύρο, ακριβώς από rgb (0,1,0) έως rgb (255,1,0):

Σμίκρυνση στα πρώτα δύο εκατοντάδες τετράγωνα, εδώ είναι τα χρώματα της πρώτης, της 256ης και της 257ης πλατείας:

3.3 Δεδομένου ότι ο κρυμμένος καμβάς μας είναι δομικά ένα αντίγραφο ανθρακούχου του κύριου καμβά, όλα τα κρυμμένα καμβά θα βρίσκονται στην ίδια θέση με τα στοιχεία του κύριου καμβά μας. Έτσι, μπορείτε τώρα να χρησιμοποιήσετε τις θέσεις x και y του ποντικιού που συλλέγετε από τον ακροατή στον κύριο καμβά για να δημιουργήσετε την ίδια θέση στον κρυμμένο καμβά. Πίσω στον ακροατή, προσθέτετε:

d3.select ('. mainCanvas') στο ('mousemove', λειτουργία () {
  
  // Σχεδιάστε τον κρυμμένο καμβά.
  κλήρωση (hiddenCanvas, true);
  // Πάρτε θέσεις ποντικιού από τον κύριο καμβά.
  var mouseX = d3.event.layerX || d3.event.offsetX;
  var mouseY = d3.event.layerY || d3.event.offsetY; });

Σημειώστε ότι παίρνουμε τις ιδιότητες event.layerX και event.layerY που επιστρέφουν τη θέση του ποντικιού, συμπεριλαμβανομένης της κύλισης. Αυτό μπορεί να σπάσει έτσι χρησιμοποιήστε το offsetX ως εναλλακτική λύση (ή απλά χρησιμοποιήστε το offsetX).

3.4 Η επιλογή: Ο καμβάς επιτρέπει σε μεγάλο βαθμό την πρόσβαση στα δεδομένα εικονοστοιχείων που το ποντίκι κινείται πάνω από τη λειτουργία getImageData () και την ιδιότητα .data. Σε πλήρη άνθιση αυτό θα μοιάζει με:

getImageData (posX, posY, 1, 1).

Θα επιστρέψει έναν πίνακα με τέσσερις αριθμούς: το R, το G, το B και το alpha. Καθώς δημιουργήσατε με σιγουριά το χάρτη colorToNode που αναθέτει τα δεδομένα στοιχείων σε κάθε κρυφό χρώμα του, μπορείτε τώρα να έχετε πρόσβαση στα στοιχεία αυτού του στοιχείου απλά κοιτώντας το χρώμα στο χάρτη!

d3.select ('. mainCanvas') στο ('mousemove', λειτουργία () {
  // Σχεδιάστε τον κρυμμένο καμβά.
  κλήρωση (hiddenCanvas, true);
  // Πάρτε θέσεις ποντικιού από τον κύριο καμβά.
  var mouseX = d3.event.layerX || d3.event.offsetX;
  var mouseY = d3.event.layerY || d3.event.offsetY;
// νέος -----------------------------------------------
  // Πάρτε την εργαλειοθήκη για τον κρυμμένο καμβά.
  var hiddenCtx = hiddenCanvas.node (). getContext ('2δ');
  // Επιλέξτε το χρώμα από τη θέση του ποντικιού.
  var col = hiddenCtx.getImageData (ποντίκιX, mouseY, 1, 1) .data;
  // Στη συνέχεια οριοθετήστε τις τιμές κατά τρόπο που το αντικείμενο χάρτη μας μπορεί να το διαβάσει.
  var colKey = 'rgb (' + col [0] + ',' + col [1] + ',' + col [2] + ')';
  // Λάβετε τα δεδομένα από τον χάρτη μας!
  var nodeData = colourToNode [colKey].
  console.log (nodeData);
});

Και πράγματι, η καταγραφή του nodeData στην κονσόλα επιστρέφει ένα αντικείμενο κάθε φορά που τοποθετείτε το δείκτη του ποντικιού πάνω από ένα τετράγωνο:

Τα δεδομένα ανά κόμβο δείχνουν τώρα την τιμή που αποτελεί τα αρχικά δεδομένα καθώς και το κλειδί hiddenCol που δείχνει το χρώμα αυτού του κόμβου για τον κρυμμένο καμβά:

3.5 Τέλος - και αυτή είναι μια τυπικότητα - προσθέτετε την επεξήγηση εργαλείων

d3.select ('. mainCanvas') στο ('mousemove', λειτουργία () {
  // Σχεδιάστε τον κρυμμένο καμβά.
  κλήρωση (hiddenCanvas, true);
  // Πάρτε θέσεις ποντικιού από τον κύριο καμβά.
  var mouseX = d3.event.layerX || d3.event.offsetX;
  var mouseY = d3.event.layerY || d3.event.offsetY;
  // Πάρτε την εργαλειοθήκη για τον κρυμμένο καμβά.
  var hiddenCtx = hiddenCanvas.node (). getContext ('2δ');
  // Επιλέξτε το χρώμα από τη θέση του ποντικιού.
  var col = hiddenCtx.getImageData (ποντίκιX, mouseY, 1, 1) .data;
  // Στη συνέχεια οριοθετήστε τις τιμές κατά τρόπο που το αντικείμενο χάρτη μας μπορεί να το διαβάσει.
  var colKey = 'rgb (' + col [0] + ',' + col [1] + ',' + col [2] + ')';
  // Λάβετε τα δεδομένα από τον χάρτη μας!
  var nodeData = colourToNode [colKey].
  
  console.log (nodeData);
  // νέος -----------------------------------------------
  αν (nodeData) {
  // Εμφανίστε τη συμβουλή εργαλείου μόνο όταν υπάρχει nodeData που βρέθηκε από το ποντίκι
    d3.select ('# tooltip')
      .style ('αδιαφάνεια', 0,8)
      .style ('top', d3.event.pageY + 5 + 'px')
      .style ('αριστερά', d3.event.pageX + 5 + 'px')
      .html (nodeData.value);
  } else {
  // Απόκρυψη της επεξήγησης όταν το ποντίκι δεν βρίσκει nodeData.
  
    d3.select ('# tooltip') στυλ ('opacity', 0);
  
  }}
}); // ακροατής / χειριστής καμβά

Αυτό είναι! Έχετε απεικονίσει ένα μεγάλο αριθμό στοιχείων σε καμβά - περισσότερο από ό, τι θα μπορούσατε να απολαύσετε χωρίς προβλήματα με το SVG. Εξακολουθήσατε να χρησιμοποιείτε το μοντέλο του κύκλου ζωής του D3 και προσθέσατε κάποια αλληλεπίδραση για να έχετε πρόσβαση στα δεδομένα που συνδέονται με κάθε στοιχείο. Αυτά τα τρία βήματα θα σας επιτρέψουν να κάνετε σχεδόν οτιδήποτε ή τουλάχιστον περισσότερο από ό, τι συνηθίζετε όταν εργάζεστε με το D3 και το SVG.

Υπάρχει ένα βήμα-προς-βήμα εγχειρίδιο από το μηδέν στο διαδραστικό D3 / καμβά στο blog μου το οποίο επιτρέπει εσωτερικές συνδέσεις σελίδας. Με αυτόν τον τρόπο μπορείτε να δείτε ολόκληρη τη διαδικασία σε μια προβολή και να κάνετε κλικ στο δρόμο σας μέσα από αυτό με ευκολία:

Κάντε κλικ για να μεταβείτε στο εγχειρίδιο

... και εδώ είναι πάλι ο πλήρης κώδικας.

Ελπίζω να σας άρεσε να το διαβάσετε και παρακαλώ να πω γεια και / ή ...

lars verspohl www.datamake.io @lars_vers https://www.linkedin.com/in/larsverspohl

... είναι πάντα ευγνώμων για ένα like ή μια συνέχεια μπορεί να επιστρέψει.