RGraph = window.RGraph || {isRGraph:
true
};
RGraph.SVG = RGraph.SVG || {};
(
function
(win, doc, undefined)
{
var
RG = RGraph,
ua = navigator.userAgent,
ma = Math,
win = window,
doc = document;
RG.SVG.Pie =
function
(conf)
{
this
.set =
function
(name, value)
{
if
(arguments.length === 1 &&
typeof
name === 'object
') {
for (i in arguments[0]) {
if (typeof i === '
string
') {
var ret = RG.SVG.commonSetter({
object: this,
name: i,
value: arguments[0][i]
});
name = ret.name;
value = ret.value;
this.set(name, value);
}
}
} else {
var ret = RG.SVG.commonSetter({
object: this,
name: name,
value: value
});
name = ret.name;
value = ret.value;
this.properties[name] = value;
// If setting the colors, update the originalColors
// property too
if (name === '
colors
') {
this.originalColors = RG.SVG.arrayClone(value);
this.colorsParsed = false;
}
}
return this;
};
this.id = conf.id;
this.uid = RG.SVG.createUID();
this.container = document.getElementById(this.id);
this.layers = {}; // MUST be before the SVG tag is created!
this.svg = RG.SVG.createSVG({object: this,container: this.container});
this.isRGraph = true;
this.width = Number(this.svg.getAttribute('
width
'));
this.height = Number(this.svg.getAttribute('
height
'));
this.data = conf.data;
this.type = '
pie
';
this.angles = [];
this.colorsParsed = false;
this.originalColors = {};
this.gradientCounter = 1;
this.nodes = [];
this.shadowNodes = [];
// Add this object to the ObjectRegistry
RG.SVG.OR.add(this);
// Set the DIV container to be inline-block
this.container.style.display = '
inline-block
';
this.properties =
{
centerx: null,
centery: null,
radius: null,
gutterLeft: 35,
gutterRight: 35,
gutterTop: 35,
gutterBottom: 35,
colors: [
'
#f66', '#6f6', '#66f', '#ff6', '#6ff', '#ccc',
'pink
', '
orange
', '
cyan
', '
maroon
', '
olive
', '
teal
'
],
strokestyle: '
rgba(0,0,0,0)
',
margin: 3,
textColor: '
black
',
textFont: '
sans-serif
',
textSize: 12,
textBold: false,
textItalic: false,
labels: [],
labelsSticks: true,
labelsSticksHlength: 50,
linewidth: 1,
tooltips: null,
tooltipsOverride: null,
tooltipsEffect: '
fade
',
tooltipsCssClass: '
RGraph_tooltip
',
tooltipsEvent: '
click
',
highlightStroke: '
rgba(0,0,0,0)
',
highlightFill: '
rgba(255,255,255,0.7)
',
highlightLinewidth: 1,
highlightStyle: '
normal
',
highlightStyleOutlineWidth: 7,
title: '
',
titleSize: 16,
titleX: null,
titleY: null,
titleHalign: '
center
',
titleValign: null,
titleColor: '
black
',
titleFont: null,
titleBold: false,
titleItalic: false,
titleSubtitle: null,
titleSubtitleSize: 10,
titleSubtitleX: null,
titleSubtitleY: null,
titleSubtitleHalign: '
center
',
titleSubtitleValign: null,
titleSubtitleColor: '
#aaa',
titleSubtitleFont:
null
,
titleSubtitleBold:
false
,
titleSubtitleItalic:
false
,
shadow:
false
,
shadowOffsetx: 2,
shadowOffsety: 2,
shadowBlur: 2,
shadowOpacity: 0.25,
exploded: 0,
roundRobinMultiplier: 1,
donut:
false
,
donutWidth: 75,
key:
null
,
keyColors:
null
,
keyOffsetx: 0,
keyOffsety: 0,
keyTextOffsetx: 0,
keyTextOffsety: -1,
keyTextSize:
null
,
keyTextBold:
null
,
keyTextItalic:
null
};
RG.SVG.getGlobals(
this
);
if
(RG.SVG.FX &&
typeof
RG.SVG.FX.decorate === '
function
') {
RG.SVG.FX.decorate(this);
}
var prop = this.properties;
//
// The draw method draws the Bar chart
//
this.draw = function ()
{
// Fire the beforedraw event
RG.SVG.fireCustomEvent(this, '
onbeforedraw
');
//(Re)set this so it doesn'
t grow endlessly
this
.angles = [];
this
.width = Number(
this
.svg.getAttribute('width
'));
this.height = Number(this.svg.getAttribute('
height
'));
// Create the defs tag if necessary
RG.SVG.createDefs(this);
this.graphWidth = this.width - prop.gutterLeft - prop.gutterRight;
this.graphHeight = this.height - prop.gutterTop - prop.gutterBottom;
// Work out the center point
this.centerx = (this.graphWidth / 2) + prop.gutterLeft;
this.centery = (this.graphHeight / 2) + prop.gutterTop;
this.radius = ma.min(this.graphWidth, this.graphHeight) / 2;
// Allow the user to override the calculated centerx/y/radius
this.centerx = typeof prop.centerx === '
number
' ? prop.centerx : this.centerx;
this.centery = typeof prop.centery === '
number
' ? prop.centery : this.centery;
this.radius = typeof prop.radius === '
number
' ? prop.radius : this.radius;
//
// Allow the centerx/centery/radius to be a plus/minus
//
if (typeof prop.radius === '
string
' && prop.radius.match(/^\+|-\d+$/) ) this.radius += parseFloat(prop.radius);
if (typeof prop.centerx === '
string
' && prop.centerx.match(/^\+|-\d+$/) ) this.centerx += parseFloat(prop.centerx);
if (typeof prop.centery === '
string
' && prop.centery.match(/^\+|-\d+$/) ) this.centery += parseFloat(prop.centery);
// Parse the colors for gradients
// Must be after the cx/cy/r calculations
RG.SVG.resetColorsToOriginalValues({object:this});
this.parseColors();
// Go through the data and work out the maximum value
this.max = RG.SVG.arrayMax(this.data);
this.total = RG.SVG.arraySum(this.data);
// Set the explosion to be an array if it'
s a number
if
(
typeof
prop.exploded ===
'number'
&& prop.exploded > 0) {
var
val = prop.exploded;
prop.exploded = [];
for
(
var
i=0; i<
this
.data.length; ++i) {
prop.exploded[i] = val;
}
}
this
.drawSegments({shadow:
true
});
RG.SVG.drawTitle(
this
);
if
(prop.labelsSticks) {
this
.drawLabelsSticks();
}
else
{
this
.drawLabels();
}
this
.drawIngraphLabels();
if
(
typeof
prop.key !==
null
&& RG.SVG.drawKey) {
RG.SVG.drawKey(
this
);
}
else
if
(!RGraph.SVG.isNull(prop.key)) {
alert(
'The drawKey() function does not exist - have you forgotten to include the key library?'
);
}
var
obj =
this
;
document.body.addEventListener(
'mousedown'
,
function
(e)
{
RG.SVG.removeHighlight(obj);
},
false
);
RG.SVG.fireCustomEvent(
this
,
'ondraw'
);
return
this
;
};
this
.drawSegments =
function
(opt)
{
var
start = 0,
end = 0,
angle = 0,
sum = RG.SVG.arraySum(
this
.data),
segment = 0;
for
(
var
i=0,len=
this
.data.length; i<len; ++i) {
var
value =
this
.data[i] * prop.roundRobinMultiplier;
start = angle;
segment = ((value / sum) * RG.SVG.TRIG.TWOPI);
end = start + segment;
var
explosion = RG.SVG.TRIG.getRadiusEndPoint({
angle: start + (segment / 2),
r: prop.exploded[i]
});
var
explosionX = explosion[1],
explosionY = explosion[0];
this
.angles[i] = {
start: start,
end: end,
angle: end - start,
halfway: ((end - start) / 2) + start,
cx:
this
.centerx + (parseFloat(explosionX) || 0),
cy:
this
.centery - (parseFloat(explosionY) || 0),
radius:
this
.radius,
object:
this
};
angle += (end - start);
}
if
(opt.shadow) {
RG.SVG.setShadow({
object:
this
,
offsetx: prop.shadowOffsetx,
offsety: prop.shadowOffsety,
blur: prop.shadowBlur,
opacity: prop.shadowOpacity,
id:
'dropShadow'
});
}
for
(
var
i=0; i<
this
.angles.length; ++i) {
var
path = RG.SVG.TRIG.getArcPath({
cx:
this
.angles[i].cx,
cy:
this
.angles[i].cy,
r:
this
.radius,
start:
this
.angles[i].start,
end:
this
.angles[i].end
});
if
(prop.donut) {
var
donutWidth = prop.donutWidth;
var
donut_path = RG.SVG.TRIG.getArcPath3({
cx:
this
.angles[i].cx,
cy:
this
.angles[i].cy,
r:
this
.radius - donutWidth,
start:
this
.angles[i].end,
end:
this
.angles[i].start,
moveto:
false
,
anticlockwise:
true
});
var
xy = RG.SVG.TRIG.getRadiusEndPoint({
angle:
this
.angles[i].end - RG.SVG.TRIG.HALFPI,
r:
this
.radius - donutWidth
});
path = path
+
" L {1} {2} "
.format(xy[0] +
this
.angles[i].cx, xy[1] +
this
.angles[i].cy)
+ donut_path
+
" Z"
;
}
else
{
path = path +
" L {1} {2} "
.format(
this
.angles[i].cx,
this
.angles[i].cy
) +
" Z"
}
var
arc = RG.SVG.create({
svg:
this
.svg,
parent:
this
.svg.all,
type:
'path'
,
attr: {
d: path,
fill: prop.colors[i],
stroke: prop.strokestyle,
'stroke-width'
: prop.linewidth,
'data-tooltip'
: (!RG.SVG.isNull(prop.tooltips) && prop.tooltips.length) ? prop.tooltips[i] :
''
,
'data-index'
: i,
'data-value'
: value,
'data-start-angle'
:
this
.angles[i].start,
'data-end-angle'
:
this
.angles[i].end,
'data-radius'
:
this
.radius,
filter: (prop.shadow && opt.shadow) ?
'url(#dropShadow)'
:
''
}
});
this
.angles[i].element = arc;
if
(prop.shadow && opt.shadow) {
this
.shadowNodes[i] = arc;
}
else
{
this
.nodes[i] = arc;
}
if
(prop.tooltips && prop.tooltips[i] && (!opt.shadow || !prop.shadow)) {
if
(prop.tooltipsEvent !==
'mousemove'
) {
prop.tooltipsEvent =
'click'
;
}
(
function
(index, obj)
{
arc.addEventListener(prop.tooltipsEvent,
function
(e)
{
var
tooltip = RG.SVG.REG.get(
'tooltip'
);
if
(tooltip && prop.tooltipsEvent ===
'mousemove'
&& index === tooltip.__index__) {
return
;
}
obj.removeHighlight();
RG.SVG.tooltip({
object: obj,
index: index,
sequentialIndex: index,
text: prop.tooltips[index],
event: e
});
obj.highlight(e.target);
var
highlight = RG.SVG.REG.get(
'highlight'
);
if
(prop.tooltipsEvent ===
'mousemove'
) {
highlight.style.cursor =
'pointer'
;
}
},
false
);
if
(prop.tooltipsEvent ===
'click'
) {
arc.addEventListener(
'mousemove'
,
function
(e)
{
e.target.style.cursor =
'pointer'
;
},
false
);
}
}(i,
this
));
}
}
if
(prop.shadow && opt.shadow) {
this
.redrawSegments();
}
};
this
.redrawSegments =
function
()
{
this
.drawSegments({shadow:
false
});
};
this
.drawLabels =
function
()
{
var
angles =
this
.angles,
prop =
this
.properties,
labels = prop.labels;
for
(
var
i=0; i<angles.length; ++i) {
var
endpoint = RG.SVG.TRIG.getRadiusEndPoint({
angle: angles[i].halfway - RG.SVG.TRIG.HALFPI,
r: angles[i].radius + 15
});
var
x = endpoint[0] + angles[i].cx,
y = endpoint[1] + angles[i].cy,
valign,
halign;
if
(angles[i].halfway > 0 && angles[i].halfway < RG.SVG.TRIG.HALFPI) {
halign = 'left
';
valign = '
bottom
';
} else if (angles[i].halfway > RG.SVG.TRIG.HALFPI && angles[i].halfway < RG.SVG.TRIG.PI) {
halign = '
left
';
valign = '
top
';
} else if (angles[i].halfway > RG.SVG.TRIG.PI && angles[i].halfway < (RG.SVG.TRIG.HALFPI + RG.SVG.TRIG.PI)) {
halign = '
right
';
valign = '
top
';
} else if (angles[i].halfway > (RG.SVG.TRIG.HALFPI + RG.SVG.TRIG.PI) && angles[i].halfway < RG.SVG.TRIG.TWOPI) {
halign = '
right
';
valign = '
top
';
}
RG.SVG.text({
object: this,
parent: this.svg.all,
tag: '
labels
',
text: typeof labels[i] === '
string
' ? labels[i] : '
',
font: prop.textFont,
size: prop.textSize,
x: x,
y: y,
valign: valign,
halign: halign,
bold: prop.textBold,
italic: prop.textItalic,
color: prop.textColor
});
}
};
//
// Draws the ingraph labels
//
this.drawIngraphLabels = function ()
{
if (prop.labelsIngraph) {
for (var i=0; i<this.angles.length; ++i) {
// Some defaults
var halign = prop.labelsIngraphHalign || '
center
',
valign = prop.labelsIngraphValign || '
center
',
font = prop.labelsIngraphFont || prop.textFont,
size = prop.labelsIngraphSize || prop.textSize,
italic = typeof prop.labelsIngraphItalic === '
boolean
' ? prop.labelsIngraphItalic : prop.textItalic,
bold = typeof prop.labelsIngraphBold === '
boolean
' ? prop.labelsIngraphBold : prop.textBold,
color = prop.labelsIngraphColor || prop.textColor,
bgcolor = prop.labelsIngraphBackground || '
transparent
',
decimals = prop.labelsIngraphDecimals || 0,
padding = typeof prop.labelsIngraphBackground === '
string
' ? 3 : 0;
// Work out the coordinates
var xy = RG.SVG.TRIG.getRadiusEndPoint({
angle: this.angles[i].halfway - RG.SVG.TRIG.HALFPI,
r: this.angles[i].radius * (typeof prop.labelsIngraphRadiusPos === '
number
' ? prop.labelsIngraphRadiusPos : 0.5)
});
if (typeof prop.labelsIngraphSpecific === '
object
' && prop.labelsIngraphSpecific) {
if (typeof prop.labelsIngraphSpecific[i] === '
string
') {
var str = prop.labelsIngraphSpecific[i];
} else {
var str = '
';
}
} else {
if (typeof prop.labelsIngraphFormatter === '
function
') {
var str = prop.labelsIngraphFormatter({
object: this,
number: this.data[i].toFixed(decimals)
})
} else {
var str = RG.SVG.numberFormat({
prepend: prop.labelsIngraphUnitsPre,
append: prop.labelsIngraphUnitsPost,
point: prop.labelsIngraphPoint,
thousand: prop.labelsIngraphThousand,
num: this.data[i].toFixed(decimals),
object: this
});
}
}
//Draw the text
RG.SVG.text({
object: this,
parent: this.svg.all,
tag: '
labels.ingraph
',
x: this.angles[i].cx + xy[0],
y: this.angles[i].cy + xy[1],
text: str,
halign: halign,
valign: valign,
font: font,
size: size,
bold: bold,
italic: italic,
color: color,
background: bgcolor,
padding: padding
});
}
}
};
//
// This function draws the labels in a list format
//
this.drawLabelsSticks = function ()
{
var labels_right = [],
labels_left = [],
labels_coords = [];
for (var i=0; i<this.angles.length; ++i) {
var angle = (this.angles[i].start + ((this.angles[i].end - this.angles[i].start) / 2)) - RGraph.SVG.TRIG.HALFPI, // Midpoint
endpoint_inner = RG.SVG.TRIG.getRadiusEndPoint({angle: angle, r: this.radius + 5}),
endpoint_outer = RG.SVG.TRIG.getRadiusEndPoint({angle: angle, r: this.radius + 20}),
explosion = [
(typeof prop.exploded === '
number
' ? prop.exploded : prop.exploded[i]),
ma.cos(angle) * (typeof prop.exploded === '
number
' ? prop.exploded : prop.exploded[i]),
ma.sin(angle) * (typeof prop.exploded === '
number
' ? prop.exploded : prop.exploded[i])
];
// Initialise this array
labels_coords[i] = [];
// Initialise this
var labels = {};
// Push the label into the correct array
if (angle > RG.SVG.TRIG.HALFPI) {
var index = labels_left.length;
labels_left[index] = [];
labels_left[index].text = prop.labels[i];
labels_left[index].halign = '
right
';
labels = labels_left;
labels_coords[i].halign = '
right
';
} else {
var index = labels_right.length;
labels_right[index] = [];
labels_right[index].text = prop.labels[i];
labels_right[index].halign = '
right
';
labels = labels_right;
labels_coords[i].halign = '
left
';
}
endpoint_inner[0] += (explosion[1] || 0);
endpoint_inner[1] += (explosion[2] || 0);
endpoint_outer[0] += (explosion[1] || 0);
endpoint_outer[1] += (explosion[2] || 0);
var x,y;
if (labels[index].text) {
var stick = RG.SVG.create({
svg: this.svg,
parent: this.svg.all,
type: '
path
',
attr: {
d: '
M {1} {2} L {3} {4}
'.format(
this.centerx + endpoint_inner[0],
this.centery + endpoint_inner[1],
this.centerx + endpoint_outer[0],
this.centery + endpoint_outer[1]
),
stroke: '
#999',
fill: 'rgba(0,0,0,0)
'
}
});
}
// The path is altered later so this needs saving
if (stick) {
labels[index].stick = stick;
}
x = (this.centerx + endpoint_outer[0] + (angle > 1.57 ? -50 : 50));
y = (this.centery + endpoint_outer[1]);
labels_coords[i].x = x ;
labels_coords[i].y = y;
labels_coords[i].text = prop.labels[i];
}
// Calculate the spacing for each side
var vspace_right = (this.height - prop.gutterTop - prop.gutterBottom) / labels_right.length;
var vspace_left = (this.height - prop.gutterTop - prop.gutterBottom) / labels_left.length;
// Reset these
x = y = 0;
// Loop through the RHS labels
for (var i=0; i<labels_right.length; ++i) {
if (labels_right[i] && labels_right[i].text) {
x = this.centerx + this.radius + 100;
y = prop.gutterTop + (vspace_right * i) + (vspace_right / 2);
// Add the label to the scene
RGraph.SVG.text({
object: this,
parent: this.svg.all,
tag: '
labels.sticks
',
text: typeof labels_right[i].text === '
string
' ? labels_right[i].text : '
',
font: prop.textFont,
size: prop.textSize,
x: x,
y: y,
valign: '
center
',
halign: labels_right[i].text,
bold: prop.textBold,
italic: prop.textItalic,
color: prop.textColor
});
// Now update the path of the stick
labels_right[i].stick.setAttribute(
'
d
',
labels_right[i].stick.getAttribute('
d
') + '
H {3} L {1} {2}
'.format(
x - 5,
y,
this.centerx + this.radius + prop.labelsSticksHlength
)
);
}
}
// Loop through the LHS labels
for (var i=0; i<labels_left.length; ++i) {
if (labels_left[i] && labels_left[i].text) {
x = this.centerx - this.radius - 100;
y = this.height - (prop.gutterTop + (vspace_left * i) + (vspace_left / 2));
// Add the label to the scene
RGraph.SVG.text({
object: this,
parent: this.svg.all,
tag: '
labels.sticks
',
text: typeof labels_left[i].text === '
string
' ? labels_left[i].text : '
',
font: prop.textFont,
size: prop.textSize,
x: x - 7,
y: y,
valign: '
center
',
halign: labels_left[i].halign,
bold: prop.textBold,
italic: prop.textItalic,
color: prop.textColor
});
// Now update the path of the stick
labels_left[i].stick.setAttribute(
'
d
',
labels_left[i].stick.getAttribute('
d
') + '
H {3} L {1} {2}
'.format(
x - 5,
y,
this.centerx - this.radius - prop.labelsSticksHlength
)
);
}
}
};
/**
* This function can be used to highlight a segment on the chart
*
* @param object segment The segment to highlight
*/
this.highlight = function (segment)
{
// Outline style highlighting
if (prop.highlightStyle === '
outline
') {
var index = segment.getAttribute('
data-index
');
var path = RGraph.SVG.TRIG.getArcPath3({
start: this.angles[index].start,
end: this.angles[index].end,
cx: this.angles[index].cx,
cy: this.angles[index].cy,
r: this.angles[index].radius + 2,
anticlockwise: false,
lineto: false
});
// Add the reverse arc
path += RGraph.SVG.TRIG.getArcPath3({
start: this.angles[index].end,
end: this.angles[index].start,
cx: this.angles[index].cx,
cy: this.angles[index].cy,
r: this.angles[index].radius + 2 + prop.highlightStyleOutlineWidth,
anticlockwise: true
});
var highlight = RG.SVG.create({
svg: this.svg,
parent: this.svg.all,
type: '
path
',
attr: {
d: path,
fill: prop.colors[index],
stroke: '
transparent
'
},
style: {
pointerEvents: '
none
'
}
});
// Regular highlighting
} else {
var highlight = RG.SVG.create({
svg: this.svg,
parent: this.svg.all,
type: '
path
',
attr: {
d: segment.getAttribute('
d
'),
fill: prop.highlightFill,
stroke: prop.highlightStroke,
'
stroke-width
': prop.highlightLinewidth
},
style: {
pointerEvents: '
none
'
}
});
}
if (prop.tooltipsEvent === '
mousemove
') {
highlight.addEventListener('
mouseout
', function (e)
{
highlight.parentNode.removeChild(highlight);
RG.SVG.hideTooltip();
RG.SVG.REG.set('
highlight
', null);
}, false);
}
// Store the highlight rect in the registry so
// it can be cleared later
RG.SVG.REG.set('
highlight
', highlight);
};
/**
* This allows for easy specification of gradients
*/
this.parseColors = function ()
{
// Save the original colors so that they can be restored when the canvas is reset
if (!Object.keys(this.originalColors).length) {
this.originalColors = {
colors: RG.SVG.arrayClone(prop.colors),
highlightFill: RG.SVG.arrayClone(prop.highlightFill)
}
}
// colors
var colors = prop.colors;
if (colors) {
for (var i=0; i<colors.length; ++i) {
colors[i] = RG.SVG.parseColorRadial({
object: this,
color: colors[i]
});
}
}
// Highlight fill
prop.highlightFill = RG.SVG.parseColorRadial({
object: this,
color: prop.highlightFill
});
};
//
// A roundRobin effect for the Pie chart
//
// @param object Options for the effect
// @param function An optional callback function to call when
// the effect is complete
//
this.roundRobin = function ()
{
var obj = this,
opt = arguments[0] || {},
data = RG.SVG.arrayClone(this.data),
prop = this.properties,
frame = 1,
frames = opt.frames || 30,
callback = typeof opt.callback === '
function
' ? opt.callback : function () {},
dataSum = RG.SVG.arraySum(this.data),
textColor = prop.textColor,
ingraph = prop.labelsIngraph;
// Set the text colors to transparent
this.properties.textColor = '
rgba(0,0,0,0)
';
this.properties.labelsIngraph = false;
// Draw the chart first
obj.draw();
// Now get the resulting angles
angles = RG.SVG.arrayClone(obj.angles);
function iterator ()
{
prop.roundRobinMultiplier = 1 / frames * frame++;
for (var i=0; i<obj.angles.length; ++i) {
var value = obj.data[i];
// NB This was an absolute git to work out for some reason.
obj.angles[i].start = angles[i].start * prop.roundRobinMultiplier;
obj.angles[i].end = angles[i].end * prop.roundRobinMultiplier;
//var segment = (((value * prop.roundRobinMultiplier) / dataSum) * RG.SVG.TRIG.TWOPI);
var segment = ((obj.angles[i].end - obj.angles[i].start) / 2);
var explodedX = ma.cos(obj.angles[i].start + segment - RG.SVG.TRIG.HALFPI) * (prop.exploded[i] || 0);
var explodedY = ma.sin(obj.angles[i].start + segment - RG.SVG.TRIG.HALFPI) * (prop.exploded[i] || 0);
var path = RG.SVG.TRIG.getArcPath({
cx: obj.centerx + explodedX,
cy: obj.centery + explodedY,
r: obj.radius,
start: obj.angles[i].start,
end: obj.angles[i].end
});
// Donut
if (prop.donut) {
var donutWidth = prop.donutWidth;
var donut_path = RG.SVG.TRIG.getArcPath({
cx: obj.angles[i].cx,
cy: obj.angles[i].cy,
r: obj.radius - donutWidth,
start: obj.angles[i].end,
end: obj.angles[i].start,
moveto: false,
anticlockwise: true
});
var xy = RG.SVG.TRIG.getRadiusEndPoint({
angle: obj.angles[i].end - RG.SVG.TRIG.HALFPI,
r: obj.radius - donutWidth
});
path = path
+ " L {1} {2} ".format(xy[0] + obj.angles[i].cx, xy[1] + obj.angles[i].cy)
+ donut_path
+ " Z";
} else {
path = path + " L {1} {2} ".format(
obj.angles[i].cx,
obj.angles[i].cy
) + " Z"
}
path = path + " L {1} {2} Z".format(
obj.centerx + explodedX,
obj.centery + explodedY
);
if (obj.shadowNodes && obj.shadowNodes[i]) {
obj.shadowNodes[i].setAttribute('
d
', path);
}
obj.nodes[i].setAttribute('
d
', path);
}
if (frame <= frames) {
RG.SVG.FX.update(iterator);
} else {
prop.textColor = textColor;
prop.labelsIngraph = ingraph;
RG.SVG.redraw(obj.svg);
callback(obj);
}
}
iterator();
return this;
};
/**
* Using a function to add events makes it easier to facilitate method
* chaining
*
* @param string type The type of even to add
* @param function func
*/
this.on = function (type, func)
{
if (type.substr(0,2) !== '
on
') {
type = '
on
' + type;
}
RG.SVG.addCustomEventListener(this, type, func);
return this;
};
//
// Used in chaining. Runs a function there and then - not waiting for
// the events to fire (eg the onbeforedraw event)
//
// @param function func The function to execute
//
this.exec = function (func)
{
func(this);
return this;
};
//
// Remove highlight from the chart (tooltips)
//
this.removeHighlight = function ()
{
var highlight = RG.SVG.REG.get('
highlight
');
if (highlight && highlight.parentNode) {
highlight.parentNode.removeChild(highlight);
}
RG.SVG.REG.set('
highlight
', null);
};
//
// Set the options that the user has provided
//
for (i in conf.options) {
if (typeof i === '
string') {
this
.set(i, conf.options[i]);
}
}
};
return
this
;
})(window, document);