From bbf7167993d99d461d79118639bec543ecaaea77 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sun, 4 Jan 2026 15:25:21 +0330 Subject: [PATCH] fix group mask image --- .../components/canvas/ObjectRenderer.tsx | 45 ++++++++++++++----- .../sidebar/settings/MaskSettings.tsx | 2 +- .../editor/components/tools/ImageObject.tsx | 16 ++++--- 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/src/pages/editor/components/canvas/ObjectRenderer.tsx b/src/pages/editor/components/canvas/ObjectRenderer.tsx index 1c862ae..f255326 100644 --- a/src/pages/editor/components/canvas/ObjectRenderer.tsx +++ b/src/pages/editor/components/canvas/ObjectRenderer.tsx @@ -53,23 +53,44 @@ const ObjectRenderer = ({ useEffect(() => { if (!groupRef.current || !shouldApplyMask) return; - // Use requestAnimationFrame to ensure shapes are rendered before caching - const rafId = requestAnimationFrame(() => { - if (!groupRef.current) return; - - // Clear cache first - groupRef.current.clearCache(); - - // Apply cache - Konva will automatically calculate bounds - groupRef.current.cache(); - groupRef.current.getLayer()?.batchDraw(); + // Use double requestAnimationFrame to ensure all changes (including stroke) are rendered before caching + let rafId1: number; + const rafId2 = requestAnimationFrame(() => { + rafId1 = requestAnimationFrame(() => { + if (!groupRef.current) return; + + // Clear cache first + groupRef.current.clearCache(); + + // Apply cache - Konva will automatically calculate bounds + groupRef.current.cache(); + groupRef.current.getLayer()?.batchDraw(); + }); }); return () => { - cancelAnimationFrame(rafId); + cancelAnimationFrame(rafId2); + if (rafId1) cancelAnimationFrame(rafId1); groupRef.current?.clearCache(); }; - }, [shouldApplyMask, maskShape?.x, maskShape?.y, maskShape?.width, maskShape?.height, maskShape?.rotation, obj.x, obj.y, obj.width, obj.height, obj.rotation]); + }, [shouldApplyMask, isSelected, maskShape?.x, maskShape?.y, maskShape?.width, maskShape?.height, maskShape?.rotation, obj.x, obj.y, obj.width, obj.height, obj.rotation, obj.maskInvert]); + + // Refresh cache after transformer is attached (when isSelected changes) + useEffect(() => { + if (!groupRef.current || !shouldApplyMask || !isSelected) return; + + // Wait for transformer to attach, then refresh cache + const timeoutId = setTimeout(() => { + if (!groupRef.current) return; + groupRef.current.clearCache(); + groupRef.current.cache(); + groupRef.current.getLayer()?.batchDraw(); + }, 150); + + return () => { + clearTimeout(timeoutId); + }; + }, [shouldApplyMask, isSelected, transformerRef]); if (obj.visible === false) { return null; diff --git a/src/pages/editor/components/sidebar/settings/MaskSettings.tsx b/src/pages/editor/components/sidebar/settings/MaskSettings.tsx index 05bab9d..b767de1 100644 --- a/src/pages/editor/components/sidebar/settings/MaskSettings.tsx +++ b/src/pages/editor/components/sidebar/settings/MaskSettings.tsx @@ -56,7 +56,7 @@ const MaskSettings = ({ objectId }: MaskSettingsProps) => { return (
{/* Section 1: Convert shape to mask (only for shapes) */} {canBeMask && ( diff --git a/src/pages/editor/components/tools/ImageObject.tsx b/src/pages/editor/components/tools/ImageObject.tsx index 514d39a..a84780d 100644 --- a/src/pages/editor/components/tools/ImageObject.tsx +++ b/src/pages/editor/components/tools/ImageObject.tsx @@ -16,11 +16,15 @@ const ImageObject = ({ const shapeRef = useRef(null); useEffect(() => { + // اگر draggable=false باشد، یعنی mask اعمال شده و transformer باید به Group متصل شود (نه Image) + // پس این useEffect را اجرا نکن + if (!draggable) return; + if (isSelected && shapeRef.current && transformerRef.current && image) { transformerRef.current.nodes([shapeRef.current]); transformerRef.current.getLayer()?.batchDraw(); } - }, [isSelected, transformerRef, image]); + }, [isSelected, transformerRef, image, draggable]); if (!image) return null; @@ -33,15 +37,17 @@ const ImageObject = ({ image={image} width={obj.width || image.width} height={obj.height || image.height} - stroke={isSelected ? "#3b82f6" : undefined} - strokeWidth={isSelected ? 3 : 0} + // اگر draggable=false باشد، یعنی mask اعمال شده و نباید stroke نمایش داده شود (Group stroke دارد) + stroke={isSelected && draggable ? "#3b82f6" : undefined} + strokeWidth={isSelected && draggable ? 3 : 0} rotation={obj.rotation || 0} draggable={draggable} - onClick={() => { + onClick={draggable ? () => { + // فقط وقتی mask اعمال نشده onClick handler را فعال کن if (shapeRef.current) { onSelect(obj.id, shapeRef.current); } - }} + } : undefined} onDragEnd={(e) => { const node = e.target; onUpdate(obj.id, {