Rose18 Rose18 - 2 months ago 36
Javascript Question

d3, Angular 2: node.getBoundingClientRect is not a function

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!

Answer

I guess you should use it:

let mouse = d3.mouse(mouseG); 

or you can write like:

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