LineElementOperate.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import { useMemo } from 'react';
  2. import { useCanvasStore } from '@/lib/store';
  3. import type { PPTLineElement } from '@/lib/types/slides';
  4. import { OperateLineHandlers } from '@/lib/types/edit';
  5. import { ResizeHandler } from './ResizeHandler';
  6. interface LineElementOperateProps {
  7. readonly elementInfo: PPTLineElement;
  8. readonly handlerVisible: boolean;
  9. readonly dragLineElement: (
  10. e: React.MouseEvent,
  11. element: PPTLineElement,
  12. command: OperateLineHandlers,
  13. ) => void;
  14. }
  15. export function LineElementOperate({
  16. elementInfo,
  17. handlerVisible,
  18. dragLineElement,
  19. }: LineElementOperateProps) {
  20. const canvasScale = useCanvasStore.use.canvasScale();
  21. const svgWidth = useMemo(
  22. () => Math.max(elementInfo.start[0], elementInfo.end[0]),
  23. [elementInfo.start, elementInfo.end],
  24. );
  25. const svgHeight = useMemo(
  26. () => Math.max(elementInfo.start[1], elementInfo.end[1]),
  27. [elementInfo.start, elementInfo.end],
  28. );
  29. const resizeHandlers = useMemo(() => {
  30. const handlers = [
  31. {
  32. handler: OperateLineHandlers.START,
  33. style: {
  34. left: elementInfo.start[0] * canvasScale + 'px',
  35. top: elementInfo.start[1] * canvasScale + 'px',
  36. },
  37. },
  38. {
  39. handler: OperateLineHandlers.END,
  40. style: {
  41. left: elementInfo.end[0] * canvasScale + 'px',
  42. top: elementInfo.end[1] * canvasScale + 'px',
  43. },
  44. },
  45. ];
  46. if (elementInfo.curve || elementInfo.broken || elementInfo.broken2) {
  47. const ctrlHandler = (elementInfo.curve || elementInfo.broken || elementInfo.broken2) as [
  48. number,
  49. number,
  50. ];
  51. handlers.push({
  52. handler: OperateLineHandlers.C,
  53. style: {
  54. left: ctrlHandler[0] * canvasScale + 'px',
  55. top: ctrlHandler[1] * canvasScale + 'px',
  56. },
  57. });
  58. } else if (elementInfo.cubic) {
  59. const [ctrlHandler1, ctrlHandler2] = elementInfo.cubic;
  60. handlers.push({
  61. handler: OperateLineHandlers.C1,
  62. style: {
  63. left: ctrlHandler1[0] * canvasScale + 'px',
  64. top: ctrlHandler1[1] * canvasScale + 'px',
  65. },
  66. });
  67. handlers.push({
  68. handler: OperateLineHandlers.C2,
  69. style: {
  70. left: ctrlHandler2[0] * canvasScale + 'px',
  71. top: ctrlHandler2[1] * canvasScale + 'px',
  72. },
  73. });
  74. }
  75. return handlers;
  76. }, [elementInfo, canvasScale]);
  77. return (
  78. <div className="line-element-operate">
  79. {handlerVisible && (
  80. <>
  81. {resizeHandlers.map((point) => (
  82. <ResizeHandler
  83. key={point.handler}
  84. style={point.style}
  85. className="operate-resize-handler"
  86. onMouseDown={(e) => {
  87. e.stopPropagation();
  88. dragLineElement(e, elementInfo, point.handler);
  89. }}
  90. />
  91. ))}
  92. <svg
  93. width={svgWidth || 1}
  94. height={svgHeight || 1}
  95. stroke={elementInfo.color}
  96. className="absolute left-0 top-0 pointer-events-none origin-top-left"
  97. style={{ transform: `scale(${canvasScale})`, overflow: 'visible' }}
  98. >
  99. {elementInfo.curve && (
  100. <g>
  101. <line
  102. className="anchor-line stroke-1 stroke-dasharray-[5_5] opacity-50"
  103. x1={elementInfo.start[0]}
  104. y1={elementInfo.start[1]}
  105. x2={elementInfo.curve[0]}
  106. y2={elementInfo.curve[1]}
  107. />
  108. <line
  109. className="anchor-line stroke-1 stroke-dasharray-[5_5] opacity-50"
  110. x1={elementInfo.end[0]}
  111. y1={elementInfo.end[1]}
  112. x2={elementInfo.curve[0]}
  113. y2={elementInfo.curve[1]}
  114. />
  115. </g>
  116. )}
  117. {elementInfo.cubic?.map((item, index) => (
  118. <g key={index}>
  119. {index === 0 && (
  120. <line
  121. className="anchor-line stroke-1 stroke-dasharray-[5_5] opacity-50"
  122. x1={elementInfo.start[0]}
  123. y1={elementInfo.start[1]}
  124. x2={item[0]}
  125. y2={item[1]}
  126. />
  127. )}
  128. {index === 1 && (
  129. <line
  130. className="anchor-line stroke-1 stroke-dasharray-[5_5] opacity-50"
  131. x1={elementInfo.end[0]}
  132. y1={elementInfo.end[1]}
  133. x2={item[0]}
  134. y2={item[1]}
  135. />
  136. )}
  137. </g>
  138. ))}
  139. </svg>
  140. </>
  141. )}
  142. </div>
  143. );
  144. }