UNPKG

molstar

Version:

A comprehensive macromolecular library.

387 lines 22.3 kB
"use strict"; /** * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> * @author Alexander Rose <alexander.rose@weirdbyte.de> */ Object.defineProperty(exports, "__esModule", { value: true }); exports.VolumeStreamingVisual = exports.CreateVolumeStreamingBehavior = exports.CreateVolumeStreamingInfo = exports.BoxifyVolumeStreaming = exports.InitVolumeStreaming = void 0; var tslib_1 = require("tslib"); var objects_1 = require("../../../../mol-plugin-state/objects"); var model_1 = require("./model"); var param_definition_1 = require("../../../../mol-util/param-definition"); var mol_task_1 = require("../../../../mol-task"); var url_1 = require("../../../../mol-util/url"); var volume_1 = require("../../../../mol-model/volume"); var mol_state_1 = require("../../../../mol-state"); var util_1 = require("./util"); var behavior_1 = require("./behavior"); var representation_1 = require("../../../../mol-plugin-state/transforms/representation"); var registry_1 = require("../../../../mol-repr/volume/registry"); var theme_1 = require("../../../../mol-theme/theme"); var geometry_1 = require("../../../../mol-math/geometry"); var linear_algebra_1 = require("../../../../mol-math/linear-algebra"); var config_1 = require("../../../config"); var structure_1 = require("../../../../mol-model/structure"); var global_transform_1 = require("../../../../mol-model/structure/model/properties/global-transform"); function addEntry(entries, method, dataId, emDefaultContourLevel) { entries.push({ source: method === 'em' ? { name: 'em', params: { isoValue: volume_1.Volume.IsoValue.absolute(emDefaultContourLevel || 0) } } : { name: 'x-ray', params: {} }, dataId: dataId }); } exports.InitVolumeStreaming = mol_state_1.StateAction.build({ display: { name: 'Volume Streaming' }, from: objects_1.PluginStateObject.Molecule.Structure, params: function (a, plugin) { var method = (0, util_1.getStreamingMethod)(a && a.data); var ids = (0, util_1.getIds)(method, a && a.data); return { method: param_definition_1.ParamDefinition.Select(method, [['em', 'EM'], ['x-ray', 'X-Ray']]), entries: param_definition_1.ParamDefinition.ObjectList({ id: param_definition_1.ParamDefinition.Text(ids[0] || '') }, function (_a) { var id = _a.id; return id; }, { defaultValue: ids.map(function (id) { return ({ id: id }); }) }), defaultView: param_definition_1.ParamDefinition.Select(method === 'em' ? 'cell' : 'selection-box', behavior_1.VolumeStreaming.ViewTypeOptions), options: param_definition_1.ParamDefinition.Group({ serverUrl: param_definition_1.ParamDefinition.Text(plugin.config.get(config_1.PluginConfig.VolumeStreaming.DefaultServer) || 'https://ds.litemol.org'), behaviorRef: param_definition_1.ParamDefinition.Text('', { isHidden: true }), emContourProvider: param_definition_1.ParamDefinition.Select('emdb', [['emdb', 'EMDB'], ['pdbe', 'PDBe']], { isHidden: true }), channelParams: param_definition_1.ParamDefinition.Value({}, { isHidden: true }) }) }; }, isApplicable: function (a, _, plugin) { var canStreamTest = plugin.config.get(config_1.PluginConfig.VolumeStreaming.CanStream); if (canStreamTest) return canStreamTest(a.data, plugin); return a.data.models.length === 1 && structure_1.Model.probablyHasDensityMap(a.data.models[0]); } })(function (_a, plugin) { var ref = _a.ref, state = _a.state, params = _a.params; return mol_task_1.Task.create('Volume Streaming', function (taskCtx) { return (0, tslib_1.__awaiter)(void 0, void 0, void 0, function () { var entries, i, il, dataId, emDefaultContourLevel, emdbIds, j, jl, emdbId, contourLevel, e_1, e_2, infoTree, info, children, infoObj, behTree; return (0, tslib_1.__generator)(this, function (_a) { switch (_a.label) { case 0: entries = []; i = 0, il = params.entries.length; _a.label = 1; case 1: if (!(i < il)) return [3 /*break*/, 16]; dataId = params.entries[i].id.toLowerCase(); emDefaultContourLevel = void 0; if (!(params.method === 'em')) return [3 /*break*/, 14]; if (!!dataId.toUpperCase().startsWith('EMD')) return [3 /*break*/, 11]; return [4 /*yield*/, taskCtx.update('Getting EMDB info...')]; case 2: _a.sent(); return [4 /*yield*/, (0, util_1.getEmdbIds)(plugin, taskCtx, dataId)]; case 3: emdbIds = _a.sent(); j = 0, jl = emdbIds.length; _a.label = 4; case 4: if (!(j < jl)) return [3 /*break*/, 10]; emdbId = emdbIds[j]; contourLevel = void 0; _a.label = 5; case 5: _a.trys.push([5, 7, , 8]); return [4 /*yield*/, (0, util_1.getContourLevel)(params.options.emContourProvider, plugin, taskCtx, emdbId)]; case 6: contourLevel = _a.sent(); return [3 /*break*/, 8]; case 7: e_1 = _a.sent(); console.info("Could not get map info for " + emdbId + ": " + e_1); return [3 /*break*/, 9]; case 8: addEntry(entries, params.method, emdbId, contourLevel || 0); _a.label = 9; case 9: ++j; return [3 /*break*/, 4]; case 10: return [3 /*break*/, 15]; case 11: _a.trys.push([11, 13, , 14]); return [4 /*yield*/, (0, util_1.getContourLevel)(params.options.emContourProvider, plugin, taskCtx, dataId)]; case 12: emDefaultContourLevel = _a.sent(); return [3 /*break*/, 14]; case 13: e_2 = _a.sent(); console.info("Could not get map info for " + dataId + ": " + e_2); return [3 /*break*/, 15]; case 14: addEntry(entries, params.method, dataId, emDefaultContourLevel || 0); _a.label = 15; case 15: ++i; return [3 /*break*/, 1]; case 16: infoTree = state.build().to(ref) .applyOrUpdateTagged(behavior_1.VolumeStreaming.RootTag, CreateVolumeStreamingInfo, { serverUrl: params.options.serverUrl, entries: entries }); return [4 /*yield*/, infoTree.commit()]; case 17: _a.sent(); info = infoTree.selector; if (!info.isOk) return [2 /*return*/]; children = state.tree.children.get(info.ref); if (!((children === null || children === void 0 ? void 0 : children.size) > 0)) return [3 /*break*/, 19]; return [4 /*yield*/, plugin.managers.structure.hierarchy.remove(children === null || children === void 0 ? void 0 : children.toArray())]; case 18: _a.sent(); _a.label = 19; case 19: infoObj = info.cell.obj; behTree = state.build().to(infoTree.ref).apply(CreateVolumeStreamingBehavior, param_definition_1.ParamDefinition.getDefaultValues(behavior_1.VolumeStreaming.createParams({ data: infoObj.data, defaultView: params.defaultView, channelParams: params.options.channelParams })), { ref: params.options.behaviorRef ? params.options.behaviorRef : void 0 }); if (params.method === 'em') { behTree.apply(VolumeStreamingVisual, { channel: 'em' }, { state: { isGhost: true }, tags: 'em' }); } else { behTree.apply(VolumeStreamingVisual, { channel: '2fo-fc' }, { state: { isGhost: true }, tags: '2fo-fc' }); behTree.apply(VolumeStreamingVisual, { channel: 'fo-fc(+ve)' }, { state: { isGhost: true }, tags: 'fo-fc(+ve)' }); behTree.apply(VolumeStreamingVisual, { channel: 'fo-fc(-ve)' }, { state: { isGhost: true }, tags: 'fo-fc(-ve)' }); } return [4 /*yield*/, state.updateTree(behTree).runInContext(taskCtx)]; case 20: _a.sent(); return [2 /*return*/]; } }); }); }); }); exports.BoxifyVolumeStreaming = mol_state_1.StateAction.build({ display: { name: 'Boxify Volume Streaming', description: 'Make the current box permanent.' }, from: behavior_1.VolumeStreaming, isApplicable: function (a) { return a.data.params.entry.params.view.name === 'selection-box'; } })(function (_a, plugin) { var a = _a.a, ref = _a.ref, state = _a.state; var params = a.data.params; if (params.entry.params.view.name !== 'selection-box') return; var box = geometry_1.Box3D.create(linear_algebra_1.Vec3.clone(params.entry.params.view.params.bottomLeft), linear_algebra_1.Vec3.clone(params.entry.params.view.params.topRight)); var r = params.entry.params.view.params.radius; geometry_1.Box3D.expand(box, box, linear_algebra_1.Vec3.create(r, r, r)); var newParams = (0, tslib_1.__assign)((0, tslib_1.__assign)({}, params), { entry: { name: params.entry.name, params: (0, tslib_1.__assign)((0, tslib_1.__assign)({}, params.entry.params), { view: { name: 'box', params: { bottomLeft: box.min, topRight: box.max } } }) } }); return state.updateTree(state.build().to(ref).update(newParams)); }); var InfoEntryParams = { dataId: param_definition_1.ParamDefinition.Text(''), source: param_definition_1.ParamDefinition.MappedStatic('x-ray', { 'em': param_definition_1.ParamDefinition.Group({ isoValue: volume_1.Volume.createIsoValueParam(volume_1.Volume.IsoValue.relative(1)) }), 'x-ray': param_definition_1.ParamDefinition.Group({}) }) }; var CreateVolumeStreamingInfo = objects_1.PluginStateTransform.BuiltIn({ name: 'create-volume-streaming-info', display: { name: 'Volume Streaming Info' }, from: objects_1.PluginStateObject.Molecule.Structure, to: model_1.VolumeServerInfo, params: function (a) { return { serverUrl: param_definition_1.ParamDefinition.Text('https://ds.litemol.org'), entries: param_definition_1.ParamDefinition.ObjectList(InfoEntryParams, function (_a) { var dataId = _a.dataId; return dataId; }, { defaultValue: [{ dataId: '', source: { name: 'x-ray', params: {} } }] }), }; } })({ apply: function (_a, plugin) { var a = _a.a, params = _a.params; return mol_task_1.Task.create('', function (taskCtx) { return (0, tslib_1.__awaiter)(void 0, void 0, void 0, function () { var entries, i, il, e, dataId, emDefaultContourLevel, header, data; return (0, tslib_1.__generator)(this, function (_a) { switch (_a.label) { case 0: entries = []; i = 0, il = params.entries.length; _a.label = 1; case 1: if (!(i < il)) return [3 /*break*/, 5]; e = params.entries[i]; dataId = e.dataId; emDefaultContourLevel = e.source.name === 'em' ? e.source.params.isoValue : volume_1.Volume.IsoValue.relative(1); return [4 /*yield*/, taskCtx.update('Getting server header...')]; case 2: _a.sent(); return [4 /*yield*/, plugin.fetch({ url: (0, url_1.urlCombine)(params.serverUrl, e.source.name + "/" + dataId.toLocaleLowerCase()), type: 'json' }).runInContext(taskCtx)]; case 3: header = _a.sent(); entries.push({ dataId: dataId, kind: e.source.name, header: header, emDefaultContourLevel: emDefaultContourLevel }); _a.label = 4; case 4: ++i; return [3 /*break*/, 1]; case 5: data = { serverUrl: params.serverUrl, entries: entries, structure: a.data }; return [2 /*return*/, new model_1.VolumeServerInfo(data, { label: 'Volume Server', description: "" + entries.map(function (e) { return e.dataId; }).join(', ') })]; } }); }); }); } }); exports.CreateVolumeStreamingInfo = CreateVolumeStreamingInfo; var CreateVolumeStreamingBehavior = objects_1.PluginStateTransform.BuiltIn({ name: 'create-volume-streaming-behavior', display: { name: 'Volume Streaming Behavior' }, from: model_1.VolumeServerInfo, to: behavior_1.VolumeStreaming, params: function (a) { return behavior_1.VolumeStreaming.createParams({ data: a && a.data }); } })({ canAutoUpdate: function (_a) { var oldParams = _a.oldParams, newParams = _a.newParams; return oldParams.entry.params.view === newParams.entry.params.view || newParams.entry.params.view.name === 'selection-box' || newParams.entry.params.view.name === 'off'; }, apply: function (_a, plugin) { var a = _a.a, params = _a.params; return mol_task_1.Task.create('Volume streaming', function (_) { return (0, tslib_1.__awaiter)(void 0, void 0, void 0, function () { var behavior; return (0, tslib_1.__generator)(this, function (_a) { switch (_a.label) { case 0: behavior = new behavior_1.VolumeStreaming.Behavior(plugin, a.data); return [4 /*yield*/, behavior.update(params)]; case 1: _a.sent(); return [2 /*return*/, new behavior_1.VolumeStreaming(behavior, { label: 'Volume Streaming', description: behavior.getDescription() })]; } }); }); }); }, update: function (_a) { var _this = this; var a = _a.a, b = _a.b, oldParams = _a.oldParams, newParams = _a.newParams; return mol_task_1.Task.create('Update Volume Streaming', function (_) { return (0, tslib_1.__awaiter)(_this, void 0, void 0, function () { var emDefaultContourLevel, ret; return (0, tslib_1.__generator)(this, function (_a) { switch (_a.label) { case 0: if (oldParams.entry.name !== newParams.entry.name) { if ('em' in newParams.entry.params.channels) { emDefaultContourLevel = b.data.infoMap.get(newParams.entry.name).emDefaultContourLevel; if (emDefaultContourLevel) { newParams.entry.params.channels['em'].isoValue = emDefaultContourLevel; } } } return [4 /*yield*/, b.data.update(newParams)]; case 1: ret = (_a.sent()) ? mol_state_1.StateTransformer.UpdateResult.Updated : mol_state_1.StateTransformer.UpdateResult.Unchanged; b.description = b.data.getDescription(); return [2 /*return*/, ret]; } }); }); }); } }); exports.CreateVolumeStreamingBehavior = CreateVolumeStreamingBehavior; var VolumeStreamingVisual = objects_1.PluginStateTransform.BuiltIn({ name: 'create-volume-streaming-visual', display: { name: 'Volume Streaming Visual' }, from: behavior_1.VolumeStreaming, to: objects_1.PluginStateObject.Volume.Representation3D, params: { channel: param_definition_1.ParamDefinition.Select('em', behavior_1.VolumeStreaming.ChannelTypeOptions, { isHidden: true }) } })({ apply: function (_a, plugin) { var a = _a.a, srcParams = _a.params, spine = _a.spine; return mol_task_1.Task.create('Volume Representation', function (ctx) { return (0, tslib_1.__awaiter)(void 0, void 0, void 0, function () { var channel, params, provider, props, repr, structure, transform; var _a, _b; return (0, tslib_1.__generator)(this, function (_c) { switch (_c.label) { case 0: channel = a.data.channels[srcParams.channel]; if (!channel) return [2 /*return*/, mol_state_1.StateObject.Null]; params = createVolumeProps(a.data, srcParams.channel); provider = registry_1.VolumeRepresentationRegistry.BuiltIn.isosurface; props = params.type.params || {}; repr = provider.factory((0, tslib_1.__assign)({ webgl: (_a = plugin.canvas3d) === null || _a === void 0 ? void 0 : _a.webgl }, plugin.representation.volume.themes), provider.getParams); repr.setTheme(theme_1.Theme.create(plugin.representation.volume.themes, { volume: channel.data }, params)); structure = (_b = spine.getAncestorOfType(objects_1.PluginStateObject.Molecule.Structure)) === null || _b === void 0 ? void 0 : _b.data; transform = (structure === null || structure === void 0 ? void 0 : structure.models.length) === 0 ? void 0 : global_transform_1.GlobalModelTransformInfo.get(structure === null || structure === void 0 ? void 0 : structure.models[0]); return [4 /*yield*/, repr.createOrUpdate(props, channel.data).runInContext(ctx)]; case 1: _c.sent(); if (transform) repr.setState({ transform: transform }); return [2 /*return*/, new objects_1.PluginStateObject.Volume.Representation3D({ repr: repr, sourceData: channel.data }, { label: Math.round(channel.isoValue.relativeValue * 100) / 100 + " \u03C3 [" + srcParams.channel + "]" })]; } }); }); }); }, update: function (_a, plugin) { var a = _a.a, b = _a.b, newParams = _a.newParams, spine = _a.spine; return mol_task_1.Task.create('Volume Representation', function (ctx) { return (0, tslib_1.__awaiter)(void 0, void 0, void 0, function () { var channel, visible, params, props; return (0, tslib_1.__generator)(this, function (_a) { switch (_a.label) { case 0: channel = a.data.channels[newParams.channel]; // TODO: is this correct behavior? if (!channel) return [2 /*return*/, mol_state_1.StateTransformer.UpdateResult.Unchanged]; visible = b.data.repr.state.visible; params = createVolumeProps(a.data, newParams.channel); props = (0, tslib_1.__assign)((0, tslib_1.__assign)({}, b.data.repr.props), params.type.params); b.data.repr.setTheme(theme_1.Theme.create(plugin.representation.volume.themes, { volume: channel.data }, params)); return [4 /*yield*/, b.data.repr.createOrUpdate(props, channel.data).runInContext(ctx)]; case 1: _a.sent(); b.data.repr.setState({ visible: visible }); b.data.sourceData = channel.data; // TODO: set the transform here as well in case the structure moves? // doing this here now breaks the code for some reason... // const structure = spine.getAncestorOfType(SO.Molecule.Structure)?.data; // const transform = structure?.models.length === 0 ? void 0 : GlobalModelTransformInfo.get(structure?.models[0]!); // if (transform) b.data.repr.setState({ transform }); return [2 /*return*/, mol_state_1.StateTransformer.UpdateResult.Updated]; } }); }); }); } }); exports.VolumeStreamingVisual = VolumeStreamingVisual; function createVolumeProps(streaming, channelName) { var channel = streaming.channels[channelName]; return representation_1.VolumeRepresentation3DHelpers.getDefaultParamsStatic(streaming.plugin, 'isosurface', { isoValue: channel.isoValue, alpha: channel.opacity, visuals: channel.wireframe ? ['wireframe'] : ['solid'] }, 'uniform', { value: channel.color }); } //# sourceMappingURL=transformers.js.map