molstar
Version:
A comprehensive macromolecular library.
127 lines (126 loc) • 4.84 kB
JavaScript
/**
* Copyright (c) 2020 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.buildVolumeHierarchy = buildVolumeHierarchy;
exports.VolumeHierarchy = VolumeHierarchy;
const objects_1 = require("../../objects");
const mol_state_1 = require("../../../mol-state");
function buildVolumeHierarchy(state, previous) {
const build = BuildState(state, previous || VolumeHierarchy());
doPreOrder(state.tree, build);
if (previous)
previous.refs.forEach(isRemoved, build);
return { hierarchy: build.hierarchy, added: build.added, changed: build.changed };
}
function VolumeHierarchy() {
return { volumes: [], lazyVolumes: [], refs: new Map() };
}
function VolumeRef(cell) {
return { kind: 'volume', cell, version: cell.transform.version, representations: [] };
}
function LazyVolumeRef(cell) {
return { kind: 'lazy-volume', cell, version: cell.transform.version };
}
function VolumeRepresentationRef(cell, volume) {
return { kind: 'volume-representation', cell, version: cell.transform.version, volume };
}
function BuildState(state, oldHierarchy) {
return { state, oldHierarchy, hierarchy: VolumeHierarchy(), changed: false, added: new Set() };
}
function createOrUpdateRefList(state, cell, list, ctor, ...args) {
const ref = ctor(...args);
list.push(ref);
state.hierarchy.refs.set(cell.transform.ref, ref);
const old = state.oldHierarchy.refs.get(cell.transform.ref);
if (old) {
if (old.version !== cell.transform.version)
state.changed = true;
}
else {
state.added.add(ref.cell.transform.ref);
state.changed = true;
}
return ref;
}
function isTypeRoot(t, target) {
return (cell, state) => !target(state) && t.is(cell.obj);
}
function noop() { }
const Mapping = [
[isTypeRoot(objects_1.PluginStateObject.Volume.Data, t => t.currentVolume), (state, cell) => {
state.currentVolume = createOrUpdateRefList(state, cell, state.hierarchy.volumes, VolumeRef, cell);
}, state => state.currentVolume = void 0],
[cell => objects_1.PluginStateObject.Volume.Lazy.is(cell.obj), (state, cell) => {
createOrUpdateRefList(state, cell, state.hierarchy.lazyVolumes, LazyVolumeRef, cell);
}, noop],
[(cell, state) => {
return !cell.state.isGhost && !!state.currentVolume && objects_1.PluginStateObject.Volume.Representation3D.is(cell.obj);
}, (state, cell) => {
if (state.currentVolume) {
createOrUpdateRefList(state, cell, state.currentVolume.representations, VolumeRepresentationRef, cell, state.currentVolume);
}
return false;
}, noop]
];
function isValidCell(cell) {
if (!cell || !(cell === null || cell === void 0 ? void 0 : cell.parent) || !cell.parent.cells.has(cell.transform.ref))
return false;
const { obj } = cell;
if (!obj || obj === mol_state_1.StateObject.Null || (cell.status !== 'ok' && cell.status !== 'error'))
return false;
return true;
}
function isRemoved(ref) {
const { cell } = ref;
if (isValidCell(cell))
return;
this.changed = true;
}
function _preOrderFunc(c) { _doPreOrder(this, this.tree.transforms.get(c)); }
function _doPreOrder(ctx, root) {
const { state } = ctx;
const cell = state.state.cells.get(root.ref);
if (!isValidCell(cell))
return;
let onLeave = void 0;
let end = false;
for (const [test, f, l] of Mapping) {
if (test(cell, state)) {
const cont = f(state, cell);
if (cont === false) {
end = true;
break;
}
onLeave = l;
break;
}
}
// TODO: might be needed in the future
// const { currentComponent, currentModel, currentStructure, currentTrajectory } = ctx.state;
// const inTrackedSubtree = currentComponent || currentModel || currentStructure || currentTrajectory;
// if (inTrackedSubtree && cell.transform.transformer.definition.isDecorator) {
// const ref = cell.transform.ref;
// const old = ctx.state.oldHierarchy.decorators.get(ref);
// if (old && old.version !== cell.transform.version) {
// ctx.state.changed = true;
// }
// ctx.state.hierarchy.decorators.set(cell.transform.ref, cell.transform);
// }
if (end)
return;
const children = ctx.tree.children.get(root.ref);
if (children && children.size) {
children.forEach(_preOrderFunc, ctx);
}
if (onLeave)
onLeave(state);
}
function doPreOrder(tree, state) {
const ctx = { tree, state };
_doPreOrder(ctx, tree.root);
return ctx.state;
}
;