LinkText is not working in tree layout d3js - d3.js

I am trying to put linkText for the link in tree layout d3js but it is not wlrking, created the jsfiddle project here. Can anybody let me know, why the linkText is not coming.
var link = svg.selectAll(".link")
.data(links, function (d) {
return d.target.id;
});
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", function (d) {
var o = {
x : source.x0,
y : source.y0
};
return diagonal({
source : o,
target : o
});
});
link.transition().duration(duration)
.style("stroke", function (d) {
return "#99FFCC";
})
.attr("d", diagonal);
link.append("text")
.attr("font-family", "Arial, Helvetica, sans-serif")
.attr("fill", "Black")
.style("font", "normal 12px Arial").attr("transform", function(d) {
return "translate(" +
(d.target.y - 50) + "," +
(d.target.x - 10) + ")";
}).attr("text-anchor", "middle").text(function (d) {
alert(d.target.label);
return d.target.label;
});

Your mistake is in here:
link.enter().insert("path", "g")
.attr("class", "link")
...
...
link.append("text")
.attr("font-family", "Arial, Helvetica, sans-serif")
.attr("fill", "Black")
This code will put the text within the path DOM, which is incorrect.
Text DOM should never be within the path DOM.
Correct code should have been this:
// Update the links…
var link = svg.selectAll("path.link")
.data(links);
//adding the text to the svg
link.enter().insert("text")
.attr("font-family", "Arial, Helvetica, sans-serif")
.attr("fill", "Black")
.style("font", "normal 12px Arial")
.attr("transform", function (d) {
return "translate(" + (d.target.y - 30) + "," + (d.target.x - 10) + ")";
})
.attr("text-anchor", "middle")
.text(function (d) {
console.log(d.target.label);
return d.target.label;
});
Full working code here.

Related

Replace space with new line charcter in texts d3js

I have a script in which I make txts in the following way:
texts = svg.selectAll(null)
.data(data)
.enter()
.append('text')
.attr("text-anchor", "middle")
.text(function(d) {
return d.abbreviation;
})
.attr("pointer-events", "none")
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.attr("fill", "black");
texts.each(function(d) {
console.log(this.getComputedTextLength());
d.size = this.getComputedTextLength() / 2 ;
});
simulation.nodes(data).on("tick", function() {
circles.attr("cx", function(d) {
return d.x = Math.max(20, Math.min(width - 20, d.x));
})
.attr("cy", function(d) {
return d.y = Math.max(20, Math.min(height - 20, d.y));
})
texts.attr("x", function(d) {
return d.x;
})
.attr("y", function(d) {
return d.y;
});
});
I am using property abbreviation in data to put text over the bubbles but I want to replace all spaces in input with new line character.
I tried some soutions like given at this link: How to linebreak an svg text in javascript?
but all texts go to left most corner or if I remove the .attr("x", 0) property from this, then the alignment of texts in not right. See picture below:
"State" should come directly below "Iowa"
Updated script:
texts = svg.selectAll(null)
.data(data)
.enter()
.append('text')
.attr("text-anchor", "middle")
.each(function (d) {
var arr = d.abbreviation.split(" ");
for (i = 0; i < arr.length; i++) {
d3.select(this).append("tspan")
.text(arr[i])
.attr("dy", i ? "1.2em" : 0)
.attr("text-anchor", "middle")
.attr("class", "tspan" + i);
}
})
.attr("pointer-events", "none")
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.attr("fill", "black");
What should I do to make the alignment right or is there any other way to do this?
There are different ways to fix this. An easy one is appending the <tspan> to a <g> element, setting all their x properties to 0 and text-anchor to middle.
Have a look at the demo:
var svg = d3.select("svg");
var data = [{
text: "some text"
}, {
text: "a longer text here"
}, {
text: "an even longer text here"
}, {
text: "short text"
}, {
text: "a long text"
}];
var texts = svg.selectAll(null)
.data(data)
.enter()
.append("g");
texts.append("text")
.attr("text-anchor", "middle")
.each(function(d) {
var arr = d.text.split(" ");
d3.select(this).selectAll(null)
.data(arr)
.enter()
.append("tspan")
.attr("text-anchor", "middle")
.attr("x", 0)
.attr("dy", function(d, i) {
return "1.2em"
})
.text(String)
})
var simulation = d3.forceSimulation(data)
.force("center", d3.forceCenter(200, 100))
.force("collide", d3.forceCollide(40))
.on("tick", tick);
function tick() {
texts.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"
})
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="400" height="250"></svg>
PS: Don't use that for loop inside the each. That's not idiomatic D3. Instead of that, just use an enter selection (refer to the demo to see how to do it).

How to fit text inside nodes at bottom in pack layout in d3?

