This demonstrates how to place values and labels between tick marks along the x-axis using D3.js.
View and run the code at https://bl.ocks.org/ecgan/6da307ac465745bfc801850f4c1b57c6.
license: gpl-3.0 |
This demonstrates how to place values and labels between tick marks along the x-axis using D3.js.
View and run the code at https://bl.ocks.org/ecgan/6da307ac465745bfc801850f4c1b57c6.
[ | |
{ | |
"value": 10, | |
"startDate": "2018-01-01", | |
"endDate": "2018-01-07", | |
"week": "Week 1" | |
}, { | |
"value": 5, | |
"startDate": "2018-01-08", | |
"endDate": "2018-01-14", | |
"week": "Week 2" | |
}, { | |
"value": 15, | |
"startDate": "2018-01-15", | |
"endDate": "2018-01-21", | |
"week": "Week 3" | |
}, { | |
"value": 45, | |
"startDate": "2018-01-22", | |
"endDate": "2018-01-29", | |
"week": "Week 4" | |
}, { | |
"value": 85, | |
"startDate": "2018-01-29", | |
"endDate": "2018-02-04", | |
"week": "Week 5" | |
}, { | |
"value": 70, | |
"startDate": "2018-02-05", | |
"endDate": "2018-02-11", | |
"week": "Week 6" | |
}, { | |
"value": 15, | |
"startDate": "2018-02-12", | |
"endDate": "2018-02-18", | |
"week": "Week 7" | |
}, { | |
"value": 40, | |
"startDate": "2018-02-19", | |
"endDate": "2018-02-25", | |
"week": "Week 8" | |
}, { | |
"value": 25, | |
"startDate": "2018-02-26", | |
"endDate": "2018-03-04", | |
"week": "Week 9" | |
}, { | |
"value": 30, | |
"startDate": "2018-03-05", | |
"endDate": "2018-03-11", | |
"week": "Week 10" | |
} | |
] |
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
.graph .line { | |
fill: none; | |
stroke: #CC0000; | |
stroke-width: 3; | |
} | |
.graph #xAxisWeek .tick.midWeek line { | |
display: none; | |
} | |
.graph #xAxisWeek .tick.endWeek text { | |
display: none; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="graph"> | |
<svg width="960" height="500"></svg> | |
</div> | |
<script> | |
let svg = d3.select("svg"); | |
let margin = {top: 20, right: 20, bottom: 30, left: 40}; | |
let width = svg.attr("width") - margin.left - margin.right; | |
let height = svg.attr("height") - margin.top - margin.bottom; | |
let g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
d3.json('data.json', (error, data) => { | |
if (error) throw error; | |
// massage data. | |
let graphData = data.map((item) => { | |
let start = new Date(item.startDate + 'T00:00:00'); | |
let end = new Date(item.endDate + 'T24:00:00'); | |
let mid = new Date((start.getTime() + end.getTime()) / 2); | |
return { | |
x: item.week, | |
y: item.value, | |
startDate: start, | |
endDate: end, | |
midDate: mid | |
}; | |
}); | |
// create scales based on data. | |
let yScale = d3.scaleLinear() | |
.rangeRound([height, 0]) | |
.domain([0, 100]) | |
.nice(); | |
let xScale = d3.scaleTime() | |
.domain([ | |
new Date(graphData[0].startDate), | |
new Date(graphData[graphData.length-1].endDate) | |
]) | |
.rangeRound([0, width]) | |
.clamp(true); | |
let lineGenerator = d3.line() | |
.x((d) => { return xScale(d.midDate); }) | |
.y((d) => { return yScale(d.y); }) | |
.curve(d3.curveLinear); | |
// generate linear graph. | |
g.append('g') | |
.attr('id', 'line') | |
.append('path') | |
.datum(graphData) | |
.attr('class', 'line') | |
.attr('d', lineGenerator); | |
// generate y-axis. | |
let yAxis = d3.axisLeft(yScale); | |
g.append('g') | |
.attr('id', 'yAxis') | |
.call(yAxis); | |
// generate x-axis. | |
let tickValues = graphData | |
.map((value) => [value.midDate, value.endDate]) | |
.reduce((acc, cur) => { | |
return acc.concat(cur); | |
}, []); | |
let xAxisWeekGenerator = d3.axisBottom(xScale) | |
.tickValues(tickValues) | |
.tickSize(10) | |
.tickPadding(5) | |
.tickFormat((d, i) => { | |
let index = Math.floor(i / 2); | |
return graphData[index].x; | |
}); | |
let xAxisWeekUi = g.append('g') | |
.attr('id', 'xAxisWeek') | |
.attr('transform', `translate(0, ${height})`) | |
.call(xAxisWeekGenerator); | |
xAxisWeekUi.selectAll('.tick') | |
.attr('class', (d, i) => { | |
if (i % 2 === 0) { | |
return 'tick midWeek'; | |
} | |
return 'tick endWeek'; | |
}); | |
}); | |
</script> | |
</body> |