UNPKG

molstar

Version:

A comprehensive macromolecular library.

172 lines 10.7 kB
"use strict"; /** * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> */ Object.defineProperty(exports, "__esModule", { value: true }); exports.AnimateModelIndex = void 0; var tslib_1 = require("tslib"); var commands_1 = require("../../../mol-plugin/commands"); var mol_state_1 = require("../../../mol-state"); var param_definition_1 = require("../../../mol-util/param-definition"); var objects_1 = require("../../objects"); var transforms_1 = require("../../transforms"); var model_1 = require("../model"); exports.AnimateModelIndex = model_1.PluginStateAnimation.create({ name: 'built-in.animate-model-index', display: { name: 'Animate Trajectory' }, isExportable: true, params: function () { return ({ mode: param_definition_1.ParamDefinition.MappedStatic('loop', { palindrome: param_definition_1.ParamDefinition.Group({}), loop: param_definition_1.ParamDefinition.Group({ direction: param_definition_1.ParamDefinition.Select('forward', [['forward', 'Forward'], ['backward', 'Backward']]) }), once: param_definition_1.ParamDefinition.Group({ direction: param_definition_1.ParamDefinition.Select('forward', [['forward', 'Forward'], ['backward', 'Backward']]) }, { isFlat: true }) }, { options: [['palindrome', 'Palindrome'], ['loop', 'Loop'], ['once', 'Once']] }), duration: param_definition_1.ParamDefinition.MappedStatic('fixed', { fixed: param_definition_1.ParamDefinition.Group({ durationInS: param_definition_1.ParamDefinition.Numeric(5, { min: 1, max: 120, step: 0.1 }, { description: 'Duration in seconds' }) }, { isFlat: true }), computed: param_definition_1.ParamDefinition.Group({ targetFps: param_definition_1.ParamDefinition.Numeric(30, { min: 5, max: 250, step: 1 }, { label: 'Target FPS' }) }, { isFlat: true }), sequential: param_definition_1.ParamDefinition.Group({ maxFps: param_definition_1.ParamDefinition.Numeric(30, { min: 5, max: 60, step: 1 }) }, { isFlat: true }) }) }); }, canApply: function (ctx) { var state = ctx.state.data; var models = state.select(mol_state_1.StateSelection.Generators.ofTransformer(transforms_1.StateTransforms.Model.ModelFromTrajectory)); for (var _i = 0, models_1 = models; _i < models_1.length; _i++) { var m = models_1[_i]; var parent_1 = mol_state_1.StateSelection.findAncestorOfType(state.tree, state.cells, m.transform.ref, objects_1.PluginStateObject.Molecule.Trajectory); if (parent_1 && parent_1.obj && parent_1.obj.data.frameCount > 1) return { canApply: true }; } return { canApply: false, reason: 'No trajectory to animate' }; }, getDuration: function (p, ctx) { var _a; if (((_a = p.duration) === null || _a === void 0 ? void 0 : _a.name) === 'fixed') { return { kind: 'fixed', durationMs: p.duration.params.durationInS * 1000 }; } else if (p.duration.name === 'computed') { var state = ctx.state.data; var models = state.select(mol_state_1.StateSelection.Generators.ofTransformer(transforms_1.StateTransforms.Model.ModelFromTrajectory)); var maxDuration = 0; for (var _i = 0, models_2 = models; _i < models_2.length; _i++) { var m = models_2[_i]; var parent_2 = mol_state_1.StateSelection.findAncestorOfType(state.tree, state.cells, m.transform.ref, objects_1.PluginStateObject.Molecule.Trajectory); if (!parent_2 || !parent_2.obj) continue; var traj = parent_2.obj; maxDuration = Math.max(Math.ceil(1000 * traj.data.frameCount / p.duration.params.targetFps), maxDuration); } return { kind: 'fixed', durationMs: maxDuration }; } return { kind: 'unknown' }; }, initialState: function () { return ({}); }, apply: function (animState, t, ctx) { return (0, tslib_1.__awaiter)(this, void 0, void 0, function () { var state, models, update, params, palindromeDirections, isEnd, allSingles, _loop_1, _i, models_3, m; return (0, tslib_1.__generator)(this, function (_a) { switch (_a.label) { case 0: // limit fps if (ctx.params.duration.name === 'sequential' && t.current > 0 && t.current - t.lastApplied < 1000 / ctx.params.duration.params.maxFps) { return [2 /*return*/, { kind: 'skip' }]; } state = ctx.plugin.state.data; models = state.select(mol_state_1.StateSelection.Generators.ofTransformer(transforms_1.StateTransforms.Model.ModelFromTrajectory)); if (models.length === 0) { // nothing more to do here return [2 /*return*/, { kind: 'finished' }]; } update = state.build(); params = ctx.params; palindromeDirections = animState.palindromeDirections || {}; isEnd = false, allSingles = true; _loop_1 = function (m) { var parent_3 = mol_state_1.StateSelection.findAncestorOfType(state.tree, state.cells, m.transform.ref, objects_1.PluginStateObject.Molecule.Trajectory); if (!parent_3 || !parent_3.obj) return "continue"; var traj = parent_3.obj; if (traj.data.frameCount <= 1) return "continue"; update.to(m).update(function (old) { var len = traj.data.frameCount; if (len !== 1) { allSingles = false; } else { return old; } if (params.duration.name === 'sequential') { var dir = 1; if (params.mode.name === 'once') { dir = params.mode.params.direction === 'backward' ? -1 : 1; // if we are at start or end already, do nothing. if ((dir === -1 && old.modelIndex === 0) || (dir === 1 && old.modelIndex === len - 1)) { isEnd = true; return old; } } else if (params.mode.name === 'palindrome') { if (old.modelIndex === 0) dir = 1; else if (old.modelIndex === len - 1) dir = -1; else dir = palindromeDirections[m.transform.ref] || 1; } palindromeDirections[m.transform.ref] = dir; var modelIndex = (old.modelIndex + dir) % len; if (modelIndex < 0) modelIndex += len; isEnd = isEnd || (dir === -1 && modelIndex === 0) || (dir === 1 && modelIndex === len - 1); return { modelIndex: modelIndex }; } else { var durationInMs = params.duration.name === 'fixed' ? params.duration.params.durationInS * 1000 : Math.ceil(1000 * traj.data.frameCount / params.duration.params.targetFps); var phase = (t.current % durationInMs) / durationInMs; if (params.mode.name === 'loop') { if (params.mode.params.direction === 'backward') { phase = 1 - phase; } } if (params.mode.name === 'palindrome') { phase = 2 * phase; if (phase > 1) phase = 2 - phase; } var modelIndex = Math.min(Math.floor(traj.data.frameCount * phase), traj.data.frameCount - 1); isEnd = isEnd || modelIndex === traj.data.frameCount - 1; return { modelIndex: modelIndex }; } }); }; for (_i = 0, models_3 = models; _i < models_3.length; _i++) { m = models_3[_i]; _loop_1(m); } if (!!allSingles) return [3 /*break*/, 2]; return [4 /*yield*/, commands_1.PluginCommands.State.Update(ctx.plugin, { state: state, tree: update, options: { doNotLogTiming: true } })]; case 1: _a.sent(); _a.label = 2; case 2: if (allSingles || (params.mode.name === 'once' && isEnd)) return [2 /*return*/, { kind: 'finished' }]; if (params.mode.name === 'palindrome') return [2 /*return*/, { kind: 'next', state: { palindromeDirections: palindromeDirections } }]; return [2 /*return*/, { kind: 'next', state: {} }]; } }); }); } }); //# sourceMappingURL=model-index.js.map