Skip to content
Snippets Groups Projects
Commit b1a0f46a authored by Alexander Rose's avatar Alexander Rose
Browse files

improved link loci handling for interactivity

parent 389e2498
No related branches found
No related tags found
No related merge requests found
......@@ -196,30 +196,33 @@ namespace StructureElement {
const elements: Loci['elements'][0][] = [];
for (const lociElement of loci.elements) {
if (lociElement.unit.kind !== Unit.Kind.Atomic) elements[elements.length] = lociElement;
if (lociElement.unit.kind === Unit.Kind.Atomic) {
const unitElements = lociElement.unit.elements;
const h = lociElement.unit.model.atomicHierarchy;
const unitElements = lociElement.unit.elements;
const h = lociElement.unit.model.atomicHierarchy;
const { index: residueIndex, offsets: residueOffsets } = h.residueAtomSegments;
const { index: residueIndex, offsets: residueOffsets } = h.residueAtomSegments;
const newIndices: UnitIndex[] = [];
const indices = lociElement.indices, len = OrderedSet.size(indices);
let i = 0;
while (i < len) {
const rI = residueIndex[unitElements[OrderedSet.getAt(indices, i)]];
i++;
while (i < len && residueIndex[unitElements[OrderedSet.getAt(indices, i)]] === rI) {
const newIndices: UnitIndex[] = [];
const indices = lociElement.indices, len = OrderedSet.size(indices);
let i = 0;
while (i < len) {
const rI = residueIndex[unitElements[OrderedSet.getAt(indices, i)]];
i++;
while (i < len && residueIndex[unitElements[OrderedSet.getAt(indices, i)]] === rI) {
i++;
}
for (let j = residueOffsets[rI], _j = residueOffsets[rI + 1]; j < _j; j++) {
const idx = OrderedSet.indexOf(unitElements, j);
if (idx >= 0) newIndices[newIndices.length] = idx as UnitIndex;
}
}
for (let j = residueOffsets[rI], _j = residueOffsets[rI + 1]; j < _j; j++) {
const idx = OrderedSet.indexOf(unitElements, j);
if (idx >= 0) newIndices[newIndices.length] = idx as UnitIndex;
}
elements[elements.length] = { unit: lociElement.unit, indices: SortedArray.ofSortedArray(newIndices) };
} else {
// coarse elements are already by-residue
elements[elements.length] = lociElement;
}
elements[elements.length] = { unit: lociElement.unit, indices: SortedArray.ofSortedArray(newIndices) };
}
return Loci(loci.structure, elements);
......
/**
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2019 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>
......@@ -8,6 +8,7 @@
import { Unit, StructureElement } from '../../structure'
import Structure from '../structure';
import { LinkType } from '../../model/types';
import { SortedArray } from '../../../../mol-data/int';
export * from './links/data'
export * from './links/intra-compute'
......@@ -61,6 +62,34 @@ namespace Link {
return true
}
// TODO
export function toStructureElementLoci(loci: Loci): StructureElement.Loci {
const elements: StructureElement.Loci['elements'][0][] = []
const map = new Map<number, number[]>()
for (const lociLink of loci.links) {
const { aIndex, aUnit, bIndex, bUnit } = lociLink
if (aUnit === bUnit) {
if (map.has(aUnit.id)) map.get(aUnit.id)!.push(aIndex, bIndex)
else map.set(aUnit.id, [aIndex, bIndex])
} else {
if (map.has(aUnit.id)) map.get(aUnit.id)!.push(aIndex)
else map.set(aUnit.id, [aIndex])
if (map.has(bUnit.id)) map.get(bUnit.id)!.push(bIndex)
else map.set(bUnit.id, [bIndex])
}
}
map.forEach((indices: number[], id: number) => {
elements.push({
unit: loci.structure.unitMap.get(id)!,
indices: SortedArray.deduplicate(SortedArray.ofUnsortedArray(indices))
})
})
return StructureElement.Loci(loci.structure, elements);
}
export function getType(structure: Structure, link: Location<Unit.Atomic>): LinkType {
if (link.aUnit === link.bUnit) {
const links = link.aUnit.links;
......
......@@ -8,7 +8,7 @@
import { Loci as ModelLoci, EmptyLoci } from '../../mol-model/loci';
import { ModifiersKeys, ButtonsType } from '../../mol-util/input/input-observer';
import { Representation } from '../../mol-repr/representation';
import { StructureElement } from '../../mol-model/structure';
import { StructureElement, Link } from '../../mol-model/structure';
import { MarkerAction } from '../../mol-util/marker-action';
import { StructureElementSelectionManager } from './structure-element-selection';
import { PluginContext } from '../context';
......@@ -90,8 +90,13 @@ namespace Interactivity {
// TODO clear, then re-apply remaining providers
}
expandLoci(loci: ModelLoci) {
return LociExpansion[this.props.lociExpansion](loci)
normalizedLoci(interactivityLoci: Loci) {
let { loci, repr } = interactivityLoci
if (this.props.lociExpansion !== 'none' && Link.isLoci(loci)) {
loci = Link.toStructureElementLoci(loci)
}
loci = LociExpansion[this.props.lociExpansion](loci)
return { loci, repr }
}
protected mark(current: Loci<ModelLoci>, action: MarkerAction) {
......@@ -111,22 +116,23 @@ namespace Interactivity {
apply(e: HighlightEvent) {
const { current, modifiers } = e
const expanded: Loci<ModelLoci> = { loci: this.expandLoci(current.loci), repr: current.repr }
if (StructureElement.isLoci(expanded.loci)) {
let loci: StructureElement.Loci = expanded.loci;
const normalized: Loci<ModelLoci> = this.normalizedLoci(current)
if (StructureElement.isLoci(normalized.loci)) {
let loci: StructureElement.Loci = normalized.loci;
if (modifiers && modifiers.shift) {
loci = this.sel.tryGetRange(loci) || loci;
}
this.mark(this.prev, MarkerAction.RemoveHighlight);
const toHighlight = { loci, repr: expanded.repr };
const toHighlight = { loci, repr: normalized.repr };
this.mark(toHighlight, MarkerAction.Highlight);
this.prev = toHighlight;
} else {
if (!Loci.areEqual(this.prev, expanded)) {
if (!Loci.areEqual(this.prev, normalized)) {
this.mark(this.prev, MarkerAction.RemoveHighlight);
this.mark(expanded, MarkerAction.Highlight);
this.prev = expanded;
this.mark(normalized, MarkerAction.Highlight);
this.prev = normalized;
}
}
}
......@@ -150,34 +156,34 @@ namespace Interactivity {
apply(e: ClickEvent) {
const { current, buttons, modifiers } = e
const expanded: Loci<ModelLoci> = { loci: this.expandLoci(current.loci), repr: current.repr }
if (expanded.loci.kind === 'empty-loci') {
const normalized: Loci<ModelLoci> = this.normalizedLoci(current)
if (normalized.loci.kind === 'empty-loci') {
if (modifiers.control && buttons === ButtonsType.Flag.Secondary) {
// clear the selection on Ctrl + Right-Click on empty
const sels = this.sel.clear();
for (const s of sels) this.mark({ loci: s }, MarkerAction.Deselect);
}
} else if (StructureElement.isLoci(expanded.loci)) {
} else if (StructureElement.isLoci(normalized.loci)) {
if (modifiers.control && buttons === ButtonsType.Flag.Secondary) {
// select only the current element on Ctrl + Right-Click
const old = this.sel.get(expanded.loci.structure);
const old = this.sel.get(normalized.loci.structure);
this.mark({ loci: old }, MarkerAction.Deselect);
this.sel.set(expanded.loci);
this.mark(expanded, MarkerAction.Select);
this.sel.set(normalized.loci);
this.mark(normalized, MarkerAction.Select);
} else if (modifiers.control && buttons === ButtonsType.Flag.Primary) {
// toggle current element on Ctrl + Left-Click
this.toggleSel(expanded as Representation.Loci<StructureElement.Loci>);
this.toggleSel(normalized as Representation.Loci<StructureElement.Loci>);
} else if (modifiers.shift && buttons === ButtonsType.Flag.Primary) {
// try to extend sequence on Shift + Left-Click
let loci: StructureElement.Loci = expanded.loci;
let loci: StructureElement.Loci = normalized.loci;
if (modifiers && modifiers.shift) {
loci = this.sel.tryGetRange(loci) || loci;
}
this.toggleSel({ loci, repr: expanded.repr });
this.toggleSel({ loci, repr: normalized.repr });
}
} else {
if (!ButtonsType.has(buttons, ButtonsType.Flag.Secondary)) return;
for (let p of this.providers) p(expanded, MarkerAction.Toggle);
for (let p of this.providers) p(normalized, MarkerAction.Toggle);
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment