瀏覽代碼

Improves transforms

main
Steve Ruiz 4 年之前
父節點
當前提交
f57507a882
共有 4 個檔案被更改,包括 154 行新增26 行删除
  1. 3
    2
      state/sessions/transform-session.ts
  2. 3
    2
      state/sessions/transform-single-session.ts
  3. 18
    2
      state/state.ts
  4. 130
    20
      utils/utils.ts

+ 3
- 2
state/sessions/transform-session.ts 查看文件

28
     this.snapshot = getTransformSnapshot(data, transformType)
28
     this.snapshot = getTransformSnapshot(data, transformType)
29
   }
29
   }
30
 
30
 
31
-  update(data: Data, point: number[]) {
31
+  update(data: Data, point: number[], isAspectRatioLocked = false) {
32
     const { transformType } = this
32
     const { transformType } = this
33
 
33
 
34
     const { currentPageId, selectedIds, shapeBounds, initialBounds } =
34
     const { currentPageId, selectedIds, shapeBounds, initialBounds } =
38
       initialBounds,
38
       initialBounds,
39
       transformType,
39
       transformType,
40
       vec.vec(this.origin, point),
40
       vec.vec(this.origin, point),
41
-      data.boundsRotation
41
+      data.boundsRotation,
42
+      isAspectRatioLocked
42
     )
43
     )
43
 
44
 
44
     this.scaleX = newBoundingBox.scaleX
45
     this.scaleX = newBoundingBox.scaleX

+ 3
- 2
state/sessions/transform-single-session.ts 查看文件

32
     this.isCreating = isCreating
32
     this.isCreating = isCreating
33
   }
33
   }
34
 
34
 
35
-  update(data: Data, point: number[]) {
35
+  update(data: Data, point: number[], isAspectRatioLocked = false) {
36
     const { transformType } = this
36
     const { transformType } = this
37
 
37
 
38
     const { initialShapeBounds, currentPageId, initialShape, id } =
38
     const { initialShapeBounds, currentPageId, initialShape, id } =
44
       initialShapeBounds,
44
       initialShapeBounds,
45
       transformType,
45
       transformType,
46
       vec.vec(this.origin, point),
46
       vec.vec(this.origin, point),
47
-      shape.rotation
47
+      shape.rotation,
48
+      isAspectRatioLocked
48
     )
49
     )
49
 
50
 
50
     this.scaleX = newBoundingBox.scaleX
51
     this.scaleX = newBoundingBox.scaleX

+ 18
- 2
state/state.ts 查看文件

168
               on: {
168
               on: {
169
                 MOVED_POINTER: "updateTransformSession",
169
                 MOVED_POINTER: "updateTransformSession",
170
                 PANNED_CAMERA: "updateTransformSession",
170
                 PANNED_CAMERA: "updateTransformSession",
171
+                PRESSED_SHIFT_KEY: "keyUpdateTransformSession",
172
+                RELEASED_SHIFT_KEY: "keyUpdateTransformSession",
171
                 STOPPED_POINTING: { do: "completeSession", to: "selecting" },
173
                 STOPPED_POINTING: { do: "completeSession", to: "selecting" },
172
                 CANCELLED: { do: "cancelSession", to: "selecting" },
174
                 CANCELLED: { do: "cancelSession", to: "selecting" },
173
               },
175
               },
569
           ? new Sessions.TransformSingleSession(
571
           ? new Sessions.TransformSingleSession(
570
               data,
572
               data,
571
               payload.target,
573
               payload.target,
572
-              screenToWorld(payload.point, data)
574
+              screenToWorld(payload.point, data),
575
+              false
573
             )
576
             )
574
           : new Sessions.TransformSession(
577
           : new Sessions.TransformSession(
575
               data,
578
               data,
585
         true
588
         true
586
       )
589
       )
587
     },
590
     },
591
+    keyUpdateTransformSession(data, payload: PointerInfo) {
592
+      session.update(
593
+        data,
594
+        screenToWorld(inputs.pointer.point, data),
595
+        payload.shiftKey,
596
+        payload.altKey
597
+      )
598
+    },
588
     updateTransformSession(data, payload: PointerInfo) {
599
     updateTransformSession(data, payload: PointerInfo) {
589
-      session.update(data, screenToWorld(payload.point, data))
600
+      session.update(
601
+        data,
602
+        screenToWorld(payload.point, data),
603
+        payload.shiftKey,
604
+        payload.altKey
605
+      )
590
     },
606
     },
591
 
607
 
592
     // Direction
608
     // Direction

+ 130
- 20
utils/utils.ts 查看文件

1043
 
1043
 
