Afficher les données au passage de la souris sur le cercle

162

J'ai un ensemble de données que je trace dans un nuage. Lorsque je passe la souris sur l'un des cercles, je voudrais qu'il apparaisse avec des données (comme les valeurs x, y, peut-être plus). Voici ce que j'ai essayé d'utiliser:

vis.selectAll("circle")
   .data(datafiltered).enter().append("svg:circle")
   .attr("cx", function(d) { return x(d.x);})
   .attr("cy", function(d) {return y(d.y)})
   .attr("fill", "red").attr("r", 15)
   .on("mouseover", function() {
        d3.select(this).enter().append("text")
            .text(function(d) {return d.x;})
            .attr("x", function(d) {return x(d.x);})
            .attr("y", function (d) {return y(d.y);}); });

Je soupçonne que j'ai besoin d'être plus informatif sur les données à saisir?

ScottieB
la source
1
J'ai aussi essayé: vis.selectAll ("circle"). Each (function (d) {vis.append ("svg: text"). Attr ("x", dx) .attr ("y", dy) .text (fonction (d) {return dx;});}); en vain hélas.
ScottieB

Réponses:

181

Je suppose que vous voulez une info-bulle. Le moyen le plus simple de le faire est d'ajouter un svg:titleélément à chaque cercle, car le navigateur se chargera d'afficher l'info-bulle et vous n'avez pas besoin du gestionnaire de la souris. Le code serait quelque chose comme

vis.selectAll("circle")
   .data(datafiltered).enter().append("svg:circle")
   ...
   .append("svg:title")
   .text(function(d) { return d.x; });

Si vous voulez des infobulles plus sophistiquées, vous pouvez utiliser par exemple tipy. Voir ici pour un exemple.

Lars Kotthoff
la source
3
J'aime ivre. Mon seul problème maintenant est qu'il pointe vers le coin supérieur gauche du cercle, plutôt que sur le bord comme dans cette démo. Je ne trouve aucune raison évidente. jsfiddle.net/scottieb/JwaaV ( éméché tout en bas)
ScottieB
Ce jsfiddle ne semble pas avoir d'infobulles?
Lars Kotthoff
Vous pouvez essayer d'ajouter l'info-bulle à un svg:gque vous superposez avec le cercle réel, mais ne donnez aucune largeur et hauteur. Actuellement, il prend la boîte englobante et place l'info-bulle au bord. Jouer avec les options de tipy pourrait également aider.
Lars Kotthoff
1
Cela ne semble plus fonctionner. J'ai également trouvé un exemple utilisant svg: title qui échoue: bl.ocks.org/ilyabo/1339996
nos
1
@nos Fonctionne pour moi.
Lars Kotthoff
145

Un très bon moyen de créer une info-bulle est décrit ici: Exemple d'infobulle simple D3

Vous devez ajouter un div

var tooltip = d3.select("body")
    .append("div")
    .style("position", "absolute")
    .style("z-index", "10")
    .style("visibility", "hidden")
    .text("a simple tooltip");

Ensuite, vous pouvez simplement le basculer en utilisant

