// Dicom saved settings var dicom_settings_db = new Dexie("dicom_settings"); dicom_settings_db.version(1).stores({ mouse_bindings: "button,mode,tool", }); cornerstoneBase64ImageLoader.external.cornerstone = cornerstone; cornerstoneWebImageLoader.external.cornerstone = cornerstone; cornerstoneWADOImageLoader.external.cornerstone = cornerstone; 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 const canvas_panel = $("
"); main_element.append(canvas_panel); main_element[0].dataset.collapsed = "none"; const cornerstone_element = $("
"); const element = cornerstone_element.get(0); canvas_panel.append(cornerstone_element); canvas_panel.append($(`
close

DICOM Summary

Patient Information

Patient Name:
Patient ID:
Patient Birth Date:
Patient Sex:

Study Information

Study Description:
Protocol Name:
Accession #:
Study Id:
Study Date:
Study Time:

Series Information

Series Description:
Series #:
Modality:
Body Part:
Series Date:
Series Time:

Instance Information

Instance #:
Acquisition #:
Acquisition Date:
Acquisition Time:
Content Date:
Content Time:

Image Information

Rows:
Columns:
Photometric Interpretation:
Image Type:
Bits Allocated:
Bits Stored:
HighBit:
Pixel Representation (0=us):
Rescale Slope:
Rescale Intercept:
Image Position Patient:
Image Orientation Patient:
Pixel Spacing:
Samples Per Pixel:

Equipment Information

Manufacturer:
Model:
Station Name:
AE Title:
Institution Name:
Software Version:
Implementation Version Name:

UIDS

Study UID:
Series UID:
Instance UID:
SOP Class UID:
Transfer Syntax UID:
Frame of Reference UID:
WADO URL:
http://localhost:3333/wado?requestType=WADO&studyUID=&seriesUID=&objectUID=&contentType=application%2Fdicom&transferSyntax=1.2.840.10008.1.2.1
`)); canvas_panel.append($(`
close
`)); // Add generic settings menus to canvas-panel $(".canvas-panel").append( $(`
close view log

Image viewer settings:

Primary

