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