jquery.flot.crosshair.js revision 4a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724
14a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair/* Flot plugin for showing crosshairs when the mouse hovers over the plot. 24a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 34a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan SinclairCopyright (c) 2007-2014 IOLA and Ole Laursen. 44a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan SinclairLicensed under the MIT license. 54a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 64a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan SinclairThe plugin supports these options: 74a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 84a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair crosshair: { 94a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair mode: null or "x" or "y" or "xy" 104a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair color: color 114a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair lineWidth: number 124a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair } 134a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 144a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan SinclairSet the mode to one of "x", "y" or "xy". The "x" mode enables a vertical 154a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclaircrosshair that lets you trace the values on the x axis, "y" enables a 164a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclairhorizontal crosshair and "xy" enables them both. "color" is the color of the 174a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclaircrosshair (default is "rgba(170, 0, 0, 0.80)"), "lineWidth" is the width of 184a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclairthe drawn lines (default is 1). 194a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 204a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan SinclairThe plugin also adds four public methods: 214a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 224a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair - setCrosshair( pos ) 234a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 244a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair Set the position of the crosshair. Note that this is cleared if the user 254a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair moves the mouse. "pos" is in coordinates of the plot and should be on the 264a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair form { x: xpos, y: ypos } (you can use x2/x3/... if you're using multiple 274a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair axes), which is coincidentally the same format as what you get from a 284a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair "plothover" event. If "pos" is null, the crosshair is cleared. 294a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 304a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair - clearCrosshair() 314a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 324a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair Clear the crosshair. 334a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 344a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair - lockCrosshair(pos) 354a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 364a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair Cause the crosshair to lock to the current location, no longer updating if 374a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair the user moves the mouse. Optionally supply a position (passed on to 384a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair setCrosshair()) to move it to. 394a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 404a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair Example usage: 414a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 424a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair var myFlot = $.plot( $("#graph"), ..., { crosshair: { mode: "x" } } }; 434a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair $("#graph").bind( "plothover", function ( evt, position, item ) { 444a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair if ( item ) { 454a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair // Lock the crosshair to the data point being hovered 464a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair myFlot.lockCrosshair({ 474a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair x: item.datapoint[ 0 ], 484a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair y: item.datapoint[ 1 ] 494a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair }); 504a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair } else { 514a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair // Return normal crosshair operation 524a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair myFlot.unlockCrosshair(); 534a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair } 544a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair }); 554a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 564a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair - unlockCrosshair() 574a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 584a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair Free the crosshair to move again after locking it. 594a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair*/ 604a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 614a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair(function ($) { 624a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair var options = { 634a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair crosshair: { 644a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair mode: null, // one of null, "x", "y" or "xy", 654a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair color: "rgba(170, 0, 0, 0.80)", 664a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair lineWidth: 1 674a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair } 684a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair }; 694a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 704a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair function init(plot) { 714a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair // position of crosshair in pixels 724a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair var crosshair = { x: -1, y: -1, locked: false }; 734a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 744a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair plot.setCrosshair = function setCrosshair(pos) { 754a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair if (!pos) 764a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair crosshair.x = -1; 774a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair else { 784a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair var o = plot.p2c(pos); 794a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair crosshair.x = Math.max(0, Math.min(o.left, plot.width())); 804a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair crosshair.y = Math.max(0, Math.min(o.top, plot.height())); 814a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair } 824a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 834a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair plot.triggerRedrawOverlay(); 844a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair }; 854a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 864a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair plot.clearCrosshair = plot.setCrosshair; // passes null for pos 874a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 884a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair plot.lockCrosshair = function lockCrosshair(pos) { 894a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair if (pos) 904a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair plot.setCrosshair(pos); 914a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair crosshair.locked = true; 924a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair }; 934a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 944a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair plot.unlockCrosshair = function unlockCrosshair() { 954a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair crosshair.locked = false; 964a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair }; 974a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 984a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair function onMouseOut(e) { 994a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair if (crosshair.locked) 1004a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair return; 1014a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 1024a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair if (crosshair.x != -1) { 1034a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair crosshair.x = -1; 1044a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair plot.triggerRedrawOverlay(); 1054a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair } 1064a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair } 1074a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 1084a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair function onMouseMove(e) { 1094a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair if (crosshair.locked) 1104a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair return; 1114a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 1124a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair if (plot.getSelection && plot.getSelection()) { 1134a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair crosshair.x = -1; // hide the crosshair while selecting 1144a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair return; 1154a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair } 1164a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 1174a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair var offset = plot.offset(); 1184a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width())); 1194a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height())); 1204a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair plot.triggerRedrawOverlay(); 1214a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair } 1224a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 1234a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair plot.hooks.bindEvents.push(function (plot, eventHolder) { 1244a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair if (!plot.getOptions().crosshair.mode) 1254a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair return; 1264a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 1274a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair eventHolder.mouseout(onMouseOut); 1284a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair eventHolder.mousemove(onMouseMove); 1294a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair }); 1304a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 1314a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair plot.hooks.drawOverlay.push(function (plot, ctx) { 1324a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair var c = plot.getOptions().crosshair; 1334a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair if (!c.mode) 1344a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair return; 1354a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 1364a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair var plotOffset = plot.getPlotOffset(); 1374a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 1384a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair ctx.save(); 1394a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair ctx.translate(plotOffset.left, plotOffset.top); 1404a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 1414a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair if (crosshair.x != -1) { 1424a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair var adj = plot.getOptions().crosshair.lineWidth % 2 ? 0.5 : 0; 1434a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 1444a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair ctx.strokeStyle = c.color; 1454a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair ctx.lineWidth = c.lineWidth; 1464a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair ctx.lineJoin = "round"; 1474a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 1484a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair ctx.beginPath(); 1494a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair if (c.mode.indexOf("x") != -1) { 1504a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair var drawX = Math.floor(crosshair.x) + adj; 1514a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair ctx.moveTo(drawX, 0); 1524a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair ctx.lineTo(drawX, plot.height()); 1534a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair } 1544a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair if (c.mode.indexOf("y") != -1) { 1554a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair var drawY = Math.floor(crosshair.y) + adj; 1564a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair ctx.moveTo(0, drawY); 1574a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair ctx.lineTo(plot.width(), drawY); 1584a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair } 1594a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair ctx.stroke(); 1604a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair } 1614a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair ctx.restore(); 1624a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair }); 1634a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 1644a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair plot.hooks.shutdown.push(function (plot, eventHolder) { 1654a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair eventHolder.unbind("mouseout", onMouseOut); 1664a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair eventHolder.unbind("mousemove", onMouseMove); 1674a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair }); 1684a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair } 1694a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair 1704a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair $.plot.plugins.push({ 1714a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair init: init, 1724a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair options: options, 1734a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair name: 'crosshair', 1744a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair version: '1.0' 1754a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair }); 1764a4f2fe02baf385f6c24fc98c6e17bf6ac5e0724Dan Sinclair})(jQuery); 177