diff --git a/anatomy/static/css/anatomy.css b/anatomy/static/css/anatomy.css index b16dd961..cc458644 100644 --- a/anatomy/static/css/anatomy.css +++ b/anatomy/static/css/anatomy.css @@ -125,7 +125,7 @@ button a { float: right; } -#dicom-element { +#dicom-image { width: 60%; float: left; height: 600px; diff --git a/anatomy/static/js/anatomy.js b/anatomy/static/js/anatomy.js index 6bf2ad09..de6e2ca1 100644 --- a/anatomy/static/js/anatomy.js +++ b/anatomy/static/js/anatomy.js @@ -36,6 +36,8 @@ $(document).ready(function () { if($("#dicom-image").length) { + console.log("Dicom element found ", $("#dicom-image")); + $('#dicom-image').bind('contextmenu', function(e) { return false; }); @@ -53,7 +55,7 @@ cornerstoneTools.init(); const RotateTool = cornerstoneTools.RotateTool; const StackScrollTool = cornerstoneTools.StackScrollTool; const MagnifyTool = cornerstoneTools.MagnifyTool; - + const ArrowAnnotateTool = cornerstoneTools.ArrowAnnotateTool; const element = document.getElementById('dicom-image'); @@ -71,14 +73,40 @@ cornerstone.loadAndCacheImage(imageId).then(function(image) { cornerstoneTools.addTool(RotateTool); cornerstoneTools.addTool(StackScrollTool); cornerstoneTools.addTool(MagnifyTool); + + cornerstoneTools.addTool(ArrowAnnotateTool, { + configuration: { + getTextCallback: () => {}, + changeTextCallback: () => {}, + allowEmptyLabel: true, + renderDashed: false, + drawHandles: false, + drawHandlesOnHover: true, + }, + }); + + + // Enable our tools // Avoid incorrect aspect ratio - cornerstone.resize(element); cornerstoneTools.setToolActive("Pan", { mouseButtonMask: 1 }); cornerstoneTools.setToolActive("Wwwc", { mouseButtonMask: 2 }); cornerstoneTools.setToolActive("ZoomMouseWheel", { mouseButtonMask: 3 }); cornerstoneTools.setToolActive("Zoom", { mouseButtonMask: 4 }); + if (element.dataset.edit_annotation == "true") { + cornerstoneTools.setToolActive("ArrowAnnotate", { mouseButtonMask: 2 }); + } else { + cornerstoneTools.setToolEnabled("ArrowAnnotate"); + } + + if (element.dataset.annotations) { + loadJsonToolStateOnCurrentImage(element.dataset.annotations) + } + + cornerstone.resize(element); + + }); } @@ -132,3 +160,44 @@ function prepAnswerData() { }) $("#id_marked_answers").val(JSON.stringify(window.marked_answers)); } + +function getJsonToolStateNoId() { + const el = document.getElementById("dicom-image"); + + const c = cornerstone.getEnabledElement(el); + + const toolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager; + + const image_id = c.image.imageId; + + const state_with_id = toolStateManager.saveToolState() + + const json_tool_state = JSON.stringify(state_with_id[image_id]); + + return json_tool_state; + +} + + +function loadJsonToolStateOnCurrentImage(json) { + let el = document.getElementById("dicom-image"); + + const toolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager; + + const c = cornerstone.getEnabledElement(el); + + let image_id = c.image.imageId; + + let tool_state_no_id = JSON.parse(json); + + let tool_state = {}; + tool_state[image_id] = tool_state_no_id; + + toolStateManager.restoreToolState(tool_state); + + cornerstone.reset(el); + + return tool_state; + + +} \ No newline at end of file diff --git a/anatomy/templates/anatomy/exam.html b/anatomy/templates/anatomy/exam.html index d60aee97..5a72776e 100644 --- a/anatomy/templates/anatomy/exam.html +++ b/anatomy/templates/anatomy/exam.html @@ -41,7 +41,7 @@
-
+
{% csrf_token %} diff --git a/anatomy/templates/anatomy/mark.html b/anatomy/templates/anatomy/mark.html index c078f663..c8fd5eb5 100644 --- a/anatomy/templates/anatomy/mark.html +++ b/anatomy/templates/anatomy/mark.html @@ -4,7 +4,7 @@

Marking question {{question_details.current}} of {{question_details.total}}

{{ question.question_type }}

-
+
{% csrf_token %} diff --git a/anatomy/templates/anatomy/question_detail.html b/anatomy/templates/anatomy/question_detail.html index 1c2cb81d..1cb07c4c 100644 --- a/anatomy/templates/anatomy/question_detail.html +++ b/anatomy/templates/anatomy/question_detail.html @@ -1,15 +1,56 @@ {% extends 'anatomy/base.html' %} {% block content %} -
+{% load static %} +
+ + +
- {{ question.created_date }} + Created: {{ question.created_date }} +
+

{{ question.GetPrimaryAnswer }}

+

{{question.question_type}}

+ Answers (score): {% for answer in question.answers.all %} + {{ answer }} ({{answer.status}}), + {% endfor %} +
+ Examinations: {% for exam in question.exams.all %} + {{ exam.name }} + {% endfor %} +
+
+ Annotation JSON: {{ question.image_annotations }}
-

{% for answer in question.answers.all %} - {{ answer }}, - {% endfor %}

{{ question.question_type.first|linebreaksbr }}

+ {% endblock %} \ No newline at end of file diff --git a/anatomy/urls.py b/anatomy/urls.py index ec4d60f8..3bb772fa 100644 --- a/anatomy/urls.py +++ b/anatomy/urls.py @@ -7,6 +7,7 @@ urlpatterns = [ # path('', views.question_list, name='question_list'), path("", views.index, name="index"), path("question//", views.question_detail, name="question_detail"), + path("question//save_annotation", views.question_save_annotation, name="question_save_annotation"), path("question//answer/", views.answer_question, name="answer_question"), diff --git a/anatomy/views.py b/anatomy/views.py index 8037fd54..e6de161a 100644 --- a/anatomy/views.py +++ b/anatomy/views.py @@ -474,6 +474,21 @@ def active_exams(request): return JsonResponse(active_exams) +def question_save_annotation(request, pk): + if request.is_ajax() and request.method=='POST': + question = get_object_or_404(AnatomyQuestion, pk=pk) + + question.image_annotations = request.POST.get("annotation") + print(question.image_annotations) + + question.save() + data = {'status':'success'} + return JsonResponse(data, status=200) + else: + data = {'status':'error'} + return JsonResponse(data, status=400) + + def exam_json(request, pk): exam = get_object_or_404(Exam, pk=pk) @@ -497,6 +512,7 @@ def exam_json(request, pk): "title": "{}".format(q.description), "question": str(q.question_type), "images": [image_as_base64(q.image)], + "annotations": [q.image_annotations], "type": "anatomy", }