bilca commited on
Commit
b111d6e
·
verified ·
1 Parent(s): e5dd3f5

Update index_sans_gif.js

Browse files
Files changed (1) hide show
  1. index_sans_gif.js +50 -107
index_sans_gif.js CHANGED
@@ -24,11 +24,18 @@
24
 
25
  // Generate a unique identifier for this widget instance.
26
  const instanceId = Math.random().toString(36).substr(2, 8);
27
-
28
- // Read required URLs from the config.
29
- var gifUrl = config.gif_url;
30
  var plyUrl = config.ply_url;
31
-
 
 
 
 
 
 
 
32
  // Determine the aspect ratio.
33
  // Default aspect: 1:1 (i.e. 100% padding-bottom)
34
  var aspectPercent = "100%";
@@ -47,6 +54,7 @@
47
  }
48
  }
49
  } else {
 
50
  var parentContainer = scriptTag.parentNode;
51
  var containerWidth = parentContainer.offsetWidth;
52
  var containerHeight = parentContainer.offsetHeight;
@@ -54,16 +62,10 @@
54
  aspectPercent = (containerHeight / containerWidth * 100) + "%";
55
  }
56
  }
57
-
58
- // Optional parameters for zoom and rotation limits.
59
- var minZoom = parseFloat(config.minZoom || "0");
60
- var maxZoom = parseFloat(config.maxZoom || "20");
61
- var minAngle = parseFloat(config.minAngle || "0");
62
- var maxAngle = parseFloat(config.maxAngle || "360");
63
-
64
  // Detect if the device is iOS.
65
  var isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
66
-
67
  // Inject CSS styles into the document head, scoped with the unique id.
68
  var styleEl = document.createElement('style');
69
  styleEl.textContent = `
@@ -84,26 +86,10 @@
84
  padding-bottom: 0 !important;
85
  z-index: 9999 !important;
86
  }
87
- /* GIF Preview styling */
88
- #gif-preview-container-${instanceId} {
89
- position: absolute;
90
- top: 0;
91
- left: 0;
92
- width: 100%;
93
- height: 100%;
94
- border: 1px solid #474558;
95
- border-radius: 10px;
96
- overflow: hidden;
97
- cursor: pointer;
98
- }
99
- #gif-preview-container-${instanceId} img {
100
- width: 100%;
101
- height: 100%;
102
- object-fit: cover;
103
- }
104
  /* Viewer Container styling */
105
  #viewer-container-${instanceId} {
106
- display: none;
 
107
  position: absolute;
108
  top: 0;
109
  left: 0;
@@ -119,7 +105,7 @@
119
  height: 100%;
120
  display: block;
121
  }
122
- /* Progress dialog styling */
123
  #progress-dialog-${instanceId} {
124
  position: absolute;
125
  top: 50%;
@@ -132,7 +118,7 @@
132
  z-index: 1000;
133
  display: none;
134
  }
135
- /* Menu content styling */
136
  #menu-content-${instanceId} {
137
  display: none;
138
  position: absolute;
@@ -161,11 +147,8 @@
161
  align-items: center;
162
  justify-content: center;
163
  }
164
- /* Positions: Close at top-left, fullscreen at top-right, help (instructions) below fullscreen */
165
- #close-btn-${instanceId} {
166
- top: 17px;
167
- left: 15px;
168
- }
169
  #fullscreen-toggle-${instanceId} {
170
  top: 17px;
171
  right: 15px;
@@ -174,37 +157,34 @@
174
  top: 72px;
175
  right: 15px;
176
  }
177
- /* Reset Camera Button below the help button */
178
  #reset-camera-btn-${instanceId} {
179
  top: 127px;
180
  right: 15px;
 
 
 
181
  }
 
182
  .reset-icon {
183
  display: inline-block;
184
- transform: translateY(-3px);
185
  }
186
  `;
187
  document.head.appendChild(styleEl);
188
-
189
  // Create the widget container and set its inner HTML.
190
  var widgetContainer = document.createElement('div');
191
  widgetContainer.id = 'ply-widget-container-' + instanceId;
192
  widgetContainer.innerHTML = `
193
- <!-- GIF Preview Container -->
194
- <div id="gif-preview-container-${instanceId}">
195
- <img id="preview-image-${instanceId}" alt="Preview" crossorigin="anonymous">
196
- </div>
197
- <!-- Viewer Container -->
198
  <div id="viewer-container-${instanceId}">
199
  <canvas id="canvas-${instanceId}"></canvas>
200
  <div id="progress-dialog-${instanceId}">
201
  <progress id="progress-indicator-${instanceId}" max="100" value="0"></progress>
202
  </div>
203
- <button id="close-btn-${instanceId}" class="widget-button">X</button>
204
  <button id="fullscreen-toggle-${instanceId}" class="widget-button">⇱</button>
205
  <button id="help-toggle-${instanceId}" class="widget-button">?</button>
206
  <button id="reset-camera-btn-${instanceId}" class="widget-button">
207
- <span class="reset-icon">🗘</span>
208
  </button>
209
  <div id="menu-content-${instanceId}">
210
  - Rotate with right click<br>
@@ -214,12 +194,9 @@
214
  </div>
215
  `;
