ソースを参照

mol-plugin: show sequence offsets in UI (wip)

David Sehnal 5 年 前
コミット
4acc36628d

+ 13 - 0
src/mol-model/structure/structure/element/loci.ts

@@ -17,6 +17,7 @@ import { sortArray, hashFnv32a, hash2 } from '../../../../mol-data/util';
 import Expression from '../../../../mol-script/language/expression';
 import { ElementIndex } from '../../model';
 import { UnitIndex } from './element';
+import { Location } from './location';
 
 /** Represents multiple element index locations */
 export interface Loci {
@@ -78,6 +79,18 @@ export namespace Loci {
         return Loci(structure, []);
     }
 
+    export function getFirstLocation(loci: Loci, e?: Location): Location | undefined {
+        if (isEmpty(loci)) return void 0;
+        const unit = loci.elements[0].unit;
+        const element = unit.elements[OrderedSet.getAt(loci.elements[0].indices, 0)];
+        if (e) {
+            e.unit = loci.elements[0].unit;
+            e.element = element;
+            return e;
+        }
+        return Location.create(unit, element);
+    }
+
     export function toStructure(loci: Loci): Structure {
         const units: Unit[] = []
         for (const e of loci.elements) {

+ 9 - 0
src/mol-plugin/skin/base/components/sequence.scss

@@ -30,4 +30,13 @@
     span {
         cursor: pointer;
     }
+
+    .msp-sequence-marker {
+        color: $sequence-marker-color;
+        // vertical-align: middle;
+        text-decoration: underline;
+        padding: 0 0 0 1ch;
+        word-break: keep-all;
+        cursor: default;
+    }
 }

+ 1 - 0
src/mol-plugin/skin/base/variables.scss

@@ -80,4 +80,5 @@ $entity-tag-color: color-lower-contrast($font-color, 20%);
 
 // sequence
 $sequence-background: $default-background;
+$sequence-marker-color: $hover-font-color;
 $sequence-select-width: 300px;

+ 25 - 5
src/mol-plugin/ui/sequence/sequence.tsx

@@ -11,12 +11,14 @@ import { Interactivity } from '../../util/interactivity';
 import { MarkerAction } from '../../../mol-util/marker-action';
 import { ButtonsType, ModifiersKeys, getButtons, getModifiers } from '../../../mol-util/input/input-observer';
 import { SequenceWrapper } from './wrapper';
-import { StructureElement } from '../../../mol-model/structure';
+import { StructureElement, StructureProperties } from '../../../mol-model/structure';
 import { Subject } from 'rxjs';
 import { debounceTime } from 'rxjs/operators';
 import { Color } from '../../../mol-util/color';
 
-type SequenceProps = { sequenceWrapper: SequenceWrapper.Any }
+type SequenceProps = { sequenceWrapper: SequenceWrapper.Any, hideMarkers?: boolean }
+
+const SequenceMarkerPeriod = 50
 
 // TODO: this is somewhat inefficient and should be done using a canvas.
 export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
@@ -101,10 +103,16 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
         if (!this.parentDiv.current) return;
         const xs = this.parentDiv.current.children;
         const { markerArray } = this.props.sequenceWrapper;
+        const markers = !this.props.hideMarkers;
 
+        let o = 0;
         for (let i = 0, _i = markerArray.length; i < _i; i++) {
-            const span = xs[i] as HTMLSpanElement;
-            if (!span) continue;
+            const span = xs[o] as HTMLSpanElement;
+            if (!span) return;
+            o++;
+            if (markers && i > 0 && i % SequenceMarkerPeriod === 0) {
+                o++;
+            }
 
             const backgroundColor = this.getBackgroundColor(markerArray[i]);
             if (span.style.backgroundColor !== backgroundColor) span.style.backgroundColor = backgroundColor;
@@ -147,9 +155,21 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
         const sw = this.props.sequenceWrapper
 
         const elems: JSX.Element[] = [];
+        const markers = !this.props.hideMarkers;
+        const location = StructureElement.Location.create();
         for (let i = 0, il = sw.length; i < il; ++i) {
             elems[elems.length] = this.residue(i, sw.residueLabel(i), sw.markerArray[i], sw.residueColor(i));
-            // TODO: add seq idx markers every N residues? Would need to modify "updateMarker"
+            if (markers && i > 0 && i % SequenceMarkerPeriod === 0) {
+                if (i === sw.length - 1) break;
+                // TODO: is this correct way to show the offset?
+                const l = StructureElement.Loci.getFirstLocation(sw.getLoci(i + 1), location);
+                if (l) {
+                    elems[elems.length] = <span key={`marker-${i}`} className='msp-sequence-marker'>{StructureProperties.residue.auth_seq_id(l)}</span>
+                } else {
+                    // do not show the marker if the seq id is not known.
+                    elems[elems.length] = <span key={`marker-${i}`} className='msp-sequence-marker'></span>
+                }
+            }
         }
 
         // calling .updateMarker here is neccesary to ensure existing