Time.Scale and RangeBand in Barchart with D3

时间:2017-04-06 16:46:57

标签: javascript d3.js bar-chart

I have a data source like :

dateRange = [
 { date: 2017-03-23, value: 10 },
 { date: 2017-03-25, value: 15 },
 { date: 2017-04-01, value: 13 },
 { date: 2017-04-02, value: 19 }
];

Results is like this : https://embed.plnkr.co/iOBAuCZmoMePL5P3Jwr4/

I'd like to generate a barchart with an x axis that covers the whole date range ( from 23 of march to 2 of april in that case ). Therefore, every single day between these two dates should appears on the x axis ( and set to 0 ).

I don't want to modify the data source. I know d3 can do that for me with d3.time.scale. As rangeBand is not available while using d3.time.scale, i can't find a way to set the correct barchart width.

Thanks for your help.

1 个答案:

答案 0 :(得分:1)

由于您使用的是序数比例,因此您只需要创建一个包含从开始日期到结束日期的所有日期的数组:

var dateArray = d3.time.days(d3.min(dataset, function(d) {
    return d.date
}), d3.time.day.offset(d3.max(dataset, function(d) {
    return d.date
}), +1));

并将该数组用于您的域名。

请注意,由于d3.time.days中的最后一个值不具有包容性,因此我必须使用offset在结束日期添加额外的一天。

以下是您更改的代码:

var margin = {
     top: 20,
     right: 0,
     bottom: 21,
     left: 30
   },
   height = 300,
   width = 400,
   w = width - margin.left - margin.right,
   h = height - margin.top - margin.bottom;
 var parseDate = d3.time.format("%Y-%m-%d").parse;

 dataset = [{
   date: '2017-03-23',
   value: 10
 }, {
   date: '2017-03-25',
   value: 15
 }, {
   date: '2017-04-01',
   value: 13
 }, {
   date: '2017-04-02',
   value: 19
 }];
 dataset.forEach(function(d) {
   d.date = parseDate(d.date);
 });

 var svg = d3.select('body')
   .append('svg')
   .attr("width", '100%')
   .attr("height", '100%')
   .attr("viewBox", "0 0 " + width + " " + height)
   .attr("preserveAspectRatio", "xMinYMin meet")
   .append("g")
   .attr("transform",
     "translate(" + margin.left + "," + margin.top + ")");

 var dateArray = d3.time.days(d3.min(dataset, function(d) {
   return d.date
 }), d3.time.day.offset(d3.max(dataset, function(d) {
   return d.date
 }), +1));

 var x = d3.scale.ordinal().rangeRoundBands([0, w], .2, .02);
 var xAxis = d3.svg.axis()
   .scale(x)
   .orient("bottom")
   .tickSize(0)
   .tickPadding(5)
   .tickFormat(d3.time.format("%d/%b"));
 x.domain(dateArray);

 svg.append("g")
   .attr("class", "axis easting")
   .attr("transform", "translate(0," + h + ")")
   .call(xAxis)
   .selectAll("text")
   .style("text-anchor", "middle");

 var y = d3.scale.linear().range([h, 0]);
 var yAxis = d3.svg.axis()
   .scale(y)
   .orient("left")
   .ticks(6);
 y.domain([0, d3.max(dataset, function(d) {
   return d.value;
 })]);

 svg.append("g")
   .attr("class", "axis northing")
   .call(yAxis)
   .selectAll("line")
   .attr("x2", w)

 svg.selectAll('rect')
   .data(dataset)
   .enter()
   .append('rect')
   .attr('width', function(d, i) {
     return x.rangeBand();
   })
   .attr('height', function(d, i) {
     return h - y(d.value);
   })
   .attr('x', function(d, i) {
     return x(d.date);
   })
   .attr('y', function(d, i) {
     return y(d.value);
   })
   .attr('fill', 'blue');
.chart {
  width: 450px;
  height: 300px;
  margin: 20px;
}

.axis {
  font-size: 10px;
  line-height: 16px;
}

.northing line {
  stroke: #F2F2F2;
}

line {
  fill: none;
  stroke: #727272;
}

path {
  fill: none;
  stroke: #727272;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>