web-dev-qa-db-fra.com

Comment amener un cercle au premier plan avec d3?

Tout d'abord, j'utilise d3.js pour afficher des cercles de différentes tailles dans des tableaux. Au survol de la souris, je veux que le cercle en cours de souris devienne plus grand, ce que je peux faire, mais je ne sais pas comment l'amener à l'avant. Actuellement, une fois rendu, il est caché derrière plusieurs autres cercles. Comment puis-je réparer cela?

Voici un exemple de code:

   .on("mouseover", function() { 
    d3.select(this).attr("r", function(d) { return 100; })
  })

J'ai essayé d'utiliser les méthodes de tri et de commande, mais elles n'ont pas fonctionné. Je suis presque sûr que je ne l'ai pas fait correctement. Des pensées?

62
areke

Vous devrez modifier l'ordre des objets et faire en sorte que le cercle sur lequel vous passez la souris soit le dernier élément ajouté. Comme vous pouvez le voir ici: https://Gist.github.com/3922684 et comme suggéré par nautat , vous devez définir ce qui suit avant votre script principal:

d3.selection.prototype.moveToFront = function() {
  return this.each(function(){
    this.parentNode.appendChild(this);
  });
};

Ensuite, il vous suffira d'appeler la fonction moveToFront sur votre objet (disons circles) au survol de la souris:

circles.on("mouseover",function(){
  var sel = d3.select(this);
  sel.moveToFront();
});

Edit: Comme suggéré par Henrik Nordberg il est nécessaire de lier les données au DOM en utilisant le deuxième argument du .data(). Cela est nécessaire pour ne pas perdre la liaison sur les éléments. Veuillez lire la réponse de Henrick (et voter en faveur!) Pour plus d'informations. En règle générale, utilisez toujours le deuxième argument de .data() lors de la liaison de données au DOM afin de tirer parti des capacités de performances complètes de d3.


Edit: Comme mentionné par Clemens Tolboom , la fonction inverse serait:

d3.selection.prototype.moveToBack = function() { 
    this.each(function() { 
        this.parentNode.firstChild
          && this.parentNode.insertBefore(this, firstChild); 
        } 
    }); 
};
116
Christopher Chiche

Si vous utilisez la méthode moveToFront(), assurez-vous que vous spécifiez le deuxième argument de la méthode de jointure data(), sinon vos données ne seront pas synchronisées avec votre DOM.

d3.js joint vos données (fournies à une méthode parse()) avec les éléments DOM que vous créez. Si vous manipulez le DOM comme proposé ci-dessus, d3.js ne saura pas quel élément DOM correspond à quel "point" de données, sauf si vous spécifiez une valeur unique pour chaque "point" de données dans l'appel data() comme appel référence API montre:

.data(data, function(d) { return d.name; })

22
Henrik Nordberg

Depuis la version 4 de d3, il existe un ensemble de fonctions intégrées qui gèrent ce type de comportement sans avoir à l'implémenter vous-même. Voir la documentation d3v4 pour plus d'informations.

Pour faire court, pour mettre un élément au premier plan, utilisez selection.raise()

selection.raise ()

Réinsère chaque élément sélectionné, dans l'ordre, en tant que dernier enfant de son parent. Équivalent à:

selection.each(function() {
this.parentNode.appendChild(this);
});

18
tmpearce

D'après ma douloureuse expérience avec IE9, l'utilisation de parentNode.appendChild peut entraîner la perte de gestionnaires d'événements dans les nœuds. J'ai donc tendance à utiliser une autre approche, c'est-à-dire trier les nœuds de sorte que celui sélectionné soit au dessus des autres:

     .on("mouseover", function(selected) {
        vis.selectAll('.node')
        .sort(function(a, b) {
          if (a.id === selected.id) {
            return 1;
          } else {
            if (b.id === selected.id) {
              return -1;
            } else {
              return 0;
            }
          }
        });
      })
13
Ilya Boyandin