質問

I am working on a d3 sample http://bost.ocks.org/mike/nations/:

enter image description here

I am trying to add tooltip of the json data on the corresponding circles as and when i move the cursor over the years. However it is showing only the first year's value. It is not displaying the data corresponding to the year selected.

<!DOCTYPE html>
<meta charset="utf-8">
<title>Mock up Bubble chart DV</title>
<style>

@import url(../style.css?20120427);

#chart {
  margin-left: -40px;
  height: 506px;
}

text {
  font: 10px sans-serif;
}

.dot {
  stroke: #000;
}

.axis path, .axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.label {
  fill: #777;
}

.year.label {
  font: 500 96px "Helvetica Neue";
  fill: #ddd;
}

.year.label.active {
  fill: #aaa;
}

.overlay {
  fill: none;
  pointer-events: all;
  cursor: ew-resize;
}

</style>

<header>
</header>

<h1>Mock up of Bubble chart DV</h1>

<p id="chart"></p>
<input type="submit" value="Start" onclick=start();>
<input type="submit" value="Stop" onclick=stop();>

<script src="http://d3js.org/d3.v2.js?2.8.1"></script>
<script>

// Various accessors that specify the four dimensions of data to visualize.
function x(d) { return d.checkins; }
function y(d) { return d.Checkintimes; }
function radius(d) { return d.teamsize; }
function color(d) { return d.region; }
function key(d) { return d.name; }
var b = false;
var svg = d3.select("#chart");
var thisyear=2000;
var parsedData;
var chksvg = d3.select("svg");



function start()
{

if(chksvg.empty())
{

    //alert("not intialised");

     document.getElementById('chart').innerHTML="";

      // Chart dimensions.
    var margin = {top: 29.5, right: 29.5, bottom: 29.5, left: 59.5},
    width = 960 - margin.right,
    height = 500 - margin.top - margin.bottom;

    // Various scales. These domains make assumptions of data, naturally.
    //var xScale = d3.scale.log().domain([300, 1e5]).range([0, width]),
    var xScale = d3.scale.log().domain([10, 3000]).range([0, width]),

    yScale = d3.scale.linear().domain([10, 85]).range([height, 0]),
    radiusScale = d3.scale.sqrt().domain([0, 40]).range([5, 40]),
    colorScale = d3.scale.category10();

    // The x & y axes.
    var xAxis = d3.svg.axis().orient("bottom").scale(xScale).ticks(12, d3.format(",d")),
    yAxis = d3.svg.axis().scale(yScale).orient("left");



    // Create the SVG container and set the origin.
    var svg = d3.select("#chart").append("svg")
    .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
    .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    // Add the x-axis.
    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    // Add the y-axis.
    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);

    // Add an x-axis label.
    svg.append("text")
        .attr("class", "x label")
        .attr("text-anchor", "end")
        .attr("x", width)
        .attr("y", height - 6)
     .text("Avg checkins/dev");

// Add a y-axis label.
svg.append("text")
    .attr("class", "y label")
    .attr("text-anchor", "end")
    .attr("y", 6)
    .attr("dy", ".75em")
    .attr("transform", "rotate(-90)")
    .text("Mean Time between successful builds(hrs)");

// Add the year label; the value is set on transition.
var label = svg.append("text")
    .attr("class", "year label")
    .attr("text-anchor", "end")
    .attr("y", height - 24)
    .attr("x", width)
    .text(2000);



}
else
{

//enableInteraction();

}

//alert("Start Clicked");
// Load the data.

