function visu_changment_ref() {
console.log("init (ne doit apparaître qu'une seule fois!")
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width/2, height]);
const dim_joueur = 500
const dim_table = 300
var domaine_vue = [-dim_joueur, dim_joueur]
const x = d3.scaleLinear()
.domain(domaine_vue)
.range([margin.left, height - margin.right])
const y = d3.scaleLinear()
.domain(domaine_vue)
.range([height - margin.bottom, margin.top])
const scale_x_joueur = d3.scaleLinear().domain([-dim_joueur, dim_joueur]).range([margin.left,height - margin.right])
const scale_y_joueur = d3.scaleLinear().domain([-dim_joueur, dim_joueur]).range([height - margin.bottom, margin.top])
const scale_x_table = d3.scaleLinear().domain([-dim_table, dim_table]).range([margin.left,height - margin.right])
const scale_y_table = d3.scaleLinear().domain([-dim_table, dim_table]).range([height - margin.bottom, margin.top])
var scale_x = scale_x_table
var scale_y = scale_y_table
var contours = d3.contourDensity()
.x(d => scale_x(d.coor_balle_x))
//.x(d => (objet_options_affichage.mode == 'joueur')?scale_x(d.pos_balle_new_ref_x):scale_x(d.coor_balle_x))
.y(d => scale_y(-d.coor_balle_y))
//.y(d => (objet_options_affichage.mode == 'joueur')?scale_y(d.pos_balle_new_ref_y+((d.nom == players[0])?-dim_joueur:dim_joueur)):scale_y(d.coor_balle_y))
.size([width, height])
.bandwidth(11)
.thresholds(30)
(csv)
const color = d3.scaleSequential(d3.interpolateYlOrBr)
.domain(d3.extent(contours, d => d.value));
var opacite_d = 1
const densite = svg.append("g")
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.selectAll(".density")
.attr("class", "density")
.data(contours)
.enter().append("path")
.attr("stroke-width", (d, i) => i % 5 ? 0.25 : 1)
.attr("d", d3.geoPath())
.attr("opacity", opacite_d)
.attr("fill", d => d3.scaleSequential(d3.interpolateYlOrBr)
.domain(d3.extent(contours, d => d.value))(d.value))
///////////////////////////////////////////
//////////////// Pie chart ////////////////
///////////////////////////////////////////
var arc = d3.arc().innerRadius(50).outerRadius(200);
const data = [50,180-40-50,40]
var cote_joueur = 1
const start_angle = Math.PI/2
const end_angle = Math.PI*1.5
const pie = d3.pie()
.padAngle(0.01)
.sort(null)
.startAngle(start_angle)
.endAngle(end_angle)
.value(d => d)
const arcs = pie(data);
var opacite_c = 0
svg.append("g")
.selectAll(".arcs")
.data(arcs)
.join("path")
.attr("class", "arcs")
.attr("opacity", opacite_c)
.attr("d", arc).attr('transform', function(d) {
return 'translate(' + scale_x(0) + ',' + scale_y(cote_joueur*dim_joueur)+')';
})
.text(d => `${d.data}`);
// Piechart 2
const domEl = d3.create('div')
.style('text-align', 'center')
.style('font-family', 'Sans-serif').style("font", "14px times");
const r = 200,
secMinScale = d3.scaleLinear().domain([0, 60]).range([0, 360]),
hourScale = d3.scaleLinear().domain([0, 180]).range([0, 360]);
const axe_circulaire = svg.append('g').classed('axis', true)
.call(d3.axisRadialInner(
hourScale.copy().range([start_angle, end_angle]),
scale_y(200 - 3)
)
.ticks(12)
.tickSize(4)
)
.attr('transform', 'translate(' + scale_x(0) + ',' + scale_y(cote_joueur*dim_joueur) + ')')
axe_circulaire.selectAll("text").style("font-size","10px")
axe_circulaire.selectAll("line").style("stroke-width", "1px").style("stroke","black").style("opacity",1)
axe_circulaire.select(".domain").style("stroke-width","1px").style("stroke","black").style("opacity",1)
const arcGenerator = d3.arc()
.outerRadius(scale_y(50))
.innerRadius(scale_y(50-1))
.startAngle(end_angle)
.endAngle(start_angle);
const axe_ortho = svg.append("path")
.attr('transform', 'translate(' + scale_x(0) + ',' + scale_y(cote_joueur*dim_joueur) + ')')
.attr("d", arcGenerator());
const start_angle_graduation = (cone_joueur == players[0])?Math.PI/2:-Math.PI/2
const end_angle_graduation = (cone_joueur == players[0])?Math.PI*1.5:Math.PI/2
const cote_joueur_graduation = (cone_joueur == players[0])?1:-1
for (let index = 0; index < 10; ++index) {
var arcGenerator_graduation = d3.arc()
.outerRadius(scale_y_joueur(index*50)-margin.top)
.innerRadius(scale_y_joueur(index*50-1)-margin.top)
.startAngle(end_angle_graduation)
.endAngle(start_angle_graduation);
svg.append("path")
.attr('transform', 'translate(' + scale_x_joueur(0) + ',' + scale_y_joueur(cote_joueur_graduation*dim_joueur) + ')')
.attr("d", arcGenerator_graduation())
.attr("opacity", 0.2);
}
//Ligne 1 cone
const ligne1 = svg.append('line')
.style("stroke", "black")
.style("stroke-width", 1)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", cote_joueur*scale_y(200)*Math.sin(Math.PI*(50+90)/180))
.attr("y2", -cote_joueur*scale_y(200)*Math.cos(Math.PI*(50+90)/180))
.attr('transform', 'translate(' + scale_x(0) + ',' + scale_y(cote_joueur*dim_joueur) + ')');
//Ligne 2 cone
const ligne2 = svg.append('line')
.style("stroke", "black")
.style("stroke-width", 1)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", cote_joueur*scale_y(200)*Math.sin(Math.PI*(180-40+90)/180))
.attr("y2", -cote_joueur*scale_y(200)*Math.cos(Math.PI*(180-40+90)/180))
.attr('transform', 'translate(' + scale_x(0) + ',' + scale_y(cote_joueur*dim_joueur) + ')');
///////////////////////////////////////
//////////////// Axis ////////////////
/////////////////////////////////////
const xAxis = g => g
.attr("transform", `translate(0,${scale_y(0)})`)
.call(d3.axisBottom(x))
const yAxis = g => g
.attr("transform", `translate(${scale_x(0)},0)`)
.call(d3.axisLeft(y))
const axe_x = svg.append("g")
.call(xAxis);
const axe_y = svg.append("g")
.call(yAxis);
//////////////////////////////////////////////
//////////////// Interactions ////////////////
//////////////////////////////////////////////
const tooltip = d3.select("body").append("div")
.attr("class", "svg-tooltip")
.style("position", "absolute")
.style("visibility", "hidden")
var symbolGenerator = d3.symbol()
.type(d3.symbolCross)
.size(30);
var pathData = symbolGenerator();
const pos_joueur1 = svg.selectAll(".cross_j1")
.data(csv.filter(d => d.nom == players[1]))
.join("path")
.attr('transform', function(d) {
return 'translate(' + scale_x(d.pos_x_joueurA_rebond) + ',' + scale_y(-d.pos_y_joueurA_rebond)+')';
})
.attr('d', pathData)
.attr("fill", d => "red")
.attr("stroke", "white")
const pos_joueur2 = svg.selectAll(".cross_j2")
.data(csv.filter(d => d.nom == players[0]))
.join("path")
.attr('transform', function(d) {
return 'translate(' + scale_x(d.pos_x_joueurB_rebond) + ',' + scale_y(-d.pos_y_joueurB_rebond)+')';
})
.attr('d', pathData)
.attr("fill", d => "red")
.attr("stroke", "white")
pos_joueur2.on("mouseenter", (event, d) => {
console.log("rebond hover", d)
tooltip.style("visibility", "visible")
.text('Faute: ' + d.faute_du_point+'\n'
+'Num point: ' + d.num_point+'\n'
+'Num coup: ' + d.num_coup+'\n'
+'Lateralité: ' + d.lateralite+'\n'
+'Lateralité suiv: ' + d.lateralite_suiv+'\n'
+'Cluster: ' + d.cluster)
});
pos_joueur2.on("mousemove", (event, d) => {
tooltip.style("top", (event.pageY - 10) + "px")
.style("left", (event.pageX + 10) + "px")
});
pos_joueur2.on("mouseleave", (event, d) => {
tooltip.style("visibility", "hidden");
});
let domElement = svg.node()
// FONCTION UPDATE https://observablehq.com/@observablehq/simple-d3-update-pattern
///////////////////////////////////////////////
/////////// Fonction de transitions ///////////
///////////////////////////////////////////////
domElement.update = function(objet_options_affichage) {
// in this case we are expecting a function that will give us a y accessor
console.log("update")
// y = updateY
// yScale.domain(d3.extent(data, y))
const temps_transition = 1000
var domaine_vue = (objet_options_affichage.mode == 'joueur')?[-dim_joueur, dim_joueur]:[-dim_table,dim_table]
// definition des axes ici
const x = d3.scaleLinear()
.domain(domaine_vue)
.range([margin.left, height - margin.right])
const y = d3.scaleLinear()
.domain(domaine_vue)
.range([height - margin.bottom, margin.top])
var scale_x = scale_x_joueur
if (objet_options_affichage.mode == 'table'){
scale_x = scale_x_table
}
var scale_y = scale_y_joueur
if (objet_options_affichage.mode == 'table'){
scale_y = scale_y_table
}
const xAxis = g => g
.attr("transform", `translate(0,${scale_y(0)})`)
.call(d3.axisBottom(x))
const yAxis = g => g
.attr("transform", `translate(${scale_x(0)},0)`)
.call(d3.axisLeft(y))
axe_x.transition()
.duration(temps_transition)
.call(xAxis)
axe_y.transition()
.duration(temps_transition)
.call(yAxis)
var contours = d3.contourDensity()
.x(d => (objet_options_affichage.mode == 'joueur')?scale_x(d.pos_balle_new_ref_x):scale_x(d.coor_balle_x))
.y(d => (objet_options_affichage.mode == 'joueur')?scale_y(d.pos_balle_new_ref_y+((d.nom == players[0])?-dim_joueur:dim_joueur)):scale_y(-d.coor_balle_y))
.size([width, height])
.bandwidth(objet_options_affichage.bandwidth)
.thresholds(30)
(objet_options_affichage.csv)
const color = d3.scaleSequential(d3.interpolateYlOrBr)
.domain(d3.extent(contours, d => d.value));
densite.data(contours)
.transition()
.duration(temps_transition)
.attr("stroke-width", (d, i) => i % 5 ? 0.25 : 1)
.attr("d", d3.geoPath())
.attr("opacity", objet_options_affichage.opacite_densite)
.attr("fill", d => d3.scaleSequential(d3.interpolateYlOrBr)
.domain(d3.extent(contours, d => d.value))(d.value))
//POS Joueurs
/*var symbolGenerator = d3.symbol()
.type(d3.symbolCross)
.size(30);
var pathData = symbolGenerator();
svg.append("cross_j1")
.selectAll(".cross_j1")
.data(objet_options_affichage.csv.filter(d => d.nom == players[1]), d => d.id_coup)
.enter()
.append("cross_j1")
.join("path")
.attr('transform', function(d) {
return 'translate(' + scale_x(d.pos_x_joueurA_rebond) + ',' + scale_y(d.pos_y_joueurA_rebond)+')';
})
.attr('d', pathData)
.attr("fill", d => "red")
.on("mouseenter", (event, d) => {
tooltip.style("visibility", "visible")
.text(d.faute_du_point+' '+d.num_point)
})
.on("mousemove", (event, d) => {
tooltip.style("top", (event.pageY - 10) + "px")
.style("left", (event.pageX + 10) + "px")
})
.on("mouseleave", (event, d) => {
tooltip.style("visibility", "hidden");
});
svg.selectAll(".cross_j1")
.data(objet_options_affichage.csv.filter(d => d.nom == players[1]), d => d.id_coup)
.exit()
.remove()
svg.selectAll(".cross_j1").data(objet_options_affichage.csv.filter(d => d.nom == players[0]), d => d.id_coup)
.join("path")
.transition().duration(temps_transition)
.attr('transform', function(d) {
return 'translate(' + scale_x(d.pos_x_joueurA_rebond) + ',' + scale_y(d.pos_y_joueurA_rebond)+')';
})
svg.append("cross_j2")
.selectAll(".cross_j2")
.data(objet_options_affichage.csv.filter(d => d.nom == players[0]), d => d.id_coup)
.enter()
.append("cross_j2")
.join("path")
.attr('transform', function(d) {
return 'translate(' + scale_x(d.pos_x_joueurA_rebond) + ',' + scale_y(d.pos_y_joueurA_rebond)+')';
})
.attr('d', pathData)
.attr("fill", d => "red")
.on("mouseenter", (event, d) => {
tooltip.style("visibility", "visible")
.text(d.faute_du_point+' '+d.num_point)
})
.on("mousemove", (event, d) => {
tooltip.style("top", (event.pageY - 10) + "px")
.style("left", (event.pageX + 10) + "px")
})
.on("mouseleave", (event, d) => {
tooltip.style("visibility", "hidden");
});
svg.selectAll(".cross_j2")
.data(objet_options_affichage.csv.filter(d => d.nom == players[0]), d => d.id_coup)
.exit()
.remove()
svg.selectAll(".cross_j2").data(objet_options_affichage.csv.filter(d => d.nom == players[0]), d => d.id_coup)
.join("path")
.transition().duration(temps_transition)
.attr('transform', function(d) {
return 'translate(' + scale_x(d.pos_x_joueurA_rebond) + ',' + scale_y(d.pos_y_joueurA_rebond)+')';
})
*/
pos_joueur1.transition()
.duration(temps_transition)
.attr('transform', function(d) {
return 'translate(' + ((objet_options_affichage.mode == 'table')?scale_x(d.pos_x_joueurA_rebond) + ',' + scale_y(-d.pos_y_joueurA_rebond):scale_x(0) + ',' + scale_y(dim_joueur))+')';
})
pos_joueur2.transition()
.duration(temps_transition)
.attr('transform', function(d) {
return 'translate(' + ((objet_options_affichage.mode == 'table')?scale_x(d.pos_x_joueurB_rebond) + ',' + scale_y(-d.pos_y_joueurB_rebond):scale_x(0) + ',' + scale_y(-dim_joueur))+')';
})
const data = [objet_options_affichage.angle_coup_droit,
180-objet_options_affichage.angle_revers-objet_options_affichage.angle_coup_droit,
objet_options_affichage.angle_revers
]
const cote_joueur = (objet_options_affichage.cone_joueur == players[0])?1:-1
const start_angle = (objet_options_affichage.cone_joueur == players[0])?Math.PI/2:-Math.PI/2
const end_angle = (objet_options_affichage.cone_joueur == players[0])?Math.PI*1.5:Math.PI/2
var arc = d3.arc()
.innerRadius(scale_y(objet_options_affichage.taille_cercle_minimal)-margin.top)
.outerRadius(scale_y(objet_options_affichage.taille_cercle_maximal)-margin.top);
const pie = d3.pie()
.padAngle(0.01)
.sort(null)
.startAngle(start_angle)
.endAngle(end_angle)
.value(d => d)
const arcs = pie(data);
svg.selectAll(".arcs")
.data(arcs).transition()
.duration(0)
.attr("opacity", (objet_options_affichage.mode == "joueur")?objet_options_affichage.opacite_cone:0)
.attr("d", arc).attr('transform', function(d) {
return 'translate(' + scale_x(0) + ',' + scale_y(cote_joueur*dim_joueur)+')';
})
.text(d => `${d.data}`);
axe_circulaire.transition()
.duration(0)
.call(d3.axisRadialInner(
hourScale.copy().range([start_angle, end_angle]),
scale_y(objet_options_affichage.taille_cercle_maximal - 1)-margin.top
)
.ticks(12)
.tickSize(8)
).attr('transform', 'translate(' + scale_x(0) + ',' + scale_y(cote_joueur*dim_joueur) + ')')
.attr("opacity", (objet_options_affichage.mode == "joueur")?1:0)
const arcGenerator_transition = d3.arc()
.outerRadius(scale_y(objet_options_affichage.taille_cercle_minimal)-margin.top)
.innerRadius(scale_y(objet_options_affichage.taille_cercle_minimal-3)-margin.top)
.startAngle(end_angle)
.endAngle(start_angle);
axe_ortho.transition()
.duration(0)
.attr('transform', 'translate(' + scale_x(0) + ',' + scale_y(cote_joueur*dim_joueur) + ')')
.attr("d", arcGenerator_transition())
.attr("opacity", (objet_options_affichage.mode == "joueur")?1:0);
ligne1.transition()
.duration(0)
.style("stroke", "black")
.style("stroke-width", 1)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", cote_joueur*(scale_y(objet_options_affichage.taille_cercle_maximal)-margin.top)*Math.sin(Math.PI*(objet_options_affichage.angle_coup_droit+90)/180)) // On prend scale_y car c'est par rapport à la taille du cercle
.attr("y2", -cote_joueur*(scale_y(objet_options_affichage.taille_cercle_maximal)-margin.top)*Math.cos(Math.PI*(objet_options_affichage.angle_coup_droit+90)/180))
.attr('transform', 'translate(' + scale_x(0) + ',' + scale_y(cote_joueur*dim_joueur) + ')')
.attr("opacity", (objet_options_affichage.mode == "joueur")?1:0);;
//Ligne 2 cone
ligne2.transition()
.duration(0)
.style("stroke", "black")
.style("stroke-width", 1)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", cote_joueur*(scale_y(objet_options_affichage.taille_cercle_maximal)-margin.top)*Math.sin(Math.PI*(180-objet_options_affichage.angle_revers+90)/180)) // On prend scale_y car c'est par rapport à la taille du cercle
.attr("y2", -cote_joueur*(scale_y(objet_options_affichage.taille_cercle_maximal)-margin.top)*Math.cos(Math.PI*(180-objet_options_affichage.angle_revers+90)/180))
.attr('transform', 'translate(' + scale_x(0) + ',' + scale_y(cote_joueur*dim_joueur) + ')')
.attr("opacity", (objet_options_affichage.mode == "joueur")?1:0);;
// TABLES
svg.append("g")
.selectAll(".rect")
.data(objet_options_affichage.csv, d => d.id_coup)
.enter()
.append("rect")
.attr("x",d => (objet_options_affichage.mode == 'table')?scale_x(-TABLE_WIDTH/2):scale_x(d.hg_x))
.attr("y", d => (objet_options_affichage.mode == 'table')?scale_y(TABLE_LENGTH/2):scale_y(d.hg_y+((d.nom == players[0])?-dim_joueur:dim_joueur)))
.attr("width", d => Math.max((objet_options_affichage.mode == 'table')?scale_x(TABLE_WIDTH)-scale_x(0):((d.pos_y_joueurA_rebond > 0)?-1:1)*(scale_x(TABLE_WIDTH)-scale_x(0)),0))
.attr("height", d => Math.max((objet_options_affichage.mode == 'joueur')?scale_y(0)-scale_y(TABLE_LENGTH):((d.pos_y_joueurA_rebond > 0)?-1:1)*(scale_y(0)-scale_y(TABLE_LENGTH)),0))
.attr("fill", "transparent")
.attr("class", "rect")
.attr("opacity", 1)
.attr("stroke", "black")
svg.selectAll(".rect").data(objet_options_affichage.csv, d => d.id_coup)
.transition().duration(temps_transition)
.attr("x",d => (objet_options_affichage.mode == 'table')?scale_x(-TABLE_WIDTH/2):scale_x(d.hg_x))
.attr("y", d => (objet_options_affichage.mode == 'table')?scale_y(TABLE_LENGTH/2):scale_y(d.hg_y+((d.nom == players[0])?-dim_joueur:dim_joueur)))
.attr("width", d => Math.max((objet_options_affichage.mode == 'table')?scale_x(TABLE_WIDTH)-scale_x(0):((d.pos_y_joueurA_rebond > 0)?-1:1)*(scale_x(TABLE_WIDTH)-scale_x(0)),0))
.attr("height", d => Math.max((objet_options_affichage.mode == 'joueur')?scale_y(0)-scale_y(TABLE_LENGTH):((d.pos_y_joueurA_rebond > 0)?-1:1)*(scale_y(0)-scale_y(TABLE_LENGTH)),0))
.attr("fill", "transparent")
.attr("opacity", objet_options_affichage.opacite_table)
.attr("stroke", "black")
svg.selectAll(".rect")
.data(objet_options_affichage.csv, d => d.id_coup)
.exit()
.remove()
// REBONDS
svg.selectAll(".circle")
.data(objet_options_affichage.csv, d => d.id_coup)
.enter()
.append("circle")
.attr("class", "circle element")
.attr("cx", d => (objet_options_affichage.mode == 'table')?scale_x(d.coor_balle_x):scale_x(d.pos_balle_new_ref_x))
.attr("cy", d => (objet_options_affichage.mode == 'table')?scale_y(-d.coor_balle_y):scale_y(d.pos_balle_new_ref_y+((d.nom == players[0])?-dim_joueur:dim_joueur)))
.attr("fill", d => c(d.nom))
.attr("r", 3)
.on("mouseenter", (event, d) => {
tooltip.style("visibility", "visible")
.text('Faute: ' + d.faute_du_point+'\n'
+'Num point: ' + d.num_point+'\n'
+'Num coup: ' + d.num_coup+'\n'
+'Lateralité: ' + d.lateralite+'\n'
+'Lateralité suiv: ' + d.lateralite_suiv+'\n'
+'Cluster: ' + d.cluster)
})
.on("mousemove", (event, d) => {
tooltip.style("top", (event.pageY - 10) + "px")
.style("left", (event.pageX + 10) + "px")
})
.on("mouseleave", (event, d) => {
tooltip.style("visibility", "hidden");
})
.on("click", (event, d) => {
d.__selected = true
mutable num_point = {num_point:d.num_point,num_coup:d.num_coup}
console.log("click1", d.num_point)
});
// EXIT
svg.selectAll(".circle")
.data(objet_options_affichage.csv, d => d.id_coup)
.exit()
.remove()
var fonction_couleur = (objet_options_affichage.couleur == "cluster")?c_clusters():((objet_options_affichage.couleur == "winner")?c_winner():c())
svg.selectAll(".circle").data(objet_options_affichage.csv, d => d.id_coup)
.transition().duration(temps_transition)
.attr("cx", d => (objet_options_affichage.mode == 'table')?scale_x(d.coor_balle_x):scale_x(d.pos_balle_new_ref_x))
.attr("cy", d => (objet_options_affichage.mode == 'table')?scale_y(-d.coor_balle_y):scale_y(d.pos_balle_new_ref_y+((d.nom == players[0])?-dim_joueur:dim_joueur)))
.attr("fill", d => (objet_options_affichage.couleur == "cluster")?c_clusters(d.cluster):((objet_options_affichage.couleur == "winner")?c_winner(d[objet_options_affichage.couleur]):c(d[objet_options_affichage.couleur])))
.attr("r", 3)
.attr("stroke", "white")
.attr("opacity", d => (d.appartient_zone)?1:0.5)
// .attr("stroke", d => (d.appartient_zone)?"red":((objet_options_affichage.couleur == "cluster")?c_clusters(d.cluster):c(d[objet_options_affichage.couleur])))
}
return domElement
}