Explorar el Código

optimization(shape and brush): drag and drop event

RoyLiu hace 4 años
padre
commit
0172dd3755
Se han modificado 3 ficheros con 116 adiciones y 49 borrados
  1. 58 26
      components/Ink/index.tsx
  2. 6 1
      components/OuterRect/index.tsx
  3. 52 22
      components/Shape/index.tsx

+ 58 - 26
components/Ink/index.tsx

@@ -20,14 +20,11 @@ const Ink: React.FC<AnnotationElementPropsType> = ({
   scale,
   id,
 }: AnnotationElementPropsType) => {
-  let points: PointType[][] = [];
-  let tempRect: HTMLCoordinateType = { top: 0, left: 0, width: 0, height: 0 };
-  const borderWidth = bdwidth * scale;
-
-  points = pointCalc(position as PointType[][], viewport.height, scale);
-  tempRect = rectCalcWithPoint(points, borderWidth);
-
+  const [points, setPoints] = useState<PointType[][]>([]);
   const [rect, setRect] = useState({ top: 0, left: 0, width: 0, height: 0 });
+  const [moving, setMoving] = useState(false);
+
+  const borderWidth = bdwidth * scale;
 
   const handleScaleOrMove = ({
     top,
@@ -35,28 +32,48 @@ const Ink: React.FC<AnnotationElementPropsType> = ({
     width = 0,
     height = 0,
   }: CoordType): void => {
-    const xScaleRate = width / tempRect.width;
-    const yScaleRate = height / tempRect.height;
-    const xDistance = left - tempRect.left;
-    const yDistance = tempRect.top - top;
-
-    const newPosition = (position as PointType[][])[0].map((ele) => ({
-      x: (ele.x + xDistance) * (xScaleRate || 1),
-      y: (ele.y + yDistance) * (yScaleRate || 1),
-    }));
-
-    setRect({
-      top,
-      left,
-      width,
-      height,
-    });
+    setMoving(true);
+
+    setRect((currentRect) => {
+      const rx = width / currentRect.width;
+      const ry = height / currentRect.height;
+      const dx = left - currentRect.left;
+      const dy = currentRect.top - top;
+      let disX = 0;
+      let disY = 0;
+
+      setPoints((currentPoint) => {
+        const newRect = rectCalcWithPoint(currentPoint, borderWidth);
+        disX = newRect.left - left;
+        disY = newRect.top - top;
 
-    onUpdate({
-      position: [newPosition],
+        const newPoints = (currentPoint as PointType[][])[0].map((ele) => {
+          let x = (ele.x + dx) * rx;
+          let y = (ele.y - dy) * ry;
+
+          if (rx !== 1 || ry !== 1) {
+            x = x - disX;
+          }
+          if (ry !== 1) {
+            y = y - disY;
+          }
+
+          return {
+            x,
+            y,
+          };
+        });
+        return [newPoints];
+      });
+
+      return { top, left, width, height };
     });
   };
 
+  const handleMouseUp = () => {
+    setMoving(false);
+  };
+
   useEffect(() => {
     const newPoints = pointCalc(
       position as PointType[][],
@@ -64,9 +81,23 @@ const Ink: React.FC<AnnotationElementPropsType> = ({
       scale,
     );
     const newRect = rectCalcWithPoint(newPoints, borderWidth);
+    setPoints(newPoints);
     setRect(newRect);
   }, [viewport, scale]);
 
+  useEffect(() => {
+    if (!moving && points[0]) {
+      const newPoints = (points as PointType[][])[0].map((ele) => ({
+        x: ele.x / scale,
+        y: (viewport.height - ele.y) / scale,
+      }));
+
+      onUpdate({
+        position: [newPoints],
+      });
+    }
+  }, [moving, points]);
+
   return (
     <>
       <AnnotationContainer
@@ -76,7 +107,7 @@ const Ink: React.FC<AnnotationElementPropsType> = ({
         width={`${rect.width}px`}
         height={`${rect.height}px`}
       >
-        <SVG viewBox={calcViewBox(tempRect, borderWidth)}>
+        <SVG viewBox={calcViewBox(rect, borderWidth)}>
           {points.map((ele: PointType[], index: number) => {
             const key = `${id}_path_${index}`;
             return (
@@ -103,6 +134,7 @@ const Ink: React.FC<AnnotationElementPropsType> = ({
           height={rect.height}
           onMove={handleScaleOrMove}
           onScale={handleScaleOrMove}
+          onMouseUp={handleMouseUp}
         />
       ) : (
         ''

+ 6 - 1
components/OuterRect/index.tsx

@@ -17,6 +17,7 @@ type Props = {
   onScale?: (scaleCoord: CoordType) => void;
   onClick?: (event: React.MouseEvent) => void;
   onDoubleClick?: () => void;
+  onMouseUp?: () => void;
 };
 
 type ObjPositionType = {
@@ -48,10 +49,11 @@ const OuterRect: React.FC<Props> = ({
   onScale,
   onClick,
   onDoubleClick,
+  onMouseUp,
 }: Props) => {
   const data = generateCirclesData(width, height);
   const [state, setState] = useState(initState);
-  const [cursorPosition, setRef] = useCursorPosition(20);
+  const [cursorPosition, setRef] = useCursorPosition(25);
 
   const handleMouseDown = (e: React.MouseEvent | React.TouchEvent): void => {
     e.preventDefault();
@@ -75,6 +77,9 @@ const OuterRect: React.FC<Props> = ({
   const handleMouseUp = (): void => {
     setRef(null);
     setState(initState);
+    if (onMouseUp) {
+      onMouseUp();
+    }
   };
 
   const calcMoveResult = (

+ 52 - 22
components/Shape/index.tsx

@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useEffect, useState } from 'react';
 
 import OuterRect from '../OuterRect';
 import SvgShapeElement from '../SvgShapeElement';
@@ -23,7 +23,13 @@ const Shape: React.FC<AnnotationElementPropsType> = ({
   isCollapse,
   onUpdate,
 }: AnnotationElementPropsType) => {
-  const annotRect = rectCalc(position as PositionType, viewport.height, scale);
+  const [moving, setMoving] = useState(false);
+  const [localePos, setLocalePos] = useState({
+    top: 0,
+    left: 0,
+    width: 0,
+    height: 0,
+  });
 
   const handleScaleOrMove = ({
     top,
@@ -31,36 +37,59 @@ const Shape: React.FC<AnnotationElementPropsType> = ({
     width = 0,
     height = 0,
   }: CoordType): void => {
+    setMoving(true);
     const newPosition = {
       top,
       left,
-      bottom: top + (height || annotRect.height),
-      right: left + (width || annotRect.width),
+      height,
+      width,
     };
 
-    onUpdate({
-      position: parsePositionForBackend(
-        obj_type,
-        newPosition,
-        viewport.height,
-        scale,
-      ),
-    });
+    setLocalePos(newPosition);
   };
 
+  const handleMouseUp = () => {
+    setMoving(false);
+  };
+
+  useEffect(() => {
+    const rect = rectCalc(position as PositionType, viewport.height, scale);
+    setLocalePos(rect);
+  }, [viewport, scale]);
+
+  useEffect(() => {
+    if (!moving) {
+      const newPosition = {
+        top: localePos.top,
+        left: localePos.left,
+        right: localePos.left + localePos.width,
+        bottom: localePos.top + localePos.height,
+      };
+
+      onUpdate({
+        position: parsePositionForBackend(
+          obj_type,
+          newPosition as PositionType,
+          viewport.height,
+          scale,
+        ),
+      });
+    }
+  }, [moving, localePos]);
+
   return (
     <>
       <AnnotationContainer
         id={id}
-        top={`${annotRect.top}px`}
-        left={`${annotRect.left}px`}
-        width={`${annotRect.width}px`}
-        height={`${annotRect.height}px`}
+        top={`${localePos.top}px`}
+        left={`${localePos.left}px`}
+        width={`${localePos.width}px`}
+        height={`${localePos.height}px`}
       >
         <SvgShapeElement
           shape={obj_type}
-          width={annotRect.width}
-          height={annotRect.height}
+          width={localePos.width}
+          height={localePos.height}
           bdcolor={bdcolor}
           transparency={transparency}
           bdwidth={bdwidth * scale}
@@ -70,12 +99,13 @@ const Shape: React.FC<AnnotationElementPropsType> = ({
       </AnnotationContainer>
       {!isCollapse ? (
         <OuterRect
-          top={annotRect.top}
-          left={annotRect.left}
-          width={annotRect.width}
-          height={annotRect.height}
+          top={localePos.top}
+          left={localePos.left}
+          width={localePos.width}
+          height={localePos.height}
           onMove={handleScaleOrMove}
           onScale={handleScaleOrMove}
+          onMouseUp={handleMouseUp}
         />
       ) : (
         ''