Browse Source

added highlight example to basic wrapper, better empty loci handling

David Sehnal 5 years ago
parent
commit
d0870e4bbb

+ 4 - 0
src/apps/basic-wrapper/index.html

@@ -105,6 +105,10 @@
 
             addControl('Apply Stripes', () => BasicMolStarWrapper.coloring.applyStripes());
 
+            addHeader('Interactivity');
+            addControl('Highlight seq_id=7', () => BasicMolStarWrapper.interactivity.highlightOn());
+            addControl('Clear Highlight', () => BasicMolStarWrapper.interactivity.clearHighlight());
+
             addHeader('Tests');
 
             addControl('Static Superposition', () => BasicMolStarWrapper.tests.staticSuperposition());

+ 24 - 2
src/apps/basic-wrapper/index.ts

@@ -11,14 +11,18 @@ import { PluginCommands } from '../../mol-plugin/command';
 import { StateTransforms } from '../../mol-plugin/state/transforms';
 import { StructureRepresentation3DHelpers } from '../../mol-plugin/state/transforms/representation';
 import { Color } from '../../mol-util/color';
-import { PluginStateObject as PSO } from '../../mol-plugin/state/objects';
+import { PluginStateObject as PSO, PluginStateObject } from '../../mol-plugin/state/objects';
 import { AnimateModelIndex } from '../../mol-plugin/state/animation/built-in';
 import { StateBuilder, StateTransform } from '../../mol-state';
 import { StripedResidues } from './coloring';
+import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
 // import { BasicWrapperControls } from './controls';
 import { StaticSuperpositionTestData, buildStaticSuperposition, dynamicSuperpositionTest } from './superposition';
 import { PDBeStructureQualityReport } from '../../mol-plugin/behavior/dynamic/custom-props';
 import { CustomToastMessage } from './controls';
+import { EmptyLoci } from '../../mol-model/loci';
+import { compile } from '../../mol-script/runtime/query/compiler';
+import { StructureSelection, QueryContext } from '../../mol-model/structure';
 require('mol-plugin/skin/light.scss')
 
 type SupportedFormats = 'cif' | 'pdb'
@@ -63,7 +67,7 @@ class BasicWrapper {
     }
 
     private visual(visualRoot: StateBuilder.To<PSO.Molecule.Structure>) {
-        visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
+        visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' }, { ref: 'seq' })
             .apply(StateTransforms.Representation.StructureRepresentation3D,
                 StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'cartoon'), { ref: 'seq-visual' });
         visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
@@ -144,6 +148,24 @@ class BasicWrapper {
         }
     }
 
+    interactivity = {
+        highlightOn: () => {
+            const seq_id = 7;
+            const query = compile<StructureSelection>(
+                MS.struct.generator.atomGroups({
+                    'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_seq_id(), seq_id]),
+                    'group-by': MS.struct.atomProperty.macromolecular.residueKey()
+                }));
+            const data = (this.plugin.state.dataState.select('asm')[0].obj as PluginStateObject.Molecule.Structure).data;
+            const sel = query(new QueryContext(data));
+            const loci = StructureSelection.toLoci2(sel);
+            this.plugin.interactivity.lociHighlights.highlightOnly({ loci });
+        },
+        clearHighlight: () => {
+            this.plugin.interactivity.lociHighlights.highlightOnly({ loci: EmptyLoci });
+        }
+    }
+
     tests = {
         staticSuperposition: async () => {
             const state = this.plugin.state.dataState;

+ 1 - 1
src/mol-model-props/common/custom-element-property.ts

@@ -117,7 +117,7 @@ namespace CustomElementProperty {
         function LabelProvider(loci: Loci): string | undefined {
             if (loci.kind === 'element-loci') {
                 const e = loci.elements[0];
-                if (!has(e.unit.model)) return void 0;
+                if (!e || !has(e.unit.model)) return void 0;
                 return params.format!(get(StructureElement.Location.create(e.unit, e.unit.elements[OrderedSet.getAt(e.indices, 0)])));
             }
             return void 0;

+ 2 - 2
src/mol-model/loci.ts

@@ -23,8 +23,8 @@ export function isEveryLoci(x: any): x is EveryLoci {
 /** A Loci that is empty */
 export const EmptyLoci = { kind: 'empty-loci' as 'empty-loci' }
 export type EmptyLoci = typeof EmptyLoci
-export function isEmptyLoci(x: any): x is EmptyLoci {
-    return !!x && x.kind === 'empty-loci';
+export function isEmptyLoci(x: Loci): x is EmptyLoci {
+    return !!x && (x.kind === 'empty-loci' || (x.kind === 'element-loci' && x.elements.length === 0));
 }
 
 /** A generic data loci */

+ 1 - 0
src/mol-plugin/behavior/dynamic/custom-props/pdbe/structure-quality-report.ts

@@ -37,6 +37,7 @@ export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: bo
 
             switch (loci.kind) {
                 case 'element-loci':
+                    if (loci.elements.length === 0) return void 0;
                     const e = loci.elements[0];
                     const u = e.unit;
                     if (!u.model.customProperties.has(StructureQualityReport.Descriptor)) return void 0;