@rcsb/rcsb-saguaro
Version:
RCSB 1D Feature Viewer
194 lines (193 loc) • 10.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RcsbFvUI = void 0;
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = tslib_1.__importDefault(require("react"));
const classes = tslib_1.__importStar(require("../../scss/RcsbFvRow.module.scss"));
const react_transition_group_1 = require("react-transition-group");
const RcsbFvDefaultConfigValues_1 = require("../RcsbFvConfig/RcsbFvDefaultConfigValues");
const RcsbFvContextManager_1 = require("../RcsbFvContextManager/RcsbFvContextManager");
const rxjs_1 = require("rxjs");
const dom_1 = require("@floating-ui/dom");
const bx_plus_svg_1 = tslib_1.__importDefault(require("./icons/bx-plus.svg"));
const bx_minus_svg_1 = tslib_1.__importDefault(require("./icons/bx-minus.svg"));
const bx_right_arrow_svg_1 = tslib_1.__importDefault(require("./icons/bx-right-arrow.svg"));
const bx_left_arrow_svg_1 = tslib_1.__importDefault(require("./icons/bx-left-arrow.svg"));
const bxs_down_arrow_svg_1 = tslib_1.__importDefault(require("./icons/bxs-down-arrow.svg"));
class RcsbFvUI extends react_1.default.Component {
constructor() {
super(...arguments);
this.collapseRef = react_1.default.createRef();
this.expandRef = react_1.default.createRef();
/**UI config Object*/
this.config = [{
icon: (0, jsx_runtime_1.jsx)(bx_plus_svg_1.default, Object.assign({}, RcsbFvUI.ICON_PROPS)),
callback: this.zoomIn.bind(this),
name: "zoom-in"
}, {
icon: (0, jsx_runtime_1.jsx)(bx_minus_svg_1.default, Object.assign({}, RcsbFvUI.ICON_PROPS)),
callback: this.zoomOut.bind(this),
name: "zoom-out"
}, {
icon: (0, jsx_runtime_1.jsx)(bx_right_arrow_svg_1.default, Object.assign({}, RcsbFvUI.ICON_PROPS)),
callback: this.move.bind(this, 1),
name: "move-right"
}, {
icon: (0, jsx_runtime_1.jsx)(bx_left_arrow_svg_1.default, Object.assign({}, RcsbFvUI.ICON_PROPS)),
callback: this.move.bind(this, -1),
name: "move-left"
}];
this.hideTask = null;
this.state = {
collapse: false
};
}
render() {
return ((0, jsx_runtime_1.jsx)("div", { id: this.props.boardId + "_uiDiv" /* RcsbFvDOMConstants.UI_DOM_ID_PREFIX */, className: classes.rcsbUI + " " + classes.rcsbSmoothDivHide, style: { position: "absolute", top: 0, left: 0 }, children: (0, jsx_runtime_1.jsxs)("div", { style: { position: "relative" }, children: [(0, jsx_runtime_1.jsx)(react_transition_group_1.CSSTransition, { in: this.state.collapse, timeout: 300, classNames: classes.rcsbCollapseUI, nodeRef: this.collapseRef, children: (0, jsx_runtime_1.jsx)("div", { style: { position: "absolute" }, className: classes.rcsbCollapsedUIDiv + " " + classes.rcsbCollapseUI, onMouseEnter: this.changeState.bind(this, { collapse: false }), ref: this.collapseRef, children: (0, jsx_runtime_1.jsx)("div", { className: classes.rcsbCollapsedIcon, children: (0, jsx_runtime_1.jsx)(bxs_down_arrow_svg_1.default, Object.assign({}, RcsbFvUI.ICON_PROPS)) }) }) }), (0, jsx_runtime_1.jsx)(react_transition_group_1.CSSTransition, { in: !this.state.collapse, timeout: 300, classNames: classes.rcsbExpandUI, nodeRef: this.expandRef, children: (0, jsx_runtime_1.jsx)("div", { style: { position: "absolute" }, className: classes.rcsbExpandUI, onMouseLeave: this.changeState.bind(this, { collapse: true }), ref: this.expandRef, children: this.config.map(button => {
return this.buildButton(button);
}) }) })] }) }));
}
componentDidMount() {
this.subscription = this.subscribe();
const refDiv = document.querySelector("#" + this.props.boardId);
if (refDiv == null)
throw "Main board DOM element not found";
this.refDiv = refDiv;
const tooltipDiv = document.querySelector("#" + this.props.boardId + "_uiDiv" /* RcsbFvDOMConstants.UI_DOM_ID_PREFIX */);
if (tooltipDiv == null)
throw "Tooltip DOM element not found";
this.tooltipDiv = tooltipDiv;
}
componentWillUnmount() {
this.subscription.unsubscribe();
}
subscribe() {
return this.props.contextManager.subscribe((o) => {
switch (o.eventType) {
case RcsbFvContextManager_1.EventType.BOARD_HOVER:
this.boardHover(o.eventData);
break;
}
});
}
boardHover(flag) {
if (flag) {
this.displayUI();
}
else {
this.hideUI();
}
}
displayUI() {
if (this.hideTask)
this.hideTask.unsubscribe();
const offsetHeight = this.props.boardConfigData.includeAxis === true ? RcsbFvDefaultConfigValues_1.RcsbFvDefaultConfigValues.trackAxisHeight + 2 : 0;
(0, dom_1.computePosition)(this.refDiv, this.tooltipDiv, {
placement: 'right-start',
middleware: [{
name: 'middleware',
fn(middlewareArguments) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const overflow = yield (0, dom_1.detectOverflow)(middlewareArguments, {
rootBoundary: "viewport"
});
if (overflow.top > offsetHeight)
return { y: overflow.top + middlewareArguments.y - offsetHeight };
return {};
});
},
}]
}).then(({ x, y }) => {
Object.assign(this.tooltipDiv.style, {
left: `${x}px`,
top: `${y + offsetHeight}px`
});
});
this.tooltipDiv.classList.remove(classes.rcsbSmoothDivHide);
this.tooltipDiv.classList.add(classes.rcsbSmoothDivDisplay);
}
hideUI() {
const tooltipDiv = document.querySelector("#" + this.props.boardId + "_uiDiv" /* RcsbFvDOMConstants.UI_DOM_ID_PREFIX */);
if (tooltipDiv == null)
return;
this.hideTask = rxjs_1.asyncScheduler.schedule(() => {
tooltipDiv.classList.remove(classes.rcsbSmoothDivDisplay);
tooltipDiv.classList.add(classes.rcsbSmoothDivHide);
}, 300);
}
buildButton(buttonConfig) {
return ((0, jsx_runtime_1.jsx)("div", { className: classes.rcsbUIButton, children: (0, jsx_runtime_1.jsx)("div", { className: classes.rcsbIcon, onClick: buttonConfig.callback, children: buttonConfig.icon }) }, buttonConfig.name));
}
changeState(state) {
this.setState(state);
}
/***************
** UI methods **
****************/
zoomIn() {
const max = this.props.boardConfigData.range != null ? this.props.boardConfigData.range.max : this.props.boardConfigData.length;
if (max == null)
return;
const currentDomain = this.props.xScale.domain();
const deltaZoom = Math.floor((currentDomain[1] - currentDomain[0]) * 0.1);
const x = currentDomain[0] + deltaZoom;
const y = currentDomain[1] - deltaZoom;
if ((y - x) > 20)
this.setDomain({ domain: [x, y] });
}
zoomOut() {
const max = this.props.boardConfigData.range != null ? this.props.boardConfigData.range.max : this.props.boardConfigData.length;
const min = this.props.boardConfigData.range != null ? this.props.boardConfigData.range.min : 1;
if (max == null)
return;
const currentDomain = this.props.xScale.domain();
const deltaZoom = Math.floor((currentDomain[1] - currentDomain[0]) * 0.1);
const x = currentDomain[0] - deltaZoom > (min - RcsbFvDefaultConfigValues_1.RcsbFvDefaultConfigValues.increasedView) ? currentDomain[0] - deltaZoom : (min - RcsbFvDefaultConfigValues_1.RcsbFvDefaultConfigValues.increasedView);
const y = currentDomain[1] + deltaZoom < max + RcsbFvDefaultConfigValues_1.RcsbFvDefaultConfigValues.increasedView ? currentDomain[1] + deltaZoom : max + RcsbFvDefaultConfigValues_1.RcsbFvDefaultConfigValues.increasedView;
if ((y - x) < (max + RcsbFvDefaultConfigValues_1.RcsbFvDefaultConfigValues.increasedView))
this.setDomain({ domain: [x, y] });
else
this.setDomain({ domain: [(min - RcsbFvDefaultConfigValues_1.RcsbFvDefaultConfigValues.increasedView), max + RcsbFvDefaultConfigValues_1.RcsbFvDefaultConfigValues.increasedView] });
}
move(direction) {
const max = this.props.boardConfigData.range != null ? this.props.boardConfigData.range.max : this.props.boardConfigData.length;
const min = this.props.boardConfigData.range != null ? this.props.boardConfigData.range.min : 1;
if (max == null)
return;
const currentDomain = this.props.xScale.domain();
let deltaZoom = Math.floor((currentDomain[1] - currentDomain[0]) * 0.1);
if (currentDomain[0] + direction * deltaZoom < (min - RcsbFvDefaultConfigValues_1.RcsbFvDefaultConfigValues.increasedView))
deltaZoom = currentDomain[0] - (min - RcsbFvDefaultConfigValues_1.RcsbFvDefaultConfigValues.increasedView);
else if (currentDomain[1] + direction * deltaZoom > (max + RcsbFvDefaultConfigValues_1.RcsbFvDefaultConfigValues.increasedView))
deltaZoom = max + RcsbFvDefaultConfigValues_1.RcsbFvDefaultConfigValues.increasedView - currentDomain[1];
const x = currentDomain[0] + direction * deltaZoom;
const y = currentDomain[1] + direction * deltaZoom;
if ((y - x) < (max + RcsbFvDefaultConfigValues_1.RcsbFvDefaultConfigValues.increasedView))
this.setDomain({ domain: [x, y] });
else
this.setDomain({ domain: [(min - RcsbFvDefaultConfigValues_1.RcsbFvDefaultConfigValues.increasedView), max + RcsbFvDefaultConfigValues_1.RcsbFvDefaultConfigValues.increasedView] });
}
/**Force all board track annotation cells to set xScale. Called when a new track has been added*/
setScale() {
if (this.props.xScale != null) {
this.props.contextManager.next({
eventType: RcsbFvContextManager_1.EventType.SCALE,
eventData: this.props.boardId
});
}
}
/**Update d3 xScale domain
* @param domainData new xScale domain
* */
setDomain(domainData) {
this.props.xScale.domain(domainData.domain);
this.setScale();
}
}
exports.RcsbFvUI = RcsbFvUI;
RcsbFvUI.ICON_PROPS = {
width: 16,
height: 16,
viewBox: "0 0 24 24"
};