216
  scriptTag.parentNode.appendChild(widgetContainer);
217
-
218
- // Grab element references.
219
- var gifPreview = document.getElementById('gif-preview-container-' + instanceId);
220
  var viewerContainer = document.getElementById('viewer-container-' + instanceId);
221
- var previewImage = document.getElementById('preview-image-' + instanceId);
222
- var closeBtn = document.getElementById('close-btn-' + instanceId);
223
  var fullscreenToggle = document.getElementById('fullscreen-toggle-' + instanceId);
224
  var helpToggle = document.getElementById('help-toggle-' + instanceId);
225
  var resetCameraBtn = document.getElementById('reset-camera-btn-' + instanceId);
@@ -227,34 +204,16 @@
227
  var canvas = document.getElementById('canvas-' + instanceId);
228
  var progressDialog = document.getElementById('progress-dialog-' + instanceId);
229
  var progressIndicator = document.getElementById('progress-indicator-' + instanceId);
230
-
231
- // Set the preview image if provided.
232
- if (gifUrl) {
233
- previewImage.src = gifUrl;
234
- }
235
-
236
  // --- Button Event Handlers ---
237
-
238
- gifPreview.addEventListener('click', function() {
239
- gifPreview.style.display = 'none';
240
- viewerContainer.style.display = 'block';
241
- initializeViewer();
242
- });
243
-
244
- closeBtn.addEventListener('click', function() {
245
- if (document.fullscreenElement === widgetContainer) {
246
- if (document.exitFullscreen) {
247
- document.exitFullscreen();
248
- }
249
- }
250
- widgetContainer.classList.remove('fake-fullscreen');
251
- viewerContainer.style.display = 'none';
252
- gifPreview.style.display = 'block';
253
- });
254
-
255
  fullscreenToggle.addEventListener('click', function() {
256
  if (isIOS) {
257
- widgetContainer.classList.toggle('fake-fullscreen');
 
 
 
 
258
  fullscreenToggle.textContent = widgetContainer.classList.contains('fake-fullscreen') ? '⇲' : '⇱';
259
  } else {
260
  if (!document.fullscreenElement) {
@@ -274,7 +233,7 @@
274
  }
275
  }
276
  });
277
-
278
  document.addEventListener('fullscreenchange', function() {
279
  if (document.fullscreenElement === widgetContainer) {
280
  fullscreenToggle.textContent = '⇲';
@@ -282,12 +241,12 @@
282
  fullscreenToggle.textContent = '⇱';
283
  }
284
  });
285
-
286
  helpToggle.addEventListener('click', function(e) {
287
  e.stopPropagation();
288
  menuContent.style.display = (menuContent.style.display === 'block') ? 'none' : 'block';
289
  });
290
-
291
  resetCameraBtn.addEventListener('click', function() {
292
  console.log("Reset camera button clicked.");
293
  if (cameraInstance && initialCameraPosition && initialCameraRotation) {
@@ -301,48 +260,29 @@
301
  }
302
  }
303
  });
304
-
305
  // --- Initialize the 3D PLY Viewer ---
