molstar
Version:
A comprehensive macromolecular library.
155 lines (154 loc) • 8.14 kB
JavaScript
"use strict";
/**
* Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.LabelTextParams = void 0;
exports.LabelTextVisual = LabelTextVisual;
const param_definition_1 = require("../../../mol-util/param-definition");
const structure_1 = require("../../../mol-model/structure");
const text_builder_1 = require("../../../mol-geo/geometry/text/text-builder");
const complex_visual_1 = require("../complex-visual");
const element_1 = require("./util/element");
const names_1 = require("../../../mol-util/color/names");
const linear_algebra_1 = require("../../../mol-math/linear-algebra");
const boundary_helper_1 = require("../../../mol-math/geometry/boundary-helper");
const element_2 = require("./util/element");
exports.LabelTextParams = {
...complex_visual_1.ComplexTextParams,
background: param_definition_1.ParamDefinition.Boolean(false),
backgroundMargin: param_definition_1.ParamDefinition.Numeric(0, { min: 0, max: 1, step: 0.01 }),
backgroundColor: param_definition_1.ParamDefinition.Color(names_1.ColorNames.black),
backgroundOpacity: param_definition_1.ParamDefinition.Numeric(0.5, { min: 0, max: 1, step: 0.01 }),
borderWidth: param_definition_1.ParamDefinition.Numeric(0.25, { min: 0, max: 0.5, step: 0.01 }),
level: param_definition_1.ParamDefinition.Select('residue', [['chain', 'Chain'], ['residue', 'Residue'], ['element', 'Element']], { isEssential: true }),
ignoreHydrogens: param_definition_1.ParamDefinition.Boolean(false),
ignoreHydrogensVariant: param_definition_1.ParamDefinition.Select('all', param_definition_1.ParamDefinition.arrayToOptions(['all', 'non-polar'])),
chainScale: param_definition_1.ParamDefinition.Numeric(10, { min: 0, max: 20, step: 0.1 }),
residueScale: param_definition_1.ParamDefinition.Numeric(1, { min: 0, max: 20, step: 0.1 }),
elementScale: param_definition_1.ParamDefinition.Numeric(0.5, { min: 0, max: 20, step: 0.1 }),
};
function LabelTextVisual(materialId) {
return (0, complex_visual_1.ComplexTextVisual)({
defaultProps: param_definition_1.ParamDefinition.getDefaultValues(exports.LabelTextParams),
createGeometry: createLabelText,
createLocationIterator: element_1.ElementIterator.fromStructure,
getLoci: element_1.getSerialElementLoci,
eachLocation: element_1.eachSerialElement,
setUpdateState: (state, newProps, currentProps) => {
state.createGeometry = (newProps.level !== currentProps.level ||
(newProps.level === 'chain' && newProps.chainScale !== currentProps.chainScale) ||
(newProps.level === 'residue' && newProps.residueScale !== currentProps.residueScale) ||
(newProps.level === 'element' && newProps.elementScale !== currentProps.elementScale) ||
newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
newProps.ignoreHydrogensVariant !== currentProps.ignoreHydrogensVariant);
}
}, materialId);
}
function createLabelText(ctx, structure, theme, props, text) {
switch (props.level) {
case 'chain': return createChainText(ctx, structure, theme, props, text);
case 'residue': return createResidueText(ctx, structure, theme, props, text);
case 'element': return createElementText(ctx, structure, theme, props, text);
}
}
//
const tmpVec = (0, linear_algebra_1.Vec3)();
const boundaryHelper = new boundary_helper_1.BoundaryHelper('98');
function createChainText(ctx, structure, theme, props, text) {
const l = structure_1.StructureElement.Location.create(structure);
const { units, serialMapping } = structure;
const { auth_asym_id, label_asym_id } = structure_1.StructureProperties.chain;
const { cumulativeUnitElementCount } = serialMapping;
const count = units.length;
const { chainScale } = props;
const builder = text_builder_1.TextBuilder.create(props, count, count / 2, text);
for (let i = 0, il = units.length; i < il; ++i) {
const unit = units[i];
l.unit = unit;
l.element = unit.elements[0];
const { center, radius } = unit.lookup3d.boundary.sphere;
linear_algebra_1.Vec3.transformMat4(tmpVec, center, unit.conformation.operator.matrix);
const authId = auth_asym_id(l);
const labelId = label_asym_id(l);
const text = authId === labelId ? labelId : `${labelId} [${authId}]`;
builder.add(text, tmpVec[0], tmpVec[1], tmpVec[2], radius, chainScale, cumulativeUnitElementCount[i]);
}
return builder.getText();
}
function createResidueText(ctx, structure, theme, props, text) {
const l = structure_1.StructureElement.Location.create(structure);
const { units, serialMapping } = structure;
const { label_comp_id } = structure_1.StructureProperties.atom;
const { auth_seq_id } = structure_1.StructureProperties.residue;
const { cumulativeUnitElementCount } = serialMapping;
const count = structure.polymerResidueCount * 2;
const { residueScale } = props;
const builder = text_builder_1.TextBuilder.create(props, count, count / 2, text);
for (let i = 0, il = units.length; i < il; ++i) {
const unit = units[i];
const c = unit.conformation;
const { elements } = unit;
l.unit = unit;
l.element = unit.elements[0];
const residueIndex = unit.model.atomicHierarchy.residueAtomSegments.index;
const groupOffset = cumulativeUnitElementCount[i];
let j = 0;
const jl = elements.length;
while (j < jl) {
const start = j, rI = residueIndex[elements[j]];
j++;
while (j < jl && residueIndex[elements[j]] === rI)
j++;
boundaryHelper.reset();
for (let eI = start; eI < j; eI++) {
c.position(elements[eI], tmpVec);
boundaryHelper.includePosition(tmpVec);
}
boundaryHelper.finishedIncludeStep();
for (let eI = start; eI < j; eI++) {
c.position(elements[eI], tmpVec);
boundaryHelper.radiusPosition(tmpVec);
}
l.element = elements[start];
const { center, radius } = boundaryHelper.getSphere();
const authSeqId = auth_seq_id(l);
const compId = label_comp_id(l);
const text = `${compId} ${authSeqId}`;
builder.add(text, center[0], center[1], center[2], radius, residueScale, groupOffset + start);
}
}
return builder.getText();
}
function createElementText(ctx, structure, theme, props, text) {
const l = structure_1.StructureElement.Location.create(structure);
const { units, serialMapping } = structure;
const { label_atom_id, label_alt_id } = structure_1.StructureProperties.atom;
const { cumulativeUnitElementCount } = serialMapping;
const sizeTheme = theme.size;
const count = structure.elementCount;
const { elementScale } = props;
const builder = text_builder_1.TextBuilder.create(props, count, count / 2, text);
for (let i = 0, il = units.length; i < il; ++i) {
const unit = units[i];
const c = unit.conformation;
const { elements } = unit;
l.unit = unit;
const groupOffset = cumulativeUnitElementCount[i];
const ignore = (0, element_2.makeElementIgnoreTest)(structure, unit, { ...props, traceOnly: false });
for (let j = 0, _j = elements.length; j < _j; j++) {
if (ignore && ignore(elements[j]))
continue;
l.element = elements[j];
c.position(l.element, tmpVec);
const atomId = label_atom_id(l);
const altId = label_alt_id(l);
const text = altId ? `${atomId}%${altId}` : atomId;
builder.add(text, tmpVec[0], tmpVec[1], tmpVec[2], sizeTheme.size(l), elementScale, groupOffset + j);
}
}
return builder.getText();
}