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 @@
Revert to an older version
+
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;