d3.json("bubble_chart_new.json", function(nations) {



  // A bisector since many nation's data is sparsely-defined.
  var bisect = d3.bisector(function(d) { return d[0]; });
  //console.log(bisect);
  // Add a dot per nation. Initialize the data at 2000, and set the colors.


  var dot = svg.append("g")
      .attr("class", "dots")
    .selectAll(".dot")
      .data(interpolateData(2000))
    .enter().append("circle")
      .attr("class", "dot")
      .style("fill", function(d) { return colorScale(color(d)); })
      .call(position)
      .sort(order);

  // Add a title.
  //dot.append("title").text(function(d) { return d.name});

  // Add an overlay for the year label.
  var box = label.node().getBBox();

  var overlay = svg.append("rect")
        .attr("class", "overlay")
        .attr("x", box.x)
        .attr("y", box.y)
        .attr("width", box.width)
        .attr("height", box.height)
        .on("mouseover", enableInteraction);

  // Start a transition that interpolates the data based on year.
  svg.transition()
      .duration(30000)
      .ease("linear")
      .tween("year", tweenYear)
      .each("end", enableInteraction);

  // Positions the dots based on data.
  function position(dot) {
    dot.attr("cx", function(d) { return xScale(x(d)); })
       .attr("cy", function(d) { return yScale(y(d)); })

       .attr("r", function(d) { return radiusScale(radius(d)); });

  }

  // Defines a sort order so that the smallest dots are drawn on top.
  function order(a, b) {
    return radius(b) - radius(a);
  }

  // After the transition finishes, you can mouseover to change the year.
  function enableInteraction() {


    var yearScale = d3.scale.linear()
        .domain([2000, 2009])
        .range([880,895])
        .clamp(true);

    // Cancel the current transition, if any.
    svg.transition().duration(0);

    overlay
        .on("mouseover", mouseover)
        .on("mouseout", mouseout)
        .on("mousemove", mousemove)
        .on("touchmove", mousemove);

    function mouseover() {
      label.classed("active", true);
    }

    function mouseout() {
      label.classed("active", false);
    }

    function mousemove() {

      //console.log(yearScale.invert(d3.mouse(this)[0]));
      displayYear(yearScale.invert(d3.mouse(this)[0]));
       dot.append("title").text(function(d,i) { return d.name + ": " + d.checkins + ":" +  d.teamsize});
    }
  }

  // Tweens the entire chart by first tweening the year, and then the data.
  // For the interpolated data, the dots and label are redrawn.
  function tweenYear() {

    var year = d3.interpolateNumber(thisyear, 2009);
    //console.log(year);
    //var year = d3.interpolateRound(thisyear, 2009);

    return function(t) { displayYear(year(t)); };
  }

  // Updates the display to show the specified year.
  function displayYear(year) {
    thisyear=year;


    dot.data(interpolateData(year), key)
    .call(position)
    .sort(order);
    label.text(Math.round(year));


)

  }

  // Interpolates the dataset for the given (fractional) year.
  function interpolateData(year) {

    var yeartest= year;    
    return nations.map(function(d,i) {



      return {


        name: d.name,
        region: d.region,
        checkins: interpolateValues(d.checkins, year),
        teamsize: interpolateValues(d.teamsize, year),
        Checkintimes: interpolateValues(d.Checkintimes, year)

      };

       //console.log(d.name + d.teamsize + d.checkins);


    });
  }

  // Finds (and possibly interpolates) the value for the specified year.
  function interpolateValues(values, year) {
    var i = bisect.left(values, year, 0, values.length - 1),
        a = values[i];
    if (i > 0) {
      var b = values[i - 1],
          t = (year - a[0]) / (b[0] - a[0]);


          /*console.log("year = " + year);
        console.log("a[0] = " +  a[0]);
        console.log("b[0] = " +  b[0]);

        console.log("t value = " + t);
        console.log("a[1] value = " + a[1]);
       console.log("return value = " + a[1] * (1 - t) + b[1] * t);*/

      //return a[1] * (1 - t) + b[1] * t;
       return a[1]* (1 - t) + b[1] * t ;

    }
    return a[1];
  }
});

}


function stop()
{

  d3.selectAll("*").transition().delay(0);


//alert("stop Clicked");
}

</script>

json file contains the following:

[ {

"name":"Search&Navigator",
"region":"IPScience",
"checkins":[[2000,100],[2001,200],[2002,300],[2003,275],[2004,222],[2005,280],[2006,281],[2007,400],[2008,55],[2009,300]],
"teamsize":[[2000,10],[2001,7],[2002,7],[2003,12],[2004,5],[2005,3],[2006,10],[2007,12],[2008,12],[2009,10]],
"Checkintimes":[[2000,40],[2001,50],[2002,60],[2003,50],[2004,40],[2005,30],[2006,30],[2007,35],[2008,30],[2009,30]]

} ]

役に立ちましたか?

解決

All you need to do is, in addition to appending the title initially, update it when the displayed year changes. That is, change

dot.data(interpolateData(year), key)
   .call(position)
   .sort(order);

to

dot.data(interpolateData(year), key)
   .call(position)
   .sort(order)
   .each(function() {
     d3.select(this).select("title")
       .text(function(d,i) { return d.name + ": " + d.checkins + ":" +  d.teamsize});
   });

in the displayYear function. The slightly awkward call to .each() is needed because the data is bound to the circles and not the title elements -- using .select() copies the data.

You can also delete

dot.append("title").text(function(d,i) { return d.name + ": " + d.checkins + ":" +  d.teamsize});

from the mousemove function, as this will add a new title element every time the mouse is moved. Instead, add .append("title") in the definition of dot.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top