molstar
Version:
A comprehensive macromolecular library.
387 lines • 22.3 kB
JavaScript
"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