Pārlūkot izejas kodu

balances dashes for ellipses

main
Steve Ruiz 4 gadus atpakaļ
vecāks
revīzija
f6c08508dc
4 mainītis faili ar 85 papildinājumiem un 26 dzēšanām
  1. 28
    21
      state/shape-utils/ellipse.tsx
  2. 1
    0
      state/shape-utils/rectangle.tsx
  3. 4
    5
      state/state.ts
  4. 52
    0
      utils/utils.ts

+ 28
- 21
state/shape-utils/ellipse.tsx Parādīt failu

1
-import { uniqueId } from 'utils/utils'
1
+import { uniqueId, getPerfectEllipseDashProps } from 'utils/utils'
2
 import vec from 'utils/vec'
2
 import vec from 'utils/vec'
3
 import { DashStyle, EllipseShape, ShapeType } from 'types'
3
 import { DashStyle, EllipseShape, ShapeType } from 'types'
4
 import { getShapeUtils } from './index'
4
 import { getShapeUtils } from './index'
6
 import { intersectEllipseBounds } from 'utils/intersections'
6
 import { intersectEllipseBounds } from 'utils/intersections'
7
 import { pointInEllipse } from 'utils/hitTests'
7
 import { pointInEllipse } from 'utils/hitTests'
8
 import { ease, getSvgPathFromStroke, rng, translateBounds } from 'utils/utils'
8
 import { ease, getSvgPathFromStroke, rng, translateBounds } from 'utils/utils'
9
-import {
10
-  defaultStyle,
11
-  getShapeStyle,
12
-  getStrokeDashArray,
13
-} from 'state/shape-styles'
9
+import { defaultStyle, getShapeStyle } from 'state/shape-styles'
14
 import getStroke from 'perfect-freehand'
10
 import getStroke from 'perfect-freehand'
15
 import { registerShapeUtils } from './register'
11
 import { registerShapeUtils } from './register'
16
 
12
 
43
   render(shape) {
39
   render(shape) {
44
     const { id, radiusX, radiusY, style } = shape
40
     const { id, radiusX, radiusY, style } = shape
45
     const styles = getShapeStyle(style)
41
     const styles = getShapeStyle(style)
42
+    const strokeWidth = +styles.strokeWidth
46
 
43
 
47
     if (style.dash === DashStyle.Solid) {
44
     if (style.dash === DashStyle.Solid) {
48
       if (!pathCache.has(shape)) {
45
       if (!pathCache.has(shape)) {
57
             id={id}
54
             id={id}
58
             cx={radiusX}
55
             cx={radiusX}
59
             cy={radiusY}
56
             cy={radiusY}
60
-            rx={Math.max(0, radiusX - +styles.strokeWidth / 2)}
61
-            ry={Math.max(0, radiusY - +styles.strokeWidth / 2)}
57
+            rx={Math.max(0, radiusX - strokeWidth / 2)}
58
+            ry={Math.max(0, radiusY - strokeWidth / 2)}
62
             stroke="none"
59
             stroke="none"
63
           />
60
           />
64
           <path d={path} fill={styles.stroke} />
61
           <path d={path} fill={styles.stroke} />
66
       )
63
       )
67
     }
64
     }
68
 
65
 
66
+    const rx = Math.max(0, radiusX - strokeWidth / 2)
67
+    const ry = Math.max(0, radiusY - strokeWidth / 2)
68
+
69
+    const { strokeDasharray, strokeDashoffset } = getPerfectEllipseDashProps(
70
+      rx,
71
+      ry,
72
+      strokeWidth,
73
+      shape.style.dash === DashStyle.Dotted ? 'dotted' : 'dashed'
74
+    )
75
+
69
     return (
76
     return (
70
-      <ellipse
71
-        id={id}
72
-        cx={radiusX}
73
-        cy={radiusY}
74
-        rx={Math.max(0, radiusX - +styles.strokeWidth / 2)}
75
-        ry={Math.max(0, radiusY - +styles.strokeWidth / 2)}
76
-        fill={styles.fill}
77
-        stroke={styles.stroke}
78
-        strokeDasharray={getStrokeDashArray(
79
-          style.dash,
80
-          +styles.strokeWidth
81
-        ).join(' ')}
82
-      />
77
+      <g id={id}>
78
+        <ellipse
79
+          id={id}
80
+          cx={radiusX}
81
+          cy={radiusY}
82
+          rx={rx}
83
+          ry={ry}
84
+          fill={styles.fill}
85
+          stroke={styles.stroke}
86
+          strokeDasharray={strokeDasharray}
87
+          strokeDashoffset={strokeDashoffset}
88
+        />
89
+      </g>
83
     )
90
     )
84
   },
91
   },
