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.Bar =
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.data = conf.data;
this.type = '
bar
';
this.coords = [];
this.coords2 = [];
this.stackedBackfaces = [];
this.originalColors = {};
this.gradientCounter = 1;
// Add this object to the ObjectRegistry
RG.SVG.OR.add(this);
this.container.style.display = '
inline-block
';
this.properties =
{
gutterLeft: 35,
gutterRight: 35,
gutterTop: 35,
gutterBottom: 35,
variant: null,
variant3dOffsetx: 10,
variant3dOffsety: 5,
backgroundColor: null,
backgroundImage: null,
backgroundImageAspect: '
none
',
backgroundImageStretch: true,
backgroundImageOpacity: null,
backgroundImageX: null,
backgroundImageY: null,
backgroundImageW: null,
backgroundImageH: null,
backgroundGrid: true,
backgroundGridColor: '
#ddd',
backgroundGridLinewidth: 1,
backgroundGridHlines:
true
,
backgroundGridHlinesCount:
null
,
backgroundGridVlines:
true
,
backgroundGridVlinesCount:
null
,
backgroundGridBorder:
true
,
backgroundGridDashed:
false
,
backgroundGridDotted:
false
,
backgroundGridDashArray:
null
,
colors: [
'red
', '
#0f0', '#00f', '#ff0', '#0ff', '#0f0','pink','orange','gray','black',
'red
', '
#0f0', '#00f', '#ff0', '#0ff', '#0f0','pink','orange','gray','black'
],
colorsSequential:
false
,
strokestyle: 'rgba(0,0,0,0)
',
errorbars: null,
hmargin: 3,
hmarginGrouped: 2,
yaxis: true,
yaxisTickmarks: true,
yaxisTickmarksLength: 3,
yaxisColor: '
black
',
yaxisScale: true,
yaxisLabels: null,
yaxisLabelsOffsetx: 0,
yaxisLabelsOffsety: 0,
yaxisLabelsCount: 5,
yaxisUnitsPre: '
',
yaxisUnitsPost: '
',
yaxisStrict: false,
yaxisDecimals: 0,
yaxisPoint: '
.
',
yaxisThousand: '
,
',
yaxisRound: false,
yaxisMax: null,
yaxisMin: 0,
yaxisFormatter: null,
xaxis: true,
xaxisTickmarks: true,
xaxisTickmarksLength: 5,
xaxisLabels: null,
xaxisLabelsPosition: '
section
',
xaxisLabelsPositionSectionTickmarksCount: null,
xaxisColor: '
black
',
xaxisLabelsOffsetx: 0,
xaxisLabelsOffsety: 0,
labelsAbove: false,
labelsAboveFont: null,
labelsAboveSize: null,
labelsAboveBold: null,
labelsAboveItalic: null,
labelsAboveColor: null,
labelsAboveBackground: null,
labelsAboveBackgroundPadding: 0,
labelsAboveUnitsPre: null,
labelsAboveUnitsPost: null,
labelsAbovePoint: null,
labelsAboveThousand: null,
labelsAboveFormatter: null,
labelsAboveDecimals: null,
labelsAboveOffsetx: 0,
labelsAboveOffsety: 0,
labelsAboveHalign: '
center
',
labelsAboveValign: '
bottom
',
labelsAboveSpecific: null,
textColor: '
black
',
textFont: '
sans-serif
',
textSize: 12,
textBold: false,
textItalic: false,
linewidth: 1,
grouping: '
grouped
',
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,
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,
errorbars:
null
,
errorbarsColor: 'black
',
errorbarsLinewidth: 1,
errorbarsCapwidth: 10,
key: null,
keyColors: null,
keyOffsetx: 0,
keyOffsety: 0,
keyTextOffsetx: 0,
keyTextOffsety: -1,
keyTextSize: null,
keyTextBold: null,
keyTextItalic: null,
keyTextFont: null
};
//
// Copy the global object properties to this instance
//
RG.SVG.getGlobals(this);
/**
* "Decorate" the object with the generic effects if the effects library has been included
*/
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
');
// Should the first thing that'
s done inthe.draw()
function
this
.width = Number(
this
.svg.getAttribute(
'width'
));
this
.height = Number(
this
.svg.getAttribute(
'height'
));
if
(prop.variant !==
'3d'
) {
prop.variant3dOffsetx = 0;
prop.variant3dOffsety = 0;
}
else
{
this
.svg.all.setAttribute(
'transform'
,
'skewY(5)'
);
}
RG.SVG.createDefs(
this
);
this
.coords = [];
this
.coords2 = [];
this
.graphWidth =
this
.width - prop.gutterLeft - prop.gutterRight;
this
.graphHeight =
this
.height - prop.gutterTop - prop.gutterBottom;
RG.SVG.resetColorsToOriginalValues({object:
this
});
this
.parseColors();
var
values = [];
for
(
var
i=0,max=0; i<
this
.data.length; ++i) {
if
(prop.errorbars &&
typeof
prop.errorbars[i] ===
'number'
) {
var
errorbar = prop.errorbars[i];
}
else
if
(prop.errorbars &&
typeof
prop.errorbars[i] ===
'object'
&&
typeof
prop.errorbars[i].max ===
'number'
) {
var
errorbar = prop.errorbars[i].max;
}
else
{
var
errorbar = 0;
}
if
(
typeof
this
.data[i] ===
'number'
) {
values.push(
this
.data[i] + errorbar);
}
else
if
(RG.SVG.isArray(
this
.data[i]) && prop.grouping ===
'grouped'
) {
values.push(RG.SVG.arrayMax(
this
.data[i]) + errorbar);
}
else
if
(RG.SVG.isArray(
this
.data[i]) && prop.grouping ===
'stacked'
) {
values.push(RG.SVG.arraySum(
this
.data[i]) + errorbar);
}
}
var
max = RG.SVG.arrayMax(values);
if
(
typeof
prop.yaxisMax ===
'number'
) {
max = prop.yaxisMax;
}
if
(prop.yaxisMin === 'mirror
' || prop.yaxisMin === '
middle
' || prop.yaxisMin === '
center
') {
var mirrorScale = true;
prop.yaxisMin = 0;
}
//
// Generate an appropiate scale
//
this.scale = RG.SVG.getScale({
object: this,
numlabels: prop.yaxisLabelsCount,
unitsPre: prop.yaxisUnitsPre,
unitsPost: prop.yaxisUnitsPost,
max: max,
min: prop.yaxisMin,
point: prop.yaxisPoint,
round: prop.yaxisRound,
thousand: prop.yaxisThousand,
decimals: prop.yaxisDecimals,
strict: typeof prop.yaxisMax === '
number
',
formatter: prop.yaxisFormatter
});
//
// Get the scale a second time if the ymin should be mirored
//
// Set the ymin to zero if it'
s szet mirror
if
(mirrorScale) {
this
.scale = RG.SVG.getScale({
object:
this
,
numlabels: prop.yaxisLabelsCount,
unitsPre: prop.yaxisUnitsPre,
unitsPost: prop.yaxisUnitsPost,
max:
this
.scale.max,
min:
this
.scale.max * -1,
point: prop.yaxisPoint,
round:
false
,
thousand: prop.yaxisThousand,
decimals: prop.yaxisDecimals,
strict:
typeof
prop.yaxisMax ===
'number'
,
formatter: prop.yaxisFormatter
});
}
this
.max =
this
.scale.max;
this
.min =
this
.scale.min;
prop.yaxisMax =
this
.scale.max;
prop.yaxisMin =
this
.scale.min;
RG.SVG.drawBackground(
this
);
if
(prop.variant ===
'3d'
) {
RG.SVG.create({
svg:
this
.svg,
parent:
this
.svg.all,
type:
'path'
,
attr: {
d:
'M {1} {2} L {3} {4} L {5} {6} L {7} {8}'
.format(
prop.gutterLeft,
prop.gutterTop,
prop.gutterLeft + prop.variant3dOffsetx,
prop.gutterTop - prop.variant3dOffsety,
prop.gutterLeft + prop.variant3dOffsetx,
this
.height - prop.gutterBottom - prop.variant3dOffsety,
prop.gutterLeft,
this
.height - prop.gutterBottom,
prop.gutterLeft,
prop.gutterTop
),
fill:
'#ddd'
,
stroke:
'#ccc'
}
});
this
.threed_xaxis_group = RG.SVG.create({
svg:
this
.svg,
type:
'g'
,
parent:
this
.svg.all,
attr: {
className:
'rgraph_3d_bar_xaxis_negative'
}
});
RG.SVG.create({
svg:
this
.svg,
parent:
this
.svg.all,
type:
'path'
,
attr: {
d:
'M {1} {2} L {3} {4} L {5} {6} L {7} {8}'
.format(
prop.gutterLeft,
this
.getYCoord(0),
prop.gutterLeft + prop.variant3dOffsetx,
this
.getYCoord(0) - prop.variant3dOffsety,
this
.width - prop.gutterRight + prop.variant3dOffsetx,
this
.getYCoord(0) - prop.variant3dOffsety,
this
.width - prop.gutterRight,
this
.getYCoord(0),
prop.gutterLeft,
this
.getYCoord(0)
),
fill:
'#ddd'
,
stroke:
'#ccc'
}
});
}
this
.drawBars();
RG.SVG.drawXAxis(
this
);
RG.SVG.drawYAxis(
this
);
this
.drawLabelsAbove();
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?'
);
}
RG.SVG.attribution(
this
);
RG.SVG.fireCustomEvent(
this
,
'ondraw'
);
return
this
;
};
this
.drawBars =
function
()
{
var
y =
this
.getYCoord(0);
if
(prop.shadow) {
RG.SVG.setShadow({
object:
this
,
offsetx: prop.shadowOffsetx,
offsety: prop.shadowOffsety,
blur: prop.shadowBlur,
opacity: prop.shadowOpacity,
id:
'dropShadow'
});
}
for
(
var
i=0,sequentialIndex=0; i<
this
.data.length; ++i,++sequentialIndex) {
if
(
typeof
this
.data[i] ===
'number'
) {
var
outerSegment =
this
.graphWidth /
this
.data.length,
height = (ma.abs(
this
.data[i]) - ma.abs(
this
.scale.min)) / (ma.abs(
this
.scale.max) - ma.abs(
this
.scale.min)) *
this
.graphHeight,
width = (
this
.graphWidth /
this
.data.length) - prop.hmargin - prop.hmargin,
x = prop.gutterLeft + prop.hmargin + (outerSegment * i);
if
(
this
.scale.min >= 0 &&
this
.scale.max > 0) {
y =
this
.getYCoord(
this
.scale.min) - height;
}
else
if
(
this
.scale.min < 0 &&
this
.scale.max > 0) {
height = (ma.abs(
this
.data[i]) / (
this
.scale.max -
this
.scale.min)) *
this
.graphHeight;
y =
this
.getYCoord(0) - height;
if
(
this
.data[i] < 0) {
y =
this
.getYCoord(0);
}
}
else
if
(
this
.scale.min < 0 &&
this
.scale.max < 0) {
height = (ma.abs(
this
.data[i]) - ma.abs(
this
.scale.max)) / (ma.abs(
this
.scale.min) - ma.abs(
this
.scale.max)) *
this
.graphHeight;
y = prop.gutterTop;
}
var
rect = RG.SVG.create({
svg:
this
.svg,
type:
'rect'
,
parent: prop.variant ===
'3d'
&&
this
.data[i] < 0 ?
this
.threed_xaxis_group :
this
.svg.all,
attr: {
stroke: prop.strokestyle,
fill: prop.colorsSequential ? (prop.colors[sequentialIndex] ? prop.colors[sequentialIndex] : prop.colors[prop.colors.length - 1]) : prop.colors[0],
x: x,
y: y,
width: width < 0 ? 0 : width,
height: height,
'stroke-width'
: prop.linewidth,
'data-original-x'
: x,
'data-original-y'
: y,
'data-original-width'
: width,
'data-original-height'
: height,
'data-tooltip'
: (!RG.SVG.isNull(prop.tooltips) && prop.tooltips.length) ? prop.tooltips[i] :
''
,
'data-index'
: i,
'data-sequential-index'
: sequentialIndex,
'data-value'
:
this
.data[i],
filter: prop.shadow ?
'url(#dropShadow)'
:
''
}
});
this
.drawErrorbar({
object:
this
,
element: rect,
index: i,
value:
this
.data[i],
type:
'normal'
});
this
.coords.push({
object:
this
,
element: rect,
x: parseFloat(rect.getAttribute(
'x'
)),
y: parseFloat(rect.getAttribute(
'y'
)),
width: parseFloat(rect.getAttribute(
'width'
)),
height: parseFloat(rect.getAttribute(
'height'
))
});
if
(!
this
.coords2[0]) {
this
.coords2[0] = [];
}
this
.coords2[0].push({
object:
this
,
element: rect,
x: parseFloat(rect.getAttribute(
'x'
)),
y: parseFloat(rect.getAttribute(
'y'
)),
width: parseFloat(rect.getAttribute(
'width'
)),
height: parseFloat(rect.getAttribute(
'height'
))
});
if
(prop.variant ===
'3d'
) {
this
.drawTop3dFace({rect: rect, value:
this
.data[i]});
this
.drawSide3dFace({rect: rect, value:
this
.data[i]});
}
if
(!RG.SVG.isNull(prop.tooltips) && prop.tooltips[sequentialIndex]) {
var
obj =
this
;
(
function
(idx, seq)
{
rect.addEventListener(prop.tooltipsEvent.replace(/^on/,
''
),
function
(e)
{
obj.removeHighlight();
RG.SVG.tooltip({
object: obj,
index: idx,
group:
null
,
sequentialIndex: seq,
text: prop.tooltips[seq],
event: e
});
obj.highlight(e.target);
},
false
);
rect.addEventListener(
'mousemove'
,
function
(e)
{
e.target.style.cursor =
'pointer'
},
false
);
})(i, sequentialIndex);
}
}
else
if
(RG.SVG.isArray(
this
.data[i]) && prop.grouping ===
'grouped'
) {
var
outerSegment = (
this
.graphWidth /
this
.data.length),
innerSegment = outerSegment - (2 * prop.hmargin);
for
(
var
j=0; j<
this
.data[i].length; ++j,++sequentialIndex) {
var
width = ( (innerSegment - ((
this
.data[i].length - 1) * prop.hmarginGrouped)) /
this
.data[i].length),
x = (outerSegment * i) + prop.hmargin + prop.gutterLeft + (j * width) + ((j - 1) * prop.hmarginGrouped);
x = prop.gutterLeft + (outerSegment * i) + (width * j) + prop.hmargin + (j * prop.hmarginGrouped);
if
(
this
.scale.min === 0 &&
this
.scale.max >
this
.scale.min) {
var
height = ((
this
.data[i][j] -
this
.scale.min) / (
this
.scale.max -
this
.scale.min)) *
this
.graphHeight,
y =
this
.getYCoord(0) - height;
}
else
if
(
this
.scale.max <= 0 &&
this
.scale.min <
this
.scale.max) {
var
height = ((
this
.data[i][j] -
this
.scale.max) / (
this
.scale.max -
this
.scale.min)) *
this
.graphHeight,
y =
this
.getYCoord(
this
.scale.max);
height = ma.abs(height);
}
else
if
(
this
.scale.max > 0 &&
this
.scale.min < 0) {
var
height = (ma.abs(
this
.data[i][j]) / (
this
.scale.max -
this
.scale.min)) *
this
.graphHeight,
y =
this
.data[i][j] < 0 ?
this
.getYCoord(0) :
this
.getYCoord(
this
.data[i][j]);
}
else
if
(
this
.scale.min > 0 &&
this
.scale.max >
this
.scale.min) {
var
height = (ma.abs(
this
.data[i][j] -
this
.scale.min) / (
this
.scale.max -
this
.scale.min)) *
this
.graphHeight,
y =
this
.getYCoord(
this
.scale.min) - height;
}
var
rect = RG.SVG.create({
svg:
this
.svg,
parent: prop.variant ===
'3d'
&&
this
.data[i][j] < 0 ?
this
.threed_xaxis_group :
this
.svg.all,
type:
'rect'
,
attr: {
stroke: prop[
'strokestyle'
],
fill: (prop.colorsSequential && prop.colors[sequentialIndex]) ? prop.colors[sequentialIndex] : prop.colors[j],
x: x,
y: y,
width: width,
height: height,
'stroke-width'
: prop.linewidth,
'data-original-x'
: x,
'data-original-y'
: y,
'data-original-width'
: width,
'data-original-height'
: height,
'data-index'
: i,
'data-subindex'
: j,
'data-sequential-index'
: sequentialIndex,
'data-tooltip'
: (!RG.SVG.isNull(prop.tooltips) && prop.tooltips.length) ? prop.tooltips[sequentialIndex] :
''
,
'data-value'
:
this
.data[i][j],
filter: prop.shadow ?
'url(#dropShadow)'
:
''
}
});
this
.drawErrorbar({
object:
this
,
element: rect,
index: sequentialIndex,
value:
this
.data[i][j],
type:
'grouped'
});
this
.coords.push({
object:
this
,
element: rect,
x: parseFloat(rect.getAttribute(
'x'
)),
y: parseFloat(rect.getAttribute(
'y'
)),
width: parseFloat(rect.getAttribute(
'width'
)),
height: parseFloat(rect.getAttribute(
'height'
))
});
if
(!
this
.coords2[i]) {
this
.coords2[i] = [];
}
this
.coords2[i].push({
object:
this
,
element: rect,
x: parseFloat(rect.getAttribute(
'x'
)),
y: parseFloat(rect.getAttribute(
'y'
)),
width: parseFloat(rect.getAttribute(
'width'
)),
height: parseFloat(rect.getAttribute(
'height'
))
});
if
(prop.variant ===
'3d'
) {
this
.drawTop3dFace({rect: rect, value:
this
.data[i][j]});
this
.drawSide3dFace({rect: rect, value:
this
.data[i][j]});
}
if
(!RG.SVG.isNull(prop.tooltips) && prop.tooltips[sequentialIndex]) {
var
obj =
this
;
(
function
(idx, seq)
{
obj.removeHighlight();
var
indexes = RG.SVG.sequentialIndexToGrouped(seq, obj.data);
rect.addEventListener(prop.tooltipsEvent.replace(/^on/,
''
),
function
(e)
{
RG.SVG.tooltip({
object: obj,
group: idx,
index: indexes[1],
sequentialIndex: seq,
text: prop.tooltips[seq],
event: e
});
obj.highlight(e.target);
},
false
);
rect.addEventListener(
'mousemove'
,
function
(e)
{
e.target.style.cursor =
'pointer'
},
false
);
})(i, sequentialIndex);
}
}
--sequentialIndex;
}
else
if
(RG.SVG.isArray(
this
.data[i]) && prop.grouping ===
'stacked'
) {
var
section = (
this
.graphWidth /
this
.data.length);
var
y =
this
.getYCoord(0);
for
(
var
j=0; j<
this
.data[i].length; ++j,++sequentialIndex) {
var
height = (
this
.data[i][j] / (
this
.max -
this
.min)) *
this
.graphHeight,
width = section - (2 * prop.hmargin),
x = prop.gutterLeft + (i * section) + prop.hmargin,
y = y - height;
if
(j === 0 && prop.shadow) {
var
fullHeight = (RG.SVG.arraySum(
this
.data[i]) / (
this
.max -
this
.min)) *
this
.graphHeight;
var
rect = RG.SVG.create({
svg:
this
.svg,
parent:
this
.svg.all,
type:
'rect'
,
attr: {
fill:
'white'
,
x: x,
y:
this
.height - prop.gutterBottom - fullHeight,
width: width,
height: fullHeight,
'stroke-width'
: 0,
'data-index'
: i,
filter:
'url(#dropShadow)'
}
});
this
.stackedBackfaces[i] = rect;
}
var
rect = RG.SVG.create({
svg:
this
.svg,
parent:
this
.svg.all,
type:
'rect'
,
attr: {
stroke: prop[
'strokestyle'
],
fill: prop.colorsSequential ? (prop.colors[sequentialIndex] ? prop.colors[sequentialIndex] : prop.colors[prop.colors.length - 1]) : prop.colors[j],
x: x,
y: y,
width: width,
height: height,
'stroke-width'
: prop.linewidth,
'data-original-x'
: x,
'data-original-y'
: y,
'data-original-width'
: width,
'data-original-height'
: height,
'data-index'
: i,
'data-subindex'
: j,
'data-sequential-index'
: sequentialIndex,
'data-tooltip'
: (!RG.SVG.isNull(prop.tooltips) && prop.tooltips.length) ? prop.tooltips[sequentialIndex] :
''
,
'data-value'
:
this
.data[i][j]
}
});
if
(j === (
this
.data[i].length - 1)) {
this
.drawErrorbar({
object:
this
,
element: rect,
index: i,
value:
this
.data[i][j],
type:
'stacked'
});
}
this
.coords.push({
object:
this
,
element: rect,
x: parseFloat(rect.getAttribute(
'x'
)),
y: parseFloat(rect.getAttribute(
'y'
)),
width: parseFloat(rect.getAttribute(
'width'
)),
height: parseFloat(rect.getAttribute(
'height'
))
});
if
(!
this
.coords2[i]) {
this
.coords2[i] = [];
}
this
.coords2[i].push({
object:
this
,
element: rect,
x: parseFloat(rect.getAttribute(
'x'
)),
y: parseFloat(rect.getAttribute(
'y'
)),
width: parseFloat(rect.getAttribute(
'width'
)),
height: parseFloat(rect.getAttribute(
'height'
))
});
if
(prop.variant ===
'3d'
) {
this
.drawTop3dFace({rect: rect, value:
this
.data[i][j]});
this
.drawSide3dFace({rect: rect, value:
this
.data[i][j]});
}
if
(!RG.SVG.isNull(prop.tooltips) && prop.tooltips[sequentialIndex]) {
var
obj =
this
;
(
function
(idx, seq)
{
rect.addEventListener(prop.tooltipsEvent.replace(/^on/,
''
),
function
(e)
{
obj.removeHighlight();
var
indexes = RG.SVG.sequentialIndexToGrouped(seq, obj.data);
RG.SVG.tooltip({
object: obj,
index: indexes[1],
group: idx,
sequentialIndex: seq,
text: prop.tooltips[seq],
event: e
});
obj.highlight(e.target);
},
false
);
rect.addEventListener(
'mousemove'
,
function
(e)
{
e.target.style.cursor =
'pointer'
;
},
false
);
})(i, sequentialIndex);
}
}
--sequentialIndex;
}
}
};
this
.getYCoord =
function
(value)
{
if
(value >
this
.scale.max) {
return
null
;
}
var
y, xaxispos = prop.xaxispos;
if
(value <
this
.scale.min) {
return
null
;
}
y = ((value -
this
.scale.min) / (
this
.scale.max -
this
.scale.min));
y *= (
this
.height - prop.gutterTop - prop.gutterBottom);
y =
this
.height - prop.gutterBottom - y;
return
y;
};
this
.highlight =
function
(rect)
{
var
x = rect.getAttribute(
'x'
),
y = rect.getAttribute(
'y'
),
width = rect.getAttribute(
'width'
),
height = rect.getAttribute(
'height'
);
var
highlight = RG.SVG.create({
svg:
this
.svg,
parent:
this
.svg.all,
type:
'rect'
,
attr: {
stroke: prop.highlightStroke,
fill: prop.highlightFill,
x: x,
y: y,
width: width,
height: height,
'stroke-width'
: prop.highlightLinewidth
},
style: {
pointerEvents:
'none'
}
});
if
(prop.tooltipsEvent ===
'mousemove'
) {
}
RG.SVG.REG.set(
'highlight'
, highlight);
};
this
.parseColors =
function
()
{
if
(!Object.keys(
this
.originalColors).length) {
this
.originalColors = {
colors: RG.SVG.arrayClone(prop.colors),
backgroundGridColor: RG.SVG.arrayClone(prop.backgroundGridColor),
highlightFill: RG.SVG.arrayClone(prop.highlightFill),
backgroundColor: RG.SVG.arrayClone(prop.backgroundColor)
}
}
var
colors = prop.colors;
if
(colors) {
for
(
var
i=0; i<colors.length; ++i) {
colors[i] = RG.SVG.parseColorLinear({
object:
this
,
color: colors[i]
});
}
}
prop.backgroundGridColor = RG.SVG.parseColorLinear({object:
this
, color: prop.backgroundGridColor});
prop.highlightFill = RG.SVG.parseColorLinear({object:
this
, color: prop.highlightFill});
prop.backgroundColor = RG.SVG.parseColorLinear({object:
this
, color: prop.backgroundColor});
};
this
.drawLabelsAbove =
function
()
{
if
(prop.labelsAbove) {
var
data_seq = RG.SVG.arrayLinearize(
this
.data),
seq = 0,
stacked_total = 0;;
for
(
var
i=0; i<
this
.coords.length; ++i,seq++) {
var
num =
typeof
this
.data[i] ===
'number'
?
this
.data[i] : data_seq[seq] ;
if
(prop.grouping === 'stacked
') {
var indexes = RG.SVG.sequentialIndexToGrouped(i, this.data);
var group = indexes[0];
var datapiece = indexes[1];
if (datapiece !== (this.data[group].length - 1) ) {
continue;
} else {
num = RG.SVG.arraySum(this.data[group]);
}
}
var str = RG.SVG.numberFormat({
object: this,
num: num.toFixed(prop.labelsAboveDecimals),
prepend: typeof prop.labelsAboveUnitsPre === '
string
' ? prop.labelsAboveUnitsPre : null,
append: typeof prop.labelsAboveUnitsPost === '
string
' ? prop.labelsAboveUnitsPost : null,
point: typeof prop.labelsAbovePoint === '
string
' ? prop.labelsAbovePoint : null,
thousand: typeof prop.labelsAboveThousand === '
string
' ? prop.labelsAboveThousand : null,
formatter: typeof prop.labelsAboveFormatter === '
function
' ? prop.labelsAboveFormatter : null
});
// Facilitate labelsAboveSpecific
if (prop.labelsAboveSpecific && prop.labelsAboveSpecific.length && (typeof prop.labelsAboveSpecific[seq] === '
string
' || typeof prop.labelsAboveSpecific[seq] === '
number
') ) {
str = prop.labelsAboveSpecific[seq];
} else if ( prop.labelsAboveSpecific && prop.labelsAboveSpecific.length && typeof prop.labelsAboveSpecific[seq] !== '
string
' && typeof prop.labelsAboveSpecific[seq] !== '
number
') {
continue;
}
var x = parseFloat(this.coords[i].element.getAttribute('
x
')) + parseFloat(this.coords[i].element.getAttribute('
width
') / 2) + prop.labelsAboveOffsetx;
if (data_seq[i] >= 0) {
var y = parseFloat(this.coords[i].element.getAttribute('
y
')) - 7 + prop.labelsAboveOffsety;
var valign = prop.labelsAboveValign;
} else {
var y = parseFloat(this.coords[i].element.getAttribute('
y
')) + parseFloat(this.coords[i].element.getAttribute('
height
')) + 7 - prop.labelsAboveOffsety;
var valign = prop.labelsAboveValign === '
top
' ? '
bottom
' : '
top
';
}
RG.SVG.text({
object: this,
parent: this.svg.all,
text: str,
x: x,
y: y,
halign: prop.labelsAboveHalign,
valign: valign,
tag: '
labels.above
',
font: prop.labelsAboveFont || prop.textFont,
size: prop.labelsAboveSize || prop.textSize,
bold: prop.labelsAboveBold || prop.textBold,
italic: prop.labelsAboveItalic || prop.textItalic,
color: prop.labelsAboveColor || prop.textColor,
background: prop.labelsAboveBackground || null,
padding: prop.labelsAboveBackgroundPadding || 0
});
}
}
};
/**
* 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);
};
//
// Draws the top of 3D bars
//
this.drawTop3dFace = function (opt)
{
var rect = opt.rect,
arr = [parseInt(rect.getAttribute('
fill
')), '
rgba(255,255,255,0.7)
'],
x = parseInt(rect.getAttribute('
x
')),
y = parseInt(rect.getAttribute('
y
')),
w = parseInt(rect.getAttribute('
width
')),
h = parseInt(rect.getAttribute('
height
')),
value = parseFloat(rect.getAttribute('
data-value
'));
rect.rgraph_3d_top_face = [];
for (var i=0; i<2; ++i) {
var color = (i === 0 ? rect.getAttribute('
fill
') : '
rgba(255,255,255,0.7)
');
var face = RG.SVG.create({
svg: this.svg,
type: '
path
',
parent: prop.variant === '
3d
' && opt.value < 0 ? this.threed_xaxis_group : this.svg.all,
attr: {
stroke: prop.strokestyle,
fill: color,
'
stroke-width
': prop.linewidth,
d: '
M {1} {2} L {3} {4} L {5} {6} L {7} {8}
'.format(
x,
y,
x + prop.variant3dOffsetx,
y - prop.variant3dOffsety,
x + w + prop.variant3dOffsetx,
y - prop.variant3dOffsety,
x + w,
y
)
}
});
// Store a reference to the rect on the front face of the bar
rect.rgraph_3d_top_face[i] = face
}
};
//
// Draws the top of 3D bars
//
this.drawSide3dFace = function (opt)
{
var rect = opt.rect,
arr = [parseInt(rect.getAttribute('
fill
')), '
rgba(0,0,0,0.3)
'],
x = parseInt(rect.getAttribute('
x
')),
y = parseInt(rect.getAttribute('
y
')),
w = parseInt(rect.getAttribute('
width
')),
h = parseInt(rect.getAttribute('
height
'));
rect.rgraph_3d_side_face = [];
for (var i=0; i<2; ++i) {
var color = (i === 0 ? rect.getAttribute('
fill
') : '
rgba(0,0,0,0.3)
');
var face = RG.SVG.create({
svg: this.svg,
type: '
path
',
parent: prop.variant === '
3d
' && opt.value < 0 ? this.threed_xaxis_group : this.svg.all,
attr: {
stroke: prop.strokestyle,
fill: color,
'
stroke-width
': prop.linewidth,
d: '
M {1} {2} L {3} {4} L {5} {6} L {7} {8}
'.format(
x + w,
y,
x + w + prop.variant3dOffsetx,
y - prop.variant3dOffsety,
x + w + prop.variant3dOffsetx,
y + h - prop.variant3dOffsety,
x + w,
y + h
)
}
});
// Store a reference to the rect on the front face of the bar
rect.rgraph_3d_side_face[i] = face
}
};
// This function is used to draw the errorbar. Its in the common
// file because it'
s used by multiple chart libraries
this
.drawErrorbar =
function
(opt)
{
var
prop =
this
.properties,
index = opt.index,
datapoint = opt.value,
linewidth = RG.SVG.getErrorbarsLinewidth({object:
this
, index: index}),
color = RG.SVG.getErrorbarsColor({object:
this
, index: index}),
capwidth = RG.SVG.getErrorbarsCapWidth({object:
this
, index: index}),
element = opt.element,
type = opt.type;
var
max = RG.SVG.getErrorbarsMaxValue({
object:
this
,
index: index
});
var
min = RG.SVG.getErrorbarsMinValue({
object:
this
,
index: index
});
if
(!max && !min) {
return
;
}
if
(type ===
'stacked'
) {
datapoint = RG.SVG.arraySum(
this
.data[index]);
}
if
(datapoint >= 0) {
var
x1 = parseFloat(element.getAttribute(
'x'
)) + (parseFloat(element.getAttribute(
'width'
)) / 2);
var
errorbarLine = RG.SVG.create({
svg:
this
.svg,
type:
'line'
,
parent:
this
.svg.all,
attr: {
x1: x1,
y1: parseFloat(element.getAttribute(
'y'
)),
x2: x1,
y2:
this
.getYCoord(parseFloat(datapoint + max)),
stroke: color,
'stroke-width'
: linewidth
}
});
var
errorbarCap = RG.SVG.create({
svg:
this
.svg,
type:
'line'
,
parent:
this
.svg.all,
attr: {
x1: parseFloat(errorbarLine.getAttribute(
'x1'
)) - (capwidth / 2),
y1: errorbarLine.getAttribute(
'y2'
),
x2: parseFloat(errorbarLine.getAttribute(
'x1'
)) + (capwidth / 2),
y2: errorbarLine.getAttribute(
'y2'
),
stroke: color,
'stroke-width'
: linewidth
}
});
if
(
typeof
min ===
'number'
) {
var
errorbarLine = RG.SVG.create({
svg:
this
.svg,
type:
'line'
,
parent:
this
.svg.all,
attr: {
x1: x1,
y1: parseFloat(element.getAttribute(
'y'
)),
x2: x1,
y2:
this
.getYCoord(parseFloat(datapoint - min)),
stroke: color,
'stroke-width'
: linewidth
}
});
var
errorbarCap = RG.SVG.create({
svg:
this
.svg,
type:
'line'
,
parent:
this
.svg.all,
attr: {
x1: parseFloat(errorbarLine.getAttribute(
'x1'
)) - (capwidth / 2),
y1: errorbarLine.getAttribute(
'y2'
),
x2: parseFloat(errorbarLine.getAttribute(
'x1'
)) + (capwidth / 2),
y2: errorbarLine.getAttribute(
'y2'
),
stroke: color,
'stroke-width'
: linewidth
}
});
}
}
else
if
(datapoint < 0) {
var
x1 = parseFloat(element.getAttribute(
'x'
)) + (parseFloat(element.getAttribute(
'width'
)) / 2),
y1 = parseFloat(element.getAttribute(
'y'
)) + parseFloat(element.getAttribute(
'height'
)),
y2 =
this
.getYCoord(parseFloat(datapoint - ma.abs(max) ))
var
errorbarLine = RG.SVG.create({
svg:
this
.svg,
type:
'line'
,
parent:
this
.svg.all,
attr: {
x1: x1,
y1: y1,
x2: x1,
y2: y2,
stroke: color,
'stroke-width'
: linewidth
}
});
var
errorbarCap = RG.SVG.create({
svg:
this
.svg,
type:
'line'
,
parent:
this
.svg.all,
attr: {
x1: parseFloat(errorbarLine.getAttribute(
'x1'
)) - (capwidth / 2),
y1: errorbarLine.getAttribute(
'y2'
),
x2: parseFloat(errorbarLine.getAttribute(
'x1'
)) + (capwidth / 2),
y2: errorbarLine.getAttribute(
'y2'
),
stroke: color,
'stroke-width'
: linewidth
}
});
if
(
typeof
min ===
'number'
) {
var
x1 = parseFloat(element.getAttribute(
'x'
)) + (parseFloat(element.getAttribute(
'width'
)) / 2);
var
errorbarLine = RG.SVG.create({
svg:
this
.svg,
type:
'line'
,
parent:
this
.svg.all,
attr: {
x1: x1,
y1:
this
.getYCoord(parseFloat(datapoint + min)),
x2: x1,
y2:
this
.getYCoord(parseFloat(datapoint)),
stroke: color,
'stroke-width'
: linewidth
}
});
var
errorbarCap = RG.SVG.create({
svg:
this
.svg,
type:
'line'
,
parent:
this
.svg.all,
attr: {
x1: parseFloat(errorbarLine.getAttribute(
'x1'
)) - (capwidth / 2),
y1: errorbarLine.getAttribute(
'y1'
),
x2: parseFloat(errorbarLine.getAttribute(
'x1'
)) + (capwidth / 2),
y2: errorbarLine.getAttribute(
'y1'
),
stroke: color,
'stroke-width'
: linewidth
}
});
}
}
};
this
.grow =
function
()
{
var
opt = arguments[0] || {},
frames = opt.frames || 30,
frame = 0,
obj =
this
,
data = [],
height =
null
,
seq = 0;
data = RG.SVG.arrayClone(
this
.data);
this
.draw();
var
iterate =
function
()
{
for
(
var
i=0,seq=0,len=obj.coords.length; i<len; ++i, ++seq) {
var
multiplier = (frame / frames)
* RG.SVG.FX.getEasingMultiplier(frames, frame)
* RG.SVG.FX.getEasingMultiplier(frames, frame);
if
(
typeof
data[i] ===
'number'
) {
height = ma.abs(obj.getYCoord(data[i]) - obj.getYCoord(0));
obj.data[i] = data[i] * multiplier;
height = multiplier * height;
obj.coords[seq].element.setAttribute(
'height'
,
height
);
obj.coords[seq].element.setAttribute(
'y'
,
data[i] < 0 ? obj.getYCoord(0) : obj.getYCoord(0) - height
);
if
(prop.variant ===
'3d'
) {
if
(obj.coords[i].element.rgraph_3d_side_face[0].parentNode) obj.coords[i].element.rgraph_3d_side_face[0].parentNode.removeChild(obj.coords[i].element.rgraph_3d_side_face[0]);
if
(obj.coords[i].element.rgraph_3d_side_face[1].parentNode) obj.coords[i].element.rgraph_3d_side_face[1].parentNode.removeChild(obj.coords[i].element.rgraph_3d_side_face[1]);
if
(obj.coords[i].element.rgraph_3d_top_face[0].parentNode) obj.coords[i].element.rgraph_3d_top_face[0].parentNode.removeChild(obj.coords[i].element.rgraph_3d_top_face[0]);
if
(obj.coords[i].element.rgraph_3d_top_face[1].parentNode) obj.coords[i].element.rgraph_3d_top_face[1].parentNode.removeChild(obj.coords[i].element.rgraph_3d_top_face[1]);
obj.drawSide3dFace({rect: obj.coords[i].element});
if
(prop.grouping ===
'grouped'
) {
obj.drawTop3dFace({rect: obj.coords[i].element });
}
if
(obj.coords[i].element.parentNode) {
var
parent = obj.coords[i].element.parentNode;
var
node = parent.removeChild(obj.coords[i].element);
parent.appendChild(node);
}
}
}
else
if
(
typeof
data[i] ===
'object'
) {
var
accumulativeHeight = 0;
for
(
var
j=0,len2=data[i].length; j<len2; ++j, ++seq) {
height = ma.abs(obj.getYCoord(data[i][j]) - obj.getYCoord(0));
height = multiplier * height;
obj.data[i][j] = data[i][j] * multiplier;
height = ma.round(height);
obj.coords[seq].element.setAttribute(
'height'
,
height
);
obj.coords[seq].element.setAttribute(
'y'
,
data[i][j] < 0 ? (obj.getYCoord(0) + accumulativeHeight) : (obj.getYCoord(0) - height - accumulativeHeight)
);
if
(prop.variant ===
'3d'
) {
if
(obj.coords[seq].element.rgraph_3d_side_face[0].parentNode) obj.coords[seq].element.rgraph_3d_side_face[0].parentNode.removeChild(obj.coords[seq].element.rgraph_3d_side_face[0]);
if
(obj.coords[seq].element.rgraph_3d_side_face[1].parentNode) obj.coords[seq].element.rgraph_3d_side_face[1].parentNode.removeChild(obj.coords[seq].element.rgraph_3d_side_face[1]);
if
(obj.coords[seq].element.rgraph_3d_top_face[0].parentNode) obj.coords[seq].element.rgraph_3d_top_face[0].parentNode.removeChild(obj.coords[seq].element.rgraph_3d_top_face[0]);
if
(obj.coords[seq].element.rgraph_3d_top_face[1].parentNode) obj.coords[seq].element.rgraph_3d_top_face[1].parentNode.removeChild(obj.coords[seq].element.rgraph_3d_top_face[1]);
obj.drawSide3dFace({rect: obj.coords[seq].element});
obj.drawTop3dFace({rect: obj.coords[seq].element});
if
(obj.coords[seq].element.parentNode) {
var
parent = obj.coords[seq].element.parentNode;
var
node = parent.removeChild(obj.coords[seq].element);
parent.appendChild(node);
}
}
accumulativeHeight += (prop.grouping ===
'stacked'
? height : 0);
}
if
(obj.stackedBackfaces[i]) {
obj.stackedBackfaces[i].setAttribute(
'height'
,
accumulativeHeight
);
obj.stackedBackfaces[i].setAttribute(
'y'
,
obj.height - prop.gutterBottom - accumulativeHeight
);
}
--seq;
}
}
if
(frame++ < frames) {
RG.SVG.FX.update(iterate);
}
else
if
(opt.callback) {
(opt.callback)(obj);
}
};
iterate();
return
this
;
};
this
.wave =
function
()
{
this
.draw();
var
obj =
this
,
opt = arguments[0] || {};
opt.frames = opt.frames || 60;
opt.startFrames = [];
opt.counters = [];
var
framesperbar = opt.frames / 3,
frame = -1,
callback = opt.callback ||
function
() {};
for
(
var
i=0,len=
this
.coords.length; i<len; i+=1) {
opt.startFrames[i] = ((opt.frames / 2) / (obj.coords.length - 1)) * i;
opt.counters[i] = 0;
this
.coords[i].element.setAttribute('height
', 0);
if (this.coords[i].element.rgraph_3d_side_face) {
var parent = this.coords[i].element.rgraph_3d_side_face[0].parentNode;
parent.removeChild(this.coords[i].element.rgraph_3d_side_face[0]);
parent.removeChild(this.coords[i].element.rgraph_3d_side_face[1]);
parent.removeChild(this.coords[i].element.rgraph_3d_top_face[0]);
parent.removeChild(this.coords[i].element.rgraph_3d_top_face[1]);
}
}
function iterator ()
{
++frame;
for (var i=0,len=obj.coords.length; i<len; i+=1) {
if (frame > opt.startFrames[i]) {
var originalHeight = obj.coords[i].element.getAttribute('
data-original-height
'),
height,
value = parseFloat(obj.coords[i].element.getAttribute('
data-value
'));
var height = ma.min(
((frame - opt.startFrames[i]) / framesperbar) * originalHeight,
originalHeight
);
obj.coords[i].element.setAttribute(
'
height
',
height < 0 ? 0 : height
);
obj.coords[i].element.setAttribute(
'
y
',
value >=0 ? obj.getYCoord(0) - height : obj.getYCoord(0)
);
// This updates the size of the 3D sides to the bar
if (prop.variant === '
3d
') {
// Remove the 3D sides to the bar
var parent = obj.coords[i].element.rgraph_3d_side_face[0].parentNode;
if (parent) parent.removeChild(obj.coords[i].element.rgraph_3d_side_face[0]);
if (parent) parent.removeChild(obj.coords[i].element.rgraph_3d_side_face[1]);
var parent = obj.coords[i].element.rgraph_3d_top_face[0].parentNode;
if (parent) parent.removeChild(obj.coords[i].element.rgraph_3d_top_face[0]);
if (parent) parent.removeChild(obj.coords[i].element.rgraph_3d_top_face[1]);
// Now remove and immediately re-add the front face of
// the bar - this is so that the front face appears
// above the other sides
if (obj.coords[i].element.parentNode) {
var parent = obj.coords[i].element.parentNode;
var node = parent.removeChild(obj.coords[i].element);
parent.appendChild(node);
}
}
if (prop.grouping === '
stacked
') {
var seq = obj.coords[i].element.getAttribute('
data-sequential-index
');
var indexes = RG.SVG.sequentialIndexToGrouped(seq, obj.data);
if (indexes[1] > 0) {
obj.coords[i].element.setAttribute(
'
y
',
parseInt(obj.coords[i - 1].element.getAttribute('
y
')) - height
);
}
}
if (prop.variant === '
3d
') {
// Add the 3D sides to the bar (again)
obj.drawSide3dFace({
rect: obj.coords[i].element,
value: obj.coords[i].element.getAttribute('
data-value
')
});
// Draw the top side of the 3D bar
if (prop.grouping === '
grouped
' || (prop.grouping === '
stacked
' && (indexes[1] + 1) === obj.data[indexes[0]].length) ) {
obj.drawTop3dFace({
rect: obj.coords[i].element,
value: obj.coords[i].element.getAttribute('
data-value
')
});
}
}
}
}
if (frame >= opt.frames) {
callback(obj);
} else {
RG.SVG.FX.update(iterator);
}
}
iterator();
return this;
};
//
// 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);