import React from 'react'; import { Root, 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 { setExternalRowTitleComponent, setRegionColors } from '../FeatureViewConfig'; import { TmRowTitleComponent } from './TmRowTitleComponent'; 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, trackWidth?: number, rowTitleWidth?: number, autoResize?: boolean }; type TmFv1DState = { featureViewer?: RcsbFv, num?: number }; export class TmFv1D extends React.Component { protected containerRef = React.createRef(); public constructor(props: TmFv1DParams) { super(props); } public async componentDidMount(): Promise { await createRcsbFeatureViewer({ elementId: this.props.elementId, url: this.props.url, side1: this.props.side1, rowTitleWidth: this.props.rowTitleWidth, trackWidth: this.props.trackWidth }); if (this.props.autoResize) { new ResizeObserver(this.resize) .observe(this.containerRef.current as Element); } } resize(entries: ResizeObserverEntry[], observer: ResizeObserver) { 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!; resizeBoardConfigTrackWidth(boardConfig, observerEntry.contentRect.width); featureViewer.updateBoardConfig({ boardConfigData: boardConfig }); } public render(): JSX.Element { return (
); } } export class TmFv1DElement extends HTMLElement { connectedCallback() { const root = createRoot(this); setTimeout(() => this.render(root), 1000); } render(root: Root) { let autoResize = true; if (this.hasAttribute("autoResize")) { const value = this.getAttribute("autoResize"); autoResize = (value == "true"); } 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; let trackWidth = !autoResize ? parseInt(this.getAttribute("trackWidth")!) || (defaultViewerWidth - ULTIMATE_GAP_CONSTANT) : calculatedWidth; trackWidth -= rowTitleWidth; console.log('Widths:', [ rowTitleWidth, trackWidth ]); root.render( ); } } 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 { 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); setExternalRowTitleComponent(rowConfig); const pfv = new RcsbFv({ boardConfigData: boardConfig, rowConfigData: rowConfig, elementId: params.elementId }); featureViewerRegistry.set(params.elementId, pfv); return pfv; } function resizeBoardConfigTrackWidth(boardConfig: RcsbFvBoardConfigInterface, width: number) { const fullWidth = width - ULTIMATE_GAP_CONSTANT; boardConfig.trackWidth = fullWidth - boardConfig.rowTitleWidth!; }