newLineChart = {
const data = genaistartups
const margin = { top: 20, right: 20, bottom: 40, left: 60 };
const width = 783;
const height = 233;
const svg = d3
.select(DOM.svg(width, height));
const xScale = d3
.scalePoint()
.domain(data.map(d => d.year))
.range([margin.left, width - margin.right])
.padding(0.1);
const yScale = d3
.scaleLinear()
.domain([0, d3.max(data, d => d.startups)])
.range([height - margin.bottom, margin.top]);
const line = d3
.line()
.x(d => xScale(d.year))
.y(d => yScale(d.startups));
const dur = 2500
const radius = 5;
svg.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "transparent");
const groupedData = Array.from(d3.group(data, d => d.country));
const uniqueCategories = groupedData.map(([category, data]) => category);
const colorScale = d3.scaleOrdinal()
.domain(uniqueCategories)
.range(d3.schemeCategory10);
groupedData.forEach(([category, data]) => {
const line = d3.line()
.x(d => xScale(d.year))
.y(d => yScale(d.startups));
const path = svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line)
.style("stroke", colorScale(category))
.style("fill", "none");
const totalLength = path.node().getTotalLength();
path.attr("stroke-dashoffset", totalLength)
.attr("stroke-dasharray", totalLength)
.transition()
.duration(2000)
.ease(d3.easeLinear)
.attr("stroke-dashoffset", 0);
svg.append("circle")
.attr("id", "circle")
.attr("cx", 100)
.attr("cy", 30 + uniqueCategories.indexOf(category) * 20)
.attr("r", 3)
.style("fill", colorScale(category));
svg.append("text")
.attr("x", 110)
.attr("y", 35 + uniqueCategories.indexOf(category) * 20)
.text(category)
.style("fill", colorScale(category))
.attr("font-family", "sans-serif")
.style("font-size", "0.7em");
});
const xAxis = d3.axisBottom(xScale);
const yAxis = d3.axisLeft(yScale);
svg.append("g")
.attr("class", "x-axis")
.attr("transform", `translate(0, ${height - margin.bottom})`)
.call(xAxis);
svg.append("g")
.attr("class", "y-axis")
.attr("transform", `translate(${margin.left}, 0)`)
.call(yAxis);
svg.select(".x-axis")
.attr("fill", "transparent")
.attr("class", "x-axis")
.call(xAxis);
svg.select(".y-axis")
.attr("fill", "transparent")
.attr("class", "y-axis")
.call(yAxis);
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", d => xScale(d.year))
.attr("cy", d => yScale(d.startups))
.attr("r", 5)
.attr("fill", d => colorScale(d.country))
.on('mouseenter', mouseEnter)
.on('mouseleave', mouseLeave);
const tooltip = svg.append('g')
.attr('visibility', 'hidden');
const tooltipHeight = 20;
const tooltipRect = tooltip.append('rect')
.attr('fill', '#a1a1a1')
.attr('rx', 5)
.attr('height', tooltipHeight);
const tooltipText = tooltip.append('text')
.attr('fill', '#fcfcfc')
.attr('font-family', 'sans-serif')
.attr('font-size', 12)
.attr('y', 2)
.attr('x', 3)
.attr('dominant-baseline', 'hanging')
function mouseEnter(event, d) {
d3.select(this)
.attr('r', radius * 1.5);
tooltipText.text("For " + d.country+ ": " + d.startups + " startups");
const labelWidth = tooltipText.node().getComputedTextLength();
tooltipRect.attr('width', labelWidth + 6);
const xPos = d3.select(this).attr("cx") + radius * 3;
const yPos = d3.select(this).attr("cy") - tooltipHeight / 2;
tooltip.attr('transform', `translate(${xPos},${yPos})`)
.attr('visibility', 'visible');
}
function mouseLeave(event, d) {
d3.select(this)
.attr('r', radius)
tooltip
.attr('visibility', 'hidden');
}
return svg.node();
}