2015-11-04 75 views
2

我需要在d3的帮助下创建具有正值和负值的条形图。图表正常和负值的组合正常工作,但如果我只通过负值或正值X轴不会到达适当的位置。感谢D3条形图无法正常使用,所有负值和正值

Jsfiddle

BarChart Image

//var data = [["Since Mar 10, 2015",150], ["1 year",-100], ["3 year",6.9], ["Since Mar 10, 2010",100]]; 

var data = [["Since Mar 10, 2015",-100], ["1 year",-10]]; 

d3.select("#example") 
.datum(data) 
.call(columnChart() 
    .width(320) 
    .height(240) 
    .x(function(d, i) { return d[0]; }) 
    .y(function(d, i) { return d[1]; })); 

function columnChart() { 
    var margin = {top: 30, right: 10, bottom: 50, left: 50}, 
    width = 20, 
    height = 20, 
    xRoundBands = 0.6, 
    xValue = function(d) { return d[0]; }, 
    yValue = function(d) { return d[1]; }, 
    xScale = d3.scale.ordinal(), 
    yScale = d3.scale.linear(), 
    yAxis = d3.svg.axis().scale(yScale).orient("left"), 
    xAxis = d3.svg.axis().scale(xScale); 
    var isNegative = false;  

function chart(selection) { 
    selection.each(function(data) { 

    // Convert data to standard representation greedily; 
    // this is needed for nondeterministic accessors. 
    for(var i=0; i< data.length; i++){ 
    if(data[i][1] < 0){ 
     isNegative = true; 
    } 
    } 

    data = data.map(function(d, i) { 
    return [xValue.call(data, d, i), yValue.call(data, d, i)]; 
    }); 

    // Update the x-scale. 
    xScale 
     .domain(data.map(function(d) { return d[0];})) 
     .rangeRoundBands([0, width - margin.left - margin.right], xRoundBands); 

    // Update the y-scale. 
    if(data.length < 2){ 
    if(data.map(function(d) { return d[1];}) < 0){ 
     yScale 
      .domain([data.map(function(d) { return d[1];}), 0]) 
      .range([height - margin.top - margin.bottom, 0]) 
      .nice();   
    }else{ 
     yScale 
      .domain([0, data.map(function(d) { return d[1];})]) 
      .range([height - margin.top - margin.bottom, 0]) 
      .nice(); 
    } 
    }else{ 
     yScale 
      .domain(d3.extent(data.map(function(d) { return d[1];}))) 
      .range([height - margin.top - margin.bottom, 0]) 
      .nice(); 
    } 

    // Select the svg element, if it exists. 
    var svg = d3.select(this).selectAll("svg").data([data]); 

    // Otherwise, create the skeletal chart. 
    var gEnter = svg.enter().append("svg").append("g"); 

    gEnter.append("g").attr("class", "y axis"); 
    gEnter.append("g").attr("class", "x axis"); 
    gEnter.append("g").attr("class", "x axis zero"); 

    // Update the outer dimensions. 
    svg .attr("width", width) 
     .attr("height", height); 

    // Update the inner dimensions. 
    var g = svg.select("g") 
     .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

    // Update the y-axis. 
    g.select(".y.axis") 
     .call(yAxis.tickSize(0).ticks(5)) 
     .selectAll("g") 
     .selectAll("text") 
     .text(function(d){ 
      return d+"%"; 
     }); 

    g.append("g") 
     .selectAll("line.line") 
     .data(yScale.ticks(5)) 
     .enter() 
     .append("line") 
     .attr(
      { 
       "class":"line grid tick", 
       "x1" : 0, 
       "x2" : (width - 60), 
       "y1" : function(d){ return yScale(d);}, 
       "y2" : function(d){ return yScale(d);}, 
      }); 
    gEnter.append("g").attr("class", "bars"); 

    // Update the bars. 
    var bar = g.select(".bars") 
    .selectAll(".bar") 
    .data(data); 

    bar.enter().append("rect"); 
    bar.exit().remove(); 
    bar .attr("class", function(d, i) { return d[1] < 0 ? "bar negative" : "bar positive"; }) 
     .attr("x", function(d) { return X(d); }) 
     .attr("y", function(d, i) { return d[1] < 0 ? Y0() : Y(d); }) 
     .attr("width", xScale.rangeBand()) 
     .attr("height", function(d, i) { return Math.abs(Y(d) - Y0()); }); 

    // x axis at the bottom of the chart 
    if(isNegative === true){ 
    var xScaleHeight = height - margin.top - margin.bottom+12; 
    }else{ 
    var xScaleHeight = height - margin.top - margin.bottom; 
}   
    g.select(".x.axis") 
    .attr("transform", "translate(0," + (xScaleHeight) + ")") 
    .call(xAxis.orient("bottom")) 
    .selectAll("text") 
    .call(wrap, xScale.rangeBand()); 

    // zero line 
    g.select(".x.axis.zero") 
    .attr("transform", "translate(0," + Y0() + ")") 
    .attr("class", "zero axis") 
    .call(xAxis.tickFormat("").tickSize(0)); 


    // Update the text in bars. 
    var bar1 = svg.select(".bars").selectAll("text").data(data); 

    bar1 .data(data) 
     .enter() 
     .append("text") 
     .attr("class", "text") 
     .text(function(d) { return d[1]+"%"; }) 
     .attr("x", function(d) { return X(d); }) 
     .attr("y", function(d, i) { return d[1] < 0 ? Math.abs(Y(d)+10) : Y(d)-2; }); 
}); 

}

// Custom function for text wrap 
    function wrap(text, width) { 
    text.each(function() { 
    var text = d3.select(this), 
    words = text.text().split(/\s+/).reverse(), 
    word, 
    line = [], 
    lineNumber = 0, 
    lineHeight = 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() > 55) { 
    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); 
    } 
} 

}); }

