|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<meta charset="utf-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> |
|
<style> |
|
body { |
|
height: 500px; |
|
background: #f98902; |
|
background-image: linear-gradient( |
|
to bottom, |
|
#f98902, |
|
#0083f7 |
|
); |
|
} |
|
text { font-size: 4px; } |
|
.title { font-size: 5px; } |
|
line, .domain { |
|
fill: none; |
|
stroke-width: .2; |
|
stroke: black; |
|
} |
|
.max { fill: white; } |
|
</style> |
|
</head> |
|
<body> |
|
<svg width="960px" height="480px" viewBox="0 0 200 100"> |
|
</svg> |
|
</body> |
|
<script> |
|
//config |
|
var s = { |
|
width: 200, |
|
height: 100, |
|
m: { |
|
top: 20, |
|
right: 20, |
|
bottom: 25, |
|
left: 30 |
|
} |
|
} |
|
s.plot = { w: s.width - s.m.left - s.m.right, h: s.height - s.m.top - s.m.bottom } |
|
//x-axis is always time, y is linear scale |
|
|
|
var x = d3.time.scale().range([0, s.plot.w]), |
|
y = d3.scale.linear().range([s.plot.h, 0]), |
|
xAxis = d3.svg.axis().scale(x).orient('bottom').tickSize(2, 0), |
|
yAxis = d3.svg.axis().scale(y).orient('left').tickSize(2, 0), |
|
formatDate = d3.time.format('%Y-%m-%d') |
|
|
|
//select svg |
|
var svg = d3.select('svg') |
|
//add group, with margin |
|
svg.append('g') |
|
.attr('class', 'graph') |
|
.attr('width', s.plot.w) |
|
.attr('height', s.plot.h) |
|
.attr('transform', 'translate('+s.m.left+','+s.m.top+')') |
|
|
|
//call data |
|
d3.json('./weather.json', function(err, data) { |
|
if (err) return console.error(err) |
|
|
|
|
|
x.domain([ |
|
new Date(d3.min(data, function(d) { return formatDate.parse(d.date) }) - 86400000), |
|
d3.max(data, function(d) { return formatDate.parse(d.date) }) |
|
]) |
|
// x.domain(d3.extent(data, function(d) { return formatDate.parse(d.date) }) ) |
|
y.domain([d3.min(data, function(d) { return d.min }), d3.max(data, function(d) { return d.max }) ]) |
|
|
|
//account for step-style line graph (add dupe day to beginning of month) |
|
var dLen = data.length, |
|
last = { |
|
date : x.domain()[0].getFullYear()+'-'+(x.domain()[0].getMonth() + 1)+'-'+x.domain()[0].getDate(), |
|
max: data[dLen - 1].max, |
|
min: data[dLen - 1].min |
|
} |
|
data.push(last) |
|
|
|
//create clipping path from d.min data |
|
createGraph(data, 'min', 'clipping') |
|
//create area graph from d.max data, clipped by d.min |
|
createGraph(data, 'max', 'min') |
|
//add title |
|
svg.append('text') |
|
.attr('x', s.width/2) |
|
.attr('y', '3em') |
|
.attr('text-anchor', 'middle') |
|
.attr('class', 'title') |
|
.text('Temperature Range in Farenheit') |
|
}) |
|
|
|
function createGraph(data, accessor, clip) { |
|
//add clipping path, if appropriate |
|
var group = (clip == 'clipping') |
|
? svg.select('.graph') |
|
.append('clipPath') |
|
.attr('id', accessor) |
|
: svg.select('.graph') |
|
|
|
group.append('path') |
|
.datum(data) |
|
.attr('class', accessor) |
|
//clip, if appropriate |
|
.attr('clip-path', (clip && clip != 'clipping') |
|
? 'url(#'+clip+')' |
|
: '' |
|
) |
|
//make area graph |
|
.attr('d', d3.svg.area() |
|
.x(function(d) { return x(formatDate.parse(d.date)) }) |
|
.y0( (clip == 'clipping') |
|
? y(y.domain()[1]) |
|
: y(y.domain()[0]) |
|
) |
|
.y1(function(d) { return y(d[accessor]) }) |
|
.interpolate('step-after') |
|
) |
|
|
|
//make axes, once |
|
if (clip != 'clipping') { |
|
// y-axis |
|
var thisAxisY = group.append('g') |
|
.attr('class', 'y axis') |
|
.call(yAxis) |
|
thisAxisY.selectAll('text') |
|
.attr('dx', 2) |
|
// x-axis |
|
var thisAxisX = group.append('g') |
|
.attr('class', 'x axis') |
|
.attr('transform', 'translate(0,'+s.plot.h+')') |
|
.call(xAxis) |
|
thisAxisX.selectAll('text') |
|
.attr('transform', 'rotate(-90)') |
|
.attr('style', 'text-anchor: end') |
|
.attr('dy', '-.75em') |
|
.attr('dx', '-.75em') |
|
} |
|
|
|
} |
|
|
|
</script> |
|
</html> |