D3 X值鼠标悬停多线图

时间:2014-12-22 06:45:12

标签: d3.js

我正在尝试为折线图中的所有值线程创建一个X值mouseoever事件。但是,我无法突出显示每一行,现在我只有一行具有鼠标悬停效果。

我想创建一个(http://bl.ocks.org/mbostock/8033015)和this(http://bl.ocks.org/mbostock/3902569)的组合。我这几天一直在努力,任何帮助都会非常感激!!!

这是我的原始代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Content-Language" content="en">
<title>Energy Production in California</title>
<style>

body { font: 14px avenir next;}

path { 
    stroke: #e5e5e5;
    stroke-width: ;
    fill: none;
}

.axis path,
.axis line {
    fill: none;
    stroke: grey;
    stroke-width: 1;
    shape-rendering: crispEdges;
}



/*.sources {
    font-size:14px;
    fill:#e5e5e5;
}

.sources:hover {
/*  font-size:18px;*/
    font-weight: 800;
    fill:#853b62;
}*/

/*.graph-svg-component {
    background-color:#e1e1e1;

}*/

div {
        padding: 15px;
        width:800px;
        margin-left:auto;
        margin-right:auto;
          border:10px ;
}

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

.focus circle {
  fill: steelblue;
  stroke: steelblue;
}

.line {
  stroke: #e5e5e5;
/*  stroke:white;*/
}

.line:hover {
  stroke: #e769ab ;
  stroke-width:2;
}

</style>
</head>
<body>

<script src="http://d3js.org/d3.v3.min.js"></script>
<div>
<script>

var margin = {top: 50, right: 140, bottom: 50, left: 80},
    width = 1000 - margin.left - margin.right,
    height = 600 - margin.top - margin.bottom;

var parseDate = d3.time.format("%Y").parse,
    bisectDate = d3.bisector(function(d) { return d.date; }).left,
    formatValue = d3.format(",.2f");

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

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

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

var voronoi = d3.geom.voronoi()
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.total_hydroelectric); })
    .clipExtent([[-margin.left, -margin.top], [width + margin.right, height + margin.bottom]]);

// var  valueline1 = d3.svg.line()
//  .x(function(d) { return x(d.date); })
//  .y(function(d) { return y(d.california_energy_production); });

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

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

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

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

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

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

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

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

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

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

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

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




var svg = d3.select("body")
    .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .attr("class", "graph-svg-component")
    .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// Get the data
