Integrating Slice Scrolling for 2D: Navigating the Shadow DOM
When working with 2D volumetric images in MorphoSource, one of our key challenges is automating the navigation through image slices. This involves interacting with shadow DOM elements and managing precise timing for image loading. Let’s explore how we’ve implemented this functionality.
Understanding the Challenge
2D volumetric images present several unique challenges:
- Elements are nested within shadow DOM
- Slice navigation requires precise timing
- Screenshots need to capture fully loaded states
- Browser automation must handle fullscreen modes
Core Implementation
Here’s how we’ve structured our slice navigation system:
def move_slices_and_screenshots():
# Chrome setup with headless mode for CI/CD
options = webdriver.ChromeOptions()
options.add_argument("--headless")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--disable-gpu")
Key Components
1. Browser Configuration
We set up Chrome with specific options for reliable headless operation:
- Headless mode for CI/CD environments
- Disabled GPU for consistent rendering
- Extended timeouts for large images
2. Shadow DOM Navigation
One of the trickiest parts is accessing elements within the shadow DOM:
# Locate the shadow host
host_element = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, "al-control-panel"))
)
# Access shadow root and find settings
al_settings = driver.execute_script(
"return arguments[0].shadowRoot.querySelector('al-settings')",
host_element
)
3. Slice Navigation
We implement controlled navigation through slices:
slice_values = [round(i * 0.1, 1) for i in range(1, 10)]
for val in slice_values:
# Set slices-index attribute
driver.execute_script(
"arguments[0].setAttribute('slices-index', arguments[1])",
al_settings,
str(val)
)
# Capture the state
screenshot_name = os.path.join(screenshots_dir, f"slice_{val}.png")
driver.save_screenshot(screenshot_name)
Critical Timing Considerations
Loading States
We’ve implemented strategic waits to ensure content is fully loaded:
# Initial page load
driver.set_page_load_timeout(30)
driver.set_script_timeout(30)
# Fullscreen transition
full_screen_btn.click()
time.sleep(360) # Allow viewer to load in fullscreen
# Between slice transitions
time.sleep(2) # Short pause for slice loading
Screenshot Management
We organize screenshots systematically:
# Create dedicated screenshot directory
screenshots_dir = "screenshots"
if not os.path.exists(screenshots_dir):
os.makedirs(screenshots_dir)
# Systematic naming convention
screenshot_name = os.path.join(screenshots_dir, f"slice_{val}.png")
Frame Management
Proper iframe handling is crucial:
# Wait for and switch to the viewer iframe
wait = WebDriverWait(driver, 20)
uv_iframe = wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, "iframe#uv-iframe"))
)
driver.switch_to.frame(uv_iframe)
Challenges and Solutions
1. Shadow DOM Access
Challenge: Traditional Selenium selectors don’t work with shadow DOM. Solution: Use JavaScript execution to traverse shadow roots:
el = driver.execute_script(
"return arguments[0].shadowRoot.querySelector('al-settings')",
host_element
)
2. Timing Management
Challenge: Different slices load at different speeds. Solution: Implemented strategic waits:
- Long initial wait for viewer loading
- Shorter waits between slice transitions
- Extended timeouts for page operations
3. Screenshot Reliability
Challenge: Ensuring screenshots capture fully loaded states. Solution: Combined approaches:
- Created dedicated screenshot directory
- Implemented systematic naming
- Added verification pauses
Best Practices
- Error Handling
- Always use try/finally blocks
- Clean up browser resources
- Maintain organized screenshot storage
- Performance Optimization
- Strategic wait times
- Efficient shadow DOM traversal
- Resource cleanup
- Maintainability
- Clear variable naming
- Documented timing decisions
- Organized file structure
Future Improvements
- Dynamic Timing
- Implement load detection
- Adjust waits based on content
- Add verification checks
- Enhanced Navigation
- Support for variable slice counts
- Custom navigation patterns
- Progress tracking
- Resource Management
- Optimized screenshot storage
- Memory usage monitoring
- Cleanup automation
Conclusion
Successfully implementing slice scrolling for 2D volumetric images requires careful attention to shadow DOM interaction, timing management, and resource handling. Our solution provides a robust foundation for automated navigation through 2D image slices while maintaining reliability and performance.
By understanding and addressing the unique challenges of shadow DOM manipulation and image loading states, we’ve created a system that can consistently capture the state of 2D volumetric images across different slices, providing valuable data for analysis and verification.