3 * Pure JavaScript plotting plugin using jQuery
8 * Copyright (c) 2009-2012 Chris Leonello
9 * jqPlot is currently available for use in all personal or commercial projects
10 * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
11 * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
12 * choose the license that best suits your project and use it accordingly.
14 * Although not required, the author would appreciate an email letting him
15 * know of any substantial use of jqPlot. You can reach the author at:
16 * chris at jqplot dot com or see http://www.jqplot.com/info.php .
18 * If you are feeling kind and generous, consider supporting the project by
19 * making a donation at: http://www.jqplot.com/donate.php .
21 * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
25 * http://hexmen.com/blog/2007/03/printf-sprintf/
26 * http://hexmen.com/js/sprintf.js
27 * The author (Ash Searle) has placed this code in the public domain:
28 * "This code is unrestricted: you are free to use it however you like."
32 // Class: $.jqplot.BezierCurveRenderer.js
33 // Renderer which draws lines as stacked bezier curves.
34 // Data for the line will not be specified as an array of
35 // [x, y] data point values, but as a an array of [start piont, bezier curve]
36 // So, the line is specified as: [[xstart, ystart], [cp1x, cp1y, cp2x, cp2y, xend, yend]].
37 $.jqplot.BezierCurveRenderer = function(){
38 $.jqplot.LineRenderer.call(this);
41 $.jqplot.BezierCurveRenderer.prototype = new $.jqplot.LineRenderer();
42 $.jqplot.BezierCurveRenderer.prototype.constructor = $.jqplot.BezierCurveRenderer;
45 // Method: setGridData
46 // converts the user data values to grid coordinates and stores them
47 // in the gridData array.
48 // Called with scope of a series.
49 $.jqplot.BezierCurveRenderer.prototype.setGridData = function(plot) {
50 // recalculate the grid data
51 var xp = this._xaxis.series_u2p;
52 var yp = this._yaxis.series_u2p;
53 // this._plotData should be same as this.data
56 this._prevGridData = [];
57 // if seriesIndex = 0, fill to x axis.
58 // if seriesIndex > 0, fill to previous series data.
60 if (data.length == 2) {
63 [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
64 [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
65 xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]),
66 xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])],
67 [xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, this._yaxis.min)],
68 [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)]
72 var psd = plot.series[idx-1].data;
74 [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
75 [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
76 xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]),
77 xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])],
78 [xp.call(this._xaxis, psd[1][4]), yp.call(this._yaxis, psd[1][5])],
79 [xp.call(this._xaxis, psd[1][2]), yp.call(this._yaxis, psd[1][3]),
80 xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]),
81 xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])]
88 [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
89 [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
90 xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]),
91 xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])],
92 [xp.call(this._xaxis, data[3][1]), yp.call(this._yaxis, this._yaxis.min)],
93 [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)]
97 var psd = plot.series[idx-1].data;
99 [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
100 [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
101 xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]),
102 xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])],
103 [xp.call(this._xaxis, psd[3][0]), yp.call(this._yaxis, psd[3][1])],
104 [xp.call(this._xaxis, psd[2][0]), yp.call(this._yaxis, psd[2][1]),
105 xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]),
106 xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])]
112 // Method: makeGridData
113 // converts any arbitrary data values to grid coordinates and
114 // returns them. This method exists so that plugins can use a series'
115 // linerenderer to generate grid data points without overwriting the
116 // grid data associated with that series.
117 // Called with scope of a series.
118 $.jqplot.BezierCurveRenderer.prototype.makeGridData = function(data, plot) {
119 // recalculate the grid data
120 var xp = this._xaxis.series_u2p;
121 var yp = this._yaxis.series_u2p;
124 // if seriesIndex = 0, fill to x axis.
125 // if seriesIndex > 0, fill to previous series data.
126 var idx = this.index;
127 if (data.length == 2) {
130 [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
131 [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
132 xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]),
133 xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])],
134 [xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, this._yaxis.min)],
135 [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)]
139 var psd = plot.series[idx-1].data;
141 [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
142 [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
143 xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]),
144 xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])],
145 [xp.call(this._xaxis, psd[1][4]), yp.call(this._yaxis, psd[1][5])],
146 [xp.call(this._xaxis, psd[1][2]), yp.call(this._yaxis, psd[1][3]),
147 xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]),
148 xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])]
155 [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
156 [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
157 xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]),
158 xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])],
159 [xp.call(this._xaxis, data[3][1]), yp.call(this._yaxis, this._yaxis.min)],
160 [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)]
164 var psd = plot.series[idx-1].data;
166 [xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])],
167 [xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]),
168 xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]),
169 xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])],
170 [xp.call(this._xaxis, psd[3][0]), yp.call(this._yaxis, psd[3][1])],
171 [xp.call(this._xaxis, psd[2][0]), yp.call(this._yaxis, psd[2][1]),
172 xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]),
173 xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])]
181 // called within scope of series.
182 $.jqplot.BezierCurveRenderer.prototype.draw = function(ctx, gd, options) {
188 var opts = (options != null) ? options : {};
189 ctx.fillStyle = opts.fillStyle || this.color;
191 ctx.moveTo(gd[0][0], gd[0][1]);
192 ctx.bezierCurveTo(gd[1][0], gd[1][1], gd[1][2], gd[1][3], gd[1][4], gd[1][5]);
193 ctx.lineTo(gd[2][0], gd[2][1]);
194 if (gd[3].length == 2) {
195 ctx.lineTo(gd[3][0], gd[3][1]);
198 ctx.bezierCurveTo(gd[3][0], gd[3][1], gd[3][2], gd[3][3], gd[3][4], gd[3][5]);
209 $.jqplot.BezierCurveRenderer.prototype.drawShadow = function(ctx, gd, options) {
210 // This is a no-op, shadows drawn with lines.
213 $.jqplot.BezierAxisRenderer = function() {
214 $.jqplot.LinearAxisRenderer.call(this);
217 $.jqplot.BezierAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
218 $.jqplot.BezierAxisRenderer.prototype.constructor = $.jqplot.BezierAxisRenderer;
221 // Axes on a plot with Bezier Curves
222 $.jqplot.BezierAxisRenderer.prototype.init = function(options){
223 $.extend(true, this, options);
224 var db = this._dataBounds;
225 // Go through all the series attached to this axis and find
226 // the min/max bounds for this axis.
227 for (var i=0; i<this._series.length; i++) {
228 var s = this._series[i];
231 for (var j=0; j<d.length; j++) {
232 if (this.name == 'xaxis' || this.name == 'x2axis') {
233 if (d[j][0] < db.min || db.min == null) {
236 if (d[j][0] > db.max || db.max == null) {
241 if (d[j][1] < db.min || db.min == null) {
244 if (d[j][1] > db.max || db.max == null) {
251 if (this.name == 'xaxis' || this.name == 'x2axis') {
252 if (d[0][0] < db.min || db.min == null) {
255 if (d[0][0] > db.max || db.max == null) {
258 for (var j=0; j<5; j+=2) {
259 if (d[1][j] < db.min || db.min == null) {
262 if (d[1][j] > db.max || db.max == null) {
268 if (d[0][1] < db.min || db.min == null) {
271 if (d[0][1] > db.max || db.max == null) {
274 for (var j=1; j<6; j+=2) {
275 if (d[1][j] < db.min || db.min == null) {
278 if (d[1][j] > db.max || db.max == null) {
287 // setup default renderers for axes and legend so user doesn't have to
288 // called with scope of plot
289 function preInit(target, data, options) {
290 options = options || {};
291 options.axesDefaults = $.extend(true, {pad:0}, options.axesDefaults);
292 options.legend = $.extend(true, {placement:'outside'}, options.legend);
293 // only set these if there is a pie series
295 if (options.seriesDefaults.renderer == $.jqplot.BezierCurveRenderer) {
298 else if (options.series) {
299 for (var i=0; i < options.series.length; i++) {
300 if (options.series[i].renderer == $.jqplot.BezierCurveRenderer) {
307 options.axesDefaults.renderer = $.jqplot.BezierAxisRenderer;
311 $.jqplot.preInitHooks.push(preInit);