rgraph-rails 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/.travis.yml +0 -1
- data/README.md +3 -3
- data/lib/rgraph-rails/version.rb +1 -1
- data/vendor/assets/javascripts/RGraph.bar.js +239 -3764
- data/vendor/assets/javascripts/RGraph.bipolar.js +115 -1986
- data/vendor/assets/javascripts/RGraph.common.annotate.js +35 -399
- data/vendor/assets/javascripts/RGraph.common.context.js +30 -600
- data/vendor/assets/javascripts/RGraph.common.core.js +403 -5187
- data/vendor/assets/javascripts/RGraph.common.csv.js +19 -275
- data/vendor/assets/javascripts/RGraph.common.deprecated.js +35 -454
- data/vendor/assets/javascripts/RGraph.common.dynamic.js +84 -1189
- data/vendor/assets/javascripts/RGraph.common.effects.js +90 -1548
- data/vendor/assets/javascripts/RGraph.common.key.js +54 -755
- data/vendor/assets/javascripts/RGraph.common.resizing.js +37 -567
- data/vendor/assets/javascripts/RGraph.common.sheets.js +29 -356
- data/vendor/assets/javascripts/RGraph.common.tooltips.js +32 -614
- data/vendor/assets/javascripts/RGraph.common.zoom.js +14 -223
- data/vendor/assets/javascripts/RGraph.cornergauge.js +71 -0
- data/vendor/assets/javascripts/RGraph.drawing.background.js +35 -620
- data/vendor/assets/javascripts/RGraph.drawing.circle.js +35 -576
- data/vendor/assets/javascripts/RGraph.drawing.image.js +52 -807
- data/vendor/assets/javascripts/RGraph.drawing.marker1.js +41 -717
- data/vendor/assets/javascripts/RGraph.drawing.marker2.js +37 -668
- data/vendor/assets/javascripts/RGraph.drawing.marker3.js +36 -563
- data/vendor/assets/javascripts/RGraph.drawing.poly.js +40 -608
- data/vendor/assets/javascripts/RGraph.drawing.rect.js +35 -597
- data/vendor/assets/javascripts/RGraph.drawing.text.js +34 -642
- data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +50 -809
- data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +51 -856
- data/vendor/assets/javascripts/RGraph.fuel.js +58 -964
- data/vendor/assets/javascripts/RGraph.funnel.js +55 -984
- data/vendor/assets/javascripts/RGraph.gantt.js +75 -1241
- data/vendor/assets/javascripts/RGraph.gauge.js +87 -1397
- data/vendor/assets/javascripts/RGraph.hbar.js +143 -2376
- data/vendor/assets/javascripts/RGraph.hprogress.js +80 -1397
- data/vendor/assets/javascripts/RGraph.line.js +241 -4162
- data/vendor/assets/javascripts/RGraph.meter.js +74 -1278
- metadata +3 -30
- data/vendor/assets/images/bg.png +0 -0
- data/vendor/assets/images/bullet.png +0 -0
- data/vendor/assets/images/facebook-large.png +0 -0
- data/vendor/assets/images/google-plus-large.png +0 -0
- data/vendor/assets/images/logo.png +0 -0
- data/vendor/assets/images/meter-image-sd-needle.png +0 -0
- data/vendor/assets/images/meter-image-sd.png +0 -0
- data/vendor/assets/images/meter-sketch-needle.png +0 -0
- data/vendor/assets/images/meter-sketch.png +0 -0
- data/vendor/assets/images/odometer-background.png +0 -0
- data/vendor/assets/images/rgraph.jpg +0 -0
- data/vendor/assets/images/title.png +0 -0
- data/vendor/assets/images/twitter-large.png +0 -0
- data/vendor/assets/javascripts/RGraph.modaldialog.js +0 -301
- data/vendor/assets/javascripts/RGraph.odo.js +0 -1265
- data/vendor/assets/javascripts/RGraph.pie.js +0 -2272
- data/vendor/assets/javascripts/RGraph.radar.js +0 -1847
- data/vendor/assets/javascripts/RGraph.rose.js +0 -1877
- data/vendor/assets/javascripts/RGraph.rscatter.js +0 -1425
- data/vendor/assets/javascripts/RGraph.scatter.js +0 -2970
- data/vendor/assets/javascripts/RGraph.semicircularprogress.js +0 -1015
- data/vendor/assets/javascripts/RGraph.thermometer.js +0 -1129
- data/vendor/assets/javascripts/RGraph.vprogress.js +0 -1452
- data/vendor/assets/javascripts/RGraph.waterfall.js +0 -1252
- data/vendor/assets/javascripts/financial-data.js +0 -1067
- data/vendor/assets/stylesheets/ModalDialog.css +0 -90
- data/vendor/assets/stylesheets/animations.css +0 -3347
- data/vendor/assets/stylesheets/website.css +0 -446
@@ -1,1847 +0,0 @@
|
|
1
|
-
// version: 2016-06-04
|
2
|
-
/**
|
3
|
-
* o--------------------------------------------------------------------------------o
|
4
|
-
* | This file is part of the RGraph package - you can learn more at: |
|
5
|
-
* | |
|
6
|
-
* | http://www.rgraph.net |
|
7
|
-
* | |
|
8
|
-
* | RGraph is dual licensed under the Open Source GPL (General Public License) |
|
9
|
-
* | v2.0 license and a commercial license which means that you're not bound by |
|
10
|
-
* | the terms of the GPL. The commercial license is just 99 GBP and you can |
|
11
|
-
* | read about it here: |
|
12
|
-
* | http://www.rgraph.net/license |
|
13
|
-
* o--------------------------------------------------------------------------------o
|
14
|
-
*/
|
15
|
-
|
16
|
-
RGraph = window.RGraph || {isRGraph: true};
|
17
|
-
|
18
|
-
/**
|
19
|
-
* The traditional radar chart constructor
|
20
|
-
*
|
21
|
-
* @param string id The ID of the canvas
|
22
|
-
* @param array data An array of data to represent
|
23
|
-
*/
|
24
|
-
RGraph.Radar = function (conf)
|
25
|
-
{
|
26
|
-
/**
|
27
|
-
* Allow for object config style
|
28
|
-
*/
|
29
|
-
if ( typeof conf === 'object'
|
30
|
-
&& typeof conf.data === 'object'
|
31
|
-
&& typeof conf.id === 'string') {
|
32
|
-
|
33
|
-
var parseConfObjectForOptions = true; // Set this so the config is parsed (at the end of the constructor)
|
34
|
-
|
35
|
-
// Turn conf.data into a multi-d array if it's not already
|
36
|
-
if (typeof conf.data[0] === 'number' || typeof conf.data[0] === 'string') {
|
37
|
-
conf.data = [conf.data];
|
38
|
-
}
|
39
|
-
|
40
|
-
} else {
|
41
|
-
|
42
|
-
var conf = {id: conf, data: []};
|
43
|
-
|
44
|
-
// Arguments style: var foo = new RGraph.Radar('cvs', [1,2,3], [1,2,3], [1,2,3]);
|
45
|
-
if (typeof arguments[1] === 'object' && typeof arguments[1][0] === 'number') {
|
46
|
-
for (var i=1; i<arguments.length; ++i) {
|
47
|
-
conf.data.push(RGraph.arrayClone(arguments[i]));
|
48
|
-
}
|
49
|
-
|
50
|
-
// Arguments style: var foo = new RGraph.Radar('cvs', [[1,2,3], [1,2,3], [1,2,3]]);
|
51
|
-
} else if ( typeof arguments[1] === 'object'
|
52
|
-
&& typeof arguments[1][0] === 'object'
|
53
|
-
&& typeof arguments[1][0][0] === 'number') {
|
54
|
-
|
55
|
-
conf.data = RGraph.arrayClone(arguments[1]);
|
56
|
-
}
|
57
|
-
}
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
this.id = conf.id;
|
63
|
-
this.canvas = document.getElementById(conf.id);
|
64
|
-
this.context = this.canvas.getContext ? this.canvas.getContext("2d") : null;
|
65
|
-
this.canvas.__object__ = this;
|
66
|
-
this.type = 'radar';
|
67
|
-
this.isRGraph = true;
|
68
|
-
this.data = [];
|
69
|
-
this.max = 0;
|
70
|
-
this.uid = RGraph.CreateUID();
|
71
|
-
this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.CreateUID();
|
72
|
-
this.colorsParsed = false;
|
73
|
-
this.coords = [];
|
74
|
-
this.coordsText = [];
|
75
|
-
this.original_data = [];
|
76
|
-
this.original_colors = [];
|
77
|
-
this.firstDraw = true; // After the first draw this will be false
|
78
|
-
|
79
|
-
/**
|
80
|
-
* Add the data to the .original_data array and work out the max value
|
81
|
-
*
|
82
|
-
* 2/5/14 Now also use this loop to ensure that the data pieces
|
83
|
-
* are numbers
|
84
|
-
*/
|
85
|
-
for (var i=0,len=conf.data.length; i<len; ++i) {
|
86
|
-
|
87
|
-
// Convert strings to numbers
|
88
|
-
for (var j=0; j<conf.data[i].length; ++j) {
|
89
|
-
if (typeof conf.data[i][j] === 'string') {
|
90
|
-
conf.data[i][j] = parseFloat(conf.data[i][j]);
|
91
|
-
}
|
92
|
-
}
|
93
|
-
|
94
|
-
this.original_data.push(RGraph.arrayClone(conf.data[i]));
|
95
|
-
this.data.push(RGraph.arrayClone(conf.data[i]));
|
96
|
-
this.max = Math.max(this.max, RGraph.arrayMax(conf.data[i]));
|
97
|
-
}
|
98
|
-
|
99
|
-
|
100
|
-
this.properties =
|
101
|
-
{
|
102
|
-
'chart.strokestyle': '#aaa',
|
103
|
-
'chart.gutter.left': 25,
|
104
|
-
'chart.gutter.right': 25,
|
105
|
-
'chart.gutter.top': 25,
|
106
|
-
'chart.gutter.bottom': 25,
|
107
|
-
'chart.linewidth': 1,
|
108
|
-
'chart.colors': ['rgba(255,255,0,0.25)','rgba(0,255,255,0.25)','rgba(255,0,0,0.5)', 'red', 'green', 'blue', 'pink', 'aqua','brown','orange','grey'],
|
109
|
-
'chart.colors.alpha': null,
|
110
|
-
'chart.circle': 0,
|
111
|
-
'chart.circle.fill': 'red',
|
112
|
-
'chart.circle.stroke': 'black',
|
113
|
-
|
114
|
-
'chart.labels': [],
|
115
|
-
'chart.labels.color': null,
|
116
|
-
'chart.labels.offset': 10,
|
117
|
-
'chart.labels.axes': '',
|
118
|
-
'chart.labels.background.fill': 'white',
|
119
|
-
'chart.labels.boxed': false,
|
120
|
-
'chart.labels.axes.bold': [],
|
121
|
-
'chart.labels.axes.boxed': null, // This defaults to true - but that's set in the Draw() method
|
122
|
-
'chart.labels.axes.boxed.zero': true,
|
123
|
-
'chart.labels.specific': [],
|
124
|
-
|
125
|
-
'chart.labels.count': 5,
|
126
|
-
'chart.background.circles': true,
|
127
|
-
'chart.background.circles.count': null,
|
128
|
-
'chart.background.circles.color': '#ddd',
|
129
|
-
'chart.background.circles.poly': true,
|
130
|
-
'chart.background.circles.spokes': 24,
|
131
|
-
'chart.text.size': 12,
|
132
|
-
'chart.text.size.scale': null,
|
133
|
-
'chart.text.font': 'Segoe UI, Arial, Verdana, sans-serif',
|
134
|
-
'chart.text.color': 'black',
|
135
|
-
'chart.text.accessible': true,
|
136
|
-
'chart.text.accessible.overflow': 'visible',
|
137
|
-
'chart.text.accessible.pointerevents': false,
|
138
|
-
'chart.title': '',
|
139
|
-
'chart.title.background': null,
|
140
|
-
'chart.title.hpos': null,
|
141
|
-
'chart.title.vpos': null,
|
142
|
-
'chart.title.color': 'black',
|
143
|
-
'chart.title.bold': true,
|
144
|
-
'chart.title.font': null,
|
145
|
-
'chart.title.x': null,
|
146
|
-
'chart.title.y': null,
|
147
|
-
'chart.title.halign': null,
|
148
|
-
'chart.title.valign': null,
|
149
|
-
'chart.linewidth': 1,
|
150
|
-
'chart.key': null,
|
151
|
-
'chart.key.background': 'white',
|
152
|
-
'chart.key.shadow': false,
|
153
|
-
'chart.key.shadow.color': '#666',
|
154
|
-
'chart.key.shadow.blur': 3,
|
155
|
-
'chart.key.shadow.offsetx': 2,
|
156
|
-
'chart.key.shadow.offsety': 2,
|
157
|
-
'chart.key.position': 'graph',
|
158
|
-
'chart.key.halign': 'right',
|
159
|
-
'chart.key.position.gutter.boxed': false,
|
160
|
-
'chart.key.position.x': null,
|
161
|
-
'chart.key.position.y': null,
|
162
|
-
'chart.key.color.shape': 'square',
|
163
|
-
'chart.key.rounded': true,
|
164
|
-
'chart.key.linewidth': 1,
|
165
|
-
'chart.key.colors': null,
|
166
|
-
'chart.key.interactive': false,
|
167
|
-
'chart.key.interactive.highlight.chart.stroke': 'rgba(255,0,0,0.3)',
|
168
|
-
'chart.key.interactive.highlight.label': 'rgba(255,0,0,0.2)',
|
169
|
-
'chart.key.text.color': 'black',
|
170
|
-
'chart.contextmenu': null,
|
171
|
-
'chart.annotatable': false,
|
172
|
-
'chart.annotate.color': 'black',
|
173
|
-
'chart.zoom.factor': 1.5,
|
174
|
-
'chart.zoom.fade.in': true,
|
175
|
-
'chart.zoom.fade.out': true,
|
176
|
-
'chart.zoom.hdir': 'right',
|
177
|
-
'chart.zoom.vdir': 'down',
|
178
|
-
'chart.zoom.frames': 25,
|
179
|
-
'chart.zoom.delay': 16.666,
|
180
|
-
'chart.zoom.shadow': true,
|
181
|
-
'chart.zoom.background': true,
|
182
|
-
'chart.zoom.action': 'zoom',
|
183
|
-
'chart.tooltips.effect': 'fade',
|
184
|
-
'chart.tooltips.event': 'onmousemove',
|
185
|
-
'chart.tooltips.css.class': 'RGraph_tooltip',
|
186
|
-
'chart.tooltips.highlight': true,
|
187
|
-
'chart.highlight.stroke': 'gray',
|
188
|
-
'chart.highlight.fill': 'rgba(255,255,255,0.7)',
|
189
|
-
'chart.highlight.point.radius': 2,
|
190
|
-
'chart.resizable': false,
|
191
|
-
'chart.resize.handle.adjust': [0,0],
|
192
|
-
'chart.resize.handle.background': null,
|
193
|
-
'chart.ymax': null,
|
194
|
-
'chart.accumulative': false,
|
195
|
-
'chart.radius': null,
|
196
|
-
'chart.events.click': null,
|
197
|
-
'chart.events.mousemove': null,
|
198
|
-
'chart.scale.decimals': 0,
|
199
|
-
'chart.scale.point': '.',
|
200
|
-
'chart.scale.thousand': ',',
|
201
|
-
'chart.units.pre': '',
|
202
|
-
'chart.units.post': '',
|
203
|
-
'chart.tooltips': null,
|
204
|
-
'chart.tooltips.event': 'onmousemove',
|
205
|
-
'chart.centerx': null,
|
206
|
-
'chart.centery': null,
|
207
|
-
'chart.radius': null,
|
208
|
-
'chart.numxticks': 5,
|
209
|
-
'chart.numyticks': 5,
|
210
|
-
'chart.axes.color': 'rgba(0,0,0,0)',
|
211
|
-
'chart.highlights': false,
|
212
|
-
'chart.highlights.stroke': '#ddd',
|
213
|
-
'chart.highlights.fill': null,
|
214
|
-
'chart.highlights.radius': 3,
|
215
|
-
'chart.fill.click': null,
|
216
|
-
'chart.fill.mousemove': null,
|
217
|
-
'chart.fill.tooltips': null,
|
218
|
-
'chart.fill.highlight.fill': 'rgba(255,255,255,0.7)',
|
219
|
-
'chart.fill.highlight.stroke': 'rgba(0,0,0,0)',
|
220
|
-
'chart.fill.mousemove.redraw': false,
|
221
|
-
'chart.animation.trace.clip': 1,
|
222
|
-
'chart.clearto': 'rgba(0,0,0,0)'
|
223
|
-
}
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
// Must have at least 3 points
|
228
|
-
for (var dataset=0; dataset<this.data.length; ++dataset) {
|
229
|
-
if (this.data[dataset].length < 3) {
|
230
|
-
alert('[RADAR] You must specify at least 3 data points');
|
231
|
-
return;
|
232
|
-
}
|
233
|
-
}
|
234
|
-
|
235
|
-
|
236
|
-
/**
|
237
|
-
* Linearize the data and then create the $ objects
|
238
|
-
*/
|
239
|
-
var idx = 0;
|
240
|
-
for (var dataset=0; dataset<this.data.length; ++dataset) {
|
241
|
-
for (var i=0,len=this.data[dataset].length; i<len; ++i) {
|
242
|
-
this['$' + (idx++)] = {};
|
243
|
-
}
|
244
|
-
}
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
/**
|
249
|
-
* Translate half a pixel for antialiasing purposes - but only if it hasn't beeen
|
250
|
-
* done already
|
251
|
-
*/
|
252
|
-
if (!this.canvas.__rgraph_aa_translated__) {
|
253
|
-
this.context.translate(0.5,0.5);
|
254
|
-
|
255
|
-
this.canvas.__rgraph_aa_translated__ = true;
|
256
|
-
}
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
// Short variable names
|
262
|
-
var RG = RGraph,
|
263
|
-
ca = this.canvas,
|
264
|
-
co = ca.getContext('2d'),
|
265
|
-
prop = this.properties,
|
266
|
-
pa2 = RG.path2,
|
267
|
-
win = window,
|
268
|
-
doc = document,
|
269
|
-
ma = Math
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
/**
|
274
|
-
* "Decorate" the object with the generic effects if the effects library has been included
|
275
|
-
*/
|
276
|
-
if (RG.Effects && typeof RG.Effects.decorate === 'function') {
|
277
|
-
RG.Effects.decorate(this);
|
278
|
-
}
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
/**
|
284
|
-
* A simple setter
|
285
|
-
*
|
286
|
-
* @param string name The name of the property to set
|
287
|
-
* @param string value The value of the property
|
288
|
-
*/
|
289
|
-
this.set =
|
290
|
-
this.Set = function (name, value)
|
291
|
-
{
|
292
|
-
var value = typeof arguments[1] === 'undefined' ? null : arguments[1];
|
293
|
-
|
294
|
-
/**
|
295
|
-
* the number of arguments is only one and it's an
|
296
|
-
* object - parse it for configuration data and return.
|
297
|
-
*/
|
298
|
-
if (arguments.length === 1 && typeof name === 'object') {
|
299
|
-
RG.parseObjectStyleConfig(this, name);
|
300
|
-
return this;
|
301
|
-
}
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
/**
|
308
|
-
* This should be done first - prepend the propertyy name with "chart." if necessary
|
309
|
-
*/
|
310
|
-
if (name.substr(0,6) != 'chart.') {
|
311
|
-
name = 'chart.' + name;
|
312
|
-
}
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
// Convert uppercase letters to dot+lower case letter
|
318
|
-
while(name.match(/([A-Z])/)) {
|
319
|
-
name = name.replace(/([A-Z])/, '.' + RegExp.$1.toLowerCase());
|
320
|
-
}
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
if (name == 'chart.text.diameter') {
|
328
|
-
name = 'chart.text.size';
|
329
|
-
}
|
330
|
-
|
331
|
-
/**
|
332
|
-
* If the name is chart.color, set chart.colors too
|
333
|
-
*/
|
334
|
-
if (name == 'chart.color') {
|
335
|
-
this.properties['chart.colors'] = [value];
|
336
|
-
}
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
prop[name] = value;
|
344
|
-
|
345
|
-
return this;
|
346
|
-
};
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
/**
|
353
|
-
* A simple getter
|
354
|
-
*
|
355
|
-
* @param string name The name of the property to get
|
356
|
-
*/
|
357
|
-
this.get =
|
358
|
-
this.Get = function (name)
|
359
|
-
{
|
360
|
-
/**
|
361
|
-
* This should be done first - prepend the property name with "chart." if necessary
|
362
|
-
*/
|
363
|
-
if (name.substr(0,6) != 'chart.') {
|
364
|
-
name = 'chart.' + name;
|
365
|
-
}
|
366
|
-
|
367
|
-
// Convert uppercase letters to dot+lower case letter
|
368
|
-
name = name.replace(/([A-Z])/g, function (str)
|
369
|
-
{
|
370
|
-
return '.' + String(RegExp.$1).toLowerCase()
|
371
|
-
});
|
372
|
-
|
373
|
-
if (name == 'chart.text.diameter') {
|
374
|
-
name = 'chart.text.size';
|
375
|
-
}
|
376
|
-
|
377
|
-
return prop[name];
|
378
|
-
};
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
/**
|
384
|
-
* The draw method which does all the brunt of the work
|
385
|
-
*/
|
386
|
-
this.draw =
|
387
|
-
this.Draw = function ()
|
388
|
-
{
|
389
|
-
/**
|
390
|
-
* Fire the onbeforedraw event
|
391
|
-
*/
|
392
|
-
RG.FireCustomEvent(this, 'onbeforedraw');
|
393
|
-
|
394
|
-
// NB: Colors are parsed further down
|
395
|
-
|
396
|
-
// Reset the coords array to stop it growing
|
397
|
-
this.coords = [];
|
398
|
-
this.coords2 = [];
|
399
|
-
this.coordsText = [];
|
400
|
-
|
401
|
-
/**
|
402
|
-
* Reset the data to the original_data
|
403
|
-
*/
|
404
|
-
this.data = RG.arrayClone(this.original_data);
|
405
|
-
|
406
|
-
// Loop thru the data array if chart.accumulative is enable checking to see if all the
|
407
|
-
// datasets have the same number of elements.
|
408
|
-
if (prop['chart.accumulative']) {
|
409
|
-
for (var i=0; i<this.data.length; ++i) {
|
410
|
-
if (this.data[i].length != this.data[0].length) {
|
411
|
-
alert('[RADAR] Error! When the radar has chart.accumulative set to true all the datasets must have the same number of elements');
|
412
|
-
}
|
413
|
-
}
|
414
|
-
}
|
415
|
-
|
416
|
-
|
417
|
-
/**
|
418
|
-
* This defaults to true, but needs to be an array with a size matching the number of
|
419
|
-
* labels.
|
420
|
-
*/
|
421
|
-
if (RG.isNull(prop['chart.labels.axes.boxed'])) {
|
422
|
-
prop['chart.labels.axes.boxed'] = [];
|
423
|
-
for (var i=0; i<(prop['chart.labels.specific'].length || prop['chart.labels.count'] || 5); ++i) {
|
424
|
-
prop['chart.labels.axes.boxed'][i] = false;
|
425
|
-
}
|
426
|
-
}
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
/**
|
432
|
-
* This is new in May 2011 and facilitates indiviual gutter settings,
|
433
|
-
* eg chart.gutter.left
|
434
|
-
*/
|
435
|
-
this.gutterLeft = prop['chart.gutter.left'];
|
436
|
-
this.gutterRight = prop['chart.gutter.right'];
|
437
|
-
this.gutterTop = prop['chart.gutter.top'];
|
438
|
-
this.gutterBottom = prop['chart.gutter.bottom'];
|
439
|
-
|
440
|
-
this.centerx = ((ca.width - this.gutterLeft - this.gutterRight) / 2) + this.gutterLeft;
|
441
|
-
this.centery = ((ca.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop;
|
442
|
-
this.radius = Math.min(ca.width - this.gutterLeft - this.gutterRight, ca.height - this.gutterTop - this.gutterBottom) / 2;
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
/**
|
447
|
-
* Allow these to be set by hand
|
448
|
-
*/
|
449
|
-
if (typeof prop['chart.centerx'] == 'number') this.centerx = 2 * prop['chart.centerx'];
|
450
|
-
if (typeof prop['chart.centery'] == 'number') this.centery = 2 * prop['chart.centery'];
|
451
|
-
if (typeof prop['chart.radius'] == 'number') this.radius = prop['chart.radius'];
|
452
|
-
|
453
|
-
|
454
|
-
/**
|
455
|
-
* Parse the colors for gradients. Its down here so that the center X/Y can be used
|
456
|
-
*/
|
457
|
-
if (!this.colorsParsed) {
|
458
|
-
|
459
|
-
this.parseColors();
|
460
|
-
|
461
|
-
// Don't want to do this again
|
462
|
-
this.colorsParsed = true;
|
463
|
-
}
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
// Work out the maximum value and the sum
|
468
|
-
if (!prop['chart.ymax']) {
|
469
|
-
|
470
|
-
// this.max is calculated in the constructor
|
471
|
-
|
472
|
-
// Work out this.max again if the chart is (now) set to be accumulative
|
473
|
-
if (prop['chart.accumulative']) {
|
474
|
-
|
475
|
-
var accumulation = [];
|
476
|
-
var len = this.original_data[0].length
|
477
|
-
|
478
|
-
for (var i=1; i<this.original_data.length; ++i) {
|
479
|
-
if (this.original_data[i].length != len) {
|
480
|
-
alert('[RADAR] Error! Stacked Radar chart datasets must all be the same size!');
|
481
|
-
}
|
482
|
-
|
483
|
-
for (var j=0; j<this.original_data[i].length; ++j) {
|
484
|
-
this.data[i][j] += this.data[i - 1][j];
|
485
|
-
this.max = Math.max(this.max, this.data[i][j]);
|
486
|
-
}
|
487
|
-
}
|
488
|
-
}
|
489
|
-
|
490
|
-
|
491
|
-
this.scale2 = RG.getScale2(this, {'max':typeof(prop['chart.ymax']) == 'number' ? prop['chart.ymax'] : this.max,
|
492
|
-
'min':0,
|
493
|
-
'scale.decimals':Number(prop['chart.scale.decimals']),
|
494
|
-
'scale.point':prop['chart.scale.point'],
|
495
|
-
'scale.thousand':prop['chart.scale.thousand'],
|
496
|
-
'scale.round':prop['chart.scale.round'],
|
497
|
-
'units.pre':prop['chart.units.pre'],
|
498
|
-
'units.post':prop['chart.units.post'],
|
499
|
-
'ylabels.count':prop['chart.labels.count']
|
500
|
-
});
|
501
|
-
this.max = this.scale2.max;
|
502
|
-
|
503
|
-
} else {
|
504
|
-
var ymax = prop['chart.ymax'];
|
505
|
-
|
506
|
-
this.scale2 = RG.getScale2(this, {'max':ymax,
|
507
|
-
'min':0,
|
508
|
-
'strict':true,
|
509
|
-
'scale.decimals':Number(prop['chart.scale.decimals']),
|
510
|
-
'scale.point':prop['chart.scale.point'],
|
511
|
-
'scale.thousand':prop['chart.scale.thousand'],
|
512
|
-
'scale.round':prop['chart.scale.round'],
|
513
|
-
'units.pre':prop['chart.units.pre'],
|
514
|
-
'units.post':prop['chart.units.post'],
|
515
|
-
'ylabels.count':prop['chart.labels.count']
|
516
|
-
});
|
517
|
-
this.max = this.scale2.max;
|
518
|
-
}
|
519
|
-
|
520
|
-
this.drawBackground();
|
521
|
-
this.drawAxes();
|
522
|
-
this.drawCircle();
|
523
|
-
this.drawLabels();
|
524
|
-
|
525
|
-
|
526
|
-
/**
|
527
|
-
* Allow clipping
|
528
|
-
*/
|
529
|
-
co.save();
|
530
|
-
co.beginPath();
|
531
|
-
co.arc(this.centerx, this.centery, this.radius * 2, -RG.HALFPI, (RG.TWOPI * prop['chart.animation.trace.clip']) - RG.HALFPI, false);
|
532
|
-
co.lineTo(this.centerx, this.centery);
|
533
|
-
co.closePath();
|
534
|
-
co.clip();
|
535
|
-
|
536
|
-
this.DrawChart();
|
537
|
-
this.DrawHighlights();
|
538
|
-
co.restore();
|
539
|
-
|
540
|
-
//
|
541
|
-
// Draw the axis labels
|
542
|
-
//
|
543
|
-
this.drawAxisLabels();
|
544
|
-
|
545
|
-
// Draw the title
|
546
|
-
if (prop['chart.title']) {
|
547
|
-
RG.DrawTitle(this, prop['chart.title'], this.gutterTop, null, prop['chart.title.diameter'] ? prop['chart.title.diameter'] : null)
|
548
|
-
}
|
549
|
-
|
550
|
-
// Draw the key if necessary
|
551
|
-
// obj, key, colors
|
552
|
-
if (prop['chart.key']) {
|
553
|
-
RG.DrawKey(this, prop['chart.key'], prop['chart.colors']);
|
554
|
-
}
|
555
|
-
|
556
|
-
/**
|
557
|
-
* Show the context menu
|
558
|
-
*/
|
559
|
-
if (prop['chart.contextmenu']) {
|
560
|
-
RG.ShowContext(this);
|
561
|
-
}
|
562
|
-
|
563
|
-
|
564
|
-
/**
|
565
|
-
* This function enables resizing
|
566
|
-
*/
|
567
|
-
if (prop['chart.resizable']) {
|
568
|
-
RG.AllowResizing(this);
|
569
|
-
}
|
570
|
-
|
571
|
-
|
572
|
-
/**
|
573
|
-
* This installs the event listeners
|
574
|
-
*/
|
575
|
-
RG.InstallEventListeners(this);
|
576
|
-
|
577
|
-
/**
|
578
|
-
* This installs the Radar chart specific area listener
|
579
|
-
*/
|
580
|
-
if ( (prop['chart.fill.click'] || prop['chart.fill.mousemove'] || !RG.is_null(prop['chart.fill.tooltips'])) && !this.__fill_click_listeners_installed__) {
|
581
|
-
this.AddFillListeners();
|
582
|
-
this.__fill_click_listeners_installed__ = true;
|
583
|
-
}
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
/**
|
588
|
-
* Fire the onfirstdraw event
|
589
|
-
*/
|
590
|
-
if (this.firstDraw) {
|
591
|
-
RG.fireCustomEvent(this, 'onfirstdraw');
|
592
|
-
this.firstDraw = false;
|
593
|
-
this.firstDrawFunc();
|
594
|
-
}
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
/**
|
600
|
-
* Fire the RGraph ondraw event
|
601
|
-
*/
|
602
|
-
RGraph.FireCustomEvent(this, 'ondraw');
|
603
|
-
|
604
|
-
return this;
|
605
|
-
};
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
/**
|
610
|
-
* Used in chaining. Runs a function there and then - not waiting for
|
611
|
-
* the events to fire (eg the onbeforedraw event)
|
612
|
-
*
|
613
|
-
* @param function func The function to execute
|
614
|
-
*/
|
615
|
-
this.exec = function (func)
|
616
|
-
{
|
617
|
-
func(this);
|
618
|
-
|
619
|
-
return this;
|
620
|
-
};
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
/**
|
626
|
-
* Draws the background circles
|
627
|
-
*/
|
628
|
-
this.drawBackground =
|
629
|
-
this.DrawBackground = function ()
|
630
|
-
{
|
631
|
-
var color = prop['chart.background.circles.color'];
|
632
|
-
var poly = prop['chart.background.circles.poly'];
|
633
|
-
var spacing = prop['chart.background.circles.spacing'];
|
634
|
-
var spokes = prop['chart.background.circles.spokes'];
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
// Set the linewidth for the grid (so that repeated redrawing works OK)
|
640
|
-
co.lineWidth = 1;
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
/**
|
646
|
-
* Draws the background circles
|
647
|
-
*/
|
648
|
-
if (prop['chart.background.circles'] && poly == false) {
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
// Draw the concentric circles
|
655
|
-
co.strokeStyle = color;
|
656
|
-
co.beginPath();
|
657
|
-
|
658
|
-
var numrings = typeof(prop['chart.background.circles.count']) == 'number' ? prop['chart.background.circles.count'] : prop['chart.labels.count'];
|
659
|
-
|
660
|
-
// TODO Currently set to 5 - needs changing
|
661
|
-
for (var r=0; r<=this.radius; r+=(this.radius / numrings)) {
|
662
|
-
co.moveTo(this.centerx, this.centery);
|
663
|
-
co.arc(this.centerx, this.centery,r, 0, RG.TWOPI, false);
|
664
|
-
}
|
665
|
-
co.stroke();
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
/**
|
672
|
-
* Draw the diagonals/spokes
|
673
|
-
*/
|
674
|
-
co.strokeStyle = color;
|
675
|
-
|
676
|
-
for (var i=0; i<360; i+=(360 / spokes)) {
|
677
|
-
co.beginPath();
|
678
|
-
co.arc(this.centerx,
|
679
|
-
this.centery,
|
680
|
-
this.radius,
|
681
|
-
(i / 360) * RG.TWOPI,
|
682
|
-
((i+0.001) / 360) * RG.TWOPI,
|
683
|
-
false); // The 0.01 avoids a bug in Chrome 6
|
684
|
-
co.lineTo(this.centerx, this.centery);
|
685
|
-
co.stroke();
|
686
|
-
}
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
/**
|
694
|
-
* The background"circles" are actually drawn as a poly based on how many points there are
|
695
|
-
* (ie hexagons if there are 6 points, squares if the are four etc)
|
696
|
-
*/
|
697
|
-
} else if (prop['chart.background.circles'] && poly == true) {
|
698
|
-
|
699
|
-
/**
|
700
|
-
* Draw the diagonals/spokes
|
701
|
-
*/
|
702
|
-
co.strokeStyle = color;
|
703
|
-
var increment = 360 / this.data[0].length
|
704
|
-
|
705
|
-
for (var i=0; i<360; i+=increment) {
|
706
|
-
co.beginPath();
|
707
|
-
co.arc(this.centerx,
|
708
|
-
this.centery,
|
709
|
-
this.radius,
|
710
|
-
((i / 360) * RG.TWOPI) - RG.HALFPI,
|
711
|
-
(((i + 0.001) / 360) * RG.TWOPI) - RG.HALFPI,
|
712
|
-
false); // The 0.001 avoids a bug in Chrome 6
|
713
|
-
co.lineTo(this.centerx, this.centery);
|
714
|
-
co.stroke();
|
715
|
-
}
|
716
|
-
|
717
|
-
|
718
|
-
/**
|
719
|
-
* Draw the lines that go around the Radar chart
|
720
|
-
*/
|
721
|
-
co.strokeStyle = color;
|
722
|
-
|
723
|
-
var numrings = typeof(prop['chart.background.circles.count']) == 'number' ? prop['chart.background.circles.count'] : prop['chart.labels.count'];
|
724
|
-
|
725
|
-
for (var r=0; r<=this.radius; r+=(this.radius / numrings)) {
|
726
|
-
co.beginPath();
|
727
|
-
for (var a=0; a<=360; a+=(360 / this.data[0].length)) {
|
728
|
-
co.arc(this.centerx,
|
729
|
-
this.centery,
|
730
|
-
r,
|
731
|
-
RG.degrees2Radians(a) - RG.HALFPI,
|
732
|
-
RG.degrees2Radians(a) + 0.001 - RG.HALFPI,
|
733
|
-
false);
|
734
|
-
}
|
735
|
-
co.closePath();
|
736
|
-
co.stroke();
|
737
|
-
}
|
738
|
-
}
|
739
|
-
};
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
/**
|
745
|
-
* Draws the axes
|
746
|
-
*/
|
747
|
-
this.drawAxes =
|
748
|
-
this.DrawAxes = function ()
|
749
|
-
{
|
750
|
-
co.strokeStyle = prop['chart.axes.color'];
|
751
|
-
|
752
|
-
var halfsize = this.radius;
|
753
|
-
|
754
|
-
co.beginPath();
|
755
|
-
/**
|
756
|
-
* The Y axis
|
757
|
-
*/
|
758
|
-
co.moveTo(Math.round(this.centerx), this.centery + this.radius);
|
759
|
-
co.lineTo(Math.round(this.centerx), this.centery - this.radius);
|
760
|
-
|
761
|
-
|
762
|
-
// Draw the bits at either end of the Y axis
|
763
|
-
co.moveTo(this.centerx - 5, Math.round(this.centery + this.radius));
|
764
|
-
co.lineTo(this.centerx + 5, Math.round(this.centery + this.radius));
|
765
|
-
co.moveTo(this.centerx - 5, Math.round(this.centery - this.radius));
|
766
|
-
co.lineTo(this.centerx + 5, Math.round(this.centery - this.radius));
|
767
|
-
|
768
|
-
// Draw Y axis tick marks
|
769
|
-
for (var y=(this.centery - this.radius); y<(this.centery + this.radius); y+=(this.radius/prop['chart.numyticks'])) {
|
770
|
-
co.moveTo(this.centerx - 3, Math.round(y));
|
771
|
-
co.lineTo(this.centerx + 3, Math.round(y));
|
772
|
-
}
|
773
|
-
|
774
|
-
/**
|
775
|
-
* The X axis
|
776
|
-
*/
|
777
|
-
co.moveTo(this.centerx - this.radius, Math.round(this.centery));
|
778
|
-
co.lineTo(this.centerx + this.radius, Math.round(this.centery));
|
779
|
-
|
780
|
-
// Draw the bits at the end of the X axis
|
781
|
-
co.moveTo(Math.round(this.centerx - this.radius), this.centery - 5);
|
782
|
-
co.lineTo(Math.round(this.centerx - this.radius), this.centery + 5);
|
783
|
-
co.moveTo(Math.round(this.centerx + this.radius), this.centery - 5);
|
784
|
-
co.lineTo(Math.round(this.centerx + this.radius), this.centery + 5);
|
785
|
-
|
786
|
-
// Draw X axis tick marks
|
787
|
-
for (var x=(this.centerx - this.radius); x<(this.centerx + this.radius); x+=(this.radius/prop['chart.numxticks'])) {
|
788
|
-
co.moveTo(Math.round(x), this.centery - 3);
|
789
|
-
co.lineTo(Math.round(x), this.centery + 3);
|
790
|
-
}
|
791
|
-
|
792
|
-
// Stroke it
|
793
|
-
co.stroke();
|
794
|
-
};
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
/**
|
800
|
-
* The function which actually draws the radar chart
|
801
|
-
*/
|
802
|
-
this.drawChart =
|
803
|
-
this.DrawChart = function ()
|
804
|
-
{
|
805
|
-
var alpha = prop['chart.colors.alpha'];
|
806
|
-
|
807
|
-
if (typeof(alpha) == 'number') {
|
808
|
-
var oldAlpha = co.globalAlpha;
|
809
|
-
co.globalAlpha = alpha;
|
810
|
-
}
|
811
|
-
|
812
|
-
var numDatasets = this.data.length;
|
813
|
-
|
814
|
-
for (var dataset=0; dataset<this.data.length; ++dataset) {
|
815
|
-
|
816
|
-
co.beginPath();
|
817
|
-
|
818
|
-
var coords_dataset = [];
|
819
|
-
|
820
|
-
for (var i=0; i<this.data[dataset].length; ++i) {
|
821
|
-
|
822
|
-
var coords = this.GetCoordinates(dataset, i);
|
823
|
-
|
824
|
-
if (coords_dataset == null) {
|
825
|
-
coords_dataset = [];
|
826
|
-
}
|
827
|
-
|
828
|
-
coords_dataset.push(coords);
|
829
|
-
this.coords.push(coords);
|
830
|
-
}
|
831
|
-
|
832
|
-
this.coords2[dataset] = coords_dataset;
|
833
|
-
|
834
|
-
|
835
|
-
/**
|
836
|
-
* Now go through the coords and draw the chart itself
|
837
|
-
*
|
838
|
-
* 18/5/2012 - chart.strokestyle can now be an array of colors as well as a single color
|
839
|
-
*/
|
840
|
-
|
841
|
-
co.strokeStyle = (typeof(prop['chart.strokestyle']) == 'object' && prop['chart.strokestyle'][dataset]) ? prop['chart.strokestyle'][dataset] : prop['chart.strokestyle'];
|
842
|
-
co.fillStyle = prop['chart.colors'][dataset] ? prop['chart.colors'][dataset] : 'rgba(0,0,0,0)';
|
843
|
-
if (co.fillStyle === 'transparent') {
|
844
|
-
co.fillStyle = 'rgba(0,0,0,0)';
|
845
|
-
}
|
846
|
-
co.lineWidth = prop['chart.linewidth'];
|
847
|
-
|
848
|
-
for (i=0; i<coords_dataset.length; ++i) {
|
849
|
-
if (i == 0) {
|
850
|
-
co.moveTo(coords_dataset[i][0], coords_dataset[i][1]);
|
851
|
-
} else {
|
852
|
-
co.lineTo(coords_dataset[i][0], coords_dataset[i][1]);
|
853
|
-
}
|
854
|
-
}
|
855
|
-
|
856
|
-
|
857
|
-
// If on the second or greater dataset, backtrack
|
858
|
-
if (prop['chart.accumulative'] && dataset > 0) {
|
859
|
-
|
860
|
-
// This goes back to the start coords of this particular dataset
|
861
|
-
co.lineTo(coords_dataset[0][0], coords_dataset[0][1]);
|
862
|
-
|
863
|
-
//Now move down to the end point of the previous dataset
|
864
|
-
co.moveTo(last_coords[0][0], last_coords[0][1]);
|
865
|
-
|
866
|
-
for (var i=coords_dataset.length - 1; i>=0; --i) {
|
867
|
-
co.lineTo(last_coords[i][0], last_coords[i][1]);
|
868
|
-
}
|
869
|
-
}
|
870
|
-
|
871
|
-
// This is used by the next iteration of the loop
|
872
|
-
var last_coords = coords_dataset;
|
873
|
-
|
874
|
-
co.closePath();
|
875
|
-
|
876
|
-
co.stroke();
|
877
|
-
co.fill();
|
878
|
-
}
|
879
|
-
|
880
|
-
// Reset the globalAlpha
|
881
|
-
if (typeof(alpha) == 'number') {
|
882
|
-
co.globalAlpha = oldAlpha;
|
883
|
-
}
|
884
|
-
};
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
/**
|
890
|
-
* Gets the coordinates for a particular mark
|
891
|
-
*
|
892
|
-
* @param number i The index of the data (ie which one it is)
|
893
|
-
* @return array A two element array of the coordinates
|
894
|
-
*/
|
895
|
-
this.getCoordinates =
|
896
|
-
this.GetCoordinates = function (dataset, index)
|
897
|
-
{
|
898
|
-
// The number of data points
|
899
|
-
var len = this.data[dataset].length;
|
900
|
-
|
901
|
-
// The magnitude of the data (NOT the x/y coords)
|
902
|
-
var mag = (this.data[dataset][index] / this.max) * this.radius;
|
903
|
-
|
904
|
-
/**
|
905
|
-
* Get the angle
|
906
|
-
*/
|
907
|
-
var angle = (RG.TWOPI / len) * index; // In radians
|
908
|
-
angle -= RG.HALFPI;
|
909
|
-
|
910
|
-
|
911
|
-
/**
|
912
|
-
* Work out the X/Y coordinates
|
913
|
-
*/
|
914
|
-
var x = Math.cos(angle) * mag;
|
915
|
-
var y = Math.sin(angle) * mag;
|
916
|
-
|
917
|
-
/**
|
918
|
-
* Put the coordinate in the right quadrant
|
919
|
-
*/
|
920
|
-
x = this.centerx + x;
|
921
|
-
y = this.centery + y;
|
922
|
-
|
923
|
-
return [x,y];
|
924
|
-
};
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
/**
|
930
|
-
* This function adds the labels to the chart
|
931
|
-
*/
|
932
|
-
this.drawLabels =
|
933
|
-
this.DrawLabels = function ()
|
934
|
-
{
|
935
|
-
var labels = prop['chart.labels'];
|
936
|
-
|
937
|
-
if (labels && labels.length > 0) {
|
938
|
-
|
939
|
-
co.lineWidth = 1;
|
940
|
-
co.strokeStyle = 'gray';
|
941
|
-
co.fillStyle = prop['chart.labels.color'] || prop['chart.text.color'];
|
942
|
-
|
943
|
-
var bgFill = prop['chart.labels.background.fill'],
|
944
|
-
bold = prop['chart.labels.bold'],
|
945
|
-
bgBoxed = prop['chart.labels.boxed'],
|
946
|
-
offset = prop['chart.labels.offset'],
|
947
|
-
font = prop['chart.text.font'],
|
948
|
-
size = prop['chart.text.size'],
|
949
|
-
radius = this.radius,
|
950
|
-
color = prop['chart.labels.color'] || prop['chart.text.color']
|
951
|
-
|
952
|
-
for (var i=0; i<labels.length; ++i) {
|
953
|
-
|
954
|
-
var angle = (RG.TWOPI / prop['chart.labels'].length) * i;
|
955
|
-
angle -= RG.HALFPI;
|
956
|
-
|
957
|
-
var x = this.centerx + (ma.cos(angle) * (radius + offset));
|
958
|
-
var y = this.centery + (ma.sin(angle) * (radius + offset));
|
959
|
-
|
960
|
-
/**
|
961
|
-
* Horizontal alignment
|
962
|
-
*/
|
963
|
-
var halign = x < this.centerx ? 'right' : 'left' ;
|
964
|
-
if (i == 0 || (i / labels.length) == 0.5) halign = 'center';
|
965
|
-
|
966
|
-
if (labels[i] && labels[i].length) {
|
967
|
-
|
968
|
-
RG.text2(this, {
|
969
|
-
'color': color,
|
970
|
-
'font':font,
|
971
|
-
'size':size,
|
972
|
-
'x':x,
|
973
|
-
'y':y,
|
974
|
-
'text':labels[i],
|
975
|
-
'valign':'center',
|
976
|
-
'halign':halign,
|
977
|
-
'bounding':bgBoxed,
|
978
|
-
'boundingFill':bgFill,
|
979
|
-
'bold':bold,
|
980
|
-
'tag': 'labels'
|
981
|
-
});
|
982
|
-
}
|
983
|
-
}
|
984
|
-
}
|
985
|
-
};
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
/**
|
991
|
-
* Draws the circle. No arguments as it gets the information from the object properties.
|
992
|
-
*/
|
993
|
-
this.drawCircle =
|
994
|
-
this.DrawCircle = function ()
|
995
|
-
{
|
996
|
-
var circle = {};
|
997
|
-
circle.limit = prop['chart.circle'];
|
998
|
-
circle.fill = prop['chart.circle.fill'];
|
999
|
-
circle.stroke = prop['chart.circle.stroke'];
|
1000
|
-
|
1001
|
-
if (circle.limit) {
|
1002
|
-
|
1003
|
-
var r = (circle.limit / this.max) * this.radius;
|
1004
|
-
|
1005
|
-
co.fillStyle = circle.fill;
|
1006
|
-
co.strokeStyle = circle.stroke;
|
1007
|
-
|
1008
|
-
co.beginPath();
|
1009
|
-
co.arc(this.centerx, this.centery, r, 0, RG.TWOPI, 0);
|
1010
|
-
co.fill();
|
1011
|
-
co.stroke();
|
1012
|
-
}
|
1013
|
-
};
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
/**
|
1019
|
-
* Unsuprisingly, draws the labels
|
1020
|
-
*/
|
1021
|
-
this.drawAxisLabels =
|
1022
|
-
this.DrawAxisLabels = function ()
|
1023
|
-
{
|
1024
|
-
/**
|
1025
|
-
* Draw specific axis labels
|
1026
|
-
*/
|
1027
|
-
if (RG.isArray(prop['chart.labels.specific']) && prop['chart.labels.specific'].length) {
|
1028
|
-
this.drawSpecificAxisLabels();
|
1029
|
-
return;
|
1030
|
-
}
|
1031
|
-
|
1032
|
-
co.lineWidth = 1;
|
1033
|
-
|
1034
|
-
// Set the color to black
|
1035
|
-
co.fillStyle = 'black';
|
1036
|
-
co.strokeStyle = 'black';
|
1037
|
-
|
1038
|
-
var r = this.radius;
|
1039
|
-
var font = prop['chart.text.font'];
|
1040
|
-
var size = typeof(prop['chart.text.size.scale']) == 'number' ? prop['chart.text.size.scale'] : prop['chart.text.size'];
|
1041
|
-
var axes = prop['chart.labels.axes'].toLowerCase();
|
1042
|
-
var color = 'rgba(255,255,255,0.9)';
|
1043
|
-
var drawzero = false;
|
1044
|
-
var units_pre = prop['chart.units.pre'];
|
1045
|
-
var units_post = prop['chart.units.post'];
|
1046
|
-
var decimals = prop['chart.scale.decimals'];
|
1047
|
-
var bold = prop['chart.labels.axes.bold'];
|
1048
|
-
var boxed = prop['chart.labels.axes.boxed'];
|
1049
|
-
var centerx = this.centerx;
|
1050
|
-
var centery = this.centery;
|
1051
|
-
var scale = this.scale;
|
1052
|
-
|
1053
|
-
co.fillStyle = prop['chart.text.color'];
|
1054
|
-
|
1055
|
-
// The "North" axis labels
|
1056
|
-
if (axes.indexOf('n') > -1) {
|
1057
|
-
for (var i=0; i<this.scale2.labels.length; ++i) {
|
1058
|
-
RG.Text2(this, {
|
1059
|
-
'bold':bold[i],
|
1060
|
-
'font':font,
|
1061
|
-
'size':size,
|
1062
|
-
'x':centerx,
|
1063
|
-
'y':centery - (r * ((i+1)/this.scale2.labels.length)),
|
1064
|
-
'text':this.scale2.labels[i],
|
1065
|
-
'valign':'center',
|
1066
|
-
'halign':'center',
|
1067
|
-
'bounding':boxed[i] || color,
|
1068
|
-
'boundingFill':color,
|
1069
|
-
'boundingStroke':'rgba(0,0,0,0)',
|
1070
|
-
'tag': 'scale'
|
1071
|
-
});
|
1072
|
-
}
|
1073
|
-
|
1074
|
-
drawzero = true;
|
1075
|
-
}
|
1076
|
-
|
1077
|
-
// The "South" axis labels
|
1078
|
-
if (axes.indexOf('s') > -1) {
|
1079
|
-
for (var i=0; i<this.scale2.labels.length; ++i) {
|
1080
|
-
RG.Text2(this, {
|
1081
|
-
'bold':bold[i],
|
1082
|
-
'font':font,
|
1083
|
-
'size':size,
|
1084
|
-
'x':centerx,
|
1085
|
-
'y':centery + (r * ((i+1)/this.scale2.labels.length)),
|
1086
|
-
'text':this.scale2.labels[i],
|
1087
|
-
'valign':'center',
|
1088
|
-
'halign':'center',
|
1089
|
-
'bounding':boxed[i] || color,
|
1090
|
-
'boundingFill':color,
|
1091
|
-
'boundingStroke':'rgba(0,0,0,0)',
|
1092
|
-
'tag': 'scale'
|
1093
|
-
});
|
1094
|
-
}
|
1095
|
-
|
1096
|
-
drawzero = true;
|
1097
|
-
}
|
1098
|
-
|
1099
|
-
// The "East" axis labels
|
1100
|
-
if (axes.indexOf('e') > -1) {
|
1101
|
-
|
1102
|
-
for (var i=0; i<this.scale2.labels.length; ++i) {
|
1103
|
-
RG.Text2(this, {
|
1104
|
-
'bold':bold[i],
|
1105
|
-
'font':font,
|
1106
|
-
'size':size,
|
1107
|
-
'x':centerx + (r * ((i+1)/this.scale2.labels.length)),
|
1108
|
-
'y':centery,
|
1109
|
-
'text':this.scale2.labels[i],
|
1110
|
-
'valign':'center',
|
1111
|
-
'halign':'center',
|
1112
|
-
'bounding':boxed[i]|| color,
|
1113
|
-
'boundingFill':color,
|
1114
|
-
'boundingStroke':'rgba(0,0,0,0)',
|
1115
|
-
'tag': 'scale'
|
1116
|
-
});
|
1117
|
-
}
|
1118
|
-
|
1119
|
-
drawzero = true;
|
1120
|
-
}
|
1121
|
-
|
1122
|
-
// The "West" axis labels
|
1123
|
-
if (axes.indexOf('w') > -1) {
|
1124
|
-
|
1125
|
-
for (var i=0; i<this.scale2.labels.length; ++i) {
|
1126
|
-
RG.Text2(this, {
|
1127
|
-
'bold':bold[i],
|
1128
|
-
'font':font,
|
1129
|
-
'size':size,
|
1130
|
-
'x':centerx - (r * ((i+1)/this.scale2.labels.length)),
|
1131
|
-
'y':centery,
|
1132
|
-
'text':this.scale2.labels[i],
|
1133
|
-
'valign':'center',
|
1134
|
-
'halign':'center',
|
1135
|
-
'bounding':boxed[i]|| color,
|
1136
|
-
'boundingFill':color,
|
1137
|
-
'boundingStroke':'rgba(0,0,0,0)',
|
1138
|
-
'tag': 'scale'
|
1139
|
-
});
|
1140
|
-
}
|
1141
|
-
|
1142
|
-
drawzero = true;
|
1143
|
-
}
|
1144
|
-
|
1145
|
-
if (drawzero) {
|
1146
|
-
RG.Text2(this, {
|
1147
|
-
'font':font,
|
1148
|
-
'size':size,
|
1149
|
-
'x':centerx,
|
1150
|
-
'y':centery,
|
1151
|
-
'text':RG.number_format(this, Number(0).toFixed(decimals), units_pre, units_post),
|
1152
|
-
'valign':'center',
|
1153
|
-
'halign':'center',
|
1154
|
-
'bounding':prop['chart.labels.axes.boxed.zero'],
|
1155
|
-
'boundingFill':color,
|
1156
|
-
'boundingStroke':'rgba(0,0,0,0)',
|
1157
|
-
'bold':prop['chart.labels.axes.bold.zero'],
|
1158
|
-
'tag': 'scale'
|
1159
|
-
});
|
1160
|
-
}
|
1161
|
-
};
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
/**
|
1167
|
-
* Draws specific axis labels
|
1168
|
-
*/
|
1169
|
-
this.drawSpecificAxisLabels =
|
1170
|
-
this.DrawSpecificAxisLabels = function ()
|
1171
|
-
{
|
1172
|
-
/**
|
1173
|
-
* Specific axis labels
|
1174
|
-
*/
|
1175
|
-
var labels = prop['chart.labels.specific'];
|
1176
|
-
var bold = RG.array_pad(prop['chart.labels.axes.bold'],labels.length);
|
1177
|
-
var boxed = RG.array_pad(prop['chart.labels.axes.boxed'],labels.length);
|
1178
|
-
var reversed_labels = RG.array_reverse(labels);
|
1179
|
-
var reversed_bold = RG.array_reverse(bold);
|
1180
|
-
var reversed_boxed = RG.array_reverse(boxed);
|
1181
|
-
var font = prop['chart.text.font'];
|
1182
|
-
var size = typeof(prop['chart.text.size.scale']) == 'number' ? prop['chart.text.size.scale'] : prop['chart.text.size'];
|
1183
|
-
var axes = prop['chart.labels.axes'].toLowerCase();
|
1184
|
-
|
1185
|
-
co.fillStyle = prop['chart.text.color'];
|
1186
|
-
|
1187
|
-
for (var i=0; i<labels.length; ++i) {
|
1188
|
-
|
1189
|
-
if (axes.indexOf('n') > -1) RG.Text2(this, {'tag': 'labels.specific', 'bold':reversed_bold[i],'font':font,'size':size,'x':this.centerx,'y':this.centery - this.radius + ((this.radius / labels.length) * i),'text':reversed_labels[i],'valign':'center','halign':'center','bounding':reversed_boxed[i],'boundingFill':'white'});
|
1190
|
-
if (axes.indexOf('s') > -1) RG.Text2(this, {'tag': 'labels.specific', 'bold':bold[i],'font':font,'size':size,'x':this.centerx,'y':this.centery + ((this.radius / labels.length) * (i+1)),'text':labels[i],'valign':'center','halign':'center','bounding':boxed[i],'boundingFill':'white'});
|
1191
|
-
|
1192
|
-
if (axes.indexOf('w') > -1) RG.Text2(this, {'tag': 'labels.specific', 'bold':reversed_bold[i],'font':font,'size':size,'x':this.centerx - this.radius + ((this.radius / labels.length) * i),'y':this.centery,'text':reversed_labels[i],'valign':'center','halign':'center','bounding':reversed_boxed[i],'boundingFill':'white'});
|
1193
|
-
if (axes.indexOf('e') > -1) RG.Text2(this, {'tag': 'labels.specific', 'bold':bold[i],'font':font,'size':size,'x':this.centerx + ((this.radius / labels.length) * (i+1)),'y':this.centery,'text':labels[i],'valign':'center','halign':'center','bounding':boxed[i],'boundingFill':'white'});
|
1194
|
-
}
|
1195
|
-
};
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
/**
|
1201
|
-
* This method eases getting the focussed point (if any)
|
1202
|
-
*
|
1203
|
-
* @param event e The event object
|
1204
|
-
*/
|
1205
|
-
this.getShape =
|
1206
|
-
this.getPoint = function (e)
|
1207
|
-
{
|
1208
|
-
for (var i=0; i<this.coords.length; ++i) {
|
1209
|
-
|
1210
|
-
var x = this.coords[i][0];
|
1211
|
-
var y = this.coords[i][1];
|
1212
|
-
var tooltips = prop['chart.tooltips'];
|
1213
|
-
var index = Number(i);
|
1214
|
-
var mouseXY = RG.getMouseXY(e);
|
1215
|
-
var mouseX = mouseXY[0];
|
1216
|
-
var mouseY = mouseXY[1];
|
1217
|
-
|
1218
|
-
if ( mouseX < (x + 5)
|
1219
|
-
&& mouseX > (x - 5)
|
1220
|
-
&& mouseY > (y - 5)
|
1221
|
-
&& mouseY < (y + 5)
|
1222
|
-
) {
|
1223
|
-
|
1224
|
-
var tooltip = RG.parseTooltipText(prop['chart.tooltips'], index);
|
1225
|
-
|
1226
|
-
return {0: this, 'object': this,
|
1227
|
-
1: x, 'x': x,
|
1228
|
-
2: y, 'y': y,
|
1229
|
-
3: null, 'dataset': null,
|
1230
|
-
4: index, 'index': i,
|
1231
|
-
'tooltip': tooltip
|
1232
|
-
}
|
1233
|
-
}
|
1234
|
-
}
|
1235
|
-
};
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
/**
|
1241
|
-
* Each object type has its own Highlight() function which highlights the appropriate shape
|
1242
|
-
*
|
1243
|
-
* @param object shape The shape to highlight
|
1244
|
-
*/
|
1245
|
-
this.highlight =
|
1246
|
-
this.Highlight = function (shape)
|
1247
|
-
{
|
1248
|
-
if (typeof prop['chart.highlight.style'] === 'function') {
|
1249
|
-
(prop['chart.highlight.style'])(shape);
|
1250
|
-
} else {
|
1251
|
-
RG.Highlight.Point(this, shape);
|
1252
|
-
}
|
1253
|
-
};
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
/**
|
1259
|
-
* The getObjectByXY() worker method. Don't call this call:
|
1260
|
-
*
|
1261
|
-
* RGraph.ObjectRegistry.getObjectByXY(e)
|
1262
|
-
*
|
1263
|
-
* @param object e The event object
|
1264
|
-
*/
|
1265
|
-
this.getObjectByXY = function (e)
|
1266
|
-
{
|
1267
|
-
var mouseXY = RG.getMouseXY(e);
|
1268
|
-
|
1269
|
-
if (
|
1270
|
-
mouseXY[0] > (this.centerx - this.radius)
|
1271
|
-
&& mouseXY[0] < (this.centerx + this.radius)
|
1272
|
-
&& mouseXY[1] > (this.centery - this.radius)
|
1273
|
-
&& mouseXY[1] < (this.centery + this.radius)
|
1274
|
-
) {
|
1275
|
-
|
1276
|
-
return this;
|
1277
|
-
}
|
1278
|
-
};
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
/**
|
1284
|
-
* This function positions a tooltip when it is displayed
|
1285
|
-
*
|
1286
|
-
* @param obj object The chart object
|
1287
|
-
* @param int x The X coordinate specified for the tooltip
|
1288
|
-
* @param int y The Y coordinate specified for the tooltip
|
1289
|
-
* @param objec tooltip The tooltips DIV element
|
1290
|
-
*/
|
1291
|
-
this.positionTooltip = function (obj, x, y, tooltip, idx)
|
1292
|
-
{
|
1293
|
-
var dataset = tooltip.__dataset__;
|
1294
|
-
var index = tooltip.__index__;
|
1295
|
-
var coordX = this.coords[index][0];
|
1296
|
-
var coordY = this.coords[index][1];
|
1297
|
-
var canvasXY = RG.getCanvasXY(obj.canvas);
|
1298
|
-
var gutterLeft = this.gutterLeft;
|
1299
|
-
var gutterTop = this.gutterTop;
|
1300
|
-
var width = tooltip.offsetWidth;
|
1301
|
-
var height = tooltip.offsetHeight;
|
1302
|
-
var mouseXY = RG.getMouseXY(window.event);
|
1303
|
-
|
1304
|
-
// Set the top position
|
1305
|
-
tooltip.style.left = 0;
|
1306
|
-
tooltip.style.top = window.event.pageY - height - 5 + 'px';
|
1307
|
-
|
1308
|
-
// By default any overflow is hidden
|
1309
|
-
tooltip.style.overflow = '';
|
1310
|
-
|
1311
|
-
// Reposition the tooltip if at the edges:
|
1312
|
-
|
1313
|
-
// LEFT edge
|
1314
|
-
if (canvasXY[0] + mouseXY[0] - (width / 2) < 0) {
|
1315
|
-
tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.1) + 'px';
|
1316
|
-
|
1317
|
-
// RIGHT edge
|
1318
|
-
} else if (canvasXY[0] + mouseXY[0] + (width / 2) > doc.body.offsetWidth) {
|
1319
|
-
tooltip.style.left = canvasXY[0] + mouseXY[0] - (width * 0.9) + 'px';
|
1320
|
-
|
1321
|
-
// Default positioning - CENTERED
|
1322
|
-
} else {
|
1323
|
-
tooltip.style.left = canvasXY[0] + mouseXY[0] - (width / 2) + 'px';
|
1324
|
-
}
|
1325
|
-
};
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
/**
|
1331
|
-
* This draws highlights on the points
|
1332
|
-
*/
|
1333
|
-
this.drawHighlights =
|
1334
|
-
this.DrawHighlights = function ()
|
1335
|
-
{
|
1336
|
-
if (prop['chart.highlights']) {
|
1337
|
-
|
1338
|
-
var sequentialIdx = 0;
|
1339
|
-
var dataset = 0;
|
1340
|
-
var index = 0;
|
1341
|
-
var radius = prop['chart.highlights.radius'];
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
for (var dataset=0; dataset <this.data.length; ++dataset) {
|
1346
|
-
for (var index=0; index<this.data[dataset].length; ++index) {
|
1347
|
-
co.beginPath();
|
1348
|
-
co.strokeStyle = prop['chart.highlights.stroke'];
|
1349
|
-
co.fillStyle = prop['chart.highlights.fill'] ? prop['chart.highlights.fill'] : ((typeof(prop['chart.strokestyle']) == 'object' && prop['chart.strokestyle'][dataset]) ? prop['chart.strokestyle'][dataset] : prop['chart.strokestyle']);
|
1350
|
-
co.arc(this.coords[sequentialIdx][0], this.coords[sequentialIdx][1], radius, 0, RG.TWOPI, false);
|
1351
|
-
co.stroke();
|
1352
|
-
co.fill();
|
1353
|
-
++sequentialIdx;
|
1354
|
-
}
|
1355
|
-
}
|
1356
|
-
|
1357
|
-
}
|
1358
|
-
};
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
/**
|
1364
|
-
* This function returns the radius (ie the distance from the center) for a particular
|
1365
|
-
* value. Note that if you want the angle for a point you can use getAngle(index)
|
1366
|
-
*
|
1367
|
-
* @param number value The value you want the radius for
|
1368
|
-
*/
|
1369
|
-
this.getRadius = function (value)
|
1370
|
-
{
|
1371
|
-
if (value < 0 || value > this.max) {
|
1372
|
-
return null;
|
1373
|
-
}
|
1374
|
-
|
1375
|
-
// Radar doesn't support minimum value
|
1376
|
-
var radius = (value / this.max) * this.radius;
|
1377
|
-
|
1378
|
-
return radius;
|
1379
|
-
};
|
1380
|
-
|
1381
|
-
|
1382
|
-
|
1383
|
-
|
1384
|
-
/**
|
1385
|
-
* This function returns the angle (in radians) for a particular index.
|
1386
|
-
*
|
1387
|
-
* @param number numitems The total number of items
|
1388
|
-
* @param number index The zero index number of the item to get the angle for
|
1389
|
-
*/
|
1390
|
-
this.getAngle = function (numitems, index)
|
1391
|
-
{
|
1392
|
-
var angle = (RG.TWOPI / numitems) * index;
|
1393
|
-
angle -= RG.HALFPI;
|
1394
|
-
|
1395
|
-
return angle;
|
1396
|
-
};
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
/**
|
1402
|
-
* This allows for easy specification of gradients
|
1403
|
-
*/
|
1404
|
-
this.parseColors = function ()
|
1405
|
-
{
|
1406
|
-
// Save the original colors so that they can be restored when the canvas is reset
|
1407
|
-
if (this.original_colors.length === 0) {
|
1408
|
-
this.original_colors['chart.colors'] = RG.array_clone(prop['chart.colors']);
|
1409
|
-
this.original_colors['chart.key.colors'] = RG.array_clone(prop['chart.key.colors']);
|
1410
|
-
this.original_colors['chart.title.color'] = RG.array_clone(prop['chart.title.color']);
|
1411
|
-
this.original_colors['chart.text.color'] = RG.array_clone(prop['chart.text.color']);
|
1412
|
-
this.original_colors['chart.highlight.stroke'] = RG.array_clone(prop['chart.highlight.stroke']);
|
1413
|
-
this.original_colors['chart.highlight.fill'] = RG.array_clone(prop['chart.highlight.fill']);
|
1414
|
-
this.original_colors['chart.circle.fill'] = RG.array_clone(prop['chart.circle.fill']);
|
1415
|
-
this.original_colors['chart.circle.stroke'] = RG.array_clone(prop['chart.circle.stroke']);
|
1416
|
-
}
|
1417
|
-
|
1418
|
-
for (var i=0; i<prop['chart.colors'].length; ++i) {
|
1419
|
-
prop['chart.colors'][i] = this.parseSingleColorForGradient(prop['chart.colors'][i]);
|
1420
|
-
}
|
1421
|
-
|
1422
|
-
var keyColors = prop['chart.key.colors'];
|
1423
|
-
|
1424
|
-
if (typeof(keyColors) != 'null' && keyColors && keyColors.length) {
|
1425
|
-
for (var i=0; i<prop['chart.key.colors'].length; ++i) {
|
1426
|
-
prop['chart.key.colors'][i] = this.parseSingleColorForGradient(prop['chart.key.colors'][i]);
|
1427
|
-
}
|
1428
|
-
}
|
1429
|
-
|
1430
|
-
prop['chart.title.color'] = this.parseSingleColorForGradient(prop['chart.title.color']);
|
1431
|
-
prop['chart.text.color'] = this.parseSingleColorForGradient(prop['chart.text.color']);
|
1432
|
-
prop['chart.highlight.stroke'] = this.parseSingleColorForGradient(prop['chart.highlight.stroke']);
|
1433
|
-
prop['chart.highlight.fill'] = this.parseSingleColorForGradient(prop['chart.highlight.fill']);
|
1434
|
-
prop['chart.circle.fill'] = this.parseSingleColorForGradient(prop['chart.circle.fill']);
|
1435
|
-
prop['chart.circle.stroke'] = this.parseSingleColorForGradient(prop['chart.circle.stroke']);
|
1436
|
-
};
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1441
|
-
/**
|
1442
|
-
* Use this function to reset the object to the post-constructor state. Eg reset colors if
|
1443
|
-
* need be etc
|
1444
|
-
*/
|
1445
|
-
this.reset = function ()
|
1446
|
-
{
|
1447
|
-
};
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
/**
|
1453
|
-
* This parses a single color value
|
1454
|
-
*/
|
1455
|
-
this.parseSingleColorForGradient = function (color)
|
1456
|
-
{
|
1457
|
-
if (!color || typeof(color) != 'string') {
|
1458
|
-
return color;
|
1459
|
-
}
|
1460
|
-
|
1461
|
-
if (color.match(/^gradient\((.*)\)$/i)) {
|
1462
|
-
|
1463
|
-
var parts = RegExp.$1.split(':');
|
1464
|
-
|
1465
|
-
// Create the gradient
|
1466
|
-
var grad = co.createRadialGradient(this.centerx, this.centery, 0, this.centerx, this.centery, this.radius);
|
1467
|
-
|
1468
|
-
var diff = 1 / (parts.length - 1);
|
1469
|
-
|
1470
|
-
grad.addColorStop(0, RG.trim(parts[0]));
|
1471
|
-
|
1472
|
-
for (var j=1; j<parts.length; ++j) {
|
1473
|
-
grad.addColorStop(j * diff, RG.trim(parts[j]));
|
1474
|
-
}
|
1475
|
-
}
|
1476
|
-
|
1477
|
-
return grad ? grad : color;
|
1478
|
-
};
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
this.addFillListeners =
|
1484
|
-
this.AddFillListeners = function (e)
|
1485
|
-
{
|
1486
|
-
var obj = this;
|
1487
|
-
|
1488
|
-
var func = function (e)
|
1489
|
-
{
|
1490
|
-
//var canvas = e.target;
|
1491
|
-
//var context = canvas.getContext('2d');
|
1492
|
-
var coords = this.coords;
|
1493
|
-
var coords2 = this.coords2;
|
1494
|
-
var mouseXY = RG.getMouseXY(e);
|
1495
|
-
var dataset = 0;
|
1496
|
-
|
1497
|
-
if (e.type == 'mousemove' && prop['chart.fill.mousemove.redraw']) {
|
1498
|
-
RG.RedrawCanvas(ca);
|
1499
|
-
}
|
1500
|
-
|
1501
|
-
for (var dataset=(obj.coords2.length-1); dataset>=0; --dataset) {
|
1502
|
-
|
1503
|
-
// Draw the path again so that it can be checked
|
1504
|
-
co.beginPath();
|
1505
|
-
co.moveTo(obj.coords2[dataset][0][0], obj.coords2[dataset][0][1]);
|
1506
|
-
for (var j=0; j<obj.coords2[dataset].length; ++j) {
|
1507
|
-
co.lineTo(obj.coords2[dataset][j][0], obj.coords2[dataset][j][1]);
|
1508
|
-
}
|
1509
|
-
|
1510
|
-
// Draw a line back to the starting point
|
1511
|
-
co.lineTo(obj.coords2[dataset][0][0], obj.coords2[dataset][0][1]);
|
1512
|
-
|
1513
|
-
// Go thru the previous datasets coords in reverse order
|
1514
|
-
if (prop['chart.accumulative'] && dataset > 0) {
|
1515
|
-
co.lineTo(obj.coords2[dataset - 1][0][0], obj.coords2[dataset - 1][0][1]);
|
1516
|
-
for (var j=(obj.coords2[dataset - 1].length - 1); j>=0; --j) {
|
1517
|
-
co.lineTo(obj.coords2[dataset - 1][j][0], obj.coords2[dataset - 1][j][1]);
|
1518
|
-
}
|
1519
|
-
}
|
1520
|
-
|
1521
|
-
co.closePath();
|
1522
|
-
|
1523
|
-
if (co.isPointInPath(mouseXY[0], mouseXY[1])) {
|
1524
|
-
var inPath = true;
|
1525
|
-
break;
|
1526
|
-
}
|
1527
|
-
}
|
1528
|
-
|
1529
|
-
// Call the events
|
1530
|
-
if (inPath) {
|
1531
|
-
|
1532
|
-
var fillTooltips = prop['chart.fill.tooltips'];
|
1533
|
-
|
1534
|
-
/**
|
1535
|
-
* Click event
|
1536
|
-
*/
|
1537
|
-
if (e.type == 'click') {
|
1538
|
-
if (prop['chart.fill.click']) {
|
1539
|
-
prop['chart.fill.click'](e, dataset);
|
1540
|
-
}
|
1541
|
-
|
1542
|
-
if (prop['chart.fill.tooltips'] && prop['chart.fill.tooltips'][dataset]) {
|
1543
|
-
obj.DatasetTooltip(e, dataset);
|
1544
|
-
}
|
1545
|
-
}
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
1549
|
-
/**
|
1550
|
-
* Mousemove event
|
1551
|
-
*/
|
1552
|
-
if (e.type == 'mousemove') {
|
1553
|
-
|
1554
|
-
if (prop['chart.fill.mousemove']) {
|
1555
|
-
prop['chart.fill.mousemove'](e, dataset);
|
1556
|
-
}
|
1557
|
-
|
1558
|
-
if (!RG.is_null(fillTooltips)) {
|
1559
|
-
e.target.style.cursor = 'pointer';
|
1560
|
-
}
|
1561
|
-
|
1562
|
-
if (prop['chart.fill.tooltips'] && prop['chart.fill.tooltips'][dataset]) {
|
1563
|
-
e.target.style.cursor = 'pointer';
|
1564
|
-
}
|
1565
|
-
}
|
1566
|
-
|
1567
|
-
e.stopPropagation();
|
1568
|
-
|
1569
|
-
} else if (e.type == 'mousemove') {
|
1570
|
-
ca.style.cursor = 'default';
|
1571
|
-
}
|
1572
|
-
};
|
1573
|
-
|
1574
|
-
/**
|
1575
|
-
* Add the click listener
|
1576
|
-
*/
|
1577
|
-
if (prop['chart.fill.click'] || !RG.is_null(prop['chart.fill.tooltips'])) {
|
1578
|
-
ca.addEventListener('click', func, false);
|
1579
|
-
}
|
1580
|
-
|
1581
|
-
/**
|
1582
|
-
* Add the mousemove listener
|
1583
|
-
*/
|
1584
|
-
if (prop['chart.fill.mousemove'] || !RG.is_null(prop['chart.fill.tooltips'])) {
|
1585
|
-
ca.addEventListener('mousemove', func, false);
|
1586
|
-
}
|
1587
|
-
};
|
1588
|
-
|
1589
|
-
|
1590
|
-
|
1591
|
-
|
1592
|
-
/**
|
1593
|
-
* This highlights a specific dataset on the chart
|
1594
|
-
*
|
1595
|
-
* @param number dataset The index of the dataset (which starts at zero)
|
1596
|
-
*/
|
1597
|
-
this.highlightDataset =
|
1598
|
-
this.HighlightDataset = function (dataset)
|
1599
|
-
{
|
1600
|
-
co.beginPath();
|
1601
|
-
for (var j=0; j<this.coords2[dataset].length; ++j) {
|
1602
|
-
if (j == 0) {
|
1603
|
-
co.moveTo(this.coords2[dataset][0][0], this.coords2[dataset][0][1]);
|
1604
|
-
} else {
|
1605
|
-
co.lineTo(this.coords2[dataset][j][0], this.coords2[dataset][j][1]);
|
1606
|
-
}
|
1607
|
-
}
|
1608
|
-
|
1609
|
-
co.lineTo(this.coords2[dataset][0][0], this.coords2[dataset][0][1]);
|
1610
|
-
|
1611
|
-
if (prop['chart.accumulative'] && dataset > 0) {
|
1612
|
-
co.lineTo(this.coords2[dataset - 1][0][0], this.coords2[dataset - 1][0][1]);
|
1613
|
-
for (var j=(this.coords2[dataset - 1].length - 1); j>=0; --j) {
|
1614
|
-
co.lineTo(this.coords2[dataset - 1][j][0], this.coords2[dataset - 1][j][1]);
|
1615
|
-
}
|
1616
|
-
}
|
1617
|
-
|
1618
|
-
co.strokeStyle = prop['chart.fill.highlight.stroke'];
|
1619
|
-
co.fillStyle = prop['chart.fill.highlight.fill'];
|
1620
|
-
|
1621
|
-
co.stroke();
|
1622
|
-
co.fill();
|
1623
|
-
};
|
1624
|
-
|
1625
|
-
|
1626
|
-
|
1627
|
-
|
1628
|
-
/**
|
1629
|
-
* Shows a tooltip for a dataset (a "fill" tooltip), You can pecify these
|
1630
|
-
* with chart.fill.tooltips
|
1631
|
-
*/
|
1632
|
-
this.datasetTooltip =
|
1633
|
-
this.DatasetTooltip = function (e, dataset)
|
1634
|
-
{
|
1635
|
-
// Highlight the dataset
|
1636
|
-
this.HighlightDataset(dataset);
|
1637
|
-
|
1638
|
-
// Use the First datapoints coords for the Y position of the tooltip NOTE The X position is changed in the
|
1639
|
-
// obj.positionTooltip() method so set the index to be the first one
|
1640
|
-
var text = prop['chart.fill.tooltips'][dataset];
|
1641
|
-
var x = 0;
|
1642
|
-
var y = this.coords2[dataset][0][1] + RG.getCanvasXY(ca)[1];
|
1643
|
-
|
1644
|
-
|
1645
|
-
// Show a tooltip
|
1646
|
-
RG.Tooltip(this, text, x, y, 0, e);
|
1647
|
-
};
|
1648
|
-
|
1649
|
-
|
1650
|
-
|
1651
|
-
|
1652
|
-
/**
|
1653
|
-
* This function handles highlighting an entire data-series for the interactive
|
1654
|
-
* key
|
1655
|
-
*
|
1656
|
-
* @param int index The index of the data series to be highlighted
|
1657
|
-
*/
|
1658
|
-
this.interactiveKeyHighlight = function (index)
|
1659
|
-
{
|
1660
|
-
var coords = this.coords2[index];
|
1661
|
-
|
1662
|
-
if (coords) {
|
1663
|
-
|
1664
|
-
var pre_linewidth = co.lineWidth;
|
1665
|
-
var pre_linecap = co.lineCap;
|
1666
|
-
|
1667
|
-
|
1668
|
-
|
1669
|
-
|
1670
|
-
// ------------------------------------------ //
|
1671
|
-
|
1672
|
-
co.lineWidth = prop['chart.linewidth'] + 10;
|
1673
|
-
co.lineCap = 'round';
|
1674
|
-
co.strokeStyle = prop['chart.key.interactive.highlight.chart.stroke'];
|
1675
|
-
|
1676
|
-
|
1677
|
-
co.beginPath();
|
1678
|
-
for (var i=0,len=coords.length; i<len; i+=1) {
|
1679
|
-
if (i == 0) {
|
1680
|
-
co.moveTo(coords[i][0], coords[i][1]);
|
1681
|
-
} else {
|
1682
|
-
co.lineTo(coords[i][0], coords[i][1]);
|
1683
|
-
}
|
1684
|
-
}
|
1685
|
-
co.closePath();
|
1686
|
-
co.stroke();
|
1687
|
-
|
1688
|
-
// ------------------------------------------ //
|
1689
|
-
|
1690
|
-
|
1691
|
-
|
1692
|
-
|
1693
|
-
// Reset the lineCap and lineWidth
|
1694
|
-
co.lineWidth = pre_linewidth;
|
1695
|
-
co.lineCap = pre_linecap;
|
1696
|
-
}
|
1697
|
-
};
|
1698
|
-
|
1699
|
-
|
1700
|
-
|
1701
|
-
|
1702
|
-
/**
|
1703
|
-
* Using a function to add events makes it easier to facilitate method chaining
|
1704
|
-
*
|
1705
|
-
* @param string type The type of even to add
|
1706
|
-
* @param function func
|
1707
|
-
*/
|
1708
|
-
this.on = function (type, func)
|
1709
|
-
{
|
1710
|
-
if (type.substr(0,2) !== 'on') {
|
1711
|
-
type = 'on' + type;
|
1712
|
-
}
|
1713
|
-
|
1714
|
-
this[type] = func;
|
1715
|
-
|
1716
|
-
return this;
|
1717
|
-
};
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
/**
|
1723
|
-
* This function runs once only
|
1724
|
-
* (put at the end of the file (before any effects))
|
1725
|
-
*/
|
1726
|
-
this.firstDrawFunc = function ()
|
1727
|
-
{
|
1728
|
-
};
|
1729
|
-
|
1730
|
-
|
1731
|
-
|
1732
|
-
|
1733
|
-
/**
|
1734
|
-
* Radar chart grow
|
1735
|
-
*
|
1736
|
-
* This effect gradually increases the magnitude of the points on the radar chart
|
1737
|
-
*
|
1738
|
-
* @param object Options for the effect
|
1739
|
-
* @param function An optional callback that is run when the effect is finished
|
1740
|
-
*/
|
1741
|
-
this.grow = function ()
|
1742
|
-
{
|
1743
|
-
var obj = this;
|
1744
|
-
var callback = arguments[1] ? arguments[1] : function () {};
|
1745
|
-
var opt = arguments[0] ? arguments[0] : {};
|
1746
|
-
var frames = opt.frames ? opt.frames : 30;
|
1747
|
-
var frame = 0;
|
1748
|
-
var data = RG.array_clone(obj.data);
|
1749
|
-
|
1750
|
-
function iterator ()
|
1751
|
-
{
|
1752
|
-
for (var i=0,len=data.length; i<len; ++i) {
|
1753
|
-
|
1754
|
-
//if (obj.original_data[i] == null) {
|
1755
|
-
// obj.original_data[i] = [];
|
1756
|
-
//}
|
1757
|
-
|
1758
|
-
for (var j=0,len2=data[i].length; j<len2; ++j) {
|
1759
|
-
obj.original_data[i][j] = (frame / frames) * data[i][j];
|
1760
|
-
}
|
1761
|
-
}
|
1762
|
-
|
1763
|
-
RGraph.clear(obj.canvas);
|
1764
|
-
RGraph.redrawCanvas(obj.canvas);
|
1765
|
-
|
1766
|
-
if (frame < frames) {
|
1767
|
-
frame++;
|
1768
|
-
RGraph.Effects.updateCanvas(iterator);
|
1769
|
-
} else {
|
1770
|
-
callback(obj);
|
1771
|
-
}
|
1772
|
-
}
|
1773
|
-
|
1774
|
-
iterator();
|
1775
|
-
|
1776
|
-
return this;
|
1777
|
-
};
|
1778
|
-
|
1779
|
-
|
1780
|
-
|
1781
|
-
|
1782
|
-
/**
|
1783
|
-
* Trace (Radar chart)
|
1784
|
-
*
|
1785
|
-
* This is a Trace effect for the Radar chart
|
1786
|
-
*
|
1787
|
-
* @param object Options for the effect. Currently only "frames" is available.
|
1788
|
-
* @param function A function that is called when the ffect is complete
|
1789
|
-
*/
|
1790
|
-
this.trace = function ()
|
1791
|
-
{
|
1792
|
-
var obj = this;
|
1793
|
-
var opt = arguments[0] || {};
|
1794
|
-
var frames = opt.frames || 60;
|
1795
|
-
var frame = 0;
|
1796
|
-
var callback = arguments[1] || function () {};
|
1797
|
-
|
1798
|
-
obj.Set('animation.trace.clip', 0);
|
1799
|
-
|
1800
|
-
|
1801
|
-
var iterator = function ()
|
1802
|
-
{
|
1803
|
-
if (frame < frames) {
|
1804
|
-
|
1805
|
-
obj.Set('animation.trace.clip', frame / frames);
|
1806
|
-
|
1807
|
-
frame++;
|
1808
|
-
RG.redrawCanvas(obj.canvas);
|
1809
|
-
RG.Effects.updateCanvas(iterator);
|
1810
|
-
|
1811
|
-
} else {
|
1812
|
-
|
1813
|
-
obj.Set('animation.trace.clip', 1);
|
1814
|
-
RG.redrawCanvas(obj.canvas);
|
1815
|
-
callback(obj);
|
1816
|
-
}
|
1817
|
-
};
|
1818
|
-
|
1819
|
-
iterator();
|
1820
|
-
|
1821
|
-
return this;
|
1822
|
-
};
|
1823
|
-
|
1824
|
-
|
1825
|
-
|
1826
|
-
|
1827
|
-
RG.att(ca);
|
1828
|
-
|
1829
|
-
|
1830
|
-
|
1831
|
-
|
1832
|
-
/**
|
1833
|
-
* Always register the object
|
1834
|
-
*/
|
1835
|
-
RG.Register(this);
|
1836
|
-
|
1837
|
-
|
1838
|
-
|
1839
|
-
|
1840
|
-
/**
|
1841
|
-
* This is the 'end' of the constructor so if the first argument
|
1842
|
-
* contains configuration data - handle that.
|
1843
|
-
*/
|
1844
|
-
if (parseConfObjectForOptions) {
|
1845
|
-
RG.parseObjectStyleConfig(this, conf.options);
|
1846
|
-
}
|
1847
|
-
};
|