@jbrowse/plugin-alignments 2.6.2 → 2.6.3

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.
@@ -0,0 +1,529 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.SharedLinearPileupDisplayMixin = void 0;
30
+ const react_1 = require("react");
31
+ const mobx_1 = require("mobx");
32
+ const mobx_state_tree_1 = require("mobx-state-tree");
33
+ const copy_to_clipboard_1 = __importDefault(require("copy-to-clipboard"));
34
+ const configuration_1 = require("@jbrowse/core/configuration");
35
+ const tracks_1 = require("@jbrowse/core/util/tracks");
36
+ const util_1 = require("@jbrowse/core/util");
37
+ const plugin_linear_genome_view_1 = require("@jbrowse/plugin-linear-genome-view");
38
+ // icons
39
+ const Icons_1 = require("@jbrowse/core/ui/Icons");
40
+ const MenuOpen_1 = __importDefault(require("@mui/icons-material/MenuOpen"));
41
+ const ClearAll_1 = __importDefault(require("@mui/icons-material/ClearAll"));
42
+ // locals
43
+ const LinearPileupDisplayBlurb_1 = __importDefault(require("./components/LinearPileupDisplayBlurb"));
44
+ const shared_1 = require("../shared");
45
+ const util_2 = require("../util");
46
+ const color_1 = require("../shared/color");
47
+ // async
48
+ const FilterByTagDlg = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('../shared/FilterByTag'))));
49
+ const ColorByTagDlg = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./components/ColorByTag'))));
50
+ const SetFeatureHeightDlg = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./components/SetFeatureHeight'))));
51
+ const SetMaxHeightDlg = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./components/SetMaxHeight'))));
52
+ // using a map because it preserves order
53
+ const rendererTypes = new Map([
54
+ ['pileup', 'PileupRenderer'],
55
+ ['svg', 'SvgFeatureRenderer'],
56
+ ]);
57
+ /**
58
+ * #stateModel SharedLinearPileupDisplayMixin
59
+ * #category display
60
+ * extends `BaseLinearDisplay`
61
+ */
62
+ function SharedLinearPileupDisplayMixin(configSchema) {
63
+ return mobx_state_tree_1.types
64
+ .compose(plugin_linear_genome_view_1.BaseLinearDisplay, mobx_state_tree_1.types.model({
65
+ /**
66
+ * #property
67
+ */
68
+ configuration: (0, configuration_1.ConfigurationReference)(configSchema),
69
+ /**
70
+ * #property
71
+ */
72
+ featureHeight: mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.number),
73
+ /**
74
+ * #property
75
+ */
76
+ noSpacing: mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.boolean),
77
+ /**
78
+ * #property
79
+ */
80
+ fadeLikelihood: mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.boolean),
81
+ /**
82
+ * #property
83
+ */
84
+ trackMaxHeight: mobx_state_tree_1.types.maybe(mobx_state_tree_1.types.number),
85
+ /**
86
+ * #property
87
+ */
88
+ colorBy: color_1.ColorByModel,
89
+ /**
90
+ * #property
91
+ */
92
+ filterBy: mobx_state_tree_1.types.optional(shared_1.FilterModel, {}),
93
+ }))
94
+ .volatile(() => ({
95
+ colorTagMap: mobx_1.observable.map({}),
96
+ featureUnderMouseVolatile: undefined,
97
+ tagsReady: false,
98
+ }))
99
+ .views(self => ({
100
+ get autorunReady() {
101
+ const view = (0, util_1.getContainingView)(self);
102
+ return (view.initialized &&
103
+ self.featureDensityStatsReady &&
104
+ !self.regionTooLarge);
105
+ },
106
+ }))
107
+ .actions(self => ({
108
+ /**
109
+ * #action
110
+ */
111
+ setTagsReady(flag) {
112
+ self.tagsReady = flag;
113
+ },
114
+ /**
115
+ * #action
116
+ */
117
+ setMaxHeight(n) {
118
+ self.trackMaxHeight = n;
119
+ },
120
+ /**
121
+ * #action
122
+ */
123
+ setFeatureHeight(n) {
124
+ self.featureHeight = n;
125
+ },
126
+ /**
127
+ * #action
128
+ */
129
+ setNoSpacing(flag) {
130
+ self.noSpacing = flag;
131
+ },
132
+ /**
133
+ * #action
134
+ */
135
+ setColorScheme(colorScheme) {
136
+ self.colorTagMap = mobx_1.observable.map({}); // clear existing mapping
137
+ self.colorBy = (0, mobx_state_tree_1.cast)(colorScheme);
138
+ if (colorScheme.tag) {
139
+ self.tagsReady = false;
140
+ }
141
+ },
142
+ /**
143
+ * #action
144
+ */
145
+ updateColorTagMap(uniqueTag) {
146
+ // pale color scheme
147
+ // https://cran.r-project.org/web/packages/khroma/vignettes/tol.html
148
+ // e.g. "tol_light"
149
+ const colorPalette = [
150
+ '#BBCCEE',
151
+ 'pink',
152
+ '#CCDDAA',
153
+ '#EEEEBB',
154
+ '#FFCCCC',
155
+ 'lightblue',
156
+ 'lightgreen',
157
+ 'tan',
158
+ '#CCEEFF',
159
+ 'lightsalmon',
160
+ ];
161
+ uniqueTag.forEach(value => {
162
+ if (!self.colorTagMap.has(value)) {
163
+ const totalKeys = [...self.colorTagMap.keys()].length;
164
+ self.colorTagMap.set(value, colorPalette[totalKeys]);
165
+ }
166
+ });
167
+ },
168
+ /**
169
+ * #action
170
+ */
171
+ setFeatureUnderMouse(feat) {
172
+ self.featureUnderMouseVolatile = feat;
173
+ },
174
+ /**
175
+ * #action
176
+ */
177
+ selectFeature(feature) {
178
+ const session = (0, util_1.getSession)(self);
179
+ if ((0, util_1.isSessionModelWithWidgets)(session)) {
180
+ const featureWidget = session.addWidget('AlignmentsFeatureWidget', 'alignmentFeature', { featureData: feature.toJSON(), view: (0, util_1.getContainingView)(self) });
181
+ session.showWidget(featureWidget);
182
+ }
183
+ session.setSelection(feature);
184
+ },
185
+ /**
186
+ * #action
187
+ * uses copy-to-clipboard and generates notification
188
+ */
189
+ copyFeatureToClipboard(feature) {
190
+ const { uniqueId, ...rest } = feature.toJSON();
191
+ const session = (0, util_1.getSession)(self);
192
+ (0, copy_to_clipboard_1.default)(JSON.stringify(rest, null, 4));
193
+ session.notify('Copied to clipboard', 'success');
194
+ },
195
+ /**
196
+ * #action
197
+ */
198
+ setConfig(conf) {
199
+ self.configuration = conf;
200
+ },
201
+ /**
202
+ * #action
203
+ */
204
+ setFilterBy(filter) {
205
+ self.filterBy = (0, mobx_state_tree_1.cast)(filter);
206
+ },
207
+ }))
208
+ .views(self => ({
209
+ /**
210
+ * #getter
211
+ */
212
+ get rendererConfig() {
213
+ const { featureHeight, noSpacing, trackMaxHeight, rendererTypeName } = self;
214
+ const configBlob = (0, configuration_1.getConf)(self, ['renderers', rendererTypeName]) || {};
215
+ return self.rendererType.configSchema.create({
216
+ ...configBlob,
217
+ ...(featureHeight !== undefined ? { height: featureHeight } : {}),
218
+ ...(noSpacing !== undefined ? { noSpacing } : {}),
219
+ ...(trackMaxHeight !== undefined
220
+ ? { maxHeight: trackMaxHeight }
221
+ : {}),
222
+ }, (0, util_1.getEnv)(self));
223
+ },
224
+ }))
225
+ .views(self => ({
226
+ /**
227
+ * #getter
228
+ */
229
+ get maxHeight() {
230
+ return (0, configuration_1.readConfObject)(self.rendererConfig, 'maxHeight');
231
+ },
232
+ /**
233
+ * #getter
234
+ */
235
+ get featureHeightSetting() {
236
+ return (0, configuration_1.readConfObject)(self.rendererConfig, 'height');
237
+ },
238
+ /**
239
+ * #getter
240
+ */
241
+ get featureUnderMouse() {
242
+ return self.featureUnderMouseVolatile;
243
+ },
244
+ /**
245
+ * #getter
246
+ */
247
+ renderReady() {
248
+ return self.tagsReady;
249
+ },
250
+ }))
251
+ .views(self => {
252
+ const { trackMenuItems: superTrackMenuItems, renderProps: superRenderProps, } = self;
253
+ return {
254
+ /**
255
+ * #getter
256
+ */
257
+ get rendererTypeName() {
258
+ const viewName = (0, configuration_1.getConf)(self, 'defaultRendering');
259
+ const rendererType = rendererTypes.get(viewName);
260
+ if (!rendererType) {
261
+ throw new Error(`unknown alignments view name ${viewName}`);
262
+ }
263
+ return rendererType;
264
+ },
265
+ /**
266
+ * #method
267
+ */
268
+ contextMenuItems() {
269
+ const feat = self.contextMenuFeature;
270
+ return feat
271
+ ? [
272
+ {
273
+ label: 'Open feature details',
274
+ icon: MenuOpen_1.default,
275
+ onClick: () => {
276
+ self.clearFeatureSelection();
277
+ if (feat) {
278
+ self.selectFeature(feat);
279
+ }
280
+ },
281
+ },
282
+ {
283
+ label: 'Copy info to clipboard',
284
+ icon: Icons_1.ContentCopy,
285
+ onClick: () => {
286
+ if (feat) {
287
+ self.copyFeatureToClipboard(feat);
288
+ }
289
+ },
290
+ },
291
+ ]
292
+ : [];
293
+ },
294
+ /**
295
+ * #getter
296
+ */
297
+ get DisplayBlurb() {
298
+ return LinearPileupDisplayBlurb_1.default;
299
+ },
300
+ /**
301
+ * #method
302
+ */
303
+ renderPropsPre() {
304
+ const { colorTagMap, colorBy, filterBy, rpcDriverName } = self;
305
+ const superProps = superRenderProps();
306
+ return {
307
+ ...superProps,
308
+ notReady: superProps.notReady || !self.renderReady(),
309
+ rpcDriverName,
310
+ displayModel: self,
311
+ colorBy: colorBy ? (0, mobx_state_tree_1.getSnapshot)(colorBy) : undefined,
312
+ filterBy: JSON.parse(JSON.stringify(filterBy)),
313
+ colorTagMap: Object.fromEntries(colorTagMap.toJSON()),
314
+ config: self.rendererConfig,
315
+ async onFeatureClick(_, featureId) {
316
+ const session = (0, util_1.getSession)(self);
317
+ const { rpcManager } = session;
318
+ try {
319
+ const f = featureId || self.featureIdUnderMouse;
320
+ if (!f) {
321
+ self.clearFeatureSelection();
322
+ }
323
+ else {
324
+ const sessionId = (0, tracks_1.getRpcSessionId)(self);
325
+ const { feature } = (await rpcManager.call(sessionId, 'CoreGetFeatureDetails', {
326
+ featureId: f,
327
+ sessionId,
328
+ layoutId: (0, util_1.getContainingView)(self).id,
329
+ rendererType: 'PileupRenderer',
330
+ }));
331
+ if (feature) {
332
+ self.selectFeature(new util_1.SimpleFeature(feature));
333
+ }
334
+ }
335
+ }
336
+ catch (e) {
337
+ console.error(e);
338
+ session.notify(`${e}`);
339
+ }
340
+ },
341
+ onClick() {
342
+ self.clearFeatureSelection();
343
+ },
344
+ // similar to click but opens a menu with further options
345
+ async onFeatureContextMenu(_, featureId) {
346
+ const session = (0, util_1.getSession)(self);
347
+ const { rpcManager } = session;
348
+ try {
349
+ const f = featureId || self.featureIdUnderMouse;
350
+ if (!f) {
351
+ self.clearFeatureSelection();
352
+ }
353
+ else {
354
+ const sessionId = (0, tracks_1.getRpcSessionId)(self);
355
+ const { feature } = (await rpcManager.call(sessionId, 'CoreGetFeatureDetails', {
356
+ featureId: f,
357
+ sessionId,
358
+ layoutId: (0, util_1.getContainingView)(self).id,
359
+ rendererType: 'PileupRenderer',
360
+ }));
361
+ if (feature) {
362
+ self.setContextMenuFeature(new util_1.SimpleFeature(feature));
363
+ }
364
+ }
365
+ }
366
+ catch (e) {
367
+ console.error(e);
368
+ session.notify(`${e}`);
369
+ }
370
+ },
371
+ };
372
+ },
373
+ /**
374
+ * #method
375
+ */
376
+ colorSchemeSubMenuItems() {
377
+ return [
378
+ {
379
+ label: 'Normal',
380
+ onClick: () => self.setColorScheme({ type: 'normal' }),
381
+ },
382
+ {
383
+ label: 'Mapping quality',
384
+ onClick: () => self.setColorScheme({ type: 'mappingQuality' }),
385
+ },
386
+ {
387
+ label: 'Strand',
388
+ onClick: () => self.setColorScheme({ type: 'strand' }),
389
+ },
390
+ {
391
+ label: 'Per-base quality',
392
+ onClick: () => self.setColorScheme({ type: 'perBaseQuality' }),
393
+ },
394
+ {
395
+ label: 'Per-base lettering',
396
+ onClick: () => self.setColorScheme({ type: 'perBaseLettering' }),
397
+ },
398
+ {
399
+ label: 'First-of-pair strand',
400
+ onClick: () => self.setColorScheme({ type: 'stranded' }),
401
+ },
402
+ {
403
+ label: 'Color by tag...',
404
+ onClick: () => {
405
+ (0, util_1.getSession)(self).queueDialog(doneCallback => [
406
+ ColorByTagDlg,
407
+ { model: self, handleClose: doneCallback },
408
+ ]);
409
+ },
410
+ },
411
+ ];
412
+ },
413
+ /**
414
+ * #method
415
+ */
416
+ trackMenuItems() {
417
+ return [
418
+ ...superTrackMenuItems(),
419
+ {
420
+ label: 'Filter by',
421
+ icon: ClearAll_1.default,
422
+ onClick: () => {
423
+ (0, util_1.getSession)(self).queueDialog(doneCallback => [
424
+ FilterByTagDlg,
425
+ { model: self, handleClose: doneCallback },
426
+ ]);
427
+ },
428
+ },
429
+ {
430
+ label: 'Set feature height',
431
+ subMenu: [
432
+ {
433
+ label: 'Normal',
434
+ onClick: () => {
435
+ self.setFeatureHeight(7);
436
+ self.setNoSpacing(false);
437
+ },
438
+ },
439
+ {
440
+ label: 'Compact',
441
+ onClick: () => {
442
+ self.setFeatureHeight(2);
443
+ self.setNoSpacing(true);
444
+ },
445
+ },
446
+ {
447
+ label: 'Manually set height',
448
+ onClick: () => {
449
+ (0, util_1.getSession)(self).queueDialog(doneCallback => [
450
+ SetFeatureHeightDlg,
451
+ { model: self, handleClose: doneCallback },
452
+ ]);
453
+ },
454
+ },
455
+ ],
456
+ },
457
+ {
458
+ label: 'Set max height...',
459
+ onClick: () => {
460
+ (0, util_1.getSession)(self).queueDialog(doneCallback => [
461
+ SetMaxHeightDlg,
462
+ { model: self, handleClose: doneCallback },
463
+ ]);
464
+ },
465
+ },
466
+ ];
467
+ },
468
+ };
469
+ })
470
+ .views(self => ({
471
+ renderProps() {
472
+ return self.renderPropsPre();
473
+ },
474
+ }))
475
+ .actions(self => ({
476
+ afterAttach() {
477
+ (0, util_2.createAutorun)(self, async () => {
478
+ const view = (0, util_1.getContainingView)(self);
479
+ if (!self.autorunReady) {
480
+ return;
481
+ }
482
+ const { colorBy } = self;
483
+ const { staticBlocks } = view;
484
+ if (colorBy === null || colorBy === void 0 ? void 0 : colorBy.tag) {
485
+ const vals = await (0, shared_1.getUniqueTagValues)(self, colorBy, staticBlocks);
486
+ self.updateColorTagMap(vals);
487
+ }
488
+ self.setTagsReady(true);
489
+ }, { delay: 1000 });
490
+ // autorun synchronizes featureUnderMouse with featureIdUnderMouse
491
+ // asynchronously. this is needed due to how we do not serialize all
492
+ // features from the BAM/CRAM over the rpc
493
+ (0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(async () => {
494
+ var _a;
495
+ const session = (0, util_1.getSession)(self);
496
+ try {
497
+ const featureId = self.featureIdUnderMouse;
498
+ if (((_a = self.featureUnderMouse) === null || _a === void 0 ? void 0 : _a.id()) !== featureId) {
499
+ if (!featureId) {
500
+ self.setFeatureUnderMouse(undefined);
501
+ }
502
+ else {
503
+ const sessionId = (0, tracks_1.getRpcSessionId)(self);
504
+ const view = (0, util_1.getContainingView)(self);
505
+ const { feature } = (await session.rpcManager.call(sessionId, 'CoreGetFeatureDetails', {
506
+ featureId,
507
+ sessionId,
508
+ layoutId: view.id,
509
+ rendererType: 'PileupRenderer',
510
+ }));
511
+ // check featureIdUnderMouse is still the same as the
512
+ // feature.id that was returned e.g. that the user hasn't
513
+ // moused over to a new position during the async operation
514
+ // above
515
+ if (self.featureIdUnderMouse === feature.uniqueId) {
516
+ self.setFeatureUnderMouse(new util_1.SimpleFeature(feature));
517
+ }
518
+ }
519
+ }
520
+ }
521
+ catch (e) {
522
+ console.error(e);
523
+ session.notify(`${e}`, 'error');
524
+ }
525
+ }));
526
+ },
527
+ }));
528
+ }
529
+ exports.SharedLinearPileupDisplayMixin = SharedLinearPileupDisplayMixin;
@@ -2,3 +2,4 @@ import PluginManager from '@jbrowse/core/PluginManager';
2
2
  export default function register(pluginManager: PluginManager): void;
