Blame | Letzte Änderung | Log anzeigen | RSS feed
/*** jqPlot* Pure JavaScript plotting plugin using jQuery** Version: 1.0.8* Revision: 1250** Copyright (c) 2009-2013 Chris Leonello* jqPlot is currently available for use in all personal or commercial projects* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can* choose the license that best suits your project and use it accordingly.** Although not required, the author would appreciate an email letting him* know of any substantial use of jqPlot. You can reach the author at:* chris at jqplot dot com or see http://www.jqplot.com/info.php .** If you are feeling kind and generous, consider supporting the project by* making a donation at: http://www.jqplot.com/donate.php .** sprintf functions contained in jqplot.sprintf.js by Ash Searle:** version 2007.04.27* author Ash Searle* http://hexmen.com/blog/2007/03/printf-sprintf/* http://hexmen.com/js/sprintf.js* The author (Ash Searle) has placed this code in the public domain:* "This code is unrestricted: you are free to use it however you like."**/(function($) {$.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]);/*** Class: $.jqplot.Highlighter* Plugin which will highlight data points when they are moused over.** To use this plugin, include the js* file in your source:** > <script type="text/javascript" src="plugins/jqplot.highlighter.js"></script>** A tooltip providing information about the data point is enabled by default.* To disable the tooltip, set "showTooltip" to false.** You can control what data is displayed in the tooltip with various* options. The "tooltipAxes" option controls whether the x, y or both* data values are displayed.** Some chart types (e.g. hi-low-close) have more than one y value per* data point. To display the additional values in the tooltip, set the* "yvalues" option to the desired number of y values present (3 for a hlc chart).** By default, data values will be formatted with the same formatting* specifiers as used to format the axis ticks. A custom format code* can be supplied with the tooltipFormatString option. This will apply* to all values in the tooltip.** For more complete control, the "formatString" option can be set. This* Allows conplete control over tooltip formatting. Values are passed to* the format string in an order determined by the "tooltipAxes" and "yvalues"* options. So, if you have a hi-low-close chart and you just want to display* the hi-low-close values in the tooltip, you could set a formatString like:** > highlighter: {* > tooltipAxes: 'y',* > yvalues: 3,* > formatString:'<table class="jqplot-highlighter">* > <tr><td>hi:</td><td>%s</td></tr>* > <tr><td>low:</td><td>%s</td></tr>* > <tr><td>close:</td><td>%s</td></tr></table>'* > }**/$.jqplot.Highlighter = function(options) {// Group: Properties////prop: show// true to show the highlight.this.show = $.jqplot.config.enablePlugins;// prop: markerRenderer// Renderer used to draw the marker of the highlighted point.// Renderer will assimilate attributes from the data point being highlighted,// so no attributes need set on the renderer directly.// Default is to turn off shadow drawing on the highlighted point.this.markerRenderer = new $.jqplot.MarkerRenderer({shadow:false});// prop: showMarker// true to show the markerthis.showMarker = true;// prop: lineWidthAdjust// Pixels to add to the lineWidth of the highlight.this.lineWidthAdjust = 2.5;// prop: sizeAdjust// Pixels to add to the overall size of the highlight.this.sizeAdjust = 5;// prop: showTooltip// Show a tooltip with data point values.this.showTooltip = true;// prop: tooltipLocation// Where to position tooltip, 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'this.tooltipLocation = 'nw';// prop: fadeTooltip// true = fade in/out tooltip, flase = show/hide tooltipthis.fadeTooltip = true;// prop: tooltipFadeSpeed// 'slow', 'def', 'fast', or number of milliseconds.this.tooltipFadeSpeed = "fast";// prop: tooltipOffset// Pixel offset of tooltip from the highlight.this.tooltipOffset = 2;// prop: tooltipAxes// Which axes to display in tooltip, 'x', 'y' or 'both', 'xy' or 'yx'// 'both' and 'xy' are equivalent, 'yx' reverses order of labels.this.tooltipAxes = 'both';// prop; tooltipSeparator// String to use to separate x and y axes in tooltip.this.tooltipSeparator = ', ';// prop; tooltipContentEditor// Function used to edit/augment/replace the formatted tooltip contents.// Called as str = tooltipContentEditor(str, seriesIndex, pointIndex)// where str is the generated tooltip html and seriesIndex and pointIndex identify// the data point being highlighted. Should return the html for the tooltip contents.this.tooltipContentEditor = null;// prop: useAxesFormatters// Use the x and y axes formatters to format the text in the tooltip.this.useAxesFormatters = true;// prop: tooltipFormatString// sprintf format string for the tooltip.// Uses Ash Searle's javascript sprintf implementation// found here: http://hexmen.com/blog/2007/03/printf-sprintf/// See http://perldoc.perl.org/functions/sprintf.html for reference.// Additional "p" and "P" format specifiers added by Chris Leonello.this.tooltipFormatString = '%.5P';// prop: formatString// alternative to tooltipFormatString// will format the whole tooltip text, populating with x, y values as// indicated by tooltipAxes option. So, you could have a tooltip like:// 'Date: %s, number of cats: %d' to format the whole tooltip at one go.// If useAxesFormatters is true, values will be formatted according to// Axes formatters and you can populate your tooltip string with// %s placeholders.this.formatString = null;// prop: yvalues// Number of y values to expect in the data point array.// Typically this is 1. Certain plots, like OHLC, will// have more y values in each data point array.this.yvalues = 1;// prop: bringSeriesToFront// This option requires jQuery 1.4+// True to bring the series of the highlighted point to the front// of other series.this.bringSeriesToFront = false;this._tooltipElem;this.isHighlighting = false;this.currentNeighbor = null;$.extend(true, this, options);};var locations = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];var locationIndicies = {'nw':0, 'n':1, 'ne':2, 'e':3, 'se':4, 's':5, 'sw':6, 'w':7};var oppositeLocations = ['se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e'];// axis.renderer.tickrenderer.formatter// called with scope of plot$.jqplot.Highlighter.init = function (target, data, opts){var options = opts || {};// add a highlighter attribute to the plotthis.plugins.highlighter = new $.jqplot.Highlighter(options.highlighter);};// called within scope of series$.jqplot.Highlighter.parseOptions = function (defaults, options) {// Add a showHighlight option to the series// and set it to true by default.this.showHighlight = true;};// called within context of plot// create a canvas which we can draw on.// insert it before the eventCanvas, so eventCanvas will still capture events.$.jqplot.Highlighter.postPlotDraw = function() {// Memory Leaks patchif (this.plugins.highlighter && this.plugins.highlighter.highlightCanvas) {this.plugins.highlighter.highlightCanvas.resetCanvas();this.plugins.highlighter.highlightCanvas = null;}if (this.plugins.highlighter && this.plugins.highlighter._tooltipElem) {this.plugins.highlighter._tooltipElem.emptyForce();this.plugins.highlighter._tooltipElem = null;}this.plugins.highlighter.highlightCanvas = new $.jqplot.GenericCanvas();this.eventCanvas._elem.before(this.plugins.highlighter.highlightCanvas.createElement(this._gridPadding, 'jqplot-highlight-canvas', this._plotDimensions, this));this.plugins.highlighter.highlightCanvas.setContext();var elem = document.createElement('div');this.plugins.highlighter._tooltipElem = $(elem);elem = null;this.plugins.highlighter._tooltipElem.addClass('jqplot-highlighter-tooltip');this.plugins.highlighter._tooltipElem.css({position:'absolute', display:'none'});this.eventCanvas._elem.before(this.plugins.highlighter._tooltipElem);};$.jqplot.preInitHooks.push($.jqplot.Highlighter.init);$.jqplot.preParseSeriesOptionsHooks.push($.jqplot.Highlighter.parseOptions);$.jqplot.postDrawHooks.push($.jqplot.Highlighter.postPlotDraw);function draw(plot, neighbor) {var hl = plot.plugins.highlighter;var s = plot.series[neighbor.seriesIndex];var smr = s.markerRenderer;var mr = hl.markerRenderer;mr.style = smr.style;mr.lineWidth = smr.lineWidth + hl.lineWidthAdjust;mr.size = smr.size + hl.sizeAdjust;var rgba = $.jqplot.getColorComponents(smr.color);var newrgb = [rgba[0], rgba[1], rgba[2]];var alpha = (rgba[3] >= 0.6) ? rgba[3]*0.6 : rgba[3]*(2-rgba[3]);mr.color = 'rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+alpha+')';mr.init();mr.draw(s.gridData[neighbor.pointIndex][0], s.gridData[neighbor.pointIndex][1], hl.highlightCanvas._ctx);}function showTooltip(plot, series, neighbor) {// neighbor looks like: {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}// gridData should be x,y pixel coords on the grid.// add the plot._gridPadding to that to get x,y in the target.var hl = plot.plugins.highlighter;var elem = hl._tooltipElem;var serieshl = series.highlighter || {};var opts = $.extend(true, {}, hl, serieshl);if (opts.useAxesFormatters) {var xf = series._xaxis._ticks[0].formatter;var yf = series._yaxis._ticks[0].formatter;var xfstr = series._xaxis._ticks[0].formatString;var yfstr = series._yaxis._ticks[0].formatString;var str;var xstr = xf(xfstr, neighbor.data[0]);var ystrs = [];for (var i=1; i<opts.yvalues+1; i++) {ystrs.push(yf(yfstr, neighbor.data[i]));}if (typeof opts.formatString === 'string') {switch (opts.tooltipAxes) {case 'both':case 'xy':ystrs.unshift(xstr);ystrs.unshift(opts.formatString);str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);break;case 'yx':ystrs.push(xstr);ystrs.unshift(opts.formatString);str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);break;case 'x':str = $.jqplot.sprintf.apply($.jqplot.sprintf, [opts.formatString, xstr]);break;case 'y':ystrs.unshift(opts.formatString);str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);break;default: // same as xyystrs.unshift(xstr);ystrs.unshift(opts.formatString);str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);break;}}else {switch (opts.tooltipAxes) {case 'both':case 'xy':str = xstr;for (var i=0; i<ystrs.length; i++) {str += opts.tooltipSeparator + ystrs[i];}break;case 'yx':str = '';for (var i=0; i<ystrs.length; i++) {str += ystrs[i] + opts.tooltipSeparator;}str += xstr;break;case 'x':str = xstr;break;case 'y':str = ystrs.join(opts.tooltipSeparator);break;default: // same as 'xy'str = xstr;for (var i=0; i<ystrs.length; i++) {str += opts.tooltipSeparator + ystrs[i];}break;}}}else {var str;if (typeof opts.formatString === 'string') {str = $.jqplot.sprintf.apply($.jqplot.sprintf, [opts.formatString].concat(neighbor.data));}else {if (opts.tooltipAxes == 'both' || opts.tooltipAxes == 'xy') {str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]) + opts.tooltipSeparator + $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]);}else if (opts.tooltipAxes == 'yx') {str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]) + opts.tooltipSeparator + $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]);}else if (opts.tooltipAxes == 'x') {str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]);}else if (opts.tooltipAxes == 'y') {str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]);}}}if ($.isFunction(opts.tooltipContentEditor)) {// args str, seriesIndex, pointIndex are essential so the hook can look up// extra data for the point.str = opts.tooltipContentEditor(str, neighbor.seriesIndex, neighbor.pointIndex, plot);}elem.html(str);var gridpos = {x:neighbor.gridData[0], y:neighbor.gridData[1]};var ms = 0;var fact = 0.707;if (series.markerRenderer.show == true) {ms = (series.markerRenderer.size + opts.sizeAdjust)/2;}var loc = locations;if (series.fillToZero && series.fill && neighbor.data[1] < 0) {loc = oppositeLocations;}switch (loc[locationIndicies[opts.tooltipLocation]]) {case 'nw':var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;break;case 'n':var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - ms;break;case 'ne':var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + fact * ms;var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;break;case 'e':var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + ms;var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;break;case 'se':var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + fact * ms;var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + fact * ms;break;case 's':var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + ms;break;case 'sw':var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + fact * ms;break;case 'w':var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - ms;var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;break;default: // same as 'nw'var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;break;}elem.css('left', x);elem.css('top', y);if (opts.fadeTooltip) {// Fix for stacked up animations. Thnanks Trevor!elem.stop(true,true).fadeIn(opts.tooltipFadeSpeed);}else {elem.show();}elem = null;}function handleMove(ev, gridpos, datapos, neighbor, plot) {var hl = plot.plugins.highlighter;var c = plot.plugins.cursor;if (hl.show) {if (neighbor == null && hl.isHighlighting) {var evt = jQuery.Event('jqplotHighlighterUnhighlight');plot.target.trigger(evt);var ctx = hl.highlightCanvas._ctx;ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);if (hl.fadeTooltip) {hl._tooltipElem.fadeOut(hl.tooltipFadeSpeed);}else {hl._tooltipElem.hide();}if (hl.bringSeriesToFront) {plot.restorePreviousSeriesOrder();}hl.isHighlighting = false;hl.currentNeighbor = null;ctx = null;}else if (neighbor != null && plot.series[neighbor.seriesIndex].showHighlight && !hl.isHighlighting) {var evt = jQuery.Event('jqplotHighlighterHighlight');evt.which = ev.which;evt.pageX = ev.pageX;evt.pageY = ev.pageY;var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data, plot];plot.target.trigger(evt, ins);hl.isHighlighting = true;hl.currentNeighbor = neighbor;if (hl.showMarker) {draw(plot, neighbor);}if (plot.series[neighbor.seriesIndex].show && hl.showTooltip && (!c || !c._zoom.started)) {showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor);}if (hl.bringSeriesToFront) {plot.moveSeriesToFront(neighbor.seriesIndex);}}// check to see if we're highlighting the wrong point.else if (neighbor != null && hl.isHighlighting && hl.currentNeighbor != neighbor) {// highlighting the wrong point.// if new series allows highlighting, highlight new point.if (plot.series[neighbor.seriesIndex].showHighlight) {var ctx = hl.highlightCanvas._ctx;ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);hl.isHighlighting = true;hl.currentNeighbor = neighbor;if (hl.showMarker) {draw(plot, neighbor);}if (plot.series[neighbor.seriesIndex].show && hl.showTooltip && (!c || !c._zoom.started)) {showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor);}if (hl.bringSeriesToFront) {plot.moveSeriesToFront(neighbor.seriesIndex);}}}}}})(jQuery);