xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
.axis path, .axis line {
stroke: #ccc;
}
.axis line {
stroke-dasharray: 2;
}
.axis text {
fill: #ccc;
}
.state text {
font-weight: 600;
}
</style>
</head>
<body>
<script>
var width = 250;
var height = 200;
var margin = {top: 20, right: 50, bottom: 20, left: 30};
var xScale = d3.scaleLinear().range([0, width]);
var yScale = d3.scaleLinear().range([height, 0]);
var xAxis = d3.axisBottom()
.scale(xScale)
.ticks(5)
.tickFormat(d => "'" + new String(d).slice(2))
.tickSizeInner(-height)
.tickSizeOuter(0)
.tickPadding(6);
var yAxis = d3.axisLeft()
.scale(yScale)
.ticks(5)
// .tickFormat(d => d + '%')
.tickSizeInner(-width)
.tickSizeOuter(0)
.tickPadding(6);
var line = d3.line()
.x(d => xScale(d.monthsince))
.y(d => yScale(d.ACOM));
var grey = '#636363';
var dispatch = d3.dispatch('load', 'yearchange')
d3.json('data.json', function(err, data) {
console.log(data);
// console.log(obj);
// console.log(flatData);
var xDomain = d3.extent(data, d => d.monthsince)
var yDomain = d3.extent(data, d => d.ACOM)
xScale.domain(xDomain);
yScale.domain(yDomain).nice();
// console.log(xDomain, yDomain)
var dataByState = d3.nest()
.key(d => d.cohort)
.entries(data);
// console.log(dataByState);
//create svg for each state
var svg = d3.select('body')
.selectAll('svg')
.data(dataByState, d=> d.state)
.enter().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] + ')');
dispatch.call('load', this, svg, dataByState);
//default hovered year to 2016
dispatch.call('yearchange', this, 0)
});
//draw the statis graph for each state
dispatch.on('load.graph', (svg,dataByState) =>{
//draw axes
svg.append('g')
// .attr('class', 'x axis') --alernative to next line
.classed('x axis', true)
.attr('transform', 'translate(' + [0, height] + ')')
.call(xAxis);
svg.append('g')
.classed('y axis', true)
.call(yAxis);
//draw lines append + datum, selectAll + data
svg.append('path')
.datum(d => d.values)
.attr('d', line)
.attr('stroke', '#addd8e')
.attr('stroke-width', 2)
.attr('fill', 'none');
//draw rectagle for hover
svg.append('rect')
.attr('width', width)
.attr('height', height)
.attr('opacity', 0)
.on('mousemove', function(){
// x, y position of mouse relative to
//the container i pass in
var [x,y] = d3.mouse(this);
var year = Math.round(xScale.invert(x));
// console.log(x,year)
dispatch.call('yearchange', this, year);
});
});
dispatch.on('load.title', (svg) => {
var title = svg.append('text');
dispatch.on('yearchange.title', year => {
title.text(d => {
var rate = d.values.find(d => d.monthsince === year);
rate = rate ? d3.format('.1f')(rate.rate) + '%' : 'N/A';
return d.key + ' (' + rate + ')';
})
})
});
dispatch.on('load.point', svg =>{
var g = svg.append('g');
g.append('circle')
.attr('fill', 'grey')
.attr('r', 5);
g.append('text')
.attr('font-size', 8)
dispatch.on('yearchange.point', year =>{
g.attr('transform',d => {
var rate = d.values.find(d => d.monthsince === year);
// console.log(d.values)
return 'translate(' + [xScale(rate.year), yScale(rate.rate)] + ')'
});
g.select('text')
.text(d => {
var rate = d.values.find(d=>d.year === year);
return rate.monthsince + '(' + d3.format('.1f')(rate.rate) + '%)';
});
});
});
</script>
</body>
https://d3js.org/d3.v4.min.js