1

First of all, I apologize for such a long post and my absolute beginner knowledge about D3 framework.

I have managed to draw the following chart using D3 framework.

enter image description here

However, I am not been able to accomplish the following things:

1) Cannot draw Y-Axis vertical sideline
2) Cannot make the Y-Axis ticks to align centered. At the moment they all are left-aligned
3) Cannot make the color of X-Axis baseline same as Y-Axis gridlines
4) Cannot make the label "Growth Target (7)" center-aligned Right now it is left-aligned

1) Y-Axis Vertical Sideline:
The text Growth Target (7) is within the chart. In order to make the gridlines to stop before this, I have used this (approach 1)

// ******************* << Custom Y axis grid lines Begins
var yGrid = svg.selectAll(".hgrid")
  .data(yTicks)
  .enter()
  .append("g")
  .attr("transform", function(d){
      return "translate(0, " + y(d) + ")"
  });

yGrid.append("line")
  .attr("class", "hgrid")
  .attr("x1", 0)
  // shorten growth target line width to give room for the label
  .attr("x2", width - growth_target_width_adjusted);

yGrid.append("text")
  .text(function(d){return d; })
  .attr("class", "hgrid-label")
  // update X and Y positions of the label
  .attr("x", -15)
  .attr("y", "0.3em");

d3.selectAll(".hgrid-label")
  .each(function (d, i) {
      d3.select(this).style("font-size", 13);
});

// ******************* Custom Y axis grid lines Ends >>

Rather than this (approach 2):

// gridlines in y axis function
function draw_yAxis_gridlines() {
  return d3.axisLeft(y)
      .tickValues(yTicks);
}

// add the Y grid lines
svg.append("g")
  .attr("class", "grid axis yAxis")
  .call(draw_yAxis_gridlines()
     .tickSize(-width)
);

The above approach 2, however, creates the Y-Axis baseline but the gridlines are using the entire chart area and overlapping the text "Growth Target (7)".

Is there any way that I can control the width of each Y-Axis line using approach 2? If not, how can I draw the Y-Axis baseline using approach 1?

2) Y-Axis ticks to align center
Currently, the Y-Axis tick values (0, 5, 10...) are left-aligned. Is there a way to make them centered?

3) Color of X-Axis baseline same as Y-Axis gridlines
In my chart above, the X-Axis color is black while the gridline colors are light gray. I need to make the X-Axis color light gray as well. What is the right way to do this?

4) Center aligning the label "Growth Target (7)"
What is the right way to make the two lines of the label centered-aligned? Right now the lines are aligned left to each other.

The desired output needs to be like this:

enter image description here

Here is the complete chart script that I have now:

function barColor(data_month, current_month) {
    if( parseInt(data_month) >= current_month)
        return "#008600";
    else
        return "#c4c4c4";
}

