@webspatial/platform-visionos 1.0.4 → 1.0.5
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 +119 -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 +1042 -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 +104 -0
- package/web-spatial/view/SpatializedElementView.swift +178 -0
- package/web-spatial/view/SpatializedStatic3DView.swift +70 -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,104 @@
|
|
|
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
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
if let spatialEntity = SpatialEntity.findNearestParent(entity: value.entity){
|
|
23
|
+
spatialScene.sendWebMsg(spatialEntity.spatialId, WebSpatialTapGuestureEvent(detail: WebSpatialTapGuestureEventDetail(location3D: value.location3D)))
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
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
|
+
}
|
|
43
|
+
}
|
|
44
|
+
isRotate = false
|
|
45
|
+
}.onEnded{ value in
|
|
46
|
+
print(value.rotation)
|
|
47
|
+
print("rotate end")
|
|
48
|
+
// isRotate = false
|
|
49
|
+
}
|
|
50
|
+
}
|
|
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
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}.onEnded{ value in
|
|
68
|
+
print("scale end")
|
|
69
|
+
// isScale = false
|
|
70
|
+
}
|
|
71
|
+
}
|
|
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
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
}.onEnded{ value in
|
|
89
|
+
print("drag end")
|
|
90
|
+
// isDrag = false
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
var body: some View {
|
|
95
|
+
RealityView(make: { content in
|
|
96
|
+
let rootEntity = spatializedDynamic3DElement.getRoot()
|
|
97
|
+
content.add(rootEntity)
|
|
98
|
+
})
|
|
99
|
+
.simultaneousGesture(spatialTapEvent)
|
|
100
|
+
.simultaneousGesture(rotate3dEvent)
|
|
101
|
+
.simultaneousGesture(dragEvent)
|
|
102
|
+
.simultaneousGesture(magnifyEvent)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
|
|
3
|
+
// zIndex() have some bug, so use zOrderBias to simulate zIndex effect
|
|
4
|
+
let zOrderBias = 0.001
|
|
5
|
+
|
|
6
|
+
struct SpatializedElementView<Content: View>: View {
|
|
7
|
+
@Environment(SpatializedElement.self) var spatializedElement: SpatializedElement
|
|
8
|
+
@Environment(SpatialScene.self) var spatialScene: SpatialScene
|
|
9
|
+
|
|
10
|
+
var parentScrollOffset: Vec2
|
|
11
|
+
var content: Content
|
|
12
|
+
|
|
13
|
+
init(parentScrollOffset: Vec2, @ViewBuilder content: () -> Content) {
|
|
14
|
+
self.parentScrollOffset = parentScrollOffset
|
|
15
|
+
self.content = content()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Begin Interaction
|
|
19
|
+
var gesture: some Gesture {
|
|
20
|
+
DragGesture()
|
|
21
|
+
.onChanged(onDragging)
|
|
22
|
+
.onEnded(onDraggingEnded)
|
|
23
|
+
.simultaneously(with:
|
|
24
|
+
RotateGesture3D()
|
|
25
|
+
.onChanged(onRotateGesture3D)
|
|
26
|
+
.onEnded(onRotateGesture3DEnd)
|
|
27
|
+
)
|
|
28
|
+
.simultaneously(with:
|
|
29
|
+
MagnifyGesture()
|
|
30
|
+
.onChanged(onMagnifyGesture)
|
|
31
|
+
.onEnded(onMagnifyGestureEnd)
|
|
32
|
+
)
|
|
33
|
+
.simultaneously(with:
|
|
34
|
+
SpatialTapGesture(count: 1)
|
|
35
|
+
.onEnded(onTapEnded)
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private func onRotateGesture3D(_ event: RotateGesture3D.Value) {
|
|
40
|
+
if spatializedElement.enableRotateGesture || spatializedElement.enableRotateStartGesture {
|
|
41
|
+
let gestureEvent = WebSpatialRotateGuestureEvent(
|
|
42
|
+
detail: .init(
|
|
43
|
+
rotation: event.rotation,
|
|
44
|
+
startAnchor3D: event.startAnchor3D,
|
|
45
|
+
startLocation3D: event.startLocation3D
|
|
46
|
+
))
|
|
47
|
+
spatialScene.sendWebMsg(spatializedElement.id, gestureEvent)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private func onRotateGesture3DEnd(_ event: RotateGesture3D.Value) {
|
|
52
|
+
if spatializedElement.enableRotateEndGesture {
|
|
53
|
+
let gestureEvent = WebSpatialRotateEndGuestureEvent(
|
|
54
|
+
detail: .init(
|
|
55
|
+
rotation: event.rotation,
|
|
56
|
+
startAnchor3D: event.startAnchor3D,
|
|
57
|
+
startLocation3D: event.startLocation3D
|
|
58
|
+
))
|
|
59
|
+
spatialScene.sendWebMsg(spatializedElement.id, gestureEvent)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private func onDragging(_ event: DragGesture.Value) {
|
|
64
|
+
if spatializedElement.enableDragStartGesture || spatializedElement.enableDragGesture {
|
|
65
|
+
let gestureEvent = WebSpatialDragGuestureEvent(detail: .init(
|
|
66
|
+
location3D: event.location3D,
|
|
67
|
+
startLocation3D: event.startLocation3D,
|
|
68
|
+
translation3D: event.translation3D,
|
|
69
|
+
predictedEndTranslation3D: event.predictedEndTranslation3D,
|
|
70
|
+
predictedEndLocation3D: event.predictedEndLocation3D,
|
|
71
|
+
velocity: event.velocity
|
|
72
|
+
))
|
|
73
|
+
spatialScene.sendWebMsg(spatializedElement.id, gestureEvent)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private func onDraggingEnded(_ event: DragGesture.Value) {
|
|
78
|
+
if spatializedElement.enableDragEndGesture {
|
|
79
|
+
let gestureEvent = WebSpatialDragEndGuestureEvent(
|
|
80
|
+
detail: .init(
|
|
81
|
+
location3D: event.location3D,
|
|
82
|
+
startLocation3D: event.startLocation3D,
|
|
83
|
+
translation3D: event.translation3D,
|
|
84
|
+
predictedEndTranslation3D: event.predictedEndTranslation3D,
|
|
85
|
+
predictedEndLocation3D: event.predictedEndLocation3D,
|
|
86
|
+
velocity: event.velocity
|
|
87
|
+
))
|
|
88
|
+
spatialScene.sendWebMsg(spatializedElement.id, gestureEvent)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private func onTapEnded(_ event: SpatialTapGesture.Value) {
|
|
93
|
+
if spatializedElement.enableTapGesture {
|
|
94
|
+
spatialScene.sendWebMsg(spatializedElement.id, WebSpatialTapGuestureEvent(detail: .init(location3D: event.location3D)))
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private func onMagnifyGesture(_ event: MagnifyGesture.Value) {
|
|
99
|
+
if spatializedElement.enableMagnifyGesture || spatializedElement.enableMagnifyStartGesture {
|
|
100
|
+
let gestureEvent = WebSpatialMagnifyGuestureEvent(
|
|
101
|
+
detail: .init(
|
|
102
|
+
magnification: event.magnification,
|
|
103
|
+
velocity: event.velocity,
|
|
104
|
+
startLocation3D: event.startLocation3D,
|
|
105
|
+
startAnchor3D: event.startAnchor3D
|
|
106
|
+
))
|
|
107
|
+
spatialScene.sendWebMsg(spatializedElement.id, gestureEvent)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private func onMagnifyGestureEnd(_ event: MagnifyGesture.Value) {
|
|
112
|
+
if spatializedElement.enableMagnifyEndGesture {
|
|
113
|
+
let gestureEvent = WebSpatialMagnifyEndGuestureEvent(
|
|
114
|
+
detail: .init(
|
|
115
|
+
magnification: event.magnification,
|
|
116
|
+
velocity: event.velocity,
|
|
117
|
+
startLocation3D: event.startLocation3D,
|
|
118
|
+
startAnchor3D: event.startAnchor3D
|
|
119
|
+
))
|
|
120
|
+
spatialScene.sendWebMsg(spatializedElement.id, gestureEvent)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// End Interaction
|
|
125
|
+
|
|
126
|
+
@ViewBuilder
|
|
127
|
+
var body: some View {
|
|
128
|
+
let transform = spatializedElement.transform
|
|
129
|
+
let translation = transform.translation
|
|
130
|
+
let scale = transform.scale
|
|
131
|
+
let rotation = transform.rotation!
|
|
132
|
+
|
|
133
|
+
let width = spatializedElement.width
|
|
134
|
+
let height = spatializedElement.height
|
|
135
|
+
let depth = spatializedElement.depth
|
|
136
|
+
let anchor = spatializedElement.rotationAnchor
|
|
137
|
+
|
|
138
|
+
let centerX = spatializedElement.clientX - (spatializedElement.scrollWithParent ? parentScrollOffset.x : 0)
|
|
139
|
+
let centerY = spatializedElement.clientY - (spatializedElement.scrollWithParent ? parentScrollOffset.y : 0)
|
|
140
|
+
|
|
141
|
+
let opacity = spatializedElement.opacity
|
|
142
|
+
let visible = spatializedElement.visible
|
|
143
|
+
let enableGesture = spatializedElement.enableGesture
|
|
144
|
+
|
|
145
|
+
let z = translation.z + (spatializedElement.zIndex * zOrderBias)
|
|
146
|
+
let smallOffset = z == 0.0 ? 0.0001 : 0
|
|
147
|
+
|
|
148
|
+
content.simultaneousGesture(enableGesture ? gesture : nil)
|
|
149
|
+
.frame(width: width, height: height)
|
|
150
|
+
.frame(depth: depth, alignment: .back)
|
|
151
|
+
.onGeometryChange3D(for: AffineTransform3D.self) { proxy in
|
|
152
|
+
let rect3d = proxy.frame(in: .named("SpatialScene"))
|
|
153
|
+
spatialScene.sendWebMsg(spatializedElement.id, SpatiaizedContainerClientCube(origin: rect3d.origin, size: rect3d.size))
|
|
154
|
+
return proxy.transform(in: .named("SpatialScene"))!
|
|
155
|
+
} action: { _, new in
|
|
156
|
+
spatialScene.sendWebMsg(spatializedElement.id, SpatiaizedContainerTransform(detail: new))
|
|
157
|
+
}
|
|
158
|
+
.frame(depth: 0, alignment: .back)
|
|
159
|
+
// use .offset(smallVal) to workaround for glassEffect not working and small width/height spatialDiv not working
|
|
160
|
+
.offset(z: smallOffset)
|
|
161
|
+
.scaleEffect(
|
|
162
|
+
x: scale.width,
|
|
163
|
+
y: scale.height,
|
|
164
|
+
z: scale.depth,
|
|
165
|
+
anchor: anchor
|
|
166
|
+
)
|
|
167
|
+
.rotation3DEffect(
|
|
168
|
+
rotation,
|
|
169
|
+
anchor: anchor
|
|
170
|
+
)
|
|
171
|
+
.offset(x: translation.x, y: translation.y)
|
|
172
|
+
.offset(z: z)
|
|
173
|
+
.position(x: centerX + width / 2, y: centerY + height / 2)
|
|
174
|
+
.offset(z: spatializedElement.backOffset)
|
|
175
|
+
.opacity(opacity)
|
|
176
|
+
.hidden(!visible)
|
|
177
|
+
}
|
|
178
|
+
}
|