Browse Source

Issue #836: autoscaling to reach responsiveness

cycle20 1 year ago
parent
commit
50cd7c3c71
2 changed files with 119 additions and 45 deletions
  1. 2 34
      src/TmFv3DApp/index.ts
  2. 117 11
      src/TmFv3DApp/tmdet-viewer/TmFv1DComponent.tsx

+ 2 - 34
src/TmFv3DApp/index.ts

@@ -1,11 +1,10 @@
 import { RcsbFv3DCustomInterface} from "../RcsbFv3D/RcsbFv3DCustom";
 import { DebugUtil } from "./tmdet-extension/debug-utils";
-import { createFeatureViewerConfing, setRegionColors } from "./FeatureViewConfig";
+import { createFeatureViewerConfing } from "./FeatureViewConfig";
 import { fetchDescriptor, registerRegionDescriptorData } from "./UniTmpHelper";
 import { TmFv3DCustom } from "./tmdet-viewer/TmFv3DCustom";
-import { RcsbFv } from "@rcsb/rcsb-saguaro";
 import { updateSiteColors } from "./tmdet-extension/tmdet-color-theme";
-import { TmFv1DElement } from "./tmdet-viewer/TmFv1DComponent";
+import { createRcsbFeatureViewer, TmFv1DElement } from "./tmdet-viewer/TmFv1DComponent";
 
 customElements.define("tm-saguaro-1d", TmFv1DElement);
 
@@ -63,37 +62,6 @@ async function createConfig(configParams: any): Promise<RcsbFv3DCustomInterface>
     return panel3dConfig;
 }
 
