简体   繁体   中英

D3 Arc Diagram: Tooltip on Circle Mouseover Not Displaying

I'm stuck on a problem and just looking for another pair of eyes to maybe spot what I'm missing.

I have an arc diagram I'm building and would like a tooltip event when I mouse over the circles/nodes.

You can see the sample bl.ock here . I thought for this to work each circle needed to be in it's own g element, which I've done. I have a function that handles the creation of the tooltip:

function tooltipText(d) {
 return "<h5>Information for " + d.token + "</h5>" +
   "<table>" +
   "<tr>" +
   "<td class='field'>Token: </td>" +
   "<td>" + d.token + "</td>" +
   "</tr>" +
   "<tr>" +
   "<td class='field'>Dialect: </td>" +
   "<td>" + d.dialect + "</td>" +
   "</tr>" +
   "<tr>" +
   "<td class='field'>IME: </td>" +
   "<td>" + d.input_method + "</td>" +
   "</tr>" +
   "<tr>" +
   "<td class='field'>Operating System: </td>" +
   "<td>" + d.operating_system + "</td>" +
   "</tr>" +
   "<tr>" +
   "<td class='field'>Trial: </td>" +
   "<td>" + d.trial + "</td>" +
   "</tr>" +
   "</table>";
}

Using CSS, the tooltip remains hidden until the mouseover is called:

.hidden {
  display: none;
  visibility: hidden;
  pointer-events: none;
}

.tooltip {
  color: #222;
  background: #fff;
  padding: .5em;
  text-shadow: #f5f5f5 0 1px 0;
  border-radius: 10px;
  border-color: #a6a6a6;
  border-width: 1px;
  border-style: solid;
  box-shadow: 0px 0px 2px 0px #a6a6a6; 
  opacity: 0.9; 
  position: absolute;
  width: 225px;
  display: block;
}

.tooltip h5 {
  font-size: 1.05rem;
}

.tooltip p {
  font-size: 0.80rem;
}

And the mouseover itself:

// Tooltip
var tooltip = d3.select("body").append("div")
  .classed("tooltip", true)
  .classed("hidden", true);

...

nodeEnter.selectAll(".node")
    .on("mousemove", function(d, i) {
      var mouse = d3.mouse(d3.select("body").node());
      tooltip
        .classed("hidden", false)
        .attr("class", "tooltip")
        .attr("style", "left:" + (mouse[0] + 20) + "px; top:" + (mouse[1] - 50) + "px")
        .html(tooltipText(d)); 
    })
    .on("mouseover", nodeOver);

Any pointers would be much appreciated.

There is a problem related to the usage of queue(), at the very beginning of JavaScript code.

I would recommend using standard D3 functions for loading data, like d3.json().

