gerd
11/8/2016 - 2:05 PM

D3 bar chart

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");
                }
            }
        }
    });
}