@webspatial/platform-visionos 1.0.5 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -39,7 +39,7 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
39
39
  var parent: (any ScrollAbleSpatialElementContainer)?
40
40
 
41
41
  // Enum
42
- public enum WindowStyle: String, Codable, CaseIterable {
42
+ enum WindowStyle: String, Codable, CaseIterable {
43
43
  case window
44
44
  case volume
45
45
  }
@@ -51,7 +51,7 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
51
51
  var setLoadingWindowData = PassthroughSubject<XLoadingViewData, Never>()
52
52
 
53
53
  var url: String = "" // start_url
54
- public var windowStyle: WindowStyle {
54
+ var windowStyle: WindowStyle {
55
55
  didSet {
56
56
  resetBackgroundMaterialOnWindowStyleChange(windowStyle)
57
57
  }
@@ -116,6 +116,35 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
116
116
  return true
117
117
  }
118
118
 
119
+ private func handleNavigationCheckCustom(_ url: URL) -> Bool {
120
+ /*
121
+ because full url is webspatial://createSpatialScene?url=xxx
122
+ we need to get the real url.
123
+ we do 2 things:
124
+
125
+ 1. let curUrl = parse url
126
+ 2. if url is in scope do webviewModel.load(curUrl)
127
+ else open in safari
128
+ */
129
+ guard let components = URLComponents(string: url.absoluteString),
130
+ let queryItems = components.queryItems
131
+ else {
132
+ print("❌ fail to parse URL")
133
+ return false
134
+ }
135
+ guard let encodedUrl = queryItems.first(where: { $0.name == "url" })?.value,
136
+ let decodedUrl = encodedUrl.removingPercentEncoding
137
+ else {
138
+ return false
139
+ }
140
+ if pwaManager.checkInScope(url: decodedUrl) {
141
+ spatialWebViewModel.load(decodedUrl)
142
+ return false
143
+ }
144
+ UIApplication.shared.open(URL(string: decodedUrl)!, options: [:], completionHandler: nil)
145
+ return false
146
+ }
147
+
119
148
  private func handleWindowOpenCustom(_ url: URL) -> WebViewElementInfo? {
120
149
  // get config from url
121
150
  guard let components = URLComponents(string: url.absoluteString),
@@ -132,6 +161,11 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
132
161
  return nil
133
162
  }
134
163
 
164
+ if !pwaManager.checkInScope(url: decodedUrl) {
165
+ UIApplication.shared.open(URL(string: decodedUrl)!, options: [:], completionHandler: nil)
166
+ return nil
167
+ }
168
+
135
169
  if let encodedConfig = queryItems.first(where: { $0.name == "config" })?.value,
136
170
  let decodedConfig = encodedConfig.removingPercentEncoding
137
171
  {
@@ -190,9 +224,9 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
190
224
  SpatialApp.Instance.closeWindowGroup(self)
191
225
  }
192
226
 
193
- public var sceneConfig: SceneOptions?
227
+ var sceneConfig: SceneOptions?
194
228
 
195
- public func moveToState(_ newState: SceneStateKind, _ sceneConfig: SceneOptions?) {
229
+ func moveToState(_ newState: SceneStateKind, _ sceneConfig: SceneOptions?) {
196
230
  print(" moveToState \(state) to \(newState) ")
197
231
 
198
232
  let oldState = state
@@ -214,7 +248,7 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
214
248
 
215
249
  } else if oldState == .idle, newState == .visible {
216
250
  // SpatialApp opened SpatialScene
217
- } else if oldState == .idle && newState == .willVisible {
251
+ } else if oldState == .idle, newState == .willVisible {
218
252
  // window.open with scene config
219
253
  SpatialApp.Instance.openWindowGroup(self, sceneConfig!)
220
254
  }
@@ -269,6 +303,8 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
269
303
 
270
304
  spatialWebViewModel
271
305
  .addNavigationListener(protocal: SpatialApp.Instance.scope, event: handleNavigationCheck)
306
+ spatialWebViewModel
307
+ .addNavigationListener(protocal: "webspatial://createSpatialScene", event: handleNavigationCheckCustom)
272
308
  }
273
309
 
274
310
  var width: Double = 0
@@ -292,7 +328,7 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
292
328
  ])