Secondary (Ctrl)
`) ) .append($("")) .append($("")) .append($("")) .append($("")) .append($("🛈")) .append( $(`
`) ); cornerstone_element.append( $( "
Image of
wc: ww:
" ) ); // Add buttons let window_presets = { "window-btn-abdomen": [400, 50], "window-btn-liver": [150, 30], "window-btn-mediastinum": [350, 50], "window-btn-lung": [1500, -600], "window-btn-brain": [80, 40], "window-btn-stroke": [40, 40], "window-btn-bone": [1800, 400] } $("#dicom-window-panel button").each((n, el) => { $(el).click((e) => { let button_id = e.target.id; let [ww, wc] = window_presets[button_id]; let viewport = cornerstone.getViewport(element); viewport.voi.windowWidth = parseFloat(ww); viewport.voi.windowCenter = parseFloat(wc); cornerstone.setViewport(element, viewport); e.preventDefault(); e.stopPropagation(); }) }) $("#dicom-settings-close").click(e => { $("#dicom-settings-panel").hide(); e.preventDefault(); }); $("#dicom-summary-close").click(e => { $("#dicom-summary-panel").hide(); e.preventDefault(); }); $("#dicom-log-close").click(e => { $("#dicom-log-panel").hide(); e.preventDefault(); }); $(".view-log-button").click(e => { $("#dicom-settings-panel").hide(); $("#dicom-log-panel").show(); e.preventDefault(); }); $("#dicom-settings-button").click(e => { $("#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 => { if (!document.fullscreenElement) { $(".canvas-panel").get(0).requestFullscreen().catch(err => { alert(`Error attempting to enable full-screen mode: ${err.message} (${err.name})`); }); } else { document.exitFullscreen(); } }); $("#dicom-toggle-mode-button").click(e => { //$("#dicom-settings-panel").toggle(); let stack = !load_as_stack; $(main_element).empty(); loadCornerstone(main_element, db, images, annotations_to_load, stack) }); $("#dicom-collapse-button").click(e => { //$("#dicom-settings-panel").toggle(); //let stack = !load_as_stack; if (main_element[0].dataset.collapsed == "none") { main_element[0].dataset.collapsed = main_element.width(); main_element.width("50px"); $("#dicom-window-panel").hide(); $(e.target).addClass("dicom-button-highlight"); } else { main_element.width(main_element[0].dataset.collapsed); main_element[0].dataset.collapsed = "none" $("#dicom-window-panel").show(); $(e.target).removeClass("dicom-button-highlight"); } resizeHandler(element); //loadCornerstone(main_element, db, images, annotations_to_load, stack) }); //let images = data["images"]; // Make sure we have an array if (!Array.isArray(images)) { images = [images]; } //let annotations = []; //if (annotations_to_load) { //annotations = annotations_to_load[figure_to_load.split("-")[1]]; //if (!Array.isArray(annotations)) { //annotations = [annotations]; //} //} let annotations = annotations_to_load; if (!Array.isArray(annotations)) { annotations = [annotations]; } function loadAnnotation(imageId, annotation) { const toolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager; if (annotation == undefined || annotation.length < 1 || annotation == [undefined]) { return } let tool_state_no_id = JSON.parse(annotation); tool_state[imageId] = tool_state_no_id; toolStateManager.restoreToolState(tool_state); } async function load(images, annotations) { let imageIds = []; for (let i = 0; i < images.length; i++) { let data_url = images[i]; const annotation = annotations[i]; // check stack type if (data_url.startsWith("data:image")) { let imageId = "base64://" + data_url.split(",")[1]; loadAnnotation(imageId, annotation); imageIds.push(imageId); } else if (data_url.startsWith("base64://") || data_url.startsWith("wadouri:")) { loadAnnotation(data_url, annotation); 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; } loadAnnotation(url, annotation); imageIds.push(url); } } const stack = { currentImageIdIndex: 0, imageIds }; //cornerstone.loadAndCacheImage(imageIds[0]).then(function(image) { cornerstone.loadAndCacheImage(imageIds[0]).then(function (image) { //console.log("LOAD and cache, then", image); loadCornerstoneMainImage(element, image, stack, db, load_as_stack); checkAnonStatus(image.data) let load_annotation_image = true; if (load_annotation_image) { getNextAnnotationImage(element) } }) .catch((err, err2) => { console.log(err); $("#dicom-log-panel").append("
").append(err.stack); }); } function loadCornerstoneThumb(image, id) { let img = $("
").get(0); img.id = "thumb-image-" + id; img.class = "thumbnail"; img.title = "Click on the thumbnail to view and manipulate the image."; img.draggable = "false"; img.style = "height: 100px; width: 100px"; $("#thumb-" + id).append(img); const element = document.getElementById("thumb-image-" + id); cornerstone.enable(element); cornerstone.displayImage(element, image); cornerstone.resize(element); } if (images.length > 1 && load_as_stack == false) { $(".canvas-panel").append("
"); for (let id = 0; id < images.length; id++) { let n = id + 1; let thumb = $( "
" + n + "
" ); $("#image-thumbs").append(thumb); $("#thumb-" + id).click((evt) => { selectThumbClick(evt, element) }).mousedown(stopEvent); let image_url = images[id]; let img; if (image_url.startsWith("data")) { // based (image) data url, just load the image directly if (image_url.startsWith("data:image/")) { img = $("", { src: image_url, id: "thumb-image-" + id, class: "thumbnail", title: "Click on the thumbnail to view and manipulate the image.", draggable: "false", style: "height: 100px;" }); $("#thumb-" + id).append(img); // otherwise try to load it as a dicom } else { // convert the data url to a file urltoFile(image_url, "dicom", "application/dicom").then(function ( dfile ) { // load the file using cornerstoneWADO file loader const imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add( dfile ); cornerstone.loadAndCacheImage(imageId).then(function (image) { loadCornerstoneThumb(image, id); }); }); } } else { if (image_url.startsWith("wadouri") || image_url.startsWith("base64")) { cornerstone.loadAndCacheImage(image_url).then(function (image) { loadCornerstoneThumb(image, id); }); } else if ((!image_url.endsWith("dicom") && !image_url.endsWith("dcm"))) { img = $("", { src: image_url, id: "thumb-image-" + id, class: "thumbnail", title: "Click on the thumbnail to view and manipulate the image.", draggable: "false", style: "height: 100px;" }); $("#thumb-" + id).append(img); // otherwise try to load it as a dicom } else { let url = "wadouri:" + image_url; cornerstone.loadAndCacheImage(url).then(function (image) { loadCornerstoneThumb(image, id); }); } } } } 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 38: // Up manualScrollDicom(1, element); e.preventDefault(); break; case 40: // down manualScrollDicom(-1, element); e.preventDefault(); 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) { // It is probably silly to do this each time we load a question const PanTool = cornerstoneTools.PanTool; const ZoomTool = cornerstoneTools.ZoomTool; const ZoomMouseWheelTool = cornerstoneTools.ZoomMouseWheelTool; const StackScrollMouseWheelTool = cornerstoneTools.StackScrollMouseWheelTool; 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 RectangleRoiTool = cornerstoneTools.RectangleRoiTool; const LengthTool = cornerstoneTools.LengthTool; const AngleTool = cornerstoneTools.AngleTool; const CobbAngleTool = cornerstoneTools.CobbAngleTool; const EraserTool = cornerstoneTools.EraserTool; cornerstone.enable(element); element.tabIndex = 0; cornerstone.displayImage(element, image); //cornerstoneTools.keyboardInput.enable(element); cornerstoneTools.addStackStateManager(element, ["stack"]); cornerstoneTools.addToolState(element, "stack", stack); cornerstoneTools.addToolForElement(element, PanTool); cornerstoneTools.addToolForElement(element, ZoomTool); cornerstoneTools.addToolForElement(element, ZoomMouseWheelTool); cornerstoneTools.addToolForElement(element, StackScrollMouseWheelTool); cornerstoneTools.addToolForElement(element, WwwcTool); cornerstoneTools.addToolForElement(element, WwwcRegionTool); cornerstoneTools.addToolForElement(element, RotateTool); cornerstoneTools.addToolForElement(element, StackScrollTool); cornerstoneTools.addToolForElement(element, MagnifyTool); cornerstoneTools.addToolForElement(element, LengthTool); cornerstoneTools.addToolForElement(element, AngleTool); cornerstoneTools.addToolForElement(element, CobbAngleTool); cornerstoneTools.addToolForElement(element, EraserTool); //cornerstoneTools.addTool(ArrowAnnotateTool); //cornerstoneTools.addTool(RectangleRoiTool); cornerstoneTools.addToolForElement(element, ArrowAnnotateTool, { configuration: { getTextCallback: () => {}, changeTextCallback: () => {}, allowEmptyLabel: true, renderDashed: false, drawHandles: false, drawHandlesOnHover: true, }, }); cornerstoneTools.addToolForElement(element, RectangleRoiTool, { configuration: { showHounsfieldUnits: false, showMinMax: false, allowEmptyLabel: true, renderDashed: false, drawHandles: false, drawHandlesOnHover: true, }, }); cornerstoneTools.setToolEnabledForElement(element, "ArrowAnnotate"); let available_tools = [ "Pan", "Zoom", "Wwwc", "WwwcRegion", "Rotate", "StackScroll", "Magnify", "Length", "ArrowAnnotate", "RectangleRoi", "Angle", "CobbAngle", "Eraser", ]; $(".mouse-binding-select option").remove(); available_tools.forEach(function (tool) { let option = ""; $(".mouse-binding-select").append(option); //$("#left-mouse-dicom").append(option); //$("#middle-mouse-dicom").append(option); //$("#right-mouse-dicom").append(option); }); $(".mouse-binding-select").on("change", function (evt) { changeMouseBinding(evt, db, element); }); // Set default tools $("#primary-mouse-binding .mouse-binding-select[data-button=1]").val("Pan"); $("#primary-mouse-binding .mouse-binding-select[data-button=2]").val("Wwwc"); $("#primary-mouse-binding .mouse-binding-select[data-button=3]").val("Zoom"); $("#primary-mouse-binding .mouse-binding-select[data-button=4]").val("Zoom"); //cornerstoneTools.setToolActive("Pan", { mouseButtonMask: 1 }); if (load_as_stack) { cornerstoneTools.setToolActiveForElement(element, "StackScrollMouseWheel", { //mouseButtonMask: [4] }); } else { cornerstoneTools.setToolActiveForElement(element, "ZoomMouseWheel", { //mouseButtonMask: [4] }); } //cornerstoneTools.setToolActive("Zoom", { mouseButtonMask: 4 }); //cornerstoneTools.setToolActive("Wwwc", { mouseButtonMask: 2 }); $("#secondary-mouse-binding .mouse-binding-select[data-button=1]").val( "Magnify" ); $("#secondary-mouse-binding .mouse-binding-select[data-button=2]").val( "Rotate" ); $("#secondary-mouse-binding .mouse-binding-select[data-button=3]").val( "StackScroll" ); $("#secondary-mouse-binding .mouse-binding-select[data-button=4]").val( "WwwcRegion" ); loadPrimaryDicomInterface(db, element); loadAltDicomInterface(db); element.addEventListener("cornerstoneimagerendered", onImageRendered); element.addEventListener("cornerstonenewimage", onNewImage); //element.addEventListener("cornerstonetoolskeydown", keyDownHandler); //setDicomCanvasNonFullscreen(element); cornerstone.reset(element); //element.scrollIntoView(false); //element.scrollTo(0); $(element).dblclick(function () { cornerstone.reset(this); }); element.removeEventListener("wheel", element.wheelEventHandler); // Add tool selector //$(".canvas-panel").append( // '' //); //$(".control-overlay") // .get(0) // .addEventListener("change", changeControlSelection); resizeHandler(element); window.addEventListener("resize", () => { resizeHandler(element) }); element.addEventListener( "contextmenu", function (e) { // do something here... e.preventDefault(); }, false ); $(element).on("mouseup", function (event) { console.log(event) if (event.which == 4) { getNextAnnotationImage(element) } $(".magnifyTool").hide(); }); } function resizeHandler(element) { let h = window.innerHeight - $("#header").height() - 16; $(element).height(h); cornerstone.resize(element, true); } async function loadPrimaryDicomInterface(db, element) { const bindings = await dicom_settings_db.mouse_bindings.where({ mode: "0" }).toArray().catch((err) => { console.log(err); }); bindings.forEach(function (b) { let sel = $("#primary-mouse-binding select[data-button=" + b.button + "]").get( 0 ); sel.value = b.tool; //sel.dispatchEvent(new Event("change")); }); registerPrimaryDicomInterface(element); } async function loadAltDicomInterface(db) { const bindings = await dicom_settings_db.mouse_bindings.where({ mode: "1" }).toArray().catch((err) => { console.log(err); }); bindings.forEach(function (b) { let sel = $( "#secondary-mouse-binding select[data-button=" + b.button + "]" ).get(0); sel.value = b.tool; }); } function onNewImage(e) { let dataSet = e.detail.image.data; checkAnonStatus(dataSet) } function checkAnonStatus(dataSet) { let accession_number = dataSet.string('x00080050').toLowerCase(); let patient_id = dataSet.string('x00100020').toLowerCase(); let not_anon = false; let site_codes = ["ref", "rk9", "ra9", "rh8", "rbz", "rba"] for (let i = 0; i < site_codes.length; i++) { if ( accession_number.startsWith(site_codes[i]) || patient_id.startsWith(site_codes[i])) { not_anon = true; } } if (not_anon) { toastr.warning(`File does not appear to be annonymised
Accession: ${accession_number}
Patient ID: ${patient_id}
`, 'Anonymisation warning', { "closeButton": false, "debug": false, "newestOnTop": false, "progressBar": false, "positionClass": "toast-top-full-width", "preventDuplicates": false, "onclick": null, "showDuration": "0", "hideDuration": "0", "timeOut": 0, "extendedTimeOut": 0, "showEasing": "swing", "hideEasing": "linear", "showMethod": "fadeIn", "hideMethod": "fadeOut", }); } } // Called when the dicom image is loaded / rendered function onImageRendered(e) { const eventData = e.detail; // Update ww/wl $("#wc").text(Math.round(eventData.viewport.voi.windowCenter)); $("#ww").text(Math.round(eventData.viewport.voi.windowWidth)); // update stack data let stack = eventData.enabledElement.toolStateManager.toolState.stack.data[0]; $("#total_image_number").text(stack.imageIds.length); $("#current_image_number").text(parseInt(stack.currentImageIdIndex) + 1); if (stack.imageIds.length > 1) { $(".thumb").removeClass("thumb-active"); $("#thumb-" + stack.currentImageIdIndex).addClass("thumb-active"); } } function stopEvent(evt) { //console.log("stop", evt) evt.preventDefault(); evt.stopPropagation(); } function selectThumbClick(evt, element) { let new_index = evt.currentTarget.dataset.id; loadStackIndex(new_index, element); evt.preventDefault(); } export function registerPrimaryDicomInterface(element) { console.log("reg primary") // Set mousetools based upon the selected options let selections = $("#primary-mouse-binding select"); selections.each((i, option) => { cornerstoneTools.setToolActiveForElement(element, option.value, { mouseButtonMask: parseInt(option.dataset.button) }); }); } export function registerAltDicomInterface(e, element) { // Called when control is pressed // Set mousetools based upon the selected options //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, { mouseButtonMask: parseInt(option.dataset.button) }); }); } function changeMouseBinding(evt, db, element) { let select = evt.currentTarget; let button = select.dataset.button; let mode = select.dataset.mode; let tool = select.value; // Directly activate primary tools (secondary will be activated when modifier // key is pressed if (mode == "0") { cornerstoneTools.setToolActiveForElement(element, tool, { mouseButtonMask: parseInt(button) }); } dicom_settings_db.mouse_bindings.put({ button: button, mode: mode, tool: tool }); //db.mouse_bindings.put({button: button, mode: mode, tool: tool}).then(loadPrimaryDicomInterface()); } export function loadStackIndex(new_index, dicom_element) { console.log("select new stack index", new_index); // There must be a better way to do this... if (dicom_element == null) { return; } let c = cornerstone.getEnabledElement(dicom_element); // let current_index = // c.toolStateManager.toolState.stack.data[0].currentImageIdIndex; c.toolStateManager.toolState.stack.data[0].currentImageIdIndex = new_index; let id = c.toolStateManager.toolState.stack.data[0].imageIds[new_index]; ////console.log("select thumb id", id); //console.log("select thumb el", dicom_element); cornerstone.loadImage(id).then(b => { //console.log("b", b); cornerstone.displayImage(dicom_element, b); }); //c = cornerstone.getEnabledElement(dicom_element) } function urltoFile(url, filename, mimeType) { return fetch(url) .then(function (res) { return res.arrayBuffer(); }) .then(function (buf) { return new File([buf], filename, { type: mimeType }); }); } function dumpDataSet(dataSet) { $('span[data-dicom]').each(function (index, value) { var attr = $(value).attr('data-dicom'); var element = dataSet.elements[attr]; var text = ""; if (element !== undefined) { var str = dataSet.string(attr); if (str !== undefined) { text = str; } } $(value).text(text); }); $('span[data-dicomUint]').each(function (index, value) { var attr = $(value).attr('data-dicomUint'); var element = dataSet.elements[attr]; var text = ""; if (element !== undefined) { if (element.length === 2) { text += dataSet.uint16(attr); } else if (element.length === 4) { text += dataSet.uint32(attr); } } $(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.saveToolState()); if (annotated_images.length > 0) { let offset = current_image; for (let i = 0; i < image_ids.length; i++) { let pointer = (i + offset) % image_ids.length; if (annotated_images.includes(image_ids[pointer])) { loadStackIndex(pointer, element); } } } } function manualScrollDicom(n, dicom_element) { // There must be a better way to do this... //dicom_element = document.getElementById("dicom-image"); let c = cornerstone.getEnabledElement(dicom_element); let max = c.toolStateManager.toolState.stack.data[0].imageIds.length; if (max < 2) { return; } let current_index = c.toolStateManager.toolState.stack.data[0].currentImageIdIndex; let new_index = current_index + n let corrected_index = Math.min(Math.max(new_index, 0), max) // TODO: if loop //if (new_index >= max) { // corrected_index = new_index - max; //} else if (new_index < 0) { // corrected_index = new_index + max; //} c.toolStateManager.toolState.stack.data[0].currentImageIdIndex = corrected_index; let id = c.toolStateManager.toolState.stack.data[0].imageIds[corrected_index]; cornerstone.loadImage(id).then((b) => { cornerstone.displayImage(dicom_element, b); }); // c = cornerstone.getEnabledElement(dicom_element) }