From b5652b8e36abcc813478c65cdbe248aae774e5db Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Wed, 27 Nov 2024 20:09:44 +0800 Subject: [PATCH] fix: normalize svg using only absolute sizing (#8854) --- packages/excalidraw/components/App.tsx | 20 ++++++++++-------- packages/excalidraw/element/image.ts | 28 ++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 5b5a3a3c1c..83bae5aba2 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -3870,14 +3870,18 @@ class App extends React.Component { nextFiles[fileData.id] = fileData; if (fileData.mimeType === MIME_TYPES.svg) { - const restoredDataURL = getDataURL_sync( - normalizeSVG(dataURLToString(fileData.dataURL)), - MIME_TYPES.svg, - ); - if (fileData.dataURL !== restoredDataURL) { - // bump version so persistence layer can update the store - fileData.version = (fileData.version ?? 1) + 1; - fileData.dataURL = restoredDataURL; + try { + const restoredDataURL = getDataURL_sync( + normalizeSVG(dataURLToString(fileData.dataURL)), + MIME_TYPES.svg, + ); + if (fileData.dataURL !== restoredDataURL) { + // bump version so persistence layer can update the store + fileData.version = (fileData.version ?? 1) + 1; + fileData.dataURL = restoredDataURL; + } + } catch (error) { + console.error(error); } } } diff --git a/packages/excalidraw/element/image.ts b/packages/excalidraw/element/image.ts index 7088e301f2..1753c9b4b9 100644 --- a/packages/excalidraw/element/image.ts +++ b/packages/excalidraw/element/image.ts @@ -105,20 +105,40 @@ export const normalizeSVG = (SVGString: string) => { svg.setAttribute("xmlns", SVG_NS); } - if (!svg.hasAttribute("width") || !svg.hasAttribute("height")) { - const viewBox = svg.getAttribute("viewBox"); - let width = svg.getAttribute("width") || "50"; - let height = svg.getAttribute("height") || "50"; + let width = svg.getAttribute("width"); + let height = svg.getAttribute("height"); + + // Do not use % or auto values for width/height + // to avoid scaling issues when rendering at different sizes/zoom levels + if (width?.includes("%") || width === "auto") { + width = null; + } + if (height?.includes("%") || height === "auto") { + height = null; + } + + const viewBox = svg.getAttribute("viewBox"); + + if (!width || !height) { + width = width || "50"; + height = height || "50"; + if (viewBox) { const match = viewBox.match(/\d+ +\d+ +(\d+) +(\d+)/); if (match) { [, width, height] = match; } } + svg.setAttribute("width", width); svg.setAttribute("height", height); } + // Make sure viewBox is set + if (!viewBox) { + svg.setAttribute("viewBox", `0 0 ${width} ${height}`); + } + return svg.outerHTML; } };