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

improved sequence numbers in sequence widget UI

parent 0a7406db
No related branches found
No related tags found
No related merge requests found
......@@ -14,7 +14,8 @@
.msp-sequence-wrapper {
word-break: break-all;
padding: $info-vertical-padding $control-spacing $info-vertical-padding $control-spacing;
// use $control-spacing for top to have space for sequence numebrs
padding: $control-spacing $control-spacing $info-vertical-padding $control-spacing;
user-select: none;
height: 100%;
overflow-y: auto;
......@@ -32,15 +33,27 @@
cursor: pointer;
}
.msp-sequence-marker {
color: $sequence-marker-color;
.msp-sequence-residue-long {
margin: 0em 0.2em 0em 0.2em;
}
.msp-sequence-residue-long-begin {
margin: 0em 0.2em 0em 0em;
}
.msp-sequence-number {
color: $sequence-number-color;
word-break: keep-all;
cursor: default;
position: relative;
top: -1.1em;
left: 3em;
left: 3.1em;
padding: 0px;
margin-left: -3em;
font-size: 80%;
}
.msp-sequence-number-long {
left: 3.3em;
}
}
\ No newline at end of file
......@@ -80,5 +80,5 @@ $entity-tag-color: color-lower-contrast($font-color, 20%);
// sequence
$sequence-background: $default-background;
$sequence-marker-color: $hover-font-color;
$sequence-number-color: $hover-font-color;
$sequence-select-width: 300px;
\ No newline at end of file
......@@ -16,9 +16,14 @@ import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { Color } from '../../../mol-util/color';
type SequenceProps = { sequenceWrapper: SequenceWrapper.Any, hideMarkers?: boolean }
type SequenceProps = {
sequenceWrapper: SequenceWrapper.Any,
sequenceNumberPeriod?: number,
hideSequenceNumbers?: boolean
}
const SequenceMarkerPeriod = 50
/** Note, if this is changed, the CSS for `msp-sequence-number` needs adjustment too */
const MaxSequenceNumberSize = 5
// TODO: this is somewhat inefficient and should be done using a canvas.
export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
......@@ -36,6 +41,12 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
if (changed) this.updateMarker();
}
private get sequenceNumberPeriod() {
return this.props.sequenceNumberPeriod !== undefined
? this.props.sequenceNumberPeriod as number
: (this.props.sequenceWrapper.length > 10 ? 10 : 1)
}
componentDidMount() {
this.plugin.interactivity.lociHighlights.addProvider(this.lociHighlightProvider)
this.plugin.interactivity.lociSelects.addProvider(this.lociSelectionProvider)
......@@ -94,31 +105,58 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
return marker === 0 ? '' : marker % 2 === 0 ? 'rgb(51, 255, 25)' /* selected */ : 'rgb(255, 102, 153)' /* highlighted */;
}
private getResidueClass(seqIdx: number, label: string) {
return label.length > 1
? (seqIdx === 0 ? 'msp-sequence-residue-long-begin' : 'msp-sequence-residue-long')
: void 0
}
private residue(seqIdx: number, label: string, marker: number, color: Color) {
const margin = label.length > 1 ? (seqIdx === 0 ? `0px 2px 0px 0px` : `0px 2px 0px 2px`) : void 0
return <span key={seqIdx} data-seqid={seqIdx} style={{ color: Color.toStyle(color), backgroundColor: this.getBackgroundColor(marker), margin }}>{label}</span>;
return <span key={seqIdx} data-seqid={seqIdx} style={{ color: Color.toStyle(color), backgroundColor: this.getBackgroundColor(marker) }} className={this.getResidueClass(seqIdx, label)}>{label}</span>;
}
private getSequenceNumberClass(seqIdx: number, label: string) {
return label.length > 1 && seqIdx > 0
? 'msp-sequence-number msp-sequence-number-long'
: 'msp-sequence-number'
}
private location = StructureElement.Location.create();
private getSequenceNumber(seqIdx: number, label: string) {
let sequenceNumber = ''
const loci = this.props.sequenceWrapper.getLoci(seqIdx)
const l = StructureElement.Loci.getFirstLocation(loci, this.location);
if (l) {
const seqId = StructureProperties.residue.auth_seq_id(l)
const insCode = StructureProperties.residue.pdbx_PDB_ins_code(l)
sequenceNumber = `${seqId}${insCode ? insCode : ''}`
}
return <span key={`marker-${seqIdx}`} className={this.getSequenceNumberClass(seqIdx, label)}>{sequenceNumber.padEnd(MaxSequenceNumberSize, '\u00A0')}</span>
}
private updateMarker() {
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++) {
if (this.hasSeqenceNumber(i)) o++;
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;
}
}
private hasSeqenceNumber(seqIdx: number) {
return !this.props.hideSequenceNumbers &&
seqIdx % this.sequenceNumberPeriod === 0 &&
seqIdx < this.props.sequenceWrapper.length
}
mouseMove = (e: React.MouseEvent) => {
e.stopPropagation();
......@@ -155,24 +193,14 @@ 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));
if (markers && i > 0 && i % SequenceMarkerPeriod === 0) {
if (i === sw.length - (1 + 5)) break;
// TODO: is this correct way to show the offset?
const l = StructureElement.Loci.getFirstLocation(sw.getLoci(i + 1), location);
if (l) {
const seqId = StructureProperties.residue.auth_seq_id(l)
const insCode = StructureProperties.residue.pdbx_PDB_ins_code(l)
const label = `${seqId}${insCode ? insCode : ''}`
elems[elems.length] = <span key={`marker-${i}`} className='msp-sequence-marker'>{label.padEnd(5, '\u00A0')}</span>
} else {
// show empty marker if the seq id is not known.
elems[elems.length] = <span key={`marker-${i}`} className='msp-sequence-marker'>{'\u00A0'.repeat(5)}</span>
}
const label = sw.residueLabel(i)
// add sequence number before name so the html element do not get separated by a line-break
if (this.hasSeqenceNumber(i)) {
elems[elems.length] = this.getSequenceNumber(i, label)
}
elems[elems.length] = this.residue(i, label, sw.markerArray[i], sw.residueColor(i));
}
// calling .updateMarker here is neccesary to ensure existing
......
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