306
  async function initializeViewer() {
307
  const SPLAT = await import("https://cdn.jsdelivr.net/npm/gsplat@latest");
308
  progressDialog.style.display = 'block';
309
  const renderer = new SPLAT.WebGLRenderer(canvas);
310
  const scene = new SPLAT.Scene();
311
- // Create the camera instance.
312
  const camera = new SPLAT.Camera();
313
-
314
- // If the config provides a camera position, update the camera.
315
- if (config.cameraPosition) {
316
- if (Array.isArray(config.cameraPosition) && config.cameraPosition.length === 3) {
317
- camera.position.set(
318
- config.cameraPosition[0],
319
- config.cameraPosition[1],
320
- config.cameraPosition[2]
321
- );
322
- } else if (typeof config.cameraPosition === 'object') {
323
- camera.position.set(
324
- config.cameraPosition.x,
325
- config.cameraPosition.y,
326
- config.cameraPosition.z
327
- );
328
- }
329
- }
330
-
331
  const controls = new SPLAT.OrbitControls(camera, canvas);
332
-
333
  cameraInstance = camera;
334
  controlsInstance = controls;
335
  initialCameraPosition = camera.position.clone();
336
  initialCameraRotation = camera.rotation.clone();
337
-
338
  canvas.style.background = "#FEFEFD";
339
  controls.maxZoom = maxZoom;
340
  controls.minZoom = minZoom;
341
  controls.minAngle = minAngle;
342
  controls.maxAngle = maxAngle;
343
-
344
  controls.update();
345
-
346
  try {
347
  await SPLAT.PLYLoader.LoadAsync(
348
  plyUrl,
@@ -356,19 +296,22 @@
356
  console.error("Error loading PLY file:", error);
357
  progressDialog.innerHTML = `<p style="color: red">Error loading model: ${error.message}</p>`;
358
  }
359
-
360
  const frame = () => {
361
  controls.update();
362
  renderer.render(scene, camera);
363
  requestAnimationFrame(frame);
364
  };
365
-
366
  const handleResize = () => {
367
  renderer.setSize(canvas.clientWidth, canvas.clientHeight);
368
  };
369
-
370
  handleResize();
371
  window.addEventListener("resize", handleResize);
372
  requestAnimationFrame(frame);
373
  }
 
 
 
374
  })();
 
24
 
25
  // Generate a unique identifier for this widget instance.
26
  const instanceId = Math.random().toString(36).substr(2, 8);
27
+
28
+ // Read required URLs and parameters from the config.
29
+ // The gifUrl is no longer used.
30
  var plyUrl = config.ply_url;
31
+
32
+ // Optional parameters for zoom and rotation limits.
33
+ // Defaults: zoom from 0 to 20; rotation from 0 to 360.
34
+ var minZoom = parseFloat(config.minZoom || "0");
35
+ var maxZoom = parseFloat(config.maxZoom || "20");
36
+ var minAngle = parseFloat(config.minAngle || "0");
37
+ var maxAngle = parseFloat(config.maxAngle || "360");
38
+
39
  // Determine the aspect ratio.
40
  // Default aspect: 1:1 (i.e. 100% padding-bottom)
41
  var aspectPercent = "100%";
 
54
  }
55
  }
56
  } else {
57
+ // If no aspect parameter is provided, compute the aspect ratio from the parent element.
58
  var parentContainer = scriptTag.parentNode;
59
  var containerWidth = parentContainer.offsetWidth;
60
  var containerHeight = parentContainer.offsetHeight;
 
62
  aspectPercent = (containerHeight / containerWidth * 100) + "%";
63
  }
64
  }
65
+
 
 
 
 
 
 
66
  // Detect if the device is iOS.
67
  var isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
68
+
69
  // Inject CSS styles into the document head, scoped with the unique id.
70
  var styleEl = document.createElement('style');
71
  styleEl.textContent = `
 
86
  padding-bottom: 0 !important;
87
  z-index: 9999 !important;
88
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  /* Viewer Container styling */
90
  #viewer-container-${instanceId} {
91
+ /* Display the viewer by default */
92
+ display: block;
93
  position: absolute;
94
  top: 0;
95
  left: 0;
 
105
  height: 100%;
106
  display: block;
107
  }
108
+ /* Progress dialog styling (as a centered div) */
109
  #progress-dialog-${instanceId} {
110
  position: absolute;
111
  top: 50%;
 
118
  z-index: 1000;
119
  display: none;
120
  }
121
+ /* Menu (instructions) content styling */
122
  #menu-content-${instanceId} {
123
  display: none;
124
  position: absolute;
 
147
  align-items: center;
148
  justify-content: center;
149
  }
150
+ /* Positions: fullscreen at top-right, help (instructions) below fullscreen,
151
+ and reset camera below help */
 
 
 
152
  #fullscreen-toggle-${instanceId} {
153
  top: 17px;
154
  right: 15px;
 
157
  top: 72px;
158
  right: 15px;
159
  }
 
160
  #reset-camera-btn-${instanceId} {
161
  top: 127px;
162
  right: 15px;
163
+ font-size: 22px;
164
+ line-height: 1;
165
+ padding: 0;
166
  }
167
+ /* Adjust the ⟲ icon position within the reset camera button */
168
  .reset-icon {
169
  display: inline-block;
 
170
  }
171
  `;
172
  document.head.appendChild(styleEl);
173
+
174
  // Create the widget container and set its inner HTML.
175
  var widgetContainer = document.createElement('div');
176
  widgetContainer.id = 'ply-widget-container-' + instanceId;
