85 votes

Existe-t-il un moyen de zoomer dans un graphique de présentation des forces D3 ?

D3 a une disposition dirigée par la force ici . Existe-t-il un moyen d'ajouter un zoom à ce graphique ? Actuellement, j'ai pu capturer l'événement de la roue de la souris, mais je ne sais pas vraiment comment écrire la fonction de redécoupage elle-même. Avez-vous des suggestions ?

    var vis = d3.select("#graph")
        .append("svg:svg")
        .call(d3.behavior.zoom().on("zoom", redraw)) // <-- redraw function
        .attr("width", w)
        .attr("height", h);

96voto

nrabinowitz Points 27991

Mise à jour 6/4/14

Voir aussi La réponse de Mike Bostock ici pour les changements dans D3 v.3 et le exemple connexe . Je pense que cela remplace probablement la réponse ci-dessous.

Mise à jour 18/02/2014

Je pense que la réponse de @ahaarnos est préférable si vous voulez que le SVG entier fasse un panoramique et un zoom. L'imbrication g dans ma réponse ci-dessous ne sont vraiment nécessaires que si vous avez des éléments sans zoom dans le même SVG (ce qui n'est pas le cas dans la question originale). Si vous faire appliquer le comportement à un g puis un élément d'arrière-plan rect ou un élément similaire est nécessaire pour garantir que le g reçoit les événements liés aux pointeurs.

Réponse originale

Je l'ai fait fonctionner en me basant sur le zoom-pan-transform exemple - vous pouvez voir mon jsFiddle ici : http://jsfiddle.net/nrabinowitz/QMKm3/

C'était un peu plus complexe que je ne l'avais espéré - vous devez imbriquer plusieurs g pour qu'il fonctionne, définissez les paramètres du SVG comme suit pointer-events à l'attribut all et ajoutez ensuite un rectangle d'arrière-plan pour recevoir les événements du pointeur (sinon, cela ne fonctionne que lorsque le pointeur se trouve sur un nœud ou un lien). Le site redraw est relativement simple, il suffit de définir un transformateur sur l'objet le plus interne g :

var vis = d3.select("#chart")
  .append("svg:svg")
    .attr("width", w)
    .attr("height", h)
    .attr("pointer-events", "all")
  .append('svg:g')
    .call(d3.behavior.zoom().on("zoom", redraw))
  .append('svg:g');

vis.append('svg:rect')
    .attr('width', w)
    .attr('height', h)
    .attr('fill', 'white');

function redraw() {
  console.log("here", d3.event.translate, d3.event.scale);
  vis.attr("transform",
      "translate(" + d3.event.translate + ")"
      + " scale(" + d3.event.scale + ")");
}

Cela met effectivement à l'échelle l'ensemble du SVG, et donc la largeur du trait également, comme un zoom sur une image.

Il y a un autre exemple qui illustre une technique similaire.

18voto

ahaarnos Points 157

Pourquoi l'imbrication <g> 's ?

Ce code ci-dessous a bien fonctionné pour moi (un seul <g> sans grand blanc aléatoire <rect> :

var svg = d3.select("body")
    .append("svg")
      .attr({
        "width": "100%",
        "height": "100%"
      })
      .attr("viewBox", "0 0 " + width + " " + height )
      .attr("preserveAspectRatio", "xMidYMid meet")
      .attr("pointer-events", "all")
    .call(d3.behavior.zoom().on("zoom", redraw));

var vis = svg
    .append('svg:g');

function redraw() {
  vis.attr("transform",
      "translate(" + d3.event.translate + ")"
      + " scale(" + d3.event.scale + ")");
}

où tous les éléments de votre svg sont ensuite ajoutés au fichier vis élément.

14voto

David Marx Points 2393

Les réponses fournies fonctionnent dans D3 v2 mais pas dans v3. J'ai synthétisé les réponses en une solution propre et j'ai résolu le problème de la v3 en utilisant la réponse fournie ici : Pourquoi la v3 de d3.js casse-t-elle mon graphique de force lors de l'implémentation du zoom alors que la v2 ne le fait pas ?

D'abord le code principal. C'est une version nettoyée de la réponse de @ahaarnos :

    var svg = d3.select("body")
        .append("svg")
        .attr("width", width)
        .attr("height", height)
            .call(d3.behavior.zoom().on("zoom", redraw))
        .append('g');

    function redraw() {
      svg.attr("transform",
          "translate(" + d3.event.translate + ")"
          + " scale(" + d3.event.scale + ")");
    }   

Vous disposez maintenant de la fonction panoramique et du zoom, mais vous ne pourrez pas faire glisser les nœuds, car la fonction panoramique remplacera la fonction de déplacement. Donc nous devons faire ceci :

var drag = force.stop().drag()
.on("dragstart", function(d) {
    d3.event.sourceEvent.stopPropagation(); // to prevent pan functionality from 
                                            //overriding node drag functionality.
    // put any other 'dragstart' actions here
});

Voici le bidule de @nrabinowitz modifié pour utiliser cette implémentation de zoom plus propre, mais illustrant comment D3v3 casse le déplacement des nœuds : http://jsfiddle.net/QMKm3/718/

Et voici le même bidule modifié pour fonctionner avec D3v3 : http://jsfiddle.net/QMKm3/719/

2voto

Cem Ünsal Points 29

J'ai réussi à faire fonctionner mon graphique sans le deuxième appendice "svg:g".

[...].attr("pointer-events", "all")
     .attr("width", width2)
     .attr("height", height2)
     .append('svg:g')
     .call(d3.behavior.zoom().on("zoom", redraw));

Le reste est identique.

2voto

Prateek Tandon Points 122

Je pense qu'il pourrait être utile de mentionner ici les concepts de zoom géométrique et sémantique tels qu'expliqués par Mike Bostock en réponse à la question suivante.

Des diagrammes/graphiques interactifs rapides et réactifs : SVG, Canvas, autre ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X