UNPKG

molstar

Version:

A comprehensive macromolecular library.

309 lines (308 loc) 16.4 kB
"use strict"; /** * Copyright (c) 2023-2025 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Adam Midlik <midlik@gmail.com> * @author David Sehnal <david.sehnal@gmail.com> * @author Aliaksei Chareshneu <chareshneu.tech@gmail.com> */ Object.defineProperty(exports, "__esModule", { value: true }); exports.BuiltinLoadingExtensions = exports.MolstarLoadingContext = void 0; exports.loadMVS = loadMVS; const snapshots_1 = require("../../mol-plugin-state/manager/snapshots"); const objects_1 = require("../../mol-plugin-state/objects"); const data_1 = require("../../mol-plugin-state/transforms/data"); const model_1 = require("../../mol-plugin-state/transforms/model"); const representation_1 = require("../../mol-plugin-state/transforms/representation"); const volume_1 = require("../../mol-plugin-state/transforms/volume"); const commands_1 = require("../../mol-plugin/commands"); const behavior_1 = require("./behavior"); const camera_1 = require("./camera"); const annotation_prop_1 = require("./components/annotation-prop"); const annotation_structure_component_1 = require("./components/annotation-structure-component"); const annotation_tooltips_prop_1 = require("./components/annotation-tooltips-prop"); const representation_2 = require("./components/custom-label/representation"); const custom_tooltips_prop_1 = require("./components/custom-tooltips-prop"); const is_mvs_model_prop_1 = require("./components/is-mvs-model-prop"); const primitives_1 = require("./components/primitives"); const is_hidden_custom_state_1 = require("./load-extensions/is-hidden-custom-state"); const non_covalent_interactions_1 = require("./load-extensions/non-covalent-interactions"); const load_generic_1 = require("./load-generic"); const load_helpers_1 = require("./load-helpers"); const mvs_data_1 = require("./mvs-data"); const tree_schema_1 = require("./tree/generic/tree-schema"); const conversion_1 = require("./tree/molstar/conversion"); const molstar_tree_1 = require("./tree/molstar/molstar-tree"); const mvs_tree_1 = require("./tree/mvs/mvs-tree"); /** Load a MolViewSpec (MVS) state(s) into the Mol* plugin as plugin state snapshots. */ async function loadMVS(plugin, data, options = {}) { plugin.errorContext.clear('mvs'); try { const mvsExtensionLoaded = plugin.state.hasBehavior(behavior_1.MolViewSpec); if (!mvsExtensionLoaded) throw new Error('MolViewSpec extension is not loaded.'); // console.log(`MVS tree:\n${MVSData.toPrettyString(data)}`) const multiData = data.kind === 'multiple' ? data : mvs_data_1.MVSData.stateToStates(data); const entries = []; for (let i = 0; i < multiData.snapshots.length; i++) { const snapshot = multiData.snapshots[i]; const previousSnapshot = i > 0 ? multiData.snapshots[i - 1] : multiData.snapshots[multiData.snapshots.length - 1]; (0, tree_schema_1.validateTree)(mvs_tree_1.MVSTreeSchema, snapshot.root, 'MVS'); if (options.sanityChecks) (0, conversion_1.mvsSanityCheck)(snapshot.root); const molstarTree = (0, conversion_1.convertMvsToMolstar)(snapshot.root, options.sourceUrl); (0, tree_schema_1.validateTree)(molstar_tree_1.MolstarTreeSchema, molstarTree, 'Converted Molstar'); const entry = molstarTreeToEntry(plugin, molstarTree, { ...snapshot.metadata, previousTransitionDurationMs: previousSnapshot.metadata.transition_duration_ms }, options); entries.push(entry); } if (!options.appendSnapshots) { plugin.managers.snapshot.clear(); } for (const entry of entries) { plugin.managers.snapshot.add(entry); } if (entries.length > 0) { await commands_1.PluginCommands.State.Snapshots.Apply(plugin, { id: entries[0].snapshot.id }); } } catch (err) { plugin.log.error(`${err}`); throw err; } finally { if (!options.doNotReportErrors) { for (const error of plugin.errorContext.get('mvs')) { plugin.log.warn(error); commands_1.PluginCommands.Toast.Show(plugin, { title: 'Error', message: error, timeoutMs: 10000 }); } } plugin.errorContext.clear('mvs'); } } function molstarTreeToEntry(plugin, tree, metadata, options) { var _a, _b, _c; const context = exports.MolstarLoadingContext.create(); const snapshot = (0, load_generic_1.loadTreeVirtual)(plugin, tree, MolstarLoadingActions, context, { replaceExisting: true, extensions: (_a = options === null || options === void 0 ? void 0 : options.extensions) !== null && _a !== void 0 ? _a : exports.BuiltinLoadingExtensions }); snapshot.canvas3d = { props: plugin.canvas3d ? (0, camera_1.modifyCanvasProps)(plugin.canvas3d.props, context.canvas) : undefined, }; if (!(options === null || options === void 0 ? void 0 : options.keepCamera)) { snapshot.camera = (0, camera_1.createPluginStateSnapshotCamera)(plugin, context, metadata); } snapshot.durationInMs = metadata.linger_duration_ms + ((_b = metadata.previousTransitionDurationMs) !== null && _b !== void 0 ? _b : 0); const entryParams = { key: metadata.key, name: metadata.title, description: metadata.description, descriptionFormat: (_c = metadata.description_format) !== null && _c !== void 0 ? _c : 'markdown', }; const entry = snapshots_1.PluginStateSnapshotManager.Entry(snapshot, entryParams); return entry; } exports.MolstarLoadingContext = { create() { return { annotationMap: new Map(), camera: { focuses: [] }, }; }, }; /** Loading actions for loading a `MolstarTree`, per node kind. */ const MolstarLoadingActions = { root(updateParent, node, context) { context.nearestReprMap = (0, load_helpers_1.makeNearestReprMap)(node); return updateParent; }, download(updateParent, node) { return load_generic_1.UpdateTarget.apply(updateParent, data_1.Download, { url: node.params.url, isBinary: node.params.is_binary, }); }, parse(updateParent, node) { const format = node.params.format; if (format === 'cif') { return load_generic_1.UpdateTarget.apply(updateParent, data_1.ParseCif, {}); } else if (format === 'pdb') { return updateParent; } else if (format === 'map') { return load_generic_1.UpdateTarget.apply(updateParent, data_1.ParseCcp4, {}); } else { console.error(`Unknown format in "parse" node: "${format}"`); return undefined; } }, trajectory(updateParent, node) { var _a, _b; const format = node.params.format; if (format === 'cif') { return load_generic_1.UpdateTarget.apply(updateParent, model_1.TrajectoryFromMmCif, { blockHeader: (_a = node.params.block_header) !== null && _a !== void 0 ? _a : '', // Must set to '' because just undefined would get overwritten by createDefaults blockIndex: (_b = node.params.block_index) !== null && _b !== void 0 ? _b : undefined, }); } else if (format === 'pdb') { return load_generic_1.UpdateTarget.apply(updateParent, model_1.TrajectoryFromPDB, {}); } else { console.error(`Unknown format in "trajectory" node: "${format}"`); return undefined; } }, model(updateParent, node, context) { const annotations = (0, load_helpers_1.collectAnnotationReferences)(node, context); const model = load_generic_1.UpdateTarget.apply(updateParent, model_1.ModelFromTrajectory, { modelIndex: node.params.model_index, }); load_generic_1.UpdateTarget.apply(model, model_1.CustomModelProperties, { properties: { [is_mvs_model_prop_1.IsMVSModelProvider.descriptor.name]: { isMvs: true }, [annotation_prop_1.MVSAnnotationsProvider.descriptor.name]: { annotations }, }, autoAttach: [ is_mvs_model_prop_1.IsMVSModelProvider.descriptor.name, annotation_prop_1.MVSAnnotationsProvider.descriptor.name, ], }); return model; }, structure(updateParent, node, context) { var _a; const props = (0, load_helpers_1.structureProps)(node); const struct = load_generic_1.UpdateTarget.apply(updateParent, model_1.StructureFromModel, props); let transformed = struct; for (const t of (0, load_helpers_1.transformProps)(node)) { transformed = load_generic_1.UpdateTarget.apply(transformed, model_1.TransformStructureConformation, t); // applying to the result of previous transform, to get the correct transform order } const annotationTooltips = (0, load_helpers_1.collectAnnotationTooltips)(node, context); const inlineTooltips = (0, load_helpers_1.collectInlineTooltips)(node, context); if (annotationTooltips.length + inlineTooltips.length > 0) { load_generic_1.UpdateTarget.apply(struct, model_1.CustomStructureProperties, { properties: { [annotation_tooltips_prop_1.MVSAnnotationTooltipsProvider.descriptor.name]: { tooltips: annotationTooltips }, [custom_tooltips_prop_1.CustomTooltipsProvider.descriptor.name]: { tooltips: inlineTooltips }, }, autoAttach: [ annotation_tooltips_prop_1.MVSAnnotationTooltipsProvider.descriptor.name, custom_tooltips_prop_1.CustomTooltipsProvider.descriptor.name, ], }); } const inlineLabels = (0, load_helpers_1.collectInlineLabels)(node, context); if (inlineLabels.length > 0) { const nearestReprNode = (_a = context.nearestReprMap) === null || _a === void 0 ? void 0 : _a.get(node); load_generic_1.UpdateTarget.apply(struct, representation_1.StructureRepresentation3D, { type: { name: representation_2.CustomLabelRepresentationProvider.name, params: { items: inlineLabels }, }, colorTheme: (0, load_helpers_1.colorThemeForNode)(nearestReprNode, context), }); } return struct; }, tooltip: undefined, // No action needed, already loaded in `structure` tooltip_from_uri: undefined, // No action needed, already loaded in `structure` tooltip_from_source: undefined, // No action needed, already loaded in `structure` component(updateParent, node) { if ((0, load_helpers_1.isPhantomComponent)(node)) { return updateParent; } const selector = node.params.selector; return load_generic_1.UpdateTarget.apply(updateParent, model_1.StructureComponent, { type: (0, load_helpers_1.componentPropsFromSelector)(selector), label: (0, load_helpers_1.prettyNameFromSelector)(selector), nullIfEmpty: false, }); }, component_from_uri(updateParent, node, context) { if ((0, load_helpers_1.isPhantomComponent)(node)) return undefined; const props = (0, load_helpers_1.componentFromXProps)(node, context); return load_generic_1.UpdateTarget.apply(updateParent, annotation_structure_component_1.MVSAnnotationStructureComponent, props); }, component_from_source(updateParent, node, context) { if ((0, load_helpers_1.isPhantomComponent)(node)) return undefined; const props = (0, load_helpers_1.componentFromXProps)(node, context); return load_generic_1.UpdateTarget.apply(updateParent, annotation_structure_component_1.MVSAnnotationStructureComponent, props); }, representation(updateParent, node, context) { return load_generic_1.UpdateTarget.apply(updateParent, representation_1.StructureRepresentation3D, { ...(0, load_helpers_1.representationProps)(node), colorTheme: (0, load_helpers_1.colorThemeForNode)(node, context), }); }, volume(updateParent, node) { var _a, _b; if ((_a = updateParent.transformer) === null || _a === void 0 ? void 0 : _a.definition.to.includes(objects_1.PluginStateObject.Format.Ccp4)) { return load_generic_1.UpdateTarget.apply(updateParent, volume_1.VolumeFromCcp4, {}); } else if ((_b = updateParent.transformer) === null || _b === void 0 ? void 0 : _b.definition.to.includes(objects_1.PluginStateObject.Format.Cif)) { return load_generic_1.UpdateTarget.apply(updateParent, volume_1.VolumeFromDensityServerCif, { blockHeader: node.params.channel_id || undefined }); } else { console.error(`Unsupported volume format`); return undefined; } }, volume_representation(updateParent, node, context) { return load_generic_1.UpdateTarget.apply(updateParent, representation_1.VolumeRepresentation3D, { ...(0, load_helpers_1.volumeRepresentationProps)(node), colorTheme: (0, load_helpers_1.volumeColorThemeForNode)(node, context), }); }, color: undefined, // No action needed, already loaded in `representation` color_from_uri: undefined, // No action needed, already loaded in `representation` color_from_source: undefined, // No action needed, already loaded in `representation` label: undefined, // No action needed, already loaded in `structure` label_from_uri(updateParent, node, context) { const props = (0, load_helpers_1.labelFromXProps)(node, context); return load_generic_1.UpdateTarget.apply(updateParent, representation_1.StructureRepresentation3D, props); }, label_from_source(updateParent, node, context) { const props = (0, load_helpers_1.labelFromXProps)(node, context); return load_generic_1.UpdateTarget.apply(updateParent, representation_1.StructureRepresentation3D, props); }, focus(updateParent, node, context) { context.camera.focuses.push({ target: updateParent.selector, params: node.params }); return updateParent; }, camera(updateParent, node, context) { context.camera.cameraParams = node.params; return updateParent; }, canvas(updateParent, node, context) { context.canvas = node.params; return updateParent; }, primitives(updateParent, tree, context) { const refs = (0, primitives_1.getPrimitiveStructureRefs)(tree); const data = load_generic_1.UpdateTarget.apply(updateParent, primitives_1.MVSInlinePrimitiveData, { node: tree }); return applyPrimitiveVisuals(data, refs); }, primitives_from_uri(updateParent, tree, context) { const data = load_generic_1.UpdateTarget.apply(updateParent, primitives_1.MVSDownloadPrimitiveData, { uri: tree.params.uri, format: tree.params.format }); return applyPrimitiveVisuals(data, new Set(tree.params.references)); }, }; function applyPrimitiveVisuals(data, refs) { const mesh = load_generic_1.UpdateTarget.setMvsDependencies(load_generic_1.UpdateTarget.apply(data, primitives_1.MVSBuildPrimitiveShape, { kind: 'mesh' }, { state: { isGhost: true } }), refs); load_generic_1.UpdateTarget.apply(mesh, representation_1.ShapeRepresentation3D); const labels = load_generic_1.UpdateTarget.setMvsDependencies(load_generic_1.UpdateTarget.apply(data, primitives_1.MVSBuildPrimitiveShape, { kind: 'labels' }, { state: { isGhost: true } }), refs); load_generic_1.UpdateTarget.apply(labels, representation_1.ShapeRepresentation3D); const lines = load_generic_1.UpdateTarget.setMvsDependencies(load_generic_1.UpdateTarget.apply(data, primitives_1.MVSBuildPrimitiveShape, { kind: 'lines' }, { state: { isGhost: true } }), refs); load_generic_1.UpdateTarget.apply(lines, representation_1.ShapeRepresentation3D); return data; } exports.BuiltinLoadingExtensions = [ non_covalent_interactions_1.NonCovalentInteractionsExtension, is_hidden_custom_state_1.IsHiddenCustomStateExtension, ];