@datagrok/bio 2.9.0 → 2.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -1
- package/detectors.js +5 -3
- package/dist/452.js +1 -1
- package/dist/452.js.map +1 -1
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/files/data/sample_HELM_empty_unkn.csv +11 -0
- package/package.json +4 -4
- package/src/analysis/sequence-space.ts +5 -6
- package/src/apps/get-region-app.ts +65 -0
- package/src/apps/web-logo-app.ts +3 -6
- package/src/package-test.ts +1 -0
- package/src/package-types.ts +13 -0
- package/src/package.ts +165 -59
- package/src/tests/converters-test.ts +2 -3
- package/src/tests/detectors-tests.ts +13 -2
- package/src/tests/renderers-monomer-placer.ts +25 -12
- package/src/tests/scoring.ts +8 -4
- package/src/tests/units-handler-get-region.ts +116 -0
- package/src/utils/cell-renderer.ts +5 -32
- package/src/utils/context-menu.ts +2 -3
- package/src/utils/convert.ts +6 -7
- package/src/utils/get-region-func-editor.ts +261 -0
- package/src/utils/get-region.ts +65 -0
- package/src/utils/multiple-sequence-alignment-ui.ts +21 -17
- package/src/viewers/web-logo-viewer.ts +73 -44
|
@@ -3,15 +3,19 @@ import * as DG from 'datagrok-api/dg';
|
|
|
3
3
|
import * as ui from 'datagrok-api/ui';
|
|
4
4
|
|
|
5
5
|
import {ALPHABET, NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
6
|
+
import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
7
|
+
import {ColumnInputOptions} from '@datagrok-libraries/utils/src/type-declarations';
|
|
8
|
+
|
|
6
9
|
import {runKalign} from './multiple-sequence-alignment';
|
|
7
10
|
import {pepseaMethods, runPepsea} from './pepsea';
|
|
8
11
|
import {checkInputColumnUI} from './check-input-column';
|
|
9
|
-
import {NotationConverter} from '@datagrok-libraries/bio/src/utils/notation-converter';
|
|
10
|
-
import {_package} from '../package';
|
|
11
12
|
import {multipleSequenceAlginmentUIOptions} from './types';
|
|
12
13
|
import {kalignVersion, msaDefaultOptions} from './constants';
|
|
14
|
+
|
|
15
|
+
import {_package} from '../package';
|
|
16
|
+
|
|
13
17
|
import '../../css/msa.css';
|
|
14
|
-
|
|
18
|
+
|
|
15
19
|
export class MsaWarning extends Error {
|
|
16
20
|
constructor(message: string, options?: ErrorOptions) {
|
|
17
21
|
super(message, options);
|
|
@@ -66,12 +70,12 @@ export async function multipleSequenceAlignmentUI(
|
|
|
66
70
|
//TODO: remove when the new version of datagrok-api is available
|
|
67
71
|
//TODO: allow only macromolecule colums to be chosen
|
|
68
72
|
const colInput = ui.columnInput('Sequence', table, seqCol, async () => {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
performAlignment = await onColInputChange(
|
|
74
|
+
colInput.value, table, pepseaInputRootStyles, kalignInputRootStyles,
|
|
75
|
+
methodInput, clustersColInput, gapOpenInput, gapExtendInput, terminalGapInput,
|
|
76
|
+
);
|
|
77
|
+
//@ts-ignore
|
|
78
|
+
}, {filter: (col: DG.Column) => col.semType === DG.SEMTYPE.MACROMOLECULE} as ColumnInputOptions
|
|
75
79
|
) as DG.InputBase<DG.Column<string>>;
|
|
76
80
|
colInput.setTooltip('Sequences column to use for alignment');
|
|
77
81
|
const clustersColInput = ui.columnInput('Clusters', table, options.clustersCol);
|
|
@@ -100,7 +104,7 @@ export async function multipleSequenceAlignmentUI(
|
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
async function onDialogOk(
|
|
103
|
-
colInput: DG.InputBase<
|
|
107
|
+
colInput: DG.InputBase<DG.Column<any>>,
|
|
104
108
|
table: DG.DataFrame,
|
|
105
109
|
performAlignment: (() => Promise<DG.Column<string> | null>) | undefined,
|
|
106
110
|
resolve: (value: DG.Column<any>) => void,
|
|
@@ -151,9 +155,9 @@ async function onColInputChange(
|
|
|
151
155
|
gapOpenInput.value = null;
|
|
152
156
|
gapExtendInput.value = null;
|
|
153
157
|
terminalGapInput.value = null;
|
|
154
|
-
const
|
|
155
|
-
const performCol: DG.Column<string> =
|
|
156
|
-
|
|
158
|
+
const potentialColUH = UnitsHandler.getOrCreate(col);
|
|
159
|
+
const performCol: DG.Column<string> = potentialColUH.isFasta() ? col :
|
|
160
|
+
potentialColUH.convert(NOTATION.FASTA);
|
|
157
161
|
return async () => await runKalign(performCol, false, unusedName, clustersColInput.value);
|
|
158
162
|
} else if (checkInputColumnUI(col, col.name,
|
|
159
163
|
[NOTATION.HELM], [], false)
|
|
@@ -163,18 +167,18 @@ async function onColInputChange(
|
|
|
163
167
|
gapExtendInput.value ??= msaDefaultOptions.pepsea.gapExtend;
|
|
164
168
|
|
|
165
169
|
return async () => await runPepsea(col, unusedName, methodInput.value!,
|
|
166
|
-
|
|
170
|
+
gapOpenInput.value!, gapExtendInput.value!, clustersColInput.value);
|
|
167
171
|
} else if (checkInputColumnUI(col, col.name, [NOTATION.SEPARATOR], [ALPHABET.UN], false)) {
|
|
168
172
|
//if the column is separator with unknown alphabet, it might be helm. check if it can be converted to helm
|
|
169
|
-
const
|
|
170
|
-
const helmCol =
|
|
173
|
+
const potentialColUH = UnitsHandler.getOrCreate(col);
|
|
174
|
+
const helmCol = potentialColUH.convert(NOTATION.HELM);
|
|
171
175
|
switchDialog(pepseaInputRootStyles, kalignInputRootStyles, 'pepsea');
|
|
172
176
|
gapOpenInput.value ??= msaDefaultOptions.pepsea.gapOpen;
|
|
173
177
|
gapExtendInput.value ??= msaDefaultOptions.pepsea.gapExtend;
|
|
174
178
|
// convert to helm and assign alignment function to PepSea
|
|
175
179
|
|
|
176
180
|
return async () => await runPepsea(helmCol, unusedName, methodInput.value!,
|
|
177
|
-
|
|
181
|
+
gapOpenInput.value!, gapExtendInput.value!, clustersColInput.value);
|
|
178
182
|
} else {
|
|
179
183
|
gapOpenInput.value = null;
|
|
180
184
|
gapExtendInput.value = null;
|
|
@@ -8,14 +8,15 @@ import {fromEvent, Observable, Subject, Unsubscribable} from 'rxjs';
|
|
|
8
8
|
import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
9
9
|
import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
|
|
10
10
|
import {
|
|
11
|
-
monomerToShort, pickUpPalette, pickUpSeqCol, TAGS as bioTAGS
|
|
11
|
+
monomerToShort, pickUpPalette, pickUpSeqCol, TAGS as bioTAGS, positionSeparator
|
|
12
12
|
} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
13
13
|
import {
|
|
14
|
-
FilterSources, HorizontalAlignments, IWebLogoViewer, PositionHeight, PositionMarginStates,
|
|
15
|
-
|
|
14
|
+
FilterSources, HorizontalAlignments, IWebLogoViewer, PositionHeight, PositionMarginStates,
|
|
15
|
+
VerticalAlignments, WebLogoProps, WebLogoPropsDefault
|
|
16
16
|
} from '@datagrok-libraries/bio/src/viewers/web-logo';
|
|
17
17
|
import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
|
|
18
18
|
import {intToHtmlA} from '@datagrok-libraries/utils/src/color';
|
|
19
|
+
import {TAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
19
20
|
import {ISeqSplitted} from '@datagrok-libraries/bio/src/utils/macromolecule/types';
|
|
20
21
|
|
|
21
22
|
import {_package} from '../package';
|
|
@@ -143,7 +144,7 @@ export class PositionInfo {
|
|
|
143
144
|
}
|
|
144
145
|
|
|
145
146
|
calcScreen(
|
|
146
|
-
posIdx: number, firstVisiblePosIdx: number,
|
|
147
|
+
isGap: (m: string) => boolean, posIdx: number, firstVisiblePosIdx: number,
|
|
147
148
|
absoluteMaxHeight: number, heightMode: PositionHeight, alphabetSizeLog: number,
|
|
148
149
|
positionWidthWithMargin: number, positionWidth: number, dpr: number, axisHeight: number
|
|
149
150
|
): void {
|
|
@@ -154,13 +155,13 @@ export class PositionInfo {
|
|
|
154
155
|
|
|
155
156
|
const entries = Object.entries(this._freqs)
|
|
156
157
|
.sort((a, b) => {
|
|
157
|
-
if (a[0]
|
|
158
|
+
if (!isGap(a[0]) && !isGap(b[0]))
|
|
158
159
|
return b[1].count - a[1].count;
|
|
159
|
-
else if (a[0]
|
|
160
|
+
else if (isGap(a[0]) && isGap(b[0]))
|
|
160
161
|
return 0;
|
|
161
|
-
else if (a[0]
|
|
162
|
+
else if (isGap(a[0]))
|
|
162
163
|
return -1;
|
|
163
|
-
else /* (b[0]
|
|
164
|
+
else /* (isGap(b[0])) */
|
|
164
165
|
return +1;
|
|
165
166
|
});
|
|
166
167
|
for (const entry of entries) {
|
|
@@ -176,10 +177,11 @@ export class PositionInfo {
|
|
|
176
177
|
}
|
|
177
178
|
|
|
178
179
|
render(g: CanvasRenderingContext2D,
|
|
180
|
+
isGap: (m: string) => boolean,
|
|
179
181
|
fontStyle: string, uppercaseLetterAscent: number, uppercaseLetterHeight: number, cp: SeqPalette
|
|
180
182
|
) {
|
|
181
183
|
for (const [monomer, pmInfo] of Object.entries(this._freqs)) {
|
|
182
|
-
if (monomer
|
|
184
|
+
if (!isGap(monomer)) {
|
|
183
185
|
const monomerTxt = monomerToShort(monomer, 5);
|
|
184
186
|
const b = pmInfo.bounds!;
|
|
185
187
|
const left = b.left;
|
|
@@ -415,21 +417,33 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
415
417
|
// -- Data --
|
|
416
418
|
|
|
417
419
|
setData(): void {
|
|
418
|
-
if (this.
|
|
419
|
-
|
|
420
|
-
this.viewed = false;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
this.updateSeqCol();
|
|
420
|
+
if (!this.setDataInProgress) this.setDataInProgress = true; else return;
|
|
421
|
+
_package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>.setData() `);
|
|
424
422
|
|
|
425
|
-
|
|
426
|
-
this.
|
|
427
|
-
|
|
428
|
-
|
|
423
|
+
this.viewPromise = this.viewPromise.then(async () => { // setData
|
|
424
|
+
if (this.viewed) {
|
|
425
|
+
await this.destroyView();
|
|
426
|
+
this.viewed = false;
|
|
427
|
+
}
|
|
428
|
+
}).then(async () => {
|
|
429
|
+
await this.detachPromise;
|
|
430
|
+
|
|
431
|
+
this.updateSeqCol();
|
|
432
|
+
}).then(async () => {
|
|
433
|
+
if (!this.viewed) {
|
|
434
|
+
await this.buildView();
|
|
435
|
+
this.viewed = true;
|
|
436
|
+
}
|
|
437
|
+
}).finally(() => {
|
|
438
|
+
this.setDataInProgress = false;
|
|
439
|
+
});
|
|
429
440
|
}
|
|
430
441
|
|
|
431
442
|
// -- View --
|
|
432
443
|
|
|
444
|
+
private viewPromise: Promise<void> = Promise.resolve();
|
|
445
|
+
private detachPromise: Promise<void> = Promise.resolve();
|
|
446
|
+
private setDataInProgress: boolean = false;
|
|
433
447
|
private viewSubs: Unsubscribable[] = [];
|
|
434
448
|
|
|
435
449
|
private async destroyView(): Promise<void> {
|
|
@@ -438,7 +452,6 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
438
452
|
|
|
439
453
|
const dataFrameTxt = `${this.dataFrame ? 'data' : 'null'}`;
|
|
440
454
|
_package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>.destroyView( dataFrame = ${dataFrameTxt} ) start`);
|
|
441
|
-
super.detach();
|
|
442
455
|
|
|
443
456
|
this.viewSubs.forEach((sub) => sub.unsubscribe());
|
|
444
457
|
this.host!.remove();
|
|
@@ -524,8 +537,6 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
524
537
|
}
|
|
525
538
|
if (this.seqCol) {
|
|
526
539
|
try {
|
|
527
|
-
const units: string = this.seqCol!.getTag(DG.TAGS.UNITS);
|
|
528
|
-
const separator: string = this.seqCol!.getTag(bioTAGS.separator);
|
|
529
540
|
this.unitsHandler = UnitsHandler.getOrCreate(this.seqCol);
|
|
530
541
|
|
|
531
542
|
this.cp = pickUpPalette(this.seqCol);
|
|
@@ -560,8 +571,8 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
560
571
|
}).reduce((max, l) => Math.max(max, l), 0);
|
|
561
572
|
|
|
562
573
|
/** positionNames and positionLabel can be set up through the column's tags only */
|
|
563
|
-
const positionNamesTxt = this.seqCol.getTag(
|
|
564
|
-
const positionLabelsTxt = this.seqCol.getTag(
|
|
574
|
+
const positionNamesTxt = this.seqCol.getTag(TAGS.positionNames);
|
|
575
|
+
const positionLabelsTxt = this.seqCol.getTag(TAGS.positionLabels);
|
|
565
576
|
this.positionNames = !!positionNamesTxt ? positionNamesTxt.split(positionSeparator).map((v) => v.trim()) :
|
|
566
577
|
[...Array(maxLength).keys()].map((jPos) => `${jPos + 1}`)/* fallback if tag is not provided */;
|
|
567
578
|
this.positionLabels = !!positionLabelsTxt ? positionLabelsTxt.split(positionSeparator).map((v) => v.trim()) :
|
|
@@ -810,10 +821,18 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
810
821
|
|
|
811
822
|
/** Remove all handlers when table is a detach */
|
|
812
823
|
public override async detach() {
|
|
813
|
-
if (this.
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
824
|
+
if (this.setDataInProgress) return;
|
|
825
|
+
_package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>.detach(), `);
|
|
826
|
+
|
|
827
|
+
const superDetach = super.detach.bind(this);
|
|
828
|
+
this.detachPromise = this.detachPromise.then(async () => { // detach
|
|
829
|
+
await this.viewPromise;
|
|
830
|
+
if (this.viewed) {
|
|
831
|
+
await this.destroyView();
|
|
832
|
+
this.viewed = false;
|
|
833
|
+
}
|
|
834
|
+
superDetach();
|
|
835
|
+
});
|
|
817
836
|
}
|
|
818
837
|
|
|
819
838
|
private _onSizeChanged: Subject<void> = new Subject<void>();
|
|
@@ -860,8 +879,10 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
860
879
|
/** Function for removing empty positions */
|
|
861
880
|
protected _removeEmptyPositions() {
|
|
862
881
|
if (this.skipEmptyPositions) {
|
|
863
|
-
this.positions = wu(this.positions)
|
|
864
|
-
|
|
882
|
+
this.positions = wu(this.positions).filter((pi) => {
|
|
883
|
+
const gapSymbol: string = this.unitsHandler!.defaultGapSymbol;
|
|
884
|
+
return !pi.hasMonomer(gapSymbol) || pi.getFreq(gapSymbol).count !== pi.rowCount;
|
|
885
|
+
}).toArray();
|
|
865
886
|
}
|
|
866
887
|
}
|
|
867
888
|
|
|
@@ -898,7 +919,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
898
919
|
if (dfFilter.get(rowI)) {
|
|
899
920
|
const seqMList: ISeqSplitted = splitted[rowI];
|
|
900
921
|
for (let jPos = 0; jPos < length; ++jPos) {
|
|
901
|
-
const m: string = seqMList[this.startPosition + jPos] ||
|
|
922
|
+
const m: string = seqMList[this.startPosition + jPos] || this.unitsHandler.defaultGapSymbol;
|
|
902
923
|
const pmInfo = this.positions[jPos].getFreq(m);
|
|
903
924
|
pmInfo.count++;
|
|
904
925
|
}
|
|
@@ -907,7 +928,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
907
928
|
|
|
908
929
|
//#region Polish freq counts
|
|
909
930
|
for (let jPos = 0; jPos < length; jPos++) {
|
|
910
|
-
// delete this.positions[jPos].freq[
|
|
931
|
+
// delete this.positions[jPos].freq[this.unitsHandler.defaultGapSymbol];
|
|
911
932
|
this.positions[jPos].calcHeights(this.positionHeight as PositionHeight);
|
|
912
933
|
}
|
|
913
934
|
//#endregion
|
|
@@ -927,7 +948,13 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
927
948
|
const alphabetSizeLog = Math.log2(alphabetSize);
|
|
928
949
|
|
|
929
950
|
for (let jPos = Math.floor(this.slider.min); jPos <= Math.floor(this.slider.max); ++jPos) {
|
|
930
|
-
|
|
951
|
+
if (!(jPos in this.positions)) {
|
|
952
|
+
console.warn(`Bio: WebLogoViewer<${this.viewerId}>.render.calculateLayoutInt() ` +
|
|
953
|
+
`this.positions.length = ${this.positions.length}, jPos = ${jPos}`);
|
|
954
|
+
continue;
|
|
955
|
+
}
|
|
956
|
+
this.positions[jPos].calcScreen((m) => { return this.unitsHandler!.isGap(m); },
|
|
957
|
+
jPos, this.slider.min, absoluteMaxHeight, this.positionHeight,
|
|
931
958
|
alphabetSizeLog, this._positionWidthWithMargin, this._positionWidth, dpr, positionLabelsHeight);
|
|
932
959
|
}
|
|
933
960
|
_package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>.render.calculateLayoutInt(), end `);
|
|
@@ -990,7 +1017,8 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
990
1017
|
const uppercaseLetterAscent = 0.25;
|
|
991
1018
|
const uppercaseLetterHeight = 12.2;
|
|
992
1019
|
for (let jPos = Math.floor(this.slider.min); jPos <= Math.floor(this.slider.max); jPos++) {
|
|
993
|
-
this.positions[jPos].render(g,
|
|
1020
|
+
this.positions[jPos].render(g, (m) => { return this.unitsHandler!.isGap(m); },
|
|
1021
|
+
fontStyle, uppercaseLetterAscent, uppercaseLetterHeight,
|
|
994
1022
|
/* this._positionWidthWithMargin, firstVisiblePosIdx,*/ this.cp);
|
|
995
1023
|
}
|
|
996
1024
|
|
|
@@ -1034,36 +1062,37 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
1034
1062
|
min: this.slider.min, max: this.slider.max,
|
|
1035
1063
|
maxRange: this.slider.maxRange
|
|
1036
1064
|
};
|
|
1037
|
-
_package.logger.debug(
|
|
1065
|
+
_package.logger.debug(
|
|
1066
|
+
`Bio: WebLogoViewer<${this.viewerId}>.sliderOnValuesChanged( ${JSON.stringify(val)} ), start`);
|
|
1038
1067
|
this.render(WlRenderLevel.Layout, 'sliderOnValuesChanged').then(() => {});
|
|
1039
1068
|
} catch (err: any) {
|
|
1040
1069
|
const errMsg = errorToConsole(err);
|
|
1041
|
-
_package.logger.error(
|
|
1070
|
+
_package.logger.error(`Bio: WebLogoViewer<${this.viewerId}>.sliderOnValuesChanged() error:\n` + errMsg);
|
|
1042
1071
|
//throw err; // Do not throw to prevent disabling event handler
|
|
1043
1072
|
}
|
|
1044
1073
|
}
|
|
1045
1074
|
|
|
1046
1075
|
private dataFrameFilterOnChanged(_value: any): void {
|
|
1047
|
-
_package.logger.debug(
|
|
1076
|
+
_package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>.dataFrameFilterChanged()`);
|
|
1048
1077
|
try {
|
|
1049
1078
|
this.updatePositions();
|
|
1050
1079
|
if (this.filterSource === FilterSources.Filtered)
|
|
1051
1080
|
this.render(WlRenderLevel.Freqs, 'dataFrameFilterOnChanged').then(() => {});
|
|
1052
1081
|
} catch (err: any) {
|
|
1053
1082
|
const errMsg = errorToConsole(err);
|
|
1054
|
-
_package.logger.error(
|
|
1083
|
+
_package.logger.error(`Bio: WebLogoViewer<${this.viewerId}>.dataFrameFilterOnChanged() error:\n` + errMsg);
|
|
1055
1084
|
//throw err; // Do not throw to prevent disabling event handler
|
|
1056
1085
|
}
|
|
1057
1086
|
}
|
|
1058
1087
|
|
|
1059
1088
|
private dataFrameSelectionOnChanged(_value: any): void {
|
|
1060
|
-
_package.logger.debug(
|
|
1089
|
+
_package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>.dataFrameSelectionOnChanged()`);
|
|
1061
1090
|
try {
|
|
1062
1091
|
if (this.filterSource === FilterSources.Selected)
|
|
1063
1092
|
this.render(WlRenderLevel.Freqs, 'dataFrameSelectionOnChanged').then(() => {});
|
|
1064
1093
|
} catch (err: any) {
|
|
1065
1094
|
const errMsg = errorToConsole(err);
|
|
1066
|
-
_package.logger.error(
|
|
1095
|
+
_package.logger.error(`Bio: WebLogoViewer<${this.viewerId}>.dataFrameSelectionOnChanged() error:\n` + errMsg);
|
|
1067
1096
|
//throw err; // Do not throw to prevent disabling event handler
|
|
1068
1097
|
}
|
|
1069
1098
|
}
|
|
@@ -1097,7 +1126,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
1097
1126
|
}
|
|
1098
1127
|
} catch (err: any) {
|
|
1099
1128
|
const errMsg = errorToConsole(err);
|
|
1100
|
-
_package.logger.error(
|
|
1129
|
+
_package.logger.error(`Bio: WebLogoViewer<${this.viewerId}>.canvasOnMouseMove() error:\n` + errMsg);
|
|
1101
1130
|
//throw err; // Do not throw to prevent disabling event handler
|
|
1102
1131
|
}
|
|
1103
1132
|
}
|
|
@@ -1120,7 +1149,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
1120
1149
|
}
|
|
1121
1150
|
} catch (err: any) {
|
|
1122
1151
|
const errMsg = errorToConsole(err);
|
|
1123
|
-
_package.logger.error(
|
|
1152
|
+
_package.logger.error(`Bio: WebLogoViewer<${this.viewerId}>.canvasOnMouseDown() error:\n` + errMsg);
|
|
1124
1153
|
//throw err; // Do not throw to prevent disabling event handler
|
|
1125
1154
|
}
|
|
1126
1155
|
}
|
|
@@ -1134,7 +1163,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
1134
1163
|
this.slider.scrollBy(this.slider.min + countOfScrollPositions);
|
|
1135
1164
|
} catch (err: any) {
|
|
1136
1165
|
const errMsg = errorToConsole(err);
|
|
1137
|
-
_package.logger.error(
|
|
1166
|
+
_package.logger.error(`Bio: WebLogoViewer<${this.viewerId}>.canvasOnWheel() error:\n` + errMsg);
|
|
1138
1167
|
//throw err; // Do not throw to prevent disabling event handler
|
|
1139
1168
|
}
|
|
1140
1169
|
}
|
|
@@ -1159,7 +1188,7 @@ export function checkSeqForMonomerAtPos(
|
|
|
1159
1188
|
): boolean {
|
|
1160
1189
|
const seqMList: ISeqSplitted = unitsHandler.splitted[rowI];
|
|
1161
1190
|
const seqM = at.pos < seqMList.length ? seqMList[at.pos] : null;
|
|
1162
|
-
return ((seqM === monomer) || (seqM === '' && monomer ===
|
|
1191
|
+
return ((seqM === monomer) || (seqM === '' && monomer === unitsHandler.defaultGapSymbol));
|
|
1163
1192
|
}
|
|
1164
1193
|
|
|
1165
1194
|
export function countForMonomerAtPosition(
|