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:

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:

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:

3. Screenshot Reliability

Challenge: Ensuring screenshots capture fully loaded states. Solution: Combined approaches:

Best Practices

  1. Error Handling
    • Always use try/finally blocks
    • Clean up browser resources
    • Maintain organized screenshot storage
  2. Performance Optimization
    • Strategic wait times
    • Efficient shadow DOM traversal
    • Resource cleanup
  3. Maintainability
    • Clear variable naming
    • Documented timing decisions
    • Organized file structure

Future Improvements

  1. Dynamic Timing
    • Implement load detection
    • Adjust waits based on content
    • Add verification checks
  2. Enhanced Navigation
    • Support for variable slice counts
    • Custom navigation patterns
    • Progress tracking
  3. 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.


Next Post →