in client/client/modules/render/variant-render/renderers/structural-variant-renderer.js [901:1171]
_renderExonsStructure(viewport:BaseViewport, chromosomeName, gene, zone = 'reference', renderGeneLabels = false) {
if (!viewport || !chromosomeName || !gene)
return;
chromosomeName = chromosomeName.toUpperCase();
if (gene.empty) {
this._renderEmptyGeneStructure(viewport, chromosomeName, zone);
return;
}
const localContainer = new PIXI.Container();
const notMaskedGraphics = new PIXI.Graphics();
this.container.addChild(localContainer);
this.container.addChild(notMaskedGraphics);
const graphics = new PIXI.Graphics();
localContainer.addChild(graphics);
const labelContainer = new PIXI.Container();
this.container.addChild(labelContainer);
const geneBorder = {
leftBorder: viewport.chromosome.start === 0,
rightBorder: viewport.chromosome.end === gene.totalExonsLength
};
const height = this.variantZonesManager.getHeight(zone, chromosomeName, 'chromosome') - 2 * this.config.chromosome.margin;
const center = this.variantZonesManager.getStartPosition(zone, chromosomeName, 'chromosome') + this.variantZonesManager.getHeight(zone, chromosomeName, 'chromosome') / 2;
let chromosomeLineRect = null;
const clippingRegion = {
x: Math.round(viewport.canvas.start) - 1,
y: Math.round(this.variantZonesManager.getStartPosition(zone, chromosomeName, 'chromosome')) - 1,
width: Math.round(viewport.canvasSize) + 2,
height: Math.round(this.variantZonesManager.getHeight(zone, chromosomeName, 'chromosome')) + 2
};
const clippingRules = {
leftClip: false,
rightClip: false
};
if (geneBorder.leftBorder && geneBorder.rightBorder) {
clippingRules.leftClip = true;
clippingRules.rightClip = true;
clippingRegion.x = Math.round(viewport.canvas.start - this.config.breakpoint.width / 3) - 1;
clippingRegion.width = Math.round(viewport.canvasSize + 2 * this.config.breakpoint.width / 3) + 2;
chromosomeLineRect = {
x1: viewport.canvas.start - this.config.breakpoint.width / 2,
y1: center - height / 4,
x2: viewport.canvas.start,
y2: center + height / 4
};
graphics.beginFill(0xaaaaaa, 1);
graphics.drawRect(
Math.round(chromosomeLineRect.x1) - .5,
Math.round(chromosomeLineRect.y1) - .5,
Math.round(chromosomeLineRect.x2 - chromosomeLineRect.x1),
Math.round(chromosomeLineRect.y2 - chromosomeLineRect.y1)
);
graphics.endFill();
chromosomeLineRect = {
x1: viewport.canvas.end,
y1: center - height / 4,
x2: viewport.canvas.end + this.config.breakpoint.width / 2,
y2: center + height / 4
};
graphics.beginFill(0xaaaaaa, 1);
graphics.drawRect(
Math.round(chromosomeLineRect.x1) - .5,
Math.round(chromosomeLineRect.y1) - .5,
Math.round(chromosomeLineRect.x2 - chromosomeLineRect.x1),
Math.round(chromosomeLineRect.y2 - chromosomeLineRect.y1)
);
graphics.endFill();
}
else if (geneBorder.leftBorder) {
clippingRules.leftClip = true;
clippingRegion.x = Math.round(viewport.canvas.start - this.config.breakpoint.width / 3) - 1;
clippingRegion.width = Math.round(viewport.canvasSize + this.config.breakpoint.width / 3) + 2;
chromosomeLineRect = {
x1: viewport.canvas.start - this.config.breakpoint.width / 2,
y1: center - height / 4,
x2: viewport.canvas.start,
y2: center + height / 4
};
graphics.beginFill(0xaaaaaa, 1);
graphics.drawRect(
Math.round(chromosomeLineRect.x1) - .5,
Math.round(chromosomeLineRect.y1) - .5,
Math.round(chromosomeLineRect.x2 - chromosomeLineRect.x1),
Math.round(chromosomeLineRect.y2 - chromosomeLineRect.y1)
);
graphics.endFill();
}
else if (geneBorder.rightBorder) {
clippingRules.rightClip = true;
clippingRegion.x = Math.round(viewport.canvas.start) - 1;
clippingRegion.width = Math.round(viewport.canvasSize + this.config.breakpoint.width / 3) + 2;
chromosomeLineRect = {
x1: viewport.canvas.end,
y1: center - height / 4,
x2: viewport.canvas.end + this.config.breakpoint.width / 2,
y2: center + height / 4
};
graphics.beginFill(0xaaaaaa, 1);
graphics.drawRect(
Math.round(chromosomeLineRect.x1) - .5,
Math.round(chromosomeLineRect.y1) - .5,
Math.round(chromosomeLineRect.x2 - chromosomeLineRect.x1),
Math.round(chromosomeLineRect.y2 - chromosomeLineRect.y1)
);
graphics.endFill();
}
let prevGeneName = null;
for (let i = 0; i < gene.consensusExons.length; i++) {
const exon = gene.consensusExons[i];
if (exon.relativePosition.end < viewport.chromosome.start || exon.relativePosition.start > viewport.chromosome.end)
continue;
let alphaRatio = 1;
if (this._hoveredDomain) {
alphaRatio = .25;
if (exon.domains && exon.domains.length > 0) {
for (let d = 0; d < exon.domains.length; d++) {
if (exon.domains[d].domain.name === this._hoveredDomain) {
alphaRatio = 1;
break;
}
}
}
}
const rect = {
x1: Math.max(viewport.project.brushBP2pixel(exon.relativePosition.start), viewport.canvas.start),
y1: this.variantZonesManager.getStartPosition(zone, chromosomeName, 'chromosome') + this.config.chromosome.margin,
x2: Math.min(viewport.project.brushBP2pixel(exon.relativePosition.end), viewport.canvas.end),
y2: this.variantZonesManager.getEndPosition(zone, chromosomeName, 'chromosome') - this.config.chromosome.margin
};
if (exon.empty) {
const emptyExonRect = {
x1: Math.max(viewport.project.brushBP2pixel(exon.relativePosition.start), viewport.canvas.start),
y1: center - height / 4,
x2: Math.min(viewport.project.brushBP2pixel(exon.relativePosition.end), viewport.canvas.end),
y2: center + height / 4
};
graphics.lineStyle(0, 0xaaaaaa, 0);
graphics.beginFill(0xaaaaaa, 1);
graphics.drawRect(
emptyExonRect.x1,
emptyExonRect.y1,
emptyExonRect.x2 - emptyExonRect.x1,
emptyExonRect.y2 - emptyExonRect.y1
);
graphics.endFill();
continue;
}
if (renderGeneLabels && !exon.empty && (!prevGeneName || prevGeneName !== exon.geneName)) {
const geneLabel = new PIXI.Text(exon.geneName, this.config.gene.label);
geneLabel.resolution = drawingConfiguration.resolution;
geneLabel.x = Math.round(Math.max(viewport.project.brushBP2pixel(exon.relativePosition.start), viewport.canvas.start));
geneLabel.y = Math.round(this.variantZonesManager.getEndPosition(zone, chromosomeName, 'gene') - geneLabel.height);
labelContainer.addChild(geneLabel);
prevGeneName = exon.geneName;
}
this._registerExonPosition(exon, rect);
const breakpointExonOffset = this.config.breakpoint.offset;
const breakpointThickness = this.config.breakpoint.thickness;
if (exon.domains && exon.domains.length > 0) {
this.domainColorsManager.fillEmptyExon(exon.geneName, graphics, {
x: rect.x1,
y: rect.y1,
width: rect.x2 - rect.x1,
height: rect.y2 - rect.y1
}, alphaRatio);
for (let j = 0; j < exon.domains.length; j++) {
const exonDomain = exon.domains[j];
let domainAlphaRatio = 1;
if (this._hoveredDomain && exonDomain.domain.name !== this._hoveredDomain) {
domainAlphaRatio = .25;
}
const domainColor = this.domainColorsManager.getDomainColor(exonDomain.domain.name);
graphics.beginFill(domainColor.fill, domainColor.alpha * domainAlphaRatio);
graphics.lineStyle(0, 0x000000, 0);
const innerRect = {
x1: Math.max(viewport.project.brushBP2pixel(exonDomain.range.start), viewport.canvas.start),
y1: this.variantZonesManager.getStartPosition(zone, chromosomeName, 'chromosome') + this.config.chromosome.margin + .5,
x2: Math.min(viewport.project.brushBP2pixel(exonDomain.range.end), viewport.canvas.end),
y2: this.variantZonesManager.getEndPosition(zone, chromosomeName, 'chromosome') - this.config.chromosome.margin - .5
};
graphics.drawRect(innerRect.x1, innerRect.y1, innerRect.x2 - innerRect.x1, innerRect.y2 - innerRect.y1);
graphics.endFill();
}
graphics.beginFill(0xffffff, 0);
graphics.lineStyle(1, 0x000000, alphaRatio);
graphics.drawRect(Math.round(rect.x1) - .5,
Math.round(rect.y1) - .5,
Math.round(rect.x2 - rect.x1),
Math.round(rect.y2 - rect.y1));
graphics.endFill();
if (exon.isBreakpoint && this._options && this._options.highlightBreakpoints) {
switch (exon.breakpointPosition) {
case 'start':
notMaskedGraphics.lineStyle(breakpointThickness, this.config.breakpoint.color, 1);
notMaskedGraphics
.moveTo(Math.round(rect.x1 - breakpointExonOffset / 2) - breakpointThickness / 2, Math.round(rect.y1 - breakpointExonOffset) - breakpointThickness / 2)
.lineTo(Math.round(rect.x1) - breakpointThickness / 2, Math.round(rect.y1 - breakpointExonOffset) - breakpointThickness / 2)
.lineTo(Math.round(rect.x1) - breakpointThickness / 2, Math.round(rect.y2 + breakpointExonOffset) - breakpointThickness / 2)
.lineTo(Math.round(rect.x1 - breakpointExonOffset / 2) - breakpointThickness / 2, Math.round(rect.y2 + breakpointExonOffset) - breakpointThickness / 2);
break;
case 'end':
notMaskedGraphics.lineStyle(breakpointThickness, this.config.breakpoint.color, 1);
notMaskedGraphics
.moveTo(Math.round(rect.x2 + breakpointExonOffset / 2) - breakpointThickness / 2, Math.round(rect.y1 - breakpointExonOffset) - breakpointThickness / 2)
.lineTo(Math.round(rect.x2) - breakpointThickness / 2, Math.round(rect.y1 - breakpointExonOffset) - breakpointThickness / 2)
.lineTo(Math.round(rect.x2) - breakpointThickness / 2, Math.round(rect.y2 + breakpointExonOffset) - breakpointThickness / 2)
.lineTo(Math.round(rect.x2 + breakpointExonOffset / 2) - breakpointThickness / 2, Math.round(rect.y2 + breakpointExonOffset) - breakpointThickness / 2);
break;
}
}
}
else {
const rect = {
x1: Math.max(viewport.project.brushBP2pixel(exon.relativePosition.start), viewport.canvas.start),
y1: this.variantZonesManager.getStartPosition(zone, chromosomeName, 'chromosome') + this.config.chromosome.margin,
x2: Math.min(viewport.project.brushBP2pixel(exon.relativePosition.end), viewport.canvas.end),
y2: this.variantZonesManager.getEndPosition(zone, chromosomeName, 'chromosome') - this.config.chromosome.margin
};
this.domainColorsManager.fillEmptyExon(exon.geneName, graphics, {
x: rect.x1,
y: rect.y1,
width: rect.x2 - rect.x1,
height: rect.y2 - rect.y1
}, alphaRatio);
graphics.lineStyle(1, 0x000000, alphaRatio);
graphics.drawRect(rect.x1 - .5, rect.y1 - .5, rect.x2 - rect.x1, rect.y2 - rect.y1);
if (exon.isBreakpoint && this._options && this._options.highlightBreakpoints) {
switch (exon.breakpointPosition) {
case 'start':
notMaskedGraphics.lineStyle(breakpointThickness, this.config.breakpoint.color, 1);
notMaskedGraphics
.moveTo(Math.round(rect.x1 - breakpointExonOffset / 2) - breakpointThickness / 2, Math.round(rect.y1 - breakpointExonOffset) - breakpointThickness / 2)
.lineTo(Math.round(rect.x1) - breakpointThickness / 2, Math.round(rect.y1 - breakpointExonOffset) - breakpointThickness / 2)
.lineTo(Math.round(rect.x1) - breakpointThickness / 2, Math.round(rect.y2 + breakpointExonOffset) - breakpointThickness / 2)
.lineTo(Math.round(rect.x1 - breakpointExonOffset / 2) - breakpointThickness / 2, Math.round(rect.y2 + breakpointExonOffset) - breakpointThickness / 2);
break;
case 'end':
notMaskedGraphics.lineStyle(breakpointThickness, this.config.breakpoint.color, 1);
notMaskedGraphics
.moveTo(Math.round(rect.x2 + breakpointExonOffset / 2) - breakpointThickness / 2, Math.round(rect.y1 - breakpointExonOffset) - breakpointThickness / 2)
.lineTo(Math.round(rect.x2) - breakpointThickness / 2, Math.round(rect.y1 - breakpointExonOffset) - breakpointThickness / 2)
.lineTo(Math.round(rect.x2) - breakpointThickness / 2, Math.round(rect.y2 + breakpointExonOffset) - breakpointThickness / 2)
.lineTo(Math.round(rect.x2 + breakpointExonOffset / 2) - breakpointThickness / 2, Math.round(rect.y2 + breakpointExonOffset) - breakpointThickness / 2);
break;
}
}
}
if (exon.strand !== undefined && exon.strand !== null) {
this.strandDirectionRenderer.renderStrandDirectionForFeature(exon.strand ? 'positive' : 'negative', {
xStart: rect.x1,
xEnd: rect.x2,
yStart: rect.y2 - (rect.y2 - rect.y1) / 2,
yEnd: rect.y2
}, localContainer, alphaRatio);
}
if (exon.index !== null && exon.index !== undefined) {
const exonLabel = new PIXI.Text(exon.index + 1, this.config.exon.label);
exonLabel.resolution = 2;
exonLabel.alpha = alphaRatio;
if (exonLabel.width < (rect.x2 - rect.x1)) {
exonLabel.x = Math.round((rect.x1 + rect.x2) / 2 - exonLabel.width / 2);
exonLabel.y = Math.round(rect.y1 + (rect.y2 - rect.y1) / 4 - exonLabel.height / 2);
localContainer.addChild(exonLabel);
}
}
}
this.featureCutOffRenderer
.beginCuttingOff(localContainer)
.cutOff(clippingRegion, clippingRules)
.endCuttingOff();
}