fix resize
This commit is contained in:
@@ -354,6 +354,18 @@ const EditorCanvas = () => {
|
|||||||
const groupWidth = maxX - minX;
|
const groupWidth = maxX - minX;
|
||||||
const groupHeight = maxY - minY;
|
const groupHeight = maxY - minY;
|
||||||
|
|
||||||
|
// Update group node directly in Konva first to prevent transformer flicker
|
||||||
|
if (layerRef.current) {
|
||||||
|
const groupNode = layerRef.current.findOne(`#${selectedObject.id}`);
|
||||||
|
if (groupNode) {
|
||||||
|
groupNode.x(minX);
|
||||||
|
groupNode.y(minY);
|
||||||
|
groupNode.width(groupWidth);
|
||||||
|
groupNode.height(groupHeight);
|
||||||
|
groupNode.rotation(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update group object with new bounds (rotation should remain 0)
|
// Update group object with new bounds (rotation should remain 0)
|
||||||
updateObject(selectedObject.id, {
|
updateObject(selectedObject.id, {
|
||||||
x: minX,
|
x: minX,
|
||||||
@@ -362,6 +374,15 @@ const EditorCanvas = () => {
|
|||||||
height: groupHeight,
|
height: groupHeight,
|
||||||
rotation: 0,
|
rotation: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Force transformer to update immediately
|
||||||
|
if (transformerRef.current && layerRef.current) {
|
||||||
|
const groupNode = layerRef.current.findOne(`#${selectedObject.id}`);
|
||||||
|
if (groupNode) {
|
||||||
|
transformerRef.current.nodes([groupNode]);
|
||||||
|
transformerRef.current.getLayer()?.batchDraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (selectedObject.type === "grid") {
|
} else if (selectedObject.type === "grid") {
|
||||||
// Handle grid objects separately
|
// Handle grid objects separately
|
||||||
const scaleX = node.scaleX();
|
const scaleX = node.scaleX();
|
||||||
@@ -386,6 +407,35 @@ const EditorCanvas = () => {
|
|||||||
node.scaleX(1);
|
node.scaleX(1);
|
||||||
node.scaleY(1);
|
node.scaleY(1);
|
||||||
|
|
||||||
|
// Handle special shapes that use radius (Circle, Triangle, Abstract)
|
||||||
|
if (selectedObject.type === "rectangle") {
|
||||||
|
if (selectedObject.shapeType === "circle") {
|
||||||
|
// Circle: maintain aspect ratio and use average scale
|
||||||
|
const avgScale = (scaleX + scaleY) / 2;
|
||||||
|
const newRadius = Math.max(5, ((selectedObject.width || 50) / 2) * avgScale);
|
||||||
|
const newSize = newRadius * 2;
|
||||||
|
updateObject(selectedObject.id, {
|
||||||
|
x: node.x(),
|
||||||
|
y: node.y(),
|
||||||
|
rotation: node.rotation(),
|
||||||
|
width: newSize,
|
||||||
|
height: newSize,
|
||||||
|
});
|
||||||
|
} else if (selectedObject.shapeType === "triangle" || selectedObject.shapeType === "abstract") {
|
||||||
|
// Triangle and Abstract: maintain aspect ratio and use average scale
|
||||||
|
const avgScale = (scaleX + scaleY) / 2;
|
||||||
|
const baseRadius = Math.min((selectedObject.width || 100) / 2, (selectedObject.height || 100) / 2);
|
||||||
|
const newRadius = Math.max(5, baseRadius * avgScale);
|
||||||
|
const newSize = newRadius * 2;
|
||||||
|
updateObject(selectedObject.id, {
|
||||||
|
x: node.x() - newSize / 2,
|
||||||
|
y: node.y() - newSize / 2,
|
||||||
|
rotation: node.rotation(),
|
||||||
|
width: newSize,
|
||||||
|
height: newSize,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Regular rectangle
|
||||||
updateObject(selectedObject.id, {
|
updateObject(selectedObject.id, {
|
||||||
x: node.x(),
|
x: node.x(),
|
||||||
y: node.y(),
|
y: node.y(),
|
||||||
@@ -394,6 +444,55 @@ const EditorCanvas = () => {
|
|||||||
height: Math.max(5, (selectedObject.height || 100) * scaleY),
|
height: Math.max(5, (selectedObject.height || 100) * scaleY),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
} else if (selectedObject.type === "line" || selectedObject.type === "arrow") {
|
||||||
|
// Line and Arrow: scale the end point
|
||||||
|
const startX = selectedObject.x || 0;
|
||||||
|
const startY = selectedObject.y || 0;
|
||||||
|
const endX = selectedObject.width || 0;
|
||||||
|
const endY = selectedObject.height || 0;
|
||||||
|
const dx = (endX - startX) * scaleX;
|
||||||
|
const dy = (endY - startY) * scaleY;
|
||||||
|
updateObject(selectedObject.id, {
|
||||||
|
x: node.x(),
|
||||||
|
y: node.y(),
|
||||||
|
rotation: node.rotation(),
|
||||||
|
width: node.x() + dx,
|
||||||
|
height: node.y() + dy,
|
||||||
|
});
|
||||||
|
} else if (selectedObject.type === "text" || selectedObject.type === "link") {
|
||||||
|
// Text and Link: calculate actual dimensions after transform
|
||||||
|
const clientRect = node.getClientRect({ skipTransform: true });
|
||||||
|
const newWidth = clientRect.width * scaleX;
|
||||||
|
const newHeight = clientRect.height * scaleY;
|
||||||
|
|
||||||
|
if (selectedObject.type === "link") {
|
||||||
|
// For link, also update fontSize
|
||||||
|
updateObject(selectedObject.id, {
|
||||||
|
x: node.x(),
|
||||||
|
y: node.y(),
|
||||||
|
rotation: node.rotation(),
|
||||||
|
fontSize: selectedObject.fontSize ? Math.max(5, selectedObject.fontSize * scaleX) : undefined,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
updateObject(selectedObject.id, {
|
||||||
|
x: node.x(),
|
||||||
|
y: node.y(),
|
||||||
|
rotation: node.rotation(),
|
||||||
|
width: Math.max(5, newWidth),
|
||||||
|
height: Math.max(5, newHeight),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Default for other objects (image, etc.)
|
||||||
|
updateObject(selectedObject.id, {
|
||||||
|
x: node.x(),
|
||||||
|
y: node.y(),
|
||||||
|
rotation: node.rotation(),
|
||||||
|
width: Math.max(5, (selectedObject.width || 100) * scaleX),
|
||||||
|
height: Math.max(5, (selectedObject.height || 100) * scaleY),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -339,13 +339,61 @@ const ObjectRenderer = ({
|
|||||||
// محاسبه موقعیت جدید object
|
// محاسبه موقعیت جدید object
|
||||||
const newX = node.x();
|
const newX = node.x();
|
||||||
const newY = node.y();
|
const newY = node.y();
|
||||||
const newWidth = Math.max(5, (obj.width || 100) * scaleX);
|
|
||||||
const newHeight = Math.max(5, (obj.height || 100) * scaleY);
|
// Handle special shapes that use radius (Circle, Triangle, Abstract)
|
||||||
|
let newWidth: number;
|
||||||
|
let newHeight: number;
|
||||||
|
let finalX = newX;
|
||||||
|
let finalY = newY;
|
||||||
|
|
||||||
|
if (obj.type === "rectangle") {
|
||||||
|
if (obj.shapeType === "circle") {
|
||||||
|
// Circle: maintain aspect ratio and use average scale
|
||||||
|
const avgScale = (scaleX + scaleY) / 2;
|
||||||
|
const newRadius = Math.max(5, ((obj.width || 50) / 2) * avgScale);
|
||||||
|
const newSize = newRadius * 2;
|
||||||
|
newWidth = newSize;
|
||||||
|
newHeight = newSize;
|
||||||
|
} else if (obj.shapeType === "triangle" || obj.shapeType === "abstract") {
|
||||||
|
// Triangle and Abstract: maintain aspect ratio and use average scale
|
||||||
|
const avgScale = (scaleX + scaleY) / 2;
|
||||||
|
const baseRadius = Math.min((obj.width || 100) / 2, (obj.height || 100) / 2);
|
||||||
|
const newRadius = Math.max(5, baseRadius * avgScale);
|
||||||
|
const newSize = newRadius * 2;
|
||||||
|
newWidth = newSize;
|
||||||
|
newHeight = newSize;
|
||||||
|
// Adjust position for centered shapes
|
||||||
|
finalX = newX - newSize / 2;
|
||||||
|
finalY = newY - newSize / 2;
|
||||||
|
} else {
|
||||||
|
// Regular rectangle
|
||||||
|
newWidth = Math.max(5, (obj.width || 100) * scaleX);
|
||||||
|
newHeight = Math.max(5, (obj.height || 100) * scaleY);
|
||||||
|
}
|
||||||
|
} else if (obj.type === "line" || obj.type === "arrow") {
|
||||||
|
// Line and Arrow: scale the end point
|
||||||
|
const startX = obj.x || 0;
|
||||||
|
const startY = obj.y || 0;
|
||||||
|
const endX = obj.width || 0;
|
||||||
|
const endY = obj.height || 0;
|
||||||
|
const dx = (endX - startX) * scaleX;
|
||||||
|
const dy = (endY - startY) * scaleY;
|
||||||
|
newWidth = newX + dx;
|
||||||
|
newHeight = newY + dy;
|
||||||
|
} else if (obj.type === "text" || obj.type === "link") {
|
||||||
|
// Text and Link: use scale directly
|
||||||
|
newWidth = Math.max(5, (obj.width || 100) * scaleX);
|
||||||
|
newHeight = Math.max(5, (obj.height || 100) * scaleY);
|
||||||
|
} else {
|
||||||
|
// Default for other objects (image, etc.)
|
||||||
|
newWidth = Math.max(5, (obj.width || 100) * scaleX);
|
||||||
|
newHeight = Math.max(5, (obj.height || 100) * scaleY);
|
||||||
|
}
|
||||||
|
|
||||||
// بهروزرسانی object
|
// بهروزرسانی object
|
||||||
onUpdate(obj.id, {
|
onUpdate(obj.id, {
|
||||||
x: newX,
|
x: finalX,
|
||||||
y: newY,
|
y: finalY,
|
||||||
rotation: node.rotation(),
|
rotation: node.rotation(),
|
||||||
width: newWidth,
|
width: newWidth,
|
||||||
height: newHeight,
|
height: newHeight,
|
||||||
@@ -356,8 +404,8 @@ const ObjectRenderer = ({
|
|||||||
// محاسبه موقعیت جدید mask
|
// محاسبه موقعیت جدید mask
|
||||||
// موقعیت نسبی را scale میکنم و به موقعیت جدید object اضافه میکنم
|
// موقعیت نسبی را scale میکنم و به موقعیت جدید object اضافه میکنم
|
||||||
// این باعث میشود که موقعیت نسبی mask نسبت به object حفظ شود
|
// این باعث میشود که موقعیت نسبی mask نسبت به object حفظ شود
|
||||||
const newMaskX = newX + (relativeX * scaleX);
|
const newMaskX = finalX + (relativeX * scaleX);
|
||||||
const newMaskY = newY + (relativeY * scaleY);
|
const newMaskY = finalY + (relativeY * scaleY);
|
||||||
const newMaskWidth = (maskShape.width || 100) * scaleX;
|
const newMaskWidth = (maskShape.width || 100) * scaleX;
|
||||||
const newMaskHeight = (maskShape.height || 100) * scaleY;
|
const newMaskHeight = (maskShape.height || 100) * scaleY;
|
||||||
|
|
||||||
|
|||||||
@@ -58,26 +58,6 @@ const AbstractShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shape
|
|||||||
y: node.y() - (obj.height || 100) / 2,
|
y: node.y() - (obj.height || 100) / 2,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
onTransformEnd={() => {
|
|
||||||
const node = shapeRef.current;
|
|
||||||
if (!node) return;
|
|
||||||
|
|
||||||
const scaleX = node.scaleX();
|
|
||||||
const scaleY = node.scaleY();
|
|
||||||
|
|
||||||
node.scaleX(1);
|
|
||||||
node.scaleY(1);
|
|
||||||
|
|
||||||
const newRadius = Math.max(5, baseRadius * Math.min(scaleX, scaleY));
|
|
||||||
const newSize = newRadius * 2;
|
|
||||||
onUpdate(obj.id, {
|
|
||||||
x: node.x() - newSize / 2,
|
|
||||||
y: node.y() - newSize / 2,
|
|
||||||
rotation: node.rotation(),
|
|
||||||
width: newSize,
|
|
||||||
height: newSize,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -46,29 +46,6 @@ const ArrowShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapePro
|
|||||||
height: newY + dy,
|
height: newY + dy,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
onTransformEnd={() => {
|
|
||||||
const node = shapeRef.current;
|
|
||||||
if (!node) return;
|
|
||||||
|
|
||||||
const scaleX = node.scaleX();
|
|
||||||
const scaleY = node.scaleY();
|
|
||||||
|
|
||||||
node.scaleX(1);
|
|
||||||
node.scaleY(1);
|
|
||||||
|
|
||||||
const newX = node.x();
|
|
||||||
const newY = node.y();
|
|
||||||
const dx = (endX - startX) * scaleX;
|
|
||||||
const dy = (endY - startY) * scaleY;
|
|
||||||
|
|
||||||
onUpdate(obj.id, {
|
|
||||||
x: newX,
|
|
||||||
y: newY,
|
|
||||||
rotation: node.rotation(),
|
|
||||||
width: newX + dx,
|
|
||||||
height: newY + dy,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -52,24 +52,6 @@ const CircleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapePr
|
|||||||
y: node.y(),
|
y: node.y(),
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
onTransformEnd={() => {
|
|
||||||
const node = shapeRef.current;
|
|
||||||
if (!node) return;
|
|
||||||
|
|
||||||
const scaleX = node.scaleX();
|
|
||||||
|
|
||||||
node.scaleX(1);
|
|
||||||
node.scaleY(1);
|
|
||||||
|
|
||||||
const newRadius = Math.max(5, ((obj.width || 50) / 2) * scaleX);
|
|
||||||
onUpdate(obj.id, {
|
|
||||||
x: node.x(),
|
|
||||||
y: node.y(),
|
|
||||||
rotation: node.rotation(),
|
|
||||||
width: newRadius * 2,
|
|
||||||
height: newRadius * 2,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -45,24 +45,6 @@ const ImageObject = ({
|
|||||||
y: node.y(),
|
y: node.y(),
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
onTransformEnd={() => {
|
|
||||||
const node = shapeRef.current;
|
|
||||||
if (!node) return;
|
|
||||||
|
|
||||||
const scaleX = node.scaleX();
|
|
||||||
const scaleY = node.scaleY();
|
|
||||||
|
|
||||||
node.scaleX(1);
|
|
||||||
node.scaleY(1);
|
|
||||||
|
|
||||||
onUpdate(obj.id, {
|
|
||||||
x: node.x(),
|
|
||||||
y: node.y(),
|
|
||||||
rotation: node.rotation(),
|
|
||||||
width: Math.max(5, (obj.width || image.width) * scaleX),
|
|
||||||
height: Math.max(5, (obj.height || image.height) * scaleY),
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -44,29 +44,6 @@ const LineShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapeProp
|
|||||||
height: newY + dy,
|
height: newY + dy,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
onTransformEnd={() => {
|
|
||||||
const node = shapeRef.current;
|
|
||||||
if (!node) return;
|
|
||||||
|
|
||||||
const scaleX = node.scaleX();
|
|
||||||
const scaleY = node.scaleY();
|
|
||||||
|
|
||||||
node.scaleX(1);
|
|
||||||
node.scaleY(1);
|
|
||||||
|
|
||||||
const newX = node.x();
|
|
||||||
const newY = node.y();
|
|
||||||
const dx = (endX - startX) * scaleX;
|
|
||||||
const dy = (endY - startY) * scaleY;
|
|
||||||
|
|
||||||
onUpdate(obj.id, {
|
|
||||||
x: newX,
|
|
||||||
y: newY,
|
|
||||||
rotation: node.rotation(),
|
|
||||||
width: newX + dx,
|
|
||||||
height: newY + dy,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -50,22 +50,6 @@ const LinkShape = ({
|
|||||||
y: node.y(),
|
y: node.y(),
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
onTransformEnd={() => {
|
|
||||||
const node = shapeRef.current;
|
|
||||||
if (!node) return;
|
|
||||||
|
|
||||||
const scaleX = node.scaleX();
|
|
||||||
|
|
||||||
node.scaleX(1);
|
|
||||||
node.scaleY(1);
|
|
||||||
|
|
||||||
onUpdate(obj.id, {
|
|
||||||
x: node.x(),
|
|
||||||
y: node.y(),
|
|
||||||
rotation: node.rotation(),
|
|
||||||
fontSize: obj.fontSize ? Math.max(5, obj.fontSize * scaleX) : undefined,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -53,24 +53,6 @@ const RectangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shap
|
|||||||
y: node.y(),
|
y: node.y(),
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
onTransformEnd={() => {
|
|
||||||
const node = shapeRef.current;
|
|
||||||
if (!node) return;
|
|
||||||
|
|
||||||
const scaleX = node.scaleX();
|
|
||||||
const scaleY = node.scaleY();
|
|
||||||
|
|
||||||
node.scaleX(1);
|
|
||||||
node.scaleY(1);
|
|
||||||
|
|
||||||
onUpdate(obj.id, {
|
|
||||||
x: node.x(),
|
|
||||||
y: node.y(),
|
|
||||||
rotation: node.rotation(),
|
|
||||||
width: Math.max(5, (obj.width || 100) * scaleX),
|
|
||||||
height: Math.max(5, (obj.height || 100) * scaleY),
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -107,29 +107,6 @@ const TextShape = ({
|
|||||||
y: node.y(),
|
y: node.y(),
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
onTransformEnd={() => {
|
|
||||||
const node = shapeRef.current;
|
|
||||||
if (!node) return;
|
|
||||||
|
|
||||||
const scaleX = node.scaleX();
|
|
||||||
const scaleY = node.scaleY();
|
|
||||||
|
|
||||||
node.scaleX(1);
|
|
||||||
node.scaleY(1);
|
|
||||||
|
|
||||||
// محاسبه اندازه واقعی متن بعد از transform
|
|
||||||
const clientRect = node.getClientRect({ skipTransform: true });
|
|
||||||
const newWidth = clientRect.width * scaleX;
|
|
||||||
const newHeight = clientRect.height * scaleY;
|
|
||||||
|
|
||||||
onUpdate(obj.id, {
|
|
||||||
x: node.x(),
|
|
||||||
y: node.y(),
|
|
||||||
rotation: node.rotation(),
|
|
||||||
width: Math.max(5, newWidth),
|
|
||||||
height: Math.max(5, newHeight),
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -54,26 +54,6 @@ const TriangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shape
|
|||||||
y: node.y() - (obj.height || 100) / 2,
|
y: node.y() - (obj.height || 100) / 2,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
onTransformEnd={() => {
|
|
||||||
const node = shapeRef.current;
|
|
||||||
if (!node) return;
|
|
||||||
|
|
||||||
const scaleX = node.scaleX();
|
|
||||||
const scaleY = node.scaleY();
|
|
||||||
|
|
||||||
node.scaleX(1);
|
|
||||||
node.scaleY(1);
|
|
||||||
|
|
||||||
const newRadius = Math.max(5, radius * Math.min(scaleX, scaleY));
|
|
||||||
const newSize = newRadius * 2;
|
|
||||||
onUpdate(obj.id, {
|
|
||||||
x: node.x() - newSize / 2,
|
|
||||||
y: node.y() - newSize / 2,
|
|
||||||
rotation: node.rotation(),
|
|
||||||
width: newSize,
|
|
||||||
height: newSize,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user