chart = {
let height = 500, width = 360
let marginTop = 8, marginRight = 8, marginBottom = 30, marginLeft = 4;
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("id","chart")
.attr("viewBox", [0, 0, width, height])
let yScale = d3.scaleBand()
.domain([0,1,2,3,4,5,6,7,8,9])
.range([height - marginBottom, marginTop])
let xMax = 1000000
let xScale = d3.scaleLinear()
.domain([0, xMax])
.range([marginLeft,width - marginRight])
let xAxis = d3.axisBottom(xScale).ticks(5).tickSizeOuter(0).tickFormat(d3.format(".1s"));
let yAxis = d3.axisLeft(yScale).ticks(0).tickSize(0).tickFormat("");
svg.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(xAxis)
.attr("id","xAxis")
.call(g => g.append("text")
.attr("x", width-marginRight)
.attr("y", 30)
.attr("text-anchor", "end")
.text("Views"));
svg.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.attr("id","yAxis")
.call(yAxis)
let monthData;
if(userInputs.month === "all"){
monthData = youtubeUS.filter(d =>
d.categoryId === +userInputs.categoryId)
}
else{
monthData = youtubeUS.filter(d =>
d3.timeFormat("%Y-%m-%d")(d.publishedAt).includes(`2021-${userInputs.month}`)
&& d.categoryId === +userInputs.categoryId)
}
monthData.sort((a,b)=> a.view_count < b.view_count ? -1 : 1)
if(monthData.length > 10){
monthData = monthData.slice(monthData.length - 10, monthData.length)
}
let barHeight = (height - marginTop - marginBottom) / 10 - 2;
for(let index=0; index<monthData.length; index++) {
let timeout = setTimeout(()=>{
// rescale y axis if necessary
if(+monthData[index].view_count > xMax){
xMax = 1 * monthData[index].view_count;
xScale = d3.scaleLinear().domain([0, xMax]).range([marginLeft,width - marginRight])
xAxis = d3.axisBottom(xScale).ticks(5).tickSizeOuter(0).tickFormat(d3.format(".1s"));
svg.select("#xAxis").transition().duration(400).call(xAxis);
svg.selectAll(".bar").transition().duration(400)
.attr("width", d=> xScale(d.view_count) - marginLeft);
svg.selectAll(".bar-svg").transition().duration(400)
.attr("x",d => xScale(d.view_count) - (barHeight) * 240/135 - 2) ;
svg.selectAll(".channel-text").transition().duration(400)
.attr("x",d => (d.view_count > 0.6 * xMax)
? xScale(0) + 5
: xScale(d.view_count) + 5)
}
let bar = svg.selectAll(`#bar-${index}`)
.data([monthData[index]])
.join("rect")
.attr("id",`#bar-${index}`)
.classed("bar",true)
.attr("x",xScale(0))
.attr("y", yScale(9))
.attr("height", height * 0.5)
.attr("width", 0)
.on("mouseover",(e)=>{
})
.transition().duration(400)
.attr("width", d=> xScale(d.view_count) - marginLeft)
.transition().duration(400).delay(1800)
.attr("height", barHeight)
.attr("y", yScale(index)) .style("stroke","rgb(180,180,180)")
let imageSVG = svg.selectAll(`#image-${index}`)
.data([monthData[index]])
.join('svg')
.classed("bar-svg",true)
.attr("viewBox", "0 0 320 180")
.attr("height", 180)
.attr("width", 0)
.attr("preserveAspectRatio", "xMidYMid slice")
.attr("x",xScale(0))
.attr("y",yScale(9) +1)
imageSVG.transition().duration(400)
.attr("width", 320)
.attr("x",d => xScale(d.view_count) - 322)
.transition().duration(400).delay(1800)
.attr("y",yScale(index)+1)
.attr('width', (barHeight) * 16/9)
.attr('height', (barHeight -2))
.attr("x",d => xScale(d.view_count) - (barHeight) * 16/9 - 2)
imageSVG.append("image")
.attr("id",`image-${index}`)
.classed("bar-image",true)
.attr('xlink:href', monthData[index].thumbnail_link)
.attr('width', 320)
.attr('height', 240)
.attr("y","-30")
svg.selectAll(`#channel-${index}`)
.data([monthData[index]])
.join('text')
.attr("id",`channel-${index}`)
.classed("channel-text",true)
.text(d=> wrap_text_array(d.channelTitle, 30)[0])
.attr("x", xScale(0))
.attr("y",yScale(9) + 150)
.transition().duration(400)
.attr("x",width - 240)
.style("opacity",1)
.transition().duration(400).delay(1800)
.attr("x",d => xScale(0) + 5)
.attr("y", yScale(index) + (height - marginTop - marginBottom) / 20 + 5)
svg.selectAll(`#title-${index}`)
.data([monthData[index]])
.join('text')
.attr("id",`title-${index}-1`)
.classed("title-text",true)
.text(d=> wrap_text_array(d.title, 30)[0])
.attr("x", xScale(0))
.attr("y",yScale(9) + 165)
.transition().duration(400)
.attr("x",width - 240)
.style("opacity",1)
.transition().duration(400).delay(1800)
.attr("x",d => xScale(d.view_count) - (barHeight) * 240/135 - 10)
.attr("y", yScale(index) + (height - marginTop - marginBottom) / 20 + 5)
.style("opacity",0)
.remove()
svg.selectAll(`#title-${index}`)
.data([monthData[index]])
.join('text')
.attr("id",`title-${index}-2`)
.classed("title-text",true)
.text(d=> wrap_text_array(d.title, 30)[1])
.attr("x", xScale(0))
.attr("y",yScale(9) + 180)
.transition().duration(400)
.attr("x",width - 240)
.style("opacity",1)
.transition().duration(400).delay(1800)
.attr("x",d => xScale(d.view_count) - (barHeight) * 240/135 - 10)
.attr("y", yScale(index) + (height - marginTop - marginBottom) / 20 + 5)
.style("opacity",0)
.remove()
let toolTip = svg.append("g")
.attr("id",`tooltip-${index}`)
.classed(`tooltip`,true)
.attr("transform", `translate(${width - marginRight - 246}, ${yScale(9)})`).style("display","none")
.style("opacity",0)
toolTip.append("rect")
.attr("x", 0)
.attr("y",0)
.attr("height", height * 2/3)
.attr("width", 246)
.attr("fill","#f9f9f9")
.attr("stroke","none")
toolTip.append("text")
.classed("tooltip-title-text",true)
.text(d=> wrap_text_array(monthData[index].title, 38)[0])
.attr("x", 3)
.attr("y",yScale(9) + 165)
toolTip.append("text")
.classed("tooltip-title-text",true)
.text(d=> wrap_text_array(monthData[index].title, 38)[1])
.attr("x", width - marginRight - 243)
.attr("y",yScale(9) + 185)
toolTip.append("text")
.text(d=> wrap_text_array(monthData[index].channelTitle, 40)[0])
.attr("x", 3)
.attr("y",yScale(9) + 205)
toolTip.append("text")
.text("Trending for "+monthData[index].trending_days+" days")
.attr("x", width - marginRight - 243)
.attr("y",yScale(9) + 235)
toolTip.append("text")
.text("to "+d3.format(".2s")(monthData[index].view_count).replace("M"," million").replace("k"," thousand")+" views")
.attr("x", width - marginRight - 243)
.attr("y",yScale(9) + 255)
toolTip.append("text")
.text("Category: "+monthData[index].categoryId)
.attr("x", width - marginRight - 243)
.attr("y",yScale(9) + 285)
toolTip.append("text")
.text("(watch video below)")
.attr("x", width - marginRight - 243)
.attr("y",yScale(9) + 315)
toolTip.append('svg')
.classed("tooltip-image",true)
.attr("viewBox", "0 0 240 135")
.attr("height", 135)
.attr("width", 240)
.attr("preserveAspectRatio", "xMidYMid slice")
.attr("x", 3)
.attr("y", 3)
.append("image")
.attr('xlink:href', monthData[index].thumbnail_link)
.attr('width', 240)
.attr('height', 180)
.attr("y","-22.5")
/*
toolTip.append('foreignObject')
.attr("x", 3)
.attr("y", 3)
.attr("width",240)
.attr("height",135)
.append("body")
.attr("xmlns","http://www.w3.org/1999/xhtml")
.append("iframe")
.attr("sandbox","allow-scripts allow-same-origin allow-cross-origin allow-presentation")
.attr("width",240)
.attr("height",135)
.attr("src", `https://www.youtube.com/embed/p9LLoijPQfg`)
.attr("allow","autoplay; encrypted-media")
*/
svg.on("click",(e)=>{
let id = e.target.id;
console.log(id)
d3.selectAll(".tooltip")
.style("display","none")
.style("opacity",0)
if(id.includes("-")){
let idx = id.split("-")[1];
let tip = d3.selectAll("#tooltip-"+idx);
tip.raise();
tip
.style("display","block")
.style("opacity",1)
.transition()
.attr("x",4)
mutable video_id = monthData[idx].video_id
}
});
},3000 * index);
}
return svg.node()
}