2016-06-19 2 views
1

Я пытаюсь сделать интерактивную линейную диаграмму с d3.js. Я получаю данные из двух файлов csv (emission.csv и gdp.csv), и мне бы хотелось, чтобы при передаче с помощью мыши на графике отобразилась своего рода метка с информацией о соответствующей точке в строке. Теперь я должен пропустить мышь на линии, чтобы показать ярлык, и я не могу понять, как делать то, что я хочу сделать. Я нашел this пример, который показывает, что я хочу, но я не могу понять некоторые из кодовых строк, и я не могу понять, как использовать его на моем графике.
Вот мой код:Интерактивная линейная диаграмма с d3.js

<!DOCTYPE html> 
<meta charset="utf-8"> 
<style> 

body { 
    font: 10px sans-serif; 
} 

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

.x.axis path { 
    /*display: none;*/ 
} 

.line { 
    fill: none; 
    stroke: steelblue; 
    stroke-width: 1.5px; 
} 

</style> 
<body> 
    <script data-require="[email protected]" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script> 
<script> 

var margin = {top: 20, right: 80, bottom: 30, left: 150}, 
    width = 960 - margin.left - margin.right, 
    height = 500 - margin.top - margin.bottom; 

var x = d3.scale.linear() 
    .range([0, width]); 

var y = d3.scale.linear() 
    .range([height, 0]); 

var color = d3.scale.category10(); 

var xAxis = d3.svg.axis() 
    .scale(x) 
    .orient("bottom"); 

var yAxis = d3.svg.axis() 
    .scale(y) 
    .orient("left"); 

var line = d3.svg.line() 
    //.interpolate("basis") 
    .x(function(d) { return x(d.year); }) 
    .y(function(d) { return y(d.emission); }); 

var svg = d3.select("body").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 + ")"); 

d3.csv("europe_emission.csv", function(error, data) { 
    if (error) throw error; 

    color.domain(d3.keys(data[0]).filter(function(key) { return key !== "year"; })); 

    var cities = color.domain().map(function(name) { 
    return { 
     name: name, 
     values: data.map(function(d) { 
     return {year: d.year, emission: +d[name]}; 
     }) 
    }; 
    }); 

    x.domain(d3.extent(data, function(d) { return d.year; })); 

    y.domain([ 
    0, 
    d3.max(cities, function(c) { return d3.max(c.values, function(v) { return v.emission; }); }) 
    ]); 

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

    svg.append("g") 
     .attr("class", "y axis") 
     .call(yAxis) 
    .append("text") 
     .attr("transform", "rotate(-90)") 
     .attr("y", 6) 
     .attr("dy", ".71em") 
     .style("text-anchor", "end") 
     .text("Emission (thousand metric tons of CO2)"); 

    var city = svg.selectAll(".city") 
     .data(cities) 
    .enter().append("g") 
     .attr("class", "city"); 


       city.append("path") 
     .attr("class", "line") 
     .attr("d", function(d) { 
     return line(d.values); 
     }) 
     .style("stroke", function(d) { 
     return color(d.name); 
     }); 

    city.append("text") 
     .datum(function(d) { 
     return { 
      name: d.name, 
      value: d.values[d.values.length - 1] 
     }; 
     }) 
     .attr("transform", function(d) { 
     return "translate(" + x(d.value.year) + "," + y(d.value.emission) + ")"; 
     }) 
     .attr("x", 3) 
     .attr("dy", ".35em") 
     .text(function(d) { 
     return d.name; 
     }); 

    var mouseG = svg.append("g") 
     .attr("class", "mouse-over-effects"); 

    mouseG.append("path") // this is the black vertical line to follow mouse 
     .attr("class", "mouse-line") 
     .style("stroke", "black") 
     .style("stroke-width", "1px") 
     .style("opacity", "0"); 

    var lines = document.getElementsByClassName('line'); 

    var mousePerLine = mouseG.selectAll('.mouse-per-line') 
     .data(cities) 
     .enter() 
     .append("g") 
     .attr("class", "mouse-per-line"); 

    mousePerLine.append("circle") 
     .attr("r", 7) 
     .style("stroke", function(d) { 
     return color(d.name); 
     }) 
     .style("fill", "none") 
     .style("stroke-width", "1px") 
     .style("opacity", "0"); 

    mousePerLine.append("text") 
     .attr("transform", "translate(10,3)"); 

    mouseG.append('svg:rect') // append a rect to catch mouse movements on canvas 
     .attr('width', width) // can't catch mouse events on a g element 
     .attr('height', height) 
     .attr('fill', 'none') 
     .attr('pointer-events', 'all') 
     .on('mouseout', function() { // on mouse out hide line, circles and text 
     d3.select(".mouse-line") 
      .style("opacity", "0"); 
     d3.selectAll(".mouse-per-line circle") 
      .style("opacity", "0"); 
     d3.selectAll(".mouse-per-line text") 
      .style("opacity", "0"); 
     }) 
     .on('mouseover', function() { // on mouse in show line, circles and text 
     d3.select(".mouse-line") 
      .style("opacity", "1"); 
     d3.selectAll(".mouse-per-line circle") 
      .style("opacity", "1"); 
     d3.selectAll(".mouse-per-line text") 
      .style("opacity", "1"); 
     }) 
     .on('mousemove', function() { // mouse moving over canvas 
     var mouse = d3.mouse(this); 
     d3.select(".mouse-line") 
      .attr("d", function() { 
      var d = "M" + mouse[0] + "," + height; 
      d += " " + mouse[0] + "," + 0; 
      return d; 
      }); 

     d3.selectAll(".mouse-per-line") 
      .attr("transform", function(d, i) { 
      //console.log(width/mouse[0]) 
      var xDate = x.invert(mouse[0]), 
       bisect = d3.bisector(function(d) { return d.year; }).right; 
       idx = bisect(d.values, xDate); 

      var beginning = 0, 
       end = lines[i].getTotalLength(), 
       target = null; 

      while (true){ 
       target = Math.floor((beginning + end)/2); 
       pos = lines[i].getPointAtLength(target); 
       if ((target === end || target === beginning) && pos.x !== mouse[0]) { 
        break; 
       } 
       if (pos.x > mouse[0])  end = target; 
       else if (pos.x < mouse[0]) beginning = target; 
       else break; //position found 
      } 

      d3.select(this).select('text') 
       .text(y.invert(pos.y).toFixed(2)); 

      return "translate(" + mouse[0] + "," + pos.y +")"; 
      }); 
     }); 




}); 

