@rcsb/rcsb-saguaro
Version:
RCSB 1D Feature Viewer
245 lines (244 loc) • 10.1 kB
JavaScript
import { RcsbBoard } from '../../RcsbBoard/RcsbBoard';
import { RcsbFvDefaultConfigValues } from '../RcsbFvConfig/RcsbFvDefaultConfigValues';
import { RcsbFvDisplay } from "./RcsbFvDisplay";
import { RcsbFvConfig } from "../RcsbFvConfig/RcsbFvConfig";
import { RcsbFvTrackData, RcsbDataManager, RcsbFvTrackDataMap } from "../../RcsbDataManager/RcsbDataManager";
import { EventType } from "../RcsbFvContextManager/RcsbFvContextManager";
/**This className provides an abstraction layer to build and manage a particular board annotation cell*/
export class RcsbFvTrack {
constructor(args, xScale, selection, contextManager) {
/**Board annotation cells may contain different tracks to avoid visual overlapping*/
this.rcsbTrackArray = new Array();
this.contextManager = contextManager;
this.xScale = xScale;
this.selection = selection;
if (typeof args.elementId === "string" && document.getElementById(args.elementId) != null) {
this.rcsbBoard = new RcsbBoard(args.elementId, xScale, this.selection, this.contextManager);
}
this.buildTrack(args);
this.subscription = this.subscribe();
this.rcsbBoard.highlightRegion(null, "set", "select", true);
}
/**Builds the board annotation cell
* @param args Board track configuration object
* */
buildTrack(args) {
this.setConfig(args);
if (typeof this.rcsbFvConfig.elementId === "string") {
this.init(this.rcsbFvConfig.elementId);
}
if (typeof this.rcsbFvConfig.trackData != "undefined" && this.rcsbFvConfig.displayType != "composite" /* RcsbFvDisplayTypes.COMPOSITE */) {
this.load(this.rcsbFvConfig.trackData);
}
else if (this.rcsbFvConfig.displayType === "composite" /* RcsbFvDisplayTypes.COMPOSITE */) {
const data = this.collectCompositeData();
if (data != null) {
this.load(data);
}
}
else {
this.buildRcsbTrack();
}
this.start();
}
/**Start rendering the board track annotation cell
* @param elementId DOM element Id
* */
init(elementId) {
if (document.getElementById(elementId) != null) {
this.elementId = elementId;
if (this.rcsbBoard === null) {
this.rcsbBoard = new RcsbBoard(this.elementId, this.xScale, this.selection, this.contextManager);
}
if (this.rcsbFvConfig.configCheck()) {
this.initRcsbBoard();
}
else {
throw "Board length is not defined";
}
}
else {
throw "HTML element " + elementId + " not found";
}
}
/**Replaces the track configuration
* @param args Board row configuration object
* */
setConfig(args) {
if (this.rcsbFvConfig == null) {
this.rcsbFvConfig = new RcsbFvConfig(args);
}
else {
this.rcsbFvConfig.updateConfig(args);
}
}
/**Sets parameters for the SVG/HTML level object manager*/
initRcsbBoard() {
if (typeof this.rcsbFvConfig.elementClickCallback === "function")
this.rcsbBoard.setElementClickCallback(this.rcsbFvConfig.elementClickCallback);
if (this.rcsbFvConfig.highlightHoverPosition === true) {
this.rcsbBoard.setHighlightHoverPosition();
}
if (this.rcsbFvConfig.highlightHoverElement === true) {
this.rcsbBoard.setHighlightHoverElement(true);
}
if (typeof this.rcsbFvConfig.highlightHoverCallback === "function") {
this.rcsbBoard.addHoverCallback(this.rcsbFvConfig.highlightHoverCallback);
}
if (typeof this.rcsbFvConfig.trackWidth === "number")
this.rcsbBoard.setBoardWidth(this.rcsbFvConfig.trackWidth);
if (typeof this.rcsbFvConfig.range === "object")
this.rcsbBoard.setRange(this.rcsbFvConfig.range.min - RcsbFvDefaultConfigValues.increasedView, this.rcsbFvConfig.range.max + RcsbFvDefaultConfigValues.increasedView);
else if (typeof this.rcsbFvConfig.length === "number")
this.rcsbBoard.setRange(1 - RcsbFvDefaultConfigValues.increasedView, this.rcsbFvConfig.length + RcsbFvDefaultConfigValues.increasedView);
}
/**Build an inner track within a board track annotation cell
* @return Inner track display object
* */
buildRcsbTrack() {
this.rcsbFvDisplay = new RcsbFvDisplay(this.rcsbFvConfig);
const rcsbTrack = this.rcsbFvDisplay.initDisplay();
rcsbTrack.height(this.rcsbFvConfig.trackHeight);
rcsbTrack.trackColor(this.rcsbFvConfig.trackColor);
this.rcsbTrackArray.push(rcsbTrack);
return rcsbTrack;
}
/**Transforms data of composite displays
* @return Array of annotation objects
* */
collectCompositeData() {
var _a;
const data = new Array();
if (((_a = this.rcsbFvConfig) === null || _a === void 0 ? void 0 : _a.displayConfig) != undefined) {
for (let displayItem of this.rcsbFvConfig.displayConfig) {
if (typeof displayItem.displayData != "undefined") {
data.push(displayItem.displayData);
}
}
if (data.length == this.rcsbFvConfig.displayConfig.length) {
return data;
}
}
return null;
}
/**Class inner function that transform annotation data for composite or single displays
* @param trackData array of annotation objects
* */
load(trackData) {
var _a;
if (this.rcsbFvConfig.displayType === "composite" /* RcsbFvDisplayTypes.COMPOSITE */ && Array.isArray(trackData)) {
const trackNonOverlappingMap = new Array();
let maxTracks = 1;
trackData.forEach((f, i) => {
if (!this.rcsbFvConfig.overlap) {
const nonOverlapping = RcsbDataManager.getNonOverlappingData(f);
trackNonOverlappingMap.push(nonOverlapping);
if (nonOverlapping.length > maxTracks)
maxTracks = nonOverlapping.length;
}
else {
trackNonOverlappingMap.push([f]);
}
});
for (let i = 0; i < maxTracks; i++) {
const rcsbCompositeTrack = this.buildRcsbTrack();
if (((_a = this.rcsbFvConfig) === null || _a === void 0 ? void 0 : _a.trackHeight) != undefined)
rcsbCompositeTrack.setCompositeHeight(i * this.rcsbFvConfig.trackHeight);
const displayIds = this.rcsbFvDisplay.getDisplayIds();
const trackDataMap = new RcsbFvTrackDataMap();
trackNonOverlappingMap.forEach((v, j) => {
const id = displayIds[j];
if (i < v.length)
trackDataMap.set(id, v[i]);
else
trackDataMap.set(id, []);
});
rcsbCompositeTrack.data(trackDataMap);
}
}
else if (trackData instanceof RcsbFvTrackData) {
let nonOverlapping;
if (!this.rcsbFvConfig.overlap) {
nonOverlapping = RcsbDataManager.getNonOverlappingData(trackData);
}
else {
nonOverlapping = [trackData];
}
nonOverlapping.forEach(trackData => {
this.buildRcsbTrack().data(trackData);
});
}
else {
throw new Error("Data loader error. Data type not supported.");
}
}
/**Add all inner track to the SVG/HTML level manager and start rendering*/
start() {
this.rcsbTrackArray.forEach(track => {
this.rcsbBoard.addTrack(track);
});
this.rcsbBoard.startBoard();
}
/**Subscribe function to handle events and communicate all board track annotations cell panels
* @return Subscription object
* */
subscribe() {
return this.contextManager.subscribe((obj) => {
if (obj.eventType === EventType.SCALE) {
this.setScale(obj.eventData);
}
else if (obj.eventType === EventType.SELECTION) {
this.setSelection(obj.eventData);
}
else if (obj.eventType === EventType.RESET) {
this.reset(obj.eventData);
}
});
}
/**Unsubscribe all functions
* */
unsubscribe() {
this.subscription.unsubscribe();
this.rcsbBoard.removeScrollEvent();
}
/**Modify d3 x-scale
* @param boardId Id of the SVG/HTML manager that triggered the event
* */
setScale(boardId) {
this.rcsbBoard.setScale(boardId);
}
/**Highlights the region(s) defined by the attribute selection
* @param selection object describing sequence regions
* */
setSelection(selection) {
this.rcsbBoard.setSelection(selection.trackId, selection.mode);
}
/**Reset the cell content
* @param trackId Event reset object interface
* */
reset(trackId) {
if (this.rcsbFvConfig.trackId === trackId) {
this._reset();
}
}
/**Reset all inner tracks*/
_reset() {
this.rcsbTrackArray = new Array();
this.rcsbBoard.reset();
}
/**Calculate height as function of the number of inner tracks
* @return Board track annotation cell height
* */
getTrackHeight() {
var _a, _b;
if (this.rcsbTrackArray.length > 0 && ((_a = this.rcsbFvConfig) === null || _a === void 0 ? void 0 : _a.trackHeight) != undefined) {
return this.rcsbTrackArray.length * this.rcsbFvConfig.trackHeight;
}
else if (((_b = this.rcsbFvConfig) === null || _b === void 0 ? void 0 : _b.trackHeight) != undefined) {
return this.rcsbFvConfig.trackHeight;
}
else {
return null;
}
}
}