feat: add Compare button for side-by-side study comparison
Adds compareStudies() to viewer.js: - Switches to 2-panel layout - Loads most recent study (studies[0]) in left panel - Loads prior study (studies[1]) in right panel - Auto-matches same orientation series (AX > SAG > COR) - Enables sync scroll automatically - Jumps both panels to middle slice Adds 'Compare' button to viewer toolbar (viewer/main.go) next to 1/2/3 Panel and 3D buttons. Sync scroll already worked across studies via slice_location matching — this just makes the workflow one click.
This commit is contained in:
parent
ade93669d3
commit
f2e352ebcf
|
|
@ -748,6 +748,58 @@ async function setPanels(count) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compare mode: 2-panel split with current + prior study, same orientation,
|
||||||
|
// sync scroll enabled. If only one study exists, loads same study in both panels.
|
||||||
|
async function compareStudies() {
|
||||||
|
if (studies.length < 1) return;
|
||||||
|
|
||||||
|
is3DMode = false;
|
||||||
|
document.getElementById('studySelect3d').style.display = 'none';
|
||||||
|
document.getElementById('panels').innerHTML = '';
|
||||||
|
panels = [];
|
||||||
|
panelCount = 0;
|
||||||
|
|
||||||
|
const studyA = studies[0]; // most recent
|
||||||
|
const studyB = studies.length > 1 ? studies[1] : studyA; // prior (or same)
|
||||||
|
|
||||||
|
// Load both panels
|
||||||
|
await addPanel();
|
||||||
|
await addPanel();
|
||||||
|
|
||||||
|
// Load study A into panel 0
|
||||||
|
currentStudyId = studyA.id;
|
||||||
|
await changeStudyForPanel(0, studyA.id);
|
||||||
|
|
||||||
|
// Load study B into panel 1
|
||||||
|
await changeStudyForPanel(1, studyB.id);
|
||||||
|
|
||||||
|
// After both are loaded, try to match orientation: prefer AX, then SAG, then COR
|
||||||
|
const preferOri = ['AX', 'SAG', 'COR'];
|
||||||
|
for (const ori of preferOri) {
|
||||||
|
const sA = (panels[0].seriesList || []).find(s => s.orientation === ori || (s.series_desc || '').toUpperCase().startsWith(ori));
|
||||||
|
const sB = (panels[1].seriesList || []).find(s => s.orientation === ori || (s.series_desc || '').toUpperCase().startsWith(ori));
|
||||||
|
if (sA && sB) {
|
||||||
|
const selA = document.getElementById('panel-0').querySelector('.series-select');
|
||||||
|
const selB = document.getElementById('panel-1').querySelector('.series-select');
|
||||||
|
if (selA) selA.value = sA.id;
|
||||||
|
if (selB) selB.value = sB.id;
|
||||||
|
await loadSeries(0, sA.id);
|
||||||
|
await loadSeries(1, sB.id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable sync scroll
|
||||||
|
const syncEl = document.getElementById('syncScroll');
|
||||||
|
if (syncEl) syncEl.checked = true;
|
||||||
|
|
||||||
|
// Sync both panels to middle slice
|
||||||
|
if (panels[0] && panels[0].slices.length) {
|
||||||
|
const mid = Math.floor(panels[0].slices.length / 2);
|
||||||
|
goToSlice(0, mid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function changeStudyForPanel(panelIdx, studyId) {
|
async function changeStudyForPanel(panelIdx, studyId) {
|
||||||
currentStudyId = studyId;
|
currentStudyId = studyId;
|
||||||
const panel = panels[panelIdx];
|
const panel = panels[panelIdx];
|
||||||
|
|
|
||||||
|
|
@ -389,6 +389,7 @@ func handleViewer(w http.ResponseWriter, r *http.Request) {
|
||||||
<button id="btn2panels" onclick="setPanels(2)">2 Panels</button>
|
<button id="btn2panels" onclick="setPanels(2)">2 Panels</button>
|
||||||
<button id="btn3panels" onclick="setPanels(3)">3 Panels</button>
|
<button id="btn3panels" onclick="setPanels(3)">3 Panels</button>
|
||||||
<button id="btn3d" onclick="set3DMode()">3D</button>
|
<button id="btn3d" onclick="set3DMode()">3D</button>
|
||||||
|
<button id="btnCompare" onclick="compareStudies()" title="Compare current vs prior study side-by-side with sync scroll">Compare</button>
|
||||||
</div>
|
</div>
|
||||||
<label id="syncLabel" class="sync-label"><input type="checkbox" id="syncScroll" checked><span>Sync</span></label>
|
<label id="syncLabel" class="sync-label"><input type="checkbox" id="syncScroll" checked><span>Sync</span></label>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue