chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);
const padding = 20;
const x = d3.scaleLinear()
.domain(d3.extent(shotdf, d => Number(d.for))).nice()
.range([margin.left, width - margin.right])
const y = d3.scaleLinear()
.domain(d3.extent(shotdf, d => Number(d.against))).nice()
.range([height - margin.bottom, 0])
const yAxis = d3
.axisLeft(y)
.tickFormat(formatTicks)
const xAxis = d3
.axisBottom(x)
.tickFormat(formatTicks)
const colorScale = d3.scaleSequential(d3.interpolateYlOrRd)
.domain([d3.min(shotdf.map(d => Number(d.for)*Number(d.against))),d3.max(shotdf.map(d => Number(d.for)*Number(d.against)))]);
const meanAxis = object => object
.attr("transform", `translate(0,${y(15)})`)
.call(d3.axisRight(y)
.ticks(1)
.tickSize(width - margin.left - margin.right))
.style('stroke', 'red')
.call(g => g.select(".domain")
.remove())
.call(g => g.selectAll(".tick:not(:first-of-type) line")
.attr("stroke-opacity", 1.0)
.attr("stroke-dasharray", "6"))
.call(g => g.selectAll(".tick text")
.text("the mean line")
.attr("x", 4)
.attr("dy", -4));
function addLabel(axis, label, x)
{
axis
.selectAll('.tick:last-of-type text')
.clone()
.text(label)
.attr('x', x)
.style('text-anchor', 'start')
.style('font-weight', 'semi-bold')
.style('fill', 'black')
}
svg.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(xAxis)
.call(addLabel, 'Shots attempted', 25);
const mainyAxis = svg.append("g")
.attr("transform", `translate(${margin.left},0)`)
.call(yAxis)
.call(addLabel, "Shots against", 25);
mainyAxis.append('g').call(meanAxis);
const dots = svg.append("g");
dots
.selectAll(".scatter")
.data(shotdf)
.join("circle")
.attr('class', 'scatter')
.attr("cx", d => x(Number(d['for'])))
.attr("cy", d => y(Number(d['against'])))
.attr("r", 5)
.attr("id", (d, i) => `${i}`)
.style('stroke', 'dodgerblue')
.style("fill", (d) => colorScale((Number(d.for)*Number(d.against))))
.style("fill-opacity", 0.25)
.on("mouseenter", showData)
.on('mouseleave', (event, d) => {
dots.selectAll('.scatter').style('opacity', 1.0);
d3.selectAll('.labelGroup').remove();
});
function showData(event, d)
{
const current = d3.select(this);
const currentTeam = d.team;
console.log("team", currentTeam)
dots
.selectAll('.scatter')
.style("opacity", function(t) {
if (t.team !== currentTeam)
{
return 0.2;
}
})
let xpos = parseFloat(current.attr('cx'));
let ypos = parseFloat(current.attr('cy'));
console.log("Xpositions {}", xpos);
const labelgroup = current.selectAll('.labelGroup').join('g').attr('class', 'labelGroup');
const label = svg
.append('text')
.attr('class', 'bar-label text-sm labelGroup labelText')
.attr('fill', 'black')
.attr('x', xpos + padding)
.attr('y', ypos + padding);
const team = label
.append('tspan')
.style('text-anchor', 'start')
.style('font-weight', 'bold')
.style('font-family', 'Arial')
.text(`Team: ${d.team}`);
const textheight = team.node().getBBox().height;
label
.append('tspan')
.attr('class', 'bar-label text-sm')
.attr('fill', 'black')
.style('text-anchor', 'start')
.style('font-weight', 'bold')
.style('font-family', 'Arial')
.attr('x', xpos + padding)
.attr('dy', textheight)
.text(`Shots conceded: ${Number(d.against)}`);
label
.append('tspan')
.attr('class', 'bar-label text-sm')
.attr('fill', 'black')
.style('text-anchor', 'start')
.style('font-weight', 'bold')
.style('font-family', 'Arial')
.attr('x', xpos + padding)
.attr('dy', textheight)
.text(`Shots attempted: ${Number(d.for)}`)
const labelBBox = label.node().getBBox();
const tooltipWidth = labelBBox.width + padding * 2;
const tooltipHeight = labelBBox.height + padding;
console.log(labelBBox);
console.log(tooltipHeight);
const tooltip = svg
.insert('rect', '.labelText')
.attr('id', 'tooltip')
.attr('class', 'labelGroup')
.attr('y', ypos)
.attr('x', xpos)
.attr('rx', 5)
.attr('ry', 5)
.style('fill', 'black')
.style('opacity', 0.5)
.attr('width', tooltipWidth)
.attr('height', tooltipHeight);
}
return svg.node();
}