beeswarm = {
let el = this
const t = d3.transition().duration(1500)
const circleFill = "#8699AC";
const highlightFill = "#FF590C";
const fontColor = "#f9f9f9";
const fontFamily = "Roboto Medium";
const radius_min = 5;
const radius_max = 30;
const strokeColor = "#505050";
const strokeWidth = radius_max *.05;
const strokeMultiple = .05;
const lineHeight = 17;
const form_check = form.playerNodeStyle === "Text" ? "#005985" : "#ECECEC";
const colorLighten = 15;
const tooltip = d3.select("body")
.append("div")
.attr("class", "toolTip")
.style("position", "absolute")
.style("visibility", "hidden")
.text("Placeholder")
.attr("class", "tooltip-box")
.style("background-color", "white")
.style("border", "1px solid black")
.style("border-radius", "5px")
.style("padding", "2.5px");
if (!el || JSON.stringify( previousPlayerList) !== JSON.stringify(form.playersSelected) || stat_select.stat[0] !== previousStatSelect) {
var fadeCircles = true;
if(previousPlayerListLength != 0){
fadeCircles = false;
}
// Update the stored value to the current playerNodeStyle
mutable previousPlayerList = form.playersSelected.slice();
mutable previousStatSelect = stat_select.stat[0];
mutable previousPlayerListLength = form.playersSelected.length;
const radiusScale = d3.scaleLinear()
.domain([d3.min(simulation.nodes(), d => d.poss), d3.max(simulation.nodes(), d => d.poss)])
.range([radius_min, radius_max ]); // Adjust the range based on your desired minimum and maximum radius
const radiusScaleMouseOver = d3.scaleLinear()
.domain([d3.min(simulation.nodes(), d => d.poss), d3.max(simulation.nodes(), d => d.poss)])
.range([radius_min*1.5, radius_max *1.5]); // Adjust the range based on your desired minimum and maximum radius
console.log("Jumping into the if")
el = DOM.svg(width, height)
const svg = d3.select(el)
el.g = svg.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`)
const xAxisGroup = el.g.append("g")
.classed("axis axis--x", true)
.attr("transform", `translate(0, ${height - margin.top - margin.bottom})`)
.call(xAxis);
el.g.append("g")
.classed("circles", true)
// create an empty selection from data binding
el.circles = el.g.select("g.circles")
.selectAll(".node")
.data(simulation.nodes(), d => d.id)
.enter()
.append("g")
.attr('class', 'node')
.attr("transform", function (d, i) {
const x = d.x;
const y = d.y;
return `translate(${x}, ${y})`;
});
// Iterate through each node
el.circles.each(function (d) {
const currentNode = d3.select(this)
const labelText = d.id;
const headshot = d.headshot;
let value = d.value;
//create circle
currentNode.append('circle')
.attr("r", d => radiusScale(d.poss)) // Set the radius based on the scale
.attr("fill", d => lightenColor(d.color, colorLighten))
.attr("stroke-width", d => radiusScale(d.POSS) * strokeMultiple)
.attr("stroke", strokeColor);
//add text
currentNode.append("text")
.style("text-anchor", "middle")
//rescale text based on size
.attr("transform", function() {
const scaleValue = radiusScale(d.poss)*0.7 / getTextRadius(getLines(labelText, lineHeight), lineHeight);
return `translate(0, 0) scale(${scaleValue})`;
})
.selectAll("tspan")
//use custom functions to split text into lines, getLines creates an array of text per line
.data(getLines(labelText, lineHeight))
.enter()
.append("tspan")
.attr("x", 0)
.attr("y", (d, i) => (i - getLines(labelText, lineHeight).length / 2 + 0.8) * lineHeight)
.style("fill", fontColor)
.style("font-family", fontFamily)
.text(m => m.text);
currentNode.append("image")
.attr("class", "headshot")
.attr("height", radiusScale(d.poss) * 2)
.attr("clip-path", d=> "circle(" + radiusScale(d.poss) + "px at " + radiusScale(d.poss) + "px " + radiusScale(d.poss) + "px)" )
.attr("href", headshot)
.attr("x", -radiusScale(d.poss)) // Adjust the image position to center it
.attr("y", -radiusScale(d.poss)*1.04)
.attr("width", radiusScale(d.poss) * 2)
.attr("preserveAspectRatio", "xMidYMid slice") // Maintain aspect ratio and fill the circle
.attr('opacity', 0);
const playersSelected = form.playersSelected;
const playersNotSelected = uniquePlayers.filter(player => !(form.playersSelected).includes(player));
playersSelected.forEach(player => {
el.circles
.filter(x => x.id == player)
.raise()
.select("circle")
.attr("fill", x => x.color)
el.circles
.filter(x => x.id == player)
.raise()
.select("image")
.attr('opacity', 1)
el.circles
.filter(x => x.id == player)
.select("text")
.attr("opacity", 0)
})
/*
if(fadeCircles){
playersNotSelected.forEach(player => {
el.circles
.filter(x => x.id == player)
.select("circle")
.attr("fill", circleFill);
})
}*/
currentNode
.style("cursor", "pointer") // Set the cursor to pointer for the entire group
.on("mouseover", (event, d) => {
mutable hoveredPlayer = d.id;
console.log("Hovered Player is " + hoveredPlayer);
// Increase the radius of the circle to 1.5 times on mouseover
d3.select(this)
.select("circle")
.transition()
.duration(200)
.attr("r", d => radiusScaleMouseOver(d.poss))
.attr("stroke-width", d => radiusScaleMouseOver(d.poss) * strokeMultiple)
.attr("fill", d => d.color);
// Change the text color to red on mouseover
d3.select(this).select("text")
.transition()
.duration(200)
.attr("opacity", 0)
//Make Image Radius Bigger on MouseOver
d3.select(this).select("image")
.transition()
.duration(200)
.attr('opacity', 1)
.attr("height", radiusScaleMouseOver(d.poss) * 2)
.attr("clip-path", d=> "circle(" + radiusScaleMouseOver(d.poss) + "px at " + radiusScaleMouseOver(d.poss) + "px " + radiusScaleMouseOver(d.poss) + "px)" )
.attr("href", headshot)
.attr("x", -radiusScaleMouseOver(d.poss)) // Adjust the image position to center it
.attr("y", -radiusScaleMouseOver(d.poss)*1.04)
.attr("width", radiusScaleMouseOver(d.poss) * 2)
.attr("preserveAspectRatio", "xMidYMid slice"); // Maintain aspect ratio and fill the circle
//raise circle and text element on hover
d3.select(event.currentTarget).raise();
//make tooltip visible, use custom function to return info about player
if(stat_select.stat[0].startsWith("efg")){
tooltip
.style("visibility", "visible")
.html(`<b>${d.id}:</b> ${(d.value * 100).toFixed(2)} eFG% on ${((d.poss).toFixed(1))} FGA / 75`)
}
else{
tooltip
.style("visibility", "visible")
.html(`<b>${d.id}:</b> ${(d.value).toFixed(2)} PPP on ${((d.poss).toFixed(1))} Poss / 75`)
}
})
.on("mouseout", function() {
// Return to the regular size on mouseout
if (!(form.playersSelected).includes(d.id)) {
console.log(form.playersSelected)
console.log(d.id)
mutable hoveredPlayer = null;
d3.select(this)
.select("circle")
.transition()
.duration(200)
.attr("r", d => radiusScale(d.poss))
.attr("stroke-width", d => radiusScale(d.poss) * strokeMultiple)
.attr("fill", d => lightenColor(d.color, colorLighten));
d3.select(this).select("image")
.transition()
.duration(200)
.attr('opacity', 0)
.attr("height", radiusScale(d.poss) * 2)
.attr("clip-path", d=> "circle(" + radiusScale(d.poss) + "px at " + radiusScale(d.poss) + "px " + radiusScale(d.poss) + "px)" )
.attr("href", headshot)
.attr("x", -radiusScale(d.poss)) // Adjust the image position to center it
.attr("y", -radiusScale(d.poss)*1.04)
.attr("width", radiusScale(d.poss) * 2)
.attr("preserveAspectRatio", "xMidYMid slice"); // Maintain aspect ratio and fill the circle
// Change the text color back to the original color on mouseout
d3.select(this).select("text")
.transition()
.duration(200)
.attr("opacity", 1);
}
else{
d3.select(this)
.select("circle")
.transition()
.duration(200)
.attr("r", d => radiusScale(d.poss))
.attr("stroke-width", d => radiusScale(d.poss) * strokeMultiple)
.attr("fill", d => d.color);
d3.select(this).select("image")
.transition()
.duration(200)
.attr("height", radiusScale(d.poss) * 2)
.attr("clip-path", d=> "circle(" + radiusScale(d.poss) + "px at " + radiusScale(d.poss) + "px " + radiusScale(d.poss) + "px)" )
.attr("href", headshot)
.attr("x", -radiusScale(d.poss)) // Adjust the image position to center it
.attr("y", -radiusScale(d.poss)*1.04)
.attr("width", radiusScale(d.poss) * 2)
.attr("preserveAspectRatio", "xMidYMid slice"); // Maintain aspect ratio and fill the circle
}
//hide tooltip after hovering
tooltip.style("visibility", "hidden");
})
.on('mousemove', (event) => {
tooltip.style("top", (event.pageY - 50) + "px").style("left", (event.pageX + 10) + "px")}
);
})
}
else {
el.g.select("g.axis.axis--x")
.transition(t)
.call(xAxis)
const update = d3.select(el)
.selectAll(".node")
.data(simulation.nodes(), d => d.id)
update
.transition(t)
.duration(1000)
.attr("transform", function (d, i) {
const x = d.x;
const y = d.y;
return `translate(${x}, ${y})`;
});
el.circles = update
}
return el
}