2016-09-11 17 views
4

私はAngular 2アプリケーションでd3を使用してグラフを描画しています。今私は複数のシリーズラインチャートを持っているので、私は、それぞれのラインでツールチップを追加しようとしています。d3、角2:node.getBoundingClientRectは関数ではありません

export class LineGraphDirective { 
    private host; 
    private svg; 
    private margin; 
    private width; 
    private height; 
    private xScale; // D3 scale in X 
    private yScale; // D3 scale in Y 
    private zScale; // D3 color scale 
    private xAxis; 
    private yAxis; 
    private line; 
    private htmlElement:HTMLElement; 
    private parseDate; 
    private ds; 

    constructor(private element:ElementRef) { 
    this.htmlElement = this.element.nativeElement; 
    this.host = d3.select(this.element.nativeElement); 
    this.parseDate = d3.timeParse('%Y-%m-%d'); 
    let data = []; 
    this.ngOnChanges(data); 
    } 

    /** 
    * Every time the @Input is updated, rebuild the chart 
    **/ 
    ngOnChanges(data):void { 
    this.setup(data); 
    this.initData(data); 
    this.buildSVG(); 
    this.scaleAxis(data); 
    this.populate(); 
    this.drawXAxis(); 
    this.drawYAxis(); 
    this.zoomEventHandler(); 
    this.addVerticalLineTooltip(); 
    } 

    private setup(data):void {} 

    private initData(data) {} 

    /** 
    * build SVG element using the configurations 
    **/ 
    private buildSVG():void {} 

    private scaleAxis(data) {} 

    /** 
    * Create x axis 
    **/ 
    private drawXAxis():void {} 

    /** 
    *create y axis 
    **/ 
    private drawYAxis():void {} 

    /** 
    * Populate the graphs 
    **/ 
    private populate():void {} 

    private addVerticalLineTooltip() { 
    // append a g for all the mouse over nonsense 
    let mouseG = this.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 
    let lines = d3.select('.line'); 

    // here's a g for each circle and text on the line 
    var mousePerLine = mouseG.selectAll('.mouse-per-line') 
     .data(this.ds) 
     .enter() 
     .append("g") 
     .attr("class", "mouse-per-line"); 

    // the circle 
    mousePerLine.append("circle") 
     .attr("r", 7) 
     .style("stroke", (d) => { 
     return this.zScale(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', this.width) 
     .attr('height', this.height) 
     .attr('fill', 'none') 
     .attr('pointer-events', 'all') 
     .on('mouseout',() => { // 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',() => { // 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',() => { // mouse moving over canvas 
     let mouse = d3.mouse(this); // this is the line I am getting error 

     // move the vertical line 
     d3.select(".mouse-line") 
      .attr("d",() => { 
      let d = "M" + mouse[0] + "," + this.height; 
      d += " " + mouse[0] + "," + 0; 
      return d; 
      }); 

     // position the circle and text 
     d3.selectAll(".mouse-per-line") 
      .attr("transform", (d, i) => { 
      let beginning = 0, 
       end = d3.select(lines[i]).node().getTotalLength(), 
       target, 
       pos; 

      while (true) { 
       target = Math.floor((beginning + end)/2); 
       pos = d3.select(lines[i]).node().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(this.yScale.invert(pos.y).toFixed(2)); 

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

    private zoomEventHandler() { 
    let zoom = d3.zoom() 
     .scaleExtent([1, 2]) 
     .translateExtent([[0, -100], this.width + 90, this.height + 100]).on("zoom",() => this.zoomed()); 
    this.svg.call(zoom); 
    } 

    private zoomed() { 

    } 
} 

ブラウザのコンソールで次のエラーメッセージが表示されます。

node.getBoundingClientRect is not a function 

Line: let mouse = d3.mouse(this); 

お勧めはありますか?

ありがとうございました!

let mouse = d3.mouse(mouseG); 

かは次のように書くことができます:

+0

問題はこの[回答](https://stackoverflow.com/a/48231153/2414015)に似ています。 – jredd

答えて

6

は、私はあなたがそれを使用する必要がありますね

let mouse = d3.mouse(d3.event.currentTarget); 
+0

2番目のオプションが機能します。しかし、今では、** end = d3.select(lines [i])。node()。getTotalLength()**で別のエラーが発生しています。** nullのプロパティ 'getTotalLength'を読み込めません。新しい質問を投稿するか、これを更新しますか? – Rose18

+0

私はあなたがそれを再現するために最小プランカを作成する必要があると思う – yurzui

+0

私は** line = document.getElementsByClassName( 'line'); ** let lines = d3.select( '。line') ; **。今私は、各ラインでサークルと垂直線を取得していますが、ツールチップではありません。私は別個の質問を掲示した.http://stackoverflow.com/questions/39438578/d3-tooltips-on-multi-series-line-chart-at-each-line-when-mouse-hover-event – Rose18

0

d3.mouse()DOMノードで呼び出す必要があります。 "this"はカスタムクラスのインスタンスなので、d3.mouse(this)は機能しません。あなたのケースでは、使用することができます

let mouse = d3.mouse(mouseG.node()); 

再度、mouseGはDOMノードではなくd3選択オブジェクトであるため、node()を呼び出す必要があります。 node()は基底の "g"ノードを返します。

関連する問題