177
  widgetContainer.innerHTML = `
178
+ <!-- Viewer Container (displayed directly) -->
 
 
 
 
179
  <div id="viewer-container-${instanceId}">
180
  <canvas id="canvas-${instanceId}"></canvas>
181
  <div id="progress-dialog-${instanceId}">
182
  <progress id="progress-indicator-${instanceId}" max="100" value="0"></progress>
183
  </div>
 
184
  <button id="fullscreen-toggle-${instanceId}" class="widget-button">⇱</button>
185
  <button id="help-toggle-${instanceId}" class="widget-button">?</button>
186
  <button id="reset-camera-btn-${instanceId}" class="widget-button">
187
+ <span class="reset-icon">⟲</span>
188
  </button>
189
  <div id="menu-content-${instanceId}">
190
  - Rotate with right click<br>
 
194
  </div>
195
  `;
196
  scriptTag.parentNode.appendChild(widgetContainer);
197
+
198
+ // Grab element references using the unique IDs.
 
199
  var viewerContainer = document.getElementById('viewer-container-' + instanceId);
 
 
200
  var fullscreenToggle = document.getElementById('fullscreen-toggle-' + instanceId);
201
  var helpToggle = document.getElementById('help-toggle-' + instanceId);
202
  var resetCameraBtn = document.getElementById('reset-camera-btn-' + instanceId);
 
204
  var canvas = document.getElementById('canvas-' + instanceId);
205
  var progressDialog = document.getElementById('progress-dialog-' + instanceId);
206
  var progressIndicator = document.getElementById('progress-indicator-' + instanceId);
207
+
 
 
 
 
 
208
  // --- Button Event Handlers ---
209
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  fullscreenToggle.addEventListener('click', function() {
211
  if (isIOS) {
212
+ if (!widgetContainer.classList.contains('fake-fullscreen')) {
213
+ widgetContainer.classList.add('fake-fullscreen');
214
+ } else {
215
+ widgetContainer.classList.remove('fake-fullscreen');
216
+ }
217
  fullscreenToggle.textContent = widgetContainer.classList.contains('fake-fullscreen') ? '⇲' : '⇱';
218
  } else {
219
  if (!document.fullscreenElement) {
 
233
  }
234
  }
235
  });
236
+
237
  document.addEventListener('fullscreenchange', function() {
238
  if (document.fullscreenElement === widgetContainer) {
239
  fullscreenToggle.textContent = '⇲';
 
241
  fullscreenToggle.textContent = '⇱';
242
  }
243
  });
244
+
245
  helpToggle.addEventListener('click', function(e) {
246
  e.stopPropagation();
247
  menuContent.style.display = (menuContent.style.display === 'block') ? 'none' : 'block';
248
  });
249
+
250
  resetCameraBtn.addEventListener('click', function() {
251
  console.log("Reset camera button clicked.");
252
  if (cameraInstance && initialCameraPosition && initialCameraRotation) {
 
260
  }
261
  }
262
  });
263
+
264
  // --- Initialize the 3D PLY Viewer ---
265
  async function initializeViewer() {
266
  const SPLAT = await import("https://cdn.jsdelivr.net/npm/gsplat@latest");
267
  progressDialog.style.display = 'block';
268
  const renderer = new SPLAT.WebGLRenderer(canvas);
269
  const scene = new SPLAT.Scene();
 
270
  const camera = new SPLAT.Camera();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  const controls = new SPLAT.OrbitControls(camera, canvas);
272
+
273
  cameraInstance = camera;
274
  controlsInstance = controls;
275
  initialCameraPosition = camera.position.clone();
276
  initialCameraRotation = camera.rotation.clone();
277
+
278
  canvas.style.background = "#FEFEFD";
279
  controls.maxZoom = maxZoom;
280
  controls.minZoom = minZoom;
281
  controls.minAngle = minAngle;
282
  controls.maxAngle = maxAngle;
283
+
284
  controls.update();
285
+
286
  try {
287
  await SPLAT.PLYLoader.LoadAsync(
288
  plyUrl,
 
296
  console.error("Error loading PLY file:", error);
297
  progressDialog.innerHTML = `<p style="color: red">Error loading model: ${error.message}</p>`;
298
  }
299
+
300
  const frame = () => {
301
  controls.update();
302
  renderer.render(scene, camera);
303
  requestAnimationFrame(frame);
304
  };
305
+
306
  const handleResize = () => {
307
  renderer.setSize(canvas.clientWidth, canvas.clientHeight);
308
  };
309
+
310
  handleResize();
311
  window.addEventListener("resize", handleResize);
312
  requestAnimationFrame(frame);
313
  }
314
+
315
+ // Initialize the viewer immediately.
316
+ initializeViewer();
317
  })();