@webspatial/platform-visionos 1.0.4 → 1.1.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.
- package/package.json +2 -2
- package/web-spatial/EventEmitter.swift +56 -0
- package/web-spatial/JSBCommand.swift +348 -0
- package/web-spatial/SpatialObject.swift +108 -0
- package/web-spatial/WebMsgCommand.swift +137 -0
- package/web-spatial/WebSpatialApp.swift +111 -0
- package/web-spatial/{libs/uiKitDelegate/Window.swift → Window.swift} +1 -0
- package/web-spatial/manager/Dynamic3DManager.swift +114 -0
- package/web-spatial/manager/JSBManager.swift +148 -0
- package/web-spatial/manager/WKWebViewManager.swift +39 -0
- package/web-spatial/{libs/webView/manifest.swift → manifest.swift} +16 -5
- package/web-spatial/model/SpatialApp.swift +190 -0
- package/web-spatial/model/SpatialScene.swift +1078 -0
- package/web-spatial/model/Spatialized2DElement.swift +128 -0
- package/web-spatial/model/SpatializedDynamic3DElement.swift +34 -0
- package/web-spatial/model/SpatializedElement.swift +95 -0
- package/web-spatial/model/SpatializedStatic3DElement.swift +19 -0
- package/web-spatial/model/dynamic3d/Geometry.swift +95 -0
- package/web-spatial/model/dynamic3d/SpatialComponent.swift +72 -0
- package/web-spatial/model/dynamic3d/SpatialEntity.swift +211 -0
- package/web-spatial/model/dynamic3d/SpatialMaterial.swift +39 -0
- package/web-spatial/model/dynamic3d/SpatialModelEntity.swift +39 -0
- package/web-spatial/model/dynamic3d/SpatialModelResource.swift +38 -0
- package/web-spatial/model/dynamic3d/SpatialTextureResource.swift +18 -0
- package/web-spatial/protocol/ScrollAbleSpatialElementContainer.swift +1 -0
- package/web-spatial/protocol/SpatialScrollAble.swift +8 -0
- package/web-spatial/protocol/SpatializedElementContainer.swift +8 -0
- package/web-spatial/protocol/WebMsgSender.swift +5 -0
- package/web-spatial/types/Vec2.swift +12 -0
- package/web-spatial/types/Vec3.swift +7 -0
- package/web-spatial/view/SceneHandlerUIView.swift +92 -0
- package/web-spatial/{views/ui/NavView.swift → view/SpatialNavView.swift} +149 -77
- package/web-spatial/view/SpatialSceneContentView.swift +218 -0
- package/web-spatial/view/SpatialSceneView.swift +53 -0
- package/web-spatial/view/Spatialized2DElementView.swift +96 -0
- package/web-spatial/view/SpatializedDynamic3DView.swift +173 -0
- package/web-spatial/view/SpatializedElementView.swift +178 -0
- package/web-spatial/view/SpatializedStatic3DView.swift +72 -0
- package/web-spatial/{views → view/view-modifier}/MaterialWithBorderCornerModifier.swift +28 -8
- package/web-spatial/webview/SpatialWebController.swift +300 -0
- package/web-spatial/webview/SpatialWebView.swift +34 -0
- package/web-spatial/webview/SpatialWebViewModel.swift +307 -0
- package/web-spatial.xcodeproj/project.pbxproj +126 -207
- package/web-spatial/libs/EventEmitter.swift +0 -25
- package/web-spatial/libs/SpatialComponent.swift +0 -24
- package/web-spatial/libs/SpatialEntity.swift +0 -172
- package/web-spatial/libs/SpatialInputComponent.swift +0 -19
- package/web-spatial/libs/SpatialMeshResource.swift +0 -12
- package/web-spatial/libs/SpatialModel3DComponent.swift +0 -51
- package/web-spatial/libs/SpatialModelComponent.swift +0 -25
- package/web-spatial/libs/SpatialObject.swift +0 -140
- package/web-spatial/libs/SpatialPhysicallyBasedMaterial.swift +0 -19
- package/web-spatial/libs/SpatialViewComponent.swift +0 -8
- package/web-spatial/libs/SpatialWindowComponent.swift +0 -454
- package/web-spatial/libs/SpatialWindowContainer.swift +0 -153
- package/web-spatial/libs/Utils/CommandManager.swift +0 -823
- package/web-spatial/libs/Utils/PerfClock.swift +0 -43
- package/web-spatial/libs/Utils/SceneManager.swift +0 -101
- package/web-spatial/libs/Utils/WindowContainerMgr.swift +0 -122
- package/web-spatial/libs/json/JsonParser.swift +0 -45
- package/web-spatial/libs/webView/UpdateSystem.swift +0 -26
- package/web-spatial/libs/webView/backend/NativeWebView.swift +0 -350
- package/web-spatial/views/ImmersiveView.swift +0 -17
- package/web-spatial/views/OpenDismissHandlerUI.swift +0 -45
- package/web-spatial/views/PlainWindowContainerView.swift +0 -132
- package/web-spatial/views/SpatialModel3DView.swift +0 -187
- package/web-spatial/views/SpatialViewUI.swift +0 -168
- package/web-spatial/views/SpatialWebViewUI.swift +0 -179
- package/web-spatial/views/VolumetricWindowContainerView.swift +0 -30
- package/web-spatial/web_spatialApp.swift +0 -141
- /package/web-spatial/{libs/Utils → Utils}/ColorExtension.swift +0 -0
- /package/web-spatial/{libs/Utils → Utils}/Logger.swift +0 -0
- /package/web-spatial/{views → view}/LoadingView.swift +0 -0
- /package/web-spatial/{views → view/view-modifier}/HideViewModifier.swift +0 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import RealityKit
|
|
2
|
+
import SwiftUI
|
|
3
|
+
|
|
4
|
+
struct SpatialSceneContentView: View {
|
|
5
|
+
@State var sceneId: String
|
|
6
|
+
var width: Double
|
|
7
|
+
var height: Double
|
|
8
|
+
|
|
9
|
+
var body: some View {
|
|
10
|
+
if let spatialScene = SpatialApp.Instance.getScene(sceneId) {
|
|
11
|
+
ZStack(alignment: Alignment.topLeading) {
|
|
12
|
+
// Display the main webview
|
|
13
|
+
if spatialScene.didFailLoad {
|
|
14
|
+
VStack {
|
|
15
|
+
Text("Failed to load webpage. Is the server running?")
|
|
16
|
+
.foregroundColor(.white)
|
|
17
|
+
Button("Reload") {
|
|
18
|
+
let url = spatialScene.spatialWebViewModel.url
|
|
19
|
+
|
|
20
|
+
spatialScene.spatialWebViewModel.load(url)
|
|
21
|
+
}
|
|
22
|
+
.foregroundColor(.white)
|
|
23
|
+
}
|
|
24
|
+
.frame(maxWidth: .infinity, maxHeight: .infinity).glassBackgroundEffect()
|
|
25
|
+
} else {
|
|
26
|
+
spatialScene.getView()
|
|
27
|
+
.materialWithBorderCorner(
|
|
28
|
+
spatialScene.backgroundMaterial,
|
|
29
|
+
spatialScene.cornerRadius,
|
|
30
|
+
spatialScene.windowStyle
|
|
31
|
+
)
|
|
32
|
+
.frame(width: width, height: height)
|
|
33
|
+
.offset(z: -1)
|
|
34
|
+
|
|
35
|
+
let childrenOfSpatialized2DElement: [SpatializedElement] = Array(spatialScene.getChildrenOfType(.Spatialized2DElement).values)
|
|
36
|
+
|
|
37
|
+
ForEach(childrenOfSpatialized2DElement, id: \.id) { child in
|
|
38
|
+
SpatializedElementView(parentScrollOffset: spatialScene.scrollOffset) {
|
|
39
|
+
Spatialized2DElementView()
|
|
40
|
+
}
|
|
41
|
+
.environment(child)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let childrenOfSpatializedStatic3DElement: [SpatializedElement] = Array(spatialScene.getChildrenOfType(.SpatializedStatic3DElement).values)
|
|
45
|
+
|
|
46
|
+
ForEach(childrenOfSpatializedStatic3DElement, id: \.id) { child in
|
|
47
|
+
SpatializedElementView(parentScrollOffset: spatialScene.scrollOffset) {
|
|
48
|
+
SpatializedStatic3DView()
|
|
49
|
+
}
|
|
50
|
+
.environment(child)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let childrenOfSpatializedDynamic3DElement: [SpatializedElement] = Array(spatialScene.getChildrenOfType(.SpatializedDynamic3DElement).values)
|
|
54
|
+
|
|
55
|
+
ForEach(childrenOfSpatializedDynamic3DElement, id: \.id) { child in
|
|
56
|
+
SpatializedElementView(parentScrollOffset: spatialScene.scrollOffset) {
|
|
57
|
+
SpatializedDynamic3DView()
|
|
58
|
+
}
|
|
59
|
+
.environment(child)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
.opacity(spatialScene.opacity)
|
|
64
|
+
.environment(spatialScene)
|
|
65
|
+
.coordinateSpace(name: "SpatialScene")
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
struct PreviewSpatializedStatic3DElement: View {
|
|
71
|
+
var sceneId: String
|
|
72
|
+
|
|
73
|
+
init() {
|
|
74
|
+
let spatialScene = SpatialApp.Instance.createScene(
|
|
75
|
+
"http://localhost:5173/",
|
|
76
|
+
.window,
|
|
77
|
+
.visible
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
let spatializedStatic3DElement: SpatializedStatic3DElement = spatialScene.createSpatializedElement(
|
|
81
|
+
.SpatializedStatic3DElement
|
|
82
|
+
)
|
|
83
|
+
spatializedStatic3DElement.transform.translation.x = 200
|
|
84
|
+
spatializedStatic3DElement.transform.translation.y = 300
|
|
85
|
+
spatializedStatic3DElement.transform.translation.z = 0
|
|
86
|
+
spatializedStatic3DElement.name = "jack"
|
|
87
|
+
|
|
88
|
+
spatializedStatic3DElement.width = 200
|
|
89
|
+
spatializedStatic3DElement.height = 100
|
|
90
|
+
|
|
91
|
+
spatializedStatic3DElement.modelURL = "http://localhost:5173/public/modelasset/cone.usdz"
|
|
92
|
+
spatializedStatic3DElement.setParent(spatialScene)
|
|
93
|
+
|
|
94
|
+
let spatializedStatic3DElementB: SpatializedStatic3DElement = spatialScene.createSpatializedElement(
|
|
95
|
+
.SpatializedStatic3DElement
|
|
96
|
+
)
|
|
97
|
+
spatializedStatic3DElementB.transform.translation.x = 700
|
|
98
|
+
spatializedStatic3DElementB.transform.translation.y = 300
|
|
99
|
+
spatializedStatic3DElementB.transform.translation.z = 0
|
|
100
|
+
spatializedStatic3DElementB.width = 200
|
|
101
|
+
spatializedStatic3DElementB.height = 200
|
|
102
|
+
spatializedStatic3DElementB.name = "tom"
|
|
103
|
+
|
|
104
|
+
spatializedStatic3DElementB.modelURL = "http://localhost:5173/public/modelasset/vehicle-speedster.usdz"
|
|
105
|
+
spatializedStatic3DElementB.setParent(spatialScene)
|
|
106
|
+
|
|
107
|
+
sceneId = spatialScene.id
|
|
108
|
+
|
|
109
|
+
print("spatialScene \(spatialScene)")
|
|
110
|
+
|
|
111
|
+
let spatializedElement: SpatializedDynamic3DElement = spatialScene.createSpatializedElement(
|
|
112
|
+
.SpatializedDynamic3DElement
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
spatializedElement.name = "dynamicCubes"
|
|
116
|
+
spatializedElement.transform.translation.x = 400
|
|
117
|
+
spatializedElement.transform.translation.y = 400
|
|
118
|
+
spatializedElement.transform.translation.z = 0
|
|
119
|
+
spatializedElement.width = 200
|
|
120
|
+
spatializedElement.height = 200
|
|
121
|
+
spatializedElement.setParent(spatialScene)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
var body: some View {
|
|
125
|
+
SpatialSceneContentView(sceneId: sceneId, width: 1200, height: 1000)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
struct PreviewSpatialized2DElement: View {
|
|
130
|
+
var sceneId: String
|
|
131
|
+
|
|
132
|
+
init() {
|
|
133
|
+
let spatialScene = SpatialApp.Instance.createScene(
|
|
134
|
+
"http://localhost:5173/",
|
|
135
|
+
.window,
|
|
136
|
+
.visible
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
let spatializedElementA: Spatialized2DElement = spatialScene.createSpatializedElement(
|
|
140
|
+
.Spatialized2DElement
|
|
141
|
+
)
|
|
142
|
+
spatializedElementA.transform.translation.x = 200
|
|
143
|
+
spatializedElementA.transform.translation.y = 300
|
|
144
|
+
spatializedElementA.transform.translation.z = 0
|
|
145
|
+
spatializedElementA.name = "jack"
|
|
146
|
+
|
|
147
|
+
spatializedElementA.width = 200
|
|
148
|
+
spatializedElementA.height = 100
|
|
149
|
+
spatializedElementA.load("http://localhost:5173/src/")
|
|
150
|
+
|
|
151
|
+
spatializedElementA.setParent(spatialScene)
|
|
152
|
+
|
|
153
|
+
let spatializedElementB: Spatialized2DElement = spatialScene.createSpatializedElement(
|
|
154
|
+
.Spatialized2DElement
|
|
155
|
+
)
|
|
156
|
+
spatializedElementB.transform.translation.x = 400
|
|
157
|
+
spatializedElementB.transform.translation.y = 300
|
|
158
|
+
spatializedElementB.transform.translation.z = 0
|
|
159
|
+
spatializedElementB.name = "jack"
|
|
160
|
+
|
|
161
|
+
spatializedElementB.width = 200
|
|
162
|
+
spatializedElementB.height = 100
|
|
163
|
+
spatializedElementB.load("http://localhost:5173/src/embed/")
|
|
164
|
+
spatializedElementB.setParent(spatialScene)
|
|
165
|
+
|
|
166
|
+
sceneId = spatialScene.id
|
|
167
|
+
|
|
168
|
+
print("spatialScene \(spatialScene)")
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
var body: some View {
|
|
172
|
+
SpatialSceneContentView(sceneId: sceneId, width: 1200, height: 1000)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
struct PreviewSpatializedDynamic3DElement: View {
|
|
177
|
+
var sceneId: String
|
|
178
|
+
|
|
179
|
+
init() {
|
|
180
|
+
let spatialScene = SpatialApp.Instance.createScene(
|
|
181
|
+
"http://localhost:5173/",
|
|
182
|
+
.window,
|
|
183
|
+
.visible
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
let spatializedElement: SpatializedDynamic3DElement = spatialScene.createSpatializedElement(
|
|
187
|
+
.SpatializedDynamic3DElement
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
spatializedElement.name = "dynamicCubes"
|
|
191
|
+
spatializedElement.transform.translation.x = 100
|
|
192
|
+
spatializedElement.transform.translation.y = 100
|
|
193
|
+
spatializedElement.transform.translation.z = 0
|
|
194
|
+
spatializedElement.width = 200
|
|
195
|
+
spatializedElement.height = 200
|
|
196
|
+
spatializedElement.setParent(spatialScene)
|
|
197
|
+
|
|
198
|
+
sceneId = spatialScene.id
|
|
199
|
+
|
|
200
|
+
print("spatialScene \(spatialScene)")
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
var body: some View {
|
|
204
|
+
SpatialSceneContentView(sceneId: sceneId, width: 1200, height: 1000)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
#Preview("PreviewSpatializedDynamic3DElement") {
|
|
209
|
+
PreviewSpatializedDynamic3DElement()
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
#Preview("PreviewSpatializedStatic3DElementWithRotation") {
|
|
213
|
+
PreviewSpatializedStatic3DElement()
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
#Preview("PreviewSpatialized2DElement") {
|
|
217
|
+
PreviewSpatialized2DElement()
|
|
218
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import _RealityKit_SwiftUI
|
|
2
|
+
import SwiftUI
|
|
3
|
+
|
|
4
|
+
struct SpatialSceneView: View {
|
|
5
|
+
@State var spatialScene: SpatialScene
|
|
6
|
+
@State private var windowResizeInProgress = false
|
|
7
|
+
@State private var timer: Timer?
|
|
8
|
+
|
|
9
|
+
var body: some View {
|
|
10
|
+
GeometryReader3D { proxy3D in
|
|
11
|
+
let width = proxy3D.size.width
|
|
12
|
+
let height = proxy3D.size.height
|
|
13
|
+
|
|
14
|
+
SceneHandlerUIView(spatialScene: spatialScene).onChange(of: proxy3D.size) {
|
|
15
|
+
windowResizeInProgress = true
|
|
16
|
+
if timer != nil {
|
|
17
|
+
timer!.invalidate()
|
|
18
|
+
}
|
|
19
|
+
// If we don't detect resolution change after x seconds we treat the resize as complete
|
|
20
|
+
timer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false) { _ in
|
|
21
|
+
windowResizeInProgress = false
|
|
22
|
+
timer = nil
|
|
23
|
+
}
|
|
24
|
+
spatialScene.updateSize3D(proxy3D.size)
|
|
25
|
+
}
|
|
26
|
+
.onAppear {
|
|
27
|
+
spatialScene.moveToState(.visible, nil)
|
|
28
|
+
spatialScene.updateSize3D(proxy3D.size)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if windowResizeInProgress {
|
|
32
|
+
let x = width / 2
|
|
33
|
+
let y = height / 2
|
|
34
|
+
VStack {}.frame(width: width, height: height).glassBackgroundEffect().padding3D(.front, -100_000)
|
|
35
|
+
.position(x: x, y: y)
|
|
36
|
+
} else {
|
|
37
|
+
SpatialSceneContentView(sceneId: spatialScene.id, width: width, height: height)
|
|
38
|
+
.ornament(attachmentAnchor: .scene(.top), contentAlignment: .center) {
|
|
39
|
+
if pwaManager.display != .fullscreen {
|
|
40
|
+
ZStack {
|
|
41
|
+
SpatialNavView(
|
|
42
|
+
spatialScene: spatialScene
|
|
43
|
+
)
|
|
44
|
+
.offset(y: -15)
|
|
45
|
+
}.frame(height: 100)
|
|
46
|
+
}
|
|
47
|
+
}.volumeBaseplateVisibility(
|
|
48
|
+
spatialScene.sceneConfig?.baseplateVisibility ?? .automatic
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import RealityKit
|
|
2
|
+
import SwiftUI
|
|
3
|
+
|
|
4
|
+
extension View {
|
|
5
|
+
@ViewBuilder
|
|
6
|
+
func `if`<Content: View>(_ condition: Bool, transform: (Self) -> Content) -> some View {
|
|
7
|
+
if condition {
|
|
8
|
+
transform(self)
|
|
9
|
+
} else {
|
|
10
|
+
self
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class Spatialized2DViewGestureData {
|
|
16
|
+
var dragStarted = false
|
|
17
|
+
var dragStart: CGFloat = 0.0
|
|
18
|
+
var dragVelocity: CGFloat = 0.0
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
struct Spatialized2DElementView: View {
|
|
22
|
+
@Environment(SpatializedElement.self) var spatializedElement: SpatializedElement
|
|
23
|
+
@Environment(SpatialScene.self) var spatialScene: SpatialScene
|
|
24
|
+
|
|
25
|
+
private var spatialized2DElement: Spatialized2DElement {
|
|
26
|
+
return spatializedElement as! Spatialized2DElement
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@State private var gestureData = Spatialized2DViewGestureData()
|
|
30
|
+
|
|
31
|
+
var body: some View {
|
|
32
|
+
// Display child spatialized2DElements
|
|
33
|
+
ZStack(alignment: Alignment.topLeading) {
|
|
34
|
+
// Display the main webview
|
|
35
|
+
spatialized2DElement.getView()
|
|
36
|
+
.materialWithBorderCorner(
|
|
37
|
+
spatialized2DElement.backgroundMaterial,
|
|
38
|
+
spatialized2DElement.cornerRadius,
|
|
39
|
+
.window
|
|
40
|
+
)
|
|
41
|
+
.simultaneousGesture(spatialized2DElement.scrollPageEnabled ? dragWebGesture : nil)
|
|
42
|
+
|
|
43
|
+
let childrenOfSpatialized2DElement: [SpatializedElement] = Array(spatialized2DElement.getChildrenOfType(.Spatialized2DElement).values)
|
|
44
|
+
|
|
45
|
+
ForEach(childrenOfSpatialized2DElement, id: \.id) { child in
|
|
46
|
+
SpatializedElementView(parentScrollOffset: spatialized2DElement.scrollOffset) {
|
|
47
|
+
Spatialized2DElementView()
|
|
48
|
+
}
|
|
49
|
+
.environment(child)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let childrenOfSpatializedStatic3DElement: [SpatializedElement] = Array(spatialized2DElement.getChildrenOfType(.SpatializedStatic3DElement).values)
|
|
53
|
+
ForEach(childrenOfSpatializedStatic3DElement, id: \.id) { child in
|
|
54
|
+
SpatializedElementView(parentScrollOffset: spatialized2DElement.scrollOffset) {
|
|
55
|
+
SpatializedStatic3DView()
|
|
56
|
+
}
|
|
57
|
+
.environment(child)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let childrenOfSpatializedDynamic3DElement: [SpatializedElement] = Array(spatialized2DElement.getChildrenOfType(.SpatializedDynamic3DElement).values)
|
|
61
|
+
|
|
62
|
+
ForEach(childrenOfSpatializedDynamic3DElement, id: \.id) { child in
|
|
63
|
+
SpatializedElementView(parentScrollOffset: spatialized2DElement.scrollOffset) {
|
|
64
|
+
SpatializedDynamic3DView()
|
|
65
|
+
}
|
|
66
|
+
.environment(child)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private var dragWebGesture: some Gesture {
|
|
72
|
+
DragGesture()
|
|
73
|
+
.onChanged { gesture in
|
|
74
|
+
print("\(spatialized2DElement.name) dragWebGesture")
|
|
75
|
+
if spatialized2DElement.scrollPageEnabled {
|
|
76
|
+
if !gestureData.dragStarted {
|
|
77
|
+
gestureData.dragStarted = true
|
|
78
|
+
gestureData.dragStart = (gesture.translation.height)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// TODO: this should have velocity
|
|
82
|
+
let delta = gestureData.dragStart - gesture.translation.height
|
|
83
|
+
gestureData.dragStart = gesture.translation.height
|
|
84
|
+
spatialScene.updateDeltaScrollOffset(Vec2(x: 0, y: delta))
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
.onEnded { _ in
|
|
88
|
+
print("\(spatialized2DElement.name) dragWebGestureEnd")
|
|
89
|
+
if spatialized2DElement.scrollPageEnabled {
|
|
90
|
+
gestureData.dragStarted = false
|
|
91
|
+
gestureData.dragStart = 0
|
|
92
|
+
spatialScene.stopScrolling()
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import RealityKit
|
|
2
|
+
import SwiftUI
|
|
3
|
+
|
|
4
|
+
struct SpatializedDynamic3DView: View {
|
|
5
|
+
@Environment(SpatializedElement.self) var spatializedElement: SpatializedElement
|
|
6
|
+
@Environment(SpatialScene.self) var spatialScene: SpatialScene
|
|
7
|
+
@State private var isDrag = false
|
|
8
|
+
@State private var isRotate = false
|
|
9
|
+
@State private var isScale = false
|
|
10
|
+
|
|
11
|
+
private var spatializedDynamic3DElement: SpatializedDynamic3DElement {
|
|
12
|
+
return spatializedElement as! SpatializedDynamic3DElement
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
var spatialTapEvent: some Gesture {
|
|
16
|
+
SpatialTapGesture(count: 1).targetedToAnyEntity()
|
|
17
|
+
.onEnded { value in
|
|
18
|
+
if let entity = value.entity as? SpatialEntity {
|
|
19
|
+
spatialScene.sendWebMsg(entity.spatialId, WebSpatialTapGuestureEvent(detail: WebSpatialTapGuestureEventDetail(location3D: value.location3D)))
|
|
20
|
+
} else {
|
|
21
|
+
if let spatialEntity = SpatialEntity.findNearestParent(entity: value.entity) {
|
|
22
|
+
spatialScene.sendWebMsg(spatialEntity.spatialId, WebSpatialTapGuestureEvent(detail: WebSpatialTapGuestureEventDetail(location3D: value.location3D)))
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
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
|
+
if !isRotate {
|
|
33
|
+
let startEvent = WebSpatialRotateStartGuestureEvent(
|
|
34
|
+
detail: .init(
|
|
35
|
+
rotation: value.rotation,
|
|
36
|
+
startAnchor3D: value.startAnchor3D,
|
|
37
|
+
startLocation3D: value.startLocation3D
|
|
38
|
+
)
|
|
39
|
+
)
|
|
40
|
+
spatialScene.sendWebMsg(entity.spatialId, startEvent)
|
|
41
|
+
isRotate = true
|
|
42
|
+
} else {
|
|
43
|
+
let gestureEvent = WebSpatialRotateGuestureEvent(
|
|
44
|
+
detail: .init(
|
|
45
|
+
rotation: value.rotation,
|
|
46
|
+
startAnchor3D: value.startAnchor3D,
|
|
47
|
+
startLocation3D: value.startLocation3D
|
|
48
|
+
)
|
|
49
|
+
)
|
|
50
|
+
spatialScene.sendWebMsg(entity.spatialId, gestureEvent)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}.onEnded { value in
|
|
54
|
+
// Always forward rotate end event to JS
|
|
55
|
+
if let entity = value.entity as? SpatialEntity {
|
|
56
|
+
let gestureEvent = WebSpatialRotateEndGuestureEvent(
|
|
57
|
+
detail: .init(
|
|
58
|
+
rotation: value.rotation,
|
|
59
|
+
startAnchor3D: value.startAnchor3D,
|
|
60
|
+
startLocation3D: value.startLocation3D
|
|
61
|
+
)
|
|
62
|
+
)
|
|
63
|
+
spatialScene.sendWebMsg(entity.spatialId, gestureEvent)
|
|
64
|
+
}
|
|
65
|
+
isRotate = false
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
var magnifyEvent: some Gesture {
|
|
70
|
+
MagnifyGesture().targetedToAnyEntity().onChanged { value in
|
|
71
|
+
// Always forward magnify gesture events to JS
|
|
72
|
+
if let entity = value.entity as? SpatialEntity {
|
|
73
|
+
if !isScale {
|
|
74
|
+
let startEvent = WebSpatialMagnifyStartGuestureEvent(
|
|
75
|
+
detail: .init(
|
|
76
|
+
magnification: value.magnification,
|
|
77
|
+
velocity: value.velocity,
|
|
78
|
+
startLocation3D: value.startLocation3D,
|
|
79
|
+
startAnchor3D: value.startAnchor3D
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
spatialScene.sendWebMsg(entity.spatialId, startEvent)
|
|
83
|
+
isScale = true
|
|
84
|
+
} else {
|
|
85
|
+
let gestureEvent = WebSpatialMagnifyGuestureEvent(
|
|
86
|
+
detail: .init(
|
|
87
|
+
magnification: value.magnification,
|
|
88
|
+
velocity: value.velocity,
|
|
89
|
+
startLocation3D: value.startLocation3D,
|
|
90
|
+
startAnchor3D: value.startAnchor3D
|
|
91
|
+
)
|
|
92
|
+
)
|
|
93
|
+
spatialScene.sendWebMsg(entity.spatialId, gestureEvent)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}.onEnded { value in
|
|
97
|
+
// Always forward magnify end event to JS
|
|
98
|
+
if let entity = value.entity as? SpatialEntity {
|
|
99
|
+
let gestureEvent = WebSpatialMagnifyEndGuestureEvent(
|
|
100
|
+
detail: .init(
|
|
101
|
+
magnification: value.magnification,
|
|
102
|
+
velocity: value.velocity,
|
|
103
|
+
startLocation3D: value.startLocation3D,
|
|
104
|
+
startAnchor3D: value.startAnchor3D
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
spatialScene.sendWebMsg(entity.spatialId, gestureEvent)
|
|
108
|
+
}
|
|
109
|
+
isScale = false
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
var dragEvent: some Gesture {
|
|
114
|
+
DragGesture().targetedToAnyEntity().onChanged { value in
|
|
115
|
+
// Always forward drag gesture events to JS
|
|
116
|
+
if let entity = value.entity as? SpatialEntity {
|
|
117
|
+
if !isDrag {
|
|
118
|
+
let startEvent = WebSpatialDragStartGuestureEvent(
|
|
119
|
+
detail: .init(
|
|
120
|
+
location3D: value.location3D,
|
|
121
|
+
startLocation3D: value.startLocation3D,
|
|
122
|
+
translation3D: value.translation3D,
|
|
123
|
+
predictedEndTranslation3D: value.predictedEndTranslation3D,
|
|
124
|
+
predictedEndLocation3D: value.predictedEndLocation3D,
|
|
125
|
+
velocity: value.velocity
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
spatialScene.sendWebMsg(entity.spatialId, startEvent)
|
|
129
|
+
isDrag = true
|
|
130
|
+
} else {
|
|
131
|
+
let gestureEvent = WebSpatialDragGuestureEvent(
|
|
132
|
+
detail: .init(
|
|
133
|
+
location3D: value.location3D,
|
|
134
|
+
startLocation3D: value.startLocation3D,
|
|
135
|
+
translation3D: value.translation3D,
|
|
136
|
+
predictedEndTranslation3D: value.predictedEndTranslation3D,
|
|
137
|
+
predictedEndLocation3D: value.predictedEndLocation3D,
|
|
138
|
+
velocity: value.velocity
|
|
139
|
+
)
|
|
140
|
+
)
|
|
141
|
+
spatialScene.sendWebMsg(entity.spatialId, gestureEvent)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}.onEnded { value in
|
|
145
|
+
// Always forward drag end event to JS
|
|
146
|
+
if let entity = value.entity as? SpatialEntity {
|
|
147
|
+
let gestureEvent = WebSpatialDragEndGuestureEvent(
|
|
148
|
+
detail: .init(
|
|
149
|
+
location3D: value.location3D,
|
|
150
|
+
startLocation3D: value.startLocation3D,
|
|
151
|
+
translation3D: value.translation3D,
|
|
152
|
+
predictedEndTranslation3D: value.predictedEndTranslation3D,
|
|
153
|
+
predictedEndLocation3D: value.predictedEndLocation3D,
|
|
154
|
+
velocity: value.velocity
|
|
155
|
+
)
|
|
156
|
+
)
|
|
157
|
+
spatialScene.sendWebMsg(entity.spatialId, gestureEvent)
|
|
158
|
+
}
|
|
159
|
+
isDrag = false
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
var body: some View {
|
|
164
|
+
RealityView(make: { content in
|
|
165
|
+
let rootEntity = spatializedDynamic3DElement.getRoot()
|
|
166
|
+
content.add(rootEntity)
|
|
167
|
+
})
|
|
168
|
+
.simultaneousGesture(spatialTapEvent)
|
|
169
|
+
.simultaneousGesture(rotate3dEvent)
|
|
170
|
+
.simultaneousGesture(dragEvent)
|
|
171
|
+
.simultaneousGesture(magnifyEvent)
|
|
172
|
+
}
|
|
173
|
+
}
|