I created d3 pack layout.Text is added in nodes. Requirement is text should be fit in circular nodes in such way that Text should be at bottom, proportional to node size and should be fit inside node.but text is either overlapping or hides behind another node or not proportional to nodes as in JSFiddle examples
http://jsfiddle.net/oo66o0q0/11/,
http://jsfiddle.net/oo66o0q0/12/,
http://jsfiddle.net/oo66o0q0/13/
.So how to resolve all issue with one code?
function treeLayout(nodes){
var node = diagramLayout.selectAll(".node");
node = node.data(nodes.descendants(), function(d) {
return d.uid;
});
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("height", nodeHeight)
.attr("width", nodeWidth)
nodeEnter.append("circle")
.attr("id", function(d) { return "node-" + d.data.name; })
.attr("r", function(d) { return d.r; })
.style("fill", function(d) { return color(d.depth); });
nodeEnter.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
var nodeText = nodeEnter.append("text")
.text(function(d) { return d.data.name; })
.attr("clip-path", function(d) { return "url(#clip-" + d.data.name + ")"; })
.style("text-anchor", "middle")
.style("stroke", "#000")
.style("stroke-width", "0.1px")
.attr("y", function(d) {
return d.r-(d.r/d.data.name.length);
})
.style("font-family", "sans-serif")
.style("font-size", function(d) {
return d.r/(d.data.name.length)+ "px";
})
}
}

Node names disappears when user mouse hover on the node name for d3 sankey layout on edge browser windows 10

I created sankey layout in d3. tooltips added on links and nodes as shown in given Jfiddle http://jsfiddle.net/n7f2dkt0/39/
Issue is Node names disappears when user mouse hover on the node name for sankey layout on edge browser.how to resolve this issue?
screenshot for error
var link = svg.append("g").selectAll(".link")
.data(energy.links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke-width", function(d) { return Math.max(1, d.dy); })
.sort(function(a, b) { return b.dy - a.dy; });
link.on("mouseover", mouseoverLink)
link.on("mouseout", mouseoutLink);
var node = svg.append("g").selectAll(".node")
.data(energy.nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.call(drag);
node.append("rect")
.attr("height", function(d) { return d.dy; })
.attr("width", sankey.nodeWidth())
.style("fill", function(d) { return d.color = color(d.name.replace(/ .*/, "")); })
.style("stroke", function(d) { return d3.rgb(d.color).darker(2); })
node.append("text")
.attr("x", -6)
.attr("y", function(d) { return d.dy / 2; })
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function(d) { return d.name; })
.filter(function(d) { return d.x < width / 2; })
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
node.on("mouseover", mouseover);
node.on("mouseout", mouseout);

Can't add title to stacked bar graph on D3

I creating a stacked bar chart using this example. The chart works and renders but I can't add a mouseover label.
I tried this...
DATE.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1); })
.style("fill", function(d) { return color(d.name); });
.append("svg:title")
.text(functino(d){return "foo"});
But this after adding the .append("svg:title... the graph stops rendering. If I remove the .style("fill... line, the graph renders, however it's not stacked and there's no mouseover feature.
I have also tried using the tooltip route. (Source)
.on("mouseover", function() { tooltip.style("display", null); })
.on("mouseout", function() { tooltip.style("display", "none"); })
.on("mousemove", function(d) {
var xPosition = d3.mouse(this)[0] - 15;
var yPosition = d3.mouse(this)[1] - 25;
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
tooltip.select("text").text(d.y);
});
// Prep the tooltip bits, initial display is hidden
var tooltip = svg.append("g")
.attr("class", "tooltip")
.style("display", "none");
tooltip.append("rect")
.attr("width", 30)
.attr("height", 20)
.attr("fill", "white")
.style("opacity", 0.5);
tooltip.append("text")
.attr("x", 15)
.attr("dy", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold");
But still not luck. Is there a library I need to load? Not sure what's going on.
The graph stop rendering when you try to append the title because you have a typo: it's function, not functino.
Besides that, this is what you need to get the value of each stacked bar:
.append("title")
.text(function(d){
return d[1]-d[0]
});
Here is the demo: https://bl.ocks.org/anonymous/raw/886d1749c4e01e191b94df23d97dcaf7/
But I don't like <title>s. They are not very versatile. Thus, instead of creating another <text>, as the second code you linked does, I prefer creating a div:
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
Which we position and set the HTML text this way:
.on("mousemove", function(d) {
tooltip.html("Value: " + (d[1] - d[0]))
.style('top', d3.event.pageY - 10 + 'px')
.style('left', d3.event.pageX + 10 + 'px')
.style("opacity", 0.9);
}).on("mouseout", function() {
tooltip.style("opacity", 0)
});
And here is the demo: https://bl.ocks.org/anonymous/raw/f6294c4d8513dbbd8152770e0750efd9/

D3 X-Value Mouseover Multiple Line Chart

I am trying to create a X-value mouseoever event for all the valuelines in my line chart. However, I couldn't get each line highlighted and right now I have only one line with mouseover effect.
I would like to create a combination of this(http://bl.ocks.org/mbostock/8033015) and this (http://bl.ocks.org/mbostock/3902569). I have been struggling with this for days, any help would be greatly appreciated!!!
Here is my original code:
<!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>
and here is my data.
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
The key here is making the voronoi work correctly; after that it all falls into place. The way you started only used the total_hydroelectric data, but it needs to take into account all your data. The quickest way to do that, it to create a flat data structure of all the data:
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"});
...
});
Later:
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);
And when you draw your lines add a class so you can find them later:
svg.append("path")
.attr("class", "line total_hydroelectric") // tag this as hydro
.attr("d", valueline2(data));
Where mouseover/mouseout then becomes:
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)");
}
In this way then the voronoi events also take care of your x-value point hover.
Here's an example putting it together.

Resources