Grafico a linee multiserie con tooltip di mouseover

Ho creato un grafico a linee multi-serie usando questo esempio di codice bl.ocks.org . Sono riuscito a ricrearlo su JSFiddle .

Grafico a linee multi-serie

Ora, sto provando ad aggiungere un suggerimento per il mouseover con valore x, che visualizza il tooltip su ciascuna linea quando si posiziona la sua posizione verticale. Qualcosa come questo , ma per più linee.

Ho trovato questa risposta StackOverflow (include un JSFiddle ), ma non riesco a farlo funzionare con il mio grafico a linee multiserie.

svg.append("path") // this is the black vertical line to follow mouse .attr("class","mouseLine") .style("stroke","black") .style("stroke-width", "1px") .style("opacity", "0"); var mouseCircle = causation.append("g") // for each line, add group to hold text and circle .attr("class","mouseCircle"); mouseCircle.append("circle") // add a circle to follow along path .attr("r", 7) .style("stroke", function(d) { console.log(d); return color(d.key); }) .style("fill","none") .style("stroke-width", "1px"); mouseCircle.append("text") .attr("transform", "translate(10,3)"); // text to hold coordinates var bisect = d3.bisector(function(d) { return d.YEAR; }).right; // reusable bisect to find points before/after line svg.append('svg:rect') // append a rect to catch mouse movements on canvas .attr('width', width) // can't catch mouse events on ag element .attr('height', height) .attr('fill', 'none') .attr('pointer-events', 'all') .on('mouseout', function(){ // on mouse out hide line, circles and text d3.select(".mouseLine") .style("opacity", "0"); d3.selectAll(".mouseCircle circle") .style("opacity", "0"); d3.selectAll(".mouseCircle text") .style("opacity", "0"); }) .on('mouseover', function(){ // on mouse in show line, circles and text d3.select(".mouseLine") .style("opacity", "1"); d3.selectAll(".mouseCircle circle") .style("opacity", "1"); d3.selectAll(".mouseCircle text") .style("opacity", "1"); }) .on('mousemove', function() { // mouse moving over canvas d3.select(".mouseLine") .attr("d", function(){ yRange = y.range(); // range of y axis var xCoor = d3.mouse(this)[0]; // mouse position in x var xDate = x.invert(xCoor); // date corresponding to mouse x d3.selectAll('.mouseCircle') // for each circle group .each(function(d,i){ var rightIdx = bisect(data[1].values, xDate); // find date in data that right off mouse var interSect = get_line_intersection(xCoor, // get the intersection of our vertical line and the data line yRange[0], xCoor, yRange[1], x(data[i].values[rightIdx-1].YEAR), y(data[i].values[rightIdx-1].VALUE), x(data[i].values[rightIdx].YEAR), y(data[i].values[rightIdx].VALUE)); d3.select(this) // move the circle to intersection .attr('transform', 'translate(' + interSect.x + ',' + interSect.y + ')'); d3.select(this.children[1]) // write coordinates out .text(xDate.toLocaleDateString() + "," + y.invert(interSect.y).toFixed(0)); }); return "M"+ xCoor +"," + yRange[0] + "L" + xCoor + "," + yRange[1]; // position vertical line }); }); // from here: https://stackoverflow.com/a/1968345/16363 function get_line_intersection(p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y) { var rV = {}; var s1_x, s1_y, s2_x, s2_y; s1_x = p1_x - p0_x; s1_y = p1_y - p0_y; s2_x = p3_x - p2_x; s2_y = p3_y - p2_y; var s, t; s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y); t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y); if (s >= 0 && s = 0 && t <= 1) { // Collision detected rV.x = p0_x + (t * s1_x); rV.y = p0_y + (t * s1_y); } return rV; } 

Quindi, per dirla semplicemente, voglio combinare il mio grafico a linee JSFiddle con questo tooltip JSFiddle . Qualcuno sa come si fa questo? O c’è un modo più semplice per creare un suggerimento come questo? Qualsiasi aiuto è apprezzato!

La domanda a cui mi hai riferito ho risposto in aprile. Da allora, ho imparato un po ‘di più su SVG e d3 , quindi lascerò che questo serva da aggiornamento a quella risposta.

Nota, ho preso in prestito un po ‘di codice dall’eccellente esempio di codice di @ Duopixel qui .

Ecco i dettagli commentati:

 // append ag for all the mouse over nonsense var mouseG = svg.append("g") .attr("class", "mouse-over-effects"); // this is the vertical line mouseG.append("path") .attr("class", "mouse-line") .style("stroke", "black") .style("stroke-width", "1px") .style("opacity", "0"); // keep a reference to all our lines var lines = document.getElementsByClassName('line'); // here's ag for each circle and text on the line var mousePerLine = mouseG.selectAll('.mouse-per-line') .data(cities) .enter() .append("g") .attr("class", "mouse-per-line"); // the circle mousePerLine.append("circle") .attr("r", 7) .style("stroke", function(d) { return color(d.name); }) .style("fill", "none") .style("stroke-width", "1px") .style("opacity", "0"); // the text mousePerLine.append("text") .attr("transform", "translate(10,3)"); // rect to capture mouse movements mouseG.append('svg:rect') .attr('width', width) .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); // move the vertical line d3.select(".mouse-line") .attr("d", function() { var d = "M" + mouse[0] + "," + height; d += " " + mouse[0] + "," + 0; return d; }); // position the circle and text 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.date; }).right; idx = bisect(d.values, xDate); // since we are use curve fitting we can't relay on finding the points like I had done in my last answer // this conducts a search using some SVG path functions // to find the correct position on the line // from http://bl.ocks.org/duopixel/3824661 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 } // update the text with y value d3.select(this).select('text') .text(y.invert(pos.y).toFixed(2)); // return position return "translate(" + mouse[0] + "," + pos.y +")"; }); }); 

Codice di lavoro completo: