Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions packages/core/src/RenderingEngine/WSIViewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,28 @@ class WSIViewport extends Viewport {
canvas.width = clientWidth;
canvas.height = clientHeight;
}
// Preserve fit-relative zoom across container size changes.
// Without this, WSIViewport keeps the old OpenLayers resolution, so
// exiting full screen (smaller container) leaves the slide zoomed in.
const map = this.map;
const view = map?.getView?.();
if (map && view) {
const extent = view.getProjection().getExtent();
const oldSize = map.getSize();
const oldResolution = view.getResolution();
let relativeZoom;
if (oldSize && oldResolution) {
relativeZoom =
view.getResolutionForExtent(extent, oldSize) / oldResolution;
}
map.updateSize();
const newSize = map.getSize();
if (relativeZoom && newSize) {
view.setResolution(
view.getResolutionForExtent(extent, newSize) / relativeZoom
);
}
Comment on lines +459 to +473

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Guard against zero dimensions and invalid extents to prevent OpenLayers crashes.

When the viewport container is temporarily hidden (e.g., inside a collapsed panel or display: none) or initialized with zero dimensions, map.getSize() returns [0, 0]. Since arrays are truthy in JavaScript, the code proceeds and computes relativeZoom as Infinity (due to division by zero in getResolutionForExtent).

When the container is later shown and resized, dividing by Infinity leads to view.setResolution(0), which corrupts the OpenLayers view state. Additionally, view.getProjection().getExtent() can return null, which causes getResolutionForExtent to throw an error.

Ensure the sizes strictly have width and height > 0 and that the resulting relativeZoom is finite before applying it.

🔒️ Proposed fix to add robust boundary checks
-      const extent = view.getProjection().getExtent();
+      const extent = view.getProjection()?.getExtent();
       const oldSize = map.getSize();
       const oldResolution = view.getResolution();
       let relativeZoom;
-      if (oldSize && oldResolution) {
+      if (extent && oldSize && oldSize[0] > 0 && oldSize[1] > 0 && oldResolution > 0) {
         relativeZoom =
           view.getResolutionForExtent(extent, oldSize) / oldResolution;
       }
       map.updateSize();
       const newSize = map.getSize();
-      if (relativeZoom && newSize) {
+      if (relativeZoom > 0 && Number.isFinite(relativeZoom) && newSize && newSize[0] > 0 && newSize[1] > 0) {
         view.setResolution(
           view.getResolutionForExtent(extent, newSize) / relativeZoom
         );
       }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const extent = view.getProjection().getExtent();
const oldSize = map.getSize();
const oldResolution = view.getResolution();
let relativeZoom;
if (oldSize && oldResolution) {
relativeZoom =
view.getResolutionForExtent(extent, oldSize) / oldResolution;
}
map.updateSize();
const newSize = map.getSize();
if (relativeZoom && newSize) {
view.setResolution(
view.getResolutionForExtent(extent, newSize) / relativeZoom
);
}
const extent = view.getProjection()?.getExtent();
const oldSize = map.getSize();
const oldResolution = view.getResolution();
let relativeZoom;
if (extent && oldSize && oldSize[0] > 0 && oldSize[1] > 0 && oldResolution > 0) {
relativeZoom =
view.getResolutionForExtent(extent, oldSize) / oldResolution;
}
map.updateSize();
const newSize = map.getSize();
if (relativeZoom > 0 && Number.isFinite(relativeZoom) && newSize && newSize[0] > 0 && newSize[1] > 0) {
view.setResolution(
view.getResolutionForExtent(extent, newSize) / relativeZoom
);
}
🧰 Tools
🪛 GitHub Actions: Docusaurus Build / 0_docusaurus-build.txt

[error] 461-461: TypeScript (tsc) failed with TS2339: Property 'getSize' does not exist on type 'WSIMapLike'.

🪛 GitHub Actions: Docusaurus Build / docusaurus-build

[error] 461-461: TypeScript (tsc) failed: TS2339: Property 'getSize' does not exist on type 'WSIMapLike'.

🪛 GitHub Actions: Validate ESM Packaging / 1_build-packages.txt

[error] 461-461: TypeScript (tsc) failed with TS2339: Property 'getSize' does not exist on type 'WSIMapLike'.

🪛 GitHub Actions: Validate ESM Packaging / build-packages

[error] 461-461: TypeScript compilation failed (tsc). TS2339: Property 'getSize' does not exist on type 'WSIMapLike'.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/RenderingEngine/WSIViewport.ts` around lines 459 - 473,
Update the viewport resize logic around `relativeZoom`, `oldSize`, and `newSize`
to require a non-null projection extent and strictly positive width and height
for both map sizes before calling `getResolutionForExtent`. Validate that the
computed `relativeZoom` is finite before applying `view.setResolution`, while
preserving the existing behavior for valid dimensions and extents.

}
this.refreshRenderValues();
};

Expand Down
Loading