Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Global tree properties #212

Merged
merged 9 commits into from
Jun 29, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified docs/moving-pictures/empress-tree-tandem.qzv
Binary file not shown.
Binary file modified docs/moving-pictures/empress-tree.qzv
Binary file not shown.
24 changes: 2 additions & 22 deletions empress/support_files/js/canvas-events.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,29 +123,9 @@ define(["glMatrix", "SelectedNodeMenu"], function (gl, SelectedNodeMenu) {
var center = canvas.offsetWidth / 2;
var mX = e.clientX - center;
var mY = center - e.clientY;
var curPos = gl.vec4.fromValues(mX, mY, 0, 1);

// move tree
var transVec = gl.vec3.create();
gl.vec3.sub(transVec, transVec, curPos);
var transMat = gl.mat4.create();
gl.mat4.fromTranslation(transMat, transVec);
gl.mat4.multiply(drawer.worldMat, transMat, drawer.worldMat);

// zoom tree
var zoomBy = e.deltaY < 0 ? drawer.scaleBy : 1 / drawer.scaleBy;
var zoomVec = gl.vec3.fromValues(zoomBy, zoomBy, zoomBy);
var zoomMat = gl.mat4.create();
gl.mat4.fromScaling(zoomMat, zoomVec);
gl.mat4.multiply(drawer.worldMat, zoomMat, drawer.worldMat);

// move tree back to original place
transVec = gl.vec3.fromValues(curPos[0], curPos[1], curPos[2]);
transMat = gl.mat4.create();
gl.mat4.fromTranslation(transMat, transVec);
gl.mat4.multiply(drawer.worldMat, transMat, drawer.worldMat);

// draw tree
// zoom tree centered at curPos
drawer.zoom(mX, mY, e.deltaY < 0);
drawer.draw();

// update the node selection menu
Expand Down
39 changes: 38 additions & 1 deletion empress/support_files/js/drawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ define(["glMatrix", "Camera"], function (gl, Camera) {
this.cam.placeCamera([0, 0, this.dim / 2], [0, 0, 0], [0, 1, 0]);

this._findViewingCenter();
this.centerCameraOn(0, 0);
};

/**
Expand Down Expand Up @@ -409,6 +408,9 @@ define(["glMatrix", "Camera"], function (gl, Camera) {
/**
* Centers the viewing window on the point (x, y).
*
* Note: This function will reset all other camera options (such as zoom).
*
*
* @param{Number} x The x position
* @param{Number} y The y position
*/
Expand All @@ -430,5 +432,40 @@ define(["glMatrix", "Camera"], function (gl, Camera) {
gl.mat4.multiply(this.worldMat, centerMat, worldMat);
};

/**
* Zooms the viewing window in or out.
*
* @param{Number} x The x position to center the zoom operation on.
* @param{Number} y The y position to center the zoom operation on.
* @param{Boolean} zoomIn If true, the camera will zoom in. If false, the
* camera will zoom out.
* Note: if zoomIn=false then the camera will zoom
* out by 1 / zoomAmount.
* @param{Number} zoomAmount The amout to zoom in or out.
*/
Drawer.prototype.zoom = function(x, y, zoomIn, zoomAmount=this.scaleBy) {
var zoomAt = gl.vec4.fromValues(x, y, 0, 1);
// move tree
var transVec = gl.vec3.create();
gl.vec3.sub(transVec, transVec, zoomAt);
var transMat = gl.mat4.create();
gl.mat4.fromTranslation(transMat, transVec);
gl.mat4.multiply(this.worldMat, transMat, this.worldMat);

// zoom tree
if (!zoomIn) zoomAmount = 1 / zoomAmount;

var zoomVec = gl.vec3.fromValues(zoomAmount, zoomAmount, zoomAmount),
zoomMat = gl.mat4.create();
gl.mat4.fromScaling(zoomMat, zoomVec);
gl.mat4.multiply(this.worldMat, zoomMat, this.worldMat);

// move tree back to original place
transVec = gl.vec3.fromValues(zoomAt[0], zoomAt[1], zoomAt[2]);
transMat = gl.mat4.create();
gl.mat4.fromTranslation(transMat, transVec);
gl.mat4.multiply(this.worldMat, transMat, this.worldMat);
};

return Drawer;
});
61 changes: 57 additions & 4 deletions empress/support_files/js/empress.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ define([
this._defaultLayout = defaultLayout;
this._currentLayout = defaultLayout;

/**
* type {Object}
* Maps tree layouts to the average point of each layout
*/
this.layoutAvgPoint = {};
/**
* @type{Number}
* The line width used for drawing "thick" lines.
Expand All @@ -174,13 +179,12 @@ define([
*/
Empress.prototype.initialize = function () {
this._drawer.initialize();
this._drawer.loadNodeBuff(this.getNodeCoords());
this.drawTree();
this._events.setMouseEvents();
var nodeNames = Object.keys(this._nameToKeys);
nodeNames = nodeNames.filter((n) => !n.startsWith("EmpressNode"));
nodeNames.sort();
this._events.autocomplete(nodeNames);
this.centerLayoutAvgPoint();
};

/**
Expand Down Expand Up @@ -1034,8 +1038,9 @@ define([
// The - 1 mimics the behavior of SidePanel._updateSample()
this.thickenSameSampleLines(this._currentLineWidth - 1);
}
this._drawer.loadNodeBuff(this.getNodeCoords());
this.drawTree();
// this._drawer.loadNodeBuff(this.getNodeCoords());
// this.drawTree();
this.centerLayoutAvgPoint();
} else {
// This should never happen under normal circumstances (the
// input to this function should always be an existing layout
Expand Down Expand Up @@ -1106,5 +1111,53 @@ define([
this.drawTree();
};

/**
* Centers the viewing window at the average of the current layout.
*/
Empress.prototype.centerLayoutAvgPoint = function() {
if (!(this._currentLayout in this.layoutAvgPoint)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, this helps defer the work until it is actually needed and it caches the results. Very useful!

// Add up x and y coordinates of all nodes in the tree (using
// current layout).
var x = 0, y = 0, zoomAmount = 0, node;
for (var i = 1; i <= this._tree.size; i++) {
node = this._treeData[i];
x += this.getX(node);
y += this.getY(node),
zoomAmount = Math.max(
zoomAmount,
Math.abs(this.getX(node)),
Math.abs(this.getY(node))
);
}

// each layout's avegerage point is define as followed:
// [x, y, zoomAmount] where x is the average of all x coordinates,
// y is the average of all y coordinates, and zoomAmount takes the
// largest x or y coordinate and normaizes it by dim / 2 (where
// dim is the dimension of the canvas).
// Note: zoomAmount is defined be a simple heuristic that should
// allow the majority of the tree to be visible in the viewing
// window.
this.layoutAvgPoint[this._currentLayout] = [
x / this._tree.size,
y / this._tree.size,
2*zoomAmount / (this._drawer.dim)
]
}

// center the viewing window on the average point of the current layout
// and zoom out so the majority of the tree is visible.
var cX = this.layoutAvgPoint[this._currentLayout][0],
cY = this.layoutAvgPoint[this._currentLayout][1];
this._drawer.centerCameraOn(cX, cY);
this._drawer.zoom(
this._drawer.treeSpaceCenterX,
this._drawer.treeSpaceCenterY,
false,
this.layoutAvgPoint[this._currentLayout][2]
);
this.drawTree();
};

return Empress;
});
3 changes: 1 addition & 2 deletions empress/support_files/js/side-panel-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -363,8 +363,7 @@ define(["underscore", "Colorer"], function (_, Colorer) {
scope.empress.setTreeNodeVisibility(scope.treeNodesChk.checked);
};
this.recenterBtn.onclick = function () {
scope.empress._drawer.centerCameraOn(0, 0);
scope.empress.drawTree();
scope.empress.centerLayoutAvgPoint();
};
fedarko marked this conversation as resolved.
Show resolved Hide resolved
};

Expand Down
53 changes: 0 additions & 53 deletions empress/support_files/templates/animate-panel.html

This file was deleted.

1 change: 0 additions & 1 deletion empress/support_files/templates/empress-template.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
<!-- Side panel -->
<div id="side-panel">
{% include 'side-panel.html'%}
{% include 'animate-panel.html' %}
</div>

<!-- show control panel button -->
Expand Down
93 changes: 74 additions & 19 deletions empress/support_files/templates/side-panel.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,6 @@
</p>
</div>

<!-- Global Tree properties -->
<button class="side-header collapsible">Tree Properties</button>
<div class="side-content control hidden">
<p>
<label for="display-nodes-chk">Show node circles?</label>
<input id="display-nodes-chk" type="checkbox" checked="true">
</p>
<p class="side-panel-notes indented">
If checked, this draws circles at the positions of all tree nodes
which had a specified name in the input Newick file.
</p>
<p>
<button id="center-tree-btn">Center Tree</button>
</p>
<p class="side-panel-notes indented">
Centers the screen on the root node of the tree.
</p>
</div>

<!-- Sample Coloring Options -->
<button class="side-header collapsible">Sample Metadata Coloring</button>
<div class="side-content control hidden">
Expand Down Expand Up @@ -119,3 +100,77 @@
Change how the tree is drawn.
</p>
</div>

<!-- animate Options -->
<button class="side-header collapsible">Animation</button>
<div class="side-content control hidden">
<p class="side-panel-notes">
Color nodes in the tree that are unique to certain groups of samples
(specified by the trajectory) at different timepoints throughout a
gradient.
</p>
<p>
<label for="animate-color-select">Choose Color Map</label>
<label class="select-container">
<select id="animate-color-select"></select>
</label>
</p>
<p>
<label for="animate-gradient">Gradient</label>
<label class="select-container">
<select id="animate-gradient"></select>
</label>
</p>
<p>
<label for="animate-trajectory">Trajectory</label>
<label class="select-container">
<select id="animate-trajectory"></select>
</label>
</p>
<p>
<label for="animate-hide-non-feature">Hide Non-Sample Features</label>
<input id="animate-hide-non-feature" type="checkbox" value="false">
</p>
<p>
<label for="animate-line-width">Line Width</label>
<input id="animate-line-width" type="number" value="1">
</p>
<div>
<p>
<button id="animate-start-btn">Start</button>
</p>
<p>
<button id="animate-stop-btn">Stop Animation</button>
</p>
<p>
<button id="animate-pause-btn">Pause</button>
</p>
<div>
<p>
<button id="animate-resume-btn">Resume</button>
<button id="animate-prev-btn">Previous Frame</button>
<button id="animate-next-btn">Next Frame</button>
</p>
</div>
</div>
</div>


<!-- Global Tree properties -->
<button class="side-header collapsible">Tree Properties</button>
<div class="side-content control hidden">
<p>
<label for="display-nodes-chk">Show node circles?</label>
<input id="display-nodes-chk" type="checkbox" checked="true">
</p>
<p class="side-panel-notes indented">
If checked, this draws circles at the positions of all tree nodes
which had a specified name in the input Newick file.
</p>
<p>
<button id="center-tree-btn">Reset Camera</button>
</p>
<p class="side-panel-notes indented">
Centers the screen on the root node of the tree.
</p>
</div>