File size: 7,285 Bytes
941cf22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
<div class="image-comparison" style="width:100%;margin:10px 0;"></div>
<style>
  .image-comparison { position: relative; }
  .image-comparison .controls { display:flex; align-items:center; gap:16px; justify-content:flex-start; margin:12px 0; }
  .image-comparison .controls label { font-size:12px; color: var(--muted-color); display:flex; align-items:center; gap:8px; }
  .image-comparison .controls select {
    font-size: 12px;
    padding: 8px 28px 8px 10px;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background-color: var(--surface-bg);
    color: var(--text-color);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%230f1115' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 8px center;
    background-size: 12px;
    -webkit-appearance: none; appearance: none; cursor: pointer;
    transition: border-color .15s ease, box-shadow .15s ease;
  }
  [data-theme="dark"] .image-comparison .controls select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  }
  .image-comparison .controls select:hover { border-color: var(--primary-color); }
  .image-comparison .controls select:focus { border-color: var(--primary-color); box-shadow: 0 0 0 3px rgba(232,137,171,.25); outline: none; }

  .image-comparison .grid { display:grid; grid-template-columns: repeat(4, 1fr); gap: 12px; width:100%; align-items: start; }
  @media (max-width: 980px) { .image-comparison .grid { grid-template-columns: repeat(2, 1fr); } }

  .image-comparison .card { position: relative; border:1px solid var(--border-color); border-radius:10px; overflow:hidden; background: var(--surface-bg); display:flex; flex-direction:column; }
  .image-comparison .card .media { position: relative; width:100%; height: 200px; background: var(--surface-2, var(--surface-bg)); display:block; }
  .image-comparison .card .media img { width:100%; height:100%; object-fit: contain; display:block; }
  .image-comparison .badge { position:absolute; top:8px; left:8px; font-size:11px; padding:3px 6px; border-radius:6px; background: var(--surface-bg); color: var(--text-color); border:1px solid var(--border-color); }
  .image-comparison .meta { padding:8px 10px; border-top:1px solid var(--border-color); font-size:12px; display:flex; height: 55px; align-items:start; justify-content:space-between; gap:8px; }
  .image-comparison .meta .label { color: var(--muted-color); }
  .image-comparison .meta .value { font-weight:600; }
</style>
<script>
  (() => {
    const bootstrap = () => {
      const mount = document.currentScript ? document.currentScript.previousElementSibling : null;
      const container = (mount && mount.querySelector && mount.querySelector('.image-comparison')) || document.querySelector('.image-comparison');
      if (!container) return;
      if (container.dataset && container.dataset.mounted === 'true') return; if (container.dataset) container.dataset.mounted = 'true';

      // Known filenames in /public/data/comparison
      const FILES = {
        '1': { 1: 'id_1_rank_1_sim_1.000.png', 2: 'id_1_rank_2_sim_0.165.png', 3: 'id_1_rank_3_sim_0.143.png' },
        '2': { 1: 'id_2_rank_1_sim_1.000.png', 2: 'id_2_rank_2_sim_0.978.png', 3: 'id_2_rank_3_sim_0.975.png' },
        '3': { 1: 'id_3_rank_1_sim_0.936.png', 2: 'id_3_rank_2_sim_0.686.png', 3: 'id_3_rank_3_sim_0.676.png' },
      };

      // Images served from [domain]/public/data/comparison/*.png → path is /data/comparison/
      const CANDIDATE_BASES = [ '/data/comparison/' ];

      const resolveBase = (candidates, filename) => new Promise((resolve) => {
        let idx = 0; const tryNext = () => {
          if (idx >= candidates.length) return resolve(candidates[0]);
          const img = new Image();
          img.onload = () => resolve(candidates[idx]);
          img.onerror = () => { idx += 1; tryNext(); };
          img.src = candidates[idx] + filename;
        }; tryNext();
      });

      // Controls
      const controls = document.createElement('div'); controls.className = 'controls';
      const label = document.createElement('label'); label.textContent = 'Example';
      const select = document.createElement('select');
      const EXAMPLE_LABELS = { '1': 'photo', '2': 'chart', '3': 'drawing' };
      ['1','2','3'].forEach((id)=>{ const o=document.createElement('option'); o.value=id; o.textContent=EXAMPLE_LABELS[id]; select.appendChild(o); });
      label.appendChild(select); controls.appendChild(label); container.appendChild(controls);

      // Grid
      const grid = document.createElement('div'); grid.className = 'grid'; container.appendChild(grid);

      let basePath = CANDIDATE_BASES[0];

      const parseInfo = (filename) => {
        const rankMatch = filename.match(/rank_(\d+)/i); const rank = rankMatch ? rankMatch[1] : '';
        const simMatch = filename.match(/sim_([0-9.]+)/i); const sim = simMatch ? simMatch[1] : '';
        return { rank, sim };
      };

      const formatSim = (val) => {
        if (val == null || val === '') return '—';
        return String(val).replace(/\.$/, '');
      };

      const render = (id) => {
        const files = FILES[id]; if (!files) return;
        const ordered = [files[1], files[1], files[2], files[3]]; // rank_1 twice then rank_2 and rank_3
        grid.innerHTML = '';
        ordered.forEach((fname, idx) => {
          const { sim } = parseInfo(fname);
          const isFirst = idx === 0;
          const isDuplicateOfFirst = idx === 1;
          const card = document.createElement('div'); card.className = 'card';
          const media = document.createElement('div'); media.className = 'media';
          const img = document.createElement('img'); img.alt = `example ${id} image ${idx+1}${isDuplicateOfFirst ? ' identical' : ''}`; img.loading = 'lazy'; img.src = basePath + fname; media.appendChild(img);
          const meta = document.createElement('div'); meta.className = 'meta';
          const left = document.createElement('span'); left.className = 'label'; left.textContent = isFirst ? 'Query' : 'Similarity';
          meta.appendChild(left);
          if (!isFirst) {
            const right = document.createElement('span'); right.className = 'value'; right.textContent = isDuplicateOfFirst ? '1.000 identical' : formatSim(sim);
            meta.appendChild(right);
          }
          card.appendChild(media); card.appendChild(meta); grid.appendChild(card);
        });
      };

      (async () => {
        // Resolve a working base then initial render
        basePath = await resolveBase(CANDIDATE_BASES, FILES['1'][1]);
        render('1');
      })();

      select.addEventListener('change', () => render(select.value));
    };

    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', bootstrap, { once: true });
    } else { bootstrap(); }
  })();
</script>