d3.csv("data_3.csv", function(error, data) {
    data.forEach(function(d) {
        d.date = parseDate(d.date);
        // d.california_energy_production = +d.california_energy_production;
        d.total_hydroelectric = +d.total_hydroelectric;
        d.nuclear = +d.nuclear;
        d.in_state_coal = +d.in_state_coal;
        d.oil = +d.oil;
        d.natural_gas = +d.natural_gas;
        d.geothermal = +d.geothermal;
        d.biomass = +d.biomass;
        d.wind = +d.wind;
        d.solar = +d.solar;
        d.other = +d.other;
        d.direct_coal_imports = +d.direct_coal_imports;
        d.other_imports = +d.other_imports;
    });

    // Scale the range of the data
    x.domain(d3.extent(data, function(d) { return d.date; }));
    y.domain([0, d3.max(data, function(d) { return Math.max( d.total_hydroelectric, d.nuclear,d.in_state_coal, d.oil, d.natural_gas, d.geothermal, d.biomass, d.wind, d.solar, d.other, d.direct_coal_imports, d.other_imports); })]);




    // Add the valueline path.
    // svg.append("path")       
    //  .attr("class", "line")
    //  .attr("d", valueline1(data));

    svg.append("path")      
        .attr("class", "line")      
        .attr("d", valueline2(data));

    svg.append("path")      
        .attr("class", "line")  
        .attr("d", valueline3(data));

    svg.append("path")      
        .attr("class", "line")      
        .attr("d", valueline4(data));

    svg.append("path")      
        .attr("class", "line")      
        .attr("d", valueline5(data));

    svg.append("path")      
        .attr("class", "line")      
        .attr("d", valueline6(data));

    svg.append("path")      
        .attr("class", "line")      
        .attr("d", valueline7(data));

    svg.append("path")      
        .attr("class", "line")      
        .attr("d", valueline8(data));

    svg.append("path")      
        .attr("class", "line")
        .attr("d", valueline9(data));

    svg.append("path")      
        .attr("class", "line")      
        .attr("d", valueline10(data));

    svg.append("path")      
        .attr("class", "line")      
        .attr("d", valueline11(data));

    svg.append("path")      
        .attr("class", "line")  
        .attr("d", valueline12(data));

    svg.append("path")      
        .attr("class", "line")      
        .attr("d", valueline13(data));

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

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

    var focus = svg.append("g")
      .attr("class", "focus")
      .style("display", "none");

    focus.append("circle")
      .attr("r", 4.5);

    focus.append("text")
      .attr("x", 9)
      .attr("dy", ".35em");

    svg.append("rect")
      .attr("class", "overlay")
      .attr("width", width)
      .attr("height", height)
      .on("mouseover", function() { focus.style("display", null); })
      .on("mouseout", function() { focus.style("display", "none"); })
      .on("mousemove", mousemove);

    function mousemove() {
    var x0 = x.invert(d3.mouse(this)[0]),
        i = bisectDate(data, x0, 1),
        d0 = data[i - 1],
        d1 = data[i],
        d = x0 - d0.date > d1.date - x0 ? d1 : d0;
    focus.attr("transform", "translate(" + x(d.date) + "," + y(d.total_hydroelectric) + ")");
    focus.select("text").text(d.total_hydroelectric + " Gigawatt/Hours");



  };



    svg.append("text")
        // .attr("class", "sources")
        .attr("transform", "translate(" + (width+3) + "," + y(data[30].total_hydroelectric) + ")")
        .attr("dy", ".35em")
        .attr("text-anchor", "start")
        .style("fill", "#898989")
        .text("Total Hydroelectric");

    svg.append("text")
        .attr("transform", "translate(" + (width+3) + "," + y(data[30].nuclear) + ")")
        .attr("dy", ".35em")
        .attr("text-anchor", "start")
        .style("fill", "#898989")
        .text("Nuclear");

    svg.append("text")
        .attr("transform", "translate(" + (width+3) + "," + y(data[30].in_state_coal) + ")")
        .attr("dy", ".35em")
        .attr("text-anchor", "start")
        .style("fill", "#898989")
        .text("In State Coal");

    svg.append("text")
        .attr("transform", "translate(" + (width+3) + "," + y(data[30].oil) + ")")
        .attr("dy", ".35em")
        .attr("text-anchor", "start")
        .style("fill", "#898989")
        .text("Oil");

    svg.append("text")
        .attr("transform", "translate(" + (width+3) + "," + y(data[30].natural_gas) + ")")
        .attr("dy", ".35em")
        .attr("text-anchor", "start")
        .style("fill", "#898989")
        .text("Natural Gas");

    svg.append("text")
        .attr("transform", "translate(" + (width+3) + "," + y(data[30].geothermal) + ")")
        .attr("dy", ".35em")
        .attr("text-anchor", "start")
        .style("fill", "#898989")
        .text("Geotheral");

    svg.append("text")
        .attr("transform", "translate(" + (width+3) + "," + y(data[30].biomass) + ")")
        .attr("dy", ".35em")
        .attr("text-anchor", "start")
        .style("fill", "#898989")
        .text("Biomass");

    svg.append("text")
        .attr("transform", "translate(" + (width+3) + "," + y(data[30].wind) + ")")
        .attr("dy", ".35em")
        .attr("text-anchor", "start")
        .style("fill", "#898989")
        .text("Wind");

    svg.append("text")
        .attr("transform", "translate(" + (width+3) + "," + y(data[30].solar) + ")")
        .attr("dy", ".35em")
        .attr("text-anchor", "start")
        .style("fill", "#898989")
        .text("Solar");

    svg.append("text")
        .attr("transform", "translate(" + (width+3) + "," + y(data[30].other) + ")")
        .attr("dy", ".35em")
        .attr("text-anchor", "start")
        .style("fill", "#898989")
        .text("Other");

    svg.append("text")
        .attr("transform", "translate(" + (width+3) + "," + y(data[30].direct_coal_imports) + ")")
        .attr("dy", ".35em")
        .attr("text-anchor", "start")
        .style("fill", "#898989")
        .text("Direct Coal Imports");

    svg.append("text")
        .attr("transform", "translate(" + (width+3) + "," + y(data[30].other_imports) + ")")
        .attr("dy", ".35em")
        .attr("text-anchor", "start")
        .style("fill", "#898989")
        .text("Other Imports");


});

</script>
</div>

</body>
</html>

这是我的数据。

