rgraph-rails 1.0.8 → 4.62

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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/lib/rgraph-rails/version.rb +1 -1
  4. data/vendor/assets/javascripts/RGraph.bar.js +16 -8
  5. data/vendor/assets/javascripts/RGraph.bipolar.js +1 -1
  6. data/vendor/assets/javascripts/RGraph.common.annotate.js +1 -1
  7. data/vendor/assets/javascripts/RGraph.common.context.js +1 -1
  8. data/vendor/assets/javascripts/RGraph.common.core.js +84 -7
  9. data/vendor/assets/javascripts/RGraph.common.csv.js +1 -1
  10. data/vendor/assets/javascripts/RGraph.common.deprecated.js +1 -1
  11. data/vendor/assets/javascripts/RGraph.common.dynamic.js +1 -1
  12. data/vendor/assets/javascripts/RGraph.common.effects.js +1 -1
  13. data/vendor/assets/javascripts/RGraph.common.key.js +3 -3
  14. data/vendor/assets/javascripts/RGraph.common.resizing.js +1 -1
  15. data/vendor/assets/javascripts/RGraph.common.sheets.js +1 -1
  16. data/vendor/assets/javascripts/RGraph.common.tooltips.js +1 -1
  17. data/vendor/assets/javascripts/RGraph.common.zoom.js +1 -1
  18. data/vendor/assets/javascripts/RGraph.drawing.background.js +1 -1
  19. data/vendor/assets/javascripts/RGraph.drawing.circle.js +1 -1
  20. data/vendor/assets/javascripts/RGraph.drawing.image.js +1 -1
  21. data/vendor/assets/javascripts/RGraph.drawing.marker1.js +1 -1
  22. data/vendor/assets/javascripts/RGraph.drawing.marker2.js +1 -1
  23. data/vendor/assets/javascripts/RGraph.drawing.marker3.js +1 -1
  24. data/vendor/assets/javascripts/RGraph.drawing.poly.js +1 -1
  25. data/vendor/assets/javascripts/RGraph.drawing.rect.js +1 -1
  26. data/vendor/assets/javascripts/RGraph.drawing.text.js +1 -1
  27. data/vendor/assets/javascripts/RGraph.drawing.xaxis.js +1 -1
  28. data/vendor/assets/javascripts/RGraph.drawing.yaxis.js +1 -1
  29. data/vendor/assets/javascripts/RGraph.fuel.js +1 -1
  30. data/vendor/assets/javascripts/RGraph.funnel.js +1 -1
  31. data/vendor/assets/javascripts/RGraph.gantt.js +1 -1
  32. data/vendor/assets/javascripts/RGraph.gauge.js +1 -1
  33. data/vendor/assets/javascripts/RGraph.hbar.js +228 -2
  34. data/vendor/assets/javascripts/RGraph.hprogress.js +1 -1
  35. data/vendor/assets/javascripts/RGraph.line.js +27 -5
  36. data/vendor/assets/javascripts/RGraph.meter.js +1 -1
  37. data/vendor/assets/javascripts/RGraph.modaldialog.js +1 -1
  38. data/vendor/assets/javascripts/RGraph.odo.js +1 -1
  39. data/vendor/assets/javascripts/RGraph.pie.js +1 -1
  40. data/vendor/assets/javascripts/RGraph.radar.js +1 -1
  41. data/vendor/assets/javascripts/RGraph.rose.js +1 -1
  42. data/vendor/assets/javascripts/RGraph.rscatter.js +1 -1
  43. data/vendor/assets/javascripts/RGraph.scatter.js +161 -34
  44. data/vendor/assets/javascripts/RGraph.semicircularprogress.js +1 -1
  45. data/vendor/assets/javascripts/RGraph.svg.bar.js +772 -103
  46. data/vendor/assets/javascripts/RGraph.svg.common.ajax.js +1 -1
  47. data/vendor/assets/javascripts/RGraph.svg.common.core.js +806 -231
  48. data/vendor/assets/javascripts/RGraph.svg.common.csv.js +1 -1
  49. data/vendor/assets/javascripts/RGraph.svg.common.fx.js +24 -24
  50. data/vendor/assets/javascripts/RGraph.svg.common.key.js +206 -0
  51. data/vendor/assets/javascripts/RGraph.svg.common.sheets.js +1 -1
  52. data/vendor/assets/javascripts/RGraph.svg.common.tooltips.js +63 -22
  53. data/vendor/assets/javascripts/RGraph.svg.hbar.js +351 -91
  54. data/vendor/assets/javascripts/RGraph.svg.line.js +159 -64
  55. data/vendor/assets/javascripts/RGraph.svg.pie.js +402 -51
  56. data/vendor/assets/javascripts/RGraph.svg.radar.js +320 -143
  57. data/vendor/assets/javascripts/RGraph.svg.rose.js +1818 -0
  58. data/vendor/assets/javascripts/RGraph.svg.scatter.js +1262 -0
  59. data/vendor/assets/javascripts/RGraph.svg.semicircularprogress.js +106 -57
  60. data/vendor/assets/javascripts/RGraph.svg.waterfall.js +1253 -0
  61. data/vendor/assets/javascripts/RGraph.thermometer.js +7 -6
  62. data/vendor/assets/javascripts/RGraph.vprogress.js +1 -1
  63. data/vendor/assets/javascripts/RGraph.waterfall.js +1 -1
  64. data/vendor/assets/javascripts/financial-data.js +1067 -0
  65. metadata +8 -5
  66. data/vendor/assets/javascripts/RGraph.cornergauge.js +0 -71
  67. data/vendor/assets/javascripts/RGraph.thermometer.old.js +0 -68
