RGraph = window.RGraph || {isRGraph:
true
,isRGraphSVG:
true
};
RGraph.SVG = RGraph.SVG || {};
RGraph.SVG.FX = RGraph.SVG.FX || {};
(
function
(win, doc, undefined)
{
var
RG = RGraph,
ua = navigator.userAgent,
ma = Math;
RG.SVG.REG = {
store: []
};
RG.SVG.OR = {objects: []};
RG.SVG.TRIG = {};
RG.SVG.TRIG.HALFPI = ma.PI * .4999;
RG.SVG.TRIG.PI = RG.SVG.TRIG.HALFPI * 2;
RG.SVG.TRIG.TWOPI = RG.SVG.TRIG.PI * 2;
RG.SVG.ISIE = ua.indexOf('rident
') > 0;
RG.SVG.ISFF = ua.indexOf('
irefox
') > 0;
RG.SVG.events = [];
// This allows you to set globalconfiguration values that are copied to
// all objects automatically.
RG.SVG.GLOBALS = {};
RG.SVG.ISFF = ua.indexOf('
Firefox
') != -1;
RG.SVG.ISOPERA = ua.indexOf('
Opera
') != -1;
RG.SVG.ISCHROME = ua.indexOf('
Chrome
') != -1;
RG.SVG.ISSAFARI = ua.indexOf('
Safari
') != -1 && !RG.SVG.ISCHROME;
RG.SVG.ISWEBKIT = ua.indexOf('
WebKit
') != -1;
RG.SVG.ISIE = ua.indexOf('
Trident
') > 0 || navigator.userAgent.indexOf('
MSIE
') > 0;
RG.SVG.ISIE6 = ua.indexOf('
MSIE 6
') > 0;
RG.SVG.ISIE7 = ua.indexOf('
MSIE 7
') > 0;
RG.SVG.ISIE8 = ua.indexOf('
MSIE 8
') > 0;
RG.SVG.ISIE9 = ua.indexOf('
MSIE 9
') > 0;
RG.SVG.ISIE10 = ua.indexOf('
MSIE 10
') > 0;
RG.SVG.ISIE11UP = ua.indexOf('
MSIE
') == -1 && ua.indexOf('
Trident
') > 0;
RG.SVG.ISIE10UP = RG.SVG.ISIE10 || RG.SVG.ISIE11UP;
RG.SVG.ISIE9UP = RG.SVG.ISIE9 || RG.SVG.ISIE10UP;
//
// Create an SVG tag
//
RG.SVG.createSVG = function (opt)
{
var container = opt.container,
obj = opt.object;
if (container.__svg__) {
return container.__svg__;
}
svg.setAttribute('
style
', '
top: 0; left: 0; position: absolute
');
svg.setAttribute('
width
', container.offsetWidth);
svg.setAttribute('
height
', container.offsetHeight);
svg.setAttribute('
version
', '
1.1
');
svg.__object__ = obj;
svg.__container__ = container;
container.appendChild(svg);
container.__svg__ = svg;
container.__object__ = obj;
var style = getComputedStyle(container);
if (style.position !== '
absolute
' && style.position !== '
fixed
' && style.position !== '
sticky
') {
container.style.position = '
relative
';
}
// Add the groups that facilitate "background layers"
var numLayers = 10;
for (var i=1; i<=numLayers; ++i) {
var group = RG.SVG.create({
svg: svg,
type: '
g
',
attr: {
className: '
background
' + i
}
});
// Store a reference to the group
obj.layers['
background
' + i] = group;
svg['
background
' + i] = group;
}
// Add the group tag to the SVG that contains all of the elements
var group = RG.SVG.create({
svg: svg,
type: '
g
',
attr: {
className: '
all-elements
'
}
});
container.__svg__.all = group;
return svg;
};
//
// Create a defs tag inside the SVG
//
RG.SVG.createDefs = function (obj)
{
if (!obj.svg.defs) {
var defs = RG.SVG.create({
svg: obj.svg,
type: '
defs
'
});
obj.svg.defs = defs;
}
return defs;
};
//
// Creates a tag depending on the args that you give
//
//@param opt object The options for the function
//
RG.SVG.create = function (opt)
{
tag = doc.createElementNS(ns, opt.type);
// Add the attributes
for (var o in opt.attr) {
if (typeof o === '
string
') {
var name = o;
if (o === '
className
') {
name = '
class
';
}
if ( (opt.type === '
a
' || opt.type === '
image
') && o === '
xlink:href
') {
tag.setAttributeNS('
http:
}
else
{
if
(RG.SVG.isNull(opt.attr[o])) {
opt.attr[o] = '
';
}
tag.setAttribute(name, String(opt.attr[o]));
}
}
}
// Add the style
for (var o in opt.style) {
if (typeof o === '
string
') {
tag.style[o] = String(opt.style[o]);
}
}
if (opt.parent) {
opt.parent.appendChild(tag);
} else {
opt.svg.appendChild(tag);
}
return tag;
};
//
// Function that adds up all of the offsetLeft and offsetTops to get
// X/Y coords for the mouse
//
//@param object e The event object
//@return array The X/Y coordinate pair representing the mouse
// location in relation to the SVG tag.
//
RG.SVG.getMouseXY = function(e)
{
// This is necessary for IE9
if (!e.target) {
return;
}
var el = e.target, offsetX = 0, offsetY = 0, x, y;
if (typeof el.offsetParent !== '
undefined
') {
do {
offsetX += el.offsetLeft;
offsetY += el.offsetTop;
} while ((el = el.offsetParent));
}
x = e.pageX;
y = e.pageY;
x -= (2 * (parseInt(document.body.style.borderLeftWidth) || 0));
y -= (2 * (parseInt(document.body.style.borderTopWidth) || 0));
// We return a javascript array with x and y defined
return [x, y];
};
//
// Draws an X axis
//
//@param The chart object
//
RG.SVG.drawXAxis = function (obj)
{
var prop = obj.properties;
// Draw the axis
if (prop.xaxis) {
var y = obj.type === '
hbar
' ? obj.height - prop.marginBottom : 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));
var axis = RG.SVG.create({
svg: obj.svg,
parent: obj.svg.all,
type: '
path
',
attr: {
d: '
M{1} {2} L{3} {4}
'.format(
prop.marginLeft,
y,
obj.width - prop.marginRight,
y
),
fill: prop.xaxisColor,
stroke: prop.xaxisColor,
'
stroke-width
': typeof prop.xaxisLinewidth === '
number
' ? prop.xaxisLinewidth : 1,
'
shape-rendering
': '
crispEdges
',
'
stroke-linecap
': '
square
'
}
});
// HBar X axis
if (obj.type === '
hbar
') {
var width = obj.graphWidth / obj.data.length,
x = prop.marginLeft,
startY = (obj.height - prop.marginBottom),
endY = (obj.height - prop.marginBottom) + prop.xaxisTickmarksLength;
// Line/Bar/Waterfall/Scatter X axis
} else {
var width = obj.graphWidth / obj.data.length,
x = prop.marginLeft,
startY = obj.getYCoord(0) - (prop.yaxisScaleMin < 0 ? prop.xaxisTickmarksLength : 0),
endY = obj.getYCoord(0) + prop.xaxisTickmarksLength;
if (obj.scale.min < 0 && obj.scale.max <= 0) {
startY = prop.marginTop;
endY = prop.marginTop - prop.xaxisTickmarksLength;
}
if (obj.scale.min > 0 && obj.scale.max > 0) {
startY = obj.getYCoord(obj.scale.min);
endY = obj.getYCoord(obj.scale.min) + prop.xaxisTickmarksLength;
}
}
// Draw the tickmarks
if (prop.xaxisTickmarks) {
// The HBar uses a scale
if (prop.xaxisScale) {
for (var i=0; i<(typeof prop.xaxisLabelsPositionEdgeTickmarksCount === '
number
' ? prop.xaxisLabelsPositionEdgeTickmarksCount : (obj.scale.numlabels + (prop.yaxis && prop.xaxisScaleMin === 0 ? 0 : 1))); ++i) {
if (obj.type === '
hbar
') {
var dataPoints = obj.data.length;
}
x = prop.marginLeft + ((i+(prop.yaxis && prop.xaxisScaleMin === 0 ? 1 : 0)) * (obj.graphWidth / obj.scale.numlabels));
// Allow Manual specification of number of tickmarks
if (typeof prop.xaxisLabelsPositionEdgeTickmarksCount === '
number
') {
dataPoints = prop.xaxisLabelsPositionEdgeTickmarksCount;
var gap = (obj.graphWidth / prop.xaxisLabelsPositionEdgeTickmarksCount);
x = (gap * i) + prop.marginLeft + gap;
}
RG.SVG.create({
svg: obj.svg,
parent: obj.svg.all,
type: '
path
',
attr: {
d: '
M{1} {2} L{3} {4}
'.format(
x,
startY,
x,
endY
),
stroke: prop.xaxisColor,
'
stroke-width
': typeof prop.xaxisLinewidth === '
number
' ? prop.xaxisLinewidth : 1,
'
shape-rendering
': "crispEdges"
}
});
}
} else {
// This style is used by Bar and Scatter charts
if (prop.xaxisLabelsPosition === '
section
') {
if (obj.type === '
bar
' || obj.type === '
waterfall
') {
var dataPoints = obj.data.length;
} else if (obj.type === '
line
'){
var dataPoints = obj.data[0].length;
} else if (obj.type === '
scatter
') {
var dataPoints = prop.xaxisLabels ? prop.xaxisLabels.length : 10;
}
// Allow Manual specification of number of tickmarks
if (typeof prop.xaxisLabelsPositionSectionTickmarksCount === '
number
') {
dataPoints = prop.xaxisLabelsPositionSectionTickmarksCount;
}
for (var i=0; i<dataPoints; ++i) {
x = prop.marginLeft + (prop.marginInnerLeft || 0) + ((i+1) * ( (obj.graphWidth - (prop.marginInnerLeft || 0) - (prop.marginInnerRight || 0) ) / dataPoints));
RG.SVG.create({
svg: obj.svg,
parent: obj.svg.all,
type: '
path
',
attr: {
d: '
M{1} {2} L{3} {4}
'.format(
x + 0.001,
startY,
x,
endY
),
stroke: prop.xaxisColor,
'
stroke-width
': typeof prop.xaxisLinewidth === '
number
' ? prop.xaxisLinewidth : 1,
'
shape-rendering
': "crispEdges"
}
});
}
// This style is used by line charts
} else if (prop.xaxisLabelsPosition === '
edge
') {
if (typeof prop.xaxisLabelsPositionEdgeTickmarksCount === '
number
') {
var len = prop.xaxisLabelsPositionEdgeTickmarksCount;
} else {
var len = obj.data && obj.data[0] && obj.data[0].length ? obj.data[0].length : 0;
}
for (var i=0; i<len; ++i) {
var gap = ( (obj.graphWidth) / (len - 1)),
x = prop.marginLeft + ((i+1) * gap);
RG.SVG.create({
svg: obj.svg,
parent: obj.svg.all,
type: '
path
',
attr: {
d: '
M{1} {2} L{3} {4}
'.format(
x + 0.001,
startY,
x,
endY
),
stroke: prop.xaxisColor,
'
stroke-width
': typeof prop.xaxisLinewidth === '
number
' ? prop.xaxisLinewidth : 1,
'
shape-rendering
': "crispEdges"
}
});
}
}
}
// Draw an extra tick if the Y axis is not being shown
// if (prop.yaxis === false || (prop.marginInnerLeft || 0) > 0) {
// WBB - line above changed to match the corresponding line in the RG.SVG.drawYAxis function
if ((prop.xaxisScaleMin !== 0 || prop.yaxis === false || obj.mirrorScale) && ((obj.scale.min < 0 && obj.scale.max <= 0) || (obj.scale.min > 0 && obj.scale.max > 0))) {
RG.SVG.create({
svg: obj.svg,
parent: obj.svg.all,
type: '
path
',
attr: {
d: '
M{1} {2} L{3} {4}
'.format(
prop.marginLeft + (prop.marginInnerLeft || 0) + 0.001,
startY,
prop.marginLeft + (prop.marginInnerLeft || 0),
endY
),
stroke: obj.properties.xaxisColor,
'
stroke-width
': typeof prop.xaxisLinewidth === '
number
' ? prop.xaxisLinewidth : 1,
'
shape-rendering
': "crispEdges",
parent: obj.svg.all,
}
});
}
}
}
//
// Draw an X axis scale
//
if (prop.xaxisScale) {
//if (obj.type === '
scatter
') {
// WBB - modified line above so that line graphs used the same X-axis as scatter graphs
if (obj.type === '
scatter
' || obj.type === '
line
') {
obj.xscale = RG.SVG.getScale({
object: obj,
numlabels: prop.xaxisLabelsCount,
unitsPre: prop.xaxisScaleUnitsPre,
unitsPost: prop.xaxisScaleUnitsPost,
max: prop.xaxisScaleMax,
min: prop.xaxisScaleMin,
point: prop.xaxisScalePoint,
round: prop.xaxisScaleRound,
thousand: prop.xaxisScaleThousand,
decimals: prop.xaxisScaleDecimals,
strict: typeof prop.xaxisScaleMax === '
number
',
formatter: prop.xaxisScaleFormatter
});
var segment = obj.graphWidth / prop.xaxisLabelsCount
for (var i=0; i<obj.xscale.labels.length; ++i) {
var x = prop.marginLeft + (segment * i) + segment + prop.xaxisLabelsOffsetx;
var y = (obj.height - prop.marginBottom) + (prop.xaxis ? prop.xaxisTickmarksLength + 6 : 10) + (prop.xaxisLinewidth || 1) + prop.xaxisLabelsOffsety;
RG.SVG.text({
object: obj,
parent: obj.svg.all,
text: obj.xscale.labels[i],
x: x,
y: y,
halign: '
center
',
valign: '
top
',
tag: '
labels.xaxis
',
font: prop.xaxisLabelsFont || prop.textFont,
size: typeof prop.xaxisLabelsSize === '
number
' ? prop.xaxisLabelsSize : prop.textSize,
bold: typeof prop.xaxisLabelsBold === '
boolean
' ? prop.xaxisLabelsBold : prop.textBold,
italic: typeof prop.xaxisLabelsItalic === '
boolean
' ? prop.xaxisLabelsItalic : prop.textItalic,
color: prop.xaxisLabelsColor || prop.textColor
});
}
// Add the minimum label if labels are enabled
if (prop.xaxisLabelsCount > 0) {
var y = obj.height - prop.marginBottom + prop.xaxisLabelsOffsety + (prop.xaxis ? prop.xaxisTickmarksLength + 6 : 10),
str = RG.SVG.numberFormat({
object: obj,
num: prop.xaxisScaleMin.toFixed(prop.xaxisScaleDecimals),
prepend: prop.xaxisScaleUnitsPre,
append: prop.xaxisScaleUnitsPost,
point: prop.xaxisScalePoint,
thousand: prop.xaxisScaleThousand,
formatter: prop.xaxisScaleFormatter
});
var text = RG.SVG.text({
object: obj,
parent: obj.svg.all,
text: typeof prop.xaxisScaleFormatter === '
function
' ? (prop.xaxisScaleFormatter)(this, prop.xaxisScaleMin) : str,
x: prop.marginLeft + prop.xaxisLabelsOffsetx,
y: y,
halign: '
center
',
valign: '
top
',
tag: '
labels.xaxis
',
font: prop.xaxisLabelsFont || prop.textFont,
size: typeof prop.xaxisLabelsSize === '
number
' ? prop.xaxisLabelsSize : prop.textSize,
bold: typeof prop.xaxisLabelsBold === '
number
' ? prop.xaxisLabelsBold : prop.textBold,
italic: typeof prop.xaxisLabelsItalic === '
boolean
' ? prop.xaxisLabelsItalic : prop.textItalic,
color: prop.xaxisLabelsColor || prop.textColor
});
}
// =========================================================================
} else {
var segment = obj.graphWidth / prop.xaxisLabelsCount,
scale = obj.scale;
for (var i=0; i<scale.labels.length; ++i) {
var x = prop.marginLeft + (segment * i) + segment + prop.xaxisLabelsOffsetx;
var y = (obj.height - prop.marginBottom) + (prop.xaxis ? prop.xaxisTickmarksLength + 6 : 10) + (prop.xaxisLinewidth || 1) + prop.xaxisLabelsOffsety;
RG.SVG.text({
object: obj,
parent: obj.svg.all,
text: obj.scale.labels[i],
x: x,
y: y,
halign: '
center
',
valign: '
top
',
tag: '
labels.xaxis
',
font: prop.xaxisLabelsFont || prop.textFont,
size: typeof prop.xaxisLabelsSize === '
number
' ? prop.xaxisLabelsSize : prop.textSize,
bold: typeof prop.xaxisLabelsBold === '
boolean
' ? prop.xaxisLabelsBold : prop.textBold,
italic: typeof prop.xaxisLabelsItalic === '
boolean
' ? prop.xaxisLabelsItalic : prop.textItalic,
color: prop.xaxisLabelsColor || prop.textColor
});
}
// Add the minimum label if labels are enabled
if (prop.xaxisLabelsCount > 0) {
var y = obj.height - prop.marginBottom + prop.xaxisLabelsOffsety + (prop.xaxis ? prop.xaxisTickmarksLength + 6 : 10),
str = RG.SVG.numberFormat({
object: obj,
num: prop.xaxisScaleMin.toFixed(prop.xaxisScaleDecimals),
prepend: prop.xaxisScaleUnitsPre,
append: prop.xaxisScaleUnitsPost,
point: prop.xaxisScalePoint,
thousand: prop.xaxisScaleThousand,
formatter: prop.xaxisScaleFormatter
});
var text = RG.SVG.text({
object: obj,
parent: obj.svg.all,
text: typeof prop.xaxisScaleFormatter === '
function
' ? (prop.xaxisScaleFormatter)(this, prop.xaxisScaleMin) : str,
x: prop.marginLeft + prop.xaxisLabelsOffsetx,
y: y,
halign: '
center
',
valign: '
top
',
tag: '
labels.xaxis
',
font: prop.xaxisLabelsFont || prop.textFont,
size: typeof prop.xaxisLabelsSize === '
number
' ? prop.xaxisLabelsSize : prop.textSize,
bold: typeof prop.xaxisLabelsBold === '
boolean
' ? prop.xaxisLabelsBold : prop.textBold,
italic: typeof prop.xaxisLabelsItalic === '
boolean
' ? prop.xaxisLabelsItalic : prop.textItalic,
color: prop.xaxisLabelsColor || prop.textColor
});
}
}
//
// Draw the X axis labels
//
} else {
if (typeof prop.xaxisLabels === '
object
' && !RG.SVG.isNull(prop.xaxisLabels) ) {
var angle = prop.xaxisLabelsAngle;
// Loop through the X labels
if (prop.xaxisLabelsPosition === '
section
') {
var segment = (obj.width - prop.marginLeft - prop.marginRight - (prop.marginInnerLeft || 0) - (prop.marginInnerRight || 0) ) / prop.xaxisLabels.length;
for (var i=0; i<prop.xaxisLabels.length; ++i) {
var x = prop.marginLeft + (prop.marginInnerLeft || 0) + (segment / 2) + (i * segment);
if (obj.scale.max <=0 && obj.scale.min < obj.scale.max) {
var y = prop.marginTop - (RG.SVG.ISFF ? 5 : 10) - (prop.xaxisLinewidth || 1) + prop.xaxisLabelsOffsety;
var valign = '
bottom
';
} else {
var y = obj.height - prop.marginBottom + (RG.SVG.ISFF ? 5 : 10) + (prop.xaxisLinewidth || 1) + prop.xaxisLabelsOffsety;
var valign = '
top
';
}
RG.SVG.text({
object: obj,
parent: obj.svg.all,
text: prop.xaxisLabels[i],
x: x + prop.xaxisLabelsOffsetx,
y: y,
valign: (typeof angle === '
number
' && angle) ? '
center
' : valign,
halign: (typeof angle === '
number
' && angle) ? '
right
' : '
center
',
angle: angle,
tag: '
labels.xaxis
',
size: typeof prop.xaxisLabelsSize === '
number
' ? prop.xaxisLabelsSize : prop.textSize,
italic: typeof prop.xaxisLabelsItalic === '
boolean
' ? prop.xaxisLabelsItalic : prop.textItalic,
font: prop.xaxisLabelsFont || prop.textFont,
bold: typeof prop.xaxisLabelsBold === '
boolean
' ? prop.xaxisLabelsBold : prop.textBold,
color: prop.xaxisLabelsColor || prop.textColor
});
}
} else if (prop.xaxisLabelsPosition === '
edge
') {
if (obj.type === '
line
') {
var hmargin = prop.marginInner;
} else {
var hmargin = 0;
}
var segment = (obj.graphWidth - hmargin - hmargin) / (prop.xaxisLabels.length - 1);
for (var i=0; i<prop.xaxisLabels.length; ++i) {
var x = prop.marginLeft + (i * segment) + hmargin;
if (obj.scale.max <= 0 && obj.scale.min < 0) {
valign = '
bottom
';
y = prop.marginTop - (RG.SVG.ISFF ? 5 : 10) - (prop.xaxisTickmarksLength - 5) - (prop.xaxisLinewidth || 1) + prop.xaxisLabelsOffsety
} else {
valign = '
top
';
y = obj.height - prop.marginBottom + (RG.SVG.ISFF ? 5 : 10) + (prop.xaxisTickmarksLength - 5) + (prop.xaxisLinewidth || 1) + prop.xaxisLabelsOffsety;
}
RG.SVG.text({
object: obj,
parent: obj.svg.all,
text: prop.xaxisLabels[i],
x: x + prop.xaxisLabelsOffsetx,
y: y,
valign: (typeof angle === '
number
' && angle) ? '
center
' : valign,
halign: (typeof angle === '
number
' && angle) ? '
right
' : '
center
',
angle: angle,
tag: '
labels.xaxis
',
size: typeof prop.xaxisLabelsSize === '
number
' ? prop.xaxisLabelsSize : prop.textSize,
italic: typeof prop.xaxisLabelsItalic === '
boolean
' ? prop.xaxisLabelsItalic : prop.textItalic,
font: prop.xaxisLabelsFont || prop.textFont,
bold: typeof prop.xaxisLabelsBold === '
boolean
' ? prop.xaxisLabelsBold : prop.textBold,
color: prop.xaxisLabelsColor || prop.textColor
});
}
}
}
}
};
//
// Draws an Y axis
//
//@param The chart object
//
RG.SVG.drawYAxis = function (obj)
{
var prop = obj.properties;
if (prop.yaxis) {
// The X coordinate that the Y axis is positioned at
if (obj.type === '
hbar
') {
var x = obj.getXCoord(prop.xaxisScaleMin > 0 ? prop.xaxisScaleMin : 0);
if (prop.xaxisScaleMin < 0 && prop.xaxisScaleMax <= 0) {
x = obj.getXCoord(prop.xaxisScaleMax);
}
// WBB this branch added to match the corresponding line in the RG.SVG.drawXAxis
} else if (obj.type === '
scatter
') {
var x = obj.getXCoord(obj.scale.min < 0 && obj.scale.max < 0 ? obj.scale.max : (obj.scale.min > 0 && obj.scale.max > 0 ? obj.scale.min : 0));
} else {
var x = prop.marginLeft;
}
var axis = RG.SVG.create({
svg: obj.svg,
parent: obj.svg.all,
type: '
path
',
attr: {
d: '
M{1} {2} L{3} {4}
'.format(
x,
prop.marginTop,
x,
obj.height - prop.marginBottom
),
stroke: prop.yaxisColor,
fill: prop.yaxisColor,
'
stroke-width
': typeof prop.yaxisLinewidth === '
number
' ? prop.yaxisLinewidth : 1,
'
shape-rendering
': "crispEdges",
'
stroke-linecap
': '
square
'
}
});
if (obj.type === '
hbar
') {
var height = (obj.graphHeight - prop.marginInnerTop - prop.marginInnerBottom) / prop.yaxisLabels.length,
y = prop.marginTop + prop.marginInnerTop,
len = prop.yaxisLabels.length,
startX = obj.getXCoord(0) + (prop.xaxisScaleMin < 0 ? prop.yaxisTickmarksLength : 0),
endX = obj.getXCoord(0) - prop.yaxisTickmarksLength;
if (prop.xaxisScaleMin < 0 && prop.xaxisScaleMax <=0) {
startX = obj.getXCoord(prop.xaxisScaleMax);
endX = obj.getXCoord(prop.xaxisScaleMax) + 5;
}
// A custom number of tickmarks
if (typeof prop.yaxisLabelsPositionSectionTickmarksCount === '
number
') {
len = prop.yaxisLabelsPositionSectionTickmarksCount;
height = (obj.graphHeight - prop.marginInnerTop - prop.marginInnerBottom) / len;
}
//
// Draw the tickmarks
//
if (prop.yaxisTickmarks) {
for (var i=0; i<len; ++i) {
// Draw the axis
var axis = RG.SVG.create({
svg: obj.svg,
parent: obj.svg.all,
type: '
path
',
attr: {
d: '
M{1} {2} L{3} {4}
'.format(
startX,
y,
endX,
y + 0.001
),
stroke: prop.yaxisColor,
'
stroke-width
': typeof prop.yaxisLinewidth === '
number
' ? prop.yaxisLinewidth : 1,
'
shape-rendering
': "crispEdges"
}
});
y += height;
}
// Draw an extra tick if the X axis position is not zero or
// if the xaxis is not being shown
if (prop.xaxis === false) {
if (obj.type === '
hbar
' && prop.xaxisScaleMin <= 0 && prop.xaxisScaleMax < 0) {
var startX = obj.getXCoord(prop.xaxisScaleMax);
var endX = obj.getXCoord(prop.xaxisScaleMax) + prop.yaxisTickmarksLength;
} else {
var startX = obj.getXCoord(0) - prop.yaxisTickmarksLength;
var endX = obj.getXCoord(0) + (prop.xaxisScaleMin < 0 ? prop.yaxisTickmarksLength : 0);
}
var axis = RG.SVG.create({
svg: obj.svg,
parent: obj.svg.all,
type: '
path
',
attr: {
d: '
M{1} {2} L{3} {4}
'.format(
startX,
ma.round(obj.height - prop.marginBottom - parseFloat(prop.marginInnerBottom)),
endX,
ma.round(obj.height - prop.marginBottom - parseFloat(prop.marginInnerBottom))
),
stroke: obj.properties.yaxisColor,
'
stroke-width
': typeof prop.yaxisLinewidth === '
number
' ? prop.yaxisLinewidth : 1,
'
shape-rendering
': "crispEdges"
}
});
}
}
//
// Bar, Line etc types of chart
//
} else {
var height = obj.graphHeight / prop.yaxisLabelsCount,
y = prop.marginTop,
len = prop.yaxisLabelsCount,
startX = prop.marginLeft,
endX = prop.marginLeft - prop.yaxisTickmarksLength;
// WBB this branch added to match the corresponding line in the RG.SVG.drawXAxis
if (obj.type === '
scatter
') {
startX = obj.getXCoord(0) - (prop.xaxisScaleMin < 0 ? prop.yaxisTickmarksLength : 0);
endX = obj.getXCoord(0) + prop.yaxisTickmarksLength;
}
if ((obj.scale.min < 0 && obj.scale.max <= 0) || (obj.scale.min > 0 && obj.scale.max > 0)) {
startX = prop.marginLeft;
endX = prop.marginLeft - prop.yaxisTickmarksLength;
}
// A custom number of tickmarks
if (typeof prop.yaxisLabelsPositionEdgeTickmarksCount === '
number
') {
len = prop.yaxisLabelsPositionEdgeTickmarksCount;
height = obj.graphHeight / len;
}
//
// Draw the tickmarks
//
if (prop.yaxisTickmarks) {
for (var i=0; i<len; ++i) {
// Draw the axis
var axis = RG.SVG.create({
svg: obj.svg,
parent: obj.svg.all,
type: '
path
',
attr: {
d: '
M{1} {2} L{3} {4}
'.format(
startX,
y,
endX,
y
),
stroke: prop.yaxisColor,
'
stroke-width
': typeof prop.yaxisLinewidth === '
number
' ? prop.yaxisLinewidth : 1,
'
shape-rendering
': "crispEdges"
}
});
y += height;
}
// Draw an extra tick if the X axis position is not zero or
//if the xaxis is not being shown
// if ( (prop.yaxisScaleMin !== 0 || prop.xaxis === false || obj.mirrorScale)
// && !(obj.scale.min > 0 && obj.scale.max > 0) ) {
// WBB lines above were changed to match the corresponding line in the RG.SVG.drawXAxis function
if ((prop.yaxisScaleMin !== 0 || prop.xaxis === false || obj.mirrorScale)
&& (x === prop.marginLeft)) {
var axis = RG.SVG.create({
svg: obj.svg,
parent: obj.svg.all,
type: '
path
',
attr: {
d: '
M{1} {2} L{3} {4}
'.format(
prop.marginLeft - prop.yaxisTickmarksLength,
obj.height - prop.marginBottom,
prop.marginLeft,
obj.height - prop.marginBottom - 0.001
),
stroke: prop.yaxisColor,
'
stroke-width
': typeof prop.yaxisLinewidth === '
number
' ? prop.yaxisLinewidth : 1,
'
shape-rendering
': "crispEdges"
}
});
}
}
}
}
//
// Draw the Y axis labels
//
if (prop.yaxisScale) {
var segment = (obj.height - prop.marginTop - prop.marginBottom) / prop.yaxisLabelsCount;
for (var i=0; i<obj.scale.labels.length; ++i) {
var y = obj.height - prop.marginBottom - (segment * i) - segment;
RG.SVG.text({
object: obj,
parent: obj.svg.all,
text: obj.scale.labels[i],
x: prop.marginLeft - 7 - (prop.yaxis ? (prop.yaxisTickmarksLength - 3) : 0) + prop.yaxisLabelsOffsetx,
y: y + prop.yaxisLabelsOffsety,
halign: prop.yaxisLabelsHalign || '
right
',
valign: prop.yaxisLabelsValign || '
center
',
tag: '
labels.yaxis
',
font: prop.yaxisLabelsFont || prop.textFont,
size: typeof prop.yaxisLabelsSize === '
number
' ? prop.yaxisLabelsSize : prop.textSize,
bold: typeof prop.yaxisLabelsBold === '
boolean
' ? prop.yaxisLabelsBold : prop.textBold,
italic: typeof prop.yaxisLabelsItalic === '
boolean
' ? prop.yaxisLabelsItalic : prop.textItalic,
color: prop.yaxisLabelsColor || prop.textColor
});
}
//
// Add the minimum label
//
var y = obj.height - prop.marginBottom,
// Changed this to use obj.scale.min instead of prop.yaxisScaleMin
// on 11/11/18 because mirrored scales had zero as the bottom
// value when it should have been a mirror of the top value
str = (prop.yaxisScaleUnitsPre + obj.scale.min.toFixed(prop.yaxisScaleDecimals).replace(/\./, prop.yaxisScalePoint) + prop.yaxisScaleUnitsPost);
var text = RG.SVG.text({
object: obj,
parent: obj.svg.all,
text: typeof prop.yaxisScaleFormatter === '
function
' ? (prop.yaxisScaleFormatter)(this, prop.yaxisScaleMin) : str,
x: prop.marginLeft - 7 - (prop.yaxis ? (prop.yaxisTickmarksLength - 3) : 0) + prop.yaxisLabelsOffsetx,
y: y + prop.yaxisLabelsOffsety,
halign: '
right
',
valign: '
center
',
tag: '
labels.yaxis
',
font: prop.yaxisLabelsFont || prop.textFont,
size: typeof prop.yaxisLabelsSize === '
number
' ? prop.yaxisLabelsSize : prop.textSize,
bold: typeof prop.yaxisLabelsBold === '
boolean
' ? prop.yaxisLabelsBold : prop.textBold,
italic: typeof prop.yaxisLabelsItalic === '
boolean
' ? prop.yaxisLabelsItalic : prop.textItalic,
color: prop.yaxisLabelsColor || prop.textColor
});
//
// Draw Y axis labels (eg when specific labels are defined or
//the chart is an HBar
//
} else if (prop.yaxisLabels && prop.yaxisLabels.length) {
for (var i=0; i<prop.yaxisLabels.length; ++i) {
var segment = (obj.graphHeight - (prop.marginInnerTop || 0) - (prop.marginInnerBottom || 0) ) / prop.yaxisLabels.length,
y = prop.marginTop + (prop.marginInnerTop || 0) + (segment * i) + (segment / 2) + prop.yaxisLabelsOffsety,
x = prop.marginLeft - 7 /*- (prop.yaxis ? (prop.yaxisTickmarksLength) : 0)*/ - (prop.yaxisLinewidth || 1) + prop.yaxisLabelsOffsetx,
halign = '
right
';
// HBar labels
if (obj.type === '
hbar
' && obj.scale.min < obj.scale.max && obj.scale.max <= 0) {
halign = '
left
';
x = obj.width - prop.marginRight + 7 + prop.yaxisLabelsOffsetx;
// HBar labels (again?)
} else if (obj.type === '
hbar
' && !prop.yaxisLabelsSpecific) {
var segment = (obj.graphHeight - (prop.marginInnerTop || 0) - (prop.marginInnerBottom || 0) ) / (prop.yaxisLabels.length);
y = prop.marginTop + (prop.marginInnerTop || 0) + (segment * i) + (segment / 2) + prop.yaxisLabelsOffsety;
// Specific scale
} else {
var segment = (obj.graphHeight - (prop.marginInnerTop || 0) - (prop.marginInnerBottom || 0) ) / (prop.yaxisLabels.length - 1);
y = obj.height - prop.marginBottom - (segment * i) + prop.yaxisLabelsOffsety;
}
var text = RG.SVG.text({
object: obj,
parent: obj.svg.all,
text: prop.yaxisLabels[i] ? prop.yaxisLabels[i] : '
',
x: x,
y: y,
halign: halign,
valign: '
center
',
tag: '
labels.yaxis
',
font: prop.yaxisLabelsFont || prop.textFont,
size: typeof prop.yaxisLabelsSize === '
number
' ? prop.yaxisLabelsSize : prop.textSize,
bold: typeof prop.yaxisLabelsBold === '
boolean
' ? prop.yaxisLabelsBold : prop.textBold,
italic: typeof prop.yaxisLabelsItalic === '
boolean
' ? prop.yaxisLabelsItalic : prop.textItalic,
color: prop.yaxisLabelsColor || prop.textColor
});
}
}
};
//
// Draws the background
//
//@param The chart object
//
RG.SVG.drawBackground = function (obj)
{
var prop = obj.properties;
// Set these properties so that if it doesn'
t exist things don
't fail
if (typeof prop.variant3dOffsetx !== '
number
') prop.variant3dOffsetx = 0;
if (typeof prop.variant3dOffsety !== '
number
') prop.variant3dOffsety = 0;
if (prop.backgroundColor) {
RG.SVG.create({
svg: obj.svg,
parent: obj.svg.all,
type: '
rect
',
attr: {
x: -1 + prop.variant3dOffsetx + prop.marginLeft,
y: -1 - prop.variant3dOffsety + prop.marginTop,
width: parseFloat(obj.svg.getAttribute('
width
')) + 2 - prop.marginLeft - prop.marginRight,
height: parseFloat(obj.svg.getAttribute('
height
')) + 2 - prop.marginTop - prop.marginBottom,
fill: prop.backgroundColor
}
});
}
// Render a background image
// <image xlink:href="firefox.jpg" x="0" y="0" height="50px" width="50px"/>
if (prop.backgroundImage) {
var attr = {
'
xlink:href
': prop.backgroundImage,
//preserveAspectRatio: '
xMidYMid slice
',
preserveAspectRatio: prop.backgroundImageAspect || '
none
',
x: prop.marginLeft,
y: prop.marginTop
};
if (prop.backgroundImageStretch) {
attr.x = prop.marginLeft + prop.variant3dOffsetx;
attr.y = prop.marginTop + prop.variant3dOffsety;
attr.width = obj.width - prop.marginLeft - prop.marginRight;
attr.height = obj.height - prop.marginTop - prop.marginBottom;
} else {
if (typeof prop.backgroundImageX === '
number
') {
attr.x = prop.backgroundImageX + prop.variant3dOffsetx;
} else {
attr.x = prop.marginLeft + prop.variant3dOffsetx;
}
if (typeof prop.backgroundImageY === '
number
') {
attr.y = prop.backgroundImageY + prop.variant3dOffsety;
} else {
attr.y = prop.marginTop + prop.variant3dOffsety;
}
if (typeof prop.backgroundImageW === '
number
') {
attr.width = prop.backgroundImageW;
}
if (typeof prop.backgroundImageH === '
number
') {
attr.height = prop.backgroundImageH;
}
}
//
// Account for the chart being 3d
//
if (prop.variant === '
3d
') {
attr.x += prop.variant3dOffsetx;
attr.y -= prop.variant3dOffsety;
}
var img = RG.SVG.create({
svg: obj.svg,
parent: obj.svg.all,
type: '
image
',
attr: attr,
style: {
opacity: typeof prop.backgroundImageOpacity === '
number
' ? prop.backgroundImageOpacity : 1
}
});
// Set the width and height if necessary
if (!prop.backgroundImageStretch) {
var img2 = new Image();
img2.src = prop.backgroundImage;
img2.onload = function ()
{
if (prop.backgroundImageW === '
number
') img.setAttribute('
width
', prop.backgroundImageW);
if (prop.backgroundImageH === '
number
') img.setAttribute('
height
', prop.backgroundImageH);
};
}
}
if (prop.backgroundGrid) {
var parts = [];
// Add the horizontal lines to the path
if (prop.backgroundGridHlines) {
if (typeof prop.backgroundGridHlinesCount === '
number
') {
var count = prop.backgroundGridHlinesCount;
} else if (obj.type === '
hbar
' || obj.type === '
bipolar
') {
if (typeof prop.yaxisLabels === '
object
' && !RG.SVG.isNull(prop.yaxisLabels) && prop.yaxisLabels.length) {
var count = prop.yaxisLabels.length;
} else if (obj.type === '
hbar
') {
var count = obj.data.length;
} else if (obj.type === '
bipolar
') {
var count = obj.left.length;
}
} else {
var count = prop.yaxisLabelsCount || 5;
}
for (var i=0; i<=count; ++i) {
parts.push('
M{1} {2} L{3} {4}
'.format(
prop.marginLeft + prop.variant3dOffsetx,
prop.marginTop + (obj.graphHeight / count) * i - prop.variant3dOffsety,
obj.width - prop.marginRight + prop.variant3dOffsetx,
prop.marginTop + (obj.graphHeight / count) * i - prop.variant3dOffsety
));
}
// Add an extra background grid line to the path - this its
// underneath the X axis and shows up if it'
s not there.
parts.push(
'M{1} {2} L{3} {4}'
.format(
prop.marginLeft + prop.variant3dOffsetx,
obj.height - prop.marginBottom - prop.variant3dOffsety,
obj.width - prop.marginRight + prop.variant3dOffsetx,
obj.height - prop.marginBottom - prop.variant3dOffsety
));
}
if
(prop.backgroundGridVlines) {
if
(obj.type ===
'line'
&& RG.SVG.isArray(obj.data[0])) {
var
len = obj.data[0].length;
}
else
if
(obj.type ===
'hbar'
) {
var
len = prop.xaxisLabelsCount || 10;
}
else
if
(obj.type ===
'bipolar'
) {
var
len = prop.xaxisLabelsCount || 10;
}
else
if
(obj.type ===
'scatter'
) {
var
len = (prop.xaxisLabels && prop.xaxisLabels.length) || 10;
}
else
if
(obj.type ===
'waterfall'
) {
var
len = obj.data.length;
}
else
{
var
len = obj.data.length;
}
var
count =
typeof
prop.backgroundGridVlinesCount ===
'number'
? prop.backgroundGridVlinesCount : len;
if
(prop.xaxisLabelsPosition ===
'edge'
) {
count--;
}
for
(
var
i=0; i<=count; ++i) {
parts.push(
'M{1} {2} L{3} {4}'
.format(
prop.marginLeft + ((obj.graphWidth / count) * i) + prop.variant3dOffsetx,
prop.marginTop - prop.variant3dOffsety,
prop.marginLeft + ((obj.graphWidth / count) * i) + prop.variant3dOffsetx,
obj.height - prop.marginBottom - prop.variant3dOffsety
));
}
}
if
(prop.backgroundGridBorder) {
parts.push(
'M{1} {2} L{3} {4} L{5} {6} L{7} {8} z'
.format(
prop.marginLeft + prop.variant3dOffsetx,
prop.marginTop - prop.variant3dOffsety,
obj.width - prop.marginRight + prop.variant3dOffsetx,
prop.marginTop - prop.variant3dOffsety,
obj.width - prop.marginRight + prop.variant3dOffsetx,
obj.height - prop.marginBottom - prop.variant3dOffsety,
prop.marginLeft + prop.variant3dOffsetx,
obj.height - prop.marginBottom - prop.variant3dOffsety
));
}
var
dasharray;
if
(prop.backgroundGridDashed) {
dasharray = [3,5];
}
else
if
(prop.backgroundGridDotted) {
dasharray = [1,3];
}
else
if
(prop.backgroundGridDashArray) {
dasharray = prop.backgroundGridDashArray;
}
else
{
dasharray =
''
;
}
var
grid = RG.SVG.create({
svg: obj.svg,
parent: obj.svg.all,
type:
'path'
,
attr: {
className:
'rgraph_background_grid'
,
d: parts.join(
' '
),
stroke: prop.backgroundGridColor,
fill:
'rgba(0,0,0,0)'
,
'stroke-width'
: prop.backgroundGridLinewidth,
'shape-rendering'
:
"crispEdges"
,
'stroke-dasharray'
: dasharray
},
style: {
pointerEvents:
'none'
}
});
}
if
(obj.type !==
'bipolar'
) {
RG.SVG.drawTitle(obj);
}
};
RG.SVG.isNull =
function
(arg)
{
if
(arg ==
null
||
typeof
arg ===
'object'
&& !arg) {
return
true
;
}
return
false
;
};
RG.SVG.getScale =
function
(opt)
{
var
obj = opt.object,
prop = obj.properties,
numlabels = opt.numlabels,
unitsPre = opt.unitsPre,
unitsPost = opt.unitsPost,
max = Number(opt.max),
min = Number(opt.min),
strict = opt.strict,
decimals = Number(opt.decimals),
point = opt.point,
thousand = opt.thousand,
originalMax = max,
round = opt.round,
scale = {max:1,labels:[],values:[]},
formatter = opt.formatter;
if
(max === 0 && min === 0) {
var
max = 1;
for
(
var
i=0; i<numlabels; ++i) {
var
label = ((((max - min) / numlabels) * (i + 1)) + min).toFixed(decimals);
scale.labels.push(unitsPre + label + unitsPost);
scale.values.push(parseFloat(label))
}
}
else
if
(max <= 1 && !strict) {
var
arr = [
1,0.5,
0.10,0.05,
0.010,0.005,
0.0010,0.0005,
0.00010,0.00005,
0.000010,0.000005,
0.0000010,0.0000005,
0.00000010,0.00000005,
0.000000010,0.000000005,
0.0000000010,0.0000000005,
0.00000000010,0.00000000005,
0.000000000010,0.000000000005,
0.0000000000010,0.0000000000005
], vals = [];
for
(
var
i=0; i<arr.length; ++i) {
if
(max > arr[i]) {
i--;
break
;
}
}
scale.max = arr[i]
scale.labels = [];
scale.values = [];
for
(
var
j=0; j<numlabels; ++j) {
var
value = ((((arr[i] - min) / numlabels) * (j + 1)) + min).toFixed(decimals);
scale.values.push(value);
scale.labels.push(RG.SVG.numberFormat({
object: obj,
num: value,
prepend: unitsPre,
append: unitsPost,
point: prop.yaxisScalePoint,
thousand: prop.yaxisScaleThousand,
formatter: formatter
}));
}
}
else
if
(!strict) {
max = ma.ceil(max);
var
interval = ma.pow(10, ma.max(1, Number(String(Number(max) - Number(min)).length - 1)) );
var
topValue = interval;
while
(topValue < max) {
topValue += (interval / 2);
}
if
(Number(originalMax) > Number(topValue)) {
topValue += (interval / 2);
}
if
(max <= 10) {
topValue = (Number(originalMax) <= 5 ? 5 : 10);
}
if
(obj &&
typeof
(round) ==
'boolean'
&& round) {
topValue = 10 * interval;
}
scale.max = topValue;
for
(
var
i=0; i<numlabels; ++i) {
var
label = RG.SVG.numberFormat({
object: obj,
num: ((((i+1) / numlabels) * (topValue - min)) + min).toFixed(decimals),
prepend: unitsPre,
append: unitsPost,
point: point,
thousand: thousand,
formatter: formatter
});
scale.labels.push(label);
scale.values.push(((((i+1) / numlabels) * (topValue - min)) + min).toFixed(decimals));
}
}
else
if
(
typeof
max ===
'number'
&& strict) {
for
(
var
i=0; i<numlabels; ++i) {
scale.labels.push(RG.SVG.numberFormat({
object: obj,
formatter: formatter,
num: ((((i+1) / numlabels) * (max - min)) + min).toFixed(decimals),
prepend: unitsPre,
append: unitsPost,
point: point,
thousand: thousand
}));
scale.values.push(
((((i+1) / numlabels) * (max - min)) + min).toFixed(decimals)
);
}
scale.max = max;
}
scale.unitsPre = unitsPre;
scale.unitsPost = unitsPost;
scale.point = point;
scale.decimals = decimals;
scale.thousand = thousand;
scale.numlabels = numlabels;
scale.round = Boolean(round);
scale.min = min;
for
(
var
i=0; i<scale.values.length; ++i) {
scale.values[i] = parseFloat(scale.values[i]);
}
return
scale;
};
RG.SVG.arrayFill =
RG.SVG.arrayPad =
function
(opt)
{
var
arr = opt.array,
len = opt.length,
value = (
typeof
opt.value ===
'undefined'
?
null
: opt.value);
if
(arr.length < len) {
for
(
var
i=arr.length; i<len; i+=1) {
arr[i] = value;
}
}
return
arr;
};
RG.SVG.arraySum =
function
(arr)
{
if
(
typeof
arr ===
'number'
) {
return
arr;
}
if
(RG.SVG.isNull(arr)) {
return
0;
}
var
i, sum, len = arr.length;
for
(i=0,sum=0;i<len;sum+=arr[i++]);
return
sum;
};
RG.SVG.arrayMax =
function
(arr)
{
var
max =
null
if
(
typeof
arr === 'number
') {
return arr;
}
if (RG.SVG.isNull(arr)) {
return 0;
}
for (var i=0,len=arr.length; i<len; ++i) {
if (typeof arr[i] === '
number
') {
var val = arguments[1] ? ma.abs(arr[i]) : arr[i];
if (typeof max === '
number
') {
max = ma.max(max, val);
} else {
max = val;
}
}
}
return max;
};
/**
* Returns the minimum numeric value which is in an array
*
* @param array arr The array (can also be a number, in which case it'
s returned
as
-is)
* @param int Whether to ignore signs (ie negative/positive)
* @
return
int The minimum value
in
the array
*/
RG.SVG.arrayMin =
function
(arr)
{
var
max =
null
,
min =
null
,
ma = Math;
if
(
typeof
arr ===
'number'
) {
return
arr;
}
if
(RG.SVG.isNull(arr)) {
return
0;
}
for
(
var
i=0,len=arr.length; i<len; ++i) {
if
(
typeof
arr[i] ===
'number'
) {
var
val = arguments[1] ? ma.abs(arr[i]) : arr[i];
if
(
typeof
min ===
'number'
) {
min = ma.min(min, val);
}
else
{
min = val;
}
}
}
return
min;
};
RG.SVG.arrayPad =
function
(arr, len)
{
if
(arr.length < len) {
var
val = arguments[2] ? arguments[2] :
null
;
for
(
var
i=arr.length; i<len; i+=1) {
arr[i] = val;
}
}
return
arr;
};
RG.SVG.arraySum =
function
(arr)
{
if
(
typeof
arr ===
'number'
) {
return
arr;
}
if
(RG.SVG.isNull(arr)) {
return
0;
}
var
i, sum, len = arr.length;
for
(i=0,sum=0;i<len;sum+=arr[i++]);
return
sum;
};
RG.SVG.arrayLinearize =
function
()
{
var
arr = [],
args = arguments
for
(
var
i=0,len=args.length; i<len; ++i) {
if
(
typeof
args[i] ===
'object'
&& args[i]) {
for
(
var
j=0,len2=args[i].length; j<len2; ++j) {
var
sub = RG.SVG.arrayLinearize(args[i][j]);
for
(
var
k=0,len3=sub.length; k<len3; ++k) {
arr.push(sub[k]);
}
}
}
else
{
arr.push(args[i]);
}
}
return
arr;
};
RG.SVG.arrayShift =
function
(arr)
{
var
ret = [];
for
(
var
i=1,len=arr.length; i<len; ++i) {
ret.push(arr[i]);
}
return
ret;
};
RG.SVG.arrayReverse =
function
(arr)
{
if
(!arr) {
return
;
}
var
newarr=[];
for
(
var
i=arr.length - 1; i>=0; i-=1) {
newarr.push(arr[i]);
}
return
newarr;
};
RG.SVG.arrayClone =
function
(obj)
{
if
(obj ===
null
||
typeof
obj !==
'object'
) {
return
obj;
}
if
(RG.SVG.isArray(obj)) {
var
temp = [];
for
(
var
i=0,len=obj.length;i<len; ++i) {
if
(
typeof
obj[i] ===
'number'
) {
temp[i] = (
function
(arg) {
return
Number(arg);})(obj[i]);
}
else
if
(
typeof
obj[i] ===
'string'
) {
temp[i] = (
function
(arg) {
return
String(arg);})(obj[i]);
}
else
if
(
typeof
obj[i] ===
'function'
) {
temp[i] = obj[i];
}
else
{
temp[i] = RG.SVG.arrayClone(obj[i]);
}
}
}
else
if
(
typeof
obj ===
'object'
) {
var
temp = {};
for
(
var
i
in
obj) {
if
(
typeof
i ===
'string'
) {
temp[i] = obj[i];
}
}
}
return
temp;
};
RG.SVG.arrayInvert =
function
(arr)
{
for
(
var
i=0,len=arr.length; i<len; ++i) {
arr[i] = !arr[i];
}
return
arr;
};
RG.SVG.arrayTrim =
function
(arr)
{
var
out = [], content =
false
;
for
(
var
i=0; i<arr.length; i++) {
if
(arr[i]) {
content =
true
;
}
if
(content) {
out.push(arr[i]);
}
}
out = RG.SVG.arrayReverse(out);
var
out2 = [], content =
false
;
for
(
var
i=0; i<out.length; i++) {
if
(out[i]) {
content =
true
;
}
if
(content) {
out2.push(out[i]);
}
}
out2 = RG.SVG.arrayReverse(out2);
return
out2;
};
RG.SVG.isArray =
function
(obj)
{
if
(obj && obj.constructor) {
var
pos = obj.constructor.toString().indexOf(
'Array'
);
}
else
{
return
false
;
}
return
obj !=
null
&&
typeof
pos ===
'number'
&&
pos > 0 &&
pos < 20;
};
RG.SVG.abs =
function
(value)
{
if
(
typeof
value ===
'string'
) {
value = parseFloat(value) || 0;
}
if
(
typeof
value ===
'number'
) {
return
ma.abs(value);
}
if
(
typeof
value ===
'object'
) {
for
(i
in
value) {
if
(
typeof
i ===
'string'
||
typeof
i ===
'number'
||
typeof
i ===
'object'
) {
value[i] = RG.SVG.abs(value[i]);
}
}
return
value;
}
return
0;
};
RG.SVG.numberFormat =
function
(opt)
{
var
obj = opt.object,
prepend = opt.prepend ? String(opt.prepend) : '
',
append = opt.append ? String(opt.append) : '
',
output = '
',
decimal_seperator = typeof opt.point === '
string
' ? opt.point : '
.
',
thousand_seperator = typeof opt.thousand === '
string
' ? opt.thousand : '
,
',
num = opt.num
decimals_trim = opt.decimals_trim;
RegExp.$1 = '
';
if (typeof opt.formatter === '
function
') {
return opt.formatter(obj, num);
}
// Ignore the preformatted version of "1e-2"
if (String(num).indexOf('
e
') > 0) {
return String(prepend + String(num) + append);
}
// We need then number as a string
num = String(num);
// Take off the decimal part - we re-append it later
if (num.indexOf('
.
') > 0) {
var tmp = num;
num = num.replace(/\.(.*)/, '
'); // The front part of the number
decimal = tmp.replace(/(.*)\.(.*)/, '
$2
'); // The decimal part of the number
} else {
decimal = '
';
}
// Thousand seperator
//var seperator = arguments[1] ? String(arguments[1]) : '
,
';
var seperator = thousand_seperator;
/**
* Work backwards adding the thousand seperators
*/
var foundPoint;
for (i=(num.length - 1),j=0; i>=0; j++,i--) {
var character = num.charAt(i);
if ( j % 3 == 0 && j != 0) {
output += seperator;
}
/**
* Build the output
*/
output += character;
}
/**
* Now need to reverse the string
*/
var rev = output;
output = '
';
for (i=(rev.length - 1); i>=0; i--) {
output += rev.charAt(i);
}
// Tidy up
//output = output.replace(/^-,/, '
-
');
if (output.indexOf('
-
' + thousand_seperator) == 0) {
output = '
-
' + output.substr(('
-
' + thousand_seperator).length);
}
// Reappend the decimal
if (decimal.length) {
output = output + decimal_seperator + decimal;
decimal = '
';
RegExp.$1 = '
';
}
//
// Trim the decimals if it'
s all zeros
if
(decimals_trim) {
output = output.replace(/0+$/,
''
);
output = output.replace(/\.$/,
''
);
}
if
(output.charAt(0) ==
'-'
) {
output = output.replace(/-/,
''
);
prepend =
'-'
+ prepend;
}
return
prepend + output + append;
};
RG.SVG.text =
function
(opt)
{
var
obj = opt.object,
parent = opt.parent || opt.object.svg.all,
size =
typeof
opt.size ===
'number'
? opt.size +
'pt'
: (
typeof
opt.size ===
'string'
? opt.size.replace(/pt$/,
''
) : 12) +
'pt'
,
bold = opt.bold ?
'bold'
:
'normal'
,
font = opt.font ? opt.font :
'sans-serif'
,
italic = opt.italic ?
'italic'
:
'normal'
,
halign = opt.halign,
valign = opt.valign,
str = opt.text,
x = opt.x,
y = opt.y,
color = opt.color ? opt.color :
'black'
,
background = opt.background ||
null
,
backgroundRounded = opt.backgroundRounded || 0,
padding = opt.padding || 0,
link = opt.link ||
''
,
linkTarget = opt.linkTarget ||
'_blank'
,
events = (opt.events ===
false
?
false
:
true
),
angle = opt.angle;
if
(
typeof
str ===
'number'
) {
str = String(str);
}
if
(RG.SVG.isNull(str)) {
str =
''
;
}
if
(str && str.substr(0,2) ==
'\r\n'
|| str.substr(0,1) ===
'\n'
) {
str =
"\u00A0"
+ str;
}
if
(halign ===
'right'
) {
halign =
'end'
;
}
else
if
(halign ===
'center'
|| halign ===
'middle'
) {
halign =
'middle'
;
}
else
{
halign =
'start'
;
}
if
(valign ===
'top'
) {
valign =
'hanging'
;
}
else
if
(valign ===
'center'
|| valign ===
'middle'
) {
valign =
'central'
;
valign =
'middle'
;
}
else
{
valign =
'bottom'
;
}
if
(link) {
var
a = RGraph.SVG.create({
svg: obj.svg,
type:
'a'
,
parent: parent,
attr: {
'xlink:href'
: link,
target: linkTarget
}
});
}
if
(str && str.indexOf && str.indexOf(
"\n"
) === -1) {
var
text = RG.SVG.create({
svg: obj.svg,
parent: link ? a : opt.parent,
type:
'text'
,
attr: {
tag: opt.tag ? opt.tag :
''
,
fill: color,
x: x,
y: y,
'font-size'
: size,
'font-weight'
: bold,
'font-family'
: font,
'font-style'
: italic,
'text-anchor'
: halign,
'dominant-baseline'
: valign
}
});
var
textNode = document.createTextNode(str);
text.appendChild(textNode);
if
(!events) {
text.style.pointerEvents =
'none'
;
}
}
else
if
(str && str.indexOf) {
var
dimensions = RG.SVG.measureText({
text:
'My'
,
bold: bold,
font: font,
size: size
});
var
lineHeight = dimensions[1];
str = str.split(/\r?\n/);
if
(valign ===
'bottom'
) {
y -= str.length * lineHeight;
}
if
(valign ===
'center'
|| valign ===
'middle'
) {
y -= (str.length * lineHeight) / 2;
}
var
text = RG.SVG.create({
svg: obj.svg,
parent: link ? a : opt.parent,
type:
'text'
,
attr: {
tag: opt.tag ? opt.tag :
''
,
fill: color,
x: x,
y: y,
'font-size'
: size,
'font-weight'
: bold,
'font-family'
: font,
'font-style'
: italic,
'text-anchor'
: halign,
'dominant-baseline'
: valign
}
});
if
(!events) {
text.style.pointerEvents =
'none'
;
}
for
(
var
i=0; i<str.length; ++i) {
var
tspan = RG.SVG.create({
svg: obj.svg,
parent: text,
type:
'tspan'
,
attr: {
x: x,
dy: dimensions ? (dimensions[1] * (i ? 1 : 0)) + 3 : 0
}
});
var
textNode = document.createTextNode(str[i]);
tspan.appendChild(textNode);
if
(!events) {
tspan.style.pointerEvents =
'none'
;
}
var
dimensions = RG.SVG.measureText({
text: str[i],
bold: bold,
font: font,
size: parseInt(size)
});
}
}
if
(
typeof
angle ===
'number'
&& angle && text) {
text.setAttribute(
'x'
, 0);
text.setAttribute(
'y'
, 0);
text.setAttribute(
'transform'
,
'translate({1} {2}) rotate({3})'
.format(x, y, -1 * angle));
}
if
(
typeof
background ===
'string'
) {
var
parent = link ? a : parent;
var
bbox = text.getBBox(),
rect = RG.SVG.create({
svg: obj.svg,
parent: parent,
type:
'rect'
,
attr: {
x: bbox.x - padding,
y: bbox.y - padding,
width: bbox.width + (padding * 2),
height: bbox.height + (padding * 2),
fill: background,
rx: backgroundRounded,
ry: backgroundRounded
}
});
if
(!events) {
rect.style.pointerEvents =
'none'
;
}
text.parentNode.insertBefore(rect, text);
}
if
(RG.SVG.ISIE && (valign ===
'hanging'
) && text) {
text.setAttribute(
'y'
, y + (text.scrollHeight / 2));
}
else
if
(RG.SVG.ISIE && valign ===
'middle'
) {
text.setAttribute(
'y'
, y + (text.scrollHeight / 3));
}
if
(RG.SVG.ISFF && text) {
Y = y + (text.scrollHeight / 3);
}
return
text;
};
RG.SVG.text.find =
function
(opt)
{
if
(
typeof
opt.object ===
'object'
&& opt.object.isRGraph) {
var
svg = opt.object.svg;
}
else
if
(
typeof
opt.svg ===
'object'
&& opt.svg.all) {
var
svg = opt.svg;
opt.object = svg.__object__;
}
var
nodes = svg.getElementsByTagName(
'text'
);
var
found = [];
for
(
var
i=0,len=nodes.length; i<len; ++i) {
var
text =
false
,
tag =
false
;
if
(
typeof
opt.text ===
'string'
&& nodes[i].innerHTML === opt.text) {
text =
true
;
}
else
if
(
typeof
opt.text ===
'object'
&& nodes[i].innerHTML.match(opt.text)) {
text =
true
;
}
else
if
(
typeof
opt.text ===
'undefined'
) {
text =
true
;
}
if
(
typeof
opt.tag ===
'string'
&& nodes[i].getAttribute(
'tag'
) === opt.tag) {
tag =
true
;
}
else
if
(
typeof
opt.tag ===
'object'
&& nodes[i].getAttribute(
'tag'
).match(opt.tag)) {
tag =
true
;
}
else
if
(
typeof
opt.tag ===
'undefined'
) {
tag =
true
;
}
if
(text ===
true
&& tag ===
true
) {
found.push(nodes[i])
}
}
if
(
typeof
opt.callback ===
'function'
) {
(opt.callback)({nodes: found,object: opt.object});
}
return
found;
};
RG.SVG.createUID =
function
()
{
return
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
.replace(/[xy]/g,
function
(c)
{
var
r = ma.random()*16|0, v = c ==
'x'
? r : (r&0x3|0x8);
return
v.toString(16);
});
};
RG.SVG.isFixed =
function
(svg)
{
var
obj = svg.parentNode,
i = 0;
while
(obj && obj.tagName.toLowerCase() !=
'body'
&& i < 99) {
if
(obj.style.position ===
'fixed'
) {
return
obj;
}
obj = obj.offsetParent;
}
return
false
;
};
RG.SVG.REG.set =
function
(name, value)
{
RG.SVG.REG.store[name] = value;
return
value;
};
RG.SVG.REG.get =
function
(name)
{
return
RG.SVG.REG.store[name];
};
RG.SVG.trim =
function
(str)
{
return
RG.SVG.ltrim(RG.SVG.rtrim(str));
};
RG.SVG.ltrim =
function
(str)
{
return
str.replace(/^(\s|\0)+/,
''
);
};
RG.SVG.rtrim =
function
(str)
{
return
str.replace(/(\s|\0)+$/,
''
);
};
RG.SVG.hideTooltip =
function
()
{
var
tooltip = RG.SVG.REG.get(
'tooltip'
);
if
(tooltip && tooltip.parentNode
) {
tooltip.parentNode.removeChild(tooltip);
tooltip.style.display =
'none'
;
tooltip.style.visibility =
'hidden'
;
RG.SVG.REG.set(
'tooltip'
,
null
);
}
if
(tooltip && tooltip.__object__) {
RG.SVG.removeHighlight(tooltip.__object__);
}
};
RG.SVG.setShadow =
function
(options)
{
var
obj = options.object,
offsetx = options.offsetx || 0,
offsety = options.offsety || 0,
blur = options.blur || 0,
opacity = options.opacity || 0,
id = options.id;
var
filter = RG.SVG.create({
svg: obj.svg,
parent: obj.svg.defs,
type:
'filter'
,
attr: {
id: id,
width:
"130%"
,
height:
"130%"
}
});
RG.SVG.create({
svg: obj.svg,
parent: filter,
type:
'feOffset'
,
attr: {
result:
'offOut'
,
'in'
:
'SourceGraphic'
,
dx: offsetx,
dy: offsety
}
});
RG.SVG.create({
svg: obj.svg,
parent: filter,
type:
'feColorMatrix'
,
attr: {
result:
'matrixOut'
,
'in'
:
'offOut'
,
type:
'matrix'
,
values:
'0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 {1} 0'
.format(
opacity
)
}
});
RG.SVG.create({
svg: obj.svg,
parent: filter,
type:
'feGaussianBlur'
,
attr: {
result:
'blurOut'
,
'in'
:
'matrixOut'
,
stdDeviation: blur
}
});
RG.SVG.create({
svg: obj.svg,
parent: filter,
type:
'feBlend'
,
attr: {
'in'
:
'SourceGraphic'
,
'in2'
:
'blurOut'
,
mode:
'normal'
}
});
};
RG.SVG.sequentialIndexToGrouped =
function
(index, data)
{
var
group = 0,
grouped_index = 0;
while
(--index >= 0) {
if
(RG.SVG.isNull(data[group])) {
group++;
grouped_index = 0;
continue
;
}
if
(
typeof
data[group] ==
'number'
) {
group++
grouped_index = 0;
continue
;
}
grouped_index++;
if
(grouped_index >= data[group].length) {
group++;
grouped_index = 0;
}
}
return
[group, grouped_index];
};
RG.SVG.groupedIndexToSequential =
function
(opt)
{
var
dataset = opt.dataset,
index = opt.index,
obj = opt.object;
for
(
var
i=0,seq=0; i<=dataset; ++i) {
for
(
var
j=0; j<obj.data[dataset].length; ++j) {
if
(i === dataset && j === index) {
return
seq;
}
seq++;
}
}
return
seq;
};
RG.SVG.arrayLinearize =
function
()
{
var
arr = [],
args = arguments
for
(
var
i=0,len=args.length; i<len; ++i) {
if
(
typeof
args[i] ===
'object'
&& args[i]) {
for
(
var
j=0,len2=args[i].length; j<len2; ++j) {
var
sub = RG.SVG.arrayLinearize(args[i][j]);
for
(
var
k=0,len3=sub.length; k<len3; ++k) {
arr.push(sub[k]);
}
}
}
else
{
arr.push(args[i]);
}
}
return
arr;
};
RG.SVG.TRIG.toCartesian =
function
(options)
{
return
{
x: options.cx + (options.r * ma.cos(options.angle)),
y: options.cy + (options.r * ma.sin(options.angle))
};
};
RG.SVG.TRIG.getHypLength =
function
(opt)
{
var
h = Math.abs(opt.x2 - opt.x1)
v = Math.abs(opt.y2 - opt.y1),
r = Math.sqrt(
(h * h)
+ (v * v)
);
return
r;
};
RG.SVG.TRIG.getAngleByXY =
function
(opt)
{
var
cx = opt.cx,
cy = opt.cy,
x = opt.x,
y = opt.y;
var
angle = ma.atan((y - cy) / (x - cx));
if
(x >= cx && y >= cy) {
angle += RG.SVG.TRIG.HALFPI;
}
else
if
(x >= cx && y < cy) {
angle = angle + RG.SVG.TRIG.HALFPI;
}
else
if
(x < cx && y < cy) {
angle = angle + RG.SVG.TRIG.PI + RG.SVG.TRIG.HALFPI;
}
else
{
angle = angle + RG.SVG.TRIG.PI + RG.SVG.TRIG.HALFPI;
}
return
angle;
};
RG.SVG.TRIG.getArcPath =
function
(options)
{
options.start -= 1.57;
options.end -= 1.57;
var
start = RG.SVG.TRIG.toCartesian({
cx: options.cx,
cy: options.cy,
r: options.r,
angle: options.start}
);
var
end = RG.SVG.TRIG.toCartesian({
cx: options.cx,
cy: options.cy,
r: options.r,
angle: options.end
});
var
diff = options.end - options.start;
var
largeArc =
'0'
;
var
sweep =
'0'
;
if
(options.anticlockwise && diff > 3.14) {
largeArc =
'0'
;
sweep =
'0'
;
}
else
if
(options.anticlockwise && diff <= 3.14) {
largeArc =
'1'
;
sweep =
'0'
;
}
else
if
(!options.anticlockwise && diff > 3.14) {
largeArc =
'1'
;
sweep =
'1'
;
}
else
if
(!options.anticlockwise && diff <= 3.14) {
largeArc =
'0'
;
sweep =
'1'
;
}
if
(options.start > options.end && options.anticlockwise && diff <= 3.14) {
largeArc =
'0'
;
sweep =
'0'
;
}
if
(options.start > options.end && options.anticlockwise && diff > 3.14) {
largeArc =
'1'
;
sweep =
'1'
;
}
if
(
typeof
options.moveto ===
'boolean'
&& options.moveto ===
false
) {
var
d = [
"A"
, options.r, options.r, 0, largeArc, sweep, end.x, end.y
];
}
else
{
var
d = [
"M"
, start.x, start.y,
"A"
, options.r, options.r, 0, largeArc, sweep, end.x, end.y
];
}
if
(options.array ===
true
) {
return
d;
}
else
{
return
d.join(
" "
);
}
};
RG.SVG.TRIG.getArcPath2 =
function
(options)
{
options.start -= 1.57;
options.end -= 1.57;
var
start = RG.SVG.TRIG.toCartesian({
cx: options.cx,
cy: options.cy,
r: options.r,
angle: options.start
});
var
end = RG.SVG.TRIG.toCartesian({
cx: options.cx,
cy: options.cy,
r: options.r,
angle: options.end
});
var
diff = ma.abs(options.end - options.start);
var
largeArc =
'0'
;
var
sweep =
'0'
;
if
(!options.anticlockwise) {
if
(diff > RG.SVG.TRIG.PI) {
largeArc =
'1'
;
sweep =
'1'
;
}
else
{
largeArc =
'0'
;
sweep =
'1'
;
}
}
else
{
if
(diff > RG.SVG.TRIG.PI) {
largeArc =
'1'
;
sweep =
'0'
;
}
else
{
largeArc =
'0'
;
sweep =
'0'
;
}
}
if
(
typeof
options.lineto ===
'boolean'
&& options.lineto ===
false
) {
var
d = [
"M"
, start.x, start.y,
"A"
, options.r, options.r, 0, largeArc, sweep, end.x, end.y
];
}
else
{
var
d = [
"M"
, options.cx, options.cy,
"L"
, start.x, start.y,
"A"
, options.r, options.r, 0, largeArc, sweep, end.x, end.y
];
}
if
(options.array ===
true
) {
return
d;
}
else
{
return
d.join(
" "
);
}
};
RG.SVG.TRIG.getArcPath3 =
function
(options)
{
options.cx = Number(options.cx);
options.cy = Number(options.cy);
options.radius = Number(options.radius);
options.start = Number(options.start);
options.end = Number(options.end);
options.start -= (ma.PI / 2);
options.end -= (ma.PI / 2);
var
start = RG.SVG.TRIG.toCartesian({
cx: options.cx,
cy: options.cy,
r: options.r,
angle: options.start
});
var
end = RG.SVG.TRIG.toCartesian({
cx: options.cx,
cy: options.cy,
r: options.r,
angle: options.end
});
var
diff = ma.abs(options.end - options.start);
var
largeArc =
'0'
;
var
sweep =
'0'
;
if
(!options.anticlockwise) {
if
(diff > RG.SVG.TRIG.PI) {
largeArc =
'1'
;
sweep =
'1'
;
}
else
{
largeArc =
'0'
;
sweep =
'1'
;
}
}
else
{
if
(diff > RG.SVG.TRIG.PI) {
largeArc =
'1'
;
sweep =
'0'
;
}
else
{
largeArc =
'0'
;
sweep =
'0'
;
}
}
if
(
typeof
options.lineto ===
'boolean'
&& options.lineto ===
false
) {
var
d = [
"M"
, start.x, start.y,
"A"
, options.r, options.r, 0, largeArc, sweep, end.x, end.y
];
}
else
{
var
d = [
"L"
, start.x, start.y,
"A"
, options.r, options.r, 0, largeArc, sweep, end.x, end.y
];
}
if
(options.array ===
true
) {
return
d;
}
else
{
return
d.join(
" "
);
}
};
RG.SVG.TRIG.getRadiusEndPoint =
function
(opt)
{
if
(arguments.length === 1) {
var
angle = opt.angle,
r = opt.r;
}
else
if
(arguments.length === 4) {
var
angle = arguments[0],
r = arguments[1];
}
var
x = ma.cos(angle) * r,
y = ma.sin(angle) * r;
return
[x, y];
};
RG.SVG.drawTitle =
function
(obj)
{
var
prop = obj.properties;
var
x = ((obj.width - prop.marginLeft - prop.marginRight) / 2) + prop.marginLeft,
y = prop.marginTop - 10,
valign =
'bottom'
;
if
(!RG.SVG.isNull(obj.properties.key)) {
y -= 20;
}
if
(
typeof
obj.properties.yaxisScaleMax ===
'number'
&& obj.properties.yaxisScaleMax <= 0
&& obj.properties.yaxisScaleMin < obj.properties.yaxisScaleMax
) {
valign =
'top'
;
y = obj.height - obj.properties.marginBottom + 10;
}
if
(
typeof
prop.titleX ===
'number'
) {
x = prop.titleX;
}
if
(
typeof
prop.titleY ===
'number'
) {
y = prop.titleY;
}
if
(
typeof
prop.titleOffsetx ===
'number'
) {
x += prop.titleOffsetx;
}
if
(
typeof
prop.titleOffsety ===
'number'
) {
y += prop.titleOffsety;
}
if
(
typeof
prop.titleSubtitle ===
'string'
||
typeof
prop.titleSubtitle ===
'number'
) {
var
titleSubtitleDim = RG.SVG.measureText({
bold: prop.titleSubtitleBold,
italic: prop.titleSubtitleItalic,
size: prop.titleSubtitleSize,
font: prop.titleSubtitleFont,
text:
'Mg'
});
y -= titleSubtitleDim[1];
}
if
(prop.title) {
RG.SVG.text({
object: obj,
svg: obj.svg,
parent: obj.svg.all,
tag:
'title'
,
text: prop.title.toString(),
x: x,
y: y,
halign: prop.titleHalign ||
'center'
,
valign: valign,
color: prop.titleColor || prop.textColor,
size:
typeof
prop.titleSize ===
'number'
? prop.titleSize : prop.textSize + 4,
bold:
typeof
prop.titleBold ===
'boolean'
? prop.titleBold : prop.textBold,
italic:
typeof
prop.titleItalic ===
'boolean'
? prop.titleItalic : prop.textItalic,
font: prop.titleFont || prop.textFont
});
}
if
(
(
typeof
prop.title === 'string
' || typeof prop.title === '
number
')
&& (typeof prop.titleSubtitle === '
string
' || typeof prop.titleSubtitle === '
number
')
) {
RG.SVG.text({
object: obj,
svg: obj.svg,
parent: obj.svg.all,
tag: '
subtitle
',
text: prop.titleSubtitle,
x: x,
y: y + 5,
halign: prop.titleHalign || '
center
',
valign: '
top
',
size: typeof prop.titleSubtitleSize === '
number
' ? prop.titleSubtitleSize : prop.textSize - 2,
color: prop.titleSubtitleColor || prop.textColor,
bold: typeof prop.titleSubtitleBold === '
boolean
' ? prop.titleSubtitleBold : prop.textBold,
italic: typeof prop.titleSubtitleItalic === '
boolean
' ? prop.titleSubtitleItalic : prop.textItalic,
font: prop.titleSubtitleFont || prop.textFont
});
}
};
/**
* Removes white-space from the start and end of a string
*
* @param string str The string to trim
*/
RG.SVG.trim = function (str)
{
return RG.SVG.ltrim(RG.SVG.rtrim(str));
};
/**
* Trims the white-space from the start of a string
*
* @param string str The string to trim
*/
RG.SVG.ltrim = function (str)
{
return String(str).replace(/^(\s|\0)+/, '
');
};
/**
* Trims the white-space off of the end of a string
*
* @param string str The string to trim
*/
RG.SVG.rtrim = function (str)
{
return String(str).replace(/(\s|\0)+$/, '
');
};
/**
* This parses a single color value
*/
RG.SVG.parseColorLinear = function (opt)
{
var obj = opt.object,
color = opt.color;
if (!color || typeof color !== '
string
') {
return color;
}
if (color.match(/^gradient\((.*)\)$/i)) {
var parts = RegExp.$1.split('
:
'),
diff = 1 / (parts.length - 1);
if (opt && opt.direction && opt.direction === '
horizontal
') {
var grad = RG.SVG.create({
type: '
linearGradient
',
parent: obj.svg.defs,
attr: {
id: '
RGraph-linear-gradient-
' + obj.uid + '
-
' + obj.gradientCounter,
x1: opt.start || 0,
x2: opt.end || '
100%
',
y1: 0,
y2: 0,
gradientUnits: opt.gradientUnits || "userSpaceOnUse"
}
});
} else {
var grad = RG.SVG.create({
type: '
linearGradient
',
parent: obj.svg.defs,
attr: {
id: '
RGraph-linear-gradient-
' + obj.uid + '
-
' + obj.gradientCounter,
x1: 0,
x2: 0,
y1: opt.start || 0,
y2: opt.end || '
100%
',
gradientUnits: opt.gradientUnits || "userSpaceOnUse"
}
});
}
// Add the first color stop
var stop = RG.SVG.create({
type: '
stop
',
parent: grad,
attr: {
offset: '
0%
',
'
stop-color
': RG.SVG.trim(parts[0])
}
});
// Add the rest of the color stops
for (var j=1,len=parts.length; j<len; ++j) {
RG.SVG.create({
type: '
stop
',
parent: grad,
attr: {
offset: (j * diff * 100) + '
%
',
'
stop-color
': RG.SVG.trim(parts[j])
}
});
}
}
color = grad ? '
url(
#RGraph-linear-gradient-' + obj.uid + '-' + (obj.gradientCounter++) + ')' : color;
return
color;
};
RG.SVG.parseColorRadial =
function
(opt)
{
var
obj = opt.object,
color = opt.color;
if
(!color ||
typeof
color !== 'string
') {
return color;
}
if (color.match(/^gradient\((.*)\)$/i)) {
var parts = RegExp.$1.split('
:
'),
diff = 1 / (parts.length - 1);
var grad = RG.SVG.create({
type: '
radialGradient
',
parent: obj.svg.defs,
attr: {
id: '
RGraph-radial-gradient-
' + obj.uid + '
-
' + obj.gradientCounter,
gradientUnits: opt.gradientUnits || '
userSpaceOnUse
',
cx: opt.cx || obj.centerx,
cy: opt.cy || obj.centery,
fx: opt.fx || obj.centerx,
fy: opt.fy || obj.centery,
r: opt.r || obj.radius
}
});
// Add the first color stop
var stop = RG.SVG.create({
type: '
stop
',
parent: grad,
attr: {
offset: '
0%
',
'
stop-color
': RG.SVG.trim(parts[0])
}
});
// Add the rest of the color stops
for (var j=1,len=parts.length; j<len; ++j) {
RG.SVG.create({
type: '
stop
',
parent: grad,
attr: {
offset: (j * diff * 100) + '
%
',
'
stop-color
': RG.SVG.trim(parts[j])
}
});
}
}
color = grad ? '
url(
#RGraph-radial-gradient-' + obj.uid + '-' + (obj.gradientCounter++) + ')' : color;
return
color;
};
RG.SVG.resetColorsToOriginalValues =
function
(opt)
{
var
obj = opt.object;
if
(obj.originalColors) {
for
(
var
j
in
obj.originalColors) {
if
(
typeof
j === 'string
') {
obj.properties[j] = RG.SVG.arrayClone(obj.originalColors[j]);
}
}
}
/**
* If the function is present on the object to reset specific
* colors - use that
*/
if (typeof obj.resetColorsToOriginalValues === '
function
') {
obj.resetColorsToOriginalValues();
}
// Hmmm... Should this be necessary? I don'
t think it will
obj.originalColors = {};
obj.colorsParsed =
false
;
obj.gradientCounter = 1;
};
RG.SVG.clear =
function
(svg)
{
for
(
var
i=1; i<=100; ++i) {
if
(svg['background
' + i]) {
// Clear all the nodes within this group
while (svg['
background
' + i].lastChild) {
svg['
background
' + i].removeChild(svg['
background
' + i].lastChild);
}
} else {
break;
}
}
// Clear all the node within the "all" group
while (svg.all.lastChild) {
svg.all.removeChild(svg.all.lastChild);
}
// Clear Line chart hotspots
if (svg.all.line_tooltip_hotspots) {
while (svg.all.line_tooltip_hotspots.lastChild) {
svg.all.line_tooltip_hotspots.removeChild(svg.all.line_tooltip_hotspots.lastChild);
}
}
};
/**
* Adds an event listener
*
* @param object obj The graph object
* @param string event The name of the event, eg ontooltip
* @param object func The callback function
*/
RG.SVG.addCustomEventListener = function (obj, name, func)
{
// Initialise the events array if necessary
if (typeof RG.SVG.events[obj.uid] === '
undefined
') {
RG.SVG.events[obj.uid] = [];
}
// Prepend "on" if necessary
if (name.substr(0, 2) !== '
on
') {
name = '
on
' + name;
}
RG.SVG.events[obj.uid].push({
object: obj,
event: name,
func: func
});
return RG.SVG.events[obj.uid].length - 1;
};
/**
* Used to fire one of the RGraph custom events
*
* @param object obj The graph object that fires the event
* @param string event The name of the event to fire
*/
RG.SVG.fireCustomEvent = function (obj, name)
{
if (obj && obj.isRGraph) {
var uid = obj.uid;
if ( typeof uid === '
string
'
&& typeof RG.SVG.events === '
object
'
&& typeof RG.SVG.events[uid] === '
object
'
&& RG.SVG.events[uid].length > 0) {
for(var j=0,len=RG.SVG.events[uid].length; j<len; ++j) {
if (RG.SVG.events[uid][j] && RG.SVG.events[uid][j].event === name) {
RG.SVG.events[uid][j].func(obj);
}
}
}
}
};
/**
* Clears all the custom event listeners that have been registered
*
* @param string optional Limits the clearing to this object UID
*/
RG.SVG.removeAllCustomEventListeners = function ()
{
var uid = arguments[0];
if (uid && RG.SVG.events[uid]) {
RG.SVG.events[uid] = {};
} else {
RG.SVG.events = [];
}
};
/**
* Clears a particular custom event listener
*
* @param object obj The graph object
* @param number i This is the index that is return by .addCustomEventListener()
*/
RG.SVG.removeCustomEventListener = function (obj, i)
{
if ( typeof RG.SVG.events === '
object
'
&& typeof RG.SVG.events[obj.uid] === '
object
'
&& typeof RG.SVG.events[obj.uid][i] === '
object
') {
RG.SVG.events[obj.uid][i] = null;
}
};
//
// Removes the highlight from the chart added by tooltips (possibly others too)
//
RG.SVG.removeHighlight = function (obj)
{
var highlight = RG.SVG.REG.get('
highlight
');
if (highlight && RG.SVG.isArray(highlight) && highlight.length) {
for (var i=0,len=highlight.length; i<len; ++i) {
if (highlight[i].parentNode) {
//obj.svg.removeChild(highlight[i]);
highlight[i].parentNode.removeChild(highlight[i]);
}
}
} else if (highlight && highlight.parentNode) {
if (obj.type === '
scatter
') {
highlight.setAttribute('
fill
', '
transparent
');
} else {
highlight.parentNode.removeChild(highlight);
}
}
};
//
// Removes the highlight from the chart added by tooltips (possibly others too)
//
RG.SVG.redraw = function ()
{
if (arguments.length === 1) {
var svg = arguments[0];
RG.SVG.clear(svg);
var objects = RG.SVG.OR.get('
id:
' + svg.parentNode.id);
for (var i=0,len=objects.length; i<len; ++i) {
// Reset the colors to the original values
RG.SVG.resetColorsToOriginalValues({object: objects[i]});
objects[i].draw();
}
} else {
var tags = RG.SVG.OR.tags();
for (var i in tags) {
RG.SVG.redraw(tags[i]);
}
}
};
//
// A better, more flexible, date parsing function
//
//@param string str The string to parse
//@return number A number, as returned by Date.parse()
//
RG.SVG.parseDate = function (str)
{
var d = new Date();
// Initialise the default values
var defaults = {
seconds: '
00
',
minutes: '
00
',
hours: '
00
',
date: d.getDate(),
month: d.getMonth() + 1,
year: d.getFullYear()
};
// Create the months array for turning textual months back to numbers
var months = ['
january
','
february
','
march
','
april
','
may
','
june
','
july
','
august
','
september
','
october
','
november
','
december
'],
months_regex = months.join('
|
');
for (var i=0; i<months.length; ++i) {
months[months[i]] = i;
months[months[i].substring(0,3)] = i;
months_regex = months_regex + '
|
' + months[i].substring(0,3);
}
// These are the seperators allowable for d/m/y and y/m/d dates
// (Its part of a regexp so the position of the square brackets
// is crucial)
var sep = '
[-./_=+~
#:;,]+';
var
tokens = str.split(/ +/);
for
(
var
i=0,len=tokens.length; i<len; ++i) {
if
(tokens[i]) {
if
(tokens[i].match(/^\d\d\d\d$/)) {
defaults.year = tokens[i];
}
var
res = isMonth(tokens[i]);
if
(
typeof
res === 'number
') {
defaults.month = res + 1; // Months are zero indexed
}
// Date
if (tokens[i].match(/^\d?\d(?:st|nd|rd|th)?$/)) {
defaults.date = parseInt(tokens[i]);
}
// Time
if (tokens[i].match(/^(\d\d):(\d\d):?(?:(\d\d))?$/)) {
defaults.hours = parseInt(RegExp.$1);
defaults.minutes = parseInt(RegExp.$2);
if (RegExp.$3) {
defaults.seconds = parseInt(RegExp.$3);
}
}
// Dateformat: XXXX-XX-XX
if (tokens[i].match(new RegExp('
^(\\d\\d\\d\\d)
' + sep + '
(\\d\\d)
' + sep + '
(\\d\\d)$
', '
i
'))) {
defaults.date = parseInt(RegExp.$3);
defaults.month = parseInt(RegExp.$2);
defaults.year = parseInt(RegExp.$1);
}
// Dateformat: XX-XX-XXXX
if (tokens[i].match(new RegExp('
^(\\d\\d)
' + sep + '
(\\d\\d)
' + sep + '
(\\d\\d\\d\\d)$
','
i
') )) {
defaults.date = parseInt(RegExp.$1);
defaults.month = parseInt(RegExp.$2);
defaults.year = parseInt(RegExp.$3);
}
}
}
// Now put the defaults into a format thats recognised by Date.parse()
str = '
{1}/{2}/{3} {4}:{5}:{6}
'.format(
defaults.year,
String(defaults.month).length === 1 ? '
0
' + (defaults.month) : defaults.month,
String(defaults.date).length === 1 ? '
0
' + (defaults.date) : defaults.date,
String(defaults.hours).length === 1 ? '
0
' + (defaults.hours) : defaults.hours,
String(defaults.minutes).length === 1 ? '
0
' + (defaults.minutes) : defaults.minutes,
String(defaults.seconds).length === 1 ? '
0
' + (defaults.seconds) : defaults.seconds
);
return Date.parse(str);
//
// Support functions
//
function isMonth(str)
{
var res = str.toLowerCase().match(months_regex);
return res ? months[res[0]] : false;
}
};
// The ObjectRegistry add function
RG.SVG.OR.add = function (obj)
{
RG.SVG.OR.objects.push(obj);
return obj;
};
// The ObjectRegistry function that returns all of the objects. Th argument
// can aither be:
//
// o omitted All of the registered objects are returned
// o id:XXX All of the objects on that SVG tag are returned
// o type:XXX All the objects of that type are returned
//
RG.SVG.OR.get = function ()
{
// Fetch objects that are on a particular SVG tag
if (typeof arguments[0] === '
string
' && arguments[0].substr(0, 3).toLowerCase() === '
id:
') {
var ret = [];
for (var i=0; i<RG.SVG.OR.objects.length; ++i) {
if (RG.SVG.OR.objects[i].id === arguments[0].substr(3)) {
ret.push(RG.SVG.OR.objects[i]);
}
}
return ret;
}
// Fetch objects that are of a particular type
//
// TODO Allow multiple types to be specified
if (typeof arguments[0] === '
string
' && arguments[0].substr(0, 4).toLowerCase() === '
type
') {
var ret = [];
for (var i=0; i<RG.SVG.OR.objects.length; ++i) {
if (RG.SVG.OR.objects[i].type === arguments[0].substr(5)) {
ret.push(RG.SVG.OR.objects[i]);
}
}
return ret;
}
// Fetch an object that has a specific UID
if (typeof arguments[0] === '
string
' && arguments[0].substr(0, 3).toLowerCase() === '
uid
') {
var ret = [];
for (var i=0; i<RG.SVG.OR.objects.length; ++i) {
if (RG.SVG.OR.objects[i].uid === arguments[0].substr(4)) {
ret.push(RG.SVG.OR.objects[i]);
}
}
return ret;
}
return RG.SVG.OR.objects;
};
// The ObjectRegistry function that returns all of the registeredt SVG tags
//
RG.SVG.OR.tags = function ()
{
var tags = [];
for (var i=0; i<RG.SVG.OR.objects.length; ++i) {
if (!tags[RG.SVG.OR.objects[i].svg.parentNode.id]) {
tags[RG.SVG.OR.objects[i].svg.parentNode.id] = RG.SVG.OR.objects[i].svg;
}
}
return tags;
};
//
// This function returns a two element array of the SVG x/y position in
// relation to the page
//
// @param object svg
//
RG.SVG.getSVGXY = function (svg)
{
var x = 0,
y = 0,
el = svg.parentNode; // !!!
do {
x += el.offsetLeft;
y += el.offsetTop;
// Account for tables in webkit
if (el.tagName.toLowerCase() == '
table
' && (RG.SVG.ISCHROME || RG.SVG.ISSAFARI)) {
x += parseInt(el.border) || 0;
y += parseInt(el.border) || 0;
}
el = el.offsetParent;
} while (el && el.tagName && el.tagName.toLowerCase() != '
body
');
var paddingLeft = svg.style.paddingLeft ? parseInt(svg.style.paddingLeft) : 0,
paddingTop = svg.style.paddingTop ? parseInt(svg.style.paddingTop) : 0,
borderLeft = svg.style.borderLeftWidth ? parseInt(svg.style.borderLeftWidth) : 0,
borderTop = svg.style.borderTopWidth ? parseInt(svg.style.borderTopWidth) : 0;
if (navigator.userAgent.indexOf('
Firefox
') > 0) {
x += parseInt(document.body.style.borderLeftWidth) || 0;
y += parseInt(document.body.style.borderTopWidth) || 0;
}
return [x + paddingLeft + borderLeft, y + paddingTop + borderTop];
};
//
// This function is a compatibility wrapper around
// the requestAnimationFrame function.
//
// @param function func The function to give to the
// requestAnimationFrame function
//
RG.SVG.FX.update = function (func)
{
win.requestAnimationFrame =
win.requestAnimationFrame ||
win.webkitRequestAnimationFrame ||
win.msRequestAnimationFrame ||
win.mozRequestAnimationFrame ||
(function (func){setTimeout(func, 16.666);});
win.requestAnimationFrame(func);
};
/**
* This function returns an easing multiplier for effects so they eas out towards the
* end of the effect.
*
* @param number frames The total number of frames
* @param number frame The frame number
*/
RG.SVG.FX.getEasingMultiplier = function (frames, frame)
{
var multiplier = ma.pow(ma.sin((frame / frames) * RG.SVG.TRIG.HALFPI), 3);
return multiplier;
};
/**
* Measures text by creating a DIV in the document and adding the relevant
* text to it, then checking the .offsetWidth and .offsetHeight.
*
* @param object opt An object containing the following:
* o text( string) The text to measure
* o bold (bool) Whether the text is bold or not
* o font (string) The font to use
* o size (number) The size of the text (in pts)
*
* @return array A two element array of the width and height of the text
*/
RG.SVG.measureText = function (opt)
{
//text, bold, font, size
var text = opt.text || '
',
bold = opt.bold || false,
italic = opt.italic || false,
font = opt.font || '
sans-serif
',
size = opt.size || 12,
str = text + '
:
' + italic + '
:
' + bold + '
:
' + font + '
:
' + size;
// Add the sizes to the cache as adding DOM elements is costly and causes slow downs
if (typeof RG.SVG.measuretext_cache === '
undefined
') {
RG.SVG.measuretext_cache = [];
}
if (typeof RG.SVG.measuretext_cache == '
object
' && RG.SVG.measuretext_cache[str]) {
return RG.SVG.measuretext_cache[str];
}
if (!RG.SVG.measuretext_cache['
text-span
']) {
var span = document.createElement('
SPAN
');
span.style.position = '
absolute
';
span.style.padding = 0;
span.style.display = '
inline
';
span.style.top = '
-200px
';
span.style.left = '
-200px
';
span.style.lineHeight = '
1em
';
document.body.appendChild(span);
// Now store the newly created DIV
RG.SVG.measuretext_cache['
text-span
'] = span;
} else if (RG.SVG.measuretext_cache['
text-span
']) {
var span = RG.SVG.measuretext_cache['
text-span
'];
}
span.innerHTML = text.replace(/\r?\n/g, '
<br />
');
span.style.fontFamily = font;
span.style.fontWeight = bold ? '
bold
' : '
normal
';
span.style.fontStyle = italic ? '
italic
' : '
normal
';
span.style.fontSize = String(size).replace(/pt$/, '
') + '
pt
';
var sizes = [span.offsetWidth, span.offsetHeight];
//document.body.removeChild(span);
RG.SVG.measuretext_cache[str] = sizes;
return sizes;
};
/**
* This function converts an array of strings to an array of numbers. Its used by the meter/gauge
* style charts so that if you want you can pass in a string. It supports various formats:
*
* '
45.2
'
* '
-45.2
'
* ['
45.2
']
* ['
-45.2
']
* '
45.2,45.2,45.2
' // A CSV style string
*
* @param number frames The string or array to parse
*/
RG.SVG.stringsToNumbers = function (str)
{
// An optional seperator to use intead of a comma
var sep = arguments[1] || '
,
';
// If it'
s already a number just
return
it
if
(
typeof
str ===
'number'
) {
return
str;
}
if
(
typeof
str ===
'string'
) {
if
(str.indexOf(sep) != -1) {
str = str.split(sep);
}
else
{
str = parseFloat(str);
}
}
if
(
typeof
str ===
'object'
) {
for
(
var
i=0,len=str.length; i<len; i+=1) {
str[i] = parseFloat(str[i]);
}
}
return
str;
};
RG.SVG.getAdjustedNumber =
function
(opt)
{
var
value = opt.value,
prop = opt.prop;
if
(
typeof
prop ===
'string'
&& match(/^(\+|-)([0-9.]+)/)) {
if
(RegExp.$1 ===
'+'
) {
value += parseFloat(RegExp.$2);
}
else
if
(RegExp.$1 ===
'-'
) {
value -= parseFloat(RegExp.$2);
}
}
return
value;
};
RG.SVG.attribution=
function
(){
return
;};
RG.SVG.parseGradient =
function
(str)
{
};
RG.SVG.random =
function
(opt)
{
var
min = opt.min,
max = opt.max,
dp = opt.dp || opt.decimals || 0,
r = ma.random();
return
Number((((max - min) * r) + min).toFixed(dp));
};
RG.SVG.arrayRand =
RG.SVG.arrayRandom =
RG.SVG.random.array =
function
(opt)
{
var
num = opt.num,
min = opt.min,
max = opt.max,
dp = opt.dp || opt.decimals || 0;
for
(
var
i=0,arr=[]; i<num; i+=1) {
arr.push(RG.SVG.random({min: min, max: max, dp: dp}));
}
return
arr;
};
RG.SVG.commonSetter =
function
(opt)
{
var
obj = opt.object,
name = opt.name,
value = opt.value;
if
(name === 'tooltipsEvent
'&& value !== '
click
' && value !== '
mousemove
') {
value = '
click
';
}
return {
name: name,
value: value
};
};
//
// Generates logs for... log charts
//
// @param object opt The options:
// o num The number
// o base The base
//
RG.SVG.log = function (opt)
{
var num = opt.num,
base = opt.base;
return ma.log(num) / (base ? ma.log(base) : 1);
};
RG.SVG.donut = function (opt)
{
var arcPath1 = RG.SVG.TRIG.getArcPath3({
cx: opt.cx,
cy: opt.cy,
r: opt.outerRadius,
start: 0,
end: RG.SVG.TRIG.TWOPI,
anticlockwise: false,
lineto: false
});
var arcPath2 = RG.SVG.TRIG.getArcPath3({
cx: opt.cx,
cy: opt.cy,
r: opt.innerRadius,
start: RG.SVG.TRIG.TWOPI,
end: 0,
anticlockwise: true,
lineto: false
});
//
// Create the red circle
//
var path = RG.SVG.create({
svg: opt.svg,
type: '
path
',
attr: {
d: arcPath1 + arcPath2,
stroke: opt.stroke,
fill: opt.fill
}
});
return path;
};
//
// Copy the globals (if any have been set) from the global object to
// this instances configuration
//
RG.SVG.getGlobals = function (obj)
{
var prop = obj.properties;
for (i in RG.SVG.GLOBALS) {
if (typeof i === '
string
') {
obj.set(i, RG.SVG.arrayClone(RG.SVG.GLOBALS[i]));
}
}
};
//
// This function adds a link to the SVG document
//
// @param object opt The various options to the function
//
RG.SVG.link = function (opt)
{
var a = RGraph.SVG.create({
svg: bar.svg,
type: '
a
',
parent: bar.svg.all,
attr: {
'
xlink:href
': href,
target: target
}
});
var text = RGraph.SVG.create({
svg: bar.svg,
type: '
text
',
parent: a,
attr: {
x: x,
y: y,
fill: fill
}
});
text.innerHTML = text;
};
// This function is used to get the errorbar MAXIMUM value. Its in the common
// file because it'
s used by multiple chart libraries
RG.SVG.getErrorbarsMaxValue =
function
(opt)
{
var
obj = opt.object,
prop = obj.properties,
index = opt.index;
if
(
typeof
prop.errorbars ===
'object'
&& !RG.SVG.isNull(prop.errorbars) &&
typeof
prop.errorbars[index] ===
'number'
) {
var
value = prop.errorbars[index];
}
else
if
(
typeof
prop.errorbars ===
'object'
&& !RG.SVG.isNull(prop.errorbars)
&&
typeof
prop.errorbars[index] ===
'object'
&& !RG.SVG.isNull(prop.errorbars[index])
&&
typeof
prop.errorbars[index].max ===
'number'
) {
var
value = prop.errorbars[index].max;
}
else
{
var
value = 0;
}
return
value;
};
RG.SVG.getErrorbarsMinValue =
function
(opt)
{
var
obj = opt.object,
prop = obj.properties,
index = opt.index;
if
(
typeof
prop.errorbars === 'object
'
&& !RG.SVG.isNull(prop.errorbars)
&& typeof prop.errorbars[index] === '
object
'
&& !RG.SVG.isNull(prop.errorbars[index])
&& typeof prop.errorbars[index].min === '
number
'
) {
var value = prop.errorbars[index].min;
} else {
var value = null;
}
return value;
};
// This function is used to get the errorbar color. Its in the common
// file because it'
s used by multiple chart libraries
RG.SVG.getErrorbarsColor =
function
(opt)
{
var
obj = opt.object,
prop = obj.properties,
index = opt.index;
var
color = prop.errorbarsColor ||
'black'
;
if
(
typeof
prop.errorbars ===
'object'
&& !RG.SVG.isNull(prop.errorbars) &&
typeof
prop.errorbars[index] ===
'object'
&& !RG.SVG.isNull(prop.errorbars[index]) &&
typeof
prop.errorbars[index].color ===
'string'
) {
color = prop.errorbars[index].color;
}
return
color;
};
RG.SVG.getErrorbarsLinewidth =
function
(opt)
{
var
obj = opt.object,
prop = obj.properties,
index = opt.index;
var
linewidth = prop.errorbarsLinewidth || 1
if
(
typeof
prop.errorbars === 'object
' && !RG.SVG.isNull(prop.errorbars) && typeof prop.errorbars[index] === '
object
' && !RG.SVG.isNull(prop.errorbars[index]) && typeof prop.errorbars[index].linewidth === '
number
') {
linewidth = prop.errorbars[index].linewidth;
}
return linewidth;
};
// This function is used to get the errorbar capWidth. Its in the common
// file because it'
s used by multiple chart libraries
RG.SVG.getErrorbarsCapWidth =
function
(opt)
{
var
obj = opt.object,
prop = obj.properties,
index = opt.index;
var
capwidth = prop.errorbarsCapwidth || 10
if
(
typeof
prop.errorbars ===
'object'
&& !RG.SVG.isNull(prop.errorbars)
&&
typeof
prop.errorbars[index] ===
'object'
&& !RG.SVG.isNull(prop.errorbars[index])
&&
typeof
prop.errorbars[index].capwidth ===
'number'
) {
capwidth = prop.errorbars[index].capwidth;
}
return
capwidth;
};
RG.SVG.propertyNameAlias =
function
(opt)
{
var
obj = opt.object;
if
(
typeof
obj.propertyNameAliases[opt.name] ===
'string'
) {
return
{
name: obj.propertyNameAliases[opt.name],
value: opt.value
};
}
else
if
(
typeof
obj.propertyNameAliases[opt.name] ===
'function'
) {
var
tmp = (obj.propertyNameAliases[opt.name])(opt);
return
{
name: tmp.name,
value: tmp.value
};
}
return
{
name: opt.name,
value: opt.value
};
};
if
(
typeof
RG.SVG.tooltip !==
'function'
) {
RG.SVG.tooltip =
function
()
{
$a(
'The tooltip library has not been included!'
);
};
}
})(window, document);
window.$p =
function
(obj)
{
var
indent = (arguments[2] ? arguments[2] :
' '
);
var
str =
''
;
var
counter =
typeof
arguments[3] ==
'number'
? arguments[3] : 0;
if
(counter >= 5) {
return
''
;
}
switch
(
typeof
obj) {
case
'string'
: str += obj +
' ('
+ (
typeof
obj) +
', '
+ obj.length +
')'
;
break
;
case
'number'
: str += obj +
' ('
+ (
typeof
obj) +
')'
;
break
;
case
'boolean'
: str += obj +
' ('
+ (
typeof
obj) +
')'
;
break
;
case
'function'
: str +=
'function () {}'
;
break
;
case
'undefined'
: str +=
'undefined'
;
break
;
case
'null'
: str +=
'null'
;
break
;
case
'object'
:
if
(RGraph.SVG.isNull(obj)) {
str += indent +
'null\n'
;
}
else
{
str += indent +
'Object {'
+
'\n'
for
(j
in
obj) {
str += indent +
' '
+ j +
' => '
+ window.$p(obj[j],
true
, indent +
' '
, counter + 1) +
'\n'
;
}
str += indent +
'}'
;
}
break
;
default
:
str +=
'Unknown type: '
+
typeof
obj +
''
;
break
;
}
if
(!arguments[1]) {
alert(str);
}
return
str;
};
window.$a =
function
(v)
{
alert(v);
};
window.$cl =
function
(v)
{
return
console.log(v);
};
if
(!String.prototype.format) {
String.prototype.format =
function
()
{
var
args = arguments;
return
this
.replace(/{(\d+)}/g,
function
(str, idx)
{
return
typeof
args[idx - 1] !==
'undefined'
? args[idx - 1] : str;
});
};
}