diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..297a8b7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+
+# testing
+/coverage
+
+# misc
+package-lock.json
\ No newline at end of file
diff --git a/README.md b/README.md
index f15e335..7fbe0f7 100644
--- a/README.md
+++ b/README.md
@@ -20,3 +20,25 @@ If you make changes and tag this project make sure that the version of the ```pa
1. Create migration script for the database and save it the SPINE repository in the folder ```src/backedn/migrations_scripts/```. ***The migration script changes at least the document having the version of the json schema used.***
1. Create a release for SPINE project including migration instructions from previous releases. Please refer to the migration script in the commit messages.
+## Testing with Jest and Ajv
+All schemas should be validated with tests, based on Ajv library. Since Jest can’t
+specify the error message, in order to display a meaningful error message,
+we will have to create a custom matcher to show our own message, returned by Ajv.
+It is shown in [Example of matcher extension](/tests/jest.ajv.schema.test.js).
+
+### Test cases
+Examples used for testing are defined in "examples" subfolders. To identify weak tests
+[Mutation tests](https://en.wikipedia.org/wiki/Mutation_testing) are applied (json files with _mutation._ prefix).
+Manual tools definitions can be tested using [automatic suite](/tests/tools2.schema.test.js)
+
+
+### Links:
+
+[Test JSON schema with AJV and Jest](https://medium.com/@moshfeu/test-json-schema-with-ajv-and-jest-c1d2984234c9 )
+
+[Getting started with JEST](https://jestjs.io/docs/en/getting-started)
+
+[Getting started with Ajv](https://github.com/ajv-validator/ajv)
+
+TODO:
+Set up coverage as in [Ajv-Istanbul](https://github.com/ajv-validator/ajv-istanbul)
\ No newline at end of file
diff --git a/examples/annotationWorkflow/tool_annotationThreeViewers.json b/examples/annotationWorkflow/tool_annotationThreeViewers.json
index 5f2a2bb..3f566b6 100644
--- a/examples/annotationWorkflow/tool_annotationThreeViewers.json
+++ b/examples/annotationWorkflow/tool_annotationThreeViewers.json
@@ -132,15 +132,41 @@
"possibleImagesToDisplay": ["imagesA"],
"hasDefaultImageToDisplay": false
},
- "displayControls":{
- "orientations": ["axial", "sagittal", "coronal"],
- "defaultOrientation": "axial",
- "smoothing": {
- "smoothingControl": true,
- "smoothingDefault": false
- }
- }
- }
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": true,
+ "controlEnabled": true
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ }
+ }
}
},
diff --git a/examples/cohort/epvs.json b/examples/cohort/epvs.json
new file mode 100644
index 0000000..2929dd0
--- /dev/null
+++ b/examples/cohort/epvs.json
@@ -0,0 +1,19 @@
+{
+ "uuid": "5ec47681-0872-4368-a53f-aaed3f8ac391",
+ "docType": "cohort",
+ "name": "EPVS MICCAI VALDO 2021",
+ "description": "EPVS dataset",
+ "creationDate": "2021-09-07T17:04:06.158040",
+ "privacy": "private",
+ "pi": "a60017ce-6be9-4054-9f84-06722d5166be",
+ "co-investigators": [
+ "0f8fc6f7-1361-4f55-9bfa-b8e70c3a5718"
+ ],
+ "logo": {
+ "type": "url",
+ "value": "https://www.miccai2021.org/files/images/layout/en/miccai2021-logo.png",
+ "url": "https://valdo.grand-challenge.org/Task3"
+ },
+ "relativePath": "EPVS_MICCAI_VALDO_2021",
+ "sourceSystem": "SPINE Insertion script"
+}
\ No newline at end of file
diff --git a/examples/cohort/epvs2.json b/examples/cohort/epvs2.json
new file mode 100644
index 0000000..815a5e5
--- /dev/null
+++ b/examples/cohort/epvs2.json
@@ -0,0 +1,30 @@
+{
+ "uuid": "8631a9d7-6247-412c-b921-a73769e16647",
+ "docType": "cohort",
+ "name": "EPVS MICCAI VALDO 2021",
+ "description": "EPVS dataset",
+ "creationDate": "2021-09-01T15:38:09.421140",
+ "privacy": "private",
+ "pi": "a60017ce-6be9-4054-9f84-06722d5166be",
+ "co-investigators": [
+ "0f8fc6f7-1361-4f55-9bfa-b8e70c3a5718"
+ ],
+ "diseases": [],
+ "keywords": [
+ {
+ "label": "Brain",
+ "iri": "http://purl.org/sig/ont/fma/fma50801"
+ },
+ {
+ "label": "MRI",
+ "iri": "http://purl.bioontology.org/ontology/SNOMEDCT/113091000"
+ }
+ ],
+ "relativePath": "EPVS_MICCAI_VALDO_2021",
+ "logo": {
+ "type": "url",
+ "value": "https://www.miccai2021.org/files/images/layout/en/miccai2021-logo.png",
+ "url": "https://valdo.grand-challenge.org/Task1"
+ },
+ "sourceSystem": "SPINE Insertion script"
+}
\ No newline at end of file
diff --git a/examples/cohort/fat.json b/examples/cohort/fat.json
new file mode 100644
index 0000000..589b25a
--- /dev/null
+++ b/examples/cohort/fat.json
@@ -0,0 +1,25 @@
+{
+ "uuid": "35d4d7d1d0fb89504a8c0c74250008af",
+ "docType": "cohort",
+ "name": "Abdominal Fat Testing",
+ "description": "Testing database for Abdominal Faat",
+ "creationDate": "2020-03-10T23:54:14.063Z",
+ "privacy": "public",
+ "pi": "a60017ce-6be9-4054-9f84-06722d5166be",
+ "co-investigators": [
+ "0f8fc6f7-1361-4f55-9bfa-b8e70c3a5718"
+ ],
+ "diseases": [],
+ "keywords": [
+ {
+ "label": "Brain",
+ "iri": "http://purl.org/sig/ont/fma/fma50801"
+ },
+ {
+ "label": "MRI",
+ "iri": "http://purl.bioontology.org/ontology/SNOMEDCT/113091000"
+ }
+ ],
+ "relativePath": "Cohort_AbdominalFat_Testing",
+ "sourceSystem": "manualInsertion"
+}
\ No newline at end of file
diff --git a/examples/cohort/lacunes.json b/examples/cohort/lacunes.json
new file mode 100644
index 0000000..c677e37
--- /dev/null
+++ b/examples/cohort/lacunes.json
@@ -0,0 +1,30 @@
+{
+ "uuid": "2be44462-b0a5-4a32-b3a7-cd33bcdff3f1",
+ "docType": "cohort",
+ "name": "LACUNES MICCAI VALDO 2021",
+ "description": "LACUNES dataset",
+ "creationDate": "2021-09-21T14:37:57.266647",
+ "relativePath": "LACUNES_MICCAI_VALDO_2021",
+ "privacy": "private",
+ "pi": "a60017ce-6be9-4054-9f84-06722d5166be",
+ "co-investigators": [
+ "0f8fc6f7-1361-4f55-9bfa-b8e70c3a5718"
+ ],
+ "diseases": [],
+ "keywords": [
+ {
+ "label": "Brain",
+ "iri": "http://purl.org/sig/ont/fma/fma50801"
+ },
+ {
+ "label": "MRI",
+ "iri": "http://purl.bioontology.org/ontology/SNOMEDCT/113091000"
+ }
+ ],
+ "logo": {
+ "type": "url",
+ "value": "https://www.miccai2021.org/files/images/layout/en/miccai2021-logo.png",
+ "url": "https://valdo.grand-challenge.org/Task3"
+ },
+ "sourceSystem": "SPINE Insertion script"
+}
\ No newline at end of file
diff --git a/examples/cohort/miccai.json b/examples/cohort/miccai.json
new file mode 100644
index 0000000..346979f
--- /dev/null
+++ b/examples/cohort/miccai.json
@@ -0,0 +1,46 @@
+ {
+ "uuid": "023e3ce2-d2e0-4b73-87c1-c0c166b8c313",
+ "docType": "cohort",
+ "name": "MICROBLEEDS MICCAI VALDO 2021",
+ "description": "MICROBLEEDS dataset. he goal of this task is to develop an automated method to segment cerebral microbleeds in MRI scans. The training set contains segmentations of microbleeds in the full brain for every case. The submitted automated methods will be applied on the hidden test set and should output microbleed segmentations for the full brain. The predicted segmentation mask should be continuous and will be thresholded at 0.5 during evaluation to obtain a binary segmentation mask (0: background, 1: microbleed). An interesting public dataset that can be used to have additional training cases, is the microbleeds dataset that was released with the following paper: Q. Dou*, H. Chen*, L. Yu, J. Qin, L. Shi, P. A. Heng, et al. 'Automatic Detection of Cerebral Microbleeds from MR Images via 3D Convolutional Neural Networks'. IEEE Transactions on Medical Imaging (TMI), 2016.This set contains 20 cases with dot annotations of microbleeds.",
+ "creationDate": "2021-09-20T16:51:33.887301",
+ "privacy": "private",
+ "relativePath": "EPVS_MICCAI_VALDO_2021",
+ "pi": "a60017ce-6be9-4054-9f84-06722d5166be",
+ "co-investigators": [
+ "0f8fc6f7-1361-4f55-9bfa-b8e70c3a5718"
+ ],
+ "diseases": [
+ {
+ "label": "Multiple Sclerosis",
+ "icdCode": "G35",
+ "url": "https://www.icd10data.com/search?s=G35"
+ },
+ {
+ "label": "Disseminated demyelination",
+ "icdCode": "G36",
+ "url": "https://www.icd10data.com/search?s=G36"
+ }
+ ],
+ "keywords": [
+ {
+ "label": "Multiple Sclerosis",
+ "iri": "http://purl.bioontology.org/ontology/SNOMEDCT/24700007"
+ },
+ {
+ "label": "Freesurfer",
+ "iri": "http://purl.org/sig/ont/fma/fma271960"
+ },
+ {
+ "label": "White Matter",
+ "iri": "http://purl.org/sig/ont/fma/fma83929"
+ }
+ ],
+ "logo": {
+ "type": "url",
+ "value": "https://www.miccai2021.org/files/images/layout/en/miccai2021-logo.png",
+ "url": "https://valdo.grand-challenge.org/Task2"
+ },
+ "sourceSystem": "SPINE Insertion script"
+ }
+
diff --git a/examples/cohort/miccai2.json b/examples/cohort/miccai2.json
new file mode 100644
index 0000000..40b29fe
--- /dev/null
+++ b/examples/cohort/miccai2.json
@@ -0,0 +1,30 @@
+{
+ "uuid": "20c2d549136e928edffcdb64b901f990",
+ "docType": "cohort",
+ "name": "Testing Openneuro. Dataset ds000221.",
+ "description": "Testing database from Openneuro",
+ "creationDate": "2019-08-21T19:32:14.063Z",
+ "privacy": "public",
+ "pi": "a60017ce-6be9-4054-9f84-06722d5166be",
+ "co-investigators": [
+ "0f8fc6f7-1361-4f55-9bfa-b8e70c3a5718"
+ ],
+ "relativePath": "CohortOpenneuro_ds0002221",
+ "sourceSystem": "manualInsertion",
+ "diseases": [],
+ "keywords": [
+ {
+ "label": "Brain",
+ "iri": "http://purl.org/sig/ont/fma/fma50801"
+ },
+ {
+ "label": "MRI",
+ "iri": "http://purl.bioontology.org/ontology/SNOMEDCT/113091000"
+ }
+ ],
+ "logo": {
+ "type": "url",
+ "value": "https://openneuro.org/assets/on-light-horz.23ff22c3.svg",
+ "url": "https://openneuro.org/datasets/ds000221/versions/1.0.0"
+ }
+}
\ No newline at end of file
diff --git a/examples/experimentalPlan/experimentConfiguration_V1_1.json b/examples/experimentalPlan/experimentConfiguration_V1_1.json
new file mode 100644
index 0000000..acf6eff
--- /dev/null
+++ b/examples/experimentalPlan/experimentConfiguration_V1_1.json
@@ -0,0 +1,175 @@
+{
+ "_id": "fc6092c28f33a27d686da9e16c000646",
+ "docType": "experimentConfiguration",
+ "creationDate": "2022-03-06T16:11:21.798Z",
+ "reference": {
+ "experimentId": "ef2173835dfc5b25509f0fa87e006929",
+ "projectId": "25b2a82a03fc48d45377c1703c4ba42e"
+ },
+ "config": {
+ "experimentalPlan": {
+ "experimentId": "ef2173835dfc5b25509f0fa87e006929",
+ "docType": "experimentalPlan",
+ "questionnaires": [
+ "5b66d65a-cd61-4358-9248-5ae53d173e62",
+ "5a8460d1-d731-4b78-9193-182d6873846f",
+ "2910b5f86d3389dbf4fd16dc27000291"
+ ],
+ "eventParameters": {
+ "tolerances": [
+ {
+ "event": "wakeUpSleep",
+ "tolerance": 2,
+ "toleranceUnit": "hours"
+ },
+ {
+ "event": "wakeUpNap",
+ "tolerance": 2,
+ "toleranceUnit": "hours"
+ }
+ ],
+ "maxAwakeTime": "15:10:00"
+ },
+ "planning": {
+ "startExperiment": {
+ "time-windows": [
+ {
+ "questionnaireId": "2910b5f86d3389dbf4fd16dc27000291",
+ "name": "one-time questionnaire starting day",
+ "trigger": "system",
+ "timeToComplete": 3,
+ "timeToCompleteUnit": "days",
+ "tolerance": 0,
+ "toleranceUnit": "hours",
+ "reminders": [6, 12, 24, 30, 36, 48, 54, 60],
+ "remindersUnit": "hours"
+ },
+ {
+ "questionnaireId": "2910b5f86d3389dbf4fd16dc27000291",
+ "name": "one-time questionnaire 25 days after the previous",
+ "trigger": "timeAfterPreviousEvent",
+ "timeAfterPreviousEvent": 25,
+ "timeAfterPreviousEventUnit": "days",
+ "timeAfterPreviousEventRelative": "eventEnds",
+ "timeToComplete": 3,
+ "timeToCompleteUnit": "days",
+ "tolerance": 0,
+ "toleranceUnit": "hours",
+ "reminders": [6, 12, 24, 30, 36, 48, 54, 60],
+ "remindersUnit": "hours"
+ },
+ {
+ "questionnaireId": "2910b5f86d3389dbf4fd16dc27000291",
+ "name": "one-time questionnaire 25 days after the previous",
+ "trigger": "timeAfterPreviousEvent",
+ "timeAfterPreviousEvent": 25,
+ "timeAfterPreviousEventUnit": "days",
+ "timeAfterPreviousEventRelative": "eventEnds",
+ "timeToComplete": 3,
+ "timeToCompleteUnit": "days",
+ "tolerance": 0,
+ "toleranceUnit": "hours",
+ "reminders": [6, 12, 24, 30, 36, 48, 54, 60],
+ "remindersUnit": "hours"
+ },
+ {
+ "questionnaireId": "2910b5f86d3389dbf4fd16dc27000291",
+ "name": "one-time questionnaire 25 days after the previous",
+ "trigger": "timeAfterPreviousEvent",
+ "timeAfterPreviousEvent": 25,
+ "timeAfterPreviousEventUnit": "days",
+ "timeAfterPreviousEventRelative": "eventEnds",
+ "timeToComplete": 3,
+ "timeToCompleteUnit": "days",
+ "tolerance": 0,
+ "toleranceUnit": "hours",
+ "reminders": [6, 12, 24, 30, 36, 48, 54, 60],
+ "remindersUnit": "hours"
+ }
+ ]
+ },
+ "evaluationPeriod": {
+ "cyclic": [ ],
+ "specialEvent": {
+ "time-windows": [
+ {
+ "questionnaireId": "5b66d65a-cd61-4358-9248-5ae53d173e62",
+ "isVAS": true,
+ "trigger": "sleep",
+ "timeToComplete": 2,
+ "timeToCompleteUnit": "hours",
+ "tolerance": 0,
+ "toleranceUnit": "minutes",
+ "reminders": [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110],
+ "remindersUnit": "minutes"
+ },
+ {
+ "questionnaireId": "5b66d65a-cd61-4358-9248-5ae53d173e62",
+ "isVAS": true,
+ "trigger": "nap",
+ "timeToComplete": 2,
+ "timeToCompleteUnit": "hours",
+ "tolerance": 0,
+ "toleranceUnit": "minutes",
+ "reminders": [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110],
+ "remindersUnit": "minutes"
+ },
+ {
+ "questionnaireId": "5a8460d1-d731-4b78-9193-182d6873846f",
+ "trigger": "wakeUpSleep",
+ "isVAS": false,
+ "timeToComplete": 2,
+ "timeToCompleteUnit": "hours",
+ "tolerance": 0,
+ "toleranceUnit": "minutes",
+ "reminders": [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110],
+ "remindersUnit": "minutes"
+ },
+ {
+ "questionnaireId": "5b66d65a-cd61-4358-9248-5ae53d173e62",
+ "isVAS": true,
+ "trigger": "wakeUpSleep",
+ "repeat": 4,
+ "unitRepeat": "hours",
+ "timeToComplete": 2,
+ "timeToCompleteUnit": "hours",
+ "tolerance": 0,
+ "toleranceUnit": "minutes",
+ "reminders": [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110],
+ "remindersUnit": "minutes"
+ },
+ {
+ "questionnaireId": "5a8460d1-d731-4b78-9193-182d6873846f",
+ "trigger": "wakeUpNap",
+ "isVAS": false,
+ "timeToComplete": 2,
+ "timeToCompleteUnit": "hours",
+ "tolerance": 0,
+ "toleranceUnit": "minutes",
+ "reminders": [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110],
+ "remindersUnit": "minutes"
+ },
+ {
+ "questionnaireId": "5b66d65a-cd61-4358-9248-5ae53d173e62",
+ "isVAS": true,
+ "trigger": "wakeUpNap",
+ "repeat": 4,
+ "unitRepeat": "hours",
+ "timeToComplete": 2,
+ "timeToCompleteUnit": "hours",
+ "tolerance": 0,
+ "toleranceUnit": "minutes",
+ "reminders": [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110],
+ "remindersUnit": "minutes"
+ }
+ ]
+ }
+ },
+ "endingExperiment": {
+ "experimentDeadlineTime":88,
+ "experimentDeadlineUnit":"days"
+ }
+ }
+ }
+ }
+}
diff --git a/examples/experimentalPlan/experimentConfiguration_V1_1Short.json b/examples/experimentalPlan/experimentConfiguration_V1_1Short.json
new file mode 100644
index 0000000..b10d408
--- /dev/null
+++ b/examples/experimentalPlan/experimentConfiguration_V1_1Short.json
@@ -0,0 +1,161 @@
+{
+ "_id": "fc6092c28f33a27d686da9e16c000646",
+ "docType": "experimentConfiguration",
+ "creationDate": "2022-03-06T16:11:21.798Z",
+ "reference": {
+ "experimentId": "ef2173835dfc5b25509f0fa87e006929",
+ "projectId": "25b2a82a03fc48d45377c1703c4ba42e"
+ },
+ "config": {
+ "experimentalPlan": {
+ "experimentId": "ef2173835dfc5b25509f0fa87e006929",
+ "docType": "experimentalPlan",
+ "questionnaires": [
+ "5b66d65a-cd61-4358-9248-5ae53d173e62",
+ "5a8460d1-d731-4b78-9193-182d6873846f",
+ "2910b5f86d3389dbf4fd16dc27000291"
+ ],
+ "eventParameters": {
+ "tolerances": [
+ {
+ "event": "wakeUpSleep",
+ "tolerance": 10,
+ "toleranceUnit": "minutes"
+ },
+ {
+ "event": "wakeUpNap",
+ "tolerance": 10,
+ "toleranceUnit": "minutes"
+ }
+ ],
+ "maxAwakeTime": "8:10:00"
+ },
+ "planning": {
+ "startExperiment": {
+ "time-windows": [
+ {
+ "questionnaireId": "2910b5f86d3389dbf4fd16dc27000291",
+ "name": "one-time questionnaire starting day",
+ "trigger": "system",
+ "timeToComplete": 1,
+ "timeToCompleteUnit": "days",
+ "tolerance": 0,
+ "toleranceUnit": "hours",
+ "reminders": [6, 12],
+ "remindersUnit": "hours"
+ },
+ {
+ "questionnaireId": "2910b5f86d3389dbf4fd16dc27000291",
+ "name": "one-time questionnaire 25 days after the previous",
+ "trigger": "timeAfterPreviousEvent",
+ "timeAfterPreviousEvent": 3,
+ "timeAfterPreviousEventUnit": "days",
+ "timeAfterPreviousEventRelative": "eventEnds",
+ "timeToComplete": 1,
+ "timeToCompleteUnit": "days",
+ "tolerance": 0,
+ "toleranceUnit": "hours",
+ "reminders": [6, 12],
+ "remindersUnit": "hours"
+ },
+ {
+ "questionnaireId": "2910b5f86d3389dbf4fd16dc27000291",
+ "name": "one-time questionnaire 25 days after the previous",
+ "trigger": "timeAfterPreviousEvent",
+ "timeAfterPreviousEvent": 3,
+ "timeAfterPreviousEventUnit": "days",
+ "timeAfterPreviousEventRelative": "eventEnds",
+ "timeToComplete": 1,
+ "timeToCompleteUnit": "days",
+ "tolerance": 0,
+ "toleranceUnit": "hours",
+ "reminders": [6, 12],
+ "remindersUnit": "hours"
+ }
+ ]
+ },
+ "evaluationPeriod": {
+ "cyclic": [ ],
+ "specialEvent": {
+ "time-windows": [
+ {
+ "questionnaireId": "5b66d65a-cd61-4358-9248-5ae53d173e62",
+ "isVAS": true,
+ "trigger": "sleep",
+ "timeToComplete": 1,
+ "timeToCompleteUnit": "hours",
+ "tolerance": 0,
+ "toleranceUnit": "minutes",
+ "reminders": [10, 20, 30, 40, 50],
+ "remindersUnit": "minutes"
+ },
+ {
+ "questionnaireId": "5b66d65a-cd61-4358-9248-5ae53d173e62",
+ "isVAS": true,
+ "trigger": "nap",
+ "timeToComplete": 1,
+ "timeToCompleteUnit": "hours",
+ "tolerance": 0,
+ "toleranceUnit": "minutes",
+ "reminders": [10, 20, 30, 40, 50],
+ "remindersUnit": "minutes"
+ },
+ {
+ "questionnaireId": "5a8460d1-d731-4b78-9193-182d6873846f",
+ "trigger": "wakeUpSleep",
+ "isVAS": false,
+ "timeToComplete": 1,
+ "timeToCompleteUnit": "hours",
+ "tolerance": 0,
+ "toleranceUnit": "minutes",
+ "reminders": [10, 20, 30, 40, 50],
+ "remindersUnit": "minutes"
+ },
+ {
+ "questionnaireId": "5b66d65a-cd61-4358-9248-5ae53d173e62",
+ "isVAS": true,
+ "trigger": "wakeUpSleep",
+ "repeat": 4,
+ "unitRepeat": "hours",
+ "timeToComplete": 1,
+ "timeToCompleteUnit": "hours",
+ "tolerance": 0,
+ "toleranceUnit": "minutes",
+ "reminders": [10, 20, 30, 40, 50],
+ "remindersUnit": "minutes"
+ },
+ {
+ "questionnaireId": "5a8460d1-d731-4b78-9193-182d6873846f",
+ "trigger": "wakeUpNap",
+ "isVAS": false,
+ "timeToComplete": 1,
+ "timeToCompleteUnit": "hours",
+ "tolerance": 0,
+ "toleranceUnit": "minutes",
+ "reminders": [10, 20, 30, 40, 50],
+ "remindersUnit": "minutes"
+ },
+ {
+ "questionnaireId": "5b66d65a-cd61-4358-9248-5ae53d173e62",
+ "isVAS": true,
+ "trigger": "wakeUpNap",
+ "repeat": 4,
+ "unitRepeat": "hours",
+ "timeToComplete": 1,
+ "timeToCompleteUnit": "hours",
+ "tolerance": 0,
+ "toleranceUnit": "minutes",
+ "reminders": [10, 20, 30, 40, 50],
+ "remindersUnit": "minutes"
+ }
+ ]
+ }
+ },
+ "endingExperiment": {
+ "experimentDeadlineTime":9,
+ "experimentDeadlineUnit":"days"
+ }
+ }
+ }
+ }
+}
diff --git a/examples/helpPanel/Identificationv4.json b/examples/helpPanel/Identificationv4.json
new file mode 100644
index 0000000..8261293
--- /dev/null
+++ b/examples/helpPanel/Identificationv4.json
@@ -0,0 +1,345 @@
+{
+ "_main": {
+ "goalAndDefinition": "
Goals:
- Identify each site of leptomeningeal metastasis (LM)\t
- To be considered one lesion, the enhancing area must be continuous (all components must demonstrate connection in at least one projection).
- Select/pin each lesion only ONCE
- Leptomeningeal metastasis are 3-dimensional objects.
- Do not select the same lesion on multiple slices or projections.
- If a lesion is “diffuse” in nature, only pin the lesion in one place.
- Pin each lesion at its approximate center point.
- If a lesion has both a linear and nodular component, pin the nodular component.
Definitions:
- Leptomeningeal enhancement: a continuous, contrast-enhancing lesions with less than 2 mm distance between the outer edge of the lesion and the leptomeninges.
",
+ "tools": "
= Turn on/off pin tool
= Undo/redo the most recently placed annotation
= Triangulate a focal area in all three projections
= Display a 3D crosshair showing the position of the slices currently shown in all 3 viewer windows
= Project annotations to adjacent slices
Neighborhood of projection = Number of adjacent slices onto which the annotations are projected
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=sBQKQ7t23mw&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=unxHdPwvoWs&feature=youtu.be"
+ },
+ "images": [
+ {
+ "name": "Definition of Leptomeningeal Metastasis (1/2)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1nKNP9s822TF6qW4aHopWIY9ec1dh9sTT",
+ "_$visited": true
+ },
+ {
+ "name": "Definition of Leptomeningeal Metastasis (2/2)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1tI2O7J4aTHFpDcJZ0U4kU2YIJ2iCKnN7",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricular nodular enhancement (1/2)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1YxGNw-AE_t0zPMwy5htz-7HDBcj7zsXa",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricular nodular enhancement (2/2)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1PDT29ASEmpajFHdadnDyAj90jAvl9p9R",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebral nodular enhancement",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1We29fGlH25hYmedNUbw71F2un51vNCg2",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebellar nodular enhancement",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1miRZ9CqAs_HnTSsG7kpFQ0jrww8iz5CV",
+ "_$visited": true
+ },
+ {
+ "name": "Leptomeningeal lesion with linear and nodular component",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1NxtOmbXfFbLYa0jyqI0Hwj8ghLgFAYnt",
+ "_$visited": true
+ },
+ {
+ "name": "Nodular enhancements in the lumbar spine (Sagittal View)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=10Wq8oDibc_3CoAUfhjVvFMjVYyFt4Leg",
+ "_$visited": true
+ },
+ {
+ "name": "Diffuse enhancement in the cervical spine (Sagittal View)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1D3hVp-BhN_-4OK5eZj9XBXgPlzq0QyuW",
+ "_$visited": true
+ }
+ ],
+ "combos": "
= Place pins (annotations) on image when pin tool is toggled
= Move between slices
= Move forward between annotations
= Move backward between annotations
= Move image
= Window image
= Window image when pin tool is toggled
= Move image
= Zoom in/out
= Zoom in/out when pin tool is toggled
= Delete annotation
",
+ "annotations": "ANNOTATION TABLE
= Edit a cell
= Delete annotation
"
+ },
+ "_goalDelta": {
+ "ops": [
+ {
+ "attributes": {
+ "bold": true
+ },
+ "insert": "Goals"
+ },
+ {
+ "insert": ":\n- Identify each site of leptomeningeal metastasis (LM)\nTo be considered one lesion, the enhancing area must be continuous (all components must demonstrate connection in at least one projection)."
+ },
+ {
+ "attributes": {
+ "list": "bullet"
+ },
+ "insert": "\n"
+ },
+ {
+ "insert": "- Select/pin each lesion only ONCE\nLeptomeningeal metastasis are 3-dimensional objects."
+ },
+ {
+ "attributes": {
+ "list": "bullet"
+ },
+ "insert": "\n"
+ },
+ {
+ "insert": "Do not select the same lesion on multiple slices or projections."
+ },
+ {
+ "attributes": {
+ "list": "bullet"
+ },
+ "insert": "\n"
+ },
+ {
+ "insert": "If a lesion is “diffuse” in nature, only pin the lesion in one place. "
+ },
+ {
+ "attributes": {
+ "list": "bullet"
+ },
+ "insert": "\n"
+ },
+ {
+ "insert": "- Pin each lesion at its approximate center point.\n- If a lesion has both a linear and nodular component, pin the nodular component. \n"
+ },
+ {
+ "attributes": {
+ "bold": true
+ },
+ "insert": "Definitions: "
+ },
+ {
+ "insert": "\n-"
+ },
+ {
+ "attributes": {
+ "bold": true
+ },
+ "insert": " Leptomeningeal enhancement: "
+ },
+ {
+ "insert": "a continuous,"
+ },
+ {
+ "attributes": {
+ "bold": true
+ },
+ "insert": " "
+ },
+ {
+ "insert": "c"
+ },
+ {
+ "attributes": {
+ "color": "black"
+ },
+ "insert": "ontrast-enhancing lesions with less than 2 mm distance between the outer edge of the lesion and the leptomeninges."
+ },
+ {
+ "insert": "\n"
+ }
+ ]
+ },
+ "_toolDelta": {
+ "ops": [
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=1HkVVlpY1r1p6YldlRhWmSYFqd5tDn1F-"
+ }
+ },
+ {
+ "insert": "= Turn on/off pin tool\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=1uyjb5n5ngjB9rzlKyyvbV_l9aWmiByx6"
+ }
+ },
+ {
+ "insert": " = Undo/redo the most recently placed annotation\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=1pd4vioZcOgcCkZJNxMiSrYSRtjIvIg27"
+ }
+ },
+ {
+ "insert": " = Triangulate a focal area in all three projections\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=1eHHxrtW3gMhlnT-m0fdyTodRazF3JCxq"
+ }
+ },
+ {
+ "insert": " = Display a 3D crosshair showing the position of the slices currently shown in all 3 viewer windows\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=11bfY3nu1E2iro8B-zac92sNI1AxXyUs9"
+ }
+ },
+ {
+ "insert": "= Project annotations to adjacent slices\nNeighborhood of projection = "
+ },
+ {
+ "attributes": {
+ "color": "black"
+ },
+ "insert": "Number of adjacent slices onto which the annotations are projected"
+ },
+ {
+ "insert": "\n\n"
+ },
+ {
+ "attributes": {
+ "header": 2
+ },
+ "insert": "\n"
+ }
+ ]
+ },
+ "_comboDelta": {
+ "ops": [
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=115RChWVB5vzscoAC05B1QR2SMH5_nVI8"
+ }
+ },
+ {
+ "insert": " = Place pins (annotations) on image when pin tool is toggled\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=1O8SkwIZgVGsD_U8JcdmKbg2tHKXtrj_h"
+ }
+ },
+ {
+ "insert": " = "
+ },
+ {
+ "attributes": {
+ "color": "black"
+ },
+ "insert": "Move between slices"
+ },
+ {
+ "insert": "\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=19MENfpFJoHZ4qzseaUM9IBSLMvMx_vA2"
+ }
+ },
+ {
+ "insert": " = Move forward between annotations\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=14LBXTLC1ycm5zIe71BeMU8i11k5wJ4OZ"
+ }
+ },
+ {
+ "insert": " = Move backward between annotations\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=1dV1dOBSZ8y5p1wnvRtlKK9WBxaO9uXKL"
+ }
+ },
+ {
+ "insert": " = Move image\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=1NFjNlFSbIEtXnf17mbq2c76GWyEXAOil"
+ }
+ },
+ {
+ "insert": " = Window image\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=1uEUpX97BuBrxOkord4Ee-dpkTga_9p69"
+ }
+ },
+ {
+ "insert": " = Window image when pin tool is toggled\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=1dV1dOBSZ8y5p1wnvRtlKK9WBxaO9uXKL"
+ }
+ },
+ {
+ "insert": " = Move image\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=1_qdp5ozWi8MhCHIq1QIcDUSd2KQjajCV"
+ }
+ },
+ {
+ "insert": " = Zoom in/out\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=1XxlCwfZPbMQZe45D7KXSwelbjbVJ10mN"
+ }
+ },
+ {
+ "insert": " = Zoom in/out when pin tool is toggled\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=1ixDZqFAniMhJnDWc6oxuUQjPP4Qbf0XA"
+ }
+ },
+ {
+ "insert": " = Delete annotation\n"
+ }
+ ]
+ },
+ "_annotationDelta": {
+ "ops": [
+ {
+ "attributes": {
+ "underline": true
+ },
+ "insert": "ANNOTATION TABLE"
+ },
+ {
+ "attributes": {
+ "header": 2
+ },
+ "insert": "\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=115RChWVB5vzscoAC05B1QR2SMH5_nVI8"
+ }
+ },
+ {
+ "insert": " = Edit a cell\n"
+ },
+ {
+ "insert": {
+ "image": "https://drive.google.com/uc?export=download&id=13brFCX5hbLAXS_wMaSjQNxetuVQpiqsI"
+ }
+ },
+ {
+ "insert": " = Delete annotation\n"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/examples/segmentationMedullaOblongata/tool_segmentationBrushOneViewer.json b/examples/segmentationMedullaOblongata/tool_segmentationBrushOneViewer.json
index ea17056..15e4881 100644
--- a/examples/segmentationMedullaOblongata/tool_segmentationBrushOneViewer.json
+++ b/examples/segmentationMedullaOblongata/tool_segmentationBrushOneViewer.json
@@ -92,21 +92,36 @@
"hasDefaultImageToDisplay": true,
"defaultImageToDisplay": "inputImage_key"
},
- "displayControls":{
- "orientation":{
+ "displayControls": {
+ "orientation": {
"controlVisible": false,
"controlEnabled": false,
- "options":[ {
- "label": "Axial",
- "value": "AXIAL"
- }]
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
},
- "smoothing":{
+ "smoothing": {
"controlVisible": false,
"controlEnabled": false,
"defaultValue": false
},
- "sequence":{
+ "sequence": {
+ "controlVisible": true,
+ "controlEnabled": true
+ },
+ "linked": {
"controlVisible": false,
"controlEnabled": false
}
diff --git a/examples/tool/abdominalFatDemo.json b/examples/tool/abdominalFatDemo.json
new file mode 100644
index 0000000..8eafa05
--- /dev/null
+++ b/examples/tool/abdominalFatDemo.json
@@ -0,0 +1,221 @@
+{
+ "miniWorkflow": {
+ "currentTool": {
+ "id":"1dd174e57260e384c4f45e9c490004a9",
+ "name": "Segmentation tool",
+ "description": "This tool is used to visualize a segmentation and check it.",
+ "version": "1.0.0",
+ "privacy": "PUBLIC",
+ "type": "SEGMENTATION_TOOL",
+ "inputs": {
+ "inputImage_key":{
+ "name": "Input image",
+ "description": "Input image",
+ "isList": false,
+ "type": "imageEntityInOut",
+ "imageEntityInOut_Type": "ANATOMICAL",
+ "imageEntityInOut_FileFormat": "nii.gz",
+ "required": true
+ },
+ "inputImage_key2":{
+ "name": "Segmentation",
+ "description": "Segmentation",
+ "isList": false,
+ "type": "roiInOut",
+ "typeROI": "EXPLICIT",
+ "required": true,
+ "imageEntityInOut_FileFormat": "nii.gz"
+ },
+ "inputLut_key1": {
+ "name": "Input LUT data",
+ "description": "Input LUT data for overlay displaying.",
+ "isList": false,
+ "type": "lookUpTable",
+ "required": true
+ },
+ "inputLutDescription_key1": {
+ "name": "Input description of LUT data",
+ "description": "Input LUT data for displaying options.",
+ "isList": false,
+ "type": "lookUpTableDescription",
+ "required": true
+ }
+ },
+ "outputs": {
+ },
+ "configuration":{
+ "luts": {
+ "lut_key1": {
+ "fromInputs": true,
+ "lutInputKey": "inputLut_key1"
+ }
+ },
+ "lutDescriptions": {
+ "lutDescription_key1": {
+ "fromInputs": true,
+ "lutDescriptionInputKey": "inputLutDescription_key1"
+ }
+ },
+ "rois": {
+ "overlays": {
+ "overlay_key_1": {
+ "fromInputs": true,
+ "imageInputKey": "inputImage_key2",
+ "lutKey": "lut_key1",
+ "lutDescriptionKey": "lutDescription_key1"
+ }
+ }
+ },
+ "scenes": {
+ "sceneKey1": {
+ "primaryImageInputKey": "inputImage_key",
+ "rois": {
+ "overlays": ["overlay_key_1"]
+ }
+ }
+ },
+ "viewers": {
+ "layout": {
+ "type": "SINGLE_WITH_WIDGET_PANEL",
+ "layoutOrder": {
+ "middle": "0"
+ }
+ },
+ "renderWindows": {
+ "0": {
+ "name": "Sagittal viewer",
+ "type": "2D",
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "AXIAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "INFERIORMOST"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#ffa07a",
+ "hasControlPanel": false
+ }
+ }
+ }
+ },
+ "widgets":
+ {
+ "brushTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "radius": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "fillingTool":{
+ "controlVisible": true,
+ "controlEnabled": true
+ },
+ "eraserTool":{
+ "controlVisible":true,
+ "controlEnabled":true,
+ "properties":{
+ "radius":{
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "labelmapLUT": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 32764
+ },
+ "labelmapUndoRedoTool":{
+ "controlVisible":true,
+ "controlEnabled":true
+ },
+ "labelmapOpacity":{
+ "controlVisible":true,
+ "controlEnabled":true,
+ "defaultValue":1
+ }
+ }
+ }
+ },
+ "currentMaterializedTask": {
+ "label": "training-9c39728c-8ce8-419e-886d-8138ba68e96e",
+ "inputs": {
+ "inputImage_key": {
+ "value": "35d4d7d1d0fb89504a8c0c7425004e25",
+ "format": "nii.gz"
+ },
+ "inputImage_key2": {
+ "value": "35d4d7d1d0fb89504a8c0c74250066d3",
+ "format": "nii.gz"
+ },
+ "inputLut_key1": {
+ "value": "ac49b96c6eea3e74c9dce58927000af5"
+ },
+ "inputLutDescription_key1": {
+ "value": "ac49b96c6eea3e74c9dce58927001617"
+ }
+ },
+ "status": "TODO",
+ "assignedTo": "gregory.bliault@u-bordeaux.fr",
+ "dueDate": "2019-09-28T22:43:29.728Z",
+ "miniWorkflow": "mw1",
+ "uuid": "53b643d3f55f98c38962b596530000d3"
+ },
+ "status": "notstarted"
+ },
+ "listOfCases": [
+ {
+ "caseNumber": "training-9c39728c-8ce8-419e-886d-8138ba68e96e",
+ "caseStatus": "notstarted"
+ }
+ ],
+ "currentCase": "training-9c39728c-8ce8-419e-886d-8138ba68e96e"
+}
\ No newline at end of file
diff --git a/examples/tool/invisibleFilterDemo.json b/examples/tool/invisibleFilterDemo.json
new file mode 100644
index 0000000..19dcf1f
--- /dev/null
+++ b/examples/tool/invisibleFilterDemo.json
@@ -0,0 +1,588 @@
+
+{
+ "miniWorkflow": {
+ "miniWorkflowPath": [
+ {
+ "stepKey": "annotation",
+ "stepName": "Identification of Leptomeningeal metastases"
+ },
+ {
+ "stepKey": "annotation",
+ "stepName": "Characterization of Leptomeningeal metastases"
+ }
+ ],
+ "currentStep": 1,
+ "currentTool": {
+ "id": "1dd174e57260e384c4f45e9c490004a9",
+ "name": "Characterization tool",
+ "description": "This tool is used to characterize previously identified ROI's.",
+ "version": "1.0.0",
+ "privacy": "PUBLIC",
+ "type": "CHARACTERIZATION_TOOL",
+ "inputs": {
+ "inputImage_key": {
+ "name": "Input image",
+ "description": "Input image",
+ "isList": false,
+ "type": "imageEntityInOut",
+ "imageEntityInOut_Type": "ANATOMICAL",
+ "imageEntityInOut_FileFormat": "nii.gz",
+ "required": true
+ },
+ "inputImage_key2": {
+ "name": "Input image",
+ "description": "Input image",
+ "isList": false,
+ "type": "imageEntityInOut",
+ "imageEntityInOut_Type": "ANATOMICAL",
+ "imageEntityInOut_FileFormat": "nii.gz",
+ "required": true
+ },
+ "inputImage_key3": {
+ "name": "Segmentation",
+ "description": "Segmentation",
+ "isList": false,
+ "type": "roiInOut",
+ "typeROI": "EXPLICIT",
+ "required": true,
+ "imageEntityInOut_FileFormat": "nii.gz"
+ },
+ "inputImage_key4": {
+ "name": "Segmentation",
+ "description": "Segmentation",
+ "isList": false,
+ "type": "roiInOut",
+ "typeROI": "EXPLICIT",
+ "required": true,
+ "imageEntityInOut_FileFormat": "nii.gz"
+ },
+ "inputImage_key5": {
+ "name": "Segmentation",
+ "description": "Segmentation",
+ "isList": false,
+ "type": "roiInOut",
+ "typeROI": "EXPLICIT",
+ "required": true,
+ "imageEntityInOut_FileFormat": "nii.gz"
+ },
+
+ "inputLut_key1": {
+ "name": "Input LUT data",
+ "description": "Input LUT data for overlay displaying.",
+ "isList": false,
+ "type": "lookUpTable",
+ "required": true
+ },
+ "inputLutDescription_key1": {
+ "name": "Input description of LUT data",
+ "description": "Input LUT data for displaying options.",
+ "isList": false,
+ "type": "lookUpTableDescription",
+ "required": true
+ }
+ },
+ "outputs": {
+ "probingBox_key": {
+ "name": "Probing box",
+ "description": "Probing box drawn by the user",
+ "isList": false,
+ "type": "roiInOut",
+ "typeROI": "IMPLICIT"
+ },
+ "otsuThreshold_key": {
+ "name": "Otsu threshold",
+ "description": "Otsu threshold calculate from the intentities inside the probing box.",
+ "isList": false,
+ "type": "Number"
+ }
+ },
+
+ "bindingWidgetOutputsToToolOutputs": [
+ {
+ "outputTool": "otsuThreshold_key",
+ "widget": {
+ "widgetKey": "samplerTool",
+ "property": "threshold"
+ }
+ },
+ {
+ "outputTool": "probingBox_key",
+ "widget": {
+ "widgetKey": "samplerTool",
+ "property": "points"
+ }
+ }
+ ],
+ "bindingSceneElementsToToolOutputs": [
+ {
+ "outputTool": "segmentation_key",
+ "roiKeyName": "overlay_key_1"
+ }
+ ],
+ "configuration": {
+ "luts": {
+ "lut_key1": {
+ "fromInputs": true,
+ "lutInputKey": "inputLut_key1"
+ }
+ },
+ "lutDescriptions": {
+ "lutDescription_key1": {
+ "fromInputs": true,
+ "lutDescriptionInputKey": "inputLutDescription_key1"
+ }
+ },
+ "rois": {
+ "overlays": {
+ "overlay_key_1": {
+ "fromInputs": false,
+ "lutKey": "lut_key1",
+ "lutDescriptionKey": "lutDescription_key1",
+ "label": "First layer"
+ }
+ },
+ "masks": {
+ },
+ "geometricalROIs": {
+ "roiList_key1": {
+ "fromInputs": true,
+ "roiInputKey": "inputROI_key1"
+ },
+ "roiList_key2": {
+ "fromInputs": false
+ }
+ }
+ },
+ "scenes": {
+ "sceneKey1": {
+ "primaryImageInputKey": "inputImage_key",
+ "rois": {
+ "overlays": [
+ "overlay_key_1"
+ ]
+ }
+ }
+ },
+ "annotationScenes": {
+ "annotationKey1": {
+ "roiInputKey": "inputROIDataList_key1",
+ "annotationDefinitionInputKey": "inputAnnotationTableDefinition_key1"
+ },
+ "annotationKey2": {
+ "roiInputKey": "inputImage_key",
+ "annotationDefinitionInputKey": "inputAnnotationFormDefinition_key1"
+ }
+ },
+ "viewers": {
+ "layout": {
+ "type": "ROW",
+ "layoutOrder": {
+ "left": "0",
+ "middleLeft": "1",
+ "middleRight": "2",
+ "right": "3"
+ }
+ },
+ "renderWindows": {
+ "0": {
+ "name": "Sagittal viewer",
+ "type": "2D",
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "SAGITTAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": true,
+ "controlEnabled": true
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel": {
+ "color": "#ffa07a"
+ }
+ },
+ "1": {
+ "name": "Middle viewer",
+ "type": "2D",
+ "linkedControlVisible": false,
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "AXIAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel": {
+ "color": "#fff967"
+ }
+ },
+ "2": {
+ "name": "Right viewer",
+ "type": "2D",
+ "linkedControlVisible": false,
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "CORONAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "CORONAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel": {
+ "color": "#90ee90"
+ }
+ },
+ "3": {
+ "name": "3D viewer",
+ "type": "3D",
+ "displayControls": {
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": true
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayImageSlices": {
+
+ }
+ }
+ }
+ },
+ "widgets": {
+ "casesControl": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "labelmapLUT": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ },
+ "brushTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "radius": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "eraserTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "radius": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "fillingTool":{
+ "controlVisible": true,
+ "controlEnabled": true
+ },
+
+ "labelmapUndoRedoTool": {
+ "controlVisible": true,
+ "controlEnabled": true
+ },
+ "intensityFilterTool": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": true,
+ "properties": {
+ "minValue": {
+ "controlVisible": false,
+ "controlEnabled": true,
+ "defaultValue": 0
+ },
+ "maxValue": {
+ "controlVisible": false,
+ "controlEnabled": true,
+ "defaultValue": 4294967295
+ },
+ "showMask": {
+ "controlVisible": false,
+ "controlEnabled": true,
+ "defaultValue": 0
+ },
+ "clear": {
+ "controlVisible": false,
+ "controlEnabled": true
+ }
+ }
+ },
+ "samplerTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "interactions": {
+ "controlVisible":false,
+ "controlEnabled":false,
+ "defaultValue": {
+ "intensityFilterTool": {
+ "type": "widget",
+ "tool": "intensityFilterTool",
+ "property": "maxValue",
+ "value": "midPoint"
+ }
+ }
+ },
+ "histogram": {
+ "controlVisible":false,
+ "controlEnabled":false,
+ "defaultValue": true
+ },
+ "onComplete": {
+ "controlVisible":false,
+ "controlEnabled":false,
+ "defaultValue": "SHOW_HISTOGRAM"
+ },
+ "bucketing": {
+ "controlVisible":false,
+ "controlEnabled":false,
+ "defaultValue": "FREEDMAN-DIACONIS"
+ }
+ }
+ },
+ "labelmapOpacity":{
+ "controlVisible":true,
+ "controlEnabled":true,
+ "defaultValue":1
+ },
+ "annotationTableTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "fullTable": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "editableROI": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "subAnnotationColumn": {
+ "controlVisible": true,
+ "controlEnabled": false
+ }
+ }
+ }
+ }
+ }
+ },
+ "currentMaterializedTask": {
+ "label": "training-9c39728c-8ce8-419e-886d-8138ba68e96e",
+ "inputs": {
+ "inputImage_key": {
+ "value": "75c919ef4923cd7eef878de2930001c3",
+ "label": "T1",
+ "format": "nii.gz"
+ },
+ "inputImage_key2": {
+ "value": "575bddd50492d394fe3e506e21134850",
+ "label": "Flair",
+ "format": "nii.gz"
+ },
+ "inputImage_key3": {
+ "value": "cfc61966aa88162e1451a66ac6002491",
+ "format": "nii.gz"
+ },
+ "inputImage_key4": {
+ "value": "cfc61966aa88162e1451a66ac6003b55",
+ "format": "nii.gz"
+ },
+ "inputImage_key5": {
+ "value": "07adbebb4a07e7a707de2e339800dcba",
+ "format": "nii.gz"
+ },
+ "inputLut_key1": {
+ "value": "c63c3c687bfeab4782a90290e1000260"
+ },
+ "inputLutDescription_key1": {
+ "value": "c63c3c687bfeab4782a90290e1003c40"
+ }
+ },
+ "status": "TODO",
+ "assignedTo": "amarciniak@bwh.harvard.edu",
+ "dueDate": "2019-09-28T22:43:29.728Z",
+ "miniWorkflow": "mw1",
+ "uuid": "06bf3451e2d63c3bf86b439838081dc7"
+ },
+ "status": "notstarted"
+ },
+ "listOfCases": [
+ {
+ "caseNumber": "NMO1",
+ "caseStatus": "notstarted"
+ },
+ {
+ "caseNumber": "NMO2",
+ "caseStatus": "notstarted",
+ "caseCurrentStep": 0
+ },
+ {
+ "caseNumber": "NMO3",
+ "caseStatus": "started",
+ "caseCurrentStep": 1
+ },
+ {
+ "caseNumber": "NMO4",
+ "caseStatus": "done"
+ },
+ {
+ "caseNumber": "NMO4",
+ "caseStatus": "done"
+ }
+ ],
+ "currentCase": "NMO1"
+}
diff --git a/examples/tool/leptomeningeal1v1.json b/examples/tool/leptomeningeal1v1.json
new file mode 100644
index 0000000..17e1ae9
--- /dev/null
+++ b/examples/tool/leptomeningeal1v1.json
@@ -0,0 +1,319 @@
+{
+ "miniWorkflow": {
+ "miniWorkflowPath": [
+ {
+ "stepKey": "annotation",
+ "stepName": "Identification of Leptomeningeal metastases"
+ }
+ ],
+ "currentStep": 1,
+ "currentTool": {
+ "id":"1dd174e57260e384c4f45e9c490004a9",
+ "name": "Pin tool",
+ "description": "This tool is used to characterize previously identified ROI's.",
+ "version": "1.0.0",
+ "privacy": "PUBLIC",
+ "type": "IDENTIFICATION_TOOL",
+ "inputs": {
+ "inputImage_key":{
+ "name": "Input image",
+ "description": "Input image",
+ "isList": false,
+ "type": "imageEntityInOut",
+ "imageEntityInOut_Type": "ANATOMICAL",
+ "imageEntityInOut_FileFormat": "nii.gz",
+ "required": true
+ }
+ },
+ "outputs": {
+ "outputAnnotationTableData_key": {
+ "name": "Output annotations data",
+ "description": "Output annotations data from annotation table",
+ "isList": false,
+ "type": "annotationTableDataInOut",
+ "required": true
+ }
+ },
+ "configuration":{
+ "scenes": {
+ "sceneKey1": {
+ "primaryImageInputKey": "inputImage_key",
+ "rois": {
+ "geometricalROIsInputKeys": [
+ "inputROIDataList_key1"
+ ]
+ }
+ }
+ },
+ "viewers": {
+ "layout": {
+ "type": "ROW",
+ "layoutOrder": {
+ "left": "0",
+ "middle": "1",
+ "right": "2"
+ }
+ },
+ "renderWindows": {
+ "0": {
+ "name": "Sagittal viewer",
+ "type": "2D",
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "SAGITTAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#ffa07a"
+ }
+ },
+ "1": {
+ "name": "Middle viewer",
+ "type": "2D",
+ "linkedControlVisible": false,
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "AXIAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "SUPERIORMOST"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#fff967"
+ }
+ },
+ "2": {
+ "name": "Right viewer",
+ "type": "2D",
+ "linkedControlVisible": false,
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "CORONAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "CORONAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#90ee90"
+ }
+ }
+ }
+ },
+ "widgets":{
+ "pinTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "markerSize": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 2
+ },
+ "fontSize":{
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 12
+ },
+ "clearAll":{
+ "controlVisible": true,
+ "controlEnabled": true
+ }
+ }
+ },
+ "projectionTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "range": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "pointerTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "mode": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": "onClick"
+ }
+ }
+ },
+ "crossHairTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "annotationTableTool": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "properties": {
+ "fullTable": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ }
+ }
+ }
+ }
+ }
+ },
+ "currentMaterializedTask": {
+ "label": "training-9c39728c-8ce8-419e-886d-8138ba68e96e",
+ "inputs": {
+ "inputImage_key": {
+ "value": "575bddd50492d394fe3e506e21134850",
+ "label": "FLAIR",
+ "format": "nii.gz"
+ }
+ },
+ "status": "TODO",
+ "assignedTo": "gregory.bliault@u-bordeaux.fr",
+ "dueDate": "2019-09-28T22:43:29.728Z",
+ "miniWorkflow": "mw1",
+ "uuid": "53b643d3f55f98c38962b596530000d3"
+ },
+ "status": "notstarted"
+ },
+ "listOfCases": [
+ {
+ "caseNumber": "LEPTO1",
+ "caseStatus": "notstarted"
+ },
+ {
+ "caseNumber": "LEPTO2",
+ "caseStatus": "notstarted"
+ }
+ ],
+ "currentCase": "LEPTO1"
+}
\ No newline at end of file
diff --git a/examples/tool/leptomeningeal1v2.json b/examples/tool/leptomeningeal1v2.json
new file mode 100644
index 0000000..21b1433
--- /dev/null
+++ b/examples/tool/leptomeningeal1v2.json
@@ -0,0 +1,481 @@
+{
+ "miniWorkflow": {
+ "miniWorkflowPath": [
+ {
+ "stepKey": "annotation",
+ "stepName": "Identification of Leptomeningeal metastases"
+ },
+ {
+ "stepKey": "annotation",
+ "stepName": "Characterization of Leptomeningeal metastases"
+ }
+ ],
+ "currentStep": 0,
+ "currentTool": {
+ "id":"1dd174e57260e384c4f45e9c490004a9",
+ "name": "Pin tool",
+ "description": "This tool is used to characterize previously identified ROI's.",
+ "version": "1.0.0",
+ "privacy": "PUBLIC",
+ "type": "ANNOTATION_TOOL",
+ "inputs": {
+ "inputImage_key":{
+ "name": "Input image",
+ "description": "Input image",
+ "isList": false,
+ "type": "imageEntityInOut",
+ "imageEntityInOut_Type": "ANATOMICAL",
+ "imageEntityInOut_FileFormat": "nii.gz",
+ "required": true
+ },
+ "inputAnnotationTableDefinition_key1": {
+ "name": "Input annotations definition",
+ "description": "Input annotations definition for annotation table",
+ "isList": false,
+ "type": "annotationTableDefinitionInputOutput",
+ "required": true
+ }
+ },
+ "outputs": {
+ "outputAnnotationTableData_key": {
+ "name": "Output annotations data",
+ "description": "Output annotations data from annotation table",
+ "isList": false,
+ "type": "annotationTableDataInOut",
+ "required": true
+ }
+ },
+ "configuration":{
+ "scenes": {
+ "sceneKey1": {
+ "primaryImageInputKey": "inputImage_key",
+ "rois": {
+ "geometricalROIsInputKeys": [
+ "outputAnnotationTableData_key"
+ ]
+ }
+ }
+ },
+ "viewers": {
+ "layout": {
+ "type": "1M2R_WIDGETS",
+ "layoutOrder": {
+ "middle": "1",
+ "upperRight": "2",
+ "lowerRight": "0"
+ }
+ },
+ "renderWindows": {
+ "0": {
+ "name": "Sagittal viewer",
+ "type": "2D",
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "SAGITTAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#ffa07a"
+ }
+ },
+ "1": {
+ "name": "Middle viewer",
+ "type": "2D",
+ "linkedControlVisible": false,
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "AXIAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "SUPERIORMOST"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#fff967"
+ }
+ },
+ "2": {
+ "name": "Right viewer",
+ "type": "2D",
+ "linkedControlVisible": false,
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "CORONAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "CORONAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#90ee90"
+ }
+ }
+ }
+ },
+ "widgets":{
+ "casesControl": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "pinTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "markerSize": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 2
+ },
+ "fontSize":{
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 12
+ },
+ "subAnnotationsAvailable":{
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "clearAll":{
+ "controlVisible": true,
+ "controlEnabled": true
+ }
+ }
+ },
+ "projectionTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "range": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "pointerTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "mode": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": "onClick"
+ }
+ }
+ },
+ "crossHairTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "customCursorTool": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": true,
+ "properties": {
+ "type": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": "fixedCrosshairRelativeCircle"
+ },
+ "diameter": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": 2
+ }
+ }
+ },
+ "annotationTableTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "fullTable": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "editableROI": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": true
+ },
+ "subAnnotationColumn":{
+ "controlVisible": true,
+ "controlEnabled": false
+ },
+ "csvExport": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ }
+ },
+ "pinUndoRedoTool":{
+ "controlVisible":true,
+ "controlEnabled":true
+ }
+ }
+ }
+ },
+ "currentMaterializedTask": {
+ "navigationRules": {
+ "forwardConfirmationWindow": true,
+ "forwardConfirmationWindowMessage": "This is message",
+ "backwardConfirmationWindow": true,
+ "backwardConfirmationWindowMessage": "This is message"
+ },
+ "label": "training-9c39728c-8ce8-419e-886d-8138ba68e96e",
+ "inputs": {
+ "inputImage_key": {
+ "value": "75c919ef4923cd7eef878de2930001c3",
+ "label": "T1",
+ "format": "nii.gz"
+ },
+ "inputAnnotationTableDefinition_key1": {
+ "value": "22e8e7c87745251cf661c72342004595"
+ }
+ },
+ "status": "TODO",
+ "assignedTo": "gregory.bliault@u-bordeaux.fr",
+ "dueDate": "2019-09-28T22:43:29.728Z",
+ "miniWorkflow": "mw1",
+ "uuid": "53b643d3f55f98c38962b596530000d3"
+ },
+ "currentHelpPanel": {
+ "_main": {
+ "goalAndDefinition": "Goals:
- Identify each site of leptomeningeal metastasis (LM)\t
- To be considered one lesion, the enhancing area must be continuous (all components must demonstrate connection in at least one projection).
- Select/pin each lesion only ONCE
- Leptomeningeal metastasis are 3-dimensional objects.
- Do not select the same lesion on multiple slices or projections.
- If a lesion is “diffuse” in nature, only pin the lesion in one place.
- Pin each lesion at its approximate center point.
- If a lesion has both a linear and nodular component, pin the nodular component.
Definitions:
- Leptomeningeal enhancement: a continuous, contrast-enhancing lesions with less than 2 mm distance between the outer edge of the lesion and the leptomeninges.
",
+ "tools": "
= Turn on/off pin tool
= Undo/redo the most recently placed annotation
= Triangulate a focal area in all three projections
= Display a 3D crosshair showing the position of the slices currently shown in all 3 viewer windows
= Project annotations to adjacent slices
Neighborhood of projection = Number of adjacent slices onto which the annotations are projected
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=sBQKQ7t23mw&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=unxHdPwvoWs&feature=youtu.be"
+ },
+ "images": [
+ {
+ "name": "Definition of Leptomeningeal Metastasis (1/2)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1nKNP9s822TF6qW4aHopWIY9ec1dh9sTT",
+ "_$visited": true
+ },
+ {
+ "name": "Definition of Leptomeningeal Metastasis (2/2)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1tI2O7J4aTHFpDcJZ0U4kU2YIJ2iCKnN7",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricular nodular enhancement (1/2)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1YxGNw-AE_t0zPMwy5htz-7HDBcj7zsXa",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricular nodular enhancement (2/2)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1PDT29ASEmpajFHdadnDyAj90jAvl9p9R",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebral nodular enhancement",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1We29fGlH25hYmedNUbw71F2un51vNCg2",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebellar nodular enhancement",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1miRZ9CqAs_HnTSsG7kpFQ0jrww8iz5CV",
+ "_$visited": true
+ },
+ {
+ "name": "Leptomeningeal lesion with linear and nodular component",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1NxtOmbXfFbLYa0jyqI0Hwj8ghLgFAYnt",
+ "_$visited": true
+ },
+ {
+ "name": "Nodular enhancements in the lumbar spine (Sagittal View)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=10Wq8oDibc_3CoAUfhjVvFMjVYyFt4Leg",
+ "_$visited": true
+ },
+ {
+ "name": "Diffuse enhancement in the cervical spine (Sagittal View)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1D3hVp-BhN_-4OK5eZj9XBXgPlzq0QyuW",
+ "_$visited": true
+ }
+ ],
+ "combos": "
= Place pins (annotations) on image when pin tool is toggled
= Move between slices
= Move forward between annotations
= Move backward between annotations
= Move image
= Window image
= Window image when pin tool is toggled
= Move image
= Zoom in/out
= Zoom in/out when pin tool is toggled
= Delete annotation
",
+ "annotations": "ANNOTATION TABLE
= Edit a cell
= Delete annotation
"
+ },
+ "Uncertainties":{
+ "goalAndDefinition": "Goal:
- please indicate if you are not certain whether an enhancement is indeed a leptomeningeal metastasis
",
+ "tools": "ANNOTATION TABLE
= Edit a cell
= Delete annotation
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=hFHQcCYNp1M&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=unxHdPwvoWs&feature=youtu.be"
+ },
+ "images": []
+ },
+ "Comments": {
+ "goalAndDefinition": "Goal:
- please enter any comments you may have separately for each leptomeningeal metastasis
",
+ "tools": "ANNOTATION TABLE
= Edit a cell
= Delete annotation
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=1qB00MCpEwQ&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=unxHdPwvoWs&feature=youtu.be"
+ },
+ "images": []
+ }
+ },
+ "status": "notstarted"
+ },
+ "listOfCases": [
+ {
+ "caseNumber": "LEPTO1",
+ "caseStatus": "notstarted"
+ },
+ {
+ "caseNumber": "LEPTO2",
+ "caseStatus": "notstarted"
+ }
+ ],
+ "currentCase": "LEPTO1"
+}
diff --git a/examples/tool/leptomeningeal2.json b/examples/tool/leptomeningeal2.json
new file mode 100644
index 0000000..b0e9fdd
--- /dev/null
+++ b/examples/tool/leptomeningeal2.json
@@ -0,0 +1,883 @@
+{
+ "miniWorkflow": {
+ "miniWorkflowPath": [
+ {
+ "stepKey": "annotation",
+ "stepName": "Identification of Leptomeningeal metastases"
+ },
+ {
+ "stepKey": "annotation",
+ "stepName": "Characterization of Leptomeningeal metastases"
+ }
+ ],
+ "currentStep": 1,
+ "currentTool": {
+ "id":"1dd174e57260e384c4f45e9c490004a9",
+ "name": "Characterization tool",
+ "description": "This tool is used to characterize previously identified ROI's.",
+ "version": "1.0.0",
+ "privacy": "PUBLIC",
+ "type": "CHARACTERIZATION_TOOL",
+ "inputs": {
+ "inputImage_key":{
+ "name": "Input image",
+ "description": "Input image",
+ "isList": false,
+ "type": "imageEntityInOut",
+ "imageEntityInOut_Type": "ANATOMICAL",
+ "imageEntityInOut_FileFormat": "nii.gz",
+ "required": true
+ },
+ "inputAnnotationTableDefinition_key1": {
+ "name": "Input annotations definition",
+ "description": "Input annotations definition for annotation table",
+ "isList": false,
+ "type": "annotationTableDefinitionInputOutput",
+ "required": true
+ },
+ "inputAnnotationFormDefinition_key1": {
+ "name": "Input annotations definition",
+ "description": "Input annotations definition for annotation table",
+ "isList": false,
+ "type": "annotationFormDefinitionInputOutput",
+ "required": true
+ },
+ "inputROIDataList_key1": {
+ "name": "Input ROis data",
+ "description": "Input ROI data for annotation table",
+ "isList": true,
+ "type": "roiInOut",
+ "typeROI": "IMPLICIT",
+ "required": true
+ }
+ },
+ "outputs": {
+ "outputAnnotationTableData_key": {
+ "name": "Output annotations data",
+ "description": "Output annotations data from annotation table",
+ "isList": false,
+ "type": "annotationTableDataInOut",
+ "required": true
+ },
+ "outputAnnotationFormData_key": {
+ "name": "Output annotations data",
+ "description": "Output annotations data from annotation form",
+ "isList": false,
+ "type": "annotationFormDataInOut",
+ "required": true
+ }
+ },
+ "configuration":{
+ "scenes": {
+ "sceneKey1": {
+ "primaryImageInputKey": "inputImage_key",
+ "rois": {
+ "geometricalROIsInputKeys": [
+ "inputROIDataList_key1"
+ ]
+ }
+ }
+ },
+ "viewers": {
+ "layout": {
+ "type": "ROW",
+ "layoutOrder": {
+ "left": "0",
+ "middle": "1",
+ "right": "2"
+ }
+ },
+ "renderWindows": {
+ "0": {
+ "name": "Sagittal viewer",
+ "type": "2D",
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "SAGITTAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#ffa07a"
+ }
+ },
+ "1": {
+ "name": "Middle viewer",
+ "type": "2D",
+ "linkedControlVisible": false,
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "AXIAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#fff967"
+ }
+ },
+ "2": {
+ "name": "Right viewer",
+ "type": "2D",
+ "linkedControlVisible": false,
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "CORONAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "CORONAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#90ee90"
+ }
+ }
+ }
+ },
+ "widgets":{
+ "casesControl": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "pinTool": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "properties": {
+ "markerSize": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": 2
+ },
+ "fontSize":{
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": 12
+ },
+ "clearAll":{
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "subAnnotationsAvailable":{
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "centering": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": true
+ }
+ }
+ },
+ "pointerTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "mode": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": "onClick"
+ }
+ }
+ },
+ "projectionTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "range": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "fiducialTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "type": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": "circle"
+ },
+ "diameter": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": 5
+ },
+ "rotation": {
+ "controlVisible": false,
+ "controlEnabled": true,
+ "defaultValue": 0
+ },
+ "adjustableZoom": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 4
+ }
+ }
+ },
+ "crossHairTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "annotationTableTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "fullTable": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "editableROI": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "subAnnotationColumn":{
+ "controlVisible": true,
+ "controlEnabled": false
+ }
+ }
+ }
+ }
+ }
+ },
+ "currentMaterializedTask": {
+ "navigationRules": {
+ "forwardConfirmationWindow": true,
+ "backwardConfirmationWindow": true
+ },
+ "label": "training-9c39728c-8ce8-419e-886d-8138ba68e96e",
+ "inputs": {
+ "inputImage_key": {
+ "value": "75c919ef4923cd7eef878de2930001c3",
+ "label": "T1",
+ "format": "nii.gz"
+ },
+ "inputAnnotationTableDefinition_key1": {
+ "value": "7e0c58ae948decbb445f6c495e0042b6"
+ },
+ "inputAnnotationFormDefinition_key1": {
+ "value": "b7fc97eb044d96113b87f38b2d000d93"
+ },
+ "inputROIDataList_key1": {
+ "value": ["75c919ef4923cd7eef878de293001652", "75c919ef4923cd7eef878de293002c70","75c919ef4923cd7eef878de2930038e0"]
+ }
+ },
+ "status": "TODO",
+ "assignedTo": "gregory.bliault@u-bordeaux.fr",
+ "dueDate": "2019-09-28T22:43:29.728Z",
+ "miniWorkflow": "mw1",
+ "uuid": "53b643d3f55f98c38962b596530000d3"
+ },
+ "currentHelpPanel": {
+ "_main": {
+ "goalAndDefinition": "Goals:
- determine the location(s) of all leptomeningeal enhancements,
- if you believe the lesion crosses two brain locations, you may choose more than one location option.
- if you are unsure about a lesion’s location, you will be able to indicate this in the uncertainties column.
Definitions:
Leptomeningeal enhancements can be seen in the following locations:
BRAIN:
- Cerebrum: Lesion located within 2mm of the cerebral cortex. The lesion should involve a cerebral sulcus to ensure that it is leptomeningeal, rather than dural-based.
- Cerebellum: Lesion located within 2mm of the cerebellar cortex (along cerebellar folia).
- Brainstem: Lesion along the surface of the brainstem, within 2mm of the brainstem parenchyma.·
- Ventricle: Lesion located within the ventricular system (lateral ventricles, third ventricle, or fourth ventricle) or along the lining of a ventricle. A ventricular lesion may grow into the periventricular space, however the inner-most edge of the lesion should be less than 2mm from the ventricular border.
- Cranial nerves: Lesion surrounding a cranial nerve.
SPINE:
- Cervical spine: Intradural extramedullary lesion located in the spinal cord between the superior end plate of C1 and the superior end plate of T1.
- Thoracic spine: Intradural extramedullary lesion located in the spinal cord between the superior end plate of T1 to the superior end plate of L1.
- Lumbar spine: Lumbar spine will encompass the lumbosacral spine and will include remainder of the spinal cord extending below the superior end plate of L1. This will include intradural extramedullary lesions of the lower lumbar spinal cord/conus medullaris and cauda equina
",
+ "tools": "
= Triangulate a focal area in all three projections
= Project annotations to adjacent slices
Neighborhood of projection = Number of adjacent slices onto which the annotations are projected
= Display a 3D crosshair showing the position of the slices currently shown in all 3 viewer windows
",
+ "combos": "
= Move between slices
= Move forward between annotations
= Move backward between annotations
= Window image
= Move image
= Zoom in/out
",
+ "annotations": "
= Edit a cell
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=0kl5sOz7PEs&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": [
+ {
+ "name": "Cerebrum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1EBsmK1qg-y2kU7mnrqi05E6g_T9u9bzr",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebellum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1kg1Y2gSJAKYLa9h9V01QcZtK4_5PVAfZ",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebellum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1C9CjjAGy8L0utDhJFjz182-awGC1QTw_",
+ "_$visited": true
+ },
+ {
+ "name": "Brainstem Midbrain",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=18Ksu2i4SoVUvjxqD40jEA3s7qvy1bfoY",
+ "_$visited": true
+ },
+ {
+ "name": "Brainstem Pons",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1-T07qu0PvZb7Nov0KPA772MdXSan4lzD",
+ "_$visited": true
+ },
+ {
+ "name": "Brainstem Medulla",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=172ZmQT05Wf6vBzOPlvadrAqhKN3J1uks",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1Kvg0CNL0LVY1ISDOlBGAGRwnbcgD7jBX",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=175gTnmem0gvNgSyP8YJQhpv-nmaAQqh1",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=158tgwe7O1q_okBRIYa_7BHSBx_YFsEA9",
+ "_$visited": true
+ },
+ {
+ "name": "Cranial Nerve III",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=17CE85JuNWTwwaJWrkHp7_fK_GXTmV0ew",
+ "_$visited": true
+ },
+ {
+ "name": "Cranial Nerve V",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1kDjxWSCA9CuMXcwuRTXGiRa8hRMvMQ8I",
+ "_$visited": true
+ },
+ {
+ "name": "Cranial Nerve VII-VIII",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1AMHAgyBSGeyRY9ESIC-8ThH_-qh1uk0N",
+ "_$visited": true
+ },
+ {
+ "name": "Lesion involving the 4th ventricle and cerebellum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1tbVv0ZmjsJM7Nlg-FI1UgTfqIzZBcsEi",
+ "_$visited": true
+ },
+ {
+ "name": "Cervical Spine",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1DuiZVwVEQWHd2uA9UkgkFj1rR6XCv3eW",
+ "_$visited": true
+ },
+ {
+ "name": "Thoracic Spine",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1XJDi9W-huc-NQsW7gwHdSdzhNFFpgCAB"
+ },
+ {
+ "name": "Lumbar Spine (Sagittal View)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1hpw9nZbxzG_ri8DxjCre3TUkOiHxuCVv",
+ "_$visited": true
+ },
+ {
+ "name": "Lumbar Spine (Axial View through the Cauda Equina)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1ILgs4FlonrFNZ15OFmG3Z7AFo527_8r9",
+ "_$visited": true
+ }
+ ]
+ },
+ "Location": {
+ "goalAndDefinition": "Goals:
- determine the location(s) of all leptomeningeal enhancements,
- if you believe the lesion crosses two brain locations, you may choose more than one location option.
- if you are unsure about a lesion’s location, you will be able to indicate this in the uncertainties column.
Definitions:
Leptomeningeal enhancements can be seen in the following locations:
BRAIN:
- Cerebrum: Lesion located within 2mm of the cerebral cortex. The lesion should involve a cerebral sulcus to ensure that it is leptomeningeal, rather than dural-based.
- Cerebellum: Lesion located within 2mm of the cerebellar cortex (along cerebellar folia).
- Brainstem: Lesion along the surface of the brainstem, within 2mm of the brainstem parenchyma.·
- Ventricle: Lesion located within the ventricular system (lateral ventricles, third ventricle, or fourth ventricle) or along the lining of a ventricle. A ventricular lesion may grow into the periventricular space, however the inner-most edge of the lesion should be less than 2mm from the ventricular border.
- Cranial nerves: Lesion surrounding a cranial nerve.
SPINE:
- Cervical spine: Intradural extramedullary lesion located in the spinal cord between the superior end plate of C1 and the superior end plate of T1.
- Thoracic spine: Intradural extramedullary lesion located in the spinal cord between the superior end plate of T1 to the superior end plate of L1.
- Lumbar spine: Lumbar spine will encompass the lumbosacral spine and will include remainder of the spinal cord extending below the superior end plate of L1. This will include intradural extramedullary lesions of the lower lumbar spinal cord/conus medullaris and cauda equina
",
+ "tools": "
= Triangulate a focal area in all three projections
= Project annotations to adjacent slices
Neighborhood of projection = Number of adjacent slices onto which the annotations are projected
= Display a 3D crosshair showing the position of the slices currently shown in all 3 viewer windows
",
+ "combos": "
= Move between slices
= Move forward between annotations
= Move backward between annotations
= Window image
= Move image
= Zoom in/out
",
+ "annotations": "
= Edit a cell
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=0kl5sOz7PEs&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": [
+ {
+ "name": "Cerebrum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1EBsmK1qg-y2kU7mnrqi05E6g_T9u9bzr",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebellum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1kg1Y2gSJAKYLa9h9V01QcZtK4_5PVAfZ",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebellum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1C9CjjAGy8L0utDhJFjz182-awGC1QTw_",
+ "_$visited": true
+ },
+ {
+ "name": "Brainstem Midbrain",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=18Ksu2i4SoVUvjxqD40jEA3s7qvy1bfoY",
+ "_$visited": true
+ },
+ {
+ "name": "Brainstem Pons",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1-T07qu0PvZb7Nov0KPA772MdXSan4lzD",
+ "_$visited": true
+ },
+ {
+ "name": "Brainstem Medulla",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=172ZmQT05Wf6vBzOPlvadrAqhKN3J1uks",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1Kvg0CNL0LVY1ISDOlBGAGRwnbcgD7jBX",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=175gTnmem0gvNgSyP8YJQhpv-nmaAQqh1",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=158tgwe7O1q_okBRIYa_7BHSBx_YFsEA9",
+ "_$visited": true
+ },
+ {
+ "name": "Cranial Nerve III",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=17CE85JuNWTwwaJWrkHp7_fK_GXTmV0ew",
+ "_$visited": true
+ },
+ {
+ "name": "Cranial Nerve V",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1kDjxWSCA9CuMXcwuRTXGiRa8hRMvMQ8I",
+ "_$visited": true
+ },
+ {
+ "name": "Cranial Nerve VII-VIII",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1AMHAgyBSGeyRY9ESIC-8ThH_-qh1uk0N",
+ "_$visited": true
+ },
+ {
+ "name": "Lesion involving the 4th ventricle and cerebellum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1tbVv0ZmjsJM7Nlg-FI1UgTfqIzZBcsEi",
+ "_$visited": true
+ },
+ {
+ "name": "Cervical Spine",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1DuiZVwVEQWHd2uA9UkgkFj1rR6XCv3eW",
+ "_$visited": true
+ },
+ {
+ "name": "Thoracic Spine",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1XJDi9W-huc-NQsW7gwHdSdzhNFFpgCAB"
+ },
+ {
+ "name": "Lumbar Spine (Sagittal View)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1hpw9nZbxzG_ri8DxjCre3TUkOiHxuCVv",
+ "_$visited": true
+ },
+ {
+ "name": "Lumbar Spine (Axial View through the Cauda Equina)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1ILgs4FlonrFNZ15OFmG3Z7AFo527_8r9",
+ "_$visited": true
+ }
+ ]
+ },
+ "Comments": {
+ "goalAndDefinition": "Instructions:
- please enter any comments you may have separately for each leptomeningeal metastasis
",
+ "tools": "",
+ "combos": "",
+ "annotations": "
= Edit a cell
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=V3dcGsSfx-E&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": []
+ },
+ "Is hydrocephalus present?": {
+ "goalAndDefinition": "Instructions:
1. Record measurements that will be used to calculate the Evan’s Index (a quantitative tool to assess for ventriculomegaly).
2. Indicate whether there is qualitative hydrocephalus.
Definitions:
1. Evan’s index measurements:

Scroll through the axial images until you find the largest width of the frontal horns. Measure the largest frontal horn width in a plane that is perpendicular to midline (between the cerebral hemispheres). On the same axial slice, measure the largest left to right internal skull diameter (inner bone edge to inner bone edge). This measurement should also be perpendicular to midline. Enter these measurements into
2. Hydrocephalus: Subjective enlargement of the ventricles without proportional widening of the cortical sulci. Periventricular edema may be seen, but is not required.
",
+ "tools": "
= Triangulate a focal area in all three projections
= Display a 3D crosshair showing the position of the slices currently shown in all 3 viewer windows
",
+ "combos": "
= Move between slices
= Window image
= Move image
= Zoom in/out
",
+ "annotations": "
= Click on “yes” or “no” button
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=mQB0-yzc60Q&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": [
+ {
+ "name": "Measurements for Evan’s Index",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=15bQgKjgVAjkXOupWeBPRbqqfjmmiVHIU",
+ "_$visited": true
+ },
+ {
+ "name": "Measurements for Evan’s Index",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1f1j7YqQpCAIhqbHSGOh2oOrUOobt48ZC",
+ "_$visited": true
+ },
+ {
+ "name": "Normal Ventricles",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1GpBcu4pAPk_wZTaszGpetrh5QwecMtIB",
+ "_$visited": true
+ },
+ {
+ "name": "Normal Ventricles",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1_Qy8vIMyJ4g_JDRdJZjECqMjXY_x8tbk",
+ "_$visited": true
+ },
+ {
+ "name": "Normal Ventrices",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1cy5IpurgfJAym_Lj4T-Wdsduo7Dr184a",
+ "_$visited": true
+ },
+ {
+ "name": "Unclear",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1lUqAO4xMrS_GC7w7nZ2iOvdnIR_VIF7-"
+ },
+ {
+ "name": "Unclear",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1GOIiS3c_7PiTMbB8qAIdmuvPAxZ8Czk1",
+ "_$visited": true
+ },
+ {
+ "name": "Hydrocephalus. Two axial slices from single brain MRI demonstrates enlarged ventricles (particularly in left temporal horn). There is periventricular edema which increases sensitivity",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=18O6s2mZW6cGdzaLU9tQHKneLQD-1a2Ie"
+ },
+ {
+ "name": "Hydrocephalus. Two axial slices from single brain MRI demonstrates enlarged ventricles (particularly in left temporal horn). There is periventricular edema which increases sensitivity",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1xxsIeIfdLWXIMuapXx_RCWrP2IlJiwFv"
+ }
+ ]
+ },
+ "Shape": {
+ "goalAndDefinition": "Goals:
- determine the shape (i.e., nodular versus linear/curvilinear) of all leptomeningeal enhancements.
- if a lesion has both nodular and linear components, select both.
Definitions:
- Nodular enhancement: mass with rounded or convex polygonal contour.
- a mass must have at least partially convex borders in three dimensions.
- can be seen in the subarachnoid space, ventricles, periventricular areas and around the spinal cord
- Linear enhancement: arranged along a straight or close-to-straight line
- in three dimensions, a linear lesion is often “sheet-like”
- can have a 2-D rounded/polygonal shape, but lacks convex borders in three dimensions.
- can be seen in cranial and spinal nerve roots, cerebellar folia, ventricles, cerebral sulci and around the spinal cord
",
+ "tools": "
= Triangulate a focal area in all three projections
= Project annotations to adjacent slices
Neighborhood of projection = Number of adjacent slices onto which the annotations are projected
= Display a 3D crosshair showing the position of the slices currently shown in all 3 viewer windows
",
+ "combos": "
= Move between slices
= Move forward between annotations
= Move backward between annotations
= Window image
= Move image
= Zoom in/out
",
+ "annotations": "
= Edit a cell
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=TClBtDEbQB4&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": [
+ {
+ "name": "Nodular enhancement in the subarachnoid space",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1lIPL9fXMkAQ-3jvnhQnB8UhZXarfUTL_",
+ "_$visited": true
+ },
+ {
+ "name": "Nodular enhancement in the fourth ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1lfnizK6wi5O72p5wGvpfoXMe9JqaXHaj",
+ "_$visited": true
+ },
+ {
+ "name": "Nodular enhancement in a periventricular area",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1tDI_RQco7TRa0Zbv-EPS5Qy6IWK8nqr_",
+ "_$visited": true
+ },
+ {
+ "name": "Nodular enhancement around the spinal cord",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=15KbCI-NUASoy-daAB_VP-f0w4OvkGAAa",
+ "_$visited": true
+ },
+ {
+ "name": "Linear/curvilinear enhancement in a cranial nerve root",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1-FTsHGD2AmHKMrif-Jb5xmVQ2RdnzYmT",
+ "_$visited": true
+ },
+ {
+ "name": "Linear/curvilinear enhancement along the cerebellar folia",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1IkG9InZ5xT4DqBtjd4CbZGddjY8BpBKD",
+ "_$visited": true
+ },
+ {
+ "name": "Linear “sheet-like” lesion, wrapping around the spinal cord",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1tDI_RQco7TRa0Zbv-EPS5Qy6IWK8nqr_",
+ "_$visited": true
+ },
+ {
+ "name": "Linear/curvilinear and nodular enhancement along the lining of a ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1MyX_mpEANpiOgzn9T82BFEMtWdHFitgX",
+ "_$visited": true
+ },
+ {
+ "name": "Linear/curvilinear enhancement along a cerebral sulcus",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1mrIu7sk3L5g-S_2LPAZfpA4mbpE0iiKD"
+ }
+ ]
+ },
+ "Size is > 5x5mm": {
+ "goalAndDefinition": "Goals:
- determine the size of all leptomeningeal enhancements using the fiducial tool

- if an enhancement has both nodular and linear components, determine size based on the nodular component.
- for a focal lesion with an irregular border, measure the largest sub-component without crossing normal tissue.
Definitions:
- note that the diameter of the red fiducial circle is 5 mm.
- if the diameter of an enhancement is greater than 5 mm in the two greatest perpendicular diameters in any 2D plane, please select “yes” under the “Size” column of the annotation table.
- if the diameter of an enhancement is equal to or smaller than 5 mm in the two greatest perpendicular diameters in any 2D plane, please select “no” under the “Size” column of the annotation table
",
+ "tools": "
= Turn on/off fiducial tool
= Triangulate a focal area in all three projections
= Project annotations to adjacent slices
Neighborhood of projection = Number of adjacent slices onto which the annotations are projected
= Display a 3D crosshair showing the position of the slices currently shown in all 3 viewer windows
",
+ "combos": "
= Move between slices
= Move forward between annotations
= Move backward between annotations
= Window image
= Move image
= Zoom in/out
",
+ "annotations": "
= Edit a cell
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=dqDNTr2ACcw&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": [
+ {
+ "name": "Lesion with size > 5 mm in bi-diameter ",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1-SM18L11DD4ON-Wk19jailg4wQ2BwTfl",
+ "_$visited": true
+ },
+ {
+ "name": "Lesion with irregular border",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1VM1Aqidordd0XRWZKkVsNgc5nbZhvhey",
+ "_$visited": true
+ }
+ ]
+ },
+ "Spatial extension": {
+ "goalAndDefinition": "Goals:
- Determine the spatial extension (i.e., focal or diffuse) of all leptomeningeal enhancements.
- If a lesion has both a focal and diffuse component, label this lesion as diffuse. The more focal component may be measurable (>5x5 mm) even though the lesion is diffuse.
Definitions:
- Focal enhancement: circumscribed area of enhancement with sharp boundaries. The lesion can be measured in two dimensions (one plane) without crossing normal brain.
- Diffuse enhancement: diffuse enhancement will encompass lesions with any of the following characteristics:
- A lesion without well-defined boundaries
- A lesion is spatially spread out such that it cannot be measured in two dimensions (one plane) without crossing normal brain parenchyma.
",
+ "tools": "
= Triangulate a focal area in all three projections
= Project annotations to adjacent slices
Neighborhood of projection = Number of adjacent slices onto which the annotations are projected
Display a 3D crosshair showing the position of the slices currently shown in all 3 viewer windows
",
+ "combos": "
= Move between slices
= Move forward between annotatio
= Move backward between annotations
= Window image
= Move image
= Zoom in/out
= Delete annotation
",
+ "annotations": "
= Edit a cell
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=Nta2Xg-KT_k&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": [
+ {
+ "name": "Cerebellar focal enhancement",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1SWzP5BbkuydkTCqRhnsvDhXe31OVt0tc",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebellar focal enhancement ",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1Hsfi0zwxmC02FYImylWTpqjogxI6Bicv",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebellar diffuse enhancement",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1b2iA6sK__mD9BZ2XlNL3Es7swWqOY379",
+ "_$visited": true
+ },
+ {
+ "name": "Focal",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1Sw15RAeSdoemxpBPN8q1XeXsJk_YSpWZ",
+ "_$visited": true
+ },
+ {
+ "name": "Focal",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1g6GPjslmnc345WfjG0rCaOdxW1BgiODp",
+ "_$visited": true
+ },
+ {
+ "name": "Diffuse",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1doy-Bh7V_N_9B4a9tvD8VVxRjXiOsCBS",
+ "_$visited": true
+ },
+ {
+ "name": "Diffuse",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1JZMUW7C5uzaS8Wjp11zgrx4zZNBvL02A"
+ }
+ ]
+ },
+ "Uncertainties": {
+ "goalAndDefinition": "Instructions:
- please indicate if you are not certain regarding the location, size, shape, and/or spatial extension of a leptomeningeal enhancement
",
+ "tools": "",
+ "combos": "",
+ "annotations": "
= Edit a cell
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=rOJdY34UFUs&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": []
+ }
+ },
+ "status": "notstarted"
+ },
+ "listOfCases": [
+ {
+ "caseNumber": "NMO1",
+ "caseStatus": "notstarted"
+ },
+ {
+ "caseNumber": "NMO2",
+ "caseStatus": "notstarted"
+ }
+ ],
+ "currentCase": "NMO1"
+}
\ No newline at end of file
diff --git a/examples/tool/leptomeningeal3.json b/examples/tool/leptomeningeal3.json
new file mode 100644
index 0000000..12b0c8a
--- /dev/null
+++ b/examples/tool/leptomeningeal3.json
@@ -0,0 +1,404 @@
+{
+ "miniWorkflow": {
+ "miniWorkflowPath": [
+ {
+ "stepKey": "annotation",
+ "stepName": "Step1"
+ },
+ {
+ "stepKey": "annotation",
+ "stepName": "Step2"
+ }
+ ],
+ "currentStep": 1,
+ "currentTool": {
+ "id":"1dd174e57260e384c4f45e9c490004a9",
+ "name": "Characterization tool",
+ "description": "This tool is used to characterize previously identified ROI's.",
+ "version": "1.0.0",
+ "privacy": "PUBLIC",
+ "type": "CHARACTERIZATION_TOOL",
+ "inputs": {
+ "inputImage_key":{
+ "name": "Input image",
+ "description": "Input image",
+ "isList": false,
+ "type": "imageEntityInOut",
+ "imageEntityInOut_Type": "ANATOMICAL",
+ "imageEntityInOut_FileFormat": "nii.gz",
+ "required": true
+ },
+ "inputAnnotationFormDefinition_key1": {
+ "name": "Input annotations definition",
+ "description": "Input annotations definition for annotation table",
+ "isList": false,
+ "type": "annotationFormDefinitionInputOutput",
+ "required": true
+ },
+ "inputROIDataList_key1": {
+ "name": "Input ROis data",
+ "description": "Input ROI data for annotation table",
+ "isList": true,
+ "type": "roiInOut",
+ "typeROI": "IMPLICIT",
+ "required": true
+ }
+ },
+ "outputs": {
+ "outputAnnotationTableData_key": {
+ "name": "Output annotations data",
+ "description": "Output annotations data from annotation table",
+ "isList": false,
+ "type": "annotationTableDataInOut",
+ "required": true
+ },
+ "outputAnnotationFormData_key": {
+ "name": "Output annotations data",
+ "description": "Output annotations data from annotation form",
+ "isList": false,
+ "type": "annotationFormDataInOut",
+ "required": true
+ }
+ },
+ "configuration":{
+ "scenes": {
+ "sceneKey1": {
+ "primaryImageInputKey": "inputImage_key",
+ "rois": {
+ "geometricalROIsInputKeys": [
+ "inputROIDataList_key1"
+ ]
+ }
+ }
+ },
+ "viewers": {
+ "layout": {
+ "type": "ROW",
+ "layoutOrder": {
+ "left": "0",
+ "middle": "1",
+ "right": "2"
+ }
+ },
+ "renderWindows": {
+ "0": {
+ "name": "Sagittal viewer",
+ "type": "2D",
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "SAGITTAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#ffa07a"
+ }
+ },
+ "1": {
+ "name": "Middle viewer",
+ "type": "2D",
+ "linkedControlVisible": false,
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "AXIAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#fff967"
+ }
+ },
+ "2": {
+ "name": "Right viewer",
+ "type": "2D",
+ "linkedControlVisible": false,
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "CORONAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "CORONAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#90ee90"
+ }
+ }
+ }
+ },
+ "widgets":{
+ "pinTool": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "properties": {
+ "markerSize": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": 2
+ },
+ "fontSize":{
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": 12
+ },
+ "clearAll":{
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "subAnnotationsAvailable":{
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "centering": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": true
+ }
+ }
+ },
+ "pointerTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "mode": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": "onClick"
+ }
+ }
+ },
+ "projectionTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "range": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "fiducialTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "type": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": "circle"
+ },
+ "diameter": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": 5
+ },
+ "rotation": {
+ "controlVisible": false,
+ "controlEnabled": true,
+ "defaultValue": 0
+ }
+ }
+ },
+ "crossHairTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "annotationTableTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "fullTable": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "editableROI": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "subAnnotationColumn":{
+ "controlVisible": true,
+ "controlEnabled": false
+ }
+ }
+ }
+ }
+ }
+ },
+ "currentMaterializedTask": {
+ "label": "training-9c39728c-8ce8-419e-886d-8138ba68e96e",
+ "inputs": {
+ "inputImage_key": {
+ "value": "310a4fa25bb6c2e79dbc0b35c900614d",
+ "label": "T1",
+ "format": "nii.gz"
+ },
+ "inputAnnotationFormDefinition_key1": {
+ "value": "3d177f94c60db9b3157d356a9f002a58"
+ },
+ "inputROIDataList_key1": {
+ "value": ["e64e724ff6782f91b0ad792220007a97","e64e724ff6782f91b0ad7922200088a0","e64e724ff6782f91b0ad792220009d79","e64e724ff6782f91b0ad79222000ac2e","e64e724ff6782f91b0ad79222000c3ae"]
+ }
+ },
+ "status": "TODO",
+ "assignedTo": "gregory.bliault@u-bordeaux.fr",
+ "dueDate": "2019-09-28T22:43:29.728Z",
+ "miniWorkflow": "mw1",
+ "uuid": "53b643d3f55f98c38962b596530000d3"
+ },
+ "status": "notstarted"
+ },
+ "listOfCases": [
+ {
+ "caseNumber": "NMO1",
+ "caseStatus": "notstarted"
+ },
+ {
+ "caseNumber": "NMO2",
+ "caseStatus": "notstarted"
+ }
+ ],
+ "currentCase": "NMO1"
+}
\ No newline at end of file
diff --git a/examples/tool/modelingToolDemo.json b/examples/tool/modelingToolDemo.json
new file mode 100644
index 0000000..0dc4179
--- /dev/null
+++ b/examples/tool/modelingToolDemo.json
@@ -0,0 +1,487 @@
+{
+ "miniWorkflow": {
+ "currentTool": {
+ "id": "1dd174e57260e384c4f45e9c490004a9",
+ "name": "Annotation tool",
+ "description": "This tool is used to visualize a segmentation and check it.",
+ "version": "1.0.0",
+ "privacy": "PUBLIC",
+ "type": "ANNOTATION_TOOL",
+ "inputs": {
+ "inputImage_key":{
+ "name": "Input image",
+ "description": "Input image",
+ "isList": false,
+ "type": "imageEntityInOut",
+ "imageEntityInOut_Type": "ANATOMICAL",
+ "imageEntityInOut_FileFormat": "nii.gz",
+ "required": true
+ },
+ "inputImage_key2":{
+ "name": "Input image",
+ "description": "Input image",
+ "isList": false,
+ "type": "imageEntityInOut",
+ "imageEntityInOut_Type": "ANATOMICAL",
+ "imageEntityInOut_FileFormat": "nii.gz",
+ "required": true
+ },
+ "inputImage_key3":{
+ "name": "Input image",
+ "description": "Input image",
+ "isList": false,
+ "type": "imageEntityInOut",
+ "imageEntityInOut_Type": "ANATOMICAL",
+ "imageEntityInOut_FileFormat": "nii.gz",
+ "required": true
+ },
+ "inputLut_key1": {
+ "name": "Input LUT data",
+ "description": "Input LUT data for overlay displaying.",
+ "isList": false,
+ "type": "lookUpTable",
+ "required": true
+ },
+ "inputLutDescription_key1": {
+ "name": "Input description of LUT data",
+ "description": "Input LUT data for displaying options.",
+ "isList": false,
+ "type": "lookUpTableDescription",
+ "required": true
+ }
+ },
+ "outputs": {
+ },
+ "configuration":{
+ "luts": {
+ "lut_key1": {
+ "fromInputs": true,
+ "lutInputKey": "inputLut_key1"
+ }
+ },
+ "lutDescriptions": {
+ "lutDescription_key1": {
+ "fromInputs": true,
+ "lutDescriptionInputKey": "inputLutDescription_key1"
+ }
+ },
+ "rois": {
+ "overlays": {
+ "overlay_key_1": {
+ "fromInputs": false,
+ "lutKey": "lut_key1",
+ "lutDescriptionKey": "lutDescription_key1"
+ }
+ }
+ },
+ "scenes": {
+ "sceneKey1": {
+ "primaryImageInputKey": "inputImage_key",
+ "rois": {
+ "overlays": [
+ "overlay_key_1"
+ ]
+ }
+ },
+ "sceneKey2": {
+ "primaryImageInputKey": "inputImage_key2"
+ },
+ "sceneKey3": {
+ "primaryImageInputKey": "inputImage_key3"
+ }
+ },
+ "viewers": {
+ "layout": {
+ "type": "ROW",
+ "layoutOrder": {
+ "left": "0",
+ "middleLeft": "1",
+ "middleRight": "2",
+ "right": "3"
+ }
+ },
+ "renderWindows": {
+ "0": {
+ "name": "Sagittal viewer",
+ "type": "2D",
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "SAGITTAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1",
+ "sceneKey2",
+ "sceneKey3"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#ffa07a"
+ }
+ },
+ "1": {
+ "name": "Coronal viewer",
+ "type": "2D",
+ "linkedControlVisible": false,
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "CORONAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1",
+ "sceneKey2",
+ "sceneKey3"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "CORONAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#fff967"
+ }
+ },
+ "2": {
+ "name": "Coronal viewer",
+ "type": "2D",
+ "linkedControlVisible": false,
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "AXIAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1",
+ "sceneKey2",
+ "sceneKey3"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel": {
+ "color": "#90ee90"
+ }
+ },
+ "3": {
+ "name": "3D viewer",
+ "type": "3D",
+ "displayControls": {
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": true
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1",
+ "sceneKey2",
+ "sceneKey3"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayImageSlices": {
+ "0": {
+ "fromState": true,
+ "stateKey": "left"
+ },
+ "1": {
+ "fromState": true,
+ "stateKey": "middleLeft"
+ },
+ "2": {
+ "fromState": true,
+ "stateKey": "middleRight"
+ }
+ }
+ }
+ }
+ },
+ "widgets": {
+ "pointerTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "mode": {
+ "controlVisible": false,
+ "controlEnabled": true,
+ "defaultValue": "onClick"
+ }
+ }
+ },
+ "pinTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "markerSize": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 2
+ },
+ "fontSize":{
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 12
+ },
+ "clearAll":{
+ "controlVisible": true,
+ "controlEnabled": true
+ }
+ }
+ },
+ "projectionTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "range": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "levelTracingTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "levelFunction": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": "DARKER"
+ },
+ "levelFunctionMargin": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 25
+ },
+ "lineWidth": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 0.1
+ },
+ "levelThreeD": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ }
+ }
+ },
+ "linkAllTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "crossHairTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "annotationOpacity": {
+ "controlVisible": true,
+ "controlEnabled": false,
+ "defaultValue": 1
+ },
+ "brushTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "radius": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "fillingTool":{
+ "controlVisible": true,
+ "controlEnabled": true
+ },
+ "eraserTool":{
+ "controlVisible":true,
+ "controlEnabled":true,
+ "properties":{
+ "radius":{
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "labelmapLUT": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ },
+ "labelmapUndoRedoTool":{
+ "controlVisible":true,
+ "controlEnabled":true
+ },
+ "labelmapOpacity":{
+ "controlVisible":true,
+ "controlEnabled":true,
+ "defaultValue":1
+ }
+ }
+ }
+ },
+ "currentMaterializedTask": {
+ "label": "training-9c39728c-8ce8-419e-886d-8138ba68e96e",
+ "inputs": {
+ "inputImage_key": {
+ "value": "20c2d549136e928edffcdb64b902474d",
+ "label": "T1",
+ "format": "nii.gz"
+ },
+ "inputImage_key2": {
+ "value": "20c2d549136e928edffcdb64b902474d",
+ "label": "T2",
+ "format": "nii.gz"
+ },
+ "inputImage_key3": {
+ "value": "20c2d549136e928edffcdb64b902474d",
+ "label": "FLAIR",
+ "format": "nii.gz"
+ },
+ "inputLut_key1": {
+ "value": "c63c3c687bfeab4782a90290e1000260"
+ },
+ "inputLutDescription_key1": {
+ "value": "c63c3c687bfeab4782a90290e1003c40"
+ }
+ },
+ "status": "TODO",
+ "assignedTo": "gregory.bliault@u-bordeaux.fr",
+ "dueDate": "2019-09-28T22:43:29.728Z",
+ "miniWorkflow": "mw1",
+ "uuid": "53b643d3f55f98c38962b596530000d3"
+ },
+ "status": "notstarted"
+ },
+ "listOfCases": [
+ {
+ "caseNumber": "training-9c39728c-8ce8-419e-886d-8138ba68e96e",
+ "caseStatus": "notstarted"
+ }
+ ],
+ "currentCase": "training-9c39728c-8ce8-419e-886d-8138ba68e96e"
+}
\ No newline at end of file
diff --git a/examples/tool/sceneDemo.json b/examples/tool/sceneDemo.json
new file mode 100644
index 0000000..2bf3029
--- /dev/null
+++ b/examples/tool/sceneDemo.json
@@ -0,0 +1,1349 @@
+{
+ "miniWorkflow": {
+ "miniWorkflowPath": [
+ {
+ "stepKey": "annotation",
+ "stepName": "Identification of Leptomeningeal metastases"
+ },
+ {
+ "stepKey": "annotation",
+ "stepName": "Characterization of Leptomeningeal metastases"
+ }
+ ],
+ "currentStep": 1,
+ "currentTool": {
+ "id": "1dd174e57260e384c4f45e9c490004a9",
+ "name": "Characterization tool",
+ "description": "This tool is used to characterize previously identified ROI's.",
+ "version": "1.0.0",
+ "privacy": "PUBLIC",
+ "type": "CHARACTERIZATION_TOOL",
+ "inputs": {
+ "inputImage_key": {
+ "name": "Input image",
+ "description": "Input image",
+ "isList": false,
+ "type": "imageEntityInOut",
+ "imageEntityInOut_Type": "ANATOMICAL",
+ "imageEntityInOut_FileFormat": "nii.gz",
+ "required": true
+ },
+ "inputImage_key2": {
+ "name": "Input image",
+ "description": "Input image",
+ "isList": false,
+ "type": "imageEntityInOut",
+ "imageEntityInOut_Type": "ANATOMICAL",
+ "imageEntityInOut_FileFormat": "nii.gz",
+ "required": true
+ },
+ "inputImage_key3": {
+ "name": "Segmentation",
+ "description": "Segmentation",
+ "isList": false,
+ "type": "roiInOut",
+ "typeROI": "EXPLICIT",
+ "required": true,
+ "imageEntityInOut_FileFormat": "nii.gz"
+ },
+ "inputImage_key4": {
+ "name": "Segmentation",
+ "description": "Segmentation",
+ "isList": false,
+ "type": "roiInOut",
+ "typeROI": "EXPLICIT",
+ "required": true,
+ "imageEntityInOut_FileFormat": "nii.gz"
+ },
+ "inputImage_key5": {
+ "name": "Segmentation",
+ "description": "Segmentation",
+ "isList": false,
+ "type": "roiInOut",
+ "typeROI": "EXPLICIT",
+ "required": true,
+ "imageEntityInOut_FileFormat": "nii.gz"
+ },
+ "inputAnnotationTableDefinition_key1": {
+ "name": "Input annotations definition",
+ "description": "Input annotations definition for annotation table",
+ "isList": false,
+ "type": "annotationTableDefinitionInputOutput",
+ "required": true
+ },
+ "inputAnnotationFormDefinition_key1": {
+ "name": "Input annotations definition",
+ "description": "Input annotations definition for annotation table",
+ "isList": false,
+ "type": "annotationFormDefinitionInputOutput",
+ "required": true
+ },
+ "inputROIDataList_key1": {
+ "name": "Input ROis data",
+ "description": "Input ROI data for annotation table",
+ "isList": true,
+ "type": "roiInOut",
+ "typeROI": "IMPLICIT",
+ "required": true
+ },
+ "inputLut_key1": {
+ "name": "Input LUT data",
+ "description": "Input LUT data for overlay displaying.",
+ "isList": false,
+ "type": "lookUpTable",
+ "required": true
+ },
+ "inputLut_key2": {
+ "name": "Input LUT data",
+ "description": "Input LUT data for overlay displaying.",
+ "isList": false,
+ "type": "lookUpTable",
+ "required": true
+ },
+ "inputLut_key3": {
+ "name": "Input LUT data",
+ "description": "Input LUT data for overlay displaying.",
+ "isList": false,
+ "type": "lookUpTable",
+ "required": true
+ },
+ "inputLutDescription_key1": {
+ "name": "Input description of LUT data",
+ "description": "Input LUT data for displaying options.",
+ "isList": false,
+ "type": "lookUpTableDescription",
+ "required": true
+ },
+ "inputLutDescription_key2": {
+ "name": "Input description of LUT data",
+ "description": "Input LUT data for displaying options.",
+ "isList": false,
+ "type": "lookUpTableDescription",
+ "required": true
+ },
+ "inputLutDescription_key3": {
+ "name": "Input description of LUT data",
+ "description": "Input LUT data for displaying options.",
+ "isList": false,
+ "type": "lookUpTableDescription",
+ "required": true
+ }
+ },
+ "outputs": {
+ "outputAnnotationTableData_key": {
+ "name": "Output annotations data",
+ "description": "Output annotations data from annotation table",
+ "isList": false,
+ "type": "annotationTableDataInOut",
+ "required": true,
+ "referenceInputKey": "inputROIDataList_key1",
+ "referenceAnnotationTableInputKey": "inputAnnotationTableDefinition_key1"
+ },
+ "outputAnnotationFormData_key": {
+ "name": "Output annotations data",
+ "description": "Output annotations data from annotation form",
+ "isList": false,
+ "type": "annotationFormDataInOut",
+ "required": true,
+ "referenceInputKey": "inputImage_key",
+ "referenceAnnotationTableInputKey": "inputAnnotationFormDefinition_key1"
+ },
+ "segmentation_key": {
+ "name": "Medulla oblongata segmentation",
+ "description": "The medulla oblongata segmentation from the user",
+ "isList": false,
+ "type": "roiInOut",
+ "typeROI": "EXPLICIT"
+ }
+ },
+ "bindingSceneElementsToToolOutputs": [
+ {
+ "outputTool": "segmentation_key",
+ "roiKeyName": "overlay_key_1"
+ }
+ ],
+ "configuration": {
+ "luts": {
+ "lut_key1": {
+ "fromInputs": true,
+ "lutInputKey": "inputLut_key1"
+ },
+ "lut_key2": {
+ "fromInputs": true,
+ "lutInputKey": "inputLut_key2"
+ },
+ "lut_key3": {
+ "fromInputs": true,
+ "lutInputKey": "inputLut_key3"
+ }
+ },
+ "lutDescriptions": {
+ "lutDescription_key1": {
+ "fromInputs": true,
+ "lutDescriptionInputKey": "inputLutDescription_key1"
+ },
+ "lutDescription_key2": {
+ "fromInputs": true,
+ "lutDescriptionInputKey": "inputLutDescription_key2"
+ },
+ "lutDescription_key3": {
+ "fromInputs": true,
+ "lutDescriptionInputKey": "inputLutDescription_key3"
+ }
+ },
+ "rois": {
+ "overlays": {
+ "overlay_key_1": {
+ "fromInputs": false,
+ "lutKey": "lut_key1",
+ "lutDescriptionKey": "lutDescription_key1",
+ "label": "First layer"
+ },
+ "overlay_key_2": {
+ "fromInputs": true,
+ "imageInputKey": "inputImage_key3",
+ "lutKey": "lut_key2",
+ "lutDescriptionKey": "lutDescription_key2",
+ "label": "Layer invisible on Init",
+ "onInit": {
+ "visible": false
+ }
+ },
+ "overlay_key_3": {
+ "fromInputs": true,
+ "imageInputKey": "inputImage_key4",
+ "lutKey": "lut_key3",
+ "lutDescriptionKey": "lutDescription_key3"
+ }
+ },
+ "masks": {
+ "mask_key1": {
+ "fromInputs": true,
+ "imageInputKey": "inputImage_key5",
+ "lutKey": "lut_key1",
+ "lutDescriptionKey": "lutDescription_key1",
+ "label": "Rectangle mask",
+ "interactions": {
+ "PREVENT_FROM_ADDING_PIN": {
+ "type": "scalar",
+ "value": 1
+ },
+ "PREVENT_FROM_CHANGING_VOXEL_VALUE": {
+ "type": "vector",
+ "value": [
+ 1,
+ 2,
+ 4
+ ]
+ }
+ }
+ }
+ },
+ "geometricalROIs": {
+ "roiList_key1": {
+ "fromInputs": true,
+ "roiInputKey": "inputROI_key1"
+ },
+ "roiList_key2": {
+ "fromInputs": false
+ }
+ }
+ },
+ "scenes": {
+ "sceneKey1": {
+ "primaryImageInputKey": "inputImage_key",
+ "rois": {
+ "overlays": [
+ "overlay_key_1"
+ ],
+ "masks": ["mask_key1"]
+ }
+ },
+ "sceneKey2": {
+ "primaryImageInputKey": "inputImage_key2",
+ "rois": {
+ "geometricalROIs": [
+ "roiList_key1"
+ ],
+ "overlays": [
+ "overlay_key_2",
+ "overlay_key_3"
+ ]
+ }
+ }
+ },
+ "annotationScenes": {
+ "annotationKey1": {
+ "roiInputKey": "inputROIDataList_key1",
+ "annotationDefinitionInputKey": "inputAnnotationTableDefinition_key1"
+ },
+ "annotationKey2": {
+ "roiInputKey": "inputImage_key",
+ "annotationDefinitionInputKey": "inputAnnotationFormDefinition_key1"
+ }
+ },
+ "viewers": {
+ "layout": {
+ "type": "ROW",
+ "layoutOrder": {
+ "left": "0",
+ "middle": "1",
+ "right": "2"
+ }
+ },
+ "renderWindows": {
+ "0": {
+ "name": "Sagittal viewer",
+ "type": "2D",
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "AXIAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ },
+ "contoursOnInit": {
+ "visible": true
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1",
+ "sceneKey2"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey2"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": true,
+ "controlEnabled": true
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel": {
+ "color": "#ffa07a"
+ }
+ },
+ "1": {
+ "name": "Middle viewer",
+ "type": "2D",
+ "linkedControlVisible": false,
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "AXIAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "contourMode": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "description": "This is optional setting responsible for displaying contour options (wireframe, offset). If not present then this contour options are visible by default. "
+ }
+ },
+ "lookAndFeel": {
+ "color": "#fff967"
+ }
+ },
+ "2": {
+ "name": "Right viewer",
+ "type": "2D",
+ "linkedControlVisible": false,
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "CORONAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayScenes": {
+ "possibleScenesToDisplay": [
+ "sceneKey1"
+ ],
+ "hasDefaultSceneToDisplay": true,
+ "defaultSceneToDisplay": "sceneKey1"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "CORONAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel": {
+ "color": "#90ee90"
+ }
+ }
+ }
+ },
+ "widgets": {
+ "smoothingAllTool": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false,
+ "properties": {
+ "scope": {
+ "defaultValue": "PRIMARY_IMAGE"
+ }
+ }
+ },
+ "casesControl": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "labelmapLUT": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ },
+ "brushTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "radius": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ },
+ "contour": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": true
+ },
+ "shape": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": "square"
+ }
+ }
+ },
+ "eraserTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "radius": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ },
+ "contour": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": true
+ },
+ "shape": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": "square"
+ }
+ }
+ },
+ "fillingTool":{
+ "controlVisible": true,
+ "controlEnabled": true
+ },
+ "customCursorTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "type": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": "crosshair"
+ },
+ "diameter": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 3
+ }
+ }
+ },
+ "inversionTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "valueToInvert": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "labelmapUndoRedoTool": {
+ "controlVisible": true,
+ "controlEnabled": true
+ },
+ "pinTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "markerSize": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": 2
+ },
+ "fontSize": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": 12
+ },
+ "clearAll": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "subAnnotationsAvailable": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "centering": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": true
+ },
+ "activeColor": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": "#ff0000"
+ },
+ "normalColor": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": "#0000ff"
+ },
+ "activeProjectionColor": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": "#ffa500"
+ },
+ "normalProjectionColor": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": "#ffff00"
+ }
+ },
+ "constraints": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": {
+ "criterion_key1": {
+ "controlElement": "viewer",
+ "property": "sliceNumber",
+ "operator": "==="
+ },
+ "criterion_key2": {
+ "controlElement": "viewer",
+ "property": "sceneKey1",
+ "operator": "==="
+ }
+ }
+ }
+ },
+ "pointerTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "mode": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": "onClick"
+ }
+ }
+ },
+ "projectionTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "range": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "fiducialTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "type": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": "circle"
+ },
+ "diameter": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": 5
+ },
+ "rotation": {
+ "controlVisible": false,
+ "controlEnabled": true,
+ "defaultValue": 0
+ },
+ "adjustableZoom": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 4
+ }
+ }
+ },
+ "crossHairTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "labelmapOpacity":{
+ "controlVisible":true,
+ "controlEnabled":true,
+ "defaultValue":1
+ },
+ "importAnnotationsFromDiskTool": {
+ "controlVisible":true,
+ "controlEnabled":true
+ },
+ "exportAnnotationsToServerTool": {
+ "controlVisible":true,
+ "controlEnabled":true
+ },
+ "exportAnnotationsToDiskTool": {
+ "controlVisible":true,
+ "controlEnabled":true
+ },
+ "spawnViewersWindowTool": {
+ "controlVisible":true,
+ "controlEnabled":true
+ },
+ "infoTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "showIntensity": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": true
+ },
+ "showWL": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": true
+ },
+ "showPosition": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": true
+ }
+ }
+ },
+ "levelTracingTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "levelFunction": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue":"DARKER"
+ },
+ "levelFunctionMargin": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue":25
+ },
+ "lineWidth": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue":0.1
+ }
+ }
+ },
+ "annotationTableTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "fullTable": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "editableROI": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "subAnnotationColumn": {
+ "controlVisible": true,
+ "controlEnabled": false
+ }
+ }
+ },
+ "hideLabelmapsTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "description": "This is optional setting for hiding segmentations functionality(key shortcut always on and optional button)."
+ },
+ "hideContoursTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "description": "This is optional setting for hiding contours functionality(key shortcut always on and optional button)."
+ }
+ }
+ }
+ },
+ "currentMaterializedTask": {
+ "label": "training-9c39728c-8ce8-419e-886d-8138ba68e96e",
+ "inputs": {
+ "inputImage_key": {
+ "value": "75c919ef4923cd7eef878de2930001c3",
+ "label": "T1",
+ "format": "nii.gz"
+ },
+ "inputImage_key2": {
+ "value": "575bddd50492d394fe3e506e21134850",
+ "label": "Flair",
+ "format": "nii.gz"
+ },
+ "inputImage_key3": {
+ "value": "cfc61966aa88162e1451a66ac6002491",
+ "format": "nii.gz"
+ },
+ "inputImage_key4": {
+ "value": "cfc61966aa88162e1451a66ac6003b55",
+ "format": "nii.gz"
+ },
+ "inputImage_key5": {
+ "value": "07adbebb4a07e7a707de2e339800dcba",
+ "format": "nii.gz"
+ },
+ "inputAnnotationTableDefinition_key1": {
+ "value": "7e0c58ae948decbb445f6c495e0042b6"
+ },
+ "inputAnnotationFormDefinition_key1": {
+ "value": "b7fc97eb044d96113b87f38b2d000d93"
+ },
+ "inputROIDataList_key1": {
+ "value": [
+ "75c919ef4923cd7eef878de293001652",
+ "75c919ef4923cd7eef878de293002c70",
+ "75c919ef4923cd7eef878de2930038e0"
+ ]
+ },
+ "inputLut_key1": {
+ "value": "c63c3c687bfeab4782a90290e1000260"
+ },
+ "inputLut_key2": {
+ "value": "c63c3c687bfeab4782a90290e1001206"
+ },
+ "inputLut_key3": {
+ "value": "c63c3c687bfeab4782a90290e1002fa9"
+ },
+ "inputLutDescription_key1": {
+ "value": "c63c3c687bfeab4782a90290e1003c40"
+ },
+ "inputLutDescription_key2": {
+ "value": "c63c3c687bfeab4782a90290e10050ed"
+ },
+ "inputLutDescription_key3": {
+ "value": "c63c3c687bfeab4782a90290e1007642"
+ }
+ },
+ "status": "TODO",
+ "assignedTo": "amarciniak@bwh.harvard.edu",
+ "dueDate": "2019-09-28T22:43:29.728Z",
+ "miniWorkflow": "mw1",
+ "uuid": "06bf3451e2d63c3bf86b439838081dc7"
+ },
+ "currentHelpPanel": {
+ "_main": {
+ "goalAndDefinition": "Goals:
- determine the location(s) of all leptomeningeal enhancements,
- if you believe the lesion crosses two brain locations, you may choose more than one location option.
- if you are unsure about a lesion’s location, you will be able to indicate this in the uncertainties column.
Definitions:
Leptomeningeal enhancements can be seen in the following locations:
BRAIN:
- Cerebrum: Lesion located within 2mm of the cerebral cortex. The lesion should involve a cerebral sulcus to ensure that it is leptomeningeal, rather than dural-based.
- Cerebellum: Lesion located within 2mm of the cerebellar cortex (along cerebellar folia).
- Brainstem: Lesion along the surface of the brainstem, within 2mm of the brainstem parenchyma.·
- Ventricle: Lesion located within the ventricular system (lateral ventricles, third ventricle, or fourth ventricle) or along the lining of a ventricle. A ventricular lesion may grow into the periventricular space, however the inner-most edge of the lesion should be less than 2mm from the ventricular border.
- Cranial nerves: Lesion surrounding a cranial nerve.
SPINE:
- Cervical spine: Intradural extramedullary lesion located in the spinal cord between the superior end plate of C1 and the superior end plate of T1.
- Thoracic spine: Intradural extramedullary lesion located in the spinal cord between the superior end plate of T1 to the superior end plate of L1.
- Lumbar spine: Lumbar spine will encompass the lumbosacral spine and will include remainder of the spinal cord extending below the superior end plate of L1. This will include intradural extramedullary lesions of the lower lumbar spinal cord/conus medullaris and cauda equina
",
+ "tools": "
= Triangulate a focal area in all three projections
= Project annotations to adjacent slices
Neighborhood of projection = Number of adjacent slices onto which the annotations are projected
= Display a 3D crosshair showing the position of the slices currently shown in all 3 viewer windows
",
+ "combos": "
= Move between slices
= Move forward between annotations
= Move backward between annotations
= Window image
= Move image
= Zoom in/out
",
+ "annotations": "
= Edit a cell
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=0kl5sOz7PEs&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": [
+ {
+ "name": "Cerebrum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1EBsmK1qg-y2kU7mnrqi05E6g_T9u9bzr",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebellum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1kg1Y2gSJAKYLa9h9V01QcZtK4_5PVAfZ",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebellum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1C9CjjAGy8L0utDhJFjz182-awGC1QTw_",
+ "_$visited": true
+ },
+ {
+ "name": "Brainstem Midbrain",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=18Ksu2i4SoVUvjxqD40jEA3s7qvy1bfoY",
+ "_$visited": true
+ },
+ {
+ "name": "Brainstem Pons",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1-T07qu0PvZb7Nov0KPA772MdXSan4lzD",
+ "_$visited": true
+ },
+ {
+ "name": "Brainstem Medulla",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=172ZmQT05Wf6vBzOPlvadrAqhKN3J1uks",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1Kvg0CNL0LVY1ISDOlBGAGRwnbcgD7jBX",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=175gTnmem0gvNgSyP8YJQhpv-nmaAQqh1",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=158tgwe7O1q_okBRIYa_7BHSBx_YFsEA9",
+ "_$visited": true
+ },
+ {
+ "name": "Cranial Nerve III",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=17CE85JuNWTwwaJWrkHp7_fK_GXTmV0ew",
+ "_$visited": true
+ },
+ {
+ "name": "Cranial Nerve V",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1kDjxWSCA9CuMXcwuRTXGiRa8hRMvMQ8I",
+ "_$visited": true
+ },
+ {
+ "name": "Cranial Nerve VII-VIII",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1AMHAgyBSGeyRY9ESIC-8ThH_-qh1uk0N",
+ "_$visited": true
+ },
+ {
+ "name": "Lesion involving the 4th ventricle and cerebellum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1tbVv0ZmjsJM7Nlg-FI1UgTfqIzZBcsEi",
+ "_$visited": true
+ },
+ {
+ "name": "Cervical Spine",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1DuiZVwVEQWHd2uA9UkgkFj1rR6XCv3eW",
+ "_$visited": true
+ },
+ {
+ "name": "Thoracic Spine",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1XJDi9W-huc-NQsW7gwHdSdzhNFFpgCAB"
+ },
+ {
+ "name": "Lumbar Spine (Sagittal View)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1hpw9nZbxzG_ri8DxjCre3TUkOiHxuCVv",
+ "_$visited": true
+ },
+ {
+ "name": "Lumbar Spine (Axial View through the Cauda Equina)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1ILgs4FlonrFNZ15OFmG3Z7AFo527_8r9",
+ "_$visited": true
+ }
+ ]
+ },
+ "Location": {
+ "goalAndDefinition": "Goals:
- determine the location(s) of all leptomeningeal enhancements,
- if you believe the lesion crosses two brain locations, you may choose more than one location option.
- if you are unsure about a lesion’s location, you will be able to indicate this in the uncertainties column.
Definitions:
Leptomeningeal enhancements can be seen in the following locations:
BRAIN:
- Cerebrum: Lesion located within 2mm of the cerebral cortex. The lesion should involve a cerebral sulcus to ensure that it is leptomeningeal, rather than dural-based.
- Cerebellum: Lesion located within 2mm of the cerebellar cortex (along cerebellar folia).
- Brainstem: Lesion along the surface of the brainstem, within 2mm of the brainstem parenchyma.·
- Ventricle: Lesion located within the ventricular system (lateral ventricles, third ventricle, or fourth ventricle) or along the lining of a ventricle. A ventricular lesion may grow into the periventricular space, however the inner-most edge of the lesion should be less than 2mm from the ventricular border.
- Cranial nerves: Lesion surrounding a cranial nerve.
SPINE:
- Cervical spine: Intradural extramedullary lesion located in the spinal cord between the superior end plate of C1 and the superior end plate of T1.
- Thoracic spine: Intradural extramedullary lesion located in the spinal cord between the superior end plate of T1 to the superior end plate of L1.
- Lumbar spine: Lumbar spine will encompass the lumbosacral spine and will include remainder of the spinal cord extending below the superior end plate of L1. This will include intradural extramedullary lesions of the lower lumbar spinal cord/conus medullaris and cauda equina
",
+ "tools": "
= Triangulate a focal area in all three projections
= Project annotations to adjacent slices
Neighborhood of projection = Number of adjacent slices onto which the annotations are projected
= Display a 3D crosshair showing the position of the slices currently shown in all 3 viewer windows
",
+ "combos": "
= Move between slices
= Move forward between annotations
= Move backward between annotations
= Window image
= Move image
= Zoom in/out
",
+ "annotations": "
= Edit a cell
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=0kl5sOz7PEs&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": [
+ {
+ "name": "Cerebrum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1EBsmK1qg-y2kU7mnrqi05E6g_T9u9bzr",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebellum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1kg1Y2gSJAKYLa9h9V01QcZtK4_5PVAfZ",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebellum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1C9CjjAGy8L0utDhJFjz182-awGC1QTw_",
+ "_$visited": true
+ },
+ {
+ "name": "Brainstem Midbrain",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=18Ksu2i4SoVUvjxqD40jEA3s7qvy1bfoY",
+ "_$visited": true
+ },
+ {
+ "name": "Brainstem Pons",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1-T07qu0PvZb7Nov0KPA772MdXSan4lzD",
+ "_$visited": true
+ },
+ {
+ "name": "Brainstem Medulla",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=172ZmQT05Wf6vBzOPlvadrAqhKN3J1uks",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1Kvg0CNL0LVY1ISDOlBGAGRwnbcgD7jBX",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=175gTnmem0gvNgSyP8YJQhpv-nmaAQqh1",
+ "_$visited": true
+ },
+ {
+ "name": "Ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=158tgwe7O1q_okBRIYa_7BHSBx_YFsEA9",
+ "_$visited": true
+ },
+ {
+ "name": "Cranial Nerve III",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=17CE85JuNWTwwaJWrkHp7_fK_GXTmV0ew",
+ "_$visited": true
+ },
+ {
+ "name": "Cranial Nerve V",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1kDjxWSCA9CuMXcwuRTXGiRa8hRMvMQ8I",
+ "_$visited": true
+ },
+ {
+ "name": "Cranial Nerve VII-VIII",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1AMHAgyBSGeyRY9ESIC-8ThH_-qh1uk0N",
+ "_$visited": true
+ },
+ {
+ "name": "Lesion involving the 4th ventricle and cerebellum",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1tbVv0ZmjsJM7Nlg-FI1UgTfqIzZBcsEi",
+ "_$visited": true
+ },
+ {
+ "name": "Cervical Spine",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1DuiZVwVEQWHd2uA9UkgkFj1rR6XCv3eW",
+ "_$visited": true
+ },
+ {
+ "name": "Thoracic Spine",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1XJDi9W-huc-NQsW7gwHdSdzhNFFpgCAB"
+ },
+ {
+ "name": "Lumbar Spine (Sagittal View)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1hpw9nZbxzG_ri8DxjCre3TUkOiHxuCVv",
+ "_$visited": true
+ },
+ {
+ "name": "Lumbar Spine (Axial View through the Cauda Equina)",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1ILgs4FlonrFNZ15OFmG3Z7AFo527_8r9",
+ "_$visited": true
+ }
+ ]
+ },
+ "Comments": {
+ "goalAndDefinition": "Instructions:
- please enter any comments you may have separately for each leptomeningeal metastasis
",
+ "tools": "",
+ "combos": "",
+ "annotations": "
= Edit a cell
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=V3dcGsSfx-E&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": []
+ },
+ "Is hydrocephalus present?": {
+ "goalAndDefinition": "Instructions:
1. Record measurements that will be used to calculate the Evan’s Index (a quantitative tool to assess for ventriculomegaly).
2. Indicate whether there is qualitative hydrocephalus.
Definitions:
1. Evan’s index measurements:

Scroll through the axial images until you find the largest width of the frontal horns. Measure the largest frontal horn width in a plane that is perpendicular to midline (between the cerebral hemispheres). On the same axial slice, measure the largest left to right internal skull diameter (inner bone edge to inner bone edge). This measurement should also be perpendicular to midline. Enter these measurements into
2. Hydrocephalus: Subjective enlargement of the ventricles without proportional widening of the cortical sulci. Periventricular edema may be seen, but is not required.
",
+ "tools": "
= Triangulate a focal area in all three projections
= Display a 3D crosshair showing the position of the slices currently shown in all 3 viewer windows
",
+ "combos": "
= Move between slices
= Window image
= Move image
= Zoom in/out
",
+ "annotations": "
= Click on “yes” or “no” button
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=mQB0-yzc60Q&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": [
+ {
+ "name": "Measurements for Evan’s Index",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=15bQgKjgVAjkXOupWeBPRbqqfjmmiVHIU",
+ "_$visited": true
+ },
+ {
+ "name": "Measurements for Evan’s Index",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1f1j7YqQpCAIhqbHSGOh2oOrUOobt48ZC",
+ "_$visited": true
+ },
+ {
+ "name": "Normal Ventricles",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1GpBcu4pAPk_wZTaszGpetrh5QwecMtIB",
+ "_$visited": true
+ },
+ {
+ "name": "Normal Ventricles",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1_Qy8vIMyJ4g_JDRdJZjECqMjXY_x8tbk",
+ "_$visited": true
+ },
+ {
+ "name": "Normal Ventrices",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1cy5IpurgfJAym_Lj4T-Wdsduo7Dr184a",
+ "_$visited": true
+ },
+ {
+ "name": "Unclear",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1lUqAO4xMrS_GC7w7nZ2iOvdnIR_VIF7-"
+ },
+ {
+ "name": "Unclear",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1GOIiS3c_7PiTMbB8qAIdmuvPAxZ8Czk1",
+ "_$visited": true
+ },
+ {
+ "name": "Hydrocephalus. Two axial slices from single brain MRI demonstrates enlarged ventricles (particularly in left temporal horn). There is periventricular edema which increases sensitivity",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=18O6s2mZW6cGdzaLU9tQHKneLQD-1a2Ie"
+ },
+ {
+ "name": "Hydrocephalus. Two axial slices from single brain MRI demonstrates enlarged ventricles (particularly in left temporal horn). There is periventricular edema which increases sensitivity",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1xxsIeIfdLWXIMuapXx_RCWrP2IlJiwFv"
+ }
+ ]
+ },
+ "Shape": {
+ "goalAndDefinition": "Goals:
- determine the shape (i.e., nodular versus linear/curvilinear) of all leptomeningeal enhancements.
- if a lesion has both nodular and linear components, select both.
Definitions:
- Nodular enhancement: mass with rounded or convex polygonal contour.
- a mass must have at least partially convex borders in three dimensions.
- can be seen in the subarachnoid space, ventricles, periventricular areas and around the spinal cord
- Linear enhancement: arranged along a straight or close-to-straight line
- in three dimensions, a linear lesion is often “sheet-like”
- can have a 2-D rounded/polygonal shape, but lacks convex borders in three dimensions.
- can be seen in cranial and spinal nerve roots, cerebellar folia, ventricles, cerebral sulci and around the spinal cord
",
+ "tools": "
= Triangulate a focal area in all three projections
= Project annotations to adjacent slices
Neighborhood of projection = Number of adjacent slices onto which the annotations are projected
= Display a 3D crosshair showing the position of the slices currently shown in all 3 viewer windows
",
+ "combos": "
= Move between slices
= Move forward between annotations
= Move backward between annotations
= Window image
= Move image
= Zoom in/out
",
+ "annotations": "
= Edit a cell
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=TClBtDEbQB4&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": [
+ {
+ "name": "Nodular enhancement in the subarachnoid space",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1lIPL9fXMkAQ-3jvnhQnB8UhZXarfUTL_",
+ "_$visited": true
+ },
+ {
+ "name": "Nodular enhancement in the fourth ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1lfnizK6wi5O72p5wGvpfoXMe9JqaXHaj",
+ "_$visited": true
+ },
+ {
+ "name": "Nodular enhancement in a periventricular area",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1tDI_RQco7TRa0Zbv-EPS5Qy6IWK8nqr_",
+ "_$visited": true
+ },
+ {
+ "name": "Nodular enhancement around the spinal cord",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=15KbCI-NUASoy-daAB_VP-f0w4OvkGAAa",
+ "_$visited": true
+ },
+ {
+ "name": "Linear/curvilinear enhancement in a cranial nerve root",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1-FTsHGD2AmHKMrif-Jb5xmVQ2RdnzYmT",
+ "_$visited": true
+ },
+ {
+ "name": "Linear/curvilinear enhancement along the cerebellar folia",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1IkG9InZ5xT4DqBtjd4CbZGddjY8BpBKD",
+ "_$visited": true
+ },
+ {
+ "name": "Linear “sheet-like” lesion, wrapping around the spinal cord",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1tDI_RQco7TRa0Zbv-EPS5Qy6IWK8nqr_",
+ "_$visited": true
+ },
+ {
+ "name": "Linear/curvilinear and nodular enhancement along the lining of a ventricle",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1MyX_mpEANpiOgzn9T82BFEMtWdHFitgX",
+ "_$visited": true
+ },
+ {
+ "name": "Linear/curvilinear enhancement along a cerebral sulcus",
+ "link": "",
+ "src": "https://drive.google.com/uc?export=download&id=1mrIu7sk3L5g-S_2LPAZfpA4mbpE0iiKD"
+ }
+ ]
+ },
+ "Size is > 5x5mm": {
+ "goalAndDefinition": "Goals:
- determine the size of all leptomeningeal enhancements using the fiducial tool

- if an enhancement has both nodular and linear components, determine size based on the nodular component.
- for a focal lesion with an irregular border, measure the largest sub-component without crossing normal tissue.
Definitions:
- note that the diameter of the red fiducial circle is 5 mm.
- if the diameter of an enhancement is greater than 5 mm in the two greatest perpendicular diameters in any 2D plane, please select “yes” under the “Size” column of the annotation table.
- if the diameter of an enhancement is equal to or smaller than 5 mm in the two greatest perpendicular diameters in any 2D plane, please select “no” under the “Size” column of the annotation table
",
+ "tools": "
= Turn on/off fiducial tool
= Triangulate a focal area in all three projections
= Project annotations to adjacent slices
Neighborhood of projection = Number of adjacent slices onto which the annotations are projected
= Display a 3D crosshair showing the position of the slices currently shown in all 3 viewer windows
",
+ "combos": "
= Move between slices
= Move forward between annotations
= Move backward between annotations
= Window image
= Move image
= Zoom in/out
",
+ "annotations": "
= Edit a cell
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=dqDNTr2ACcw&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": [
+ {
+ "name": "Lesion with size > 5 mm in bi-diameter ",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1-SM18L11DD4ON-Wk19jailg4wQ2BwTfl",
+ "_$visited": true
+ },
+ {
+ "name": "Lesion with irregular border",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1VM1Aqidordd0XRWZKkVsNgc5nbZhvhey",
+ "_$visited": true
+ }
+ ]
+ },
+ "Spatial extension": {
+ "goalAndDefinition": "Goals:
- Determine the spatial extension (i.e., focal or diffuse) of all leptomeningeal enhancements.
- If a lesion has both a focal and diffuse component, label this lesion as diffuse. The more focal component may be measurable (>5x5 mm) even though the lesion is diffuse.
Definitions:
- Focal enhancement: circumscribed area of enhancement with sharp boundaries. The lesion can be measured in two dimensions (one plane) without crossing normal brain.
- Diffuse enhancement: diffuse enhancement will encompass lesions with any of the following characteristics:
- A lesion without well-defined boundaries
- A lesion is spatially spread out such that it cannot be measured in two dimensions (one plane) without crossing normal brain parenchyma.
",
+ "tools": "
= Triangulate a focal area in all three projections
= Project annotations to adjacent slices
Neighborhood of projection = Number of adjacent slices onto which the annotations are projected
Display a 3D crosshair showing the position of the slices currently shown in all 3 viewer windows
",
+ "combos": "
= Move between slices
= Move forward between annotatio
= Move backward between annotations
= Window image
= Move image
= Zoom in/out
= Delete annotation
",
+ "annotations": "
= Edit a cell
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=Nta2Xg-KT_k&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": [
+ {
+ "name": "Cerebellar focal enhancement",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1SWzP5BbkuydkTCqRhnsvDhXe31OVt0tc",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebellar focal enhancement ",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1Hsfi0zwxmC02FYImylWTpqjogxI6Bicv",
+ "_$visited": true
+ },
+ {
+ "name": "Cerebellar diffuse enhancement",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1b2iA6sK__mD9BZ2XlNL3Es7swWqOY379",
+ "_$visited": true
+ },
+ {
+ "name": "Focal",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1Sw15RAeSdoemxpBPN8q1XeXsJk_YSpWZ",
+ "_$visited": true
+ },
+ {
+ "name": "Focal",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1g6GPjslmnc345WfjG0rCaOdxW1BgiODp",
+ "_$visited": true
+ },
+ {
+ "name": "Diffuse",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1doy-Bh7V_N_9B4a9tvD8VVxRjXiOsCBS",
+ "_$visited": true
+ },
+ {
+ "name": "Diffuse",
+ "link": "",
+ "src": " https://drive.google.com/uc?export=download&id=1JZMUW7C5uzaS8Wjp11zgrx4zZNBvL02A"
+ }
+ ]
+ },
+ "Uncertainties": {
+ "goalAndDefinition": "Instructions:
- please indicate if you are not certain regarding the location, size, shape, and/or spatial extension of a leptomeningeal enhancement
",
+ "tools": "",
+ "combos": "",
+ "annotations": "
= Edit a cell
",
+ "videos": {
+ "goalAndDefinition": "https://www.youtube.com/watch?v=rOJdY34UFUs&feature=youtu.be",
+ "tools": "https://www.youtube.com/watch?v=LcZ31mRQ7bg&feature=youtu.be"
+ },
+ "images": []
+ }
+ },
+ "status": "notstarted"
+ },
+ "listOfCases": [
+ {
+ "caseNumber": "NMO1",
+ "caseStatus": "notstarted"
+ },
+ {
+ "caseNumber": "NMO2",
+ "caseStatus": "notstarted",
+ "caseCurrentStep": 0
+ },
+ {
+ "caseNumber": "NMO3",
+ "caseStatus": "started",
+ "caseCurrentStep": 1
+ },
+ {
+ "caseNumber": "NMO4",
+ "caseStatus": "done"
+ },
+ {
+ "caseNumber": "NMO4",
+ "caseStatus": "done"
+ }
+ ],
+ "currentCase": "NMO1"
+}
\ No newline at end of file
diff --git a/examples/viewer/full.example.json b/examples/viewer/full.example.json
new file mode 100644
index 0000000..849bc49
--- /dev/null
+++ b/examples/viewer/full.example.json
@@ -0,0 +1,83 @@
+{
+ "name": "Sagittal viewer",
+ "type": "2D",
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "AXIAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayImages": {
+ "possibleImagesToDisplay": [
+ "inputImage_key2"
+ ],
+ "hasDefaultImageToDisplay": true,
+ "defaultImageToDisplay": "inputImage_key2"
+ },
+ "displayLabelMaps": {
+ "possibleImagesToDisplay": [
+ "inputImage_key2"
+ ],
+ "hasDefaultLabelMapToDisplay": true,
+ "defaultImageToDisplay": "inputImage_key2"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ }
+ ]
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ },
+ "linked": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#90ee90",
+ "hasRim": true,
+ "hasControlPanel":false
+ },
+ "interactions": {
+ "activeViewer": {
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "crossHairTool": {
+ "controlEnabled": true,
+ "defaultValue": {
+ "viewers": {
+ "middle": {
+ "color": "#00FF00"
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/viewer/leptostep1middle.example.json b/examples/viewer/leptostep1middle.example.json
new file mode 100644
index 0000000..5e6e2be
--- /dev/null
+++ b/examples/viewer/leptostep1middle.example.json
@@ -0,0 +1,56 @@
+{
+ "name": "Middle viewer",
+ "type": "2D",
+ "linkedControlVisible": false,
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "AXIAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "SUPERIORMOST"
+ },
+ "initialWindowLevel": {
+ "strategy": "dynamic",
+ "value": "MIDDLE-FULL"
+ }
+ },
+ "displayImages": {
+ "possibleImagesToDisplay": [
+ "inputImage_key"
+ ],
+ "hasDefaultImageToDisplay": true,
+ "defaultImageToDisplay": "inputImage_key"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Sagittal",
+ "value": "SAGITTAL"
+ },
+ {
+ "label": "Coronal",
+ "value": "CORONAL"
+ },
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel":{
+ "color":"#fff967"
+ }
+}
\ No newline at end of file
diff --git a/examples/viewer/viewer.example.json b/examples/viewer/viewer.example.json
new file mode 100644
index 0000000..71dd956
--- /dev/null
+++ b/examples/viewer/viewer.example.json
@@ -0,0 +1,54 @@
+{
+ "name": "Sagittal viewer",
+ "type": "2D",
+ "initialState": {
+ "orientationAndSliceNumber": {
+ "orientation": "AXIAL",
+ "strategy": "DYNAMIC",
+ "dynamicSliceValue": "MIDDLE"
+ },
+ "initialWindowLevel": {
+ "strategy": "DYNAMIC",
+ "dynamicStrategy": "FULLWINDOW_MIDDLELEVEL"
+ }
+ },
+ "displayImages": {
+ "possibleImagesToDisplay": [
+ "inputImage_key2"
+ ],
+ "hasDefaultImageToDisplay": true,
+ "defaultImageToDisplay": "inputImage_key2"
+ },
+ "displayControls": {
+ "orientation": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "options": [
+ {
+ "label": "Axial",
+ "value": "AXIAL"
+ }
+ ],
+ "defaultValue": "AXIAL"
+ },
+ "smoothing": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "sequence": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ },
+ "lookAndFeel": {
+ "color": "#ff0000",
+ "hasControlPanel": false
+ },
+ "interactions": {
+ "activeViewer": {
+ "controlEnabled": false,
+ "defaultValue": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/widgets/full.example.json b/examples/widgets/full.example.json
new file mode 100644
index 0000000..9262a74
--- /dev/null
+++ b/examples/widgets/full.example.json
@@ -0,0 +1,377 @@
+{
+ "pinTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "markerSize": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 2
+ },
+ "fontSize":{
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 12
+ },
+ "clearAll":{
+ "controlVisible": true,
+ "controlEnabled": true
+ },
+ "subAnnotationsAvailable":{
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ },
+ "centering": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": true
+ },
+ "selectionOnly": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "constraints":{
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": {
+ "criterion_key1": {"controlElement":"viewer","property":"sliceNumber","operator": "==="},
+ "criterion_key2": {"controlElement":"viewer","property":"imageId","operator": "==="}
+ }
+ }
+ }
+ },
+ "projectionTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "range": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ },
+ "rangeForKey": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": 5
+ }
+ }
+ },
+ "customCursorTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "type": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": "whiskers"
+ },
+ "diameter": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 3
+ }
+ }
+ },
+ "pointerTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "mode": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": "onClick"
+ }
+ }
+ },
+ "crossHairTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "brushTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "size": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "fillingTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "eraserTool":{
+ "controlVisible":true,
+ "controlEnabled":true,
+ "properties":{
+ "size":{
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "labelmapUndoRedoTool": {
+ "controlVisible": true,
+ "controlEnabled": true
+ },
+ "labelmapOpacity": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ },
+ "annotationOpacity": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": 1
+ },
+ "annotationTableTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "fullTable": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "editableROI": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": true
+ },
+ "subAnnotationColumn":{
+ "controlVisible": true,
+ "controlEnabled": false
+ },
+ "csvExport": {
+ "controlVisible": false,
+ "controlEnabled": false
+ }
+ }
+ },
+ "echoTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "linkAllTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "smoothingAllTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "fiducialTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "type": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": "circle"
+ },
+ "diameter": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": 5
+ },
+ "rotation": {
+ "controlVisible": false,
+ "controlEnabled": true,
+ "defaultValue": 0
+ },
+ "adjustableZoom": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 4
+ }
+ }
+ },
+ "pinUndoRedoTool":{
+ "controlVisible":true,
+ "controlEnabled":true
+ },
+ "labelmapLUT": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": 1,
+ "properties": {
+ "options": [
+ {
+ "value": 1,
+ "label": "Lesion",
+ "color": "#f00",
+ "iri": "http://moj.kod"
+ },
+ {
+ "value": 2,
+ "label": "Plaque",
+ "color": "#0f0909"
+ },
+ {
+ "value": 3,
+ "label": "Toxin",
+ "color": "#00f"
+ },
+ {
+ "value": 4,
+ "label": "Tumor",
+ "color": "#f8f"
+ },
+ {
+ "value": 5,
+ "label": "Aging",
+ "color": "#8ff"
+ }
+ ]
+ }
+ },
+ "windowLevelAllTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "samplerTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "interactions": {
+ "controlVisible":false,
+ "controlEnabled":false,
+ "defaultValue": {
+ "intensityFilterTool": {
+ "type": "widget",
+ "tool": "intensityFilterTool",
+ "property": "maxValue",
+ "value": "midPoint"
+ }
+ }
+ },
+ "histogram": {
+ "controlVisible":false,
+ "controlEnabled":false,
+ "defaultValue": true
+ },
+ "onComplete": {
+ "controlVisible":false,
+ "controlEnabled":false,
+ "defaultValue": "SHOW_HISTOGRAM"
+ },
+ "bucketing": {
+ "controlVisible":false,
+ "controlEnabled":false,
+ "defaultValue": "FREEDMAN-DIACONIS"
+ }
+ }
+ },
+ "intensityFilterTool": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": true,
+ "properties": {
+ "minValue": {
+ "controlVisible": false,
+ "controlEnabled": true,
+ "defaultValue": 0
+ },
+ "maxValue": {
+ "controlVisible": false,
+ "controlEnabled": true,
+ "defaultValue": 4294967295
+ },
+ "showMask": {
+ "controlVisible": false,
+ "controlEnabled": true,
+ "defaultValue": 0
+ },
+ "clear": {
+ "controlVisible": false,
+ "controlEnabled": true
+ }
+ }
+ },
+ "hideContoursTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "description": "This is optional setting for hiding contours functionality(key shortcut always on and optional button)."
+ },
+ "hideLabelmapsTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "description": "This is optional setting for hiding segmentations functionality(key shortcut always on and optional button)."
+ },
+ "levelTracingTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "levelFunction": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue":"DARKER"
+ },
+ "levelFunctionMargin": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue":25
+ },
+ "lineWidth": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue":0.1
+ }
+ }
+ },
+ "infoTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "showIntensity": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": true
+ },
+ "showWL": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": true
+ },
+ "showPosition": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": true
+ }
+ }
+ },
+ "spawnViewersWindowTool": {
+ "controlVisible":true,
+ "controlEnabled":true
+ },
+ "exportAnnotationsToServerTool": {
+ "controlVisible":true,
+ "controlEnabled":true
+ },
+ "exportAnnotationsToDiskTool": {
+ "controlVisible":true,
+ "controlEnabled":true
+ },
+ "importAnnotationsFromDiskTool": {
+ "controlVisible":true,
+ "controlEnabled":true
+ }
+}
\ No newline at end of file
diff --git a/examples/widgets/leptostep1.example.json b/examples/widgets/leptostep1.example.json
new file mode 100644
index 0000000..8aaac82
--- /dev/null
+++ b/examples/widgets/leptostep1.example.json
@@ -0,0 +1,62 @@
+{
+ "pinTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "properties": {
+ "markerSize": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 2
+ },
+ "fontSize":{
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 12
+ },
+ "clearAll":{
+ "controlVisible": true,
+ "controlEnabled": true
+ }
+ }
+ },
+ "projectionTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "range": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": 1
+ }
+ }
+ },
+ "pointerTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false,
+ "properties": {
+ "mode": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": "onClick"
+ }
+ }
+ },
+ "crossHairTool": {
+ "controlVisible": true,
+ "controlEnabled": true,
+ "defaultValue": false
+ },
+ "annotationTableTool": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "properties": {
+ "fullTable": {
+ "controlVisible": false,
+ "controlEnabled": false,
+ "defaultValue": false
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/widgets/mutation.example.json b/examples/widgets/mutation.example.json
new file mode 100644
index 0000000..8e86b19
--- /dev/null
+++ b/examples/widgets/mutation.example.json
@@ -0,0 +1,13 @@
+{
+ "pinTool": {
+ "controlVisible": true,
+ "controlEnable": true,
+ "properties": {
+ "markerSize": {
+ "controlVisible": "true",
+ "controlEnabled": true,
+ "defaultValue": "4"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index f15549c..2ca7264 100644
--- a/package.json
+++ b/package.json
@@ -2,10 +2,37 @@
"name": "SPINE-json-schema",
"author": "Alfredo Morales Pinzon",
"license": "MIT",
- "keywords": ["SPINE", "schema", "model", "json", "Image Processing", "pipelines", "workflow"],
+ "keywords": [
+ "SPINE",
+ "schema",
+ "model",
+ "json",
+ "Image Processing",
+ "pipelines",
+ "workflow"
+ ],
"description": "Set of JSON schemas for the SPINE Virtual Laboratory",
- "version": "1.0.0",
+ "version": "2.5.0",
"dependencies": {
-
+ "ajv": "^6.12.2"
+ },
+ "devDependencies": {
+ "ajv-istanbul": "^0.1.0",
+ "jest": "^26.0.1"
+ },
+ "scripts": {
+ "test": "jest"
+ },
+ "jest": {
+ "collectCoverage": true,
+ "coverageReporters": [
+ "html"
+ ],
+ "globals": {
+ "ajv": null
+ },
+ "setupFilesAfterEnv": [
+ "/tests/setupTests.js"
+ ]
}
}
diff --git a/schemas/annotation.schema.json b/schemas/annotation.schema.json
index 9f25d1c..9289195 100644
--- a/schemas/annotation.schema.json
+++ b/schemas/annotation.schema.json
@@ -75,7 +75,7 @@
}
},
"required": ["roiId", "workflowId", "materializedTaskId", "taskId", "questionId"],
- "additionalProperties": false
+ "additionalProperties": true
}
]
}
@@ -204,8 +204,7 @@
"annotationProperties":{
"properties": {
"value": {
- "description": "Text in the open-ended question.",
- "type": "string"
+ "description": "Text in the open-ended question."
}
},
"required": ["value"]
diff --git a/schemas/cohort.schema.json b/schemas/cohort.schema.json
new file mode 100644
index 0000000..5fa999d
--- /dev/null
+++ b/schemas/cohort.schema.json
@@ -0,0 +1,142 @@
+{
+ "$id":"https://raw.githubusercontent.com/SPINEProject/SPINE-json-schema/master/schemas/cohort.schema.json",
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Cohort schema",
+ "description": "Schema for cohort document.",
+ "$comment": "The schema can be indirectly applied to both CouchDB document and Cohort API response data, assuming that: 'uuid' property replaced '_id' and 'rev' property is removed.",
+ "type": "object",
+ "definitions": {
+ "cohortLogo": {
+ "$id" : "#cohortLogo",
+ "description": "Logo of a given cohort",
+ "type": "object",
+ "properties": {
+ "type": {
+ "description":"Type of medium to be used to display image.",
+ "$comment": "So far only one option is available: 'url', since this can be used both for links and serialized image data. In future other forms of embedding external graphics can be useful",
+ "type":"string",
+ "enum": ["url"]
+ },
+ "value": {
+ "description":"The link to logo or encoded with base64 serialized version of cohort",
+ "$comment": "The value can be an absolute link eg.https://www.miccai2021.org/files/images/layout/en/miccai2021-logo.png or encoded string with binaries, i.e. data:image/png;base64,...",
+ "type":"string"
+ },
+ "url": {
+ "description":"Link to the external Cohort home page",
+ "type":"string"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "properties": {
+ "uuid": {
+ "description": "Cohort UUID",
+ "type": "string"
+ },
+ "docType": {
+ "description": "Cohort",
+ "type": "string",
+ "enum": ["cohort"]
+ },
+ "name": {
+ "description": "Cohort name",
+ "type": "string"
+ },
+ "pi": {
+ "description": "Identifier of Principal Investigator of cohort",
+ "$comment": "Uses uuid format",
+ "type": "string"
+ },
+ "co-investigators": {
+ "description": "Identifiers of co-investigators of cohort",
+ "$comment": "Uses uuid format",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "description": {
+ "description": "Cohort description",
+ "type": "string"
+ },
+ "version": {
+ "description": "Cohort version",
+ "type": "string"
+ },
+ "creationDate":{
+ "description": "Date of creation of the cohort.",
+ "$comment": "Uses ISO 8601",
+ "type":"string"
+ },
+ "privacy": {
+ "description": "Cohort privacy",
+ "type": "string",
+ "enum": [
+ "PUBLIC",
+ "public",
+ "PRIVATE",
+ "private"
+ ]
+ },
+ "relativePath": {
+ "description": "Relative Path to cohort folder in filesystem",
+ "$comment": "This is for visualization of assets",
+ "type": "string"
+ },
+ "sourceSystem": {
+ "description": "How cohort was introduced into SPINE",
+ "type": "string",
+ "enum": ["SPINE Insertion script","manualInsertion"]
+ },
+ "logo": {
+ "$ref": "#/definitions/cohortLogo"
+ },
+ "keywords": {
+ "description": "Array of keywords defining contents of cohort",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "label": {
+ "description":"Keyword label",
+ "type": "string"
+ },
+ "iri": {
+ "description":"internationalized Resource Identifier for keyword concept",
+ "$comment":"This is an ontological identifier, that can be used as link in some cases, eg. http://purl.bioontology.org/ontology/SNOMEDCT/24700007",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "diseases": {
+ "description": "Array of disease codes for cohort",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "label": {
+ "description":"Label to be displayed along with the disease code, eg. Multiple Sclerosis",
+ "type": "string"
+ },
+ "icdCode": {
+ "description":"International Classification of Diseases Code",
+ "$comment":"This is an ICD 10 code, eg. G35 for MS",
+ "type": "string"
+ },
+ "url": {
+ "description":"Link to external page with disease classification",
+ "$comment":"This link can refer to external page with disease description, eg. https://www.icd10data.com/search?s=G36",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": ["name","privacy","uuid","pi","docType"]
+}
\ No newline at end of file
diff --git a/schemas/core.schema.json b/schemas/core.schema.json
index 32613cd..54ffcc8 100644
--- a/schemas/core.schema.json
+++ b/schemas/core.schema.json
@@ -43,8 +43,9 @@
"description": "SPINE Type",
"type": "string",
"enum": ["String","Number","imageFileInOut","imageEntityInOut",
- "auxiliaryImageFile","lookupTableInOut","roiInOut","annotationInOut",
- "roiWithAnnotationsInOut","annotationTableDefinitionInOut"]
+ "auxiliaryImageFile","lookUpTable","lookUpTableDescription","roiInOut","annotationInOut",
+ "roiWithAnnotationsInOut","annotationTableDefinitionInputOutput", "annotationFormDefinitionInputOutput",
+ "annotationTableDataInOut", "annotationFormDataInOut","polyRoiInOut"]
},
"inputOutput": {
@@ -160,6 +161,23 @@
]
},
+ "annotationFormDefinitionInOut": {
+ "$id": "#annotationFormDefinitionInOut",
+ "description": "Schema defining an annotation form definition as input output",
+ "allOf":[
+ {"$ref": "#/definitions/inputOutput_spine"},
+ {
+ "properties": {
+ "type":{
+ "type": "string",
+ "enum": ["annotationFormDefinitionInputOutput"]
+ }
+ },
+ "required": ["type"]
+ }
+ ]
+ },
+
"annotationTableDefinitionInOut": {
"$id": "#annotationTableDefinitionInOut",
"description": "Schema defining an annotation table definition as input output",
@@ -169,7 +187,7 @@
"properties": {
"type":{
"type": "string",
- "enum": ["annotationTableDefinitionInOut"]
+ "enum": ["annotationTableDefinitionInputOutput"]
}
},
"required": ["type"]
@@ -187,6 +205,12 @@
"type":{
"type": "string",
"enum": ["annotationTableDataInOut"]
+ },
+ "referenceInputKey":{
+ "type": "string"
+ },
+ "referenceAnnotationTableInputKey":{
+ "type": "string"
}
},
"required": ["type"]
@@ -194,6 +218,48 @@
]
},
+ "annotationFormDataInOut": {
+ "$id": "#annotationFormDataInOut",
+ "description": "Schema defining an annotation form data as input output",
+ "allOf":[
+ {"$ref": "#/definitions/inputOutput_spine"},
+ {
+ "properties": {
+ "type":{
+ "type": "string",
+ "enum": ["annotationFormDataInOut"]
+ },
+ "referenceInputKey":{
+ "type": "string"
+ },
+ "referenceAnnotationTableInputKey":{
+ "type": "string"
+ }
+ },
+ "required": ["type"]
+ }
+ ]
+ },
+ "polyRoiInOut": {
+ "$id": "#polyRoiInOut",
+ "description": "Schema defining a polydata as input output",
+ "allOf":[
+ {"$ref": "#/definitions/inputOutput_spine"},
+ {
+ "properties": {
+ "type":{
+ "type": "string",
+ "enum": ["polyRoiInOut"]
+ },
+ "dataEntityInOut_FileFormat":{
+ "type": "string"
+ }
+ },
+ "required": ["type"]
+ }
+ ]
+ },
+
"lookupTableInOut_FileFormat": {
"$id" : "#lookupTableInOut_Type",
"description": "File format for lookup tables",
@@ -210,13 +276,30 @@
"properties": {
"type":{
"type": "string",
- "enum": ["lookupTableInOut"]
+ "enum": ["lookUpTable"]
},
"lookupTableInOut_FileFormat": {
"$ref": "#/definitions/lookupTableInOut_FileFormat"
}
},
- "required": ["type","lookupTableInOut_FileFormat"]
+ "required": ["type"]
+ }
+ ]
+ },
+
+ "lookUpTableDescriptionInOut": {
+ "$id": "#lookUpTableDescriptionInOut",
+ "description": "Schema defining an lookup table description as input or output",
+ "allOf":[
+ {"$ref": "#/definitions/inputOutput_spine"},
+ {
+ "properties": {
+ "type":{
+ "type": "string",
+ "enum": ["lookUpTableDescription"]
+ }
+ },
+ "required": ["type"]
}
]
},
@@ -326,7 +409,7 @@
"$ref": "#/definitions/roiInOut_FileFormat"
}
},
- "required": ["type","schema","roiInOut_FileFormat"]
+ "required": ["type"]
}
]
},
@@ -399,8 +482,12 @@
{"$ref": "#/definitions/Number"},
{"$ref": "#/definitions/imageFileInOut"},
{"$ref": "#/definitions/lookupTableInOut"},
+ {"$ref": "#/definitions/lookUpTableDescriptionInOut"},
{"$ref": "#/definitions/annotationTableDefinitionInOut"},
- {"$ref": "#/definitions/annotationTableDataInOut"}
+ {"$ref": "#/definitions/annotationTableDataInOut"},
+ {"$ref": "#/definitions/annotationFormDefinitionInOut"},
+ {"$ref": "#/definitions/annotationFormDataInOut"},
+ {"$ref": "#/definitions/polyRoiInOut"}
]
}
diff --git a/schemas/experimentalPlan.schema.json b/schemas/experimentalPlan.schema.json
new file mode 100644
index 0000000..baaa346
--- /dev/null
+++ b/schemas/experimentalPlan.schema.json
@@ -0,0 +1,128 @@
+{
+ "$id":"https://raw.githubusercontent.com/SPINEProject/SPINE-json-schema/master/schemas/experimentalPlan.schema.json",
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Description of Experimental Plan ",
+ "description": "Schema for Experimental plan being a part of experiment configuration.",
+ "type": "object",
+ "definitions":{
+ "timeWindow": {
+ "$id": "#timeWindow",
+ "description": "Boolean flags defining controls for a given widget.",
+ "type": "object",
+ "$comment": "So far control components for widgets are implemented with Toggleable Buttons. Model can be extended by adding other complex controls, eg. sets of buttons, dropdown etc.",
+ "properties": {
+ "controlVisible": {
+ "type": "boolean",
+ "description": "Defines whether control component (eg. Button) is visible."
+ },
+ "controlEnabled": {
+ "type": "boolean",
+ "description": "Defines whether control component (eg. Button) is enabled, ie. can change a state. If not enabled, then works only as indicator."
+ }
+ },
+ "required": ["controlEnabled", "controlVisible"]
+ }
+ },
+ "properties": {
+ "experimentId": {
+ "type": "string",
+ "description": "Reference to the experiment id"
+ },
+ "docType": {
+ "type": "string",
+ "description": "Type of document",
+ "enum": [
+ "experimentalPlan"
+ ]
+ },
+ "questionnaires": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "description": "Reference to the questionnaire Id"
+ }
+ },
+ "eventParameters": {
+ "type": "object",
+ "description": "Properties parameterizing event handling in mobile application, eg. after clicking on 'sleep' button",
+ "properties": {
+ "tolerances": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "event": {
+ "type": "string",
+ "enum": ["wakeUpSleep","wakeUpNap"],
+ "description": "Type of event"
+ },
+ "tolerance": {
+ "type": "number"
+ },
+ "toleranceUnit": {
+ "type": "string",
+ "enum": ["days","hours","minutes"],
+ "description": "Time unit for 'toleranceUnit'"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "maxAwakeTime": {
+ "type": "string",
+ "pattern": "[0-9]{0,2}:[0-9]{2}:[0-9]{2}"
+ }
+ },
+ "additionalProperties": false
+ },
+ "planning": {
+ "type": "object",
+ "properties": {
+ "startExperiment": {
+ "type": "object",
+ "properties": {
+ "time-windows": {
+
+ }
+ }
+ },
+ "evaluationPeriod": {
+ "type": "object"
+ },
+ "endingExperiment": {
+ "type": "object",
+ "properties": {
+ "time-windows": {
+
+ },
+ "ending-criteria": {
+ "type": "string",
+ "enum": ["timeAfterExperimentStart"]
+ },
+ "timeAfterExperimentStart":{
+ "type": "number",
+ "description": "Criterion for executing questionnaires if defined in time-windows section."
+ },
+ "timeAfterExperimentStartUnit":{
+ "type": "string",
+ "description": "Time unit for 'timeAfterExperimentStartUnit'"
+ },
+ "experimentDeadlineTime":{
+ "type": "number",
+ "description": "Stop criterion for experiment. It is calculated in relation to the starting time of experiment"
+ },
+ "experimentDeadlineUnit":{
+ "type": "string",
+ "enum": ["days","hours","minutes"],
+ "description": "Time unit for 'experimentDeadlineTime'"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "required": ["experimentId", "docType","questionnaires","planning"],
+ "additionalProperties": false
+}
diff --git a/schemas/helpPanel.schema.json b/schemas/helpPanel.schema.json
new file mode 100644
index 0000000..cab5a2a
--- /dev/null
+++ b/schemas/helpPanel.schema.json
@@ -0,0 +1,8 @@
+{
+ "$id": "https://raw.githubusercontent.com/SPINEProject/SPINE-json-schema/master/schemas/helpPanel.schema.json",
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$comment": "TODO Finish me!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11",
+ "title": "Help Panel Schema",
+ "description": "Schema of help panel data TODO Finish me",
+ "type": "object"
+}
\ No newline at end of file
diff --git a/schemas/roi.schema.json b/schemas/roi.schema.json
index 18806c2..3987e72 100644
--- a/schemas/roi.schema.json
+++ b/schemas/roi.schema.json
@@ -322,5 +322,5 @@
}
},
"additionalProperties": false,
- "required": ["typeROI", "status", "reference", "properties"]
+ "required": ["typeROI", "properties"]
}
diff --git a/schemas/tool.schema.json b/schemas/tool.schema.json
index 6b9ba8a..97540d6 100644
--- a/schemas/tool.schema.json
+++ b/schemas/tool.schema.json
@@ -30,15 +30,18 @@
"toolType":{
"$id": "#toolType",
"description": "Type of tool. This defines the layout to be used. SLICE_SELECTOR_TOOL refers to a tool where a slice is selected. SEGMENTATION_TOOL refers to a tool where a segmentation is created. CONFIRMATION_TOOL refers to a tool to confirm results, the output is only true/false without need for binding to anything.",
+ "$comment": "It is deprecated property. There is no much use of it due to the fact that tool configuration is now flexible and allows to have both segmentation and annotation widgets in a single configuration.",
"type": "string",
- "enum": ["SLICE_SELECTOR_TOOL", "SEGMENTATION_TOOL", "CONFIRMATION_TOOL"]
+ "enum": ["SLICE_SELECTOR_TOOL", "SEGMENTATION_TOOL", "CONFIRMATION_TOOL", "ANNOTATION_TOOL",
+ "IDENTIFICATION_TOOL", "CHARACTERIZATION_TOOL", "SLICE_SELECTOR_PICKER_TOOL", "SLICE_SELECTOR_TOOL_RANGED",
+ "SLICE_SELECTOR_WITH_PICKER", "VISUALIZATION_TOOL"]
},
"layoutViewersType":{
"$id": "#layoutViewersType",
"description": "Type of viewers layout.",
"type": "string",
- "enum": ["SINGLE", "FOUR_IN_A_ROW", "THREE_IRREGULAR", "GRID"]
+ "enum": ["SINGLE","1M1R_IN_ROW","SINGLE_WITH_WIDGET_PANEL", "1M4R", "1M2R", "1M2R_WIDGETS","1M1R_ARROWS", "ROW"]
},
"possibleValueInAnnotationTable": {
@@ -193,7 +196,10 @@
"patternProperties": {
".*": {
"description": "Configuration of a viewer",
- "$ref": "viewer.schema.json"
+ "oneOf":[
+ {"$ref": "viewer.schema.json#/definitions/viewer2D"},
+ {"$ref": "viewer.schema.json#/definitions/viewer3D"}
+ ]
}
}
}
@@ -201,6 +207,170 @@
"required": ["layout", "renderWindows"]
},
+ "scenesConfiguration": {
+ "$id": "#scenesConfiguration",
+ "description": "Configuration of scene elements like original image, overlays (rois).",
+ "type": "object",
+ "properties": {
+ "primaryImageInputKey": {
+ "description": "The reference key to input image being used as reference image. All other images (eg. MRI, segmentations, attention maps) will use the space of original image. If overlays are of different size, they will be resampled and cut according to primary Image space (bounding box and origin).",
+ "type": "string"
+ },
+ "rois": {
+ "description": "The object defining all scene elements (rois) to be visualized.",
+ "type": "object",
+ "properties": {
+ "overlays": {
+ "description": "The array of reference keys that needs to be visualized in scene. The order is important - following layers can cover predecessors",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "masks": {
+ "description": "The array of reference keys that needs to be visualized in scene. The order is important - following layers can cover predecessors",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "geometricalROIs": {
+ "description": "The array of reference keys that needs to be visualized in scene. The order is important - following layers can cover predecessors",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "polydatas": {
+ "description": "The array of reference keys that needs to be visualized in scene. The order is important - following layers can cover predecessors",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "required": ["primaryImageInputKey"]
+ },
+
+ "lookupTableConfiguration": {
+ "$id": "#lookupTableConfiguration",
+ "description": "Configuration of lookup table",
+ "type": "object",
+ "properties": {
+ "fromInputs": {
+ "description": "Shall lookup table configuration be taken from file. If so, proper input should be created.",
+ "type": "boolean"
+ },
+ "lutInputKey": {
+ "description": "The key of input providing lookup table configuration (value).",
+ "type": "string"
+ },
+ "type": {
+ "description": "The type of LUT when not provided by input.",
+ "$comment": "TODO: Establish whether still in use",
+ "type": "string",
+ "enum": ["none"]
+ }
+ },
+ "additionalProperties": false,
+ "required": ["fromInputs"]
+ },
+ "lookupTableDescriptionConfiguration": {
+ "$id": "#lookupTableDescriptionConfiguration",
+ "description": "Configuration of lookup table description",
+ "type": "object",
+ "properties": {
+ "fromInputs": {
+ "description": "Shall lookup table description configuration be taken from file. If so, proper input should be created.",
+ "type": "boolean"
+ },
+ "lutDescriptionInputKey": {
+ "description": "The key of input providing lookup table configuration (value)."
+ },
+ "type": {
+ "description": "The type of LUT description when not provided by input.",
+ "$comment": "TODO: Establish whether still in use",
+ "type": "string",
+ "enum": ["none"]
+ }
+ },
+ "additionalProperties": false,
+ "required": ["fromInputs"]
+ },
+ "overlayConfiguration": {
+ "$id": "#overlayConfiguration",
+ "description": "Configuration of overlay (labelmap, segmentation) to be visualized in the tool.",
+ "type": "object",
+ "properties": {
+ "fromInputs": {
+ "description": "Shall overlay configuration be taken from file. If so, proper input should be created.",
+ "type": "boolean"
+ },
+ "lutKey": {
+ "description": "The reference key of lookup table that needs to be used to visualize label values with proper colors. Refers to lookup table configuration section.",
+ "type": "string"
+ },
+ "lutDescriptionKey": {
+ "description": "The reference key of lookup table description that needs to be used to provide legend for overlay. Refers to lookup table descriptions configuration section. ",
+ "type": "string"
+ },
+ "label": {
+ "description": "The label for an overlay to be displayed in legend (eg. 'Contribution of John Doe', 'Segmentation of Medulla Oblongata', etc.).",
+ "type": "string"
+ },
+ "imageInputKey": {
+ "description": "The optional reference key to the input providing overlay data (if 'fromInputs' is set to be true)",
+ "type": "string"
+ },
+ "onInit": {
+ "description": "The set of predefined conditions determining initial state of overlay",
+ "type": "object",
+ "properties": {
+ "visible": {
+ "description": "Shall overlay be visible when tool is initialized",
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "required": ["fromInputs","lutDescriptionKey","lutKey"]
+ },
+
+ "scalarTypeValueConfiguration": {
+ "$id": "#scalarTypeValueConfiguration",
+ "description": "Configuration of type and value properties for scalar",
+ "type": "object",
+ "properties": {
+ "type": {
+ "description": "Defines type of value ",
+ "type": "string",
+ "enum": ["scalar"]
+ },
+ "value": {
+ "description": "Defines value ",
+ "type": "number"
+ }
+ }
+ },
+ "vectorTypeValueConfiguration": {
+ "$id": "#vectorTypeValueConfiguration",
+ "description": "Configuration of type and value properties for vector",
+ "type": "object",
+ "properties": {
+ "type": {
+ "description": "Defines type of value ",
+ "type": "string",
+ "enum": ["vector"]
+ },
+ "value": {
+ "description": "Defines value ",
+ "type": "array"
+ }
+ }
+ },
"widgetsTool": {
"$id": "#widgetsTool",
"description": "Widget for the annotation tool.",
@@ -404,6 +574,135 @@
"description": "Configuration of the particular tool. For instance the particular configuration of an anotation tool.",
"type": "object",
"properties": {
+ "luts": {
+ "description": "Map of lookup table configurations",
+ "patternProperties" : {
+ ".*" : {
+ "allOf":[
+ {"$ref": "#lookupTableConfiguration"}
+ ]
+ }
+ }
+ },
+ "lutDescriptions": {
+ "description": "Map of lookup table descriptions configurations",
+ "patternProperties" : {
+ ".*" : {
+ "allOf":[
+ {"$ref": "#lookupTableDescriptionConfiguration"}
+ ]
+ }
+ }
+ },
+ "rois": {
+ "description": "Configuration of the regions of interests. Contains maps of different scene objects, like overlays, masks and geometrical ROIs",
+ "properties": {
+ "overlays": {
+ "description": "Map of overlays (labelmaps, segmentations) used in a tool.",
+ "patternProperties" : {
+ ".*" : {
+ "allOf":[
+ {"$ref": "#overlayConfiguration"}
+ ],
+ "properties": {
+ "fromInputs": {},
+ "lutKey": {},
+ "lutDescriptionKey": {},
+ "label": {},
+ "imageInputKey": {},
+ "onInit": {}
+ },
+ "additionalProperties": false
+ }
+ }
+ },
+ "masks": {
+ "description": "Map of overlays (labelmaps, segmentations) being used as masks in a tool.",
+ "patternProperties" : {
+ ".*" : {
+ "allOf":[
+ {"$ref": "#overlayConfiguration"}
+ ],
+ "properties": {
+ "fromInputs": {},
+ "lutKey": {},
+ "lutDescriptionKey": {},
+ "label": {},
+ "imageInputKey": {},
+ "onInit": {},
+ "interactions": {
+ "description": "The definition of interactions between mask and other elements of tool. This is property that really distinguishes mask from overlay",
+ "type": "object",
+ "properties": {
+ "PREVENT_FROM_ADDING_PIN": {
+ "description": "The interaction between mask and anotation tool preventing from adding pin in a voxel belonging to mask",
+ "type": "object",
+ "properties": {
+ "type": {},
+ "value": {}
+ },
+ "oneOf": [
+ {"$ref": "#scalarTypeValueConfiguration"},
+ {"$ref": "#vectorTypeValueConfiguration"}
+ ],
+ "additionalProperties": false
+ },
+ "PREVENT_FROM_CHANGING_VOXEL_VALUE": {
+ "description": "The interaction between mask and painting tools preventing from changing a value of voxel being at the same location as voxel belonging to mask",
+ "type": "object",
+ "properties": {
+ "type": {},
+ "value": {}
+ },
+ "oneOf": [
+ {"$ref": "#scalarTypeValueConfiguration"},
+ {"$ref": "#vectorTypeValueConfiguration"}
+ ],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ },
+ "geometricalROIs": {
+ "description": "Map of geometrical (implicit) ROIs to be used in tool. TODO: To be finished - it is only a placeholder."
+ },
+ "polydatas": {
+ "description": "Map of polydata ROIs to be used in a tool.",
+ "$comment": "This needs to be extended",
+ "patternProperties" : {
+ ".*" : {
+ "properties": {
+ "fromInputs": {
+ "description": "Shall polydata be taken from file. If so, proper input should be created.",
+ "type": "boolean"
+ },
+ "dataInputKey": {
+ "description": "The reference key to input providing polydata.",
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "scenes": {
+ "description": "Configuration of the scenes to be displayed in viewers.",
+ "type": "object",
+ "patternProperties" : {
+ ".*" : {
+ "allOf":[
+ {"$ref": "#/definitions/scenesConfiguration"}
+ ]}
+ }
+ },
+ "annotationScenes": {
+ "description": "Map of data bindings between ROIs and annotations with respect to scenes. TODO: To be finished - it is only a placeholder."
+ },
"viewers": {
"description": "Configuration of the viewers for the tool.",
"$ref": "#/definitions/viewersTool"
@@ -412,7 +711,9 @@
"description": "Configuration of the widgets for the tool.",
"$ref": "#/definitions/widgetsTool"
}
- }
+ },
+ "required": ["scenes", "viewers"],
+ "additionalProperties": false
}
},
"required": ["name", "description", "version", "privacy", "type", "inputs", "outputs", "configuration"]
diff --git a/schemas/viewer.schema.json b/schemas/viewer.schema.json
index 3611418..8062aa6 100644
--- a/schemas/viewer.schema.json
+++ b/schemas/viewer.schema.json
@@ -9,6 +9,24 @@
],
"definitions":{
+ "toolbarControls": {
+ "$id": "#toolbarControls",
+ "description": "Boolean flags defining controls for a given property.",
+ "type": "object",
+ "$comment": "This defines control components for viewers.",
+ "properties": {
+ "controlVisible": {
+ "type": "boolean",
+ "description": "Defines whether control component (eg. Button) is visible."
+ },
+ "controlEnabled": {
+ "type": "boolean",
+ "description": "Defines whether control component (eg. Button) is enabled, ie. can change a state. If not enabled, then works only as indicator."
+ }
+ },
+ "required": ["controlEnabled", "controlVisible"]
+ },
+
"orientationType":{
"$id": "#orientationType",
"description": "Type of orientations",
@@ -27,12 +45,12 @@
"$id": "#dynamicValueInitialSlice",
"description": "Value for initial slices calculated dynamically for a given image",
"type": "string",
- "enum": ["LOWERMOST", "UPPERMOST", "LEFTMOST", "RIGHTMOST", "POSTERIORMOST", "ANTERIORMOST", "MIDDLE"]
+ "enum": ["INFERIORMOST", "SUPERIORMOST", "LEFTMOST", "RIGHTMOST", "POSTERIORMOST", "ANTERIORMOST", "MIDDLE","LABELMAP_COG"]
},
"strategyInitialWindowLevel":{
"$id": "#strategyInitialWindowLevel",
- "description": "Strategy to define initial window/level. DYNAMIC uses the intensity ranges of the image to dynamicall set the window/level values. NUMBER uses predefined values.",
+ "description": "Strategy to define initial window/level. DYNAMIC uses the intensity ranges of the image to dynamically set the window/level values. NUMBER uses predefined values.",
"type": "string",
"enum": ["DYNAMIC", "NUMBER"]
},
@@ -46,6 +64,7 @@
"viewerType":{
"$id": "#viewerType",
+ "$comment": "Deprecated definition since viewers have it defined in properties. It is kept for future extensions",
"description": "Type of viewers",
"type": "string",
"enum": ["2D", "3D"]
@@ -72,181 +91,462 @@
"orientation"
]
- }
-
- },
- "properties": {
- "name": {
- "description": "Name of the viewer",
- "type": "string"
- },
- "type":{
- "description": "Type of viewer",
- "$ref": "#/definitions/viewerType"
},
- "initialState":{
- "description": "Initial state of the viewer",
- "properties":{
- "orientationAndSliceNumber": {
- "description": "Initial orientation and slice number",
- "type": "object",
+
+ "viewer2D": {
+ "$id": "#viewer2D",
+ "description": "All the viewer properties that can be exposed",
+ "type": "object",
+ "properties": {
+ "name": {
+ "description": "Name of the viewer",
+ "type": "string"
+ },
+ "type":{
+ "description": "Type of viewer",
+ "type": "string",
+ "enum": ["2D"]
+ },
+ "initialState":{
+ "description": "Initial state of the viewer",
"properties":{
- "orientation": {
- "$ref": "#/definitions/orientationType"
+ "orientationAndSliceNumber": {
+ "description": "Initial orientation and slice number",
+ "$comment": "TODO: make patterns for property values, i.e. strategy=number, required sliceNumber",
+ "type": "object",
+ "properties":{
+ "orientation": {
+ "$ref": "#/definitions/orientationType"
+ },
+ "strategy": {
+ "description": "Strategy to define the initial slice",
+ "$ref": "#/definitions/strategyInitialSlice"
+ },
+ "dynamicSliceValue":{
+ "description": "Initial slice value",
+ "$ref": "#/definitions/dynamicValueInitialSlice"
+ },
+ "predefinedSliceNumber":{
+ "description": "Predefined slice number",
+ "type": "number"
+ },
+ "sliceNumber":{
+ "description": "The reference key to input containing slice number value",
+ "type": "string"
+ }
+ },
+ "oneOf":[
+ {
+ "required": ["orientation", "strategy", "dynamicSliceValue"]
+ },
+ {
+ "required": ["orientation", "strategy", "predefinedSliceNumber"]
+ },
+ {
+ "required": ["orientation", "strategy", "sliceValue"]
+ }
+ ]
},
- "strategy": {
- "description": "Strategy to define the initial slice",
- "$ref": "#/definitions/strategyInitialSlice"
+ "initialWindowLevel":{
+ "description": "Initial window/level for the viewer",
+ "type": "object",
+ "properties":{
+ "strategy": {
+ "description": "Strategy to define the initial window/level",
+ "$ref": "#/definitions/strategyInitialWindowLevel"
+ },
+ "dynamicStrategy":{
+ "description": "Initial slice value",
+ "$ref": "#/definitions/dynamicStrategyWindowLevel"
+ },
+ "predefinedWindowWidth":{
+ "description": "Predefined window width",
+ "type": "number"
+ },
+ "predefinedLevelValue":{
+ "description": "Predefined level value",
+ "type": "number"
+ }
+ },
+ "oneOf":[
+ {
+ "required": ["strategy", "dynamicStrategy"]
+ },
+ {
+ "required": ["orientation", "dynamicStrategy", "predefinedWindowWidth", "predefinedLevelValue"]
+ }
+ ]
+ }
+ },
+ "required": ["orientationAndSliceNumber", "initialWindowLevel"]
+ },
+ "displayImages":{
+ "description": "Display options of the viewer regarding the images.",
+ "type": "object",
+ "properties":{
+ "possibleImagesToDisplay": {
+ "description": "List of input images the viewer can display. The input images must reference an id of the input images.",
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1
},
- "dynamicSliceValue":{
- "description": "Initial slice value",
- "$ref": "#/definitions/dynamicValueInitialSlice"
+ "hasDefaultImageToDisplay":{
+ "description": "True is there is a default image to display",
+ "type": "boolean"
},
- "predefinedSliceNumber":{
- "description": "Predefined slice number",
- "type": "number"
+ "defaultImageToDisplay": {
+ "description": "Id of the input images to be displayed",
+ "type": "string"
}
},
- "oneOf":[
- {
- "required": ["orientation", "strategy", "dynamicSliceValue"]
+ "required": ["possibleImagesToDisplay", "hasDefaultImageToDisplay"],
+ "dependencies": {
+ "defaultImageToDisplay": {
+ "properties": {
+ "hasDefaultImageToDisplay": {
+ "enum": [true]
+ }
+ }
+ }
+ }
+ },
+ "windowLevel": {
+ "description": "Window/Level configuration for the viewer",
+ "type": "object",
+ "properties": {
+ "userCanChangeWindowLevel":{
+ "description": "If the user is able to control the Window/Level.",
+ "type": "boolean",
+ "default": true
},
- {
- "required": ["orientation", "strategy", "predefinedSliceNumber"]
+ "defaultValue": {
+ "description": "Default values for the Window/Level.",
+ "type": "object",
+ "properties": {
+ "window": {
+ "description": "Default Window value.",
+ "type": "number",
+ "default": 0
+ },
+ "level": {
+ "description": "Default Level value.",
+ "type": "number",
+ "default": 0
+ }
+ }
}
- ]
+ },
+ "required": ["userCanChangeWindowLevel"]
},
- "initialWindowLevel":{
- "description": "Initial window/level for the viewer",
+ "displayControls":{
+ "description": "Display controls of the viewer.",
"type": "object",
"properties":{
- "strategy": {
- "description": "Strategy to define the initial window/level",
- "$ref": "#/definitions/strategyInitialWindowLevel"
+ "orientation": {
+ "description": "Orientation settings",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "controlVisible": {},
+ "controlEnabled": {},
+ "options":{
+ "description": "Orientation options for the viewer control components",
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 3,
+ "items": {
+ "type": "object",
+ "description": "Orientation option has mandatory enumerated value and mandatory label of any value",
+ "properties":{
+ "label": {
+ "type":"string"
+ },
+ "value": {
+ "type":"string",
+ "enum": ["SAGITTAL","CORONAL","AXIAL"]
+ }
+ },
+ "required": ["label","value"]
+ }
+ },
+ "defaultValue": {
+ "description": "Default orientation of the viewer. It is not required since initial setting should be inherited from initial state of orientation. ",
+ "type": "string",
+ "enum":["SAGITTAL","CORONAL","AXIAL"]
+ }
+ },
+ "required": ["controlVisible","controlEnabled"]
},
- "dynamicStrategy":{
- "description": "Initial slice value",
- "$ref": "#/definitions/dynamicStrategyWindowLevel"
+ "smoothing":{
+ "description": "Smoothing control for the images",
+ "type": "object",
+ "additionalProperties": false,
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties":{
+ "controlVisible": {},
+ "controlEnabled": {},
+ "defaultValue": {
+ "type": "boolean",
+ "description": "Initial setting (whether smoothing is on or off)"
+ }
+ },
+ "required": ["defaultValue", "controlVisible","controlEnabled"]
},
- "predefinedWindowWidth":{
- "description": "Predefined window width",
- "type": "number"
+ "sequence":{
+ "description": "Control for change of the main image in viewer",
+ "type": "object",
+ "additionalProperties": false,
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties":{
+ "controlVisible": {},
+ "controlEnabled": {}
+ },
+ "required": ["controlVisible","controlEnabled"]
},
- "predefinedLevelValue":{
- "description": "Predefined level value",
- "type": "number"
+ "linked":{
+ "description": "Control for linking of viewers",
+ "type": "object",
+ "additionalProperties": false,
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties":{
+ "controlVisible": {},
+ "controlEnabled": {}
+ },
+ "required": ["controlVisible","controlEnabled"]
}
},
- "oneOf":[
- {
- "required": ["strategy", "dynamicStrategy"]
- },
- {
- "required": ["orientation", "dynamicStrategy", "predefinedWindowWidth", "predefinedLevelValue"]
- }
- ]
+ "required": ["orientation", "smoothing"]
}
},
- "required": ["orientationAndSliceNumber", "initialWindowLevel"]
+ "required":["name", "type", "initialState"]
},
- "displayImages":{
- "description": "Display options of the viewer regarding the images.",
+ "viewer3D": {
+ "$id": "#viewer3D",
+ "description": "All the viewer properties that can be exposed",
"type": "object",
- "properties":{
- "possibleImagesToDisplay": {
- "description": "List of input images the viewer can display. The input images must reference an id of the input images.",
- "type": "array",
- "items": {
- "type": "string"
- },
- "minItems": 1
+ "properties": {
+ "name": {
+ "description": "Name of the viewer",
+ "type": "string"
},
- "hasDefaultImageToDisplay":{
- "description": "True is there is a default image to display",
- "type": "boolean"
+ "type":{
+ "description": "Type of viewer",
+ "type": "string",
+ "enum": ["3D"]
},
- "defaultImageToDisplay": {
- "description": "Id of the input images to be displayed",
- "type": "string"
- }
- },
- "required": ["possibleImagesToDisplay", "hasDefaultImageToDisplay"],
- "dependencies": {
- "defaultImageToDisplay": {
- "properties": {
- "hasDefaultImageToDisplay": {
- "enum": [true]
+ "initialState":{
+ "description": "Initial state of the viewer",
+ "properties":{
+ "orientationAndSliceNumber": {
+ "description": "Initial orientation and slice number",
+ "type": "object",
+ "properties":{
+ "orientation": {
+ "$ref": "#/definitions/orientationType"
+ },
+ "strategy": {
+ "description": "Strategy to define the initial slice",
+ "$ref": "#/definitions/strategyInitialSlice"
+ },
+ "dynamicSliceValue":{
+ "description": "Initial slice value",
+ "$ref": "#/definitions/dynamicValueInitialSlice"
+ },
+ "predefinedSliceNumber":{
+ "description": "Predefined slice number",
+ "type": "number"
+ }
+ },
+ "oneOf":[
+ {
+ "required": ["orientation", "strategy", "dynamicSliceValue"]
+ },
+ {
+ "required": ["orientation", "strategy", "predefinedSliceNumber"]
+ }
+ ]
+ },
+ "initialWindowLevel":{
+ "description": "Initial window/level for the viewer",
+ "type": "object",
+ "properties":{
+ "strategy": {
+ "description": "Strategy to define the initial window/level",
+ "$ref": "#/definitions/strategyInitialWindowLevel"
+ },
+ "dynamicStrategy":{
+ "description": "Initial slice value",
+ "$ref": "#/definitions/dynamicStrategyWindowLevel"
+ },
+ "predefinedWindowWidth":{
+ "description": "Predefined window width",
+ "type": "number"
+ },
+ "predefinedLevelValue":{
+ "description": "Predefined level value",
+ "type": "number"
+ }
+ },
+ "oneOf":[
+ {
+ "required": ["strategy", "dynamicStrategy"]
+ },
+ {
+ "required": ["orientation", "dynamicStrategy", "predefinedWindowWidth", "predefinedLevelValue"]
+ }
+ ]
}
}
- }
- }
- },
- "windowLevel": {
- "description": "Window/Level configuration for the viewer",
- "type": "object",
- "properties": {
- "userCanChangeWindowLevel":{
- "description": "If the user is able to control the Window/Level.",
- "type": "boolean",
- "default": true
},
- "defaultValue": {
- "description": "Default values for the Window/Level.",
+ "displayImages":{
+ "description": "Display options of the viewer regarding the images.",
"type": "object",
- "properties": {
- "window": {
- "description": "Default Window value.",
- "type": "number",
- "default": 0
+ "properties":{
+ "possibleImagesToDisplay": {
+ "description": "List of input images the viewer can display. The input images must reference an id of the input images.",
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1
+ },
+ "hasDefaultImageToDisplay":{
+ "description": "True is there is a default image to display",
+ "type": "boolean"
},
- "level": {
- "description": "Default Level value.",
- "type": "number",
- "default": 0
+ "defaultImageToDisplay": {
+ "description": "Id of the input images to be displayed",
+ "type": "string"
+ }
+ },
+ "required": ["possibleImagesToDisplay", "hasDefaultImageToDisplay"],
+ "dependencies": {
+ "defaultImageToDisplay": {
+ "properties": {
+ "hasDefaultImageToDisplay": {
+ "enum": [true]
+ }
+ }
}
}
- }
- },
- "required": ["userCanChangeWindowLevel"]
- },
- "displayControls":{
- "description": "Display controls of the viewer.",
- "type": "object",
- "properties":{
- "orientations": {
- "description": "Possible orientations of the images",
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["axial", "sagittal", "coronal"]
- },
- "minItems": 1
},
- "defaultOrientation": {
- "description": "Default orientation of the images",
- "type": "string",
- "enum": ["axial", "sagittal", "coronal"]
- },
- "smoothing":{
- "description": "Smoothing control for the images",
- "type": "object",
- "properties":{
- "smoothingControl": {
- "description": "Smoothing control for the viewer",
- "type": "boolean",
- "default": true
- },
- "smoothingDefault":{
- "description": "Smoothing default value for the viewer",
- "type": "boolean",
- "default": false
- }
- },
- "required": ["smoothingControl", "smoothingDefault"]
- }
+ "windowLevel": {
+ "description": "Window/Level configuration for the viewer",
+ "type": "object",
+ "properties": {
+ "userCanChangeWindowLevel":{
+ "description": "If the user is able to control the Window/Level.",
+ "type": "boolean",
+ "default": true
+ },
+ "defaultValue": {
+ "description": "Default values for the Window/Level.",
+ "type": "object",
+ "properties": {
+ "window": {
+ "description": "Default Window value.",
+ "type": "number",
+ "default": 0
+ },
+ "level": {
+ "description": "Default Level value.",
+ "type": "number",
+ "default": 0
+ }
+ }
+ }
+ },
+ "required": ["userCanChangeWindowLevel"]
+ },
+ "displayControls":{
+ "description": "Display controls of the viewer.",
+ "type": "object",
+ "properties":{
+ "orientation": {
+ "description": "Orientation settings",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "controlVisible": {},
+ "controlEnabled": {},
+ "options":{
+ "description": "Orientation options for the viewer control components",
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 3,
+ "items": {
+ "type": "object",
+ "description": "Orientation option has mandatory enumerated value and mandatory label of any value",
+ "properties":{
+ "label": {
+ "type":"string"
+ },
+ "value": {
+ "type":"string",
+ "enum": ["SAGITTAL","CORONAL","AXIAL"]
+ }
+ },
+ "required": ["label","value"]
+ }
+ },
+ "defaultValue": {
+ "description": "Default orientation of the viewer",
+ "type": "string",
+ "enum":["SAGITTAL","CORONAL","AXIAL"]
+ }
+ },
+ "required": ["defaultValue", "controlVisible","controlEnabled"]
+ },
+ "smoothing":{
+ "description": "Smoothing control for the images",
+ "type": "object",
+ "additionalProperties": false,
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties":{
+ "controlVisible": {},
+ "controlEnabled": {},
+ "defaultValue": {
+ "type": "boolean",
+ "description": "Initial setting (whether smoothing is on or off)"
+ }
+ },
+ "required": ["defaultValue", "controlVisible","controlEnabled"]
+ },
+ "sequence":{
+ "description": "Control for change of the main image in viewer",
+ "type": "object",
+ "additionalProperties": false,
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties":{
+ "controlVisible": {},
+ "controlEnabled": {}
+ },
+ "required": ["controlVisible","controlEnabled"]
+ },
+ "linked":{
+ "description": "Control for linking of viewers",
+ "type": "object",
+ "additionalProperties": false,
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties":{
+ "controlVisible": {},
+ "controlEnabled": {}
+ },
+ "required": ["controlVisible","controlEnabled"]
+ }
+ },
+ "required": ["smoothing"]
+ },
+ "displayScenes":{
+ "description": "Display controls of the viewer."
+ },
+ "displayImageSlices":{
+ "description": "Display image slice actors in the scene. The actors can be associated with state of other viewers."
+ }
},
- "required": ["orientations", "defaultOrientation", "smoothing"]
+ "required":["name", "type"]
}
- },
- "required":["name", "type", "initialState"]
+ }
}
\ No newline at end of file
diff --git a/schemas/widget.schema.json b/schemas/widget.schema.json
new file mode 100644
index 0000000..d0e9a51
--- /dev/null
+++ b/schemas/widget.schema.json
@@ -0,0 +1,1098 @@
+{
+ "$id":"https://raw.githubusercontent.com/SPINEProject/SPINE-json-schema/master/schemas/widget.schema.json",
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Widget schema",
+ "description": "Schema for Widget Tools",
+ "type": "object",
+ "additionalProperties": false,
+ "definitions":{
+ "toolbarControls": {
+ "$id": "#toolbarControls",
+ "description": "Boolean flags defining controls for a given widget.",
+ "type": "object",
+ "$comment": "So far control components for widgets are implemented with Toggleable Buttons. Model can be extended by adding other complex controls, eg. sets of buttons, dropdown etc.",
+ "properties": {
+ "controlVisible": {
+ "type": "boolean",
+ "description": "Defines whether control component (eg. Button) is visible."
+ },
+ "controlEnabled": {
+ "type": "boolean",
+ "description": "Defines whether control component (eg. Button) is enabled, ie. can change a state. If not enabled, then works only as indicator."
+ }
+ },
+ "required": ["controlEnabled", "controlVisible"]
+ },
+ "markerSize": {
+ "$id":"#markerSize",
+ "description": "Property defining size of pin (marker).",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "integer"
+ }
+ },
+ "required": ["defaultValue"]
+ },
+ "fontSize": {
+ "$id":"#fontSize",
+ "description": "Property defining size of label for Pin.",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "integer"
+ }
+ },
+ "required": ["defaultValue"]
+ },
+ "clearAllPins": {
+ "$id":"#clearAllPins",
+ "description": "Property defining whether Button for clearing pins should be visible.",
+ "allOf": [{ "$ref": "#toolbarControls" }]
+ },
+ "subAnnotationsAvailable": {
+ "$id":"#subAnnotationsAvailable",
+ "description": "Property defining whether pins for subannotations should be visible.",
+ "$comment": "So far controlVisible/controlEnabled are ignored, since functionality can be set only in widget configuration. There is no control component in frontend to switch on/off.",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "boolean"
+ }
+ },
+ "required": ["defaultValue"]
+ },
+ "pinCentering": {
+ "$id":"#pinCentering",
+ "description": "Property defining whether view should be centered on an active pins when navigating forward/backward, or using ROI buttons in Annotation Table",
+ "$comment": "So far controlVisible/controlEnabled are ignored, since functionality can be set only in widget configuration. There is no control component in frontend to switch on/off.",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "boolean"
+ }
+ },
+ "required": ["defaultValue"]
+ },
+ "pinSelectionOnly": {
+ "$id":"#pinSelectionOnly",
+ "description": "Optional property defining whether pins are in read-only mode (selection). Default is false. If pins are in selectionOly mode, they cannot be added with mouse left click. This can be useful in situation when pinTool Toggle button is not visible, and tool is on.",
+ "$comment": "So far controlVisible/controlEnabled are ignored, since functionality can be set only in widget configuration. There is no control component in frontend to switch on/off.",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "boolean"
+ }
+ },
+ "required": ["defaultValue"]
+ },
+ "pinCriterion":{
+ "$id":"#pinCriterion",
+ "type": "object",
+ "description": "Single criterion used to constrain visibility of Pins.",
+ "$comment": "Can be reorganized in a way that control elements will have their own specific syntax and schema.",
+ "additionalProperties": false,
+ "properties": {
+ "controlElement": {
+ "type": "string",
+ "description": "Tool element which state is used to calculate criterion.",
+ "enum": ["viewer"],
+ "$comment": "So far it is defined for viewer only. In future can be extended for tools, widgets state, etc."
+ },
+ "property": {
+ "type": "string",
+ "description": "Property of control element which state is used to calculate criterion. For example viewer['sliceNumber'] can be calculated.",
+ "enum": ["sliceNumber","imageId","orientation"],
+ "$comment": "Can be easily extended to other viewer state properties."
+ },
+ "operator": {
+ "type": "string",
+ "description": "Operator used to calculate Predicate.",
+ "enum": ["==="],
+ "$comment": "Should be merged with Experiment.schema definitions."
+ }
+ }
+ },
+ "pinCriteria": {
+ "$id":"#pinCriteria",
+ "type": "object",
+ "patternProperties" : {
+ ".*" : {
+ "type": "object",
+ "$ref": "#/definitions/pinCriterion"
+ }
+ },
+ "examples": [
+ {
+ "criterion_key1": {"controlElement":"viewer","property":"sliceNumber","operator": "==="},
+ "criterion_key2": {"controlElement":"viewer","property":"imageId","operator": "==="}
+ }
+ ]
+ },
+ "pinConstraints": {
+ "$id":"#pinConstraints",
+ "description": "Optional property defining additional conditions for displaying pins. Default is turned off. See example below.",
+ "$comment": "So far controlVisible/controlEnabled are ignored, since functionality can be set only in widget configuration. There is no control component in frontend to switch on/off.",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {"$ref": "#pinCriteria"}
+ },
+ "required": ["defaultValue"]
+ },
+ "projectionRange": {
+ "$id":"#projectionRange",
+ "description": "Optional property defining range of projection, as number of surrounding slices.",
+ "$comment": "So far controlVisible/controlEnabled are ignored, since functionality can be set only in widget configuration. There is no control component in frontend to switch on/off.",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {"type": "integer"}
+ },
+ "required": ["defaultValue"]
+ },
+ "customCursorType": {
+ "$id":"#customCursorType",
+ "description": "Property defining type of cursor.",
+ "$comment": "Custom cursor might have different shape and implementation.",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "string",
+ "enum": ["crosshair","circle","whiskers","checkered","twoEllipses","animatedEllipse","rotatedEllipse","fixedCrosshairRelativeCircle","dottedCrosshair"]
+ }
+ },
+ "required": ["defaultValue"]
+ },
+ "customCursorDiameter": {
+ "$id":"#customCursorDiameter",
+ "description": "Property defining diameter of cursor in millimeters. Size is calculated in image (real world) space.",
+ "$comment": "This does not have to apply to all of the shapes.",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "integer"
+ }
+ },
+ "required": ["defaultValue"]
+ },
+ "pointerMode": {
+ "$id":"#pointerMode",
+ "description": "Property defining mode (type of interaction) of pointer tool.",
+ "$comment": "Modes are related to UI event types. There might be possible to define modeOptions in future.",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "string",
+ "enum": ["onClick","onMove"]
+ }
+ },
+ "required": ["defaultValue"]
+ },
+ "brushSize": {
+ "$id":"#brushSize",
+ "description": "Property defining size. Can be used to define brush or eraser tool size.",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "integer"
+ }
+ },
+ "required": ["defaultValue"]
+ },
+ "labelmapItem":{
+ "$id":"#labelmapItem",
+ "type": "object",
+ "description": "Definition of labelmap value.",
+ "additionalProperties": false,
+ "properties": {
+ "value": {
+ "type": "integer",
+ "description": "Value assigned to voxel"
+ },
+ "label": {
+ "type": "string",
+ "description": "Name to display. Can be a name of annotated region, pathological change, etc. Examples: lesion, tumor, medulla oblongata."
+ },
+ "iri": {
+ "type": "string",
+ "description": "If segmentation refers to real world entity, iri should refer to Ontology Id, defined as IRI address.",
+ "format": "uri"
+ },
+ "color": {
+ "type": "string",
+ "description": "Color in RGB space.",
+ "$comment": "Notation with 3 and six positions can be used.",
+ "pattern": "^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$"
+ }
+ },
+ "required": ["color","value","label"]
+ },
+ "pinToolProperties": {
+ "$id":"#pinToolProperties",
+ "description": "Set of properties for Pin Tool.",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "markerSize": {"$ref": "#/definitions/markerSize"},
+ "fontSize": {"$ref": "#/definitions/fontSize"},
+ "clearAll": {"$ref":"#/definitions/clearAllPins"},
+ "selectionOnly": {"$ref":"#/definitions/pinSelectionOnly"},
+ "subAnnotationsAvailable": {"$ref":"#/definitions/subAnnotationsAvailable"},
+ "centering": {"$ref":"#/definitions/pinCentering"},
+ "constraints": {"$ref": "#/definitions/pinConstraints"}
+ },
+ "required": ["markerSize","fontSize","clearAll"]
+ },
+ "projectionToolProperties": {
+ "$id":"#projectionToolProperties",
+ "description": "Set of properties for Projection Tool.",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "range": {
+ "$ref": "#/definitions/projectionRange"
+ },
+ "rangeForKey": {
+ "$ref": "#/definitions/projectionRange",
+ "description": "As in /projectionRange description, with difference that applied only to set range when 'P' key is pressed."
+ }
+ }
+ },
+ "customCursorToolProperties": {
+ "$id":"#customCursorToolProperties",
+ "description": "Set of properties for Custom Cursor Tool.",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "$ref": "#/definitions/customCursorType"
+ },
+ "diameter": {
+ "$ref": "#/definitions/customCursorDiameter"
+ }
+ }
+ },
+ "fiducialToolProperties": {
+ "$id":"#customCursorToolProperties",
+ "description": "Set of properties for Custom Cursor Tool.",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "$ref": "#/definitions/customCursorType",
+ "$comment": "identical as in custom cursor"
+ },
+ "diameter": {
+ "$ref": "#/definitions/customCursorDiameter",
+ "$comment": "identical as in custom cursor"
+ },
+ "rotation": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "integer",
+ "description": "Fiducial rotation in degrees.",
+ "minimum": 0
+ }
+ }
+ },
+ "adjustableZoom": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "number",
+ "description": "Ratio between display and fiducial size. Diameter of fiducial is equal to display width for ratio = 0.5",
+ "minimum": 0.01
+ }
+ }
+ }
+ }
+ },
+ "pointerToolProperties": {
+ "$id":"#pointerToolProperties",
+ "description": "Set of properties for Pointer Tool.",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "mode": {
+ "$ref": "#/definitions/pointerMode"
+ }
+ }
+ },
+ "brushToolProperties": {
+ "$id":"#brushToolProperties",
+ "description": "Set of properties for Brush Tool.",
+ "$comment": "Properties as threshold, colormap LUT, layer are moved out from here.",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "size": {
+ "$ref": "#/definitions/brushSize"
+ }
+ }
+ },
+ "eraserToolProperties": {
+ "$id":"#eraserToolProperties",
+ "description": "Set of properties for Eraser Tool.",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "size": {
+ "$ref": "#/definitions/brushSize",
+ "$comment": "Identical to brush size property."
+ }
+ }
+ },
+ "labelmapLUTProperties": {
+ "$id":"#labelmapLUTProperties",
+ "description": "Set of properties for labelmap.",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "options": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/labelmapItem"
+ }
+ }
+ }
+ },
+ "annotationTableProperties": {
+ "$id":"#annotationTableProperties",
+ "description": "Set of properties for annotation table component.",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "fullTable": {
+ "description": "Property defining whether 'full table mode' should be visible initially. Full table mode shows both 'active row' and full table with annotations.",
+ "$comment": "Control enabled/visible properties define whether full table can be displayed. If they set to false,and defaultValue is false, then full table is not visible.",
+ "allOf": [
+ {
+ "$ref": "#toolbarControls"
+ }
+ ],
+ "properties": {
+ "defaultValue": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "defaultValue"
+ ]
+ },
+ "editableROI": {
+ "description": "Property defining whether rows can be modified/deleted.",
+ "$comment": "If property not defined, default is true. Control visible/enabled defined but not used here.",
+ "allOf": [
+ {
+ "$ref": "#toolbarControls"
+ }
+ ],
+ "properties": {
+ "defaultValue": {
+ "type": "boolean",
+ "default": true
+ }
+ },
+ "required": [
+ "defaultValue"
+ ]
+ },
+ "subAnnotationColumn": {
+ "description": "Property defining whether column to set active roi to generate subannotations with mouse left click should be visible.",
+ "$comment": "controlVisible/enabled define full control here.",
+ "allOf": [
+ {
+ "$ref": "#toolbarControls"
+ }
+ ]
+ },
+ "csvExport": {
+ "description": "Property defining whether button with CSV Export functionality should be rendered and working.",
+ "$comment": "controlVisible/enabled define full control here.",
+ "allOf": [
+ {
+ "$ref": "#toolbarControls"
+ }
+ ]
+ }
+ }
+ },
+ "samplerToolInteraction": {
+ "$id":"#samplerToolInteraction",
+ "description": "Definition of tool that is using sampled statistics calculated with sampler tool.",
+ "additionalProperties": false,
+ "required": ["type", "tool","property","value"],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": ["widget"],
+ "$comment": "One option so far",
+ "description": "Type of interacting tool. If widget, other widget definition is required. TODO define interaction"
+ },
+ "tool": {
+ "type": "string",
+ "enum": ["intensityFilterTool"],
+ "$comment": "One option so far",
+ "description": "Widget id."
+ },
+ "property": {
+ "type": "string",
+ "enum": ["maxValue","minValue"],
+ "$comment": "This definition requires extension to other tools props.",
+ "description": "Name of property in destination tool (eg. intensityFilterTool.maxValue)"
+ },
+ "value": {
+ "type": "string",
+ "enum": ["midPoint"],
+ "$comment": "One option so far. Needs to be expanded in code to others, ie. threshols, stats.minimum, stats. maximum, etc.",
+ "description": "Name of statistics calculated with sampler tool"
+ }
+ }
+ },
+ "samplerToolProperties": {
+ "$id":"#samplerToolProperties",
+ "description": "Set of properties for Sampler Tool (Data Probe).",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "interactions": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "description": "Defines other tools that can be affected by sampler. For example, filter intensities can use statistics from sample like minimum, maximum, mid value etc.",
+ "$comment": "Control visible/enabled defined but not used here.",
+ "properties": {
+ "defaultValue": {
+ "maxProperties": 1,
+ "minProperties": 1,
+ "$comment": "Only one interaction is defined so far. FUTURE RELEASES: add another widgets into properties section if implemented.",
+ "properties": {
+ "intensityFilterTool": {
+ "type": "object",
+ "$ref": "#samplerToolInteraction"
+ }
+ }
+ }
+ }
+ },
+ "histogram": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "description": "The control over displaying histogram. If visible, then button for displaying histogram in Widget Toolbar is displayed.",
+ "properties": {
+ "defaultValue": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ },
+ "onComplete": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "$comment": "Control visible/enabled defined but not used here.",
+ "description": "Property defining what action should take place after setting the sample rectangle. For example, displaying histogram.",
+ "properties": {
+ "defaultValue": {
+ "type": "string",
+ "enum": ["SHOW_HISTOGRAM"],
+ "$comment": "One option so far."
+ }
+ }
+ },
+ "bucketing": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "description": "Optional property defining the algorithm to be used for initialization of histogram bins.",
+ "$comment": "If not defined, number of bins is equal to 256.",
+ "properties": {
+ "defaultValue": {
+ "type": "string",
+ "enum": ["SQRT","STURGES","FREEDMAN-DIACONIS","RICE","SCOTT"],
+ "$comment": "Other options are available. This definition needs to be expanded with regular expressions. TODO"
+ }
+ }
+ }
+ }
+ },
+ "intensityFilterToolProperties": {
+ "$id":"#intensityFilterToolProperties",
+ "description": "Set of properties for Intensity Filter",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "minValue": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "description": "The initial value for lower boundary of filter",
+ "properties": {
+ "defaultValue": {
+ "type": "number",
+ "default": 0
+ }
+ }
+ },
+ "maxValue": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "description": "The initial value for upper boundary of filter",
+ "properties": {
+ "defaultValue": {
+ "type": "number",
+ "default": 4294967295
+ }
+ }
+ },
+ "showMask": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "description": "The initial label value (to use with LUT) to display mask.",
+ "$comment": "Not implemented yet.",
+ "properties": {
+ "defaultValue": {
+ "type": "number",
+ "default": 0
+ }
+ }
+ },
+ "clear": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "description": "Control button for clearing fields"
+ }
+
+ }
+ },
+ "levelTracingToolProperties": {
+ "$id":"#levelTracingToolProperties",
+ "description": "Set of properties for Level Tracing Tool",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "levelFunction": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "description": "The type of level function",
+ "properties": {
+ "defaultValue": {
+ "type": "string",
+ "enum": ["DARKER","BRIGHTER","DARKER_WITH_MARGIN","BRIGHTER_WITH_MARGIN"]
+ }
+ }
+ },
+ "levelFunctionMargin": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "description": "The optional margin of tolerance for level function",
+ "properties": {
+ "defaultValue": {
+ "type": "number",
+ "default": 25
+ }
+ }
+ },
+ "lineWidth": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "description": "The line width for the contour renderer.",
+ "properties": {
+ "defaultValue": {
+ "type": "number",
+ "default": 0.1
+ }
+ }
+ }
+ }
+ },
+ "infoToolProperties": {
+ "$id":"#infoToolProperties",
+ "description": "Set of properties for Info Tool",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "showIntensity": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "description": "Defines whether intensity pointed by mouse cursor should be displayed",
+ "properties": {
+ "defaultValue": {
+ "type": "boolean",
+ "default": false
+ }
+ }
+ },
+ "showWL": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "description": "Defines whether Window/Level range should be displayed",
+ "properties": {
+ "defaultValue": {
+ "type": "boolean",
+ "default": false
+ }
+ }
+ },
+ "showPosition": {
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "description": "Defines whether position of cursor in image space IJK and real world space XYZ should be displayed",
+ "properties": {
+ "defaultValue": {
+ "type": "boolean",
+ "default": false
+ }
+ }
+ }
+ }
+ },
+ "pinTool": {
+ "$id": "#pinTool",
+ "description": "Tool for pin management.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "properties": { "$ref": "#/definitions/pinToolProperties"}
+ },
+ "required": ["properties"]
+ },
+ "projectionTool": {
+ "$id": "#projectionTool",
+ "description": "Tool for projection management.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "properties": { "$ref": "#/definitions/projectionToolProperties"}
+ }
+ },
+ "customCursorTool": {
+ "$id": "#customCursorTool",
+ "description": "Tool for custom cursor management.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "properties": { "$ref": "#/definitions/customCursorToolProperties"}
+ }
+ },
+ "pointerTool": {
+ "$id": "#pointerTool",
+ "description": "Tool for pointer management. Pointer is changing slices in remaining viewers according to intersection of slices at pointed voxel.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "properties": { "$ref": "#/definitions/pointerToolProperties"}
+ }
+ },
+ "crossHairTool": {
+ "$id": "#crossHairTool",
+ "description": "Tool for displaying indication of slices.",
+ "$comment": "It can be defined in viewer's interaction schema with a different syntax.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "boolean"
+ }
+ }
+ },
+ "brushTool": {
+ "$id": "#brushTool",
+ "description": "Tool for drawing in segmentation layer.",
+ "$comment": "TODO Design inputs and widget to handle state of colormap LUT, thresholding intensities when drawing and layers. There will be missing props here!",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "boolean",
+ "description": "Optional parameter defining whether widget should be on when view is initialised. This can be overwritten by other elements - brushTool, fillingTool, eraserTool are mutually exclusive - only one of them can be on at te same time.",
+ "default": false
+ },
+ "properties": { "$ref": "#/definitions/brushToolProperties"}
+ }
+ },
+ "echoTool": {
+ "$id": "#echoTool",
+ "description": "Widget adding cursor echoes on remaining fields. Widget controls camera too - centering and zooming are projected fro main viewer to others.",
+ "$comment": "Widget works properly only if viewers are set in the same orientation and displaying co-registered images.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "boolean"
+ }
+ }
+ },
+ "eraserTool": {
+ "$id": "#eraserTool",
+ "description": "Tool for erasing in segmentation layer. By default it uses 0 to fill erased voxels.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "boolean",
+ "description": "Optional parameter defining whether widget should be on when view is initialised. This can be overwritten by other elements - brushTool, fillingTool, eraserTool are mutually exclusive - only one of them can be on at te same time.",
+ "default": false
+ },
+ "properties": { "$ref": "#/definitions/eraserToolProperties"}
+ }
+ },
+ "fillingTool": {
+ "$id": "#fillingTool",
+ "description": "Tool for filling in closed shapes in segmentation layer.",
+ "$comment": "Comments as in #brushTool.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "boolean",
+ "description": "Optional parameter defining whether widget should be on when view is initialised. This can be overwritten by other elements - brushTool, fillingTool, eraserTool are mutually exclusive - only one of them can be on at te same time.",
+ "default": false
+ }
+ }
+ },
+ "labelmapUndoRedoTool": {
+ "$id": "#labelmapUndoRedoTool",
+ "description": "Widget displaying history controls for segmentation.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }]
+ },
+ "pinUndoRedoTool": {
+ "$id": "#pinUndoRedoTool",
+ "description": "Widget displaying history controls for pins. Save creating, deleting and selecting actions.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }]
+ },
+ "labelmapOpacity": {
+ "$id": "#labelmapOpacity",
+ "description": "Widget for control over labelmap opacity.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "number",
+ "description": "Opacity value.",
+ "minimum": 0,
+ "maximum": 1
+ }
+ }
+ },
+ "labelmapLUT": {
+ "$id": "#labelmapLUT",
+ "description": "Tool defining labelmap.",
+ "$comment": "TODO Labelmap should be provided by input",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "integer",
+ "description": "Parameter defining labelmap value to use when view is initialised.",
+ "default": false
+ },
+ "properties": { "$ref": "#/definitions/labelmapLUTProperties"}
+ }
+ },
+ "linkAllTool": {
+ "$id": "#linkAllTool",
+ "description": "Widget linking all viewers (slice change is applied to all viewers). Turning on means turning on 'linked' property in all viewers. It can be implemented with toggleable button or checkbox.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "boolean"
+ }
+ }
+ },
+ "annotationOpacity": {
+ "$id": "#annotationOpacity",
+ "description": "Widget for control over annotation opacity.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "number",
+ "description": "Opacity value.",
+ "minimum": 0,
+ "maximum": 1
+ }
+ }
+ },
+ "annotationTableTool": {
+ "$id": "#annotationTableTool",
+ "description": "Widget for control over annotation table component",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "properties": { "$ref": "#/definitions/annotationTableProperties"}
+ }
+ },
+ "smoothingAllTool": {
+ "$id": "#smoothingAllTool",
+ "description": "Widget turning on/off smoothing in all viewers. It can be implemented with toggleable button or checkbox.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "defaultValue": {
+ "type": "boolean"
+ }
+ }
+ },
+ "fiducialTool": {
+ "$id": "#fiducialTool",
+ "description": "Widget for responsible for displaying fiducial and modifying behavior of roi navigation. Widget 'on' causes that viewer is centered on image",
+ "$comment": "This widget is based on custom cursor.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "properties": {
+ "controlVisible": {},
+ "controlEnabled": {},
+ "defaultValue": {
+ "type": "boolean",
+ "description": "Optional parameter defining whether widget should be on when view is initialised."
+ },
+ "properties": { "$ref": "#/definitions/fiducialToolProperties"}
+ }
+ },
+ "windowLevelAllTool": {
+ "$id": "#windowLevelAllTool",
+ "description": "Widget linking all viewers for Window Level synchronization.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "additionalProperties": false,
+ "properties": {
+ "controlVisible": {},
+ "controlEnabled": {},
+ "defaultValue": {
+ "type": "boolean"
+ }
+ }
+ },
+ "samplerTool": {
+ "$id": "#samplerTool",
+ "description": "Widget for sampling intensities in a given region in image. This tool is calculating statistics for a set of voxel intensities located inside red rectangle rendered in image slice. Optionally pixel histogram can be visualized",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "additionalProperties": false,
+ "properties": {
+ "controlVisible": {},
+ "controlEnabled": {},
+ "defaultValue": {
+ "type": "boolean"
+ },
+ "properties": { "$ref": "#/definitions/samplerToolProperties"}
+ }
+ },
+ "intensityFilterTool": {
+ "$id": "#intensityFilterTool",
+ "description": "Widget for filtering voxel intensities during drawing (brush, filling tool, drawer, level tracing, etc.) and erasing. Can be interacting with sampler. ",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "additionalProperties": false,
+ "properties": {
+ "controlVisible": {},
+ "controlEnabled": {},
+ "defaultValue": {
+ "type": "boolean"
+ },
+ "properties": { "$ref": "#/definitions/intensityFilterToolProperties"}
+ }
+ },
+ "hideContoursTool": {
+ "$id": "#hideContoursTool",
+ "description": "Widget for hiding the contours.",
+ "$comment": "This is out-dated",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "additionalProperties": false,
+ "properties": {
+ "controlVisible": {},
+ "controlEnabled": {},
+ "description": {
+ "type": "string",
+ "description": "This property can be used to describe tool."
+ },
+ "defaultValue": {
+ "type": "boolean"
+ }
+ }
+ },
+ "hideLabelmapsTool": {
+ "$id": "#hideLabelmapsTool",
+ "description": "This is an optional widget for hiding segmentations functionality (shortcut to hide segmentations is alwasy on - optional widget is just for additional button in Widget Toolbar).",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "additionalProperties": false,
+ "properties": {
+ "controlVisible": {},
+ "controlEnabled": {},
+ "description": {
+ "type": "string",
+ "description": "This property can be used to describe tool."
+ },
+ "defaultValue": {
+ "type": "boolean"
+ }
+ }
+ },
+ "levelTracingTool": {
+ "$id": "#levelTracingTool",
+ "description": "This is an optional widget for Level Tracing Tool.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "additionalProperties": false,
+ "properties": {
+ "controlVisible": {},
+ "controlEnabled": {},
+ "defaultValue": {
+ "type": "boolean"
+ },
+ "properties": { "$ref": "#/definitions/levelTracingToolProperties"}
+ }
+ },
+ "infoTool": {
+ "$id": "#infoTool",
+ "description": "Widget displaying information about WL parameters and intensity of voxel pointed by mouse cursor. In case of multiple primary images, the information is provided for active (in control) layer only.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "additionalProperties": false,
+ "properties": {
+ "controlVisible": {},
+ "controlEnabled": {},
+ "defaultValue": {
+ "type": "boolean"
+ },
+ "properties": { "$ref": "#/definitions/infoToolProperties"}
+ }
+ },
+ "spawnViewersWindowTool": {
+ "$id": "#spawnViewersWindowTool",
+ "description": "Widget for displaying viewers in separate (spawned) window which can be moved to any monitor.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "additionalProperties": false,
+ "properties": {
+ "controlVisible": {},
+ "controlEnabled": {},
+ "defaultValue": {
+ "type": "boolean"
+ }
+ }
+ },
+ "exportAnnotationsToServerTool": {
+ "$id": "#exportAnnotationsToServerTool",
+ "description": "Widget for saving temporary annotations to server.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "additionalProperties": false,
+ "properties": {
+ "controlVisible": {},
+ "controlEnabled": {},
+ "defaultValue": {
+ "type": "boolean"
+ }
+ }
+ },
+ "exportAnnotationsToDiskTool": {
+ "$id": "#exportAnnotationsToDiskTool",
+ "description": "Widget for saving temporary annotations to local disk as json file.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "additionalProperties": false,
+ "properties": {
+ "controlVisible": {},
+ "controlEnabled": {},
+ "defaultValue": {
+ "type": "boolean"
+ }
+ }
+ },
+ "importAnnotationsFromDiskTool": {
+ "$id": "#importAnnotationsFromDiskTool",
+ "description": "Widget for loading temporary annotations from local disk as json file.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "additionalProperties": false,
+ "properties": {
+ "controlVisible": {},
+ "controlEnabled": {},
+ "defaultValue": {
+ "type": "boolean"
+ }
+ }
+ },
+ "roiTableTool": {
+ "$id": "#roiTableTool",
+ "description": "Widget displaying table of ROIs. To be used in visualization tool. Designed for input from experimental dataset only.",
+ "type": "object",
+ "allOf": [{ "$ref": "#toolbarControls" }],
+ "additionalProperties": false,
+ "properties": {
+ "controlVisible": {},
+ "controlEnabled": {},
+ "defaultValue": {
+ "description": "Flag indicating whether table should be visible on init",
+ "type": "boolean"
+ }
+ }
+ },
+ "mainTool": {
+ "$id": "#mainTool",
+ "description": "Widget defining properties of the entire manual tool.",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "activeViewer ": {
+ "description": "Defines which viewer will be initially the source of events",
+ "type": "string"
+ },
+ "leftButtonMode": {
+ "description": "Defines which widget will be used initially on mouse left-click (important for mutually exclusive brush, fill, pin etc.). Widgets are encoded with numbers",
+ "type": "number",
+ "maximum": 10,
+ "minimum": 0,
+ "$comment": " NONE: 0,PIN: 2,BRUSH: 3,ERASER: 4,FILLING: 5,AZIMUTH: 6, RULER:7,SAMPLER:8,LEVEL:9,DRAW:10"
+ },
+ "annotationsVisible": {
+ "description": "Defines whether annotations shall be visible on init",
+ "type": "boolean"
+ },
+ "projectionsVisible": {
+ "description": "Defines whether annotation projections shall be visible on init",
+ "type": "boolean"
+ },
+ "navigationModeLabel": {
+ "description": "Defines which transition after going to next/previous step should take place: to the next step or to the next case (keeping the same step)",
+ "type": "string",
+ "enum": ["step","case"],
+ "$comment": "By default step is used"
+ },
+ "autosaving": {
+ "description": "Defines whether and how often autosaving for a chosen outputs shall be applied",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "interval": {
+ "description": "if set up, defines how often (in seconds) autosave should be performed",
+ "type": "number"
+ }
+ }
+ }
+ }
+ }
+ },
+ "properties": {
+ "pinTool": { "$ref": "#/definitions/pinTool"},
+ "projectionTool": { "$ref": "#/definitions/projectionTool"},
+ "customCursorTool": { "$ref": "#/definitions/customCursorTool"},
+ "pointerTool": { "$ref": "#/definitions/pointerTool"},
+ "crossHairTool": {"$ref": "#/definitions/crossHairTool"},
+ "brushTool": {"$ref": "#/definitions/brushTool"},
+ "echoTool": {"$ref": "#/definitions/echoTool"},
+ "fiducialTool": {"$ref": "#/definitions/fiducialTool"},
+ "eraserTool": {"$ref": "#/definitions/eraserTool"},
+ "fillingTool": {"$ref": "#/definitions/fillingTool"},
+ "labelmapLUT": {"$ref": "#/definitions/labelmapLUT"},
+ "labelmapUndoRedoTool": {"$ref": "#/definitions/labelmapUndoRedoTool"},
+ "labelmapOpacity": {"$ref": "#/definitions/labelmapOpacity"},
+ "linkAllTool": {"$ref": "#/definitions/linkAllTool"},
+ "annotationOpacity": {"$ref": "#/definitions/annotationOpacity"},
+ "annotationTableTool": {"$ref": "#/definitions/annotationTableTool"},
+ "smoothingAllTool": {"$ref": "#/definitions/smoothingAllTool"},
+ "pinUndoRedoTool": {"$ref": "#/definitions/pinUndoRedoTool"},
+ "windowLevelAllTool": {"$ref": "#/definitions/windowLevelAllTool"},
+ "samplerTool": {"$ref": "#/definitions/samplerTool"},
+ "intensityFilterTool": {"$ref": "#/definitions/intensityFilterTool"},
+ "hideContoursTool": {"$ref": "#/definitions/hideContoursTool"},
+ "hideLabelmapsTool": {"$ref": "#/definitions/hideLabelmapsTool"},
+ "levelTracingTool": {"$ref": "#/definitions/levelTracingTool"},
+ "infoTool": {"$ref": "#/definitions/infoTool"},
+ "spawnViewersWindowTool": {"$ref": "#/definitions/spawnViewersWindowTool"},
+ "exportAnnotationsToServerTool": {"$ref": "#/definitions/exportAnnotationsToServerTool"},
+ "exportAnnotationsToDiskTool": {"$ref": "#/definitions/exportAnnotationsToDiskTool"},
+ "importAnnotationsFromDiskTool": {"$ref": "#/definitions/importAnnotationsFromDiskTool"},
+ "roiTableTool": {"$ref": "#/definitions/roiTableTool"},
+ "mainTool": {"$ref": "#/definitions/mainTool"}
+ }
+}
\ No newline at end of file
diff --git a/tests/cohort.schema.test.js b/tests/cohort.schema.test.js
new file mode 100644
index 0000000..f3b2beb
--- /dev/null
+++ b/tests/cohort.schema.test.js
@@ -0,0 +1,22 @@
+const path = require('path');
+const fs = require('fs');
+const cohortSchema = require('../schemas/cohort.schema');
+
+
+let { test, expect ,it, describe} = global;
+
+
+describe('Automatic Suite for testing all cohorts in examples folder', () => {
+
+ const directoryPath = path.join(__dirname, '../examples/cohort');
+ const files = fs.readdirSync(directoryPath, function (err, files) { if (err) return []; });
+ files.forEach(file=> {
+
+ if (file.includes(".json")){
+ test(`checks for ${file}`, () => {
+ expect(true).toBeAjvValid(cohortSchema,require( "../examples/cohort/"+file.split(".json")[0]));
+ });
+ }
+ });
+});
+
diff --git a/tests/errorMessage.js b/tests/errorMessage.js
new file mode 100644
index 0000000..d5e815e
--- /dev/null
+++ b/tests/errorMessage.js
@@ -0,0 +1,9 @@
+export default function errorMessage (errors) {
+ return (errors || []).map(error => {
+ try {
+ return `AJV error: keyword: ${error.keyword}\n message: ${error.message} \n data path${error.dataPath}\n schemaPath: ${error.schemaPath}\n`;
+ } catch (error) {
+ return error.message;
+ }
+ }).join('\n');
+}
\ No newline at end of file
diff --git a/tests/experimentalPlan.schema.test.js b/tests/experimentalPlan.schema.test.js
new file mode 100644
index 0000000..8983fe6
--- /dev/null
+++ b/tests/experimentalPlan.schema.test.js
@@ -0,0 +1,22 @@
+const path = require('path');
+const fs = require('fs');
+const planSchema = require('../schemas/experimentalPlan.schema');
+
+
+let { test, expect , describe} = global;
+
+
+describe('Automatic Suite for testing all plans in examples folder', () => {
+
+ const examplesPath = '../examples/experimentalPlan/';
+ const directoryPath = path.join(__dirname, examplesPath);
+ const files = fs.readdirSync(directoryPath, function (err, files) { if (err) return []; });
+ files.forEach(file=> {
+ if (file.includes(".json")){
+ test(`checks for ${file}`, () => {
+ expect(true).toBeAjvValid(planSchema,require( examplesPath+file.split(".json")[0]).config.experimentalPlan);
+ });
+ }
+ });
+});
+
diff --git a/tests/jest.ajv.test.js b/tests/jest.ajv.test.js
new file mode 100644
index 0000000..66ea127
--- /dev/null
+++ b/tests/jest.ajv.test.js
@@ -0,0 +1,60 @@
+/**
+ *This test shows how to use Ajv variables locally - error messages, validate and others can be customized
+ * in files
+ *
+ */
+
+var Ajv = require('ajv'); //We need to override ajv, if we want to customize it
+var ajv = new Ajv();
+
+let { it, expect } = global;
+
+const validateSecuredUrl = function (schema, uri) {
+ validateSecuredUrl.errors = [{keyword: 'secured', message: 'avatar url must be "https" schema', params: {keyword: 'secured'}}];
+ return uri.indexOf('https://') === 0;
+};
+
+ajv.addKeyword('securedUrl', {
+ validate: validateSecuredUrl,
+ errors: true
+});
+
+
+test(`should user's schema be valid`, () => {
+ const shema = {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "fullname": {
+ "type": "string",
+ "minLength": 2
+ },
+ "avatar": {
+ "type": "string",
+ "format": "uri",
+ "securedUrl": true,
+ },
+ },
+ },
+ };
+
+ const valid = ajv.validate(shema, [
+ {
+ fullname: 'ab',
+ avatar: "http://mywebsite.com/path/to/avatar"
+ }
+ ]);
+
+ // this function can be used globally
+ const errorMessage = (ajv.errors || []).map(error => {
+ try {
+ return `AJV error: keyword: ${error.keyword}\n message: ${error.message} \n data path: ${error.dataPath}\n schema path: ${error.schemaPath}\n`;
+ } catch (error) {
+ return error.message;
+ }
+ }).join('\n');
+
+
+ expect(valid).not.toBeValid(errorMessage); // we want to have error in "http" - uncomment "not" to see error and message
+});
\ No newline at end of file
diff --git a/tests/setupTests.js b/tests/setupTests.js
new file mode 100644
index 0000000..8236b98
--- /dev/null
+++ b/tests/setupTests.js
@@ -0,0 +1,73 @@
+const istanbul = require('istanbul');
+
+
+const taskSchema = require ("../schemas/task.schema");
+const coreSchema = require ("../schemas/core.schema");
+const viewerSchema = require ("../schemas/viewer.schema");
+const annotationSchema = require ("../schemas/annotation.schema");
+// const annotationForm = require ("../schemas/annotationForm.schema");
+const roiSchema = require ("../schemas/roi.schema");
+const toolSchema = require('../schemas/tool.schema');
+
+
+/**
+ * Matcher for Ajv.
+ * Defined here, so can be used globally.
+ * This file has to be referred in package.json
+ */
+expect.extend({
+ toBeValid(isValid, errorMessage) {
+ return {
+ message: () => isValid ? '' : errorMessage,
+ pass: isValid
+ }
+ }
+});
+
+
+/**
+ * Matcher for Ajv.
+ * Defined here, so can be used globally.
+ * This file has to be referred in package.json
+ */
+expect.extend({
+ toBeAjvValid(toBeValid, schema, example) {
+ const valid = ajv.validate(schema, example);
+ const errorMessage = (ajv.errors || []).map(error => {
+ try {
+ const params = (Object.keys(error.params) || []).map(param => {return param.concat("=",error.params[param])}).join('\n');
+ return `AJV: keyword: ${error.keyword}\n`
+ +`message: ${error.message} \n`
+ +`data path: ${error.dataPath}\n`
+ +`schema path: ${error.schemaPath}\n`
+ +`parameters: ${params}\n`;
+ } catch (error) {
+ return error.message;
+ }
+ }).join('\n');
+ if(toBeValid)
+ return {
+ message: () => valid ? '' : errorMessage,
+ pass: valid
+ };
+ else
+ return {
+ message: errorMessage,
+ pass: !valid
+ };
+ }
+});
+
+
+beforeAll(() => {
+ const Ajv = require('ajv');
+ global.ajv = new Ajv(); //setting global variable declared in package.json jest configuration
+ require('ajv-istanbul')(global.ajv);
+ ajv.addSchema(coreSchema,'coreSchema');
+ ajv.addSchema(taskSchema,'taskSchema');
+ ajv.addSchema(annotationSchema,'annotationSchema');
+ // ajv.addSchema(annotationForm,'annotationForm');
+ ajv.addSchema(roiSchema,'roiSchema');
+ ajv.addSchema(toolSchema,'toolSchema');
+ ajv.addSchema(viewerSchema,'viewerSchema');
+});
diff --git a/tests/tool.schema.test.js b/tests/tool.schema.test.js
new file mode 100644
index 0000000..ed6a6c1
--- /dev/null
+++ b/tests/tool.schema.test.js
@@ -0,0 +1,13 @@
+const toolSchema = require('../schemas/tool.schema');
+
+
+let { test, expect ,it} = global;
+
+test('tool schema for tool_sliceSelectorInAxialDirection', () => {
+ expect(true).toBeAjvValid(toolSchema,require( "../examples/tool/invisibleFilterDemo").miniWorkflow.currentTool);
+});
+
+
+test('tool schema ', () => {
+ expect(true).toBeAjvValid(toolSchema,require( "../examples/tool/sceneDemo").miniWorkflow.currentTool);
+});
\ No newline at end of file
diff --git a/tests/tools2.schema.test.js b/tests/tools2.schema.test.js
new file mode 100644
index 0000000..def300d
--- /dev/null
+++ b/tests/tools2.schema.test.js
@@ -0,0 +1,36 @@
+const path = require('path');
+const fs = require('fs');
+const toolSchema = require('../schemas/tool.schema');
+
+
+let { test, expect ,it, describe} = global;
+
+
+describe('Automatic Suite for testing all tools in examples folder', () => {
+
+ const directoryPath = path.join(__dirname, '../examples/tool');
+ const files = fs.readdirSync(directoryPath, function (err, files) { if (err) return []; });
+ files.forEach(file=> {
+
+ if (file.includes(".json")){
+ test(`checks for ${file}`, () => {
+ expect(true).toBeAjvValid(toolSchema,require( "../examples/tool/"+file.split(".json")[0]).miniWorkflow.currentTool);
+ });
+ }
+ });
+});
+
+describe('Automatic Suite for testing all tools in remote location folder', () => {
+
+ const globalPath = "c:\\PATH"; // PUT YOUR LOCAL FOLDER HERE
+ const files = fs.readdirSync(globalPath, function (err, files) { if (err) return []; });
+ files.forEach(file=> {
+ if (file.includes(".json")){
+ const jsonObject = require( globalPath+file.split(".json")[0]);
+ if (jsonObject!=null && jsonObject.miniWorkflow!=null && jsonObject.miniWorkflow.currentTool!=null)
+ test(`checks for ${file}`, () => {
+ expect(true).toBeAjvValid(toolSchema,jsonObject.miniWorkflow.currentTool);
+ });
+ }
+ });
+});
\ No newline at end of file
diff --git a/tests/viewer.schema.test.js b/tests/viewer.schema.test.js
new file mode 100644
index 0000000..bfb8bb8
--- /dev/null
+++ b/tests/viewer.schema.test.js
@@ -0,0 +1,24 @@
+const schema = require('../schemas/viewer.schema');
+const data1 = require( "../examples/viewer/viewer.example");
+const data2 = require( "../examples/viewer/leptostep1middle.example");
+let { test, expect ,it, describe} = global;
+
+// Uncomment below if you want to override ajv for some reasons!!!
+// var Ajv = require('ajv');
+// var ajv = new Ajv();
+
+
+describe('Viewer schemas', () => {
+
+ test('Simple viewer', () => {
+ expect(true).toBeAjvValid(schema, data1);
+ });
+
+ test('Full example viewer', () => {
+ expect(true).toBeAjvValid(schema, data1);
+ });
+
+ test('Lepto project, step1, Middle viewer', () => {
+ expect(true).toBeAjvValid(schema, data2);
+ });
+});
\ No newline at end of file
diff --git a/tests/widget.schema.test.js b/tests/widget.schema.test.js
new file mode 100644
index 0000000..9cad653
--- /dev/null
+++ b/tests/widget.schema.test.js
@@ -0,0 +1,22 @@
+const schema = require('../schemas/widget.schema');
+let { test, expect ,describe} = global;
+
+// Uncomment below if you want to override ajv for some reasons!!!
+// var Ajv = require('ajv');
+// var ajv = new Ajv();
+
+
+describe('Widget schemas', () => {
+
+ test('Full widget configuration', () => {
+ expect(true).toBeAjvValid(schema, require( "../examples/widgets/full.example"));
+ });
+
+ test('Lepto project, step1, widgets', () => {
+ expect(true).toBeAjvValid(schema, require( "../examples/widgets/leptostep1.example"));
+ });
+
+ test('Mutation test for widgets3', () => {
+ expect(true).not.toBeAjvValid(schema, require( "../examples/widgets/mutation.example")); // mutation, so valid condition is negated
+ });
+});
\ No newline at end of file