Mostrar dados sobre o mouse sobre o círculo

162

Eu tenho um conjunto de dados que estou plotando em uma dispersão. Ao passar o mouse sobre um dos círculos, gostaria que ele aparecesse com dados (como valores x, y, talvez mais). Aqui está o que eu tentei 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);}); });

Eu suspeito que preciso ser mais informativo sobre quais dados inserir?

ScottieB
fonte
1
Eu também tentei: vis.selectAll ("circle"). Each (function (d) {vis.append ("svg: text"). Attr ("x", dx) .attr ("y", dy) .text (função (d) {return dx;});}); sem sucesso, infelizmente.
29512 ScottieB

Respostas:

181

Presumo que o que você deseja é uma dica de ferramenta. A maneira mais fácil de fazer isso é anexar um svg:titleelemento a cada círculo, pois o navegador cuidará de mostrar a dica de ferramenta e você não precisará do manipulador do mouse. O código seria algo como

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

Se você quiser dicas de ferramentas mais sofisticadas, poderá usar embriagado, por exemplo. Veja aqui um exemplo.

Lars Kotthoff
fonte
3
Eu gosto de embriagado. Meu único problema agora é que ele aponta para o canto superior esquerdo do círculo, e não para a borda, como na demonstração. Não estou encontrando nenhuma razão óbvia para isso. jsfiddle.net/scottieb/JwaaV (embriagado na parte inferior) #
ScottieB
Esse jsfiddle parece não ter dicas de ferramentas?
Lars Kotthoff
Você pode tentar adicionar a dica de ferramenta a uma svg:gsobreposição com o círculo real, mas dê largura e altura zero. Atualmente, ele pega a caixa delimitadora e coloca a dica na borda. Brincar com as opções de tipsy pode ajudar também.
Lars Kotthoff
1
Parece que não funciona mais. Também achei um exemplo usando SVG: título que falha: bl.ocks.org/ilyabo/1339996
nºs
1
@nos Funciona para mim.
Lars Kotthoff
144

Uma maneira realmente boa de fazer uma dica de ferramenta é descrita aqui: Exemplo simples de dica de ferramenta D3

Você precisa anexar uma div

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

Então você pode simplesmente alternar 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.pageYé a coordenada atual do mouse.

Se você deseja alterar o texto, pode usar tooltip.text("my tooltip text");

Exemplo de trabalho

Pwdr
fonte
4
Você pode vincular dados a essa dica de ferramenta?
Jorge Leitao
2
Depois, você pode vincular dados a todos os elementos DOM.
Pwdr
para vincular os dados a isso, basta adicionar d entre parênteses da seguinte maneira: function (d) {... e alterar o texto para o que você quiser. Por exemplo, digamos que você tenha um nome seria: tooltip.text (d.name):
thatOneGuy
39

Há uma biblioteca incrível para fazer isso que eu descobri recentemente. É simples de usar e o resultado é bastante elegante: ponta d3.

Você pode ver um exemplo aqui :

insira a descrição da imagem aqui

Basicamente, tudo o que você precisa fazer é fazer o download ( index.js ), incluir o script:

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

e siga as instruções aqui (mesmo link do exemplo)

Mas para o seu código, seria algo como:

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

crie seu svg (como você já faz)

var svg = ...

chame o método:

svg.call(tip);

adicione dica ao seu objeto:

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

Não se esqueça de adicionar o 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
fonte
2
A última ponta d3 suporta d3v4 muito bem. Não é óbvio se você pesquisar no Google, mas está funcionando muito bem para mim com o d3v4.
moodboom
6

Você pode passar os dados a serem usados ​​na mouseover assim - o evento mouseover usa uma função com os enterdados editados anteriormente como argumento (e o índice como segundo argumento), para que você não precise usar enter()uma 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
fonte
Obrigado. Eu realmente precisava d3.select(this)modificar a forma e não sabia como obter a instância em uma entrada / atualização.
Turbo
Você está usando algumas funções x () e y () que não estão definidas no seu código. Eu acho que isso pode ser removido.
Robert
eles foram dados no OP
danimal 5/03/19
5

Este exemplo conciso demonstra como é comum criar dicas de ferramentas personalizadas no 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
fonte
Se alguém precisar que a dica de ferramenta se mova em relação à posição do objeto. Como no caso de um gráfico em árvore. Você pode querer usar return tooltip.style("top", (d.x + 40) + "px") .style("left", (d.y + 80) + "px");no 'mousemove'atributo A d.xajuda irá mover a ferramenta de ponta em relação ao objeto, não a página inteira
Chandra Kanth