Prechádzať zdrojové kódy

first version of resizable panels

bioinsilico 3 rokov pred
rodič
commit
fe088dfb70

+ 20 - 20
package-lock.json

@@ -9196,9 +9196,9 @@
       }
     },
     "@rcsb/rcsb-saguaro-app": {
-      "version": "2.0.0-beta.3",
-      "resolved": "https://registry.npmjs.org/@rcsb/rcsb-saguaro-app/-/rcsb-saguaro-app-2.0.0-beta.3.tgz",
-      "integrity": "sha512-3uY+FUknKkM1V6kfgJ+LFRKfCgWKV3vG9wifznZpjw78rmKjWRC8GAF9v6eKVHAsLpANVapKlzmYvNwqoQuMCQ==",
+      "version": "2.0.0-beta.4",
+      "resolved": "https://registry.npmjs.org/@rcsb/rcsb-saguaro-app/-/rcsb-saguaro-app-2.0.0-beta.4.tgz",
+      "integrity": "sha512-5XKQj/AWH8BK3CA73ZvnL+W6Ygxbijl3SK40SPO43yeP/wKqHvS4Kwq2C00k5ccFBO4TtGc8IXzstAm5CqtU1Q==",
       "requires": {
         "@rcsb/rcsb-saguaro": "^1.8.3",
         "@rcsb/rcsb-saguaro-api": "^1.0.6",
@@ -18626,9 +18626,9 @@
       }
     },
     "victory": {
-      "version": "35.9.0",
-      "resolved": "https://registry.npmjs.org/victory/-/victory-35.9.0.tgz",
-      "integrity": "sha512-FT6mZespzmFk0+t2N0q3/h3YcZVUzm2SVBDbrETb6/ZQdgCx0dthtvpWrss9AqLsVMo71Morz+GyvSr3hdT46Q==",
+      "version": "35.9.1",
+      "resolved": "https://registry.npmjs.org/victory/-/victory-35.9.1.tgz",
+      "integrity": "sha512-nVVRXb2wmvqBjgwe36gFOHJaNBzskgcgH3LiPL7EmWVysQcyoQeiQnIPWa/8i9WjHMZNMeOqq7TELKF0ntu9Sg==",
       "requires": {
         "victory-area": "^35.9.0",
         "victory-axis": "^35.9.0",
@@ -18639,7 +18639,7 @@
         "victory-candlestick": "^35.9.0",
         "victory-chart": "^35.9.0",
         "victory-core": "^35.9.0",
-        "victory-create-container": "^35.9.0",
+        "victory-create-container": "^35.9.1",
         "victory-cursor-container": "^35.9.0",
         "victory-errorbar": "^35.9.0",
         "victory-group": "^35.9.0",
@@ -18652,9 +18652,9 @@
         "victory-selection-container": "^35.9.0",
         "victory-shared-events": "^35.9.0",
         "victory-stack": "^35.9.0",
-        "victory-tooltip": "^35.9.0",
+        "victory-tooltip": "^35.9.1",
         "victory-voronoi": "^35.9.0",
-        "victory-voronoi-container": "^35.9.0",
+        "victory-voronoi-container": "^35.9.1",
         "victory-zoom-container": "^35.9.0"
       }
     },
@@ -18784,16 +18784,16 @@
       }
     },
     "victory-create-container": {
-      "version": "35.9.0",
-      "resolved": "https://registry.npmjs.org/victory-create-container/-/victory-create-container-35.9.0.tgz",
-      "integrity": "sha512-yC5NOA9LswYOxG6VXwPE1y2lSzYoKSovJO2MKwKmhXUzJtUJMtju67Y/d2VFkYTJMDC8LUW+9AEP6mrZ45wvDA==",
+      "version": "35.9.1",
+      "resolved": "https://registry.npmjs.org/victory-create-container/-/victory-create-container-35.9.1.tgz",
+      "integrity": "sha512-SzVZUsYxGVuGGAOeCdZgLITMM1nTELrtnJjL0J3vwW8l9QW77LDEi/oRLG+052zNupJGYaEU2kCt2sqTctraRw==",
       "requires": {
         "lodash": "^4.17.19",
         "victory-brush-container": "^35.9.0",
         "victory-core": "^35.9.0",
         "victory-cursor-container": "^35.9.0",
         "victory-selection-container": "^35.9.0",
-        "victory-voronoi-container": "^35.9.0",
+        "victory-voronoi-container": "^35.9.1",
         "victory-zoom-container": "^35.9.0"
       }
     },