@@ -1,4 +1,4 @@
1
- // version: 2017-01-02
1
+ // version: 2017-05-08
2
2
  /**
3
3
  * o--------------------------------------------------------------------------------o
4
4
  * | This file is part of the RGraph package - you can learn more at: |
@@ -1,4 +1,4 @@
1
- // version: 2017-01-02
1
+ // version: 2017-05-08
2
2
  /**
3
3
  * o--------------------------------------------------------------------------------o
4
4
  * | This file is part of the RGraph package - you can learn more at: |
@@ -65,7 +65,7 @@
65
65
  //
66
66
  RG.SVG.createSVG = function (opt)
67
67
  {
68
- var container = opt.container;
68
+ var container = opt.container;
69
69
 
70
70
  if (container.__svg__) {
71
71
  return container.__svg__;
@@ -75,6 +75,7 @@
75
75
  svg.setAttribute('style', 'top: 0; left: 0; position: absolute');
76
76
  svg.setAttribute('width', container.offsetWidth);
77
77
  svg.setAttribute('height', container.offsetHeight);
78
+ svg.setAttribute('version', '1.1');
78
79
  svg.setAttributeNS("http://www.w3.org/2000/xmlns/", 'xmlns', 'http://www.w3.org/2000/svg');
79
80
  svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink");
80
81
  container.appendChild(svg);
@@ -82,6 +83,17 @@
82
83
  container.__svg__ = svg;
83
84
  container.style.position = 'relative';
84
85
 
86
+ // Add the group tag to the SVG that contains all of the elements
87
+ var group = RG.SVG.create({
88
+ svg: svg,
89
+ type: 'g',
90
+ attr: {
91
+ className: 'all-elements'
92
+ }
93
+ });
94
+
95
+ container.__svg__.all = group;
96
+
85
97
  return svg;
86
98
  };
87
99
 
@@ -97,13 +109,16 @@
97
109
  //
98
110
  RG.SVG.createDefs = function (obj)
99
111
  {
100
- var defs = RG.SVG.create({
101
- svg: obj.svg,
102
- type: 'defs'
103
- });
112
+ if (!obj.svg.defs) {
113
+
114
+ var defs = RG.SVG.create({
115
+ svg: obj.svg,
116
+ type: 'defs'
117
+ });
118
+
119
+ obj.svg.defs = defs;
120
+ }
104
121
 
105
- obj.defs = defs;
106
-
107
122
  return defs;
108
123
  };
109
124
 
@@ -133,7 +148,7 @@
133
148
  if (o === 'className') {
134
149
  name = 'class';
135
150
  }
136
- if (opt.type === 'a' && o === 'xlink:href') {
151
+ if ( (opt.type === 'a' || opt.type === 'image') && o === 'xlink:href') {
137
152
  tag.setAttributeNS('http://www.w3.org/1999/xlink', o, String(opt.attr[o]));
138
153
  } else {
139
154
  tag.setAttribute(name, String(opt.attr[o]));
@@ -176,10 +191,11 @@
176
191
  // Draw the axis
177
192
  if (prop.xaxis) {
178
193
 
179
- var y = obj.type === 'hbar' ? obj.height - prop.gutterBottom : obj.getYCoord(0);
194
+ var y = obj.type === 'hbar' ? obj.height - prop.gutterBottom : obj.getYCoord(obj.scale.min < 0 && obj.scale.max < 0 ? obj.scale.max : (obj.scale.min > 0 && obj.scale.max > 0 ? obj.scale.min : 0));
180
195
 
181
196
  var axis = RG.SVG.create({
182
197
  svg: obj.svg,
198
+ parent: obj.svg.all,
183
199
  type: 'path',
184
200
  attr: {
185
201
  d: 'M{1} {2} L{3} {4}'.format(
@@ -190,7 +206,9 @@
190
206
  ),
191
207
  fill: prop.xaxisColor,
192
208
  stroke: prop.xaxisColor,
193
- 'shape-rendering': "crispEdges"
209
+ 'stroke-width': typeof prop.xaxisLinewidth === 'number' ? prop.xaxisLinewidth : 1,
210
+ 'shape-rendering': 'crispEdges',
211
+ 'stroke-linecap': 'square'
194
212
  }
195
213
  });
196
214
 
@@ -202,14 +220,23 @@
202
220
  startY = (obj.height - prop.gutterBottom),
203
221
  endY = (obj.height - prop.gutterBottom) + prop.xaxisTickmarksLength;
204
222
 
205
- // Line/Bar X axis
223
+ // Line/Bar/Waterfall/Scatter X axis
206
224
  } else {
207
225
  var width = obj.graphWidth / obj.data.length,
208
226
  x = prop.gutterLeft,
209
227
  startY = obj.getYCoord(0) - (prop.yaxisMin < 0 ? prop.xaxisTickmarksLength : 0),
210
228
  endY = obj.getYCoord(0) + prop.xaxisTickmarksLength;
211
- }
229
+
230
+ if (obj.scale.min < 0 && obj.scale.max <= 0) {
231
+ startY = prop.gutterTop;
232
+ endY = prop.gutterTop - prop.xaxisTickmarksLength;
233
+ }
212
234
 
235
+ if (obj.scale.min > 0 && obj.scale.max > 0) {
236
+ startY = obj.getYCoord(obj.scale.min);
237
+ endY = obj.getYCoord(obj.scale.min) + prop.xaxisTickmarksLength;
238
+ }
239
+ }
213
240
 
214
241
 
215
242
 
@@ -221,7 +248,7 @@
221
248
  // Draw the tickmarks
222
249
  if (prop.xaxisTickmarks) {
223
250
 
224
- // TH HBar uses a scale
251
+ // The HBar uses a scale
225
252
  if (prop.xaxisScale) {
226
253
 
227
254
  for (var i=0; i<(obj.scale.numlabels + (prop.yaxis && prop.xaxisMin === 0 ? 0 : 1)); ++i) {
@@ -234,6 +261,7 @@
234
261
 
235
262
  RG.SVG.create({
236
263
  svg: obj.svg,
264
+ parent: obj.svg.all,
237
265
  type: 'path',
238
266
  attr: {
239
267
  d: 'M{1} {2} L{3} {4}'.format(
@@ -243,6 +271,7 @@
243
271
  endY
244
272
  ),
245
273
  stroke: prop.xaxisColor,
274
+ 'stroke-width': typeof prop.xaxisLinewidth === 'number' ? prop.xaxisLinewidth : 1,
246
275
  'shape-rendering': "crispEdges"
247
276
  }
248
277
  });
@@ -252,23 +281,25 @@
252
281
 
253
282
 
254
283
  } else {
255
-
284
+
256
285
  // This style is used by Bar and Scatter charts
257
286
  if (prop.xaxisLabelsPosition === 'section') {
258
-
259
- for (var i=0; i<obj.data.length; ++i) {
260
-
261
- if (obj.type === 'bar') {
262
- var dataPoints = obj.data.length;
263
- } else if (obj.type === 'line'){
264
- var dataPoints = obj.data[0].length;
265
- }
266
-
287
+
288
+ if (obj.type === 'bar' || obj.type === 'waterfall') {
289
+ var dataPoints = obj.data.length;
290
+ } else if (obj.type === 'line'){
291
+ var dataPoints = obj.data[0].length;
292
+ } else if (obj.type === 'scatter') {
293
+ var dataPoints = prop.xaxisLabels ? prop.xaxisLabels.length : 10;
294
+ }
295
+
296
+ for (var i=0; i<dataPoints; ++i) {
267
297
 
268
298
  x = prop.gutterLeft + ((i+1) * (obj.graphWidth / dataPoints));
269
-
299
+
270
300
  RG.SVG.create({
271
301
  svg: obj.svg,
302
+ parent: obj.svg.all,
272
303
  type: 'path',
273
304
  attr: {
274
305
  d: 'M{1} {2} L{3} {4}'.format(
@@ -278,11 +309,12 @@
278
309
  endY
279
310
  ),
280
311
  stroke: prop.xaxisColor,
312
+ 'stroke-width': typeof prop.xaxisLinewidth === 'number' ? prop.xaxisLinewidth : 1,
281
313
  'shape-rendering': "crispEdges"
282
314
  }
283
315
  });
284
316
  }
285
-
317
+
286
318
  // This style is used by line charts
287
319
  } else if (prop.xaxisLabelsPosition === 'edge') {
288
320
 
@@ -296,9 +328,10 @@
296
328
 
297
329
  var gap = ( (obj.graphWidth) / (len - 1)),
298
330
  x = prop.gutterLeft + ((i+1) * gap);
299
-
331
+
300
332
  RG.SVG.create({
301
333
  svg: obj.svg,
334
+ parent: obj.svg.all,
302
335
  type: 'path',
303
336
  attr: {
304
337
  d: 'M{1} {2} L{3} {4}'.format(
@@ -308,6 +341,7 @@
308
341
  endY
309
342
  ),
310
343
  stroke: prop.xaxisColor,
344
+ 'stroke-width': typeof prop.xaxisLinewidth === 'number' ? prop.xaxisLinewidth : 1,
311
345
  'shape-rendering': "crispEdges"
312
346
  }
313
347
  });
@@ -324,6 +358,7 @@
324
358
  if (prop.yaxis === false) {
325
359
  RG.SVG.create({
326
360
  svg: obj.svg,
361
+ parent: obj.svg.all,
327
362
  type: 'path',
328
363
  attr: {
329
364
  d: 'M{1} {2} L{3} {4}'.format(
@@ -333,7 +368,9 @@
333
368
  endY
334
369
  ),
335
370
  stroke: obj.properties.xaxisColor,
336
- 'shape-rendering': "crispEdges"
371
+ 'stroke-width': typeof prop.xaxisLinewidth === 'number' ? prop.xaxisLinewidth : 1,
372
+ 'shape-rendering': "crispEdges",
373
+ parent: obj.svg.all,
337
374
  }
338
375
  });
339
376
  }
@@ -364,9 +401,10 @@
364
401
 
365
402
  RG.SVG.text({
366
403
  object: obj,
404
+ parent: obj.svg.all,
367
405
  text: obj.scale.labels[i],
368
406
  x: x,
369
- y: (obj.height - prop.gutterBottom) + (prop.xaxis ? prop.xaxisTickmarksLength + 6 : 10) + prop.xaxisLabelsOffsety,
407
+ y: (obj.height - prop.gutterBottom) + (prop.xaxis ? prop.xaxisTickmarksLength + 6 : 10) + (prop.xaxisLinewidth || 1) + prop.xaxisLabelsOffsety,
370
408
  halign: 'center',
371
409
  valign: 'top',
372
410
  font: prop.xaxisTextFont || prop.textFont,
@@ -381,31 +419,34 @@
381
419
 
382
420
 
383
421
 
384
- // Add the minimum label
385
- var y = obj.height - prop.gutterBottom + prop.xaxisLabelsOffsety + (prop.xaxis ? prop.xaxisTickmarksLength + 6 : 10),
386
- str = RG.SVG.numberFormat({
422
+ // Add the minimum label if labels are enabled
423
+ if (prop.xaxisLabelsCount > 0) {
424
+ var y = obj.height - prop.gutterBottom + prop.xaxisLabelsOffsety + (prop.xaxis ? prop.xaxisTickmarksLength + 6 : 10),
425
+ str = RG.SVG.numberFormat({
426
+ object: obj,
427
+ num: prop.xaxisMin.toFixed(prop.xaxisDecimals),
428
+ prepend: prop.xaxisUnitsPre,
429
+ append: prop.xaxisUnitsPost,
430
+ point: prop.xaxisPoint,
431
+ thousand: prop.xaxisThousand,
432
+ formatter: prop.xaxisFormatter
433
+ });
434
+
435
+ var text = RG.SVG.text({
387
436
  object: obj,
388
- num: prop.xaxisMin.toFixed(prop.xaxisDecimals),
389
- prepend: prop.xaxisUnitsPre,
390
- append: prop.xaxisUnitsPost,
391
- point: prop.xaxisPoint,
392
- thousand: prop.xaxisThousand,
393
- formatter: prop.xaxisFormatter
437
+ parent: obj.svg.all,
438
+ text: typeof prop.xaxisFormatter === 'function' ? (prop.xaxisFormatter)(this, prop.xaxisMin) : str,
439
+ x: prop.gutterLeft + prop.xaxisLabelsOffsetx,
440
+ y: y,
441
+ halign: 'center',
442
+ valign: 'top',
443
+ font: prop.xaxisTextFont || prop.textFont,
444
+ size: prop.xaxisTextSize || (typeof prop.textSize === 'number' ? prop.textSize + 'pt' : prop.textSize),
445
+ bold: prop.xaxisTextBold || prop.textBold,
446
+ italic: prop.xaxisTextItalic || prop.textItalic,
447
+ color: prop.xaxisTextColor || prop.textColor
394
448
  });
395
-
396
- var text = RG.SVG.text({
397
- object: obj,
398
- text: typeof prop.xaxisFormatter === 'function' ? (prop.xaxisFormatter)(this, prop.xaxisMin) : str,
399
- x: prop.gutterLeft + prop.xaxisLabelsOffsetx,
400
- y: y,
401
- halign: 'center',
402
- valign: 'top',
403
- font: prop.xaxisTextFont || prop.textFont,
404
- size: prop.xaxisTextSize || (typeof prop.textSize === 'number' ? prop.textSize + 'pt' : prop.textSize),
405
- bold: prop.xaxisTextBold || prop.textBold,
406
- italic: prop.xaxisTextItalic || prop.textItalic,
407
- color: prop.xaxisTextColor || prop.textColor
408
- });
449
+ }
409
450
 
410
451
  //
411
452
  // Draw the X axis labels
@@ -421,13 +462,22 @@
421
462
  for (var i=0; i<prop.xaxisLabels.length; ++i) {
422
463
 
423
464
  var x = prop.gutterLeft + (segment / 2) + (i * segment);
465
+
466
+ if (obj.scale.max <=0 && obj.scale.min < obj.scale.max) {
467
+ var y = prop.gutterTop - (RG.SVG.ISFF ? 5 : 10) - (prop.xaxisLinewidth || 1) + prop.xaxisLabelsOffsety;
468
+ var valign = 'bottom';
469
+ } else {
470
+ var y = obj.height - prop.gutterBottom + (RG.SVG.ISFF ? 5 : 10) + (prop.xaxisLinewidth || 1) + prop.xaxisLabelsOffsety;
471
+ var valign = 'top';
472
+ }
424
473
 
425
474
  RG.SVG.text({
426
475
  object: obj,
476
+ parent: obj.svg.all,
427
477
  text: prop.xaxisLabels[i],
428
478
  x: x + prop.xaxisLabelsOffsetx,
429
- y: obj.height - prop.gutterBottom + (RG.SVG.ISFF ? 5 : 10) + prop.xaxisLabelsOffsety,
430
- valign: 'top',
479
+ y: y,
480
+ valign: valign,
431
481
  halign: 'center',
432
482
  size: prop.xaxisTextSize || prop.textSize,
433
483
  italic: prop.xaxisTextItalic || prop.textItalic,
@@ -451,13 +501,22 @@
451
501
  for (var i=0; i<prop.xaxisLabels.length; ++i) {
452
502
 
453
503
  var x = prop.gutterLeft + (i * segment) + hmargin;
504
+
505
+ if (obj.scale.max <= 0 && obj.scale.min < 0) {
506
+ valign = 'bottom';
507
+ y = prop.gutterTop - (RG.SVG.ISFF ? 5 : 10) - (prop.xaxisTickmarksLength - 5) - (prop.xaxisLinewidth || 1) + prop.xaxisLabelsOffsety
508
+ } else {
509
+ valign = 'top';
510
+ y = obj.height - prop.gutterBottom + (RG.SVG.ISFF ? 5 : 10) + (prop.xaxisTickmarksLength - 5) + (prop.xaxisLinewidth || 1) + prop.xaxisLabelsOffsety;
511
+ }
454
512
 
455
513
  RG.SVG.text({
456
514
  object: obj,
515
+ parent: obj.svg.all,
457
516
  text: prop.xaxisLabels[i],
458
517
  x: x + prop.xaxisLabelsOffsetx,
459
- y: obj.height - prop.gutterBottom + (RG.SVG.ISFF ? 5 : 10) + (prop.xaxisTickmarksLength - 5) + prop.xaxisLabelsOffsety,
460
- valign: 'top',
518
+ y: y,
519
+ valign: valign,
461
520
  halign: 'center',
462
521
  size: prop.xaxisTextSize || prop.textSize,
463
522
  italic: prop.xaxisTextItalic || prop.textItalic,
@@ -490,10 +549,21 @@
490
549
  if (prop.yaxis) {
491
550
 
492
551
  // The X coordinate that the Y axis is positioned at
493
- var x = obj.type === 'hbar' ? obj.getXCoord(0) : prop.gutterLeft;
552
+ if (obj.type === 'hbar') {
553
+
554
+ var x = obj.getXCoord(prop.xaxisMin > 0 ? prop.xaxisMin : 0);
555
+
556
+ if (prop.xaxisMin < 0 && prop.xaxisMax <= 0) {
557
+ x = obj.getXCoord(prop.xaxisMax);
558
+ }
559
+ } else {
560
+ var x = prop.gutterLeft;
561
+ }
562
+
494
563
 
495
564
  var axis = RG.SVG.create({
496
565
  svg: obj.svg,
566
+ parent: obj.svg.all,
497
567
  type: 'path',
498
568
  attr: {
499
569
  d: 'M{1} {2} L{3} {4}'.format(
@@ -504,7 +574,9 @@
504
574
  ),
505
575
  stroke: prop.yaxisColor,
506
576
  fill: prop.yaxisColor,
507
- 'shape-rendering': "crispEdges"
577
+ 'stroke-width': typeof prop.yaxisLinewidth === 'number' ? prop.yaxisLinewidth : 1,
578
+ 'shape-rendering': "crispEdges",
579
+ 'stroke-linecap': 'square'
508
580
  }
509
581
  });
510
582
 
@@ -516,21 +588,27 @@
516
588
 
517
589
  if (obj.type === 'hbar') {
518
590
 
519
- var height = obj.graphHeight / prop.yaxisLabels.length,
520
- y = prop.gutterTop,
591
+ var height = (obj.graphHeight - prop.vmarginTop - prop.vmarginBottom) / prop.yaxisLabels.length,
592
+ y = prop.gutterTop + prop.vmarginTop,
521
593
  len = prop.yaxisLabels.length,
522
594
  startX = obj.getXCoord(0) + (prop.xaxisMin < 0 ? prop.yaxisTickmarksLength : 0),
523
595
  endX = obj.getXCoord(0) - prop.yaxisTickmarksLength;
524
596
 
597
+ if (obj.type === 'hbar' && prop.xaxisMin < 0 && prop.xaxisMax <=0) {
598
+ startX = obj.getXCoord(prop.xaxisMax);
599
+ endX = obj.getXCoord(prop.xaxisMax) + 5;
600
+ }
601
+
525
602
  //
526
603
  // Draw the tickmarks
527
604
  //
528
605
  if (prop.yaxisTickmarks) {
529
606
  for (var i=0; i<len; ++i) {
530
-
607
+
531
608
  // Draw the axis
532
609
  var axis = RG.SVG.create({
533
610
  svg: obj.svg,
611
+ parent: obj.svg.all,
534
612
  type: 'path',
535
613
  attr: {
536
614
  d: 'M{1} {2} L{3} {4}'.format(
@@ -540,6 +618,7 @@
540
618
  y + 0.001
541
619
  ),
542
620
  stroke: prop.yaxisColor,
621
+ 'stroke-width': typeof prop.yaxisLinewidth === 'number' ? prop.yaxisLinewidth : 1,
543
622
  'shape-rendering': "crispEdges"
544
623
  }
545
624
  });
@@ -549,19 +628,32 @@
549
628
 
550
629
 
551
630
  // Draw an extra tick if the X axis position is not zero or
552
- //if the xaxis is not being shown
631
+ // if the xaxis is not being shown
553
632
  if (prop.xaxis === false) {
633
+
634
+ if (obj.type === 'hbar' && prop.xaxisMin <= 0 && prop.xaxisMax < 0) {
635
+ var startX = obj.getXCoord(prop.xaxisMax);
636
+ var endX = obj.getXCoord(prop.xaxisMax) + prop.yaxisTickmarksLength;
637
+
638
+ } else {
639
+ var startX = obj.getXCoord(0) - prop.yaxisTickmarksLength;
640
+ var endX = obj.getXCoord(0) + (prop.xaxisMin < 0 ? prop.yaxisTickmarksLength : 0);
641
+ }
642
+
554
643
  var axis = RG.SVG.create({
555
644
  svg: obj.svg,
645
+ parent: obj.svg.all,
556
646
  type: 'path',
557
647
  attr: {
558
648
  d: 'M{1} {2} L{3} {4}'.format(
559
- obj.getXCoord(0) - prop.yaxisTickmarksLength - 1,
560
- obj.height - prop.gutterBottom,
561
- obj.getXCoord(0) + (obj.type === 'hbar' && prop.xaxisMin < 0 ? 3 : 0),
562
- obj.height - prop.gutterBottom - 0.001
649
+ startX,
650
+ obj.height - prop.gutterBottom - parseFloat(prop.vmarginBottom),
651
+
652
+ endX,
653
+ obj.height - prop.gutterBottom - parseFloat(prop.vmarginBottom) - 0.001
563
654
  ),
564
655
  stroke: obj.properties.yaxisColor,
656
+ 'stroke-width': typeof prop.yaxisLinewidth === 'number' ? prop.yaxisLinewidth : 1,
565
657
  'shape-rendering': "crispEdges"
566
658
  }
567
659
  });
@@ -588,6 +680,7 @@
588
680
  // Draw the axis
589
681
  var axis = RG.SVG.create({
590
682
  svg: obj.svg,
683
+ parent: obj.svg.all,
591
684
  type: 'path',
592
685
  attr: {
593
686
  d: 'M{1} {2} L{3} {4}'.format(
@@ -597,6 +690,7 @@
597
690
  y + 0.001
598
691
  ),
599
692
  stroke: prop.yaxisColor,
693
+ 'stroke-width': typeof prop.yaxisLinewidth === 'number' ? prop.yaxisLinewidth : 1,
600
694
  'shape-rendering': "crispEdges"
601
695
  }
602
696
  });
@@ -607,9 +701,13 @@
607
701
 
608
702
  // Draw an extra tick if the X axis position is not zero or
609
703
  //if the xaxis is not being shown
610
- if (obj.type !== 'hbar' && (prop.yaxisMin !== 0 || prop.xaxis === false)) {
704
+ if ( (prop.yaxisMin !== 0 || prop.xaxis === false)
705
+ && !(obj.scale.min > 0 && obj.scale.max > 0) ) {
706
+
707
+
611
708
  var axis = RG.SVG.create({
612
709
  svg: obj.svg,
710
+ parent: obj.svg.all,
613
711
  type: 'path',
614
712
  attr: {
615
713
  d: 'M{1} {2} L{3} {4}'.format(
@@ -619,6 +717,7 @@
619
717
  obj.height - prop.gutterBottom - 0.001
620
718
  ),
621
719
  stroke: prop.yaxisColor,
720
+ 'stroke-width': typeof prop.yaxisLinewidth === 'number' ? prop.yaxisLinewidth : 1,
622
721
  'shape-rendering': "crispEdges"
623
722
  }
624
723
  });
@@ -645,6 +744,7 @@
645
744
 
646
745
  RG.SVG.text({
647
746
  object: obj,
747
+ parent: obj.svg.all,
648
748
  text: obj.scale.labels[i],
649
749
  x: prop.gutterLeft - 7 - (prop.yaxis ? (prop.yaxisTickmarksLength - 3) : 0) + prop.yaxisLabelsOffsetx,
650
750
  y: y + prop.yaxisLabelsOffsety,
@@ -669,6 +769,7 @@
669
769
 
670
770
  var text = RG.SVG.text({
671
771
  object: obj,
772
+ parent: obj.svg.all,
672
773
  text: typeof prop.yaxisFormatter === 'function' ? (prop.yaxisFormatter)(this, prop.yaxisMin) : str,
673
774
  x: prop.gutterLeft - 7 - (prop.yaxis ? (prop.yaxisTickmarksLength - 3) : 0) + prop.yaxisLabelsOffsetx,
674
775
  y: y + prop.yaxisLabelsOffsety,
@@ -690,15 +791,34 @@
690
791
 
691
792
  for (var i=0; i<prop.yaxisLabels.length; ++i) {
692
793
 
693
- var segment = obj.graphHeight / prop.yaxisLabels.length,
694
- y = prop.gutterTop + (segment * i) + (segment / 2) + prop.yaxisLabelsOffsety;
794
+ var segment = (obj.graphHeight - (prop.vmarginTop || 0) - (prop.vmarginBottom || 0) ) / prop.yaxisLabels.length,
795
+ y = prop.gutterTop + (prop.vmarginTop || 0) + (segment * i) + (segment / 2) + prop.yaxisLabelsOffsety,
796
+ x = prop.gutterLeft - 7 /*- (prop.yaxis ? (prop.yaxisTickmarksLength) : 0)*/ - (prop.yaxisLinewidth || 1) + prop.yaxisLabelsOffsetx,
797
+ halign = 'right';
798
+
799
+ // HBar labels
800
+ if (obj.type === 'hbar' && obj.scale.min < obj.scale.max && obj.scale.max <= 0) {
801
+ halign = 'left';
802
+ x = obj.width - prop.gutterRight + 7 + prop.yaxisLabelsOffsetx;
803
+
804
+ // HBar labels
805
+ } else if (obj.type === 'hbar' && !prop.yaxisLabelsSpecific) {
806
+ var segment = (obj.graphHeight - (prop.vmarginTop || 0) - (prop.vmarginBottom || 0) ) / (prop.yaxisLabels.length);
807
+ y = prop.gutterTop + (prop.vmarginTop || 0) + (segment * i) + (segment / 2) + prop.yaxisLabelsOffsetx;
808
+
809
+ // Specific scale
810
+ } else {
811
+ var segment = (obj.graphHeight - (prop.vmarginTop || 0) - (prop.vmarginBottom || 0) ) / (prop.yaxisLabels.length - 1);
812
+ y = obj.height - prop.gutterBottom - (segment * i) + prop.yaxisLabelsOffsetx;
813
+ }
695
814
 