I made a code sample based on your block. the only difference from your example is that data is inside JavaScript function. The tooltips work!

 var width = 960, height = 400, margin = 20, pad = margin / 2, padding = 100, radius = 6, yfixed = pad + radius; // Legend variables var legend_x = 0, legend_y = 5, legend_width = 175, legend_height = 620, legend_margin = 20 key_y = 40, key_x = 16, mapped_y = legend_y + legend_height - 90; var color = d3.scale.category20(); // Tooltip var tooltip = d3.select("body").append("div") .classed("tooltip", true) .classed("hidden", true); var graph = getData(); arcDiagram(graph); // Main //----------------------------------------------------- function arcDiagram(graph) { var radius = d3.scale.sqrt() .domain([0, 20]) .range([0, 15]); var svg = d3.select("#chart").append("svg") .attr("id", "arc") .attr("width", width) .attr("height", height); // create plot within svg var plot = svg.append("g") .attr("id", "plot") .attr("transform", "translate(" + padding + ", " + padding + ")"); // count the paths graph.links.forEach(function(d, i) { var pathCount = 0; for (var j = 0; j < i; j++) { var otherPath = graph.links[j]; if (otherPath.source === d.source && otherPath.target === d.target) { pathCount++; } } // console.log(pathCount) d.pathCount = pathCount; }); // fix graph links to map to objects graph.links.forEach(function(d, i) { d.source = isNaN(d.source) ? d.source : graph.nodes[d.source]; d.target = isNaN(d.target) ? d.target : graph.nodes[d.target]; }); linearLayout(graph.nodes); drawLinks(graph.links); drawNodes(graph.nodes); } // layout nodes linearly function linearLayout(nodes) { nodes.sort(function(a, b) { return a.uniq - b.uniq; }); var xscale = d3.scale.linear() .domain([0, nodes.length - 1]) .range([radius, width - margin - radius]); nodes.forEach(function(d, i) { dx = xscale(i); dy = yfixed; }); } function drawNodes(nodes) { var gnodes = d3.select("#plot").selectAll("g.node") .data(nodes); var nodeEnter = gnodes.enter() .append('g') .attr("class", "gnode"); nodeEnter.append("circle") .attr("class", "node") .attr("id", function(d, i) { return d.name; }) .attr("cx", function(d, i) { return dx; }) .attr("cy", function(d, i) { return dy; }) .attr("r", 14) .style("stroke", function(d, i) { return color(d.type); }); // Handling mouseover functions nodeEnter.selectAll(".node") .on("mousemove", function(d, i) { var mouse = d3.mouse(d3.select("body").node()); tooltip .classed("hidden", false) .attr("class", "tooltip") .attr("style", "left:" + (mouse[0] + 20) + "px; top:" + (mouse[1] - 50) + "px") .html(tooltipText(d)); }) .on("mouseover", nodeOver); nodeEnter.append("text") .style("text-anchor", "middle") .attr("dx", function(d) { return dx; }) .attr("dy", function(d) { return dy + 5; }) .text(function(d) { return d.token; }); d3.select("#trial2") .on("mouseover", trialOver); } function drawLinks(links) { var radians = d3.scale.linear() .range([Math.PI / 2, 3 * Math.PI / 2]); var arc = d3.svg.line.radial() .interpolate("basis") .tension(0) .angle(function(d) { return radians(d); }); d3.select("#plot").selectAll(".link") .data(links) .enter().append("path") .attr("class", "link") .style("stroke-width", function(d) { return (2 + d.pathCount); }) .attr("transform", function(d, i) { var xshift = d.source.x + (d.target.x - d.source.x) / 2; var yshift = yfixed; return "translate(" + xshift + ", " + yshift + ")"; }) .attr("d", function(d, i) { var xdist = Math.abs(d.source.x - d.target.x); arc.radius(xdist / 2); var points = d3.range(0, Math.ceil(xdist / 3)); radians.domain([0, points.length - 1]); return arc(points); }) .on("mouseover", edgeOver); } // Draw legend //----------------------------------------------------- function drawLegend(d) { var legend = svg.append("g") .attr("class", "legend"); var key = legend.append("g") // Initial key.append("circle") .attr("id", "legend_initial") .attr("cx", legend_x + key_x) .attr("cy", legend_y + key_y + 5) .attr("r", 5) .style("fill", "blue"); key.append("text") .attr("class", "legendText") .attr("id", "legend_initial_label") .attr("x", legend_x + key_x + 10) .attr("y", legend_y + 10 + key_y) .text("Initial"); // Selection key.append("circle") .attr("id", "legend_selection") .attr("cx", function() { return legend_x + key_x }) .attr("cy", function() { return legend_y + legend_margin + key_y + 5 }) .attr("r", 5) .style("fill", "lightblue"); key.append("text") .attr("class", "legendText") .attr("id", "legend_selection_label") .attr("x", legend_x + key_x + 10) .attr("y", legend_y + legend_margin + 10 + key_y) .text("Selection"); // Final key.append("circle") .attr("id", "legend_final") .attr("cx", legend_x + key_x) .attr("cy", legend_y + 2 * legend_margin + key_y + 5) .attr("r", 5) .style("fill", "orange"); key.append("text") .attr("class", "legendText") .attr("id", "legend_final_label") .attr("x", legend_x + key_x + 10) .attr("y", legend_y + 2 * legend_margin + 10 + key_y) .text("Final"); // Delete key.append("circle") .attr("id", "legend_delete") .attr("cx", legend_x + key_x) .attr("cy", legend_y + 3 * legend_margin + key_y + 5) .attr("r", 5) .style("fill", "gold"); key.append("text") .attr("class", "legendText") .attr("id", "legend_delete_label") .attr("x", legend_x + key_x + 10) .attr("y", legend_y + 3 * legend_margin + 10 + key_y) .text("Delete"); } function tooltipText(d) { return "<h5>Information for " + d.token + "</h5>" + "<table>" + "<tr>" + "<td class='field'>Token: </td>" + "<td>" + d.token + "</td>" + "</tr>" + "<tr>" + "<td class='field'>Dialect: </td>" + "<td>" + d.dialect + "</td>" + "</tr>" + "<tr>" + "<td class='field'>IME: </td>" + "<td>" + d.input_method + "</td>" + "</tr>" + "<tr>" + "<td class='field'>Operating System: </td>" + "<td>" + d.operating_system + "</td>" + "</tr>" + "<tr>" + "<td class='field'>Trial: </td>" + "<td>" + d.trial + "</td>" + "</tr>" + "</table>"; } function nodeOver(d, i) { d3.selectAll("path").style("stroke", function(p) { return p.source == d || p.target == d ? "#17becf" : "#888888" }) } function edgeOver(d) { d3.selectAll("path").style("stroke", function(p) { return p == d ? "#17becf" : "#888888" }) } function trialOver(d) { var active, changedOpacity; d3.select("#arcToken"); // function) } function tokenOver(d, i) { d3.selectAll(this).style("stroke", function(d) { return p.token == d ? "#17becf" : "#888888" }) } function getData() { return { "nodes": [{ "token": "x", "type": "initial", "uniq": "1", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "ia", "type": "final", "uniq": "2", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "1", "type": "selection", "uniq": "3", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "m", "type": "initial", "uniq": "4", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "a", "type": "final", "uniq": "5", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "1", "type": "selection", "uniq": "6", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "y", "type": "initial", "uniq": "7", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "in", "type": "final", "uniq": "8", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "l", "type": "initial", "uniq": "9", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "iao", "type": "final", "uniq": "10", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "_", "type": "selection", "uniq": "11", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "*", "type": "productive-delete", "uniq": "12", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "j", "type": "initial", "uniq": "13", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "un", "type": "final", "uniq": "14", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "z", "type": "initial", "uniq": "15", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "1", "type": "selection", "uniq": "16", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "*", "type": "productive-delete", "uniq": "17", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "j", "type": "initial", "uniq": "18", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "iu", "type": "final", "uniq": "19", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }, { "token": "1", "type": "selection", "uniq": "20", "age_group": "18-30", "dialect": "cantonese", "gender": "female", "operating_system": "mac", "input_method": "apple", "trial": "2", "chinese": "", "english": "" }], "links": [{ "source": 0, "target": 1 }, { "source": 0, "target": 1 }, { "source": 0, "target": 1 }, { "source": 0, "target": 1 }, { "source": 0, "target": 1 }, { "source": 0, "target": 1 }, { "source": 1, "target": 3 }, { "source": 1, "target": 3 }, { "source": 1, "target": 3 }, { "source": 1, "target": 3 }, { "source": 1, "target": 3 }, { "source": 1, "target": 2 }, { "source": 2, "target": 3 }, { "source": 3, "target": 4 }, { "source": 3, "target": 4 }, { "source": 3, "target": 4 }, { "source": 3, "target": 4 }, { "source": 3, "target": 4 }, { "source": 3, "target": 4 }, { "source": 4, "target": 5 }, { "source": 4, "target": 6 }, { "source": 4, "target": 6 }, { "source": 4, "target": 5 }, { "source": 4, "target": 5 }, { "source": 4, "target": 5 }, { "source": 5, "target": 6 }, { "source": 5, "target": 6 }, { "source": 5, "target": 6 }, { "source": 6, "target": 7 }, { "source": 6, "target": 7 }, { "source": 6, "target": 7 }, { "source": 6, "target": 7 }, { "source": 6, "target": 7 }, { "source": 6, "target": 7 }, { "source": 7, "target": 12 }, { "source": 7, "target": 12 }, { "source": 7, "target": 12 }, { "source": 7, "target": 12 }, { "source": 7, "target": 12 }, { "source": 7, "target": 8 }, { "source": 8, "target": 9 }, { "source": 9, "target": 10 }, { "source": 10, "target": 11 }, { "source": 11, "target": 12 }, { "source": 12, "target": 13 }, { "source": 12, "target": 13 }, { "source": 12, "target": 13 }, { "source": 12, "target": 13 }, { "source": 12, "target": 13 }, { "source": 12, "target": 13 }, { "source": 13, "target": 14 }, { "source": 14, "target": 15 }, { "source": 15, "target": 16 }, { "source": 16, "target": 17 }, { "source": 13, "target": 17 }, { "source": 13, "target": 17 }, { "source": 13, "target": 17 }, { "source": 13, "target": 17 }, { "source": 13, "target": 17 }, { "source": 17, "target": 18 }, { "source": 17, "target": 18 }, { "source": 17, "target": 18 }, { "source": 17, "target": 18 }, { "source": 17, "target": 18 }, { "source": 17, "target": 18 }, { "source": 18, "target": 19 }, { "source": 18, "target": 19 }, { "source": 18, "target": 19 }, { "source": 18, "target": 19 }, { "source": 18, "target": 19 }] }; } 
 @import url(http://fonts.googleapis.com/css?family=Lato:300,400); body { font-family: 'Lato', sans-serif; font-weight: 300; background: #fff; } b { font-weight: 900; } #chart { position: relative; } .outline { fill: none; stroke: #888888; stroke-width: 1px; } .hidden { display: none; visibility: hidden; pointer-events: none; } .tooltip { color: #222; background: #fff; padding: .5em; text-shadow: #f5f5f5 0 1px 0; border-radius: 10px; border-color: #a6a6a6; border-width: 1px; border-style: solid; box-shadow: 0px 0px 2px 0px #a6a6a6; opacity: 0.9; position: absolute; width: 225px; display: block; } .tooltip h5 { font-size: 1.05rem; } .tooltip p { font-size: 0.80rem; } table { border: none; margin: 0; padding: 0; border-spacing: 0; width: 100%; } td { text-align: right; padding: 2px 0!important; } tr { margin: 0; background-color: white; } .node { fill: #fff; stroke: steelblue; stroke-width: 2.5px; font: 10px sans-serif; } .node text { color: #333; } .link { fill: none; stroke: #888888; stroke-weight: 1px; stroke-opacity: 0.5; } .legend { font-size: 12px; } /*rect { stroke-width: 2; }*/ .highlight { stroke: red; stroke-weight: 4px; stroke-opacity: 1.0; } .row { padding-top: 50px; } .col-md-3 { background: rgba(250, 255, 255, 0.5); border-left: 1px solid #333; height: 100%; } #english { padding: 1em; background: rgba(250, 255, 255, 1); border-bottom: 1px solid #ccc; } #chinese { padding: 1em; background: rgba(250, 255, 255, 1); border-bottom: 1px solid #ccc; } #source { color: brown; } /* Filters */ #accordion { position: fixed; width: 20%; right: 1; } .panel-body { background: rgba(250, 255, 255, 0.5); } .panel-default > .panel-heading { /*background: #fff;*/ } .panel-heading { padding: 0; border-top-left-radius: 0px; border-top-right-radius: 0px; } .panel-group .panel { border-radius: 0; } .panel-group { margin-bottom: 0; } .panel-title a { color: #333; text-align: left; width: 100%; display: block; padding: 10px 15px; font-size: 14px; outline: none; } .panel-title a:hover, .panel-title a:focus, .panel-title a:active { text-decoration: none; outline: none; } .panel-options { padding: 5px; } .legend circle { fill: none; stroke: #ccc; } .legend text { fill: #777; font: 10px sans-serif; text-anchor: middle; } 
 <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Chinese Input</title> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="style.css"> <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> <script src="http://d3js.org/queue.v1.min.js"></script> <script src="visualization.js"></script> </head> <body> <div id="chart"></div> </body> </html> 

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM