Browse Source

improved LociLabelManager to handle multiple loci

Alexander Rose 5 years ago
parent
commit
4d3914426e

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

@@ -241,7 +241,7 @@ namespace Loci {
     /**
      * Converts structure related loci to StructureElement.Loci and applies
      * granularity if given
-    */
+     */
     export function normalize(loci: Loci, granularity?: Granularity) {
         if (granularity !== 'element' && Bond.isLoci(loci)) {
             // convert Bond.Loci to a StructureElement.Loci so granularity can be applied

+ 4 - 4
src/mol-plugin-state/helpers/structure-representation-params.ts

@@ -46,7 +46,7 @@ export function createStructureRepresentationParams
     (ctx: PluginContext, structure?: Structure, props?: StructureRepresentationBuiltInProps<R, C, S>): StateTransformer.Params<StructureRepresentation3D>
 export function createStructureRepresentationParams
     <R extends RepresentationProvider<Structure>, C extends ColorTheme.Provider, S extends SizeTheme.Provider>
-    (ctx: PluginContext, structure?: Structure, props?: StructureRepresentationProps<R, C, S>): StateTransformer.Params<StructureRepresentation3D> 
+    (ctx: PluginContext, structure?: Structure, props?: StructureRepresentationProps<R, C, S>): StateTransformer.Params<StructureRepresentation3D>
 export function createStructureRepresentationParams(ctx: PluginContext, structure?: Structure, props: any = {}): StateTransformer.Params<StructureRepresentation3D>  {
     const p = props as StructureRepresentationBuiltInProps;
     if (typeof p.type === 'string' || typeof p.color === 'string' || typeof p.size === 'string') return createParamsByName(ctx, structure || Structure.Empty, props);
@@ -86,7 +86,7 @@ export function createStructureSizeThemeParams(ctx: PluginContext, structure: St
 function createParamsByName(ctx: PluginContext, structure: Structure, props: StructureRepresentationBuiltInProps): StateTransformer.Params<StructureRepresentation3D> {
     const typeProvider = (props.type && ctx.representation.structure.registry.get(props.type))
         || ctx.representation.structure.registry.default.provider;
-    const colorProvider = (props.color && ctx.representation.structure.themes.colorThemeRegistry.get(props.color)) 
+    const colorProvider = (props.color && ctx.representation.structure.themes.colorThemeRegistry.get(props.color))
         || ctx.representation.structure.themes.colorThemeRegistry.get(typeProvider.defaultColorTheme.name);
     const sizeProvider = (props.size && ctx.representation.structure.themes.sizeThemeRegistry.get(props.size))
         || ctx.representation.structure.themes.sizeThemeRegistry.get(typeProvider.defaultSizeTheme.name);
@@ -104,11 +104,11 @@ function createParamsByName(ctx: PluginContext, structure: Structure, props: Str
 function createParamsProvider(ctx: PluginContext, structure: Structure, props: StructureRepresentationProps = {}): StateTransformer.Params<StructureRepresentation3D> {
     const { themes: themeCtx } = ctx.representation.structure
     const themeDataCtx = { structure };
-    
+
     const repr = props.type || ctx.representation.structure.registry.default.provider;
     const reprDefaultParams = PD.getDefaultValues(repr.getParams(themeCtx, structure));
     const reprParams = Object.assign(reprDefaultParams, props.typeParams);
-    
+
     const color = props.color || themeCtx.colorThemeRegistry.get(repr.defaultColorTheme.name);
     const colorDefaultParams = PD.getDefaultValues(color.getParams(themeDataCtx));
     if (color.name === repr.defaultColorTheme.name) Object.assign(colorDefaultParams, repr.defaultColorTheme.props);

+ 1 - 1
src/mol-plugin-state/helpers/structure-selection-query.ts

@@ -77,7 +77,7 @@ function StructureSelectionQuery(label: string, expression: Expression, props: S
             if (props.ensureCustomProperties) {
                 await props.ensureCustomProperties({ fetch: plugin.fetch, runtime }, structure)
             }
-            if (!_query) _query = compile<StructureSelection>(expression)    
+            if (!_query) _query = compile<StructureSelection>(expression)
             return _query(new QueryContext(structure, { currentSelection }));
         }
     }

+ 28 - 37
src/mol-plugin-state/manager/interactivity.ts

@@ -1,11 +1,11 @@
 /**
- * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { EmptyLoci, EveryLoci, isEmptyLoci, Loci as ModelLoci } from '../../mol-model/loci';
+import { EveryLoci, isEmptyLoci, Loci } from '../../mol-model/loci';
 import { Structure, StructureElement } from '../../mol-model/structure';
 import { PluginContext } from '../../mol-plugin/context';
 import { Representation } from '../../mol-repr/representation';
@@ -63,25 +63,16 @@ class InteractivityManager extends PluginComponent<InteractivityManagerState> {
 }
 
 namespace InteractivityManager {
-    export interface Loci<T extends ModelLoci = ModelLoci> { loci: T, repr?: Representation.Any }
-
-    export namespace Loci {
-        export function areEqual(a: Loci, b: Loci) {
-            return a.repr === b.repr && ModelLoci.areEqual(a.loci, b.loci);
-        }
-        export const Empty: Loci = { loci: EmptyLoci };
-    }
-
     export const Params = {
-        granularity: PD.Select('residue', ModelLoci.GranularityOptions, { label: 'Picking Level', description: 'Controls if selections are expanded upon picking to whole residues, chains, structures, instances, or left as atoms and coarse elements' }),
+        granularity: PD.Select('residue', Loci.GranularityOptions, { label: 'Picking Level', description: 'Controls if selections are expanded upon picking to whole residues, chains, structures, instances, or left as atoms and coarse elements' }),
     }
     export type Params = typeof Params
     export type Props = PD.Values<Params>
 
-    export interface HoverEvent { current: Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys }
-    export interface ClickEvent { current: Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys }
+    export interface HoverEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys }
+    export interface ClickEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys }
 
-    export type LociMarkProvider = (loci: Loci, action: MarkerAction) => void
+    export type LociMarkProvider = (loci: Representation.Loci, action: MarkerAction) => void
 
     export abstract class LociMarkManager {
         protected providers: LociMarkProvider[] = [];
@@ -102,13 +93,13 @@ namespace InteractivityManager {
             // TODO clear, then re-apply remaining providers
         }
 
-        protected normalizedLoci(interactivityLoci: Loci, applyGranularity = true) {
-            const { loci, repr } = interactivityLoci
+        protected normalizedLoci(reprLoci: Representation.Loci, applyGranularity = true) {
+            const { loci, repr } = reprLoci
             const granularity =  applyGranularity ? this.props.granularity : undefined
-            return { loci: ModelLoci.normalize(loci, granularity), repr }
+            return { loci: Loci.normalize(loci, granularity), repr }
         }
 
-        protected mark(current: Loci<ModelLoci>, action: MarkerAction) {
+        protected mark(current: Representation.Loci, action: MarkerAction) {
             for (let p of this.providers) p(current, action);
         }
 
@@ -121,16 +112,16 @@ namespace InteractivityManager {
     //
 
     export class LociHighlightManager extends LociMarkManager {
-        private prev: Loci[] = [];
+        private prev: Representation.Loci[] = [];
 
-        private isHighlighted(loci: Loci) {
+        private isHighlighted(loci: Representation.Loci) {
             for (const p of this.prev) {
-                if (Loci.areEqual(p, loci)) return true
+                if (Representation.Loci.areEqual(p, loci)) return true
             }
             return false
         }
 
-        private addHighlight(loci: Loci) {
+        private addHighlight(loci: Representation.Loci) {
             this.mark(loci, MarkerAction.Highlight);
             this.prev.push(loci)
         }
@@ -142,14 +133,14 @@ namespace InteractivityManager {
             this.prev.length = 0
         }
 
-        highlight(current: Loci, applyGranularity = true) {
+        highlight(current: Representation.Loci, applyGranularity = true) {
             const normalized = this.normalizedLoci(current, applyGranularity)
             if (!this.isHighlighted(normalized)) {
                 this.addHighlight(normalized)
             }
         }
 
-        highlightOnly(current: Loci, applyGranularity = true) {
+        highlightOnly(current: Representation.Loci, applyGranularity = true) {
             const normalized = this.normalizedLoci(current, applyGranularity)
             if (!this.isHighlighted(normalized)) {
                 this.clearHighlights()
@@ -157,7 +148,7 @@ namespace InteractivityManager {
             }
         }
 
-        highlightOnlyExtend(current: Loci, applyGranularity = true) {
+        highlightOnlyExtend(current: Representation.Loci, applyGranularity = true) {
             const normalized = this.normalizedLoci(current, applyGranularity)
             if (StructureElement.Loci.is(normalized.loci)) {
                 const loci = {
@@ -175,8 +166,8 @@ namespace InteractivityManager {
     //
 
     export class LociSelectManager extends LociMarkManager {
-        toggle(current: Loci<ModelLoci>, applyGranularity = true) {
-            if (ModelLoci.isEmpty(current.loci)) return;
+        toggle(current: Representation.Loci, applyGranularity = true) {
+            if (Loci.isEmpty(current.loci)) return;
 
             const normalized = this.normalizedLoci(current, applyGranularity)
             if (StructureElement.Loci.is(normalized.loci)) {
@@ -186,8 +177,8 @@ namespace InteractivityManager {
             }
         }
 
-        toggleExtend(current: Loci<ModelLoci>, applyGranularity = true) {
-            if (ModelLoci.isEmpty(current.loci)) return;
+        toggleExtend(current: Representation.Loci, applyGranularity = true) {
+            if (Loci.isEmpty(current.loci)) return;
 
             const normalized = this.normalizedLoci(current, applyGranularity)
             if (StructureElement.Loci.is(normalized.loci)) {
@@ -196,7 +187,7 @@ namespace InteractivityManager {
             }
         }
 
-        select(current: Loci<ModelLoci>, applyGranularity = true) {
+        select(current: Representation.Loci, applyGranularity = true) {
             const normalized = this.normalizedLoci(current, applyGranularity)
             if (StructureElement.Loci.is(normalized.loci)) {
                 this.sel.modify('add', normalized.loci);
@@ -204,7 +195,7 @@ namespace InteractivityManager {
             this.mark(normalized, MarkerAction.Select);
         }
 
-        selectJoin(current: Loci<ModelLoci>, applyGranularity = true) {
+        selectJoin(current: Representation.Loci, applyGranularity = true) {
             const normalized = this.normalizedLoci(current, applyGranularity)
             if (StructureElement.Loci.is(normalized.loci)) {
                 this.sel.modify('intersect', normalized.loci);
@@ -212,7 +203,7 @@ namespace InteractivityManager {
             this.mark(normalized, MarkerAction.Select);
         }
 
-        selectOnly(current: Loci<ModelLoci>, applyGranularity = true) {
+        selectOnly(current: Representation.Loci, applyGranularity = true) {
             this.deselectAll()
             const normalized = this.normalizedLoci(current, applyGranularity)
             if (StructureElement.Loci.is(normalized.loci)) {
@@ -221,7 +212,7 @@ namespace InteractivityManager {
             this.mark(normalized, MarkerAction.Select);
         }
 
-        deselect(current: Loci<ModelLoci>, applyGranularity = true) {
+        deselect(current: Representation.Loci, applyGranularity = true) {
             const normalized = this.normalizedLoci(current, applyGranularity)
             if (StructureElement.Loci.is(normalized.loci)) {
                 this.sel.modify('remove', normalized.loci);
@@ -234,11 +225,11 @@ namespace InteractivityManager {
             this.mark({ loci: EveryLoci }, MarkerAction.Deselect);
         }
 
-        deselectAllOnEmpty(current: Loci<ModelLoci>) {
+        deselectAllOnEmpty(current: Representation.Loci) {
             if (isEmptyLoci(current.loci)) this.deselectAll()
         }
 
-        protected mark(current: Loci<ModelLoci>, action: MarkerAction.Select | MarkerAction.Deselect) {
+        protected mark(current: Representation.Loci, action: MarkerAction.Select | MarkerAction.Deselect) {
             const { loci } = current
             if (StructureElement.Loci.is(loci)) {
                 // do a full deselect/select for the current structure so visuals that are
@@ -251,7 +242,7 @@ namespace InteractivityManager {
             }
         }
 
-        private toggleSel(current: Loci<ModelLoci>) {
+        private toggleSel(current: Representation.Loci) {
             if (this.sel.has(current.loci)) {
                 this.sel.modify('remove', current.loci);
                 this.mark(current, MarkerAction.Deselect);

+ 42 - 11
src/mol-plugin-state/manager/loci-label.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2020 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>
@@ -9,6 +9,7 @@ import { PluginContext } from '../../mol-plugin/context';
 import { Loci } from '../../mol-model/loci';
 import { Representation } from '../../mol-repr/representation';
 import { MarkerAction } from '../../mol-util/marker-action';
+import { arrayRemoveAtInPlace } from '../../mol-util/array';
 
 export type LociLabelEntry = JSX.Element | string
 export type LociLabelProvider = (info: Loci, repr?: Representation<any>) => LociLabelEntry | undefined
@@ -18,25 +19,55 @@ export class LociLabelManager {
 
     addProvider(provider: LociLabelProvider) {
         this.providers.push(provider);
+        this.isDirty = true
+        this.showLabels()
     }
 
     removeProvider(provider: LociLabelProvider) {
         this.providers = this.providers.filter(p => p !== provider);
-        // Event.Interactivity.Highlight.dispatch(this.ctx, []);
+        this.isDirty = true
+        this.showLabels()
     }
 
-    private empty: LociLabelEntry[] = [];
-    private getInfo({ loci, repr }: Representation.Loci, action: MarkerAction) {
-        if (Loci.isEmpty(loci) || action !== MarkerAction.Highlight) return this.empty;
-        const info: LociLabelEntry[] = [];
-        for (let p of this.providers) {
-            const e = p(loci, repr);
-            if (e) info.push(e);
+    private locis: Representation.Loci[] = []
+
+    private mark(loci: Representation.Loci, action: MarkerAction) {
+        const idx = this.locis.findIndex(l => Representation.Loci.areEqual(loci, l))
+        if (idx === -1 && action === MarkerAction.Highlight) {
+            this.locis.push(loci)
+            this.isDirty = true
+        } else if(idx !== -1 && action === MarkerAction.RemoveHighlight) {
+            arrayRemoveAtInPlace(this.locis, idx)
+            this.isDirty = true
+        }
+    }
+
+    private isDirty = false
+    private entries: LociLabelEntry[] = []
+
+    private showLabels() {
+        this.ctx.behaviors.labels.highlight.next({ entries: this.getEntries() })
+    }
+
+    private getEntries() {
+        if (this.isDirty) {
+            this.entries.length = 0
+            for (const provider of this.providers) {
+                for (const loci of this.locis) {
+                    if (Loci.isEmpty(loci.loci)) continue
+                    const entry = provider(loci.loci, loci.repr)
+                    if (entry) this.entries.push(entry)
+                }
+            }
+            this.isDirty = false
         }
-        return info;
+        return this.entries
     }
 
     constructor(public ctx: PluginContext) {
-        ctx.managers.interactivity.lociHighlights.addProvider((loci, action) => ctx.behaviors.labels.highlight.next({ entries: this.getInfo(loci, action) }))
+        ctx.managers.interactivity.lociHighlights.addProvider((loci, action) => {
+            this.mark(loci, action)
+            this.showLabels()
+        })
     }
 }

+ 6 - 6
src/mol-plugin-ui/sequence/sequence.tsx

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  * @author David Sehnal <david.sehnal@gmail.com>
@@ -7,7 +7,6 @@
 
 import * as React from 'react'
 import { PluginUIComponent } from '../base';
-import { InteractivityManager } from '../../mol-plugin-state/manager/interactivity';
 import { MarkerAction } from '../../mol-util/marker-action';
 import { ButtonsType, ModifiersKeys, getButtons, getModifiers, getButton } from '../../mol-util/input/input-observer';
 import { SequenceWrapper } from './wrapper';
@@ -16,6 +15,7 @@ import { Subject } from 'rxjs';
 import { debounceTime } from 'rxjs/operators';
 import { Color } from '../../mol-util/color';
 import { OrderedSet } from '../../mol-data/int';
+import { Representation } from '../../mol-repr/representation';
 
 type SequenceProps = {
     sequenceWrapper: SequenceWrapper.Any,
@@ -32,12 +32,12 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
     private lastMouseOverSeqIdx = -1;
     private highlightQueue = new Subject<{ seqIdx: number, buttons: number, button: number, modifiers: ModifiersKeys }>();
 
-    private lociHighlightProvider = (loci: InteractivityManager.Loci, action: MarkerAction) => {
+    private lociHighlightProvider = (loci: Representation.Loci, action: MarkerAction) => {
         const changed = this.props.sequenceWrapper.markResidue(loci.loci, action)
         if (changed) this.updateMarker();
     }
 
-    private lociSelectionProvider = (loci: InteractivityManager.Loci, action: MarkerAction) => {
+    private lociSelectionProvider = (loci: Representation.Loci, action: MarkerAction) => {
         const changed = this.props.sequenceWrapper.markResidue(loci.loci, action)
         if (changed) this.updateMarker();
     }
@@ -88,7 +88,7 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
     }
 
     hover(loci: StructureElement.Loci | undefined, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
-        const ev = { current: InteractivityManager.Loci.Empty, buttons, button, modifiers }
+        const ev = { current: Representation.Loci.Empty, buttons, button, modifiers }
         if (loci !== undefined && !StructureElement.Loci.isEmpty(loci)) {
             ev.current = { loci };
         }
@@ -96,7 +96,7 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
     }
 
     click(loci: StructureElement.Loci | undefined, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
-        const ev = { current: InteractivityManager.Loci.Empty, buttons, button, modifiers }
+        const ev = { current: Representation.Loci.Empty, buttons, button, modifiers }
         if (loci !== undefined && !StructureElement.Loci.isEmpty(loci)) {
             ev.current = { loci };
         }

+ 1 - 1
src/mol-plugin-ui/structure/measurements.tsx

@@ -301,7 +301,7 @@ class MeasurementEntry extends PurePluginUIComponent<{ cell: StructureMeasuremen
                 <ActionMenu items={this.actions} onSelect={this.selectAction} />
                 <div className='msp-control-offset'>
                     <ExpandGroup header='Options' noOffset>
-                        <UpdateTransformControl state={cell.parent} transform={cell.transform} customHeader='none' />
+                        <UpdateTransformControl state={cell.parent} transform={cell.transform} customHeader='none' autoHideApply />
                     </ExpandGroup>
                 </div>
             </>}

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

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2020 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>
@@ -10,7 +10,6 @@ import { PluginContext } from '../../../mol-plugin/context';
 import { PluginStateObject as SO } from '../../../mol-plugin-state/objects';
 import { lociLabel } from '../../../mol-theme/label';
 import { PluginBehavior } from '../behavior';
-import { InteractivityManager } from '../../../mol-plugin-state/manager/interactivity';
 import { StateTreeSpine } from '../../../mol-state/tree/spine';
 import { StateSelection } from '../../../mol-state';
 import { ButtonsType, ModifiersKeys } from '../../../mol-util/input/input-observer';
@@ -19,6 +18,7 @@ import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { EmptyLoci, Loci } from '../../../mol-model/loci';
 import { Structure } from '../../../mol-model/structure';
 import { arrayMax } from '../../../mol-util/array';
+import { Representation } from '../../../mol-repr/representation';
 
 const B = ButtonsType
 const M = ModifiersKeys
@@ -39,7 +39,7 @@ export const HighlightLoci = PluginBehavior.create({
     name: 'representation-highlight-loci',
     category: 'interaction',
     ctor: class extends PluginBehavior.Handler<HighlightLociProps> {
-        private lociMarkProvider = (interactionLoci: InteractivityManager.Loci, action: MarkerAction) => {
+        private lociMarkProvider = (interactionLoci: Representation.Loci, action: MarkerAction) => {
             if (!this.ctx.canvas3d) return;
             this.ctx.canvas3d.mark({ loci: interactionLoci.loci }, action)
         }
@@ -92,9 +92,9 @@ export const SelectLoci = PluginBehavior.create({
     category: 'interaction',
     ctor: class extends PluginBehavior.Handler<SelectLociProps> {
         private spine: StateTreeSpine.Impl
-        private lociMarkProvider = (interactionLoci: InteractivityManager.Loci, action: MarkerAction) => {
+        private lociMarkProvider = (reprLoci: Representation.Loci, action: MarkerAction) => {
             if (!this.ctx.canvas3d) return;
-            this.ctx.canvas3d.mark({ loci: interactionLoci.loci }, action)
+            this.ctx.canvas3d.mark({ loci: reprLoci.loci }, action)
         }
         private applySelectMark(ref: string, clear?: boolean) {
             const cell = this.ctx.state.data.cells.get(ref)
@@ -111,10 +111,10 @@ export const SelectLoci = PluginBehavior.create({
             }
         }
         register() {
-            const lociIsEmpty = (current: InteractivityManager.Loci) => Loci.isEmpty(current.loci)
-            const lociIsNotEmpty = (current: InteractivityManager.Loci) => !Loci.isEmpty(current.loci)
+            const lociIsEmpty = (current: Representation.Loci) => Loci.isEmpty(current.loci)
+            const lociIsNotEmpty = (current: Representation.Loci) => !Loci.isEmpty(current.loci)
 
-            const actions: [keyof typeof DefaultSelectLociBindings, (current: InteractivityManager.Loci) => void, ((current: InteractivityManager.Loci) => boolean) | undefined][] = [
+            const actions: [keyof typeof DefaultSelectLociBindings, (current: Representation.Loci) => void, ((current: Representation.Loci) => boolean) | undefined][] = [
                 ['clickSelect', current => this.ctx.managers.interactivity.lociSelects.select(current), lociIsNotEmpty],
                 ['clickToggle', current => this.ctx.managers.interactivity.lociSelects.toggle(current), lociIsNotEmpty],
                 ['clickToggleExtend', current => this.ctx.managers.interactivity.lociSelects.toggleExtend(current), lociIsNotEmpty],

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

@@ -49,6 +49,7 @@ import { TaskManager } from './util/task-manager';
 import { PluginToastManager } from './util/toast';
 import { ViewportScreenshotHelper } from './util/viewport-screenshot';
 import { PLUGIN_VERSION, PLUGIN_VERSION_DATE } from './version';
+import { Representation } from '../mol-repr/representation';
 
 export class PluginContext {
     private disposed = false;
@@ -90,8 +91,8 @@ export class PluginContext {
             isBusy: this.ev.behavior<boolean>(false)
         },
         interaction: {
-            hover: this.ev.behavior<InteractivityManager.HoverEvent>({ current: InteractivityManager.Loci.Empty, modifiers: ModifiersKeys.None, buttons: 0, button: 0 }),
-            click: this.ev.behavior<InteractivityManager.ClickEvent>({ current: InteractivityManager.Loci.Empty, modifiers: ModifiersKeys.None, buttons: 0, button: 0 })
+            hover: this.ev.behavior<InteractivityManager.HoverEvent>({ current: Representation.Loci.Empty, modifiers: ModifiersKeys.None, buttons: 0, button: 0 }),
+            click: this.ev.behavior<InteractivityManager.ClickEvent>({ current: Representation.Loci.Empty, modifiers: ModifiersKeys.None, buttons: 0, button: 0 })
         },
         labels: {
             highlight: this.ev.behavior<{ entries: ReadonlyArray<LociLabelEntry> }>({ entries: [] })