696
815
  var text = RG.SVG.text({
697
816
  object: obj,
817
+ parent: obj.svg.all,
698
818
  text: prop.yaxisLabels[i] ? prop.yaxisLabels[i] : '',
699
- x: prop.gutterLeft - 7 /*- (prop.yaxis ? (prop.yaxisTickmarksLength) : 0)*/ + prop.yaxisLabelsOffsetx,
819
+ x: x,
700
820
  y: y,
701
- halign: 'right',
821
+ halign: halign,
702
822
  valign: 'center',
703
823
  font: prop.yaxisTextFont || prop.textFont,
704
824
  size: prop.yaxisTextSize || (typeof prop.textSize === 'number' ? prop.textSize + 'pt' : prop.textSize),
@@ -724,33 +844,117 @@
724
844
  //
725
845
  RG.SVG.drawBackground = function (obj)
726
846
  {
727
- var prop = obj.properties;
847
+ var prop = obj.properties;
848
+
849
+ // Set these properties so that if it doesn't exist things don't fail
850
+ if (typeof prop.variant3dOffsetx !== 'number') prop.variant3dOffsetx = 0;
851
+ if (typeof prop.variant3dOffsety !== 'number') prop.variant3dOffsety = 0;
852
+
853
+
854
+
855
+
856
+ if (prop.backgroundColor) {
857
+ RG.SVG.create({
858
+ svg: obj.svg,
859
+ parent: obj.svg.all,
860
+ type: 'rect',
861
+ attr: {
862
+ x: -1 + prop.variant3dOffsetx,
863
+ y: -1 - prop.variant3dOffsety,
864
+ width: parseFloat(obj.svg.getAttribute('width')) + 2,
865
+ height: parseFloat(obj.svg.getAttribute('height')) + 2,
866
+ fill: prop.backgroundColor
867
+ }
868
+ });
869
+ }
870
+
871
+ // Render a background image
872
+ // <image xlink:href="firefox.jpg" x="0" y="0" height="50px" width="50px"/>
873
+ if (prop.backgroundImage) {
874
+
875
+ var attr = {
876
+ 'xlink:href': prop.backgroundImage,
877
+ //preserveAspectRatio: 'xMidYMid slice',
878
+ preserveAspectRatio: prop.backgroundImageAspect || 'none',
879
+ x: prop.gutterLeft,
880
+ y: prop.gutterTop
881
+ };
882
+
883
+ if (prop.backgroundImageStretch) {
884
+
885
+ attr.x = prop.gutterLeft + prop.variant3dOffsetx;
886
+ attr.y = prop.gutterTop + prop.variant3dOffsety;
887
+ attr.width = obj.width - prop.gutterLeft - prop.gutterRight;
888
+ attr.height = obj.height - prop.gutterTop - prop.gutterBottom;
889
+
890
+ } else {
891
+
892
+ if (typeof prop.backgroundImageX === 'number') {
893
+ attr.x = prop.backgroundImageX + prop.variant3dOffsetx;
894
+ }
895
+
896
+ if (typeof prop.backgroundImageY === 'number') {
897
+ attr.y = prop.backgroundImageY + prop.variant3dOffsety;
898
+ }
899
+
900
+ if (typeof prop.backgroundImageW === 'number') {
901
+ attr.width = prop.backgroundImageW;
902
+ }
903
+
904
+ if (typeof prop.backgroundImageH === 'number') {
905
+ attr.height = prop.backgroundImageH;
906
+ }
907
+ }
908
+
909
+ //
910
+ // Account for the chart being 3d
911
+ //
912
+ if (prop.variant === '3d') {
913
+ attr.x += prop.variant3dOffsetx;
914
+ attr.y -= prop.variant3dOffsety;
915
+ }
916
+
917
+
918
+
919
+ var img = RG.SVG.create({
920
+ svg: obj.svg,
921
+ parent: obj.svg.all,
922
+ type: 'image',
923
+ attr: attr,
924
+ style: {
925
+ opacity: typeof prop.backgroundImageOpacity === 'number' ? prop.backgroundImageOpacity : 1
926
+ }
927
+ });
928
+ }
728
929
 
729
930
  if (prop .backgroundGrid) {
730
931
 
731
932
  var parts = [];
732
-
933
+
934
+
935
+
733
936
  // Add the horizontal lines to the path
734
937
  if (prop.backgroundGridHlines) {
735
938
 
736
939
  var count = typeof prop.backgroundGridHlinesCount === 'number' ? prop.backgroundGridHlinesCount : (obj.type === 'hbar' ? (prop.yaxisLabels.length || obj.data.length || 5) : prop.yaxisLabelsCount);
737
940
 
738
941
  for (var i=0; i<count; ++i) {
942
+
739
943
  parts.push('M{1} {2} L{3} {4}'.format(
740
- prop.gutterLeft,
741
- prop.gutterTop + (obj.graphHeight / count) * i,
742
- obj.width - prop.gutterRight,
743
- prop.gutterTop + (obj.graphHeight / count) * i
944
+ prop.gutterLeft + prop.variant3dOffsetx,
945
+ prop.gutterTop + (obj.graphHeight / count) * i - prop.variant3dOffsety,
946
+ obj.width - prop.gutterRight + prop.variant3dOffsetx,
947
+ prop.gutterTop + (obj.graphHeight / count) * i - prop.variant3dOffsety
744
948
  ));
745
949
  }
746
950
 
747
951
  // Add an extra background grid line to the path - this its
748
952
  // underneath the X axis and shows up if its not there.
749
953
  parts.push('M{1} {2} L{3} {4}'.format(
750
- prop.gutterLeft,
751
- obj.height - prop.gutterBottom,
752
- obj.width - prop.gutterRight,
753
- obj.height - prop.gutterBottom
954
+ prop.gutterLeft + prop.variant3dOffsetx,
955
+ obj.height - prop.gutterBottom - prop.variant3dOffsety,
956
+ obj.width - prop.gutterRight + prop.variant3dOffsetx,
957
+ obj.height - prop.gutterBottom - prop.variant3dOffsety
754
958
  ));
755
959
  }
756
960
 
@@ -762,7 +966,9 @@
762
966
  if (obj.type === 'line' && RG.SVG.isArray(obj.data[0])) {
763
967
  var len = obj.data[0].length;
764
968
  } else if (obj.type === 'hbar') {
765
- var len = prop.xaxisLabelsCount;
969
+ var len = prop.xaxisLabelsCount || 10;
970
+ } else if (obj.type === 'scatter') {
971
+ var len = (prop.xaxisLabels && prop.xaxisLabels.length) || 10;
766
972
  } else {
767
973
  var len = obj.data.length;
768
974
  }
@@ -775,10 +981,10 @@
775
981
 
776
982
  for (var i=0; i<=count; ++i) {
777
983
  parts.push('M{1} {2} L{3} {4}'.format(
778
- prop.gutterLeft + ((obj.graphWidth / count) * i),
779
- prop.gutterTop,
780
- prop.gutterLeft + ((obj.graphWidth / count) * i),
781
- obj.height - prop.gutterBottom
984
+ prop.gutterLeft + ((obj.graphWidth / count) * i) + prop.variant3dOffsetx,
985
+ prop.gutterTop - prop.variant3dOffsety,
986
+ prop.gutterLeft + ((obj.graphWidth / count) * i) + prop.variant3dOffsetx,
987
+ obj.height - prop.gutterBottom - prop.variant3dOffsety
782
988
  ));
783
989
  }
784
990
  }
@@ -791,17 +997,17 @@
791
997
  if (prop.backgroundGridBorder) {
792
998
  parts.push('M{1} {2} L{3} {4} L{5} {6} L{7} {8} z'.format(
793
999
 
794
- prop.gutterLeft,
795
- prop.gutterTop,
1000
+ prop.gutterLeft + prop.variant3dOffsetx,
1001
+ prop.gutterTop - prop.variant3dOffsety,
796
1002
 
797
- obj.width - prop.gutterRight,
798
- prop.gutterTop,
1003
+ obj.width - prop.gutterRight + prop.variant3dOffsetx,
1004
+ prop.gutterTop - prop.variant3dOffsety,
799
1005
 
800
- obj.width - prop.gutterRight,
801
- obj.height - prop.gutterBottom,
1006
+ obj.width - prop.gutterRight + prop.variant3dOffsetx,
1007
+ obj.height - prop.gutterBottom - prop.variant3dOffsety,
802
1008
 
803
- prop.gutterLeft,
804
- obj.height - prop.gutterBottom
1009
+ prop.gutterLeft + prop.variant3dOffsetx,
1010
+ obj.height - prop.gutterBottom - prop.variant3dOffsety
805
1011
  ));
806
1012
  }
807
1013
 
@@ -810,6 +1016,7 @@
810
1016
  // Now draw the path
811
1017
  var grid = RG.SVG.create({
812
1018
  svg: obj.svg,
1019
+ parent: obj.svg.all,
813
1020
  type: 'path',
814
1021
  attr: {
815
1022
  d: parts.join(' '),
@@ -892,13 +1099,13 @@
892
1099
  * ** Must be first **
893
1100
  */
894
1101
 
895
- if (!max) {
1102
+ if (max === 0 && min === 0) {
896
1103
 
897
- var max = 1;
1104
+ var max = 1;
898
1105
 
899
1106
  for (var i=0; i<numlabels; ++i) {
900
1107
 
901
- var label = ((((max - min) / numlabels) + min) * (i + 1)).toFixed(decimals);
1108
+ var label = ((((max - min) / numlabels) * (i + 1)) + min).toFixed(decimals);
902
1109
 
903
1110
  scale.labels.push(unitsPre + label + unitsPost);
904
1111
  scale.values.push(parseFloat(label))
@@ -1647,7 +1854,7 @@
1647
1854
  RG.SVG.text = function (opt)
1648
1855
  {
1649
1856
  var obj = opt.object,
1650
- parent = opt.parent,
1857
+ parent = opt.parent || opt.object.svg.all,
1651
1858
  size = opt.size,
1652
1859
  bold = opt.bold,
1653
1860
  font = opt.font,
@@ -1687,7 +1894,7 @@
1687
1894
 
1688
1895
  var text = RG.SVG.create({
1689
1896
  svg: obj.svg,
1690
- parent: opt.parent || null,
1897
+ parent: opt.parent,
1691
1898
  type: 'text',
1692
1899
  attr: {
1693
1900
  fill: color,
@@ -1714,17 +1921,19 @@
1714
1921
 
1715
1922
  var bbox = text.getBBox(),
1716
1923
  rect = RG.SVG.create({
1717
- svg: obj.svg,
1718
- type: 'rect',
1719
- attr: {
1720
- x: bbox.x - padding,
1721
- y: bbox.y - padding,
1722
- width: bbox.width + (padding * 2),
1723
- height: bbox.height + (padding * 2),
1724
- fill: background
1725
- }
1726
- });
1727
- obj.svg.insertBefore(rect, text);
1924
+ svg: obj.svg,
1925
+ parent: opt.parent,
1926
+ type: 'rect',
1927
+ attr: {
1928
+ x: bbox.x - padding,
1929
+ y: bbox.y - padding,
1930
+ width: bbox.width + (padding * 2),
1931
+ height: bbox.height + (padding * 2),
1932
+ fill: background
1933
+ }
1934
+ });
1935
+
1936
+ parent.insertBefore(rect, text);
1728
1937
  }
1729
1938
 
1730
1939
 
@@ -1892,7 +2101,6 @@
1892
2101
  RG.SVG.hideTooltip = function ()
1893
2102
  {
1894
2103
  var tooltip = RG.SVG.REG.get('tooltip');
1895
- //uid = arguments[0] && arguments[0].uid ? arguments[0].uid : null;
1896
2104
 
1897
2105
  if (tooltip && tooltip.parentNode /*&& (!uid || uid == tooltip.__canvas__.uid)*/) {
1898
2106
  tooltip.parentNode.removeChild(tooltip);
@@ -1900,7 +2108,7 @@
1900
2108
  tooltip.style.visibility = 'hidden';
1901
2109
  RG.SVG.REG.set('tooltip', null);
1902
2110
  }
1903
-
2111
+
1904
2112
  if (tooltip && tooltip.__object__) {
1905
2113
  RG.SVG.removeHighlight(tooltip.__object__);
1906
2114
  }
@@ -1927,7 +2135,7 @@
1927
2135
 
1928
2136
  var filter = RG.SVG.create({
1929
2137
  svg: obj.svg,
1930
- parent: obj.defs,
2138
+ parent: obj.svg.defs,
1931
2139
  type: 'filter',
1932
2140
  attr: {
1933
2141
  id: id,
@@ -1993,7 +2201,7 @@
1993
2201
 
1994
2202
 
1995
2203
  /**
1996
- * Takes a sequential index abd returns the group/index variation of it. Eg if you have a
2204
+ * Takes a sequential index and returns the group/index variation of it. Eg if you have a
1997
2205
  * sequential index from a grouped bar chart this function can be used to convert that into
1998
2206
  * an appropriate group/index combination
1999
2207
  *
@@ -2064,6 +2272,8 @@
2064
2272
  //
2065
2273
  // @patam object options The options/arg to the function
2066
2274
  //
2275
+ // NB ** Still used by the Pie chart and the semi-circular Meter **
2276
+ //
2067
2277
  RG.SVG.TRIG.getArcPath = function (options)
2068
2278
  {
2069
2279
  //
@@ -2142,6 +2352,163 @@
2142
2352
 
2143
2353
 
2144
2354
 
2355
+ //
2356
+ // Gets a path that is usable by the SVG A path command
2357
+ //
2358
+ // @patam object options The options/arg to the function
2359
+ //
2360
+ RG.SVG.TRIG.getArcPath2 = function (options)
2361
+ {
2362
+ //
2363
+ // Make circles start at the top instead of the right hand side
2364
+ //
2365
+ options.start -= 1.57;
2366
+ options.end -= 1.57;
2367
+
2368
+ var start = RG.SVG.TRIG.toCartesian({
2369
+ cx: options.cx,
2370
+ cy: options.cy,
2371
+ r: options.r,
2372
+ angle: options.start
2373
+ });
2374
+
2375
+ var end = RG.SVG.TRIG.toCartesian({
2376
+ cx: options.cx,
2377
+ cy: options.cy,
2378
+ r: options.r,
2379
+ angle: options.end
2380
+ });
2381
+
2382
+ var diff = ma.abs(options.end - options.start);
2383
+
2384
+ // Initial values
2385
+ var largeArc = '0';
2386
+ var sweep = '0';
2387
+
2388
+ //TODO Put various options here for the correct combination of flags to use
2389
+ if (!options.anticlockwise) {
2390
+ if (diff > RG.SVG.TRIG.PI) {
2391
+ largeArc = '1';
2392
+ sweep = '1';
2393
+ } else {
2394
+ largeArc = '0';
2395
+ sweep = '1';
2396
+ }
2397
+ } else {
2398
+ if (diff > RG.SVG.TRIG.PI) {
2399
+ largeArc = '1';
2400
+ sweep = '0';
2401
+ } else {
2402
+ largeArc = '0';
2403
+ sweep = '0';
2404
+ }
2405
+ }
2406
+
2407
+ if (typeof options.lineto === 'boolean' && options.lineto === false) {
2408
+ var d = [
2409
+ "M", start.x, start.y,
2410
+ "A", options.r, options.r, 0, largeArc, sweep, end.x, end.y
2411
+ ];
2412
+ } else {
2413
+ var d = [
2414
+ "M", options.cx, options.cy,
2415
+ "L", start.x, start.y,
2416
+ "A", options.r, options.r, 0, largeArc, sweep, end.x, end.y
2417
+ ];
2418
+ }
2419
+
2420
+ if (options.array === true) {
2421
+ return d;
2422
+ } else {
2423
+ return d.join(" ");
2424
+ }
2425
+ };
2426
+
2427
+
2428
+
2429
+
2430
+
2431
+
2432
+
2433
+
2434
+ //
2435
+ // Gets a path that is usable by the SVG A path command
2436
+ //
2437
+ // @patam object options The options/arg to the function
2438
+ //
2439
+ RG.SVG.TRIG.getArcPath3 = function (options)
2440
+ {
2441
+ //
2442
+ // Make circles start at the top instead of the right hand side
2443
+ //
2444
+ options.start -= 1.57;
2445
+ options.end -= 1.57;
2446
+
2447
+ var start = RG.SVG.TRIG.toCartesian({
2448
+ cx: options.cx,
2449
+ cy: options.cy,
2450
+ r: options.r,
2451
+ angle: options.start
2452
+ });
2453
+
2454
+ var end = RG.SVG.TRIG.toCartesian({
2455
+ cx: options.cx,
2456
+ cy: options.cy,
2457
+ r: options.r,
2458
+ angle: options.end
2459
+ });
2460
+
2461
+ var diff = ma.abs(options.end - options.start);
2462
+
2463
+ // Initial values
2464
+ var largeArc = '0';
2465
+ var sweep = '0';
2466
+
2467
+ //TODO Put various options here for the correct combination of flags to use
2468
+ if (!options.anticlockwise) {
2469
+ if (diff > RG.SVG.TRIG.PI) {
2470
+ largeArc = '1';
2471
+ sweep = '1';
2472
+ } else {
2473
+ largeArc = '0';
2474
+ sweep = '1';
2475
+ }
2476
+ } else {
2477
+ if (diff > RG.SVG.TRIG.PI) {
2478
+ largeArc = '1';
2479
+ sweep = '0';
2480
+ } else {
2481
+ largeArc = '0';
2482
+ sweep = '0';
2483
+ }
2484
+ }
2485
+
2486
+ if (typeof options.lineto === 'boolean' && options.lineto === false) {
2487
+ var d = [
2488
+ "M", start.x, start.y,
2489
+ "A", options.r, options.r, 0, largeArc, sweep, end.x, end.y
2490
+ ];
2491
+ } else {
2492
+ var d = [
2493
+ "L", start.x, start.y,
2494
+ "A", options.r, options.r, 0, largeArc, sweep, end.x, end.y
2495
+ ];
2496
+ }
2497
+
2498
+ if (options.array === true) {
2499
+ return d;
2500
+ } else {
2501
+ return d.join(" ");
2502
+ }
2503
+ };
2504
+
2505
+
2506
+
2507
+
2508
+
2509
+
2510
+
2511
+
2145
2512
  /**
2146
2513
  * This function gets the end point (X/Y coordinates) of a given radius.
2147
2514
  * You pass it the center X/Y and the radius and this function will return
@@ -2183,7 +2550,8 @@
2183
2550
  */
2184
2551
  RG.SVG.drawTitle = function (obj)
2185
2552
  {
2186
- var prop = obj.properties;
2553
+ var prop = obj.properties;
2554
+ var valign = 'bottom';
2187
2555
 
2188
2556
  //
2189
2557
  // The Pie chart title should default to being above the centerx
@@ -2203,19 +2571,37 @@
2203
2571
 
2204
2572
 
2205
2573
 
2206
- prop.titleY = typeof prop.titleY === 'number' ? prop.titleY : prop.gutterTop - 10;
2574
+
2575
+ if (obj.scale && obj.scale.max <= 0 && obj.scale.min < 0 && typeof prop.titleY !== 'number' && obj.type !== 'hbar') {
2576
+ prop.titleY = obj.height - prop.gutterBottom + 10;
2577
+ var positionBottom = true;
2578
+ valign = 'top';
2579
+ } else if (typeof prop.titleY !== 'number') {
2580
+ var positionBottom = false;
2581
+ prop.titleY = prop.gutterTop - 10;
2582
+ valign = 'bottom';
2583
+
2584
+ // Account for the key
2585
+ if (!RG.SVG.isNull(prop.key)) {
2586
+ prop.titleY -= (2 * (prop.keyTextSize || prop.textSize));
2587
+ }
2588
+ }
2207
2589
 
2208
2590
  // If a subtitle is specified move the title up a bit in
2209
2591
  // order to accommodate it
2210
- if (prop.titleSubtitle && typeof prop.titleSubtitleY !== 'number') {
2592
+ if (prop.titleSubtitle && typeof prop.titleSubtitleY !== 'number' && !positionBottom) {
2211
2593
  prop.titleY = prop.titleY - (prop.titleSubtitleSize * 1.5);
2212
2594
  }
2213
2595
 
2214
2596
  // Work out the subtitle size
2215
2597
  prop.titleSubTitleSize = prop.titleSubTitleSize || prop.textSize;
2216
-
2598
+
2217
2599
  // Work out the subtitle Y position
2218
- prop.titleSubtitleY = prop.titleSubtitleY || prop.titleY + 8;
2600
+ prop.titleSubtitleY = prop.titleSubtitleY || prop.titleY + 18;
2601
+
2602
+ if (positionBottom && typeof prop.titleSubtitleY !== 'number') {
2603
+ prop.titleSubtitleY = prop.titleY + 26;
2604
+ }
2219
2605
 
2220
2606
 
2221
2607
 
@@ -2228,14 +2614,15 @@
2228
2614
  RG.SVG.text({
2229
2615
  object: obj,
2230
2616
  svg: obj.svg,
2617
+ parent: obj.svg.all,
2231
2618
  text: prop.title.toString(),
2232
2619
  size: prop.titleSize || (prop.textSize + 4) || 16,
2233
2620
 
2234
- x: typeof prop.titleX === 'number' ? prop.titleX : prop.gutterLeft + obj.graphWidth / 2,
2235
- y: prop.titleY,
2621
+ x: typeof prop.titleX === 'number' ? prop.titleX + (prop.variant3dOffsetx || 0) : prop.gutterLeft + (obj.graphWidth / 2) + (prop.variant3dOffsetx || 0),
2622
+ y: prop.titleY + (prop.variant3dOffsety || 0),
2236
2623
 
2237
2624
  halign: prop.titleHalign || 'center',
2238
- valign: prop.titleValign || 'bottom',
2625
+ valign: prop.titleValign || valign,
2239
2626
  color: prop.titleColor || prop.textColor || 'black',
2240
2627
  bold: prop.titleBold || false,
2241
2628
  italic: prop.titleItalic || false,
@@ -2250,12 +2637,13 @@
2250
2637
  RG.SVG.text({
2251
2638
  object: obj,
2252
2639
  svg: obj.svg,
2640
+ parent: obj.svg.all,
2253
2641
  text: prop.titleSubtitle,
2254
2642
  size: prop.titleSubtitleSize,
2255
- x: typeof prop.titleSubtitleX === 'number' ? prop.titleSubtitleX : prop.gutterLeft + obj.graphWidth / 2,
2256
- y: prop.titleSubtitleY,
2643
+ x: typeof prop.titleSubtitleX === 'number' ? prop.titleSubtitleX : prop.gutterLeft + (obj.graphWidth / 2) + (prop.variant3dOffsetx || 0),
2644
+ y: prop.titleSubtitleY + (prop.variant3dOffsety || 0),
2257
2645
  halign: prop.titleSubtitleHalign || 'center',
2258
- valign: prop.titleSubtitleValign || 'bottom',
2646
+ valign: prop.titleSubtitleValign || valign,
2259
2647
  color: prop.titleSubtitleColor || prop.textColor || '#aaa',
2260
2648
  bold: prop.titleSubtitleBold || false,
2261
2649
  italic: prop.titleSubtitleItalic || false,
@@ -2342,7 +2730,7 @@
2342
2730
  if (opt && opt.direction && opt.direction === 'horizontal') {
2343
2731
  var grad = RG.SVG.create({
2344
2732
  type: 'linearGradient',
2345
- parent: obj.defs,
2733
+ parent: obj.svg.defs,
2346
2734
  attr: {
2347
2735
  id: 'RGraph-linear-gradient' + obj.gradientCounter,
2348
2736
  x1: opt.start || 0,
@@ -2357,7 +2745,7 @@
2357
2745
 
2358
2746
  var grad = RG.SVG.create({
2359
2747
  type: 'linearGradient',
2360
- parent: obj.defs,
2748
+ parent: obj.svg.defs,
2361
2749
  attr: {
2362
2750
  id: 'RGraph-linear-gradient' + obj.gradientCounter,
2363
2751
  x1: 0,
@@ -2425,15 +2813,15 @@
2425
2813
 
2426
2814
  var grad = RG.SVG.create({
2427
2815
  type: 'radialGradient',
2428
- parent: obj.defs,
2816
+ parent: obj.svg.defs,
2429
2817
  attr: {
2430
2818
  id: 'RGraph-radial-gradient' + obj.gradientCounter,
2431
- gradientUnits: 'userSpaceOnUse',
2432
- cx: obj.centerx,
2433
- cy: obj.centery,
2434
- fx: obj.centerx,
2435
- fy: obj.centery,
2436
- r: obj.radius
2819
+ gradientUnits: opt.gradientUnits || 'userSpaceOnUse',
2820
+ cx: opt.cx || obj.centerx,
2821
+ cy: opt.cy || obj.centery,
2822
+ fx: opt.fx || obj.centerx,
2823
+ fy: opt.fy || obj.centery,
2824
+ r: opt.r || obj.radius
2437
2825
  }
2438
2826
  });
2439
2827
 
@@ -2499,7 +2887,8 @@
2499
2887
  obj.resetColorsToOriginalValues();
2500
2888
  }
2501
2889
 
2502
- // Hmmm... Should this be necessary?
2890
+ // Hmmm... Should this be necessary? I don't think it will
2891
+ // do any harm to leave it in.
2503
2892
  obj.originalColors = {};
2504
2893
 
2505
2894
 
@@ -2527,9 +2916,13 @@
2527
2916
  //
2528
2917
  RG.SVG.clear = function (svg)
2529
2918
  {
2530
- while (svg.lastChild) {
2531
- svg.removeChild(svg.lastChild);
2919
+ while (svg.all.lastChild) {
2920
+ svg.all.removeChild(svg.all.lastChild);
2532
2921
  }
2922
+
2923
+ //while (svg.lastChild) {
2924
+ // svg.removeChild(svg.lastChild);
2925
+ //}
2533
2926
  };
2534
2927
 
2535
2928
 
@@ -2663,11 +3056,16 @@
2663
3056
  if (highlight && RG.SVG.isArray(highlight) && highlight.length) {
2664
3057
  for (var i=0,len=highlight.length; i<len; ++i) {
2665
3058
  if (highlight[i].parentNode) {
2666
- obj.svg.removeChild(highlight[i]);
3059
+ //obj.svg.removeChild(highlight[i]);
3060
+ highlight[i].parentNode.removeChild(highlight[i]);
2667
3061
  }
2668
3062
  }
2669
3063
  } else if (highlight && highlight.parentNode) {
2670
- highlight.parentNode.removeChild(highlight);
3064
+ if (obj.type === 'scatter') {
3065
+ highlight.setAttribute('fill', 'transparent');
3066
+ } else {
3067
+ highlight.parentNode.removeChild(highlight);
3068
+ }
2671
3069
  }
2672
3070
  };
2673
3071
 
@@ -2688,7 +3086,7 @@
2688
3086
  var svg = arguments[0];
2689
3087
 
2690
3088
  RG.SVG.clear(svg);
2691
-
3089
+
2692
3090
  var objects = RG.SVG.OR.get('id:' + svg.parentNode.id);
2693
3091
 
2694
3092
  for (var i=0,len=objects.length; i<len; ++i) {
@@ -2696,7 +3094,6 @@
2696
3094
  // Reset the colors to the original values
2697
3095
  RG.SVG.resetColorsToOriginalValues({object: objects[i]});
2698
3096
 
2699
-
2700
3097
  objects[i].draw();
2701
3098
  }
2702
3099
  } else {
@@ -2716,63 +3113,112 @@
2716
3113
 
2717
3114
 
2718
3115
 
2719
- /**
2720
- * This is the same as Date.parse - though a little more flexible and accepts
2721
- * a few more formats.
2722
- *
2723
- * @param string str The date string to parse
2724
- * @return Returns the same thing as Date.parse
2725
- */
3116
+ //
3117
+ // A better, more flexible, date parsing function
3118
+ //
3119
+ //@param string str The string to parse
3120
+ //@retutn number A number, as returned by Date.parse()
3121
+ //
2726
3122
  RG.SVG.parseDate = function (str)
2727
3123
  {
2728
- str = RG.SVG.trim(str);
3124
+ var d = new Date();
2729
3125
 
2730
- // Allow for: now (just the word "now")
2731
- if (str === 'now') {
2732
- str = (new Date()).toString();
2733
- }
3126
+ // Initialise the default values
3127
+ var defaults = {
3128
+ seconds: '00',
3129
+ minutes: '00',
3130
+ hours: '00',
3131
+ date: d.getDate(),
3132
+ month: d.getMonth() + 1,
3133
+ year: d.getFullYear()
3134
+ };
2734
3135
 
3136
+ // Create the months array for turning textual months back to numbers
3137
+ var months = ['january','february','march','april','may','june','july','august','september','october','november','december'],
3138
+ months_regex = months.join('|');
2735
3139
 
2736
- // Allow for: 22-11-2013
2737
- // Allow for: 22/11/2013
2738
- // Allow for: 22-11-2013 12:09:09
2739
- // Allow for: 22/11/2013 12:09:09
2740
- if (str.match(/^(\d\d)(?:-|\/)(\d\d)(?:-|\/)(\d\d\d\d)(.*)$/)) {
2741
- str = '{1}/{2}/{3}{4}'.format(
2742
- RegExp.$3,
2743
- RegExp.$2,
2744
- RegExp.$1,
2745
- RegExp.$4
2746
- );
3140
+ for (var i=0; i<months.length; ++i) {
3141
+ months[months[i]] = i;
3142
+ months[months[i].substring(0,3)] = i;
3143
+ months_regex = months_regex + '|' + months[i].substring(0,3);
2747
3144
  }
2748
3145
 
2749
- // Allow for: 2013-11-22 12:12:12 or 2013/11/22 12:12:12
2750
- if (str.match(/^(\d\d\d\d)(-|\/)(\d\d)(-|\/)(\d\d)( |T)(\d\d):(\d\d):(\d\d)$/)) {
2751
- str = RegExp.$1 + '-' + RegExp.$3 + '-' + RegExp.$5 + 'T' + RegExp.$7 + ':' + RegExp.$8 + ':' + RegExp.$9;
2752
- }
3146
+ // These are the seperators allowable for d/m/y and y/m/d dates
3147
+ // (Its part of a regexp so the position of the square brackets
3148
+ // is crucial)
3149
+ var sep = '[-./_=+~#:;,]+';
2753
3150
 
2754
- // Allow for: 2013-11-22
2755
- if (str.match(/^\d\d\d\d-\d\d-\d\d$/)) {
2756
- str = str.replace(/-/g, '/');
2757
- }
2758
3151
 
3152
+ // Tokenise the string
3153
+ var tokens = str.split(/ +/);
2759
3154
 
2760
- // Allow for: 12:09:44 (time only using todays date)
2761
- if (str.match(/^\d\d:\d\d:\d\d$/)) {
2762
-
2763
- var dateObj = new Date();
2764
- var date = dateObj.getDate();
2765
- var month = dateObj.getMonth() + 1;
2766
- var year = dateObj.getFullYear();
2767
-
2768
- // Pad the date/month with a zero if it's not two characters
2769
- if (String(month).length === 1) month = '0' + month;
2770
- if (String(date).length === 1) date = '0' + date;
3155
+ // Loop through each token checking what is is
3156
+ for (var i=0,len=tokens.length; i<len; ++i) {
3157
+ if (tokens[i]) {
3158
+
3159
+ // Year
3160
+ if (tokens[i].match(/^\d\d\d\d$/)) {
3161
+ defaults.year = tokens[i];
3162
+ }
3163
+
3164
+ // Month
3165
+ var res = isMonth(tokens[i]);
3166
+ if (typeof res === 'number') {
3167
+ defaults.month = res + 1; // Months are zero indexed
3168
+ }
3169
+
3170
+ // Date
3171
+ if (tokens[i].match(/^\d?\d(?:st|nd|rd|th)?$/)) {
3172
+ defaults.date = parseInt(tokens[i]);
3173
+ }
3174
+
3175
+ // Time
3176
+ if (tokens[i].match(/^(\d\d):(\d\d)(?:(\d\d))?$/)) {
3177
+ defaults.hours = parseInt(RegExp.$1);
3178
+ defaults.minutes = parseInt(RegExp.$2);
3179
+
3180
+ if (RegExp.$3) {
3181
+ defaults.seconds = parseInt(RegExp.$3);
3182
+ }
3183
+ }
3184
+
3185
+ // Dateformat: XXXX-XX-XX
3186
+ if (tokens[i].match(new RegExp('^(\\d\\d\\d\\d)' + sep + '(\\d\\d)' + sep + '(\\d\\d)$', 'i'))) {
3187
+ defaults.date = parseInt(RegExp.$3);
3188
+ defaults.month = parseInt(RegExp.$2);
3189
+ defaults.year = parseInt(RegExp.$1);
3190
+ }
2771
3191
 
2772
- str = (year + '/' + month + '/' + date) + ' ' + str;
3192
+ // Dateformat: XX-XX-XXXX
3193
+ if (tokens[i].match(new RegExp('^(\\d\\d)' + sep + '(\\d\\d)' + sep + '(\\d\\d\\d\\d)$','i') )) {
3194
+ defaults.date = parseInt(RegExp.$1);
3195
+ defaults.month = parseInt(RegExp.$2);
3196
+ defaults.year = parseInt(RegExp.$3);
3197
+ }
3198
+ }
2773
3199
  }
2774
3200
 
3201
+ // Now put the defaults into a format thats recognised by Date.parse()
3202
+ str = '{1}/{2}/{3} {4}:{5}:{6}'.format(
3203
+ defaults.year,
3204
+ String(defaults.month).length === 1 ? '0' + (defaults.month) : defaults.month,
3205
+ String(defaults.date).length === 1 ? '0' + (defaults.date) : defaults.date,
3206
+ String(defaults.hours).length === 1 ? '0' + (defaults.hours) : defaults.hours,
3207
+ String(defaults.minutes).length === 1 ? '0' + (defaults.minutes) : defaults.minutes,
3208
+ String(defaults.seconds).length === 1 ? '0' + (defaults.seconds) : defaults.seconds
3209
+ );
3210
+
2775
3211
  return Date.parse(str);
3212
+
3213
+ //
3214
+ // Support functions
3215
+ //
3216
+ function isMonth(str)
3217
+ {
3218
+ var res = str.toLowerCase().match(months_regex);
3219
+
3220
+ return res ? months[res[0]] : false;
3221
+ }
2776
3222
  };
2777
3223
 
2778
3224
 
@@ -2928,32 +3374,6 @@
2928
3374
 
2929
3375
 
2930
3376
 
2931
- /**
2932
- * This function determines whther a canvas is fixed (CSS positioning) or not. If not it returns
2933
- * false. If it is then the element that is fixed is returned (it may be a parent of the canvas).
2934
- *
2935
- * @return Either false or the fixed positioned element
2936
- */
2937
- RG.isFixed = function (canvas)
2938
- {
2939
- var obj = canvas;
2940
- var i = 0;
2941
-
2942
- while (obj && obj.tagName.toLowerCase() != 'body' && i < 99) {
2943
-
2944
- if (obj.style.position == 'fixed') {
2945
- return obj;
2946
- }
2947
-
2948
- obj = obj.offsetParent;
2949
- }
2950
-
2951
- return false;
2952
- };
2953
-
2954
-
2955
-
2956
-
2957
3377
 
2958
3378
 
2959
3379
 
@@ -3032,31 +3452,36 @@
3032
3452
  }
3033
3453
 
3034
3454
  if (typeof RG.SVG.measuretext_cache == 'object' && RG.SVG.measuretext_cache[str]) {
3455
+
3035
3456
  return RG.SVG.measuretext_cache[str];
3036
3457
  }
3037
3458
 
3038
- if (!RG.SVG.measuretext_cache['text-div']) {
3039
- var div = document.createElement('DIV');
3040
- div.style.position = 'absolute';
3041
- div.style.top = '-100px';
3042
- div.style.left = '-100px';
3043
- document.body.appendChild(div);
3459
+ if (!RG.SVG.measuretext_cache['text-span']) {
3460
+ var span = document.createElement('SPAN');
3461
+ span.style.position = 'absolute';
3462
+ //span.style.backgroundColor = 'red';
3463
+ span.style.padding = 0;
3464
+ span.style.display = 'inline';
3465
+ span.style.top = '-200px';
3466
+ span.style.left = '-200px';
3467
+ span.style.lineHeight = '1em';
3468
+ document.body.appendChild(span);
3044
3469
 
3045
3470
  // Now store the newly created DIV
3046
- RG.SVG.measuretext_cache['text-div'] = div;
3471
+ RG.SVG.measuretext_cache['text-span'] = span;
3047
3472
 
3048
- } else if (RG.SVG.measuretext_cache['text-div']) {
3049
- var div = RG.SVG.measuretext_cache['text-div'];
3473
+ } else if (RG.SVG.measuretext_cache['text-span']) {
3474
+ var span = RG.SVG.measuretext_cache['text-span'];
3050
3475
  }
3051
3476
 
3052
- div.innerHTML = text.replace(/\r\n/g, '<br />');
3053
- div.style.fontFamily = font;
3054
- div.style.fontWeight = bold ? 'bold' : 'normal';
3055
- div.style.fontSize = size + 'pt';
3477
+ span.innerHTML = text.replace(/\r\n/g, '<br />');
3478
+ span.style.fontFamily = font;
3479
+ span.style.fontWeight = bold ? 'bold' : 'normal';
3480
+ span.style.fontSize = size + 'pt';
3056
3481
 
3057
- var sizes = [div.offsetWidth, div.offsetHeight];
3482
+ var sizes = [span.offsetWidth, span.offsetHeight];
3058
3483
 
3059
- //document.body.removeChild(div);
3484
+ //document.body.removeChild(span);
3060
3485
  RG.SVG.measuretext_cache[str] = sizes;
3061
3486
 
3062
3487
  return sizes;
@@ -3156,6 +3581,8 @@
3156
3581
  //
3157
3582
  RG.SVG.attribution = function (obj)
3158
3583
  {
3584
+ return;
3585
+ /*
3159
3586
  var prop = obj.properties;
3160
3587
 
3161
3588
  if (!prop.attribution && typeof prop.attribution !== 'undefined') {
@@ -3166,9 +3593,12 @@
3166
3593
  // Create the A tag
3167
3594
  var a = RG.SVG.create({
3168
3595
  svg: obj.svg,
3596
+ parent: obj.svg.all,
3169
3597
  type: 'a',
3170
3598
  attr: {
3171
- 'xlink:href': prop.attributionHref || 'http://www.rgraph.net'
3599
+ rel: 'nofollow',
3600
+ target: '_blank',
3601
+ 'xlink:href': prop.attributionHref || 'http://www.rgraph.net/'
3172
3602
  }
3173
3603
  });
3174
3604
 
@@ -3196,7 +3626,7 @@
3196
3626
  var text = RG.SVG.text({
3197
3627
  object: obj,
3198
3628
  parent: a,
3199
- text: typeof prop.attributionText === 'string' ? prop.attributionText : 'RGraph.net',
3629
+ text: typeof prop.attributionText === 'string' ? prop.attributionText : 'JavaScript charts with RGraph',
3200
3630
  x: x,
3201
3631
  y: y,
3202
3632
  halign: prop.attributionHalign || 'right',
@@ -3207,6 +3637,23 @@
3207
3637
  italic: prop.attributionItalic,
3208
3638
  bold: prop.attributionBold
3209
3639
  });
3640
+ */
3641
+ };
3642
+
3643
+
3644
+
3645
+
3646
+
3647
+
3648
+
3649
+
3650
+ /**
3651
+ * Parse a gradient and returns the various parts
3652
+ *
3653
+ * @param string str The gradient string
3654
+ */
3655
+ RG.SVG.parseGradient = function (str)
3656
+ {
3210
3657
  };
3211
3658
 
3212
3659
 
@@ -3223,11 +3670,13 @@
3223
3670
  * @param number max The maximum value
3224
3671
  * @param number OPTIONAL Number of decimal places
3225
3672
  */
3226
- RG.SVG.random = function (min, max)
3673
+ RG.SVG.random = function (opt)
3227
3674
  {
3228
- var dp = arguments[2] ? arguments[2] : 0;
3229
- var r = ma.random();
3230
-
3675
+ var min = opt.min,
3676
+ max = opt.max,
3677
+ dp = opt.dp || opt.decimals || 0,
3678
+ r = ma.random();
3679
+
3231
3680
  return Number((((max - min) * r) + min).toFixed(dp));
3232
3681
  };
3233
3682
 
@@ -3238,6 +3687,132 @@
3238
3687
 
3239
3688
 
3240
3689
 
3690
+ /**
3691
+ * Fill an array full of random numbers
3692
+ */
3693
+ RG.SVG.arrayRand =
3694
+ RG.SVG.arrayRandom =
3695
+ RG.SVG.random.array = function (opt)
3696
+ {
3697
+ var num = opt.num,
3698
+ min = opt.min,
3699
+ max = opt.max,
3700
+ dp = opt.dp || opt.decimals || 0;
3701
+
3702
+ for(var i=0,arr=[]; i<num; i+=1) {
3703
+ arr.push(RG.SVG.random({min: min, max: max, dp: dp}));
3704
+ }
3705
+
3706
+ return arr;
3707
+ };
3708
+
3709
+
3710
+
3711
+
3712
+
3713
+
3714
+
3715
+
3716
+ //
3717
+ // This function is called by each objects setter so that common BC
3718
+ // and adjustments are centralised. And there's less typing for me too.
3719
+ //
3720
+ // @param object opt An object of options to the function, which are:
3721
+ // object: The chart object
3722
+ // name: The name of the config parameter
3723
+ // value: The value thats being set
3724
+ //
3725
+ RG.SVG.commonSetter = function (opt)
3726
+ {
3727
+ var obj = opt.object,
3728
+ name = opt.name,
3729
+ value = opt.value;
3730
+
3731
+ // The default event for tooltips is click
3732
+ if (name === 'tooltipsEvent'&& value !== 'click' && value !== 'mousemove') {
3733
+ value = 'click';
3734
+ }
3735
+
3736
+ return {
3737
+ name: name,
3738
+ value: value
3739
+ };
3740
+ };
3741
+
3742
+
3743
+
3744
+
3745
+
3746
+
3747
+
3748
+
3749
+ //
3750
+ // Generates logs for... log charts
3751
+ //
3752
+ // @param object opt The options:
3753
+ // o num The number
3754
+ // o base The base
3755
+ //
3756
+ RG.SVG.log = function (opt)
3757
+ {
3758
+ var num = opt.num,
3759
+ base = opt.base;
3760
+
3761
+ return ma.log(num) / (base ? ma.log(base) : 1);
3762
+ };
3763
+
3764
+
3765
+
3766
+
3767
+
3768
+
3769
+
3770
+
3771
+ RG.SVG.donut = function (opt)
3772
+ {
3773
+ var arcPath1 = RG.SVG.TRIG.getArcPath3({
3774
+ cx: opt.cx,
3775
+ cy: opt.cy,
3776
+ r: opt.outerRadius,
3777
+ start: 0,
3778
+ end: RG.SVG.TRIG.TWOPI,
3779
+ anticlockwise: false,
3780
+ lineto: false
3781
+ });
3782
+
3783
+ var arcPath2 = RG.SVG.TRIG.getArcPath3({
3784
+ cx: opt.cx,
3785
+ cy: opt.cy,
3786
+ r: opt.innerRadius,
3787
+ start: RG.SVG.TRIG.TWOPI,
3788
+ end: 0,
3789
+ anticlockwise: true,
3790
+ lineto: false
3791
+ });
3792
+
3793
+ //
3794
+ // Create the red circle
3795
+ //
3796
+ var path = RG.SVG.create({
3797
+ svg: opt.svg,
3798
+ type: 'path',
3799
+ attr: {
3800
+ d: arcPath1 + arcPath2,
3801
+ stroke: opt.stroke,
3802
+ fill: opt.fill
3803
+ }
3804
+ });
3805
+
3806
+ return path;
3807
+ };
3808
+
3809
+
3810
+
3811
+
3812
+
3813
+
3814
+
3815
+
3241
3816
  //
3242
3817
  // This is here so that if the tooltip library has not
3243
3818
  // been included, this function will show an alert