function draw_gp_chart(data_str) {

    var chart_container = jQuery("#ecbg_unitary");
    jQuery(chart_container).html("");

    var w = parseInt(jQuery(chart_container).width());
    var h = 375;
    var barPadding = 2;

    // set the dimensions and margins of the graph
    var margin = {top: 30, right: 20, bottom: 30, left: 40};
    var width = w - margin.left - margin.right;
    var height = h - margin.top - margin.bottom;
    var growth_target_width_adjusted = margin.left + margin.right;

    var svg = d3.select("#ecbg_unitary")
        .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + ", 10)");

    var data = data_str;

    // set the ranges (less width of chart to allow room for Growth Target label)
    var x = d3.scaleBand().range([0, width - growth_target_width_adjusted]).padding(0.2);
    var y = d3.scaleLinear().range([height, 0]);


    // Scale the range of the data in the domains
    x.domain(data.map(function (d) {
        return d.month;
    }));

    var y_domain_upperBound = d3.max(data, function (d) {
        return d.points;
    });
    y_domain_upperBound = Math.round(y_domain_upperBound / 10) * 10 + 10;
    y.domain([0, y_domain_upperBound]);

    // Create Y-Axis tick array to draw grid lines
    var yTicks = [];
    var tickInterval = 5;
    for (var i = 0; i <= y_domain_upperBound; i = i + tickInterval) {
        yTicks.push(i);
    }

    // gridlines in y axis function
    function draw_yAxis_gridlines() {
        return d3.axisLeft(y)
            .tickValues(yTicks);
    }

    // ******************* << Growth Target line Begins
    var targetGoalArr = [parseInt(jQuery("#ecbg_unitary_growth_target").val())];

    var target = svg.selectAll(".targetgoal")
        .data(targetGoalArr)
        .enter()
        .append("g")
        .attr("transform", function(d){
            return "translate(0, " + y(d) + ")"
        });

    target.append("line")
        .attr("class", "targetgoal")
        .attr("x1", 0)
        // shorten growth target line width to give room for the label
        .attr("x2", width - growth_target_width_adjusted);

    // Adding two SVG text elements since SVG text element does not support text-wrapping.
    // ref: https://stackoverflow.com/a/13254862/1496518
    // Option 2: may be tried later - https://bl.ocks.org/mbostock/7555321

    // Text element 1
    target.append("text")
        .text(function(d){return "Growth " })
        .attr("class", "tglebal")
        // update X position of the label
        .attr("x", width - growth_target_width_adjusted + 5)
        .attr("y", "-0.3em");

    // Text element 2
    target.append("text")
        .text(function(d){return "Target (" + d + ")" })
        .attr("class", "tglebal")
        // update X position of the label
        .attr("x", width - growth_target_width_adjusted + 5)
        .attr("y", "1em");

    d3.selectAll(".tglebal")
        .each(function (d, i) {
            d3.select(this).style("font-size", 12);
        });

    // ******************* Growth Target line Ends >>

    // ******************* << Custom Y axis grid lines Begins
    var yGrid = svg.selectAll(".hgrid")
        .data(yTicks)
        .enter()
        .append("g")
        .attr("transform", function(d){
            return "translate(0, " + y(d) + ")"
        });

    yGrid.append("line")
        .attr("class", "hgrid")
        .attr("x1", 0)
        // shorten growth target line width to give room for the label
        .attr("x2", width - growth_target_width_adjusted);

    yGrid.append("text")
        .text(function(d){return d; })
        .attr("class", "hgrid-label")
        // update X and Y positions of the label
        .attr("x", -15)
        .attr("y", "0.3em");

    d3.selectAll(".hgrid-label")
        .each(function (d, i) {
            d3.select(this).style("font-size", 13);
        });

    // ******************* Custom Y axis grid lines Ends >>

    // append the rectangles for the bar chart
    svg.selectAll("rect")
        .data(data)
        .enter().append("rect")
        .attr("x", function (d) {
            return x(d.month);
        })
        .attr("width", x.bandwidth())
        .attr("y", function (d) {
            return y(d.points);
        })
        .attr("height", function (d) {
            return height - y(d.points);
        })
        //.attr("height", function(d) {return d.points;})
        .attr("fill", function (d) {
            return barColor(d.data_month_number, d.current_month_number)
        });


    // column labels
    svg.selectAll(".colvalue")
        .data(data)
        .enter()
        .append("text")
        .attr("class", "colvalue")
        .text(function (d) {
            return d.points;
        })
        .attr("text-anchor", "middle")
        .attr("x", function (d, i) {
            return x(d.month) + x.bandwidth() / 2;
        })
        //.attr("x", function(d) { return x(d.month); })
        .attr("y", function (d) {
            //return h - (d.points * 4) - 10;
            return y(d.points) - 10;
        })
        .attr("font-family", "Roboto")
        .attr("font-size", "13px")
        .attr("font-weight", "bold")
        .attr("fill", "#606668");

    // add the x Axis
    svg.append("g")
        .attr("class", "axis")
        .attr("transform", "translate(0," + height + ")")
        .call(d3.axisBottom(x));

    // text label (axis name) for the x axis
    var xAxisNameHeightFromTop = height + margin.bottom + 20;

    svg.append("g")
        .attr("class", "x-axis-name")
        .append("text")
        .attr("transform", "translate(" + width / 2 + ", " + xAxisNameHeightFromTop + ")")
        .style("text-anchor", "middle")
        .text("MONTH");

    // text label for the y axis
    svg.append("g")
        .attr("class", "y-axis-name")
        .append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 0 - margin.left)
        .attr("x", 0 - (height / 2))
        .attr("dy", "1em")
        .style("text-anchor", "middle")
        .text("SALES UNITS");

    // add the Y grid lines
    /*svg.append("g")
        .attr("class", "grid axis yAxis")
        .call(draw_yAxis_gridlines()
            .tickSize(-width)
        );*/

    d3.selectAll(".yAxis>.tick>text")
        .each(function (d, i) {
            d3.select(this).style("font-size", 13);
        });
}
Subrata Sarkar
  • 2,975
  • 6
  • 45
  • 85

0 Answers0