Published
Edited
Mar 3, 2019
1 star
Insert cell
Insert cell
colors = ({
blue: '#00e0e0',
orange: '#f5ab35',
darkBlue: '#007acc',
})
Insert cell
Insert cell
tlColors = ({
month: '#ccc',
today: '#888',
open: '#FFD200',
school: '#72CDF4',
closed: '#005581',
textSchool: '#fff',
textOpen: '#1295d8',
textClosed: 'white',
})
Insert cell
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()
}
Insert cell
Insert cell
Insert cell
{
const height = 100
const margin = {
left:10
}
const svg = d3.select(DOM.svg(width, height))
const g = svg.append('g')
.attr('transform', `translate(${margin.left},0)`)
const agg = d3.merge(Object.keys(courses).map(k=>courses[k]))
const sumUnits = d3.sum(agg, d=>d.units)
const x = d3.scaleLinear()
.domain([0, sumUnits])
.range([0, width])
const counts = Object.keys(courses).map(k=>courses[k])
const rectWidth = (d) => d.count/sumUnits*width
const data = Object.keys(courses).map(k=>({type:k, courses:courses[k], count: d3.sum(courses[k], c=>c.units)}))
console.log(data)
g.append('g')
.attr('transform', `translate(0,${height/2-30})`)
.call(d3.axisTop(x))
const dataG = g.selectAll('rect').data( data ).enter()
.append('g')
.attr('transform', (d,i,a)=>{
//rectWidth( d3.select(a[i-1]).data()[0])
return `translate(${i>0 ? data.reduce((a,v,iX)=> a + (iX < i? rectWidth(v) :0),0) : 0},${height/2})`})

dataG.append('rect')
.attr('height', 20)
.attr('width', rectWidth)
.attr('fill', (d,i,a)=>d3.schemeCategory10[i])
dataG.append('text')
.text(d=>d.type)
.attr('text-anchor','start')
.attr('alignment-baseline','hanging')
.attr('font-size', 20)
.attr('fill', 'white')
yield svg.node()
}
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more