jquery-svg-rails 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ /* http://keith-wood.name/svg.html
2
+ SVG filters for jQuery v1.5.0.
3
+ Written by Keith Wood (kbwood{at}iinet.com.au) August 2007.
4
+ Available under the MIT (http://keith-wood.name/licence.html) license.
5
+ Please attribute the author if you use it. */
6
+ (function($){$.svg.addExtension('filters',SVGFilter);$.extend($.svg._wrapperClass.prototype,{filter:function(a,b,x,y,c,d,e){var f=this._args(arguments,['id','x','y','width','height']);return this._makeNode(f.parent,'filter',$.extend({id:f.id,x:f.x,y:f.y,width:f.width,height:f.height},f.settings||{}))}});function SVGFilter(a){this._wrapper=a}$.extend(SVGFilter.prototype,{distantLight:function(a,b,c,d,e){var f=this._wrapper._args(arguments,['result','azimuth','elevation']);return this._wrapper._makeNode(f.parent,'feDistantLight',$.extend({result:f.result,azimuth:f.azimuth,elevation:f.elevation},f.settings||{}))},pointLight:function(a,b,x,y,z,c){var d=this._wrapper._args(arguments,['result','x','y','z']);return this._wrapper._makeNode(d.parent,'fePointLight',$.extend({result:d.result,x:d.x,y:d.y,z:d.z},d.settings||{}))},spotLight:function(a,b,x,y,z,c,d,e,f){var g=this._wrapper._args(arguments,['result','x','y','z','toX','toY','toZ'],['toX']);var h=$.extend({result:g.result,x:g.x,y:g.y,z:g.z},(g.toX!=null?{pointsAtX:g.toX,pointsAtY:g.toY,pointsAtZ:g.toZ}:{}));return this._wrapper._makeNode(g.parent,'feSpotLight',$.extend(h,g.settings||{}))},blend:function(a,b,c,d,e,f){var g=this._wrapper._args(arguments,['result','mode','in1','in2']);return this._wrapper._makeNode(g.parent,'feBlend',$.extend({result:g.result,mode:g.mode,in_:g.in1,in2:g.in2},g.settings||{}))},colorMatrix:function(a,b,c,d,e,f){var g=this._wrapper._args(arguments,['result','in1','type','values']);if($.isArray(g.values)){var h='';for(var i=0;i<g.values.length;i++){h+=(i===0?'':' ')+g.values[i].join(' ')}g.values=h}else if(typeof g.values==='object'){g.settings=g.values;g.values=null}var j=$.extend({result:g.result,in_:g.in1,type:g.type},(g.values!=null?{values:g.values}:{}));return this._wrapper._makeNode(g.parent,'feColorMatrix',$.extend(j,g.settings||{}))},componentTransfer:function(a,b,c,d){var e=this._wrapper._args(arguments,['result','functions']);var f=this._wrapper._makeNode(e.parent,'feComponentTransfer',$.extend({result:e.result},e.settings||{}));var g=['R','G','B','A'];for(var i=0;i<Math.min(4,e.functions.length);i++){var h=e.functions[i];var j=$.extend({type:h[0]},(h[0]==='table'||h[0]==='discrete'?{tableValues:h[1].join(' ')}:(h[0]==='linear'?{slope:h[1],intercept:h[2]}:(h[0]==='gamma'?{amplitude:h[1],exponent:h[2],offset:h[3]}:{}))));this._wrapper._makeNode(f,'feFunc'+g[i],j)}return f},composite:function(a,b,c,d,e,f,g,h,i,j){var k=this._wrapper._args(arguments,['result','operator','in1','in2','k1','k2','k3','k4'],['k1']);var l=$.extend({result:k.result,operator:k.operator,'in':k.in1,in2:k.in2},(k.k1!=null?{k1:k.k1,k2:k.k2,k3:k.k3,k4:k.k4}:{}));return this._wrapper._makeNode(k.parent,'feComposite',$.extend(l,k.settings||{}))},convolveMatrix:function(a,b,c,d,e){var f=this._wrapper._args(arguments,['result','order','matrix']);var g='';for(var i=0;i<f.matrix.length;i++){g+=(i===0?'':' ')+f.matrix[i].join(' ')}f.matrix=g;return this._wrapper._makeNode(f.parent,'feConvolveMatrix',$.extend({result:f.result,order:f.order,kernelMatrix:f.matrix},f.settings||{}))},diffuseLighting:function(a,b,c,d){var e=this._wrapper._args(arguments,['result','colour'],['colour']);return this._wrapper._makeNode(e.parent,'feDiffuseLighting',$.extend($.extend({result:e.result},(e.colour?{lightingColor:e.colour}:{})),e.settings||{}))},displacementMap:function(a,b,c,d,e){var f=this._wrapper._args(arguments,['result','in1','in2']);return this._wrapper._makeNode(f.parent,'feDisplacementMap',$.extend({result:f.result,in_:f.in1,in2:f.in2},f.settings||{}))},flood:function(a,b,x,y,c,d,e,f,g){var h=this._wrapper._args(arguments,['result','x','y','width','height','colour','opacity']);if(arguments.length<6){h.colour=h.x;h.opacity=h.y;h.settings=h.width;h.x=null}var i=$.extend({result:h.result,floodColor:h.colour,floodOpacity:h.opacity},(h.x!=null?{x:h.x,y:h.y,width:h.width,height:h.height}:{}));return this._wrapper._makeNode(h.parent,'feFlood',$.extend(i,h.settings||{}))},gaussianBlur:function(a,b,c,d,e,f){var g=this._wrapper._args(arguments,['result','in1','stdDevX','stdDevY'],['stdDevY']);return this._wrapper._makeNode(g.parent,'feGaussianBlur',$.extend({result:g.result,in_:g.in1,stdDeviation:g.stdDevX+(g.stdDevY?' '+g.stdDevY:'')},g.settings||{}))},image:function(a,b,c,d){var e=this._wrapper._args(arguments,['result','href']);var f=this._wrapper._makeNode(e.parent,'feImage',$.extend({result:e.result},e.settings||{}));f.setAttributeNS($.svg.xlinkNS,'href',e.href);return f},merge:function(a,b,c,d){var e=this._wrapper._args(arguments,['result','refs']);var f=this._wrapper._makeNode(e.parent,'feMerge',$.extend({result:e.result},e.settings||{}));for(var i=0;i<e.refs.length;i++){this._wrapper._makeNode(f,'feMergeNode',{in_:e.refs[i]})}return f},morphology:function(a,b,c,d,e,f,g){var h=this._wrapper._args(arguments,['result','in1','operator','radiusX','radiusY'],['radiusY']);return this._wrapper._makeNode(h.parent,'feMorphology',$.extend({result:h.result,in_:h.in1,operator:h.operator,radius:h.radiusX+(h.radiusY?' '+h.radiusY:'')},h.settings||{}))},offset:function(a,b,c,d,e,f){var g=this._wrapper._args(arguments,['result','in1','dx','dy']);return this._wrapper._makeNode(g.parent,'feOffset',$.extend({result:g.result,in_:g.in1,dx:g.dx,dy:g.dy},g.settings||{}))},specularLighting:function(a,b,c,d,e,f,g){var h=this._wrapper._args(arguments,['result','in1','surfaceScale','specularConstant','specularExponent'],['surfaceScale','specularConstant','specularExponent']);return this._wrapper._makeNode(h.parent,'feSpecularLighting',$.extend({result:h.result,in_:h.in1,surfaceScale:h.surfaceScale,specularConstant:h.specularConstant,specularExponent:h.specularExponent},h.settings||{}))},tile:function(a,b,c,x,y,d,e,f){var g=this._wrapper._args(arguments,['result','in1','x','y','width','height']);return this._wrapper._makeNode(g.parent,'feTile',$.extend({result:g.result,in_:g.in1,x:g.x,y:g.y,width:g.width,height:g.height},g.settings||{}))},turbulence:function(a,b,c,d,e,f){var g=this._wrapper._args(arguments,['result','type','baseFreq','octaves'],['octaves']);return this._wrapper._makeNode(g.parent,'feTurbulence',$.extend({result:g.result,type:g.type,baseFrequency:g.baseFreq,numOctaves:g.octaves},g.settings||{}))}})})(jQuery)
@@ -0,0 +1,1539 @@
1
+ /* http://keith-wood.name/svg.html
2
+ SVG graphing extension for jQuery v1.5.0.
3
+ Written by Keith Wood (kbwood{at}iinet.com.au) August 2007.
4
+ Available under the MIT (http://keith-wood.name/licence.html) license.
5
+ Please attribute the author if you use it. */
6
+
7
+ (function($) { // Hide scope, no $ conflict
8
+
9
+ $.svg.addExtension('graph', SVGGraph);
10
+
11
+ $.svg.graphing = new SVGGraphing();
12
+
13
+ /** The SVG graphing manager.
14
+ <p>Use the singleton instance of this class, $.svg.graphing,
15
+ to interact with the SVG graphing functionality.</p>
16
+ @module SVGGraphing */
17
+ function SVGGraphing() {
18
+ this.regional = [];
19
+ this.regional[''] = {percentageText: 'Percentage'};
20
+ this.region = this.regional[''];
21
+ }
22
+
23
+ $.extend(SVGGraphing.prototype, {
24
+ _chartTypes: [],
25
+
26
+ /** Add a new chart rendering type to the package.
27
+ <p>The rendering object must implement the following functions: <code>getTitle()</code>,
28
+ <code>getDescription()</code>, <code>getOptions()</code>, <code>drawChart(graph)</code>.</p>
29
+ @param id {string} The ID of this graph renderer.
30
+ @param chartType {object} The object implementing this chart type. */
31
+ addChartType: function(id, chartType) {
32
+ this._chartTypes[id] = chartType;
33
+ },
34
+
35
+ /** Retrieve the list of chart types.
36
+ @return {object[]} The array of chart types indexed by ID */
37
+ chartTypes: function() {
38
+ return this._chartTypes;
39
+ }
40
+ });
41
+
42
+ /** The SVG graph manager.
43
+ <p>Use the singleton instance of this class, $.svg.graph,
44
+ to interact with the SVG graph functionality.</p>
45
+ @module SVGGraph */
46
+ function SVGGraph(wrapper) {
47
+ this._wrapper = wrapper; // The attached SVG wrapper object
48
+ this._drawNow = false; // True for immediate update, false to wait for redraw call
49
+ for (var id in $.svg.graphing._chartTypes) {
50
+ this._chartType = $.svg.graphing._chartTypes[id]; // Use first graph renderer
51
+ break;
52
+ }
53
+ this._chartOptions = {}; // Extra options for the graph type
54
+ // The graph title and settings
55
+ this._title = {value: '', offset: 25, settings: {textAnchor: 'middle'}};
56
+ this._area = [0.1, 0.1, 0.8, 0.9]; // The chart area: left, top, right, bottom, > 1 in pixels, <= 1 as proportion
57
+ this._chartFormat = {fill: 'none', stroke: 'black'}; // The formatting for the chart area
58
+ this._gridlines = []; // The formatting of the x- and y-gridlines
59
+ this._series = []; // The series to be plotted, each is an object
60
+ this._onstatus = null; // The callback function for status updates
61
+ this._chartCont = this._wrapper.svg(0, 0, 0, 0, {class_: 'svg-graph'}); // The main container for the graph
62
+
63
+ this.xAxis = new SVGGraphAxis(this); // The main x-axis
64
+ this.xAxis.title('', 40);
65
+ this.yAxis = new SVGGraphAxis(this); // The main y-axis
66
+ this.yAxis.title('', 40);
67
+ this.x2Axis = null; // The secondary x-axis
68
+ this.y2Axis = null; // The secondary y-axis
69
+ this.legend = new SVGGraphLegend(this); // The chart legend
70
+ this._drawNow = true;
71
+ }
72
+
73
+ $.extend(SVGGraph.prototype, {
74
+
75
+ /* Useful indexes. */
76
+ /** Index in a dimensions array for x-coordinate. */
77
+ X: 0,
78
+ /** Index in a dimensions array for y-coordinate. */
79
+ Y: 1,
80
+ /** Index in a dimensions array for width. */
81
+ W: 2,
82
+ /** Index in a dimensions array for height. */
83
+ H: 3,
84
+ /** Index in an area array for left x-coordinate. */
85
+ L: 0,
86
+ /** Index in an area array for top y-coordinate. */
87
+ T: 1,
88
+ /** Index in an area array for right x-coordinate. */
89
+ R: 2,
90
+ /** Index in an area array for bottom y-coordinate. */
91
+ B: 3,
92
+
93
+ /* Standard percentage axis. */
94
+ _percentageAxis: new SVGGraphAxis(this, $.svg.graphing.region.percentageText, 0, 100, 10, 0),
95
+
96
+ /** Set or retrieve the container for the graph.
97
+ @param cont {SVGElement} The container for the graph.
98
+ @return {SVGGraph|SVGElement} This graph object or the current container (if no parameters). */
99
+ container: function(cont) {
100
+ if (arguments.length === 0) {
101
+ return this._chartCont;
102
+ }
103
+ this._chartCont = cont;
104
+ return this;
105
+ },
106
+
107
+ /** Set or retrieve the type of chart to be rendered.
108
+ <p>See <code>$.svg.graphing.getChartTypes()</code> for the list of available types.</p>
109
+ @param id {string} The ID of the chart type.
110
+ @param [options] {object} Additional settings for this chart type.
111
+ @return {SVGGraph|string} This graph object or the chart type (if no parameters).
112
+ @deprecated Use <code>type()</code>. */
113
+ chartType: function(id, options) {
114
+ return (arguments.length === 0 ? this.type() : this.type(id, options));
115
+ },
116
+
117
+ /** Set or retrieve the type of chart to be rendered.
118
+ <p>See <code>$.svg.graphing.getChartTypes()</code> for the list of available types.</p>
119
+ @param id {string} The ID of the chart type.
120
+ @param [options] {object} Additional settings for this chart type.
121
+ @return {SVGGraph|string} This graph object or the chart type (if no parameters). */
122
+ type: function(id, options) {
123
+ if (arguments.length === 0) {
124
+ return this._chartType;
125
+ }
126
+ var chartType = $.svg.graphing._chartTypes[id];
127
+ if (chartType) {
128
+ this._chartType = chartType;
129
+ this._chartOptions = $.extend({}, options || {});
130
+ }
131
+ this._drawGraph();
132
+ return this;
133
+ },
134
+
135
+ /** Set or retrieve additional options for the particular chart type.
136
+ @param options {object} The extra options.
137
+ @return {SVGGraph|object} This graph object or the chart options (if no parameters).
138
+ @deprecated Use <code>options()</code>. */
139
+ chartOptions: function(options) {
140
+ return(arguments.length === 0 ? this.options() : this.options(options));
141
+ },
142
+
143
+ /** Set or retrieve additional options for the particular chart type.
144
+ @param options {object} The extra options.
145
+ @return {SVGGraph|object} This graph object or the chart options (if no parameters). */
146
+ options: function(options) {
147
+ if (arguments.length === 0) {
148
+ return this._chartOptions;
149
+ }
150
+ this._chartOptions = $.extend({}, options);
151
+ this._drawGraph();
152
+ return this;
153
+ },
154
+
155
+ /** Set or retrieve the background of the graph chart.
156
+ @param fill {string} How to fill the chart background.
157
+ @param [stroke] {string} The colour of the outline.
158
+ @param [settings] {object} Additional formatting for the chart background.
159
+ @return {SVGGraph|object} This graph object or the chart format (if no parameters).
160
+ @deprecated Use <code>format()</code>. */
161
+ chartFormat: function(fill, stroke, settings) {
162
+ return (arguments.length === 0 ? this.format() : this.format(fill, stroke, settings));
163
+ },
164
+
165
+ /** Set or retrieve the background of the graph chart.
166
+ @param fill {string} How to fill the chart background.
167
+ @param [stroke] {string} The colour of the outline.
168
+ @param [settings] {object} Additional formatting for the chart background.
169
+ @return {SVGGraph|object} This graph object or the chart format (if no parameters). */
170
+ format: function(fill, stroke, settings) {
171
+ if (arguments.length === 0) {
172
+ return this._chartFormat;
173
+ }
174
+ if (typeof stroke === 'object') {
175
+ settings = stroke;
176
+ stroke = null;
177
+ }
178
+ this._chartFormat = $.extend({fill: fill}, (stroke ? {stroke: stroke} : {}), settings || {});
179
+ this._drawGraph();
180
+ return this;
181
+ },
182
+
183
+ /** Set or retrieve the main chart area.
184
+ @param left {number|number[]} > 1 is pixels, <= 1 is proportion of width or array for left, top, right, bottom.
185
+ @param [top] {number} > 1 is pixels, <= 1 is proportion of height.
186
+ @param [right] {number} > 1 is pixels, <= 1 is proportion of width.
187
+ @param [bottom] {number} > 1 is pixels, <= 1 is proportion of height.
188
+ @return {SVGGraph|number[]} This graph object or the chart area: left, top, right, bottom (if no parameters).
189
+ @deprecated Use <code>area()</code>. */
190
+ chartArea: function(left, top, right, bottom) {
191
+ return (arguments.length === 0 ? this.area() : this.area(left, top, right, bottom));
192
+ },
193
+
194
+ /** Set or retrieve the main chart area.
195
+ @param left {number|number[]} > 1 is pixels, <= 1 is proportion of width or array for left, top, right, bottom.
196
+ @param [top] {number} > 1 is pixels, <= 1 is proportion of height.
197
+ @param [right] {number} > 1 is pixels, <= 1 is proportion of width.
198
+ @param [bottom] {number} > 1 is pixels, <= 1 is proportion of height.
199
+ @return {SVGGraph|number[]} This graph object or the chart area: left, top, right, bottom (if no parameters). */
200
+ area: function(left, top, right, bottom) {
201
+ if (arguments.length === 0) {
202
+ return this._area;
203
+ }
204
+ this._area = ($.isArray(left) ? left : [left, top, right, bottom]);
205
+ this._drawGraph();
206
+ return this;
207
+ },
208
+
209
+ /** Set or retrieve the gridlines formatting for the graph chart.
210
+ @param xSettings {string|object} The colour of the gridlines along the x-axis,
211
+ or formatting for the gridlines along the x-axis, or <code>null</code> for none.
212
+ @param ySettings {string|object} The colour of the gridlines along the y-axis,
213
+ or formatting for the gridlines along the y-axis, or <code>null</code> for none.
214
+ @return {SVGGraph|object[]} This graph object or the gridlines formatting (if no parameters) */
215
+ gridlines: function(xSettings, ySettings) {
216
+ if (arguments.length === 0) {
217
+ return this._gridlines;
218
+ }
219
+ this._gridlines = [(typeof xSettings === 'string' ? {stroke: xSettings} : xSettings),
220
+ (typeof ySettings === 'string' ? {stroke: ySettings} : ySettings)];
221
+ if (this._gridlines[0] == null && this._gridlines[1] == null) {
222
+ this._gridlines = [];
223
+ }
224
+ this._drawGraph();
225
+ return this;
226
+ },
227
+
228
+ /** Set or retrieve the title of the graph and its formatting.
229
+ @param value {string} The title.
230
+ @param [offset] {number} The vertical positioning of the title > 1 is pixels, <= 1 is proportion of width.
231
+ @param [colour] {string} The colour of the title.
232
+ @param [settings] {object} Formatting for the title.
233
+ @return {SVGGraph|object} This graph object or value, offset, and settings for the title (if no parameters). */
234
+ title: function(value, offset, colour, settings) {
235
+ if (arguments.length === 0) {
236
+ return this._title;
237
+ }
238
+ if (typeof offset !== 'number') {
239
+ settings = colour;
240
+ colour = offset;
241
+ offset = null;
242
+ }
243
+ if (typeof colour !== 'string') {
244
+ settings = colour;
245
+ colour = null;
246
+ }
247
+ this._title = {value: value, offset: offset || this._title.offset,
248
+ settings: $.extend({textAnchor: 'middle'}, (colour ? {fill: colour} : {}), settings || {})};
249
+ this._drawGraph();
250
+ return this;
251
+ },
252
+
253
+ /** Add a series of values to be plotted on the graph.
254
+ @param [name] {string} The name of this series.
255
+ @param values {number[]} The values to be plotted.
256
+ @param fill {string} How the plotted values are filled.
257
+ @param [stroke] {string} The colour of the plotted lines.
258
+ @param [strokeWidth] {number} The width of the plotted lines.
259
+ @param [settings] {object} Additional settings for the plotted values.
260
+ @return {SVGGraph} This graph object. */
261
+ addSeries: function(name, values, fill, stroke, strokeWidth, settings) {
262
+ this._series.push(new SVGGraphSeries(this, name, values, fill, stroke, strokeWidth, settings));
263
+ this._drawGraph();
264
+ return this;
265
+ },
266
+
267
+ /** Retrieve the series wrappers.
268
+ @param [i] {number} The series index.
269
+ @return {SVGGraphSeries|SVGGraphSeries[]} The specified series or the list of series. */
270
+ series: function(i) {
271
+ return (arguments.length > 0 ? this._series[i] : null) || this._series;
272
+ },
273
+
274
+ /** Suppress drawing of the graph until redraw() is called.
275
+ @return {SVGGraph} This graph object. */
276
+ noDraw: function() {
277
+ this._drawNow = false;
278
+ return this;
279
+ },
280
+
281
+ /** Redraw the entire graph with the current settings and values.
282
+ @return {SVGGraph} This graph object. */
283
+ redraw: function() {
284
+ this._drawNow = true;
285
+ this._drawGraph();
286
+ return this;
287
+ },
288
+
289
+ /** Set the callback function for status updates.
290
+ @param onstatus {function} The callback function.
291
+ @return {SVGGraph} This graph object. */
292
+ status: function(onstatus) {
293
+ this._onstatus = onstatus;
294
+ return this;
295
+ },
296
+
297
+ /** Actually draw the graph (if allowed) based on the graph type set.
298
+ @private */
299
+ _drawGraph: function() {
300
+ if (!this._drawNow) {
301
+ return;
302
+ }
303
+ while (this._chartCont.firstChild) {
304
+ this._chartCont.removeChild(this._chartCont.firstChild);
305
+ }
306
+ if (!this._chartCont.parent) {
307
+ this._wrapper._svg.appendChild(this._chartCont);
308
+ }
309
+ // Set sizes if not already there
310
+ if (!this._chartCont.width) {
311
+ this._chartCont.setAttribute('width',
312
+ parseInt(this._chartCont.getAttribute('width'), 10) || this._wrapper.width());
313
+ }
314
+ else if (this._chartCont.width.baseVal) {
315
+ this._chartCont.width.baseVal.value = this._chartCont.width.baseVal.value || this._wrapper.width();
316
+ }
317
+ else {
318
+ this._chartCont.width = this._chartCont.width || this._wrapper.width();
319
+ }
320
+ if (!this._chartCont.height) {
321
+ this._chartCont.setAttribute('height',
322
+ parseInt(this._chartCont.getAttribute('height'), 10) || this._wrapper.height());
323
+ }
324
+ else if (this._chartCont.height.baseVal) {
325
+ this._chartCont.height.baseVal.value = this._chartCont.height.baseVal.value || this._wrapper.height();
326
+ }
327
+ else {
328
+ this._chartCont.height = this._chartCont.height || this._wrapper.height();
329
+ }
330
+ this._chartType.drawGraph(this);
331
+ },
332
+
333
+ /** Decode an attribute value.
334
+ @private
335
+ @param node {SVGElement} The node to examine.
336
+ @param name {string} The attribute name.
337
+ @return {string} The actual value. */
338
+ _getValue: function(node, name) {
339
+ return (!node[name] ? parseInt(node.getAttribute(name), 10) :
340
+ (node[name].baseVal ? node[name].baseVal.value : node[name]));
341
+ },
342
+
343
+ /** Draw the graph title - centred.
344
+ @private */
345
+ _drawTitle: function() {
346
+ this._wrapper.text(this._chartCont, this._getValue(this._chartCont, 'width') / 2,
347
+ this._title.offset, this._title.value, this._title.settings);
348
+ },
349
+
350
+ /** Calculate the actual dimensions of the chart area.
351
+ @private
352
+ @param [area] {number[]} The area values to evaluate, defaulting to the current ones.
353
+ @return {number[]} An array of dimension values: left, top, width, height. */
354
+ _getDims: function(area) {
355
+ area = area || this._area;
356
+ var availWidth = this._getValue(this._chartCont, 'width');
357
+ var availHeight = this._getValue(this._chartCont, 'height');
358
+ var left = (area[this.L] > 1 ? area[this.L] : availWidth * area[this.L]);
359
+ var top = (area[this.T] > 1 ? area[this.T] : availHeight * area[this.T]);
360
+ var width = (area[this.R] > 1 ? area[this.R] : availWidth * area[this.R]) - left;
361
+ var height = (area[this.B] > 1 ? area[this.B] : availHeight * area[this.B]) - top;
362
+ return [left, top, width, height];
363
+ },
364
+
365
+ /** Draw the chart background, including gridlines.
366
+ @private
367
+ @param [noXGrid=false] {boolean} <code>true</code> to suppress the x-gridlines, <code>false</code> to draw them.
368
+ @param [noYGrid=false] {boolean} <code>true</code> to suppress the y-gridlines, <code>false</code> to draw them.
369
+ @return {SVGEelement} The background group element */
370
+ _drawChartBackground: function(noXGrid, noYGrid) {
371
+ var bg = this._wrapper.group(this._chartCont, {class_: 'background'});
372
+ var dims = this._getDims();
373
+ this._wrapper.rect(bg, dims[this.X], dims[this.Y], dims[this.W], dims[this.H], this._chartFormat);
374
+ if (this._gridlines[0] && this.yAxis._ticks.major && !noYGrid) {
375
+ this._drawGridlines(bg, this.yAxis, true, dims, this._gridlines[0]);
376
+ }
377
+ if (this._gridlines[1] && this.xAxis._ticks.major && !noXGrid) {
378
+ this._drawGridlines(bg, this.xAxis, false, dims, this._gridlines[1]);
379
+ }
380
+ return bg;
381
+ },
382
+
383
+ /** Draw one set of gridlines.
384
+ @private
385
+ @param bg {SVGElement} The background group element.
386
+ @param axis {SVGGraphAxis} The axis definition.
387
+ @param horiz {boolean} <code>true</code> if horizontal, <code>false</code> if vertical.
388
+ @param dims {number[]} The left, top, width, height of the chart area.
389
+ @param format {object} Additional settings for the gridlines. */
390
+ _drawGridlines: function(bg, axis, horiz, dims, format) {
391
+ var g = this._wrapper.group(bg, format);
392
+ var scale = (horiz ? dims[this.H] : dims[this.W]) / (axis._scale.max - axis._scale.min);
393
+ var major = Math.floor(axis._scale.min / axis._ticks.major) * axis._ticks.major;
394
+ major = (major < axis._scale.min ? major + axis._ticks.major : major);
395
+ while (major <= axis._scale.max) {
396
+ var v = (horiz ? axis._scale.max - major : major - axis._scale.min) * scale +
397
+ (horiz ? dims[this.Y] : dims[this.X]);
398
+ this._wrapper.line(g, (horiz ? dims[this.X] : v), (horiz ? v : dims[this.Y]),
399
+ (horiz ? dims[this.X] + dims[this.W] : v), (horiz ? v : dims[this.Y] + dims[this.H]));
400
+ major += axis._ticks.major;
401
+ }
402
+ },
403
+
404
+ /** Draw the axes in their standard configuration.
405
+ @private
406
+ @param [noX=false] {boolean} <code>true</code> to suppress the x-axes, <code>false</code> to draw it. */
407
+ _drawAxes: function(noX) {
408
+ var dims = this._getDims();
409
+ if (this.xAxis && !noX) {
410
+ if (this.xAxis._title) {
411
+ this._wrapper.text(this._chartCont, dims[this.X] + dims[this.W] / 2,
412
+ dims[this.Y] + dims[this.H] + this.xAxis._titleOffset, this.xAxis._title, this.xAxis._titleFormat);
413
+ }
414
+ this._drawAxis(this.xAxis, 'xAxis', dims[this.X], dims[this.Y] + dims[this.H],
415
+ dims[this.X] + dims[this.W], dims[this.Y] + dims[this.H]);
416
+ }
417
+ if (this.yAxis) {
418
+ if (this.yAxis._title) {
419
+ this._wrapper.text(this._chartCont, 0, 0, this.yAxis._title, $.extend({textAnchor: 'middle',
420
+ transform: 'translate(' + (dims[this.X] - this.yAxis._titleOffset) + ',' +
421
+ (dims[this.Y] + dims[this.H] / 2) + ') rotate(-90)'}, this.yAxis._titleFormat || {}));
422
+ }
423
+ this._drawAxis(this.yAxis, 'yAxis', dims[this.X], dims[this.Y], dims[this.X], dims[this.Y] + dims[this.H]);
424
+ }
425
+ if (this.x2Axis && !noX) {
426
+ if (this.x2Axis._title) {
427
+ this._wrapper.text(this._chartCont, dims[this.X] + dims[this.W] / 2,
428
+ dims[this.X] - this.x2Axis._titleOffset, this.x2Axis._title, this.x2Axis._titleFormat);
429
+ }
430
+ this._drawAxis(this.x2Axis, 'x2Axis', dims[this.X], dims[this.Y], dims[this.X] + dims[this.W], dims[this.Y]);
431
+ }
432
+ if (this.y2Axis) {
433
+ if (this.y2Axis._title) {
434
+ this._wrapper.text(this._chartCont, 0, 0, this.y2Axis._title, $.extend({textAnchor: 'middle',
435
+ transform: 'translate(' + (dims[this.X] + dims[this.W] + this.y2Axis._titleOffset) + ',' +
436
+ (dims[this.Y] + dims[this.H] / 2) + ') rotate(-90)'}, this.y2Axis._titleFormat || {}));
437
+ }
438
+ this._drawAxis(this.y2Axis, 'y2Axis', dims[this.X] + dims[this.W], dims[this.Y],
439
+ dims[this.X] + dims[this.W], dims[this.Y] + dims[this.H]);
440
+ }
441
+ },
442
+
443
+ /** Draw an axis and its tick marks.
444
+ @private
445
+ @param axis {SVGGraphAxis} The axis definition.
446
+ @param id {string} The identifier for the axis group element.
447
+ @param x1 {number} Starting x-coodinate for the axis.
448
+ @param y1 {number} Starting y-coodinate for the axis.
449
+ @param x2 {number} Ending x-coodinate for the axis.
450
+ @param y2 {number} Ending y-coodinate for the axis. */
451
+ _drawAxis: function(axis, id, x1, y1, x2, y2) {
452
+ var horiz = (y1 === y2);
453
+ var gl = this._wrapper.group(this._chartCont, $.extend({class_: id}, axis._lineFormat));
454
+ var gt = this._wrapper.group(this._chartCont, $.extend({class_: id + 'Labels',
455
+ textAnchor: (horiz ? 'middle' : 'end')}, axis._labelFormat));
456
+ this._wrapper.line(gl, x1, y1, x2, y2);
457
+ if (axis._ticks.major) {
458
+ var bottomRight = (x2 > (this._getValue(this._chartCont, 'width') / 2) &&
459
+ y2 > (this._getValue(this._chartCont, 'height') / 2));
460
+ var scale = (horiz ? x2 - x1 : y2 - y1) / (axis._scale.max - axis._scale.min);
461
+ var size = axis._ticks.size;
462
+ var major = Math.floor(axis._scale.min / axis._ticks.major) * axis._ticks.major;
463
+ major = (major < axis._scale.min ? major + axis._ticks.major : major);
464
+ var minor = (!axis._ticks.minor ? axis._scale.max + 1 :
465
+ Math.floor(axis._scale.min / axis._ticks.minor) * axis._ticks.minor);
466
+ minor = (minor < axis._scale.min ? minor + axis._ticks.minor : minor);
467
+ var offsets = this._getTickOffsets(axis, bottomRight);
468
+ var count = 0;
469
+ while (major <= axis._scale.max || minor <= axis._scale.max) {
470
+ var cur = Math.min(major, minor);
471
+ var len = (cur === major ? size : size / 2);
472
+ var v = (horiz ? x1 : y1) + (horiz ? cur - axis._scale.min : axis._scale.max - cur) * scale;
473
+ this._wrapper.line(gl, (horiz ? v : x1 + len * offsets[0]), (horiz ? y1 + len * offsets[0] : v),
474
+ (horiz ? v : x1 + len * offsets[1]), (horiz ? y1 + len * offsets[1] : v));
475
+ if (cur === major) {
476
+ this._wrapper.text(gt, (horiz ? v : x1 - size), (horiz ? y1 + 2 * size : v),
477
+ (axis._labels ? axis._labels[count++] : '' + cur));
478
+ }
479
+ major += (cur === major ? axis._ticks.major : 0);
480
+ minor += (cur === minor ? axis._ticks.minor : 0);
481
+ }
482
+ }
483
+ },
484
+
485
+ /** Calculate offsets based on axis and tick positions.
486
+ @private
487
+ @param axis {SVGGraphAxis} The axis definition.
488
+ @param bottomRight {boolean} <code>true</code> if this axis is appearing on the bottom or
489
+ right of the chart area, <code>false</code> if to the top or left.
490
+ @return {number[]} The array of offset multipliers (-1..+1). */
491
+ _getTickOffsets: function(axis, bottomRight) {
492
+ return [(axis._ticks.position === (bottomRight ? 'in' : 'out') || axis._ticks.position === 'both' ? -1 : 0),
493
+ (axis._ticks.position === (bottomRight ? 'out' : 'in') || axis._ticks.position === 'both' ? +1 : 0), ];
494
+ },
495
+
496
+ /** Retrieve the standard percentage axis.
497
+ @private
498
+ @return {SVGGraphAxis} Percentage axis. */
499
+ _getPercentageAxis: function() {
500
+ this._percentageAxis._title = $.svg.graphing.region.percentageText;
501
+ return this._percentageAxis;
502
+ },
503
+
504
+ /** Calculate the column totals across all the series.
505
+ @private
506
+ @return {number[]} The column totals. */
507
+ _getTotals: function() {
508
+ var totals = [];
509
+ var numVal = (this._series.length ? this._series[0]._values.length : 0);
510
+ for (var i = 0; i < numVal; i++) {
511
+ totals[i] = 0;
512
+ for (var j = 0; j < this._series.length; j++) {
513
+ totals[i] += this._series[j]._values[i];
514
+ }
515
+ }
516
+ return totals;
517
+ },
518
+
519
+ /** Draw the chart legend.
520
+ @private */
521
+ _drawLegend: function() {
522
+ if (!this.legend._show) {
523
+ return;
524
+ }
525
+ var g = this._wrapper.group(this._chartCont, {class_: 'legend'});
526
+ var dims = this._getDims(this.legend._area);
527
+ this._wrapper.rect(g, dims[this.X], dims[this.Y], dims[this.W], dims[this.H], this.legend._bgSettings);
528
+ var horiz = dims[this.W] > dims[this.H];
529
+ var numSer = this._series.length;
530
+ var offset = (horiz ? dims[this.W] : dims[this.H]) / numSer;
531
+ var xBase = dims[this.X] + 5;
532
+ var yBase = dims[this.Y] + ((horiz ? dims[this.H] : offset) + this.legend._sampleSize) / 2;
533
+ for (var i = 0; i < numSer; i++) {
534
+ var series = this._series[i];
535
+ this._wrapper.rect(g, xBase + (horiz ? i * offset : 0),
536
+ yBase + (horiz ? 0 : i * offset) - this.legend._sampleSize,
537
+ this.legend._sampleSize, this.legend._sampleSize,
538
+ {fill: series._fill, stroke: series._stroke, strokeWidth: 1});
539
+ this._wrapper.text(g, xBase + (horiz ? i * offset : 0) + this.legend._sampleSize + 5,
540
+ yBase + (horiz ? 0 : i * offset), series._name, this.legend._textSettings);
541
+ }
542
+ },
543
+
544
+ /** Show the current value status on hover.
545
+ @private
546
+ @param elem {string|SVGElement} The selector or SVG element to show the status in.
547
+ @param label {string} The current label.
548
+ @param value {number} The current value. */
549
+ _showStatus: function(elem, label, value) {
550
+ var status = this._onstatus;
551
+ if (this._onstatus) {
552
+ $(elem).hover(function() { status.apply(this, [label, value]); },
553
+ function() { status.apply(this, ['', 0]); });
554
+ }
555
+ }
556
+ });
557
+
558
+ /** A graph series definition.
559
+ @module SVGGraphSeries */
560
+
561
+ /** Details about each graph series.
562
+ <p>Created through <code>graph.addSeries()</code>.</p>
563
+ @param graph {SVGGraph} The owning graph.
564
+ @param [name] {string} The name of this series.
565
+ @param values {number[]} The values to be plotted.
566
+ @param fill {string} How the plotted values are filled.
567
+ @param [stroke] {string} The colour of the plotted lines.
568
+ @param [strokeWidth] {number} The width of the plotted lines.
569
+ @param [settings] {object} Additional settings for the plotted values.
570
+ @return {SVGGraphSeries} The new series object. */
571
+ function SVGGraphSeries(graph, name, values, fill, stroke, strokeWidth, settings) {
572
+ if (typeof name !== 'string') {
573
+ settings = strokeWidth;
574
+ strokeWidth = stroke;
575
+ stroke = fill;
576
+ fill = values;
577
+ values = name;
578
+ name = null;
579
+ }
580
+ if (typeof stroke !== 'string') {
581
+ settings = strokeWidth;
582
+ strokeWidth = stroke;
583
+ stroke = null;
584
+ }
585
+ if (typeof strokeWidth !== 'number') {
586
+ settings = strokeWidth;
587
+ strokeWidth = null;
588
+ }
589
+ this._graph = graph; // The owning graph
590
+ this._name = name || ''; // The name of this series
591
+ this._values = values || []; // The list of values for this series
592
+ this._axis = 1; // Which axis this series applies to: 1 = primary, 2 = secondary
593
+ this._fill = fill || 'green'; // How the series is plotted
594
+ this._stroke = stroke || 'black'; // The colour for the (out)line
595
+ this._strokeWidth = strokeWidth || 1; // The (out)line width
596
+ this._settings = settings || {}; // Additional formatting settings for the series
597
+ }
598
+
599
+ $.extend(SVGGraphSeries.prototype, {
600
+
601
+ /** Set or retrieve the name for this series.
602
+ @param name {string} The series' name.
603
+ @return {SVGGraphSeries|string} This series object or the series name (if no parameters). */
604
+ name: function(name) {
605
+ if (arguments.length === 0) {
606
+ return this._name;
607
+ }
608
+ this._name = name;
609
+ this._graph._drawGraph();
610
+ return this;
611
+ },
612
+
613
+ /** Set or retrieve the values for this series.
614
+ @param [name] {string} The series' name.
615
+ @param values {number[]} The values to be graphed.
616
+ @return {SVGGraphSeries|number[]} This series object or the series values (if no parameters). */
617
+ values: function(name, values) {
618
+ if (arguments.length === 0) {
619
+ return this._values;
620
+ }
621
+ if ($.isArray(name)) {
622
+ values = name;
623
+ name = null;
624
+ }
625
+ this._name = name || this._name;
626
+ this._values = values;
627
+ this._graph._drawGraph();
628
+ return this;
629
+ },
630
+
631
+ /** Set or retrieve the formatting for this series.
632
+ @param fill {string} How the values are filled when plotted.
633
+ @param [stroke] {string} The (out)line colour.
634
+ @param [strokeWidth] {number} The line's width.
635
+ @param [settings] {object} Additional formatting settings for the series.
636
+ @return {SVGGraphSeries|object} This series object or formatting settings (if no parameters). */
637
+ format: function(fill, stroke, strokeWidth, settings) {
638
+ if (arguments.length === 0) {
639
+ return $.extend({fill: this._fill, stroke: this._stroke, strokeWidth: this._strokeWidth}, this._settings);
640
+ }
641
+ if (typeof stroke !== 'string') {
642
+ settings = strokeWidth;
643
+ strokeWidth = stroke;
644
+ stroke = null;
645
+ }
646
+ if (typeof strokeWidth !== 'number') {
647
+ settings = strokeWidth;
648
+ strokeWidth = null;
649
+ }
650
+ this._fill = fill || this._fill;
651
+ this._stroke = stroke || this._stroke;
652
+ this._strokeWidth = strokeWidth || this._strokeWidth;
653
+ $.extend(this._settings, settings || {});
654
+ this._graph._drawGraph();
655
+ return this;
656
+ },
657
+
658
+ /** Return to the parent graph.
659
+ @return {SVGGraph} The parent graph. */
660
+ end: function() {
661
+ return this._graph;
662
+ }
663
+ });
664
+
665
+ /** A graph axis definition.
666
+ @module SVGGraphAxis */
667
+
668
+ /** Details about each graph axis.
669
+ @param graph {SVGGraph} The owning graph.
670
+ @param title {string} The title of the axis.
671
+ @param min [number} The minimum value displayed on this axis.
672
+ @param max {number} The maximum value displayed on this axis.
673
+ @param major {number} The distance between major ticks.
674
+ @param [minor] {number} The distance between minor ticks.
675
+ @return {SVGGraphAxis} The new axis object. */
676
+ function SVGGraphAxis(graph, title, min, max, major, minor) {
677
+ this._graph = graph; // The owning graph
678
+ this._title = title || ''; // Title of this axis
679
+ this._titleFormat = {}; // Formatting settings for the title
680
+ this._titleOffset = 0; // The offset for positioning the title
681
+ this._labels = null; // List of labels for this axis - one per possible value across all series
682
+ this._labelFormat = {}; // Formatting settings for the labels
683
+ this._lineFormat = {stroke: 'black', strokeWidth: 1}; // Formatting settings for the axis lines
684
+ this._ticks = {major: major || 10, minor: minor || 0, size: 10, position: 'out'}; // Tick mark options
685
+ this._scale = {min: min || 0, max: max || 100}; // Axis scale settings
686
+ this._crossAt = 0; // Where this axis crosses the other one
687
+ }
688
+
689
+ $.extend(SVGGraphAxis.prototype, {
690
+
691
+ /** Set or retrieve the scale for this axis.
692
+ @param min {number} The minimum value shown.
693
+ @param max {number} The maximum value shown.
694
+ @return {SVGGraphAxis|object} This axis object or min and max values (if no parameters). */
695
+ scale: function(min, max) {
696
+ if (arguments.length === 0) {
697
+ return this._scale;
698
+ }
699
+ this._scale.min = min;
700
+ this._scale.max = max;
701
+ this._graph._drawGraph();
702
+ return this;
703
+ },
704
+
705
+ /** Set or retrieve the ticks for this axis.
706
+ @param major {number} The distance between major ticks.
707
+ @param minor {number} The distance between minor ticks.
708
+ @param [size] {number} The length of the major ticks (minor are half).
709
+ @param [position] {string} The location of the ticks: 'in', 'out', 'both'.
710
+ @return {SVGGraphAxis|object} This axis object or major, minor, size, and position values (if no parameters). */
711
+ ticks: function(major, minor, size, position) {
712
+ if (arguments.length === 0) {
713
+ return this._ticks;
714
+ }
715
+ if (typeof size === 'string') {
716
+ position = size;
717
+ size = null;
718
+ }
719
+ this._ticks.major = major;
720
+ this._ticks.minor = minor;
721
+ this._ticks.size = size || this._ticks.size;
722
+ this._ticks.position = position || this._ticks.position;
723
+ this._graph._drawGraph();
724
+ return this;
725
+ },
726
+
727
+ /** Set or retrieve the title for this axis.
728
+ @param title {string} The title text
729
+ @param [offset] {number} The distance to offset the title position.
730
+ @param [colour] {string} How to colour the title.
731
+ @param [format] {object} Formatting settings for the title.
732
+ @return {SVGGraphAxis|object} This axis object or title, offset, and format values (if no parameters). */
733
+ title: function(title, offset, colour, format) {
734
+ if (arguments.length === 0) {
735
+ return {title: this._title, offset: this._titleOffset, format: this._titleFormat};
736
+ }
737
+ if (typeof offset !== 'number') {
738
+ format = colour;
739
+ colour = offset;
740
+ offset = null;
741
+ }
742
+ if (typeof colour !== 'string') {
743
+ format = colour;
744
+ colour = null;
745
+ }
746
+ this._title = title;
747
+ this._titleOffset = (offset != null ? offset : this._titleOffset);
748
+ if (colour || format) {
749
+ this._titleFormat = $.extend(format || {}, (colour ? {fill: colour} : {}));
750
+ }
751
+ this._graph._drawGraph();
752
+ return this;
753
+ },
754
+
755
+ /** Set or retrieve the labels for this axis.
756
+ @param labels {string[]} The text for each entry.
757
+ @param [colour] {string} How to colour the labels.
758
+ @param [format] {object} Formatting settings for the labels.
759
+ @return {SVGGraphAxis|object} This axis object or labels and format values (if no parameters). */
760
+ labels: function(labels, colour, format) {
761
+ if (arguments.length === 0) {
762
+ return {labels: this._labels, format: this._labelFormat};
763
+ }
764
+ if (typeof colour !== 'string') {
765
+ format = colour;
766
+ colour = null;
767
+ }
768
+ this._labels = labels;
769
+ if (colour || format) {
770
+ this._labelFormat = $.extend(format || {}, (colour ? {fill: colour} : {}));
771
+ }
772
+ this._graph._drawGraph();
773
+ return this;
774
+ },
775
+
776
+ /** Set or retrieve the line formatting for this axis.
777
+ @param colour {string} The line's colour
778
+ @param [width] {number} The line's width.
779
+ @param [settings] {object} Additional formatting settings for the line.
780
+ @return {SVGGraphAxis|object} This axis object or line formatting values (if no parameters). */
781
+ line: function(colour, width, settings) {
782
+ if (arguments.length === 0) {
783
+ return this._lineFormat;
784
+ }
785
+ if (typeof width === 'object') {
786
+ settings = width;
787
+ width = null;
788
+ }
789
+ $.extend(this._lineFormat, {stroke: colour}, (width ? {strokeWidth: width} : {}), settings || {});
790
+ this._graph._drawGraph();
791
+ return this;
792
+ },
793
+
794
+ /** Return to the parent graph.
795
+ @return {SVGGraph} The parent graph. */
796
+ end: function() {
797
+ return this._graph;
798
+ }
799
+ });
800
+
801
+ /** A graph legend definition.
802
+ @module SVGGraphLegend */
803
+
804
+ /** Details about each graph legend.
805
+ @param graph {SVGGraph} The owning graph.
806
+ @param [bgSettings] {object} Additional formatting settings for the legend background.
807
+ @param [textSettings] {object} Additional formatting settings for the legend text.
808
+ @return {SVGGraphLegend} The new legend object. */
809
+ function SVGGraphLegend(graph, bgSettings, textSettings) {
810
+ this._graph = graph; // The owning graph
811
+ this._show = true; // Show the legend?
812
+ this._area = [0.9, 0.1, 1.0, 0.9]; // The legend area: left, top, right, bottom, > 1 in pixels, <= 1 as proportion
813
+ this._sampleSize = 15; // Size of sample box
814
+ this._bgSettings = bgSettings || {stroke: 'gray'}; // Additional formatting settings for the legend background
815
+ this._textSettings = textSettings || {}; // Additional formatting settings for the text
816
+ }
817
+
818
+ $.extend(SVGGraphLegend.prototype, {
819
+
820
+ /** Set or retrieve whether the legend should be shown.
821
+ @param show {boolean} <code>true</code> to display it, <code>false</code> to hide it.
822
+ @return {SVGGraphLegend|boolean} This legend object or show the legend? (if no parameters) */
823
+ show: function(show) {
824
+ if (arguments.length === 0) {
825
+ return this._show;
826
+ }
827
+ this._show = show;
828
+ this._graph._drawGraph();
829
+ return this;
830
+ },
831
+
832
+ /** Set or retrieve the legend area.
833
+ @param left {number|number[]} > 1 is pixels, <= 1 is proportion of width or array for left, top, right, bottom.
834
+ @param [top] {number) > 1 is pixels, <= 1 is proportion of height.
835
+ @param [right] {number) > 1 is pixels, <= 1 is proportion of width.
836
+ @param [bottom] {number) > 1 is pixels, <= 1 is proportion of height.
837
+ @return {SVGGraphLegend|number[]} This legend object or the legend area:
838
+ left, top, right, bottom (if no parameters). */
839
+ area: function(left, top, right, bottom) {
840
+ if (arguments.length === 0) {
841
+ return this._area;
842
+ }
843
+ this._area = ($.isArray(left) ? left : [left, top, right, bottom]);
844
+ this._graph._drawGraph();
845
+ return this;
846
+ },
847
+
848
+ /** Set or retrieve additional settings for the legend area.
849
+ @param [sampleSize] {number} The size of the sample box to display.
850
+ @param bgSettings {object} Additional formatting settings for the legend background.
851
+ @param [textSettings] {object} Additional formatting settings for the legend text.
852
+ @return {SVGGraphLegend|object} This legend object or
853
+ bgSettings and textSettings for the legend (if no parameters). */
854
+ settings: function(sampleSize, bgSettings, textSettings) {
855
+ if (arguments.length === 0) {
856
+ return {sampleSize: this._sampleSize, bgSettings: this._bgSettings, textSettings: this._textSettings};
857
+ }
858
+ if (typeof sampleSize !== 'number') {
859
+ textSettings = bgSettings;
860
+ bgSettings = sampleSize;
861
+ sampleSize = null;
862
+ }
863
+ this._sampleSize = sampleSize || this._sampleSize;
864
+ this._bgSettings = bgSettings;
865
+ this._textSettings = textSettings || this._textSettings;
866
+ this._graph._drawGraph();
867
+ return this;
868
+ },
869
+
870
+ /** Return to the parent graph.
871
+ @return {SVGGraph} The parent graph. */
872
+ end: function() {
873
+ return this._graph;
874
+ }
875
+ });
876
+
877
+ //==============================================================================
878
+
879
+ /** Round a number to a given number of decimal points.
880
+ @private
881
+ @param num {number} The original value.
882
+ @param dec {number} The number of decimal points to retain.
883
+ @return {number} The rounded number. */
884
+ function roundNumber(num, dec) {
885
+ return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
886
+ }
887
+
888
+ var barOptions = ['barWidth (number) - the width of each bar', 'barGap (number) - the gap between sets of bars'];
889
+
890
+ //------------------------------------------------------------------------------
891
+
892
+ /** Draw a standard grouped column bar chart.
893
+ @module SVGColumnChart */
894
+ function SVGColumnChart() {
895
+ }
896
+
897
+ $.extend(SVGColumnChart.prototype, {
898
+
899
+ /** Retrieve the display title for this chart type.
900
+ @return {string} Its title. */
901
+ title: function() {
902
+ return 'Basic column chart';
903
+ },
904
+
905
+ /** Retrieve a description of this chart type.
906
+ @return {string} Its description. */
907
+ description: function() {
908
+ return 'Compare sets of values as vertical bars with grouped categories.';
909
+ },
910
+
911
+ /** Retrieve a list of the options that may be set for this chart type.
912
+ @return {string[]} Its options list. */
913
+ options: function() {
914
+ return barOptions;
915
+ },
916
+
917
+ /** Actually draw the graph in this type's style.
918
+ @param graph {SVGGraph} The graph object. */
919
+ drawGraph: function(graph) {
920
+ graph._drawChartBackground(true);
921
+ var barWidth = graph._chartOptions.barWidth || 10;
922
+ var barGap = graph._chartOptions.barGap || 10;
923
+ var numSer = graph._series.length;
924
+ var numVal = (numSer ? (graph._series[0])._values.length : 0);
925
+ var dims = graph._getDims();
926
+ var xScale = dims[graph.W] / ((numSer * barWidth + barGap) * numVal + barGap);
927
+ var yScale = dims[graph.H] / (graph.yAxis._scale.max - graph.yAxis._scale.min);
928
+ this._chart = graph._wrapper.group(graph._chartCont, {class_: 'chart'});
929
+ for (var i = 0; i < numSer; i++) {
930
+ this._drawSeries(graph, i, numSer, barWidth, barGap, dims, xScale, yScale);
931
+ }
932
+ graph._drawTitle();
933
+ graph._drawAxes(true);
934
+ this._drawXAxis(graph, numSer, numVal, barWidth, barGap, dims, xScale);
935
+ graph._drawLegend();
936
+ },
937
+
938
+ /** Plot an individual series.
939
+ @private
940
+ @param graph {SVGGraph} The graph object.
941
+ @param cur {number} The current series index.
942
+ @param numSer {number} The number of points in this series.
943
+ @param barWidth {number} The width of each bar.
944
+ @param barGap {number} The space between bars.
945
+ @param dims {number[]} The dimensions of the drawing area.
946
+ @param xScale {number} The scaling factor in the horizontal direction.
947
+ @param yScale {number} The scaling factor in the vertical direction. */
948
+ _drawSeries: function(graph, cur, numSer, barWidth, barGap, dims, xScale, yScale) {
949
+ var series = graph._series[cur];
950
+ var g = graph._wrapper.group(this._chart,
951
+ $.extend({class_: 'series' + cur, fill: series._fill, stroke: series._stroke,
952
+ strokeWidth: series._strokeWidth}, series._settings || {}));
953
+ for (var i = 0; i < series._values.length; i++) {
954
+ var r = graph._wrapper.rect(g,
955
+ dims[graph.X] + xScale * (barGap + i * (numSer * barWidth + barGap) + (cur * barWidth)),
956
+ dims[graph.Y] + yScale * (graph.yAxis._scale.max - series._values[i]),
957
+ xScale * barWidth, yScale * series._values[i]);
958
+ graph._showStatus(r, series._name, series._values[i]);
959
+ }
960
+ },
961
+
962
+ /** Draw the x-axis and its ticks.
963
+ @private
964
+ @param graph {SVGGraph} The graph object.
965
+ @param numSer {number} The number of points in this series.
966
+ @param numVal {number} The current value index.
967
+ @param barWidth {number} The width of each bar.
968
+ @param barGap {number} The space between bars.
969
+ @param dims {number[]} The dimensions of the drawing area.
970
+ @param xScale {number} The scaling factor in the horizontal direction. */
971
+ _drawXAxis: function(graph, numSer, numVal, barWidth, barGap, dims, xScale) {
972
+ var axis = graph.xAxis;
973
+ if (axis._title) {
974
+ graph._wrapper.text(graph._chartCont, dims[graph.X] + dims[graph.W] / 2,
975
+ dims[graph.Y] + dims[graph.H] + axis._titleOffset,
976
+ axis._title, $.extend({textAnchor: 'middle'}, axis._titleFormat || {}));
977
+ }
978
+ var gl = graph._wrapper.group(graph._chartCont, $.extend({class_: 'xAxis'}, axis._lineFormat));
979
+ var gt = graph._wrapper.group(graph._chartCont, $.extend({class_: 'xAxisLabels',
980
+ textAnchor: 'middle'}, axis._labelFormat));
981
+ graph._wrapper.line(gl, dims[graph.X], dims[graph.Y] + dims[graph.H],
982
+ dims[graph.X] + dims[graph.W], dims[graph.Y] + dims[graph.H]);
983
+ if (axis._ticks.major) {
984
+ var offsets = graph._getTickOffsets(axis, true);
985
+ for (var i = 1; i < numVal; i++) {
986
+ var x = dims[graph.X] + xScale * (barGap / 2 + i * (numSer * barWidth + barGap));
987
+ graph._wrapper.line(gl, x, dims[graph.Y] + dims[graph.H] + offsets[0] * axis._ticks.size,
988
+ x, dims[graph.Y] + dims[graph.H] + offsets[1] * axis._ticks.size);
989
+ }
990
+ for (var i = 0; i < numVal; i++) {
991
+ var x = dims[graph.X] + xScale * (barGap / 2 + (i + 0.5) * (numSer * barWidth + barGap));
992
+ graph._wrapper.text(gt, x, dims[graph.Y] + dims[graph.H] + 2 * axis._ticks.size,
993
+ (axis._labels ? axis._labels[i] : '' + i));
994
+ }
995
+ }
996
+ }
997
+ });
998
+
999
+ //------------------------------------------------------------------------------
1000
+
1001
+ /** Draw a stacked column bar chart.
1002
+ @module SVGStackedColumnChart */
1003
+ function SVGStackedColumnChart() {
1004
+ }
1005
+
1006
+ $.extend(SVGStackedColumnChart.prototype, {
1007
+
1008
+ /** Retrieve the display title for this chart type.
1009
+ @return {string} Its title. */
1010
+ title: function() {
1011
+ return 'Stacked column chart';
1012
+ },
1013
+
1014
+ /** Retrieve a description of this chart type.
1015
+ @return {string} Its description. */
1016
+ description: function() {
1017
+ return 'Compare sets of values as vertical bars showing ' +
1018
+ 'relative contributions to the whole for each category.';
1019
+ },
1020
+
1021
+ /** Retrieve a list of the options that may be set for this chart type.
1022
+ @return {string[]} Its options list. */
1023
+ options: function() {
1024
+ return barOptions;
1025
+ },
1026
+
1027
+ /** Actually draw the graph in this type's style.
1028
+ @param graph {SVGGraph} The graph object. */
1029
+ drawGraph: function(graph) {
1030
+ var bg = graph._drawChartBackground(true, true);
1031
+ var dims = graph._getDims();
1032
+ if (graph._gridlines[0] && graph.xAxis._ticks.major) {
1033
+ graph._drawGridlines(bg, graph._getPercentageAxis(), true, dims, graph._gridlines[0]);
1034
+ }
1035
+ var barWidth = graph._chartOptions.barWidth || 10;
1036
+ var barGap = graph._chartOptions.barGap || 10;
1037
+ var numSer = graph._series.length;
1038
+ var numVal = (numSer ? (graph._series[0])._values.length : 0);
1039
+ var xScale = dims[graph.W] / ((barWidth + barGap) * numVal + barGap);
1040
+ var yScale = dims[graph.H];
1041
+ this._chart = graph._wrapper.group(graph._chartCont, {class_: 'chart'});
1042
+ this._drawColumns(graph, numSer, numVal, barWidth, barGap, dims, xScale, yScale);
1043
+ graph._drawTitle();
1044
+ graph._wrapper.text(graph._chartCont, 0, 0, $.svg.graphing.region.percentageText,
1045
+ $.extend({textAnchor: 'middle', transform: 'translate(' +
1046
+ (dims[graph.X] - graph.yAxis._titleOffset) + ',' +
1047
+ (dims[graph.Y] + dims[graph.H] / 2) + ') rotate(-90)'}, graph.yAxis._titleFormat || {}));
1048
+ var pAxis = $.extend({}, graph._getPercentageAxis());
1049
+ $.extend(pAxis._labelFormat, graph.yAxis._labelFormat || {});
1050
+ graph._drawAxis(pAxis, 'yAxis', dims[graph.X], dims[graph.Y], dims[graph.X], dims[graph.Y] + dims[graph.H]);
1051
+ this._drawXAxis(graph, numVal, barWidth, barGap, dims, xScale);
1052
+ graph._drawLegend();
1053
+ },
1054
+
1055
+ /** Plot all of the columns.
1056
+ @private
1057
+ @param graph {SVGGraph} The graph object.
1058
+ @param numSer {number} The number of points in this series.
1059
+ @param numVal {number} The current value index.
1060
+ @param barWidth {number} The width of each bar.
1061
+ @param barGap {number} The space between bars.
1062
+ @param dims {number[]} The dimensions of the drawing area.
1063
+ @param xScale {number} The scaling factor in the horizontal direction.
1064
+ @param yScale {number} The scaling factor in the vertical direction. */
1065
+ _drawColumns: function(graph, numSer, numVal, barWidth, barGap, dims, xScale, yScale) {
1066
+ var totals = graph._getTotals();
1067
+ var accum = [];
1068
+ for (var i = 0; i < numVal; i++) {
1069
+ accum[i] = 0;
1070
+ }
1071
+ for (var s = 0; s < numSer; s++) {
1072
+ var series = graph._series[s];
1073
+ var g = graph._wrapper.group(this._chart, $.extend({class_: 'series' + s, fill: series._fill,
1074
+ stroke: series._stroke, strokeWidth: series._strokeWidth}, series._settings || {}));
1075
+ for (var i = 0; i < series._values.length; i++) {
1076
+ accum[i] += series._values[i];
1077
+ var r = graph._wrapper.rect(g, dims[graph.X] + xScale * (barGap + i * (barWidth + barGap)),
1078
+ dims[graph.Y] + yScale * (totals[i] - accum[i]) / totals[i],
1079
+ xScale * barWidth, yScale * series._values[i] / totals[i]);
1080
+ graph._showStatus(r, series._name, roundNumber(series._values[i] / totals[i] * 100, 2));
1081
+ }
1082
+ }
1083
+ },
1084
+
1085
+ /** Draw the x-axis and its ticks.
1086
+ @private
1087
+ @param graph {SVGGraph} The graph object.
1088
+ @param numVal {number} The current value index.
1089
+ @param barWidth {number} The width of each bar.
1090
+ @param barGap {number} The space between bars.
1091
+ @param dims {number[]} The dimensions of the drawing area.
1092
+ @param xScale {number} The scaling factor in the horizontal direction. */
1093
+ _drawXAxis: function(graph, numVal, barWidth, barGap, dims, xScale) {
1094
+ var axis = graph.xAxis;
1095
+ if (axis._title) {
1096
+ graph._wrapper.text(graph._chartCont, dims[graph.X] + dims[graph.W] / 2,
1097
+ dims[graph.Y] + dims[graph.H] + axis._titleOffset,
1098
+ axis._title, $.extend({textAnchor: 'middle'}, axis._titleFormat || {}));
1099
+ }
1100
+ var gl = graph._wrapper.group(graph._chartCont, $.extend({class_: 'xAxis'}, axis._lineFormat));
1101
+ var gt = graph._wrapper.group(graph._chartCont, $.extend({class_: 'xAxisLabels',
1102
+ textAnchor: 'middle'}, axis._labelFormat));
1103
+ graph._wrapper.line(gl, dims[graph.X], dims[graph.Y] + dims[graph.H],
1104
+ dims[graph.X] + dims[graph.W], dims[graph.Y] + dims[graph.H]);
1105
+ if (axis._ticks.major) {
1106
+ var offsets = graph._getTickOffsets(axis, true);
1107
+ for (var i = 1; i < numVal; i++) {
1108
+ var x = dims[graph.X] + xScale * (barGap / 2 + i * (barWidth + barGap));
1109
+ graph._wrapper.line(gl, x, dims[graph.Y] + dims[graph.H] + offsets[0] * axis._ticks.size,
1110
+ x, dims[graph.Y] + dims[graph.H] + offsets[1] * axis._ticks.size);
1111
+ }
1112
+ for (var i = 0; i < numVal; i++) {
1113
+ var x = dims[graph.X] + xScale * (barGap / 2 + (i + 0.5) * (barWidth + barGap));
1114
+ graph._wrapper.text(gt, x, dims[graph.Y] + dims[graph.H] + 2 * axis._ticks.size,
1115
+ (axis._labels ? axis._labels[i] : '' + i));
1116
+ }
1117
+ }
1118
+ }
1119
+ });
1120
+
1121
+ //------------------------------------------------------------------------------
1122
+
1123
+ /** Draw a standard grouped row bar chart.
1124
+ @module SVGRowChart */
1125
+ function SVGRowChart() {
1126
+ }
1127
+
1128
+ $.extend(SVGRowChart.prototype, {
1129
+
1130
+ /** Retrieve the display title for this chart type.
1131
+ @return {string} Its title. */
1132
+ title: function() {
1133
+ return 'Basic row chart';
1134
+ },
1135
+
1136
+ /** Retrieve a description of this chart type.
1137
+ @return {string} Its description. */
1138
+ description: function() {
1139
+ return 'Compare sets of values as horizontal rows with grouped categories.';
1140
+ },
1141
+
1142
+ /** Retrieve a list of the options that may be set for this chart type.
1143
+ @return {string[]} Its options list. */
1144
+ options: function() {
1145
+ return barOptions;
1146
+ },
1147
+
1148
+ /** Actually draw the graph in this type's style.
1149
+ @param graph {SVGGraph} The graph object. */
1150
+ drawGraph: function(graph) {
1151
+ var bg = graph._drawChartBackground(true, true);
1152
+ var dims = graph._getDims();
1153
+ graph._drawGridlines(bg, graph.yAxis, false, dims, graph._gridlines[0]);
1154
+ var barWidth = graph._chartOptions.barWidth || 10;
1155
+ var barGap = graph._chartOptions.barGap || 10;
1156
+ var numSer = graph._series.length;
1157
+ var numVal = (numSer ? (graph._series[0])._values.length : 0);
1158
+ var xScale = dims[graph.W] / (graph.yAxis._scale.max - graph.yAxis._scale.min);
1159
+ var yScale = dims[graph.H] / ((numSer * barWidth + barGap) * numVal + barGap);
1160
+ this._chart = graph._wrapper.group(graph._chartCont, {class_: 'chart'});
1161
+ for (var i = 0; i < numSer; i++) {
1162
+ this._drawSeries(graph, i, numSer, barWidth, barGap, dims, xScale, yScale);
1163
+ }
1164
+ graph._drawTitle();
1165
+ this._drawAxes(graph, numSer, numVal, barWidth, barGap, dims, yScale);
1166
+ graph._drawLegend();
1167
+ },
1168
+
1169
+ /** Plot an individual series.
1170
+ @private
1171
+ @param graph {SVGGraph} The graph object.
1172
+ @param cur {number} The current series index.
1173
+ @param numSer {number} The number of points in this series.
1174
+ @param barWidth {number} The width of each bar.
1175
+ @param barGap {number} The space between bars.
1176
+ @param dims {number[]} The dimensions of the drawing area.
1177
+ @param xScale {number} The scaling factor in the horizontal direction.
1178
+ @param yScale {number} The scaling factor in the vertical direction. */
1179
+ _drawSeries: function(graph, cur, numSer, barWidth, barGap, dims, xScale, yScale) {
1180
+ var series = graph._series[cur];
1181
+ var g = graph._wrapper.group(this._chart, $.extend({class_: 'series' + cur, fill: series._fill,
1182
+ stroke: series._stroke, strokeWidth: series._strokeWidth}, series._settings || {}));
1183
+ for (var i = 0; i < series._values.length; i++) {
1184
+ var r = graph._wrapper.rect(g, dims[graph.X] + xScale * (0 - graph.yAxis._scale.min),
1185
+ dims[graph.Y] + yScale * (barGap + i * (numSer * barWidth + barGap) + (cur * barWidth)),
1186
+ xScale * series._values[i], yScale * barWidth);
1187
+ graph._showStatus(r, series._name, series._values[i]);
1188
+ }
1189
+ },
1190
+
1191
+ /** Draw the axes for this graph.
1192
+ @private
1193
+ @param graph {SVGGraph} The graph object.
1194
+ @param numSer {number} The number of points in this series.
1195
+ @param numVal {number} The current value index.
1196
+ @param barWidth {number} The width of each bar.
1197
+ @param barGap {number} The space between bars.
1198
+ @param dims {number[]} The dimensions of the drawing area.
1199
+ @param yScale {number} The scaling factor in the vertical direction. */
1200
+ _drawAxes: function(graph, numSer, numVal, barWidth, barGap, dims, yScale) {
1201
+ // X-axis
1202
+ var axis = graph.yAxis;
1203
+ if (axis) {
1204
+ if (axis._title) {
1205
+ graph._wrapper.text(graph._chartCont, dims[graph.X] + dims[graph.W] / 2,
1206
+ dims[graph.Y] + dims[graph.H] + axis._titleOffset, axis._title, axis._titleFormat);
1207
+ }
1208
+ graph._drawAxis(axis, 'xAxis', dims[graph.X], dims[graph.Y] + dims[graph.H],
1209
+ dims[graph.X] + dims[graph.W], dims[graph.Y] + dims[graph.H]);
1210
+ }
1211
+ // Y-axis
1212
+ var axis = graph.xAxis;
1213
+ if (axis._title) {
1214
+ graph._wrapper.text(graph._chartCont, 0, 0, axis._title, $.extend({textAnchor: 'middle',
1215
+ transform: 'translate(' + (dims[graph.X] - axis._titleOffset) + ',' +
1216
+ (dims[graph.Y] + dims[graph.H] / 2) + ') rotate(-90)'}, axis._titleFormat || {}));
1217
+ }
1218
+ var gl = graph._wrapper.group(graph._chartCont, $.extend({class_: 'yAxis'}, axis._lineFormat));
1219
+ var gt = graph._wrapper.group(graph._chartCont, $.extend(
1220
+ {class_: 'yAxisLabels', textAnchor: 'end'}, axis._labelFormat));
1221
+ graph._wrapper.line(gl, dims[graph.X], dims[graph.Y], dims[graph.X], dims[graph.Y] + dims[graph.H]);
1222
+ if (axis._ticks.major) {
1223
+ var offsets = graph._getTickOffsets(axis, false);
1224
+ for (var i = 1; i < numVal; i++) {
1225
+ var y = dims[graph.Y] + yScale * (barGap / 2 + i * (numSer * barWidth + barGap));
1226
+ graph._wrapper.line(gl, dims[graph.X] + offsets[0] * axis._ticks.size, y,
1227
+ dims[graph.X] + offsets[1] * axis._ticks.size, y);
1228
+ }
1229
+ for (var i = 0; i < numVal; i++) {
1230
+ var y = dims[graph.Y] + yScale * (barGap / 2 + (i + 0.5) * (numSer * barWidth + barGap));
1231
+ graph._wrapper.text(gt, dims[graph.X] - axis._ticks.size, y,
1232
+ (axis._labels ? axis._labels[i] : '' + i));
1233
+ }
1234
+ }
1235
+ }
1236
+ });
1237
+
1238
+ //------------------------------------------------------------------------------
1239
+
1240
+ /** Draw a stacked row bar chart.
1241
+ @module SVGStackedRowChart */
1242
+ function SVGStackedRowChart() {
1243
+ }
1244
+
1245
+ $.extend(SVGStackedRowChart.prototype, {
1246
+
1247
+ /** Retrieve the display title for this chart type.
1248
+ @return {string} Its title. */
1249
+ title: function() {
1250
+ return 'Stacked row chart';
1251
+ },
1252
+
1253
+ /** Retrieve a description of this chart type.
1254
+ @return {string} Its description. */
1255
+ description: function() {
1256
+ return 'Compare sets of values as horizontal bars showing ' +
1257
+ 'relative contributions to the whole for each category.';
1258
+ },
1259
+
1260
+ /** Retrieve a list of the options that may be set for this chart type.
1261
+ @return {string[]} Its options list. */
1262
+ options: function() {
1263
+ return barOptions;
1264
+ },
1265
+
1266
+ /** Actually draw the graph in this type's style.
1267
+ @param graph {SVGGraph} The graph object. */
1268
+ drawGraph: function(graph) {
1269
+ var bg = graph._drawChartBackground(true, true);
1270
+ var dims = graph._getDims();
1271
+ if (graph._gridlines[0] && graph.xAxis._ticks.major) {
1272
+ graph._drawGridlines(bg, graph._getPercentageAxis(), false, dims, graph._gridlines[0]);
1273
+ }
1274
+ var barWidth = graph._chartOptions.barWidth || 10;
1275
+ var barGap = graph._chartOptions.barGap || 10;
1276
+ var numSer = graph._series.length;
1277
+ var numVal = (numSer ? (graph._series[0])._values.length : 0);
1278
+ var xScale = dims[graph.W];
1279
+ var yScale = dims[graph.H] / ((barWidth + barGap) * numVal + barGap);
1280
+ this._chart = graph._wrapper.group(graph._chartCont, {class_: 'chart'});
1281
+ this._drawRows(graph, numSer, numVal, barWidth, barGap, dims, xScale, yScale);
1282
+ graph._drawTitle();
1283
+ graph._wrapper.text(graph._chartCont, dims[graph.X] + dims[graph.W] / 2,
1284
+ dims[graph.Y] + dims[graph.H] + graph.xAxis._titleOffset, $.svg.graphing.region.percentageText,
1285
+ $.extend({textAnchor: 'middle'}, graph.yAxis._titleFormat || {}));
1286
+ var pAxis = $.extend({}, graph._getPercentageAxis());
1287
+ $.extend(pAxis._labelFormat, graph.yAxis._labelFormat || {});
1288
+ graph._drawAxis(pAxis, 'xAxis', dims[graph.X], dims[graph.Y] + dims[graph.H],
1289
+ dims[graph.X] + dims[graph.W], dims[graph.Y] + dims[graph.H]);
1290
+ this._drawYAxis(graph, numVal, barWidth, barGap, dims, yScale);
1291
+ graph._drawLegend();
1292
+ },
1293
+
1294
+ /** Plot all of the rows.
1295
+ @private
1296
+ @param graph {SVGGraph} The graph object.
1297
+ @param numSer {number} The number of points in this series.
1298
+ @param numVal {number} The current value index.
1299
+ @param barWidth {number} The width of each bar.
1300
+ @param barGap {number} The space between bars.
1301
+ @param dims {number[]} The dimensions of the drawing area.
1302
+ @param xScale {number} The scaling factor in the horizontal direction.
1303
+ @param yScale {number} The scaling factor in the vertical direction. */
1304
+ _drawRows: function(graph, numSer, numVal, barWidth, barGap, dims, xScale, yScale) {
1305
+ var totals = graph._getTotals();
1306
+ var accum = [];
1307
+ for (var i = 0; i < numVal; i++) {
1308
+ accum[i] = 0;
1309
+ }
1310
+ for (var s = 0; s < numSer; s++) {
1311
+ var series = graph._series[s];
1312
+ var g = graph._wrapper.group(this._chart, $.extend({class_: 'series' + s, fill: series._fill,
1313
+ stroke: series._stroke, strokeWidth: series._strokeWidth}, series._settings || {}));
1314
+ for (var i = 0; i < series._values.length; i++) {
1315
+ var r = graph._wrapper.rect(g, dims[graph.X] + xScale * accum[i] / totals[i],
1316
+ dims[graph.Y] + yScale * (barGap + i * (barWidth + barGap)),
1317
+ xScale * series._values[i] / totals[i], yScale * barWidth);
1318
+ graph._showStatus(r, series._name, roundNumber(series._values[i] / totals[i] * 100, 2));
1319
+ accum[i] += series._values[i];
1320
+ }
1321
+ }
1322
+ },
1323
+
1324
+ /** Draw the y-axis and its ticks.
1325
+ @private
1326
+ @param graph {SVGGraph} The graph object.
1327
+ @param numVal {number} The current value index.
1328
+ @param barWidth {number} The width of each bar.
1329
+ @param barGap {number} The space between bars.
1330
+ @param dims {number[]} The dimensions of the drawing area.
1331
+ @param yScale {number} The scaling factor in the vertical direction. */
1332
+ _drawYAxis: function(graph, numVal, barWidth, barGap, dims, yScale) {
1333
+ var axis = graph.xAxis;
1334
+ if (axis._title) {
1335
+ graph._wrapper.text(graph._chartCont, 0, 0, axis._title, $.extend({textAnchor: 'middle',
1336
+ transform: 'translate(' + (dims[graph.X] - axis._titleOffset) + ',' +
1337
+ (dims[graph.Y] + dims[graph.H] / 2) + ') rotate(-90)'}, axis._titleFormat || {}));
1338
+ }
1339
+ var gl = graph._wrapper.group(graph._chartCont, $.extend({class_: 'yAxis'}, axis._lineFormat));
1340
+ var gt = graph._wrapper.group(graph._chartCont,
1341
+ $.extend({class_: 'yAxisLabels', textAnchor: 'end'}, axis._labelFormat));
1342
+ graph._wrapper.line(gl, dims[graph.X], dims[graph.Y], dims[graph.X], dims[graph.Y] + dims[graph.H]);
1343
+ if (axis._ticks.major) {
1344
+ var offsets = graph._getTickOffsets(axis, false);
1345
+ for (var i = 1; i < numVal; i++) {
1346
+ var y = dims[graph.Y] + yScale * (barGap / 2 + i * (barWidth + barGap));
1347
+ graph._wrapper.line(gl, dims[graph.X] + offsets[0] * axis._ticks.size, y,
1348
+ dims[graph.X] + offsets[1] * axis._ticks.size, y);
1349
+ }
1350
+ for (var i = 0; i < numVal; i++) {
1351
+ var y = dims[graph.Y] + yScale * (barGap / 2 + (i + 0.5) * (barWidth + barGap));
1352
+ graph._wrapper.text(gt, dims[graph.X] - axis._ticks.size, y,
1353
+ (axis._labels ? axis._labels[i] : '' + i));
1354
+ }
1355
+ }
1356
+ }
1357
+ });
1358
+
1359
+ //------------------------------------------------------------------------------
1360
+
1361
+ /** Draw a standard line chart.
1362
+ @module SVGLineChart */
1363
+ function SVGLineChart() {
1364
+ }
1365
+
1366
+ $.extend(SVGLineChart.prototype, {
1367
+
1368
+ /** Retrieve the display title for this chart type.
1369
+ @return {string} Its title. */
1370
+ title: function() {
1371
+ return 'Basic line chart';
1372
+ },
1373
+
1374
+ /** Retrieve a description of this chart type.
1375
+ @return {string} Its description. */
1376
+ description: function() {
1377
+ return 'Compare sets of values as continuous lines.';
1378
+ },
1379
+
1380
+ /** Retrieve a list of the options that may be set for this chart type.
1381
+ @return {string[]} Its options list. */
1382
+ options: function() {
1383
+ return [];
1384
+ },
1385
+
1386
+ /** Actually draw the graph in this type's style.
1387
+ @param graph {SVGGraph} The graph object. */
1388
+ drawGraph: function(graph) {
1389
+ graph._drawChartBackground();
1390
+ var dims = graph._getDims();
1391
+ var xScale = dims[graph.W] / (graph.xAxis._scale.max - graph.xAxis._scale.min);
1392
+ var yScale = dims[graph.H] / (graph.yAxis._scale.max - graph.yAxis._scale.min);
1393
+ this._chart = graph._wrapper.group(graph._chartCont, {class_: 'chart'});
1394
+ for (var i = 0; i < graph._series.length; i++) {
1395
+ this._drawSeries(graph, i, dims, xScale, yScale);
1396
+ }
1397
+ graph._drawTitle();
1398
+ graph._drawAxes();
1399
+ graph._drawLegend();
1400
+ },
1401
+
1402
+ /** Plot an individual series.
1403
+ @private
1404
+ @param graph {SVGGraph} The graph object.
1405
+ @param cur {number} The current series index.
1406
+ @param dims {number[]} The dimensions of the drawing area.
1407
+ @param xScale {number} The scaling factor in the horizontal direction.
1408
+ @param yScale {number} The scaling factor in the vertical direction. */
1409
+ _drawSeries: function(graph, cur, dims, xScale, yScale) {
1410
+ var series = graph._series[cur];
1411
+ var path = graph._wrapper.createPath();
1412
+ for (var i = 0; i < series._values.length; i++) {
1413
+ var x = dims[graph.X] + i * xScale;
1414
+ var y = dims[graph.Y] + (graph.yAxis._scale.max - series._values[i]) * yScale;
1415
+ if (i === 0) {
1416
+ path.move(x, y);
1417
+ }
1418
+ else {
1419
+ path.line(x, y);
1420
+ }
1421
+ }
1422
+ var p = graph._wrapper.path(this._chart, path, $.extend({id: 'series' + cur, fill: 'none',
1423
+ stroke: series._stroke, strokeWidth: series._strokeWidth}, series._settings || {}));
1424
+ graph._showStatus(p, series._name, 0);
1425
+ }
1426
+ });
1427
+
1428
+ //------------------------------------------------------------------------------
1429
+
1430
+ /** Draw a standard pie chart.
1431
+ @module SVGPieChart */
1432
+ function SVGPieChart() {
1433
+ }
1434
+
1435
+ $.extend(SVGPieChart.prototype, {
1436
+
1437
+ _options: ['explode (number or number[]) - indexes of sections to explode out of the pie',
1438
+ 'explodeDist (number) - the distance to move an exploded section',
1439
+ 'pieGap (number) - the distance between pies for multiple values'],
1440
+
1441
+ /** Retrieve the display title for this chart type.
1442
+ @return {string} Its title. */
1443
+ title: function() {
1444
+ return 'Pie chart';
1445
+ },
1446
+
1447
+ /** Retrieve a description of this chart type.
1448
+ @return {string} Its description. */
1449
+ description: function() {
1450
+ return 'Compare relative sizes of values as contributions to the whole.';
1451
+ },
1452
+
1453
+ /** Retrieve a list of the options that may be set for this chart type.
1454
+ @return {string[]} Its options list. */
1455
+ options: function() {
1456
+ return this._options;
1457
+ },
1458
+
1459
+ /** Actually draw the graph in this type's style.
1460
+ @param graph {SVGGraph} The graph object. */
1461
+ drawGraph: function(graph) {
1462
+ graph._drawChartBackground(true, true);
1463
+ this._chart = graph._wrapper.group(graph._chartCont, {class_: 'chart'});
1464
+ var dims = graph._getDims();
1465
+ this._drawSeries(graph, dims);
1466
+ graph._drawTitle();
1467
+ graph._drawLegend();
1468
+ },
1469
+
1470
+ /** Plot all the series.
1471
+ @private
1472
+ @param graph {SVGGraph} The graph object.
1473
+ @param dims {number[]} The dimensions of the drawing area. */
1474
+ _drawSeries: function(graph, dims) {
1475
+ var totals = graph._getTotals();
1476
+ var numSer = graph._series.length;
1477
+ var numVal = (numSer ? (graph._series[0])._values.length : 0);
1478
+ var path = graph._wrapper.createPath();
1479
+ var explode = graph._chartOptions.explode || [];
1480
+ explode = ($.isArray(explode) ? explode : [explode]);
1481
+ var explodeDist = graph._chartOptions.explodeDist || 10;
1482
+ var pieGap = (numVal <= 1 ? 0 : graph._chartOptions.pieGap || 10);
1483
+ var xBase = (dims[graph.W] - (numVal * pieGap) - pieGap) / numVal / 2;
1484
+ var yBase = dims[graph.H] / 2;
1485
+ var radius = Math.min(xBase, yBase) - (explode.length > 0 ? explodeDist : 0);
1486
+ var gt = graph._wrapper.group(graph._chartCont, $.extend(
1487
+ {class_: 'xAxisLabels', textAnchor: 'middle'}, graph.xAxis._labelFormat));
1488
+ var gl = [];
1489
+ for (var i = 0; i < numVal; i++) {
1490
+ var cx = dims[graph.X] + xBase + (i * (2 * Math.min(xBase, yBase) + pieGap)) + pieGap;
1491
+ var cy = dims[graph.Y] + yBase;
1492
+ var curTotal = 0;
1493
+ for (var j = 0; j < numSer; j++) {
1494
+ var series = graph._series[j];
1495
+ if (i === 0) {
1496
+ gl[j] = graph._wrapper.group(this._chart,
1497
+ $.extend({class_: 'series' + j, fill: series._fill, stroke: series._stroke,
1498
+ strokeWidth: series._strokeWidth}, series._settings || {}));
1499
+ }
1500
+ if (series._values[i] === 0) {
1501
+ continue;
1502
+ }
1503
+ var start = (curTotal / totals[i]) * 2 * Math.PI;
1504
+ curTotal += series._values[i];
1505
+ var end = (curTotal / totals[i]) * 2 * Math.PI;
1506
+ var exploding = false;
1507
+ for (var k = 0; k < explode.length; k++) {
1508
+ if (explode[k] === j) {
1509
+ exploding = true;
1510
+ break;
1511
+ }
1512
+ }
1513
+ var x = cx + (exploding ? explodeDist * Math.cos((start + end) / 2) : 0);
1514
+ var y = cy + (exploding ? explodeDist * Math.sin((start + end) / 2) : 0);
1515
+ var p = graph._wrapper.path(gl[j], path.reset().move(x, y).
1516
+ line(x + radius * Math.cos(start), y + radius * Math.sin(start)).
1517
+ arc(radius, radius, 0, (end - start < Math.PI ? 0 : 1), 1,
1518
+ x + radius * Math.cos(end), y + radius * Math.sin(end)).close());
1519
+ graph._showStatus(p, series._name, roundNumber((end - start) / 2 / Math.PI * 100, 2));
1520
+ }
1521
+ if (graph.xAxis) {
1522
+ graph._wrapper.text(gt, cx, dims[graph.Y] + dims[graph.H] + graph.xAxis._titleOffset,
1523
+ graph.xAxis._labels[i])
1524
+ }
1525
+ }
1526
+ }
1527
+ });
1528
+
1529
+ //------------------------------------------------------------------------------
1530
+
1531
+ // Basic chart types
1532
+ $.svg.graphing.addChartType('column', new SVGColumnChart());
1533
+ $.svg.graphing.addChartType('stackedColumn', new SVGStackedColumnChart());
1534
+ $.svg.graphing.addChartType('row', new SVGRowChart());
1535
+ $.svg.graphing.addChartType('stackedRow', new SVGStackedRowChart());
1536
+ $.svg.graphing.addChartType('line', new SVGLineChart());
1537
+ $.svg.graphing.addChartType('pie', new SVGPieChart());
1538
+
1539
+ })(jQuery)