1044
 export function getTransformedBoundingBox(
1044
 export function getTransformedBoundingBox(
1045
   bounds: Bounds,
1045
   bounds: Bounds,
1046
-  handle: TransformCorner | TransformEdge,
1046
+  handle: TransformCorner | TransformEdge | "center",
1047
   delta: number[],
1047
   delta: number[],
1048
-  rotation = 0
1048
+  rotation = 0,
1049
+  isAspectRatioLocked = false
1049
 ) {
1050
 ) {
1050
   // Create top left and bottom right corners.
1051
   // Create top left and bottom right corners.
1051
   let [ax0, ay0] = [bounds.minX, bounds.minY]
1052
   let [ax0, ay0] = [bounds.minX, bounds.minY]
1052
   let [ax1, ay1] = [bounds.maxX, bounds.maxY]
1053
   let [ax1, ay1] = [bounds.maxX, bounds.maxY]
1053
 
1054
 
1054
-  // Create a second set of corners for the result.
1055
+  // Create a second set of corners for the new box.
1055
   let [bx0, by0] = [bounds.minX, bounds.minY]
1056
   let [bx0, by0] = [bounds.minX, bounds.minY]
1056
   let [bx1, by1] = [bounds.maxX, bounds.maxY]
1057
   let [bx1, by1] = [bounds.maxX, bounds.maxY]
1057
 
1058
 
1059
+  // If the drag is on the center, just translate the bounds.
1060
+  if (handle === "center") {
1061
+    return {
1062
+      minX: bx0 + delta[0],
1063
+      minY: by0 + delta[1],
1064
+      maxX: bx1 + delta[0],
1065
+      maxY: by1 + delta[1],
1066
+      width: bx1 - bx0,
1067
+      height: by1 - by0,
1068
+      scaleX: 1,
1069
+      scaleY: 1,
1070
+    }
1071
+  }
1072
+
1058
   // Counter rotate the delta. This lets us make changes as if
1073
   // Counter rotate the delta. This lets us make changes as if
1059
   // the (possibly rotated) boxes were axis aligned.
1074
   // the (possibly rotated) boxes were axis aligned.
1060
-  const [dx, dy] = vec.rot(delta, -rotation)
1075
+  let [dx, dy] = vec.rot(delta, -rotation)
1061
 
1076
 
1062
-  // Depending on the dragging handle (an edge or corner of
1063
-  // the bounding box), use the delta to adjust the result's corners.
1077
+  /*
1078
+  1. Delta
1064
 
1079
 
1080
+  Use the delta to adjust the new box by changing its corners.
1081
+  The dragging handle (corner or edge) will determine which 
1082
+  corners should change.
1083
+  */
1065
   switch (handle) {
1084
   switch (handle) {
1066
     case TransformEdge.Top:
1085
     case TransformEdge.Top:
1067
     case TransformCorner.TopLeft:
1086
     case TransformCorner.TopLeft:
1092
     }
1111
     }
1093
   }
1112
   }
1094
 
1113
 
1095
-  // If the bounds are rotated, get a vector from the rotated anchor
1096
-  // corner in the inital bounds to the rotated anchor corner in the
1097
-  // result's bounds. Subtract this vector from the result's corners,
1098
-  // so that the two anchor points (initial and result) will be equal.
1114
+  const aw = ax1 - ax0
1115
+  const ah = ay1 - ay0
1116
+
1117
+  const scaleX = (bx1 - bx0) / aw
1118
+  const scaleY = (by1 - by0) / ah
1119
+
1120
+  const bw = Math.abs(bx1 - bx0)
1121
+  const bh = Math.abs(by1 - by0)
1122
+
1123
+  /*
1124
+  2. Aspect ratio
1125
+
1126
+  If the aspect ratio is locked, adjust the corners so that the
1127
+  new box's aspect ratio matches the original aspect ratio.
1128
+  */
1129
+
1130
+  if (isAspectRatioLocked) {
1131
+    const ar = aw / ah
1132
+    const isTall = ar < bw / bh
1133
+    const tw = bw * (scaleY < 0 ? 1 : -1) * (1 / ar)
1134
+    const th = bh * (scaleX < 0 ? 1 : -1) * ar
1135
+
1136
+    switch (handle) {
1137
+      case TransformCorner.TopLeft: {
1138
+        if (isTall) by0 = by1 + tw
1139
+        else bx0 = bx1 + th
1140
+        break
1141
+      }
1142
+      case TransformCorner.TopRight: {
1143
+        if (isTall) by0 = by1 + tw
1144
+        else bx1 = bx0 - th
1145
+        break
1146
+      }
1147
+      case TransformCorner.BottomRight: {
1148
+        if (isTall) by1 = by0 - tw
1149
+        else bx1 = bx0 - th
1150
+        break
1151
+      }
1152
+      case TransformCorner.BottomLeft: {
1153
+        if (isTall) by1 = by0 - tw
1154
+        else bx0 = bx1 + th
1155
+        break
1156
+      }
1157
+      case TransformEdge.Bottom:
1158
+      case TransformEdge.Top: {
1159
+        const m = (bx0 + bx1) / 2
1160
+        const w = bh * ar
1161
+        bx0 = m - w / 2
1162
+        bx1 = m + w / 2
1163
+        break
1164
+      }
1165
+      case TransformEdge.Left:
1166
+      case TransformEdge.Right: {
1167
+        const m = (by0 + by1) / 2
1168
+        const h = bw / ar
1169
+        by0 = m - h / 2
1170
+        by1 = m + h / 2
1171
+        break
1172
+      }
1173
+    }
1174
+  }
1175
+
1176
+  /*
1177
+  3. Rotation
1178
+
1179
+  If the bounds are rotated, get a vector from the rotated anchor
1180
+  corner in the inital bounds to the rotated anchor corner in the
1181
+  result's bounds. Subtract this vector from the result's corners,
1182
+  so that the two anchor points (initial and result) will be equal.
1183
+  */
1099
 
