bilca commited on
Commit
06c7831
·
verified ·
1 Parent(s): db46978

Update index_sans_gif.js

Browse files
Files changed (1) hide show
  1. index_sans_gif.js +139 -44
index_sans_gif.js CHANGED
@@ -1,9 +1,14 @@
1
  (function() {
 
2
  let cameraInstance = null;
3
  let controlsInstance = null;
4
  let initialCameraPosition = null;
5
  let initialCameraRotation = null;
 
 
 
6
 
 
7
  function getScriptQueryParam(param) {
8
  var params = new URLSearchParams("");
9
  if (document.currentScript && document.currentScript.src.indexOf('?') !== -1) {
@@ -15,40 +20,74 @@
15
  return params.get(param);
16
  }
17
 
 
 
18
  var plyUrl = getScriptQueryParam("ply_url");
 
 
 
19
  var minZoom = parseFloat(getScriptQueryParam("minZoom") || "0");
20
  var maxZoom = parseFloat(getScriptQueryParam("maxZoom") || "20");
21
  var minAngle = parseFloat(getScriptQueryParam("minAngle") || "0");
22
  var maxAngle = parseFloat(getScriptQueryParam("maxAngle") || "360");
 
 
23
  var isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
24
 
 
25
  var styleEl = document.createElement('style');
26
  styleEl.textContent = `
27
- #viewer-container {
 
28
  position: relative;
29
  width: 100%;
30
- height: 100vh;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  background: #FEFEFD;
32
  border: 1px solid #474558;
33
  border-radius: 10px;
34
  }
35
- #canvas {
 
36
  width: 100%;
37
  height: 100%;
38
  display: block;
39
  }
40
- #progress-dialog {
 
41
  position: absolute;
42
  top: 50%;
43
  left: 50%;
44
  transform: translate(-50%, -50%);
 
45
  background: rgba(255,255,255,0.9);
46
  padding: 20px;
47
  border-radius: 5px;
48
  z-index: 1000;
49
  display: none;
50
  }
51
- #menu-content {
 
52
  display: none;
53
  position: absolute;
54
  top: 62px;
@@ -61,6 +100,7 @@
61
  line-height: 1.4;
62
  color: #474558;
63
  }
 
64
  .widget-button {
65
  position: absolute;
66
  width: 45px;
@@ -75,69 +115,112 @@
75
  align-items: center;
76
  justify-content: center;
77
  }
78
- #fullscreen-toggle { top: 17px; right: 15px; }
79
- #help-toggle { top: 72px; right: 15px; }
80
- #reset-camera-btn { top: 127px; right: 15px; }
 
 
 
 
 
 
 
 
 
 
 
81
  `;
82
  document.head.appendChild(styleEl);
83
 
84
- var viewerContainer = document.createElement('div');
85
- viewerContainer.id = 'viewer-container';
86
- viewerContainer.innerHTML = `
87
- <canvas id="canvas"></canvas>
88
- <div id="progress-dialog">
89
- <progress id="progress-indicator" max="100" value="0"></progress>
90
- </div>
91
- <button id="fullscreen-toggle" class="widget-button">⇱</button>
92
- <button id="help-toggle" class="widget-button">?</button>
93
- <button id="reset-camera-btn" class="widget-button">⟲</button>
94
- <div id="menu-content">
95
- - Rotate with right click<br>
96
- - Zoom in/out with middle click<br>
97
- - Translate with left click
 
 
 
 
98
  </div>
99
  `;
100
- document.currentScript.parentNode.appendChild(viewerContainer);
101
 
102
- var fullscreenToggle = document.getElementById('fullscreen-toggle');
103
- var helpToggle = document.getElementById('help-toggle');
104
- var resetCameraBtn = document.getElementById('reset-camera-btn');
105
- var menuContent = document.getElementById('menu-content');
106
- var canvas = document.getElementById('canvas');
107
- var progressDialog = document.getElementById('progress-dialog');
108
- var progressIndicator = document.getElementById('progress-indicator');
 
 
 
 
109
 
110
  fullscreenToggle.addEventListener('click', function() {
111
  if (isIOS) {
112
- viewerContainer.classList.toggle('fake-fullscreen');
113
- fullscreenToggle.textContent = viewerContainer.classList.contains('fake-fullscreen') ? '⇲' : '⇱';
 
 
 
 
114
  } else {
115
  if (!document.fullscreenElement) {
116
- viewerContainer.requestFullscreen();
 
 
 
 
 
 
 
 
117
  } else {
118
- document.exitFullscreen();
 
 
119
  }
120
  }
121
  });
122
 
123
  document.addEventListener('fullscreenchange', function() {
124
- fullscreenToggle.textContent = document.fullscreenElement ? '⇲' : '⇱';
 
 
 
 
125
  });
126
 
127
  helpToggle.addEventListener('click', function(e) {
128
  e.stopPropagation();
129
- menuContent.style.display = menuContent.style.display === 'block' ? 'none' : 'block';
130
  });
131
 
132
  resetCameraBtn.addEventListener('click', function() {
 
133
  if (cameraInstance && initialCameraPosition && initialCameraRotation) {
134
- cameraInstance.position.copy(initialCameraPosition);
135
- cameraInstance.rotation.copy(initialCameraRotation);
136
- if (typeof cameraInstance.update === 'function') cameraInstance.update();
137
- if (controlsInstance && typeof controlsInstance.update === 'function') controlsInstance.update();
 
 
 
 
138
  }
139
  });
140
 
 
141
  async function initializeViewer() {
142
  const SPLAT = await import("https://cdn.jsdelivr.net/npm/gsplat@latest");
143
  progressDialog.style.display = 'block';
@@ -156,12 +239,17 @@
156
  controls.minZoom = minZoom;
157
  controls.minAngle = minAngle;
158
  controls.maxAngle = maxAngle;
 
159
  controls.update();
160
 
161
  try {
162
- await SPLAT.PLYLoader.LoadAsync(plyUrl, scene, (progress) => {
163
- progressIndicator.value = progress * 100;
164
- });
 
 
 
 
165
  progressDialog.style.display = 'none';
166
  } catch (error) {
167
  console.error("Error loading PLY file:", error);
@@ -174,8 +262,15 @@
174
  requestAnimationFrame(frame);
175
  };
176
 
177
- window.addEventListener("resize", () => renderer.setSize(canvas.clientWidth, canvas.clientHeight));
 
 
 
 
 
178
  requestAnimationFrame(frame);
179
  }
 
 
180
  initializeViewer();
181
  })();
 
1
  (function() {
2
+ // --- Outer scope variables for camera state ---
3
  let cameraInstance = null;
4
  let controlsInstance = null;
5
  let initialCameraPosition = null;
6
  let initialCameraRotation = null;
7
+
8
+ // Generate a unique identifier for this widget instance.
9
+ const instanceId = Math.random().toString(36).substr(2, 8);
10
 
11
+ // Helper: Get query parameters from THIS script’s src URL.
12
  function getScriptQueryParam(param) {
13
  var params = new URLSearchParams("");
14
  if (document.currentScript && document.currentScript.src.indexOf('?') !== -1) {
 
20
  return params.get(param);
21
  }
22
 
23
+ // Read required URLs.
24
+ // The gifUrl is no longer used.
25
  var plyUrl = getScriptQueryParam("ply_url");
26
+
27
+ // Optional parameters for zoom and rotation limits.
28
+ // Defaults: zoom from 0 to 20; rotation from 0 to 360.
29
  var minZoom = parseFloat(getScriptQueryParam("minZoom") || "0");
30
  var maxZoom = parseFloat(getScriptQueryParam("maxZoom") || "20");
31
  var minAngle = parseFloat(getScriptQueryParam("minAngle") || "0");
32
  var maxAngle = parseFloat(getScriptQueryParam("maxAngle") || "360");
33
+
34
+ // Detect if the device is iOS.
35
  var isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
36
 
37
+ // Inject CSS styles into the document head, scoped with the unique id.
38
  var styleEl = document.createElement('style');
39
  styleEl.textContent = `
40
+ /* Widget container styling */
41
+ #ply-widget-container-${instanceId} {
42
  position: relative;
43
  width: 100%;
44
+ height: 0;
45
+ padding-bottom: 100%;
46
+ }
47
+ /* When in fake fullscreen mode (iOS fallback) */
48
+ #ply-widget-container-${instanceId}.fake-fullscreen {
49
+ position: fixed !important;
50
+ top: 0 !important;
51
+ left: 0 !important;
52
+ width: 100vw !important;
53
+ height: 100vh !important;
54
+ padding-bottom: 0 !important;
55
+ z-index: 9999 !important;
56
+ }
57
+ /* Viewer Container styling */
58
+ #viewer-container-${instanceId} {
59
+ /* Display the viewer by default */
60
+ display: block;
61
+ position: absolute;
62
+ top: 0;
63
+ left: 0;
64
+ width: 100%;
65
+ height: 100%;
66
  background: #FEFEFD;
67
  border: 1px solid #474558;
68
  border-radius: 10px;
69
  }
70
+ /* Canvas fills the viewer container */
71
+ #canvas-${instanceId} {
72
  width: 100%;
73
  height: 100%;
74
  display: block;
75
  }
76
+ /* Progress dialog styling (as a centered div) */
77
+ #progress-dialog-${instanceId} {
78
  position: absolute;
79
  top: 50%;
80
  left: 50%;
81
  transform: translate(-50%, -50%);
82
+ border: none;
83
  background: rgba(255,255,255,0.9);
84
  padding: 20px;
85
  border-radius: 5px;
86
  z-index: 1000;
87
  display: none;
88
  }
89
+ /* Menu (instructions) content styling */
90
+ #menu-content-${instanceId} {
91
  display: none;
92
  position: absolute;
93
  top: 62px;
 
100
  line-height: 1.4;
101
  color: #474558;
102
  }
103
+ /* Button styling */
104
  .widget-button {
105
  position: absolute;
106
  width: 45px;
 
115
  align-items: center;
116
  justify-content: center;
117
  }
118
+ /* Positions: fullscreen at top-right, help (instructions) below fullscreen,
119
+ and reset camera below help */
120
+ #fullscreen-toggle-${instanceId} {
121
+ top: 17px;
122
+ right: 15px;
123
+ }
124
+ #help-toggle-${instanceId} {
125
+ top: 72px;
126
+ right: 15px;
127
+ }
128
+ #reset-camera-btn-${instanceId} {
129
+ top: 127px;
130
+ right: 15px;
131
+ }
132
  `;
133
  document.head.appendChild(styleEl);
134
 
135
+ // Create the widget container and set its inner HTML.
136
+ var widgetContainer = document.createElement('div');
137
+ widgetContainer.id = 'ply-widget-container-' + instanceId;
138
+ widgetContainer.innerHTML = `
139
+ <!-- Viewer Container (displayed directly) -->
140
+ <div id="viewer-container-${instanceId}">
141
+ <canvas id="canvas-${instanceId}"></canvas>
142
+ <div id="progress-dialog-${instanceId}">
143
+ <progress id="progress-indicator-${instanceId}" max="100" value="0"></progress>
144
+ </div>
145
+ <button id="fullscreen-toggle-${instanceId}" class="widget-button">⇱</button>
146
+ <button id="help-toggle-${instanceId}" class="widget-button">?</button>
147
+ <button id="reset-camera-btn-${instanceId}" class="widget-button">⟲</button>
148
+ <div id="menu-content-${instanceId}">
149
+ - Rotate with right click<br>
150
+ - Zoom in/out with middle click<br>
151
+ - Translate with left click
152
+ </div>
153
  </div>
154
  `;
155
+ document.currentScript.parentNode.appendChild(widgetContainer);
156
 
157
+ // Grab element references using the unique IDs.
158
+ var viewerContainer = document.getElementById('viewer-container-' + instanceId);
159
+ var fullscreenToggle = document.getElementById('fullscreen-toggle-' + instanceId);
160
+ var helpToggle = document.getElementById('help-toggle-' + instanceId);
161
+ var resetCameraBtn = document.getElementById('reset-camera-btn-' + instanceId);
162
+ var menuContent = document.getElementById('menu-content-' + instanceId);
163
+ var canvas = document.getElementById('canvas-' + instanceId);
164
+ var progressDialog = document.getElementById('progress-dialog-' + instanceId);
165
+ var progressIndicator = document.getElementById('progress-indicator-' + instanceId);
166
+
167
+ // --- Button Event Handlers ---
168
 
169
  fullscreenToggle.addEventListener('click', function() {
170
  if (isIOS) {
171
+ if (!widgetContainer.classList.contains('fake-fullscreen')) {
172
+ widgetContainer.classList.add('fake-fullscreen');
173
+ } else {
174
+ widgetContainer.classList.remove('fake-fullscreen');
175
+ }
176
+ fullscreenToggle.textContent = widgetContainer.classList.contains('fake-fullscreen') ? '⇲' : '⇱';
177
  } else {
178
  if (!document.fullscreenElement) {
179
+ if (widgetContainer.requestFullscreen) {
180
+ widgetContainer.requestFullscreen();
181
+ } else if (widgetContainer.webkitRequestFullscreen) {
182
+ widgetContainer.webkitRequestFullscreen();
183
+ } else if (widgetContainer.mozRequestFullScreen) {
184
+ widgetContainer.mozRequestFullScreen();
185
+ } else if (widgetContainer.msRequestFullscreen) {
186
+ widgetContainer.msRequestFullscreen();
187
+ }
188
  } else {
189
+ if (document.exitFullscreen) {
190
+ document.exitFullscreen();
191
+ }
192
  }
193
  }
194
  });
195
 
196
  document.addEventListener('fullscreenchange', function() {
197
+ if (document.fullscreenElement === widgetContainer) {
198
+ fullscreenToggle.textContent = '⇲';
199
+ } else {
200
+ fullscreenToggle.textContent = '⇱';
201
+ }
202
  });
203
 
204
  helpToggle.addEventListener('click', function(e) {
205
  e.stopPropagation();
206
+ menuContent.style.display = (menuContent.style.display === 'block') ? 'none' : 'block';
207
  });
208
 
209
  resetCameraBtn.addEventListener('click', function() {
210
+ console.log("Reset camera button clicked.");
211
  if (cameraInstance && initialCameraPosition && initialCameraRotation) {
212
+ cameraInstance.position = initialCameraPosition.clone();
213
+ cameraInstance.rotation = initialCameraRotation.clone();
214
+ if (typeof cameraInstance.update === 'function') {
215
+ cameraInstance.update();
216
+ }
217
+ if (controlsInstance && typeof controlsInstance.update === 'function') {
218
+ controlsInstance.update();
219
+ }
220
  }
221
  });
222
 
223
+ // --- Initialize the 3D PLY Viewer ---
224
  async function initializeViewer() {
225
  const SPLAT = await import("https://cdn.jsdelivr.net/npm/gsplat@latest");
226
  progressDialog.style.display = 'block';
 
239
  controls.minZoom = minZoom;
240
  controls.minAngle = minAngle;
241
  controls.maxAngle = maxAngle;
242
+
243
  controls.update();
244
 
245
  try {
246
+ await SPLAT.PLYLoader.LoadAsync(
247
+ plyUrl,
248
+ scene,
249
+ (progress) => {
250
+ progressIndicator.value = progress * 100;
251
+ }
252
+ );
253
  progressDialog.style.display = 'none';
254
  } catch (error) {
255
  console.error("Error loading PLY file:", error);
 
262
  requestAnimationFrame(frame);
263
  };
264
 
265
+ const handleResize = () => {
266
+ renderer.setSize(canvas.clientWidth, canvas.clientHeight);
267
+ };
268
+
269
+ handleResize();
270
+ window.addEventListener("resize", handleResize);
271
  requestAnimationFrame(frame);
272
  }
273
+
274
+ // Initialize the viewer immediately.
275
  initializeViewer();
276
  })();