166 votes

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

J'ai un ensemble de données que je trace dans un nuage de points. Lorsque je passe la souris sur l'un des cercles, je voudrais qu'il apparaisse avec des données (comme les valeurs x, y, voire 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 suppose que je dois être plus informatif sur les données à saisir ?

1 votes

J'ai aussi essayé : vis.selectAll("circle").each(function (d) { vis.append("svg:text").attr("x", d.x).attr("y", d.y) .text(function (d) { return d.x ; }) ; }) ; sans succès hélas.

2 votes

190voto

Lars Kotthoff Points 44924

Je suppose que ce que vous voulez, c'est une infobulle. La manière la plus simple de le faire est d'ajouter un fichier svg:title à chaque cercle, car le navigateur se chargera d'afficher l'infobulle et vous n'aurez pas besoin du gestionnaire de 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 tipsy par exemple. Voir ici pour un exemple.

3 votes

J'aime bien tipsy. Mon seul problème est qu'il pointe vers le coin supérieur gauche du cercle, plutôt que vers le bord comme dans la démo. Je ne trouve pas de raison évidente à cela. jsfiddle.net/scottieb/JwaaV (tipsy tout en bas)

0 votes

Ce jsfiddle ne semble pas avoir d'infobulles ?

0 votes

Vous pouvez essayer d'ajouter l'info-bulle à un svg:g que l'on superpose avec le cercle réel, mais dont la largeur et la hauteur sont nulles. Actuellement, il prend la boîte englobante et place l'info-bulle sur le bord. Jouer avec les options de tipsy pourrait également vous aider.

148voto

Pwdr Points 854

Une très bonne façon de créer une infobulle est décrite ici : Exemple simple d'infobulle 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 faire 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.pageY est la coordonnée actuelle de la souris.

Si vous voulez changer le texte, vous pouvez utiliser tooltip.text("my tooltip text");

Exemple de travail

4 votes

Pouvez-vous lier des données à cette infobulle ?

2 votes

Je crois que vous pouvez lier des données à chaque élément du DOM.

0 votes

Pour lier les données, il suffit d'ajouter d à l'intérieur de la parenthèse comme suit : function(d){ ... et de changer le texte en ce que vous voulez. Par exemple, si vous avez un nom, ce sera : tooltip.text(d.name) :

40voto

DanielX2010 Points 990

J'ai récemment découvert une bibliothèque géniale qui permet de le faire. Elle est simple à utiliser et le résultat est assez soigné : d3-tip.

Vous pouvez voir un exemple ici :

enter image description here

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

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

puis suivez les instructions de 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éer votre svg (comme vous le faites déjà)

var svg = ...

appeler la méthode :

svg.call(tip);

ajoutez une pointe à 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>

2 votes

Les dernières d3-tip supporte très bien la d3v4. Ce n'est pas évident si vous cherchez sur Google, mais ça marche très bien pour moi avec d3v4.

0 votes

Malheureusement, la fonction .attr() ne fonctionne plus dans D3 v5.

8voto

Mikhail Shabrikov Points 5735

Cet exemple concis démontre de manière courante comment créer une infobulle 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>

6voto

danimal Points 626

Vous pouvez transmettre les données à utiliser dans le mouseover de la manière suivante : l'événement mouseover utilise une fonction avec vos données précédentes. enter ed en tant qu'argument (et l'index en tant que second argument), de sorte que vous n'avez pas besoin d'utiliser la commande 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)); 
});

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