1184
 
1100
   if (rotation % (Math.PI * 2) !== 0) {
1185
   if (rotation % (Math.PI * 2) !== 0) {
1101
     let cv = [0, 0]
1186
     let cv = [0, 0]
1104
     const c1 = vec.med([bx0, by0], [bx1, by1])
1189
     const c1 = vec.med([bx0, by0], [bx1, by1])
1105
 
1190
 
1106
     switch (handle) {
1191
     switch (handle) {
1107
-      case TransformCorner.TopLeft:
1108
-      case TransformEdge.Top:
1109
-      case TransformEdge.Left: {
1192
+      case TransformCorner.TopLeft: {
1110
         cv = vec.sub(
1193
         cv = vec.sub(
1111
           vec.rotWith([bx1, by1], c1, rotation),
1194
           vec.rotWith([bx1, by1], c1, rotation),
1112
           vec.rotWith([ax1, ay1], c0, rotation)
1195
           vec.rotWith([ax1, ay1], c0, rotation)
1120
         )
1203
         )
1121
         break
1204
         break
1122
       }
1205
       }
1123
-      case TransformCorner.BottomRight:
1124
-      case TransformEdge.Bottom:
1125
-      case TransformEdge.Right: {
1206
+      case TransformCorner.BottomRight: {
1126
         cv = vec.sub(
1207
         cv = vec.sub(
1127
           vec.rotWith([bx0, by0], c1, rotation),
1208
           vec.rotWith([bx0, by0], c1, rotation),
1128
           vec.rotWith([ax0, ay0], c0, rotation)
1209
           vec.rotWith([ax0, ay0], c0, rotation)
1136
         )
1217
         )
1137
         break
1218
         break
1138
       }
1219
       }
1220
+      case TransformEdge.Top: {
1221
+        cv = vec.sub(
1222
+          vec.rotWith(vec.med([bx0, by1], [bx1, by1]), c1, rotation),
1223
+          vec.rotWith(vec.med([ax0, ay1], [ax1, ay1]), c0, rotation)
1224
+        )
1225
+        break
1226
+      }
1227
+      case TransformEdge.Left: {
1228
+        cv = vec.sub(
1229
+          vec.rotWith(vec.med([bx1, by0], [bx1, by1]), c1, rotation),
1230
+          vec.rotWith(vec.med([ax1, ay0], [ax1, ay1]), c0, rotation)
1231
+        )
1232
+        break
1233
+      }
1234
+      case TransformEdge.Bottom: {
1235
+        cv = vec.sub(
1236
+          vec.rotWith(vec.med([bx0, by0], [bx1, by0]), c1, rotation),
1237
+          vec.rotWith(vec.med([ax0, ay0], [ax1, ay0]), c0, rotation)
1238
+        )
1239
+        break
1240
+      }
1241
+      case TransformEdge.Right: {
1242
+        cv = vec.sub(
1243
+          vec.rotWith(vec.med([bx0, by0], [bx0, by1]), c1, rotation),
1244
+          vec.rotWith(vec.med([ax0, ay0], [ax0, ay1]), c0, rotation)
1245
+        )
1246
+        break
1247
+      }
1139
     }
1248
     }
1140
 
1249
 
1141
     ;[bx0, by0] = vec.sub([bx0, by0], cv)
1250
     ;[bx0, by0] = vec.sub([bx0, by0], cv)
1142
     ;[bx1, by1] = vec.sub([bx1, by1], cv)
1251
     ;[bx1, by1] = vec.sub([bx1, by1], cv)
1143
   }
1252
   }
1144
 
1253
 
1145
-  // If the axes are flipped (e.g. if the right edge has been dragged
1146
-  // left past the initial left edge) then swap points on that axis.
1254
+  /*
1255
+  4. Flips
1147
 
1256
 
1148
-  let scaleX = (bx1 - bx0) / (ax1 - ax0)
1149
-  let scaleY = (by1 - by0) / (ay1 - ay0)
1257
+  If the axes are flipped (e.g. if the right edge has been dragged
1258
+  left past the initial left edge) then swap points on that axis.
1259
+  */
1150
 
1260
 
1151
   if (bx1 < bx0) {
1261
   if (bx1 < bx0) {
1152
     ;[bx1, bx0] = [bx0, bx1]
1262
     ;[bx1, bx0] = [bx0, bx1]

Loading…
取消
儲存