Raven
Raven

Reputation: 713

how to left align ticks in d3 bar chart

i created a stacked bar graph.
on the y axis side i have ticks with varying lengths. what i am trying to accomplish is to align the text in the tick to the left. this is my example:http://jsfiddle.net/2khbceut/2/

html

<title>Diverging Stacked Bar Chart with D3.js</title>
<body>
    <div id="figure" align="center" style="margin-bottom: 50px;"></div>
</body>

javascript

$(document).ready(getTopolegy());





function getTopolegy(){

      var data = null;
        var links = parseTopology(data);
        createChart(links);

}

function parseTopology(data){
  var links=[{1:5,2:5,3:10,N:20,link_name: "Link CHGIL21CRS-SFXCA21CRS"},
            {1:5,2:5,3:10,N:20,link_name: "Link NYCNY21CRS-NYCNY22CRS"}];

  return links;  
}

function jsonNameToId(name){
  switch (allocated_priority) {
  case "allocated_priority":
    return 1;
  case "allocated_default":
    return 2;
  case "spare_capacity":
    return 3;
  case "total":
    return "N";
  default:
    return 999;
  }
}

function createChart(data){
  var margin = {top: 50, right: 20, bottom: 10, left: 210},
    width = 1000 - margin.left - margin.right,
    height = 100 - margin.top - margin.bottom;

var y = d3.scale.ordinal()
    .rangeRoundBands([0, height], .3);

var x = d3.scale.linear()
    .rangeRound([0, width]);

var color = d3.scale.ordinal()
    .range(["#cccccc", "#92c6db", "#086fad"]);

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("top");

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")

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

  color.domain(["Allocated Priority %", "Allocated Default %", "Spare Capacity %"]);


  // d3.csv("js/raw_data.csv", function(error, data) {

  data.forEach(function(d) {
    d["Allocated Priority %"] = +d[1]*100/d.N;
    d["Allocated Default %"] = +d[2]*100/d.N;
    d["Spare Capacity %"] = +d[3]*100/d.N;

    var x0 = 0;
    var idx = 0;
    d.boxes = color.domain().map(function(name) { return {name: name, x0: x0, x1: x0 += +d[name], N: +d.N, n: +d[idx += 1]}; });

  });

  var min_val = d3.min(data, function(d) {
          return d.boxes["0"].x0;
          });

  var max_val = d3.max(data, function(d) {
          return d.boxes["2"].x1;
          });

  x.domain([min_val, max_val]).nice();
  y.domain(data.map(function(d) { return d.link_name; }));

  svg.append("g")
      .attr("class", "x axis")
      .call(xAxis);

  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)

  var vakken = svg.selectAll(".Link")
      .data(data)
    .enter().append("g")
      .attr("class", "bar")
      .attr("transform", function(d) { return "translate(0," + y(d.link_name) + ")"; });

  var bars = vakken.selectAll("rect")
      .data(function(d) { return d.boxes; })
    .enter().append("g").attr("class", "subbar");

  bars.append("rect")
      .attr("height", y.rangeBand())
      .attr("x", function(d) { return x(d.x0); })
      .attr("width", function(d) { return x(d.x1) - x(d.x0); })
      .style("fill", function(d) { return color(d.name); });

  bars.append("text")
      .attr("x", function(d) { return x(d.x0); })
      .attr("y", y.rangeBand()/2)
      .attr("dy", "0.5em")
      .attr("dx", "0.5em")
      .style("font" ,"10px sans-serif")
      .style("text-anchor", "begin")
      .text(function(d) { return d.n !== 0 && (d.x1-d.x0)>3 ? d.n : "" });

  vakken.insert("rect",":first-child")
      .attr("height", y.rangeBand())
      .attr("x", "1")
      .attr("width", width)
      .attr("fill-opacity", "0.5")
      .style("fill", "#F5F5F5")
      .attr("class", function(d,index) { return index%2==0 ? "even" : "uneven"; });

  svg.append("g")
      .attr("class", "y axis")
  .append("line")
      .attr("x1", x(0))
      .attr("x2", x(0))
      .attr("y2", height);

  var startp = svg.append("g").attr("class", "legendbox").attr("id", "mylegendbox");
  // this is not nice, we should calculate the bounding box and use that
  var legend_tabs = [0, 150, 300];
  var legend = startp.selectAll(".legend")
      .data(color.domain().slice())
    .enter().append("g")
      .attr("class", "legend")
      .attr("transform", function(d, i) { return "translate(" + legend_tabs[i] + ",-45)"; });

  legend.append("rect")
      .attr("x", 0)
      .attr("width", 18)
      .attr("height", 18)
      .style("fill", color);

  legend.append("text")
      .attr("x", 22)
      .attr("y", 9)
      .attr("dy", ".35em")
      .style("text-anchor", "begin")
      .style("font" ,"10px sans-serif")
      .text(function(d) { return d; });

  d3.selectAll(".axis path")
      .style("fill", "none")
      .style("stroke", "#000")
      .style("shape-rendering", "crispEdges")

  d3.selectAll(".axis line")
      .style("fill", "none")
      .style("stroke", "#000")
      .style("shape-rendering", "crispEdges")

  var movesize = width/2 - startp.node().getBBox().width/2;
  d3.selectAll(".legendbox").attr("transform", "translate(" + movesize  + ",0)");

// });



}

as can be seen the current positioning of the tick text is to the right. i tried the following idea:

 svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
  .selectAll("text")
    .style("text-anchor", "start");

but it did not position the ticks in the desired alignment. any ideas?

Upvotes: 1

Views: 4070

Answers (2)

garetheddies
garetheddies

Reputation: 11

You can set the text-anchor to "start" and adjust the x position with translate, I added the code below in the chart model "boxPlotChart.js"

 g.select('.nv-y.nv-axis').selectAll('.tick').selectAll('text')
                .style('text-anchor','start')
                .attr('transform', function(d,i,j) { return 'translate(-14,0)' });

 g.select('.nv-y.nv-axis').selectAll('.nv-axisMaxMin').selectAll('text')
                .style('text-anchor','start')
                .attr('transform', function(d,i,j) { return 'translate(-16,0)' });

Upvotes: 0

meetamit
meetamit

Reputation: 25157

You can make the Y axis right-oriented, which will have the effect of positioning all the labels to the right of the axis, left-aligning them:

var yAxis = d3.svg.axis()
  .scale(y)
  .orient("right")// <- 1st step

At that point the labels would disappear, because they'll get covered up by the bars of the graph.

But then you can shift all those left-aligned labels some constant distance in the negative X direction, such that they're back on the left side of the Y axis, but still left-aligned the way you wanted. tickPadding() is a way to shift them:

var yAxis = d3.svg.axis()
  .scale(y)
  .orient("right")
  .tickPadding(-180)

Here's your example, modified with the above: http://jsfiddle.net/2khbceut/3/

Maybe hardcoding the -180 is ok for you. If you need that amount to be dynamic, you can compute it using getBBox() on each text element of the axis and taking the maximum width to be the negative offset.

Upvotes: 3

Related Questions