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 + ")");

				});

原文地址:https://www.cnblogs.com/chenjy1225/p/11368632.html