higlass
Version:
HiGlass Hi-C / genomic / large data viewer
331 lines (275 loc) • 9 kB
JavaScript
// @ts-nocheck
import ChromosomeInfo from './ChromosomeInfo';
import TiledPixiTrack from './TiledPixiTrack';
import { colorToHex } from './utils';
// Configs
import { GLOBALS } from './configs';
class ChromosomeGrid extends TiledPixiTrack {
constructor(context, options) {
super(context, options);
const {
chromInfoPath,
dataConfig,
animate,
pubSub,
orientation = '2d',
isOverlay = false,
} = context;
this.chromInfo = null;
this.animate = animate;
this.orientation = orientation;
this.isOverlay = isOverlay;
/** The previous chromInfoPath approach to loading chromosome size.
*
* This is superseded by loading chromosome sizes directly from the
* tileset info object
*/
if (chromInfoPath) {
ChromosomeInfo(
chromInfoPath,
(newChromInfo) => {
this.chromInfo = newChromInfo;
this.tilesetInfoReceived();
},
this.pubSub,
);
}
}
/** We got tileset info which (presumably) has chromsizes.
*
* Set up all the graphics objects necessary for rendering
* the chromosome grid.
*/
tilesetInfoReceived() {
this.texts = [];
this.lineGraphics = new GLOBALS.PIXI.Graphics();
this.lineGraphics1dH = new GLOBALS.PIXI.Graphics();
this.lineGraphics1dV = new GLOBALS.PIXI.Graphics();
this.lineGraphics2d = new GLOBALS.PIXI.Graphics();
this.mask1dH = new GLOBALS.PIXI.Graphics();
this.mask1dV = new GLOBALS.PIXI.Graphics();
this.mask2d = new GLOBALS.PIXI.Graphics();
this.lineGraphics.addChild(this.lineGraphics1dH);
this.lineGraphics1dH.addChild(this.mask1dH);
this.lineGraphics.addChild(this.lineGraphics1dV);
this.lineGraphics1dV.addChild(this.mask1dV);
this.lineGraphics.addChild(this.lineGraphics2d);
this.lineGraphics2d.addChild(this.mask2d);
this.pMain.addChild(this.lineGraphics);
this.draw();
this.animate();
}
calculateVisibleTiles() {
/** This track does not use tiles so return an empty set */
return [];
}
drawLines(orientation = this.orientation, left = 0, top = 0) {
let graphics = this.lineGraphics;
if (this.isOverlay && orientation === '1d-horizontal') {
graphics = this.lineGraphics1dH;
}
if (this.isOverlay && orientation === '1d-vertical') {
graphics = this.lineGraphics1dV;
}
if (this.isOverlay && orientation === '2d') {
graphics = this.lineGraphics2d;
}
const strokeColor = colorToHex(
this.options.lineStrokeColor ? this.options.lineStrokeColor : 'blue',
);
const strokeWidth = this.options.lineStrokeWidth
? this.options.lineStrokeWidth
: 1;
graphics.lineStyle(strokeWidth, strokeColor, 1.0);
// Vertical lines
if (orientation === '2d' || orientation === '1d-horizontal') {
graphics.moveTo(this._xScale(0) + left, top);
graphics.lineTo(this._xScale(0) + left, this.dimensions[1] + top);
}
// Horizontal lines
if (orientation === '2d' || orientation === '1d-vertical') {
graphics.moveTo(left, this._yScale(0) + top);
graphics.lineTo(this.dimensions[0] + left, this._yScale(0) + top);
}
for (let i = 0; i < this.chromInfo.cumPositions.length; i++) {
const chrPos = this.chromInfo.cumPositions[i];
const chrEnd = chrPos.pos + +this.chromInfo.chromLengths[chrPos.chr] + 1;
// Vertical lines
if (orientation === '2d' || orientation === '1d-horizontal') {
graphics.moveTo(this._xScale(chrEnd) + left, top);
graphics.lineTo(this._xScale(chrEnd) + left, this.dimensions[1] + top);
}
// Horizontal lines
if (orientation === '2d' || orientation === '1d-vertical') {
graphics.moveTo(left, this._yScale(chrEnd) + top);
graphics.lineTo(this.dimensions[0] + left, this._yScale(chrEnd) + top);
}
}
}
draw() {
if (!this.texts) {
return;
}
if (!this.tilesetInfo) {
return;
}
this.lineGraphics.clear();
if (this.isOverlay) {
this.lineGraphics1dH.clear();
this.lineGraphics1dV.clear();
this.lineGraphics2d.clear();
this.mask1dH.clear();
this.mask1dV.clear();
this.mask2d.clear();
this.mask1dH.beginFill(0xffffff);
this.mask1dV.beginFill(0xffffff);
this.mask2d.beginFill(0xff0000);
for (let i = 0; i < this.options.orientationsAndPositions.length; i++) {
const orientation =
this.options.orientationsAndPositions[i].orientation;
const { left, top, width, height } =
this.options.orientationsAndPositions[i].position;
if (orientation === '1d-horizontal') {
this.mask1dH.drawRect(left, top, width, height);
}
if (orientation === '1d-vertical') {
this.mask1dV.drawRect(left, top, width, height);
}
if (orientation === '2d') {
this.mask2d.drawRect(left, top, width, height);
}
this.drawLines(orientation, left, top);
}
this.lineGraphics1dH.mask = this.mask1dH;
this.lineGraphics1dV.mask = this.mask1dV;
this.lineGraphics2d.mask = this.mask2d;
} else {
this.drawLines();
}
}
setPosition(newPosition) {
super.setPosition(newPosition);
[this.pMain.position.x, this.pMain.position.y] = this.position;
}
zoomed(newXScale, newYScale) {
this.xScale(newXScale);
this.yScale(newYScale);
this.draw();
}
createSvgLine(x1, x2, y1, y2, stroke, strokeWidth) {
const line = document.createElement('line');
line.setAttribute('x1', x1);
line.setAttribute('x2', x2);
line.setAttribute('y1', y1);
line.setAttribute('y2', y2);
line.setAttribute('stroke', stroke);
line.setAttribute('stroke-width', strokeWidth);
return line;
}
drawLinesSvg(output, orientation, width, height, left = 0, top = 0) {
const strokeColor = this.options.lineStrokeColor
? this.options.lineStrokeColor
: 'blue';
const strokeWidth = this.options.lineStrokeWidth;
// First horizontal line
if (orientation === '2d' || orientation === '1d-vertical') {
const y = this._yScale(0);
if (y > 0 && y < top + height) {
output.appendChild(
this.createSvgLine(
left,
width + left,
y + top,
y + top,
strokeColor,
strokeWidth,
),
);
}
}
// First vertical line
if (orientation === '2d' || orientation === '1d-horizontal') {
const x = this._xScale(0);
if (x > 0 && x < left + width) {
output.appendChild(
this.createSvgLine(
x + left,
x + left,
top,
height + top,
strokeColor,
strokeWidth,
),
);
}
}
for (let i = 0; i < this.chromInfo.cumPositions.length; i++) {
const chrPos = this.chromInfo.cumPositions[i];
const chrEnd = chrPos.pos + +this.chromInfo.chromLengths[chrPos.chr] + 1;
if (orientation === '2d' || orientation === '1d-vertical') {
const y = this._yScale(chrEnd);
if (y > 0 && y < top + height) {
output.appendChild(
this.createSvgLine(
left,
width + left,
y + top,
y + top,
strokeColor,
strokeWidth,
),
);
}
}
if (orientation === '2d' || orientation === '1d-horizontal') {
const x = this._xScale(chrEnd);
if (x > 0 && x < left + width) {
output.appendChild(
this.createSvgLine(
x + left,
x + left,
top,
height + top,
strokeColor,
strokeWidth,
),
);
}
}
}
}
exportSVG() {
let track = null;
let base = null;
if (super.exportSVG) {
[base, track] = super.exportSVG();
} else {
base = document.createElement('g');
track = base;
}
const output = document.createElement('g');
track.appendChild(output);
base.setAttribute('id', 'ChromosomeGrid');
output.setAttribute(
'transform',
`translate(${this.position[0]},${this.position[1]})`,
);
if (!this.chromInfo) {
// we haven't received the chromosome info yet
return [base, track];
}
if (this.isOverlay) {
for (let i = 0; i < this.options.orientationsAndPositions.length; i++) {
const orientation =
this.options.orientationsAndPositions[i].orientation;
const { left, top, width, height } =
this.options.orientationsAndPositions[i].position;
this.drawLinesSvg(output, orientation, width, height, left, top);
}
} else {
this.drawLinesSvg(output, this.orientation, ...this.dimensions);
}
return [base, track];
}
}
export default ChromosomeGrid;