D3 bar chart
/**
/ * Function to draw bar chart
* @class lexisnexis.component.drawVerticalBarChart
*/
jQuery.namespace('lexisnexis.component');
/**
* @constructor
*/
lexisnexis.component.drawVerticalBarChart = function(divId, data, configValues) {
try {
dataSet = jQuery.parseJSON(data);
} catch (err) {
dataSet = data;
}
try {
config = jQuery.parseJSON(configValues);
} catch (err) {
config = configValues;
}
var defaultConfig = {
canvasWidth : 300,
canvasHeight : 200,
barsWidthTotal : 300,
tickCount : 5,
marginLeft : 70,
marginRight : 20,
marginTop : 10,
marginBottom : 40,
viewBoxLeft:0,
viewBoxTop:0,
viewBoxWidth:365,
viewBoxHeight:270,
enableLinks : false,
enableYAxisLabel : false,
enableYAxisInPercent : false,
enableXAxisBarLabel : true,
xAxisEllipsisTip : false,
wrapXAxisLabel : false,
legend : false,
legendLabel : false,
legendLinkLabel : '',
linkURL : '',
longText : false
};
$.extend(defaultConfig, config);
LN.debug(defaultConfig.canvasHeight);
var emptyArr = [];
dataSet.forEach(function (d,i) {
emptyArr.push( (parseInt(d.value)>0) );
});
var isEmpty = emptyArr.indexOf(true) < 0;
// width of each bar
var barWidth = defaultConfig.barsWidthTotal / (dataSet.length * 2);
var max = d3.max(dataSet, function(d) {
return d.value;
});
var scaling = max / (defaultConfig.tickCount - 2) ;
var enableLinks = defaultConfig.enableLinks;
var enableYAxisLabel = defaultConfig.enableYAxisLabel;
var enableYAxisInPercent = defaultConfig.enableYAxisInPercent;
var enableXAxisBarLabel = defaultConfig.enableXAxisBarLabel;
var xAxisEllipsisTip = defaultConfig.xAxisEllipsisTip;
var wrapXAxisLabel = defaultConfig.wrapXAxisLabel;
var tempLongDisplayName;
var longDisplayName;
// setting up the x axis to be equal to the dataset length and the range bars
// to occupy
var x = d3.scale.linear().domain([ 0, dataSet.length ])
.range([ 30, defaultConfig.barsWidthTotal ]);
if(wrapXAxisLabel){
x = d3.scale.ordinal()
.rangeRoundBands([0, defaultConfig.barsWidthTotal],.5, .15);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
x.domain(dataSet.map(function(d,i) {
return d.label;
}));
}
// setting up y axis to take maximum of the dataset value and the height to
// use.
var y = d3.scale.linear().domain([ 0, d3.max(dataSet, function(d) {
return d3.sum([ d.value, scaling ]);
}) ]).rangeRound([ defaultConfig.canvasHeight, 0 ]);
var scaleYAxis = d3.svg.axis().scale(y).orient("left")
.ticks(defaultConfig.tickCount, [ "$", "," ])
.tickSize(-defaultConfig.barsWidthTotal);
if(enableYAxisInPercent){
LN.debug("enable the Y Axis label in %");
scaleYAxis = d3.svg.axis().scale(y).orient("left")
.ticks(defaultConfig.tickCount, [ "%", "," ])
.tickSize(-defaultConfig.barsWidthTotal-20);
}
var canvas = d3.select(divId).classed("ln-svg-container", true).append("svg:svg") .classed("ln-barchart-responsive", true)
.attr('viewBox', [defaultConfig.viewBoxLeft, defaultConfig.viewBoxTop, defaultConfig.viewBoxWidth, defaultConfig.viewBoxHeight].join(' '))
.attr('perserveAspectRatio', 'xMidYMid meet')
.append("g")
.attr("transform", "translate(" + defaultConfig.marginLeft + "," + defaultConfig.marginTop + ")");
LN.debug(defaultConfig.canvasHeight + defaultConfig.marginTop + defaultConfig.marginBottom);
if(xAxisEllipsisTip){
var div = d3.select("body").append("div")
.attr("class", "ln-barChart-xAxis-tooltip ln-barchart-toolTip-font")
.style("opacity", 0);
}
//enable the Y Axis label
if(enableYAxisLabel){
LN.debug("enable the Y Axis label");
canvas.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - 55)
.attr("x",0 - (defaultConfig.canvasHeight / 2))
.attr("dy", "1em")
.attr("class", "ln-barChart-yAxis-Label")
.text("% Population");
}
var wraptext;
if(wrapXAxisLabel){
wraptext = canvas.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + defaultConfig.canvasHeight + ")")
.call(xAxis);
}
canvas.append("g").attr("class", "y axis").call(scaleYAxis);
canvas.selectAll("g").filter(function(d) {
return d;
}).classed("minor", true);
// Drawing individual bar with hyper text enabled in the canvas. attribut x
// and y going to give the position of the point and attribute height and
// width is going to draw the bar
LN.debug("enable links in default");
LN.debug(defaultConfig.enableLinks);
var wrapElem = canvas.selectAll("rect").data(dataSet).enter();
if (enableLinks && !isEmpty) {
// to include hyperlinks
wrapElem = wrapElem.append("svg:a").attr("xlink:href", function(d) {
return LN.getContextPath()+d.link;
});
} else {
wrapElem = wrapElem.append("g");
}
// Add the region for the bar charts
wrapElem.append("svg:rect")
// to fill the color of the bar
.style("fill", function(d) {
return d.color;
})
// position or index for the bar.
.attr("x", function(d, i) {
return wrapXAxisLabel ? x(d.label) : x(i);
})
// to provide additional space above the bars
.attr("y", function(d) {
return y(d.value);
})
// drawing the bar to match the value from the dataset
.attr("height", function(d) {
return defaultConfig.canvasHeight - y(d.value);
})
.attr("width", (wrapXAxisLabel ? x.rangeBand() : barWidth));
//Enabling XAxis bar label
if(enableXAxisBarLabel){
//Create the text element wrapper either with or without an enclosing hyperlink.
var wrapTextValue = null;
var wrapTextLabel = null;
if (enableLinks && !isEmpty) {
var wrapAnchor = canvas.selectAll("text.xAxis").data(dataSet).enter().append("svg:a")
.attr("xlink:href", function(d) {
return LN.getContextPath()+d.link;
});
wrapTextValue = wrapAnchor.append("svg:text").attr("class", "ln-barChart-label-underLine");
wrapTextLabel = wrapAnchor.append("svg:text").attr("class", "ln-barChart-label-underLine");
} else {
wrapTextValue = canvas.selectAll("text.xAxis").data(dataSet).enter()
.append("svg:text");
wrapTextLabel = canvas.selectAll("text.xAxis").data(dataSet).enter()
.append("svg:text");
}
var fillColor = enableLinks ? "blue" : "black";
LN.debug("Enabling XAxis bar label and adding the text to the below label");
wrapTextValue.attr("x", function(d, i) {
return x(i) - 35 + barWidth / 2;
})
.attr("y", defaultConfig.canvasHeight + 15)
.attr("width", 10)
.attr("dx", barWidth / 2)
.attr("text-anchor", "middle")
.text(function(d) {
return "$" + numeral(d.value).format('0,0') + " ";
}).attr("fill", fillColor);
wrapTextLabel.attr("x", function(d, i) {
return x(i) - 35 + barWidth / 2;
})
.attr("y", defaultConfig.canvasHeight + 20)
.attr("width", 10)
.attr("dx", barWidth / 2)
.attr("dy", ".85em")
.attr("text-anchor", "middle")
.text(function(d,i) {
return defaultConfig.longText ? d.displayEllipsisLabel : d.label;
}).attr("fill", fillColor);
}
if(xAxisEllipsisTip){
d3.selectAll("text[x='0']").style("cursor", "pointer").on('mouseover', function(d,i){
longDisplayName = getTooltipValue(d);
div.transition()
.duration(100)
.style("opacity", .9);
var tspan = $(this).find('a tspan')[0];
if (tspan == null){
tspan = $(this).find('tspan')[0];
}
var xpos = $(tspan).offset().left;
var ypos = $(tspan).offset().top + 5;
var browser = {
isIe: function () {
return navigator.appVersion.indexOf("MSIE") != -1;
},
navigator: navigator.appVersion,
getVersion: function() {
var version = 999; // we assume a sane browser
if (navigator.appVersion.indexOf("MSIE") != -1){
// bah, IE again, lets downgrade version number
version = parseFloat(navigator.appVersion.split("MSIE")[1]);
}
return version;
}
};
div.html(longDisplayName)
.style("position", "absolute");
if (browser.isIe() && browser.getVersion()>= 7) {
ypos += 45;
xpos -= (i==1) ? 40 : 45;
div.style("left", xpos + "px")
.style("top", ypos + "px").style("width", "7%");
}else{
ypos += 40;
div.style("left", xpos + "px")
.style("top", ypos + "px").style("width", "8.5%").style("word-wrap","break-word");
}
})
.on("mouseout", function(d) {
div.transition()
.duration(30)
.style("opacity", 0);
});
}
if(wrapXAxisLabel){
var textWrapWidth = x.rangeBand() + 10;
wraptext.selectAll(".tick text")
.call(wrap, textWrapWidth, enableLinks, defaultConfig.longText);
}
function getTooltipValue(d) {
var l = (!defaultConfig.longText && enableLinks) ? d.label : d;
for(var i in data) {
if(l === data[i].label) {
tempLongDisplayName = data[i].displayEllipsisLabel;
return tempLongDisplayName;
}
}
}
};
function wrap(text, width, enableLinks, useLongText) {
text.data(dataSet).each(function(d) {
var patientCount = d.value;
var text = d3.select(this),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // em
y = 6,
dy = parseFloat(text.attr("dy"));
var wrapper = null;
var textUsed = (useLongText) ? d.displayEllipsisLabel : text.text();
var words = textUsed.trim().split(/\s+/).reverse();
text.text(null);
// Create wrapper element, as a hyperlink or group.
if(enableLinks && patientCount>0){
wrapper = text.append("svg:a").attr("xlink:href", function(d) {
return LN.getContextPath()+d.link;
});
} else {
wrapper = text;
}
var tspan = wrapper.append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
if (enableLinks){
tspan.attr("class","ln-barChart-label-underLine");
}
var isLengthGreater = false;
var cLine = null;
var xValue = 0;
while (word = words.pop()) {
line.push(word);
cLine = line.join(" ");
tspan.text(cLine).attr("x", xValue);
isLengthGreater = tspan.node().getComputedTextLength() > width+50;
hasDelimiter = cLine.charAt(cLine.length-1) == ':' || cLine.charAt(cLine.length-1) == ',';
if (isLengthGreater || hasDelimiter) {
if (isLengthGreater) {
line.pop();
tspan.text(line.join(" "));
} else {
tspan.text(line.join(" "));
line.pop();
word = '';
}
line = [word];
tspan = wrapper.append("tspan")
.attr("x", xValue)
.attr("y", y)
.attr("dy", ++lineNumber * lineHeight + dy + "em")
.text(word);
if (enableLinks){
tspan.attr("class","ln-barChart-label-underLine");
}
}
}
});
}