From 1baa8a1b927fbc792f642435f64710efeb1e0f5f Mon Sep 17 00:00:00 2001 From: Taylor Hanayik <hanayik@gmail.com> Date: Wed, 2 Oct 2024 23:35:17 +0100 Subject: [PATCH] allow drag and drop using new dcm2niix build --- index.html | 16 ++++++---- main.js | 77 ++++++++++++++++++++++++++++++++++++++++++++++- niivue.css | 14 ++++++++- package-lock.json | 8 ++--- package.json | 4 +-- 5 files changed, 105 insertions(+), 14 deletions(-) diff --git a/index.html b/index.html index ff800bf..dc7c97b 100644 --- a/index.html +++ b/index.html @@ -10,14 +10,18 @@ <body> <header id="header"> + <div id="dropTarget" class="drop-target"> + <p>Drop a folder of DICOM files here</p> + <p>Or use the file input button below</p> + </div> <!-- ordered list for instructions --> <ol id="instructions"> <li> - <!-- directory input --> - <label for="fileInput" id="fileInputLabel" class="file-input-label"> - Choose a folder of DICOM files - </label> - <input type="file" id="fileInput" webkitdirectory multiple /> + <!-- directory input --> + <label for="fileInput" id="fileInputLabel" class="file-input-label"> + Choose a folder of DICOM files + </label> + <input type="file" id="fileInput" webkitdirectory multiple /> </li> <li> <!-- file select for converted files returned from dcm2niix --> @@ -26,7 +30,7 @@ </li> <li> <!-- optional: save nii file in the niivue canvas from conversion --> - <label for="saveButton" id="saveButtonLabel">Optional: save the nifti file you are viewing</label> + <label for="saveButton" id="saveButtonLabel">Optional: save the nifti file you are viewing</label> <button id="saveButton" class="hidden">Save nifti</button> </li> </ol> diff --git a/main.js b/main.js index c39d63a..24b41c5 100644 --- a/main.js +++ b/main.js @@ -121,6 +121,11 @@ const runDcm2niix = async (files) => { console.log(resultFileList); hideLoadingCircle() showFileSelect() + // set the first file as the selected file + fileSelect.value = 0 + // trigger the change event + const event = new Event('change') + fileSelect.dispatchEvent(event) } catch (error) { console.error(error); resultFileList = [] @@ -139,6 +144,72 @@ const ensureObjectOfObjects = (obj) => { } } +async function handleDrop(e) { + e.preventDefault(); // prevent navigation to open file + const items = e.dataTransfer.items; + try { + showLoadingCircle() + const files = []; + for (let i = 0; i < items.length; i++) { + const item = items[i].webkitGetAsEntry(); + if (item) { + await traverseFileTree(item, '', files); + } + } + const dcm2niix = new Dcm2niix(); + await dcm2niix.init() + resultFileList = await dcm2niix.inputFromDropItems(files).run() + resultFileList = resultFileList.filter(file => file.name.endsWith('.nii')) + updateSelectItems(resultFileList) + console.log(resultFileList); + hideLoadingCircle() + showFileSelect() + // set the first file as the selected file + fileSelect.value = 0 + // trigger the change event + const event = new Event('change') + fileSelect.dispatchEvent(event) + showText('') + } catch (error) { + console.error(error); + hideLoadingCircle() + hideFileSelect() + showText('Error converting files. Check the console for more information.') + } +} + +async function traverseFileTree(item, path = '', fileArray) { + return new Promise((resolve) => { + if (item.isFile) { + item.file(file => { + file.fullPath = path + file.name; + // IMPORTANT: _webkitRelativePath is required for dcm2niix to work. + // We need to add this property so we can parse multiple directories correctly. + // the "webkitRelativePath" property on File objects is read-only, so we can't set it directly, hence the underscore. + file._webkitRelativePath = path + file.name; + fileArray.push(file); + resolve(); + }); + } else if (item.isDirectory) { + const dirReader = item.createReader(); + const readAllEntries = () => { + dirReader.readEntries(entries => { + if (entries.length > 0) { + const promises = []; + for (const entry of entries) { + promises.push(traverseFileTree(entry, path + item.name + '/', fileArray)); + } + Promise.all(promises).then(readAllEntries); + } else { + resolve(); + } + }); + }; + readAllEntries(); + } + }); +} + async function main() { fileInput.addEventListener('change', async (event) => { if (event.target.files.length === 0) { @@ -147,13 +218,17 @@ async function main() { } console.log('Selected files:', event.target.files); const selectedFiles = event.target.files; - const files = ensureObjectOfObjects(selectedFiles) + const files = ensureObjectOfObjects(selectedFiles) // probably not needed anymore with new dcm2niix version await runDcm2niix(files) }); // when user changes the file to view fileSelect.onchange = handleFileSelectChange + // handle drag and drop + dropTarget.ondrop = handleDrop; + dropTarget.ondragover = (e) => {e.preventDefault();} + // when user clicks save saveButton.onclick = handleSaveButtonClick diff --git a/niivue.css b/niivue.css index f128776..567c771 100644 --- a/niivue.css +++ b/niivue.css @@ -16,10 +16,22 @@ body { background: #303030; } +.drop-target { + display: flex; + flex-direction: column; + width: 100%; + padding: 10px; + border: 2px dashed white; + border-radius: 5px; + text-align: center; + background-color: #000000; + color: white; +} + header { display: flex; gap: 2rem; - flex-direction: row; + flex-direction: column; margin: 10px; } diff --git a/package-lock.json b/package-lock.json index 06e4e37..0f797fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "niivue-dcm2niix", "version": "1.0.0", "dependencies": { - "@niivue/dcm2niix": "^0.1.1-dev.1", + "@niivue/dcm2niix": "^0.1.1-dev.2", "@niivue/niivue": "^0.45.1" }, "devDependencies": { @@ -428,9 +428,9 @@ } }, "node_modules/@niivue/dcm2niix": { - "version": "0.1.1-dev.1", - "resolved": "https://registry.npmjs.org/@niivue/dcm2niix/-/dcm2niix-0.1.1-dev.1.tgz", - "integrity": "sha512-cwmBMALsFhTX+YOI1nAnQKe/CfkiPmJKPly3GVGxLy7sECJOlpwjziPkj/YUeHJImmurRKUVoC8qjVXSxUrofQ==", + "version": "0.1.1-dev.2", + "resolved": "https://registry.npmjs.org/@niivue/dcm2niix/-/dcm2niix-0.1.1-dev.2.tgz", + "integrity": "sha512-3iUrh7hW9/ezWTG74vIrl2eQJUAC8kv0vmwQzXiE88mu7e+Z3GMkmqmLVcJ9E9LjtIwQOnPfUB+Uj2Q8lU6acA==", "license": "BSD-2-Clause" }, "node_modules/@niivue/niivue": { diff --git a/package.json b/package.json index 9358603..9e4eb47 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "niivue-dcm2niix", "private": true, - "version": "1.0.0", + "version": "1.0.1", "type": "module", "scripts": { "dev": "vite", @@ -9,7 +9,7 @@ "preview": "vite preview" }, "dependencies": { - "@niivue/dcm2niix": "^0.1.1-dev.1", + "@niivue/dcm2niix": "^0.1.1-dev.2", "@niivue/niivue": "^0.45.1" }, "devDependencies": {