web-dev-qa-db-fra.com

sélecteur d3 pour enfants immédiats

Je peux évidemment faire ceci:

d3.selectAll('div#some-div>ul')

Mais que se passe-t-il si j'utilise un nœud DOM ou une sélection D3 existante: 

d3.select(this).selectAll('ul')

va me chercher tous les ULs descendants. Donc si

var div = d3.select('div') 

m'a obtenu ce noeud:

<div>
  <ul>
    <li>foo
      <ul><li>bar</li></ul>
    </li>
  <ul>
</div>

Ensuite 

var uls = div.selectAll('ul') 

va me chercher deux UL. Je suppose que je pourrais distinguer un niveau supérieur comme:

uls.filter(function() { return this.parentNode === div.node() }

Donc, j'ai répondu à ma propre question. Peut-être que ce sera utile à quelqu'un. Ou peut-être que quelqu'un peut recommander une solution moins laide.

La réponse de nrabinowitz ci-dessous est meilleure et renvoie des résultats identiques à ceux ci-dessus. Voici un violon altéré qui les compare (mais n'utilise pas console.log, qui agit bizarrement pour moi dans jsfiddle)}

27
Sigfried

La solution de @ nrabinowitz ne fonctionne pas tout le temps. 

Dans mon cas, j'essayais de faire d3.select(this).selectAll(".childNode > *").

J'essayais donc d'obtenir tous les enfants immédiats de .childNode. Le problème est qu'il s'agissait d'une pile imbriquée. Ainsi, .childNode pouvait également apparaître dans les enfants, ce qui posait problème. 

Le meilleur moyen que j'ai trouvé est:

var child = d3.select(this).select(".childNode");
var sel = d3.select(this).selectAll(".childNode > *").filter(function() { 
    return this.parentNode == child.node();
});
3
Glenn

Je ne m'attendais pas à ce que cela fonctionne, mais il semblerait que D3 sous-sélectionne tout élément enfant de la sélection et que correspond au sélecteur - cela fonctionne donc:

d3.select(this).selectAll('div > ul');

Voir http://jsfiddle.net/g3aay/2/

21
nrabinowitz

Si quelqu'un est toujours intéressé, d3.select(this.childNodes) m'aidait à résoudre mon problème de sélection de tous les enfants immédiats. Alternativement, vous pouvez utiliser 

selection.select(function(){
  return this.childNodes;
})
18
Xenthor

La méthode selectAll repose sur la méthode native querySelectorAll (au moins en v4). 

Cela signifie que vous pouvez utiliser le pseudo-sélecteur :scope:

var uls = div.selectAll(':scope > ul') 

le pseudo sélecteur :scope est actuellement une spécification draft et n'est pas encore pris en charge par tous les navigateurs. Plus d'informations sur le pseudo sélecteur :scope disponible sur MDN

1
Cyril Durand

​d3.selectAll('#id > *') peut être utilisé, p.ex. dans ​d3.selectAll('#id > *').remove() pour supprimer tous les enfants d'un élément avec id = id

0

Basé sur la solution de Sigfrid, voici quelque chose que j'ai ajouté au prototype, dans un projet sur lequel je travaille.

  /**
   * Helper that allows to select direct children.
   * See https://stackoverflow.com/questions/20569670/d3-selector-for-immediate-children
   *
   * @param {string} selector
   * @returns {Selection}
   */
  d3.selectAll('__nonexisting__').__proto__.MYPREFIX_selectChildren = function (selector) {
    var expectedParent = this.node();
    return this.selectAll(selector).filter(
      function() {
        return this.parentNode === expectedParent;
      }
    );
  };

La façon dont je saisis l'objet prototype a l'air un peu maladroite. Peut-être y a-t-il un meilleur moyen.

"MYPREFIX_" est destiné à empêcher les conflits de noms.

Le jsdoc @returns {Selection} est ambigu, ce type est malheureusement déclaré dans une fermeture et ne possède pas de nom global référençable par jsdoc (afaik).

Une fois ce fichier inclus, vous pouvez alors procéder comme suit:

d3.select('#some_id').MYPREFIX_selectChildren('ul')
0
donquixote