chart = {
const globalScale = width / 5000
const svg = d3.create('svg')
.attr('viewBox', [0, 0, width+350, height+100])
.attr('fill', 'transparent')
svg.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "transparent");
svg
.append('rect')
.attr('width', 235)
.attr('height', 70)
.attr('x', 5)
.attr('y', 5)
.attr('fill', '#636465')
svg
.append('rect')
.attr('width', 15)
.attr('height', 15)
.attr('x', 10)
.attr('y', 10)
.attr('fill', '#9547D2')
svg
.append('rect')
.attr('width', 15)
.attr('height', 15)
.attr('x', 10)
.attr('y', 30)
.attr('fill', '#E6FA03')
svg
.append('rect')
.attr('width', 15)
.attr('height', 15)
.attr('x', 10)
.attr('y', 50)
.attr('fill', '#6FF803')
svg // added text for NLP to legend
.append('text')
.attr('font-family', 'Verdana, sans-serif')
.attr("font-size", '12px')
.attr("fill", '#D1D5DB')
.attr('x', 30)
.attr('y', 22.5)
.text("Funding above $1B")
svg // added text for CV to legend
.append('text')
.attr('font-family', 'Verdana, sans-serif')
.attr("font-size", '12px')
.attr("fill", '#D1D5DB')
.attr('x', 30)
.attr('y', 42.5)
.text("Funding between $500M and $1B")
svg // added text for VL to legend
.append('text')
.attr('font-family', 'Verdana, sans-serif')
.attr("font-size", '12px')
.attr("fill", '#D1D5DB')
.attr('x', 30)
.attr('y', 62.5)
.text("Funding below $500M")
const g = svg.append('g')
.attr('cursor', 'grab')
g.selectAll('rect') // creates line for timeline
.data(epochs)
.join('rect')
.attr('x', ({from}) => from)
.attr('y', (height/1.5)+100)
.attr('width', ({duration}) => duration)
.attr('height', height/50)
.attr('fill', (d, i) => d3.interpolateGreens(1-(i/20))) //changed color and range
.on('click', (event) => {
console.log('Clicked', event)
})
const groupEventLabels = svg.append('g')
.attr('class', 'event-labels')
.attr('cursor', 'grab')
const dur = 400
const eventLabels = groupEventLabels.selectAll('event-labels')
.data(highcategory) //changed data
.join('g')
.attr('transform', ({Time}) => 'translate('+ Time * globalScale +' '+height/2+')')
eventLabels.append('circle') // changed appearance and placement of circles
.attr('cx', 0)
.attr('cy', 225)
.attr('r', 5)
.style('opacity', 0)
.attr('transform-origin', '50% 50%')
.attr('stroke', '#9547D2')
.attr('stroke-width', 2)
.attr('fill', '#9547D2')
.transition() // this transition makes the data points appear roughly in order
.duration(dur)
.ease(d3.easeLinear)
.delay((d, i) => (i+4) * dur)
.style('opacity', 1);
eventLabels.append('text') // changed appearance and placement of text
.attr('x', 10)
.attr('y', 30+100)
.style('opacity', 0)
.attr('text-anchor', 'start')
.attr('alignment-baseline', 'middle')
.text(d => d.Name)
.attr('font-family', 'Verdana, sans-serif')
.attr("font-size", '14px')
.attr("fill", '#9547D2')
.transition() // this transition makes the data points appear roughly in order
.duration(dur)
.ease(d3.easeLinear)
.delay((d, i) => (i+4) * dur)
.style('opacity', 1);
eventLabels.append('rect') // changed appearance and placement of lines
.attr('x', -0.5)
.attr('y', 21+100)
.style('opacity', 0)
.attr('width', 1)
.attr('height', height*0.5)
.attr('stroke', '#D1D5DB')
.attr('stroke-width', 0)
.attr('fill', '#9547D2')
.transition() // this transition makes the data points appear roughly in order
.duration(dur)
.ease(d3.easeLinear)
.delay((d, i) => (i+4) * dur)
.style('opacity', 1);
const eventLabels2 = groupEventLabels.selectAll('event-labels') // added group due to more data
.data(mediumcategory) // changed data
.join('g')
.attr('transform', ({Time}) => 'translate('+ Time * globalScale +' '+height/2+')')
eventLabels2.append('circle') // changed appearance and placement of circles
.attr("cy", 225)
.attr('cx', 0)
.style('opacity', 0)
.attr('r', 5)
.attr('transform-origin', '50% 50%')
.attr('stroke', '#E6FA03')
.attr('stroke-width', 2)
.attr('fill', '#E6FA03')
.transition() // this transition makes the data points appear roughly in order
.duration(dur)
.ease(d3.easeLinear)
.delay((d, i) => i * (dur-100))
.style('opacity', 1);
eventLabels2.append('text') // changedchanged appearance and placement of text
.attr('x', 10)
.attr('y', 51+100)
.style('opacity', 0)
.attr('text-anchor', 'start')
.attr('alignment-baseline', 'middle')
.text(d => d.Name)
.attr('font-family', 'Verdana, sans-serif')
.attr("font-size", '14px')
.attr("fill", '#E6FA03')
.transition() // this transition makes the data points appear roughly in order
.duration(dur)
.ease(d3.easeLinear)
.delay((d, i) => i * (dur-100))
.style('opacity', 1);
eventLabels2.append('rect') // changchanged appearance and placement of lines
.attr('x', -0.5)
.attr('y', 45+100)
.style('opacity', 0)
.attr('width', 1)
.attr('height', height*0.375)
.attr('stroke', '#D1D5DB')
.attr('stroke-width', 0)
.attr('fill', '#E6FA03')
.transition() // this transition makes the data points appear roughly in order
.duration(dur)
.ease(d3.easeLinear)
.delay((d, i) => i * (dur-100))
.style('opacity', 1);
const eventLabels3 = groupEventLabels.selectAll('event-labels') // added group due to more data
.data(lowcategory) // changed data
.join('g')
.attr('transform', ({Time}) => 'translate('+ Time * globalScale +' '+height/2+')')
eventLabels3.append('circle') // changed appearance and placement of circles
.attr('cx', 0)
.attr('cy', 225)
.style('opacity', 0)
.attr('r', 5)
.attr('transform-origin', '50% 50%')
.attr('stroke', '#6FF803')
.attr('stroke-width', 2)
.attr('fill', '#6FF803')
.transition() // this transition makes the data points appear roughly in order
.duration(dur)
.ease(d3.easeLinear)
.delay((d, i) => (i+14) * dur)
.style('opacity', 1);
eventLabels3.append('text') // changed appearance and placement of text
.attr('x', 10)
.attr('y', 76+100)
.style('opacity', 0)
.attr('text-anchor', 'start')
.attr('alignment-baseline', 'middle')
.text(d => d.Name)
.attr('font-family', 'Verdana, sans-serif')
.attr("font-size", '14px')
.attr("fill", '#6FF803')
.transition() // this transition makes the data points appear roughly in order
.duration(dur)
.ease(d3.easeLinear)
.delay((d, i) => (i+14) * dur)
.style('opacity', 1);
eventLabels3.append('rect') // changed appearance and placement of lines
.attr('x', -0.5)
.attr('y', 70+100)
.style('opacity', 0)
.attr('width', 1)
.attr('height', height*0.25)
.attr('stroke', '#6FF803')
.attr('stroke-width', 0)
.attr('fill', '#6FF803')
.transition() // this transition makes the data points appear roughly in order
.duration(dur)
.ease(d3.easeLinear)
.delay((d, i) => (i+14) * dur)
.style('opacity', 1);
const groupTimeLabels = svg.append('g')
.attr('class', 'time-labels')
.attr('cursor', 'grab')
const timeLabels = groupTimeLabels.selectAll('time-labels') // adding dates to the timeline
.data(timeLabelsData)
.join('g')
.attr('transform', ({Time}) => 'translate('+ Time * globalScale +' '+height/2+')')
timeLabels.append('text') // adds the labels
.attr('x', 10)
.attr('y', (height - 20)+100)
.attr('text-anchor', 'start')
.attr('alignment-baseline', 'middle')
.text(d => d.text)
.attr('font-family', 'Verdana, sans-serif')
.attr("font-size", '14px')
.attr("fill", '#D1D5DB')
timeLabels.append('rect') // adds the lines down from the timeline to the dates
.attr('x', -0.5)
.attr('y', (height*0.62)+100)
.attr('width', 1)
.attr('height', height*0.31)
.attr('stroke', '#D1D5DB')
.attr('stroke-width', 0)
.attr('fill', '#D1D5DB')
timeLabels.append('rect') // added line underneath dates for style
.attr('x', -0.5)
.attr('y', (height*0.93)+100)
.attr('width', width*0.05)
.attr('height', 1)
.attr('stroke', '#D1D5DB')
.attr('stroke-width', 0)
.attr('fill', '#D1D5DB')
const zoom = d3.zoom() // zoom interaction
.extent(extent)
.scaleExtent(scaleExtent)
.translateExtent(translateExtent)
.on('zoom', () => {
const {k, x, y} = d3.event.transform
g.attr('transform', 'translate(' + x + ' 0) scale(' + (k) + ' 1)')
eventLabels.attr('transform', ({Time}) => 'translate(' + (x + Time * k) + ' '+ 10 +')')
eventLabels2.attr('transform', ({Time}) => 'translate(' + (x + Time * k) + ' '+ 10 +')') // added zoom interaction for data
eventLabels3.attr('transform', ({Time}) => 'translate(' + (x + Time * k) + ' '+ 10 +')') // added zoom interaction for data
timeLabels.attr('transform', ({time}) => 'translate(' + (x + time * k) + ' '+ 10 +')')
})
svg.call(zoom)
svg.call(zoom.scaleBy, globalScale)
return svg.node();
}