85
 
92
 

+ 1
- 0
state/shape-utils/rectangle.tsx Parādīt failu

82
           style.dash,
82
           style.dash,
83
           +styles.strokeWidth
83
           +styles.strokeWidth
84
         ).join(' ')}
84
         ).join(' ')}
85
+        strokeDashoffset={-(size[0] + size[1])}
85
       />
86
       />
86
     )
87
     )
87
   },
88
   },

+ 4
- 5
state/state.ts Parādīt failu

929
       return data.hoveredId === payload.target
929
       return data.hoveredId === payload.target
930
     },
930
     },
931
     pointInSelectionBounds(data, payload: PointerInfo) {
931
     pointInSelectionBounds(data, payload: PointerInfo) {
932
-      if (getSelectedIds(data).size === 0) return false
932
+      const bounds = getSelectionBounds(data)
933
 
933
 
934
-      return pointInBounds(
935
-        screenToWorld(payload.point, data),
936
-        getSelectionBounds(data)
937
-      )
934
+      if (!bounds) return false
935
+
936
+      return pointInBounds(screenToWorld(payload.point, data), bounds)
938
     },
937
     },
939
     pointHitsShape(data, payload: PointerInfo) {
938
     pointHitsShape(data, payload: PointerInfo) {
940
       const shape = getShape(data, payload.target)
939
       const shape = getShape(data, payload.target)

+ 52
- 0
utils/utils.ts Parādīt failu

1791
 
1791
 
1792
   updateParents(data, parentToUpdateIds)
1792
   updateParents(data, parentToUpdateIds)
1793
 }
1793
 }
1794
+
1795
+export function perimeterOfEllipse(rx: number, ry: number): number {
1796
+  const h = Math.pow(rx - ry, 2) / Math.pow(rx + ry, 2)
1797
+  const p = Math.PI * (rx + ry) * (1 + (3 * h) / (10 + Math.sqrt(4 - 3 * h)))
1798
+  return p
1799
+}
1800
+
1801
+/**
1802
+ * Get the stroke-dasharray and stroke-dashoffset properties for a dashed or dotted ellipse.
1803
+ * @param rx The radius of the ellipse on the x axis.
1804
+ * @param ry The radius of the ellipse on the y axis.
1805
+ * @param strokeWidth The shape's stroke-width property.
1806
+ * @param style "dashed" or "dotted" (default "dashed")
1807
+ */
1808
+export function getPerfectEllipseDashProps(
1809
+  rx: number,
1810
+  ry: number,
1811
+  strokeWidth: number,
1812
+  style: 'dashed' | 'dotted' = 'dashed'
1813
+) {
1814
+  let dashLength: number
1815
+  let strokeDashoffset: number
1816
+  let ratio: number
1817
+
1818
+  if (style === 'dashed') {
1819
+    dashLength = strokeWidth * 2
1820
+    ratio = 1
1821
+    strokeDashoffset = dashLength / 2
1822
+  } else {
1823
+    dashLength = strokeWidth / 4
1824
+    ratio = 4
1825
+    strokeDashoffset = 0
1826
+  }
1827
+
1828
+  // Find perimeter of the ellipse
1829
+  const h = Math.pow(rx - ry, 2) / Math.pow(rx + ry, 2)
1830
+  const perimeter =
1831
+    Math.PI * (rx + ry) * (1 + (3 * h) / (10 + Math.sqrt(4 - 3 * h)))
1832
+
1833
+  // Find the number of dashes (with one more for good measure)
1834
+  let dashes = perimeter / dashLength / (2 * ratio)
1835
+  dashes = dashes - (dashes % 4)
1836
+  // dashes++
1837
+
1838
+  // Find the gap length
1839
+  const gapLength = (perimeter - dashes * dashLength) / dashes
1840
+
1841
+  return {
1842
+    strokeDasharray: [dashLength, gapLength].join(' '),
1843
+    strokeDashoffset,
1844
+  }
1845
+}

Notiek ielāde…
Atcelt
Saglabāt