LiamKhoaLe's picture
Upd JS, CSS
43a02d9
const testerInput = document.getElementById("tester");
const samplerInput = document.getElementById("samplers");
const actionContainer = document.getElementById("action-container");
const resultsSection = document.getElementById("results");
let canvas = document.getElementById("lines-canvas");
let ctx = canvas.getContext("2d");
let generateBtn, loaderDiv;
function resetUI() {
resultsSection.classList.add("hidden");
resultsSection.innerHTML = `
<canvas id="lines-canvas"></canvas>
<div id="result-layout">
<div id="tester-column"></div>
<div id="sampler-column"></div>
</div>
`;
// Re-attach canvas & ctx properly
canvas = document.getElementById("lines-canvas");
ctx = canvas.getContext("2d");
canvas.width = 0;
canvas.height = 0;
// Remove old button & loader if exists
if (loaderDiv) loaderDiv.remove();
if (generateBtn) generateBtn.remove();
}
testerInput.addEventListener("change", handleFileChange);
samplerInput.addEventListener("change", handleFileChange);
function handleFileChange() {
resetUI();
const testerReady = testerInput.files.length === 1;
const samplersReady =
samplerInput.files.length > 0 && samplerInput.files.length <= 5;
if (samplerInput.files.length > 5) {
alert("You can upload a maximum of 5 sampler photos.");
samplerInput.value = "";
return;
}
if (testerReady && samplersReady) {
generateBtn = document.createElement("button");
generateBtn.textContent = "Generate Comparison";
generateBtn.className = "generate-btn";
generateBtn.onclick = sendComparison;
actionContainer.appendChild(generateBtn);
}
}
function showLoader() {
loaderDiv = document.createElement("div");
loaderDiv.className = "loader";
actionContainer.appendChild(loaderDiv);
}
async function sendComparison() {
generateBtn.disabled = true;
showLoader();
const formData = new FormData();
formData.append("tester", testerInput.files[0]);
for (let file of samplerInput.files) formData.append("samplers", file);
try {
const res = await fetch("/compare", { method: "POST", body: formData });
if (!res.ok) throw new Error(await res.text());
const data = await res.json();
renderResults(data);
} catch (err) {
alert("Error: " + err.message);
} finally {
generateBtn.disabled = false;
loaderDiv.remove();
}
}
function getBorderColor(percent) {
if (percent < 30) return "#ef4444"; // red
if (percent <= 50) return "#fb923c"; // orange
if (percent <= 80) return "#22c55e"; // green
return "#a855f7"; // purple
}
function renderResults({ tester, results }) {
resultsSection.classList.remove("hidden");
const testerColumn = document.getElementById("tester-column");
const samplerColumn = document.getElementById("sampler-column");
const testerSquare = createSquare(testerInput.files[0], "#3b82f6");
testerSquare.classList.add("tester-node");
testerColumn.appendChild(testerSquare);
// Append results
results.forEach((r,idx)=>{
const square = createSquare(
samplerInput.files[idx],
getBorderColor(r.similarity)
);
samplerColumn.appendChild(square);
/* Wait for browser calculate layout then draw line */
requestAnimationFrame(()=>drawLineBetween(testerSquare,square,r.similarity));
});
}
function createSquare(file, borderColor) {
const url = URL.createObjectURL(file);
const div = document.createElement("div");
div.className = "square";
div.style.border = `4px solid ${borderColor}`;
const img = document.createElement("img");
img.src = url;
div.appendChild(img);
return div;
}
function drawLineBetween(el1, el2, similarity) {
const rect1 = el1.getBoundingClientRect();
const rect2 = el2.getBoundingClientRect();
const offset = resultsSection.getBoundingClientRect();
// Compute canvas size on first call
if (canvas.width === 0) {
canvas.width = resultsSection.scrollWidth;
canvas.height = resultsSection.getBoundingClientRect().height;
}
const x1 = rect1.right - offset.left;
const y1 = rect1.top + rect1.height / 2 - offset.top;
const x2 = rect2.left - offset.left;
const y2 = rect2.top + rect2.height / 2 - offset.top;
ctx.strokeStyle = getBorderColor(similarity);
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
// Label
const label = document.createElement("div");
label.className = "label";
label.textContent = similarity.toFixed(0) + "%";
label.style.left = (x1 + x2) / 2 + "px";
label.style.top = (y1 + y2) / 2 + "px";
resultsSection.appendChild(label);
}