_manageReferenceViewports()

in client/client/modules/render/variant-render/renderers/structural-variant-renderer.js [104:358]


    _manageReferenceViewports(config) {
        this._breakpointPositioning.clear();
        if (!this._transcriptExpandedStatus) {
            this._transcriptExpandedStatus = {};
        }
        let maximumItemsLength = 0;
        let maximumLeftLength = 0;
        let maximumRightLength = 0;
        let maximumBreakpointsPerChromosome = 0;
        const chromosomeVisualInfo = {};
        const refZone = {name: 'reference', zones: []};
        let maxChromosomeLabelSize = 0;

        const geneTranscriptsZones = [];

        for (let i = 0; i < this.variant.analysisResult.chromosomes.length; i++) {
            const name = this._getChromosomeDisplayName(this.variant.analysisResult.chromosomes[i]);
            const size = PixiTextSize.getTextSize(name, this.config.chromosome.label);
            if (maxChromosomeLabelSize < size.width) {
                maxChromosomeLabelSize = size.width;
            }
        }
        for (let i = 0; i < this.variant.analysisResult.chromosomes.length; i++) {
            const subZone = {
                name: this.variant.analysisResult.chromosomes[i].toUpperCase(),
                zones: []
            };
            refZone.zones.push(subZone);
            const breakpointsAtChromosome = this.variant.analysisResult.breakpoints.filter(breakpoint => breakpoint.chromosome.name.toLowerCase() === this.variant.analysisResult.chromosomes[i]);
            let itemsLengthAtChromosome = 0;
            const genes = {};
            const geneNames = [];
            const visualBreakpoints = [];
            let prevGene = null;
            let prevPosition = null;
            let maxTranscriptsPerChromosome = 0;
            let emptyGenesLength = 0;
            for (let j = 0; j < breakpointsAtChromosome.length; j++) {
                const breakpoint = breakpointsAtChromosome[j];
                if (breakpoint.affectedGene !== undefined && breakpoint.affectedGene !== null) {
                    const affectedGene = breakpoint.affectedGene;
                    if (!affectedGene.empty) {
                        if (maxTranscriptsPerChromosome < affectedGene.transcripts.length) {
                            maxTranscriptsPerChromosome = affectedGene.transcripts.length;
                        }
                    }
                    if (prevGene && prevPosition && (prevGene.empty || affectedGene.empty || prevGene.name !== affectedGene.name)) {
                        const left = {
                            gene: prevGene,
                            range: {
                                start: prevPosition,
                                end: prevGene.empty ? emptyGeneSize : prevGene.totalExonsLength
                            }
                        };
                        const right = {
                            gene: affectedGene,
                            range: {
                                start: affectedGene.empty ? 0 : breakpoint.relativePositions[affectedGene.name],
                                end: affectedGene.empty ? emptyGeneSize / 2 : affectedGene.totalExonsLength
                            }
                        };
                        visualBreakpoints.push({
                            left,
                            right
                        });
                    }
                    const left = {
                        gene: affectedGene,
                        range: {
                            start: affectedGene.empty ? 0 : ((prevGene && prevGene.name === affectedGene.name) ? prevPosition : 0),
                            end: affectedGene.empty ? emptyGeneSize / 2 : breakpoint.relativePositions[breakpoint.affectedGene.name]
                        }
                    };
                    const right = {
                        gene: affectedGene,
                        range: {
                            start: affectedGene.empty ? emptyGeneSize / 2 : breakpoint.relativePositions[breakpoint.affectedGene.name],
                            end: affectedGene.empty ? emptyGeneSize : affectedGene.totalExonsLength
                        }
                    };
                    visualBreakpoints.push({
                        left,
                        right,
                        dataBreakpoint: breakpoint
                    });

                    prevGene = affectedGene;
                    prevPosition = affectedGene.empty ? emptyGeneSize / 2 : breakpoint.relativePositions[breakpoint.affectedGene.name];
                    if (affectedGene.empty) {
                        emptyGenesLength += emptyGeneSize;
                    }
                    else {
                        if (!genes.hasOwnProperty(affectedGene.name)) {
                            genes[affectedGene.name] = 0;
                            geneNames.push(affectedGene.name);
                        }
                        let itemsLengthAtGene = 0;
                        for (let k = 0; k < affectedGene.consensusExons.length; k++) {
                            itemsLengthAtGene += (affectedGene.consensusExons[k].end - affectedGene.consensusExons[k].start);
                        }
                        genes[affectedGene.name] = itemsLengthAtGene;
                    }
                }
            }
            subZone.zones.push({name: 'gene'});
            subZone.zones.push({name: 'upper', zones: [{name: 'edges'}]});
            subZone.zones.push({name: 'chromosome'});
            subZone.zones.push({name: 'down', zones: [{name: 'edges'}]});

            for (let j = 0; j < geneNames.length; j++) {
                itemsLengthAtChromosome += genes[geneNames[j]];
            }
            itemsLengthAtChromosome += emptyGenesLength;
            chromosomeVisualInfo[this.variant.analysisResult.chromosomes[i]] = {
                itemsLength: itemsLengthAtChromosome,
                visualBreakpoints: visualBreakpoints
            };
            if (maximumBreakpointsPerChromosome < visualBreakpoints.length) {
                maximumBreakpointsPerChromosome = visualBreakpoints.length;
            }
            if (maximumItemsLength < itemsLengthAtChromosome) {
                maximumItemsLength = itemsLengthAtChromosome;
            }
        }
        if (maximumBreakpointsPerChromosome === 1) {
            for (let i = 0; i < this.variant.analysisResult.chromosomes.length; i++) {
                const chromosomeName = this.variant.analysisResult.chromosomes[i];
                if (chromosomeVisualInfo[chromosomeName].visualBreakpoints.length === 1) {
                    const visualBreakpoint = chromosomeVisualInfo[chromosomeName].visualBreakpoints[0];
                    chromosomeVisualInfo[chromosomeName].leftPart = visualBreakpoint.left.range.end - visualBreakpoint.left.range.start;
                    if (visualBreakpoint.left.range.end - visualBreakpoint.left.range.start > maximumLeftLength) {
                        maximumLeftLength = visualBreakpoint.left.range.end - visualBreakpoint.left.range.start;
                    }
                    if (visualBreakpoint.right.range.end - visualBreakpoint.right.range.start > maximumRightLength) {
                        maximumRightLength = visualBreakpoint.right.range.end - visualBreakpoint.right.range.start;
                    }
                }
            }
            maximumItemsLength = maximumLeftLength + maximumRightLength;
        }
        this._visualAreaOffset = this.config.reference.width + this.config.reference.margin.x + this.config.chromosome.margin + this.config.breakpoint.width / 2;
        const offset = this._visualAreaOffset + maxChromosomeLabelSize;
        this._mainOffset = offset - 5;
        const usefulCanvasLength = config.width - maximumBreakpointsPerChromosome * this.config.breakpoint.width - 2 * offset;
        const factor = usefulCanvasLength / maximumItemsLength;

        const convertBpToPixels = (bp) => bp * factor;

        const registerViewport = (name, bpRange, canvasStart) => {
            const canvasParams = {
                start: canvasStart,
                end: canvasStart + convertBpToPixels(bpRange.end - bpRange.start)
            };
            const viewport = new BaseViewport({chromosome: bpRange, brush: bpRange, canvas: canvasParams});
            let viewports = this.viewports.get(name.toUpperCase());
            if (!viewports) {
                viewports = [];
            }
            viewports.push(viewport);
            this.viewports.set(name.toUpperCase(), viewports);
            return viewport;
        };

        const registerViewportByRange = (name, bpRange, canvasRange) => {
            const viewport = new BaseViewport({chromosome: bpRange, brush: bpRange, canvas: canvasRange});
            let viewports = this.viewports.get(name.toUpperCase());
            if (!viewports) {
                viewports = [];
            }
            viewports.push(viewport);
            this.viewports.set(name.toUpperCase(), viewports);
            return viewport;
        };

        for (let i = 0; i < this.variant.analysisResult.geneNames.length; i++) {
            const gene = this.variant.analysisResult.genes[this.variant.analysisResult.geneNames[i]].gene;
            if (this._transcriptExpandedStatus[gene.name.toUpperCase()] === undefined) {
                this._transcriptExpandedStatus[gene.name.toUpperCase()] = false;
            }
            const start = 0;
            let end = null;
            const zone = {
                name: `${gene.name} transcripts`,
                zones: [{name: 'transcriptLabel'}]
            };
            const geneTranscriptsZone = {
                name: 'transcriptsZone',
                zones: [],
                expanded: this._transcriptExpandedStatus[gene.name.toUpperCase()]
            };
            zone.zones.push(geneTranscriptsZone);
            geneTranscriptsZones.push(zone);
            for (let j = 0; j < gene.transcripts.length; j++) {
                const transcript = gene.transcripts[j];
                for (let t = 0; t < transcript.canonicalCds.length; t++) {
                    const cds = transcript.canonicalCds[t];
                    if (end === null || end < cds.positionFromStart.end) {
                        end = cds.positionFromStart.end;
                    }
                }
                geneTranscriptsZone.zones.push({
                    name: `${gene.name}_transcript_${j}`,
                    zones: [{name: 'transcriptName'}, {name: 'transcript'}]
                });
                registerViewportByRange(`${gene.name}_transcript_${j}`,
                    {start, end},
                    {
                        start: offset + this.config.transcript.radio.radius * 2 +
                        this.config.transcript.radio.margin * 2,
                        end: config.width - offset
                    });
            }
            geneTranscriptsZone.zones.push({name: 'buffer'});
        }

        for (let i = 0; i < this.variant.analysisResult.chromosomes.length; i++) {
            const chromosomeName = this.variant.analysisResult.chromosomes[i];
            const chromosomeWidthPx = convertBpToPixels(chromosomeVisualInfo[chromosomeName].itemsLength) + chromosomeVisualInfo[chromosomeName].visualBreakpoints.length * this.config.breakpoint.width;
            let startX = config.width / 2 - chromosomeWidthPx / 2;
            if (chromosomeVisualInfo[chromosomeName].leftPart !== undefined) {
                startX = offset + convertBpToPixels(maximumLeftLength - chromosomeVisualInfo[chromosomeName].leftPart);
            }
            for (let j = 0; j < chromosomeVisualInfo[chromosomeName].visualBreakpoints.length; j++) {
                const visualBreakpoint = chromosomeVisualInfo[chromosomeName].visualBreakpoints[j];
                if (j < chromosomeVisualInfo[chromosomeName].visualBreakpoints.length - 1) {
                    // left viewport
                    const viewportCanvasWidth = convertBpToPixels(visualBreakpoint.left.range.end - visualBreakpoint.left.range.start);
                    const viewport = registerViewport(`${chromosomeName}:${visualBreakpoint.left.gene.name}`, visualBreakpoint.left.range, startX);
                    startX += this.config.breakpoint.width + viewportCanvasWidth;
                    if (visualBreakpoint.dataBreakpoint) {
                        this._breakpointPositioning.set(visualBreakpoint.dataBreakpoint, {
                            start: viewport.canvas.end,
                            end: viewport.canvas.end + this.config.breakpoint.width
                        });
                    }
                }
                else {
                    // left & right viewports
                    const leftViewportCanvasWidth = convertBpToPixels(visualBreakpoint.left.range.end - visualBreakpoint.left.range.start);
                    const viewport = registerViewport(`${chromosomeName}:${visualBreakpoint.left.gene.name}`, visualBreakpoint.left.range, startX);
                    startX += this.config.breakpoint.width + leftViewportCanvasWidth;
                    if (visualBreakpoint.dataBreakpoint) {
                        this._breakpointPositioning.set(visualBreakpoint.dataBreakpoint, {
                            start: viewport.canvas.end,
                            end: viewport.canvas.end + this.config.breakpoint.width
                        });
                    }
                    const rightViewportCanvasWidth = convertBpToPixels(visualBreakpoint.right.range.end - visualBreakpoint.right.range.start);
                    registerViewport(`${chromosomeName}:${visualBreakpoint.right.gene.name}`, visualBreakpoint.right.range, startX);
                    startX += this.config.breakpoint.width + rightViewportCanvasWidth;
                }
            }
        }
        return [...geneTranscriptsZones, refZone];
    }