Conversation
A custom icon whose width and height differ was stretched into a square on both the graph canvas and DOM surfaces (search results, legends), instead of being scaled down while preserving its aspect ratio. Affects raster images and SVGs alike. Root causes, all now fixed: - defaultNodeStyle forced backgroundWidth/backgroundHeight to the same 60% for every icon regardless of shape. useGraphStyles now computes per-icon percentages from the icon's real aspect ratio, falling back to 60%/60% only when dimensions are unknown. - Icon dimensions were never measured: raster icons resolved synchronously with no size info, and SVGs weren't inspected at all. iconRegistry now measures a raster's natural size via `Image`, and extracts an SVG's size from its width/height or viewBox. - iconImageUrl forced every SVG's own intrinsic width/height to a fixed 24x24 square before handing it to cytoscape. For a non-square icon this baked a mismatched-aspect letterbox into the rasterized image, which cytoscape's own aspect-aware background-width/height then stretched a second time — distorting worse than doing nothing. It now scales the intrinsic box to the icon's real aspect ratio instead. - An SVG with width/height but no viewBox has no coordinate system to scale from, so forcing a different display box just clips the content instead of scaling it. Added ensureSvgViewBox() to synthesize one when missing, applied wherever an SVG is sanitized (DOM render and canvas resolution) via a new shared SVG_ALLOWED_ATTR allowlist — DOMPurify's default SVG profile otherwise strips width/height/viewBox outright. - VertexIcon's plain `<img>` (non-SVG raster fallback) had no `object-fit`, so the browser's default `fill` stretched it; added `object-contain`. Added an `Image` test double to setupTests.ts, since jsdom never decodes images and would otherwise hang any test that resolves a raster icon's dimensions.
|
Your root-cause analysis is correct. There's a shorter route to the same pixels, though. Wrap every icon, raster included, in a padded square SVG and let The prototype I sent produces pixel-identical output to your branch across 4:1, 1:4, 1:1, 10:1 and a raster, in Chrome, Firefox and Safari 27. No measurement anywhere. Note that This also lands the canvas on the same mechanism What it removes
Still neededDelete Restore the Comment the Fix the PR description's SVG bullet. It says SVGs "already carry a viewBox, so they letterbox themselves naturally," but the branch rewrites every SVG's intrinsic size. Your commit message has it right. Rebase too. The Pre-existingThe review surfaced several older issues in files you touched. #2182 is filed; I'm tracking the rest. None block this. |
Description
Non-square custom vertex icons (raster images and SVG) were stretched into a square instead of scaled down to fit, distorting them. This happened consistently on both the graph canvas and DOM surfaces (search results, legend).
The root cause: Cytoscape's
drawInscribedImagedoes not preserve aspect ratio whenbackground-widthandbackground-heightare both set to percentages. They override the image's natural dimensions, thenbackground-fit: containscales the already-squashed result — the image is already distorted by then. The DOM rendered images withobject-fit: fill(default), which has identical behavior.How it's fixed
Icon measurement and aspect-ratio carry: The icon registry now measures the natural width/height of raster images when they resolve. That ratio is carried on the icon object through the system.
Aspect-fit computation: The background width/height for the Cytoscape canvas are computed from the target box (60% of node size) and the image's aspect ratio. The shorter axis is shrunk so the image fits inside the box without stretching — e.g., a 4:1 wide logo becomes
60%width,15%height.DOM surface fix:
VertexIcongainsobject-containso its<img>respects the aspect ratio.SVG handling: SVG images already carry a viewBox, so they letterbox themselves naturally with
preserveAspectRatio=xMidYMid meet. New utility functions extract and validate viewBox data.How to read
Supporting files (tests, minor updates): CONTEXT.md, setupTests.ts, and test files for all new/modified functions.
Validation
All unit tests pass. Manual testing confirmed non-square icons now render at their natural aspect ratio on the graph canvas and in DOM surfaces (search results, legend).
Before Fix

After Fix
