Browse Source

feat: support roundness for images (#7558)

Co-authored-by: dwelle <[email protected]>
Aashir Israr 1 năm trước cách đây
mục cha
commit
2409c091ff

+ 4 - 1
packages/excalidraw/element/typeChecks.ts

@@ -214,7 +214,10 @@ export const isBoundToContainer = (
 };
 
 export const isUsingAdaptiveRadius = (type: string) =>
-  type === "rectangle" || type === "embeddable" || type === "iframe";
+  type === "rectangle" ||
+  type === "embeddable" ||
+  type === "iframe" ||
+  type === "image";
 
 export const isUsingProportionalRadius = (type: string) =>
   type === "line" || type === "arrow" || type === "diamond";

+ 36 - 0
packages/excalidraw/renderer/renderElement.ts

@@ -344,6 +344,17 @@ const drawElementOnCanvas = (
         ? renderConfig.imageCache.get(element.fileId)?.image
         : undefined;
       if (img != null && !(img instanceof Promise)) {
+        if (element.roundness && context.roundRect) {
+          context.beginPath();
+          context.roundRect(
+            0,
+            0,
+            element.width,
+            element.height,
+            getCornerRadius(Math.min(element.width, element.height), element),
+          );
+          context.clip();
+        }
         context.drawImage(
           img,
           0 /* hardcoded for the selection box*/,
@@ -1301,6 +1312,31 @@ export const renderElementToSvg = (
           }) rotate(${degree} ${cx} ${cy})`,
         );
 
+        if (element.roundness) {
+          const clipPath = svgRoot.ownerDocument!.createElementNS(
+            SVG_NS,
+            "clipPath",
+          );
+          clipPath.id = `image-clipPath-${element.id}`;
+
+          const clipRect = svgRoot.ownerDocument!.createElementNS(
+            SVG_NS,
+            "rect",
+          );
+          const radius = getCornerRadius(
+            Math.min(element.width, element.height),
+            element,
+          );
+          clipRect.setAttribute("width", `${element.width}`);
+          clipRect.setAttribute("height", `${element.height}`);
+          clipRect.setAttribute("rx", `${radius}`);
+          clipRect.setAttribute("ry", `${radius}`);
+          clipPath.appendChild(clipRect);
+          addToRoot(clipPath, element);
+
+          g.setAttributeNS(SVG_NS, "clip-path", `url(#${clipPath.id})`);
+        }
+
         const clipG = maybeWrapNodesInFrameClipPath(
           element,
           root,

+ 2 - 1
packages/excalidraw/scene/comparisons.ts

@@ -42,7 +42,8 @@ export const canChangeRoundness = (type: ElementOrToolType) =>
   type === "embeddable" ||
   type === "arrow" ||
   type === "line" ||
-  type === "diamond";
+  type === "diamond" ||
+  type === "image";
 
 export const canHaveArrowheads = (type: ElementOrToolType) => type === "arrow";
 

+ 1 - 1
packages/excalidraw/tests/__snapshots__/export.test.tsx.snap

@@ -21,5 +21,5 @@ exports[`export > exporting svg containing transformed images > svg export outpu
     </style>
     
   </defs>
-  <g transform="translate(30.710678118654755 30.710678118654755) rotate(315 50 50)" data-id="id1"><use href="#image-file_A" width="100" height="100" opacity="1"></use></g><g transform="translate(130.71067811865476 30.710678118654755) rotate(45 25 25)" data-id="id2"><use href="#image-file_A" width="50" height="50" opacity="1" transform="scale(-1, 1) translate(-50 0)"></use></g><g transform="translate(30.710678118654755 130.71067811865476) rotate(45 50 50)" data-id="id3"><use href="#image-file_A" width="100" height="100" opacity="1" transform="scale(1, -1) translate(0 -100)"></use></g><g transform="translate(130.71067811865476 130.71067811865476) rotate(315 25 25)" data-id="id4"><use href="#image-file_A" width="50" height="50" opacity="1" transform="scale(-1, -1) translate(-50 -50)"></use></g></svg>"
+  <clipPath id="image-clipPath-id1" data-id="id1"><rect width="100" height="100" rx="25" ry="25"></rect></clipPath><g transform="translate(30.710678118654755 30.710678118654755) rotate(315 50 50)" clip-path="url(#image-clipPath-id1)" data-id="id1"><use href="#image-file_A" width="100" height="100" opacity="1"></use></g><clipPath id="image-clipPath-id2" data-id="id2"><rect width="50" height="50" rx="12.5" ry="12.5"></rect></clipPath><g transform="translate(130.71067811865476 30.710678118654755) rotate(45 25 25)" clip-path="url(#image-clipPath-id2)" data-id="id2"><use href="#image-file_A" width="50" height="50" opacity="1" transform="scale(-1, 1) translate(-50 0)"></use></g><clipPath id="image-clipPath-id3" data-id="id3"><rect width="100" height="100" rx="25" ry="25"></rect></clipPath><g transform="translate(30.710678118654755 130.71067811865476) rotate(45 50 50)" clip-path="url(#image-clipPath-id3)" data-id="id3"><use href="#image-file_A" width="100" height="100" opacity="1" transform="scale(1, -1) translate(0 -100)"></use></g><clipPath id="image-clipPath-id4" data-id="id4"><rect width="50" height="50" rx="12.5" ry="12.5"></rect></clipPath><g transform="translate(130.71067811865476 130.71067811865476) rotate(315 25 25)" clip-path="url(#image-clipPath-id4)" data-id="id4"><use href="#image-file_A" width="50" height="50" opacity="1" transform="scale(-1, -1) translate(-50 -50)"></use></g></svg>"
 `;