myChart = {
sortedbarLineData.forEach(function (d) {
d.AvgMOTP_Score = +d.AvgMOTP_Score;
d.PrincipalActiveYears = +d.PrincipalActiveYears;
});
const div = html`<div style='max-width: 1000px; padding: 0px; margin: 0px;'></div>`;
const ttDiv = d3.select("body").append("div")
.attr("id", "myTooltip")
const svg = d3.select(div)
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",`translate(${margin.left}, ${margin.top})`)
const x = svg.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${height})`)
.call(xAxis)
x.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.2em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
x.selectAll("line")
.attr("transform", `translate(${xScale.bandwidth()/2}, 0)`)
.attr("stroke","grey")
.attr("stroke-width","0.5px");
//append a group element and insert y axis
svg.append("g")
.attr("class", "y axis")
.attr("transform", `translate(${width},0)`)
.call(yAxis)
svg.append("g")
.attr("class", "y axis yAxisLine")
.call(yAxisLine)
// Data line and dots group
const lineAndDots = svg.append("g")
.attr("class", "line-and-dots")
.attr("transform", `translate(${xScale.bandwidth()/2}, 0)`)
// Data line
lineAndDots.append("path")
.datum(sortedbarLineData)
.attr("class", "data-line")
.style("stroke-width","3")
.style("stroke-opacity","0.5")
.attr("d", lineMaker);
// an equivalent expression
// const path = svg.append('path').attr('d', lineMaker(lineData));
/*Difference between datum() and data() in D3
# selection.data([values[, key]])
Joins the specified array of data with the current selection. The specified values is an array of data values, such as an array of numbers or objects, or a function that returns an array of values.
...
# selection.datum([value])
Gets or sets the bound data for each selected element. Unlike the selection.data method, this method does not compute a join (and thus does not compute enter and exit selections).*/
// Data dots
lineAndDots.selectAll(".dot")
.data(sortedbarLineData)
.enter().append("circle")
.attr("class", "dot")
.style("opacity","0.6")
.attr("r", 3)
.attr("cx", d=> xScale(d.Fake_DBN))
.attr("cy", d=> yScaleLine(d.AvgMOTP_Score));
// label on Data dots
lineAndDots.selectAll("text")
.data(sortedbarLineData)
.enter().append("text")
.style("fill", "purple")
.style("text-anchor", "middle")
.attr("font-size", 12)
.attr("x", d=> xScale(d.Fake_DBN))
.attr("y", d=> yScaleLine(d.AvgMOTP_Score)-1) //move text up by 1 px
.text(d=>d.AvgMOTP_Score);
//append rectangles (bars)
const g = svg.selectAll(".bar-group")
.data(sortedbarLineData)
.enter().append("g")
.attr("class","bar-group");
g.append("rect")// enter() creates the initial join of data to elements, creating one rectangle element for every data element in the data source
.attr("class", "bar")
.attr("x", d => xScale(d.Fake_DBN)) //x position of the top-left point of the rect
.attr("y", d => yScale(d.PrincipalActiveYears)) //y position of the top-left point of the rect
.attr("height", d => height - yScale(d.PrincipalActiveYears)) //height starts from the TOP and moves down due to SVG Coordinate system
.attr("width", d => xScale.bandwidth())
.style("fill", 'orange')
.style("fill-opacity","0.4")
//add lables on the bar
g.append("text")
.attr("class", "barLable")
.attr("transform", "rotate(-90)")
.style("fill", "black")
.style("text-anchor", "middle") //default is anchor on the left
.attr("x",d => height - yScale(d.PrincipalActiveYears)-yScale(0)- (height - yScale(d.PrincipalActiveYears))/2) // because of the rotate!!!
.attr("y",d=> xScale(d.Fake_DBN)+ xScale.bandwidth()/1.5) // because of the rotate!!!
// .attr("x", d => xScale(d.Fake_DBN) + xScale.bandwidth()/2) //middle of the corresponding bar horizontally
// .attr("y", d => yScale(d.PrincipalActiveYears)) //middle of the corresponding bar vertically
.text(d=>{
return ((height - yScale(d.PrincipalActiveYears))>=25? d.PrincipalActiveYears: '')
});
//add tooltip. on event
g.selectAll("rect").on("mouseover",function(d){
ttDiv.transition()
.duration(200)
.style("opacity", 0.9);
ttDiv.html("<strong>"+d.Fake_DBN+ "</strong><br/>School MOTP score Avg: <strong>"+d.AvgMOTP_Score +"</strong><br/> Principal active years: <strong>"+d.PrincipalActiveYears +"</strong><br/>" )
.style("font","13px")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px"); //Recover the mouse position when the event happens.Can add a numeric value next to pageX or Y to adjust the tooltip position
//style("top", d3.select(this).attr("cy") + "px"); Aother option -- It selects the element that is hovered. Thus, it is possible to get whatever attribute or style of this element, like its position.
d3.select(this).style("fill","yellow");//highlight the mouseover element
})
.on("mouseout", function(d) {
ttDiv.transition()
.duration(200)
.style("opacity", 0);
d3.select(this).style("fill","orange");//change color of the mouseover element back to original color
});
const colorScale = d3.scaleOrdinal()
.domain(["MOTP Avg Score to Date","Principal Active Years"])
.range(['purple', 'orange'])
const legend_g = svg.selectAll(".legend")
.data(colorScale.domain())
.enter().append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 11)
.attr("transform", (d, i) => `translate(${width+20},${i * 20})`); //legend on the right edge in the SVG. 'i*20' is to space out the item vertically here
legend_g.append("rect")
.attr("x", 0)
.attr("y",height/2)
.attr("width", 10)
.attr("height", 10)
.attr("fill", colorScale);
legend_g.append("text")
.attr("x", 12)
.attr("y", height/2 + 10)
//.attr("dy", ".35em")
//.text(d=>d)
.text(d => {
return (d ==2017? '2017 rating avg.':d)
});
return div
}