d3 mouseover Tips
本篇简单介绍d3 mouseover添加tips的实现
绘制曲线
- 以前几篇的
d3
曲线为例
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="test-svg">
</div>
</body>
<script src="https://d3js.org/d3.v5.js"></script>
<script>
window.onload = function() {
// 数据
var data = [{
date: new Date(2019, 3, 24),
value: 23.24
}, {
date: new Date(2019, 3, 25),
value: 72.15
}, {
date: new Date(2019, 3, 26),
value: 38.84
}, {
date: new Date(2019, 3, 27),
value: 58.62
}, {
date: new Date(2019, 3, 30),
value: 10.80
}, {
date: new Date(2019, 4, 1),
value: 85.47
}];
var width = 800,
height = 400,
padding = {
top: 40,
right: 40,
bottom: 40,
left: 40
};
var colors = d3.schemeSet2;
var svg = d3.select("#test-svg")
.append('svg')
.attr('width', width + 'px')
.attr('height', height + 'px');
// x轴:时间轴
var xScale = d3.scaleTime()
.domain(d3.extent(data, function(d) {
return d.date;
}))
.range([padding.left, width - padding.right]);
var xAxis = d3.axisBottom()
.scale(xScale)
.tickSize(10);
var bisect = d3.bisector(function(d) {
return d.date;
}).left;
svg.append('g')
.call(xAxis)
.attr("transform", "translate(0," + (height - padding.bottom) + ")")
.selectAll("text")
.attr("font-size", "10px")
.attr("dx", "50px");
var ymax = d3.max(data, function(d) {
return d.value;
});
// y轴
var yScale = d3.scaleLinear()
.domain([0, ymax])
.range([height - padding.bottom, padding.top]);
var yAxis = d3.axisLeft()
.scale(yScale)
.ticks(10);
svg.append('g')
.call(yAxis)
.attr("transform", "translate(" + padding.left + ",0)");
var curveLine = d3.line()
.x(function(d) {
return xScale(d.date);
})
.y(function(d) {
return yScale(d.value);
})
.curve(d3.curveCatmullRom.alpha(0.5));
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("d", curveLine);
}
</script>
</html>
添加坐标点标识
svg.append("g")
.selectAll('circle')
.data(data)
.join("circle")
.attr("r", 5)
.attr("fill", "white")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("transform", function(item) {
return "translate(" + xScale(item.date) + "," + yScale(item.value) + ")";
})
添加tips
- 添加tips,一个圆点及数据文本
var tips = svg.append("g")
.attr("class", "tips")
.style("display", "none");
tips.append("circle")
.attr("r", 3);
tips.append("text")
.attr("x", 8)
.attr("dy", ".35em");
添加事件
-
添加一个和
svg
同等大小的透明rect
面板用来触发事件 -
获取坐标
// d3.mouse(this)[0] 获取当前鼠标位置的x坐标
// xScale.invert() 转为曲线上的x坐标
xScale.invert(d3.mouse(this)[0])
// d3.bisector() 获取当前曲线上x坐标对应数据中的点序号
var bisect = d3.bisector(function(d) {
return d.date;
}).left;
bisect(data, xdata, 1, data.length - 1);
svg.append("rect")
.attr("class", "overPlane")
.attr("width", width)
.attr("height", height)
.attr("opacity", 0)
.on("mouseover", function() {
tips.style("display", null);
})
.on("mouseout", function() {
tips.style("display", "none");
})
.on("mousemove", function() {
var xdata = xScale.invert(d3.mouse(this)[0]);
var yIndex = bisect(data, xdata, 1, data.length - 1);
var d0 = data[yIndex - 1],
d1 = data[yIndex],
d = xdata - d0.date > d1.date - xdata ? d1 : d0;
tips.attr("transform", "translate(" + xScale(d.date) + "," + yScale(d.value) + ")");
tips.select("text").text(d.value);
});
线性的数值展示
.on("mousemove", function() {
var mouse = d3.mouse(this);
var begin = 0,
end = line[0].getTotalLength(),
target = null;
// 已知当前鼠标x轴坐标,求出对应的path上的坐标点
while(true) {
target = Math.floor((begin + end) / 2);
// getPointAtLength 返回给定路径上给定长度的点坐标
pos = line[0].getPointAtLength(target);
if((target === end || target === begin) && pos.x !== mouse[0]) {
break;
}
// 当返回的路径的x坐标和鼠标对应的x坐标重合 break;
if(pos.x > mouse[0]) end = target;
else if(pos.x < mouse[0]) begin = target;
else break;
}
tips.select("text").text(yScale.invert(pos.y).toFixed(2));
tips.attr("transform", "translate(" + mouse[0] + "," + pos.y + ")");
});