Mercurial > hg > orthanc-tcia
view WebApplication/app.js @ 37:8bb64b689841 default tip
added CITATION.cff
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Sat, 06 Apr 2024 17:30:56 +0200 |
parents | b6801cfb19d2 |
children |
line wrap: on
line source
/** * TCIA plugin for Orthanc * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. **/ // https://stackoverflow.com/a/13818704/881731 function globStringToRegex(str) { function preg_quote (str, delimiter) { // http://kevin.vanzonneveld.net // + original by: booeyOH // + improved by: Ates Goral (http://magnetiq.com) // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + bugfixed by: Onno Marsman // + improved by: Brett Zamir (http://brett-zamir.me) // * example 1: preg_quote("$40"); // * returns 1: '\$40' // * example 2: preg_quote("*RRRING* Hello?"); // * returns 2: '\*RRRING\* Hello\?' // * example 3: preg_quote("\\.+*?[^]$(){}=!<>|:"); // * returns 3: '\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:' return (str + '').replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\' + (delimiter || '') + '-]', 'g'), '\\$&'); } return new RegExp(preg_quote(str, '').replace(/\\\*/g, '.*').replace(/\\\?/g, '.'), 'gi'); } var app = new Vue({ el: '#app', data: function() { return { // Used by import jobId : '', importedPatients : [], // Used by explorer filter : '', collections : [], activeCollection : '', activePatientId : '', patients : [], studies : [], series : {}, openedStudies : {}, selectedSeries : {} } }, computed: { allSelectedSeries: function() { var count = 0; for (var seriesInstanceUid in this.selectedSeries) { if (this.selectedSeries[seriesInstanceUid] === true) { count ++; } } return count; } }, methods: { openJob: function() { if (this.jobId != '') { window.open('../../app/explorer.html#job?uuid=' + this.jobId, '_blank'); } }, refreshSeriesCount: function() { var that = this; // The use of "let" instead of "var" is mandatory so that the // scope of "i" matches that of the "for" loop for (let i = 0; i < that.importedPatients.length; i++) { axios.post('../../tools/find', { 'Expand' : true, 'Level' : 'Series', 'Query' : { 'PatientID' : that.importedPatients[i].PatientID } }) .then(function(series) { var availableSeries = new Set(); for (var j = 0; j < series.data.length; j++) { availableSeries.add(series.data[j].MainDicomTags.SeriesInstanceUID); } var count = 0; for (var j = 0; j < that.importedPatients[i].SeriesInstanceUID.length; j++) { if (availableSeries.has(that.importedPatients[i].SeriesInstanceUID[j])) { count ++; } } that.importedPatients[i].CompletedSeries = count; }); } }, getJobPatients: function() { this.importedPatients = []; if (this.jobId == '') { return; } var that = this; axios.get('../../jobs/' + this.jobId) .then(function(job) { var series = job.data.Content.Series; var index = {}; for (var i = 0; i < series.length; i++) { var id = (series[i].Collection + '|' + series[i].PatientID); if (id in index) { var patient = index[id]; patient.SeriesInstanceUID.push(series[i].SeriesInstanceUID); patient.InstancesCount += series[i].InstancesCount; patient.Size += parseInt(series[i].Size, 10); } else { index[id] = { 'Collection' : series[i].Collection, 'PatientID' : series[i].PatientID, 'OrthancID' : series[i].OrthancID, 'CompletedSeries' : 0, 'SeriesInstanceUID' : [ series[i].SeriesInstanceUID ], 'InstancesCount' : series[i].InstancesCount, 'Size' : parseInt(series[i].Size, 10) } } } that.importedPatients = Object.values(index); that.importedPatients.sort(function(a, b) { if (a.Collection < b.Collection) { return -1; } else if (a.Collection > b.Collection) { return 1; } else { return a.PatientID < b.PatientID ? -1 : 1; } }); that.refreshSeriesCount(); }); }, importCart: function() { var that = this; var blob = this.$refs.cart.files[0]; if (blob === undefined) { alert('No cart was provided'); } else { var reader = new FileReader(); reader.readAsText(blob); reader.onerror = function (error) { alert('Cannot read the cart'); }; reader.onload = function () { that.jobId = ''; that.importedPatients = []; var base64 = btoa(reader.result); axios.post('../import', { 'Type' : 'NbiaClientSpreadsheet', 'Content' : base64, 'Asynchronous' : true }) .then(function(response) { that.jobId = response.data.ID; that.getJobPatients(); window.location.href = '#import-status'; }) .catch(function(error) { alert('Cannot process the cart, check that this is a valid NBIA spreadsheet file in CSV format'); }); }; } }, concatenateTcia : function(arr, field) { var s = ''; arr.sort(function(a, b) { if (a[field] < b[field]) { return -1; } else if (a[field] > b[field]) { return 1; } else { return 0; } }); for (var i = 0; i < arr.length; i++) { if (field in arr[i]) { if (s != '') { s += ', '; } s += arr[i][field]; } } return s; }, listCollections : function() { this.activeCollection = ''; this.filter = ''; window.location.href = '#explore-tcia'; }, listPatients : function() { this.activePatientId = ''; this.filter = ''; window.location.href = '#explore-tcia'; }, openCollection : function(collection) { var that = this; axios.get('../proxy/getPatient', { params : { Collection : collection } }) .then(function(patients) { that.activeCollection = collection; that.patients = patients.data; that.filter = ''; window.location.href = '#explore-tcia'; }); }, openPatient : function(patientId) { var that = this; axios.get('../proxy/getPatientStudy', { params : { Collection : this.activeCollection, PatientID : patientId } }) .then(function(studies) { that.filter = ''; that.activePatientId = patientId; that.studies = studies.data; that.openedStudies = {}; that.series = {}; that.selectedSeries = {}; window.location.href = '#explore-tcia'; axios.get('../proxy/getSeries', { params : { Collection : this.activeCollection, PatientID : patientId } }) .then(function(series) { that.series = {}; for (var i = 0; i < series.data.length; i++) { var studyInstanceUid = series.data[i].StudyInstanceUID; if (!(studyInstanceUid in that.series)) { that.series[studyInstanceUid] = []; } that.series[studyInstanceUid].push(series.data[i]); } }); }); }, openStudy: function(studyInstanceUid) { this.$set(this.openedStudies, studyInstanceUid, true); }, closeStudy: function(studyInstanceUid) { this.$set(this.openedStudies, studyInstanceUid, false); }, countSelectedSeries: function(studyInstanceUid) { var count = 0; if (studyInstanceUid in this.series) { for (var i = 0; i < this.series[studyInstanceUid].length; i++) { if (this.selectedSeries[this.series[studyInstanceUid][i].SeriesInstanceUID] === true) { count ++; } } return count; } else { return 0; } }, setAllSeries: function(studyInstanceUid, isSelected) { if (studyInstanceUid in this.series) { for (var i = 0; i < this.series[studyInstanceUid].length; i++) { this.$set(this.selectedSeries, this.series[studyInstanceUid][i].SeriesInstanceUID, isSelected); } } }, importSelectedSeries: function() { var content = []; for (var studyInstanceUid in this.series) { var series = this.series[studyInstanceUid]; for (var i = 0; i < series.length; i++) { if (this.selectedSeries[series[i].SeriesInstanceUID] === true) { var size = 0; // TODO content.push({ 'Collection' : this.activeCollection, 'PatientID' : this.activePatientId, 'SeriesInstanceUID' : series[i].SeriesInstanceUID, 'InstancesCount' : series[i].ImageCount, 'Size' : size.toString() }); } } } var that = this; this.jobId = ''; this.importedPatients = []; axios.post('../import', { 'Type' : 'Series', 'Content' : content, 'Asynchronous' : true }) .then(function(response) { that.jobId = response.data.ID; that.getJobPatients(); window.location.href = '#import-status'; }) .catch(function(error) { alert('Cannot import the selected series'); }); }, clearCache: function() { axios.post('../clear-cache', {}) .catch(function(error) { alert('Cannot clear the cache'); }); } }, mounted: function() { var that = this; axios.get('../proxy/getCollectionValues') .then(function(collections) { // Only use 1 axios query at a time, in order to avoid // overwhelming the browser function getModalityValues(i) { if (i < that.collections.length) { var collection = that.collections[i]; axios.get('../proxy/getModalityValues', { params : { Collection : collection.Name } }) .then(function(modalities) { var content = that.collections[i]; content.Modalities = that.concatenateTcia(modalities.data, 'Modality'); that.$set(that.collections, i, content); getModalityValues(i + 1); }); } } function getBodyPartValues(i) { if (i < that.collections.length) { var collection = that.collections[i]; axios.get('../proxy/getBodyPartValues', { params : { Collection : collection.Name } }) .then(function(parts) { var content = that.collections[i]; content.BodyParts = that.concatenateTcia(parts.data, 'BodyPartExamined'); that.$set(that.collections, i, content); getBodyPartValues(i + 1); }); } } for (let i = 0; i < collections.data.length; i++) { that.$set(that.collections, i, { Name : collections.data[i].Collection, Modalities : '...', BodyParts : '...' }); } getModalityValues(0); getBodyPartValues(0); }); } })