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

Merge branch 'dev'

parents 9aaaa1e9 86719779
No related branches found
No related tags found
No related merge requests found
Pipeline #88109 passed with stages
in 1 minute and 16 seconds
......@@ -26,6 +26,8 @@ python3 -m http.server
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`.
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..
### Web-component
A few files needs to be imported in the page before the component is attempted to be loaded:
......@@ -53,7 +55,7 @@ A few files needs to be imported in the page before the component is attempted t
#### A) Ligand interactions
```html
<pdb-ligand-env pdb-id="1cbs" pdb-res-id="200" pdb-chain-id="A"></pdb-ligand-env>
<pdb-ligand-env pdb-id="1cbs" pdb-res-id="200" pdb-chain-id="A" environment="development"></pdb-ligand-env>
```
#### B) Bound molecule interactions
......@@ -116,6 +118,7 @@ and then the component can be instantiated as simply as:
```javascript
let component = document.getElementById('SIA-component');
let environemnt = "development";
let uiParams = {
reinitialize: true, // allow reinitialize option in the component menu
zoom: true, // allow scene zoom
......@@ -128,7 +131,7 @@ let uiParams = {
tooltip: true // show residue tooltip on mouse hover
};
this.display = new Visualization(this, uiParams);
this.display = new Visualization(this, uiParams, environment);
// to display bound molecule interactions
this.display.initBoundMoleculeInteractions('3d12', 'bm1');
......@@ -153,3 +156,4 @@ this.display.initLigandDisplay('HEM');
| 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)` |
| zoom-on | boolean | No | Allow zoom functionality on the component level. |
| environment | string | No | What data should be used: one of `production`, `development`, `internal` or a shorthand `prod`, `dev`, `int`. |
......@@ -98,10 +98,10 @@
backgroundColour: '0xFFFFFF',
//customColorList: [0xff0000, 0x0000ff],
//representationStyle: representationStyle//,
// customData: {
// url: `https://wwwdev.ebi.ac.uk/pdbe/coordinates/${params.pdbid}/ligandInteraction?&authAsymId=${params.chain}&authSeqNumber=${params.resid}&radius=5&dataSource=hydrogens`,
// format: 'cif'
// }
customData: {
url: `https://wwwdev.ebi.ac.uk/pdbe/coordinates/${params.pdbid}/ligandInteraction?&authAsymId=${params.chain}&authSeqNumber=${params.resid}&radius=5&dataSource=hydrogens`,
format: 'cif'
}
}
var pdbeMolstar = new MolStarPdbeWrapper();
pdbeMolstar.render(document.getElementById('3dViewer'), initParams);
......@@ -118,7 +118,7 @@
<div style="position: relative; float: left;">
<div id='3dViewer' style="position:relative; width: 500px;height: 500px;"></div>
</div>
<div style="position: relative; float: left;">
<!-- <div style="position: relative; float: left;">
<div id="rt 1" style="width: 500px; height: 500px; position: relative">
<pdb-ligand-env pdb-id="5e98" bound-molecule-id="bm1" zoom-on></pdb-ligand-env>
</div>
......@@ -127,7 +127,7 @@
<div id="rt 1" style="width: 500px; height: 500px; position: relative">
<pdb-ligand-env pdb-id="5e98" bound-molecule-id="bm1" entity-id="3" zoom-on></pdb-ligand-env>
</div>
</div>
</div> -->
<!--
Further use in the app for bound molecule interactions:
......
......@@ -17,6 +17,7 @@ class pdbLigandEnv extends LitElement {
substructureHighlight: { type: Array, attribute: 'substructure' },
substructureColor: { type: String, attribute: 'color' },
zoomOn: { type: Boolean, attribute: 'zoom-on' },
env: { type: String, attribute: 'environment' },
};
}
......@@ -28,7 +29,9 @@ class pdbLigandEnv extends LitElement {
let uiParams = new Config.UIParameters();
uiParams.zoom = this.zoomOn;
this.display = new Visualization(this, uiParams);
let env = this.env === undefined ? "production" : this.env;
this.display = new Visualization(this, uiParams, env);
if (this.pdbId) {
if (this.entityId) {
......
......@@ -97,13 +97,13 @@ class Depiction {
}
public highlightSubgraph(atoms: Array<string>, color: string = undefined) {
if (!this.atoms || !atoms) return;
if (!this.atoms || !atoms) return;
this.highlight.selectAll('*').remove();
color = color ? color : "#BFBFBF";
let atomsToHighlight = this.atoms.filter(x => atoms.includes(x.name));
this.highlight.selectAll()
.data(atomsToHighlight)
.enter()
......@@ -123,7 +123,7 @@ class Depiction {
.attr('style', `fill:none;fill-rule:evenodd;stroke:${color};stroke-width:22px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1`)
}
public addContour(data: any) {
public addContour(data: any) {
this.contour.selectAll('*').remove();
this.contour.append('div').text(`'contour data goes here: ${data}`);
......@@ -155,12 +155,14 @@ class Depiction {
*/
private appendTexts(): void {
this.structure.selectAll()
.data(this.atoms.filter(x => Object.keys(x.label).length !== 0).map(x => x.label))
.data(this.atoms.filter(x => Object.keys(x.labels).length !== 0).map(x => x.labels).reduce((a, b) => a.concat(b)))
.enter()
.append('text')
.attr('style', (x: any) => x.style)
.attr('x', (x: any) => x.x)
.attr('y', (x: any) => x.y)
.attr('dominant-baseline', (x: any) => x['dominant-baseline'])
.attr('text-anchor', (x: any) => x['text-anchor'])
.each(function (x: any) {
for (var i = 0; i < x.tspans.length; i++) {
d3.select(this)
......@@ -179,7 +181,7 @@ class Depiction {
*/
private appendClarityNodes(): void {
this.structure.selectAll()
.data(this.atoms.filter(x => Object.keys(x.label).length != 0))
.data(this.atoms.filter(x => Object.keys(x.labels).length != 0))
.enter().append('circle')
.classed('pdb-lig-env-svg-shadow-node', true)
.attr('cx', (x: any) => x.position.x)
......@@ -190,7 +192,7 @@ class Depiction {
public getCenter(ids: string[]): Vector2D {
let coords = new Array<Vector2D>();
ids.forEach(x => {
let pos = this.atoms.find(y => y.name === x).position;
coords.push(pos);
......@@ -232,16 +234,16 @@ class Depiction {
*
* @class Atom
* @param {string} name Unique atom name.
* @param {any} label Atom label
* @param {any} labels Atom label
* @param {Vector2D} position Position of the atom in 2D coordinate system.
*/
class Atom {
name: string;
label: any;
labels: any;
position: Vector2D;
constructor(item: any) {
this.name = item.name;
this.label = item.label;
this.labels = item.labels;
this.position = new Vector2D(item.x, item.y)
}
......
......@@ -19,6 +19,7 @@ class Visualization {
// #endregion
// #region data properties
private environment: Model.Environment;
private pdbId: string;
private bindingSite: Model.BindingSite;
private depiction: Depiction;
......@@ -32,8 +33,9 @@ class Visualization {
public fullScreen: boolean;
// #endregion
constructor(element: HTMLElement, uiParameters: Config.UIParameters = undefined) {
constructor(element: HTMLElement, uiParameters: Config.UIParameters = undefined, env: string = "production") {
this.parent = element;
this.environment = this.parseEnvironment(env);
this.parent.style.cssText += "display: block; height: 100%; width: 100%; position: relative;";
this.visualsMapper = new VisualsMapper();
......@@ -108,11 +110,17 @@ class Visualization {
this.fireExternalLinkEvent(x, Config.interactionClickEvent);
}
private linkMouseOverEventHandler(x: Model.Link) {
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);
this.fireExternalLinkEvent(x, Config.interactionMouseoverEvent);
}
private linkMouseOutEventHandler() {
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);
this.fireExternalLinkLeaveEvent();
}
......@@ -150,16 +158,15 @@ class Visualization {
*/
public initBoundMoleculeInteractions(pdbid: string, bmId: string) {
this.pdbId = pdbid;
let url = Resources.boundMoleculeAPI(pdbid, bmId);
let url = Resources.boundMoleculeAPI(pdbid, bmId, this.environment);
d3.json(url)
.catch(e => this.processError(e, 'No interactions to display'))
.catch(e => this.processError(e, 'No interactions data are available.'))
.then((data: any) => this.addBoundMoleculeInteractions(data, bmId))
.then(() => new Promise(resolve => setTimeout(resolve, 1500)))
.then(() => this.centerScene());
}
// #region public methods
/**
* Download carbohydrate interactions data from PDBe Graph API end point
* /pdb/carbohydrate_polymer_interactions
......@@ -174,7 +181,7 @@ class Visualization {
*/
public initCarbohydratePolymerInteractions(pdbid: string, bmId: string, entityId: string) {
this.pdbId = pdbid;
let url = Resources.carbohydratePolymerAPI(pdbid, bmId, entityId);
let url = Resources.carbohydratePolymerAPI(pdbid, bmId, entityId, this.environment);
d3.json(url)
.catch(e => this.processError(e, 'No interactions to display'))
......@@ -197,10 +204,10 @@ class Visualization {
*/
public initLigandInteractions(pdbId: string, resId: number, chainId: string) {
this.pdbId = pdbId;
let url = Resources.ligandInteractionsAPI(pdbId, chainId, resId);
let url = Resources.ligandInteractionsAPI(pdbId, chainId, resId, this.environment);
d3.json(url)
.catch(e => this.processError(e, 'No interactions to display'))
.catch(e => this.processError(e, 'No interactions data are available.'))
.then((data: any) => this.addLigandInteractions(data))
.then(() => new Promise(resolve => setTimeout(resolve, 1500)))
.then(() => this.centerScene());
......@@ -215,10 +222,10 @@ class Visualization {
* @memberof Visualization
*/
public async initLigandDisplay(ligandId: string) {
const ligandUrl = Resources.ligandAnnotationAPI(ligandId);
const ligandUrl = Resources.ligandAnnotationAPI(ligandId, this.environment);
return d3.json(ligandUrl)
.catch(e => this.processError(e, `Depiction ${ligandId} not found`))
.catch(e => this.processError(e, `Component ${ligandId} was not found.`))
.then((d: any) => this.addDepiction(d, true))
.then(() => this.centerScene());
}
......@@ -559,15 +566,15 @@ class Visualization {
.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) => this.linkMouseOverEventHandler(x))
.on('mouseleave', () => this.linkMouseOutEventHandler());
.on('mouseenter', (x: Model.Link, index: number, group: any) => this.linkMouseOverEventHandler(x, index, group))
.on('mouseleave', (_, index: number, group: any) => this.linkMouseOutEventHandler(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) => this.linkMouseOverEventHandler(x))
.on('mouseleave', () => this.linkMouseOutEventHandler());
.on('mouseenter', (x: Model.Link, y: any, z: any) => this.linkMouseOverEventHandler(x, y, z))
.on('mouseleave', (_, index: number, group: any) => this.linkMouseOutEventHandler(index, group));
}
......@@ -623,7 +630,9 @@ class Visualization {
private processError(e: any, msg: string) {
this.canvas.append('text')
.classed('pdb-lig-env-svg-node', true)
.attr('x', this.parent.clientWidth / 3)
.attr('dominant-baseline', 'center')
.attr('text-anchor', 'middle')
.attr('x', this.parent.clientWidth / 2)
.attr('y', this.parent.clientHeight / 2)
.text(msg)
......@@ -861,5 +870,39 @@ class Visualization {
// .attr('fill', x)
// );
}
}
private parseEnvironment(env: string): Model.Environment {
let environment = undefined;
if (env === undefined) {
environment = Model.Environment.Production
}
else {
env = env.toLowerCase();
switch (env) {
case "production":
case "prod": {
environment = Model.Environment.Production;
break;
}
case "development":
case "dev":
{
environment = Model.Environment.Development;
break;
}
case "internal":
case "int": {
environment = Model.Environment.Internal;
break;
}
default: {
console.log(`Unknown environment ${env}. Using production instead.`);
environment = Model.Environment.Production;
}
}
}
return environment;
}
}
......@@ -2,7 +2,7 @@ namespace Model {
"use strict";
/**
*
* Interaction type
*
* @export
* @enum {number}
......@@ -15,6 +15,19 @@ namespace Model {
GroupGroup
}
/**
* What environment should be used
*
* @export
* @enum {number}
*/
export enum Environment {
Production,
Development,
Internal
}
export class InteractionTypeUtil {
public static parse(value: string) {
if (value === 'atom_atom') return InteractionType.AtomAtom;
......
namespace Resources {
export const apiServer: string = 'https://wwwdev.ebi.ac.uk/pdbe/graph-api';
export const glycanSymbols: string = 'https://pdbe.gitdocs.ebi.ac.uk/web-components/ligand-env/pdb-snfg-visuals.xml';
export const glycanMapping: string = 'https://pdbe.gitdocs.ebi.ac.uk/web-components/ligand-env/het_mapping.json';
export const componentSvgCss: string = 'https://pdbe.gitdocs.ebi.ac.uk/web-components/ligand-env/pdb-ligand-env-svg.css';
namespace Resources {
export const productionAPI: string = 'https://www.ebi.ac.uk/pdbe/graph-api';
export const devAPI: string = 'https://wwwdev.ebi.ac.uk/pdbe/graph-api';
export const intAPI: string = 'https://wwwint.ebi.ac.uk/pdbe/graph-api';
// export const glycanSymbols: string = 'https://pdbe.gitdocs.ebi.ac.uk/web-components/ligand-env/pdb-snfg-visuals.xml';
// export const glycanMapping: string = 'https://pdbe.gitdocs.ebi.ac.uk/web-components/ligand-env/het_mapping.json';
// export const componentSvgCss: string = 'https://pdbe.gitdocs.ebi.ac.uk/web-components/ligand-env/pdb-ligand-env-svg.css';
export const glycanSymbols: string = 'https://www.ebi.ac.uk/pdbe/pdb-component-library/data/ligand-env/pdb-snfg-visuals.xml';
export const glycanMapping: string = 'https://www.ebi.ac.uk/pdbe/pdb-component-library/data/het_mapping.json';
export const componentSvgCss: string = 'https://www.ebi.ac.uk/pdbe/pdb-component-library/data/pdb-ligand-env-svg.css';
export const residueTypeURL: string = "https://www.ebi.ac.uk/pdbe/api/pdb/compound/summary/";
export function ligandAnnotationAPI(ligandName: string): string {
return `https://www.ebi.ac.uk/pdbe/static/files/pdbechem_v2/${ligandName}/annotation`;
export function ligandAnnotationAPI(ligandName: string, env: Model.Environment): string {
let url = '';
switch (env) {
case Model.Environment.Production: {
url = `https://www.ebi.ac.uk/pdbe/static/files/pdbechem_v2/${ligandName}/annotation`;
break;
}
case Model.Environment.Development:
case Model.Environment.Internal:
url = `https://wwwdev.ebi.ac.uk/pdbe/static/files/pdbechem_v2/${ligandName}/annotation`;
}
return url;
}
export function boundMoleculeAPI(pdbId: string, bmId: string): string {
return `${apiServer}/pdb/bound_molecule_interactions/${pdbId}/${bmId}`;
export function boundMoleculeAPI(pdbId: string, bmId: string, env: Model.Environment): string {
let url = '';
switch (env) {
case Model.Environment.Production: {
url = `${productionAPI}/pdb/bound_molecule_interactions/${pdbId}/${bmId}`;
break;
}
case Model.Environment.Development: {
url = `${devAPI}/pdb/bound_molecule_interactions/${pdbId}/${bmId}`;
break;
}
case Model.Environment.Internal: {
url = `${intAPI}/pdb/bound_molecule_interactions/${pdbId}/${bmId}`;
break;
}
}
return url;
}
export function carbohydratePolymerAPI(pdbId: string, bmId: string, entityId: string): string {
return `${apiServer}/pdb/carbohydrate_polymer_interactions/${pdbId}/${bmId}/${entityId}`;
export function carbohydratePolymerAPI(pdbId: string, bmId: string, entityId: string, env: Model.Environment): string {
let url = '';
switch (env) {
case Model.Environment.Production: {
url = `${productionAPI}/pdb/carbohydrate_polymer_interactions/${pdbId}/${bmId}/${entityId}`;
break;
}
case Model.Environment.Development: {
url = `${devAPI}/pdb/carbohydrate_polymer_interactions/${pdbId}/${bmId}/${entityId}`;
break;
}
case Model.Environment.Internal: {
url = `${intAPI}/pdb/carbohydrate_polymer_interactions/${pdbId}/${bmId}/${entityId}`;
break;
}
}
return url;
}
export function ligandInteractionsAPI(pdbId: string, chainId: string, resId: number) {
return `${apiServer}/pdb/bound_ligand_interactions/${pdbId}/${chainId}/${resId}`;
export function ligandInteractionsAPI(pdbId: string, chainId: string, resId: number, env: Model.Environment) {
let url = '';
switch (env) {
case Model.Environment.Production: {
url = `${productionAPI}/pdb/bound_ligand_interactions/${pdbId}/${chainId}/${resId}`;
break;
}
case Model.Environment.Development: {
url = `${devAPI}/pdb/bound_ligand_interactions/${pdbId}/${chainId}/${resId}`;
break;
}
case Model.Environment.Internal: {
url = `${intAPI}/pdb/bound_ligand_interactions/${pdbId}/${chainId}/${resId}`;
break;
}
}
return url;
}
export function residueTypeAPI(chemCompId: string): string {
export function residueTypeAPI(chemCompId: string): string {
return `${residueTypeURL}${chemCompId}`;
}
}
\ No newline at end of file
}
......@@ -9,7 +9,7 @@ let helpLigands = `
<td>
<div class="pdb-lig-env-help-residue" style="background: #C048C0;"></div>
</td>
<td>negativelly charged</td>
<td>negatively charged</td>
</tr>
<tr>
<td>
......@@ -36,7 +36,7 @@ let helpLigands = `
<td>
<div class="pdb-lig-env-help-residue" style="background: #F01505;"></div>
</td>
<td>positivelly charged</td>
<td>positively charged</td>
<td>
<div class="pdb-lig-env-help-residue" style="background: #F2F2F2;"></div>
</td>
......@@ -98,19 +98,19 @@ let helpBonds = `
</td>
<td>vdw</td>
</tr>
</table>
<table class="pdb-lig-env-help-table" style="margin-top: 5px;">
<tr>
<td>
<hr style="border: 0 none; border-top: 5px solid black; background: none; height: 0;" />
</td>
<td>covalent</td>
<td>
<hr style="border: 0 none; border-top: 5px dashed black; background: none; height: 0;" />
</td>
<td>non-covalent</td>
</tr>
</table>`
// <table class="pdb-lig-env-help-table" style="margin-top: 5px;">
// <tr>
// <td>
// <hr style="border: 0 none; border-top: 5px solid black; background: none; height: 0;" />
// </td>
// <td>covalent</td>
// <td>
// <hr style="border: 0 none; border-top: 5px dashed black; background: none; height: 0;" />
// </td>
// <td>non-covalent</td>
// </tr>
// </table>`
// #endregion help
......@@ -232,7 +232,7 @@ class UI {
if (params.reinitialize) {
dynamicPanel.append('i')
.attr('id', 'pdb-lig-env-home-btn')
.attr('title', 'Reset Camera')
.attr('title', 'Reinitialize')
.attr('class', 'icon icon-common icon-sync-alt')
.on('click', () => this.reinitialize());
}
......
......@@ -78,6 +78,10 @@
stroke: black;
}
.pdb-lig-env-svg-bond-highlighted line {
stroke-width: 10px !important;
}
.pdb-lig-env-svg-node circle {
stroke-width: 3px;
}
......
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