Spaces:
Running
Running
Update index.html
Browse files- index.html +48 -2
index.html
CHANGED
|
@@ -995,10 +995,15 @@ tbody tr:last-child td { border-bottom: none; }
|
|
| 995 |
</div>
|
| 996 |
|
| 997 |
<div class="panel">
|
| 998 |
-
<div class="panel-h"><h3>Stream distribution</h3></div>
|
| 999 |
<div class="panel-b"><div class="dist" id="dist"></div></div>
|
| 1000 |
</div>
|
| 1001 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1002 |
<div class="panel">
|
| 1003 |
<div class="tools">
|
| 1004 |
<div class="search"><input type="search" id="search" placeholder="filter rows…"></div>
|
|
@@ -1185,6 +1190,47 @@ tbody tr:last-child td { border-bottom: none; }
|
|
| 1185 |
'<div class="dist-bar"><i class="' + barClass(name) + '" style="width:' + pct + '%"></i></div></div>';
|
| 1186 |
}).join("");
|
| 1187 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1188 |
if (data.sheet_url) {
|
| 1189 |
$("sheetLink").href = data.sheet_url;
|
| 1190 |
$("sheetLink").classList.remove("hidden");
|
|
@@ -1324,4 +1370,4 @@ tbody tr:last-child td { border-bottom: none; }
|
|
| 1324 |
})();
|
| 1325 |
</script>
|
| 1326 |
</body>
|
| 1327 |
-
</html>
|
|
|
|
| 995 |
</div>
|
| 996 |
|
| 997 |
<div class="panel">
|
| 998 |
+
<div class="panel-h"><h3>Stream distribution <span style="font-weight:400;opacity:.6">(model prediction)</span></h3></div>
|
| 999 |
<div class="panel-b"><div class="dist" id="dist"></div></div>
|
| 1000 |
</div>
|
| 1001 |
|
| 1002 |
+
<div class="panel">
|
| 1003 |
+
<div class="panel-h"><h3>Class placement <span style="font-weight:400;opacity:.6">(after top-up)</span></h3></div>
|
| 1004 |
+
<div class="panel-b"><div class="dist" id="classDist"></div></div>
|
| 1005 |
+
</div>
|
| 1006 |
+
|
| 1007 |
<div class="panel">
|
| 1008 |
<div class="tools">
|
| 1009 |
<div class="search"><input type="search" id="search" placeholder="filter rows…"></div>
|
|
|
|
| 1190 |
'<div class="dist-bar"><i class="' + barClass(name) + '" style="width:' + pct + '%"></i></div></div>';
|
| 1191 |
}).join("");
|
| 1192 |
|
| 1193 |
+
const classCounts = {};
|
| 1194 |
+
const classInfo = {
|
| 1195 |
+
"4C": { stream: "Account", second: "account", label: "Account", rule: "highest Mathematics mark (Account needs strong Math)" },
|
| 1196 |
+
"4D": { stream: "Reka Cipta", second: "reka", label: "Reka Cipta", rule: "highest overall average" },
|
| 1197 |
+
};
|
| 1198 |
+
Object.values(classInfo).forEach((i) => { i.fit = 0; i.topup = 0; i.second = 0; });
|
| 1199 |
+
displayList.forEach((r) => {
|
| 1200 |
+
const c = String(r["Suggested Class"] || "").trim();
|
| 1201 |
+
if (!c) return;
|
| 1202 |
+
classCounts[c] = (classCounts[c] || 0) + 1;
|
| 1203 |
+
const info = classInfo[c];
|
| 1204 |
+
if (!info) return;
|
| 1205 |
+
if (String(r["Recommended Stream"] || "") === info.stream) info.fit++;
|
| 1206 |
+
else {
|
| 1207 |
+
info.topup++;
|
| 1208 |
+
if (String(r["Second Stream"] || "").toLowerCase().includes(info.second)) info.second++;
|
| 1209 |
+
}
|
| 1210 |
+
});
|
| 1211 |
+
const classTot = Object.values(classCounts).reduce((a, b) => a + b, 0) || 1;
|
| 1212 |
+
const classBar = { "4A": "s", "4B": "s", "4C": "a", "4D": "r", "SASTERA": "o" };
|
| 1213 |
+
$("classDist").innerHTML = ["4A", "4B", "4C", "4D", "SASTERA"].map((name) => {
|
| 1214 |
+
const n = classCounts[name] || 0;
|
| 1215 |
+
const pct = Math.round((n / classTot) * 100);
|
| 1216 |
+
const info = classInfo[name];
|
| 1217 |
+
let btn = "", detail = "";
|
| 1218 |
+
if (info) {
|
| 1219 |
+
btn = ' <button type="button" class="info-btn" data-info="' + name + '" aria-label="Info about class ' + name + '" ' +
|
| 1220 |
+
'style="width:18px;height:18px;border-radius:50%;border:1px solid var(--line-strong);background:transparent;color:var(--cyan);font-size:11px;line-height:1;cursor:pointer;margin-left:6px;vertical-align:middle">i</button>';
|
| 1221 |
+
detail = '<div class="info-detail hidden" id="info-' + name + '" style="font-size:12px;line-height:1.6;color:var(--text-2, #9bb0c4);background:var(--cyan-dim);border:1px solid var(--line);border-radius:6px;padding:8px 10px;margin:6px 0 2px">' +
|
| 1222 |
+
'<div><b>' + info.fit + '</b> truly suited — the model recommended ' + esc(info.label) + '.</div>' +
|
| 1223 |
+
'<div><b>' + info.topup + '</b> placed to fill the class to at least 25 — they come from Art / Other' +
|
| 1224 |
+
(info.topup ? ' (' + info.second + ' of them had ' + esc(info.label) + ' as their second stream)' : '') + '.</div>' +
|
| 1225 |
+
'<div style="opacity:.75">Top-up students are the Art / Other students with the ' + info.rule + '.</div></div>';
|
| 1226 |
+
}
|
| 1227 |
+
return '<div class="dist-item"><div class="name">' + esc(name) + btn + "<b>" + n + "</b></div>" +
|
| 1228 |
+
'<div class="dist-bar"><i class="' + classBar[name] + '" style="width:' + pct + '%"></i></div>' + detail + "</div>";
|
| 1229 |
+
}).join("");
|
| 1230 |
+
$("classDist").querySelectorAll(".info-btn").forEach((b) => {
|
| 1231 |
+
b.addEventListener("click", () => $("info-" + b.dataset.info).classList.toggle("hidden"));
|
| 1232 |
+
});
|
| 1233 |
+
|
| 1234 |
if (data.sheet_url) {
|
| 1235 |
$("sheetLink").href = data.sheet_url;
|
| 1236 |
$("sheetLink").classList.remove("hidden");
|
|
|
|
| 1370 |
})();
|
| 1371 |
</script>
|
| 1372 |
</body>
|
| 1373 |
+
</html>
|