Переглянути джерело

mol-plugin: SubstructureParentHelper

David Sehnal 6 роки тому
батько
коміт
3d4f40f680

+ 2 - 2
src/mol-plugin/behavior/dynamic/representation.ts

@@ -24,7 +24,7 @@ export const HighlightLoci = PluginBehavior.create({
     ctor: class extends PluginBehavior.Handler {
         register(): void {
             let prev: Representation.Loci = { loci: EmptyLoci, repr: void 0 };
-            const sel = this.ctx.selection.structure;
+            const sel = this.ctx.helpers.structureSelection;
 
             this.subscribeObservable(this.ctx.events.canvas3d.highlight, ({ current, modifiers }) => {
                 if (!this.ctx.canvas3d) return;
@@ -58,7 +58,7 @@ export const SelectLoci = PluginBehavior.create({
     category: 'interaction',
     ctor: class extends PluginBehavior.Handler {
         register(): void {
-            const sel = this.ctx.selection.structure;
+            const sel = this.ctx.helpers.structureSelection;
 
             const toggleSel = (current: Representation.Loci<StructureElement.Loci>) => {
                 if (sel.has(current.loci)) {

+ 4 - 2
src/mol-plugin/context.ts

@@ -31,6 +31,7 @@ import { LociLabelEntry, LociLabelManager } from './util/loci-label-manager';
 import { TaskManager } from './util/task-manager';
 import { PLUGIN_VERSION, PLUGIN_VERSION_DATE } from './version';
 import { StructureElementSelectionManager } from './util/structure-element-selection';
+import { SubstructureParentHelper } from './util/substructure-parent-helper';
 
 export class PluginContext {
     private disposed = false;
@@ -99,8 +100,9 @@ export class PluginContext {
     readonly customModelProperties = new CustomPropertyRegistry();
     readonly customParamEditors = new Map<string, StateTransformParameters.Class>();
 
-    readonly selection = {
-        structure: new StructureElementSelectionManager(this)
+    readonly helpers = {
+        structureSelection: new StructureElementSelectionManager(this),
+        substructureParent: new SubstructureParentHelper(this)
     };
 
     initViewer(canvas: HTMLCanvasElement, container: HTMLDivElement) {

+ 14 - 47
src/mol-plugin/util/structure-element-selection.ts

@@ -4,34 +4,29 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
+import { OrderedSet } from 'mol-data/int';
 import { EmptyLoci, Loci } from 'mol-model/loci';
 import { Structure, StructureElement } from 'mol-model/structure';
-import { State, StateObject, StateSelection } from 'mol-state';
+import { StateObject } from 'mol-state';
 import { PluginContext } from '../context';
 import { PluginStateObject } from '../state/objects';
-import { OrderedSet } from 'mol-data/int';
 
 export { StructureElementSelectionManager };
 
 class StructureElementSelectionManager {
     private entries = new Map<string, SelectionEntry>();
 
-    // maps structure to a parent StateObjectCell
-    private mapping = {
-        root: new Map<Structure, string>(),
-        tracked: new Map<string, Structure>()
-    };
-
     private getEntry(s: Structure) {
-        if (!this.mapping.root.has(s)) return;
-        const key = this.mapping.root.get(s)!;
-        if (!this.entries.has(key)) {
+        const cell = this.plugin.helpers.substructureParent.get(s);
+        if (!cell) return;
+        const ref = cell.transform.ref;
+        if (!this.entries.has(ref)) {
             const entry = SelectionEntry(s);
-            this.entries.set(key, entry);
+            this.entries.set(ref, entry);
             return entry;
         }
 
-        return this.entries.get(key)!;
+        return this.entries.get(ref)!;
     }
 
     add(loci: StructureElement.Loci): Loci {
@@ -112,27 +107,11 @@ class StructureElementSelectionManager {
         return ret || EmptyLoci;
     }
 
-    private addMapping(state: State, ref: string, obj: StateObject) {
-        if (!PluginStateObject.Molecule.Structure.is(obj)) return;
-        const parent = state.select(StateSelection.Generators.byRef(ref).rootOfType([PluginStateObject.Molecule.Structure]))[0];
-        this.mapping.tracked.set(ref, obj.data);
-        if (!parent) {
-            this.mapping.root.set(obj.data, ref);
-        } else {
-            this.mapping.root.set(obj.data, parent.transform.ref);
-        }
-    }
-
-    private removeMapping(ref: string) {
-        if (!this.mapping.tracked.has(ref)) return;
-        const s = this.mapping.tracked.get(ref)!;
-        this.mapping.tracked.delete(ref);
-        const root = this.mapping.root.get(s);
-        this.mapping.root.delete(s);
-        if (root === ref) this.entries.delete(ref);
+    private onRemove(ref: string) {
+        if (this.entries.has(ref)) this.entries.delete(ref);
     }
 
-    private updateMapping(state: State, ref: string, oldObj: StateObject | undefined, obj: StateObject) {
+    private onUpdate(ref: string, oldObj: StateObject | undefined, obj: StateObject) {
         if (!PluginStateObject.Molecule.Structure.is(obj)) return;
 
         if (this.entries.has(ref)) {
@@ -146,24 +125,12 @@ class StructureElementSelectionManager {
 
             // clear the selection
             this.entries.set(ref, SelectionEntry(obj.data));
-        } else {
-            this.removeMapping(ref);
-            this.addMapping(state, ref, obj);
         }
     }
 
-    constructor(plugin: PluginContext) {
-        plugin.state.dataState.events.object.created.subscribe(e => {
-            this.addMapping(e.state, e.ref, e.obj);
-        });
-
-        plugin.state.dataState.events.object.removed.subscribe(e => {
-            this.removeMapping(e.ref);
-        });
-
-        plugin.state.dataState.events.object.updated.subscribe(e => {
-            this.updateMapping(e.state, e.ref, e.oldObj, e.obj);
-        });
+    constructor(private plugin: PluginContext) {
+        plugin.state.dataState.events.object.removed.subscribe(e => this.onRemove(e.ref));
+        plugin.state.dataState.events.object.updated.subscribe(e => this.onUpdate(e.ref, e.oldObj, e.obj));
     }
 }
 

+ 63 - 0
src/mol-plugin/util/substructure-parent-helper.ts

@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { Structure } from 'mol-model/structure';
+import { State, StateObject, StateSelection, StateObjectCell } from 'mol-state';
+import { PluginContext } from '../context';
+import { PluginStateObject } from '../state/objects';
+
+export { SubstructureParentHelper };
+
+class SubstructureParentHelper {
+    private root = new Map<Structure, string>();
+    private tracked = new Map<string, Structure>();
+
+    get(s: Structure): StateObjectCell<PluginStateObject.Molecule.Structure> | undefined {
+        const r = this.root.get(s);
+        if (!r) return;
+        return this.plugin.state.dataState.cells.get(r);
+    }
+
+    private addMapping(state: State, ref: string, obj: StateObject) {
+        if (!PluginStateObject.Molecule.Structure.is(obj)) return;
+        const parent = state.select(StateSelection.Generators.byRef(ref).rootOfType([PluginStateObject.Molecule.Structure]))[0];
+        this.tracked.set(ref, obj.data);
+        if (!parent) {
+            this.root.set(obj.data, ref);
+        } else {
+            this.root.set(obj.data, parent.transform.ref);
+        }
+    }
+
+    private removeMapping(ref: string) {
+        if (!this.tracked.has(ref)) return;
+        const s = this.tracked.get(ref)!;
+        this.tracked.delete(ref);
+        this.root.get(s);
+        this.root.delete(s);
+    }
+
+    private updateMapping(state: State, ref: string, oldObj: StateObject | undefined, obj: StateObject) {
+        if (!PluginStateObject.Molecule.Structure.is(obj)) return;
+
+        this.removeMapping(ref);
+        this.addMapping(state, ref, obj);
+    }
+
+    constructor(private plugin: PluginContext) {
+        plugin.state.dataState.events.object.created.subscribe(e => {
+            this.addMapping(e.state, e.ref, e.obj);
+        });
+
+        plugin.state.dataState.events.object.removed.subscribe(e => {
+            this.removeMapping(e.ref);
+        });
+
+        plugin.state.dataState.events.object.updated.subscribe(e => {
+            this.updateMapping(e.state, e.ref, e.oldObj, e.obj);
+        });
+    }
+}