// The x-accessor for the path generator; xScale ∘ xValue. 
    function X(d) { 
    return xScale(d[0]); 
} 

function Y0() { 
    return yScale(0); 
} 

// The x-accessor for the path generator; yScale ∘ yValue. 
function Y(d) { 
    return yScale(d[1]); 
} 

chart.margin = function(_) { 
    if (!arguments.length) return margin; 
    margin = _; 
    return chart; 
    }; 

chart.width = function(_) { 
    if (!arguments.length) return width; 
    width = _; 
    return chart; 
    }; 

    chart.height = function(_) { 
    if (!arguments.length) return height; 
    height = _; 
    return chart; 
    }; 

    chart.x = function(_) { 
    if (!arguments.length) return xValue; 
    xValue = _; 
    return chart; 
    }; 

    chart.y = function(_) { 
    if (!arguments.length) return yValue; 
     yValue = _; 
     return chart; 
    }; 

    return chart; 
} 
+0

它工作正常,您认为它应该在哪里结合? – ozil

+0

嘿@ozil请尝试使用所有正数值,例如“var data = [[”自2015年3月10日以后“,100],[”1年“,200]];”X轴将消失。 – MohitAgrawal

+0

你总是想缩放Y轴吗?那么只是在做http://jsfiddle.net/fjuak9bo/8/? – Ian

回答

2

我已经修改了你的例子稍微http://jsfiddle.net/fjuak9bo/9/,我相信为您提供所需的解决方案。

重要的部分是适当地设置您的domainyscale。在这里,我检测所有值是否为+ ve或-ve,并将域设置为-100-0或0-100。

yScale.domain([-100, 100]) 
      .range([height - margin.top - margin.bottom, 0]) 
      .nice();   

    if(min > 0) { 
     // All positive 
     yScale.domain([0, 100]); 
    } else if(max < 0) { 
     // All negative 
     yScale.domain([-100, 0]); 
    } 

如果您的值超过了+ - 100%,您可以根据需要扩展域上的最小/最大值。

+0

感谢您的快速回复@lan,但是如果我通过“data = [[”自2015年3月10日以来, - 100],[“1年”,150]] “钢条走出图表比例,我也需要零轴动态。 – MohitAgrawal

+0

噢,谢谢我为我工作得很好。谢谢@lan – MohitAgrawal

+0

@MohitAgrawal:好的 - 这工作正常吗?还是有一些额外的东西需要回答?如果这符合你的要求或足够的解释让你完成你所需要的,请随时接受这个答案。否则,如果你细说一点,我可以更新/添加评论来解释。 – Ian