我现在已经画出了带坐标的曲线图,数据是后台加载来的 现在想要实现一个功能就是鼠标画上的时候可以有一条跟随鼠标的十字线,分别从x和y轴拉过来,并且显示当前的xy坐标,并在一个方框内显示当前点的其他描述内容。类似这样的。
效果图:
代码:
D3.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>D3</title> <link rel="stylesheet" href="css/D3.css"> </head> <body> <div id="container"> <div id="dialog"></div> </div> <script src="http://d3js.org/d3.v3.js"></script> <script src="js/D3_line_point.js"></script> </body> </html>
D3.css
body { font: 10px sans-serif; } path { fill: none; stroke: #4682B4; stroke-width: 2; } .domain, .tick line { stroke: gray; stroke-width: 1; } .circle { fill: white; stroke: steelblue; stroke-width: 2px; } .area { fill: steelblue; stroke: none; opacity: 0.1; } .zeroline { fill: none; stroke: red; stroke-width: 0.5px; stroke-dasharray: 5 5; } .zerolinetext { fill: red; } .overlay { fill: none; stroke: none; pointer-events: all; } .focusLine { fill: none; stroke: steelblue; stroke-width: 0.5px; } .focusCircle { fill: red; } #dialog{ width: 160px; height: 60px; background-color: #4682B4; position: fixed; top:50px; left:600px; opacity: 0; line-height: 20px; }
D3_line_point.js
var data = []; var currentValue = 100; var random = d3.random.normal(0, 20.0); for (var i = 0; i < 100; i++) { var currentDate = new Date(); currentDate.setDate(currentDate.getDate() + i); data.push([currentDate, currentValue]); currentValue = currentValue + random(); } var drawLineGraph = function(containerHeight, containerWidth, data, yLabel, warnLine) { var svg = d3.select("body").append("svg") .attr("width", containerWidth) .attr("height", containerHeight); var margin = { top: 50, left: 50, right: 50, bottom: 50 }; var height = containerHeight - margin.top - margin.bottom; var width = containerWidth - margin.left - margin.right; var xDomain = d3.extent(data, function(d) { return d[0]; }) var yDomain = d3.extent(data, function(d) { return d[1]; }); var xScale = d3.time.scale().range([0, width]).domain(xDomain); var yScale = d3.scale.linear().range([height, 0]).domain(yDomain); var xAxis = d3.svg.axis().scale(xScale).orient('bottom'); var yAxis = d3.svg.axis().scale(yScale).orient('left'); var line = d3.svg.line() .x(function(d) { return xScale(d[0]); }) .y(function(d) { return yScale(d[1]); }); var area = d3.svg.area() .x(function(d) { return xScale(d[0]); }) .y0(function(d) { return yScale(d[1]); }) .y1(height); var g = svg.append('g').attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')'); g.append('path') .datum(data) .attr('class', 'area') .attr('d', area); g.append('g') .attr('class', 'x axis') .attr('transform', 'translate(0, ' + height + ')') .call(xAxis); g.append('g') .attr('class', 'y axis') .call(yAxis) .append('text') .attr('transform', 'rotate(-90)') .attr('y', 6) .attr('dy', '.71em') .attr('text-anchor', 'end') .text(yLabel); g.append('path') .datum(data) .attr('class', 'line') .attr('d', line); g.selectAll('circle').data(data).enter().append('circle') .attr('cx', function(d) { return xScale(d[0]); }) .attr('cy', function(d) { return yScale(d[1]); }) .attr('r', 3) .attr('class', 'circle'); // focus tracking var focus = g.append('g').style('display', 'none'); focus.append('line') .attr('id', 'focusLineX') .attr('class', 'focusLine'); focus.append('line') .attr('id', 'focusLineY') .attr('class', 'focusLine'); focus.append('circle') .attr('id', 'focusCircle') .attr('r', 5) .attr('class', 'circle focusCircle'); var bisectDate = d3.bisector(function(d) { return d[0]; }).left; g.append('rect') .attr('class', 'overlay') .attr('width', width) .attr('height', height) .on('mouseover', function() { focus.style('display', null); d3.select('#dialog') .style('opacity',0); }) .on('mouseout', function() { focus.style('display', 'none'); d3.select('#dialog') .style('opacity',0); }) .on('mousemove', function() { var mouse = d3.mouse(this); var mouseDate = xScale.invert(mouse[0]); var i = bisectDate(data, mouseDate); // returns the index to the current data item var d0 = data[i - 1] var d1 = data[i]; // work out which date value is closest to the mouse var d = mouseDate - d0[0] > d1[0] - mouseDate ? d1 : d0; var x = xScale(d[0]); var y = yScale(d[1]); focus.select('#focusCircle') .attr('cx', x) .attr('cy', y); focus.select('#focusLineX') .attr('x1', x).attr('y1', yScale(yDomain[0])) .attr('x2', x).attr('y2', yScale(yDomain[1])); focus.select('#focusLineY') .attr('x1', xScale(xDomain[0])).attr('y1', y) .attr('x2', xScale(xDomain[1])).attr('y2', y); d3.select('#dialog') //.attr('transform', 'translate(' + x + ',' + y + ')') //.attr('text-anchor', 'middle') .style('opacity','0.7') .text(d[0]+' '+d[1]); }); // warn line if (warnLine && yDomain[0] < warnLine.lineValue && yDomain[1] > warnLine.lineValue) { g.append('line') .attr('x1', xScale(xDomain[0])) .attr('y1', yScale(warnLine.lineValue)) .attr('x2', xScale(xDomain[1])) .attr('y2', yScale(warnLine.lineValue)) .attr('class', 'zeroline'); g.append('text') .attr('x', xScale(xDomain[1])) .attr('y', yScale(warnLine.lineValue)) .attr('dy', '1em') .attr('text-anchor', 'end') .text(warnLine.label) .attr('class', 'zerolinetext'); } }; drawLineGraph(400, 800, data, "Intensity", { lineValue: 200, label: "OMG!" });