timeline = function * (width){
const qtrHeight = 100
const height = 250
const svg = d3.select(DOM.svg(width,height))
const x = d3.scaleTime()
.domain([d3.min(dates,d=>d.start),d3.max(dates,d=>d.end)])
.range([0,width])
const g = svg.append('g')
const months = d3.timeMonths(new Date(), d3.max(dates, d=>d.end))
const monthG = g.selectAll('.month').data(months).enter().append('g')
.attr('transform', d=>`translate(${x(d)}, ${height/2+qtrHeight/2+10})`)
const monthTickLength = 40;
monthG
.append('path')
.attr('d', `M 0 0 L 0 ${monthTickLength}`)
.attr('stroke', '#ccc')
.attr('stroke-dasharray', '1,2')
monthG
.append('text')
.text((d,i)=>(((+d3.timeFormat('%m')(d) % 3) === 0) ? d3.timeFormat('%b')(d) : ``))
.attr('transform', `translate(0,${monthTickLength+5}) rotate(45)`)
.attr('fill', tlColors.month)
const todayG = g.append('g')
.attr('transform', `translate(${x(new Date())}, 0)`)
todayG.append('text')
.attr('transform', `translate(${20}, 45)`)
.attr('text-anchor', 'middle')
.attr('font-size', 20)
.attr('font-weight', 600)
.attr('fill', tlColors.today)
.text('Today')
todayG.append('path')
.attr('transform', `translate(${0}, 100)`)
.attr('d', 'M 0 0 L 0 -50 ')
.attr('stroke', tlColors.today)
.attr('stroke-width', 2)
.attr('fill', 'none')
.attr('stroke-dasharray', '3,6,3')
const yearMarkers = g.selectAll('.year').data([2019,2020]).enter().append('g')
.attr('transform', d=>`translate(${x(new Date(d,0,1))+1}, 0)`)
yearMarkers.append('text')
.attr('transform', d=>`translate(${0}, ${height})`)
.attr('text-anchor', 'start')
.attr('font-size', 20)
.attr('font-weight', 600)
.attr('fill', tlColors.today)
.text(d=>d)
yearMarkers.append('path')
.attr('transform', d=>`translate(${0}, 80)`)
.attr('d', 'M 0 10 L 0 150')
.attr('stroke', tlColors.today)
.attr('stroke-width', 2)
.attr('fill', 'none')
.attr('stroke-dasharray', '3,6,3')
const qtr = g.selectAll('.time').data(dates).enter()
.append('g')
.attr('transform', d=>`translate(${x(d.start)}, ${height/2-qtrHeight/2})`)
qtr.append('rect')
.attr('width', d=>x(d.end)-x(d.start))
.attr('height', qtrHeight)
.attr('rx', 10)
.attr('ry', 10)
.attr('fill', d=>{
if(d.at === 'open')
return tlColors.open
if(d.at === 'school')
return tlColors.school
return tlColors.closed
})
const t = qtr.append('text')
.attr('y', qtrHeight/2)
.attr('x', q=>(x(q.end)-x(q.start))/2)
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'middle')
.attr('fill', d=>(d.at==='open') ? tlColors.textOpen : tlColors.textSchool)
.attr('font-weight',600)
t.selectAll('.xxx').data(q=>[q,q]).enter()
.append('tspan')
.attr('x', q=>(x(q.end)-x(q.start))/2)
.attr('y', (d,i)=>qtrHeight/2+(i?20:0))
.text((d,i)=>{
if(d.at==='open') {
if(!i) return `Open for`;
if(d.for==='internship')
return `Internship`
return 'Full-Time'
}
if(!i)
return `${d.time.slice(0,2).toUpperCase()}${d.start.getFullYear()-2000}`
return `${d.at[0].toUpperCase() + d.at.slice(1)}`;
})
yield svg.node()
}