在d3.js中将x轴与刻度线对齐

时间:2015-04-28 16:19:10

标签: d3.js

如何将x轴值正确排列到图表中的垂直线?目前他们没有正确对齐。

var data = [
  {
    "due": 89.99, 
    "datestr": "2012-12-01 00:00:00", 
    "paid": 89.99
  }, 
  {
    "due": 89.99, 
    "datestr": "2013-01-01 00:00:00", 
    "paid": 101.25
  }, 
  {
    "due": 109.99, 
    "datestr": "2013-02-01 00:00:00", 
    "paid": 143.69
  }, 
  {
    "due": 109.99, 
    "datestr": "2013-03-01 00:00:00", 
    "paid": 130.65
  }, 
  {
    "due": 139.99, 
    "datestr": "2013-04-01 00:00:00", 
    "paid": 150.25
  },

  {
    "due": 149.99, 
    "datestr": "2013-05-01 00:00:00", 
    "paid": 139.99
  },
  {
    "due": 149.99, 
    "datestr": "2013-06-01 00:00:00", 
    "paid": 139.99
  },
  {
    "due": 89.99, 
    "datestr": "2013-07-01 00:00:00", 
    "paid": 139.99
  }
];




//Load values into new arrays

var amtDue = new Array();
var amtPaid = new Array();

for(var i=0; i < data.length; i++) {
  amtDue[i] = data[i].due;
  amtPaid[i] = data[i].paid;
}

// Margins, width and height. 
var margin = {top: 20, right: 20, bottom: 60, left: 50},
    width = 1000,
    height = 400,
    padding = 100;

// Scales.
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var due = d3.scale.linear().range([0, width]);
var paid = d3.scale.linear().range([0, width]);


//Domains
x.domain([d3.min(data, function(d) { return d.date; }), d3.max(data, function(d) { return d.date;})]);
y.domain([50, 300]);
due.domain([0, amtDue.length]);
paid.domain([0, amtPaid.length]);

// Construct our SVG object.
var svg = d3.select(".system-efficiency").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// X-axis MONTHS.
var xAxis = d3.svg.axis()
    .scale(x)
    .orient("top")
    .tickSize(-height)
    .tickFormat(d3.time.format('%b'));
svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(100," + 0 + ")")
    .call(xAxis);

//X-axis Due Date
var dDate = d3.svg.axis()
    .scale(due)
    .orient("bottom")
    .tickSize(0)
    .tickFormat(function(d, i) {return amtDue[i];});
svg.append("g")
    .attr("class", "damount axis")
    .attr("transform", "translate(100," + (height) + ")")
    .call(dDate);

//X-axis Paid Date
var pDate = d3.svg.axis()
    .scale(paid)
    .orient("bottom")
    .tickSize(0)
    .tickFormat(function(d, i) {return amtPaid[i];});
svg.append("g")
    .attr("class", "pamount axis")
    .attr("transform", "translate(100," + (height+20) + ")")
    .call(pDate);

//Y-axis
var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")
    .tickSize(0);

svg.append("g")
    .attr("class", "y axis")
    .attr("transform", "translate(" + 0 + ",0)")
    .call(yAxis);

// Date parsing.
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S");
data.forEach(function(d) {
  d.date = parseDate.parse(d.datestr);
  d.close = +d.close;
});

// Set scale domains. 
x.domain(d3.extent(data, function(d) { return d.date; }));
//y.domain([0, d3.max(data, function(d) { return d.due; })]);

// Call x-axis. 
d3.select(".x.axis")
    //.transition().duration(1000)
    .call(xAxis);


// Draw bars for amount due. 
var bars = svg.selectAll("rect")
        .data(data, function(d) { return d.datestr; });

bars.exit().remove();

// bars.transition().duration(1000)
//     .attr("x", function(d) { return x(d.date); })
//     .attr("width", width / data.length)
//     .attr("y", function(d) { return y(d.due); })
//     .attr("height", function(d) { return height - y(d.due);});

bars.enter().append("rect")
    .attr("class", "duebar")
    .attr("width", width/data.length)
    .attr("x", function(d, i) {  return i * (width / data.length); })
    .attr("y", height)
    .attr("height", 0)
    .transition().duration(1000)
    .attr("y", function(d) { return y(d.due); })
    .attr("height", function(d) { return (y(d.due)+3)-y(d.due);});



// Line function.
var line = d3.svg.line()
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.paid); });


// Draw line. 
 svg.append("path")
      .datum(data)
      .attr("class", "line")
      .attr("d", line);

这是fiddle

1 个答案:

答案 0 :(得分:2)

在这里小提琴:http://jsfiddle.net/henbox/hbmwbnx6/

使用您当前的方法,这是可以修复的。首先,您有8个数据值(Dec&#39; 12到7月和#39; 13)。将d3.time.scale()与该日期域一起使用将为您提供8个月的&#39;勾选,但是比例分为7个相等的间隙&#39;在蜱之间。

因此,要排列d3.scale.linear()比例,您应该使用:

due.domain([0, amtDue.length - 1]);

而不是:

due.domain([0, amtDue.length]);

因为数组长度从1开始计数,而不是0。

另请注意,我从您的代码中删除了多个横向translate

我之所以这样说只是一种解决方法,那就是&#34;到期的条数&#34;几个月没有正确排队。这是因为条形宽度相等(使用.attr("width", width/(data.length -1)))但是月份(d3.time标度)的长度不相等:

mis-aligned bars

解决方法是使用x(时间)刻度来定义条宽

<强>更新

通过从数据中获取当前日期和之前的日期值,这里是对条形宽度问题的(略微hacky)解决方案的更新:http://jsfiddle.net/henbox/hbmwbnx6/1/

代码是:

// The first date from your data - don't hardcode!
var previousdate = new Date("2012-12-01 00:00:00")

bars.enter().append("rect")
    .attr("class", "duebar")
    .attr("width", function(d, i) { 
        widthval = x(d.date) - (x(previousdate));
        previousdate = d.date;
        return widthval;
    })
    .attr("x", function(d, i) { 
        xval = x(previousdate);
        previousdate = d.date;
        console.log(previousdate);
        return xval;
    })
    ...

请注意,此代码突出显示了另一个问题:条形图显示在两个日期之间显示数据,但实际显示特定时间点的数据。 12月&​​12;&#39;到期金额&#39;值未显示,而Jan&#13; 13值在图表中显示为为12月和1月之间的条。您需要决定如何显示此