export function renderGroups()

in client/client/modules/render/tracks/bam/internal/renderer/features/groupsRenderer.js [13:136]


export function renderGroups(features, groups, drawingConfig, labelsManager) {
    const {
        alignmentRowHeight,
        config,
        groupNamesContainer,
        groupsBackground,
        groupsSeparatorGraphics,
        height,
        scrollY,
        topMargin,
        viewport} = drawingConfig;
    groupsSeparatorGraphics.clear();
    if (features.groupMode === groupModes.defaultGroupingMode) {
        return;
    }

    const backgroundGraphics = new PIXI.Graphics();

    groupsBackground.addChild(backgroundGraphics);

    const graphics = new PIXI.Graphics();
    groupNamesContainer.addChild(graphics);

    const yElementOffset = alignmentRowHeight === 1 ? 0 : config.yElementOffset;
    const yScale = alignmentRowHeight - yElementOffset;

    const yOffset = scrollY * alignmentRowHeight - yElementOffset;

    const projectY = y => (Math.round(yScale / 2 - yOffset + y * alignmentRowHeight + topMargin));

    const labels = [];
    for (let i = 0; i < groups.length; i++) {
        const group = groups[i];
        const label = labelsManager
            ? labelsManager.getLabel(group.displayName.toUpperCase(), config.groupNames.label)
            : undefined;
        labels.push(label);
    }
    const labelsPositions = [];
    const submitLabel = (label) => {
        let intersects = labelsPositions.length > 0;
        while (intersects) {
            intersects = false;
            for (let i = 0; i < labelsPositions.length; i++) {
                const candidateLabel = labelsPositions[i];
                if (labelsIntersects(candidateLabel, label)) {
                    intersects = true;
                    label.x = candidateLabel.x + candidateLabel.width + 1;
                    break;
                }
            }
        }
        labelsPositions.push(label);
        return label;
    };

    const BP_OFFSET = 0.5;

    for (let i = 0; i < groups.length; i++) {
        const group = groups[i];
        const label = labels[i];
        const y = features.viewAsPairs ? group.previousPairedLinesCount : group.previousLinesCount;
        const yEnd = y + (features.viewAsPairs ? group.pairedLines.length : group.lines.length);
        if (yEnd < scrollY)
            continue;
        const yPx = Math.max(topMargin, projectY(y - BP_OFFSET) - config.groupNames.margin.y);
        if (label) {
            if (i % 2 === 1) {
                backgroundGraphics
                    .lineStyle(0, 0x000000, 0)
                    .beginFill(config.groupNames.oddFill, 1)
                    .drawRect(
                        0,
                        projectY(y - BP_OFFSET),
                        viewport.canvasSize,
                        projectY(yEnd - BP_OFFSET) - projectY(y - BP_OFFSET))
                    .endFill();
                if (yScale > config.groupNames.separator.hideThreshold) {
                    groupsSeparatorGraphics
                        .lineStyle(config.groupNames.separator.strokeThickness,
                            config.groupNames.separator.stroke,
                            config.groupNames.separator.strokeAlpha)
                        .moveTo(0, projectY(y - BP_OFFSET) - config.groupNames.separator.strokeThickness / 2)
                        .lineTo(viewport.canvasSize,
                            projectY(y - BP_OFFSET) - config.groupNames.separator.strokeThickness / 2)
                        .moveTo(0,
                            projectY(yEnd - BP_OFFSET) - config.groupNames.separator.strokeThickness / 2)
                        .lineTo(viewport.canvasSize,
                            projectY(yEnd - BP_OFFSET) - config.groupNames.separator.strokeThickness / 2);
                }
            }

            const labelRect = submitLabel({
                height: label.height + 2 * config.groupNames.margin.y,
                width: label.width + 2 * config.groupNames.margin.x,
                x: Math.round(config.groupNames.offset) - config.groupNames.margin.x,
                y: yPx,
            });

            label.x = Math.round(labelRect.x + config.groupNames.margin.x);
            label.y = Math.round(labelRect.y + config.groupNames.margin.y);
            graphics
                .beginFill(config.groupNames.background.fill, config.groupNames.background.alpha)
                .lineStyle(config.groupNames.background.strokeThickness, config.groupNames.background.stroke, config.groupNames.background.alpha)
                .drawRoundedRect(
                    labelRect.x + config.groupNames.background.strokeThickness / 2,
                    labelRect.y + config.groupNames.background.strokeThickness / 2,
                    labelRect.width,
                    labelRect.height,
                    labelRect.height / 2
                )
                .endFill();
            groupNamesContainer.addChild(label);
        }
    }
    backgroundGraphics.endFill();
    const mask = new PIXI.Graphics();
    mask.beginFill(0x000000, 1)
        .drawRect(0, topMargin, viewport.canvasSize, height - topMargin)
        .endFill();
    groupNamesContainer.mask = mask;
    groupsBackground.mask = mask;
    groupsSeparatorGraphics.mask = mask;
}