Mostrar datos al pasar el mouse del círculo

162

Tengo un conjunto de datos que estoy trazando en una dispersión. Cuando pase el mouse sobre uno de los círculos, me gustaría que aparezca con datos (como valores x, y, tal vez más). Esto es lo que intenté usar:

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);}); });

Sospecho que necesito ser más informativo sobre qué datos ingresar.

ScottieB
fuente
1
También probé: vis.selectAll ("circle"). Each (function (d) {vis.append ("svg: text"). Attr ("x", dx) .attr ("y", dy) .text (function (d) {return dx;});}); en vano, por desgracia.
ScottieB

Respuestas:

181

Supongo que lo que quieres es una información sobre herramientas. La forma más fácil de hacer esto es agregar un svg:titleelemento a cada círculo, ya que el navegador se encargará de mostrar la información sobre herramientas y no necesita el controlador del mouse. El código sería algo como

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

Si desea información sobre herramientas más sofisticada, puede usar tipsy, por ejemplo. Ver aquí para un ejemplo.

Lars Kotthoff
fuente
3
Me gusta achispar Mi único problema ahora es que apunta a la esquina superior izquierda del círculo, en lugar del borde como en esa demostración. No encuentro ninguna razón obvia por qué. jsfiddle.net/scottieb/JwaaV (borracho en la parte inferior)
ScottieB
¿Ese jsfiddle no parece tener información sobre herramientas?
Lars Kotthoff
Podría intentar agregar la información sobre herramientas a una svg:gque se superpone con el círculo real, pero dar cero ancho y alto. Actualmente está tomando el cuadro delimitador y colocando la información sobre herramientas en el borde. Jugar con las opciones de tipsy también podría ayudar.
Lars Kotthoff
1
Parece que ya no funciona. También encontré un ejemplo usando svg: title que falla: bl.ocks.org/ilyabo/1339996
nos
1
@nos funciona para mí.
Lars Kotthoff
145

Aquí se describe una muy buena manera de hacer una información sobre herramientas: ejemplo simple de información sobre herramientas D3

Tienes que agregar un div

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

Entonces puedes alternarlo usando

.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.pageYes la coordenada actual del mouse.

Si quieres cambiar el texto puedes usar tooltip.text("my tooltip text");

Ejemplo de trabajo

Pwdr
fuente
44
¿Puedes vincular datos a esta información sobre herramientas?
Jorge Leitao
2
Afaik puede vincular datos a cada elemento DOM.
Pwdr
para enlazar los datos a esto, simplemente agregue d dentro del paréntesis de esta manera: function (d) {... y cambie el texto a lo que quiera. Por ejemplo, supongamos que tiene un nombre que sería: tooltip.text (d.name):
thatOneGuy
39

Hay una biblioteca impresionante para hacer eso que descubrí recientemente. Es simple de usar y el resultado es bastante bueno: d3-tip.

Puedes ver un ejemplo aquí :

ingrese la descripción de la imagen aquí

Básicamente, todo lo que tiene que hacer es descargar ( index.js ), incluir el script:

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

y luego siga las instrucciones desde aquí (mismo enlace como ejemplo)

Pero para su código, sería algo como:

define el método:

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>";
  })

crea tu svg (como ya lo haces)

var svg = ...

llama al método:

svg.call(tip);

agregue propina a su objeto:

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

No olvides agregar el 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
fuente
2
El último d3-tip admite d3v4 muy bien. No es obvio si buscas en Google, pero me está funcionando muy bien con d3v4.
moodboom
6

Puede pasar los datos que se usarán en el mouseover de esta manera: el evento mouseover usa una función con sus enterdatos editados previamente como argumento (y el índice como segundo argumento), por lo que no necesita usar enter()una segunda vez.

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
fuente
Gracias. Realmente necesitaba d3.select(this)modificar la forma y no sabía cómo obtener la instancia en una entrada / actualización.
Turbo
Está utilizando algunas funciones x () e y () que no están definidas en su código. Creo que eso se puede eliminar.
Robert
fueron dados en el OP
danimal
5

Este ejemplo conciso demuestra de manera común cómo crear información sobre herramientas personalizada en 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
fuente
Si alguien necesita la punta de la herramienta para moverse en relación con la posición del objeto. Como en el caso de un gráfico de árbol. Es posible que desee utilizar return tooltip.style("top", (d.x + 40) + "px") .style("left", (d.y + 80) + "px");en el 'mousemove'atributo. Esto d.xayudará a mover la información sobre la herramienta en relación con el objeto, no toda la página
Chandra Kanth