-/**
- * Create an Rcsb Saguaro 1D viewer instance.
- *
- * @param elementId id of parent element
- * @param url source of JSON config
- * @param side1 side1 paramter to update site colors, if it is needed
- */
-async function createRcsbFeatureViewer(params: {
-    elementId: string, url: string, side1: string, trackWidth?: number, rowTitleWidth?: number }): Promise<RcsbFv> {
-
-    updateSiteColors(params.side1 as any);
-
-    const featureTracks = await fetchDescriptor(params.url);
-    const blockConfig = featureTracks.blockConfig;
-    const boardConfig = blockConfig[0].featureViewConfig[0].boardConfig;
-    boardConfig.trackWidth = params.trackWidth ?? 600;
-    boardConfig.rowTitleWidth = params.rowTitleWidth ?? 160;
-
-    const rowConfig = blockConfig[0].featureViewConfig[0].rowConfig;
-    setRegionColors(rowConfig);
-
-    const pfv = new RcsbFv({
-        boardConfigData: boardConfig,
-        rowConfigData: rowConfig,
-        elementId: params.elementId
-    });
-    (window as any).pfv = pfv;
-    console.log(pfv);
-    return new Promise<RcsbFv>((resolve) => { resolve(pfv); });
-}
-
 export {
     DebugUtil,
     createRcsb3DViewer,

+ 117 - 11
src/TmFv3DApp/tmdet-viewer/TmFv1DComponent.tsx

@@ -1,7 +1,15 @@
 import React from 'react';
 import { createRoot } from 'react-dom/client';
+import { updateSiteColors } from '../tmdet-extension/tmdet-color-theme';
+import { RcsbFv, RcsbFvBoardConfigInterface } from '@rcsb/rcsb-saguaro';
+import { fetchDescriptor } from '../UniTmpHelper';
+import { setRegionColors } from '../FeatureViewConfig';
 
-export type TmFv1DParams = {
+const defaultViewerWidth = 600;
+const defaultRowTitleWidth = 100;
+const ULTIMATE_GAP_CONSTANT = 4; // I do not know why it is 4.
+
+type TmFv1DParams = {
     elementId: string,
     url: string,
     side1: string,
@@ -9,7 +17,13 @@ export type TmFv1DParams = {
     rowTitleWidth?: number
 };
 
-export class TmFv1D extends React.Component {
+type TmFv1DState = {
+    featureViewer?: RcsbFv,
+    num?: number
+};
+
+
+export class TmFv1D extends React.Component<TmFv1DParams, TmFv1DState> {
 
     protected containerRef = React.createRef<HTMLDivElement>();
 
@@ -17,20 +31,39 @@ export class TmFv1D extends React.Component {
         super(props);
     }
 
-    public componentDidMount(): void {
+    public async componentDidMount(): Promise<void> {
+        console.log('PROPS', this.props);
+
+        await createRcsbFeatureViewer({
+            elementId: this.props.elementId,
+            url: this.props.url,
+            side1: this.props.side1,
+            rowTitleWidth: this.props.rowTitleWidth,
+            trackWidth: this.props.trackWidth
+        });
+
         new ResizeObserver(this.resize)
             .observe(this.containerRef.current as Element);
     }
 
-    resize() {
-        console.log('Observer works');
+    resize(entries: ResizeObserverEntry[], observer: ResizeObserver) {
+        console.log('Observer params', [ entries, observer ]);
+        const currentId = entries[0].target.id;
+        const observerEntry = entries[0];
+        const featureViewer = featureViewerRegistry.get(currentId) as RcsbFv;
+        const boardConfig = featureViewer.getBoardConfig();
+        boardConfig.trackWidth = observerEntry.contentRect.width - boardConfig.rowTitleWidth!;
+        scaleBoardConfigWidths(currentId, boardConfig, observerEntry);
+
+        featureViewer.updateBoardConfig({ boardConfigData: boardConfig });
     }
 
     public render(): JSX.Element {
         return (
-            <div ref={this.containerRef} style={{ borderWidth: "1px", borderStyle: "solid", borderBlockColor: "black" }}>
-                Hello
-            </div>
+            <div ref={this.containerRef}
+                id={ this.props.elementId }
+                style={{ borderWidth: "0px", padding: "0px" }}
+            />
         );
     }
 
@@ -38,11 +71,84 @@ export class TmFv1D extends React.Component {
 
 export class TmFv1DElement extends HTMLElement {
 
-    constructor() {
-        super();
+    connectedCallback() {
         const root = createRoot(this);
+
+        const elementId = this.getAttribute("elementId")!;
+        const url = this.getAttribute("url")!;
+        const side1 = this.getAttribute("side1")!;
+        const calculatedWidth = calculateViewerWidth(this.parentElement);
+        const rowTitleWidth = parseInt(this.getAttribute("rowTitleWidth")!)
+            || defaultRowTitleWidth;
+        const trackWidth = (parseInt(this.getAttribute("trackWidth")!)
+            || calculatedWidth) - rowTitleWidth;
+        console.log('Widths:', [ rowTitleWidth, trackWidth ]);
+
         root.render(
-            <TmFv1D></TmFv1D>
+            <TmFv1D
+                elementId={ elementId }
+                url={ url }
+                side1={ side1 }
+                trackWidth={ trackWidth }
+                rowTitleWidth={ rowTitleWidth }
+            />
         );
     }
 }
+
+function calculateViewerWidth(parent: HTMLElement|null) {
+    if (!parent) {
+        return defaultViewerWidth;
+    }
+    const boundingRect = parent.getBoundingClientRect();
+    const computedStyle = window.getComputedStyle(parent);
+    const extraWidth = parseInt(computedStyle.paddingLeft)
+        + parseInt(computedStyle.paddingRight)
+        + parseInt(computedStyle.borderLeftWidth)
+        + parseInt(computedStyle.borderRightWidth);
+
+    return boundingRect.width - extraWidth - ULTIMATE_GAP_CONSTANT;
+}
+
+const featureViewerRegistry = new Map();
+
+/**
+ * Create an Rcsb Saguaro 1D viewer instance.
+ *
+ * @param elementId id of parent element
+ * @param url source of JSON config
+ * @param side1 side1 paramter to update site colors, if it is needed
+ */
+export async function createRcsbFeatureViewer(params: {
+    elementId: string, url: string, side1: string, trackWidth?: number, rowTitleWidth?: number }): Promise<RcsbFv> {
+
+    updateSiteColors(params.side1 as any);
+
+    const featureTracks = await fetchDescriptor(params.url);
+    const blockConfig = featureTracks.blockConfig;
+    const boardConfig = blockConfig[0].featureViewConfig[0].boardConfig;
+    boardConfig.trackWidth = params.trackWidth ?? 600;
+    boardConfig.rowTitleWidth = params.rowTitleWidth ?? 160;
+
+    const rowConfig = blockConfig[0].featureViewConfig[0].rowConfig;
+    setRegionColors(rowConfig);
+
+    const pfv = new RcsbFv({
+        boardConfigData: boardConfig,
+        rowConfigData: rowConfig,
+        elementId: params.elementId
+    });
+    featureViewerRegistry.set(params.elementId, pfv);
+
+    return pfv;
+}
+
+function scaleBoardConfigWidths(elementId: string, boardConfig: RcsbFvBoardConfigInterface, entry: ResizeObserverEntry) {
+    const container = document.getElementById(elementId);
+    const fullWidth = boardConfig.trackWidth! + boardConfig.rowTitleWidth! + ULTIMATE_GAP_CONSTANT;
+    const ratio = entry.contentRect.width / fullWidth;
+    console.log('Before scaling', [ boardConfig.trackWidth, boardConfig.rowTitleWidth, ratio ]);
+    boardConfig.trackWidth = Math.floor(ratio * boardConfig.trackWidth!);
+    boardConfig.rowTitleWidth! = Math.floor(ratio * boardConfig.rowTitleWidth!);
+    console.log('After scaling', [ boardConfig.trackWidth, boardConfig.rowTitleWidth ]);
+}