date,california_energy_production,total_hydroelectric,nuclear,in_state_coal,oil,natural_gas,geothermal,biomass,wind,solar,other,direct_coal_imports,other_imports
1983,199609,59351,6738,563,6535,45486,7020,731,52,2,0,17001,56130
1984,211900,46880,13467,731,2632,58248,9272,1099,192,11,0,18080,61288
1985,210172,33898,18911,865,2790,69771,10957,1171,655,33,0,14112,57009
1985,211028,44478,28000,1033,3126,49260,13094,2063,1221,64,6,17588,51095
1987,220371,27140,32995,1163,2143,75437,14083,2461,1713,188,5,17544,45499
1988,232926,26692,35481,1791,8158,74221,14194,4092,1824,315,4,19243,46911
1989,238567,32742,33803,2479,9275,78916,15247,5204,2139,471,4,17223,41064
1990,252355,26092,36586,3692,4449,76082,16038,6644,2418,681,4,17710,61959
1991,242343,23244,37167,3050,523,75828,15566,7312,2669,719,0,20392,55873
1992,245535,22373,38622,3629,107,87032,16491,7362,2707,700,2,28806,37704
1993,242026,41595,36579,2549,2085,70715,15770,5760,2867,857,0,20358,42892
1994,256719,25626,38828,2655,1954,95025,15573,7173,3293,798,0,22440,43354
1995,256367,51665,36186,1136,489,78378,14267,5969,3182,793,0,16788,47514
1996,253621,47883,39753,2870,693,66711,13539,5557,3154,832,343,22590,49696
1997,230243,41400,37267,2276,143,74341,11950,5701,2739,810,896,22411,30310
1998,244577,48757,41715,2701,123,82052,12554,5266,2776,839,230,22570,24993
1999,243077,41627,40419,3602,55,84703,13251,5663,3433,838,0,22802,26685
2000,246876,42053,43533,3183,449,106878,13456,6086,3604,860,0,23877,2897
2001,267399,24988,33294,4041,379,116369,13525,5761,3242,836,38,23699,41227
2002,274444,31359,34353,4275,87,92752,13396,6196,3546,851,35,23653,63941
2003,280026,36341,35594,4269,103,94715,13329,6092,3316,759,108,23148,62253
2004,290211,34490,30241,4086,127,105358,13494,6080,4258,741,48,24504,66785
2005,289177,40263,36155,4283,148,97110,13292,6076,4084,660,24,24114,62967
2006,298454,48559,32036,4190,134,109316,13093,5861,4902,616,34,14452,65263
2007,304823,27105,35698,4217,103,120459,13029,5743,5570,668,15,14417,77799
2008,307448,24460,32482,3977,92,123036,12907,5927,5724,733,39,14463,83608
2009,299101,29220,31509,3735,67,117277,12907,6096,6249,851,20,13556,77615
2010,291310,34327,32214,3406,52,109916,12740,5960,6172,912,12,13119,72481
2011,293875,42731,36666,3120,36,91276,12685,5986,7598,1097,13,13032,79633
2012,302113,27459,18491,1580,90,121761,12733,6121,9242,1834,14,9716,93071
2013,296569,24098,17860,1018,38,120896,12485,6466,12694,4154,14,11824,85022

1 个答案:

答案 0 :(得分:0)

这里的关键是让voronoi正常工作;之后,一切都落到了位置。您开始的方式只使用了total_hydroelectric数据,但它需要考虑您的所有数据。最快捷的方法是创建所有数据的平面数据结构:

var flatData = [];
data.forEach(function(d) {
    d.date = parseDate(d.date);
    // d.california_energy_production = +d.california_energy_production;
    d.total_hydroelectric = +d.total_hydroelectric;
    d.nuclear = +d.nuclear;
    d.in_state_coal = +d.in_state_coal;
    ...        
    flatData.push({date: d.date, value: d.total_hydroelectric, key: "total_hydroelectric"});
    flatData.push({date: d.date, value: d.nuclear, key: "nuclear"});
    flatData.push({date: d.date, value: d.in_state_coal, key: "in_state_coal"});
    ...
});

随后:

voronoiGroup.selectAll("path")
  .data(voronoi(flatData))
  .enter().append("path")
  .attr("d", function(d) { return "M" + d.join("L") + "Z"; })
  .datum(function(d) { return d.point; })
  .on("mouseover", mouseover)
  .on("mouseout", mouseout);

当你绘制线条时,添加一个类,以便稍后找到它们:

svg.append("path")      
    .attr("class", "line total_hydroelectric") // tag this as hydro
    .attr("d", valueline2(data));

鼠标悬停/鼠标输出变为:

function mouseover(d) {
  d3.select("."+d.key).classed("line-hover", true);
  focus.attr("transform", "translate(" + x(d.date) + "," + y(d.value) + ")");
  focus.select("text").text(d.date);
}

function mouseout(d) {
  d3.select("."+d.key).classed("line-hover", false);
  focus.attr("transform", "translate(-100,-100)");
}

通过这种方式,voronoi事件也可以处理您的x值点悬停。

这是an example putting it together