diff --git a/public/index.html b/public/index.html index 8cca6aee..96b3d414 100644 --- a/public/index.html +++ b/public/index.html @@ -816,6 +816,7 @@ + diff --git a/public/js/collabClient.js b/public/js/collabClient.js index 54ae80a7..f3465ee4 100644 --- a/public/js/collabClient.js +++ b/public/js/collabClient.js @@ -178,6 +178,7 @@ const collabClient = (function(){ * the collaboration. * @param {number} msg.requesterId The id assigned to the local member * by the server. + * @param {Object} msg.metadata Image metadata properties */ function _handleSummary(msg) { if (msg.image !== tmapp.getImageName()) { diff --git a/public/js/tmapp.js b/public/js/tmapp.js index 7c7cc392..efd64b32 100644 --- a/public/js/tmapp.js +++ b/public/js/tmapp.js @@ -128,6 +128,34 @@ const tmapp = (function() { ctx.opacity = 1-_currState.transparency; } + function _setWarp(v,transform) { + //update additional viewers + const plus = (a,b) => ({x:a.x+b.x, y:a.y+b.y}); + const minus = (a,b) => ({x:a.x-b.x, y:a.y-b.y}); + const scale = (a,b) => ({x:a.x*b, y:a.y*b}); + + new Promise(resolve => setTimeout(resolve, 1000)) + .then(() => { + console.log('WARP: ',v.transform,v.viewport.getZoom(),v,_viewer); + const width0 = _viewer.world.getItemAt(0).source.dimensions.x; + const width1 = v.world.getItemAt(0).source.dimensions.x; + console.log(width0,':',width1,':',width1/width0); + + v.transform.scale = transform.scale*width1/width0; //Scale around upper left corner (before translation) + + //v.transform.position = coordinateHelper.imageToViewport(scale(transform.position,-1)); + v.transform.position = scale(transform.position,-1/width0/v.transform.scale); + //v.transform.position={x: -0.0026180219960755258, y: 0.013377241423963737}; + //v.transform.position={x:-0.5, y:0}; //In its own coordinates + //v.transform.position=scale(v.transform.position,1/v.transform.scale); //In its own coordinates + + v.transform.rotation = transform.rotation; //Rotation around top left of _viewer (after scale and translate) + + console.log(v.transform); + _updateRotation(); + _updateZoom();}); + } + function _updateZoom(e) { if (!_viewer) { throw new Error("Tried to update zoom of nonexistent viewer."); @@ -143,6 +171,8 @@ const tmapp = (function() { tmappUI.setImageZoom(Math.round(zoom*10)/10); _currState.zoom = zoom; +console.log('zoom',zoom); + //update additional viewers _viewers.forEach(v => { if (v===_viewer) { @@ -171,15 +201,20 @@ const tmapp = (function() { _currState.x = position.x; _currState.y = position.y; +console.log('pos',position); + //update additional viewers const plus = (a,b) => ({x:a.x+b.x, y:a.y+b.y}); const minus = (a,b) => ({x:a.x-b.x, y:a.y-b.y}); - const scale = (a,b) => ({x:a.x*b, y:a.y*b}); + const scale = (a,s) => ({x:a.x*s, y:a.y*s}); + const deg2rad = (r) => (r*Math.PI/180); + const rotate = (a,r) => ({x:a.x*Math.cos(r)+a.y*Math.sin(r), y:-a.x*Math.sin(r)+a.y*Math.cos(r)}); _viewers.forEach(v => { if (v===_viewer) { return; } - const scaledPosition=scale(position,1/v.transform.scale); + let scaledPosition=scale(position,1/v.transform.scale); + scaledPosition=rotate(scaledPosition,deg2rad(v.transform.rotation)); if (v.freeze) { v.transform.position=minus(v.viewport.getCenter(),scaledPosition); console.log('Position: ',v.transform.position); @@ -209,7 +244,7 @@ const tmapp = (function() { if (v===_viewer) { return; } - if (v.freeze) { + if (v.freeze) { //This bugs, need to update position as well v.transform.rotation=v.viewport.getRotation()-rotation; console.log('Rotation: ',v.transform.rotation); } @@ -344,6 +379,10 @@ const tmapp = (function() { return imageStack; } + function _imageWarpName(imageInfo) { + return `${_imageDir}${imageInfo.name}_warp.json`; + } + function _openImages(viewer,imageStack) { const initialZ = 0; const offset = Math.floor(imageStack.length / 2); @@ -565,10 +604,16 @@ const tmapp = (function() { showNavigationControl: withOverlay //For the moment we don't support multiple controls }); const newViewer = OpenSeadragon(options); - newViewer.transform = {scale:1, position:{x:0, y:0}, rotation:0}; // Rigid + newViewer.transform = {scale:1, position:{x:0, y:0}, rotation:0}; // Similarity transform + + //Load warp if existing + const warpName=_imageWarpName(image); + promiseHttpRequest("GET", warpName) + .then(JSON.parse) + .then(result=>_setWarp(newViewer,result)) + .catch((e)=>console.log('Warp: ',e)); _nextViewerId++; - - + //Put first _viewers.unshift(newViewer); _viewersOrder(); //Set z-index diff --git a/public/js/utils/XHRUtils.js b/public/js/utils/XHRUtils.js new file mode 100644 index 00000000..16e70e24 --- /dev/null +++ b/public/js/utils/XHRUtils.js @@ -0,0 +1,54 @@ +/** + * Utility functions for XMLHttpRequest (XHR) related stuff. + * + * @namespace XHRUtils + */ + const XHRUtils = (function() { + "use strict"; + + /** + * Promisified XHR function + * https://stackoverflow.com/questions/48969495/in-javascript-how-do-i-should-i-use-async-await-with-xmlhttprequest + * @param {*} method + * @param {*} url + * @param {boolean} noCache + */ + function makeRequest(method, url, noCache=true) { + return new Promise(function (resolve, reject) { + let xhr = new XMLHttpRequest(); + xhr.open(method, url); + + if (noCache) { + // Turn off caching of response + xhr.setRequestHeader("Cache-Control", "no-cache, no-store, must-revalidate, max-age=0"); // HTTP 1.1 + xhr.setRequestHeader("Pragma", "no-cache"); // HTTP 1.0 + xhr.setRequestHeader("Expires", "0"); // Proxies + } + + xhr.onload = function () { + if (this.status >= 200 && this.status < 300) { + resolve(xhr.responseText); + } else { + reject({ + status: this.status, + statusText: xhr.statusText + }); + } + }; + xhr.onerror = function () { + reject({ + status: this.status, + statusText: xhr.statusText + }); + }; + xhr.send(); + }); + } + + return { + makeRequest + }; +})(); + +//I think this one may live in the global namespace +const promiseHttpRequest = XHRUtils.makeRequest;