forked from ScoDoc/ScoDoc
337 lines
8.0 KiB
JavaScript
337 lines
8.0 KiB
JavaScript
//
|
|
// Diagramme "radar" montrant les notes d'un étudiant
|
|
//
|
|
// ScoDoc, (c) E. Viennet 2012
|
|
//
|
|
// Ce code utilise d3.js
|
|
|
|
$().ready(function () {
|
|
var etudid = $("#etudid")[0].value;
|
|
var formsemestre_id = $("#formsemestre_id")[0].value;
|
|
get_notes_and_draw(formsemestre_id, etudid);
|
|
});
|
|
|
|
var WIDTH = 460; // taille du canvas SVG
|
|
var HEIGHT = WIDTH;
|
|
var CX = WIDTH / 2; // coordonnees centre du cercle
|
|
var CY = HEIGHT / 2;
|
|
var RR = 0.4 * WIDTH; // Rayon du cercle exterieur
|
|
|
|
/* Emplacements des marques (polygones et axe gradué) */
|
|
var R_TICS = [8, 10, 20]; /* [6, 8, 10, 12, 14, 16, 18, 20]; */
|
|
var R_AXIS_TICS = [4, 6, 8, 10, 12, 14, 16, 18, 20];
|
|
var NB_TICS = R_TICS.length;
|
|
|
|
function get_notes_and_draw(formsemestre_id, etudid) {
|
|
console.log("get_notes(" + formsemestre_id + ", " + etudid + " )");
|
|
/* Recupère le bulletin de note et extrait tableau de notes */
|
|
/*
|
|
var notes = [
|
|
{ 'module' : 'E1',
|
|
'note' : 13,
|
|
'moy' : 16 },
|
|
];
|
|
*/
|
|
var query =
|
|
SCO_URL +
|
|
"/Notes/formsemestre_bulletinetud?formsemestre_id=" +
|
|
formsemestre_id +
|
|
"&etudid=" +
|
|
etudid +
|
|
"&fmt=json&version=selectedevals&force_publishing=1";
|
|
|
|
$.get(query, "", function (bul) {
|
|
var notes = [];
|
|
bul.ue.forEach(function (ue, i, ues) {
|
|
ue["module"].forEach(function (m, i) {
|
|
notes.push({
|
|
code: m["code"],
|
|
titre: m["titre"],
|
|
note: m["note"]["value"],
|
|
moy: m["note"]["moy"],
|
|
});
|
|
});
|
|
});
|
|
draw_radar(notes);
|
|
});
|
|
}
|
|
|
|
function draw_radar(notes) {
|
|
/* Calcul coordonnées des éléments */
|
|
var nmod = notes.length;
|
|
var angle = (2 * Math.PI) / nmod;
|
|
|
|
for (var i = 0; i < notes.length; i++) {
|
|
var d = notes[i];
|
|
var cx = Math.sin(i * angle);
|
|
var cy = -Math.cos(i * angle);
|
|
d["x_v"] = CX + ((RR * d.note) / 20) * cx;
|
|
d["y_v"] = CY + ((RR * d.note) / 20) * cy;
|
|
d["x_moy"] = CX + ((RR * d.moy) / 20) * cx;
|
|
d["y_moy"] = CY + ((RR * d.moy) / 20) * cy;
|
|
d["x_20"] = CX + RR * cx;
|
|
d["y_20"] = CY + RR * cy;
|
|
d["x_label"] = CX + (RR + 25) * cx - 10;
|
|
d["y_label"] = CY + (RR + 25) * cy + 10;
|
|
d["tics"] = [];
|
|
// Coords des tics sur chaque axe
|
|
for (var j = 0; j < NB_TICS; j++) {
|
|
var r = (R_TICS[j] / 20) * RR;
|
|
d["tics"][j] = { x: CX + r * cx, y: CY + r * cy };
|
|
}
|
|
}
|
|
|
|
var notes_circ = notes.slice(0);
|
|
notes_circ.push(notes[0]);
|
|
var notes_circ_valid = notes_circ.filter(function (e, i, a) {
|
|
return e.note != "NA" && e.note != "-";
|
|
});
|
|
var notes_valid = notes.filter(function (e, i, a) {
|
|
return e.note != "NA" && e.note != "-";
|
|
});
|
|
|
|
/* Crée l'élément SVG */
|
|
g = d3
|
|
.select("#radar_bulletin")
|
|
.append("svg")
|
|
.attr("class", "radar")
|
|
.attr("width", WIDTH + 100)
|
|
.attr("height", HEIGHT);
|
|
|
|
/* Centre */
|
|
g.append("circle")
|
|
.attr("cy", CY)
|
|
.attr("cx", CX)
|
|
.attr("r", 2)
|
|
.attr("class", "radar_center_mark");
|
|
|
|
/* Lignes "tics" */
|
|
for (var j = 0; j < NB_TICS; j++) {
|
|
var ligne_tics = d3.svg
|
|
.line()
|
|
.x(function (d) {
|
|
return d["tics"][j]["x"];
|
|
})
|
|
.y(function (d) {
|
|
return d["tics"][j]["y"];
|
|
});
|
|
g.append("svg:path")
|
|
.attr("class", "radar_disk_tic")
|
|
.attr("id", "radar_disk_tic_" + R_TICS[j])
|
|
.attr("d", ligne_tics(notes_circ));
|
|
}
|
|
|
|
/* Lignes radiales pour chaque module */
|
|
g.selectAll("radar_rad")
|
|
.data(notes)
|
|
.enter()
|
|
.append("line")
|
|
.attr("x1", CX)
|
|
.attr("y1", CY)
|
|
.attr("x2", function (d) {
|
|
return d["x_20"];
|
|
})
|
|
.attr("y2", function (d) {
|
|
return d["y_20"];
|
|
})
|
|
.attr("class", "radarrad");
|
|
|
|
/* Lignes entre notes */
|
|
var ligne = d3.svg
|
|
.line()
|
|
.x(function (d) {
|
|
return d["x_v"];
|
|
})
|
|
.y(function (d) {
|
|
return d["y_v"];
|
|
});
|
|
|
|
g.append("svg:path")
|
|
.attr("class", "radarnoteslines")
|
|
.attr("d", ligne(notes_circ_valid));
|
|
|
|
var ligne_moy = d3.svg
|
|
.line()
|
|
.x(function (d) {
|
|
return d["x_moy"];
|
|
})
|
|
.y(function (d) {
|
|
return d["y_moy"];
|
|
});
|
|
|
|
g.append("svg:path")
|
|
.attr("class", "radarmoylines")
|
|
.attr("d", ligne_moy(notes_circ_valid));
|
|
|
|
/* Points (notes) */
|
|
g.selectAll("circle1")
|
|
.data(notes_valid)
|
|
.enter()
|
|
.append("circle")
|
|
.attr("cx", function (d) {
|
|
return d["x_v"];
|
|
})
|
|
.attr("cy", function (d) {
|
|
return d["y_v"];
|
|
})
|
|
.attr("r", function (x, i) {
|
|
return 3;
|
|
})
|
|
.style("stroke-width", 1)
|
|
.style("stroke", "black")
|
|
.style("fill", "blue")
|
|
.on("mouseover", function (d) {
|
|
var rwidth = 310;
|
|
var x = d["x_v"];
|
|
if (x - CX < 0) {
|
|
x = x + 5;
|
|
if (x + rwidth + 12 > WIDTH) {
|
|
x = WIDTH - rwidth - 12;
|
|
}
|
|
} else {
|
|
if (x - CX > 0) {
|
|
x = x - rwidth - 5;
|
|
if (x < 12) {
|
|
x = 12;
|
|
}
|
|
} else {
|
|
x = CX - rwidth / 2;
|
|
}
|
|
}
|
|
var yrect = d["y_v"];
|
|
var ytext = d["y_v"];
|
|
if (yrect - CY > 0) {
|
|
yrect = yrect - 5 - 20;
|
|
ytext = ytext - 5 - 20 + 16;
|
|
} else {
|
|
yrect = yrect + 5;
|
|
ytext = ytext + 5 + 16;
|
|
}
|
|
var r = g
|
|
.append("rect")
|
|
.attr("class", "radartip")
|
|
.attr("x", x)
|
|
.attr("y", yrect);
|
|
|
|
var txt = g
|
|
.append("text")
|
|
.text("Note: " + d.note + "/20, moyenne promo: " + d.moy + "/20")
|
|
.attr("class", "radartip")
|
|
.attr("x", x + 5)
|
|
.attr("y", ytext);
|
|
r.attr("width", rwidth).attr("height", 20);
|
|
})
|
|
.on("mouseout", function (d) {
|
|
d3.selectAll(".radartip").remove();
|
|
});
|
|
|
|
/* Valeurs des notes */
|
|
g.selectAll("notes_labels")
|
|
.data(notes_valid)
|
|
.enter()
|
|
.append("text")
|
|
.text(function (d) {
|
|
return d["note"];
|
|
})
|
|
.attr("x", function (d) {
|
|
return d["x_v"];
|
|
})
|
|
.attr("y", function (d) {
|
|
if (d["y_v"] > CY) return d["y_v"] + 16;
|
|
else return d["y_v"] - 8;
|
|
})
|
|
.attr("class", "note_label");
|
|
|
|
/* Petits points sur les moyennes */
|
|
g.selectAll("circle2")
|
|
.data(notes_valid)
|
|
.enter()
|
|
.append("circle")
|
|
.attr("cx", function (d) {
|
|
return d["x_moy"];
|
|
})
|
|
.attr("cy", function (d) {
|
|
return d["y_moy"];
|
|
})
|
|
.attr("r", function (x, i) {
|
|
return 2;
|
|
})
|
|
.style("stroke-width", 0)
|
|
.style("stroke", "black")
|
|
.style("fill", "rgb(20,90,50)");
|
|
|
|
/* Valeurs sur axe */
|
|
g.selectAll("textaxis")
|
|
.data(R_AXIS_TICS)
|
|
.enter()
|
|
.append("text")
|
|
.text(String)
|
|
.attr("x", CX - 10)
|
|
.attr("y", function (x, i) {
|
|
return CY - (x * RR) / 20 + 6;
|
|
})
|
|
.attr("class", "textaxis");
|
|
|
|
/* Noms des modules */
|
|
g.selectAll("text_modules")
|
|
.data(notes)
|
|
.enter()
|
|
.append("text")
|
|
.text(function (d) {
|
|
return d["code"];
|
|
})
|
|
.attr("x", function (d) {
|
|
return d["x_label"];
|
|
})
|
|
.attr("y", function (d) {
|
|
return d["y_label"];
|
|
})
|
|
.attr("dx", 0)
|
|
.attr("dy", 0)
|
|
.on("mouseover", function (d) {
|
|
var x = d["x_label"];
|
|
var yrect = d["y_label"];
|
|
var ytext = d["y_label"];
|
|
var titre = d["titre"].replace("'", "'").substring(0, 64);
|
|
var rwidth = titre.length * 9; // rough estimate of string width in pixels
|
|
if (x - CX < 0) {
|
|
x = x + 5;
|
|
if (x + rwidth + 12 > WIDTH) {
|
|
x = WIDTH - rwidth - 12;
|
|
}
|
|
} else {
|
|
if (x - CX > 0) {
|
|
x = x - rwidth - 5;
|
|
if (x < 12) {
|
|
x = 12;
|
|
}
|
|
} else {
|
|
x = CX - rwidth / 2;
|
|
}
|
|
}
|
|
if (yrect - CY > 0) {
|
|
yrect = yrect - 5 - 20;
|
|
ytext = ytext - 5 - 20 + 16;
|
|
} else {
|
|
yrect = yrect + 5;
|
|
ytext = ytext + 5 + 16;
|
|
}
|
|
var r = g
|
|
.append("rect")
|
|
.attr("class", "radartip")
|
|
.attr("x", x)
|
|
.attr("y", yrect)
|
|
.attr("height", 20)
|
|
.attr("width", rwidth);
|
|
var txt = g
|
|
.append("text")
|
|
.text(titre)
|
|
.attr("class", "radartip")
|
|
.attr("x", x + 5)
|
|
.attr("y", ytext);
|
|
})
|
|
.on("mouseout", function (d) {
|
|
d3.selectAll(".radartip").remove();
|
|
});
|
|
}
|