Compare commits

...
116 Commits
Author SHA1 Message Date
Ross f323dfd559 imrove multiuser sync support 2026-06-29 09:38:26 +01:00
Ross 0c4da6e022 multiuser sync updates 2026-06-22 09:37:08 +01:00
Ross d0f3431ef4 start ortho automode 2026-06-08 13:50:42 +01:00
Ross b961a806d9 start implmeentting proper crosshairs 2026-06-08 12:51:08 +01:00
Ross 1ddc9a810a update 2026-06-08 09:50:55 +01:00
Ross b2bd2791a5 fix some loading issues and rework cine button 2026-05-28 22:53:52 +01:00
Ross b527eb1139 many updates 2026-05-21 22:44:13 +01:00
Ross 6a0552c843 feat(mobile): implement mobile stack drag-and-drop functionality with improved viewport handling 2026-05-19 14:47:41 +01:00
Ross a5c530a907 feat(mobile): enhance mobile interaction with new touch controls and layout adjustments 2026-05-19 14:26:28 +01:00
Ross 41f13ade5e feat(b-values): implement parsing for multiple b-value formats and update default setting 2026-05-19 13:26:32 +01:00
Ross b0d8c72636 feat(logger): enhance logging configuration with minLevel and silent option
- Added a new LogLevel "silent" to suppress logging output.
- Replaced the debug boolean flag in LoggerConfig with a minLevel property to specify the minimum log level.
- Updated shouldLog function to respect the new minLevel configuration.
- Modified parseDebugFlag to return appropriate LogLevel based on truthy values.
- Updated main.tsx to accommodate changes in logging configuration, including parsing minLevel from attributes and options.
- Deprecated the debug flag in favor of minLevel for better clarity and control over logging behavior.
2026-05-19 12:55:44 +01:00
Ross 4dd63668b0 feat(logging): implement structured logging with configurable options
- Added a logger utility to manage logging levels and formats.
- Integrated logging into main application and non-DICOM test components.
- Enhanced error handling with logging for invalid JSON data.
- Introduced global functions to set and get logging configurations.
- Updated DICOM viewer mounting logic to support logging configurations.
2026-05-19 09:41:52 +01:00
Ross 77bbbd548e Enhance stack management by preventing duplicate stacks and optimizing stack index usage 2026-05-18 22:31:28 +01:00
Ross 7c17a27ec3 try to fix fluro 2026-05-18 17:26:27 +01:00
Ross 68248737ec Enhance stack management by adding series groups support and improving multiframe handling 2026-05-18 16:31:15 +01:00
Ross 13361a30a5 Refactor DICOM viewer mounting logic and enhance container management
- Introduced a new `mountContainer` function to handle individual container mounting and unmounting.
- Added `shouldMountContainer` to determine if a container should be mounted based on provided options.
- Enhanced `parseToDescriptors` to improve parsing of image stack data, supporting both named stacks and plain arrays.
- Updated `mountDicomViewers` to utilize the new mounting logic and streamline container processing.
- Exposed `remountDicomViewer` globally for dynamic remounting of specific containers.
- Removed redundant debug logging and improved error handling for invalid data.
2026-05-18 14:07:33 +01:00
Ross 627cd740f1 Enhance debugging capabilities by adding detailed logging for thumbnail generation and viewer mounting processes 2026-05-18 13:14:15 +01:00
Ross af6e22fd91 Enhance viewport preset management by adding active preset tracking and applying presets on image changes 2026-05-18 12:39:08 +01:00
Ross 7b786fcf9f Refactor stack thumbnail management with dedicated setter and localStorage integration for stack panel width 2026-05-18 12:33:28 +01:00
Ross c9902a2e15 Enhance loading state management by adding 'displayset' option and improve user feedback during data loading 2026-05-18 12:29:42 +01:00
Ross 99df1cd1c1 Add stripWadouriPrefix function and refactor image ID handling for improved URL normalization 2026-05-18 12:17:35 +01:00
Ross f169238057 Enhance viewer functionality with volume diagnostics and fullscreen toggle 2026-05-18 11:51:38 +01:00
Ross f0e0fe0ef6 Implement drag-and-drop functionality for viewport stack management with visual drop zone previews 2026-05-18 11:37:34 +01:00
Ross 19702b6052 Refactor CT presets and enhance modality-specific preset options for improved functionality 2026-05-18 10:48:28 +01:00
Ross 1674254a3c Add clearViewer function to reset viewer state and annotations 2026-05-11 11:34:36 +01:00
RossandCopilot aeb04bcf2f Refactor URL normalization to ensure valid wadouri: prefix for DICOM entries
Co-authored-by: Copilot <copilot@github.com>
2026-04-28 15:01:47 +01:00
Ross e29bce42e2 Implement resizable stack panel with min/max width constraints and update side menu button positioning 2026-04-27 12:02:54 +01:00
Ross d34772a3fa Refactor fullscreen exit logic to use appRootRef for improved reliability 2026-04-27 09:43:41 +01:00
Ross add45567d8 Enhance metadata caching in setLoadedImageIdsAndCacheMeta and add forced warm-up for visible stack viewports 2026-04-27 09:34:07 +01:00
Ross 3294151a92 Add shift key support for reference cursors and update button text 2026-04-27 09:26:27 +01:00
Ross 776b5faffe Refactor grid button styles for improved visibility and interaction 2026-04-27 09:21:59 +01:00
Ross c5a58da6a3 Refactor annotation import handling to improve race condition management and type safety 2026-03-23 11:08:21 +00:00
Ross be16e3554f Add defensive guards and queueing for annotation imports to handle race conditions 2026-03-23 11:02:03 +00:00
Ross 6cd9e33e65 Refactor annotation delete button styles for improved UI consistency 2026-03-23 10:41:36 +00:00
Ross e161377245 Add test links page for easy access to viewer test cases 2026-03-23 10:10:39 +00:00
Ross 1efd81bb0b Add embedded viewer test page with initial layout and functionality 2026-03-23 10:03:42 +00:00
Ross c0c5cd6195 Enhance tool options dropdowns to include icons for improved UI clarity 2026-03-23 09:43:57 +00:00
Ross 0c4db1904c Enhance tool options with icons for a more compact UI and improve annotation display styles for better readability 2026-03-16 14:29:39 +00:00
Ross 52f4be1a96 Refactor viewport state restoration and enhance error handling for volume and stack loading 2026-03-16 14:08:40 +00:00
Ross 8faa7e9be4 Add directory loading support and enhance file handling in the viewer 2026-03-16 12:31:42 +00:00
Ross adff7caffd Enhance error handling for graphics rendering and update external image loader registration 2026-03-16 11:09:04 +00:00
Ross 8dc4bb0aaa Add graphics error handling and notification for WebGL issues 2026-03-16 10:53:26 +00:00
Ross ef62ffac9f add basic non dicom support 2025-12-15 11:39:44 +00:00
Ross 72462b49ef Add support for external image loading and enhance pan/zoom interactions 2025-12-15 09:15:27 +00:00
Ross 181f471806 basic 2025-12-15 09:07:36 +00:00
Ross 8a0a08000e add basic thumbnail support 2025-12-15 09:04:54 +00:00
Ross 6ee9489a5f Add debug logging for thumbnail generation and improve error handling 2025-10-13 09:56:26 +01:00
Ross 6e70a32ffe Enhance dropdown scrolling behavior to prevent wheel event propagation and allow smooth navigation 2025-10-06 13:14:54 +01:00
Ross 5b3e47edea Add thumbnail generation for image stacks and improve rendering logic 2025-09-22 15:13:01 +01:00
Ross 8d67078a90 Add reset button to viewport for restoring default properties 2025-09-22 11:58:35 +01:00
Ross 9c3c3573bc Increase z-index for bottom controls to ensure proper layering and interaction 2025-09-22 11:56:24 +01:00
Ross f695fcccd0 Add thumbnail image display for stacks and relocate settings button to viewport area 2025-09-22 11:34:16 +01:00
Ross 2f14631ad0 Enhance right-side stack panel interaction with hover button and settings button adjustments 2025-09-22 11:26:30 +01:00
Ross 0ba752c28e Update settings button position to avoid overlap with right-side controls 2025-09-22 11:04:19 +01:00
Ross 82d4c94255 Refactor right-side stack panel to simplify open state management and remove pinning functionality 2025-09-22 11:03:30 +01:00
Ross f4497ef59d Remove right-side stack panel implementation and update comments for clarity 2025-09-22 10:59:33 +01:00
Ross e685b8b11d Refactor stack panel functionality to remove top bar and implement toggle for right-side panel visibility 2025-09-22 10:58:05 +01:00
Ross 67329d0468 Refactor layout to integrate right-side stack panel with improved hover and pinning functionality 2025-09-22 10:26:49 +01:00
Ross 6ab976a82b Add pinnable right-side stack panel with hover functionality 2025-09-22 09:47:31 +01:00
Ross 4bff9b39f3 Add toggle functionality for top stack bar visibility and persistent button to reveal it 2025-09-22 09:41:03 +01:00
Ross e6a6128aca Replace stackId with studyId in named stacks and update App component to include studyId in stack entries 2025-09-15 14:28:08 +01:00
Ross 654abaaaf4 Implement drag-and-drop functionality for stack selection and enhance stack grouping by studyId in the DICOM viewer 2025-09-15 14:14:47 +01:00
Ross 1a8fb26a29 Add stackId support to named stacks for improved data handling 2025-09-15 14:03:57 +01:00
Ross b66352f9b9 Enhance stack handling by adding studyId support and improving descriptor parsing logic 2025-09-15 13:48:25 +01:00
Ross 2c9b0345c4 Implement code changes to enhance functionality and improve performance 2025-09-15 12:42:55 +01:00
Ross 9080370bd1 Add CSS styles for improved layout and add named stacks examples in DICOM viewer 2025-09-15 12:40:11 +01:00
Ross 044057675e Enhance validation for DICOM viewer input data
- Added validation checks for nested stacks and stack objects to ensure imageIds are valid arrays of strings.
- Implemented console warnings for invalid entries, including nested stacks and stack objects, to aid in debugging.
- Improved error handling for unknown or invalid entries in the parsed data.
2025-09-15 12:33:35 +01:00
Ross 8de4efc3e2 refactor image stack handling to support richer data formats and improve clarity 2025-09-15 12:25:57 +01:00
Ross c3ea2b4478 add cornerstoneDICOMImageLoader to global window interface for enhanced accessibility 2025-09-15 12:18:18 +01:00
Ross e2f1afe225 add cornerstone3d to global window interface for enhanced functionality 2025-09-08 11:45:40 +01:00
Ross efc91f8b19 add mouse tool bindings persistence with localStorage 2025-08-11 11:01:39 +01:00
Ross de9cf60adc refactor context menu and keyboard navigation handling for improved clarity and maintainability 2025-08-11 10:58:22 +01:00
Ross c6f8b271a9 fix some display set restoring issues 2025-06-30 11:27:22 +01:00
Ross b917ca72c9 scope oncontextmenu correctly 2025-06-30 10:05:05 +01:00
Ross e6f64a6a97 allow annotation navigation disabling 2025-06-30 09:40:50 +01:00
Ross 3a92f5afba try and make preset menu always clickable 2025-06-30 09:29:57 +01:00
Ross 86a7bd143f allow bar navigation for volume 2025-06-23 16:27:29 +01:00
Ross 865bc956c7 fix loading window / level when importing volume 2025-06-23 16:01:14 +01:00
Ross c063a3a6f3 . 2025-06-23 15:15:58 +01:00
Ross d5046659fd fix scroll and position reloaded for volume 2025-06-23 15:12:33 +01:00
Ross 28884670e4 fix viewport overlay 2025-06-23 11:48:46 +01:00
Ross 98c71e73e2 . 2025-06-23 11:31:14 +01:00
Ross c27a52243f correct export volume orientation 2025-06-23 10:46:03 +01:00
Ross ce13f9cad2 add a few new features 2025-06-23 09:53:09 +01:00
Ross 11d1dc4339 . 2025-06-11 19:32:18 +01:00
Ross 21dca7d4b5 update packages 2025-06-10 10:14:58 +01:00
Ross f596dc83c9 . 2025-06-09 17:01:10 +01:00
Ross a9e3c215ed add props for annontations and viewerstate 2025-06-09 14:02:27 +01:00
Ross 28569a1c94 a lot of fixes 2025-06-09 13:31:56 +01:00
Ross 7d8caebf8c . 2025-06-09 10:18:02 +01:00
Ross adbbf48a28 . 2025-06-09 10:00:08 +01:00
Ross b1db098a49 fix annotation selection 2025-06-03 21:39:07 +01:00
Ross cdbe31df6b add simple annotation navigation 2025-06-03 16:22:01 +01:00
Ross c21fe2cbd7 fix viewport importing 2025-06-03 16:06:37 +01:00
Ross 8c218d42f4 get legacy annotation import working 2025-06-03 15:45:11 +01:00
Ross 2518da4413 numerous more fixes 2025-06-02 12:37:01 +01:00
Ross 43c3f75889 some cleanup and start movinig to multiple instances 2025-06-02 10:39:07 +01:00
Ross 3f6c68523e . 2025-06-02 10:30:21 +01:00
Ross 38620d969b add a new no label arrow tool 2025-06-02 10:17:51 +01:00
Ross b408ba96b3 fix tool import 2025-06-02 09:59:51 +01:00
Ross 1fd3020f0c improve export schema 2025-06-01 22:17:41 +01:00
Ross 313c7a9e9a basic viewport save and restore fnuctiontality 2025-05-31 21:29:37 +01:00
Ross 40be13b51a some visual tidy up 2025-05-31 15:28:40 +01:00
Ross 4875b95ab2 more improvements 2025-05-31 15:14:46 +01:00
Ross c7728bf1a2 further improvements 2025-05-31 11:24:20 +01:00
Ross c90c280255 start fixing ts errors 2025-05-31 10:23:52 +01:00
Ross be0d71d19d . 2025-05-30 18:06:22 +01:00
Ross 92e07717da pre mouse changes 2025-05-29 22:35:06 +01:00
Ross 52776fa71b fix image index positioning 2025-05-27 23:12:35 +01:00
Ross a245c55216 finish reference cursors 2025-05-27 22:09:45 +01:00
Ross ffb478af59 working reference lines 2025-05-27 16:25:12 +01:00
Ross 81edcea5ea basic reference line functions 2025-05-25 21:13:45 +01:00
Ross a803e351c3 pre perviewport stacks 2025-05-24 22:37:19 +01:00
Ross 8d673fe28d lots of fixes 2025-05-24 22:12:59 +01:00
Ross 1eba20c27a start adding volume toolgroup 2025-05-24 12:26:02 +01:00
Ross e7d584cd87 numerous fixes 2025-05-24 11:17:39 +01:00
291 changed files with 13962 additions and 2028 deletions
+193 -1
View File
@@ -5,9 +5,201 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<style>
html, body {
height: auto;
min-height: 100%;
overflow: unset!important;
margin: 0;
}
/* Make viewer roots flow normally on the page */
.dicom-viewer-root {
display: block;
}
</style>
</head>
<body>
<div id="root"></div>
<!-- <div id="root" class="dicom-viewer-test-root" style="max-height:500px; height:500px; overflow:auto;"></div> -->
<div id="root" class="dicom-viewer-root" style="max-height:500px; height:500px; overflow:auto;"
data-images="[&quot;http://localhost:8000/media/atlas/dicom/0fb1283bab62d691bdaf7c7e47b8c674b600cddb.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/c98950f460ed153c14bd1d0d32e712397ace4564.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/512bfc7f9d07d54ae8f92af1ab98be390174d618.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/5f0a6b97da797b7639361732599bfcf607c17dfc.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/c5f854a8c2ac36da60c8a5a2bc215639d5302d20.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/0cec8d98bd80818c38c657b9c5934b30316920a2.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/613166d33e9e35898238f0bd334969c500822bbf.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/48801a3aa1fea5d943cc934b74e9bc7273c1e944.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/db8ddb477387a41b023efae98e7e40be890886ef.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/8720dc9b0b3b2c596f1d87acc951818307b7ad6a.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/24d1e5397fa97dd0c904568a20e4649fea13d1cf.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/bb586d17474988a07b1c90afce456abd7f69a753.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/24fa49c0e482bb885c92b71f74451f558940cb4b.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/6d9b09614f74b21a0b2778a5129d22b3cbafd3da.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/39963ce191beafe943a9cf980f7320adad74c1d5.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/09adc694456f1e51a5ab9c1cf7eaf9d748c938db.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/d4f6521a9e9a26975e1218ba3b7f48a78ac46d8f.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/0e1490ed17cdf2ceb1bcf069400f8f47a4437561.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/2cb43b50760d9335df9a5f2d6bd645daf2a0c917.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/9b02fae29bf6e775c5ba94b0b7158e10d4697ff6.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/9628d1d2fb457bc6f03efa8c980ef3165092230f.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/b879d6488a79d38ba374366f5543aab49fa8cb86.dcm&quot;]"
data-auto-cache-stack="true"
data-viewerstate='{"grid":{"rows":1,"cols":3},"modes":["stack","volume","volume"],"stacks":[{"i":["wadouri:http://localhost:8000/media/atlas/dicom/b879d6488a79d38ba374366f5543aab49fa8cb86.dcm","wadouri:http://localhost:8000/media/atlas/dicom/9628d1d2fb457bc6f03efa8c980ef3165092230f.dcm","wadouri:http://localhost:8000/media/atlas/dicom/9b02fae29bf6e775c5ba94b0b7158e10d4697ff6.dcm","wadouri:http://localhost:8000/media/atlas/dicom/2cb43b50760d9335df9a5f2d6bd645daf2a0c917.dcm","wadouri:http://localhost:8000/media/atlas/dicom/0e1490ed17cdf2ceb1bcf069400f8f47a4437561.dcm","wadouri:http://localhost:8000/media/atlas/dicom/d4f6521a9e9a26975e1218ba3b7f48a78ac46d8f.dcm","wadouri:http://localhost:8000/media/atlas/dicom/09adc694456f1e51a5ab9c1cf7eaf9d748c938db.dcm","wadouri:http://localhost:8000/media/atlas/dicom/39963ce191beafe943a9cf980f7320adad74c1d5.dcm","wadouri:http://localhost:8000/media/atlas/dicom/6d9b09614f74b21a0b2778a5129d22b3cbafd3da.dcm","wadouri:http://localhost:8000/media/atlas/dicom/24fa49c0e482bb885c92b71f74451f558940cb4b.dcm","wadouri:http://localhost:8000/media/atlas/dicom/bb586d17474988a07b1c90afce456abd7f69a753.dcm","wadouri:http://localhost:8000/media/atlas/dicom/24d1e5397fa97dd0c904568a20e4649fea13d1cf.dcm","wadouri:http://localhost:8000/media/atlas/dicom/8720dc9b0b3b2c596f1d87acc951818307b7ad6a.dcm","wadouri:http://localhost:8000/media/atlas/dicom/db8ddb477387a41b023efae98e7e40be890886ef.dcm","wadouri:http://localhost:8000/media/atlas/dicom/48801a3aa1fea5d943cc934b74e9bc7273c1e944.dcm","wadouri:http://localhost:8000/media/atlas/dicom/613166d33e9e35898238f0bd334969c500822bbf.dcm","wadouri:http://localhost:8000/media/atlas/dicom/0cec8d98bd80818c38c657b9c5934b30316920a2.dcm","wadouri:http://localhost:8000/media/atlas/dicom/c5f854a8c2ac36da60c8a5a2bc215639d5302d20.dcm","wadouri:http://localhost:8000/media/atlas/dicom/5f0a6b97da797b7639361732599bfcf607c17dfc.dcm","wadouri:http://localhost:8000/media/atlas/dicom/512bfc7f9d07d54ae8f92af1ab98be390174d618.dcm","wadouri:http://localhost:8000/media/atlas/dicom/c98950f460ed153c14bd1d0d32e712397ace4564.dcm","wadouri:http://localhost:8000/media/atlas/dicom/0fb1283bab62d691bdaf7c7e47b8c674b600cddb.dcm"],"u":"2.1163931708166249655895918785713305273005"}],"stackIdx":[0,0,0],"stackPos":[0,173,10],"props":[{"voiRange":{"lower":-958.5,"upper":705.5},"invert":false,"interpolationType":1,"VOILUTFunction":"LINEAR"},{"voiRange":{"lower":-1798,"upper":1641},"invert":false,"colormap":{"name":"Grayscale","opacity":1,"threshold":null}},{"voiRange":{"lower":302,"upper":2069},"invert":false,"colormap":{"name":"Grayscale","opacity":1,"threshold":null}}],"cam":[{"viewUp":[-0.015545368194580078,-0.12045262008905411,0.9925973415374756],"viewPlaneNormal":[0.9998766662057034,-0.00409140293321022,0.015162875697125405],"position":[276.090926593084,-63.25300826357402,25.12347315106698],"focalPoint":[59.93107667300279,-62.36850213007119,21.845463926704127],"parallelProjection":true,"parallelScale":170.33890849893743,"viewAngle":90,"flipHorizontal":false,"flipVertical":false,"rotation":0},{"viewUp":[0,0,1],"viewPlaneNormal":[0,-1,0],"position":[-6.060784295600456,-273.9517816053456,20.844714115543866],"focalPoint":[-6.060784295600456,-46.51629576550185,20.844714115543866],"parallelProjection":true,"parallelScale":150.85189284207627,"viewAngle":90,"flipHorizontal":false,"flipVertical":false,"rotation":0},{"viewUp":[0,0,1],"viewPlaneNormal":[1,0,0],"position":[218.5103649207617,-62.09846953239139,20.844714115543866],"focalPoint":[-8.925120919082055,-62.09846953239139,20.844714115543866],"parallelProjection":true,"parallelScale":157.88941096127814,"viewAngle":90,"flipHorizontal":false,"flipVertical":false,"rotation":0}],"orientations":[null,"coronal","sagittal"],"volumeSliceIndices":[null,173,10]}'
></div>
<!--
<div
class="dicom-viewer-root"
id="viewer_named_simple"
data-named-stacks='[
{
"name": "CT Head (Study A)",
"imageIds": [
"http://localhost:8000/media/atlas/dicom/head_0001.dcm",
"http://localhost:8000/media/atlas/dicom/head_0002.dcm",
"http://localhost:8000/media/atlas/dicom/head_0003.dcm"
]
},
{
"name": "CT Chest (Study B)",
"imageIds": [
"wadouri:http://localhost:8000/media/atlas/dicom/chest_0001.dcm",
"wadouri:http://localhost:8000/media/atlas/dicom/chest_0002.dcm"
]
}
]'
style="width:600px;height:400px;"
></div>
<div
class="dicom-viewer-root"
id="viewer_named_cases"
data-named-stacks='[
{
"caseId": "CASE-001",
"studyId": "STUDY-001",
"stacks": [
{
"name": "Abdomen - Portal Venous",
"imageIds": [
"http://localhost:8000/media/atlas/dicom/abdomen_pv_0001.dcm",
"http://localhost:8000/media/atlas/dicom/abdomen_pv_0002.dcm"
]
},
{
"name": "Abdomen - Non-contrast",
"imageIds": [
"http://localhost:8000/media/atlas/dicom/abdomen_nc_0001.dcm"
]
}
]
},
{
"caseId": "CASE-002",
"studyId": "STUDY-002",
"stacks": [
{
"name": "Chest - CTA",
"imageIds": [
"http://localhost:8000/media/atlas/dicom/cta_0001.dcm",
"http://localhost:8000/media/atlas/dicom/cta_0002.dcm"
]
}
]
}
]'
style="width:600px;height:400px;margin-top:12px;"
></div> -->
<!-- <div id="root2" class="dicom-viewer-root" style="max-height:500px; height:500px; overflow:auto;"
data-images="[&quot;http://localhost:8000/media/atlas/dicom/4596ea7654b7a5074d2c3f40039c556b11fb01ae.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/b2fa301bc731d15be3e000402c9a79c114d17aa5.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/66310ef801fbecb37c5ced160c450dfd5ecc6d2d.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/63d2d117bf256a76a61190066f91eda6c4d67c8f.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/181a3575ea7fb8bf8f6449ff61e6e369a3247454.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/7c5c0538339266ac8897fa21c481b2f61172068e.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/1681410681308af7111af6644fed598fde304b96.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/4adcd3d7a64a9c59b530f730ce0d991bf7f27813.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/671e6004c7fb402a627a2282bbf304d7b4dcc12b.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/8d18ac56914b9de72b8aecced09654ec4b2c9bb7.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/74ce708a90dff0636fc4bc914fe47e8b6d9320bd.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/a96b6c9900570e076edf849a0ae3b52734ed2650.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/0183718d9336458478ec42130395d78e01492bd6.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/52eee968bbce5590274346eed43f1837f9daba11.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/961449f88197566c4643fcfd20f48ea4e810490b.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/1a16ad5b25e11739eadbcb8ea461072b100113a0.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/b89ddcc3f499059d2dedb0028a2bb1ce4abf5574.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/c1379c03a4e449c2fa88784d601cb766af907739.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/4fb532d5003c59a73f7e4248f365b1a8660ea710.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/e861b0de042a1f213cbccc995679aacd29c7ef53.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/1a854282afe264c3afff6a6e287cd646b2193a0c.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/f59d6d9bc33160abad3af8e2b246179b3574d884.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/04fadab0ed8b3f1925e601c4f9cfb792c95626c2.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/d45d0b12fb650e65daeeee4e5fa3b21c988597f6.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/e19c47b7787ac45dbc225319dfa143dc2c1fdf1f.dcm&quot;, &quot;http://localhost:8000/media/atlas/dicom/dccabf3103a5be254a45457ce2d8d9ce9cb19a6a.dcm&quot;]"
data-auto-cache-stack="true"
></div> -->
<script type="module" src="/src/main.tsx"></script>
<input type="file" id="dicomInput" multiple />
<button onclick="sendToViewer()">Send to Viewer</button>
<button onclick="testLoadWadouriStack()">Test Load wadouri Stack</button>
<button onclick="testLoadWadouriStack2()">Test Load wadouri Stack 2</button>
<script>
function sendToViewer() {
const files = document.getElementById('dicomInput').files;
if (window.loadDicomStackFromFiles) {
window.loadDicomStackFromFiles(files);
} else {
alert("Viewer API not ready");
}
}
function testLoadWadouriStack() {
const urls = [
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_757_XQQyovo.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_766_8fWI0Qc.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_774_c8IpxUu.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_758_6WKI7ws.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_767_TduVOb8.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_775_7zWneQ0.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_759_BtKzgS5.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_768_RdvtM8K.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_776_LhVY3Ty.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_760_a8CiR4J.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_769_YHyJ1l6.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_777_8IFYJmL.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_761_vyvO1EN.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_770_vQwi4LW.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_778_BwGAMOR.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_762_DhSgQsm.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_771_xifitCl.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_779_LyA1zYn.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_763_aVjff3H.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_772_cDQZtxQ.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_780_qaZqsqg.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_764_dDoeldL.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_773_93Hvedg.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_781_bEx9Owg.dcm",
"https://www.penracourses.org.uk/media/atlas/dicom/IMG_765_qmd5mYJ.dcm"
];
const wadouriList = urls.map(url => "wadouri:" + url);
if (window.loadDicomStackFromWadouriList) {
window.loadDicomStackFromWadouriList(wadouriList);
} else {
alert("Viewer API not ready");
}
}
function testLoadWadouriStack2() {
const urls = [
"https://www.penracourses.org.uk/media/atlas/picture/37b89ead539fdbbc719845333ed89498fc1e2feb",
"https://www.penracourses.org.uk/media/atlas/picture/6eefab8694dbdcb38e8732319f38eabd14068d0d",
"https://www.penracourses.org.uk/media/atlas/picture/27faaddb0167f359bae951020cabd15b9158c15f",
"https://www.penracourses.org.uk/media/atlas/picture/8097cd95acca6c1a97f050ec5c96c1661290058d",
"https://www.penracourses.org.uk/media/atlas/picture/5dd6147fa3362ab52b87903aa670c1ee6e489b78",
"https://www.penracourses.org.uk/media/atlas/picture/c8a794e75a3a28177c71792044518a4a294dc6c6",
"https://www.penracourses.org.uk/media/atlas/picture/6102f3d482e8242cd4ca9e3477c3e8ede5cd6b49",
"https://www.penracourses.org.uk/media/atlas/picture/2f3407a8fafd283a219cec01c45190907b5214f6",
"https://www.penracourses.org.uk/media/atlas/picture/ae61b2c4a09c810a7711aa473b4c5553816a2c47",
"https://www.penracourses.org.uk/media/atlas/picture/c1ac31aebba99645c11e11ac4e96bef8a544ffe1",
"https://www.penracourses.org.uk/media/atlas/picture/c357353b07d4366802b68a9c7ba90104b64f0b06",
"https://www.penracourses.org.uk/media/atlas/picture/ac80a92442a68ca58a0b5c793c9ff39678cf1267",
"https://www.penracourses.org.uk/media/atlas/picture/2856b3a5503540f2d5257d1b1793a3a2ee31024f",
"https://www.penracourses.org.uk/media/atlas/picture/f097bd9d1d9ae33fd20ee57bd4de8187cf338913",
"https://www.penracourses.org.uk/media/atlas/picture/76a764bdc860182374a0701f1c338bdf7d8e05a0",
"https://www.penracourses.org.uk/media/atlas/picture/1c09f607ca2485b2681197e6e8555393879e5a04",
"https://www.penracourses.org.uk/media/atlas/picture/616498815182e1d093c0011b90c3fb309caadb8f",
"https://www.penracourses.org.uk/media/atlas/picture/9d04d2370d3f8e3b0220ff0f460ba12625ef3857",
"https://www.penracourses.org.uk/media/atlas/picture/fb94a8645a0159b0e9725c0718dd723f86008008",
"https://www.penracourses.org.uk/media/atlas/picture/43cb8280cb9dd96ddfde8028cfb20e60dfe5d756",
"https://www.penracourses.org.uk/media/atlas/picture/65a8cbbc9b837e66e1f07ed6ecbc1dd22ea28b65",
"https://www.penracourses.org.uk/media/atlas/picture/147a29e905fcc3c0bd2d38848beb80328c007436",
"https://www.penracourses.org.uk/media/atlas/picture/2b8fde7b6736bd5eba3f64bd26b291634ff9a719",
"https://www.penracourses.org.uk/media/atlas/picture/9904072307db5935bc07c1eda762aebb972950e8",
"https://www.penracourses.org.uk/media/atlas/picture/3b4b4f1ab6c5b944c267209bb298281e0f669a2d",
"https://www.penracourses.org.uk/media/atlas/picture/6530f91afa0021dd5ca6f4f067112ef647c42314",
"https://www.penracourses.org.uk/media/atlas/picture/2a071c131e484213b7198c6320e8a63a176b34b0",
"https://www.penracourses.org.uk/media/atlas/picture/efb13b2d01651b542880ef8d1d09487bc128a459",
"https://www.penracourses.org.uk/media/atlas/picture/272800e852655f6c9ec107bd31c620e8f774afea",
"https://www.penracourses.org.uk/media/atlas/picture/3434977ed6d75f858b02e86c9e616cd774c5c9bf",
"https://www.penracourses.org.uk/media/atlas/picture/1b1fa4cfd2a177db0f449e4a37634250e69ec7e1",
"https://www.penracourses.org.uk/media/atlas/picture/72ea7d1b931f246e340665cbe067c3cb4a22176d",
"https://www.penracourses.org.uk/media/atlas/picture/f8c1d6dd25617f0c710e2f01b05d1cba3d72367f",
"https://www.penracourses.org.uk/media/atlas/picture/333b535df6f5e501a5a8a70c2156fcb3f94c23f8",
"https://www.penracourses.org.uk/media/atlas/picture/2ccb2a892d1d2d7022ddf7e59ccb3a184fb2676a",
"https://www.penracourses.org.uk/media/atlas/picture/a9bef320ed90508f5466010a6af8eee86b6324c2",
"https://www.penracourses.org.uk/media/atlas/picture/ba714cdffe76cfa95f8f7d9dee940d1ed8b8be77",
"https://www.penracourses.org.uk/media/atlas/picture/1f2a1b7a371f72a2696c003f551caa92ebee2cc7",
"https://www.penracourses.org.uk/media/atlas/picture/387d0fb40b96d5c532d66329f964811ca54d9c46",
"https://www.penracourses.org.uk/media/atlas/picture/71e0c4b40bd12bb7fa5d8aa30e60c58dd936ccc0"
];
const wadouriList = urls.map(url => "wadouri:" + url);
if (window.loadDicomStackFromWadouriList) {
window.loadDicomStackFromWadouriList(wadouriList);
} else {
alert("Viewer API not ready");
}
}
</script>
</body>
</html>
+3259 -1584
View File
File diff suppressed because it is too large Load Diff
+9 -7
View File
@@ -5,16 +5,19 @@
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"build": "tsc && vite build && cp dist/index.js /home/ross/penracourses/rad/rad/static/dv3d/index.js",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@cornerstonejs/calculate-suv": "1.1.0",
"@cornerstonejs/core": "^2.1.16",
"@cornerstonejs/dicom-image-loader": "^2.1.16",
"@cornerstonejs/nifti-volume-loader": "^2.1.16",
"@cornerstonejs/tools": "^2.1.16",
"@cornerstonejs/calculate-suv": "^1.1.0",
"@cornerstonejs/core": "^3.19.5",
"@cornerstonejs/dicom-image-loader": "^3.19.5",
"@cornerstonejs/nifti-volume-loader": "^3.19.5",
"@cornerstonejs/tools": "^3.19.5",
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-charls": "^1.2.3",
"@cornerstonejs/codec-openjpeg": "^1.2.4",
"dcmjs": "0.33.0",
"dicom-parser": "1.8.21",
"dicomweb-client": "0.10.4",
@@ -43,7 +46,6 @@
"rollup-plugin-dts": "^6.1.1",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-terser": "^7.0.2",
"typescript": "^5.6.3",
"vite": "^5.2.0",
"vite-plugin-static-copy": "^1.0.5"
@@ -0,0 +1,129 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Embedded Viewer — Test Page</title>
<style>
html,body{height:100%;margin:0;font-family:system-ui,Segoe UI,Roboto,Helvetica,Arial}
header{background:#111;color:#fff;padding:12px 20px}
header h1{margin:0;font-size:18px}
.page{display:flex;gap:20px;padding:20px}
.main{flex:1}
.sidebar{width:260px;background:#f6f6f6;padding:12px;border-radius:6px}
.dicom-viewer-root{width:100%;height:72vh;background:#222;color:#fff;border-radius:6px;overflow:hidden}
.controls{margin:12px 0}
.note{background:#eef;padding:10px;border-radius:4px}
</style>
</head>
<body>
<header>
<h1>Embedded Viewer Test</h1>
</header>
<div class="page">
<main class="main">
<p class="note">This page demonstrates the DICOM viewer embedded alongside other content.</p>
<div class="controls">
<button onclick="document.getElementById('main_viewer').scrollIntoView({behavior:'smooth'})">Scroll to viewer</button>
<button onclick="console.log('Example action')">Example action</button>
</div>
<div id="main_viewer" class="dicom-viewer-root" data-auto-cache-stack="false"></div>
<section style="margin-top:16px">
<h2>Related information</h2>
<p>Here you can place text, controls, or other UI components while the viewer stays mounted within the page layout.</p>
</section>
</main>
<aside class="sidebar">
<h3>Sidebar</h3>
<p>Extra controls, metadata, or notes can live here.</p>
<ul>
<li>Patient: Anonymous</li>
<li>Study: Demo stack</li>
<li>Notes: Test page</li>
</ul>
</aside>
</div>
<!-- Provide noop React Refresh preamble to avoid plugin-react runtime errors -->
<script>
window.$RefreshReg$ = window.$RefreshReg$ || function() {};
window.$RefreshSig$ = window.$RefreshSig$ || function() { return function(type) { return type; }; };
</script>
<script type="module" src="/src/main.tsx"></script>
<script>
// Reuse the same viewer state as the penra test for convenience
const state = {"grid":{"rows":1,"cols":3},"modes":["stack","stack","stack"],"stacks":[{"i":["wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_573_PN7j4gd.dcm","wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_580_kBgyDxS.dcm","wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_572_DYQisSg.dcm"]},{"i":["wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_588_tGfMjqb.dcm","wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_592_Js4efiI.dcm","wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_584_U8WCsNY.dcm"]},{"i":["wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_631_NxRBhMn.dcm","wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_619_2cVhUyC.dcm","wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_607_VvL52Af.dcm"]}],"stackIdx":[0,2,1],"stackPos":[0,0,2],"props":[{"voiRange":{"lower":39.15,"upper":559.17},"invert":false,"interpolationType":1,"VOILUTFunction":"LINEAR","colormap":{"name":"Grayscale","opacity":[]}}],"cam":[null,null,null],"orientations":[null,null,null],"volumeSliceIndices":[null,null,null]};
function callWhenReady(fnName, payload) {
const maxWait = 5000;
const start = Date.now();
(function check() {
if (window[fnName] && typeof window[fnName] === 'function') {
try {
window[fnName](payload);
console.log('imported viewer state via', fnName);
} catch (e) {
console.error('importViewerState call failed', e);
}
return;
}
if (Date.now() - start > maxWait) {
console.warn('Timed out waiting for', fnName);
return;
}
setTimeout(check, 2000);
})();
}
document.addEventListener('DOMContentLoaded', () => {
(function loadStacksThenImport() {
if (!state.stacks || !Array.isArray(state.stacks)) {
callWhenReady('importViewerState_main_viewer', state);
return;
}
function pushStacks() {
const fnName = 'loadAdditionalStack_main_viewer';
if (window[fnName] && typeof window[fnName] === 'function') {
try {
state.stacks.forEach(s => {
if (s && Array.isArray(s.i) && s.i.length) {
window[fnName](s.i);
}
});
console.log('Requested viewer to load', state.stacks.length, 'stacks');
} catch (e) {
console.warn('loadAdditionalStack call failed', e);
}
setTimeout(() => { callWhenReady('importViewerState_main_viewer', state); }, 2000);
return true;
}
return false;
}
const started = pushStacks();
if (!started) {
const maxWait = 5000;
const start = Date.now();
(function waitForApi() {
if (pushStacks()) return;
if (Date.now() - start > maxWait) {
console.warn('Timed out waiting for loadAdditionalStack API; importing state directly');
callWhenReady('importViewerState_main_viewer', state);
return;
}
setTimeout(waitForApi, 2000);
})();
}
})();
});
</script>
</body>
</html>
+29
View File
@@ -0,0 +1,29 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Empty Viewer Test</title>
<style>
html,body{height:100%;margin:0}
.dicom-viewer-root{width:100%;height:100vh;background:#222;color:#fff}
</style>
</head>
<body>
<div id="root" class="dicom-viewer-root" style="width:100%;height:100vh;"
data-auto-cache-stack="false"
data-empty="true"
></div>
<!-- Provide a small noop React Refresh preamble to avoid plugin-react preamble errors -->
<script>
// If plugin-react's preamble wasn't injected for some reason, provide no-op
// implementations so the runtime does not throw. This disables fast-refresh
// semantics for this page but keeps HMR from crashing.
window.$RefreshReg$ = window.$RefreshReg$ || function() {};
window.$RefreshSig$ = window.$RefreshSig$ || function() { return function(type) { return type; }; };
</script>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+128
View File
@@ -0,0 +1,128 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Fluoro Multiframe Test</title>
<style>
html,
body {
height: 100%;
margin: 0;
}
.dicom-viewer-root {
width: 100%;
height: 100vh;
background: #222;
color: #fff;
}
</style>
</head>
<body>
<div
id="main_viewer"
class="dicom-viewer-root"
data-auto-cache-stack="false"
></div>
<!-- Provide noop React Refresh preamble to avoid plugin-react runtime errors -->
<script>
window.$RefreshReg$ = window.$RefreshReg$ || function () {};
window.$RefreshSig$ =
window.$RefreshSig$ ||
function () {
return function (type) {
return type;
};
};
</script>
<script type="module" src="/src/main.tsx"></script>
<script>
// Viewer state for fluoro multiframe images (using relative paths from public/test_images/)
const state = {
grid: { rows: 1, cols: 2 },
modes: ["stack", "stack"],
stacks: [
{
i: [
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/1.3.12.2.1107.5.4.5.180506.30000026031914043350300000126.4.dcm",
],
},
],
stackIdx: [0, 1],
stackPos: [0, 1],
props: [
{
voiRange: { lower: 0, upper: 500 },
invert: false,
interpolationType: 1,
VOILUTFunction: "LINEAR",
colormap: { name: "Grayscale", opacity: [] },
},
{
voiRange: { lower: 0, upper: 500 },
invert: false,
interpolationType: 1,
VOILUTFunction: "LINEAR",
colormap: { name: "Grayscale", opacity: [] },
},
],
cam: [
{
viewUp: [0, 0, 1],
viewPlaneNormal: [1, 0, 0],
position: [150, 0, 0],
focalPoint: [0, 0, 0],
parallelProjection: true,
parallelScale: 100,
viewAngle: 90,
flipHorizontal: false,
flipVertical: false,
rotation: 0,
},
{
viewUp: [0, 0, 1],
viewPlaneNormal: [1, 0, 0],
position: [150, 0, 0],
focalPoint: [0, 0, 0],
parallelProjection: true,
parallelScale: 100,
viewAngle: 90,
flipHorizontal: false,
flipVertical: false,
rotation: 0,
},
],
orientations: [null, null],
volumeSliceIndices: [null, null],
};
function callWhenReady(fnName, payload) {
const maxWait = 5000;
const start = Date.now();
(function check() {
if (window[fnName] && typeof window[fnName] === "function") {
try {
window[fnName](payload);
console.log("imported viewer state via", fnName);
} catch (e) {
console.error("importViewerState call failed", e);
}
return;
}
if (Date.now() - start > maxWait) {
console.warn("Timed out waiting for", fnName);
return;
}
setTimeout(check, 2000);
})();
}
document.addEventListener("DOMContentLoaded", () => {
callWhenReady("importViewerState", state);
});
</script>
</body>
</html>
+196
View File
@@ -0,0 +1,196 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Load Directory Test</title>
<style>
body { font-family: system-ui, Arial; padding: 18px; background: #f6f6f8; color: #111 }
.controls { margin: 12px 0 }
.file-row { display:flex; gap:8px; align-items:center; padding:6px 8px; border-bottom:1px solid #eee }
.path { font-family: monospace; color:#444; flex:1 }
button { padding:6px 10px }
#fileList { border:1px solid #ddd; background:#fff; border-radius:6px; max-height:60vh; overflow:auto }
</style>
</head>
<body>
<h2>Directory Loader (recursive)</h2>
<p>Select a folder (uses `webkitdirectory`) — files will be read recursively.
This page will call <code>window.loadDicomStackFromFiles(files)</code> if available in the viewer.</p>
<div class="controls">
<input id="dirInput" type="file" webkitdirectory directory multiple />
<label style="margin-left:12px"><input id="onlyDcm" type="checkbox" checked /> Show only <code>.dcm</code></label>
<button id="loadSelected">Load Selected</button>
<button id="loadAll">Load All</button>
<button id="openViewerAndSend">Open Viewer & Send</button>
<button id="clear">Clear</button>
</div>
<div id="fileList"></div>
<script>
(function(){
const input = document.getElementById('dirInput');
const fileListDiv = document.getElementById('fileList');
const onlyDcmChk = document.getElementById('onlyDcm');
function asArray(fileList){ return Array.prototype.slice.call(fileList || []); }
function renderFiles(files){
fileListDiv.innerHTML = '';
if (!files || files.length === 0) {
fileListDiv.innerHTML = '<div style="padding:12px;color:#666">No files selected</div>';
return;
}
const frag = document.createDocumentFragment();
files.forEach((f, idx) => {
const row = document.createElement('div');
row.className = 'file-row';
const cb = document.createElement('input');
cb.type = 'checkbox';
cb.checked = true;
cb.dataset.idx = idx;
const pathEl = document.createElement('div');
pathEl.className = 'path';
// webkitRelativePath shows the folder structure when directory input used
pathEl.textContent = f.webkitRelativePath || f.name;
const sizeEl = document.createElement('div');
sizeEl.style.width = '90px';
sizeEl.style.textAlign = 'right';
sizeEl.style.color = '#666';
sizeEl.textContent = (f.size/1024).toFixed(1)+' kB';
row.appendChild(cb);
row.appendChild(pathEl);
row.appendChild(sizeEl);
frag.appendChild(row);
});
fileListDiv.appendChild(frag);
}
function filterFiles(files){
const onlyDcm = onlyDcmChk.checked;
if (!onlyDcm) return files;
return files.filter(f => f.name.toLowerCase().endsWith('.dcm'));
}
input.addEventListener('change', ()=>{
const all = asArray(input.files);
const filtered = filterFiles(all);
// Save filtered list on the element for retrieval
input._currentFiles = filtered;
renderFiles(filtered);
});
document.getElementById('loadSelected').addEventListener('click', ()=>{
const current = input._currentFiles || [];
if (!current.length) return alert('No files selected. Choose a folder first.');
// collect checked indices
const checked = Array.from(fileListDiv.querySelectorAll('input[type=checkbox]'))
.filter(cb=>cb.checked)
.map(cb=>parseInt(cb.dataset.idx,10))
.filter(n=>!Number.isNaN(n));
const chosen = checked.map(i=>current[i]).filter(Boolean);
if (!chosen.length) return alert('No files checked.');
sendToViewer(chosen);
});
document.getElementById('loadAll').addEventListener('click', ()=>{
const current = input._currentFiles || [];
if (!current.length) return alert('No files selected. Choose a folder first.');
sendToViewer(current);
});
document.getElementById('openViewerAndSend').addEventListener('click', async ()=>{
const current = input._currentFiles || [];
if (!current.length) return alert('No files selected. Choose a folder first.');
// Open the viewer root in a new tab/window
const viewerWin = window.open('/', '_blank');
if (!viewerWin) return alert('Failed to open viewer window (popup blocked).');
// Wait for the viewer window to expose loadDicomStackFromFiles
const timeoutMs = 15000;
const start = Date.now();
const poll = () => new Promise((resolve, reject) => {
const iv = setInterval(() => {
try {
if (viewerWin && (viewerWin.loadDicomStackFromFiles || viewerWin.loadDicomStackFromWadouriList)) {
clearInterval(iv);
resolve(true);
}
if (Date.now() - start > timeoutMs) {
clearInterval(iv);
reject(new Error('Timed out waiting for viewer API'));
}
} catch (e) {
// cross-origin or not ready
}
}, 250);
});
try {
await poll();
// call the function on the opened viewer window
if (viewerWin.loadDicomStackFromFiles) {
viewerWin.loadDicomStackFromFiles(current);
alert('Sent '+current.length+' file(s) to the newly opened viewer.');
} else if (viewerWin.loadDicomStackFromWadouriList) {
// fallback for remote URLs
const wadouriList = current.map(f => 'wadouri:' + URL.createObjectURL(f));
viewerWin.loadDicomStackFromWadouriList(wadouriList);
alert('Sent '+current.length+' wadouri image(s) to the newly opened viewer.');
} else {
alert('Viewer opened but API not available.');
}
} catch (e) {
console.error('openViewerAndSend failed', e);
alert('Timed out waiting for viewer to be ready. Check the viewer tab.');
}
});
document.getElementById('clear').addEventListener('click', ()=>{
input.value = null;
input._currentFiles = [];
renderFiles([]);
});
function sendToViewer(files){
// Prefer calling the viewer global if present
if (window.loadDicomStackFromFiles && typeof window.loadDicomStackFromFiles === 'function') {
try {
// The viewer accepts FileList or File[] per typing; pass array
window.loadDicomStackFromFiles(files);
alert('Sent '+files.length+' file(s) to viewer (window.loadDicomStackFromFiles).');
return;
} catch (e) {
console.error('loadDicomStackFromFiles failed', e);
alert('Viewer call failed (see console).');
return;
}
}
// Fallback: try posting to parent (if embedded)
if (window.parent && window.parent !== window) {
try {
window.parent.postMessage({ type: 'loadFiles', filesCount: files.length }, '*');
alert('Posted message to parent with '+files.length+' files.');
return;
} catch (e) {
// ignore
}
}
alert('Viewer integration function `window.loadDicomStackFromFiles` not found on this page.');
}
// Initial empty render
renderFiles([]);
})();
</script>
</body>
</html>
+25
View File
@@ -0,0 +1,25 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DV3D — Non-DICOM Test</title>
<style>
html,body { height:100%; margin:0; background:#111 }
#non-dicom-root { width: 100vw; height: 100vh; }
</style>
</head>
<body>
<div id="non-dicom-root" class="dicom-viewer-root"></div>
<!-- Provide a small noop React Refresh preamble to avoid plugin-react preamble errors -->
<script>
// If plugin-react's preamble wasn't injected for some reason, provide no-op
// implementations so the runtime does not throw. This disables fast-refresh
// semantics for this page but keeps HMR from crashing.
window.$RefreshReg$ = window.$RefreshReg$ || function() {};
window.$RefreshSig$ = window.$RefreshSig$ || function() { return function(type) { return type; }; };
</script>
<!-- Vite can load TSX modules directly in dev mode -->
<script type="module" src="/src/nonDicomTest.tsx"></script>
</body>
</html>
+353
View File
@@ -0,0 +1,353 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Penra Courses — Viewer Test</title>
<style>
html,
body {
height: 100%;
margin: 0;
}
.dicom-viewer-root {
width: 100%;
height: 100vh;
background: #222;
color: #fff;
}
</style>
</head>
<body>
<div
id="main_viewer"
class="dicom-viewer-root"
data-auto-cache-stack="false"
></div>
<!-- Provide noop React Refresh preamble to avoid plugin-react runtime errors -->
<script>
window.$RefreshReg$ = window.$RefreshReg$ || function () {};
window.$RefreshSig$ =
window.$RefreshSig$ ||
function () {
return function (type) {
return type;
};
};
</script>
<script type="module" src="/src/main.tsx"></script>
<script>
// Viewer state to import
const state = {
grid: { rows: 1, cols: 3 },
modes: ["stack", "stack", "stack"],
stacks: [
{
i: [
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_573_PN7j4gd.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_580_kBgyDxS.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_572_DYQisSg.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_579_ya291yy.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_571_nThHs31.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_578_1eEKjB2.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_570_qT5wuZX.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_577_v2bo1kn.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_569_oV2dHz8.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_576_kgF1iXK.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_568_iY1z50L.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_575_BipYnZH.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_567_HawAeuC.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_574_FrcCKA7.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_566_AUDtXEf.dcm",
],
},
{
i: [
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_588_tGfMjqb.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_592_Js4efiI.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_584_U8WCsNY.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_595_vFPcByt.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_587_jnB3wGF.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_591_1XZY7Le.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_583_C9KGrQ9.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_594_SqzeIRU.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_586_Hupum4d.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_590_pbyuWr4.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_582_6u9iQt1.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_593_rOYWenQ.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_585_4z2K1tj.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_589_F5fn0Wp.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_581_jmCHi0D.dcm",
],
},
{
i: [
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_631_NxRBhMn.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_619_2cVhUyC.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_607_VvL52Af.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_627_RVhaiKA.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_615_nQtPQHJ.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_603_bAAqdKn.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_623_wy2tc7i.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_611_zZY7rSC.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_599_PUL3TkF.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_630_wIQBYJQ.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_618_oi80wJN.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_606_47SpfNJ.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_626_UNSOCYt.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_614_vcVgojF.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_602_VoRYz3y.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_622_Rj39VCd.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_610_AhQNlyr.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_598_pnjpR3G.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_629_hKAK6Ph.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_617_smztH5n.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_605_EfNQSic.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_625_asIOR8i.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_613_Qaa63p7.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_601_E8lUIGL.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_621_X45Edxw.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_609_P3mWXkz.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_597_alsdinT.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_628_51IriRz.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_616_sc6CY4V.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_604_HG8um6d.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_624_qr7EmUd.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_612_NUr6yLq.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_600_ngZGDnx.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_620_FfONZ99.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_608_j131qxy.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_596_stFfHXn.dcm",
],
},
{
i: [
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_792_og2P5S6.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_793_3tKkg87.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_794_s8FB3dq.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_795_8HeRpXV.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_796_tllvzjH.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_797_AXieNgu.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_798_L8YapjK.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_799_kvuLUsW.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_800_i2eSNzF.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_801_dR3KPL5.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_802_cDgm138.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_803_Bj3PZyX.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_804_CEqcWo2.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_805_5R2LmiA.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_806_RgmKU6b.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_807_BKTkmJv.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_808_OQOf2MC.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_809_lxnU3mr.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_810_8vG5Ett.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_811_poX6D2s.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_812_k46Ws88.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_813_7Ft4JOE.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_814_V5lJKxR.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_815_1hFehRl.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_816_34UqY7Z.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_817_YG28gpL.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_818_wonhIz5.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_819_bv3zaOx.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_820_xEjnfcI.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_821_cH9fPxl.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_822_lWmBHxs.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_823_ybix6Gz.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_824_q430lCK.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_825_28trFVc.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_826_7BF6HBF.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_827_ipmO3HH.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_828_Zuppb9h.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_829_TMuror5.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_830_Mnaj7oR.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_831_2U6zI7M.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_832_V9fvVdM.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_833_AAFaoOW.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_834_vxBJLIn.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_835_ZppFa6u.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_836_adRHoD3.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_837_jjfHCn3.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_838_N21h3ne.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_839_n6FWmeX.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_840_dErur0M.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_841_PcoTakk.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_842_UmTu7Fg.dcm",
"wadouri:https://www.penracourses.org.uk/media/atlas/dicom/IMG_843_USByQXH.dcm",
],
}
],
stackIdx: [0, 2, 1],
stackPos: [0, 0, 2],
props: [
{
voiRange: { lower: 39.150000000000034, upper: 559.1700000000001 },
invert: false,
interpolationType: 1,
VOILUTFunction: "LINEAR",
colormap: { name: "Grayscale", opacity: [] },
},
{
voiRange: { lower: 23.330000000000013, upper: 333.23 },
invert: false,
interpolationType: 1,
VOILUTFunction: "LINEAR",
colormap: { name: "Grayscale", opacity: [] },
},
{
voiRange: { lower: 35.47000000000003, upper: 504.35 },
invert: false,
interpolationType: 1,
VOILUTFunction: "LINEAR",
colormap: { name: "Grayscale", opacity: [] },
},
],
cam: [
{
viewUp: [
-0.00001587091537658125, -0.015633516013622284,
0.9998778104782104,
],
viewPlaneNormal: [
0.9999420159200826, 0.010767119415860999, 0.00018422042758444397,
],
position: [
229.83617495377155, 41.64140067850747, 119.19293043555355,
],
focalPoint: [
-54.36633106082782, 38.581180913933935, 119.14057149238982,
],
parallelProjection: true,
parallelScale: 204.18618383081306,
viewAngle: 90,
flipHorizontal: false,
flipVertical: false,
rotation: 0,
},
{
viewUp: [
0.0010457660537213087, -0.9813110828399658, 0.1924252212047577,
],
viewPlaneNormal: [
0.04514460865590469, -0.19218279979693106, -0.9803202210357175,
],
position: [
-21.89042091369629, 36.68157196044922, 65.77458190917969,
],
focalPoint: [
-27.218482971191406, 59.3633918762207, 181.4740447998047,
],
parallelProjection: true,
parallelScale: 81.6656748487095,
viewAngle: 90,
flipHorizontal: false,
flipVertical: false,
rotation: 0,
},
{
viewUp: [
-0.00001587091537658125, -0.015633516013622284,
0.9998778104782104,
],
viewPlaneNormal: [
0.9999420159493561, 0.010767116601264741, 0.00018422603640028001,
],
position: [238.6157989501953, 43.7907600402832, 106.84664916992188],
focalPoint: [
-45.586692810058594, 40.73054122924805, 106.7942886352539,
],
parallelProjection: true,
parallelScale: 178.65974529053696,
viewAngle: 90,
flipHorizontal: false,
flipVertical: false,
rotation: 0,
},
],
orientations: [null, null, null],
volumeSliceIndices: [null, null, null],
};
function callWhenReady(fnName, payload) {
const maxWait = 5000;
const start = Date.now();
(function check() {
if (window[fnName] && typeof window[fnName] === "function") {
try {
window[fnName](payload);
console.log("imported viewer state via", fnName);
} catch (e) {
console.error("importViewerState call failed", e);
}
return;
}
if (Date.now() - start > maxWait) {
console.warn("Timed out waiting for", fnName);
return;
}
setTimeout(check, 2000);
})();
}
document.addEventListener("DOMContentLoaded", () => {
// Ask the viewer to load the stacks first (via exposed API), then wait 2s and import the viewer state.
(function loadStacksThenImport() {
if (!state.stacks || !Array.isArray(state.stacks)) {
callWhenReady("importViewerState_main_viewer", state);
return;
}
function pushStacks() {
const fnName = "loadAdditionalStack_main_viewer";
if (window[fnName] && typeof window[fnName] === "function") {
try {
state.stacks.forEach((s) => {
if (s && Array.isArray(s.i) && s.i.length) {
// call the viewer API to load this stack into available stacks
window[fnName](s.i);
}
});
console.log(
"Requested viewer to load",
state.stacks.length,
"stacks",
);
} catch (e) {
console.warn("loadAdditionalStack call failed", e);
}
// Give the viewer 2 seconds to fetch/cache and mount imageIds, then import state
setTimeout(() => {
callWhenReady("importViewerState_main_viewer", state);
}, 2000);
return true;
}
return false;
}
const started = pushStacks();
if (!started) {
// wait for the viewer API then retry
const maxWait = 5000;
const start = Date.now();
(function waitForApi() {
if (pushStacks()) return;
if (Date.now() - start > maxWait) {
console.warn(
"Timed out waiting for loadAdditionalStack API; importing state directly",
);
callWhenReady("importViewerState_main_viewer", state);
return;
}
setTimeout(waitForApi, 2000);
})();
}
})();
});
</script>
</body>
</html>
+31
View File
@@ -0,0 +1,31 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Test Pages — Links</title>
<style>
body{font-family:system-ui,Segoe UI,Roboto,Helvetica,Arial;margin:24px;color:#111}
h1{margin-top:0}
ul{line-height:1.6}
a{color:#0366d6}
.note{background:#f6f8fa;padding:10px;border-radius:6px;margin-bottom:12px}
</style>
</head>
<body>
<h1>Available Test Pages</h1>
<p class="note">Open any of these pages directly in the dev server to view the corresponding test.</p>
<ul>
<li><a href="/penra-test.html">penra-test.html</a> — original Penra viewer test</li>
<li><a href="/embedded-viewer-test.html">embedded-viewer-test.html</a> — viewer embedded with surrounding content</li>
<li><a href="/empty-viewer.html">empty-viewer.html</a> — empty viewer placeholder</li>
<li><a href="/load-dir-test.html">load-dir-test.html</a> — directory loading test</li>
<li><a href="/non-dicom-test.html">non-dicom-test.html</a> — non-DICOM handling test</li>
<li><a href="/index.html">index.html</a> — project index</li>
<li><a href="/fluoro-test.html">fluoro-test.html</a> — fluoro multiframe test</li>
</ul>
<p>If you want these links added to the README, tell me and I will update it.</p>
</body>
</html>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More