147 lines
4.8 KiB
TypeScript
147 lines
4.8 KiB
TypeScript
import { useMemo } from 'react';
|
|
import { useCanvasStore } from '@/lib/store';
|
|
import type { PPTShapeElement } from '@openmaic/dsl';
|
|
import type { OperateResizeHandlers } from '@/lib/types/edit';
|
|
import { SHAPE_PATH_FORMULAS } from '@/configs/shapes';
|
|
import { useCommonOperate } from '../hooks/useCommonOperate';
|
|
import { RotateHandler } from './RotateHandler';
|
|
import { ResizeHandler } from './ResizeHandler';
|
|
import { BorderLine } from './BorderLine';
|
|
|
|
interface ShapeElementOperateProps {
|
|
readonly elementInfo: PPTShapeElement;
|
|
readonly handlerVisible: boolean;
|
|
readonly rotateElement: (e: React.MouseEvent, element: PPTShapeElement) => void;
|
|
readonly scaleElement: (
|
|
e: React.MouseEvent,
|
|
element: PPTShapeElement,
|
|
command: OperateResizeHandlers,
|
|
) => void;
|
|
readonly moveShapeKeypoint: (
|
|
e: React.MouseEvent,
|
|
element: PPTShapeElement,
|
|
index: number,
|
|
) => void;
|
|
}
|
|
|
|
export function ShapeElementOperate({
|
|
elementInfo,
|
|
handlerVisible,
|
|
rotateElement,
|
|
scaleElement,
|
|
moveShapeKeypoint,
|
|
}: ShapeElementOperateProps) {
|
|
const canvasScale = useCanvasStore.use.canvasScale();
|
|
|
|
const scaleWidth = useMemo(
|
|
() => elementInfo.width * canvasScale,
|
|
[elementInfo.width, canvasScale],
|
|
);
|
|
const scaleHeight = useMemo(
|
|
() => elementInfo.height * canvasScale,
|
|
[elementInfo.height, canvasScale],
|
|
);
|
|
const { resizeHandlers, borderLines } = useCommonOperate(scaleWidth, scaleHeight);
|
|
|
|
const keypoints = useMemo(() => {
|
|
if (!elementInfo.pathFormula || elementInfo.keypoints === undefined) return [];
|
|
const pathFormula = SHAPE_PATH_FORMULAS[elementInfo.pathFormula];
|
|
|
|
return elementInfo.keypoints.map((keypoint, index) => {
|
|
const getBaseSize = pathFormula.getBaseSize![index];
|
|
const relative = pathFormula.relative![index];
|
|
const keypointPos = getBaseSize(elementInfo.width, elementInfo.height) * keypoint;
|
|
|
|
let styles: React.CSSProperties = {};
|
|
if (relative === 'left') styles = { left: keypointPos * canvasScale + 'px' };
|
|
else if (relative === 'right')
|
|
styles = {
|
|
left: (elementInfo.width - keypointPos) * canvasScale + 'px',
|
|
};
|
|
else if (relative === 'center')
|
|
styles = {
|
|
left: ((elementInfo.width - keypointPos) / 2) * canvasScale + 'px',
|
|
};
|
|
else if (relative === 'top') styles = { top: keypointPos * canvasScale + 'px' };
|
|
else if (relative === 'bottom')
|
|
styles = {
|
|
top: (elementInfo.height - keypointPos) * canvasScale + 'px',
|
|
};
|
|
else if (relative === 'left_bottom')
|
|
styles = {
|
|
left: keypointPos * canvasScale + 'px',
|
|
top: elementInfo.height * canvasScale + 'px',
|
|
};
|
|
else if (relative === 'right_bottom')
|
|
styles = {
|
|
left: (elementInfo.width - keypointPos) * canvasScale + 'px',
|
|
top: elementInfo.height * canvasScale + 'px',
|
|
};
|
|
else if (relative === 'top_right')
|
|
styles = {
|
|
left: elementInfo.width * canvasScale + 'px',
|
|
top: keypointPos * canvasScale + 'px',
|
|
};
|
|
else if (relative === 'bottom_right')
|
|
styles = {
|
|
left: elementInfo.width * canvasScale + 'px',
|
|
top: (elementInfo.height - keypointPos) * canvasScale + 'px',
|
|
};
|
|
|
|
return {
|
|
keypoint,
|
|
styles,
|
|
};
|
|
});
|
|
}, [elementInfo, canvasScale]);
|
|
|
|
return (
|
|
<div className="shape-element-operate">
|
|
{borderLines.map((line) => (
|
|
<BorderLine
|
|
key={line.type}
|
|
type={line.type}
|
|
style={line.style}
|
|
className="operate-border-line"
|
|
/>
|
|
))}
|
|
{handlerVisible && (
|
|
<>
|
|
{resizeHandlers.map((point) => (
|
|
<ResizeHandler
|
|
key={point.direction}
|
|
type={point.direction}
|
|
rotate={elementInfo.rotate}
|
|
style={point.style}
|
|
className="operate-resize-handler"
|
|
onMouseDown={(e) => {
|
|
e.stopPropagation();
|
|
scaleElement(e, elementInfo, point.direction);
|
|
}}
|
|
/>
|
|
))}
|
|
<RotateHandler
|
|
className="operate-rotate-handler"
|
|
style={{ left: scaleWidth / 2 + 'px' }}
|
|
onMouseDown={(e) => {
|
|
e.stopPropagation();
|
|
rotateElement(e, elementInfo);
|
|
}}
|
|
/>
|
|
{keypoints.map((keypoint, index) => (
|
|
<div
|
|
key={index}
|
|
className="operate-keypoint-handler absolute w-[10px] h-[10px] left-0 top-0 m-[-5px_0_0_-5px] border border-primary bg-[#ffe873] rounded-[1px]"
|
|
style={keypoint.styles}
|
|
onMouseDown={(e) => {
|
|
e.stopPropagation();
|
|
moveShapeKeypoint(e, elementInfo, index);
|
|
}}
|
|
/>
|
|
))}
|
|
</>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|