File size: 4,605 Bytes
1e21006
 
 
 
43a02d9
 
1e21006
 
 
 
 
7f0a0f6
 
 
 
 
 
 
8df9f56
f1ef6af
f9350de
 
43a02d9
 
8df9f56
f1ef6af
1e21006
 
 
 
8df9f56
1e21006
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2941c67
 
 
 
1e21006
2941c67
 
f1ef6af
 
 
 
 
 
2941c67
f1ef6af
 
1e21006
f1ef6af
1e21006
 
2941c67
1e21006
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
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);
}