我创建了一个差异图表,现在我想为该图表添加一个工具提示,我创建了一条在图表上移动的线,现在我想将图表的值显示为工具提示,即x和y值,这里是(日期,打开,关闭)在鼠标移动线上的图表上,任何参考或指导将非常有帮助 .
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.area.above {
fill:rgb(252,141,89);
}
.area.below {
fill:rgb(145,207,96);
}
.line {
fill: none;
stroke: #000;
stroke-width: 1.5px;
}
</style>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.timeParse("%Y-%m-%d");
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear() .range([height, 0]);
var xAxis = d3.axisBottom().scale(x);
var yAxis = d3.axisLeft() .scale(y).ticks(20);
//leg
//var c = d3.scaleOrdinal(d3.schemeCategory10);
var line = d3.area()
.curve(d3.curveBasis)
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d["open"]); });
var area = d3.area()
.curve(d3.curveBasis)
.x(function(d) { return x(d.date); })
.y1(function(d) { return y(d["open"]); });
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.csv("data/morley1.csv", function (error, data) {
if (error) throw error;
data.forEach(function(d) {
d.date = parseDate(d.date);
d.open = +d.open;
d.close=+d.close;
});
data.sort(function(a,b){
return a.date-b.date
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) {
return Math.max(d.close, d.open); })]);
svg.datum(data);
svg.append("clipPath")
.attr("id", "clip-below")
.append("path")
.attr("d", area.y0(height));
svg.append("clipPath")
.attr("id", "clip-above")
.append("path")
.attr("d", area.y0(0));
svg.append("path")
.attr("class", "area above")
.attr("clip-path", "url(#clip-above)")
.attr("d", area.y0(function(d) { return y(d["close"]); }));
svg.append("path")
.attr("class", "area below")
.attr("clip-path", "url(#clip-below)")
.attr("d", area);
svg.append("path")
.attr("class", "line")
.attr("d", line);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class","y axis")
.call(yAxis)
});
var mouseG = svg.append("g") // this the black vertical line to folow mouse
.attr("class","mouse-over-effects");
mouseG.append("path")
.attr("class","mouse-line")
.style("stroke","black")
.style("stroke-width","1px")
.style("opacity","0");
var lines = document.getElementsByClassName("line");
var mousePerLine = mouseG.selectAll(".mouse-per-line")
//.data(data)
.enter()
.append("g")
.attr("class","mouse-per-line");
mousePerLine.append("circle")
.attr("r",7)
.style("stroke",function(d){
return color(d.name);
})
.style("fill", "none")
.style("stroke-width", "1px")
.style("opacity", "0");
mousePerLine.append("text")
.attr("transform","translate(10,3)");
mouseG.append("rect")
.attr("width",width)
.attr("height",height)
.attr("fill","none")
.attr("pointer-events","all")
.on("mouseout",function(){
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",function(){
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",function(){
var mouse = d3.mouse(this);
console.log("Mouse:",mouse);
d3.select(".mouse-line")
.attr("d",function(){
var d = "M" + mouse[0] +"," + height;
d+=" " +mouse[0] + "," + 0;
return d;
})
// .attr("d",function(){
// var d = "M" + w +"," + mouse[1];
// d+=" " +0 + "," + mouse[1];
// return d;
// });
d3.selectAll(".mouse-per-line")
.attr("transform",function(d,i){
console.log(width/(mouse[0]));
var xDate = scaleX.invert(mouse[0]),
bisect =d3.bisector(function(d){ return d.date;}).right;
idx = bisect(d.values,xDate);
console.log("xDate:",xDate);
console.log("bisect",bisect);
console.log("idx:",idx)
var beginning = 0,
end = lines[i].getTotalLength(),
target = null;
console.log("end",end);
while(true){
target = Math.floor((beginning+end)/2)
console.log("Target:",target);
pos = lines[i].getPointAtLength(target);
console.log("Position",pos.y);
console.log("What is the position here:",pos)
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
}
d3.select(this).select("text")
.text(scaleY.invert(pos.y).toFixed(1))
.attr("fill",function(d){
return color(d.name)
});
return "translate(" +mouse[0]+","+pos.y+")";
});
});
</script>