Implement code changes to enhance functionality and improve performance
This commit is contained in:
+237
-139
@@ -76,7 +76,7 @@ $(document).ready(function () {
|
|||||||
if (dicom_images.length) {
|
if (dicom_images.length) {
|
||||||
|
|
||||||
for (let element of dicom_images) {
|
for (let element of dicom_images) {
|
||||||
setUpDicom(element)
|
setUpDicom3d(element)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -361,159 +361,257 @@ function loadJsonToolStateOnCurrentImage(json) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setUpDicom(element) {
|
//async function setUpDicom(element) {
|
||||||
|
// console.log("setUpDicom (original)", element);
|
||||||
|
//
|
||||||
|
// $(element).bind('contextmenu', function (e) {
|
||||||
|
// return false;
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// $(element).dblclick((evt) => {
|
||||||
|
// element.requestFullscreen();
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// cornerstoneBase64ImageLoader.external.cornerstone = cornerstone;
|
||||||
|
// cornerstoneWebImageLoader.external.cornerstone = cornerstone;
|
||||||
|
// cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
|
||||||
|
//
|
||||||
|
// cornerstoneTools.init();
|
||||||
|
// const PanTool = cornerstoneTools.PanTool;
|
||||||
|
// const ZoomTool = cornerstoneTools.ZoomTool;
|
||||||
|
// const ZoomMouseWheelTool = cornerstoneTools.ZoomMouseWheelTool;
|
||||||
|
// const WwwcTool = cornerstoneTools.WwwcTool;
|
||||||
|
// const WwwcRegionTool = cornerstoneTools.WwwcRegionTool;
|
||||||
|
// const RotateTool = cornerstoneTools.RotateTool;
|
||||||
|
// const StackScrollTool = cornerstoneTools.StackScrollTool;
|
||||||
|
// const MagnifyTool = cornerstoneTools.MagnifyTool;
|
||||||
|
// const ArrowAnnotateTool = cornerstoneTools.ArrowAnnotateTool;
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// const images = element.dataset.url.split(",");
|
||||||
|
//
|
||||||
|
// //console.log("Dicom - load imageId: ", imageIds);
|
||||||
|
// //for (let index = 0; index < imageIds.length; index++) {
|
||||||
|
// // if (imageIds[index].endsWith("dcm")) {
|
||||||
|
// // imageIds[index] = "wadouri:" + imageIds[index];
|
||||||
|
// // }
|
||||||
|
//
|
||||||
|
// //}
|
||||||
|
// let imageIds = [];
|
||||||
|
// for (let i = 0; i < images.length; i++) {
|
||||||
|
// let data_url = images[i];
|
||||||
|
// // check stack type
|
||||||
|
// if (data_url.startsWith("data:image")) {
|
||||||
|
// let imageId = "base64://" + data_url.split(",")[1];
|
||||||
|
//
|
||||||
|
// imageIds.push(imageId);
|
||||||
|
// } else if (data_url.startsWith("base64://") || data_url.startsWith("wadouri:")) {
|
||||||
|
//
|
||||||
|
// imageIds.push(data_url);
|
||||||
|
//
|
||||||
|
// // Treat application/octet-stream as if they are dicoms
|
||||||
|
// } else if (data_url.startsWith("data:application/dicom") || data_url.startsWith("data:application/octet-stream")) {
|
||||||
|
// //stack = stack.split(";")[1];
|
||||||
|
//
|
||||||
|
// let dfile = await urltoFile(data_url, "dicom", "application/dicom");
|
||||||
|
//
|
||||||
|
// const imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add(
|
||||||
|
// dfile
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// loadAnnotation(imageId, annotation);
|
||||||
|
//
|
||||||
|
// imageIds.push(imageId);
|
||||||
|
// //cornerstone.loadImage(imageId).then(function(image) {
|
||||||
|
// // tempFunction(image);
|
||||||
|
// //});
|
||||||
|
// } else {
|
||||||
|
// let url;
|
||||||
|
// // This doesn't seem to have any benefit
|
||||||
|
// //if (data_url.startsWith("http")) {
|
||||||
|
// // url = data_url;
|
||||||
|
// //} else {
|
||||||
|
// // url = window.location.href.replace(/\/\#\/?$/, '') + "/" + data_url
|
||||||
|
// //}
|
||||||
|
// url = data_url;
|
||||||
|
//
|
||||||
|
// if (url.endsWith("dcm")) {
|
||||||
|
// url = "wadouri:" + url;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // if there is no extension treat it as a dicom
|
||||||
|
// if (/(?:\/|^)[^.\/]+$/.test(url)) {
|
||||||
|
// url = "wadouri:" + url;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// imageIds.push(url);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// cornerstone.enable(element);
|
||||||
|
// cornerstone.loadAndCacheImage(imageIds[0]).then(function (image) {
|
||||||
|
// cornerstone.displayImage(element, image);
|
||||||
|
//
|
||||||
|
// cornerstoneTools.addToolForElement(element, PanTool);
|
||||||
|
// cornerstoneTools.addToolForElement(element, ZoomTool);
|
||||||
|
// cornerstoneTools.addToolForElement(element, ZoomMouseWheelTool);
|
||||||
|
// cornerstoneTools.addToolForElement(element, WwwcTool);
|
||||||
|
// cornerstoneTools.addToolForElement(element, WwwcRegionTool);
|
||||||
|
// cornerstoneTools.addToolForElement(element, RotateTool);
|
||||||
|
// cornerstoneTools.addToolForElement(element, StackScrollTool);
|
||||||
|
// cornerstoneTools.addToolForElement(element, MagnifyTool);
|
||||||
|
//
|
||||||
|
// cornerstoneTools.addToolForElement(element, ArrowAnnotateTool, {
|
||||||
|
// configuration: {
|
||||||
|
// getTextCallback: () => {},
|
||||||
|
// changeTextCallback: () => {},
|
||||||
|
// allowEmptyLabel: true,
|
||||||
|
// renderDashed: false,
|
||||||
|
// drawHandles: false,
|
||||||
|
// drawHandlesOnHover: true,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// // Enable our tools
|
||||||
|
// // Avoid incorrect aspect ratio
|
||||||
|
// cornerstoneTools.setToolActiveForElement(element, "Pan", {
|
||||||
|
// mouseButtonMask: 1
|
||||||
|
// });
|
||||||
|
// cornerstoneTools.setToolActiveForElement(element, "Wwwc", {
|
||||||
|
// mouseButtonMask: 2
|
||||||
|
// });
|
||||||
|
// cornerstoneTools.setToolActiveForElement(element, "ZoomMouseWheel", {
|
||||||
|
// mouseButtonMask: 3
|
||||||
|
// });
|
||||||
|
// cornerstoneTools.setToolActiveForElement(element, "Zoom", {
|
||||||
|
// mouseButtonMask: 4
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// if (element.dataset.edit_annotation == "true") {
|
||||||
|
// cornerstoneTools.setToolActiveForElement(element, "ArrowAnnotate", {
|
||||||
|
// mouseButtonMask: 2
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// cornerstoneTools.setToolEnabledForElement(element, "ArrowAnnotate");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (element.dataset.annotations) {
|
||||||
|
// loadJsonToolStateOnCurrentImage(element.dataset.annotations)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// cornerstone.resize(element);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// }).catch((err, err2) => {
|
||||||
|
// console.log(err);
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//console.log("setUpDicom defined");
|
||||||
|
//
|
||||||
|
//// keep reference to the existing 2D setup
|
||||||
|
//window.setUpDicomClassic = setUpDicom;
|
||||||
|
|
||||||
console.log("Dicom element found ", $(element));
|
async function setUpDicom3d(element) {
|
||||||
|
console.log("setUpDicom3d (cornerstone3d) for", element);
|
||||||
|
|
||||||
$(element).bind('contextmenu', function (e) {
|
// parse images from dataset
|
||||||
return false;
|
let raw = element.dataset.url || "";
|
||||||
});
|
if (!raw) return;
|
||||||
|
let images;
|
||||||
$(element).dblclick((evt) => {
|
try {
|
||||||
element.requestFullscreen();
|
images = JSON.parse(raw);
|
||||||
})
|
} catch (e) {
|
||||||
|
images = raw.split(",").map(s => s.trim()).filter(Boolean);
|
||||||
cornerstoneBase64ImageLoader.external.cornerstone = cornerstone;
|
|
||||||
cornerstoneWebImageLoader.external.cornerstone = cornerstone;
|
|
||||||
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
|
|
||||||
|
|
||||||
cornerstoneTools.init();
|
|
||||||
const PanTool = cornerstoneTools.PanTool;
|
|
||||||
const ZoomTool = cornerstoneTools.ZoomTool;
|
|
||||||
const ZoomMouseWheelTool = cornerstoneTools.ZoomMouseWheelTool;
|
|
||||||
const WwwcTool = cornerstoneTools.WwwcTool;
|
|
||||||
const WwwcRegionTool = cornerstoneTools.WwwcRegionTool;
|
|
||||||
const RotateTool = cornerstoneTools.RotateTool;
|
|
||||||
const StackScrollTool = cornerstoneTools.StackScrollTool;
|
|
||||||
const MagnifyTool = cornerstoneTools.MagnifyTool;
|
|
||||||
const ArrowAnnotateTool = cornerstoneTools.ArrowAnnotateTool;
|
|
||||||
|
|
||||||
|
|
||||||
const images = element.dataset.url.split(",");
|
|
||||||
|
|
||||||
//console.log("Dicom - load imageId: ", imageIds);
|
|
||||||
//for (let index = 0; index < imageIds.length; index++) {
|
|
||||||
// if (imageIds[index].endsWith("dcm")) {
|
|
||||||
// imageIds[index] = "wadouri:" + imageIds[index];
|
|
||||||
// }
|
|
||||||
|
|
||||||
//}
|
|
||||||
let imageIds = [];
|
|
||||||
for (let i = 0; i < images.length; i++) {
|
|
||||||
let data_url = images[i];
|
|
||||||
// check stack type
|
|
||||||
if (data_url.startsWith("data:image")) {
|
|
||||||
let imageId = "base64://" + data_url.split(",")[1];
|
|
||||||
|
|
||||||
imageIds.push(imageId);
|
|
||||||
} else if (data_url.startsWith("base64://") || data_url.startsWith("wadouri:")) {
|
|
||||||
|
|
||||||
imageIds.push(data_url);
|
|
||||||
|
|
||||||
// Treat application/octet-stream as if they are dicoms
|
|
||||||
} else if (data_url.startsWith("data:application/dicom") || data_url.startsWith("data:application/octet-stream")) {
|
|
||||||
//stack = stack.split(";")[1];
|
|
||||||
|
|
||||||
let dfile = await urltoFile(data_url, "dicom", "application/dicom");
|
|
||||||
|
|
||||||
const imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add(
|
|
||||||
dfile
|
|
||||||
);
|
|
||||||
|
|
||||||
loadAnnotation(imageId, annotation);
|
|
||||||
|
|
||||||
imageIds.push(imageId);
|
|
||||||
//cornerstone.loadImage(imageId).then(function(image) {
|
|
||||||
// tempFunction(image);
|
|
||||||
//});
|
|
||||||
} else {
|
|
||||||
let url;
|
|
||||||
// This doesn't seem to have any benefit
|
|
||||||
//if (data_url.startsWith("http")) {
|
|
||||||
// url = data_url;
|
|
||||||
//} else {
|
|
||||||
// url = window.location.href.replace(/\/\#\/?$/, '') + "/" + data_url
|
|
||||||
//}
|
|
||||||
url = data_url;
|
|
||||||
|
|
||||||
if (url.endsWith("dcm")) {
|
|
||||||
url = "wadouri:" + url;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there is no extension treat it as a dicom
|
|
||||||
if (/(?:\/|^)[^.\/]+$/.test(url)) {
|
|
||||||
url = "wadouri:" + url;
|
|
||||||
}
|
|
||||||
|
|
||||||
imageIds.push(url);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (!images || images.length === 0) return;
|
||||||
|
|
||||||
cornerstone.enable(element);
|
// ensure element has a viewport-like appearance
|
||||||
cornerstone.loadAndCacheImage(imageIds[0]).then(function (image) {
|
element.style.width = element.style.width || "500px";
|
||||||
cornerstone.displayImage(element, image);
|
element.style.height = element.style.height || "500px";
|
||||||
|
element.style.position = element.style.position || "relative";
|
||||||
|
element.innerHTML = ""; // clear
|
||||||
|
|
||||||
cornerstoneTools.addToolForElement(element, PanTool);
|
// create a unique rendering engine / viewport ids per element
|
||||||
cornerstoneTools.addToolForElement(element, ZoomTool);
|
const renderingEngineId = `rendingEngine`;
|
||||||
cornerstoneTools.addToolForElement(element, ZoomMouseWheelTool);
|
const viewportId = `CT_AXIAL-STACK`;
|
||||||
cornerstoneTools.addToolForElement(element, WwwcTool);
|
|
||||||
cornerstoneTools.addToolForElement(element, WwwcRegionTool);
|
|
||||||
cornerstoneTools.addToolForElement(element, RotateTool);
|
|
||||||
cornerstoneTools.addToolForElement(element, StackScrollTool);
|
|
||||||
cornerstoneTools.addToolForElement(element, MagnifyTool);
|
|
||||||
|
|
||||||
cornerstoneTools.addToolForElement(element, ArrowAnnotateTool, {
|
try {
|
||||||
configuration: {
|
// dynamic import of cornerstone3D core + dicom loader
|
||||||
getTextCallback: () => {},
|
const coreModule = window.cornerstone3d
|
||||||
changeTextCallback: () => {},
|
const dicomLoaderModule = window.cornerstoneDICOMImageLoader
|
||||||
allowEmptyLabel: true,
|
|
||||||
renderDashed: false,
|
await coreModule.init();
|
||||||
drawHandles: false,
|
await dicomLoaderModule.init();
|
||||||
drawHandlesOnHover: true,
|
|
||||||
},
|
const { RenderingEngine, Enums } = coreModule;
|
||||||
|
const { chunkManager } = dicomLoaderModule; // may exist for some setups
|
||||||
|
|
||||||
|
// create engine and enable a Stack viewport
|
||||||
|
const renderingEngine = new RenderingEngine(renderingEngineId);
|
||||||
|
console.log(renderingEngine)
|
||||||
|
|
||||||
|
const viewportInput = {
|
||||||
|
viewportId,
|
||||||
|
type: Enums.ViewportType.STACK,
|
||||||
|
element,
|
||||||
|
//viewportType: Enums.ViewportType.STACK, // Stack viewport for slice stacks
|
||||||
|
};
|
||||||
|
|
||||||
|
renderingEngine.enableElement(viewportInput);
|
||||||
|
|
||||||
|
const viewport = renderingEngine.getViewport(viewportId);
|
||||||
|
|
||||||
|
// Prepare imageIds: ensure remote URLs are usable by dicom-image-loader (wadouri:)
|
||||||
|
const imageIds = images.map((url) => {
|
||||||
|
url = url.trim();
|
||||||
|
// if it's already a scheme we pass through; otherwise treat as wadouri
|
||||||
|
if (/^(wadouri:|base64:|data:)/i.test(url)) return url;
|
||||||
|
return `wadouri:${url}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// If dicom-image-loader provides a metadata cache factory, pre-cache metadata
|
||||||
|
if (typeof dicomLoaderModule.createImageIdsAndCacheMetaData === "function") {
|
||||||
// Enable our tools
|
try {
|
||||||
// Avoid incorrect aspect ratio
|
// attempt to call helper to cache meta-data for the first image (best-effort)
|
||||||
cornerstoneTools.setToolActiveForElement(element, "Pan", {
|
await dicomLoaderModule.createImageIdsAndCacheMetaData({
|
||||||
mouseButtonMask: 1
|
imageIds,
|
||||||
});
|
});
|
||||||
cornerstoneTools.setToolActiveForElement(element, "Wwwc", {
|
} catch (e) {
|
||||||
mouseButtonMask: 2
|
// not fatal — continue
|
||||||
});
|
console.warn("createImageIdsAndCacheMetaData failed (continuing):", e);
|
||||||
cornerstoneTools.setToolActiveForElement(element, "ZoomMouseWheel", {
|
}
|
||||||
mouseButtonMask: 3
|
|
||||||
});
|
|
||||||
cornerstoneTools.setToolActiveForElement(element, "Zoom", {
|
|
||||||
mouseButtonMask: 4
|
|
||||||
});
|
|
||||||
|
|
||||||
if (element.dataset.edit_annotation == "true") {
|
|
||||||
cornerstoneTools.setToolActiveForElement(element, "ArrowAnnotate", {
|
|
||||||
mouseButtonMask: 2
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
cornerstoneTools.setToolEnabledForElement(element, "ArrowAnnotate");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.dataset.annotations) {
|
await viewport.setStack(imageIds, 0);
|
||||||
loadJsonToolStateOnCurrentImage(element.dataset.annotations)
|
|
||||||
}
|
|
||||||
|
|
||||||
cornerstone.resize(element);
|
viewport.render();
|
||||||
|
|
||||||
|
// store references for debugging/use elsewhere
|
||||||
|
element._cornerstone3d = {
|
||||||
|
renderingEngineId,
|
||||||
|
viewportId,
|
||||||
|
renderingEngine,
|
||||||
|
viewport,
|
||||||
|
imageIds,
|
||||||
|
};
|
||||||
|
|
||||||
}).catch((err, err2) => {
|
console.log("setUpDicom3d complete", element._cornerstone3d);
|
||||||
console.log(err);
|
return element._cornerstone3d;
|
||||||
});
|
} catch (err) {
|
||||||
|
console.error("setUpDicom3d failed:", err);
|
||||||
|
// per request: no fallback here — rethrow so caller can handle if desired
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.setUpDicom = setUpDicom;
|
// expose globally like existing code expects
|
||||||
|
window.setUpDicom = setUpDicom3d;
|
||||||
|
|
||||||
|
|
||||||
//function keyUpHandler(e) {
|
//function keyUpHandler(e) {
|
||||||
// if (e.key == "Control") {
|
// if (e.key == "Control") {
|
||||||
|
|||||||
+615
-188
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user