如何在图形的hover转折点上显示Y轴值

我正在使用java脚本和canvas制作图表。 下面是jsfiddle链接

http://jsfiddle.net/ghan_123/n0r796ae/

我想在hover泡沫(转折点)上显示值

1月8日价格2100

java脚本

var CanvasChart = function () { var ctx; var margin = { top: 40, left: 75, right: 0, bottom: 75 }; var chartHeight, chartWidth, yMax, xMax, data; var maxYValue = 0; var ratio = 0; var renderType = { lines: 'lines', points: 'points' }; var render = function(canvasId, dataObj) { data = dataObj; getMaxDataYValue(); var canvas = document.getElementById(canvasId); chartHeight = canvas.getAttribute('height'); chartWidth = canvas.getAttribute('width'); xMax = chartWidth - (margin.left + margin.right); yMax = chartHeight - (margin.top + margin.bottom); ratio = yMax / maxYValue; ctx = canvas.getContext("2d"); renderChart(); }; var renderChart = function () { renderBackground(); renderText(); renderLinesAndLabels(); //render data based upon type of renderType(s) that client supplies if (data.renderTypes == undefined || data.renderTypes == null) data.renderTypes = [renderType.lines]; for (var i = 0; i < data.renderTypes.length; i++) { renderData(data.renderTypes[i]); } }; var getMaxDataYValue = function () { for (var i = 0; i  maxYValue) maxYValue = data.dataPoints[i].y; } }; var renderBackground = function() { var lingrad = ctx.createLinearGradient(margin.left, margin.top, xMax - margin.right, yMax); lingrad.addColorStop(0.0, '#ffffff'); lingrad.addColorStop(0.2, '#fff'); lingrad.addColorStop(0.8, '#fff'); lingrad.addColorStop(1, '#ffffff'); ctx.fillStyle = lingrad; ctx.fillRect(margin.left, margin.top, xMax - margin.left, yMax - margin.top); ctx.fillStyle = '#6A6A6A'; }; var renderText = function() { var labelFont = (data.labelFont != null) ? data.labelFont : '20pt Arial'; ctx.font = labelFont; ctx.textAlign = "center"; //Title var txtSize = ctx.measureText(data.title); ctx.fillText(data.title, (chartWidth / 2), (margin.top / 2)); //X-axis text txtSize = ctx.measureText(data.xLabel); ctx.fillText(data.xLabel, margin.left + (xMax / 2) - (txtSize.width / 2), yMax + (margin.bottom / 1.2)); //Y-axis text ctx.save(); ctx.rotate(-Math.PI / 2); ctx.font = labelFont; ctx.fillText(data.yLabel, (yMax / 2) * -1, margin.left / 4); ctx.restore(); }; var renderLinesAndLabels = function () { //Vertical guide lines var yInc = yMax / data.dataPoints.length; var yPos = 0; var yLabelInc = (maxYValue * ratio) / data.dataPoints.length; var xInc = getXInc(); var xPos = margin.left; for (var i = 0; i = 14) ? txtSize.width : 10) - 7, yPos + 4); //x axis labels txt = data.dataPoints[i].x; txtSize = ctx.measureText(txt); ctx.fillText(txt, xPos, yMax + (margin.bottom / 3)); xPos += xInc; } //Vertical line drawLine(margin.left, margin.top, margin.left, yMax, 'black'); //Horizontal Line drawLine(margin.left, yMax, xMax, yMax, 'black'); }; var renderData = function(type) { var xInc = getXInc(); var prevX = 0, prevY = 0; for (var i = 0; i < data.dataPoints.length; i++) { var pt = data.dataPoints[i]; var ptY = (maxYValue - pt.y) * ratio; if (ptY  0 && type == renderType.lines) { //Draw connecting lines drawLine(ptX, ptY, prevX, prevY, '#309FB2', 2); } if (type == renderType.points) { var radgrad = ctx.createRadialGradient(ptX, ptY, 8, ptX - 5, ptY - 5, 0); radgrad.addColorStop(0, '#309FB2'); radgrad.addColorStop(0.9, 'White'); ctx.beginPath(); ctx.fillStyle = radgrad; //Render circle ctx.arc(ptX, ptY, 8, 0, 2 * Math.PI, false) ctx.fill(); ctx.lineWidth = 1; ctx.strokeStyle = '#000'; ctx.stroke(); ctx.closePath(); } prevX = ptX; prevY = ptY; } }; var getXInc = function() { return Math.round(xMax / data.dataPoints.length) - 1; }; var drawLine = function(startX, startY, endX, endY, strokeStyle, lineWidth) { if (strokeStyle != null) ctx.strokeStyle = strokeStyle; if (lineWidth != null) ctx.lineWidth = lineWidth; ctx.beginPath(); ctx.moveTo(startX, startY); ctx.lineTo(endX, endY); ctx.stroke(); ctx.closePath(); }; return { renderType: renderType, render: render }; } (); $(document).ready(function () { var dataDef = { title: "US Population Chart", xLabel: 'Date', yLabel: 'Price', labelFont: '19pt Arial', dataPointFont: '10pt Arial', renderTypes: [CanvasChart.renderType.lines, CanvasChart.renderType.points], dataPoints: [{ x: '1-aug', y: 2100 }, { x: '2-aug', y: 2000 }, { x: '3-aug', y: 2200 }, { x: '4-aug', y: 1800 }, { x: '5-aug', y: 1500 }, { x: '6-aug', y: 3000 }, ] }; CanvasChart.render('canvas', dataDef); }); 

HTML部分

   

这是使用普通旧DIV作为工具提示的简单方法。

在此处输入图像描述

  • 创建一个div作为工具提示(tooltip-div)。
  • 最初隐藏tooltip-div。
  • 听取mousemove事件。
  • 在mousemove处理程序中,如果鼠标位于任何数据点内,则进行命中测试。
  • 如果鼠标位于数据点内,

    1. 在tooltip-div中设置所需的文本,
    2. 使用CSS在数据点上移动tooltip-div,
    3. 显示tooltip-div。

这是带注释的代码和演示:

 var CanvasChart = function () { var ctx; var margin = { top: 40, left: 75, right: 0, bottom: 75 }; var chartHeight, chartWidth, yMax, xMax, data; var maxYValue = 0; var ratio = 0; var renderType = { lines: 'lines', points: 'points' }; // addition var dataXY=[]; var render = function(canvasId, dataObj) { data = dataObj; getMaxDataYValue(); var canvas = document.getElementById(canvasId); chartHeight = canvas.getAttribute('height'); chartWidth = canvas.getAttribute('width'); xMax = chartWidth - (margin.left + margin.right); yMax = chartHeight - (margin.top + margin.bottom); ratio = yMax / maxYValue; ctx = canvas.getContext("2d"); renderChart(); }; var renderChart = function () { renderBackground(); renderText(); renderLinesAndLabels(); //render data based upon type of renderType(s) that client supplies if (data.renderTypes == undefined || data.renderTypes == null) data.renderTypes = [renderType.lines]; for (var i = 0; i < data.renderTypes.length; i++) { renderData(data.renderTypes[i]); } }; var getMaxDataYValue = function () { for (var i = 0; i < data.dataPoints.length; i++) { if (data.dataPoints[i].y > maxYValue) maxYValue = data.dataPoints[i].y; } }; var renderBackground = function() { var lingrad = ctx.createLinearGradient(margin.left, margin.top, xMax - margin.right, yMax); lingrad.addColorStop(0.0, '#ffffff'); lingrad.addColorStop(0.2, '#fff'); lingrad.addColorStop(0.8, '#fff'); lingrad.addColorStop(1, '#ffffff'); ctx.fillStyle = lingrad; ctx.fillRect(margin.left, margin.top, xMax - margin.left, yMax - margin.top); ctx.fillStyle = '#6A6A6A'; }; var renderText = function() { var labelFont = (data.labelFont != null) ? data.labelFont : '20pt Arial'; ctx.font = labelFont; ctx.textAlign = "center"; //Title var txtSize = ctx.measureText(data.title); ctx.fillText(data.title, (chartWidth / 2), (margin.top / 2)); //X-axis text txtSize = ctx.measureText(data.xLabel); ctx.fillText(data.xLabel, margin.left + (xMax / 2) - (txtSize.width / 2), yMax + (margin.bottom / 1.2)); //Y-axis text ctx.save(); ctx.rotate(-Math.PI / 2); ctx.font = labelFont; ctx.fillText(data.yLabel, (yMax / 2) * -1, margin.left / 4); ctx.restore(); }; var renderLinesAndLabels = function () { //Vertical guide lines var yInc = yMax / data.dataPoints.length; var yPos = 0; var yLabelInc = (maxYValue * ratio) / data.dataPoints.length; var xInc = getXInc(); var xPos = margin.left; for (var i = 0; i < data.dataPoints.length; i++) { yPos += (i == 0) ? margin.top : yInc; //Draw horizontal lines drawLine(margin.left, yPos, xMax, yPos, '#E8E8E8'); //y axis labels ctx.font = (data.dataPointFont != null) ? data.dataPointFont : '10pt Calibri'; var txt = Math.round(maxYValue - ((i == 0) ? 0 : yPos / ratio)); var txtSize = ctx.measureText(txt); ctx.fillText(txt, margin.left - ((txtSize.width >= 14) ? txtSize.width : 10) - 7, yPos + 4); //x axis labels txt = data.dataPoints[i].x; txtSize = ctx.measureText(txt); ctx.fillText(txt, xPos, yMax + (margin.bottom / 3)); xPos += xInc; } //Vertical line drawLine(margin.left, margin.top, margin.left, yMax, 'black'); //Horizontal Line drawLine(margin.left, yMax, xMax, yMax, 'black'); }; var renderData = function(type) { var xInc = getXInc(); var prevX = 0, prevY = 0; // addition dataXY.length=0; for (var i = 0; i < data.dataPoints.length; i++) { var pt = data.dataPoints[i]; var ptY = (maxYValue - pt.y) * ratio; if (ptY < margin.top) ptY = margin.top; var ptX = (i * xInc) + margin.left; if (i > 0 && type == renderType.lines) { //Draw connecting lines drawLine(ptX, ptY, prevX, prevY, '#309FB2', 2); } if (type == renderType.points) { var radgrad = ctx.createRadialGradient(ptX, ptY, 8, ptX - 5, ptY - 5, 0); radgrad.addColorStop(0, '#309FB2'); radgrad.addColorStop(0.9, 'White'); ctx.beginPath(); ctx.fillStyle = radgrad; //Render circle ctx.arc(ptX, ptY, 8, 0, 2 * Math.PI, false) ctx.fill(); ctx.lineWidth = 1; ctx.strokeStyle = '#000'; ctx.stroke(); ctx.closePath(); // addition dataXY.push({cx:ptX,cy:ptY,r:8,tipText:'Price='+pt.y+' on '+pt.x}); } prevX = ptX; prevY = ptY; } }; var getXInc = function() { return Math.round(xMax / data.dataPoints.length) - 1; }; var drawLine = function(startX, startY, endX, endY, strokeStyle, lineWidth) { if (strokeStyle != null) ctx.strokeStyle = strokeStyle; if (lineWidth != null) ctx.lineWidth = lineWidth; ctx.beginPath(); ctx.moveTo(startX, startY); ctx.lineTo(endX, endY); ctx.stroke(); ctx.closePath(); }; return { renderType: renderType, render: render, // added comma // addition dataXY: dataXY }; } (); // // end CanvasChart ///////////////////////////// // addition var CanvasTooltip=(function(){ // ctor function CanvasTooltip(canvasId,targets){ var that=this; this.$canvas=$("#"+canvasId); this.targets=targets; this.openTooltipIndex=-1; // add tip elements this.init(); this.$tip=$('#canvasTip').hide(); // eventing this.offsetX,this.offsetY; this.reOffset(); this.$canvas.on('mousemove',function(e){ that.handleMouseMove(e); }); $(window).on('scroll',function(e){ that.reOffset(); }); } CanvasTooltip.prototype.reOffset=function(){ var BB=this.$canvas[0].getBoundingClientRect(); this.offsetX=BB.left; this.offsetY=BB.top; }; CanvasTooltip.prototype.init=function(){ this.$canvas.wrap('
'); $('#canvasTipWrapper').css({'position':'relative'}); $('
') .css({ 'position':'absolute', 'border':'1px solid gray', 'border-left-width':'7px', 'border-left-color':'maroon', 'margin-bottom':'20px', 'background':'rgba(255,255,255,1.00)', 'padding-left':'5px', 'padding-right':'5px', 'max-width':'150px' }) .appendTo('#canvasTipWrapper'); }; CanvasTooltip.prototype.handleMouseMove =function(e){ e.preventDefault(); e.stopPropagation(); var mouseX=parseInt(e.clientX-this.offsetX); var mouseY=parseInt(e.clientY-this.offsetY); // hit-test each target var hit=-1; for(var i=0;i
 body{ background-color: ivory; } #canvas{border:1px solid red; margin:0 auto; }