Sfoglia il codice sorgente

feat: Adds rounded icons, joins and caps. (#3521)

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
vanilla_orig
David Luzar 4 anni fa
parent
commit
178ee04d82
Nessun account collegato all'indirizzo email del committer

+ 30
- 90
src/components/icons.tsx Vedi File

@@ -222,14 +222,12 @@ export const SendToBackIcon = React.memo(
222 222
           d="M18 7.333C18 6.597 17.403 6 16.667 6H7.333C6.597 6 6 6.597 6 7.333v9.334C6 17.403 6.597 18 7.333 18h9.334c.736 0 1.333-.597 1.333-1.333V7.333z"
223 223
           fill={activeElementColor(theme)}
224 224
           stroke={activeElementColor(theme)}
225
-          strokeLinejoin="round"
226 225
           strokeWidth="2"
227 226
         />
228 227
         <path
229 228
           d="M11 3a1 1 0 00-1-1H3a1 1 0 00-1 1v7a1 1 0 001 1h8V3zM22 14a1 1 0 00-1-1h-7a1 1 0 00-1 1v7a1 1 0 001 1h8v-8z"
230 229
           fill={iconFillColor(theme)}
231 230
           stroke={iconFillColor(theme)}
232
-          strokeLinejoin="round"
233 231
           strokeWidth="2"
234 232
         />
235 233
       </>,
@@ -335,7 +333,6 @@ export const DistributeHorizontallyIcon = React.memo(
335 333
   ({ theme }: { theme: "light" | "dark" }) =>
336 334
     createIcon(
337 335
       <>
338
-        <path d="M5 5V19Z" fill="black" />
339 336
         <path
340 337
           d="M19 5V19M5 5V19"
341 338
           stroke={iconFillColor(theme)}
@@ -479,42 +476,16 @@ export const GroupIcon = React.memo(({ theme }: { theme: "light" | "dark" }) =>
479 476
         stroke={iconFillColor(theme)}
480 477
         strokeWidth="2"
481 478
       />
482
-      <rect
483
-        x="2.5"
484
-        y="2.5"
485
-        width="30"
486
-        height="30"
487
-        fill={handlerColor(theme)}
488
-        stroke={iconFillColor(theme)}
489
-        strokeWidth="6"
490
-      />
491
-      <rect
492
-        x="2.5"
493
-        y="149.5"
494
-        width="30"
495
-        height="30"
496
-        fill={handlerColor(theme)}
497
-        stroke={iconFillColor(theme)}
498
-        strokeWidth="6"
499
-      />
500
-      <rect
501
-        x="147.5"
502
-        y="149.5"
503
-        width="30"
504
-        height="30"
505
-        fill={handlerColor(theme)}
506
-        stroke={iconFillColor(theme)}
507
-        strokeWidth="6"
508
-      />
509
-      <rect
510
-        x="147.5"
511
-        y="2.5"
512
-        width="30"
513
-        height="30"
479
+      <g
514 480
         fill={handlerColor(theme)}
515 481
         stroke={iconFillColor(theme)}
516 482
         strokeWidth="6"
517
-      />
483
+      >
484
+        <rect x="2.5" y="2.5" width="30" height="30" />
485
+        <rect x="2.5" y="149.5" width="30" height="30" />
486
+        <rect x="147.5" y="149.5" width="30" height="30" />
487
+        <rect x="147.5" y="2.5" width="30" height="30" />
488
+      </g>
518 489
     </>,
519 490
     { width: 182, height: 182, mirror: true },
520 491
   ),
@@ -536,60 +507,18 @@ export const UngroupIcon = React.memo(
536 507
           stroke={iconFillColor(theme)}
537 508
           strokeWidth="2"
538 509
         />
539
-        <rect
540
-          x="2.5"
541
-          y="2.5"
542
-          width="30"
543
-          height="30"
544
-          fill={handlerColor(theme)}
545
-          stroke={iconFillColor(theme)}
546
-          strokeWidth="6"
547
-        />
548
-        <rect
549
-          x="78.5"
550
-          y="149.5"
551
-          width="30"
552
-          height="30"
510
+        <g
553 511
           fill={handlerColor(theme)}
554 512
           stroke={iconFillColor(theme)}
555 513
           strokeWidth="6"
556
-        />
557
-        <rect
558
-          x="147.5"
559
-          y="149.5"
560
-          width="30"
561
-          height="30"
562
-          fill={handlerColor(theme)}
563
-          stroke={iconFillColor(theme)}
564
-          strokeWidth="6"
565
-        />
566
-        <rect
567
-          x="147.5"
568
-          y="78.5"
569
-          width="30"
570
-          height="30"
571
-          fill={handlerColor(theme)}
572
-          stroke={iconFillColor(theme)}
573
-          strokeWidth="6"
574
-        />
575
-        <rect
576
-          x="105.5"
577
-          y="2.5"
578
-          width="30"
579
-          height="30"
580
-          fill={handlerColor(theme)}
581
-          stroke={iconFillColor(theme)}
582
-          strokeWidth="6"
583
-        />
584
-        <rect
585
-          x="2.5"
586
-          y="102.5"
587
-          width="30"
588
-          height="30"
589
-          fill={handlerColor(theme)}
590
-          stroke={iconFillColor(theme)}
591
-          strokeWidth="6"
592
-        />
514
+        >
515
+          <rect x="2.5" y="2.5" width="30" height="30" />
516
+          <rect x="78.5" y="149.5" width="30" height="30" />
517
+          <rect x="147.5" y="149.5" width="30" height="30" />
518
+          <rect x="147.5" y="78.5" width="30" height="30" />
519
+          <rect x="105.5" y="2.5" width="30" height="30" />
520
+          <rect x="2.5" y="102.5" width="30" height="30" />
521
+        </g>
593 522
       </>,
594 523
       { width: 182, height: 182, mirror: true },
595 524
     ),
@@ -631,9 +560,10 @@ export const StrokeWidthIcon = React.memo(
631 560
   ({ theme, strokeWidth }: { theme: "light" | "dark"; strokeWidth: number }) =>
632 561
     createIcon(
633 562
       <path
634
-        d="M6 10H34"
563
+        d="M6 10H32"
635 564
         stroke={iconFillColor(theme)}
636 565
         strokeWidth={strokeWidth}
566
+        strokeLinecap="round"
637 567
         fill="none"
638 568
       />,
639 569
       { width: 40, height: 20 },
@@ -648,6 +578,7 @@ export const StrokeStyleSolidIcon = React.memo(
648 578
         stroke={iconFillColor(theme)}
649 579
         strokeWidth={2}
650 580
         fill="none"
581
+        strokeLinecap="round"
651 582
       />,
652 583
       {
653 584
         width: 40,
@@ -665,6 +596,7 @@ export const StrokeStyleDashedIcon = React.memo(
665 596
         strokeWidth={2.5}
666 597
         strokeDasharray={"10, 8"}
667 598
         fill="none"
599
+        strokeLinecap="round"
668 600
       />,
669 601
       { width: 40, height: 20 },
670 602
     ),
@@ -674,11 +606,12 @@ export const StrokeStyleDottedIcon = React.memo(
674 606
   ({ theme }: { theme: "light" | "dark" }) =>
675 607
     createIcon(
676 608
       <path
677
-        d="M6 10H34"
609
+        d="M6 10H36"
678 610
         stroke={iconFillColor(theme)}
679 611
         strokeWidth={2.5}
680
-        strokeDasharray={"4, 4"}
612
+        strokeDasharray={"2, 4.5"}
681 613
         fill="none"
614
+        strokeLinecap="round"
682 615
       />,
683 616
       { width: 40, height: 20 },
684 617
     ),
@@ -691,6 +624,7 @@ export const SloppinessArchitectIcon = React.memo(
691 624
         d="M3.00098 16.1691C6.28774 13.9744 19.6399 2.8905 22.7215 3.00082C25.8041 3.11113 19.1158 15.5488 21.4962 16.8309C23.8757 18.1131 34.4155 11.7148 37.0001 10.6919"
692 625
         stroke={iconFillColor(theme)}
693 626
         strokeWidth={2}
627
+        strokeLinecap="round"
694 628
         fill="none"
695 629
       />,
696 630
       { width: 40, height: 20, mirror: true },
@@ -704,6 +638,7 @@ export const SloppinessArtistIcon = React.memo(
704 638
         d="M3 17C6.68158 14.8752 16.1296 9.09849 22.0648 6.54922C28 3.99995 22.2896 13.3209 25 14C27.7104 14.6791 36.3757 9.6471 36.3757 9.6471M6.40706 15C13 11.1918 20.0468 1.51045 23.0234 3.0052C26 4.49995 20.457 12.8659 22.7285 16.4329C25 20 36.3757 13 36.3757 13"
705 639
         stroke={iconFillColor(theme)}
706 640
         strokeWidth={2}
641
+        strokeLinecap="round"
707 642
         fill="none"
708 643
       />,
709 644
       { width: 40, height: 20, mirror: true },
@@ -717,6 +652,7 @@ export const SloppinessCartoonistIcon = React.memo(
717 652
         d="M3 15.6468C6.93692 13.5378 22.5544 2.81528 26.6206 3.00242C30.6877 3.18956 25.6708 15.3346 27.4009 16.7705C29.1309 18.2055 35.4001 12.4762 37 11.6177M3.97143 10.4917C6.61158 9.24563 16.3706 2.61886 19.8104 3.01724C23.2522 3.41472 22.0773 12.2013 24.6181 12.8783C27.1598 13.5536 33.3179 8.04068 35.0571 7.07244"
718 653
         stroke={iconFillColor(theme)}
719 654
         strokeWidth={2}
655
+        strokeLinecap="round"
720 656
         fill="none"
721 657
       />,
722 658
       { width: 40, height: 20, mirror: true },
@@ -730,6 +666,7 @@ export const EdgeSharpIcon = React.memo(
730 666
         d="M10 17L10 5L35 5"
731 667
         stroke={iconFillColor(theme)}
732 668
         strokeWidth={2}
669
+        strokeLinecap="round"
733 670
         fill="none"
734 671
       />,
735 672
       { width: 40, height: 20, mirror: true },
@@ -743,6 +680,7 @@ export const EdgeRoundIcon = React.memo(
743 680
         d="M10 17V15C10 8 13 5 21 5L33.5 5"
744 681
         stroke={iconFillColor(theme)}
745 682
         strokeWidth={2}
683
+        strokeLinecap="round"
746 684
         fill="none"
747 685
       />,
748 686
       { width: 40, height: 20, mirror: true },
@@ -902,6 +840,7 @@ export const TextAlignLeftIcon = React.memo(
902 840
       <path
903 841
         d="M12.83 352h262.34A12.82 12.82 0 00288 339.17v-38.34A12.82 12.82 0 00275.17 288H12.83A12.82 12.82 0 000 300.83v38.34A12.82 12.82 0 0012.83 352zm0-256h262.34A12.82 12.82 0 00288 83.17V44.83A12.82 12.82 0 00275.17 32H12.83A12.82 12.82 0 000 44.83v38.34A12.82 12.82 0 0012.83 96zM432 160H16a16 16 0 00-16 16v32a16 16 0 0016 16h416a16 16 0 0016-16v-32a16 16 0 00-16-16zm0 256H16a16 16 0 00-16 16v32a16 16 0 0016 16h416a16 16 0 0016-16v-32a16 16 0 00-16-16z"
904 842
         fill={iconFillColor(theme)}
843
+        strokeLinecap="round"
905 844
       />,
906 845
       { width: 448, height: 512 },
907 846
     ),
@@ -924,6 +863,7 @@ export const TextAlignRightIcon = React.memo(
924 863
       <path
925 864
         d="M16 224h416a16 16 0 0016-16v-32a16 16 0 00-16-16H16a16 16 0 00-16 16v32a16 16 0 0016 16zm416 192H16a16 16 0 00-16 16v32a16 16 0 0016 16h416a16 16 0 0016-16v-32a16 16 0 00-16-16zm3.17-384H172.83A12.82 12.82 0 00160 44.83v38.34A12.82 12.82 0 00172.83 96h262.34A12.82 12.82 0 00448 83.17V44.83A12.82 12.82 0 00435.17 32zm0 256H172.83A12.82 12.82 0 00160 300.83v38.34A12.82 12.82 0 00172.83 352h262.34A12.82 12.82 0 00448 339.17v-38.34A12.82 12.82 0 00435.17 288z"
926 865
         fill={iconFillColor(theme)}
866
+        strokeLinecap="round"
927 867
       />,
928 868
       { width: 448, height: 512 },
929 869
     ),

+ 1
- 0
src/locales/en.json Vedi File

@@ -158,6 +158,7 @@
158 158
     "ellipse": "Ellipse",
159 159
     "arrow": "Arrow",
160 160
     "line": "Line",
161
+    "freedraw": "Draw",
161 162
     "text": "Text",
162 163
     "library": "Library",
163 164
     "lock": "Keep selected tool active after drawing"

+ 12
- 4
src/renderer/renderElement.ts Vedi File

@@ -32,8 +32,8 @@ const defaultAppState = getDefaultAppState();
32 32
 
33 33
 const CANVAS_PADDING = 20;
34 34
 
35
-const DASHARRAY_DASHED = [12, 8];
36
-const DASHARRAY_DOTTED = [3, 6];
35
+const getDashArrayDashed = (strokeWidth: number) => [8, 8 + strokeWidth];
36
+const getDashArrayDotted = (strokeWidth: number) => [1.5, 6 + strokeWidth];
37 37
 
38 38
 export interface ExcalidrawElementWithCanvas {
39 39
   element: ExcalidrawElement | ExcalidrawTextElement;
@@ -122,12 +122,17 @@ const drawElementOnCanvas = (
122 122
     case "rectangle":
123 123
     case "diamond":
124 124
     case "ellipse": {
125
+      context.lineJoin = "round";
126
+      context.lineCap = "round";
125 127
       rc.draw(getShapeForElement(element) as Drawable);
126 128
       break;
127 129
     }
128 130
     case "arrow":
129 131
     case "draw":
130 132
     case "line": {
133
+      context.lineJoin = "round";
134
+      context.lineCap = "round";
135
+
131 136
       (getShapeForElement(element) as Drawable[]).forEach((shape) => {
132 137
         rc.draw(shape);
133 138
       });
@@ -202,9 +207,9 @@ export const generateRoughOptions = (element: ExcalidrawElement): Options => {
202 207
     seed: element.seed,
203 208
     strokeLineDash:
204 209
       element.strokeStyle === "dashed"
205
-        ? DASHARRAY_DASHED
210
+        ? getDashArrayDashed(element.strokeWidth)
206 211
         : element.strokeStyle === "dotted"
207
-        ? DASHARRAY_DOTTED
212
+        ? getDashArrayDotted(element.strokeWidth)
208 213
         : undefined,
209 214
     // for non-solid strokes, disable multiStroke because it tends to make
210 215
     // dashes/dots overlay each other
@@ -568,6 +573,7 @@ export const renderElementToSvg = (
568 573
         node.setAttribute("stroke-opacity", `${opacity}`);
569 574
         node.setAttribute("fill-opacity", `${opacity}`);
570 575
       }
576
+      node.setAttribute("stroke-linecap", "round");
571 577
       node.setAttribute(
572 578
         "transform",
573 579
         `translate(${offsetX || 0} ${
@@ -583,6 +589,8 @@ export const renderElementToSvg = (
583 589
       generateElementShape(element, generator);
584 590
       const group = svgRoot.ownerDocument!.createElementNS(SVG_NS, "g");
585 591
       const opacity = element.opacity / 100;
592
+      group.setAttribute("stroke-linecap", "round");
593
+
586 594
       (getShapeForElement(element) as Drawable[]).forEach((shape) => {
587 595
         const node = rsvg.draw(shape);
588 596
         if (opacity !== 1) {

+ 2
- 0
src/tests/scene/__snapshots__/export.test.ts.snap Vedi File

@@ -35,6 +35,7 @@ exports[`exportToSvg with default arguments 1`] = `
35 35
   
36 36
   
37 37
   <g
38
+    stroke-linecap="round"
38 39
     transform="translate(10 10) rotate(0 50 50)"
39 40
   >
40 41
     <path
@@ -51,6 +52,7 @@ exports[`exportToSvg with default arguments 1`] = `
51 52
     />
52 53
   </g>
53 54
   <g
55
+    stroke-linecap="round"
54 56
     transform="translate(10 10) rotate(0 50 50)"
55 57
   >
56 58
     <path

Loading…
Annulla
Salva