.
This commit is contained in:
@@ -178,7 +178,7 @@ function loadDicomViewer(images_to_load, annotations_to_load) {
|
||||
console.log(images);
|
||||
|
||||
let annotations = single_dicom.dataset.annotations;
|
||||
if (annotations != undefined) {
|
||||
if (annotations_to_load != undefined) {
|
||||
annotations = annotations_to_load;
|
||||
} else if (annotations && annotations.indexOf(",") > 0) {
|
||||
annotations = JSON.parse(annotations);
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.6 on 2021-08-20 09:09
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rapids', '0029_rapidimage_image_annotations'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='rapidimage',
|
||||
name='image_annotations',
|
||||
field=models.TextField(blank=True, help_text='Stores a JSON representation of annotations to be applied by cornerstonetools', null=True),
|
||||
),
|
||||
]
|
||||
+1
-1
@@ -388,7 +388,7 @@ class RapidImage(models.Model):
|
||||
image = models.FileField(upload_to=image_directory_path)
|
||||
|
||||
image_annotations = models.TextField(
|
||||
blank=True,
|
||||
blank=True, null=True,
|
||||
help_text="Stores a JSON representation of annotations to be applied by cornerstonetools",
|
||||
)
|
||||
|
||||
|
||||
@@ -89,15 +89,16 @@
|
||||
<summary>
|
||||
Image viewer
|
||||
</summary>
|
||||
<div id="single-dicom-viewer" class="dicom-viewer" data-images="{{ question.get_image_url_array }}" data-annotations='{{question.get_image_annotations}}'>
|
||||
<div id="single-dicom-viewer" class="dicom-viewer" data-images="{{ question.get_image_url_array }}"
|
||||
data-annotations='{{question.get_image_annotations}}'>
|
||||
</div>
|
||||
<button id="save-annotations">Save Annotations</button>
|
||||
</details>
|
||||
|
||||
<div class="pre-whitespace multi-image-block"><b>Image annotations:</b>
|
||||
<div class=""><b>Image annotations:</b>
|
||||
{% for image in question.images.all %}
|
||||
<span class="image-block">
|
||||
Image {{ forloop.counter }}: {{image.image_annotations}}
|
||||
Image {{ forloop.counter }}: {{image.image_annotations}}<br />
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
+6
-3
@@ -1160,10 +1160,13 @@ def question_save_annotation(request, pk):
|
||||
|
||||
question_images = question.images.all()
|
||||
|
||||
for n, annotation in enumerate(image_annotations):
|
||||
for n, image in enumerate(question_images):
|
||||
annotation = image_annotations[n]
|
||||
if annotation != "undefined":
|
||||
question_images[n].image_annotations = annotation
|
||||
question_images[n].save()
|
||||
image.image_annotations = annotation
|
||||
else:
|
||||
image.image_annotations = ""
|
||||
image.save()
|
||||
|
||||
data = {"status": "success"}
|
||||
return JsonResponse(data, status=200)
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
|
||||
#djDebug #djDebugToolbarHandle {
|
||||
position: fixed;
|
||||
transform: rotate(-90deg);
|
||||
transform: translateY(-100%) rotate(-90deg);
|
||||
transform-origin: right bottom;
|
||||
background-color: #fff;
|
||||
border: 1px solid #111;
|
||||
|
||||
@@ -7,21 +7,30 @@ $$.on(djDebug, "click", ".switchHistory", function (event) {
|
||||
const newStoreId = this.dataset.storeId;
|
||||
const tbody = this.closest("tbody");
|
||||
|
||||
tbody
|
||||
.querySelector(".djdt-highlighted")
|
||||
.classList.remove("djdt-highlighted");
|
||||
const highlighted = tbody.querySelector(".djdt-highlighted");
|
||||
if (highlighted) {
|
||||
highlighted.classList.remove("djdt-highlighted");
|
||||
}
|
||||
this.closest("tr").classList.add("djdt-highlighted");
|
||||
|
||||
ajaxForm(this).then(function (data) {
|
||||
djDebug.setAttribute("data-store-id", newStoreId);
|
||||
Object.keys(data).forEach(function (panelId) {
|
||||
const panel = document.getElementById(panelId);
|
||||
if (panel) {
|
||||
panel.outerHTML = data[panelId].content;
|
||||
document.getElementById("djdt-" + panelId).outerHTML =
|
||||
data[panelId].button;
|
||||
}
|
||||
});
|
||||
// Check if response is empty, it could be due to an expired store_id.
|
||||
if (Object.keys(data).length === 0) {
|
||||
const container = document.getElementById("djdtHistoryRequests");
|
||||
container.querySelector(
|
||||
'button[data-store-id="' + newStoreId + '"]'
|
||||
).innerHTML = "Switch [EXPIRED]";
|
||||
} else {
|
||||
Object.keys(data).forEach(function (panelId) {
|
||||
const panel = document.getElementById(panelId);
|
||||
if (panel) {
|
||||
panel.outerHTML = data[panelId].content;
|
||||
document.getElementById("djdt-" + panelId).outerHTML =
|
||||
data[panelId].button;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -29,12 +38,14 @@ $$.on(djDebug, "click", ".refreshHistory", function (event) {
|
||||
event.preventDefault();
|
||||
const container = document.getElementById("djdtHistoryRequests");
|
||||
ajaxForm(this).then(function (data) {
|
||||
// Remove existing rows first then re-populate with new data
|
||||
container
|
||||
.querySelectorAll("tr[data-store-id]")
|
||||
.forEach(function (node) {
|
||||
node.remove();
|
||||
});
|
||||
data.requests.forEach(function (request) {
|
||||
if (
|
||||
!container.querySelector('[data-store-id="' + request.id + '"]')
|
||||
) {
|
||||
container.innerHTML = request.content + container.innerHTML;
|
||||
}
|
||||
container.innerHTML = request.content + container.innerHTML;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,59 +1,75 @@
|
||||
const timingOffset = performance.timing.navigationStart,
|
||||
timingEnd = performance.timing.loadEventEnd,
|
||||
totalTime = timingEnd - timingOffset;
|
||||
function getLeft(stat) {
|
||||
return ((performance.timing[stat] - timingOffset) / totalTime) * 100.0;
|
||||
}
|
||||
function getCSSWidth(stat, endStat) {
|
||||
let width =
|
||||
((performance.timing[endStat] - performance.timing[stat]) / totalTime) *
|
||||
100.0;
|
||||
// Calculate relative percent (same as sql panel logic)
|
||||
width = (100.0 * width) / (100.0 - getLeft(stat));
|
||||
return width < 1 ? "2px" : width + "%";
|
||||
}
|
||||
function addRow(tbody, stat, endStat) {
|
||||
const row = document.createElement("tr");
|
||||
if (endStat) {
|
||||
// Render a start through end bar
|
||||
row.innerHTML =
|
||||
"<td>" +
|
||||
stat.replace("Start", "") +
|
||||
"</td>" +
|
||||
'<td><svg class="djDebugLineChart" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 5" preserveAspectRatio="none"><rect y="0" height="5" fill="#ccc" /></svg></td>' +
|
||||
"<td>" +
|
||||
(performance.timing[stat] - timingOffset) +
|
||||
" (+" +
|
||||
(performance.timing[endStat] - performance.timing[stat]) +
|
||||
")</td>";
|
||||
row.querySelector("rect").setAttribute(
|
||||
"width",
|
||||
getCSSWidth(stat, endStat)
|
||||
);
|
||||
} else {
|
||||
// Render a point in time
|
||||
row.innerHTML =
|
||||
"<td>" +
|
||||
stat +
|
||||
"</td>" +
|
||||
'<td><svg class="djDebugLineChart" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 5" preserveAspectRatio="none"><rect y="0" height="5" fill="#ccc" /></svg></td>' +
|
||||
"<td>" +
|
||||
(performance.timing[stat] - timingOffset) +
|
||||
"</td>";
|
||||
row.querySelector("rect").setAttribute("width", 2);
|
||||
import { $$ } from "./utils.js";
|
||||
|
||||
function insertBrowserTiming() {
|
||||
console.log(["inserted"]);
|
||||
const timingOffset = performance.timing.navigationStart,
|
||||
timingEnd = performance.timing.loadEventEnd,
|
||||
totalTime = timingEnd - timingOffset;
|
||||
function getLeft(stat) {
|
||||
return ((performance.timing[stat] - timingOffset) / totalTime) * 100.0;
|
||||
}
|
||||
function getCSSWidth(stat, endStat) {
|
||||
let width =
|
||||
((performance.timing[endStat] - performance.timing[stat]) /
|
||||
totalTime) *
|
||||
100.0;
|
||||
// Calculate relative percent (same as sql panel logic)
|
||||
width = (100.0 * width) / (100.0 - getLeft(stat));
|
||||
return width < 1 ? "2px" : width + "%";
|
||||
}
|
||||
function addRow(tbody, stat, endStat) {
|
||||
const row = document.createElement("tr");
|
||||
if (endStat) {
|
||||
// Render a start through end bar
|
||||
row.innerHTML =
|
||||
"<td>" +
|
||||
stat.replace("Start", "") +
|
||||
"</td>" +
|
||||
'<td><svg class="djDebugLineChart" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 5" preserveAspectRatio="none"><rect y="0" height="5" fill="#ccc" /></svg></td>' +
|
||||
"<td>" +
|
||||
(performance.timing[stat] - timingOffset) +
|
||||
" (+" +
|
||||
(performance.timing[endStat] - performance.timing[stat]) +
|
||||
")</td>";
|
||||
row.querySelector("rect").setAttribute(
|
||||
"width",
|
||||
getCSSWidth(stat, endStat)
|
||||
);
|
||||
} else {
|
||||
// Render a point in time
|
||||
row.innerHTML =
|
||||
"<td>" +
|
||||
stat +
|
||||
"</td>" +
|
||||
'<td><svg class="djDebugLineChart" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 5" preserveAspectRatio="none"><rect y="0" height="5" fill="#ccc" /></svg></td>' +
|
||||
"<td>" +
|
||||
(performance.timing[stat] - timingOffset) +
|
||||
"</td>";
|
||||
row.querySelector("rect").setAttribute("width", 2);
|
||||
}
|
||||
row.querySelector("rect").setAttribute("x", getLeft(stat));
|
||||
tbody.appendChild(row);
|
||||
}
|
||||
|
||||
const browserTiming = document.getElementById("djDebugBrowserTiming");
|
||||
// Determine if the browser timing section has already been rendered.
|
||||
if (browserTiming.classList.contains("djdt-hidden")) {
|
||||
const tbody = document.getElementById("djDebugBrowserTimingTableBody");
|
||||
// This is a reasonably complete and ordered set of timing periods (2 params) and events (1 param)
|
||||
addRow(tbody, "domainLookupStart", "domainLookupEnd");
|
||||
addRow(tbody, "connectStart", "connectEnd");
|
||||
addRow(tbody, "requestStart", "responseEnd"); // There is no requestEnd
|
||||
addRow(tbody, "responseStart", "responseEnd");
|
||||
addRow(tbody, "domLoading", "domComplete"); // Spans the events below
|
||||
addRow(tbody, "domInteractive");
|
||||
addRow(tbody, "domContentLoadedEventStart", "domContentLoadedEventEnd");
|
||||
addRow(tbody, "loadEventStart", "loadEventEnd");
|
||||
browserTiming.classList.remove("djdt-hidden");
|
||||
}
|
||||
row.querySelector("rect").setAttribute("x", getLeft(stat));
|
||||
tbody.appendChild(row);
|
||||
}
|
||||
|
||||
const tbody = document.getElementById("djDebugBrowserTimingTableBody");
|
||||
// This is a reasonably complete and ordered set of timing periods (2 params) and events (1 param)
|
||||
addRow(tbody, "domainLookupStart", "domainLookupEnd");
|
||||
addRow(tbody, "connectStart", "connectEnd");
|
||||
addRow(tbody, "requestStart", "responseEnd"); // There is no requestEnd
|
||||
addRow(tbody, "responseStart", "responseEnd");
|
||||
addRow(tbody, "domLoading", "domComplete"); // Spans the events below
|
||||
addRow(tbody, "domInteractive");
|
||||
addRow(tbody, "domContentLoadedEventStart", "domContentLoadedEventEnd");
|
||||
addRow(tbody, "loadEventStart", "loadEventEnd");
|
||||
document.getElementById("djDebugBrowserTiming").classList.remove("djdt-hidden");
|
||||
const djDebug = document.getElementById("djDebug");
|
||||
// Insert the browser timing now since it's possible for this
|
||||
// script to miss the initial panel load event.
|
||||
insertBrowserTiming();
|
||||
$$.onPanelRender(djDebug, "TimerPanel", insertBrowserTiming);
|
||||
|
||||
@@ -20,7 +20,8 @@ const djdt = {
|
||||
if (!this.className) {
|
||||
return;
|
||||
}
|
||||
const current = document.getElementById(this.className);
|
||||
const panelId = this.className;
|
||||
const current = document.getElementById(panelId);
|
||||
if ($$.visible(current)) {
|
||||
djdt.hide_panels();
|
||||
} else {
|
||||
@@ -39,13 +40,24 @@ const djdt = {
|
||||
window.location
|
||||
);
|
||||
url.searchParams.append("store_id", store_id);
|
||||
url.searchParams.append("panel_id", this.className);
|
||||
url.searchParams.append("panel_id", panelId);
|
||||
ajax(url).then(function (data) {
|
||||
inner.previousElementSibling.remove(); // Remove AJAX loader
|
||||
inner.innerHTML = data.content;
|
||||
$$.executeScripts(data.scripts);
|
||||
$$.applyStyles(inner);
|
||||
djDebug.dispatchEvent(
|
||||
new CustomEvent("djdt.panel.render", {
|
||||
detail: { panelId: panelId },
|
||||
})
|
||||
);
|
||||
});
|
||||
} else {
|
||||
djDebug.dispatchEvent(
|
||||
new CustomEvent("djdt.panel.render", {
|
||||
detail: { panelId: panelId },
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,6 +190,7 @@ const djdt = {
|
||||
requestAnimationFrame(function () {
|
||||
djdt.handleDragged = false;
|
||||
});
|
||||
djdt.ensure_handle_visibility();
|
||||
}
|
||||
});
|
||||
const show =
|
||||
@@ -198,6 +211,15 @@ const djdt = {
|
||||
e.classList.remove("djdt-active");
|
||||
});
|
||||
},
|
||||
ensure_handle_visibility() {
|
||||
const handle = document.getElementById("djDebugToolbarHandle");
|
||||
// set handle position
|
||||
const handleTop = Math.min(
|
||||
localStorage.getItem("djdt.top") || 0,
|
||||
window.innerHeight - handle.offsetWidth
|
||||
);
|
||||
handle.style.top = handleTop + "px";
|
||||
},
|
||||
hide_toolbar() {
|
||||
djdt.hide_panels();
|
||||
|
||||
@@ -205,16 +227,8 @@ const djdt = {
|
||||
|
||||
const handle = document.getElementById("djDebugToolbarHandle");
|
||||
$$.show(handle);
|
||||
// set handle position
|
||||
let handleTop = localStorage.getItem("djdt.top");
|
||||
if (handleTop) {
|
||||
handleTop = Math.min(
|
||||
handleTop,
|
||||
window.innerHeight - handle.offsetHeight
|
||||
);
|
||||
handle.style.top = handleTop + "px";
|
||||
}
|
||||
|
||||
djdt.ensure_handle_visibility();
|
||||
window.addEventListener("resize", djdt.ensure_handle_visibility);
|
||||
document.removeEventListener("keydown", onKeyDown);
|
||||
|
||||
localStorage.setItem("djdt.show", "false");
|
||||
@@ -237,6 +251,7 @@ const djdt = {
|
||||
$$.hide(document.getElementById("djDebugToolbarHandle"));
|
||||
$$.show(document.getElementById("djDebugToolbar"));
|
||||
localStorage.setItem("djdt.show", "true");
|
||||
window.removeEventListener("resize", djdt.ensure_handle_visibility);
|
||||
},
|
||||
cookie: {
|
||||
get(key) {
|
||||
|
||||
@@ -7,6 +7,21 @@ const $$ = {
|
||||
}
|
||||
});
|
||||
},
|
||||
onPanelRender(root, panelId, fn) {
|
||||
/*
|
||||
This is a helper function to attach a handler for a `djdt.panel.render`
|
||||
event of a specific panel.
|
||||
|
||||
root: The container element that the listener should be attached to.
|
||||
panelId: The Id of the panel.
|
||||
fn: A function to execute when the event is triggered.
|
||||
*/
|
||||
root.addEventListener("djdt.panel.render", function (event) {
|
||||
if (event.detail.panelId === panelId) {
|
||||
fn.call(event);
|
||||
}
|
||||
});
|
||||
},
|
||||
show(element) {
|
||||
element.classList.remove("djdt-hidden");
|
||||
},
|
||||
|
||||
@@ -178,7 +178,7 @@ function loadDicomViewer(images_to_load, annotations_to_load) {
|
||||
console.log(images);
|
||||
|
||||
let annotations = single_dicom.dataset.annotations;
|
||||
if (annotations != undefined) {
|
||||
if (annotations_to_load != undefined) {
|
||||
annotations = annotations_to_load;
|
||||
} else if (annotations && annotations.indexOf(",") > 0) {
|
||||
annotations = JSON.parse(annotations);
|
||||
|
||||
@@ -11,6 +11,7 @@ cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
|
||||
|
||||
cornerstoneTools.init();
|
||||
|
||||
let tool_state = {};
|
||||
|
||||
|
||||
export function loadCornerstone(main_element, db, images, annotations_to_load, load_as_stack = false) {
|
||||
@@ -180,15 +181,14 @@ export function loadCornerstone(main_element, db, images, annotations_to_load, l
|
||||
|
||||
|
||||
function loadAnnotation(imageId, annotation) {
|
||||
console.log("loadAnnotations", imageId, annotations);
|
||||
console.log("loadAnnotations", imageId, annotation);
|
||||
const toolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager;
|
||||
|
||||
if (annotation == undefined || annotation.length < 1 || annotation == [undefined]) { return }
|
||||
|
||||
console.log(annotation);
|
||||
console.log("1234", annotation);
|
||||
let tool_state_no_id = JSON.parse(annotation);
|
||||
|
||||
let tool_state = {};
|
||||
tool_state[imageId] = tool_state_no_id;
|
||||
|
||||
toolStateManager.restoreToolState(tool_state);
|
||||
|
||||
Reference in New Issue
Block a user