Skip to content

Commit

Permalink
Merge pull request #187 from colin-combe/master
Browse files Browse the repository at this point in the history
fix for jumping around nodes when collapsing or changing scale
  • Loading branch information
colin-combe authored Oct 19, 2021
2 parents 0d844e8 + 78432c5 commit 35a38ab
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 69 deletions.
6 changes: 3 additions & 3 deletions dist/complexviewer.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "complexviewer",
"version": "2.1.14",
"version": "2.1.15",
"description": "A network visualisation that displays molecular interaction data, including detailed residue-level information such as binding sites. Used in EBI's Complex Portal and elsewhere.",
"author": {
"name": "Colin Combe",
Expand Down
45 changes: 13 additions & 32 deletions src/js/app.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// eslint-disable-next-line no-unused-vars
import * as css from "../css/xinet.css";
import "../css/xinet.css";
import packageInfo from "../../package.json";
import * as d3 from "d3";
import * as d3_chromatic from "d3-scale-chromatic";
import * as cola from "./cola";
import * as rgb_color from "rgb-color";
import * as Rgb_color from "rgb-color";

import {svgUtils} from "./svgexp";
import {readMijson} from "./read-mijson";
Expand All @@ -17,7 +16,7 @@ import * as $ from "jquery";

export class App {
constructor(/*HTMLDivElement*/networkDiv, maxCountInitiallyExpanded = 4) {
//this.debug = true;
// this.debug = true;
this.el = networkDiv;
//avoids prob with 'save - web page complete'
this.el.textContent = ""; //https://stackoverflow.com/questions/3955229/remove-all-child-elements-of-a-dom-node-in-javascript
Expand Down Expand Up @@ -57,7 +56,7 @@ export class App {
.attr("type", "radio")
.on("change", function (d) {
self.preventDefaultsAndStopPropagation(d);
self.contextMenuProt.setStickScale(d, self.contextMenuResNo, self.contextMenuPoint);
self.contextMenuProt.setStickScale(d, self.contextMenuPoint);
});
const contextMenu = d3.select(".custom-menu-margin").node();
contextMenu.onmouseout = function (evt) {
Expand Down Expand Up @@ -233,7 +232,6 @@ export class App {
}
NaryLink.naryColors = d3.scale.ordinal().range(complexColors);

this.proteinCount = 0;
this.z = 1;
this.hideTooltip();
this.state = App.STATES.MOUSE_UP;
Expand Down Expand Up @@ -412,7 +410,7 @@ export class App {

self.d3cola.nodes(nodes).links(links);

let groupDebugSel, participantDebugSel;
let /*groupDebugSel,*/ participantDebugSel;
if (self.debug) {
// groupDebugSel = d3.select(self.container).selectAll(".group")
// .data(groups);
Expand Down Expand Up @@ -476,7 +474,7 @@ export class App {
.on("tick", function () {
const nodes = self.d3cola.nodes();
for (let node of nodes) {
node.setPosition(node.x, node.y);
node.setPositionFromCola(node.x, node.y);
}
self.setAllLinkCoordinates();
self.zoomToExtent();
Expand Down Expand Up @@ -702,7 +700,7 @@ export class App {
if (anno.fuzzyStart || anno.fuzzyEnd) {
if (!this.uncertainCategories.has(name)) {
// make transparent version of color
const temp = new rgb_color(color);
const temp = new Rgb_color(color);
const transpColor = "rgba(" + temp.r + "," + temp.g + "," + temp.b + ", 0.6)";
createHatchedFill("hatched_" + anno.description + "_" + color.toString(), transpColor);
this.uncertainCategories.add(anno.description);
Expand Down Expand Up @@ -751,7 +749,7 @@ export class App {
}
if (this.uncertainCategories.has(desc)) {
// make transparent version of color
const temp = new rgb_color(this.featureColors(desc));
const temp = new Rgb_color(this.featureColors(desc));
const transpColor = "rgba(" + temp.r + "," + temp.g + "," + temp.b + ", 0.6)";
featureType.uncertain = {"color": transpColor};
}
Expand Down Expand Up @@ -849,7 +847,7 @@ export class App {
}

//listeners also attached to mouse events by Interactor (and Rotator) and Link, those consume their events
//mouse down on svgElement must be allowed to propogate (to fire event on Prots/Links)
//mouse down on svgElement must be allowed to propagate (to fire event on interactors/links)
mouseDown(evt) {
evt.preventDefault();
this.d3cola.stop();
Expand Down Expand Up @@ -911,7 +909,7 @@ export class App {
const time = new Date().getTime();
//eliminate some spurious mouse up events - a simple version of debouncing but it seems to work better than for e.g. _.debounce
if ((time - this.lastMouseUp) > 150) {
if (this.dragElement && this.dragElement.type === "protein" && this.state !== App.STATES.DRAGGING) {
if (this.dragElement && this.dragElement.type === "protein" && this.state !== App.STATES.DRAGGING && !this.dragElement.busy) {
if (!this.dragElement.expanded) {
this.dragElement.setExpanded(true);
this.notifyExpandListeners();
Expand All @@ -920,25 +918,11 @@ export class App {

let p = this.getEventPoint(evt);
// if (isNaN(p.x)) { //?
// alert("isNaN", p);
// alert(p.x);
// // alert("isNaN", p);
// // alert(p.x);
// p = this.getEventPoint(this.dragStart);
// }
// this.contextMenuPoint = p.matrixTransform(this.container.getCTM().inverse());
//

/*
let xOffset = (this.width / 2 - (this.getSymbolRadius()));
if (this.expanded) {
xOffset = xOffset - (this.size / 2 * this.stickZoom);
}
*/

// this.contextMenuResNo = ((p.x - this.dragElement.ix) / (this.z * this.dragElement.stickZoom ))
// + (this.dragElement.size / 2);//+
// console.log(this.contextMenuResNo);


this.contextMenuPoint = p.matrixTransform(this.container.getCTM().inverse());
const menu = d3.select(".custom-menu-margin");
let pageX, pageY;
if (evt.pageX) {
Expand Down Expand Up @@ -982,9 +966,6 @@ export class App {

mouseOut() {
this.hideTooltip();
// don't, causes prob's - RenderedInteractor mouseOut getting propogated?
// d3.select(".custom-menu-margin").style("display", "none");
// d3.select(".group-custom-menu-margin").style("display", "none");
}

getEventPoint(evt) {
Expand Down
4 changes: 0 additions & 4 deletions src/js/read-mijson.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,10 @@ export function readMijson(/*miJson*/miJson, /*App*/ app, expand = true) {
miJson = cloneComplexInteractors(miJson);

//get interactors
app.proteinCount = 0;
app.interactors = new Map();
for (let datum of miJson.data) {
if (datum.object === "interactor") {
app.interactors.set(datum.id, datum);
if (datum.id.indexOf("uniprotkb_") === 0) { // todo - is this best way to test this?
app.proteinCount++;
}
}
}

Expand Down
23 changes: 17 additions & 6 deletions src/js/viz/interactor/interactor.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,21 +140,32 @@ export class Interactor {
return [this.ix, this.iy]; // todo - type of return is kind of inconsistent
}

setPosition(x, y) {
this.px = this.ix;
this.py = this.iy;
/* leave this.x and this.y as they were set by cola (notice lack of parameters to function),
calculate centre of interactor's glyph (i.e. centre of symbol excluding label),
call setPosition with those
*/
setPositionFromCola() {
//remember previous position
this.px = this.x;
this.py = this.y;

let xOffset = (this.width / 2 - (this.getSymbolRadius()));
if (this.expanded) {
xOffset = xOffset - (this.size / 2 * this.stickZoom);
}
this.ix = x + xOffset;

this.setPosition(this.x + xOffset, this.y);
}

setPosition(x, y) {
this.ix = x;
this.iy = y;
this.upperGroup.setAttribute("transform", "translate(" + this.ix + " " + this.iy + ")");
}

changePosition(x, y) {
this.px = this.ix;
this.py = this.iy;
// this.px = this.ix; //no need to remember previous position (?)
// this.py = this.iy;
this.ix -= x;
this.iy -= y;
this.upperGroup.setAttribute("transform", "translate(" + this.ix + " " + this.iy + ")");
Expand Down
41 changes: 18 additions & 23 deletions src/js/viz/interactor/polymer.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,25 @@ export class Polymer extends Interactor {
this.highlight.setAttribute("stroke-opacity", show ? "1" : "0");
}

setStickScale(scale, residuePos, svgP) { // scale to @scale, leaving residue number @residuePos at position @svgP



// const oldScale = this.stickZoom;
setStickScale(scale, svgP) { // scale to @scale, leaving same residue under mouse
const oldScale = this.stickZoom;
// //dist from centre
// const dx = (this.ix - svgP.x);
// // new dist from centre
// const nx = dx * scale / oldScale;
const dIx = (this.ix - svgP.x);
// console.log("dist from centre ", dIx);
// new dist from centre
const nx = dIx * scale / oldScale;
// console.log("new dist from centre ", nx);

// //required change
// const rx = nx - dx;
const rx = nx - dIx;

// //new pos
// const x = this.ix + rx;
// // const y = this.iy + ry;
const x = this.ix + rx;

this.stickZoom = scale;
// const x = (-1 * ((residuePos - (this.size / 2)) * this.stickZoom)) + svgP.x;

this.scale();
// this.setPosition(this.ix, this.iy);//y);
this.setPosition(x, this.iy);//y);
this.setAllLinkCoordinates();
}

Expand Down Expand Up @@ -161,13 +160,10 @@ export class Polymer extends Interactor {

toCircle(transition = true, svgP) {
const transitionTime = transition ? Polymer.transitionTime : 0;

//svgP = null;// temp hack - you can uncomment this is you experience things 'flying off screen'
this.postAnimExpanded = false; // bit of a hack, used for updating listeners before anim complete, todo - is there better way
this.busy = true;

const r = this.getSymbolRadius();
//

d3.select(this.background).transition()
.attr("x", -r).attr("y", -r)
.attr("width", r * 2).attr("height", r * 2)
Expand All @@ -185,16 +181,15 @@ export class Polymer extends Interactor {
.duration(transitionTime);

const stickZoomInterpol = d3.interpolate(this.stickZoom, 0);
// var rotationInterpol = d3.interpolate((this.rotation > 180) ? this.rotation - 360 : this.rotation, 0);
const labelTransform = d3.transform(this.labelSVG.getAttribute("transform"));
const labelStartPoint = labelTransform.translate[0];
const labelTranslateInterpol = d3.interpolate(labelStartPoint, -(r + 5));

let xInterpol = null,
yInterpol = null;
let xInterpol = null;//,
// yInterpol = null;
if (typeof svgP !== "undefined" && svgP !== null) {
xInterpol = d3.interpolate(this.ix, svgP.x);
yInterpol = d3.interpolate(this.iy, svgP.y);
// yInterpol = d3.interpolate(this.iy, svgP.y);
}

const self = this;
Expand Down Expand Up @@ -243,9 +238,9 @@ export class Polymer extends Interactor {
const labelTransform = d3.transform(self.labelSVG.getAttribute("transform"));
const k = self.app.svgElement.createSVGMatrix().rotate(labelTransform.rotate).translate(labelTranslateInterpol(cubicInOut(interp)), self.labelY); //.scale(z).translate(-c.x, -c.y);
self.labelSVG.transform.baseVal.initialize(self.app.svgElement.createSVGTransformFromMatrix(k));
//~

if (xInterpol !== null) {
self.setPosition(xInterpol(cubicInOut(interp)), yInterpol(cubicInOut(interp)));
self.setPosition(xInterpol(cubicInOut(interp)), self.iy);//yInterpol(cubicInOut(interp)));
}

self.stickZoom = stickZoomInterpol(cubicInOut(interp));
Expand Down

0 comments on commit 35a38ab

Please sign in to comment.