Spaces:
Running
Running
Update index.js
Browse files
index.js
CHANGED
@@ -11,6 +11,15 @@
|
|
11 |
return params.get(param);
|
12 |
}
|
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
// Inject CSS styles into the document head.
|
15 |
var styleEl = document.createElement('style');
|
16 |
styleEl.textContent = `
|
@@ -67,11 +76,11 @@
|
|
67 |
padding: 20px;
|
68 |
border-radius: 5px;
|
69 |
}
|
70 |
-
/* Menu (
|
71 |
#menu-content {
|
72 |
display: none;
|
73 |
position: absolute;
|
74 |
-
top:
|
75 |
right: 15px;
|
76 |
background: #FFFEF4;
|
77 |
border: 1px solid #474558;
|
@@ -96,14 +105,19 @@
|
|
96 |
align-items: center;
|
97 |
justify-content: center;
|
98 |
}
|
|
|
99 |
#close-btn {
|
100 |
top: 17px;
|
101 |
left: 15px;
|
102 |
}
|
103 |
-
#
|
104 |
top: 17px;
|
105 |
right: 15px;
|
106 |
}
|
|
|
|
|
|
|
|
|
107 |
`;
|
108 |
document.head.appendChild(styleEl);
|
109 |
|
@@ -122,7 +136,8 @@
|
|
122 |
<progress id="progress-indicator" max="100" value="0"></progress>
|
123 |
</dialog>
|
124 |
<button id="close-btn" class="widget-button">X</button>
|
125 |
-
<button id="
|
|
|
126 |
<div id="menu-content">
|
127 |
- Rotate with right click<br>
|
128 |
- Zoom in/out with middle click<br>
|
@@ -130,7 +145,7 @@
|
|
130 |
</div>
|
131 |
</div>
|
132 |
`;
|
133 |
-
// Append widgetContainer to the current script's parent
|
134 |
document.currentScript.parentNode.appendChild(widgetContainer);
|
135 |
|
136 |
// Grab element references.
|
@@ -138,20 +153,20 @@
|
|
138 |
var viewerContainer = document.getElementById('viewer-container');
|
139 |
var previewImage = document.getElementById('preview-image');
|
140 |
var closeBtn = document.getElementById('close-btn');
|
141 |
-
var
|
|
|
142 |
var menuContent = document.getElementById('menu-content');
|
143 |
var canvas = document.getElementById('canvas');
|
144 |
var progressDialog = document.getElementById('progress-dialog');
|
145 |
var progressIndicator = document.getElementById('progress-indicator');
|
146 |
|
147 |
-
//
|
148 |
-
var gifUrl = getScriptQueryParam("gif_url");
|
149 |
-
var plyUrl = getScriptQueryParam("ply_url");
|
150 |
-
|
151 |
if (gifUrl) {
|
152 |
previewImage.src = gifUrl;
|
153 |
}
|
154 |
|
|
|
|
|
155 |
// When the preview image is clicked, hide it, show the viewer, and initialize the 3D viewer.
|
156 |
gifPreview.addEventListener('click', function() {
|
157 |
gifPreview.style.display = 'none';
|
@@ -159,19 +174,53 @@
|
|
159 |
initializeViewer();
|
160 |
});
|
161 |
|
162 |
-
// Close button
|
163 |
closeBtn.addEventListener('click', function() {
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
viewerContainer.style.display = 'none';
|
165 |
gifPreview.style.display = 'block';
|
166 |
});
|
167 |
|
168 |
-
//
|
169 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
170 |
e.stopPropagation();
|
171 |
menuContent.style.display = (menuContent.style.display === 'block') ? 'none' : 'block';
|
172 |
});
|
173 |
|
174 |
-
// Initialize the 3D PLY
|
175 |
async function initializeViewer() {
|
176 |
// Dynamically import the gsplat library.
|
177 |
const SPLAT = await import("https://cdn.jsdelivr.net/npm/gsplat@latest");
|
@@ -183,14 +232,14 @@
|
|
183 |
const controls = new SPLAT.OrbitControls(camera, canvas);
|
184 |
|
185 |
canvas.style.background = "#FEFEFD";
|
186 |
-
controls.maxZoom =
|
187 |
-
controls.minZoom =
|
188 |
-
controls.minAngle =
|
189 |
-
controls.maxAngle =
|
190 |
|
191 |
controls.update();
|
192 |
|
193 |
-
// Load the PLY model from the provided URL
|
194 |
try {
|
195 |
await SPLAT.PLYLoader.LoadAsync(
|
196 |
plyUrl,
|
@@ -199,7 +248,7 @@
|
|
199 |
progressIndicator.value = progress * 100;
|
200 |
}
|
201 |
);
|
202 |
-
//
|
203 |
if (typeof progressDialog.close === 'function') {
|
204 |
progressDialog.close();
|
205 |
} else {
|
|
|
11 |
return params.get(param);
|
12 |
}
|
13 |
|
14 |
+
// Read required URLs and optional limits from the query parameters.
|
15 |
+
var gifUrl = getScriptQueryParam("gif_url");
|
16 |
+
var plyUrl = getScriptQueryParam("ply_url");
|
17 |
+
// Optional parameters for zoom and angle limits:
|
18 |
+
var minZoom = parseFloat(getScriptQueryParam("minZoom")) || 1.5;
|
19 |
+
var maxZoom = parseFloat(getScriptQueryParam("maxZoom")) || 5;
|
20 |
+
var minAngle = parseFloat(getScriptQueryParam("minAngle")) || 0;
|
21 |
+
var maxAngle = parseFloat(getScriptQueryParam("maxAngle")) || 90;
|
22 |
+
|
23 |
// Inject CSS styles into the document head.
|
24 |
var styleEl = document.createElement('style');
|
25 |
styleEl.textContent = `
|
|
|
76 |
padding: 20px;
|
77 |
border-radius: 5px;
|
78 |
}
|
79 |
+
/* Menu (instructions) content styling */
|
80 |
#menu-content {
|
81 |
display: none;
|
82 |
position: absolute;
|
83 |
+
top: 72px;
|
84 |
right: 15px;
|
85 |
background: #FFFEF4;
|
86 |
border: 1px solid #474558;
|
|
|
105 |
align-items: center;
|
106 |
justify-content: center;
|
107 |
}
|
108 |
+
/* Positions: Close at top-left, fullscreen at top-right, help (instructions) below fullscreen */
|
109 |
#close-btn {
|
110 |
top: 17px;
|
111 |
left: 15px;
|
112 |
}
|
113 |
+
#fullscreen-toggle {
|
114 |
top: 17px;
|
115 |
right: 15px;
|
116 |
}
|
117 |
+
#help-toggle {
|
118 |
+
top: 72px;
|
119 |
+
right: 15px;
|
120 |
+
}
|
121 |
`;
|
122 |
document.head.appendChild(styleEl);
|
123 |
|
|
|
136 |
<progress id="progress-indicator" max="100" value="0"></progress>
|
137 |
</dialog>
|
138 |
<button id="close-btn" class="widget-button">X</button>
|
139 |
+
<button id="fullscreen-toggle" class="widget-button">⇱</button>
|
140 |
+
<button id="help-toggle" class="widget-button">?</button>
|
141 |
<div id="menu-content">
|
142 |
- Rotate with right click<br>
|
143 |
- Zoom in/out with middle click<br>
|
|
|
145 |
</div>
|
146 |
</div>
|
147 |
`;
|
148 |
+
// Append widgetContainer to the current script's parent so it appears in place.
|
149 |
document.currentScript.parentNode.appendChild(widgetContainer);
|
150 |
|
151 |
// Grab element references.
|
|
|
153 |
var viewerContainer = document.getElementById('viewer-container');
|
154 |
var previewImage = document.getElementById('preview-image');
|
155 |
var closeBtn = document.getElementById('close-btn');
|
156 |
+
var fullscreenToggle = document.getElementById('fullscreen-toggle');
|
157 |
+
var helpToggle = document.getElementById('help-toggle');
|
158 |
var menuContent = document.getElementById('menu-content');
|
159 |
var canvas = document.getElementById('canvas');
|
160 |
var progressDialog = document.getElementById('progress-dialog');
|
161 |
var progressIndicator = document.getElementById('progress-indicator');
|
162 |
|
163 |
+
// Set the preview image if provided.
|
|
|
|
|
|
|
164 |
if (gifUrl) {
|
165 |
previewImage.src = gifUrl;
|
166 |
}
|
167 |
|
168 |
+
// --- Button Event Handlers ---
|
169 |
+
|
170 |
// When the preview image is clicked, hide it, show the viewer, and initialize the 3D viewer.
|
171 |
gifPreview.addEventListener('click', function() {
|
172 |
gifPreview.style.display = 'none';
|
|
|
174 |
initializeViewer();
|
175 |
});
|
176 |
|
177 |
+
// Close button: hide the viewer and show the preview.
|
178 |
closeBtn.addEventListener('click', function() {
|
179 |
+
// Exit fullscreen if active.
|
180 |
+
if (document.fullscreenElement === widgetContainer) {
|
181 |
+
if (document.exitFullscreen) {
|
182 |
+
document.exitFullscreen();
|
183 |
+
}
|
184 |
+
}
|
185 |
viewerContainer.style.display = 'none';
|
186 |
gifPreview.style.display = 'block';
|
187 |
});
|
188 |
|
189 |
+
// Fullscreen toggle: toggle fullscreen on the widget container.
|
190 |
+
fullscreenToggle.addEventListener('click', function() {
|
191 |
+
if (!document.fullscreenElement) {
|
192 |
+
if (widgetContainer.requestFullscreen) {
|
193 |
+
widgetContainer.requestFullscreen();
|
194 |
+
} else if (widgetContainer.webkitRequestFullscreen) {
|
195 |
+
widgetContainer.webkitRequestFullscreen();
|
196 |
+
} else if (widgetContainer.mozRequestFullScreen) {
|
197 |
+
widgetContainer.mozRequestFullScreen();
|
198 |
+
} else if (widgetContainer.msRequestFullscreen) {
|
199 |
+
widgetContainer.msRequestFullscreen();
|
200 |
+
}
|
201 |
+
} else {
|
202 |
+
if (document.exitFullscreen) {
|
203 |
+
document.exitFullscreen();
|
204 |
+
}
|
205 |
+
}
|
206 |
+
});
|
207 |
+
|
208 |
+
// Update the fullscreen button icon on fullscreen change.
|
209 |
+
document.addEventListener('fullscreenchange', function() {
|
210 |
+
if (document.fullscreenElement === widgetContainer) {
|
211 |
+
fullscreenToggle.textContent = '⇲';
|
212 |
+
} else {
|
213 |
+
fullscreenToggle.textContent = '⇱';
|
214 |
+
}
|
215 |
+
});
|
216 |
+
|
217 |
+
// Help (instructions) toggle: show/hide the instructions.
|
218 |
+
helpToggle.addEventListener('click', function(e) {
|
219 |
e.stopPropagation();
|
220 |
menuContent.style.display = (menuContent.style.display === 'block') ? 'none' : 'block';
|
221 |
});
|
222 |
|
223 |
+
// --- Initialize the 3D PLY Viewer ---
|
224 |
async function initializeViewer() {
|
225 |
// Dynamically import the gsplat library.
|
226 |
const SPLAT = await import("https://cdn.jsdelivr.net/npm/gsplat@latest");
|
|
|
232 |
const controls = new SPLAT.OrbitControls(camera, canvas);
|
233 |
|
234 |
canvas.style.background = "#FEFEFD";
|
235 |
+
controls.maxZoom = maxZoom;
|
236 |
+
controls.minZoom = minZoom;
|
237 |
+
controls.minAngle = minAngle;
|
238 |
+
controls.maxAngle = maxAngle;
|
239 |
|
240 |
controls.update();
|
241 |
|
242 |
+
// Load the PLY model from the provided URL.
|
243 |
try {
|
244 |
await SPLAT.PLYLoader.LoadAsync(
|
245 |
plyUrl,
|
|
|
248 |
progressIndicator.value = progress * 100;
|
249 |
}
|
250 |
);
|
251 |
+
// Hide the progress dialog when done.
|
252 |
if (typeof progressDialog.close === 'function') {
|
253 |
progressDialog.close();
|
254 |
} else {
|