source: main/trunk/greenstone3/web/interfaces/default/js/panoramaViewer.js@ 26872

Last change on this file since 26872 was 26872, checked in by davidb, 11 years ago

Support files to provide a Panorama viewer. Falls back to a canvas element if the browser does not support WebGL

File size: 12.2 KB
Line 
1// Array element swap code by Richard Scarrott
2// http://jsperf.com/array-prototype-move
3Array.prototype.move = function(pos1, pos2) {
4 // local variables
5 var i, tmp;
6 // cast input parameters to integers
7 pos1 = parseInt(pos1, 10);
8 pos2 = parseInt(pos2, 10);
9 // if positions are different and inside array
10 if (pos1 !== pos2 && 0 <= pos1 && pos1 <= this.length && 0 <= pos2 && pos2 <= this.length) {
11 // save element from position 1
12 tmp = this[pos1];
13 // move element down and shift other elements up
14 if (pos1 < pos2) {
15 for (i = pos1; i < pos2; i++) {
16 this[i] = this[i + 1];
17 }
18 }
19 // move element up and shift other elements down
20 else {
21 for (i = pos1; i > pos2; i--) {
22 this[i] = this[i - 1];
23 }
24 }
25 // put element from position 1 to destination
26 this[pos2] = tmp;
27 }
28}
29
30 var panoContainer, camera, scene, renderer, projector;
31
32var mouse = { x: 0, y: 0 };
33
34var fov = 70, maxFov = 90, minFov = 15,
35 width,height, aspect,
36 isUserInteracting = false,
37 onMouseDownMouseX = 0, onMouseDownMouseY = 0,
38 lon = 0, onMouseDownLon = 0,
39 lat = 0, onMouseDownLat = 0,
40 phi = 0, theta = 0,
41 mesh, sphereRadius = 500,
42 meshRotation = Math.PI,
43 panoSelectionRadius = 40;
44
45
46var panoDocList = new Array();
47panoDocList.ids = new Array();
48panoDocList.getDocByIndex = function(index) {
49 return panoDocList[panoDocList.ids[index]];
50};
51
52var nearbyPanoList = new Array();
53nearbyPanoList.ids = new Array();
54nearbyPanoList.pos = new Array();
55
56
57function initPanoramaViewer() {
58
59 //Creating the document list to store data about the panoramams
60 var jsonNodeDiv = $("#jsonPanoNodes");
61 if(jsonNodeDiv.length) {
62 var jsonNodehtml = jsonNodeDiv.html();
63 var jsonNodes = eval(jsonNodehtml);
64 if(jsonNodes && jsonNodes.length > 0) {
65 for(var i = 0; i < jsonNodes.length; i++) {
66 panoDocList[jsonNodes[i].nodeID] = jsonNodes[i];
67 panoDocList.ids.push(jsonNodes[i].nodeID);
68 }
69 } else {
70 $("pano-container").css({visibility:"hidden", height:"0px"});
71 }
72 }
73
74 panoContainer = document.getElementById( 'pano-container' );
75
76 // Creating the camera
77 // Setting width and height variables as the container dimensions changes when fov is changed
78 width = panoContainer.offsetWidth;
79 height = panoContainer.offsetHeight;
80 aspect = width / height;
81
82 // camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 1100 );
83 // camera = new THREE.PerspectiveCamera( fov, container.offsetWidth / container.offsetHeight, 1, 1100 );
84 camera = new THREE.PerspectiveCamera( fov, aspect, 1, 1100 );
85 camera.target = new THREE.Vector3(0, 0, 0 );
86
87 // Creating the scene
88 scene = new THREE.Scene();
89
90 projector = new THREE.Projector();
91
92 // Creating a sphere with the panorama applied as a texture
93 if (Detector.webgl) {
94 mesh = new THREE.Mesh( new THREE.SphereGeometry( sphereRadius, 60, 40 ), new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( gs.collectionMetadata.httpPath + '/import/panorama/' + 'panorama0.jpg' ), wireframe: false } ) );
95 } else {
96 mesh = new THREE.Mesh( new THREE.SphereGeometry( sphereRadius, 30, 20 ), new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( gs.collectionMetadata.httpPath + '/import/panorama/' + 'panorama0.jpg' ), wireframe: false, overdraw: true } ) );
97 }
98 mesh.scale.x = -1;
99 // mesh.rotation.y = meshRotation + (90 * Math.PI / 180);
100 scene.add( mesh ); // Adding the sphere to the scene
101
102 switchPanorama(panoDocList.ids[0]);
103
104 renderer = Detector.webgl? new THREE.WebGLRenderer(): new THREE.CanvasRenderer();
105 //renderer.setSize( window.innerWidth, window.innerHeight );
106 //renderer.setSize(container.offsetWidth,container.offsetHeight);
107 renderer.setSize(width,height);
108
109 panoContainer.appendChild( renderer.domElement );
110
111 // Adding in Mouse events
112 panoContainer.addEventListener( 'mousedown', onDocumentMouseDown, false );
113 document.addEventListener( 'mousemove', onDocumentMouseMove, false );
114 document.addEventListener( 'mouseup', onDocumentMouseUp, false );
115 panoContainer.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
116 panoContainer.addEventListener( 'DOMMouseScroll', onDocumentMouseWheel, false);
117
118 // window.addEventListener( 'resize', onWindowResize, false );
119}
120
121function degreesToCoords(degrees, radius) {
122 return new THREE.Vector3(Math.cos(degrees * Math.PI/180) * radius, 0, Math.sin(degrees * Math.PI/180) * radius);
123}
124
125
126function calculateBearing(from, to) {
127 // x is lat and y is long
128 var R = 6371; // km
129 var lat1 = from.x * Math.PI / 180;
130 var lat2 = to.x * Math.PI / 180;
131 var dLon = (to.y-from.y) * Math.PI / 180;
132 var y = Math.sin(dLon) * Math.cos(lat2);
133 var x = Math.cos(lat1)*Math.sin(lat2) -
134 Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
135 var brng = (Math.atan2(y, x)) * 180 / Math.PI;
136 return (brng + 360) % 360;
137}
138
139function calculateDistance(from, to) {
140 // x is lat and y is long
141 var R = 6371; // km
142 var dLat = (from.x-to.x) * Math.PI / 180;
143 var dLon = (from.y-to.y) * Math.PI / 180;
144 var lat1 = from.x * Math.PI / 180;
145 var lat2 = to.x * Math.PI / 180;
146
147 var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
148 Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
149 var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
150 var d = R * c;
151 // return distance in metres
152 return d * 1000;
153}
154
155/*
156function fullscreenToggle () {
157 console.log("blah");
158 if( THREEx.FullScreen.activated() ){
159 THREEx.FullScreen.cancel();
160
161 camera.aspect = width / height;
162 camera.updateProjectionMatrix();
163
164 renderer.setSize( width, height );
165
166 }else{
167 console.log("Fullscreen");
168 THREEx.FullScreen.request(document.getElementById( 'asdf' ));
169
170 //THREEx.FullScreen.request(panoContainer);
171
172 // THREEx.FullScreen.request(document.getElementById( renderer ));
173 camera.aspect = window.innerWidth / window.innerHeight;
174 camera.updateProjectionMatrix();
175
176 //renderer.setSize( window.innerWidth, window.innerHeight );
177
178 }
179}
180*/
181
182function switchPanorama( panoramaID, destMarker ) {
183 // Building the file path
184 var sourceFile = gs.documentMetadata[panoramaID].SourceFile;
185 var assocfilepath = gs.documentMetadata[panoramaID].assocfilepath;
186 var httpPath = gs.collectionMetadata.httpPath;
187
188 var fullPanoURL = httpPath + "/index/assoc/" + assocfilepath + "/" + sourceFile;
189
190 console.log("pano URL = " + fullPanoURL);
191
192 // Creating the material
193 if (Detector.webgl) {
194 var texture = new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( fullPanoURL ), opacity: 0 } );
195 } else {
196 var texture = new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( fullPanoURL ), opacity: 0, wireframe: false, overdraw: true } );
197 }
198
199 if (destMarker) {
200 new TWEEN.Tween(mesh.position).to({x: -destMarker.position.x, y: -destMarker.position.y, z: -destMarker.position.z}, 500).onComplete(function () {
201 mesh.position = new THREE.Vector3(destMarker.position.x,destMarker.position.y,destMarker.position.z);
202 new TWEEN.Tween(mesh.position).to({x: 0, y: 0,z: 0},500).start();
203 }).start();
204 }
205
206 new TWEEN.Tween(mesh.materials[0]).to({opacity: 0}, 500).onComplete(function () {
207 mesh.materials[0] = texture;
208 new TWEEN.Tween(mesh.materials[0]).to({opacity: 1}, 500).start();
209 }).start();
210
211 // Setting the mesh material
212
213
214 // Rotation
215 if (gs.documentMetadata[panoramaID].cv_rotation)
216 mesh.rotation.y = meshRotation + (gs.documentMetadata[panoramaID].cv_rotation * Math.PI / 180);
217 else
218 mesh.rotation.y = meshRotation;
219
220 // Checking if there are markers to remove
221 if (nearbyPanoList.length > 1) {
222 for(var i = 0; i < nearbyPanoList.length; i++) {
223 panoContainer.removeChild(nearbyPanoList[i]);
224 // document.body.appendChild(nearbyPanoList[i]);
225 nearbyPanoList[i].deactivate();
226 }
227 }
228
229 // Clearing the array
230 nearbyPanoList = new Array();
231
232 // Moving the selected pano to the front of the panolist array
233 panoDocList.move(panoDocList.ids.indexOf(panoramaID), 0);
234 panoDocList.ids.move(panoDocList.ids.indexOf(panoramaID), 0);
235
236 var startPanoLonLat = new THREE.Vector3(gs.documentMetadata[panoramaID].Latitude,gs.documentMetadata[panoramaID].Longitude);
237
238 // going through the panolist checking the distance
239 for(var i = 1; i < panoDocList.ids.length; i++) {
240 var endPanoLonLat = new THREE.Vector3(gs.documentMetadata[panoDocList.ids[i]].Latitude,gs.documentMetadata[panoDocList.ids[i]].Longitude);
241 if(calculateDistance(startPanoLonLat,endPanoLonLat) < panoSelectionRadius) {
242 var bearing = calculateBearing(startPanoLonLat,endPanoLonLat);
243 console.log(bearing);
244 var pos = degreesToCoords(bearing, sphereRadius);
245 var navMarker = NavMarker.create(panoDocList.ids[i],pos);
246 nearbyPanoList.push(navMarker);
247 //navMarker.addEventListener('click', switchPanorama(hash), false);
248 navMarker.addEventListener('click', function(e) {
249 var sender = (e && e.target) || (window.event && window.event.srcElement);
250 switchPanorama(sender.hash, sender); }, false);
251 }
252 }
253
254 // Going through the new nearbyPanoList and adding in the markers to the scene
255 for(var i = 0; i < nearbyPanoList.length; i++) {
256 panoContainer.appendChild(nearbyPanoList[i]);
257 nearbyPanoList[i].activate();
258 }
259
260}
261
262/*
263function onWindowResize() {
264 camera.aspect = window.innerWidth / window.innerHeight;
265 camera.updateProjectionMatrix();
266
267 renderer.setSize( window.innerWidth, window.innerHeight );
268}
269*/
270
271function onDocumentMouseDown( event ) {
272 event.preventDefault();
273
274 isUserInteracting = true;
275
276 onPointerDownPointerX = event.clientX;
277 onPointerDownPointerY = event.clientY;
278
279 onPointerDownLon = lon;
280 onPointerDownLat = lat;
281
282}
283
284function onDocumentMouseMove( event ) {
285 if ( isUserInteracting ) {
286
287 lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
288 lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
289 }
290}
291
292function onDocumentMouseUp( event ) {
293 var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
294 projector.unprojectVector( vector, camera );
295 isUserInteracting = false;
296}
297
298function onDocumentMouseWheel( event ) {
299
300 // WebKit
301
302 if ( event.wheelDeltaY ) {
303
304 fov -= event.wheelDeltaY * 0.05;
305
306 // Opera / Explorer 9
307
308 } else if ( event.wheelDelta ) {
309
310 fov -= event.wheelDelta * 0.05;
311
312 // Firefox
313
314 } else if ( event.detail ) {
315
316 fov += event.detail * 1.0;
317
318 }
319
320 if ( fov > maxFov) {
321 fov = maxFov;
322 } else if (fov < minFov) {
323 fov = minFov;
324 }
325
326 // camera.projectionMatrix.makePerspective( fov, container.offsetWidth / container.offsetHeight, 1, 1100 );
327 camera.projectionMatrix = THREE.Matrix4.makePerspective( fov, aspect , 1, 1100 );
328 _render();
329
330}
331
332function _animate() {
333
334 requestAnimationFrame( _animate );
335 _render();
336 TWEEN.update();
337
338}
339
340function _render() {
341 /*
342 lat = Math.max( - 85, Math.min( 85, lat ) );
343 phi = THREE.Math.degToRad( 90 - lat );
344 theta = THREE.Math.degToRad( lon );
345 */
346
347 lat = Math.max( - 85, Math.min( 85, lat ) );
348 phi = ( 90 - lat ) * Math.PI / 180;
349 theta = lon * Math.PI / 180;
350
351 camera.target.x = sphereRadius * Math.sin( phi ) * Math.cos( theta );
352 camera.target.y = sphereRadius * Math.cos( phi );
353 camera.target.z = sphereRadius * Math.sin( phi ) * Math.sin( theta );
354
355 camera.lookAt( camera.target );
356
357 /*
358 // distortion
359 camera.position.x = - camera.target.x;
360 camera.position.y = - camera.target.y;
361 camera.position.z = - camera.target.z;
362 */
363
364 var camUnitVector = camera.target.clone().normalize();
365 var i, angle, sameSide, p2D, marker;
366
367 for (i = 0; i < nearbyPanoList.length; ++i) {
368 marker = nearbyPanoList[i];
369 p2D = projector.projectVector(marker.position.clone(), camera);
370
371 p2D.x = (p2D.x + 1)/2 * width;
372 p2D.y = - (p2D.y - 1)/2 * height;
373
374 //my trick
375 angle = Math.acos(camUnitVector.dot(marker.unitVector)) * 180 / 3.14;
376 sameSide = (angle < 90);
377
378 if(!sameSide || p2D.x < 0 || p2D.x > width ||
379 p2D.y < 0 || p2D.y > height) {
380 marker.visible(false);
381 } else {
382 marker.visible(true);
383 marker.setPosition(p2D.x, p2D.y);
384 }
385 }
386
387
388 renderer.render( scene, camera );
389
390}
Note: See TracBrowser for help on using the repository browser.