</script> 

europe_emission.csv:

год, Королевство Соединенное, Италия, Франция, Испания, Германия
2012,483423,386666,368845,276636,821717
2011,464036 , 413379,364819,280922,810441
2010,504997,424993,391075,280377,829401
2009,487442,414809,381992,293732,785602
2008,536733,463695,400720,333181,851111
2007,554251,475436,407254,363744,848548
2006,561128,483533,416414,356712,873246
2005,561101,488078,425740,365478,861733
2004,563962,489367,422201,350071 , 881743
2003,562296,486559,420492,333168,893599
2002,551553,470530,412019,328878,890875
2001,567904,468283,416267,308786,907541
2000,556667,462277,415079 , 308026,891515
1999,548047,458824,418193,294901,887890
1998,555499,453524,426564,271515,915176
1997,550525,442371,404884,263303,923080
1996,575026,438303,411302,250543,951863
1995,553701,444943,398480,262860,930857
1994,562061,419903,391681,249451 , 932485
1993,568100,427170,391484,237253,948683
1992,581828,433867,413020,245814,957561
1991,598323,434156,423121,237179,1004735
1990,591499,434656,398769 , 227508,1042065

+0

Вы видели это [ответ] (http://stackoverflow.com/a/34887578/16363)? – Mark

+0

Я изменил код и файл .csv, но у меня все еще есть проблема, и я не могу понять, почему ... это похоже на ваш ответ! .. спасибо, что помогли мне –

ответ

1

Это заняло у меня слишком много времени, чтобы понять, но это ваши данные сортировки. Моя ссылка выше приняла значения возрастающей оси x, вы опускаетесь, поэтому ваши дорожки рисуются назад справа налево. Либо сортировать данные, или изменить функцию поиска, чтобы перейти справа налево:

 d3.selectAll(".mouse-per-line") 
     .attr("transform", function(d, i) { 

      var beginning = 0, 
      end = lines[i].getTotalLength(), 
      target = null; 

      while (true) { 
      target = Math.floor((beginning + end)/2); 
      pos = lines[i].getPointAtLength(target); 
      if ((target === end || target === beginning) && pos.x !== mouse[0]) { 
       break; 
      } 
      if (pos.x > mouse[0]) beginning = target; //<-- this was end = target 
      else if (pos.x < mouse[0]) end = target; //<-- this was beginning = target 
      else break; 
      } 

      d3.select(this).select('text') 
      .text(y.invert(pos.y).toFixed(2)); 

      return "translate(" + mouse[0] + "," + pos.y + ")"; 
     }); 

Фиксированный код here.

+0

спасибо! он отлично работает! –

Смежные вопросы