293
329
  }
294
330
 
295
- public var didFailLoad = false
331
+ var didFailLoad = false
296
332
 
297
333
  private func setupWebViewStateListener() {
298
334
  spatialWebViewModel.addStateListener(.didStartLoad) {
@@ -608,9 +644,7 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
608
644
  if let enableDragEndGesture = command.enableDragEndGesture {
609
645
  spatializedElement.enableDragEndGesture = enableDragEndGesture
610
646
  }
611
- if let enableRotateStartGesture = command.enableRotateStartGesture {
612
- spatializedElement.enableRotateStartGesture = enableRotateStartGesture
613
- }
647
+
614
648
  if let enableRotateGesture = command.enableRotateGesture {
615
649
  spatializedElement.enableRotateGesture = enableRotateGesture
616
650
  }
@@ -618,10 +652,6 @@ class SpatialScene: SpatialObject, ScrollAbleSpatialElementContainer, WebMsgSend
618
652
  spatializedElement.enableRotateEndGesture = enableRotateEndGesture
619
653
  }
620
654
 
621
- if let enableMagnifyStartGesture = command.enableMagnifyStartGesture {
622
- spatializedElement.enableMagnifyStartGesture = enableMagnifyStartGesture
623
- }
624
-
625
655
  if let enableMagnifyGesture = command.enableMagnifyGesture {
626
656
  spatializedElement.enableMagnifyGesture = enableMagnifyGesture
627
657
  }
@@ -53,6 +53,8 @@ class Spatialized2DElement: SpatializedElement, ScrollAbleSpatialElementContaine
53
53
  self._scrollOffset.y = point.y
54
54
  }
55
55
  spatialWebViewModel.scrollEnabled = false
56
+
57
+ defaultAlignment = .center
56
58
  }
57
59
 
58
60
  // Spatialized2DElement can hold a collection of SpatializedElement children
