本篇簡單介紹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 + ")");
});