Browse Source

load row title click && 2 polymer molstar components

bioinsilico 2 years ago
parent
commit
b10e68097d

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "@rcsb/rcsb-saguaro-3d",
-  "version": "2.2.0-uniprot-msa.2",
+  "version": "2.2.0-uniprot-msa.3",
   "description": "RCSB Molstar/Saguaro Web App",
   "main": "build/dist/app.js",
   "files": [

+ 1 - 1
src/RcsbFvSequence/SequenceViews/RcsbView/PfvManagerFactoryImplementation/UniprotPfvComponents/UniprotRowMarkComponent.tsx

@@ -26,7 +26,7 @@ interface UniprotRowMarkState {
 
 export class UniprotRowMarkComponent extends React.Component <UniprotRowMarkInterface,UniprotRowMarkState> {
 
-    private readonly HOVER_COLOR: string = "#666";
+    private readonly HOVER_COLOR: string = "rgb(51, 122, 183)";
     private readonly ACTIVE_COLOR: string ="rgb(51, 122, 183)";
     private subscription: Subscription;
 

+ 0 - 7
src/RcsbFvSequence/SequenceViews/RcsbView/PfvManagerFactoryImplementation/UniprotPfvComponents/UniprotRowTitleCheckbox.tsx

@@ -51,16 +51,9 @@ export class UniprotRowTitleCheckbox extends React.Component <UniprotRowTitleChe
         this.subscription = this.props.stateManager.subscribe<"representation-change",{label:string;isHidden:boolean;} & {tag:UniprotRowTitleCheckboxInterface["tag"];isHidden:boolean;pdb:{entryId:string;entityId:string;};}>((o)=>{
             if(o.type == "representation-change" && o.view == "3d-view" && o.data)
                 this.structureViewerRepresentationChange(o.data);
-            if(o.type == "representation-change" && o.view == "1d-view" && o.data)
-                this.sequenceViewerRepresentationChange(o.data);
         })
     }
 
-    private sequenceViewerRepresentationChange(d:{tag:UniprotRowTitleCheckboxInterface["tag"];isHidden:boolean;pdb:{entryId:string;entityId:string;};}): void {
-        if(this.props.tag == "aligned" && d.tag == "polymer" && this.props.entityId == d.pdb.entityId && this.props.entryId == d.pdb.entryId)
-            this.setState({checked:!d.isHidden})
-    }
-
     private structureViewerRepresentationChange(d:{label:string;isHidden:boolean;}): void {
         const row: string[] = d.label.split(TagDelimiter.entity);
         const suffix: string = row.pop()!;

+ 32 - 5
src/RcsbFvSequence/SequenceViews/RcsbView/PfvManagerFactoryImplementation/UniprotPfvComponents/UniprotRowTitleComponent.tsx

@@ -14,26 +14,32 @@ import {RcsbFvStateManager} from "../../../../../RcsbFvState/RcsbFvStateManager"
 import {Subscription} from "rxjs";
 import {TagDelimiter} from "@rcsb/rcsb-saguaro-app";
 import {UniprotRowTitleCheckbox} from "./UniprotRowTitleCheckbox";
+import {MouseEvent} from "react";
 
 interface UniprotRowTitleInterface extends RcsbFvRowTitleInterface {
     alignmentContext: AlignmentRequestContextType;
     targetAlignment: TargetAlignment;
     stateManager:RcsbFvStateManager;
-
+    titleClick: ()=>void;
 }
 
 interface UniprotRowTitleState {
     expandTitle: boolean;
     disabled: boolean;
+    titleColor: string;
 }
 
 export class UniprotRowTitleComponent extends React.Component <UniprotRowTitleInterface, UniprotRowTitleState> {
 
     private readonly configData : RcsbFvRowConfigInterface;
     private subscription: Subscription;
+    private readonly HOVER_COLOR: string = "#ccc";
+    private readonly ACTIVE_COLOR: string ="rgb(51, 122, 183)";
+
     readonly state = {
         expandTitle: false,
-        disabled: true
+        disabled: true,
+        titleColor: this.HOVER_COLOR
     };
 
     constructor(props: UniprotRowTitleInterface) {
@@ -43,7 +49,14 @@ export class UniprotRowTitleComponent extends React.Component <UniprotRowTitleIn
 
     public render(): JSX.Element{
        return <div style={{textAlign:"right"}}>
-           <a style={{MozUserSelect:"none", WebkitUserSelect:"none", msUserSelect:"none"}} href={`/structure/${TagDelimiter.parseEntity(this.props.targetAlignment.target_id!).entryId}#entity-${TagDelimiter.parseEntity(this.props.targetAlignment.target_id!).entityId}`}>{this.props.targetAlignment.target_id}</a>
+           <div style={{
+               MozUserSelect:"none",
+               WebkitUserSelect:"none",
+               msUserSelect:"none",
+               display:"inline-block",
+               color: this.state.titleColor,
+               cursor: "pointer"
+           }} onClick={(e: MouseEvent)=>this.click(e)} onMouseOver={()=>this.hover(true)} onMouseOut={()=>this.hover(false)}>{this.props.targetAlignment.target_id}</div>
            <UniprotRowTitleCheckbox disabled={this.state.disabled} {...TagDelimiter.parseEntity(this.props.targetAlignment.target_id!)} tag={"aligned"} stateManager={this.props.stateManager}/>
            <UniprotRowTitleCheckbox disabled={this.state.disabled} {...TagDelimiter.parseEntity(this.props.targetAlignment.target_id!)} tag={"polymer"} stateManager={this.props.stateManager}/>
            <UniprotRowTitleCheckbox disabled={this.state.disabled} {...TagDelimiter.parseEntity(this.props.targetAlignment.target_id!)} tag={"non-polymer"} stateManager={this.props.stateManager}/>
@@ -68,10 +81,24 @@ export class UniprotRowTitleComponent extends React.Component <UniprotRowTitleIn
     private modelChange(): void {
         if(this.props.targetAlignment.target_id && this.props.stateManager.assemblyModelSate.getMap().has(this.props.targetAlignment.target_id)){
             if(this.state.disabled)
-                this.setState({disabled:false})
+                this.setState({disabled:false, titleColor:this.ACTIVE_COLOR});
         }else if(!this.state.disabled){
-            this.setState({disabled:true})
+            this.setState({disabled:true, titleColor:this.HOVER_COLOR});
         }
     }
 
+    private hover(flag: boolean): void {
+        if(this.state.disabled && flag)
+            this.setState({titleColor:this.ACTIVE_COLOR});
+        else if(this.state.disabled && !flag)
+            this.setState({titleColor:this.HOVER_COLOR});
+    }
+
+    private click(e: MouseEvent){
+        if(e.shiftKey)
+            document.location.href = `/structure/${TagDelimiter.parseEntity(this.props.targetAlignment.target_id!).entryId}#entity-${TagDelimiter.parseEntity(this.props.targetAlignment.target_id!).entityId}`;
+        else
+            this.props.titleClick();
+    }
+
 }

+ 2 - 1
src/RcsbFvSequence/SequenceViews/RcsbView/PfvManagerFactoryImplementation/UniprotPfvManagerFactory.ts

@@ -66,7 +66,8 @@ class UniprotPfvManager<R> extends AbstractPfvManager<{upAcc:string},R,{context:
                                 rowTitleAdditionalProps:{
                                     alignmentContext,
                                     targetAlignment,
-                                    stateManager: this.stateManager
+                                    stateManager: this.stateManager,
+                                    titleClick: ()=> this.loadAlignment(alignmentContext,targetAlignment)
                                 }
                             }
                         });

+ 3 - 7
src/RcsbFvStructure/StructureViewerBehaviour/UniprotBehaviour.ts

@@ -149,15 +149,11 @@ class UniprotBehaviour<R> implements StructureViewerBehaviourInterface {
                     }
                     break;
                 case "polymer":
-                    this.stateManager.assemblyModelSate.getModelChainInfo(`${data.pdb.entryId}${TagDelimiter.entity}${data.pdb.entityId}`)?.chains.forEach(chain=>{
-                        chain.operators.forEach(operatorInfo=>{
-                            const componentId: string = `${data.pdb.entryId}${TagDelimiter.entity}${data.pdb.entityId}${TagDelimiter.instance}${chain.label}${TagDelimiter.assembly}${operatorInfo.ids.join(",")}${TagDelimiter.assembly}${data.tag}`;
-                            this.structureViewer.displayComponent(componentId, !data.isHidden);
-                        });
-                    });
+                    const componentId: string = `${data.pdb.entryId}${TagDelimiter.entity}${data.pdb.entityId}${TagDelimiter.assembly}${data.tag}`;
+                    this.structureViewer.displayComponent(componentId, !data.isHidden);
                     break;
                 case "non-polymer":
-                    createSelectionExpressions(data.pdb.entryId).map(expression=>expression.tag).filter(tag=>tag!="water").forEach(tag=>{
+                    createSelectionExpressions(data.pdb.entryId).map(expression=>expression.tag).filter(tag=>(tag!="water" && tag != "polymer")).forEach(tag=>{
                         const componentId: string = `${data.pdb.entryId}${TagDelimiter.entity}${data.pdb.entityId}${TagDelimiter.assembly}${tag}`;
                         this.structureViewer.displayComponent(componentId, !data.isHidden);
                     });

+ 63 - 26
src/RcsbFvStructure/StructureViewers/MolstarViewer/TrajectoryPresetProvider/AlignmentRepresentationPresetProvider.ts

@@ -48,43 +48,80 @@ export const AlignmentRepresentationPresetProvider = StructureRepresentationPres
             const entryId = params.pdb?.entryId!;
             const entityId = params.pdb?.entityId!;
             const l = StructureElement.Location.create(structure);
+            const unit = structure.units.find((u,n)=>u.model.atomicHierarchy.chains.label_entity_id.value(n) === params.pdb?.entityId);
+            if(!unit)
+                return;
+            StructureElement.Location.set(l, structure, unit, unit.elements[0]);
+            const alignedAsymId = SP.chain.label_asym_id(l);
+            const alignedOperators = SP.unit.pdbx_struct_oper_list_ids(l);
+            const alignedOperatorName = SP.unit.operator_name(l);
+            const alignedType = SP.entity.type(l);
+            if(alignedType != "polymer")
+                return;
+            let comp = await plugin.builders.structure.tryCreateComponentFromExpression(
+                structureCell,
+                MS.struct.generator.atomGroups({
+                    'chain-test': MS.core.logic.and([
+                        MS.core.rel.eq([MS.ammp('label_asym_id'), alignedAsymId]),
+                        MS.core.rel.eq([MS.acp('operatorName'), alignedOperatorName])
+                    ])
+                }),
+                uniqid(`${entryId}${TagDelimiter.entity}${entityId}${TagDelimiter.instance}${alignedAsymId}${TagDelimiter.entity}${alignedOperators.join(",")}`),
+                {
+                    label: `${entryId}${TagDelimiter.entity}${entityId}${TagDelimiter.instance}${alignedAsymId}${TagDelimiter.assembly}${alignedOperators.join(",")}${TagDelimiter.assembly}${alignedType}`
+                }
+            );
+            //TODO This needs to be called after tryCreateComponentFromExpression
+            let reprBuild = reprBuilder(plugin, {
+                ignoreHydrogens: true,
+                ignoreLight: false,
+                quality: "auto"
+            });
+            reprBuild.builder.buildRepresentation(reprBuild.update, comp, {
+                color: PLDDTConfidenceColorThemeProvider.isApplicable({ structure }) ? PLDDTConfidenceColorThemeProvider.name as ColorTheme.BuiltIn : "chain-id",
+                type: "cartoon"
+            });
+            await reprBuild.update.commit({ revertOnError: false });
+
+            const expressions = []
             const asymObserved: {[key:string]:boolean} = {};
-            for(const unit of structure.units) {
+            for(const unit of structure.units){
                 StructureElement.Location.set(l, structure, unit, unit.elements[0]);
                 const asymId = SP.chain.label_asym_id(l);
-                const operators = SP.unit.pdbx_struct_oper_list_ids(l);
                 const operatorName = SP.unit.operator_name(l);
+                if(asymId == alignedAsymId && operatorName == alignedOperatorName)
+                    continue;
                 if(asymObserved[`${asymId}${TagDelimiter.assembly}${operatorName}`])
                     continue;
                 asymObserved[`${asymId}${TagDelimiter.assembly}${operatorName}`] = true;
                 const type = SP.entity.type(l);
                 if (type == "polymer") {
-                    const comp = await plugin.builders.structure.tryCreateComponentFromExpression(
-                        structureCell,
-                        MS.struct.generator.atomGroups({
-                            'chain-test': MS.core.logic.and([
-                                MS.core.rel.eq([MS.ammp('label_asym_id'), asymId]),
-                                MS.core.rel.eq([MS.acp('operatorName'), operatorName])
-                            ])
-                        }),
-                        uniqid(`${entryId}${TagDelimiter.entity}${entityId}${TagDelimiter.instance}${asymId}${TagDelimiter.entity}${operators.join(",")}`),
-                        {
-                            label: `${entryId}${TagDelimiter.entity}${entityId}${TagDelimiter.instance}${asymId}${TagDelimiter.assembly}${operators.join(",")}${TagDelimiter.assembly}${type}`
-                        }
-                    );
-                    //TODO This needs to be called after tryCreateComponentFromExpression
-                    const { update, builder } = reprBuilder(plugin, {
-                        ignoreHydrogens: true,
-                        ignoreLight: false,
-                        quality: "auto"
-                    });
-                    builder.buildRepresentation(update, comp, {
-                        color: PLDDTConfidenceColorThemeProvider.isApplicable({ structure }) ? PLDDTConfidenceColorThemeProvider.name as ColorTheme.BuiltIn : "chain-id",
-                        type: "cartoon"
-                    });
-                    await update.commit({ revertOnError: false });
+                    expressions.push(MS.core.logic.and([
+                        MS.core.rel.eq([MS.ammp('label_asym_id'), asymId]),
+                        MS.core.rel.eq([MS.acp('operatorName'), operatorName])
+                    ]))
                 }
             }
+            comp = await plugin.builders.structure.tryCreateComponentFromExpression(
+                structureCell,
+                MS.struct.generator.atomGroups({
+                    'chain-test': MS.core.logic.or(expressions)
+                }),
+                uniqid(`${entryId}${TagDelimiter.entity}${entityId}${TagDelimiter.assembly}${alignedType}`),
+                {
+                    label: `${entryId}${TagDelimiter.entity}${entityId}${TagDelimiter.assembly}${alignedType}`
+                }
+            );
+            reprBuild = reprBuilder(plugin, {
+                ignoreHydrogens: true,
+                ignoreLight: false,
+                quality: "auto"
+            });
+            reprBuild.builder.buildRepresentation(reprBuild.update, comp, {
+                color: PLDDTConfidenceColorThemeProvider.isApplicable({ structure }) ? PLDDTConfidenceColorThemeProvider.name as ColorTheme.BuiltIn : "chain-id",
+                type: "cartoon"
+            });
+            await reprBuild.update.commit({ revertOnError: false });
             for(const expression of createSelectionExpressions(entryId)){
                 if(expression.tag == "polymer")
                     continue;