Explorar el Código

feat: add line shape (#371)

* feat: add line shape

* fix: align line tool

* fix: hitbox bug sw to ne

* fix: add stroke width n sloppiness  for line

* fix: center line inside a panel box

* fix: use color as a unique key
Bakhtiiar Muzakparov hace 5 años
padre
commit
8db8827c6f

+ 1 - 0
src/components/ColorPicker.tsx

@@ -33,6 +33,7 @@ const Picker = function({
             title={color}
             tabIndex={0}
             style={{ backgroundColor: color }}
+            key={color}
           >
             {color === "transparent" ? (
               <div className="color-picker-transparent"></div>

+ 9 - 0
src/element/bounds.ts

@@ -48,3 +48,12 @@ export function getArrowPoints(element: ExcalidrawElement) {
 
   return [x1, y1, x2, y2, x3, y3, x4, y4];
 }
+
+export function getLinePoints(element: ExcalidrawElement) {
+  const x1 = 0;
+  const y1 = 0;
+  const x2 = element.width;
+  const y2 = element.height;
+
+  return [x1, y1, x2, y2];
+}

+ 9 - 1
src/element/collision.ts

@@ -4,7 +4,8 @@ import { ExcalidrawElement } from "./types";
 import {
   getArrowPoints,
   getDiamondPoints,
-  getElementAbsoluteCoords
+  getElementAbsoluteCoords,
+  getLinePoints
 } from "./bounds";
 
 export function hitTest(
@@ -153,6 +154,13 @@ export function hitTest(
       //    /
       distanceBetweenPointAndSegment(x, y, x4, y4, x2, y2) < lineThreshold
     );
+  } else if (element.type === "line") {
+    const [x1, y1, x2, y2] = getLinePoints(element);
+    // The computation is done at the origin, we need to add a translation
+    x -= element.x;
+    y -= element.y;
+
+    return distanceBetweenPointAndSegment(x, y, x1, y1, x2, y2) < lineThreshold;
   } else if (element.type === "text") {
     const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
 

+ 1 - 1
src/element/handlerRectangles.ts

@@ -76,7 +76,7 @@ export function handlerRectangles(
     8
   ]; // se
 
-  if (element.type === "arrow") {
+  if (element.type === "arrow" || element.type === "line") {
     return {
       nw: handlers.nw,
       se: handlers.se

+ 2 - 1
src/element/index.ts

@@ -2,7 +2,8 @@ export { newElement, duplicateElement } from "./newElement";
 export {
   getElementAbsoluteCoords,
   getDiamondPoints,
-  getArrowPoints
+  getArrowPoints,
+  getLinePoints
 } from "./bounds";
 
 export { handlerRectangles } from "./handlerRectangles";

+ 21 - 1
src/renderer/renderElement.ts

@@ -1,6 +1,10 @@
 import { ExcalidrawElement } from "../element/types";
 import { isTextElement } from "../element/typeChecks";
-import { getDiamondPoints, getArrowPoints } from "../element/bounds";
+import {
+  getDiamondPoints,
+  getArrowPoints,
+  getLinePoints
+} from "../element/bounds";
 import { RoughCanvas } from "roughjs/bin/canvas";
 import { Drawable } from "roughjs/bin/core";
 
@@ -118,6 +122,22 @@ export function renderElement(
     (element.shape as Drawable[]).forEach(shape => rc.draw(shape));
     context.globalAlpha = 1;
     return;
+  } else if (element.type === "line") {
+    const [x1, y1, x2, y2] = getLinePoints(element);
+    const options = {
+      stroke: element.strokeColor,
+      strokeWidth: element.strokeWidth,
+      roughness: element.roughness,
+      seed: element.seed
+    };
+
+    if (!element.shape) {
+      element.shape = generator.line(x1, y1, x2, y2, options);
+    }
+
+    context.globalAlpha = element.opacity / 100;
+    rc.draw(element.shape as Drawable);
+    context.globalAlpha = 1;
   } else if (isTextElement(element)) {
     context.globalAlpha = element.opacity / 100;
     const font = context.font;

+ 2 - 1
src/scene/comparisons.ts

@@ -18,7 +18,8 @@ export const hasStroke = (elements: readonly ExcalidrawElement[]) =>
       (element.type === "rectangle" ||
         element.type === "ellipse" ||
         element.type === "diamond" ||
-        element.type === "arrow")
+        element.type === "arrow" ||
+        element.type === "line")
   );
 
 export const hasText = (elements: readonly ExcalidrawElement[]) =>

+ 16 - 0
src/shapes.tsx

@@ -55,6 +55,22 @@ export const SHAPES = [
       </svg>
     ),
     value: "text"
+  },
+  {
+    icon: (
+      // custom
+      <svg viewBox="0 0 6 6">
+        <line
+          x1="0"
+          y1="3"
+          x2="6"
+          y2="3"
+          stroke="black"
+          strokeLinecap="round"
+        />
+      </svg>
+    ),
+    value: "line"
   }
 ];