3
3
  export { default as linearPileupDisplayStateModelFactory } from './model';
4
4
  export { default as linearPileupDisplayConfigSchemaFactory } from './configSchema';
5
+ export { SharedLinearPileupDisplayMixin } from './SharedLinearPileupDisplayMixin';
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.linearPileupDisplayConfigSchemaFactory = exports.linearPileupDisplayStateModelFactory = void 0;
6
+ exports.SharedLinearPileupDisplayMixin = exports.linearPileupDisplayConfigSchemaFactory = exports.linearPileupDisplayStateModelFactory = void 0;
7
7
  const configSchema_1 = __importDefault(require("./configSchema"));
8
8
  const model_1 = __importDefault(require("./model"));
9
9
  const DisplayType_1 = __importDefault(require("@jbrowse/core/pluggableElementTypes/DisplayType"));
@@ -28,3 +28,5 @@ var model_2 = require("./model");
28
28
  Object.defineProperty(exports, "linearPileupDisplayStateModelFactory", { enumerable: true, get: function () { return __importDefault(model_2).default; } });
29
29
  var configSchema_2 = require("./configSchema");
30
30
  Object.defineProperty(exports, "linearPileupDisplayConfigSchemaFactory", { enumerable: true, get: function () { return __importDefault(configSchema_2).default; } });
31
+ var SharedLinearPileupDisplayMixin_1 = require("./SharedLinearPileupDisplayMixin");
32
+ Object.defineProperty(exports, "SharedLinearPileupDisplayMixin", { enumerable: true, get: function () { return SharedLinearPileupDisplayMixin_1.SharedLinearPileupDisplayMixin; } });