d3,Angular 2:node.getBoundingClientRect 不是函数
Posted
技术标签:
【中文标题】d3,Angular 2:node.getBoundingClientRect 不是函数【英文标题】:d3, Angular 2: node.getBoundingClientRect is not a function 【发布时间】:2017-01-19 04:00:48 【问题描述】:我在 Angular 2 应用程序中使用 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 = 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);
有什么建议吗?
谢谢!
【问题讨论】:
你的问题和这个answer类似。 【参考方案1】:我猜你应该使用它:
let mouse = d3.mouse(mouseG);
或者你可以这样写:
let mouse = d3.mouse(d3.event.currentTarget);
【讨论】:
第二个选项有效。但是现在我在 end = d3.select(lines[i]).node().getTotalLength() 遇到另一个错误,因为 Cannot read property 'getTotalLength' of null .我应该发布一个新问题还是更新这个问题? 我认为你需要创建一个最小的 plunker 来重现它 我不得不使用 let lines = document.getElementsByClassName('line'); 而不是 let lines = d3.select('.line');。现在我得到了每行都有圆圈的垂直线,但不是工具提示。我已经发布了一个单独的问题。***.com/questions/39438578/…【参考方案2】:d3.mouse() 需要在 DOM 节点上调用。 d3.mouse(this) 不起作用,因为“this”是您的自定义类的一个实例。在您的情况下,您可以使用
let mouse = d3.mouse(mouseG.node());
您需要调用node(),因为mouseG 是一个d3 选择对象,而不是DOM 节点。 node() 返回底层的“g”节点。
【讨论】:
以上是关于d3,Angular 2:node.getBoundingClientRect 不是函数的主要内容,如果未能解决你的问题,请参考以下文章
Angular 2.0 和 D3.js 不在 svg 上应用 Css [重复]
将 D3.js 导入 Angular 2 应用程序的正确方法
如何将 D3.js 与 Renderer API 与 Angular 2 集成