client/client/modules/render/tracks/bam/internal/renderer/features/alignmentsRenderer.js (586 lines of code) (raw):
import * as PIXI from 'pixi.js-legacy';
import {drawingConfiguration} from '../../../../../core';
import {ColorProcessor} from '../../../../../utilities';
import {bisulfiteTypes, partTypes} from '../../../modes';
const Math = window.Math;
export const CAN_SHOW_DETAILS_FACTOR = 0.5;
export const BP_OFFSET = 0.5;
const ALIGNMENT_ARROW_DIRECTION_LEFT = -1;
const ALIGNMENT_ARROW_DIRECTION_RIGHT = 1;
const baseLabelStyle = {
fill: 0xFFFFFF,
fontFamily: 'arial',
fontSize: '6pt',
fontWeight: 'normal'
};
const BISULFITE_CONVERSION = 'bisulfiteConversion';
export class AlignmentsRenderer {
constructor(
viewport,
config,
colors,
alignmentRowHeight,
topMargin,
y,
features,
labelsManager,
height,
bisulfiteModeContext
) {
this._graphics = new PIXI.Graphics();
this._container = new PIXI.Container();
this._container.addChild(this._graphics);
this._viewport = viewport;
this._colors = colors;
this._features = features;
this._labelsManager = labelsManager;
this._height = height;
this._baseColor = colors.base;
this._topMargin = topMargin;
this._yGlobalScale = alignmentRowHeight;
this._yElementOffset = this._yGlobalScale === 1 ? 0 : config.yElementOffset;
this._yScale = this._yGlobalScale - this._yElementOffset;
this._linesOffset = y * this._yGlobalScale - this._yElementOffset;
const DEGREES_60_FACTOR = 3;
this._figOffset = Math.floor(this._convertY(1) / DEGREES_60_FACTOR); // 60 degrees
this._lineWidth = 1;
this._renderOffset = this._lineWidth / 2;
this._minimumPx = viewport.project.brushBP2pixel(Math.max(0, viewport.brush.start - viewport.actualBrushSize));
this._maximumPx = viewport.project.brushBP2pixel(Math.min(viewport.chromosome.end, viewport.brush.end + viewport.actualBrushSize));
this._contoured = false;
this._hovered = false;
const canShowLettersFactor = 10;
this._canShowDetails = viewport.factor > CAN_SHOW_DETAILS_FACTOR;
this._canShowLetters = viewport.factor > canShowLettersFactor;
this.bisulfiteModeContext = bisulfiteModeContext;
}
startRender(hovered = false) {
this._hovered = hovered;
this._graphics.lineStyle(0, this._colors.base, 0);
this._graphics.beginFill(this._colors.base, 1);
}
finishRender(renderer) {
this._graphics.endFill();
const bamTexture = renderer.generateTexture(this._container, {
scaleMode: drawingConfiguration.scaleMode,
resolution: drawingConfiguration.resolution
});
const bamSprite = new PIXI.Sprite(bamTexture);
bamSprite.position.x = this._textureStartX;
bamSprite.position.y = this._textureStartY;
const mask = new PIXI.Graphics();
mask.beginFill(0x000000, 1)
.drawRect(0, this._topMargin, this._viewport.canvasSize, this._height - this._topMargin)
.endFill();
bamSprite.mask = mask;
this._container.removeChildren();
return bamSprite;
}
set line(value) {
this._currentLine = value;
}
static getRenderEntryVerticalPositioning(renderEntry) {
let localYOffset = 0;
let localYHeight = 1;
if (renderEntry.isPaired) {
const pairedReadHeight = 0.5;
if (renderEntry.isOverlaps) {
if (renderEntry.isLeft) {
localYOffset = .0;
localYHeight = pairedReadHeight;
}
else if (renderEntry.isRight) {
localYOffset = 1.1 - pairedReadHeight;
localYHeight = pairedReadHeight;
}
}
}
return {localYHeight, localYOffset};
}
_checkTextureCoordinates({x, y}) {
if (x !== undefined && x !== null && (!this._textureStartX || x < this._textureStartX)) {
this._textureStartX = x;
}
if (y !== undefined && y !== null && (!this._textureStartY || y < this._textureStartY)) {
this._textureStartY = y;
}
}
_initReadColorModeNoColor() {
this._setColor(this._baseColor = this._colors.base);
}
_initReadColorModePairOrientation(renderEntry) {
if (!renderEntry.spec.pairSimplified ||
this._colors.pairOrientationAndInsertSize[renderEntry.spec.pairSimplified] === undefined) {
this._setColor(this._baseColor = this._colors.base);
} else {
this._setColor(this._baseColor = this._colors.pairOrientationAndInsertSize[renderEntry.spec.pairSimplified]);
}
}
_initReadColorModeReadStrand(renderEntry) {
this._setColor(this._baseColor = this._colors.strand[renderEntry.spec.strand]);
}
_initReadColorModeInsertSize(renderEntry) {
this._setColor(this._baseColor = this._colors.pairOrientationAndInsertSize[renderEntry.spec.insertSize]);
}
_initReadColorModeInsertSizeAndPairOrientation(renderEntry) {
if (!renderEntry.spec.insertSizeAndPairOrientation ||
this._colors.pairOrientationAndInsertSize[renderEntry.spec.insertSizeAndPairOrientation] === undefined) {
this._setColor(this._baseColor = this._colors.base);
}
else {
this._setColor(this._baseColor = this._colors.pairOrientationAndInsertSize[renderEntry.spec.insertSizeAndPairOrientation]);
}
}
_initReadColorModeFirstInPairStrand(renderEntry) {
switch (renderEntry.spec.pair) {
case undefined:
this._setColor(this._baseColor = this._colors.base);
break;
case 'R2L1':
case 'L1R2':
case 'L1L2':
case 'L2L1':
this._setColor(this._baseColor = this._colors.strand.forward);
break;
case 'R1L2':
case 'L2R1':
case 'R1R2':
case 'R2R1':
this._setColor(this._baseColor = this._colors.strand.reverse);
break;
default:
this._setColor(this._baseColor = this._colors.base);
break;
}
}
_initReadColorModeBisulfiteConversion(renderEntry) {
switch (renderEntry.spec.pair) {
case 'R2L1':
case 'L1R2':
case 'L1L2':
case 'L2L1':
this._setColor(this._baseColor = this._colors.bisulfite.F1R2);
break;
case 'R1L2':
case 'L2R1':
case 'R1R2':
case 'R2R1':
this._setColor(this._baseColor = this._colors.bisulfite.F2R1);
break;
default:
this._setColor(this._baseColor = this._colors.base);
break;
}
}
_initReadColorModeNomeSeqBisulfiteConversion(renderEntry) {
const paired = ['R2L1', 'L1R2', 'L1L2', 'L2L1', 'R1L2', 'L2R1', 'R1R2', 'R2R1'];
if (paired.includes(renderEntry.spec.pair)) {
this._setColor(this._baseColor = this._colors.bisulfite.F1R2);
} else {
this._setColor(this._baseColor = this._colors.base);
}
}
_initRead(renderEntry) {
this._contoured = this._features.shadeByQuality && renderEntry.spec.lowQ;
switch (this._features.colorMode) {
case 'noColor':
this._initReadColorModeNoColor();
break;
case 'pairOrientation':
this._initReadColorModePairOrientation(renderEntry);
break;
case 'readStrand':
this._initReadColorModeReadStrand(renderEntry);
break;
case 'insertSize':
this._initReadColorModeInsertSize(renderEntry);
break;
case 'insertSizeAndPairOrientation':
this._initReadColorModeInsertSizeAndPairOrientation(renderEntry);
break;
case 'firstInPairStrand':
this._initReadColorModeFirstInPairStrand(renderEntry);
break;
case 'bisulfiteConversion':
switch (this._features.bisulfiteMode) {
case 'NOMeSeq':
this._initReadColorModeNomeSeqBisulfiteConversion(renderEntry);
break;
default:
this._initReadColorModeBisulfiteConversion(renderEntry);
break;
}
}
}
_renderArrow(renderEntry, direction) {
// direction === -1 - left, direction === 1 - right
const {localYHeight, localYOffset} = AlignmentsRenderer.getRenderEntryVerticalPositioning(renderEntry);
if (!this._canShowDetails || this._yScale === 1)
return;
this._checkTextureCoordinates({x: Math.floor(this._projectX(renderEntry.startIndex))});
this._setColor(this._hovered ? ColorProcessor.darkenColor(this._baseColor, 0.1) : this._baseColor, this._contoured ? 0.5 : 1);
if (!this._contoured) {
this._graphics.lineStyle(this._lineWidth, this._hovered ? ColorProcessor.darkenColor(this._baseColor, 0.1) : this._baseColor, 1);
}
this._graphics.moveTo(Math.floor(this._projectX(renderEntry.startIndex)) - direction * this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset)));
this._graphics.lineTo(Math.floor(this._projectX(renderEntry.startIndex)) - direction * this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset + localYHeight)) - this._lineWidth);
this._graphics.lineStyle(0, this._baseColor, 0);
this._graphics.drawPolygon([
Math.floor(this._projectX(renderEntry.startIndex)) - direction * this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset)),
Math.floor(this._projectX(renderEntry.startIndex) + direction * this._figOffset),
Math.floor(this._projectY(localYOffset + localYHeight / 2)),
Math.floor(this._projectX(renderEntry.startIndex)) - direction * this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset + localYHeight) - this._lineWidth)
]);
if (this._hovered) {
this._graphics.endFill();
this._graphics.lineStyle(this._lineWidth, this._hovered ? ColorProcessor.darkenColor(this._baseColor) : this._baseColor, 1);
this._graphics.moveTo(Math.floor(this._projectX(renderEntry.startIndex)) - direction * this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset)));
this._graphics.lineTo(Math.floor(this._projectX(renderEntry.startIndex) + direction * this._figOffset),
Math.floor(this._projectY(localYOffset + localYHeight / 2)));
this._graphics.moveTo(Math.floor(this._projectX(renderEntry.startIndex) + direction * this._figOffset),
Math.floor(this._projectY(localYOffset + localYHeight / 2)));
this._graphics.lineTo(Math.floor(this._projectX(renderEntry.startIndex)) - direction * this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset + localYHeight)) - this._lineWidth);
this._graphics.lineStyle(0, this._baseColor, 0);
this._graphics.beginFill(this._currentColor, this._currentAlpha);
this._checkTextureCoordinates({
x: Math.min(Math.floor(this._projectX(renderEntry.startIndex) + direction * this._figOffset),
Math.floor(this._projectX(renderEntry.startIndex)) - direction * this._lineWidth / 2.0) - this._lineWidth / 2.0,
y: Math.floor(this._projectY(localYOffset)) - this._lineWidth
});
} else {
this._checkTextureCoordinates({
x: Math.min(Math.floor(this._projectX(renderEntry.startIndex) + direction * this._figOffset),
Math.floor(this._projectX(renderEntry.startIndex)) - direction * this._lineWidth / 2.0),
y: Math.floor(this._projectY(localYOffset)) - this._lineWidth
});
}
}
_renderMatch(renderEntry) {
const {localYHeight, localYOffset} = AlignmentsRenderer.getRenderEntryVerticalPositioning(renderEntry);
if (this._viewport.isShortenedIntronsMode) {
for (let r = 0; r < this._viewport.shortenedIntronsViewport._coveredRange.ranges.length; r++) {
const range = this._viewport.shortenedIntronsViewport._coveredRange.ranges[r];
if ((range.startIndex >= renderEntry.startIndex && range.startIndex < renderEntry.endIndex) ||
(range.endIndex >= renderEntry.startIndex && range.endIndex < renderEntry.endIndex) ||
(range.startIndex >= renderEntry.startIndex && range.endIndex < renderEntry.endIndex) ||
(range.startIndex <= renderEntry.startIndex && range.endIndex >= renderEntry.endIndex)) {
this._renderReadBordersWithBreaks(
this._baseColor,
Math.max(renderEntry.startIndex, range.startIndex),
Math.min(renderEntry.endIndex, range.endIndex + 1),
renderEntry.startIndex < range.startIndex,
renderEntry.endIndex > range.endIndex,
this._contoured,
localYOffset,
localYHeight
);
}
}
} else {
this._renderReadBorders(
this._baseColor,
renderEntry.startIndex,
renderEntry.endIndex,
this._contoured,
localYOffset,
localYHeight
);
}
}
_renderInsertion(renderEntry) {
if (!this._canShowDetails)
return;
const {localYHeight, localYOffset} = AlignmentsRenderer.getRenderEntryVerticalPositioning(renderEntry);
this._checkTextureCoordinates({
x: this._projectX(renderEntry.startIndex)
});
this._graphics.lineStyle(this._lineWidth, this._colors.ins, 1);
const x0 = Math.floor(this._projectX(renderEntry.startIndex) >> 0);
const x1 = Math.floor(x0 - this._figOffset - this._renderOffset);
const x2 = Math.floor(x0 + this._figOffset + this._renderOffset);
const y0 = Math.floor((this._projectY(localYOffset) >> 0) + this._renderOffset);
const y1 = Math.floor((this._projectY(localYOffset + localYHeight) >> 0) - this._renderOffset);
this._graphics.moveTo(x1, y0 + this._lineWidth / 2.0);
this._graphics.lineTo(x2, y0 + this._lineWidth / 2.0);
this._graphics.moveTo(x0 - this._lineWidth / 2.0, y0);
this._graphics.lineTo(x0 - this._lineWidth / 2.0, y1);
this._graphics.moveTo(x1, y1 + this._lineWidth / 2.0);
this._graphics.lineTo(x2, y1 + this._lineWidth / 2.0);
this._graphics.lineStyle(0, this._baseColor, 0);
this._checkTextureCoordinates({x: x1, y: Math.min(y0 + this._lineWidth / 2.0, y1 + this._lineWidth / 2.0)});
}
_renderDeletion(renderEntry) {
if (!this._canShowDetails)
return;
const {localYHeight, localYOffset} = AlignmentsRenderer.getRenderEntryVerticalPositioning(renderEntry);
this._checkTextureCoordinates({
x: this._projectX(renderEntry.startIndex)
});
this._setColor(this._colors.bg);
this._scaledRect(renderEntry.startIndex, localYOffset, renderEntry.length, localYHeight);
this._graphics.lineStyle(this._lineWidth, this._colors.del, 1);
this._graphics.moveTo(Math.floor(this._projectX(renderEntry.startIndex) - this._renderOffset) + this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset) + this._renderOffset));
this._graphics.lineTo(Math.floor(this._projectX(renderEntry.startIndex) - this._renderOffset) + this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset + localYHeight) - this._renderOffset));
this._graphics.moveTo(Math.floor(this._projectX(renderEntry.startIndex) - this._renderOffset),
Math.floor(this._projectY(localYOffset + localYHeight / 2)) + this._lineWidth / 2.0);
this._graphics.lineTo(Math.floor(this._projectX(renderEntry.endIndex) - this._renderOffset),
Math.floor(this._projectY(localYOffset + localYHeight / 2)) + this._lineWidth / 2.0);
this._graphics.moveTo(Math.floor(this._projectX(renderEntry.endIndex) - this._renderOffset) + this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset) + this._renderOffset));
this._graphics.lineTo(Math.floor(this._projectX(renderEntry.endIndex) - this._renderOffset) + this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset + localYHeight) - this._renderOffset));
this._graphics.lineStyle(0, this._baseColor, 0);
this._checkTextureCoordinates({
x: Math.floor(this._projectX(renderEntry.startIndex) - this._renderOffset) + this._lineWidth / 2.0,
y: this._projectY(localYOffset) + this._renderOffset
});
}
_getReadBreaks(renderEntry) {
let breakOnLeft = false;
let breakOnRight = false;
if (this._viewport.isShortenedIntronsMode) {
for (let r = 0; r < this._viewport.shortenedIntronsViewport._coveredRange.ranges.length; r++) {
const range = this._viewport.shortenedIntronsViewport._coveredRange.ranges[r];
if (range.startIndex === renderEntry.startIndex) {
breakOnLeft = true;
} else if (range.endIndex === renderEntry.startIndex) {
breakOnRight = true;
}
}
}
return {breakOnLeft, breakOnRight};
}
_getStyleForBase(renderEntry) {
const isBisulfite = this._features.colorMode === BISULFITE_CONVERSION;
if (!isBisulfite) {
return {
color: this._colors[renderEntry.base],
style: baseLabelStyle
};
}
const isCytosine = renderEntry.type === partTypes.cytosineMismatch;
const isNoncytosine = renderEntry.type === partTypes.noncytosineMismatch;
const letterColor = isCytosine ?
this._colors.bisulfite.cytosineMismatch :
(isNoncytosine ?
this._colors.bisulfite.noncytosineMismatch :
this._colors.bisulfite.mismatch
);
const baseLabelBisulfiteStyle = {...baseLabelStyle};
baseLabelBisulfiteStyle.fill = letterColor;
return {
color: this._canShowLetters ? this._baseColor : letterColor,
style: baseLabelBisulfiteStyle
};
}
_renderBase(renderEntry) {
const {localYHeight, localYOffset} = AlignmentsRenderer.getRenderEntryVerticalPositioning(renderEntry);
const {breakOnLeft, breakOnRight} = this._getReadBreaks(renderEntry);
const start = renderEntry.startIndex + (breakOnLeft ? BP_OFFSET : 0);
const end = renderEntry.endIndex + (breakOnRight ? -BP_OFFSET : 0);
const {color, style} = this._getStyleForBase(renderEntry);
this._setColor(color);
this._scaledRect(
start,
localYOffset,
end - start,
localYHeight,
this._canShowLetters && this._yScale > 1 ? BP_OFFSET : 0);
if (
!breakOnLeft &&
!breakOnRight &&
this._canShowLetters &&
this._yScale > 1 &&
!renderEntry.isOverlaps &&
this._labelsManager
) {
const sprite = this._labelsManager.getLabel(
renderEntry.base,
style
);
sprite.x = Math.round(this._projectX(renderEntry.startIndex + BP_OFFSET) - sprite.width / 2);
sprite.y = Math.round(this._projectY(localYOffset + localYHeight / 2) - sprite.height / 2);
this._container.addChild(sprite);
}
this._setColor(this._colors.bg);
this._checkTextureCoordinates({
x: this._projectX(start),
y: this._projectY(localYOffset)
});
}
_renderMismatch(renderEntry) {
if (this._features.mismatches) {
this._renderBase(renderEntry);
}
}
_renderPairedReadConnection(renderEntry) {
if (this._yScale === 1) {
return;
}
const {localYHeight, localYOffset} = AlignmentsRenderer.getRenderEntryVerticalPositioning(renderEntry);
this._checkTextureCoordinates({
x: Math.floor(this._projectX(renderEntry.startIndex) - this._renderOffset),
y: Math.floor(this._projectY(localYOffset + localYHeight / 2)) + this._lineWidth / 2.0
});
this._graphics.lineStyle(this._lineWidth, this._colors.spliceJunctions, 1);
this._graphics.moveTo(Math.floor(this._projectX(renderEntry.startIndex) - this._renderOffset),
Math.floor(this._projectY(localYOffset + localYHeight / 2)) + this._lineWidth / 2.0);
this._graphics.lineTo(Math.floor(this._projectX(renderEntry.endIndex) - this._renderOffset),
Math.floor(this._projectY(localYOffset + localYHeight / 2)) + this._lineWidth / 2.0);
this._graphics.lineStyle(0, this._baseColor, 0);
}
_renderSpliceJunction(renderEntry) {
const {localYHeight, localYOffset} = AlignmentsRenderer.getRenderEntryVerticalPositioning(renderEntry);
this._checkTextureCoordinates({
x: Math.floor(this._projectX(renderEntry.startIndex) - this._renderOffset) + this._lineWidth / 2.0,
y: Math.floor(this._projectY(localYOffset) + this._renderOffset)
});
const spliceJunctionColor = 0x96B8C8; //todo config
this._setColor(this._colors.bg);
this._scaledRect(renderEntry.startIndex, localYOffset, renderEntry.length, localYHeight);
this._graphics.lineStyle(this._lineWidth, spliceJunctionColor, 1);
this._graphics.moveTo(Math.floor(this._projectX(renderEntry.startIndex) - this._renderOffset) + this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset) + this._renderOffset));
this._graphics.lineTo(Math.floor(this._projectX(renderEntry.startIndex) - this._renderOffset) + this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset + localYHeight) - this._renderOffset));
this._graphics.moveTo(Math.floor(this._projectX(renderEntry.startIndex) - this._renderOffset),
Math.floor(this._projectY(localYOffset + localYHeight / 2)) + this._lineWidth / 2.0);
this._graphics.lineTo(Math.floor(this._projectX(renderEntry.endIndex) - this._renderOffset),
Math.floor(this._projectY(localYOffset + localYHeight / 2)) + this._lineWidth / 2.0);
this._graphics.moveTo(Math.floor(this._projectX(renderEntry.endIndex) - this._renderOffset) + this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset) + this._renderOffset));
this._graphics.lineTo(Math.floor(this._projectX(renderEntry.endIndex) - this._renderOffset) + this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset + localYHeight) - this._renderOffset));
this._graphics.lineStyle(0, this._baseColor, 0);
}
render(renderEntry) {
switch (renderEntry.type) {
case partTypes.initRead: {
this._initRead(renderEntry);
}
break;
case partTypes.leftArrow: {
this._renderArrow(renderEntry, ALIGNMENT_ARROW_DIRECTION_LEFT);
}
break;
case partTypes.rightArrow: {
this._renderArrow(renderEntry, ALIGNMENT_ARROW_DIRECTION_RIGHT);
}
break;
case partTypes.match: {
this._renderMatch(renderEntry);
}
break;
case partTypes.insertion: {
this._renderInsertion(renderEntry);
}
break;
case partTypes.deletion: {
this._renderDeletion(renderEntry);
}
break;
case partTypes.softClipBase: {
this._renderBase(renderEntry);
}
break;
case partTypes.base:
case partTypes.cytosineMismatch:
case partTypes.noncytosineMismatch: {
this._renderMismatch(renderEntry);
}
break;
case partTypes.pairedReadConnection: {
this._renderPairedReadConnection(renderEntry);
}
break;
case partTypes.spliceJunctions: {
this._renderSpliceJunction(renderEntry);
}
break;
case partTypes.methylatedBase:
case partTypes.unmethylatedBase:
case partTypes.cgMethylatedBase:
case partTypes.cgUnmethylatedBase:
case partTypes.gcMethylatedBase:
case partTypes.gcUnmethylatedBase: {
this._renderMethylation(renderEntry);
}
break;
}
}
_renderMethylation(renderEntry) {
const {localYHeight, localYOffset} =
AlignmentsRenderer.getRenderEntryVerticalPositioning(renderEntry);
const {breakOnLeft, breakOnRight} = this._getReadBreaks(renderEntry);
const start = renderEntry.startIndex + (breakOnLeft ? BP_OFFSET : 0);
const end = renderEntry.endIndex + (breakOnRight ? -BP_OFFSET : 0);
const type = bisulfiteTypes.numbers[renderEntry.type];
this._setColor(this._colors.bisulfite[type]);
this._scaledRect(
start,
localYOffset,
end - start,
localYHeight,
0);
}
_setColor(color, alpha = 1) {
if (color !== this._currentColor || alpha !== this._currentAlpha) {
this._graphics.endFill();
this._currentColor = color;
this._currentAlpha = alpha;
this._graphics.beginFill(this._currentColor, this._currentAlpha);
}
}
_convertY(y) {
return y * this._yScale;
}
_projectX(x) {
return Math.max(this._minimumPx, Math.min(this._maximumPx, this._viewport.project.brushBP2pixel(x - BP_OFFSET)));
}
_projectY(y) {
return (y * this._yScale - this._linesOffset + this._currentLine * this._yGlobalScale + this._topMargin);
}
_scaledRect(x, y, width, height, margin = 0) {
const x1 = Math.floor(this._projectX(x) + margin);
const x2 = Math.floor(this._projectX(x + width) - margin);
this._graphics.drawRect(
x1,
Math.floor(this._projectY(y)),
x2 - x1,
Math.floor(this._convertY(height) >> 0)
);
}
_renderReadBorders(color, startIndex, endIndex, renderContoured, localYOffset, localYHeight) {
this._setColor(this._hovered ? ColorProcessor.darkenColor(color, 0.1) : color, renderContoured ? 0.5 : 1);
this._graphics.lineStyle(0, this._baseColor, 0);
this._scaledRect(startIndex, localYOffset, endIndex - startIndex, localYHeight);
if (this._hovered) {
this._graphics.endFill();
this._graphics.lineStyle(this._lineWidth, ColorProcessor.darkenColor(color), 1);
this._graphics.moveTo(Math.floor(this._projectX(startIndex)) + this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset)) - this._lineWidth / 2.0);
this._graphics.lineTo(Math.floor(this._projectX(startIndex)) + this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset + localYHeight)) - this._lineWidth / 2.0);
this._graphics.moveTo(Math.floor(this._projectX(startIndex)),
Math.floor(this._projectY(localYOffset + localYHeight)) - this._lineWidth);
this._graphics.lineTo(Math.floor(this._projectX(endIndex)),
Math.floor(this._projectY(localYOffset + localYHeight)) - this._lineWidth);
this._graphics.moveTo(Math.floor(this._projectX(endIndex)) - this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset + localYHeight)) - this._lineWidth / 2.0);
this._graphics.lineTo(Math.floor(this._projectX(endIndex)) - this._lineWidth / 2.0,
Math.floor(this._projectY(localYOffset)) - this._lineWidth / 2.0);
this._graphics.moveTo(Math.floor(this._projectX(endIndex)),
Math.floor(this._projectY(localYOffset)));
this._graphics.lineTo(Math.floor(this._projectX(startIndex)),
Math.floor(this._projectY(localYOffset)));
this._graphics.lineStyle(0, color, 0);
this._graphics.beginFill(this._currentColor, this._currentAlpha);
if (!this._textureStartX || (Math.floor(this._projectX(startIndex)) - this._lineWidth / 2.0) < this._textureStartX) {
this._textureStartX = Math.floor(this._projectX(startIndex)) - this._lineWidth / 2.0;
}
if (!this._textureStartY || this._projectY(localYOffset) - this._lineWidth < this._textureStartY) {
this._textureStartY = this._projectY(localYOffset) - this._lineWidth;
}
} else {
if (!this._textureStartX || (Math.floor(this._projectX(startIndex))) < this._textureStartX) {
this._textureStartX = Math.floor(this._projectX(startIndex));
}
if (!this._textureStartY || this._projectY(localYOffset) < this._textureStartY) {
this._textureStartY = this._projectY(localYOffset);
}
}
}
_renderReadBordersWithBreaks(color, startIndex, endIndex, breakStart, breakEnd, renderContoured, localYOffset, localYHeight) {
startIndex = startIndex + (breakStart ? BP_OFFSET : 0);
endIndex = endIndex + (breakEnd ? -BP_OFFSET : 0);
if (!this._textureStartX || this._projectX(startIndex) < this._textureStartX) {
this._textureStartX = this._projectX(startIndex);
}
this._renderReadBorders(color, startIndex, endIndex, renderContoured, localYOffset, localYHeight);
}
}