[9335] | 1 | (function($) { |
---|
| 2 | /** |
---|
| 3 | * Class: $.jqplot.BoxplotRenderer |
---|
| 4 | * jqPlot Plugin to draw box plots <http://en.wikipedia.org/wiki/Box_plot>. |
---|
| 5 | * |
---|
| 6 | * To use this plugin, include the renderer js file in |
---|
| 7 | * your source: |
---|
| 8 | * |
---|
| 9 | * > <script type="text/javascript" src="plugins/jqplot.boxplotRenderer.js"></script> |
---|
| 10 | * |
---|
| 11 | * Then you set the renderer in the series options on your plot: |
---|
| 12 | * |
---|
| 13 | * > series: [{renderer:$.jqplot.BoxplotRenderer}] |
---|
| 14 | * |
---|
| 15 | * Data should be specified like so: |
---|
| 16 | * |
---|
| 17 | * > dat = [[sample_id, min, q1, median, q3, max], ...] |
---|
| 18 | * |
---|
| 19 | */ |
---|
| 20 | $.jqplot.BoxplotRenderer = function(){ |
---|
| 21 | // subclass line renderer to make use of some of its methods. |
---|
| 22 | $.jqplot.LineRenderer.call(this); |
---|
| 23 | // prop: boxWidth |
---|
| 24 | // Default will auto calculate based on plot width and number |
---|
| 25 | // of boxes displayed. |
---|
| 26 | this.boxWidth = 'auto'; |
---|
| 27 | this._boxMaxWidth = 100; // if 'auto', cap at this max |
---|
| 28 | // prop: lineWidth |
---|
| 29 | // The thickness of all lines drawn. Default is 1.5 pixels. |
---|
| 30 | this.lineWidth = 1.5; |
---|
| 31 | }; |
---|
| 32 | |
---|
| 33 | $.jqplot.BoxplotRenderer.prototype = new $.jqplot.LineRenderer(); |
---|
| 34 | $.jqplot.BoxplotRenderer.prototype.constructor = $.jqplot.BoxplotRenderer; |
---|
| 35 | |
---|
| 36 | // called with scope of series. |
---|
| 37 | $.jqplot.BoxplotRenderer.prototype.init = function(options) { |
---|
| 38 | this.lineWidth = options.lineWidth || this.renderer.lineWidth; |
---|
| 39 | $.jqplot.LineRenderer.prototype.init.call(this, options); |
---|
| 40 | // set the yaxis data bounds here to account for high and low values |
---|
| 41 | var db = this._yaxis._dataBounds; |
---|
| 42 | var d = this._plotData; |
---|
| 43 | for (var j=0, dj=d[j]; j<d.length; dj=d[++j]) { |
---|
| 44 | if (dj[1] < db.min || db.min == null) |
---|
| 45 | db.min = dj[1]; |
---|
| 46 | if (dj[5] > db.max || db.max == null) |
---|
| 47 | db.max = dj[5]; |
---|
| 48 | } |
---|
| 49 | }; |
---|
| 50 | |
---|
| 51 | // called within scope of series. |
---|
| 52 | $.jqplot.BoxplotRenderer.prototype.draw = function(ctx, gd, options) { |
---|
| 53 | var d = this.data; |
---|
| 54 | var r = this.renderer; |
---|
| 55 | var xp = this._xaxis.series_u2p; |
---|
| 56 | var yp = this._yaxis.series_u2p; |
---|
| 57 | if (!options) |
---|
| 58 | options = {}; |
---|
| 59 | if (!('lineWidth' in options)) |
---|
| 60 | $.extend(true, options, {lineWidth: this.lineWidth}); |
---|
| 61 | var boxopts = $.extend(true, {}, options, {strokeRect: true}); |
---|
| 62 | var boxW = options.boxWidth || r.boxWidth; |
---|
| 63 | if (boxW == 'auto') |
---|
| 64 | boxW = Math.min(r._boxMaxWidth, 0.6 * ctx.canvas.width/d.length); |
---|
| 65 | var endW = boxW / 2; // min and max ticks are half the box width |
---|
| 66 | boxW -= this.lineWidth*2; |
---|
| 67 | ctx.save(); |
---|
| 68 | if (this.show) { |
---|
| 69 | for (var i=0, di=d[i]; i<d.length; di=d[++i]) { |
---|
| 70 | var x = xp(di[0]), |
---|
| 71 | min = yp(di[1]), |
---|
| 72 | q1 = yp(di[2]), |
---|
| 73 | med = yp(di[3]), |
---|
| 74 | q3 = yp(di[4]), |
---|
| 75 | max = yp(di[5]); |
---|
| 76 | |
---|
| 77 | var endL = x - endW/2; // start (left) x coord of min/max ticks |
---|
| 78 | var endR = x + endW/2; // end (right) x coord of min/max ticks |
---|
| 79 | var medL = x - boxW/2; // start (left) x coord of median tick |
---|
| 80 | var medR = x + boxW/2; // end (right) x coord of median tick |
---|
| 81 | |
---|
| 82 | // draw whiskers |
---|
| 83 | r.shapeRenderer.draw(ctx, [[x, min], [x, q1]], options); |
---|
| 84 | r.shapeRenderer.draw(ctx, [[x, q3], [x, max]], options); |
---|
| 85 | |
---|
| 86 | // draw min and max ticks |
---|
| 87 | r.shapeRenderer.draw(ctx, [[endL, min], [endR, min]], options); |
---|
| 88 | r.shapeRenderer.draw(ctx, [[endL, max], [endR, max]], options); |
---|
| 89 | // median tick is full box width |
---|
| 90 | r.shapeRenderer.draw(ctx, [[medL, med], [medR, med]], options); |
---|
| 91 | |
---|
| 92 | // draw box |
---|
| 93 | boxH = q1 - q3; |
---|
| 94 | boxpoints = [medL, q3, boxW, boxH]; |
---|
| 95 | r.shapeRenderer.draw(ctx, boxpoints, boxopts); |
---|
| 96 | } |
---|
| 97 | } |
---|
| 98 | ctx.restore(); |
---|
| 99 | }; |
---|
| 100 | |
---|
| 101 | $.jqplot.BoxplotRenderer.prototype.drawShadow = function(ctx, gd, options) { |
---|
| 102 | // This is a no-op, shadows drawn with lines. |
---|
| 103 | }; |
---|
| 104 | |
---|
| 105 | // called with scope of plot. |
---|
| 106 | $.jqplot.BoxplotRenderer.checkOptions = function(target, data, options) { |
---|
| 107 | // provide some sensible highlighter options by default |
---|
| 108 | hldefaults = { |
---|
| 109 | showMarker: false, |
---|
| 110 | tooltipAxes: 'y', |
---|
| 111 | yvalues: 5, |
---|
| 112 | formatString: '<table class="jqplot-highlighter">' + |
---|
| 113 | '<tr><td>min:</td><td>%s</td></tr>' + |
---|
| 114 | '<tr><td>q1:</td><td>%s</td></tr>' + |
---|
| 115 | '<tr><td>med:</td><td>%s</td></tr>' + |
---|
| 116 | '<tr><td>q3:</td><td>%s</td></tr>' + |
---|
| 117 | '<tr><td>max:</td><td>%s</td></tr>' + |
---|
| 118 | '</table>' |
---|
| 119 | }; |
---|
| 120 | if (!options.highlighter) |
---|
| 121 | options.highlighter = {show: true}; |
---|
| 122 | if (options.highlighter.show) { |
---|
| 123 | for (opt in hldefaults) { |
---|
| 124 | if (!(opt in options.highlighter)) { |
---|
| 125 | options.highlighter[opt] = hldefaults[opt]; |
---|
| 126 | } |
---|
| 127 | } |
---|
| 128 | } |
---|
| 129 | }; |
---|
| 130 | |
---|
| 131 | $.jqplot.preInitHooks.push($.jqplot.BoxplotRenderer.checkOptions); |
---|
| 132 | |
---|
| 133 | })(jQuery); |
---|