@@ -26,20 +26,20 @@ class SpatializedElement: SpatialObject {
26
26
  var enableDragStartGesture: Bool = false
27
27
  var enableDragGesture: Bool = false
28
28
  var enableDragEndGesture: Bool = false
29
- var enableRotateStartGesture: Bool = false
30
29
  var enableRotateGesture: Bool = false
31
30
  var enableRotateEndGesture: Bool = false
32
- var enableMagnifyStartGesture: Bool = false
33
31
  var enableMagnifyGesture: Bool = false
34
32
  var enableMagnifyEndGesture: Bool = false
35
33
  var enableTapGesture: Bool = false
36
34
 
35
+ var defaultAlignment: DepthAlignment = .back
36
+
37
37
  var enableGesture: Bool {
38
- return enableDragStartGesture || enableDragGesture || enableDragEndGesture || enableRotateStartGesture || enableRotateGesture || enableRotateEndGesture || enableMagnifyStartGesture || enableMagnifyGesture || enableMagnifyEndGesture || enableTapGesture
38
+ return enableDragStartGesture || enableDragGesture || enableDragEndGesture || enableRotateGesture || enableRotateEndGesture || enableMagnifyGesture || enableMagnifyEndGesture || enableTapGesture
39
39
  }
40
40
 
41
41
  enum CodingKeys: String, CodingKey {
42
- case clientX, clientY, width, height, depth, backOffset, transform, rotationAnchor, opacity, visible, scrollWithParent, zIndex, parent, enableGesture, enableTapGesture, enableDragGesture, enableDragEndGesture, enableRotateStartGesture, enableRotateGesture, enableRotateEndGesture, enableMagnifyStartGesture, enableMagnifyGesture, enableMagnifyEndGesture
42
+ case clientX, clientY, width, height, depth, backOffset, transform, rotationAnchor, opacity, visible, scrollWithParent, zIndex, parent, enableGesture, enableTapGesture, enableDragStartGesture, enableDragGesture, enableDragEndGesture, enableRotateGesture, enableRotateEndGesture, enableMagnifyGesture, enableMagnifyEndGesture
43
43
  }
44
44
 
45
45
  override func encode(to encoder: Encoder) throws {
@@ -60,12 +60,11 @@ class SpatializedElement: SpatialObject {
60
60
  try container.encode(parent?.id, forKey: .parent)
61
61
  try container.encode(enableGesture, forKey: .enableGesture)
62
62
  try container.encode(enableTapGesture, forKey: .enableTapGesture)
63
+ try container.encode(enableDragStartGesture, forKey: .enableDragStartGesture)
63
64
  try container.encode(enableDragGesture, forKey: .enableDragGesture)
64
65
  try container.encode(enableDragEndGesture, forKey: .enableDragEndGesture)
65
- try container.encode(enableRotateStartGesture, forKey: .enableRotateStartGesture)
66
66
  try container.encode(enableRotateGesture, forKey: .enableRotateGesture)
67
67
  try container.encode(enableRotateEndGesture, forKey: .enableRotateEndGesture)
68
- try container.encode(enableMagnifyStartGesture, forKey: .enableMagnifyStartGesture)
69
68
  try container.encode(enableMagnifyGesture, forKey: .enableMagnifyGesture)
70
69
  try container.encode(enableMagnifyEndGesture, forKey: .enableMagnifyEndGesture)
71
70
  }
@@ -1,118 +1,123 @@
1
- import SwiftUI
2
1
  import RealityKit
2
+ import SwiftUI
3
3
 
4
4
  @Observable
5
5
  class SpatialEntity: Entity, SpatialObjectProtocol {
6
6
  let spatialId: String
7
-
7
+
8
8
  private var _isDestroyed: Bool = false
9
9
  var isDestroyed: Bool {
10
10
  return _isDestroyed
11
11
  }
12
- internal var listeners: [String: [(_ object: Any, _ data: Any) -> Void]] = [:]
13
-
12
+
13
+ var listeners: [String: [(_ object: Any, _ data: Any) -> Void]] = [:]
14
+
14
15
  private var _enableTap: Bool = false
15
16
  private var _enableRotate: Bool = false
16
- private var _enableRotateStart: Bool = false
17
17
  private var _enableRotateEnd: Bool = false
18
18
  private var _enableDrag: Bool = false
19
19
  private var _enableDragStart: Bool = false
20
20
  private var _enableDragEnd: Bool = false
21
21
  private var _enableMagnify: Bool = false
22
- private var _enableMagnifyStart: Bool = false
23
22
  private var _enableMagnifyEnd: Bool = false
24
-
25
- internal var rotation: simd_quatd = simd_quatd()
26
- internal var spatialChildren: [String:SpatialEntity] = [:]
27
- internal var spatialComponents: [String: SpatialComponent] = [:]
28
-
23
+
24
+ var rotation: simd_quatd = .init()
25
+ var spatialChildren: [String: SpatialEntity] = [:]
26
+ var spatialComponents: [String: SpatialComponent] = [:]
27
+
29
28
  var enableTap: Bool {
30
29
  return _enableTap
31
30
  }
31
+
32
32
  var enableRotate: Bool {
33
- return _enableRotate || _enableRotateStart
33
+ return _enableRotate || _enableRotateEnd
34
34
  }
35
+
35
36
  var enableDrag: Bool {
36
- return _enableDrag || _enableDragStart
37
+ return _enableDrag || _enableDragStart || _enableDragEnd
37
38
  }
39
+
38
40
  var enableMagnify: Bool {
39
- return _enableMagnify || _enableMagnifyStart
41
+ return _enableMagnify || _enableMagnifyEnd
40
42
  }
41
-
43
+
42
44
  var enableRotateEnd: Bool {
43
45
  return _enableRotateEnd
44
46
  }
47
+
45
48
  var enableDragEnd: Bool {
46
49
  return _enableDragEnd
47
50
  }
51
+
48
52
  var enableMagnifyEnd: Bool {
49
53
  return _enableMagnifyEnd
50
54
  }
51
-
55
+
52
56
  var enableInteractive: Bool {
53
- return enableTap || enableRotate || enableDrag || enableMagnify || enableRotateEnd || enableDragEnd || enableMagnifyEnd
57
+ return enableTap || enableRotate || enableDrag || enableMagnify
54
58
  }
55
-
59
+
56
60
  required init() {
57
- self.spatialId = UUID().uuidString
61
+ spatialId = UUID().uuidString
58
62
  super.init()
59
- SpatialObject.objects[spatialId] = self
63
+ SpatialObject.serialQueue.sync {
64
+ SpatialObject.objects[spatialId] = self
65
+ }
60
66
  SpatialObjectWeakRefManager.setWeakRef(spatialId, self)
61
67
  }
62
-
63
- init(_ _name:String){
64
- self.spatialId = UUID().uuidString
68
+
69
+ init(_ _name: String) {
70
+ spatialId = UUID().uuidString
65
71
  super.init()
66
- self.name = _name
67
- SpatialObject.objects[spatialId] = self
72
+ name = _name
73
+ SpatialObject.serialQueue.sync {
74
+ SpatialObject.objects[spatialId] = self
75
+ }
68
76
  SpatialObjectWeakRefManager.setWeakRef(spatialId, self)
69
77
  }
70
-
71
- func addChild(entity:SpatialEntity){
78
+
79
+ func addChild(entity: SpatialEntity) {
72
80
  spatialChildren[entity.spatialId] = entity
73
81
  super.addChild(entity)
74
82
  }
75
-
76
- func removeChild(id:String){
77
- if let entity = spatialChildren[id]{
83
+
84
+ func removeChild(id: String) {
85
+ if let entity = spatialChildren[id] {
78
86
  super.removeChild(entity)
79
87
  spatialChildren.removeValue(forKey: id)
80
- }
81
- else {
88
+ } else {
82
89
  print("no child found")
83
90
  }
84
91
  }
85
-
86
- func removeFromParent(){
87
- if let parent = parent as? SpatialEntity{
92
+
93
+ func removeFromParent() {
94
+ if let parent = parent as? SpatialEntity {
88
95
  parent.removeChild(self)
89
96
  }
90
97
  }
91
-
98
+
92
99
  func addComponent(_ comp: SpatialComponent) {
93
100
  spatialComponents[comp.type.rawValue] = comp
94
101
  comp.addToEntity(entity: self)
95
102
  }
96
-
103
+
97
104
  func removeComponent(_ comp: SpatialComponent) {
98
105
  if spatialComponents[comp.type.rawValue] != nil {
99
106
  comp.removeFromEntity(entity: self)
100
107
  spatialComponents.removeValue(forKey: comp.type.rawValue)
101
108
  }
102
109
  }
103
-
104
- func updateTransform(_ matrix:[String:Float]){
110
+
111
+ func updateTransform(_ matrix: [String: Float]) {
105
112
  transform.matrix = float4x4([matrix["0"]!, matrix["1"]!, matrix["2"]!, matrix["3"]!], [matrix["4"]!, matrix["5"]!, matrix["6"]!, matrix["7"]!], [matrix["8"]!, matrix["9"]!, matrix["10"]!, matrix["11"]!], [matrix["12"]!, matrix["13"]!, matrix["14"]!, matrix["15"]!])
106
113
  }
107
-
108
- func updateGesture(_ type:String, _ isEable:Bool){
109
- switch WebSpatialGestureType(rawValue: type){
114
+
115
+ func updateGesture(_ type: String, _ isEable: Bool) {
116
+ switch WebSpatialGestureType(rawValue: type) {
110
117
  case .spatialtap:
111
118
  _enableTap = isEable
112
119
  case .spatialrotate:
113
120
  _enableRotate = isEable
114
- case .spatialrotatestart:
115
- _enableRotateStart = isEable
116
121
  case .spatialrotateend:
117
122
  _enableRotateEnd = isEable
118
123
  case .spatialdrag:
@@ -123,46 +128,42 @@ class SpatialEntity: Entity, SpatialObjectProtocol {
123
128
  _enableDragEnd = isEable
124
129
  case .spatialmagnify:
125
130
  _enableMagnify = isEable
126
- case .spatialmagnifystart:
127
- _enableMagnifyStart = isEable
128
131
  case .spatialmagnifyend:
129
132
  _enableMagnifyEnd = isEable
130
133
  default:
131
134
  return
132
135
  }
133
-
136
+
134
137
  if enableInteractive {
135
- if !components.has(InputTargetComponent.self){
138
+ if !components.has(InputTargetComponent.self) {
136
139
  components.set(InputTargetComponent())
137
140
  }
138
- }
139
- else {
140
- if components.has(InputTargetComponent.self){
141
+ } else {
142
+ if components.has(InputTargetComponent.self) {
141
143
  components.remove(InputTargetComponent.self)
142
144
  }
143
145
  }
144
146
  }
145
-
146
- static func findNearestParent(entity: Entity) -> SpatialEntity?{
147
- if let parent = entity.parent as? SpatialEntity{
147
+
148
+ static func findNearestParent(entity: Entity) -> SpatialEntity? {
149
+ if let parent = entity.parent as? SpatialEntity {
148
150
  return parent
149
- }
150
- else if entity.parent != nil {
151
+ } else if entity.parent != nil {
151
152
  return findNearestParent(entity: entity.parent!)
152
153
  }
153
154
  return nil
154
155
  }
155
-
156
+
156
157
  func setRotation(_ rotation: simd_quatd) {
157
158
  self.rotation = rotation
158
- self.transform.rotation = simd_quatf(ix: Float(rotation.imag.x), iy: Float(rotation.imag.y), iz: Float(rotation.imag.z), r: Float(rotation.real))
159
+ transform.rotation = simd_quatf(ix: Float(rotation.imag.x), iy: Float(rotation.imag.y), iz: Float(rotation.imag.z), r: Float(rotation.real))
159
160
  }
160
-
161
+
161
162
  // Encodable
162
163
  enum CodingKeys: String, CodingKey {
163
164
  case id, name, isDestroyed, children, components
164
165
  }
165
-
166
+
166
167
  func encode(to encoder: any Encoder) throws {
167
168
  var container = encoder.container(keyedBy: CodingKeys.self)
168
169
  try container.encode(spatialId, forKey: .id)
@@ -171,12 +172,12 @@ class SpatialEntity: Entity, SpatialObjectProtocol {
171
172
  try container.encode(spatialChildren, forKey: .children)
172
173
  try container.encode(spatialComponents, forKey: .components)
173
174
  }
174
-
175
+
175
176
  // Equatable
176
177
  static func == (lhs: SpatialEntity, rhs: SpatialEntity) -> Bool {
177
178
  return lhs.spatialId == rhs.spatialId
178
179
  }
179
-
180
+
180
181
  func destroy() {
181
182
  if _isDestroyed {
182
183
  return
@@ -187,24 +188,26 @@ class SpatialEntity: Entity, SpatialObjectProtocol {
187
188
 
188
189
  emit(event: SpatialObject.Events.Destroyed.rawValue, data: ["object": self])
189
190
  listeners = [:]
190
- SpatialObject.objects.removeValue(forKey: spatialId)
191
+ SpatialObject.serialQueue.sync {
192
+ SpatialObject.objects.removeValue(forKey: spatialId)
193
+ }
191
194
  }
192
-
193
- internal func onDestroy() {
194
- if(parent != nil){
195
+
196
+ func onDestroy() {
197
+ if parent != nil {
195
198
  removeFromParent()
196
199
  }
197
200
  components.removeAll()
198
- spatialChildren.forEach { id, child in
201
+ for (id, child) in spatialChildren {
199
202
  child.destroy()
200
203
  }
201
204
  spatialChildren = [:]
202
- spatialComponents.forEach { id, components in
205
+ for (id, components) in spatialComponents {
203
206
  components.destroy()
204
207
  }
205
208
  spatialComponents = [:]
206
209
  }
207
-
210
+
208
211
  deinit {
209
212
  SpatialObjectWeakRefManager.removeWeakRef(spatialId)
210
213
  }
@@ -71,7 +71,7 @@ struct Spatialized2DElementView: View {
71
71
  private var dragWebGesture: some Gesture {
72
72
  DragGesture()
73
73
  .onChanged { gesture in
74
- print("\(spatialized2DElement.name) dragWebGesture")
74
+ // print("\(spatialized2DElement.name) dragWebGesture")
75
75
  if spatialized2DElement.scrollPageEnabled {
76
76
  if !gestureData.dragStarted {
77
77
  gestureData.dragStarted = true
@@ -7,90 +7,99 @@ struct SpatializedDynamic3DView: View {
7
7
  @State private var isDrag = false
8
8
  @State private var isRotate = false
9
9
  @State private var isScale = false
10
-
10
+
11
11
  private var spatializedDynamic3DElement: SpatializedDynamic3DElement {
12
12
  return spatializedElement as! SpatializedDynamic3DElement
13
13
  }
14
-
15
- var spatialTapEvent: some Gesture{
14
+
15
+ var spatialTapEvent: some Gesture {
16
16
  SpatialTapGesture(count: 1).targetedToAnyEntity()
17
- .onEnded{ value in
18
- if let entity = value.entity as? SpatialEntity{
17
+ .onEnded { value in
18
+ if let entity = value.entity as? SpatialEntity {
19
19
  spatialScene.sendWebMsg(entity.spatialId, WebSpatialTapGuestureEvent(detail: WebSpatialTapGuestureEventDetail(location3D: value.location3D)))
20
- }
21
- else {
22
- if let spatialEntity = SpatialEntity.findNearestParent(entity: value.entity){
20
+ } else {
21
+ if let spatialEntity = SpatialEntity.findNearestParent(entity: value.entity) {
23
22
  spatialScene.sendWebMsg(spatialEntity.spatialId, WebSpatialTapGuestureEvent(detail: WebSpatialTapGuestureEventDetail(location3D: value.location3D)))
24
23
  }
25
24
  }
26
- }
25
+ }
27
26
  }
28
-
29
- var rotate3dEvent: some Gesture{
30
- RotateGesture3D().targetedToAnyEntity().onChanged{ value in
31
- print(value.gestureValue)
32
- if let entity = value.entity as? SpatialEntity{
33
- if entity.enableTap == true {
34
- // if(isRotate == false){
35
- // print("start rotate")
36
- // }
37
- // else{
38
- // print("rotating")
39
- // }
40
- // isRotate = true
41
- return
42
- }
27
+
28
+ var rotate3dEvent: some Gesture {
29
+ RotateGesture3D().targetedToAnyEntity().onChanged { value in
30
+ // Always forward rotate gesture events to JS
31
+ if let entity = value.entity as? SpatialEntity {
32
+ let gestureEvent = WebSpatialRotateGuestureEvent(
33
+ detail: .init(
34
+ quaternion: Quaternion(
35
+ x: value.rotation.quaternion.imag.x,
36
+ y: value.rotation.quaternion.imag.y,
37
+ z: value.rotation.quaternion.imag.z,
38
+ w: value.rotation.quaternion.real
39
+ )
40
+ )
41
+ )
42
+ spatialScene.sendWebMsg(entity.spatialId, gestureEvent)
43
+ }
44
+ }.onEnded { value in
45
+ // Always forward rotate end event to JS
46
+ if let entity = value.entity as? SpatialEntity {
47
+ let gestureEvent = WebSpatialRotateEndGuestureEvent()
48
+ spatialScene.sendWebMsg(entity.spatialId, gestureEvent)
43
49
  }
44
50
  isRotate = false
45
- }.onEnded{ value in
46
- print(value.rotation)
47
- print("rotate end")
48
- // isRotate = false
49
51
  }
50
52
  }
51
-
52
- var magnifyEvent: some Gesture{
53
- MagnifyGesture().targetedToAnyEntity().onChanged{ value in
54
- print(value)
55
- if let entity = value.entity as? SpatialEntity{
56
- if entity.enableTap == true {
57
- // if(isScale == false){
58
- // print("start scale")
59
- // }
60
- // else{
61
- // print("scaling")
62
- // }
63
- // isScale = true
64
- return
65
- }
53
+
54
+ var magnifyEvent: some Gesture {
55
+ MagnifyGesture().targetedToAnyEntity().onChanged { value in
56
+ // Always forward magnify gesture events to JS
57
+ if let entity = value.entity as? SpatialEntity {
58
+ let detail = WebSpatialMagnifyGuestureEventDetail(magnification: value.magnification)
59
+ let gestureEvent = WebSpatialMagnifyGuestureEvent(
60
+ detail: detail
61
+ )
62
+ spatialScene.sendWebMsg(entity.spatialId, gestureEvent)
63
+ }
64
+ }.onEnded { value in
65
+ // Always forward magnify end event to JS
66
+ if let entity = value.entity as? SpatialEntity {
67
+ let gestureEvent = WebSpatialMagnifyEndGuestureEvent()
68
+ spatialScene.sendWebMsg(entity.spatialId, gestureEvent)
66
69
  }
67
- }.onEnded{ value in
68
- print("scale end")
69
- // isScale = false
70
+ isScale = false
70
71
  }
71
72
  }
72
-
73
- var dragEvent: some Gesture{
74
- DragGesture().targetedToAnyEntity().onChanged{ value in
75
- if let entity = value.entity as? SpatialEntity{
76
- if entity.enableTap == true {
77
- // if(isDrag == false){
78
- // print("start drag")
79
- // }
80
- // else{
81
- // print("dragging")
82
- // }
83
- // isDrag = true
84
- return
73
+
74
+ var dragEvent: some Gesture {
75
+ DragGesture().targetedToAnyEntity().onChanged { value in
76
+ // Always forward drag gesture events to JS
77
+ if let entity = value.entity as? SpatialEntity {
78
+ if !isDrag {
79
+ let startEvent = WebSpatialDragStartGuestureEvent(
80
+ detail: .init(
81
+ startLocation3D: value.startLocation3D
82
+ )
83
+ )
84
+ spatialScene.sendWebMsg(entity.spatialId, startEvent)
85
+ isDrag = true
86
+ } else {
87
+ let gestureEvent = WebSpatialDragGuestureEvent(
88
+ detail: .init(translation3D: value.translation3D)
89
+ )
90
+ spatialScene.sendWebMsg(entity.spatialId, gestureEvent)
85
91
  }
86
92
  }
87
-
88
- }.onEnded{ value in
89
- print("drag end")
90
- // isDrag = false
93
+ }.onEnded { value in
94
+ // Always forward drag end event to JS
95
+ if let entity = value.entity as? SpatialEntity {
96
+ let gestureEvent = WebSpatialDragEndGuestureEvent()
97
+ spatialScene.sendWebMsg(entity.spatialId, gestureEvent)
98
+ }
99
+ isDrag = false
91
100
  }
92
101
  }
93
-
102
+
94
103
  var body: some View {
95
104
  RealityView(make: { content in
96
105
  let rootEntity = spatializedDynamic3DElement.getRoot()