@@ -18958,9 +18958,9 @@
       }
     },
     "victory-tooltip": {
-      "version": "35.9.0",
-      "resolved": "https://registry.npmjs.org/victory-tooltip/-/victory-tooltip-35.9.0.tgz",
-      "integrity": "sha512-Jj4Y/HQbkWs4v+kjJCs/eVWlzckIwV3gcGSy0HJvv03sXVf2mwFEAGS7/F4IOCaJGcsJlTC4m30yB+nhZgqlgQ==",
+      "version": "35.9.1",
+      "resolved": "https://registry.npmjs.org/victory-tooltip/-/victory-tooltip-35.9.1.tgz",
+      "integrity": "sha512-VQmH2Rf9+bFSoFKXKezsFTW9vF0l+0WAmKVueeSNTyxXF9nQnaqKPtuz9w29CimVbYe3VCJ2HHGWX36bzwLoHg==",
       "requires": {
         "lodash": "^4.17.19",
         "prop-types": "^15.5.8",
@@ -18979,16 +18979,16 @@
       }
     },
     "victory-voronoi-container": {
-      "version": "35.9.0",
-      "resolved": "https://registry.npmjs.org/victory-voronoi-container/-/victory-voronoi-container-35.9.0.tgz",
-      "integrity": "sha512-T95+eR0tjj9vAzzGk/c/PiJ0xunMsDzSa912zMExt+fDDtVXfd0xO9ji1qSWZldZo9spUUxyg01DK/X2VVsKow==",
+      "version": "35.9.1",
+      "resolved": "https://registry.npmjs.org/victory-voronoi-container/-/victory-voronoi-container-35.9.1.tgz",
+      "integrity": "sha512-1ex52heROKg62S8aqBh2tEW+8fjwXD+DNfQxH2hjkUc+kl3K8BVjwsl/c//DM32lvjbRoBv3BifJiIsfDbnBGg==",
       "requires": {
         "delaunay-find": "0.0.6",
         "lodash": "^4.17.19",
         "prop-types": "^15.5.8",
         "react-fast-compare": "^2.0.0",
         "victory-core": "^35.9.0",
-        "victory-tooltip": "^35.9.0"
+        "victory-tooltip": "^35.9.1"
       }
     },
     "victory-zoom-container": {

+ 1 - 1
package.json

@@ -78,7 +78,7 @@
   "dependencies": {
     "@rcsb/rcsb-molstar": "file:../rcsb-molstar",
     "@rcsb/rcsb-saguaro": "^1.8.0",
-    "@rcsb/rcsb-saguaro-app": "^2.0.0-beta.3",
+    "@rcsb/rcsb-saguaro-app": "^2.0.0-beta.4",
     "molstar": "^2.0.7",
     "react-select": "^3.0.8"
   },

+ 53 - 9
src/RcsbFv3D/RcsbFv3DComponent.tsx

@@ -16,7 +16,7 @@ import {
 import {Subscription} from "rxjs";
 import {PluginContext} from "molstar/lib/mol-plugin/context";
 import {RcsbFvSelection} from "../RcsbFvSelection/RcsbFvSelection";
-import {CSSProperties} from "react";
+import {CSSProperties, MouseEvent} from "react";
 
 export interface RcsbFv3DComponentInterface {
     structurePanelConfig:RcsbFvStructureInterface;
@@ -32,16 +32,23 @@ export interface RcsbFv3DComponentInterface {
     fullScreen: boolean;
 }
 
-export class RcsbFv3DComponent extends React.Component <RcsbFv3DComponentInterface, {structurePanelConfig:RcsbFvStructureInterface, sequencePanelConfig:RcsbFvSequenceInterface}> {
+interface RcsbFv3DComponentState {
+    structurePanelConfig:RcsbFvStructureInterface;
+    sequencePanelConfig:RcsbFvSequenceInterface;
+    pfvScreenFraction: number;
+}
+
+export class RcsbFv3DComponent extends React.Component <RcsbFv3DComponentInterface, RcsbFv3DComponentState> {
 
-    private readonly pfvScreenFraction = 0.55;
     private readonly plugin: SaguaroPluginInterface;
     private readonly selection: RcsbFvSelection = new RcsbFvSelection();
     private subscription: Subscription;
+    private readonly ROOT_DIV_ID: string = "rootPanel";
 
-    readonly state: {structurePanelConfig:RcsbFvStructureInterface, sequencePanelConfig:RcsbFvSequenceInterface} = {
+    readonly state: RcsbFv3DComponentState = {
         structurePanelConfig: this.props.structurePanelConfig,
-        sequencePanelConfig: this.props.sequencePanelConfig
+        sequencePanelConfig: this.props.sequencePanelConfig,
+        pfvScreenFraction: 0.55
     }
 
     constructor(props: RcsbFv3DComponentInterface) {
@@ -51,7 +58,8 @@ export class RcsbFv3DComponent extends React.Component <RcsbFv3DComponentInterfa
 
     render(): JSX.Element {
         return (
-            <div style={RcsbFv3DComponent.mainDivCssConfig(this.props.cssConfig?.rootPanel)} className={ this.props.fullScreen ? classes.fullScreen+" "+classes.rcsbFvMain : classes.rcsbFvMain} >
+            <div style={RcsbFv3DComponent.mainDivCssConfig(this.props.cssConfig?.rootPanel)} className={ this.props.fullScreen ? classes.fullScreen : ""} >
+                <div id={this.ROOT_DIV_ID} className={classes.rcsbFvMain} onMouseMove={(evt: MouseEvent<HTMLDivElement>)=>{this.mouseMove(evt)}} onMouseUp={ (e)=>{this.splitPanelMouseUp()} }>
                     <div style={this.structureCssConfig(this.props.cssConfig?.structurePanel)} className={classes.rcsbFvCell}>
                         <RcsbFvStructure
                             {...this.state.structurePanelConfig}
@@ -72,6 +80,12 @@ export class RcsbFv3DComponent extends React.Component <RcsbFv3DComponentInterfa
                             unmount={this.props.unmount}
                         />
                     </div>
+                    <div
+                        onMouseDown={ ()=>{this.splitPanelMouseDown()} }
+                        className={classes.rcsbFvSplitPanel}
+                        style={{right:Math.round((1-this.state.pfvScreenFraction)*100)+"%"}}
+                    />
+                </div>
             </div>
         );
     }
@@ -85,17 +99,17 @@ export class RcsbFv3DComponent extends React.Component <RcsbFv3DComponentInterfa
     }
 
     private structureCssConfig(css: CSSProperties | undefined): CSSProperties{
-        const widthFr: number = Math.round((1-this.pfvScreenFraction)*100);
+        const widthFr: number = Math.round((1-this.state.pfvScreenFraction)*100);
         const cssWidth: string = widthFr.toString()+"%";
         const cssHeight: string = "100%";
         return {...{width:cssWidth, height:cssHeight, zIndex:100}, ...css };
     }
 
     private sequenceCssConfig(css: CSSProperties | undefined): CSSProperties{
-        const widthFr: number = Math.round((this.pfvScreenFraction)*100);
+        const widthFr: number = Math.round((this.state.pfvScreenFraction)*100);
         const cssWidth: string = widthFr.toString()+"%";
         const cssHeight: string = "100%";
-        return {...{width:cssWidth, height:cssHeight, overflow:"auto", paddingBottom:5}, ...css };
+        return {...{width:cssWidth, height:cssHeight, overflowY:"auto", overflowX:"hidden", paddingBottom:5}, ...css };
     }
 
     private static mainDivCssConfig(css: CSSProperties | undefined): CSSProperties{
@@ -131,4 +145,34 @@ export class RcsbFv3DComponent extends React.Component <RcsbFv3DComponentInterfa
         }
     }
 
+    private splitPanelMouseDown(): void {
+        const element: HTMLElement | null = document.getElementById(this.ROOT_DIV_ID);
+        if(!element)return;
+        element.style.cursor = "ew-resize";
+        document.body.classList.add(classes.disableTextSelection);
+        this.resize = (evt: MouseEvent<HTMLDivElement>)=>{
+            const rect: DOMRect | undefined = element.getBoundingClientRect();
+            const x: number = evt.clientX - rect.left;
+            this.setState({pfvScreenFraction:x/rect.width});
+        };
+    }
+
+    private splitPanelMouseUp(): void {
+        if(typeof this.resize === "function") {
+            const element: HTMLElement | null = document.getElementById(this.ROOT_DIV_ID);
+            if (!element) return;
+            element.style.cursor = "auto";
+            document.body.classList.remove(classes.disableTextSelection);
+            window.dispatchEvent(new Event('resize'));
+            this.resize = null;
+        }
+    }
+
+    private mouseMove(evt: MouseEvent<HTMLDivElement>): void{
+        if(typeof this.resize === "function")
+            this.resize(evt);
+    }
+
+    private resize: null | ((evt: MouseEvent<HTMLDivElement>)=>void) = null;
+
 }

+ 20 - 4
src/styles/RcsbFvStyle.module.scss

@@ -1,10 +1,19 @@
+.disableTextSelection {
+  -webkit-touch-callout: none;
+  -webkit-user-select: none;
+  -khtml-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+}
+
 .fullScreen {
   position: fixed;
   top: 0;
   left: 0;
-  height: 100%;
-  width: 100%;
-  overflow: auto;
+  bottom: 0;
+  right: 0;
+  z-index: 10;
 }
 
 .rcsbFvMain * {
@@ -15,10 +24,17 @@
   width: 100%;
   height: 100%;
   background-color: #fff;
-  z-index: 10;
   display: flex;
   flex-wrap: nowrap;
   flex-direction: row-reverse;
+  position: relative;
+}
+
+.rcsbFvSplitPanel{
+  height:100%;
+  border-left: 1px solid rgb(236, 242, 248);
+  position: absolute;
+  cursor: ew-resize;
 }
 
 .rcsbFvCell {