Skip to content
Snippets Groups Projects
Commit acdc46b8 authored by Lukas Pravda's avatar Lukas Pravda
Browse files

change the way highlight of selected nodes is made

parent 5cea7d9e
No related branches found
No related tags found
No related merge requests found
Pipeline #99202 passed with stages
in 1 minute and 14 seconds
......@@ -27,6 +27,7 @@ class Visualization {
private visualsMapper: VisualsMapper;
private interactionsData: any;
private selectedResidueHash: string;
private nodeDragged: boolean;
private rProvider: ResidueProvider;
......@@ -42,6 +43,7 @@ class Visualization {
this.rProvider = ResidueProvider.getInstance(this.environment);
this.fullScreen = false;
this.bindingSites = new Array<Model.BindingSite>();
this.nodeDragged = false;
if (uiParameters === undefined) uiParameters = new Config.UIParameters();
......@@ -71,7 +73,7 @@ class Visualization {
this.addMarkers();
}
// #region even handlers
// #region event handlers
private getZoomHandler() {
return d3.zoom()
.scaleExtent([1 / 10, 10])
......@@ -87,7 +89,7 @@ class Visualization {
this.nodes?.each((node: Model.InteractionNode, index: number, group: any) => {
this.nodeDim(node, index, group);
if (node.id === hash) {
this.selectedResidueHash = hash;
this.nodeHighlight(node, index, group);
......@@ -97,7 +99,6 @@ class Visualization {
}
private nodeMouseLeaveEventHandler() {
if (this.fullScreen) return;
......@@ -109,22 +110,34 @@ class Visualization {
});
}
private linkMouseClickEventHandler(x: Model.Link) {
this.fireExternalLinkEvent(x, Config.interactionClickEvent);
private linkMouseOverEventHandler(x: Model.Link, i: number, g: any) {
if (!this.nodeDragged) {
this.linkHighlight(x, i, g);
this.fireExternalLinkEvent(x, Config.interactionMouseoverEvent);
}
}
private linkMouseOverEventHandler(x: Model.Link, index: number, group: any) {
let parent = d3.select(group[index]).node().parentNode;
d3.select(parent).classed('pdb-lig-env-svg-bond-highlighted', true);
private linkMouseOutEventHandler(x: Model.Link, i: number, g: any) {
if (!this.nodeDragged) {
this.linkDim(x, i, g);
this.fireExternalNullEvent(Config.interactionMouseoutEvent);
}
}
this.fireExternalLinkEvent(x, Config.interactionMouseoverEvent);
//https://stackoverflow.com/questions/40722344/understanding-d3-with-an-example-mouseover-mouseup-with-multiple-arguments
private nodeMouseoverEventHandler(x: Model.InteractionNode, i: number, g: any) {
if (!this.nodeDragged) {
this.nodeHighlight(x, i, g);
this.fireExternalNodeEvent(x, Config.interactionMouseoverEvent);
}
}
private linkMouseOutEventHandler(index: number, group: any) {
let parent = d3.select(group[index]).node().parentNode;
d3.select(parent).classed('pdb-lig-env-svg-bond-highlighted', false);
private nodeMouseoutEventHandler(x: Model.InteractionNode, i: number, g: any) {
if (!this.nodeDragged) {
this.nodeDim(x, i, g);
this.fireExternalLinkLeaveEvent();
this.fireExternalNullEvent(Config.interactionMouseoutEvent);
}
}
private dragHandler = d3.drag()
......@@ -136,10 +149,14 @@ class Visualization {
x.fy = x.y;
})
.on('drag', (x: Model.InteractionNode) => {
this.nodeDragged = true;
x.fx = d3.event.x;
x.fy = d3.event.y;
})
.on('end', (x: Model.InteractionNode) => {
this.nodeDragged = false;
if (!d3.event.active) this.simulation.alphaTarget(0);
x.fx = d3.event.x;
x.fy = d3.event.y;
......@@ -377,18 +394,18 @@ class Visualization {
* @memberof Visualization
*/
public reinitialize() {
if (this.bindingSites.length > 1 && this.depiction !== undefined) {
this.presentBindingSite = this.bindingSites[0];
this.bindingSites.pop();
this.depictionRoot.selectAll('*').remove();
this.depiction = undefined;
this.nullNodesPositions();
this.setupScene().then(() => this.centerScene());
}
else if (this.depiction === undefined) {
else if (this.depiction === undefined) {
this.nullNodesPositions();
this.setupScene().then(() => this.centerScene());
}
......@@ -397,7 +414,7 @@ class Visualization {
this.setupLigandScene().then(() => this.centerScene());
}
this.hideLigandLabel();
this.fireExternalNullEvent(Config.interactionHideLabelEvent);
}
......@@ -486,7 +503,7 @@ class Visualization {
return 'blank.svg';
}
private nullNodesPositions() {
private nullNodesPositions() {
this.presentBindingSite.interactionNodes.forEach((x: Model.InteractionNode) => {
if (!x.static) {
x.fx = null;
......@@ -498,22 +515,6 @@ class Visualization {
// #region fire events
//https://stackoverflow.com/questions/40722344/understanding-d3-with-an-example-mouseover-mouseup-with-multiple-arguments
private fireExternalNodeMouseEnterEvent(x: Model.InteractionNode, i: number, g: any) {
this.nodeHighlight(x, i, g);
this.fireExternalNodeEvent(x, Config.interactionMouseoverEvent);
}
private fireExternalNodeMouseLeaveEvent(x: Model.InteractionNode, i: number, g: any) {
this.nodeDim(x, i, g);
const e = new CustomEvent(Config.interactionMouseoutEvent, {
bubbles: true,
detail: {}
});
this.parent.dispatchEvent(e);
}
private fireExternalLinkEvent(link: Model.Link, eventName: string) {
let atomsSource = [];
let atomsTarget = [];
......@@ -568,8 +569,8 @@ class Visualization {
this.parent.dispatchEvent(e);
}
private fireExternalLinkLeaveEvent() {
const e = new CustomEvent(Config.interactionMouseoutEvent, {
private fireExternalNullEvent(eventName: string) {
const e = new CustomEvent(eventName, {
bubbles: true,
detail: {}
});
......@@ -595,16 +596,15 @@ class Visualization {
this.links
.append('line')
.classed('pdb-lig-env-svg-shadow-bond', (x: Model.Link) => x.getLinkClass() !== 'hydrophobic')
.on('click', (x: Model.Link) => this.linkMouseClickEventHandler(x))
.on('mouseenter', (x: Model.Link, index: number, group: any) => this.linkMouseOverEventHandler(x, index, group))
.on('mouseleave', (_, index: number, group: any) => this.linkMouseOutEventHandler(index, group));
.on('mouseleave', (x: Model.Link, index: number, group: any) => this.linkMouseOutEventHandler(x, index, group));
this.links
.append('line')
.attr('class', (e: Model.Link) => `pdb-lig-env-svg-bond pdb-lig-env-svg-bond-${e.getLinkClass()}`)
.attr('marker-mid', (e: Model.Link) => e.hasClash() ? 'url(#clash)' : '')
.on('mouseenter', (x: Model.Link, y: any, z: any) => this.linkMouseOverEventHandler(x, y, z))
.on('mouseleave', (_, index: number, group: any) => this.linkMouseOutEventHandler(index, group));
.on('mouseleave', (x: Model.Link, index: number, group: any) => this.linkMouseOutEventHandler(x, index, group));
}
......@@ -616,7 +616,7 @@ class Visualization {
.style('dominant-baseline', 'central')
.each(function (e: Model.InteractionNode) {
let labels = [e.residue.chemCompId, `${e.residue.chainId} ${e.residue.authorResidueNumber}`];
for (var i = 0; i < labels.length; i++) {
for (let i = 0; i < labels.length; i++) {
d3.select(this)
.append('tspan')
.attr('dy', (i * 20) - 4)
......@@ -643,7 +643,7 @@ class Visualization {
if (!n.residue.isLigand) return;
this.nodeDim(n, i, g);
this.fireExternalNodeMouseLeaveEvent(n, i, g);
this.nodeMouseoutEventHandler(n, i, g);
this.showLigandLabel(n);
this.initLigandInteractions(this.pdbId, n.residue.authorResidueNumber, n.residue.chainId);
......@@ -714,10 +714,9 @@ class Visualization {
this.nodes.filter((x: Model.InteractionNode) => !x.residue.isLigand)
.on('click', (x: Model.InteractionNode) => this.fireExternalNodeEvent(x, Config.interactionClickEvent))
.attr('class', (x: Model.InteractionNode) => `pdb-lig-env-svg-node pdb-lig-env-svg-${x.residue.getResidueType()}-res`)
.on('mouseenter', (x: Model.InteractionNode, i: number, g: any) => this.fireExternalNodeMouseEnterEvent(x, i, g))
.on('mouseleave', (x: Model.InteractionNode, i: number, g: any) => this.fireExternalNodeMouseLeaveEvent(x, i, g));
.on('mouseenter', (x: Model.InteractionNode, i: number, g: any) => this.nodeMouseoverEventHandler(x, i, g))
.on('mouseleave', (x: Model.InteractionNode, i: number, g: any) => this.nodeMouseoutEventHandler(x, i, g));
this.nodes.filter((x: Model.InteractionNode) => !x.residue.isLigand && this.visualsMapper.glycanMapping.has(x.residue.chemCompId))
.html((e: Model.InteractionNode) => this.visualsMapper.getGlycanImage(e.residue.chemCompId));
......@@ -761,7 +760,7 @@ class Visualization {
this.setupLinks();
// setup nodes; wait for resources to be ready
this.presentBindingSite.interactionNodes.forEach(x => ResidueProvider.getInstance(this.environment).downloadAnnotation(x.residue));
this.presentBindingSite.interactionNodes.forEach(x => this.rProvider.downloadAnnotation(x.residue));
await Promise.all(this.rProvider.downloadPromises);
await Promise.all([this.visualsMapper.graphicsPromise, this.visualsMapper.mappingPromise]);
......@@ -771,8 +770,8 @@ class Visualization {
.enter().append('g')
.attr('class', (e: Model.InteractionNode) => `pdb-lig-env-svg-node pdb-lig-env-svg-${e.residue.getResidueType()}-res`)
.on('click', (x: Model.InteractionNode, i: number, g: any) => this.selectLigand(x, i, g))
.on('mouseover', (x: Model.InteractionNode, i: number, g: any) => this.fireExternalNodeMouseEnterEvent(x, i, g))
.on('mouseout', (x: Model.InteractionNode, i: number, g: any) => this.fireExternalNodeMouseLeaveEvent(x, i, g));
.on('mouseover', (x: Model.InteractionNode, i: number, g: any) => this.nodeMouseoverEventHandler(x, i, g))
.on('mouseout', (x: Model.InteractionNode, i: number, g: any) => this.nodeMouseoutEventHandler(x, i, g));
this.nodes.filter((n: Model.InteractionNode) =>
......@@ -827,8 +826,25 @@ class Visualization {
x.scale = 1.5;
if (x.residue.isLigand) d3.select(g[i]).style('cursor', 'pointer');
d3.select(g[i])
//.transition()
.attr('transform', () => `translate(${x.x},${x.y}) scale(${x.scale})`);
let otherNodes = [x];
this.links.filter((l: Model.Link) => l.containsNode(x)).each((lnk: Model.Link) => {
let otherNode = lnk.getOtherNode(x);
otherNodes.push(otherNode);
});
this.nodes
.filter((node: Model.InteractionNode) => !otherNodes.includes(node))
.attr('opacity', 0.4);
this.links
.filter((l: Model.Link) => !l.containsNode(x))
//.transition()
.attr('opacity', 0.4);
}
......@@ -836,12 +852,57 @@ class Visualization {
x.scale = 1.0;
if (x.residue.isLigand) d3.select(g[i]).style('cursor', 'default');
d3.select(g[i])
//.transition()
.attr('transform', `translate(${x.x},${x.y}) scale(${x.scale})`);
this.links.attr('opacity', 1);
this.nodes.attr('opacity', 1);
// g.forEach((_, index) => {
// if (i != index) {
// d3.select(g[index])//.transition()
// .attr('opacity', 1);
// }
// });
// this.links
// .filter((l: Model.Link) => !l.containsNode(x))
// //.transition()
// .attr('opacity', 1);
}
private linkHighlight(x: Model.Link, i: number, g: any) {
let parent = d3.select(g[i]).node().parentNode;
d3.select(parent).classed('pdb-lig-env-svg-bond-highlighted', true);
this.links
.filter((l: Model.Link) => l !== x)
//.transition()
.attr('opacity', 0.4);
this.nodes
.filter((l: Model.InteractionNode) => !(l === x.source || l === x.target))
//.transition()
.attr('opacity', 0.4);
}
private linkDim(x: Model.Link, i: number, g: any) {
let parent = d3.select(g[i]).node().parentNode;
d3.select(parent).classed('pdb-lig-env-svg-bond-highlighted', false);
this.links
.filter((l: Model.Link) => l !== x)
//.transition()
.attr('opacity', 1);
this.nodes
.filter((l: Model.InteractionNode) => !(l === x.source || l === x.target))
//.transition()
.attr('opacity', 1);
}
private showLigandLabel(x: Model.InteractionNode) {
const e = new CustomEvent(Config.interactionShowLabelEvent, {
bubbles: true,
......@@ -853,34 +914,18 @@ class Visualization {
this.parent.dispatchEvent(e);
}
private hideLigandLabel() {
const e = new CustomEvent(Config.interactionHideLabelEvent, {
bubbles: true,
detail: {}
});
this.parent.dispatchEvent(e);
}
private addMarkers() {
// let mapping = new Map<string, string>([
// // ["arrow-electrostatic", "#3F26BF"],
// // ["arrow-vdw", "#9B7653"],
// // ["arrow-metal", "#008080"],
// // ["arrow-aromatic", "#AD4379"],
let defs = this.svg.append('defs')
// proper background for depiction tspans
// gracefully coppied from: https://stackoverflow.com/questions/15500894/background-color-of-text-in-svg
// gracefully copied from: https://stackoverflow.com/questions/15500894/background-color-of-text-in-svg
let filter = defs.append('filter')
.attr('x', 0)
.attr('y', 0)
.attr('width', 1)
.attr('height', 1)
.attr('id', 'solid-background')
filter.append('feFlood').attr('flood-color', 'white')
filter.append('feComposite').attr('in', 'SourceGraphic')
......@@ -897,21 +942,6 @@ class Visualization {
.append('path')
.attr('d', 'M22.245,4.015c0.313,0.313,0.313,0.826,0,1.139l-6.276,6.27c-0.313,0.312-0.313,0.826,0,1.14l6.273,6.272 c0.313,0.313,0.313,0.826,0,1.14l-2.285,2.277c-0.314,0.312-0.828,0.312-1.142,0l-6.271-6.271c-0.313-0.313-0.828-0.313-1.141,0 l-6.276,6.267c-0.313,0.313-0.828,0.313-1.141,0l-2.282-2.28c-0.313-0.313-0.313-0.826,0-1.14l6.278-6.269 c0.313-0.312,0.313-0.826,0-1.14L1.709,5.147c-0.314-0.313-0.314-0.827,0-1.14l2.284-2.278C4.308,1.417,4.821,1.417,5.135,1.73 L11.405,8c0.314,0.314,0.828,0.314,1.141,0.001l6.276-6.267c0.312-0.312,0.826-0.312,1.141,0L22.245,4.015z')
.attr('style', 'stroke:#FF5050;stroke-width:3px;');
// mapping.forEach((x, y) =>
// d3.select('defs').append('marker')
// .attr('id', y)
// .attr("markerWidth", 15)
// .attr("markerHeight", 15)
// .attr("refX", 7)
// .attr("refY", 3)
// .attr("orient", "auto")
// .attr('markerUnits', 'strokeWidth')
// .attr('viewBox', '0 0 20 20')
// .append('path')
// .attr('d', 'M0,0 L0,6 L9,3 z')
// .attr('fill', x)
// );
}
private parseEnvironment(env: string): Model.Environment {
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment