2016-07-21 8 views
1

hier ist meine js Geige: https://jsfiddle.net/DerNalia/3wzLv9yg/1/d3.js v4, wie habe ich eine Linie folgen Sie der Maus bei Hover, aber auch einen Kreis folgen dem Pfad?

Ich habe hier den Code zu interpretieren versucht: Multiseries line chart with mouseover tooltip, aber ich kann es einfach nicht zum Laufen zu bringen scheinen.

Dies ist, was ich bisher habe - es ist so ziemlich eine Kopie Paste.

// append a g 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 a g for each circle and text on the line 
var mousePerLine = mouseG.selectAll('.mouse-per-line') 
    .data(data) 
    .enter() 
    .append("g") 
    .attr("class", "mouse-per-line"); 

// the circle 
mousePerLine.append("circle") 
    .attr("r", 7) 
    .style("stroke", function(d) { 
    return 'red'; 
    }) 
    .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]) 
     console.log(mouse[1]); 
     var xDate = x.invert(mouse[0]), 
      bisect = d3.bisector(function(d) { return d.x; }).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)); 

       d3.select(this).select('circle') 
       .attr('cy', pos.x) 
       .attr('cx', pos.y); 

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

Falls etwas mit der Geige schief geht, hier ist das, was ich zur Zeit:

enter image description here

Und hier ist, wie ich es (pardon schreckliche Farbe Fähigkeiten) erscheinen soll: enter image description here

Mein Problem könnte auch mit meinem Fehler zusammenhängen. Eigenschaft 'Länge' von nicht definiert kann nicht gelesen werden.

Antwort

3

Aktualisiert Fiddle: https://jsfiddle.net/3wzLv9yg/2/. Es gibt ein paar Dinge, die schief gehen:

Line Circles

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

Diese Anweisung fügt ein neues g Element für jeden Datenpunkt , anstatt für jede Zeile. Ersetzen Sie es durch ein Array mit der Länge der Anzahl der Zeilen, um ein Element für jede Zeile zu erhalten. Zum Beispiel ersetzen Sie .data(data) durch .data(d3.range(lines.length)).

Mehrere Techniken der Kreis Standort Position

Es sieht aus wie Sie zwei verschiedene Techniken kombiniert haben, um die y-Position von Ihren Kreisen zu berechnen, eine Einbeziehung von Datenwerten berechnet wird, und die andere aus dem SVG-Elemente zu berechnen.

Der Code, der aus Datenwerten berechnet hat diese Zeilen:

var xDate = x.invert(mouse[0]), 
    bisect = d3.bisector(function(d) { return d.x; }).right; 
    idx = bisect(d.values, xDate); 

in bisect(d.values, xDate); als d.values ein Fehler Es gibt nirgendwo zugewiesen. Es sollte bisect(data, xDate); sein, aber es kann irrelevant sein, da es nirgendwo anders verwendet wird, da der Rest der Funktion y-Position aus den Svg-Pfaden berechnet. Sie können von bisect und idx loszuwerden, wenn Sie diesen Ansatz verwenden:

var xDate = x.invert(mouse[0]); 

Lage Umgebung

Dies sollte Konsole Fehler lindern, aber die Maus Kreise verfolgen immer noch nicht richtig. Das ist, weil die Lage des Kreises festgelegt werden zweimal:

d3.select(this).select('circle') 
    .attr('cy', pos.x) 
    .attr('cx', pos.y); 

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

Diese Aussagen Sätze des g Element an die richtige Stelle, aber es stellt auch die circle zu einem in gleicher Höhe gegenüber. Du brauchst nur einen. Da die aktuelle Implementierung das Element transform des Elements g festlegt, ist es wahrscheinlich einfacher, dieses Element beizubehalten und den Kreisversatz zu beseitigen.Alle

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

die Änderungen sind hier: https://jsfiddle.net/3wzLv9yg/2/

+0

Dank einer Tonne für den eingehenden Blick auf den Code! hilft viel. – NullVoxPopuli

+0

Gern geschehen! Schön, dass es hilft. – Steve