Javascript d3:鼠标悬停事件时,多系列折线图上每行的工具提示
我在Angular 2应用程序中使用d3绘制图表。现在我有了一个多系列的折线图,所以当我将鼠标悬停在垂直位置时,我尝试在每一行添加工具提示Javascript d3:鼠标悬停事件时,多系列折线图上每行的工具提示,javascript,angularjs,d3.js,typescript,Javascript,Angularjs,D3.js,Typescript,我在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 sca
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 + ")";
});
});
}
}
上面的控制台日志在鼠标悬停事件中正确打印Y轴值
任何建议
谢谢大家! 我已经根据您的要求在多系列折线图上创建了工具提示,效果很好 您需要对代码进行一些更改,以设置下面示例链接中工具提示的位置 参见这里的示例 你可以这样做
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 + ")";
});
d3.全选(“.每行鼠标”)
.attr(“变换”,(d,i,f)=>{
控制台日志(i);
让开始=0,
end=d3.select(行[i]).node().getTotalLength(),
目标,,
销售时点情报系统;
while(true){
目标=数学楼层((开始+结束)/2);
pos=d3.select(行[i]).node().getPointAtLength(目标);
如果((目标==结束| |目标==开始)&&pos.x!==鼠标[0]){
打破
}
如果(pos.x>鼠标[0])结束=目标;
否则,如果(位置x<鼠标[0])开始=目标;
else break;//找到位置
}
console.log(此.yScale.invert(位置y).toFixed(2));
//用y值更新文本
d3.select(f[i]).select('text')/**错误此.querySelector不是函数
.text(此.yScale.invert(位置y).toFixed(2));
//返回位置
返回“translate”(“+mouse[0]+”,“+pos.y+”);
});
在OP中添加一些关于错误的细节,然后建议代码会更好
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 + ")";
});