This commit is contained in:
Ross
2021-12-04 16:09:12 +00:00
parent 11cd73ec64
commit 39e93932b7
8 changed files with 427 additions and 8380 deletions
+1 -1
View File
@@ -44,7 +44,7 @@
color: lightblue;
}
.single-dicom-viewer {
.cornerstone-element {
position: relative;
height: 100%;
}
+108 -108
View File
@@ -370,114 +370,114 @@ function setUpDicom(element) {
}
function keyUpHandler(e) {
if (e.key == "Control") {
dicomViewer.registerPrimaryDicomInterface(e);
window.control_pressed = false;
}
}
function keyDownHandler(e) {
// Ignore our custom keybindings if we are currently in a field that
// accepts some kind of input
if ($("*:focus:not(disabled)").is("textarea, input")) {
// unless a modifier key is pressed (not shift)
if (e.altKey ? true : false || e.ctrlKey ? true : false) {} else {
return;
}
}
if (e.key == "Control") {
if (window.control_pressed == false) {
window.control_pressed = true;
dicomViewer.registerAltDicomInterface(e);
}
}
var charCode = typeof e.which == "number" ? e.which : e.keyCode;
console.log(e, charCode);
function numberKeyPressed(e, x) {
if (e.altKey ? true : false) {
dicomViewer.selectThumb(x);
e.preventDefault();
} else {}
}
switch (charCode) {
case 13: // Return
if (e.shiftKey ? true : false) {
//$(".next-button:last").click();
} else {
//$(".check-button:last").click();
}
break;
case 32: // Space
if (e.shiftKey ? true : false) {
//$(".previous-button:last").click();
} else {
//$(".next-button:last").click();
}
e.preventDefault(); // Needed to stop the default action (scroll)
break;
case 46: // .
//toggleFlagged();
break;
// Numbers 1-9 select the corresponding answer (if it exists)
// TODO: fix for multi question questions
case 49: // 1
numberKeyPressed(e, 0);
break;
case 50: // 2
numberKeyPressed(e, 1);
break;
case 51: // 3
numberKeyPressed(e, 2);
break;
case 52: // 4
numberKeyPressed(e, 3);
break;
case 53: // 5
numberKeyPressed(e, 4);
break;
case 54: // 6
numberKeyPressed(e, 5);
break;
case 55: // 7
numberKeyPressed(e, 6);
break;
case 56: // 8
numberKeyPressed(e, 7);
break;
case 57: // 9
numberKeyPressed(e, 8);
break;
case 72: // H
previousQuestion();
break;
case 76: // L
//nextQuestion();
break;
case 102: // f
//$("#filter-toggle").click();
break;
case 103: // g
//$("#options").slideDown("slow");
//$("#goto-question-input").focus();
//e.preventDefault();
break;
// Vim like scrolling (incredibly important)
case 106: // j
//window.scrollBy(0, 25);
break;
case 107: // k
//window.scrollBy(0, -25);
break;
}
}
//function keyUpHandler(e) {
// if (e.key == "Control") {
// dicomViewer.registerPrimaryDicomInterface(e);
// window.control_pressed = false;
// }
//}
//
//function keyDownHandler(e) {
// // Ignore our custom keybindings if we are currently in a field that
// // accepts some kind of input
// if ($("*:focus:not(disabled)").is("textarea, input")) {
// // unless a modifier key is pressed (not shift)
// if (e.altKey ? true : false || e.ctrlKey ? true : false) {} else {
// return;
// }
// }
//
// if (e.key == "Control") {
// if (window.control_pressed == false) {
// window.control_pressed = true;
// dicomViewer.registerAltDicomInterface(e);
// }
// }
//
// var charCode = typeof e.which == "number" ? e.which : e.keyCode;
// console.log(e, charCode);
//
// function numberKeyPressed(e, x) {
// if (e.altKey ? true : false) {
// dicomViewer.selectThumb(x);
// e.preventDefault();
// } else {}
// }
//
// switch (charCode) {
// case 13: // Return
// if (e.shiftKey ? true : false) {
// //$(".next-button:last").click();
// } else {
// //$(".check-button:last").click();
// }
// break;
// case 32: // Space
// if (e.shiftKey ? true : false) {
// //$(".previous-button:last").click();
// } else {
// //$(".next-button:last").click();
// }
// e.preventDefault(); // Needed to stop the default action (scroll)
// break;
// case 46: // .
// //toggleFlagged();
// break;
//
// // Numbers 1-9 select the corresponding answer (if it exists)
// // TODO: fix for multi question questions
// case 49: // 1
// numberKeyPressed(e, 0);
// break;
// case 50: // 2
// numberKeyPressed(e, 1);
// break;
// case 51: // 3
// numberKeyPressed(e, 2);
// break;
// case 52: // 4
// numberKeyPressed(e, 3);
// break;
// case 53: // 5
// numberKeyPressed(e, 4);
// break;
// case 54: // 6
// numberKeyPressed(e, 5);
// break;
// case 55: // 7
// numberKeyPressed(e, 6);
// break;
// case 56: // 8
// numberKeyPressed(e, 7);
// break;
// case 57: // 9
// numberKeyPressed(e, 8);
// break;
// case 72: // H
// previousQuestion();
// break;
// case 76: // L
// //nextQuestion();
// break;
//
// case 102: // f
// //$("#filter-toggle").click();
// break;
// case 103: // g
// //$("#options").slideDown("slow");
// //$("#goto-question-input").focus();
// //e.preventDefault();
// break;
//
// // Vim like scrolling (incredibly important)
// case 106: // j
// //window.scrollBy(0, 25);
// break;
// case 107: // k
// //window.scrollBy(0, -25);
// break;
// }
//}
function create_popup_window(url, title) {
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+198 -63
View File
@@ -9,17 +9,22 @@ cornerstoneBase64ImageLoader.external.cornerstone = cornerstone;
cornerstoneWebImageLoader.external.cornerstone = cornerstone;
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
cornerstoneTools.init();
cornerstoneTools.init({ keyboardEnabled: true });
let tool_state = {};
export function loadCornerstone(main_element, db, images, annotations_to_load, load_as_stack = false) {
// canvas-panel holds the enabled elements and all tools / menus
main_element.append("<div class='canvas-panel'></div>");
const canvas_panel = $("<div class='canvas-panel'></div>");
main_element.append(canvas_panel);
main_element[0].dataset.collapsed = "none";
$(".canvas-panel").append($("<div class='single-dicom-viewer'></div>"));
$(".canvas-panel").append($(`<div id='dicom-summary-panel'>
const cornerstone_element = $("<div class='cornerstone-element'></div>");
const element = cornerstone_element.get(0);
canvas_panel.append(cornerstone_element);
canvas_panel.append($(`<div id='dicom-summary-panel'>
<span id="dicom-summary-close" class="close-button"><a href="#">close</a></span>
<div class="container-fluid">
<h1>DICOM Summary</h1>
@@ -309,16 +314,14 @@ export function loadCornerstone(main_element, db, images, annotations_to_load, l
</div>
</div>`));
let single_dicom_viewer = main_element.find(".single-dicom-viewer").get(0);
//console.log(single_dicom_viewer);
$(".canvas-panel").append($(`<div id='dicom-log-panel'>
canvas_panel.append($(`<div id='dicom-log-panel'>
<span id="dicom-log-close" class="close-button"><a href="#">close</a></span>
</div>`));
// Add generic settings menus to canvas-panel
$(".canvas-panel").append(
$(`<div id='dicom-settings-panel'>
$(`<div id='dicom-settings-panel'>
<span id="dicom-settings-close" class="close-button"><a href="#">close</a></span>
<span class="view-log-button"><a href="#">view log</a></span>
<h3>Image viewer settings:</h3>
@@ -380,7 +383,7 @@ export function loadCornerstone(main_element, db, images, annotations_to_load, l
</div>
</div>`)
)
)
.append($("<span id='dicom-toggle-mode-button' class='dicom-button' title='toggle stack/thumbnail view'>↻</span>"))
.append($("<span id='dicom-fullscreen-button' class='dicom-button' title='toggle stack/thumbnail view'>⛶</span>"))
.append($("<span id='dicom-settings-button' class='dicom-button' title='open settings'>&#9881;</span>"))
@@ -398,7 +401,7 @@ export function loadCornerstone(main_element, db, images, annotations_to_load, l
</div>`)
);
$(single_dicom_viewer).append(
cornerstone_element.append(
$(
"<div id='dicom-overlay'>Image <span id='current_image_number'></span> of <span id='total_image_number'></span><br />wc: <span id='wc'></span> ww: <span id='ww'></span></div>"
)
@@ -417,15 +420,13 @@ export function loadCornerstone(main_element, db, images, annotations_to_load, l
$("#dicom-window-panel button").each((n, el) => {
$(el).click((e) => {
//console.log(e);
//console.log(e.target);
let button_id = e.target.id;
let [ww, wc] = window_presets[button_id];
let viewport = cornerstone.getViewport(single_dicom_viewer);
let viewport = cornerstone.getViewport(element);
viewport.voi.windowWidth = parseFloat(ww);
viewport.voi.windowCenter = parseFloat(wc);
cornerstone.setViewport(single_dicom_viewer, viewport);
cornerstone.setViewport(element, viewport);
e.preventDefault();
e.stopPropagation();
@@ -454,6 +455,13 @@ export function loadCornerstone(main_element, db, images, annotations_to_load, l
$("#dicom-settings-panel").toggle();
});
$("#dicom-info-button").click(e => {
try {
// todo improve
dumpDataSet(cornerstone.getEnabledElement(element).image.data);
} catch {
console.log("unable to extract dicom data")
}
$("#dicom-summary-panel").toggle();
});
$("#dicom-fullscreen-button").click(e => {
@@ -486,7 +494,7 @@ export function loadCornerstone(main_element, db, images, annotations_to_load, l
$("#dicom-window-panel").show();
$(e.target).removeClass("dicom-button-highlight");
}
resizeHandler();
resizeHandler(element);
//loadCornerstone(main_element, db, images, annotations_to_load, stack)
});
@@ -497,7 +505,6 @@ export function loadCornerstone(main_element, db, images, annotations_to_load, l
images = [images];
}
//console.log("Images", images)
//let annotations = [];
//if (annotations_to_load) {
@@ -510,11 +517,9 @@ export function loadCornerstone(main_element, db, images, annotations_to_load, l
if (!Array.isArray(annotations)) {
annotations = [annotations];
}
//console.log("annon", annotations);
function loadAnnotation(imageId, annotation) {
//console.log("loadAnnotations", imageId, annotation);
const toolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager;
if (annotation == undefined || annotation.length < 1 || annotation == [undefined]) {
@@ -529,7 +534,6 @@ export function loadCornerstone(main_element, db, images, annotations_to_load, l
}
async function load(images, annotations) {
//console.log("LOAD", images);
let imageIds = [];
for (let i = 0; i < images.length; i++) {
let data_url = images[i];
@@ -593,12 +597,16 @@ export function loadCornerstone(main_element, db, images, annotations_to_load, l
imageIds
};
//cornerstone.loadAndCacheImage(imageIds[0]).then(function(image) {
//console.log("load and cache", imageIds[0])
cornerstone.loadAndCacheImage(imageIds[0]).then(function (image) {
//console.log("LOAD and cache, then", image);
loadCornerstoneMainImage(single_dicom_viewer, image, stack, db, load_as_stack);
})
//console.log("LOAD and cache, then", image);
loadCornerstoneMainImage(element, image, stack, db, load_as_stack);
let load_annotation_image = true;
if (load_annotation_image) {
getNextAnnotationImage(element)
}
})
.catch((err, err2) => {
console.log(err);
$("#dicom-log-panel").append("<br/>").append(err.stack);
@@ -636,13 +644,12 @@ export function loadCornerstone(main_element, db, images, annotations_to_load, l
"</span></div>"
);
$("#image-thumbs").append(thumb);
$("#thumb-" + id).click(selectThumbClick).mousedown(stopEvent);
$("#thumb-" + id).click((evt) => { selectThumbClick(evt, element) }).mousedown(stopEvent);
let image_url = images[id];
let img;
//console.log("load thumb", image_url);
if (image_url.startsWith("data")) {
// based (image) data url, just load the image directly
@@ -670,7 +677,7 @@ export function loadCornerstone(main_element, db, images, annotations_to_load, l
);
cornerstone.loadAndCacheImage(imageId).then(function (image) {
loadCornerstoneThumb(image, id);
});
});
});
}
} else {
@@ -703,12 +710,124 @@ export function loadCornerstone(main_element, db, images, annotations_to_load, l
}
load(images, annotations);
main_element.keydown((evt) => { keyDownHandler(evt, element) });
main_element.keyup((evt) => { keyUpHandler(evt, element) });
}
function keyUpHandler(e, element) {
if (e.key == "Control") {
registerPrimaryDicomInterface(element);
window.control_pressed = false;
}
}
function keyDownHandler(e, element) {
//// Ignore our custom keybindings if we are currently in a field that
//// accepts some kind of input
//if ($("*:focus:not(disabled)").is("textarea, input")) {
// // unless a modifier key is pressed (not shift)
// if (e.altKey ? true : false || e.ctrlKey ? true : false) {} else {
// return;
// }
//}
if (e.key == "Control") {
if (window.control_pressed != true) {
window.control_pressed = true;
registerAltDicomInterface(e, element);
}
}
var charCode = typeof e.which == "number" ? e.which : e.keyCode;
function numberKeyPressed(e, x) {
if (e.altKey ? true : false) {
loadStackIndex(x, element);
e.preventDefault();
} else { }
}
switch (charCode) {
case 13: // Return
getNextAnnotationImage(element);
if (e.shiftKey ? true : false) {
//$(".next-button:last").click();
} else {
//$(".check-button:last").click();
}
break;
case 32: // Space
if (e.shiftKey ? true : false) {
//$(".previous-button:last").click();
} else {
//$(".next-button:last").click();
}
e.preventDefault(); // Needed to stop the default action (scroll)
break;
case 46: // .
//toggleFlagged();
break;
// Numbers 1-9 select the corresponding answer (if it exists)
// TODO: fix for multi question questions
case 49: // 1
numberKeyPressed(e, 0);
break;
case 50: // 2
numberKeyPressed(e, 1);
break;
case 51: // 3
numberKeyPressed(e, 2);
break;
case 52: // 4
numberKeyPressed(e, 3);
break;
case 53: // 5
numberKeyPressed(e, 4);
break;
case 54: // 6
numberKeyPressed(e, 5);
break;
case 55: // 7
numberKeyPressed(e, 6);
break;
case 56: // 8
numberKeyPressed(e, 7);
break;
case 57: // 9
numberKeyPressed(e, 8);
break;
case 72: // H
previousQuestion();
break;
case 76: // L
//nextQuestion();
break;
case 102: // f
//$("#filter-toggle").click();
break;
case 103: // g
//$("#options").slideDown("slow");
//$("#goto-question-input").focus();
//e.preventDefault();
break;
// Vim like scrolling (incredibly important)
case 106: // j
//window.scrollBy(0, 25);
break;
case 107: // k
//window.scrollBy(0, -25);
break;
}
}
function loadCornerstoneMainImage(element, image, stack, db, load_as_stack) {
//dumpDataSet(image.data)
//console.log("loadCornerstoneMainImage")
//console.log("load as stack:", load_as_stack)
// It is probably silly to do this each time we load a question
const PanTool = cornerstoneTools.PanTool;
const ZoomTool = cornerstoneTools.ZoomTool;
@@ -723,11 +842,13 @@ function loadCornerstoneMainImage(element, image, stack, db, load_as_stack) {
const RectangleRoiTool = cornerstoneTools.RectangleRoiTool;
const LengthTool = cornerstoneTools.LengthTool;
//console.log("enable element", element);
cornerstone.enable(element);
element.tabIndex = 0;
cornerstone.displayImage(element, image);
//cornerstoneTools.keyboardInput.enable(element);
cornerstoneTools.addStackStateManager(element, ["stack"]);
cornerstoneTools.addToolState(element, "stack", stack);
@@ -746,8 +867,8 @@ function loadCornerstoneMainImage(element, image, stack, db, load_as_stack) {
cornerstoneTools.addToolForElement(element, ArrowAnnotateTool, {
configuration: {
getTextCallback: () => {},
changeTextCallback: () => {},
getTextCallback: () => { },
changeTextCallback: () => { },
allowEmptyLabel: true,
renderDashed: false,
drawHandles: false,
@@ -765,7 +886,8 @@ function loadCornerstoneMainImage(element, image, stack, db, load_as_stack) {
},
});
cornerstoneTools.setToolEnabledForElement(element, "ArrowAnnotate");
//cornerstoneTools.setToolEnabledForElement(element, "ArrowAnnotate");
//cornerstoneTools.setToolEnabledForElement(element, ArrowAnnotateTool);
let available_tools = [
@@ -789,8 +911,8 @@ function loadCornerstoneMainImage(element, image, stack, db, load_as_stack) {
//$("#middle-mouse-dicom").append(option);
//$("#right-mouse-dicom").append(option);
});
$(".mouse-binding-select").on("change", function (e) {
changeMouseBinding(e, db);
$(".mouse-binding-select").on("change", function (evt) {
changeMouseBinding(evt, db, element);
});
// Set default tools
@@ -799,7 +921,6 @@ function loadCornerstoneMainImage(element, image, stack, db, load_as_stack) {
$("#primary-mouse-binding .mouse-binding-select[data-button=4]").val("Zoom");
//cornerstoneTools.setToolActive("Pan", { mouseButtonMask: 1 });
//console.log(load_as_stack);
if (load_as_stack) {
cornerstoneTools.setToolActiveForElement(element, "StackScrollMouseWheel", {
mouseButtonMask: 3
@@ -821,10 +942,11 @@ function loadCornerstoneMainImage(element, image, stack, db, load_as_stack) {
"WwwcRegion"
);
loadPrimaryDicomInterface(db);
loadPrimaryDicomInterface(db, element);
loadAltDicomInterface(db);
element.addEventListener("cornerstoneimagerendered", onImageRendered);
//element.addEventListener("cornerstonetoolskeydown", keyDownHandler);
//setDicomCanvasNonFullscreen(element);
cornerstone.reset(element);
@@ -846,9 +968,9 @@ function loadCornerstoneMainImage(element, image, stack, db, load_as_stack) {
// .get(0)
// .addEventListener("change", changeControlSelection);
resizeHandler();
resizeHandler(element);
window.addEventListener("resize", resizeHandler);
window.addEventListener("resize", () => { resizeHandler(element) });
element.addEventListener(
"contextmenu",
function (e) {
@@ -864,14 +986,13 @@ function loadCornerstoneMainImage(element, image, stack, db, load_as_stack) {
});
}
function resizeHandler() {
let element = document.getElementsByClassName("single-dicom-viewer")[0];
function resizeHandler(element) {
let h = window.innerHeight - $("#header").height() - 16;
$(element).height(h);
cornerstone.resize(element, true);
}
async function loadPrimaryDicomInterface(db) {
async function loadPrimaryDicomInterface(db, element) {
const bindings = await dicom_settings_db.mouse_bindings.where({
mode: "0"
}).toArray().catch((err) => {
@@ -884,7 +1005,7 @@ async function loadPrimaryDicomInterface(db) {
sel.value = b.tool;
//sel.dispatchEvent(new Event("change"));
});
registerPrimaryDicomInterface();
registerPrimaryDicomInterface(element);
}
async function loadAltDicomInterface(db) {
@@ -904,14 +1025,6 @@ async function loadAltDicomInterface(db) {
// Called when the dicom image is loaded / rendered
function onImageRendered(e) {
const eventData = e.detail;
//console.log(e);
try {
// todo improve
dumpDataSet(eventData.image.data);
} catch {
console.log("unable to extract dicom data")
}
// Update ww/wl
$("#wc").text(Math.round(eventData.viewport.voi.windowCenter));
@@ -945,16 +1058,16 @@ function stopEvent(evt) {
evt.stopPropagation();
}
function selectThumbClick(evt) {
function selectThumbClick(evt, element) {
let new_index = evt.currentTarget.dataset.id;
selectThumb(new_index);
loadStackIndex(new_index, element);
evt.preventDefault();
}
export function registerPrimaryDicomInterface() {
export function registerPrimaryDicomInterface(element) {
console.log("reg primary")
// Set mousetools based upon the selected options
let element = document.getElementsByClassName("single-dicom-viewer")[0];
let selections = $("#primary-mouse-binding select");
selections.each((i, option) => {
cornerstoneTools.setToolActiveForElement(element, option.value, {
@@ -963,11 +1076,12 @@ export function registerPrimaryDicomInterface() {
});
}
export function registerAltDicomInterface(e) {
export function registerAltDicomInterface(e, element) {
// Called when control is pressed
// Set mousetools based upon the selected options
let element = document.getElementsByClassName("single-dicom-viewer")[0];
//let element = document.getElementsByClassName("cornerstone-element")[0];
console.log("reg alt", element)
let selections = $("#secondary-mouse-binding select");
selections.each((i, option) => {
cornerstoneTools.setToolActiveForElement(element, option.value, {
@@ -976,8 +1090,8 @@ export function registerAltDicomInterface(e) {
});
}
function changeMouseBinding(e, db) {
let select = e.currentTarget;
function changeMouseBinding(evt, db, element) {
let select = evt.currentTarget;
let button = select.dataset.button;
let mode = select.dataset.mode;
let tool = select.value;
@@ -985,7 +1099,6 @@ function changeMouseBinding(e, db) {
// Directly activate primary tools (secondary will be activated when modifier
// key is pressed
if (mode == "0") {
let element = document.getElementsByClassName("single-dicom-viewer")[0];
cornerstoneTools.setToolActiveForElement(element, tool, {
mouseButtonMask: parseInt(button)
});
@@ -999,10 +1112,9 @@ function changeMouseBinding(e, db) {
//db.mouse_bindings.put({button: button, mode: mode, tool: tool}).then(loadPrimaryDicomInterface());
}
export function selectThumb(new_index) {
//console.log("select thumb new index", new_index);
export function loadStackIndex(new_index, dicom_element) {
console.log("select new stack index", new_index);
// There must be a better way to do this...
let dicom_element = document.getElementsByClassName("single-dicom-viewer")[0];
if (dicom_element == null) {
return;
}
@@ -1061,4 +1173,27 @@ function dumpDataSet(dataSet) {
$(value).text(text);
});
}
export function getNextAnnotationImage(element) {
const enabled_element = cornerstone.getEnabledElement(element)
const image_ids = enabled_element.toolStateManager.toolState.stack.data[0].imageIds;
const current_image = enabled_element.toolStateManager.toolState.stack.data[0].currentImageIdIndex;
const annotated_images = Object.getOwnPropertyNames(cornerstoneTools.globalImageIdSpecificToolStateManager.toolState);
console.log("getNextAnnotationImage", image_ids, current_image, annotated_images);
if (annotated_images.length > 0) {
let offset = current_image;
for( let i=0; i < image_ids.length; i++) {
console.log("i", i)
let pointer = (i + offset) % image_ids.length;
console.log("pointer", pointer, image_ids[pointer]);
console.log(annotated_images);
if (annotated_images.includes(image_ids[pointer])) {
console.log("load")
loadStackIndex(pointer, element);
}
}
}
}