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); |
---|