2016-09-11 12 views
2

私はAngular 2アプリケーションでd3のグラフを描いています。今私は複数のシリーズラインチャートを持っているので、私は、それぞれのラインでツールチップを追加しようとしています。d3:マウスのホバーイベント時の各行のマルチシリーズ折れ線グラフのツールチップ

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 = document.getElementsByClassName('line'); 

    // here's a g for each circle and text on the line 
    let 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(d3.event.currentTarget); 
     console.log(lines); 

     // 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) => { 
      console.log(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 
      } 
      console.log(this.yScale.invert(pos.y).toFixed(2)); 

      // update the text with y value 
      d3.select(this).select('text') // **Error this.querySelector is not a function 
       .text(this.yScale.invert(pos.y).toFixed(2)); 

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

ここでは、各行に垂直線を丸で示していますが、値(ツールチップ)は表示されません。コンソールログに次のエラーが表示されます。

this.querySelector is not a function 

console.log(this.yScale.invert(pos.y).toFixed(2)); 

上記のコンソールログは、マウスのホバーイベントでY軸の値を正しく出力します。

提案があります。

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

答えて

1

私はあなたの要件に応じて、マルチシリーズ折れ線グラフ上にツールチップを作成しています。あなたが怒鳴るの例からツールチップの位置を設定するためにあなたのコードにいくつかの変更を加える必要があり

はここ

Multi Series Line Chart with Tooltip

0

あなたはこの

d3.selectAll(".mouse-per-line") 
     .attr("transform", (d, i, f) => { 
     console.log(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 
     } 
     console.log(this.yScale.invert(pos.y).toFixed(2)); 

     // update the text with y value 
     d3.select(f[i]).select('text') // **Error this.querySelector is not a function 
      .text(this.yScale.invert(pos.y).toFixed(2)); 

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

を追加行うことができます

参照例リンクOPのエラーに関する詳細のビットを入力して、コードをより良いものにすることを提案する –

関連する問題