Mercurial > hg > orthanc-stl
comparison Sources/OrthancExplorer.js @ 31:ab231760799d
added button to import STL
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 04 Apr 2024 18:05:13 +0200 |
parents | dd0cd39e6259 |
children | 13698d34e059 |
comparison
equal
deleted
inserted
replaced
30:3570c23764d4 | 31:ab231760799d |
---|---|
145 }); | 145 }); |
146 } | 146 } |
147 } | 147 } |
148 | 148 |
149 | 149 |
150 $('#series').live('pagebeforeshow', function() { | 150 function AddGenerateFromNIfTIButton(studyId) { |
151 var seriesId = $.mobile.pageData.uuid; | 151 if (${HAS_CREATE_DICOM_STL} && |
152 | 152 ${SHOW_NIFTI_BUTTON}) { |
153 $('#stl-viewer-series').remove(); | 153 $('#stl-attach-nifti').remove(); |
154 $('#stl-generate-rtstruct-series').remove(); | 154 |
155 | 155 var nifti = $('<a>') |
156 GetResource('/series/' + seriesId, function(series) { | 156 .attr('id', 'stl-attach-nifti') |
157 if (series['Instances'].length == 1) { | |
158 var instanceId = series['Instances'][0]; | |
159 | |
160 $.ajax({ | |
161 url: '/instances/' + instanceId + '/metadata/SopClassUid', | |
162 success: function(sopClassUid) { | |
163 | |
164 if (sopClassUid == STL_PLUGIN_SOP_CLASS_UID_STL) { | |
165 // This is an "Encapsulated STL Storage" IOD, register the button | |
166 AddOpenStlViewerButton(instanceId, 'stl-viewer-series', 'series-info'); | |
167 } | |
168 else if (sopClassUid == STL_PLUGIN_SOP_CLASS_UID_RT_STRUCT) { | |
169 AddGenerateFromRtStructButton(instanceId, 'stl-generate-rtstruct-series', 'series-info'); | |
170 } | |
171 | |
172 } | |
173 }); | |
174 } | |
175 }); | |
176 }); | |
177 | |
178 | |
179 $('#instance').live('pagebeforeshow', function() { | |
180 var instanceId = $.mobile.pageData.uuid; | |
181 | |
182 $('#stl-viewer-instance').remove(); | |
183 $('#stl-generate-rtstruct-instance').remove(); | |
184 | |
185 $.ajax({ | |
186 url: '/instances/' + instanceId + '/metadata/SopClassUid', | |
187 success: function(sopClassUid) { | |
188 | |
189 if (sopClassUid == STL_PLUGIN_SOP_CLASS_UID_STL) { | |
190 // This is an "Encapsulated STL Storage" IOD, register the button | |
191 AddOpenStlViewerButton(instanceId, 'stl-viewer-instance', 'instance-info'); | |
192 } | |
193 else if (sopClassUid == STL_PLUGIN_SOP_CLASS_UID_RT_STRUCT) { | |
194 AddGenerateFromRtStructButton(instanceId, 'stl-generate-rtstruct-instance', 'instance-info'); | |
195 } | |
196 | |
197 } | |
198 }); | |
199 }); | |
200 | |
201 | |
202 $('#study').live('pagebeforeshow', function() { | |
203 if (${HAS_CREATE_DICOM_STL}) { | |
204 var studyId = $.mobile.pageData.uuid; | |
205 | |
206 $('#stl-attach-nifti-study').remove(); | |
207 | |
208 var b = $('<a>') | |
209 .attr('id', 'stl-attach-nifti-study') | |
210 .attr('data-role', 'button') | 157 .attr('data-role', 'button') |
211 .attr('href', '#') | 158 .attr('href', '#') |
212 .attr('data-icon', 'search') | 159 .attr('data-icon', 'search') |
213 .attr('data-theme', 'e') | 160 .attr('data-theme', 'e') |
214 .text('Attach NIfTI 3D model') | 161 .text('Attach NIfTI 3D model') |
215 .button(); | 162 .button(); |
216 | 163 |
217 b.insertAfter($('#study-info')); | 164 nifti.insertAfter($('#study-info')); |
218 b.click(function() { | 165 nifti.click(function() { |
219 | 166 |
220 var options = $('<ul>') | 167 var options = $('<ul>') |
221 .attr('data-divider-theme', 'd') | 168 .attr('data-divider-theme', 'd') |
222 .attr('data-role', 'listview'); | 169 .attr('data-role', 'listview'); |
223 | 170 |
224 var upload = $('<input>') | 171 var upload = $('<input>') |
225 .attr('type', 'file') | 172 .attr('type', 'file') |
226 .attr('id', 'stl-attach-nifti-study-upload') | 173 .attr('id', 'stl-attach-nifti-upload') |
227 .attr('data-theme', 'a'); | 174 .attr('data-theme', 'a'); |
228 | 175 |
229 options.append($('<li>').text('Choose the NIfTI file:')); | 176 options.append($('<li>').text('Choose the NIfTI file:')); |
230 options.append($('<li>').append(upload)); | 177 options.append($('<li>').append(upload)); |
231 options.append($('<li>').text('Resolution:')); | 178 options.append($('<li>').text('Resolution:')); |
232 options.append($('<li>').append($('<select>') | 179 options.append($('<li>').append($('<select>') |
233 .attr('id', 'stl-attach-nifti-study-resolution') | 180 .attr('id', 'stl-attach-nifti-resolution') |
234 .attr('data-theme', 'a') | 181 .attr('data-theme', 'a') |
235 .append($('<option>').attr('value', '256').text('256')) | 182 .append($('<option>').attr('value', '256').text('256')) |
236 .append($('<option>').attr('value', '128').text('128')) | 183 .append($('<option>').attr('value', '128').text('128')) |
237 .append($('<option>').attr('value', '512').text('512')))); | 184 .append($('<option>').attr('value', '512').text('512')))); |
238 options.append($('<li>') | 185 options.append($('<li>') |
239 .append($('<input>') | 186 .append($('<input>') |
240 .attr('id', 'stl-attach-nifti-study-smooth') | 187 .attr('id', 'stl-attach-nifti-smooth') |
241 .attr('type', 'checkbox') | 188 .attr('type', 'checkbox') |
242 .attr('data-theme', 'a') | 189 .attr('data-theme', 'a') |
243 .attr('checked', '')) | 190 .attr('checked', '')) |
244 .append($('<label>') | 191 .append($('<label>') |
245 .attr('for', 'stl-attach-nifti-study-smooth') | 192 .attr('for', 'stl-attach-nifti-smooth') |
246 .text('Smooth volume'))); | 193 .text('Smooth volume'))); |
247 | 194 |
248 options.append($('<li>').append( | 195 options.append($('<li>').append( |
249 $('<a>') | 196 $('<a>') |
250 .attr('href', '#') | 197 .attr('href', '#') |
251 .attr('rel', 'close').attr('data-theme', 'b') | 198 .attr('rel', 'close').attr('data-theme', 'b') |
252 .text('Generate') | 199 .text('Generate') |
253 .click(function(e) { | 200 .click(function(e) { |
254 e.preventDefault(); | 201 e.preventDefault(); |
255 | 202 |
256 var fileInput = document.getElementById('stl-attach-nifti-study-upload'); | 203 var fileInput = document.getElementById('stl-attach-nifti-upload'); |
257 var resolution = $('#stl-attach-nifti-study-resolution').val(); | 204 var resolution = $('#stl-attach-nifti-resolution').val(); |
258 var smooth = $('#stl-attach-nifti-study-smooth').is(':checked'); | 205 var smooth = $('#stl-attach-nifti-smooth').is(':checked'); |
259 | 206 |
260 if (fileInput.files.length == 0) { | 207 if (fileInput.files.length == 0) { |
261 alert('No NIfTI file was selected'); | 208 alert('No NIfTI file was selected'); |
262 return; | 209 return; |
263 } | 210 } |
302 headerClose: true, | 249 headerClose: true, |
303 forceInput: false, | 250 forceInput: false, |
304 width: '100%', | 251 width: '100%', |
305 blankContent: options | 252 blankContent: options |
306 }); | 253 }); |
307 | |
308 }); | 254 }); |
309 } | 255 } |
256 } | |
257 | |
258 | |
259 function AddImportSTLButton(studyId) { | |
260 if (${HAS_CREATE_DICOM_STL}) { | |
261 $('#stl-attach-instance').remove(); | |
262 | |
263 var instance = $('<a>') | |
264 .attr('id', 'stl-attach-instance') | |
265 .attr('data-role', 'button') | |
266 .attr('href', '#') | |
267 .attr('data-icon', 'search') | |
268 .attr('data-theme', 'e') | |
269 .text('Attach STL model') | |
270 .button(); | |
271 | |
272 instance.insertAfter($('#study-info')); | |
273 instance.click(function() { | |
274 | |
275 var options = $('<ul>') | |
276 .attr('data-divider-theme', 'd') | |
277 .attr('data-role', 'listview'); | |
278 | |
279 var upload = $('<input>') | |
280 .attr('type', 'file') | |
281 .attr('id', 'stl-attach-instance-upload') | |
282 .attr('data-theme', 'a'); | |
283 | |
284 options.append($('<li>').text('Choose the STL file:')); | |
285 options.append($('<li>').append(upload)); | |
286 | |
287 options.append($('<li>').text('Series description:')); | |
288 options.append($('<li>').append($('<input>') | |
289 .attr('type', 'text') | |
290 .attr('id', 'stl-attach-instance-description') | |
291 .attr('data-theme', 'b') | |
292 .val('Imported STL'))); | |
293 | |
294 options.append($('<li>').append( | |
295 $('<a>') | |
296 .attr('href', '#') | |
297 .attr('rel', 'close').attr('data-theme', 'b') | |
298 .text('Import') | |
299 .click(function(e) { | |
300 e.preventDefault(); | |
301 | |
302 var fileInput = document.getElementById('stl-attach-instance-upload'); | |
303 var description = $('#stl-attach-instance-description').val(); | |
304 | |
305 if (fileInput.files.length == 0) { | |
306 alert('No Instance file was selected'); | |
307 return; | |
308 } | |
309 | |
310 reader = new FileReader(); | |
311 reader.onload = function() { | |
312 | |
313 // https://github.com/axios/axios/issues/513 | |
314 var stl = reader.result; | |
315 var stlBase64 = btoa(new Uint8Array(stl).reduce((data, byte) => data + String.fromCharCode(byte), '')); | |
316 | |
317 $.ajax({ | |
318 url: '../tools/create-dicom', | |
319 type: 'POST', | |
320 data: JSON.stringify({ | |
321 'Content' : 'data:model/stl;base64,' + stlBase64, | |
322 'Parent' : studyId, | |
323 'Tags' : { | |
324 'SeriesDescription' : description | |
325 } | |
326 }), | |
327 dataType: 'json', | |
328 success: function(s) { | |
329 $.mobile.changePage('#series?uuid=' + s.ParentSeries, { | |
330 allowSamePageTransition: true | |
331 }); | |
332 }, | |
333 error: function() { | |
334 alert('Error while generating the 3D model'); | |
335 } | |
336 }); | |
337 | |
338 }; | |
339 | |
340 reader.readAsArrayBuffer(fileInput.files[0]); | |
341 }))); | |
342 | |
343 // Launch the dialog | |
344 $('#dialog').simpledialog2({ | |
345 mode: 'blank', | |
346 animate: false, | |
347 headerText: 'Attach STL', | |
348 headerClose: true, | |
349 forceInput: false, | |
350 width: '100%', | |
351 blankContent: options | |
352 }); | |
353 }); | |
354 } | |
355 } | |
356 | |
357 | |
358 | |
359 $('#series').live('pagebeforeshow', function() { | |
360 var seriesId = $.mobile.pageData.uuid; | |
361 | |
362 $('#stl-viewer-series').remove(); | |
363 $('#stl-generate-rtstruct-series').remove(); | |
364 | |
365 GetResource('/series/' + seriesId, function(series) { | |
366 if (series['Instances'].length == 1) { | |
367 var instanceId = series['Instances'][0]; | |
368 | |
369 $.ajax({ | |
370 url: '/instances/' + instanceId + '/metadata/SopClassUid', | |
371 success: function(sopClassUid) { | |
372 | |
373 if (sopClassUid == STL_PLUGIN_SOP_CLASS_UID_STL) { | |
374 // This is an "Encapsulated STL Storage" IOD, register the button | |
375 AddOpenStlViewerButton(instanceId, 'stl-viewer-series', 'series-info'); | |
376 } | |
377 else if (sopClassUid == STL_PLUGIN_SOP_CLASS_UID_RT_STRUCT) { | |
378 AddGenerateFromRtStructButton(instanceId, 'stl-generate-rtstruct-series', 'series-info'); | |
379 } | |
380 | |
381 } | |
382 }); | |
383 } | |
384 }); | |
310 }); | 385 }); |
386 | |
387 | |
388 $('#instance').live('pagebeforeshow', function() { | |
389 var instanceId = $.mobile.pageData.uuid; | |
390 | |
391 $('#stl-viewer-instance').remove(); | |
392 $('#stl-generate-rtstruct-instance').remove(); | |
393 | |
394 $.ajax({ | |
395 url: '/instances/' + instanceId + '/metadata/SopClassUid', | |
396 success: function(sopClassUid) { | |
397 | |
398 if (sopClassUid == STL_PLUGIN_SOP_CLASS_UID_STL) { | |
399 // This is an "Encapsulated STL Storage" IOD, register the button | |
400 AddOpenStlViewerButton(instanceId, 'stl-viewer-instance', 'instance-info'); | |
401 } | |
402 else if (sopClassUid == STL_PLUGIN_SOP_CLASS_UID_RT_STRUCT) { | |
403 AddGenerateFromRtStructButton(instanceId, 'stl-generate-rtstruct-instance', 'instance-info'); | |
404 } | |
405 | |
406 } | |
407 }); | |
408 }); | |
409 | |
410 | |
411 $('#study').live('pagebeforeshow', function() { | |
412 var studyId = $.mobile.pageData.uuid; | |
413 AddImportSTLButton(studyId); | |
414 AddGenerateFromNIfTIButton(studyId); | |
415 }); |