UNPKG

molstar

Version:

A comprehensive macromolecular library.

376 lines 17.9 kB
"use strict"; /** * Copyright (c) 2018-2021 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.PluginStateSnapshotManager = void 0; var tslib_1 = require("tslib"); var immutable_1 = require("immutable"); var component_1 = require("../component"); var utf8_1 = require("../../mol-io/common/utf8"); var zip_1 = require("../../mol-util/zip/zip"); var data_source_1 = require("../../mol-util/data-source"); var object_1 = require("../../mol-util/object"); var version_1 = require("../../mol-plugin/version"); var PluginStateSnapshotManager = /** @class */ (function (_super) { (0, tslib_1.__extends)(PluginStateSnapshotManager, _super); function PluginStateSnapshotManager(plugin) { var _this = _super.call(this, { current: void 0, entries: (0, immutable_1.List)(), isPlaying: false, nextSnapshotDelayInMs: PluginStateSnapshotManager.DefaultNextSnapshotDelayInMs }) || this; _this.plugin = plugin; _this.entryMap = new Map(); _this.events = { changed: _this.ev() }; _this.timeoutHandle = void 0; _this.next = function () { return (0, tslib_1.__awaiter)(_this, void 0, void 0, function () { var next, snapshot, delay; return (0, tslib_1.__generator)(this, function (_a) { switch (_a.label) { case 0: this.timeoutHandle = void 0; next = this.getNextId(this.state.current, 1); if (!next || next === this.state.current) { this.stop(); return [2 /*return*/]; } snapshot = this.setCurrent(next); return [4 /*yield*/, this.plugin.state.setSnapshot(snapshot)]; case 1: _a.sent(); delay = typeof snapshot.durationInMs !== 'undefined' ? snapshot.durationInMs : this.state.nextSnapshotDelayInMs; if (this.state.isPlaying) this.timeoutHandle = setTimeout(this.next, delay); return [2 /*return*/]; } }); }); }; return _this; // TODO make nextSnapshotDelayInMs editable } PluginStateSnapshotManager.prototype.getIndex = function (e) { return this.state.entries.indexOf(e); }; PluginStateSnapshotManager.prototype.getEntry = function (id) { if (!id) return; return this.entryMap.get(id); }; PluginStateSnapshotManager.prototype.remove = function (id) { var e = this.entryMap.get(id); if (!e) return; this.entryMap.delete(id); this.updateState({ current: this.state.current === id ? void 0 : this.state.current, entries: this.state.entries.delete(this.getIndex(e)) }); this.events.changed.next(void 0); }; PluginStateSnapshotManager.prototype.add = function (e) { this.entryMap.set(e.snapshot.id, e); this.updateState({ current: e.snapshot.id, entries: this.state.entries.push(e) }); this.events.changed.next(void 0); }; PluginStateSnapshotManager.prototype.replace = function (id, snapshot) { var old = this.getEntry(id); if (!old) return; var idx = this.getIndex(old); // The id changes here! var e = PluginStateSnapshotManager.Entry(snapshot, { name: old.name, description: old.description }); this.entryMap.set(snapshot.id, e); this.updateState({ current: e.snapshot.id, entries: this.state.entries.set(idx, e) }); this.events.changed.next(void 0); }; PluginStateSnapshotManager.prototype.move = function (id, dir) { var len = this.state.entries.size; if (len < 2) return; var e = this.getEntry(id); if (!e) return; var from = this.getIndex(e); var to = (from + dir) % len; if (to < 0) to += len; var f = this.state.entries.get(to); var entries = this.state.entries.asMutable(); entries.set(to, e); entries.set(from, f); this.updateState({ current: e.snapshot.id, entries: entries.asImmutable() }); this.events.changed.next(void 0); }; PluginStateSnapshotManager.prototype.clear = function () { if (this.state.entries.size === 0) return; this.entryMap.clear(); this.updateState({ current: void 0, entries: (0, immutable_1.List)() }); this.events.changed.next(void 0); }; PluginStateSnapshotManager.prototype.setCurrent = function (id) { var e = this.getEntry(id); if (e) { this.updateState({ current: id }); this.events.changed.next(void 0); } return e && e.snapshot; }; PluginStateSnapshotManager.prototype.getNextId = function (id, dir) { var len = this.state.entries.size; if (!id) { if (len === 0) return void 0; var idx_1 = dir === -1 ? len - 1 : 0; return this.state.entries.get(idx_1).snapshot.id; } var e = this.getEntry(id); if (!e) return; var idx = this.getIndex(e); if (idx < 0) return; idx = (idx + dir) % len; if (idx < 0) idx += len; return this.state.entries.get(idx).snapshot.id; }; PluginStateSnapshotManager.prototype.setStateSnapshot = function (snapshot) { return (0, tslib_1.__awaiter)(this, void 0, void 0, function () { var entries, _i, _a, e, current, entry, next; return (0, tslib_1.__generator)(this, function (_b) { switch (_b.label) { case 0: if (snapshot.version !== version_1.PLUGIN_VERSION) { // TODO // console.warn('state snapshot version mismatch'); } this.clear(); entries = (0, immutable_1.List)().asMutable(); for (_i = 0, _a = snapshot.entries; _i < _a.length; _i++) { e = _a[_i]; this.entryMap.set(e.snapshot.id, e); entries.push(e); } current = snapshot.current ? snapshot.current : snapshot.entries.length > 0 ? snapshot.entries[0].snapshot.id : void 0; this.updateState({ current: current, entries: entries.asImmutable(), isPlaying: false, nextSnapshotDelayInMs: snapshot.playback ? snapshot.playback.nextSnapshotDelayInMs : PluginStateSnapshotManager.DefaultNextSnapshotDelayInMs }); this.events.changed.next(void 0); if (!current) return [2 /*return*/]; entry = this.getEntry(current); next = entry && entry.snapshot; if (!next) return [2 /*return*/]; return [4 /*yield*/, this.plugin.state.setSnapshot(next)]; case 1: _b.sent(); if (snapshot.playback && snapshot.playback.isPlaying) this.play(true); return [2 /*return*/, next]; } }); }); }; PluginStateSnapshotManager.prototype.syncCurrent = function (options) { var snapshot = this.plugin.state.getSnapshot(options === null || options === void 0 ? void 0 : options.params); if (this.state.entries.size === 0 || !this.state.current) { this.add(PluginStateSnapshotManager.Entry(snapshot, { name: options === null || options === void 0 ? void 0 : options.name, description: options === null || options === void 0 ? void 0 : options.description })); } else { this.replace(this.state.current, snapshot); } }; PluginStateSnapshotManager.prototype.getStateSnapshot = function (options) { // TODO: diffing and all that fancy stuff this.syncCurrent(options); return { timestamp: +new Date(), version: version_1.PLUGIN_VERSION, name: options && options.name, description: options && options.description, current: this.state.current, playback: { isPlaying: !!(options && options.playOnLoad), nextSnapshotDelayInMs: this.state.nextSnapshotDelayInMs }, entries: this.state.entries.valueSeq().toArray() }; }; PluginStateSnapshotManager.prototype.serialize = function (options) { return (0, tslib_1.__awaiter)(this, void 0, void 0, function () { var json, state, zipDataObj, assets, _i, _a, _b, asset, file, _c, _d, _e, index, data, zipFile; return (0, tslib_1.__generator)(this, function (_f) { switch (_f.label) { case 0: json = JSON.stringify(this.getStateSnapshot({ params: options === null || options === void 0 ? void 0 : options.params }), null, 2); if (!(!(options === null || options === void 0 ? void 0 : options.type) || options.type === 'json' || options.type === 'molj')) return [3 /*break*/, 1]; return [2 /*return*/, new Blob([json], { type: 'application/json;charset=utf-8' })]; case 1: state = new Uint8Array((0, utf8_1.utf8ByteCount)(json)); (0, utf8_1.utf8Write)(state, 0, json); zipDataObj = { 'state.json': state }; assets = []; _i = 0, _a = this.plugin.managers.asset.assets; _f.label = 2; case 2: if (!(_i < _a.length)) return [3 /*break*/, 5]; _b = _a[_i], asset = _b.asset, file = _b.file; assets.push([asset.id, asset]); _c = zipDataObj; _d = "assets/" + asset.id; _e = Uint8Array.bind; return [4 /*yield*/, file.arrayBuffer()]; case 3: _c[_d] = new (_e.apply(Uint8Array, [void 0, _f.sent()]))(); _f.label = 4; case 4: _i++; return [3 /*break*/, 2]; case 5: if (assets.length > 0) { index = JSON.stringify(assets, null, 2); data = new Uint8Array((0, utf8_1.utf8ByteCount)(index)); (0, utf8_1.utf8Write)(data, 0, index); zipDataObj['assets.json'] = data; } return [4 /*yield*/, this.plugin.runTask((0, zip_1.Zip)(zipDataObj))]; case 6: zipFile = _f.sent(); return [2 /*return*/, new Blob([zipFile], { type: 'application/zip' })]; } }); }); }; PluginStateSnapshotManager.prototype.open = function (file) { return (0, tslib_1.__awaiter)(this, void 0, void 0, function () { var fn, data, snapshot, data, assets_1, stateFile, stateData, file_1, json, _a, _b, _i, json_1, _c, id, asset, snapshot, e_1; return (0, tslib_1.__generator)(this, function (_d) { switch (_d.label) { case 0: _d.trys.push([0, 8, , 9]); fn = file.name.toLowerCase(); if (!(fn.endsWith('json') || fn.endsWith('molj'))) return [3 /*break*/, 2]; return [4 /*yield*/, this.plugin.runTask((0, data_source_1.readFromFile)(file, 'string'))]; case 1: data = _d.sent(); snapshot = JSON.parse(data); if (PluginStateSnapshotManager.isStateSnapshot(snapshot)) { return [2 /*return*/, this.setStateSnapshot(snapshot)]; } else if (PluginStateSnapshotManager.isStateSnapshot(snapshot.data)) { return [2 /*return*/, this.setStateSnapshot(snapshot.data)]; } else { this.plugin.state.setSnapshot(snapshot); } return [3 /*break*/, 7]; case 2: return [4 /*yield*/, this.plugin.runTask((0, data_source_1.readFromFile)(file, 'zip'))]; case 3: data = _d.sent(); assets_1 = Object.create(null); (0, object_1.objectForEach)(data, function (v, k) { if (k === 'state.json' || k === 'assets.json') return; var name = k.substring(k.indexOf('/') + 1); assets_1[name] = new File([v], name); }); stateFile = new File([data['state.json']], 'state.json'); return [4 /*yield*/, this.plugin.runTask((0, data_source_1.readFromFile)(stateFile, 'string'))]; case 4: stateData = _d.sent(); if (!data['assets.json']) return [3 /*break*/, 6]; file_1 = new File([data['assets.json']], 'assets.json'); _b = (_a = JSON).parse; return [4 /*yield*/, this.plugin.runTask((0, data_source_1.readFromFile)(file_1, 'string'))]; case 5: json = _b.apply(_a, [_d.sent()]); for (_i = 0, json_1 = json; _i < json_1.length; _i++) { _c = json_1[_i], id = _c[0], asset = _c[1]; this.plugin.managers.asset.set(asset, assets_1[id]); } _d.label = 6; case 6: snapshot = JSON.parse(stateData); return [2 /*return*/, this.setStateSnapshot(snapshot)]; case 7: return [3 /*break*/, 9]; case 8: e_1 = _d.sent(); this.plugin.log.error("Reading state: " + e_1); return [3 /*break*/, 9]; case 9: return [2 /*return*/]; } }); }); }; PluginStateSnapshotManager.prototype.play = function (delayFirst) { if (delayFirst === void 0) { delayFirst = false; } this.updateState({ isPlaying: true }); if (delayFirst) { var e = this.getEntry(this.state.current); if (!e) { this.next(); return; } this.events.changed.next(void 0); var snapshot = e.snapshot; var delay = typeof snapshot.durationInMs !== 'undefined' ? snapshot.durationInMs : this.state.nextSnapshotDelayInMs; this.timeoutHandle = setTimeout(this.next, delay); } else { this.next(); } }; PluginStateSnapshotManager.prototype.stop = function () { this.updateState({ isPlaying: false }); if (typeof this.timeoutHandle !== 'undefined') clearTimeout(this.timeoutHandle); this.timeoutHandle = void 0; this.events.changed.next(void 0); }; PluginStateSnapshotManager.prototype.togglePlay = function () { if (this.state.isPlaying) { this.stop(); this.plugin.managers.animation.stop(); } else { this.play(); } }; PluginStateSnapshotManager.DefaultNextSnapshotDelayInMs = 1500; return PluginStateSnapshotManager; }(component_1.StatefulPluginComponent)); exports.PluginStateSnapshotManager = PluginStateSnapshotManager; (function (PluginStateSnapshotManager) { function Entry(snapshot, params) { return (0, tslib_1.__assign)({ timestamp: +new Date(), snapshot: snapshot }, params); } PluginStateSnapshotManager.Entry = Entry; function isStateSnapshot(x) { var s = x; return !!s && !!s.timestamp && !!s.entries; } PluginStateSnapshotManager.isStateSnapshot = isStateSnapshot; })(PluginStateSnapshotManager || (PluginStateSnapshotManager = {})); exports.PluginStateSnapshotManager = PluginStateSnapshotManager; //# sourceMappingURL=snapshots.js.map