简体   繁体   中英

Horizontal Bar chart using d3 js

I am using d3.js for plotting a bar chart. I want to show bar chart between two input values but in form of string values instead of integer values in x-axis.

[![An example of what I am trying to achive][1]][1]

var y-axis= ['Accessories', 'Audiophile', 'Camera & Photo', 'Cell Phones', 'Computers','eBook Readers'];

var x-axis= ['development', 'design', 'testing', 'UAT', 'LiveDeployment'];

Reference url which I have used is [D3 js simple horizontal bar chart][2]

Code Consist below features : 1) Horizontal bar using D3 js and custom x-axis labels 2) Show x-axis lines as text wrap : (01/01/2016 Production Start Date) 3) Show y-axis lines as text wrap : (Category 1Category 1Category 1Category 1)

function wrap(text, width) {
  text.each(function() {
    var text = d3.select(this),
        words = text.text().split(/\s+/).reverse(),
        word,
        line = [],
        lineNumber = 0,
        lineHeight = 1.1, // ems
        y = text.attr("y"),
        dy = parseFloat(text.attr("dy")),
        tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
    while (word = words.pop()) {
      line.push(word);
      tspan.text(line.join(" "));
      if (tspan.node().getComputedTextLength() > width) {
        line.pop();
        tspan.text(line.join(" "));
        line = [word];
        tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
      }
    }
  });
}

data = [
    {label:"Category 1Category 1Category 1", value:25},
    {label:"Category 2", value:50},
    {label:"Category 3", value:100},
    {label:"Category 4", value:75},
    {label:"Category 5", value:40},
    {label:"Category 6", value:20}
];

var axisMargin = 10,
margin = 20,
valueMargin = 2,
width = parseInt(d3.select('#barchart').style('width'), 9),
height = parseInt(d3.select('body').style('height'), 9),
barHeight = (height-axisMargin-margin*2)* 0.6/data.length,
barPadding = (height-axisMargin-margin*2)*0.4/data.length,
data, bar, svg, scale, scale2, xAxis, labelWidth = 0;

max = d3.max(data, function(d) { return d.value; });

svg = d3.select('#barchart')
        .append("svg")
        .attr("width", width)
        .attr("height", height);


bar = svg.selectAll("g")
        .data(data)
        .enter()
        .append("g");

bar.attr("class", "bar")
        .attr("cx",0)
        .attr("transform", function(d, i) {
            return "translate(" + margin + "," + (i * (barHeight + barPadding) + barPadding) + ")";
        });

bar.append("text")
        .attr("class", "label")
        .attr("y", barHeight / 2)
        .attr("dy", ".35em") //vertical align middle
        .text(function(d){
            return d.label;
        }).each(function() {
            labelWidth = 150; //Math.ceil(Math.max(labelWidth, this.getBBox().width));
        })
        .call(wrap, 150);


scale = d3.scale.linear()
        .domain([0, max])
        .range([0, width - margin*2 - labelWidth]);

/*scale = d3.scale.linear()
        .domain([0, max])
        .range([0, width - margin*2 - labelWidth]);

xAxis = d3.svg.axis()
        .scale(scale)
        .tickSize(-height + 2*margin + axisMargin);
        .orient("bottom");*/

var scale2 = d3.scale.ordinal()
      .domain(["01/01/2016 Production Start Date", "01/01/2016 Production End Date", "Transcoding", "Encryption", "Published", "Published Release Date"])
      .rangePoints([0, width - margin*2 - labelWidth]);

var xAxis = d3.svg.axis()
        .scale(scale2)
        .tickSize(-height + 2*margin + axisMargin)
        .orient("bottom");        

bar.append("rect")
    .attr("transform", "translate("+labelWidth+", 0)")
    .attr("height", barHeight)
    .attr("width", function(d){
        return scale(d.value);
});

bar.append("text")
    .attr("class", "value")
    .attr("y", barHeight / 2)
    .attr("dx", -valueMargin + labelWidth) //margin right
    .attr("dy", ".35em") //vertical align middle
    .attr("text-anchor", "end")
    .text(function(d){
            return (d.value+"%");
        })
    .attr("x", function(d){
        var width = this.getBBox().width;
        return Math.max(width + valueMargin, scale(d.value));
});

svg.insert("g",":first-child")
        .attr("class", "axisHorizontal")
        .attr("transform", "translate(" + (margin + labelWidth) + ","+ (height - axisMargin - margin)+")")
        .call(xAxis)
        .selectAll(".tick text")
        .call(wrap, 100);

You certainly can format the ticks, but there is an easy workaround: create another scale just for the ticks, and call this alternative scale for your x axis:

var xScaleString = d3.scale.ordinal()
      .domain(["design", "development", "testing", "UAT"])
      .rangePoints([0, width]);

The advantage of using this unusual approach is that you can spread the strings along the x axis the way you want. The disadvantage is that you may not have a perfect match regarding the values of your original scale (10, 20, 30 etc).

Remember to keep your original scale (it's the one used for the rectangles).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM