Mercurial > hg > digilib-old
comparison webapp/src/main/webapp/jquery/svg/jquery.svgplot.js @ 903:7779b37d1d05
refactored into maven modules per servlet type.
can build servlet-api 2.3 and 3.0 via profile now!
author | robcast |
---|---|
date | Tue, 26 Apr 2011 20:24:31 +0200 |
parents | client/src/main/webapp/jquery/svg/jquery.svgplot.js@ba1eb2d821a2 |
children | 301ef9bf1965 |
comparison
equal
deleted
inserted
replaced
902:89ba3ffcf552 | 903:7779b37d1d05 |
---|---|
1 /* http://keith-wood.name/svg.html | |
2 SVG plotting extension for jQuery v1.4.3. | |
3 Written by Keith Wood (kbwood{at}iinet.com.au) December 2008. | |
4 Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and | |
5 MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses. | |
6 Please attribute the author if you use it. */ | |
7 | |
8 (function($) { // Hide scope, no $ conflict | |
9 | |
10 $.svg.addExtension('plot', SVGPlot); | |
11 | |
12 /* Extension point for SVG plotting. | |
13 Access through svg.plot. */ | |
14 function SVGPlot(wrapper) { | |
15 this._wrapper = wrapper; // The attached SVG wrapper object | |
16 this._drawNow = false; // True for immediate update, false to wait for redraw call | |
17 // The plot title and settings | |
18 this._title = {value: '', offset: 25, settings: {textAnchor: 'middle'}}; | |
19 this._area = [0.1, 0.1, 0.8, 0.9]; // The chart area: left, top, right, bottom, | |
20 // > 1 in pixels, <= 1 as proportion | |
21 this._areaFormat = {fill: 'none', stroke: 'black'}; // The formatting for the plot area | |
22 this._gridlines = []; // The formatting of the x- and y-gridlines | |
23 this._equalXY = true; // True for equal-sized x- and y-units, false to fill available space | |
24 this._functions = []; // The functions to be plotted, each is an object | |
25 this._onstatus = null; // The callback function for status updates | |
26 this._uuid = new Date().getTime(); | |
27 this._plotCont = this._wrapper.svg(0, 0, 0, 0, {class_: 'svg-plot'}); // The main container for the plot | |
28 | |
29 this.xAxis = new SVGPlotAxis(this); // The main x-axis | |
30 this.xAxis.title('X', 20); | |
31 this.yAxis = new SVGPlotAxis(this); // The main y-axis | |
32 this.yAxis.title('Y', 20); | |
33 this.legend = new SVGPlotLegend(this); // The plot legend | |
34 this._drawNow = true; | |
35 } | |
36 | |
37 $.extend(SVGPlot.prototype, { | |
38 | |
39 /* Useful indexes. */ | |
40 X: 0, | |
41 Y: 1, | |
42 W: 2, | |
43 H: 3, | |
44 L: 0, | |
45 T: 1, | |
46 R: 2, | |
47 B: 3, | |
48 | |
49 /* Set or retrieve the container for the plot. | |
50 @param cont (SVG element) the container for the plot | |
51 @return (SVGPlot) this plot object or | |
52 (SVG element) the current container (if no parameters) */ | |
53 container: function(cont) { | |
54 if (arguments.length == 0) { | |
55 return this._plotCont; | |
56 } | |
57 this._plotCont = cont; | |
58 return this; | |
59 }, | |
60 | |
61 /* Set or retrieve the main plotting area. | |
62 @param left (number) > 1 is pixels, <= 1 is proportion of width or | |
63 (number[4]) for left, top, right, bottom | |
64 @param top (number) > 1 is pixels, <= 1 is proportion of height | |
65 @param right (number) > 1 is pixels, <= 1 is proportion of width | |
66 @param bottom (number) > 1 is pixels, <= 1 is proportion of height | |
67 @return (SVGPlot) this plot object or | |
68 (number[4]) the plotting area: left, top, right, bottom (if no parameters) */ | |
69 area: function(left, top, right, bottom) { | |
70 if (arguments.length == 0) { | |
71 return this._area; | |
72 } | |
73 this._area = (isArray(left) ? left : [left, top, right, bottom]); | |
74 this._drawPlot(); | |
75 return this; | |
76 }, | |
77 | |
78 /* Set or retrieve the background of the plot area. | |
79 @param fill (string) how to fill the area background | |
80 @param stroke (string) the colour of the outline (optional) | |
81 @param settings (object) additional formatting for the area background (optional) | |
82 @return (SVGPlot) this plot object or | |
83 (object) the area format (if no parameters) */ | |
84 format: function(fill, stroke, settings) { | |
85 if (arguments.length == 0) { | |
86 return this._areaFormat; | |
87 } | |
88 if (typeof stroke == 'object') { | |
89 settings = stroke; | |
90 stroke = null; | |
91 } | |
92 this._areaFormat = $.extend({fill: fill}, | |
93 (stroke ? {stroke: stroke} : {}), settings || {}); | |
94 this._drawPlot(); | |
95 return this; | |
96 }, | |
97 | |
98 /* Set or retrieve the gridlines formatting for the plot area. | |
99 @param xSettings (string) the colour of the gridlines along the x-axis, or | |
100 (object) formatting for the gridlines along the x-axis, or | |
101 null for none | |
102 @param ySettings (string) the colour of the gridlines along the y-axis, or | |
103 (object) formatting for the gridlines along the y-axis, or | |
104 null for none | |
105 @return (SVGPlot) this plot object or | |
106 (object[2]) the gridlines formatting (if no parameters) */ | |
107 gridlines: function(xSettings, ySettings) { | |
108 if (arguments.length == 0) { | |
109 return this._gridlines; | |
110 } | |
111 this._gridlines = [(typeof xSettings == 'string' ? {stroke: xSettings} : xSettings), | |
112 (typeof ySettings == 'string' ? {stroke: ySettings} : ySettings)]; | |
113 if (this._gridlines[0] == null && this._gridlines[1] == null) { | |
114 this._gridlines = []; | |
115 } | |
116 this._drawPlot(); | |
117 return this; | |
118 }, | |
119 | |
120 /* Set or retrieve the equality of the x- and y-axes. | |
121 @param value (boolean) true for equal x- and y-units, false to fill the available space | |
122 @return (SVGPlot) this plot object or | |
123 (boolean) the current setting (if no parameters) */ | |
124 equalXY: function(value) { | |
125 if (arguments.length == 0) { | |
126 return this._equalXY; | |
127 } | |
128 this._equalXY = value; | |
129 return this; | |
130 }, | |
131 | |
132 /* Set or retrieve the title of the plot and its formatting. | |
133 @param value (string) the title | |
134 @param offset (number) the vertical positioning of the title | |
135 > 1 is pixels, <= 1 is proportion of width (optional) | |
136 @param colour (string) the colour of the title (optional) | |
137 @param settings (object) formatting for the title (optional) | |
138 @return (SVGPlot) this plot object or | |
139 (object) value, offset, and settings for the title (if no parameters) */ | |
140 title: function(value, offset, colour, settings) { | |
141 if (arguments.length == 0) { | |
142 return this._title; | |
143 } | |
144 if (typeof offset != 'number') { | |
145 settings = colour; | |
146 colour = offset; | |
147 offset = null; | |
148 } | |
149 if (typeof colour != 'string') { | |
150 settings = colour; | |
151 colour = null; | |
152 } | |
153 this._title = {value: value, offset: offset || this._title.offset, | |
154 settings: $.extend({textAnchor: 'middle'}, | |
155 (colour ? {fill: colour} : {}), settings || {})}; | |
156 this._drawPlot(); | |
157 return this; | |
158 }, | |
159 | |
160 /* Add a function to be plotted on the plot. | |
161 @param name (string) the name of this series (optional) | |
162 @param fn (function) the function to be plotted | |
163 @param range (number[2]) the range of values to plot (optional) | |
164 @param points (number) the number of points to plot within this range (optional) | |
165 @param stroke (string) the colour of the plotted lines (optional) | |
166 @param strokeWidth (number) the width of the plotted lines (optional) | |
167 @param settings (object) additional settings for the plotted values (optional) | |
168 @return (SVGPlot) this plot object */ | |
169 addFunction: function(name, fn, range, points, stroke, strokeWidth, settings) { | |
170 this._functions.push(new SVGPlotFunction( | |
171 this, name, fn, range, points, stroke, strokeWidth, settings)); | |
172 this._drawPlot(); | |
173 return this; | |
174 }, | |
175 | |
176 /* Retrieve the function wrappers. | |
177 @param i (number) the function index (optional) | |
178 @return (SVGPlotFunction) the specified function or | |
179 (SVGPlotFunction[]) the list of functions */ | |
180 functions: function(i) { | |
181 return (arguments.length > 0 ? this._functions[i] : null) || this._functions; | |
182 }, | |
183 | |
184 /* Suppress drawing of the plot until redraw() is called. | |
185 @return (SVGPlot) this plot object */ | |
186 noDraw: function() { | |
187 this._drawNow = false; | |
188 return this; | |
189 }, | |
190 | |
191 /* Redraw the entire plot with the current settings and values. | |
192 @return (SVGPlot) this plot object */ | |
193 redraw: function() { | |
194 this._drawNow = true; | |
195 this._drawPlot(); | |
196 return this; | |
197 }, | |
198 | |
199 /* Set the callback function for status updates. | |
200 @param onstatus (function) the callback function | |
201 @return (SVGPlot) this plot object */ | |
202 status: function(onstatus) { | |
203 this._onstatus = onstatus; | |
204 return this; | |
205 }, | |
206 | |
207 /* Actually draw the plot (if allowed). */ | |
208 _drawPlot: function() { | |
209 if (!this._drawNow) { | |
210 return; | |
211 } | |
212 while (this._plotCont.firstChild) { | |
213 this._plotCont.removeChild(this._plotCont.firstChild); | |
214 } | |
215 if (!this._plotCont.parent) { | |
216 this._wrapper._svg.appendChild(this._plotCont); | |
217 } | |
218 // Set sizes if not already there | |
219 if (!this._plotCont.width) { | |
220 this._plotCont.setAttribute('width', | |
221 parseInt(this._plotCont.getAttribute('width'), 10) || this._wrapper._width()); | |
222 } | |
223 else if (this._plotCont.width.baseVal) { | |
224 this._plotCont.width.baseVal.value = | |
225 this._plotCont.width.baseVal.value || this._wrapper._width(); | |
226 } | |
227 else { | |
228 this._plotCont.width = this._plotCont.width || this._wrapper._width(); | |
229 } | |
230 if (!this._plotCont.height) { | |
231 this._plotCont.setAttribute('height', | |
232 parseInt(this._plotCont.getAttribute('height'), 10) || this._wrapper._height()); | |
233 } | |
234 else if (this._plotCont.height.baseVal) { | |
235 this._plotCont.height.baseVal.value = | |
236 this._plotCont.height.baseVal.value || this._wrapper._height(); | |
237 } | |
238 else { | |
239 this._plotCont.height = this._plotCont.height || this._wrapper._height(); | |
240 } | |
241 this._drawChartBackground(); | |
242 var dims = this._getDims(); | |
243 var clip = this._wrapper.other(this._plotCont, 'clipPath', {id: 'clip' + this._uuid}); | |
244 this._wrapper.rect(clip, dims[this.X], dims[this.Y], dims[this.W], dims[this.H]); | |
245 this._plot = this._wrapper.group(this._plotCont, | |
246 {class_: 'foreground', clipPath: 'url(#clip' + this._uuid + ')'}); | |
247 this._drawAxis(true); | |
248 this._drawAxis(false); | |
249 for (var i = 0; i < this._functions.length; i++) { | |
250 this._plotFunction(this._functions[i], i); | |
251 } | |
252 this._drawTitle(); | |
253 this._drawLegend(); | |
254 }, | |
255 | |
256 /* Decode an attribute value. | |
257 @param node the node to examine | |
258 @param name the attribute name | |
259 @return the actual value */ | |
260 _getValue: function(node, name) { | |
261 return (!node[name] ? parseInt(node.getAttribute(name), 10) : | |
262 (node[name].baseVal ? node[name].baseVal.value : node[name])); | |
263 }, | |
264 | |
265 /* Calculate the actual dimensions of the plot area. | |
266 @param area (number[4]) the area values to evaluate (optional) | |
267 @return (number[4]) an array of dimension values: left, top, width, height */ | |
268 _getDims: function(area) { | |
269 var otherArea = (area != null); | |
270 area = area || this._area; | |
271 var availWidth = this._getValue(this._plotCont, 'width'); | |
272 var availHeight = this._getValue(this._plotCont, 'height'); | |
273 var left = (area[this.L] > 1 ? area[this.L] : availWidth * area[this.L]); | |
274 var top = (area[this.T] > 1 ? area[this.T] : availHeight * area[this.T]); | |
275 var width = (area[this.R] > 1 ? area[this.R] : availWidth * area[this.R]) - left; | |
276 var height = (area[this.B] > 1 ? area[this.B] : availHeight * area[this.B]) - top; | |
277 if (this._equalXY && !otherArea) { | |
278 var scale = Math.min(width / (this.xAxis._scale.max - this.xAxis._scale.min), | |
279 height / (this.yAxis._scale.max - this.yAxis._scale.min)); | |
280 width = scale * (this.xAxis._scale.max - this.xAxis._scale.min); | |
281 height = scale * (this.yAxis._scale.max - this.yAxis._scale.min); | |
282 } | |
283 return [left, top, width, height]; | |
284 }, | |
285 | |
286 /* Calculate the scaling factors for the plot area. | |
287 @return (number[2]) the x- and y-scaling factors */ | |
288 _getScales: function() { | |
289 var dims = this._getDims(); | |
290 return [dims[this.W] / (this.xAxis._scale.max - this.xAxis._scale.min), | |
291 dims[this.H] / (this.yAxis._scale.max - this.yAxis._scale.min)]; | |
292 }, | |
293 | |
294 /* Draw the chart background, including gridlines. | |
295 @param noXGrid (boolean) true to suppress the x-gridlines, false to draw them (optional) | |
296 @param noYGrid (boolean) true to suppress the y-gridlines, false to draw them (optional) | |
297 @return (element) the background group element */ | |
298 _drawChartBackground: function(noXGrid, noYGrid) { | |
299 var bg = this._wrapper.group(this._plotCont, {class_: 'background'}); | |
300 var dims = this._getDims(); | |
301 this._wrapper.rect(bg, dims[this.X], dims[this.Y], dims[this.W], dims[this.H], this._areaFormat); | |
302 if (this._gridlines[0] && this.yAxis._ticks.major && !noYGrid) { | |
303 this._drawGridlines(bg, true, this._gridlines[0], dims); | |
304 } | |
305 if (this._gridlines[1] && this.xAxis._ticks.major && !noXGrid) { | |
306 this._drawGridlines(bg, false, this._gridlines[1], dims); | |
307 } | |
308 return bg; | |
309 }, | |
310 | |
311 /* Draw one set of gridlines. | |
312 @param bg (element) the background group element | |
313 @param horiz (boolean) true if horizontal, false if vertical | |
314 @param format (object) additional settings for the gridlines */ | |
315 _drawGridlines: function(bg, horiz, format, dims) { | |
316 var g = this._wrapper.group(bg, format); | |
317 var axis = (horiz ? this.yAxis : this.xAxis); | |
318 var scales = this._getScales(); | |
319 var major = Math.floor(axis._scale.min / axis._ticks.major) * axis._ticks.major; | |
320 major += (major <= axis._scale.min ? axis._ticks.major : 0); | |
321 while (major < axis._scale.max) { | |
322 var v = (horiz ? axis._scale.max - major : major - axis._scale.min) * | |
323 scales[horiz ? 1 : 0] + (horiz ? dims[this.Y] : dims[this.X]); | |
324 this._wrapper.line(g, (horiz ? dims[this.X] : v), (horiz ? v : dims[this.Y]), | |
325 (horiz ? dims[this.X] + dims[this.W] : v), (horiz ? v : dims[this.Y] + dims[this.H])); | |
326 major += axis._ticks.major; | |
327 } | |
328 }, | |
329 | |
330 /* Draw an axis, its tick marks, and title. | |
331 @param horiz (boolean) true for x-axis, false for y-axis */ | |
332 _drawAxis: function(horiz) { | |
333 var id = (horiz ? 'x' : 'y') + 'Axis'; | |
334 var axis = (horiz ? this.xAxis : this.yAxis); | |
335 var axis2 = (horiz ? this.yAxis : this.xAxis); | |
336 var dims = this._getDims(); | |
337 var scales = this._getScales(); | |
338 var gl = this._wrapper.group(this._plot, $.extend({class_: id}, axis._lineFormat)); | |
339 var gt = this._wrapper.group(this._plot, $.extend({class_: id + 'Labels', | |
340 textAnchor: (horiz ? 'middle' : 'end')}, axis._labelFormat)); | |
341 var zero = (horiz ? axis2._scale.max : -axis2._scale.min) * | |
342 scales[horiz ? 1 : 0] + (horiz ? dims[this.Y] : dims[this.X]); | |
343 this._wrapper.line(gl, (horiz ? dims[this.X] : zero), (horiz ? zero : dims[this.Y]), | |
344 (horiz ? dims[this.X] + dims[this.W] : zero), | |
345 (horiz ? zero : dims[this.Y] + dims[this.H])); | |
346 if (axis._ticks.major) { | |
347 var size = axis._ticks.size; | |
348 var major = Math.floor(axis._scale.min / axis._ticks.major) * axis._ticks.major; | |
349 major = (major < axis._scale.min ? major + axis._ticks.major : major); | |
350 var minor = (!axis._ticks.minor ? axis._scale.max + 1 : | |
351 Math.floor(axis._scale.min / axis._ticks.minor) * axis._ticks.minor); | |
352 minor = (minor < axis._scale.min ? minor + axis._ticks.minor : minor); | |
353 var offsets = [(axis._ticks.position == 'nw' || axis._ticks.position == 'both' ? -1 : 0), | |
354 (axis._ticks.position == 'se' || axis._ticks.position == 'both' ? +1 : 0)]; | |
355 while (major <= axis._scale.max || minor <= axis._scale.max) { | |
356 var cur = Math.min(major, minor); | |
357 var len = (cur == major ? size : size / 2); | |
358 var xy = (horiz ? cur - axis._scale.min : axis._scale.max - cur) * | |
359 scales[horiz ? 0 : 1] + (horiz ? dims[this.X] : dims[this.Y]); | |
360 this._wrapper.line(gl, (horiz ? xy : zero + len * offsets[0]), | |
361 (horiz ? zero + len * offsets[0] : xy), | |
362 (horiz ? xy : zero + len * offsets[1]), | |
363 (horiz ? zero + len * offsets[1] : xy)); | |
364 if (cur == major && cur != 0) { | |
365 this._wrapper.text(gt, (horiz ? xy : zero - size), | |
366 (horiz ? zero - size : xy), '' + cur); | |
367 } | |
368 major += (cur == major ? axis._ticks.major : 0); | |
369 minor += (cur == minor ? axis._ticks.minor : 0); | |
370 } | |
371 } | |
372 if (axis._title) { | |
373 if (horiz) { | |
374 this._wrapper.text(this._plotCont, dims[this.X] - axis._titleOffset, | |
375 zero, axis._title, $.extend({textAnchor: 'end'}, axis._titleFormat || {})); | |
376 } | |
377 else { | |
378 this._wrapper.text(this._plotCont, zero, | |
379 dims[this.Y] + dims[this.H] + axis._titleOffset, | |
380 axis._title, $.extend({textAnchor : 'middle'}, axis._titleFormat || {})); | |
381 } | |
382 } | |
383 }, | |
384 | |
385 /* Plot an individual function. */ | |
386 _plotFunction: function(fn, cur) { | |
387 var dims = this._getDims(); | |
388 var scales = this._getScales(); | |
389 var path = this._wrapper.createPath(); | |
390 var range = fn._range || [this.xAxis._scale.min, this.xAxis._scale.max]; | |
391 var xScale = (range[1] - range[0]) / fn._points; | |
392 var first = true; | |
393 for (var i = 0; i <= fn._points; i++) { | |
394 var x = range[0] + i * xScale; | |
395 if (x > this.xAxis._scale.max + xScale) { | |
396 break; | |
397 } | |
398 if (x < this.xAxis._scale.min - xScale) { | |
399 continue; | |
400 } | |
401 var px = (x - this.xAxis._scale.min) * scales[0] + dims[this.X]; | |
402 var py = dims[this.H] - ((fn._fn(x) - this.yAxis._scale.min) * scales[1]) + dims[this.Y]; | |
403 path[(first ? 'move' : 'line') + 'To'](px, py); | |
404 first = false; | |
405 } | |
406 var p = this._wrapper.path(this._plot, path, | |
407 $.extend({class_: 'fn' + cur, fill: 'none', stroke: fn._stroke, | |
408 strokeWidth: fn._strokeWidth}, fn._settings || {})); | |
409 this._showStatus(p, fn._name); | |
410 }, | |
411 | |
412 /* Draw the plot title - centred. */ | |
413 _drawTitle: function() { | |
414 this._wrapper.text(this._plotCont, this._getValue(this._plotCont, 'width') / 2, | |
415 this._title.offset, this._title.value, this._title.settings); | |
416 }, | |
417 | |
418 /* Draw the chart legend. */ | |
419 _drawLegend: function() { | |
420 if (!this.legend._show) { | |
421 return; | |
422 } | |
423 var g = this._wrapper.group(this._plotCont, {class_: 'legend'}); | |
424 var dims = this._getDims(this.legend._area); | |
425 this._wrapper.rect(g, dims[this.X], dims[this.Y], dims[this.W], dims[this.H], | |
426 this.legend._bgSettings); | |
427 var horiz = dims[this.W] > dims[this.H]; | |
428 var numFn = this._functions.length; | |
429 var offset = (horiz ? dims[this.W] : dims[this.H]) / numFn; | |
430 var xBase = dims[this.X] + 5; | |
431 var yBase = dims[this.Y] + ((horiz ? dims[this.H] : offset) + this.legend._sampleSize) / 2; | |
432 for (var i = 0; i < numFn; i++) { | |
433 var fn = this._functions[i]; | |
434 this._wrapper.rect(g, xBase + (horiz ? i * offset : 0), | |
435 yBase + (horiz ? 0 : i * offset) - this.legend._sampleSize, | |
436 this.legend._sampleSize, this.legend._sampleSize, {fill: fn._stroke}); | |
437 this._wrapper.text(g, xBase + (horiz ? i * offset : 0) + this.legend._sampleSize + 5, | |
438 yBase + (horiz ? 0 : i * offset), fn._name, this.legend._textSettings); | |
439 } | |
440 }, | |
441 | |
442 /* Show the current value status on hover. */ | |
443 _showStatus: function(elem, label) { | |
444 var status = this._onstatus; | |
445 if (this._onstatus) { | |
446 $(elem).hover(function(evt) { status.apply(this, [label]); }, | |
447 function() { status.apply(this, ['']); }); | |
448 } | |
449 } | |
450 }); | |
451 | |
452 /* Details about each plot function. | |
453 @param plot (SVGPlot) the owning plot | |
454 @param name (string) the name of this function (optional) | |
455 @param fn (function) the function to be plotted | |
456 @param range (number[2]) the range of values to be plotted (optional) | |
457 @param points (number) the number of points to plot within this range (optional) | |
458 @param stroke (string) the colour of the (out)line for the plot (optional) | |
459 @param strokeWidth (number) the width of the (out)line for the plot (optional) | |
460 @param settings (object) additional formatting settings (optional) | |
461 @return (SVGPlotFunction) the new plot function object */ | |
462 function SVGPlotFunction(plot, name, fn, range, points, stroke, strokeWidth, settings) { | |
463 if (typeof name != 'string') { | |
464 settings = strokeWidth; | |
465 strokeWidth = stroke; | |
466 stroke = points; | |
467 points = range; | |
468 range = fn; | |
469 fn = name; | |
470 name = null; | |
471 } | |
472 if (!isArray(range)) { | |
473 settings = strokeWidth; | |
474 strokeWidth = stroke; | |
475 stroke = points; | |
476 points = range; | |
477 range = null; | |
478 } | |
479 if (typeof points != 'number') { | |
480 settings = strokeWidth; | |
481 strokeWidth = stroke; | |
482 stroke = points; | |
483 points = null; | |
484 } | |
485 if (typeof stroke != 'string') { | |
486 settings = strokeWidth; | |
487 strokeWidth = stroke; | |
488 stroke = null; | |
489 } | |
490 if (typeof strokeWidth != 'number') { | |
491 settings = strokeWidth; | |
492 strokeWidth = null; | |
493 } | |
494 this._plot = plot; // The owning plot | |
495 this._name = name || ''; // Display name | |
496 this._fn = fn || identity; // The actual function: y = fn(x) | |
497 this._range = range; // The range of values plotted | |
498 this._points = points || 100; // The number of points plotted | |
499 this._stroke = stroke || 'black'; // The line colour | |
500 this._strokeWidth = strokeWidth || 1; // The line width | |
501 this._settings = settings || {}; // Any other settings | |
502 } | |
503 | |
504 $.extend(SVGPlotFunction.prototype, { | |
505 | |
506 /* Set or retrieve the name for this function. | |
507 @param name (string) the function's name | |
508 @return (SVGPlotFunction) this plot function object or | |
509 (string) the function name (if no parameters) */ | |
510 name: function(name) { | |
511 if (arguments.length == 0) { | |
512 return this._name; | |
513 } | |
514 this._name = name; | |
515 this._plot._drawPlot(); | |
516 return this; | |
517 }, | |
518 | |
519 /* Set or retrieve the function to be plotted. | |
520 @param name (string) the function's name (optional) | |
521 @param fn (function) the function to be ploted | |
522 @return (SVGPlotFunction) this plot function object or | |
523 (function) the actual function (if no parameters) */ | |
524 fn: function(name, fn) { | |
525 if (arguments.length == 0) { | |
526 return this._fn; | |
527 } | |
528 if (typeof name == 'function') { | |
529 fn = name; | |
530 name = null; | |
531 } | |
532 this._name = name || this._name; | |
533 this._fn = fn; | |
534 this._plot._drawPlot(); | |
535 return this; | |
536 }, | |
537 | |
538 /* Set or retrieve the range of values to be plotted. | |
539 @param min (number) the minimum value to be plotted | |
540 @param max (number) the maximum value to be plotted | |
541 @return (SVGPlotFunction) this plot function object or | |
542 (number[2]) the value range (if no parameters) */ | |
543 range: function(min, max) { | |
544 if (arguments.length == 0) { | |
545 return this._range; | |
546 } | |
547 this._range = (min == null ? null : [min, max]); | |
548 this._plot._drawPlot(); | |
549 return this; | |
550 }, | |
551 | |
552 /* Set or retrieve the number of points to be plotted. | |
553 @param value (number) the number of points to plot | |
554 @return (SVGPlotFunction) this plot function object or | |
555 (number) the number of points (if no parameters) */ | |
556 points: function(value) { | |
557 if (arguments.length == 0) { | |
558 return this._points; | |
559 } | |
560 this._points = value; | |
561 this._plot._drawPlot(); | |
562 return this; | |
563 }, | |
564 | |
565 /* Set or retrieve the formatting for this function. | |
566 @param stroke (string) the (out)line colour | |
567 @param strokeWidth (number) the line's width (optional) | |
568 @param settings (object) additional formatting settings for the function (optional) | |
569 @return (SVGPlotFunction) this plot function object or | |
570 (object) formatting settings (if no parameters) */ | |
571 format: function(stroke, strokeWidth, settings) { | |
572 if (arguments.length == 0) { | |
573 return $.extend({stroke: this._stroke, | |
574 strokeWidth: this._strokeWidth}, this._settings); | |
575 } | |
576 if (typeof strokeWidth != 'number') { | |
577 settings = strokeWidth; | |
578 strokeWidth = null; | |
579 } | |
580 this._stroke = stroke || this._stroke; | |
581 this._strokeWidth = strokeWidth || this._strokeWidth; | |
582 $.extend(this._settings, settings || {}); | |
583 this._plot._drawPlot(); | |
584 return this; | |
585 }, | |
586 | |
587 /* Return to the parent plot. */ | |
588 end: function() { | |
589 return this._plot; | |
590 } | |
591 }); | |
592 | |
593 /* Default function to plot. | |
594 @param x (number) the input value | |
595 @return (number) the same value */ | |
596 function identity(x) { | |
597 return x; | |
598 } | |
599 | |
600 /* Details about each plot axis. | |
601 @param plot (SVGPlot) the owning plot | |
602 @param title (string) the title of the axis | |
603 @param min (number) the minimum value displayed on this axis | |
604 @param max (number) the maximum value displayed on this axis | |
605 @param major (number) the distance between major ticks | |
606 @param minor (number) the distance between minor ticks (optional) | |
607 @return (SVGPlotAxis) the new axis object */ | |
608 function SVGPlotAxis(plot, title, min, max, major, minor) { | |
609 this._plot = plot; // The owning plot | |
610 this._title = title || ''; // The plot's title | |
611 this._titleFormat = {}; // Formatting settings for the title | |
612 this._titleOffset = 0; // The offset for positioning the title | |
613 this._labelFormat = {}; // Formatting settings for the labels | |
614 this._lineFormat = {stroke: 'black', strokeWidth: 1}; // Formatting settings for the axis lines | |
615 this._ticks = {major: major || 10, minor: minor || 0, size: 10, position: 'both'}; // Tick mark options | |
616 this._scale = {min: min || 0, max: max || 100}; // Axis scale settings | |
617 this._crossAt = 0; // Where this axis crosses the other one. */ | |
618 } | |
619 | |
620 $.extend(SVGPlotAxis.prototype, { | |
621 | |
622 /* Set or retrieve the scale for this axis. | |
623 @param min (number) the minimum value shown | |
624 @param max (number) the maximum value shown | |
625 @return (SVGPlotAxis) this axis object or | |
626 (object) min and max values (if no parameters) */ | |
627 scale: function(min, max) { | |
628 if (arguments.length == 0) { | |
629 return this._scale; | |
630 } | |
631 this._scale.min = min; | |
632 this._scale.max = max; | |
633 this._plot._drawPlot(); | |
634 return this; | |
635 }, | |
636 | |
637 /* Set or retrieve the ticks for this axis. | |
638 @param major (number) the distance between major ticks | |
639 @param minor (number) the distance between minor ticks | |
640 @param size (number) the length of the major ticks (minor are half) (optional) | |
641 @param position (string) the location of the ticks: | |
642 'nw', 'se', 'both' (optional) | |
643 @return (SVGPlotAxis) this axis object or | |
644 (object) major, minor, size, and position values (if no parameters) */ | |
645 ticks: function(major, minor, size, position) { | |
646 if (arguments.length == 0) { | |
647 return this._ticks; | |
648 } | |
649 if (typeof size == 'string') { | |
650 position = size; | |
651 size = null; | |
652 } | |
653 this._ticks.major = major; | |
654 this._ticks.minor = minor; | |
655 this._ticks.size = size || this._ticks.size; | |
656 this._ticks.position = position || this._ticks.position; | |
657 this._plot._drawPlot(); | |
658 return this; | |
659 }, | |
660 | |
661 /* Set or retrieve the title for this axis. | |
662 @param title (string) the title text | |
663 @param offset (number) the distance to offset the title position (optional) | |
664 @param colour (string) how to colour the title (optional) | |
665 @param format (object) formatting settings for the title (optional) | |
666 @return (SVGPlotAxis) this axis object or | |
667 (object) title, offset, and format values (if no parameters) */ | |
668 title: function(title, offset, colour, format) { | |
669 if (arguments.length == 0) { | |
670 return {title: this._title, offset: this._titleOffset, format: this._titleFormat}; | |
671 } | |
672 if (typeof offset != 'number') { | |
673 format = colour; | |
674 colour = offset; | |
675 offset = null; | |
676 } | |
677 if (typeof colour != 'string') { | |
678 format = colour; | |
679 colour = null; | |
680 } | |
681 this._title = title; | |
682 this._titleOffset = (offset != null ? offset : this._titleOffset); | |
683 if (colour || format) { | |
684 this._titleFormat = $.extend(format || {}, (colour ? {fill: colour} : {})); | |
685 } | |
686 this._plot._drawPlot(); | |
687 return this; | |
688 }, | |
689 | |
690 /* Set or retrieve the label format for this axis. | |
691 @param colour (string) how to colour the labels (optional) | |
692 @param format (object) formatting settings for the labels (optional) | |
693 @return (SVGPlotAxis) this axis object or | |
694 (object) format values (if no parameters) */ | |
695 format: function(colour, format) { | |
696 if (arguments.length == 0) { | |
697 return this._labelFormat; | |
698 } | |
699 if (typeof colour != 'string') { | |
700 format = colour; | |
701 colour = null; | |
702 } | |
703 this._labelFormat = $.extend(format || {}, (colour ? {fill: colour} : {})); | |
704 this._plot._drawPlot(); | |
705 return this; | |
706 }, | |
707 | |
708 /* Set or retrieve the line formatting for this axis. | |
709 @param colour (string) the line's colour | |
710 @param width (number) the line's width (optional) | |
711 @param settings (object) additional formatting settings for the line (optional) | |
712 @return (SVGPlotAxis) this axis object or | |
713 (object) line formatting values (if no parameters) */ | |
714 line: function(colour, width, settings) { | |
715 if (arguments.length == 0) { | |
716 return this._lineFormat; | |
717 } | |
718 if (typeof width != 'number') { | |
719 settings = width; | |
720 width = null; | |
721 } | |
722 $.extend(this._lineFormat, {stroke: colour, strokeWidth: | |
723 width || this._lineFormat.strokeWidth}, settings || {}); | |
724 this._plot._drawPlot(); | |
725 return this; | |
726 }, | |
727 | |
728 /* Return to the parent plot. */ | |
729 end: function() { | |
730 return this._plot; | |
731 } | |
732 }); | |
733 | |
734 /* Details about the plot legend. | |
735 @param plot (SVGPlot) the owning plot | |
736 @param bgSettings (object) additional formatting settings for the legend background (optional) | |
737 @param textSettings (object) additional formatting settings for the legend text (optional) | |
738 @return (SVGPlotLegend) the new legend object */ | |
739 function SVGPlotLegend(plot, bgSettings, textSettings) { | |
740 this._plot = plot; // The owning plot | |
741 this._show = true; // Show the legend? | |
742 this._area = [0.9, 0.1, 1.0, 0.9]; // The legend area: left, top, right, bottom, | |
743 // > 1 in pixels, <= 1 as proportion | |
744 this._sampleSize = 15; // Size of sample box | |
745 this._bgSettings = bgSettings || {stroke: 'gray'}; // Additional formatting settings for the legend background | |
746 this._textSettings = textSettings || {}; // Additional formatting settings for the text | |
747 } | |
748 | |
749 $.extend(SVGPlotLegend.prototype, { | |
750 | |
751 /* Set or retrieve whether the legend should be shown. | |
752 @param show (boolean) true to display it, false to hide it | |
753 @return (SVGPlotLegend) this legend object or | |
754 (boolean) show the legend? (if no parameters) */ | |
755 show: function(show) { | |
756 if (arguments.length == 0) { | |
757 return this._show; | |
758 } | |
759 this._show = show; | |
760 this._plot._drawPlot(); | |
761 return this; | |
762 }, | |
763 | |
764 /* Set or retrieve the legend area. | |
765 @param left (number) > 1 is pixels, <= 1 is proportion of width or | |
766 (number[4]) for left, top, right, bottom | |
767 @param top (number) > 1 is pixels, <= 1 is proportion of height | |
768 @param right (number) > 1 is pixels, <= 1 is proportion of width | |
769 @param bottom (number) > 1 is pixels, <= 1 is proportion of height | |
770 @return (SVGPlotLegend) this legend object or | |
771 (number[4]) the legend area: left, top, right, bottom (if no parameters) */ | |
772 area: function(left, top, right, bottom) { | |
773 if (arguments.length == 0) { | |
774 return this._area; | |
775 } | |
776 this._area = (isArray(left) ? left : [left, top, right, bottom]); | |
777 this._plot._drawPlot(); | |
778 return this; | |
779 }, | |
780 | |
781 /* Set or retrieve additional settings for the legend area. | |
782 @param sampleSize (number) the size of the sample box to display (optional) | |
783 @param bgSettings (object) additional formatting settings for the legend background | |
784 @param textSettings (object) additional formatting settings for the legend text (optional) | |
785 @return (SVGPlotLegend) this legend object or | |
786 (object) bgSettings and textSettings for the legend (if no parameters) */ | |
787 settings: function(sampleSize, bgSettings, textSettings) { | |
788 if (arguments.length == 0) { | |
789 return {sampleSize: this._sampleSize, bgSettings: this._bgSettings, | |
790 textSettings: this._textSettings}; | |
791 } | |
792 if (typeof sampleSize == 'object') { | |
793 textSettings = bgSettings; | |
794 bgSettings = sampleSize; | |
795 sampleSize = null; | |
796 } | |
797 this._sampleSize = sampleSize || this._sampleSize; | |
798 this._bgSettings = bgSettings; | |
799 this._textSettings = textSettings || this._textSettings; | |
800 this._plot._drawPlot(); | |
801 return this; | |
802 }, | |
803 | |
804 /* Return to the parent plot. */ | |
805 end: function() { | |
806 return this._plot; | |
807 } | |
808 }); | |
809 | |
810 //============================================================================== | |
811 | |
812 /* Determine whether an object is an array. */ | |
813 function isArray(a) { | |
814 return (a && a.constructor == Array); | |
815 } | |
816 | |
817 })(jQuery) |