.on("mouseover", function(){return tooltip.style("visibility", "visible");})
.on("mousemove", function(){return tooltip.style("top",
    (d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");})
.on("mouseout", function(){return tooltip.style("visibility", "hidden");});

d3.event.pageX/ d3.event.pageYest la coordonnée courante de la souris.

Si vous souhaitez modifier le texte, vous pouvez utiliser tooltip.text("my tooltip text");

Exemple de travail

Pwdr
la source
4
Pouvez-vous lier des données à cette info-bulle?
Jorge Leitao
2
Afaik, vous pouvez lier des données à chaque élément DOM.
Pwdr
pour lier les données à cela, ajoutez simplement d entre les parenthèses comme ceci: function (d) {... et changez le texte en ce que vous voulez. Par exemple, disons que vous avez un nom, ce serait: tooltip.text (d.name):
thatOneGuy
39

Il existe une bibliothèque géniale pour faire cela que j'ai récemment découverte. C'est simple à utiliser et le résultat est assez soigné: d3-tip.

Vous pouvez voir un exemple ici :

entrez la description de l'image ici

En gros, tout ce que vous avez à faire est de télécharger ( index.js ), d'inclure le script:

<script src="index.js"></script>

puis suivez les instructions d' ici (même lien que l'exemple)

Mais pour votre code, ce serait quelque chose comme:

définir la méthode:

var tip = d3.tip()
  .attr('class', 'd3-tip')
  .offset([-10, 0])
  .html(function(d) {
    return "<strong>Frequency:</strong> <span style='color:red'>" + d.frequency + "</span>";
  })

créez votre svg (comme vous le faites déjà)

var svg = ...

appelez la méthode:

svg.call(tip);

ajoutez une astuce à votre objet:

vis.selectAll("circle")
   .data(datafiltered).enter().append("svg:circle")
...
   .on('mouseover', tip.show)
   .on('mouseout', tip.hide)

N'oubliez pas d'ajouter le CSS:

<style>
.d3-tip {
  line-height: 1;
  font-weight: bold;
  padding: 12px;
  background: rgba(0, 0, 0, 0.8);
  color: #fff;
  border-radius: 2px;
}

/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
  box-sizing: border-box;
  display: inline;
  font-size: 10px;
  width: 100%;
  line-height: 1;
  color: rgba(0, 0, 0, 0.8);
  content: "\25BC";
  position: absolute;
  text-align: center;
}

/* Style northward tooltips differently */
.d3-tip.n:after {
  margin: -1px 0 0 0;
  top: 100%;
  left: 0;
}
</style>
DanielX2010
la source
2
Le dernier d3-tip prend en charge d3v4 très bien. Ce n'est pas évident si vous recherchez sur Google, mais cela fonctionne très bien pour moi avec d3v4.
moodboom
6

Vous pouvez transmettre les données à utiliser dans le mouseover comme ceci - l'événement mouseover utilise une fonction avec vos enterdonnées précédemment éditées comme argument (et l'index comme deuxième argument) donc vous n'avez pas besoin de l'utiliser enter()une deuxième fois.

vis.selectAll("circle")
.data(datafiltered).enter().append("svg:circle")
.attr("cx", function(d) { return x(d.x);})
.attr("cy", function(d) {return y(d.y)})
.attr("fill", "red").attr("r", 15)
.on("mouseover", function(d,i) {
    d3.select(this).append("text")
        .text( d.x)
        .attr("x", x(d.x))
        .attr("y", y(d.y)); 
});
danimal
la source
Merci. J'avais vraiment besoin de d3.select(this)pour modifier la forme et je ne savais pas comment obtenir l'instance dans une entrée / mise à jour.
Turbo
Vous utilisez certaines fonctions x () et y () qui ne sont pas définies dans votre code. Je pense que cela peut être supprimé.
Robert
ils ont été donnés dans l'OP
danimal
5

Cet exemple concis montre comment créer une info-bulle personnalisée dans d3.

var w = 500;
var h = 150;

var dataset = [5, 10, 15, 20, 25];

// firstly we create div element that we can use as
// tooltip container, it have absolute position and
// visibility: hidden by default

var tooltip = d3.select("body")
  .append("div")
  .attr('class', 'tooltip');

var svg = d3.select("body")
  .append("svg")
  .attr("width", w)
  .attr("height", h);

// here we add some circles on the page

var circles = svg.selectAll("circle")
  .data(dataset)
  .enter()
  .append("circle");

circles.attr("cx", function(d, i) {
    return (i * 50) + 25;
  })
  .attr("cy", h / 2)
  .attr("r", function(d) {
    return d;
  })
  
  // we define "mouseover" handler, here we change tooltip
  // visibility to "visible" and add appropriate test
  
  .on("mouseover", function(d) {
    return tooltip.style("visibility", "visible").text('radius = ' + d);
  })
  
  // we move tooltip during of "mousemove"
  
  .on("mousemove", function() {
    return tooltip.style("top", (event.pageY - 30) + "px")
      .style("left", event.pageX + "px");
  })
  
  // we hide our tooltip on "mouseout"
  
  .on("mouseout", function() {
    return tooltip.style("visibility", "hidden");
  });
.tooltip {
    position: absolute;
    z-index: 10;
    visibility: hidden;
    background-color: lightblue;
    text-align: center;
    padding: 4px;
    border-radius: 4px;
    font-weight: bold;
    color: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.min.js"></script>

Mikhail Shabrikov
la source
Si quelqu'un a besoin de l'info-bulle pour se déplacer par rapport à la position de l'objet. Comme dans le cas d'un arbre graphique. Vous voudrez peut-être utiliser return tooltip.style("top", (d.x + 40) + "px") .style("left", (d.y + 80) + "px");dans l' 'mousemove'attribut. La d.xvolonté aide à déplacer l'outil pointe par rapport à l'objet, et non pas la page entière
Chandra Kanth