ソースを参照

improves appearance on safari

main
Steve Ruiz 4年前
コミット
708223fffa

+ 1
- 1
components/canvas/bounds/bounding-box.tsx ファイルの表示

@@ -20,7 +20,7 @@ export default function Bounds() {
20 20
   if (!bounds) return null
21 21
   if (!isSelecting) return null
22 22
 
23
-  const size = (isMobile().any ? 16 : 8) / zoom // Touch target size
23
+  const size = (isMobile().any ? 12 : 8) / zoom // Touch target size
24 24
 
25 25
   return (
26 26
     <g

+ 25
- 0
components/canvas/defs.tsx ファイルの表示

@@ -0,0 +1,25 @@
1
+import { getShapeUtils } from "lib/shape-utils"
2
+import { useSelector } from "state"
3
+import { deepCompareArrays, getPage } from "utils/utils"
4
+
5
+export default function Defs() {
6
+  const currentPageShapeIds = useSelector(({ data }) => {
7
+    return Object.values(getPage(data).shapes)
8
+      .sort((a, b) => a.childIndex - b.childIndex)
9
+      .map((shape) => shape.id)
10
+  }, deepCompareArrays)
11
+
12
+  return (
13
+    <defs>
14
+      {currentPageShapeIds.map((id) => (
15
+        <Def key={id} id={id} />
16
+      ))}
17
+    </defs>
18
+  )
19
+}
20
+
21
+export function Def({ id }: { id: string }) {
22
+  const shape = useSelector(({ data }) => getPage(data).shapes[id])
23
+
24
+  return getShapeUtils(shape).render(shape)
25
+}

+ 5
- 5
components/canvas/shape.tsx ファイルの表示

@@ -6,14 +6,14 @@ import { getShapeUtils } from "lib/shape-utils"
6 6
 import { getPage } from "utils/utils"
7 7
 
8 8
 function Shape({ id }: { id: string }) {
9
-  const rGroup = useRef<SVGGElement>(null)
10
-
11 9
   const isHovered = useSelector((state) => state.data.hoveredId === id)
12 10
 
13 11
   const isSelected = useSelector((state) => state.values.selectedIds.has(id))
14 12
 
15 13
   const shape = useSelector(({ data }) => getPage(data).shapes[id])
16 14
 
15
+  const rGroup = useRef<SVGGElement>(null)
16
+
17 17
   const handlePointerDown = useCallback(
18 18
     (e: React.PointerEvent) => {
19 19
       e.stopPropagation()
@@ -72,9 +72,9 @@ function Shape({ id }: { id: string }) {
72 72
       onPointerMove={handlePointerMove}
73 73
     >
74 74
       <defs>{getShapeUtils(shape).render(shape)}</defs>
75
-      <HoverIndicator as="use" xlinkHref={"#" + id} />
76
-      <MainShape as="use" xlinkHref={"#" + id} {...shape.style} />
77
-      <Indicator as="use" xlinkHref={"#" + id} />
75
+      <HoverIndicator as="use" href={"#" + id} />
76
+      <MainShape as="use" href={"#" + id} {...shape.style} />
77
+      <Indicator as="use" href={"#" + id} />
78 78
     </StyledGroup>
79 79
   )
80 80
 }

+ 33
- 1
hooks/useZoomEvents.ts ファイルの表示

@@ -2,6 +2,7 @@ import React, { useEffect, useRef } from "react"
2 2
 import state from "state"
3 3
 import inputs from "state/inputs"
4 4
 import * as vec from "utils/vec"
5
+import { usePinch } from "react-use-gesture"
5 6
 
6 7
 /**
7 8
  * Capture zoom gestures (pinches, wheels and pans) and send to the state.
@@ -65,5 +66,36 @@ export default function useZoomEvents(
65 66
     }
66 67
   }, [ref])
67 68
 
68
-  return {}
69
+  const rPinchDa = useRef<number[] | undefined>(undefined)
70
+  const rPinchAngle = useRef<number>(undefined)
71
+  const rPinchPoint = useRef<number[] | undefined>(undefined)
72
+
73
+  const bind = usePinch(({ pinching, da, origin }) => {
74
+    if (!pinching) {
75
+      state.send("STOPPED_PINCHING")
76
+      rPinchDa.current = undefined
77
+      rPinchPoint.current = undefined
78
+      return
79
+    }
80
+
81
+    if (rPinchPoint.current === undefined) {
82
+      state.send("STARTED_PINCHING")
83
+      rPinchDa.current = da
84
+      rPinchPoint.current = origin
85
+    }
86
+
87
+    const [distanceDelta, angleDelta] = vec.sub(rPinchDa.current, da)
88
+
89
+    state.send("PINCHED", {
90
+      delta: vec.sub(rPinchPoint.current, origin),
91
+      point: origin,
92
+      distanceDelta,
93
+      angleDelta,
94
+    })
95
+
96
+    rPinchDa.current = da
97
+    rPinchPoint.current = origin
98
+  })
99
+
100
+  return { ...bind() }
69 101
 }

+ 1
- 0
package.json ファイルの表示

@@ -21,6 +21,7 @@
21 21
     "react": "17.0.2",
22 22
     "react-dom": "17.0.2",
23 23
     "react-feather": "^2.0.9",
24
+    "react-use-gesture": "^9.1.3",
24 25
     "uuid": "^8.3.2"
25 26
   },
26 27
   "devDependencies": {

+ 31
- 5
state/state.ts ファイルの表示

@@ -130,6 +130,7 @@ const state = createState({
130 130
             STRETCHED: "stretchSelection",
131 131
             DISTRIBUTED: "distributeSelection",
132 132
             MOVED: "moveSelection",
133
+            STARTED_PINCHING: { to: "pinching" },
133 134
           },
134 135
           initial: "notPointing",
135 136
           states: {
@@ -248,6 +249,12 @@ const state = createState({
248 249
             },
249 250
           },
250 251
         },
252
+        pinching: {
253
+          on: {
254
+            STOPPED_PINCHING: { to: "selecting" },
255
+            PINCHED: { do: "pinchCamera" },
256
+          },
257
+        },
251 258
         draw: {
252 259
           initial: "creating",
253 260
           states: {
@@ -829,12 +836,31 @@ const state = createState({
829 836
 
830 837
       setZoomCSS(camera.zoom)
831 838
     },
832
-    panCamera(data, payload: { delta: number[]; point: number[] }) {
839
+    panCamera(data, payload: { delta: number[] }) {
833 840
       const { camera } = data
834
-      data.camera.point = vec.sub(
835
-        camera.point,
836
-        vec.div(payload.delta, camera.zoom)
837
-      )
841
+      camera.point = vec.sub(camera.point, vec.div(payload.delta, camera.zoom))
842
+    },
843
+    pinchCamera(
844
+      data,
845
+      payload: {
846
+        delta: number[]
847
+        distanceDelta: number
848
+        angleDelta: number
849
+        point: number[]
850
+      }
851
+    ) {
852
+      const { camera } = data
853
+
854
+      camera.point = vec.sub(camera.point, vec.div(payload.delta, camera.zoom))
855
+
856
+      const next = camera.zoom - (payload.distanceDelta / 300) * camera.zoom
857
+
858
+      const p0 = screenToWorld(payload.point, data)
859
+      camera.zoom = clamp(next, 0.1, 3)
860
+      const p1 = screenToWorld(payload.point, data)
861
+      camera.point = vec.add(camera.point, vec.sub(p1, p0))
862
+
863
+      setZoomCSS(camera.zoom)
838 864
     },
839 865
     deleteSelectedIds(data) {
840 866
       commands.deleteSelected(data)

+ 2
- 2
styles/stitches.config.ts ファイルの表示

@@ -45,7 +45,7 @@ const { styled, global, css, theme, getCssString } = createCss({
45 45
     zStrokeWidth: () => (value: number | number[]) => {
46 46
       if (Array.isArray(value)) {
47 47
         return {
48
-          strokeWidth: `calc(${value[0]} / var(--camera-zoom))`,
48
+          strokeWidth: `calc(${value[0]}px / var(--camera-zoom))`,
49 49
         }
50 50
       }
51 51
 
@@ -61,7 +61,7 @@ const { styled, global, css, theme, getCssString } = createCss({
61 61
       // }
62 62
 
63 63
       return {
64
-        strokeWidth: `calc(${value} / var(--camera-zoom))`,
64
+        strokeWidth: `calc(${value}px / var(--camera-zoom))`,
65 65
       }
66 66
     },
67 67
   },

+ 5
- 0
yarn.lock ファイルの表示

@@ -6697,6 +6697,11 @@ react-style-singleton@^2.1.0:
6697 6697
     invariant "^2.2.4"
6698 6698
     tslib "^1.0.0"
6699 6699
 
6700
+react-use-gesture@^9.1.3:
6701
+  version "9.1.3"
6702
+  resolved "https://registry.yarnpkg.com/react-use-gesture/-/react-use-gesture-9.1.3.tgz#92bd143e4f58e69bd424514a5bfccba2a1d62ec0"
6703
+  integrity sha512-CdqA2SmS/fj3kkS2W8ZU8wjTbVBAIwDWaRprX7OKaj7HlGwBasGEFggmk5qNklknqk9zK/h8D355bEJFTpqEMg==
6704
+
6700 6705
 react@17.0.2:
6701 6706
   version "17.0.2"
6702 6707
   resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"

読み込み中…
キャンセル
保存