Refactor DICOM viewer initialization to use safe mounting helper for improved reliability and error handling
This commit is contained in:
@@ -1016,7 +1016,8 @@
|
||||
let dicomViewerLoaded = false;
|
||||
dicomDetails.addEventListener("toggle", function() {
|
||||
if (!dicomViewerLoaded && dicomDetails.open) {
|
||||
window.mountDicomViewers();
|
||||
// Use safe mount helper to avoid arbitrary timeouts
|
||||
try { mountDicomViewersSafely(); } catch (e) { if (window.mountDicomViewers) try { window.mountDicomViewers(); } catch (er) { console.warn(er); } }
|
||||
dicomViewerLoaded = true;
|
||||
}
|
||||
});
|
||||
@@ -1162,25 +1163,23 @@
|
||||
} else {
|
||||
viewer_element_3d = null;
|
||||
}
|
||||
// We have a slight delay to allow the viewer to load
|
||||
setTimeout(function () {
|
||||
// Then we load the annotation and viewport
|
||||
window.mountDicomViewers();
|
||||
if (load_3d) {
|
||||
console.log("loading 3d")
|
||||
|
||||
//setTimeout(function () {
|
||||
// console.log("loading 3d annotation")
|
||||
// importAnnotations_root(annotationjson3d)
|
||||
// importViewerState_root(viewerState);
|
||||
//}, 1000);
|
||||
} else {
|
||||
console.log("not loading 3d")
|
||||
// Initialize viewer deterministically after injecting HTML
|
||||
(async function(){
|
||||
try {
|
||||
await mountDicomViewersSafely();
|
||||
if (load_3d) {
|
||||
console.log("loading 3d");
|
||||
// deferred 3D import can be handled here if needed
|
||||
} else {
|
||||
console.log("not loading 3d");
|
||||
}
|
||||
} catch(e){
|
||||
console.warn('Viewer init error:', e);
|
||||
}
|
||||
}, 200);
|
||||
})();
|
||||
|
||||
document.getElementById("reload-finding").addEventListener("click", function () {
|
||||
window.mountDicomViewers();
|
||||
mountDicomViewersSafely();
|
||||
});
|
||||
|
||||
// Initialize the DICOM viewer with the images and annotations
|
||||
@@ -1201,6 +1200,36 @@
|
||||
const dsFullscreenModal = new bootstrap.Modal(document.getElementById("displaysetFullscreenModal"));
|
||||
|
||||
// Loader functions: can be called directly on reload
|
||||
// Helper: wait for mount function and mount the viewers safely
|
||||
function waitForMountFn(timeout = 5000) {
|
||||
if (window.mountDicomViewers) return Promise.resolve(window.mountDicomViewers);
|
||||
return new Promise((resolve, reject) => {
|
||||
const start = Date.now();
|
||||
function poll() {
|
||||
if (window.mountDicomViewers) return resolve(window.mountDicomViewers);
|
||||
if (Date.now() - start > timeout) return reject(new Error('mountDicomViewers not available'));
|
||||
requestAnimationFrame(poll);
|
||||
}
|
||||
poll();
|
||||
});
|
||||
}
|
||||
|
||||
async function mountDicomViewersSafely(timeout = 5000) {
|
||||
try {
|
||||
// wait for layout to stabilise
|
||||
await new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r)));
|
||||
const mountFn = await waitForMountFn(timeout);
|
||||
try { mountFn(); } catch (e) { console.warn('mountDicomViewers failed', e); }
|
||||
// allow any async render to settle then force a resize event
|
||||
requestAnimationFrame(() => {
|
||||
try { window.dispatchEvent(new Event('resize')); } catch (e) {}
|
||||
if (typeof window.resizeDicomViewers === 'function') try { window.resizeDicomViewers(); } catch (e) {}
|
||||
});
|
||||
} catch (err) {
|
||||
console.warn('Viewer initialization deferred/fallback:', err);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDisplaysetModal(url, dsId) {
|
||||
if (!url && dsId) url = `/atlas/${dsId}/display_sets/modal`;
|
||||
if (!url) return;
|
||||
@@ -1217,7 +1246,8 @@
|
||||
}
|
||||
} catch (e) { console.warn(e); }
|
||||
try { setUrlParam('displayset', dsId); } catch (e) {}
|
||||
setTimeout(function () { try { window.mountDicomViewers(); } catch (e) { console.warn('mountDicomViewers not available', e); } }, 500);
|
||||
// Initialize viewer deterministically after injecting HTML
|
||||
mountDicomViewersSafely();
|
||||
dsModal.show();
|
||||
} catch (error) {
|
||||
console.error('Error loading display set details:', error);
|
||||
@@ -1249,7 +1279,8 @@
|
||||
document.getElementById('displaysetFullscreenRight').innerHTML = tmp.innerHTML;
|
||||
try { if (dsId) { setUrlParam('displayset', dsId); setUrlParam('displayset_full', '1'); } } catch (e) {}
|
||||
dsFullscreenModal.show();
|
||||
setTimeout(function () { try { window.mountDicomViewers(); } catch (e) { console.warn('mountDicomViewers not available for fullscreen', e); } }, 500);
|
||||
// Ensure viewer is mounted and resized after moving into fullscreen
|
||||
mountDicomViewersSafely();
|
||||
} catch (error) {
|
||||
console.error('Error loading fullscreen display set:', error);
|
||||
document.getElementById('displaysetFullscreenLeft').innerHTML = '<p style="color:#fff; padding:1rem;">Failed to load viewer</p>';
|
||||
@@ -1266,11 +1297,12 @@
|
||||
const resp = await fetch(url);
|
||||
const html = await resp.text();
|
||||
modalBody.innerHTML = html;
|
||||
setTimeout(function () { try { window.mountDicomViewers(); } catch (e) { console.warn('mountDicomViewers not available', e); } }, 200);
|
||||
// Ensure viewers mount after content injection
|
||||
mountDicomViewersSafely();
|
||||
try { setUrlParam('finding', findingId); } catch (e) {}
|
||||
const modal = new bootstrap.Modal(document.getElementById('findingModal'));
|
||||
modal.show();
|
||||
document.getElementById('reload-finding')?.addEventListener('click', function () { window.mountDicomViewers(); });
|
||||
document.getElementById('reload-finding')?.addEventListener('click', function () { mountDicomViewersSafely(); });
|
||||
} catch (e) {
|
||||
console.error('Error loading finding details:', e);
|
||||
modalBody.innerHTML = '<p>Failed to load finding details.</p>';
|
||||
|
||||
@@ -38,20 +38,48 @@
|
||||
{% block js %}
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Delay mounting slightly to ensure viewer assets and DOM are ready
|
||||
setTimeout(function() { window.mountDicomViewers(); }, 500);
|
||||
// Helper: wait for mount function and mount the viewers safely
|
||||
function waitForMountFn(timeout = 5000) {
|
||||
if (window.mountDicomViewers) return Promise.resolve(window.mountDicomViewers);
|
||||
return new Promise((resolve, reject) => {
|
||||
const start = Date.now();
|
||||
function poll() {
|
||||
if (window.mountDicomViewers) return resolve(window.mountDicomViewers);
|
||||
if (Date.now() - start > timeout) return reject(new Error('mountDicomViewers not available'));
|
||||
requestAnimationFrame(poll);
|
||||
}
|
||||
poll();
|
||||
});
|
||||
}
|
||||
|
||||
async function mountDicomViewersSafely(timeout = 5000) {
|
||||
try {
|
||||
await new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r)));
|
||||
const mountFn = await waitForMountFn(timeout);
|
||||
try { mountFn(); } catch (e) { console.warn('mountDicomViewers failed', e); }
|
||||
requestAnimationFrame(() => { try { window.dispatchEvent(new Event('resize')); } catch (e) {} });
|
||||
} catch (err) {
|
||||
console.warn('Viewer initialization deferred/fallback:', err);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize viewers deterministically
|
||||
mountDicomViewersSafely();
|
||||
|
||||
|
||||
{% if selected_displayset %}
|
||||
setTimeout(function() {
|
||||
importAnnotations_main_viewer({{ selected_displayset.annotations|safe }});
|
||||
importViewerState_main_viewer({{ selected_displayset.viewerstate|safe }});
|
||||
// Highlight the selected displayset row
|
||||
var selectedRow = document.getElementById("displayset-{{ selected_displayset.pk }}");
|
||||
if (selectedRow) {
|
||||
selectedRow.style.border = "2px solid #ffc107";
|
||||
}
|
||||
}, 1000);
|
||||
(async function(){
|
||||
try {
|
||||
await mountDicomViewersSafely();
|
||||
importAnnotations_main_viewer({{ selected_displayset.annotations|safe }});
|
||||
importViewerState_main_viewer({{ selected_displayset.viewerstate|safe }});
|
||||
// Highlight the selected displayset row
|
||||
var selectedRow = document.getElementById("displayset-{{ selected_displayset.pk }}");
|
||||
if (selectedRow) {
|
||||
selectedRow.style.border = "2px solid #ffc107";
|
||||
}
|
||||
} catch (e) { console.warn('failed to import selected displayset state', e); }
|
||||
})();
|
||||
|
||||
{% if edit %}
|
||||
var editButton = document.getElementById("displayset-{{ selected_displayset.pk }}-edit-btn");
|
||||
|
||||
@@ -91,6 +91,29 @@
|
||||
function hideResourceLocal(){ const disp=document.getElementById('resourceDisplay'); const inner=document.getElementById('resourceInner'); if(disp) disp.style.display='none'; if(inner) inner.innerHTML=''; }
|
||||
(function(){ const disp=document.getElementById('resourceDisplay'); if(!disp) return; disp.addEventListener('click', function(e){ const close = e.target.closest && e.target.closest('#resourceClose'); if (close) hideResourceLocal(); }); })();
|
||||
|
||||
// Helper to safely mount the DICOM viewers (waits for bundle and layout)
|
||||
function waitForMountFn(timeout = 5000) {
|
||||
if (window.mountDicomViewers) return Promise.resolve(window.mountDicomViewers);
|
||||
return new Promise((resolve, reject) => {
|
||||
const start = Date.now();
|
||||
function poll() {
|
||||
if (window.mountDicomViewers) return resolve(window.mountDicomViewers);
|
||||
if (Date.now() - start > timeout) return reject(new Error('mountDicomViewers not available'));
|
||||
requestAnimationFrame(poll);
|
||||
}
|
||||
poll();
|
||||
});
|
||||
}
|
||||
|
||||
async function mountDicomViewersSafely(timeout = 5000) {
|
||||
try {
|
||||
await new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r)));
|
||||
const mountFn = await waitForMountFn(timeout);
|
||||
try { mountFn(); } catch (e) { console.warn('mountDicomViewers failed', e); }
|
||||
requestAnimationFrame(() => { try { window.dispatchEvent(new Event('resize')); } catch (e) {} });
|
||||
} catch (err) { console.warn('Viewer initialization deferred/fallback:', err); }
|
||||
}
|
||||
|
||||
bc.onmessage = (event) => {
|
||||
// Ensure any existing overlay is closed on new load
|
||||
try { hideResourceLocal(); } catch(_) {}
|
||||
@@ -182,7 +205,7 @@
|
||||
delete document.getElementById("root").dataset.annotationjson;
|
||||
}
|
||||
|
||||
window.mountDicomViewers();
|
||||
mountDicomViewersSafely();
|
||||
bc.postMessage({"type": "open-complete-local"});
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user