Browse Source

improves indicators (roll into arrow shape)

main
Steve Ruiz 4 years ago
parent
commit
ffc180fa1c
2 changed files with 65 additions and 33 deletions
  1. 1
    1
      packages/core/src/utils/svg.ts
  2. 64
    32
      packages/tldraw/src/shape/shapes/arrow/arrow.tsx

+ 1
- 1
packages/core/src/utils/svg.ts View File

@@ -40,8 +40,8 @@ export class Svg {
40 40
       r,
41 41
       r,
42 42
       0,
43
-      Utils.getSweep(C, A, B) > 0 ? '1' : '0',
44 43
       0,
44
+      Utils.getArcLength(C, r, A, B) > 0 ? '1' : '0',
45 45
       B[0],
46 46
       B[1],
47 47
     ].join(' ')

+ 64
- 32
packages/tldraw/src/shape/shapes/arrow/arrow.tsx View File

@@ -8,6 +8,7 @@ import {
8 8
   Intersect,
9 9
   TLHandle,
10 10
   TLPointerInfo,
11
+  Svg,
11 12
 } from '@tldraw/core'
12 13
 import getStroke from 'perfect-freehand'
13 14
 import { defaultStyle, getPerfectDashProps, getShapeStyle } from '~shape/shape-styles'
@@ -235,57 +236,88 @@ export class Arrow extends TLDrawShapeUtil<ArrowShape> {
235 236
 
236 237
   renderIndicator(shape: ArrowShape) {
237 238
     const {
238
-      handles: { start, end },
239
-      bend,
239
+      decorations,
240
+      handles: { start, end, bend: _bend },
240 241
       style,
241 242
     } = shape
242 243
 
243
-    const path = Utils.getFromCache(this.simplePathCache, shape, () =>
244
-      getArrowArcPath(start, end, getCtp(shape), bend)
245
-    )
246
-    const styles = getShapeStyle(style, false)
247
-
248
-    const { strokeWidth } = styles
244
+    const { strokeWidth } = getShapeStyle(style, false)
249 245
 
250 246
     const arrowDist = Vec.dist(start.point, end.point)
251 247
 
252 248
     const arrowHeadlength = Math.min(arrowDist / 3, strokeWidth * 8)
253 249
 
254
-    let insetStart: number[]
255
-    let insetEnd: number[]
250
+    const aw = arrowHeadlength / 2
256 251
 
257
-    if (bend === 0) {
258
-      insetStart = Vec.nudge(start.point, end.point, arrowHeadlength)
259
-      insetEnd = Vec.nudge(end.point, start.point, arrowHeadlength)
252
+    const path: (string | number)[] = []
253
+
254
+    const isStraightLine = Vec.dist(_bend.point, Vec.round(Vec.med(start.point, end.point))) < 1
255
+
256
+    if (isStraightLine) {
257
+      path.push(Svg.moveTo(start.point), Svg.lineTo(end.point))
258
+
259
+      if (decorations?.start) {
260
+        const point = start.point
261
+        const ints = Intersect.circle.lineSegment(start.point, aw, start.point, end.point).points
262
+        const int = ints[0]
263
+
264
+        path.push(
265
+          Svg.moveTo(Vec.nudge(Vec.rotWith(int, point, Math.PI / 6), point, -aw)),
266
+          Svg.lineTo(start.point),
267
+          Svg.lineTo(Vec.nudge(Vec.rotWith(int, point, -Math.PI / 6), point, -aw))
268
+        )
269
+      }
270
+
271
+      if (decorations?.end) {
272
+        const point = end.point
273
+        const ints = Intersect.circle.lineSegment(end.point, aw, start.point, end.point).points
274
+        const int = ints[0]
275
+
276
+        path.push(
277
+          Svg.moveTo(Vec.nudge(Vec.rotWith(int, point, Math.PI / 6), point, -aw)),
278
+          Svg.lineTo(end.point),
279
+          Svg.lineTo(Vec.nudge(Vec.rotWith(int, point, -Math.PI / 6), point, -aw))
280
+        )
281
+      }
260 282
     } else {
261 283
       const circle = getCtp(shape)
284
+      const center = [circle[0], circle[1]]
285
+      const radius = circle[2]
286
+      const sweep = Utils.getArcLength(center, radius, start.point, end.point) > 0
262 287
 
263
-      const arcLength = Utils.getArcLength(
264
-        [circle[0], circle[1]],
265
-        circle[2],
266
-        start.point,
267
-        end.point
288
+      path.push(
289
+        Svg.moveTo(start.point),
290
+        `A ${radius} ${radius} 0 0 ${sweep ? '1' : '0'} ${end.point}`
268 291
       )
269 292
 
270
-      const center = [circle[0], circle[1]]
271
-      const radius = circle[2]
272
-      const sa = Vec.angle(center, start.point)
273
-      const ea = Vec.angle(center, end.point)
274
-      const t = arrowHeadlength / Math.abs(arcLength)
293
+      if (decorations?.start) {
294
+        const point = start.point
295
+        const ints = Intersect.circle.circle(center, radius, point, aw).points
296
+        const int = sweep ? ints[0] : ints[1]
275 297
 
276
-      insetStart = Vec.nudgeAtAngle(center, Utils.lerpAngles(sa, ea, t), radius)
277
-      insetEnd = Vec.nudgeAtAngle(center, Utils.lerpAngles(ea, sa, t), radius)
298
+        path.push(
299
+          Svg.moveTo(Vec.nudge(Vec.rotWith(int, point, Math.PI / 6), point, -aw)),
300
+          Svg.lineTo(start.point),
301
+          Svg.lineTo(Vec.nudge(Vec.rotWith(int, point, -Math.PI / 6), point, -aw))
302
+        )
303
+      }
304
+
305
+      if (decorations?.end) {
306
+        const point = end.point
307
+        const ints = Intersect.circle.circle(center, radius, point, aw).points
308
+        const int = sweep ? ints[1] : ints[0]
309
+
310
+        path.push(
311
+          Svg.moveTo(Vec.nudge(Vec.rotWith(int, point, Math.PI / 6), point, -aw)),
312
+          Svg.lineTo(end.point),
313
+          Svg.lineTo(Vec.nudge(Vec.rotWith(int, point, -Math.PI / 6), point, -aw))
314
+        )
315
+      }
278 316
     }
279 317
 
280 318
     return (
281 319
       <g>
282
-        <path d={path} />
283
-        {shape.decorations?.start === Decoration.Arrow && (
284
-          <path d={getArrowHeadPath(shape, start.point, insetStart)} />
285
-        )}
286
-        {shape.decorations?.end === Decoration.Arrow && (
287
-          <path d={getArrowHeadPath(shape, end.point, insetEnd)} />
288
-        )}
320
+        <path d={path.join()} />
289 321
       </g>
290 322
     )
291 323
   }

Loading…
Cancel
Save