Skip to content

[Bug] RenderingEngine.resize() silently dropped when _animationFrameSet is true— causes stale canvas size and mispositioned annotations #2667

@prat3185

Description

@prat3185

Describe the Bug

In a multi-viewport setup, calling renderingEngine.resize(true) can be silently dropped if any viewport has a pending render (_animationFrameSet === true).
The _resizeVTKViewports method in ContextPoolRenderingEngine has an early return when _animationFrameSet is true, which causes the resize to be lost entirely — it is never retried or deferred.

This causes

  1. Mispositioned annotations — Tools like probe, length, angle, and segmentation overlays which uses world-to-canvas transformation . When the canvas dimensions don't match the actual container size, all annotations are placed at wrong positions, and existing annotations appear shifted or scaled incorrectly.

Root Cause

In ContextPoolRenderingEngine._resizeVTKViewports(), when this._animationFrameSet is true, the method returns early without performing the resize and without scheduling a retry:

if (this._animationFrameSet) {
  return; // resize is silently dropped
}

In a multi-viewport scenario, where 1st viewport is resized, enabling or rendering a second viewport sets _animationFrameSet = true on the shared rendering engine making the 'resize()' call to be dropped silently on viewport 1.

Steps to Reproduce

  1. Open https://www.cornerstonejs.org/live-examples/annotationtoolmodes
  2. Wait for the image to load.
  3. Draw an annotation.
  4. Paste the following script in DevTools Console:
(function reproduceBug() {
  const cs = window.cornerstone;
  const renderingEngine = cs.getRenderingEngines()[0];
  const viewport1 = renderingEngine.getViewports()[0];

  const element2 = document.createElement('div');
  element2.style.width = '400px';
  element2.style.height = '400px';
  document.getElementById('content').appendChild(element2);

  renderingEngine.enableElement({
    viewportId: 'VIEWPORT_2',
    type: cs.Enums.ViewportType.STACK,
    element: element2,
    defaultOptions: { background: [0, 0, 0] },
  });

  const canvasBefore = { w: viewport1.canvas.width, h: viewport1.canvas.height };

  viewport1.element.style.width = '250px';
  viewport1.element.style.height = '250px';

  renderingEngine.renderViewport('VIEWPORT_2');
  renderingEngine.resize(true);

  const canvasAfter = { w: viewport1.canvas.width, h: viewport1.canvas.height };

  console.log('Canvas BEFORE:', canvasBefore.w, 'x', canvasBefore.h);
  console.log('Canvas AFTER: ', canvasAfter.w, 'x', canvasAfter.h);
  console.log('Container NOW: 250 x 250');

  if (canvasAfter.w === canvasBefore.w && canvasAfter.h === canvasBefore.h) {
    console.error(
      '🐛 BUG: resize() was silently dropped.',
      'Canvas is', canvasAfter.w + 'x' + canvasAfter.h,
      'but container is 250x250.',
      'canvasToWorld / worldToCanvas will return wrong coordinates.',
      'All annotations will be mispositioned.'
    );
  } else {
    console.log('✅ resize() worked correctly');
  }
})();
Image Image

The current behavior

RenderingEngine.resize() does not resize Canvas post resizing the viewport.
Annotation stays at same position and not at moved to anatomically correct position

The expected behavior

RenderingEngine.resize() should update viewport1's canvas dimensions to match its new 250×250 container, keeping canvasToWorld / worldToCanvas transforms correct and annotations accurately positioned.

System Information

chrome
window 11

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions