最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - d3, Angular 2: node.getBoundingClientRect is not a function - Stack Overflow

matteradmin13PV0评论

I am drawing charts with d3 in my Angular 2 application. Now I have a multi series line chart so I am trying to add tool tips at each line when hover its' vertical position.

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() {

  }
}

I am getting following error message on browser console.

node.getBoundingClientRect is not a function

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

Any suggestions?

Thank you!

I am drawing charts with d3 in my Angular 2 application. Now I have a multi series line chart so I am trying to add tool tips at each line when hover its' vertical position.

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() {

  }
}

I am getting following error message on browser console.

node.getBoundingClientRect is not a function

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

Any suggestions?

Thank you!

Share Improve this question asked Sep 11, 2016 at 16:05 Rose18Rose18 3,1628 gold badges51 silver badges100 bronze badges 1
  • Your problem is similar to this answer. – jredd Commented Jan 17, 2018 at 7:17
Add a comment  | 

2 Answers 2

Reset to default 17

I guess you should use it:

let mouse = d3.mouse(mouseG); 

or you can write like:

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

d3.mouse() needs to be called on a DOM node. d3.mouse(this) does not work, because "this" is an instance of your custom class. In your case, you can use

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

You need to call node(), because, again, mouseG is a d3 selection object, not a DOM node. node() returns the underlying "g" node.

Post a comment

comment list (0)

  1. No comments so far