Skip to content
Snippets Groups Projects
Commit db7be3f5 authored by Sreenath Sasidharan Nair's avatar Sreenath Sasidharan Nair
Browse files

Merge branch 'PDBE-3362' into 'master'

Added features for aggregated ligand interaction view and interactivity with heat map

See merge request !4
parents 329914a0 260597f8
No related branches found
No related tags found
1 merge request!4Added features for aggregated ligand interaction view and interactivity with heat map
Pipeline #517434 failed with stage
in 56 seconds
Showing with 8332 additions and 1980 deletions
# PDB ligand environment component # PDB LigandEnv component
This is a web-component to display ligand structure in 2D along with its interactions. Ligand can be perceived as a set of covalently linked pdb residues (refered to as bound molecule) or a single pdb residue. This depiction can be enriched with a substructure highlight, atom names, and binding site interactions. This is a web-component to display ligand structure in 2D along with its interactions. This depiction can be enriched with substructure highlight, atom names, binding site interactions and aggregated protein-ligand interactions.
## Step after cloning (use local server to see demo pages) ## Installation
```shell ```shell
npm run install npm install
npm run build npm run build
npm run start npm run start
open any of the *.html pages in the demo directory
``` ```
To see demo, copy demo directory to build and open any of the html pages.
## Component modes ## Component modes
* Mode A: Display bound molecule and its interactions * Mode A: Display ligand and its interactions (Using pdb-id, pdb-res-id and pdb-chain-id)
* Mode B: Display ligand and its interactions * Mode B: Display boundmolecule and its interactions (Using pdb-id and bound-molecule-id)
* Mode C: Display ligand (chemical component) only * Mode C: Display ligand only (Using pdb-res-name)
* Mode D: Display ligand and aggregated interactions (Using pdb-res-name and contact-type)
| Mode A | Mode B | Mode C | | Mode A | Mode B | Mode C | Mode D |
|:------------------: | :-------: | :-------: | |:------------------: | :-------: | :-------: | :-------: |
| <img src="https://www.ebi.ac.uk/~lpravda/imgs/1cbs_REA_200_A.png"/>| <img src="https://www.ebi.ac.uk/~lpravda/imgs/3d12_bm1.png"/> | <img src="https://www.ebi.ac.uk/pdbe-srv/pdbechem/image/showNew?code=VIA&size=500"/> | | <img src="dependencies/REA_A_200.png">| <img src="dependencies/3d12_bm1.png"/> | <img src="https://ftp.ebi.ac.uk/pub/databases/msd/pdbechem_v2/ccd/V/VIA/VIA_500.svg"/> | <img src="dependencies/STI_aggregated_interactions.png"> |
| [1cbs REA 200 A](https://www.ebi.ac.uk/pdbe/entry/pdb/1cbs/bound/REA) | 3D12 bm1 (`2xGLC-2xBGC-LXZ-NGA-GL0`)| [wwPDB CCD - VIA](https://pdbe.org/chem/VIA) | [1cbs REA 200 A](https://www.ebi.ac.uk/pdbe/entry/pdb/1cbs/bound/REA) | [3D12 bm1 (`2xGLC-2xBGC-LXZ-NGA-GL0`)](https://www.ebi.ac.uk/pdbe/entry/pdb/3d12/branched/4)| [wwPDB CCD - VIA](https://pdbe.org/chem/VIA) | STI |
## How to use it ## How to use it
The component can be inserted into the pages by two different ways. Either as a `web-component` using html tag, or directly by using javascript as a `plugin`. PDB LigandEnv can be inserted into web pages in two different ways. Either as a `web-component` using html tag, or directly by using javascript as a `plugin`.
Interactions data displayed by the component can come from three different environments `Production`, `Development`, `Internal`. If no environment is specified `Production` is used as default.. Interactions data displayed by the component can come from three different environments `Production`, `Development`, `Internal`. If no environment is specified `Production` is used as default..
...@@ -53,7 +53,7 @@ A few files needs to be imported in the page before the component is attempted t ...@@ -53,7 +53,7 @@ A few files needs to be imported in the page before the component is attempted t
charset="utf-8"></script> charset="utf-8"></script>
<!--PDBe interactions component--> <!--PDBe interactions component-->
<script type="module" src="pdb-ligand-env-component-0.3.0-min.js"></script> <script type="module" src="pdb-ligand-env-component-2.0.0-min.js"></script>
``` ```
#### A) Ligand interactions #### A) Ligand interactions
...@@ -68,16 +68,20 @@ A few files needs to be imported in the page before the component is attempted t ...@@ -68,16 +68,20 @@ A few files needs to be imported in the page before the component is attempted t
<pdb-ligand-env pdb-id="3d12" bound-molecule-id="bm1"></pdb-ligand-env> <pdb-ligand-env pdb-id="3d12" bound-molecule-id="bm1"></pdb-ligand-env>
``` ```
#### C) Ligand/chemical component #### C) Ligand
```html ```html
<pdb-ligand-env pdb-res-name="CLR" zoom-on ></pdb-ligand-env> <pdb-ligand-env pdb-res-name="CLR" zoom-on ></pdb-ligand-env>
``` ```
#### D) Ligand and aggregated interactions
```html
<pdb-ligand-env pdb-res-name="STI", contact-type=["hbond","hydrophobic","vdw"]></pdb-ligand-env>
```
The component contains a number of properties that can be set, in order to change data that are being displayed. First you need to define a component on the page: The component contains a number of properties that can be set, in order to change data that are being displayed. First you need to define a component on the page:
```html ```html
<pdb-ligand-env id='SIA-component'></pdb-ligand-env> <pdb-ligand-env id='SIA-component'></pdb-ligand-env>
``` ```
...@@ -87,14 +91,15 @@ and then inject data you want to display e.g.: ...@@ -87,14 +91,15 @@ and then inject data you want to display e.g.:
let chemUrl = `https://www.ebi.ac.uk/pdbe/static/files/pdbechem_v2/SIA/annotation`; let chemUrl = `https://www.ebi.ac.uk/pdbe/static/files/pdbechem_v2/SIA/annotation`;
let interactionsURL = "https://wwwdev.ebi.ac.uk/pdbe/graph-api/pdb/bound_ligand_interactions/4yy1/A/604"; let interactionsURL = "https://wwwdev.ebi.ac.uk/pdbe/graph-api/pdb/bound_ligand_interactions/4yy1/A/604";
let component = document.getElementById('SIA-component'); let component = document.getElementById('SIA-component');
(async() => {
const depiction = await (await fetch(chemUrl)).json(); const depiction = await (await fetch(chemUrl)).json();
const interactionsData = await (await fetch(interactionsURL)).json(); const interactionsData = await (await fetch(interactionsURL)).json();
const atomsToHighlight = ['C10', 'C11', 'O10']; const atomsToHighlight = ['C10', 'C11', 'O10'];
component.depiction = depiction; component.depiction = depiction;
component.ligandHighlight = atomsToHighlight; component.ligandHighlight = atomsToHighlight;
component.interactions = interactionsData; component.interactions = interactionsData;
})()
``` ```
### Plugin ### Plugin
...@@ -148,6 +153,13 @@ this.display.initLigandInteractions('1cbs', 200, 'A'); ...@@ -148,6 +153,13 @@ this.display.initLigandInteractions('1cbs', 200, 'A');
// to display chemical component with atom names only // to display chemical component with atom names only
this.display.initLigandDisplay('HEM', true); this.display.initLigandDisplay('HEM', true);
// to display aggregated protein-ligand interactions
this.display.initLigandDisplay('STI').then(() => {
this.display.initLigandWeights('STI').then(() => {
this.display.showWeights(["hydrophobic"]);
})
})
```` ````
## Parameters ## Parameters
...@@ -157,7 +169,8 @@ this.display.initLigandDisplay('HEM', true); ...@@ -157,7 +169,8 @@ this.display.initLigandDisplay('HEM', true);
| pdb-id | string | No | PDB id of a protein to retrieve interactions from. `(mode A and B only)` | | pdb-id | string | No | PDB id of a protein to retrieve interactions from. `(mode A and B only)` |
| bound-molecule-id | string | No | PDB bound molecule id `(mode A only)` | | bound-molecule-id | string | No | PDB bound molecule id `(mode A only)` |
| pdb-res-name | string | No | PDB residue name aka: *auth_comp_id* `(mode C only)` | pdb-res-name | string | No | PDB residue name aka: *auth_comp_id* `(mode C only)`
| pdb-res-id | number | No | PDB residue id aka: *auth_seq_id* `(mode B only)` | pdb-res-id | number | No | PDB residue id aka: *auth_seq_id* `(mode B only)` |
| contact-type | string[] | No | protein-ligand contact_type calculated by pdbe-arpeggio `(mode D only)` |
| pdb-chain-id | string | No | PDB residue chain aka: *auth_asym_id* `(mode B only)`| | pdb-chain-id | string | No | PDB residue chain aka: *auth_asym_id* `(mode B only)`|
| substructure | string[] | No | List of atom names to be highlighted on the ligand structure | | substructure | string[] | No | List of atom names to be highlighted on the ligand structure |
| color | string | No | HEX representation of the color highlight. `(Default: #D3D3D3)` | | color | string | No | HEX representation of the color highlight. `(Default: #D3D3D3)` |
......
<!doctype html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v5.min.js"></script>
<!-- CSS style to be used for scene drawing (required for saving SVGs.) -->
<link rel="stylesheet" href="http://127.0.0.1:8080/pdb-ligand-env-svg.css" />
<!-- UI icons -->
<link rel="stylesheet" href="https://ebi.emblstatic.net/web_guidelines/EBI-Icon-fonts/v1.3/fonts.css" />
<!-- Web component polyfill (only loads what it needs) -->
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs/webcomponents-lite.js" charset="utf-8">
</script>
<script src="https://cdn.jsdelivr.net/npm/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"
charset="utf-8"></script>
<!--PDBe interactions component-->
<script type="module" src="http://127.0.0.1:8080/pdb-ligand-env-component-1.0.0-min.js"></script>
</head>
<body>
<!--Mode A-->
<div style="position: relative; float: left;">
<div style="width: 500px; height: 500px; position: relative">
<pdb-ligand-env pdb-res-name="STI", contact-type="total"></pdb-ligand-env>
</div>
</div>
</body>
</html>
\ No newline at end of file
dependencies/3d12_bm1.png

37.9 KiB

dependencies/REA_A_200.png

47.1 KiB

dependencies/STI_aggregated_interactions.png

32.8 KiB

...@@ -4,6 +4,7 @@ const del = require('del'); ...@@ -4,6 +4,7 @@ const del = require('del');
const concat = require('gulp-concat'); const concat = require('gulp-concat');
const header = require('gulp-header'); const header = require('gulp-header');
const minify = require("gulp-minify"); const minify = require("gulp-minify");
const cp = require('child_process');
const PACKAGE_ROOT_PATH = process.cwd(); const PACKAGE_ROOT_PATH = process.cwd();
const PKG_JSON = require(path.join(PACKAGE_ROOT_PATH, "package.json")); const PKG_JSON = require(path.join(PACKAGE_ROOT_PATH, "package.json"));
...@@ -18,7 +19,7 @@ const banner = ['/**', ...@@ -18,7 +19,7 @@ const banner = ['/**',
].join('\n'); ].join('\n');
const license = ['/**', const license = ['/**',
' * Copyright 2019-2020 Lukas Pravda <lpravda@ebi.ac.uk>', ' * Copyright 2024-2030 Protein Data Bank in Europe <pdbehelp@ebi.ac.uk>',
' * European Bioinformatics Institute (EBI, http://www.ebi.ac.uk/)', ' * European Bioinformatics Institute (EBI, http://www.ebi.ac.uk/)',
' * European Molecular Biology Laboratory (EMBL, http://www.embl.de/)', ' * European Molecular Biology Laboratory (EMBL, http://www.embl.de/)',
' * Licensed under the Apache License, Version 2.0 (the "License");', ' * Licensed under the Apache License, Version 2.0 (the "License");',
...@@ -94,5 +95,11 @@ gulp.task('minifyPlugin', () => { ...@@ -94,5 +95,11 @@ gulp.task('minifyPlugin', () => {
.pipe(gulp.dest('build/')); .pipe(gulp.dest('build/'));
}); });
gulp.task('createDoc', function (cb) {
cp.exec('./node_modules/.bin/jsdoc -c jsdoc.json', function(err, stdout, stderr){
cb(err);
})
});
gulp.task('default', gulp.series('clean', 'copyAppCSS', 'concat', 'concatCSS', gulp.task('default', gulp.series('clean', 'copyAppCSS', 'concat', 'concatCSS',
'copyXML', 'copyIndex', 'copyMapping', 'minifyPlugin')); 'copyXML', 'copyIndex', 'copyMapping', 'minifyPlugin', 'createDoc'));
\ No newline at end of file \ No newline at end of file
{
"tags": {
"allowUnknownTags": true
},
"opts": {
"template": "node_modules/better-docs",
"destination": "build/docs"
},
"plugins": [
"node_modules/better-docs/typescript",
"plugins/markdown"
],
"source": {
"includePattern": "\\.(jsx|js|ts|tsx)$",
"include": ["README.md", "src/component", "src/plugin"]
},
"templates": {
"cleverLinks": false,
"monospaceLinks": false,
"default": {
"outputSourceFiles": true
},
"path": "ink-docstrap",
"theme": "cerulean",
"navType": "vertical",
"linenums": true,
"dateFormat": "MMMM Do YYYY, h:mm:ss a"
}
}
\ No newline at end of file
This diff is collapsed.
{ {
"name": "pdb-ligand-env", "name": "pdb-ligand-env",
"version": "1.0.0", "version": "2.0.0",
"description": "", "description": "",
"main": "app.js", "main": "app.js",
"dependencies": { "dependencies": {
"@types/d3": "^5.16.3", "@types/d3": "^5.16.3",
"@types/d3-tip": "^3.5.5", "@types/d3-tip": "^3.5.5",
"@types/ws": "^8.5.4",
"d3": "^5.16.0", "d3": "^5.16.0",
"d3-tip": "^0.9.1", "d3-tip": "^0.9.1",
"d3scription": "^1.0.1", "d3scription": "^1.0.1",
"lit-element": "^2.4.0", "lit-element": "^2.4.0",
"typescript": "^4.0.2" "typescript": "^5.3.3"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.3", "@babel/core": "^7.12.3",
...@@ -18,7 +19,8 @@ ...@@ -18,7 +19,8 @@
"@babel/preset-env": "^7.12.1", "@babel/preset-env": "^7.12.1",
"@babel/runtime": "^7.12.1", "@babel/runtime": "^7.12.1",
"@webcomponents/webcomponentsjs": "^2.5.0", "@webcomponents/webcomponentsjs": "^2.5.0",
"babel-loader": "^8.1.0", "babel-loader": "^9.1.3",
"better-docs": "^2.7.3",
"browser-sync": "^2.26.13", "browser-sync": "^2.26.13",
"camelcase": "^5.0.0", "camelcase": "^5.0.0",
"clean-webpack-plugin": "^1.0.1", "clean-webpack-plugin": "^1.0.1",
...@@ -30,14 +32,16 @@ ...@@ -30,14 +32,16 @@
"gulp-concat": "^2.6.1", "gulp-concat": "^2.6.1",
"gulp-header": "^2.0.9", "gulp-header": "^2.0.9",
"gulp-minify": "^3.1.0", "gulp-minify": "^3.1.0",
"jsdoc": "^4.0.2",
"live-server": "^1.2.1", "live-server": "^1.2.1",
"npm-run-all": "^4.1.3", "npm-run-all": "^4.1.3",
"onchange": "^6.1.1", "onchange": "^6.1.1",
"style-loader": "^0.23.1", "style-loader": "^0.23.1",
"ts-node": "^7.0.1", "ts-node": "^7.0.1",
"url-loader": "^1.1.2", "url-loader": "^1.1.2",
"webpack": "^5.2.0", "webpack": "^5.89.0",
"webpack-cli": "^3.3.12" "webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
}, },
"scripts": { "scripts": {
"tscW": "tsc -w", "tscW": "tsc -w",
......
...@@ -3,6 +3,14 @@ import { LitElement } from 'lit-element'; ...@@ -3,6 +3,14 @@ import { LitElement } from 'lit-element';
import "../styles/pdb-ligand-env.css"; import "../styles/pdb-ligand-env.css";
// Extend the LitElement base class // Extend the LitElement base class
/**
* PDB LigandEnv component to display ligand structure in 2D along with its interactions.
* This depiction can be enriched with substructure highlight, atom names, binding site
* interactions and aggregated protein-ligand interactions
* @component
* @example <caption> Basic usage </caption>
* <pdb-ligand-env pdb-id="1cbs" pdb-res-id="200" pdb-chain-id="A" environment="development"></pdb-ligand-env>
*/
class pdbLigandEnv extends LitElement { class pdbLigandEnv extends LitElement {
//Get properties / attribute values //Get properties / attribute values
...@@ -13,6 +21,7 @@ class pdbLigandEnv extends LitElement { ...@@ -13,6 +21,7 @@ class pdbLigandEnv extends LitElement {
entityId: { type: String, attribute: 'entity-id' }, entityId: { type: String, attribute: 'entity-id' },
resName: { type: String, attribute: 'pdb-res-name' }, resName: { type: String, attribute: 'pdb-res-name' },
resId: { type: Number, attribute: 'pdb-res-id' }, resId: { type: Number, attribute: 'pdb-res-id' },
contactType: {type: Array, attribute: 'contact-type', noAccessors: true},
chainId: { type: String, attribute: 'pdb-chain-id' }, chainId: { type: String, attribute: 'pdb-chain-id' },
substructureHighlight: { type: Array, attribute: 'substructure' }, substructureHighlight: { type: Array, attribute: 'substructure' },
substructureColor: { type: String, attribute: 'color' }, substructureColor: { type: String, attribute: 'color' },
...@@ -22,11 +31,27 @@ class pdbLigandEnv extends LitElement { ...@@ -22,11 +31,27 @@ class pdbLigandEnv extends LitElement {
}; };
} }
// Create custom accessors for contactType
set contactType(value) {
let prevCType = this._contactType + "";
this._contactType = value;
if (prevCType.length > 0) {
this.renderLigandEnv();
}
}
get contactType() { return this._contactType; }
constructor() { constructor() {
super(); super();
} }
async connectedCallback() { async connectedCallback() {
this.renderLigandEnv();
}
renderLigandEnv() {
this.innerHTML = "";
this.highlightSubstructure = []; this.highlightSubstructure = [];
let uiParams = new Config.UIParameters(); let uiParams = new Config.UIParameters();
uiParams.zoom = this.zoomOn; uiParams.zoom = this.zoomOn;
...@@ -47,12 +72,22 @@ class pdbLigandEnv extends LitElement { ...@@ -47,12 +72,22 @@ class pdbLigandEnv extends LitElement {
this.display.initLigandInteractions(this.pdbId, this.resId, this.chainId); this.display.initLigandInteractions(this.pdbId, this.resId, this.chainId);
} }
} }
else if (this.resName) { else if (this.resName){
this.display.initLigandDisplay(this.resName, names).then(() => this.display.centerScene()); this.display.initLigandDisplay(this.resName, names).then(() => {
if (this.contactType){
if(this.display.ligandIntxData === undefined){
this.display.initLigandWeights(this.resName).then(() => {
this.display.showWeights(this.contactType);
})
}
else {
this.display.showWeights(this.contactType);
}
}
})
} }
} }
//#region properties //#region properties
set depiction(data) { set depiction(data) {
if (!data) return; if (!data) return;
...@@ -61,6 +96,10 @@ class pdbLigandEnv extends LitElement { ...@@ -61,6 +96,10 @@ class pdbLigandEnv extends LitElement {
this.display.centerScene(); this.display.centerScene();
} }
set atomWeights(contactType) {
this.display.showWeights(contactType);
}
set highlightSubstructure(data) { set highlightSubstructure(data) {
if (!data || !this.display) { if (!data || !this.display) {
console.log(`Argument needs to be a non empty array of strings.`); console.log(`Argument needs to be a non empty array of strings.`);
...@@ -78,12 +117,6 @@ class pdbLigandEnv extends LitElement { ...@@ -78,12 +117,6 @@ class pdbLigandEnv extends LitElement {
this.display.addLigandHighlight(this.substructureHighlight, this.highlightColor); this.display.addLigandHighlight(this.substructureHighlight, this.highlightColor);
} }
set contourData(data) {
if (!data || !this.display || !this.display.depiction !== undefined) return;
this.display.addContours(data);
}
set zoom(data) { set zoom(data) {
if (this.display !== undefined) this.display.toggleZoom(data); if (this.display !== undefined) this.display.toggleZoom(data);
} }
...@@ -104,4 +137,4 @@ class pdbLigandEnv extends LitElement { ...@@ -104,4 +137,4 @@ class pdbLigandEnv extends LitElement {
} }
// Register the new element with the browser. // Register the new element with the browser.
customElements.define('pdb-ligand-env', pdbLigandEnv); customElements.define('pdb-ligand-env', pdbLigandEnv);
\ No newline at end of file
...@@ -7,10 +7,16 @@ namespace Config { ...@@ -7,10 +7,16 @@ namespace Config {
export const interactionShowLabelEvent: string = 'PDB.interactions.showLabel'; export const interactionShowLabelEvent: string = 'PDB.interactions.showLabel';
export const interactionHideLabelEvent: string = 'PDB.interactions.hideLabel'; export const interactionHideLabelEvent: string = 'PDB.interactions.hideLabel';
export const LigandShowAtomEvent: string = 'PDB.ligand.showAtom';
export const LigandHideAtomEvent: string = 'PDB.ligand.hideAtom';
export const molstarClickEvent: string = 'PDB.molstar.click'; export const molstarClickEvent: string = 'PDB.molstar.click';
export const molstarMouseoverEvent: string = 'PDB.molstar.mouseover'; export const molstarMouseoverEvent: string = 'PDB.molstar.mouseover';
export const molstarMouseoutEvent: string = 'PDB.molstar.mouseout'; export const molstarMouseoutEvent: string = 'PDB.molstar.mouseout';
export const ligandHeatmapMouseoverEvent: string = 'PDB.ligHeatmap.mouseover';
export const ligandHeatmapMouseoutEvent: string = 'PDB.ligHeatmap.mouseout';
export const aaTypes = new Map<string, Array<string>>([ export const aaTypes = new Map<string, Array<string>>([
['hydrophobic', new Array<string>('A', 'I', 'L', 'M', 'F', 'W', 'V')], ['hydrophobic', new Array<string>('A', 'I', 'L', 'M', 'F', 'W', 'V')],
['positive', Array<string>('K', 'R', 'O')], ['positive', Array<string>('K', 'R', 'O')],
......
/** /**
* This class contains all the details which are necessary for redrawing * This class contains all the details which are necessary for redrawing
* RDKIt style 2D molecule depiction on a client side as well as some * RDKit style 2D molecule depiction on a client side as well as some
* other logic which should hopefully help with the initial placement of * other logic for initial placement of
* binding partners in the residue-level view. * binding partners in the residue-level view.
* *
* @author Lukas Pravda <lpravda@ebi.ac.uk>
* @class Depiction * @class Depiction
* @param {string} ccdId PDB CCD id. * @param {HTMLElement} parent HTMLElement on which depiction to be displayed.
* @param {Atom[]} atoms List of atoms. * @param {any} root SVG element for the depiction.
* @param {Bond[]} bonds Visual representation of bonds. * @param {any} data Json annotation of ligand SVG
* They do not correlate 1:1 with a number of bonds! **/
* @param {Vector2D} resolution x,y dimension of the image. Needs to be used
* for a scene shift, so it is centered.
*/
class Depiction { class Depiction {
ccdId: string; ccdId: string;
atoms: Atom[]; atoms: Atom[];
bonds: Bond[]; bonds: Bond[];
resolution: Vector2D; resolution: Vector2D;
private parent: HTMLElement;
private root: d3.Selection<SVGGElement, unknown, null, undefined>; private root: d3.Selection<SVGGElement, unknown, null, undefined>;
private structure: d3.Selection<SVGGElement, unknown, null, undefined>;
private contour: d3.Selection<SVGGElement, unknown, null, undefined>;
private highlight: d3.Selection<SVGGElement, unknown, null, undefined>; private highlight: d3.Selection<SVGGElement, unknown, null, undefined>;
public weight: d3.Selection<SVGGElement, unknown, null, undefined>;
private structure: d3.Selection<SVGGElement, unknown, null, undefined>;
constructor(parent: any, data: any) { constructor(parent: HTMLElement, root: any, data: any) {
this.root = parent this.root = root;
this.parent = parent;
this.highlight = this.root.append('g').attr('id', 'highlight'); this.highlight = this.root.append('g').attr('id', 'highlight');
this.weight = this.root.append('g').attr('id', 'weight');
this.structure = this.root.append('g').attr('id', 'structure'); this.structure = this.root.append('g').attr('id', 'structure');
this.contour = this.root.append('g').attr('id', 'contour');
this.ccdId = data.ccd_id; this.ccdId = data.ccd_id;
this.resolution = new Vector2D(data.resolution.x, data.resolution.y); this.resolution = new Vector2D(data.resolution.x, data.resolution.y);
...@@ -53,7 +50,9 @@ class Depiction { ...@@ -53,7 +50,9 @@ class Depiction {
} }
this.bonds.push(bond); this.bonds.push(bond);
}); });
} }
...@@ -62,10 +61,10 @@ class Depiction { ...@@ -62,10 +61,10 @@ class Depiction {
* atom. * atom.
* *
* Present implementation sorts all the partners based on the atom * Present implementation sorts all the partners based on the atom
* degree and then gets the one with the lovest degree and places * degree and then gets the one with the lowest degree and places
* the initial residue position along the vector pointing from it. * the initial residue position along the vector pointing from it.
* *
* @param {string[]} atomNames list of atom names the bound residue * @param {string[]} atomNames array of atom names the bound residue
* has a contact with. * has a contact with.
* @returns {Vector2D} Returns an initial placement of the residue in contact. * @returns {Vector2D} Returns an initial placement of the residue in contact.
* @memberof Depiction * @memberof Depiction
...@@ -89,6 +88,13 @@ class Depiction { ...@@ -89,6 +88,13 @@ class Depiction {
return new Vector2D(x, y); return new Vector2D(x, y);
} }
/**
* Draws ligand structure by appending svg:path
* elements corresponding to bonds and atoms with labels
* @param {boolean} true if atom names need to be displayed
* @memberof Depiction
*/
public draw(atomNames: boolean = false) { public draw(atomNames: boolean = false) {
this.structure.selectAll("*").remove(); this.structure.selectAll("*").remove();
...@@ -99,6 +105,12 @@ class Depiction { ...@@ -99,6 +105,12 @@ class Depiction {
else this.appendLabels(); else this.appendLabels();
} }
/**
* Highlights atoms and bonds connecting them
* @param {string[]} atoms array of atom names to higlight
* @param {string} color color to be used for higlighting
* @memberof Depiction
*/
public highlightSubgraph(atoms: Array<string>, color: string = undefined) { public highlightSubgraph(atoms: Array<string>, color: string = undefined) {
if (!this.atoms || !atoms) return; if (!this.atoms || !atoms) return;
...@@ -125,17 +137,75 @@ class Depiction { ...@@ -125,17 +137,75 @@ class Depiction {
.attr('d', x => `M ${x.bgn.position.x},${x.bgn.position.y} ${x.end.position.x},${x.end.position.y}`) .attr('d', x => `M ${x.bgn.position.x},${x.bgn.position.y} ${x.end.position.x},${x.end.position.y}`)
.attr('style', `fill:none;fill-rule:evenodd;stroke:${color};stroke-width:22px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1`) .attr('style', `fill:none;fill-rule:evenodd;stroke:${color};stroke-width:22px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1`)
} }
/**
* Adds circles around atoms corresponding to the value of
* their weights.The size, color and number of crcles around
* atom indicates the strength of weight. Currently maximum of
* three circles are drawn
* @param {any} weights objects with atom names and value of weight
* @param {string} colorScheme Name of color to be used for circles
* @memberof Depiction
*/
public addCircles(weights: any, colorScheme: string): void {
this.atoms.forEach(x => {
x.value = weights.filter(y => y.atom == x.name).map(z => z.value)[0]
public addContour(data: any) { })
this.contour.selectAll('*').remove(); const data = this.atoms.filter(x => x.value >0);
const intxWeights = weights.map(x => x.value);
const gradient = new Model.Gradient(intxWeights, colorScheme).getScales();
const q1 = d3.quantile(intxWeights, 0.25);
const q3 = d3.quantile(intxWeights, 0.75);
const firstScale = gradient.firstScale;
const secondScale = gradient.secondScale;
const thirdScale = gradient.thirdScale;
this.weight.selectAll()
.data(data)
.enter()
.each(function(x: any){
if(x.value >= q1){
d3.select(this)
.append('circle')
.attr('cx', x.position.x)
.attr('cy', x.position.y)
.attr('r', secondScale.radiusScale(x.value))
.attr('fill', secondScale.colorScale(x.value))
.attr("fill-opacity", "0.5")
if(x.value >= q3){
d3.select(this)
.append('circle')
.attr('cx', x.position.x)
.attr('cy', x.position.y)
.attr('r', thirdScale.radiusScale(x.value))
.attr('fill', thirdScale.colorScale(x.value))
.attr("fill-opacity", "0.5")
}
}
});
this.contour.append('div').text(`'contour data goes here: ${data}`); this.weight.selectAll()
.data(data)
.enter()
.append('circle')
.attr("cx", x => x.position.x)
.attr("cy", x => x.position.y)
.attr("r", x => firstScale.radiusScale(x.value))
.attr("fill", x=> firstScale.colorScale(x.value))
.attr("fill-opacity", "0.5")
.on('mouseenter', (x:Atom) => this.atomMouseEnterEventHandler(x, true))
.on('mouseleave', () => this.atomMouseLeaveEventHandler(true));
} }
/** /**
* Appends to a given selection the visual representation of bonds as svg:path elements. * Appends to a given selection the visual representation of
* * bonds as svg:path elements.
* representation of the bond visuals. * representation of the bond visuals.
* @private
* @memberof Depiction * @memberof Depiction
*/ */
private appendBondVisuals(): void { private appendBondVisuals(): void {
...@@ -149,7 +219,7 @@ class Depiction { ...@@ -149,7 +219,7 @@ class Depiction {
/** /**
* Append atom name labels to the visualization. * Append atom name labels to the visualization.
* * @private
* @memberof Depiction * @memberof Depiction
*/ */
private appendAtomNames() { private appendAtomNames() {
...@@ -167,12 +237,8 @@ class Depiction { ...@@ -167,12 +237,8 @@ class Depiction {
} }
/** /**
* Append depiction labels to the visualization. Because RDKIt places * Append depiction labels to the visualization.
* the labels slightly differently this information needs to be * @private
* consumed too, because we cannot use just atom position directly.
* Also there are all sorts of colorful subscripts and superscripts,
* so it is much easier to use it this way.
*
* @memberof Depiction * @memberof Depiction
*/ */
private appendLabels() { private appendLabels() {
...@@ -183,7 +249,7 @@ class Depiction { ...@@ -183,7 +249,7 @@ class Depiction {
.data(data) .data(data)
.enter() .enter()
.append('g') .append('g')
.attr('filter', 'url(#solid-background)') .attr('filter', 'labels')
.each(function (x: any) { .each(function (x: any) {
for (var i = 0; i < x.labels.length; i++) { for (var i = 0; i < x.labels.length; i++) {
d3.select(this) d3.select(this)
...@@ -196,6 +262,12 @@ class Depiction { ...@@ -196,6 +262,12 @@ class Depiction {
}); });
} }
/**
* Finds the center of an array of atoms
* @param {string} ids atom ids
* @return {Vector2D} coordinates of center
* @memeberof Depiction
*/
public getCenter(ids: string[]): Vector2D { public getCenter(ids: string[]): Vector2D {
let coords = new Array<Vector2D>(); let coords = new Array<Vector2D>();
...@@ -214,7 +286,6 @@ class Depiction { ...@@ -214,7 +286,6 @@ class Depiction {
* *
* *
* @param {Map<string, number>} map * @param {Map<string, number>} map
* @returns
* @memberof Depiction * @memberof Depiction
*/ */
public sortMap(map: Map<string, number>) { public sortMap(map: Map<string, number>) {
...@@ -232,9 +303,81 @@ class Depiction { ...@@ -232,9 +303,81 @@ class Depiction {
return newMap; return newMap;
} }
// #region event handlers
/**
* Mouse enter event handler for circles around atoms
* depicting their weights
* @public
* @param {Atom} atom object
* @param {boolean} propagation if event should be triggered on external components
* @memebrof Depiction
*/
public atomMouseEnterEventHandler(x: Atom, propagation: boolean){
this.fireExternalAtomEvent(x, propagation, Config.LigandShowAtomEvent);
}
/**
* Mouse leave event handler for circlea round atoms
* depicting their weights
* @public
* @param {boolean} propagation if event should be triggered on external components
* @memberof Depiction
*/
public atomMouseLeaveEventHandler(propagation: boolean){
this.fireExternalNullEvent(propagation, Config.LigandHideAtomEvent);
}
// #endregion
// #region fire events
/**
* Dispatches custom event to display atom names and
* corresponding weights on tooltip on mouse enter
* @private
* @param {Atom} atom object
* @param {string} eventName name of event
* @memeberof Depiction
*/
private fireExternalAtomEvent(atom: Atom, propagation:boolean, eventName: string){
const e = new CustomEvent(eventName, {
bubbles: true,
detail: {
tooltip: atom.toTooltip(),
external: propagation
}
});
this.parent.dispatchEvent(e);
}
/**
* Dispatches event to hide tooltip on mouse leave
* @private
* @param {boolean} propagation if event should be triggered on external components
* @param {string} eventName name of event
* @memeberof Depiction
*/
private fireExternalNullEvent(propagation:boolean, eventName: string) {
const e = new CustomEvent(eventName, {
bubbles: true,
detail: {
external: propagation
}
});
this.parent.dispatchEvent(e);
}
// #endregion
} }
/** /**
* Atom from the depiction * Atom from the depiction
* *
...@@ -247,27 +390,37 @@ class Atom { ...@@ -247,27 +390,37 @@ class Atom {
name: string; name: string;
labels: any; labels: any;
position: Vector2D; position: Vector2D;
connectivity: number connectivity: number;
value: number;
constructor(item: any) { constructor(item: any) {
this.name = item.name; this.name = item.name;
this.labels = item.labels; this.labels = item.labels;
this.position = new Vector2D(item.x, item.y); this.position = new Vector2D(item.x, item.y);
this.connectivity = 0; this.connectivity = 0;
this.value = 0;
} }
/** /**
* *
* *
* @param {Atom} other * @param {Atom} other
* @returns true if the atoms are equal * @returns {boolean} true if the atoms are equal
* @memberof Atom * @memberof Atom
*/ */
public equals(other: Atom) { public equals(other: Atom): boolean {
if (!(other instanceof Atom)) return false; if (!(other instanceof Atom)) return false;
return other.name === this.name; return other.name === this.name;
} }
/**
* @return {string} name of atom
* @memberof Atom
*/
public toTooltip(): string {
return `<span>${this.name} | ${this.value}</span>`;
}
} }
/** /**
...@@ -340,7 +493,6 @@ class Vector2D { ...@@ -340,7 +493,6 @@ class Vector2D {
} }
} }
/** /**
* Represents a bond in a 2D depiction. * Represents a bond in a 2D depiction.
* *
...@@ -356,12 +508,6 @@ class Bond { ...@@ -356,12 +508,6 @@ class Bond {
coords: string; coords: string;
style: string; style: string;
/**
*Creates an instance of the bond.
* @param {Atom} a
* @param {Atom} b
* @memberof Bond
*/
constructor(a: Atom, b: Atom, coords: string, style: string) { constructor(a: Atom, b: Atom, coords: string, style: string) {
this.bgn = a; this.bgn = a;
this.end = b; this.end = b;
...@@ -389,7 +535,7 @@ class Bond { ...@@ -389,7 +535,7 @@ class Bond {
* Check whether or not a bond contains the atom. * Check whether or not a bond contains the atom.
* *
* @param {Atom} other The other side of the bond * @param {Atom} other The other side of the bond
* @returns True if the atom is a part of the bond, false otherwise. * @returns {boolean} True if the atom is a part of the bond, false otherwise.
* @memberof Bond * @memberof Bond
*/ */
public containsAtom(other: Atom) { public containsAtom(other: Atom) {
......
/**
* This class contains methods for creating all the visualization
* components of the LigandEnv
*
* @class Visualization
* @param {HTMLElement} element HTMLElement to display the visualization
* @param {Config.UIParameters} uiParameters UI parameter configurations
* @param {string} env environment to fetch data from
*
*/
class Visualization { class Visualization {
// component related // component related
private parent: HTMLElement; private parent: HTMLElement;
...@@ -26,6 +36,7 @@ class Visualization { ...@@ -26,6 +36,7 @@ class Visualization {
private visualsMapper: VisualsMapper; private visualsMapper: VisualsMapper;
private interactionsData: any; private interactionsData: any;
private ligandIntxData: any;
private selectedResidueHash: string; private selectedResidueHash: string;
private nodeDragged: boolean; private nodeDragged: boolean;
...@@ -68,8 +79,11 @@ class Visualization { ...@@ -68,8 +79,11 @@ class Visualization {
if (uiParameters.zoom) this.zoomHandler = this.getZoomHandler(); if (uiParameters.zoom) this.zoomHandler = this.getZoomHandler();
document.addEventListener(Config.ligandHeatmapMouseoverEvent, e => this.ligHeatmapMouseoverEventHandler(e));
document.addEventListener(Config.ligandHeatmapMouseoutEvent, () => this.ligHeatmapMouseoutEventHandler());
document.addEventListener(Config.molstarClickEvent, e => this.molstarClickEventHandler(e)); document.addEventListener(Config.molstarClickEvent, e => this.molstarClickEventHandler(e));
document.addEventListener(Config.molstarMouseoverEvent, e => this.molstarClickEventHandler(e)); document.addEventListener(Config.molstarMouseoverEvent, e => this.molstarClickEventHandler(e));
document.addEventListener(Config.molstarMouseoutEvent, () => this.molstarMouseoutEventHandler()); document.addEventListener(Config.molstarMouseoutEvent, () => this.molstarMouseoutEventHandler());
d3.select(this.parent).on('resize', () => this.resize()); d3.select(this.parent).on('resize', () => this.resize());
...@@ -95,7 +109,7 @@ class Visualization { ...@@ -95,7 +109,7 @@ class Visualization {
private molstarClickEventHandler(e: any) { private molstarClickEventHandler(e: any) {
if (this.fullScreen) return; if (this.fullScreen) return;
let hash = `${e.eventData.auth_asym_id}${e.eventData.auth_seq_id}${e.eventData.ins_code}`; let hash = `${e.eventData.auth_asym_id}${e.eventData.auth_seq_id}${e.eventData.ins_code}`;
this.nodes?.each((node: Model.InteractionNode, index: number, group: any) => { this.nodes?.each((node: Model.InteractionNode, index: number, group: any) => {
this.nodeDim(node, index, group); this.nodeDim(node, index, group);
...@@ -109,6 +123,22 @@ class Visualization { ...@@ -109,6 +123,22 @@ class Visualization {
} }
private ligHeatmapMouseoverEventHandler(e: any) {
if (this.depiction === undefined) return;
const atomName = e.detail.name; // CustomEvent
const atom = this.depiction.atoms.filter(x => x.value >0 && x.name === atomName);
if (atom.length > 0) {
this.depiction.atomMouseEnterEventHandler(atom[0], true);
} else {
this.depiction.atomMouseLeaveEventHandler(false);
}
}
private ligHeatmapMouseoutEventHandler() {
if (this.depiction === undefined) return;
this.depiction.atomMouseLeaveEventHandler(true);
}
/** /**
* Handles mouse leave molstar event. Removes interaction node highlight * Handles mouse leave molstar event. Removes interaction node highlight
...@@ -260,7 +290,7 @@ class Visualization { ...@@ -260,7 +290,7 @@ class Visualization {
* PDBeChem process. * PDBeChem process.
* *
* @param {string} ligandId * @param {string} ligandId
* @returns * @param {boolean} withNames true for displaying atom names
* @memberof Visualization * @memberof Visualization
*/ */
public async initLigandDisplay(ligandId: string, withNames: boolean = false) { public async initLigandDisplay(ligandId: string, withNames: boolean = false) {
...@@ -272,19 +302,50 @@ class Visualization { ...@@ -272,19 +302,50 @@ class Visualization {
.then(() => this.centerScene()); .then(() => this.centerScene());
} }
/**
* Download aggregated protein-ligand interactions data.
*
* @param {string} ligandId
* @memberof Visualization
*/
public async initLigandWeights(ligandId: string){
const weightUrl = `https://raw.githubusercontent.com/roshkjr/Learning-sources/main/${ligandId}_atom_residue_intx.json`
return d3.json(weightUrl)
.then((d: any) => this.ligandIntxData = d);
}
/** /**
* Add depiction to the canvas from external resource. * Add depiction to the canvas from external resource.
* *
* @param {*} depiction Content of annotation.json file generated by * @param {any} depiction Content of annotation.json file generated by
* the PDBeChem process. * the PDBeChem process.
* @param {boolean} withNames true for displaying atom names
* @memberof Visualization * @memberof Visualization
*/ */
public addDepiction(depiction: any, withNames: boolean) { public addDepiction(depiction: any, withNames: boolean) {
this.depiction = new Depiction(this.depictionRoot, depiction); this.depiction = new Depiction(this.parent, this.depictionRoot, depiction);
this.depiction.draw(withNames); this.depiction.draw(withNames);
} }
/**
* Adds circles around atoms higlighting the weights of atoms.
*
* @param {string} contactType
* @memberof Visualization
*/
public showWeights(contactType: string[]){
if ((this.depiction === undefined) || (this.ligandIntxData) === undefined) return;
const atomPropensity= new Model.LigandIntx(this.ligandIntxData, contactType).getAtomIntxPropensity();
const colorScheme = "Greens";
this.depiction.addCircles(atomPropensity, colorScheme);
if(this.zoomHandler !== undefined){
this.zoomHandler(this.svg, d3.zoomIdentity)
};
}
/** /**
* Show depiction with/without atom names * Show depiction with/without atom names
...@@ -312,26 +373,16 @@ class Visualization { ...@@ -312,26 +373,16 @@ class Visualization {
* @memberof Visualization * @memberof Visualization
*/ */
public addLigandHighlight(highlight: string[], color: string = undefined) { public addLigandHighlight(highlight: string[], color: string = undefined) {
if (!this.depiction) return;
this.depiction.highlightSubgraph(highlight, color); this.depiction.highlightSubgraph(highlight, color);
} }
/**
* Add contours to the ligand structure. The previous contours are
* going to be removed.
*
* @param {*} data
* @memberof Visualization
*/
public addContours(data: any) {
this.depiction.addContour(data);
}
/** /**
* Add ligand interactions to the canvas * Add ligand interactions to the canvas
* *
* @param {*} data Data content of the API end point * @param {*} data Data content of the API end point
* /pdb/bound_ligand_interactions * /pdb/bound_ligand_interactions
* @param {boolean} true if atom names to be displayed
* @memberof Visualization * @memberof Visualization
*/ */
public addLigandInteractions(data: any, withNames: boolean = false) { public addLigandInteractions(data: any, withNames: boolean = false) {
...@@ -356,7 +407,7 @@ class Visualization { ...@@ -356,7 +407,7 @@ class Visualization {
/** /**
* Add bound molecule interactions to the canvas. * Add bound molecule interactions to the canvas.
* *
* @param {*} data Data content of the API end point * @param {any} data Data content of the API end point
* /pdb/bound_molecule_interactions * /pdb/bound_molecule_interactions
* @param {string} bmId Bound molecule id * @param {string} bmId Bound molecule id
* @memberof Visualization * @memberof Visualization
...@@ -376,6 +427,7 @@ class Visualization { ...@@ -376,6 +427,7 @@ class Visualization {
// #region menu functions // #region menu functions
/** /**
* Export scene into an SVG components. It relies on the availability * Export scene into an SVG components. It relies on the availability
* of the external CSS for SVG styling. Otherwise it does not work. * of the external CSS for SVG styling. Otherwise it does not work.
...@@ -611,6 +663,7 @@ class Visualization { ...@@ -611,6 +663,7 @@ class Visualization {
this.parent.dispatchEvent(e); this.parent.dispatchEvent(e);
} }
// #endregion fire events // #endregion fire events
...@@ -668,7 +721,6 @@ class Visualization { ...@@ -668,7 +721,6 @@ class Visualization {
* @param {Model.InteractionNode} n Interaction node user clicked to * @param {Model.InteractionNode} n Interaction node user clicked to
* @param {number} i index o the interaction node * @param {number} i index o the interaction node
* @param {*} g group of interaction nodes * @param {*} g group of interaction nodes
* @returns
* @memberof Visualization * @memberof Visualization
*/ */
private selectLigand(n: Model.InteractionNode, i: number, g: any) { private selectLigand(n: Model.InteractionNode, i: number, g: any) {
...@@ -783,7 +835,7 @@ class Visualization { ...@@ -783,7 +835,7 @@ class Visualization {
/** /**
* Setup display of interactions for bound molecule. * Setup display of interactions for bound molecule.
* * This includes: setup of links, nodes, simulation and subscribing to relevant events. * This includes: setup of links, nodes, simulation and subscribing to relevant events.
* No depiction is required for this step. * No depiction is required for this step.
* *
* @private * @private
......
...@@ -59,6 +59,8 @@ namespace Model { ...@@ -59,6 +59,8 @@ namespace Model {
/** /**
* Data model representing a single residue, which is a part of the * Data model representing a single residue, which is a part of the
* bound molecule. This residue is unique in the entire binding site. * bound molecule. This residue is unique in the entire binding site.
* @param {any} data
* @param {boolean} isLigand true if the residue is a ligand
*/ */
export class Residue { export class Residue {
id: string id: string
...@@ -496,4 +498,114 @@ namespace Model { ...@@ -496,4 +498,114 @@ namespace Model {
} }
} }
export class LigandIntx{
data: any;
contactTypes: string[];
filteredData: any;
constructor(data: any, contactTypes:string[]){
this.data = data;
this.contactTypes = contactTypes;
this.filteredData = this.getFilteredData();
}
private getAtomResidueObj(x: string[]){
return {
"atom": x[0],
"AA": x[1],
"count": x[2]
}
}
private getFilteredData(){
const filteredData = new Array();
for (const contactType in this.data){
if (this.contactTypes.includes(contactType)){
filteredData.push(...this.data[contactType].map(this.getAtomResidueObj));
}
}
return filteredData
}
public getAtomIntxPropensity(){
const atomCount = new Array();
this.filteredData.reduce(function(acc, currentValue){
if(!acc[currentValue.atom]){
acc[currentValue.atom] = {"atom": currentValue.atom, "count": 0};
atomCount.push(acc[currentValue.atom]);
}
acc[currentValue.atom].count += currentValue.count;
return acc
},{});
const totalIntx = atomCount.reduce(function(acc, currentValue){
acc += currentValue.count;
return acc;
}, 0)
const atomPropensity = atomCount.map((x) =>
({"atom": x.atom,
"value": (x.count/totalIntx).toFixed(2)
})
);
return atomPropensity
}
}
/**
* Data model representing scale of a circles
* Stores scale for radius and color
*/
export class Scale{
radiusScale: any;
colorScale: any;
constructor(radiusScale:any, colorScale:any){
this.radiusScale = radiusScale;
this.colorScale = colorScale;
}
}
/**
* Gradient object with three
* level scales for circles to highlight
* @param {any} weight
* @param {string} colorScheme color to be used for generating gradient
*/
export class Gradient {
weight: any;
colorScheme: string;
constructor(weight: any, colorScheme:string){
this.weight = weight;
this.colorScheme = colorScheme;
}
/**
* Generates three level scales for the
* Gradient object
*/
public getScales(){
const color = d3[`scheme${this.colorScheme}`][9];
const weightMax = Number(d3.max(this.weight));
const gradient = {firstScale: new Scale(d3.scaleLinear([0, weightMax], [20, 30]),
d3.scaleLinear([0,weightMax], ["#FFFFFF", color[4]])),
secondScale: new Scale(d3.scaleLinear([0,weightMax], [10, 20]),
d3.scaleLinear([0, weightMax], [color[5], color[7]])),
thirdScale: new Scale(d3.scaleLinear([0, weightMax], [2, 10]),
d3.scaleLinear([0, weightMax], [color[8], color[9]]))
};
return gradient
}
}
} }
\ No newline at end of file
...@@ -45,7 +45,7 @@ class ResidueProvider { ...@@ -45,7 +45,7 @@ class ResidueProvider {
* Get single letter abbreviation of the ligand. * Get single letter abbreviation of the ligand.
* *
* @param {string} name Name of the chemical compound * @param {string} name Name of the chemical compound
* @returns Single letter abbreviation of the ligand * @returns {string} Single letter abbreviation of the ligand
* @memberof ResidueProvider * @memberof ResidueProvider
*/ */
public getAminoAcidAbbreviation(name: string): string { public getAminoAcidAbbreviation(name: string): string {
...@@ -57,7 +57,6 @@ class ResidueProvider { ...@@ -57,7 +57,6 @@ class ResidueProvider {
* Fetch single letter abbreviations from API if they are not present * Fetch single letter abbreviations from API if they are not present
* *
* @param {string} n * @param {string} n
* @returns
* @memberof ResidueProvider * @memberof ResidueProvider
*/ */
public downloadAnnotation(r: Model.Residue): void { public downloadAnnotation(r: Model.Residue): void {
......
...@@ -128,7 +128,6 @@ namespace Resources { ...@@ -128,7 +128,6 @@ namespace Resources {
* @param {string} chainId * @param {string} chainId
* @param {number} resId * @param {number} resId
* @param {Model.Environment} env * @param {Model.Environment} env
* @returns
*/ */
export function ligandInteractionsAPI(pdbId: string, chainId: string, resId: number, env: Model.Environment) { export function ligandInteractionsAPI(pdbId: string, chainId: string, resId: number, env: Model.Environment) {
let url = ''; let url = '';
......
...@@ -114,6 +114,9 @@ let helpBonds = ` ...@@ -114,6 +114,9 @@ let helpBonds = `
// #endregion help // #endregion help
/**
* @class UI
*/
class UI { class UI {
...@@ -143,7 +146,6 @@ class UI { ...@@ -143,7 +146,6 @@ class UI {
* *
* @param {Config.UIParameters} p Object with annotation which * @param {Config.UIParameters} p Object with annotation which
* UI elements should be created. * UI elements should be created.
* @returns
* @memberof UI * @memberof UI
*/ */
public register(p: Config.UIParameters) { public register(p: Config.UIParameters) {
...@@ -263,6 +265,8 @@ class UI { ...@@ -263,6 +265,8 @@ class UI {
this.parent.addEventListener(Config.interactionClickEvent, e => this.nodeMouseEnterEventHandler(e)); this.parent.addEventListener(Config.interactionClickEvent, e => this.nodeMouseEnterEventHandler(e));
this.parent.addEventListener(Config.interactionMouseoverEvent, e => this.nodeMouseEnterEventHandler(e)); this.parent.addEventListener(Config.interactionMouseoverEvent, e => this.nodeMouseEnterEventHandler(e));
this.parent.addEventListener(Config.interactionMouseoutEvent, () => this.nodeMouseLeaveEventHandler()); this.parent.addEventListener(Config.interactionMouseoutEvent, () => this.nodeMouseLeaveEventHandler());
this.parent.addEventListener(Config.LigandShowAtomEvent, e => this.nodeMouseEnterEventHandler(e));
this.parent.addEventListener(Config.LigandHideAtomEvent, () => this.nodeMouseLeaveEventHandler());
} }
if (this.residueLabel !== undefined) { if (this.residueLabel !== undefined) {
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
"declaration": true, "declaration": true,
"module": "none", "module": "none",
"moduleResolution": "node", "moduleResolution": "node",
"out": "build/pdb-ligand-env-plugin.js" "outFile": "build/pdb-ligand-env-plugin.js"
}, },
"include": ["src/plugin/**/*", ], "include": ["src/plugin/**/*", ],
"exclude": [ "exclude": [
......
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