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

Last change on this file since 33148 was 33148, checked in by wy59, 5 years ago
  1. Untested changes to Panorama viewer related xsl and js files to incorporate Coordinate meta wherever Latitude and Longitude meta was referred to. There's no way to test as we have no existing or tutorial collection making use of the Panorama Viewer to hand, however, a lot of the code added to deal with Coordinates is identical to other Coordinate insertions where Lat Long was used in classifier.xsl, document.xsl and map-tools.xsl and map-scripts.js. 2. Added new and removed finished TODOs.
File size: 12.9 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
30var 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 / 2 * 3,
43 panoSelectionRadius = 40;
44
45var panoDocList = new Array();
46panoDocList.ids = new Array();
47panoDocList.getDocByIndex = function(index) {
48 return panoDocList[panoDocList.ids[index]];
49};
50
51var nearbyPanoList = new Array();
52nearbyPanoList.ids = new Array();
53
54function initPanoramaViewer() {
55 //Creating the document list to store data about the panoramams
56 var jsonNodeDiv = $("#jsonPanoNodes");
57 if(jsonNodeDiv.length) {
58 var jsonNodehtml = jsonNodeDiv.html();
59 var jsonNodes = eval(jsonNodehtml);
60 if(jsonNodes && jsonNodes.length > 0) {
61 for(var i = 0; i < jsonNodes.length; i++) {
62 panoDocList[jsonNodes[i].nodeID] = jsonNodes[i];
63 panoDocList.ids.push(jsonNodes[i].nodeID);
64 }
65 } else {
66 $("pano-container").css({visibility:"hidden", height:"0px"});
67 }
68 }
69
70 panoContainer = document.getElementById( 'pano-container' );
71 // Creating the camera
72 // Setting width and height variables as the container dimensions changes when fov is changed
73 if(panoContainer.className == "pano_canvas_fullscreen") {
74 width = window.innerWidth;
75 height = window.innerHeight;
76 aspect = width / height;
77 } else if(panoContainer.className == "pano_canvas_half") {
78 width = panoContainer.offsetWidth;
79 height = panoContainer.offsetHeight;
80 aspect = width / height;
81 }
82 camera = new THREE.PerspectiveCamera( fov, aspect, 1, 1100 );
83 camera.target = new THREE.Vector3(0, 0, 0 );
84
85 // Creating the scene
86 scene = new THREE.Scene();
87
88 projector = new THREE.Projector();
89
90 var sourceFile = gs.documentMetadata[panoDocList.ids[0]].Image;
91 var assocfilepath = gs.documentMetadata[panoDocList.ids[0]].assocfilepath;
92 var httpPath = gs.collectionMetadata.httpPath;
93
94 var fullPanoURL = httpPath + "/index/assoc/" + assocfilepath + "/" + sourceFile;
95
96 // Creating a sphere with the panorama applied as a texture
97 if (Detector.webgl) {
98 mesh = new THREE.Mesh( new THREE.SphereGeometry( sphereRadius, 60, 40 ), new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( fullPanoURL ), wireframe: false, overdraw: true, opacity:0 } ) );
99 } else {
100 mesh = new THREE.Mesh( new THREE.SphereGeometry( sphereRadius, 30, 20 ), new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( fullPanoURL ), wireframe: false, overdraw: true, opacity:0 } ) );
101 }
102
103 mesh.scale.x = -1;
104 // Adding the sphere to the scene
105 scene.add( mesh );
106
107 switchPanorama(panoDocList.ids[0]);
108
109 renderer = Detector.webgl? new THREE.WebGLRenderer(): new THREE.CanvasRenderer();
110 renderer.setSize(width,height);
111
112 panoContainer.appendChild( renderer.domElement );
113
114 // Adding in Mouse events
115 panoContainer.addEventListener( 'mousedown', onDocumentMouseDown, false );
116 document.addEventListener( 'mousemove', onDocumentMouseMove, false );
117 document.addEventListener( 'mouseup', onDocumentMouseUp, false );
118 panoContainer.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
119 panoContainer.addEventListener( 'DOMMouseScroll', onDocumentMouseWheel, false);
120
121 if(panoContainer.className == "pano_canvas_fullscreen")
122 window.addEventListener( 'resize', onWindowResize, false );
123}
124
125function degreesToCoords(degrees, radius) {
126 return new THREE.Vector3(Math.cos(degrees * Math.PI/180) * radius, 0, Math.sin(degrees * Math.PI/180) * radius);
127}
128
129
130function calculateBearing(from, to) {
131 // x is lat and y is long
132 var R = 6371; // km
133 var lat1 = from.x * Math.PI / 180;
134 var lat2 = to.x * Math.PI / 180;
135 var dLon = (to.y-from.y) * Math.PI / 180;
136 var y = Math.sin(dLon) * Math.cos(lat2);
137 var x = Math.cos(lat1)*Math.sin(lat2) -
138 Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
139 var brng = (Math.atan2(y, x)) * 180 / Math.PI;
140 return (brng + 360) % 360;
141}
142
143function calculateDistance(from, to) {
144 // x is lat and y is long
145 var R = 6371; // km
146 var dLat = (from.x-to.x) * Math.PI / 180;
147 var dLon = (from.y-to.y) * Math.PI / 180;
148 var lat1 = from.x * Math.PI / 180;
149 var lat2 = to.x * Math.PI / 180;
150
151 var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
152 Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
153 var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
154 var d = R * c;
155 // return distance in metres
156 return d * 1000;
157}
158
159function switchPanorama( panoramaID, destMarker ) {
160 // Building the file path
161 var sourceFile = gs.documentMetadata[panoramaID].Image;
162 var assocfilepath = gs.documentMetadata[panoramaID].assocfilepath;
163 var httpPath = gs.collectionMetadata.httpPath;
164
165 var fullPanoURL = httpPath + "/index/assoc/" + assocfilepath + "/" + sourceFile;
166
167 // Creating the material
168 if (Detector.webgl) {
169 var texture = new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( fullPanoURL ), opacity: 0 } );
170 } else {
171 var texture = new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( fullPanoURL ), opacity: 0, wireframe: false, overdraw: true } );
172 }
173
174 if (destMarker) {
175 new TWEEN.Tween(mesh.position).to({x: -destMarker.position.x, y: -destMarker.position.y, z: -destMarker.position.z}, 500).onComplete(function () {
176 mesh.position = new THREE.Vector3(destMarker.position.x,destMarker.position.y,destMarker.position.z);
177 new TWEEN.Tween(mesh.position).to({x: 0, y: 0,z: 0},500).start();
178 }).start();
179 }
180
181 new TWEEN.Tween(mesh.materials[0]).to({opacity: 0}, 500).onComplete(function () {
182 // Rotation
183 if (gs.documentMetadata[panoramaID].Angle) {
184 var temp = 360 + parseFloat(gs.documentMetadata[panoramaID].Angle);
185 temp = temp % 360;
186 console.log(temp);
187 mesh.rotation.y = meshRotation + (gs.documentMetadata[panoramaID].Angle * Math.PI / 180);
188 } else if (gs.documentMetadata[panoramaID].cv_rotation)
189 mesh.rotation.y = meshRotation + (gs.documentMetadata[panoramaID].cv_rotation * Math.PI / 180);
190 else
191 mesh.rotation.y = meshRotation;
192
193 mesh.materials[0] = texture;
194 new TWEEN.Tween(mesh.materials[0]).to({opacity: 1}, 500).start();
195 }).start();
196
197
198 // Checking if there are markers to remove
199 if (nearbyPanoList.length > 0) {
200 for(var i = 0; i < nearbyPanoList.length; i++) {
201 panoContainer.removeChild(nearbyPanoList[i]);
202 // document.body.appendChild(nearbyPanoList[i]);
203 nearbyPanoList[i].deactivate();
204 }
205 }
206
207 // Clearing the array
208 nearbyPanoList = new Array();
209
210 // Moving the selected pano to the front of the panolist array
211 panoDocList.move(panoDocList.ids.indexOf(panoramaID), 0);
212 panoDocList.ids.move(panoDocList.ids.indexOf(panoramaID), 0);
213
214 var startPanoLonLat;
215 if(typeof gs.documentMetadata[panoramaID].Coordinate !== 'undefined'){ // we have Coordinate meta
216 var coordInfo = getLatLngForCoord(gs.documentMetadata[panoramaID].Coordinate);
217 startPanoLonLat = new THREE.Vector3(coordInfo.lat,coordInfo.lng);
218 } else {
219 startPanoLonLat = new THREE.Vector3(gs.documentMetadata[panoramaID].Latitude,gs.documentMetadata[panoramaID].Longitude);
220 }
221
222 // going through the panolist checking the distance
223 for(var i = 1; i < panoDocList.ids.length; i++) {
224 var endPanoLonLat;
225 if(typeof gs.documentMetadata[panoDocList.ids[i]].Coordinate !== 'undefined'){ // we have Coordinate meta
226 var coordInfo = getLatLngForCoord(gs.documentMetadata[panoDocList.ids[i]].Coordinate);
227 endPanoLonLat = new THREE.Vector3(coordInfo.lat,coordInfo.lng);
228 } else {
229 endPanoLonLat = new THREE.Vector3(gs.documentMetadata[panoDocList.ids[i]].Latitude,gs.documentMetadata[panoDocList.ids[i]].Longitude);
230 }
231 if(calculateDistance(startPanoLonLat,endPanoLonLat) < panoSelectionRadius) {
232 var bearing = calculateBearing(startPanoLonLat,endPanoLonLat);
233 var pos = degreesToCoords(bearing, sphereRadius);
234 var navMarker = NavMarker.create(panoDocList.ids[i],pos);
235 nearbyPanoList.push(navMarker);
236 //navMarker.addEventListener('click', switchPanorama(hash), false);
237 navMarker.addEventListener('click', function(e) {
238 var sender = (e && e.target) || (window.event && window.event.srcElement);
239 switchPanorama(sender.hash, sender); }, false);
240 }
241 }
242
243 // Going through the new nearbyPanoList and adding in the markers to the scene
244 for(var i = 0; i < nearbyPanoList.length; i++) {
245 panoContainer.appendChild(nearbyPanoList[i]);
246 nearbyPanoList[i].activate();
247 }
248
249}
250
251// DUPLICATED FROM map-scripts.js
252function getLatLngForCoord(coord) {
253
254 // https://stackoverflow.com/questions/2559318/how-to-check-for-an-undefined-or-null-variable-in-javascript
255 if(!coord) {
256 // some_variable is either null, undefined, 0, NaN, false, or an empty string
257 console.log("@@@@ In panoramaViewer::getLatLngForCoord(): no or invalid coord info");
258 return null;
259 }
260
261 // coord is of the form: "37S77 157E53"
262 // lat will be 37S77, lng 157E53.
263 var indexOfSpace = coord.indexOf(" ");
264 if(indexOfSpace === -1) {
265 console.log("@@@@ In panoramaViewer::getLatLngForCoord(): bad format for coord " + coord);
266 return null;
267 }
268 var latitude = coord.substring(0, indexOfSpace);
269 var longitude = coord.substring(indexOfSpace+1);
270 return {lat: latitude, lng: longitude}; // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects
271}
272
273function onWindowResize() {
274 camera.aspect = window.innerWidth / window.innerHeight;
275 camera.updateProjectionMatrix();
276
277 renderer.setSize( window.innerWidth, window.innerHeight );
278}
279
280
281function onDocumentMouseDown( event ) {
282 event.preventDefault();
283 isUserInteracting = true;
284 onPointerDownPointerX = event.clientX;
285 onPointerDownPointerY = event.clientY;
286 onPointerDownLon = lon;
287 onPointerDownLat = lat;
288
289}
290
291function onDocumentMouseMove( event ) {
292 if ( isUserInteracting ) {
293 lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
294 lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
295 }
296}
297
298function onDocumentMouseUp( event ) {
299 var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
300 projector.unprojectVector( vector, camera );
301 isUserInteracting = false;
302}
303
304function onDocumentMouseWheel( event ) {
305 if ( event.wheelDeltaY ) {
306 // WebKit
307 fov -= event.wheelDeltaY * 0.05;
308 } else if ( event.wheelDelta ) {
309 // Opera / Explorer 9
310 fov -= event.wheelDelta * 0.05;
311 } else if ( event.detail ) {
312 // Firefox
313 fov += event.detail * 1.0;
314 }
315
316 if ( fov > maxFov) {
317 fov = maxFov;
318 } else if (fov < minFov) {
319 fov = minFov;
320 }
321
322 camera.projectionMatrix = THREE.Matrix4.makePerspective( fov, aspect , 1, 1100 );
323 _render();
324}
325
326function _animate() {
327 requestAnimationFrame( _animate );
328 _render();
329 TWEEN.update();
330
331}
332
333function _render() {
334 lat = Math.max( - 85, Math.min( 85, lat ) );
335 phi = ( 90 - lat ) * Math.PI / 180;
336 theta = lon * Math.PI / 180;
337
338 camera.target.x = sphereRadius * Math.sin( phi ) * Math.cos( theta );
339 camera.target.y = sphereRadius * Math.cos( phi );
340 camera.target.z = sphereRadius * Math.sin( phi ) * Math.sin( theta );
341
342 camera.lookAt( camera.target );
343
344 /*
345 // distortion
346 camera.position.x = - camera.target.x;
347 camera.position.y = - camera.target.y;
348 camera.position.z = - camera.target.z;
349 */
350
351 var camUnitVector = camera.target.clone().normalize();
352 var i, angle, sameSide, p2D, marker;
353
354 // Snippet of code from Thanh Tran from in2ideas
355 // [email protected]
356 for (i = 0; i < nearbyPanoList.length; ++i) {
357 marker = nearbyPanoList[i];
358 p2D = projector.projectVector(marker.position.clone(), camera);
359
360 p2D.x = (p2D.x + 1)/2 * width;
361 p2D.y = - (p2D.y - 1)/2 * height;
362
363 angle = Math.acos(camUnitVector.dot(marker.unitVector)) * 180 / 3.14;
364 sameSide = (angle < 90);
365
366 if(!sameSide || p2D.x < 0 || p2D.x > width ||
367 p2D.y < 0 || p2D.y > height) {
368 marker.visible(false);
369 } else {
370 marker.visible(true);
371 marker.setPosition(p2D.x, p2D.y);
372 }
373 }
374 renderer.render( scene, camera );
375}
Note: See TracBrowser for help on using the repository browser.