@jbrowse/plugin-alignments 2.1.7 → 2.2.1

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.
Files changed (226) hide show
  1. package/dist/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js +12 -13
  2. package/dist/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js.map +1 -1
  3. package/dist/AlignmentsTrack/index.d.ts +1 -1
  4. package/dist/AlignmentsTrack/index.js +16 -6
  5. package/dist/AlignmentsTrack/index.js.map +1 -1
  6. package/dist/BamAdapter/BamAdapter.d.ts +7 -3
  7. package/dist/BamAdapter/BamAdapter.js +36 -31
  8. package/dist/BamAdapter/BamAdapter.js.map +1 -1
  9. package/dist/BamAdapter/BamSlightlyLazyFeature.js +1 -0
  10. package/dist/BamAdapter/BamSlightlyLazyFeature.js.map +1 -1
  11. package/dist/BamAdapter/MismatchParser.d.ts +2 -2
  12. package/dist/BamAdapter/MismatchParser.js +4 -7
  13. package/dist/BamAdapter/MismatchParser.js.map +1 -1
  14. package/dist/BamAdapter/configSchema.d.ts +2 -2
  15. package/dist/BamAdapter/configSchema.js +27 -2
  16. package/dist/BamAdapter/configSchema.js.map +1 -1
  17. package/dist/BamAdapter/index.js +7 -5
  18. package/dist/BamAdapter/index.js.map +1 -1
  19. package/dist/CramAdapter/CramAdapter.d.ts +13 -7
  20. package/dist/CramAdapter/CramAdapter.js +56 -61
  21. package/dist/CramAdapter/CramAdapter.js.map +1 -1
  22. package/dist/CramAdapter/CramSlightlyLazyFeature.d.ts +15 -23
  23. package/dist/CramAdapter/CramSlightlyLazyFeature.js +10 -217
  24. package/dist/CramAdapter/CramSlightlyLazyFeature.js.map +1 -1
  25. package/dist/CramAdapter/CramTestAdapters.d.ts +1 -1
  26. package/dist/CramAdapter/CramTestAdapters.js +1 -1
  27. package/dist/CramAdapter/CramTestAdapters.js.map +1 -1
  28. package/dist/CramAdapter/configSchema.d.ts +2 -3
  29. package/dist/CramAdapter/configSchema.js +44 -22
  30. package/dist/CramAdapter/configSchema.js.map +1 -1
  31. package/dist/CramAdapter/index.js +7 -5
  32. package/dist/CramAdapter/index.js.map +1 -1
  33. package/dist/CramAdapter/util.d.ts +18 -0
  34. package/dist/CramAdapter/util.js +241 -0
  35. package/dist/CramAdapter/util.js.map +1 -0
  36. package/dist/HtsgetBamAdapter/HtsgetBamAdapter.d.ts +5 -2
  37. package/dist/HtsgetBamAdapter/HtsgetBamAdapter.js +15 -20
  38. package/dist/HtsgetBamAdapter/HtsgetBamAdapter.js.map +1 -1
  39. package/dist/HtsgetBamAdapter/configSchema.d.ts +2 -2
  40. package/dist/HtsgetBamAdapter/configSchema.js +20 -3
  41. package/dist/HtsgetBamAdapter/configSchema.js.map +1 -1
  42. package/dist/LinearAlignmentsDisplay/components/AlignmentsDisplay.js +1 -1
  43. package/dist/LinearAlignmentsDisplay/components/AlignmentsDisplay.js.map +1 -1
  44. package/dist/LinearAlignmentsDisplay/models/configSchema.d.ts +2 -2
  45. package/dist/LinearAlignmentsDisplay/models/configSchema.js +23 -6
  46. package/dist/LinearAlignmentsDisplay/models/configSchema.js.map +1 -1
  47. package/dist/LinearAlignmentsDisplay/models/model.d.ts +77 -10
  48. package/dist/LinearAlignmentsDisplay/models/model.js +102 -9
  49. package/dist/LinearAlignmentsDisplay/models/model.js.map +1 -1
  50. package/dist/LinearPileupDisplay/configSchema.d.ts +4 -4
  51. package/dist/LinearPileupDisplay/configSchema.js +22 -5
  52. package/dist/LinearPileupDisplay/configSchema.js.map +1 -1
  53. package/dist/LinearPileupDisplay/index.d.ts +3 -0
  54. package/dist/LinearPileupDisplay/index.js +3 -0
  55. package/dist/LinearPileupDisplay/index.js.map +1 -1
  56. package/dist/LinearPileupDisplay/model.d.ts +100 -6
  57. package/dist/LinearPileupDisplay/model.js +611 -503
  58. package/dist/LinearPileupDisplay/model.js.map +1 -1
  59. package/dist/LinearSNPCoverageDisplay/components/Tooltip.d.ts +1 -1
  60. package/dist/LinearSNPCoverageDisplay/models/configSchema.js +33 -4
  61. package/dist/LinearSNPCoverageDisplay/models/configSchema.js.map +1 -1
  62. package/dist/LinearSNPCoverageDisplay/models/model.d.ts +87 -4
  63. package/dist/LinearSNPCoverageDisplay/models/model.js +240 -159
  64. package/dist/LinearSNPCoverageDisplay/models/model.js.map +1 -1
  65. package/dist/PileupRPC/rpcMethods.d.ts +1 -1
  66. package/dist/PileupRPC/rpcMethods.js +12 -7
  67. package/dist/PileupRPC/rpcMethods.js.map +1 -1
  68. package/dist/PileupRenderer/PileupLayoutSession.d.ts +1 -1
  69. package/dist/PileupRenderer/PileupRenderer.d.ts +1 -1
  70. package/dist/PileupRenderer/PileupRenderer.js +37 -34
  71. package/dist/PileupRenderer/PileupRenderer.js.map +1 -1
  72. package/dist/PileupRenderer/configSchema.d.ts +2 -2
  73. package/dist/PileupRenderer/configSchema.js +37 -2
  74. package/dist/PileupRenderer/configSchema.js.map +1 -1
  75. package/dist/PileupRenderer/index.js +8 -6
  76. package/dist/PileupRenderer/index.js.map +1 -1
  77. package/dist/SNPCoverageAdapter/configSchema.d.ts +2 -3
  78. package/dist/SNPCoverageAdapter/configSchema.js +15 -4
  79. package/dist/SNPCoverageAdapter/configSchema.js.map +1 -1
  80. package/dist/SNPCoverageAdapter/index.d.ts +1 -2
  81. package/dist/SNPCoverageAdapter/index.js +17 -14
  82. package/dist/SNPCoverageAdapter/index.js.map +1 -1
  83. package/dist/SNPCoverageRenderer/configSchema.d.ts +2 -2
  84. package/dist/SNPCoverageRenderer/configSchema.js +21 -1
  85. package/dist/SNPCoverageRenderer/configSchema.js.map +1 -1
  86. package/dist/SNPCoverageRenderer/index.d.ts +0 -1
  87. package/dist/SNPCoverageRenderer/index.js +1 -4
  88. package/dist/SNPCoverageRenderer/index.js.map +1 -1
  89. package/dist/index.d.ts +3 -2
  90. package/dist/index.js +4 -2
  91. package/dist/index.js.map +1 -1
  92. package/esm/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js +12 -13
  93. package/esm/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js.map +1 -1
  94. package/esm/AlignmentsTrack/index.d.ts +1 -1
  95. package/esm/AlignmentsTrack/index.js +16 -6
  96. package/esm/AlignmentsTrack/index.js.map +1 -1
  97. package/esm/BamAdapter/BamAdapter.d.ts +7 -3
  98. package/esm/BamAdapter/BamAdapter.js +36 -31
  99. package/esm/BamAdapter/BamAdapter.js.map +1 -1
  100. package/esm/BamAdapter/BamSlightlyLazyFeature.js +1 -0
  101. package/esm/BamAdapter/BamSlightlyLazyFeature.js.map +1 -1
  102. package/esm/BamAdapter/MismatchParser.d.ts +2 -2
  103. package/esm/BamAdapter/MismatchParser.js +4 -7
  104. package/esm/BamAdapter/MismatchParser.js.map +1 -1
  105. package/esm/BamAdapter/configSchema.d.ts +2 -2
  106. package/esm/BamAdapter/configSchema.js +27 -2
  107. package/esm/BamAdapter/configSchema.js.map +1 -1
  108. package/esm/BamAdapter/index.js +7 -5
  109. package/esm/BamAdapter/index.js.map +1 -1
  110. package/esm/CramAdapter/CramAdapter.d.ts +13 -7
  111. package/esm/CramAdapter/CramAdapter.js +56 -61
  112. package/esm/CramAdapter/CramAdapter.js.map +1 -1
  113. package/esm/CramAdapter/CramSlightlyLazyFeature.d.ts +15 -23
  114. package/esm/CramAdapter/CramSlightlyLazyFeature.js +10 -217
  115. package/esm/CramAdapter/CramSlightlyLazyFeature.js.map +1 -1
  116. package/esm/CramAdapter/CramTestAdapters.d.ts +1 -1
  117. package/esm/CramAdapter/CramTestAdapters.js +1 -1
  118. package/esm/CramAdapter/CramTestAdapters.js.map +1 -1
  119. package/esm/CramAdapter/configSchema.d.ts +2 -3
  120. package/esm/CramAdapter/configSchema.js +44 -22
  121. package/esm/CramAdapter/configSchema.js.map +1 -1
  122. package/esm/CramAdapter/index.js +8 -6
  123. package/esm/CramAdapter/index.js.map +1 -1
  124. package/esm/CramAdapter/util.d.ts +18 -0
  125. package/esm/CramAdapter/util.js +236 -0
  126. package/esm/CramAdapter/util.js.map +1 -0
  127. package/esm/HtsgetBamAdapter/HtsgetBamAdapter.d.ts +5 -2
  128. package/esm/HtsgetBamAdapter/HtsgetBamAdapter.js +15 -20
  129. package/esm/HtsgetBamAdapter/HtsgetBamAdapter.js.map +1 -1
  130. package/esm/HtsgetBamAdapter/configSchema.d.ts +2 -2
  131. package/esm/HtsgetBamAdapter/configSchema.js +20 -3
  132. package/esm/HtsgetBamAdapter/configSchema.js.map +1 -1
  133. package/esm/LinearAlignmentsDisplay/components/AlignmentsDisplay.js +1 -1
  134. package/esm/LinearAlignmentsDisplay/components/AlignmentsDisplay.js.map +1 -1
  135. package/esm/LinearAlignmentsDisplay/models/configSchema.d.ts +2 -2
  136. package/esm/LinearAlignmentsDisplay/models/configSchema.js +23 -6
  137. package/esm/LinearAlignmentsDisplay/models/configSchema.js.map +1 -1
  138. package/esm/LinearAlignmentsDisplay/models/model.d.ts +77 -10
  139. package/esm/LinearAlignmentsDisplay/models/model.js +102 -9
  140. package/esm/LinearAlignmentsDisplay/models/model.js.map +1 -1
  141. package/esm/LinearPileupDisplay/configSchema.d.ts +4 -4
  142. package/esm/LinearPileupDisplay/configSchema.js +22 -5
  143. package/esm/LinearPileupDisplay/configSchema.js.map +1 -1
  144. package/esm/LinearPileupDisplay/index.d.ts +3 -0
  145. package/esm/LinearPileupDisplay/index.js +1 -0
  146. package/esm/LinearPileupDisplay/index.js.map +1 -1
  147. package/esm/LinearPileupDisplay/model.d.ts +100 -6
  148. package/esm/LinearPileupDisplay/model.js +611 -503
  149. package/esm/LinearPileupDisplay/model.js.map +1 -1
  150. package/esm/LinearSNPCoverageDisplay/components/Tooltip.d.ts +1 -1
  151. package/esm/LinearSNPCoverageDisplay/models/configSchema.js +33 -4
  152. package/esm/LinearSNPCoverageDisplay/models/configSchema.js.map +1 -1
  153. package/esm/LinearSNPCoverageDisplay/models/model.d.ts +87 -4
  154. package/esm/LinearSNPCoverageDisplay/models/model.js +240 -159
  155. package/esm/LinearSNPCoverageDisplay/models/model.js.map +1 -1
  156. package/esm/PileupRPC/rpcMethods.d.ts +1 -1
  157. package/esm/PileupRPC/rpcMethods.js +12 -7
  158. package/esm/PileupRPC/rpcMethods.js.map +1 -1
  159. package/esm/PileupRenderer/PileupLayoutSession.d.ts +1 -1
  160. package/esm/PileupRenderer/PileupRenderer.d.ts +1 -1
  161. package/esm/PileupRenderer/PileupRenderer.js +37 -34
  162. package/esm/PileupRenderer/PileupRenderer.js.map +1 -1
  163. package/esm/PileupRenderer/configSchema.d.ts +2 -2
  164. package/esm/PileupRenderer/configSchema.js +37 -2
  165. package/esm/PileupRenderer/configSchema.js.map +1 -1
  166. package/esm/PileupRenderer/index.js +8 -6
  167. package/esm/PileupRenderer/index.js.map +1 -1
  168. package/esm/SNPCoverageAdapter/configSchema.d.ts +2 -3
  169. package/esm/SNPCoverageAdapter/configSchema.js +15 -4
  170. package/esm/SNPCoverageAdapter/configSchema.js.map +1 -1
  171. package/esm/SNPCoverageAdapter/index.d.ts +1 -2
  172. package/esm/SNPCoverageAdapter/index.js +17 -15
  173. package/esm/SNPCoverageAdapter/index.js.map +1 -1
  174. package/esm/SNPCoverageRenderer/configSchema.d.ts +2 -2
  175. package/esm/SNPCoverageRenderer/configSchema.js +21 -1
  176. package/esm/SNPCoverageRenderer/configSchema.js.map +1 -1
  177. package/esm/SNPCoverageRenderer/index.d.ts +0 -1
  178. package/esm/SNPCoverageRenderer/index.js +1 -3
  179. package/esm/SNPCoverageRenderer/index.js.map +1 -1
  180. package/esm/index.d.ts +3 -2
  181. package/esm/index.js +2 -2
  182. package/esm/index.js.map +1 -1
  183. package/package.json +4 -3
  184. package/src/AlignmentsFeatureDetail/AlignmentsFeatureDetail.tsx +17 -16
  185. package/src/AlignmentsFeatureDetail/__snapshots__/index.test.js.snap +41 -513
  186. package/src/AlignmentsFeatureDetail/index.test.js +6 -4
  187. package/src/AlignmentsTrack/index.ts +18 -12
  188. package/src/BamAdapter/BamAdapter.ts +42 -41
  189. package/src/BamAdapter/BamSlightlyLazyFeature.ts +2 -1
  190. package/src/BamAdapter/MismatchParser.test.ts +21 -12
  191. package/src/BamAdapter/MismatchParser.ts +7 -10
  192. package/src/BamAdapter/__snapshots__/BamAdapter.test.ts.snap +135 -135
  193. package/src/BamAdapter/configSchema.ts +57 -29
  194. package/src/BamAdapter/index.ts +7 -8
  195. package/src/CombinationTest.test.ts +107 -0
  196. package/src/CramAdapter/CramAdapter.test.ts +1 -2
  197. package/src/CramAdapter/CramAdapter.ts +83 -84
  198. package/src/CramAdapter/CramSlightlyLazyFeature.ts +18 -218
  199. package/src/CramAdapter/CramTestAdapters.ts +1 -1
  200. package/src/CramAdapter/__snapshots__/CramAdapter.test.ts.snap +31 -31
  201. package/src/CramAdapter/__snapshots__/util.test.ts.snap +14 -0
  202. package/src/CramAdapter/configSchema.ts +54 -30
  203. package/src/CramAdapter/index.ts +8 -9
  204. package/src/CramAdapter/util.test.ts +26 -0
  205. package/src/CramAdapter/util.ts +251 -0
  206. package/src/HtsgetBamAdapter/HtsgetBamAdapter.ts +14 -21
  207. package/src/HtsgetBamAdapter/configSchema.ts +36 -19
  208. package/src/LinearAlignmentsDisplay/components/AlignmentsDisplay.tsx +3 -1
  209. package/src/LinearAlignmentsDisplay/models/configSchema.ts +23 -10
  210. package/src/LinearAlignmentsDisplay/models/model.tsx +107 -11
  211. package/src/LinearPileupDisplay/configSchema.ts +25 -9
  212. package/src/LinearPileupDisplay/index.ts +5 -0
  213. package/src/LinearPileupDisplay/model.ts +151 -34
  214. package/src/LinearSNPCoverageDisplay/models/configSchema.ts +36 -9
  215. package/src/LinearSNPCoverageDisplay/models/model.ts +83 -4
  216. package/src/PileupRPC/rpcMethods.ts +15 -20
  217. package/src/PileupRenderer/{PileupRenderer.tsx → PileupRenderer.ts} +53 -63
  218. package/src/PileupRenderer/configSchema.ts +39 -2
  219. package/src/PileupRenderer/index.ts +8 -9
  220. package/src/SNPCoverageAdapter/configSchema.ts +21 -12
  221. package/src/SNPCoverageAdapter/index.ts +17 -18
  222. package/src/SNPCoverageRenderer/configSchema.ts +23 -1
  223. package/src/SNPCoverageRenderer/index.ts +1 -8
  224. package/src/__snapshots__/index.test.ts.snap +1 -1
  225. package/src/index.ts +11 -4
  226. package/src/declare.d.ts +0 -1
@@ -27,548 +27,656 @@ const rendererTypes = new Map([
27
27
  ['pileup', 'PileupRenderer'],
28
28
  ['svg', 'SvgFeatureRenderer'],
29
29
  ]);
30
- const stateModelFactory = (configSchema) => types
31
- .compose('LinearPileupDisplay', BaseLinearDisplay, types.model({
32
- type: types.literal('LinearPileupDisplay'),
33
- configuration: ConfigurationReference(configSchema),
34
- showSoftClipping: false,
35
- featureHeight: types.maybe(types.number),
36
- noSpacing: types.maybe(types.boolean),
37
- fadeLikelihood: types.maybe(types.boolean),
38
- trackMaxHeight: types.maybe(types.number),
39
- mismatchAlpha: types.maybe(types.boolean),
40
- sortedBy: types.maybe(types.model({
41
- type: types.string,
42
- pos: types.number,
43
- tag: types.maybe(types.string),
44
- refName: types.string,
45
- assemblyName: types.string,
46
- })),
47
- colorBy: types.maybe(types.model({
48
- type: types.string,
49
- tag: types.maybe(types.string),
50
- extra: types.frozen(),
51
- })),
52
- filterBy: types.optional(types.model({
53
- flagInclude: types.optional(types.number, 0),
54
- flagExclude: types.optional(types.number, 1540),
55
- readName: types.maybe(types.string),
56
- tagFilter: types.maybe(types.model({ tag: types.string, value: types.string })),
57
- }), {}),
58
- }))
59
- .volatile(() => ({
60
- colorTagMap: observable.map({}),
61
- modificationTagMap: observable.map({}),
62
- featureUnderMouseVolatile: undefined,
63
- ready: false,
64
- }))
65
- .actions(self => ({
66
- setReady(flag) {
67
- self.ready = flag;
68
- },
69
- setMaxHeight(n) {
70
- self.trackMaxHeight = n;
71
- },
72
- setFeatureHeight(n) {
73
- self.featureHeight = n;
74
- },
75
- setNoSpacing(flag) {
76
- self.noSpacing = flag;
77
- },
78
- setColorScheme(colorScheme) {
79
- self.colorTagMap = observable.map({}); // clear existing mapping
80
- self.colorBy = cast(colorScheme);
81
- self.ready = false;
82
- },
83
- updateModificationColorMap(uniqueModifications) {
84
- const colorPalette = ['red', 'blue', 'green', 'orange', 'purple'];
85
- uniqueModifications.forEach(value => {
86
- if (!self.modificationTagMap.has(value)) {
87
- const totalKeys = [...self.modificationTagMap.keys()].length;
88
- const newColor = colorPalette[totalKeys];
89
- self.modificationTagMap.set(value, newColor);
90
- }
91
- });
92
- },
93
- updateColorTagMap(uniqueTag) {
94
- // pale color scheme
95
- // https://cran.r-project.org/web/packages/khroma/vignettes/tol.html
96
- // e.g. "tol_light"
97
- const colorPalette = [
98
- '#BBCCEE',
99
- 'pink',
100
- '#CCDDAA',
101
- '#EEEEBB',
102
- '#FFCCCC',
103
- 'lightblue',
104
- 'lightgreen',
105
- 'tan',
106
- '#CCEEFF',
107
- 'lightsalmon',
108
- ];
109
- uniqueTag.forEach(value => {
110
- if (!self.colorTagMap.has(value)) {
111
- const totalKeys = [...self.colorTagMap.keys()].length;
112
- const newColor = colorPalette[totalKeys];
113
- self.colorTagMap.set(value, newColor);
114
- }
115
- });
116
- },
117
- setFeatureUnderMouse(feat) {
118
- self.featureUnderMouseVolatile = feat;
119
- },
120
- }))
121
- .actions(self => ({
122
- afterAttach() {
123
- addDisposer(self, autorun(async () => {
124
- try {
125
- const { rpcManager } = getSession(self);
126
- const view = getContainingView(self);
127
- const { sortedBy, colorBy, parentTrack, adapterConfig, rendererType, } = self;
128
- if (!view.initialized ||
129
- !self.estimatedStatsReady ||
130
- self.regionTooLarge) {
131
- return;
132
- }
133
- const { staticBlocks, bpPerPx } = view;
134
- // continually generate the vc pairing, set and rerender if any
135
- // new values seen
136
- if (colorBy === null || colorBy === void 0 ? void 0 : colorBy.tag) {
137
- self.updateColorTagMap(await getUniqueTagValues(self, colorBy, staticBlocks));
138
- }
139
- if ((colorBy === null || colorBy === void 0 ? void 0 : colorBy.type) === 'modifications') {
140
- const adapter = getConf(parentTrack, ['adapter']);
141
- self.updateModificationColorMap(await getUniqueModificationValues(self, adapter, colorBy, staticBlocks));
142
- }
143
- if (sortedBy) {
144
- const { pos, refName, assemblyName } = sortedBy;
145
- // render just the sorted region first
146
- // @ts-ignore
147
- await self.rendererType.renderInClient(rpcManager, {
148
- assemblyName,
149
- regions: [
150
- {
151
- start: pos,
152
- end: pos + 1,
153
- refName,
154
- assemblyName,
155
- },
156
- ],
157
- adapterConfig: adapterConfig,
158
- rendererType: rendererType.name,
159
- sessionId: getRpcSessionId(self),
160
- layoutId: view.id,
161
- timeout: 1000000,
162
- ...self.renderProps(),
163
- });
164
- self.setReady(true);
165
- self.setCurrBpPerPx(bpPerPx);
30
+ /**
31
+ * #stateModel LinearPileupDisplay
32
+ * extends `BaseLinearDisplay`
33
+ */
34
+ function stateModelFactory(configSchema) {
35
+ return types
36
+ .compose('LinearPileupDisplay', BaseLinearDisplay, types.model({
37
+ /**
38
+ * #property
39
+ */
40
+ type: types.literal('LinearPileupDisplay'),
41
+ /**
42
+ * #property
43
+ */
44
+ configuration: ConfigurationReference(configSchema),
45
+ /**
46
+ * #property
47
+ */
48
+ showSoftClipping: false,
49
+ /**
50
+ * #property
51
+ */
52
+ featureHeight: types.maybe(types.number),
53
+ /**
54
+ * #property
55
+ */
56
+ noSpacing: types.maybe(types.boolean),
57
+ /**
58
+ * #property
59
+ */
60
+ fadeLikelihood: types.maybe(types.boolean),
61
+ /**
62
+ * #property
63
+ */
64
+ trackMaxHeight: types.maybe(types.number),
65
+ /**
66
+ * #property
67
+ */
68
+ mismatchAlpha: types.maybe(types.boolean),
69
+ /**
70
+ * #property
71
+ */
72
+ sortedBy: types.maybe(types.model({
73
+ type: types.string,
74
+ pos: types.number,
75
+ tag: types.maybe(types.string),
76
+ refName: types.string,
77
+ assemblyName: types.string,
78
+ })),
79
+ /**
80
+ * #property
81
+ */
82
+ colorBy: types.maybe(types.model({
83
+ type: types.string,
84
+ tag: types.maybe(types.string),
85
+ extra: types.frozen(),
86
+ })),
87
+ /**
88
+ * #property
89
+ */
90
+ filterBy: types.optional(types.model({
91
+ flagInclude: types.optional(types.number, 0),
92
+ flagExclude: types.optional(types.number, 1540),
93
+ readName: types.maybe(types.string),
94
+ tagFilter: types.maybe(types.model({ tag: types.string, value: types.string })),
95
+ }), {}),
96
+ }))
97
+ .volatile(() => ({
98
+ colorTagMap: observable.map({}),
99
+ modificationTagMap: observable.map({}),
100
+ featureUnderMouseVolatile: undefined,
101
+ currSortBpPerPx: 0,
102
+ ready: false,
103
+ }))
104
+ .actions(self => ({
105
+ /**
106
+ * #action
107
+ */
108
+ setReady(flag) {
109
+ self.ready = flag;
110
+ },
111
+ /**
112
+ * #action
113
+ */
114
+ setCurrSortBpPerPx(n) {
115
+ self.currSortBpPerPx = n;
116
+ },
117
+ /**
118
+ * #action
119
+ */
120
+ setMaxHeight(n) {
121
+ self.trackMaxHeight = n;
122
+ },
123
+ /**
124
+ * #action
125
+ */
126
+ setFeatureHeight(n) {
127
+ self.featureHeight = n;
128
+ },
129
+ /**
130
+ * #action
131
+ */
132
+ setNoSpacing(flag) {
133
+ self.noSpacing = flag;
134
+ },
135
+ /**
136
+ * #action
137
+ */
138
+ setColorScheme(colorScheme) {
139
+ self.colorTagMap = observable.map({}); // clear existing mapping
140
+ self.colorBy = cast(colorScheme);
141
+ self.ready = false;
142
+ },
143
+ /**
144
+ * #action
145
+ */
146
+ updateModificationColorMap(uniqueModifications) {
147
+ const colorPalette = ['red', 'blue', 'green', 'orange', 'purple'];
148
+ uniqueModifications.forEach(value => {
149
+ if (!self.modificationTagMap.has(value)) {
150
+ const totalKeys = [...self.modificationTagMap.keys()].length;
151
+ const newColor = colorPalette[totalKeys];
152
+ self.modificationTagMap.set(value, newColor);
166
153
  }
167
- else {
168
- self.setReady(true);
154
+ });
155
+ },
156
+ /**
157
+ * #action
158
+ */
159
+ updateColorTagMap(uniqueTag) {
160
+ // pale color scheme
161
+ // https://cran.r-project.org/web/packages/khroma/vignettes/tol.html
162
+ // e.g. "tol_light"
163
+ const colorPalette = [
164
+ '#BBCCEE',
165
+ 'pink',
166
+ '#CCDDAA',
167
+ '#EEEEBB',
168
+ '#FFCCCC',
169
+ 'lightblue',
170
+ 'lightgreen',
171
+ 'tan',
172
+ '#CCEEFF',
173
+ 'lightsalmon',
174
+ ];
175
+ uniqueTag.forEach(value => {
176
+ if (!self.colorTagMap.has(value)) {
177
+ const totalKeys = [...self.colorTagMap.keys()].length;
178
+ const newColor = colorPalette[totalKeys];
179
+ self.colorTagMap.set(value, newColor);
169
180
  }
170
- }
171
- catch (e) {
172
- console.error(e);
173
- self.setError(e);
174
- }
175
- }, { delay: 1000 }));
176
- // autorun synchronizes featureUnderMouse with featureIdUnderMouse
177
- addDisposer(self, autorun(async () => {
178
- var _a;
179
- const session = getSession(self);
180
- try {
181
- const featureId = self.featureIdUnderMouse;
182
- if (((_a = self.featureUnderMouse) === null || _a === void 0 ? void 0 : _a.id()) !== featureId) {
183
- if (!featureId) {
184
- self.setFeatureUnderMouse(undefined);
181
+ });
182
+ },
183
+ /**
184
+ * #action
185
+ */
186
+ setFeatureUnderMouse(feat) {
187
+ self.featureUnderMouseVolatile = feat;
188
+ },
189
+ }))
190
+ .actions(self => ({
191
+ afterAttach() {
192
+ addDisposer(self, autorun(async () => {
193
+ try {
194
+ const { rpcManager } = getSession(self);
195
+ const view = getContainingView(self);
196
+ const { sortedBy, colorBy, parentTrack, adapterConfig, rendererType, } = self;
197
+ if (!view.initialized ||
198
+ !self.estimatedStatsReady ||
199
+ self.regionTooLarge) {
200
+ return;
185
201
  }
186
- else {
187
- const sessionId = getRpcSessionId(self);
188
- const view = getContainingView(self);
189
- const { feature } = (await session.rpcManager.call(sessionId, 'CoreGetFeatureDetails', {
190
- featureId,
191
- sessionId,
192
- layoutId: view.id,
193
- rendererType: 'PileupRenderer',
194
- }));
195
- // check featureIdUnderMouse is still the same as the
196
- // feature.id that was returned e.g. that the user hasn't
197
- // moused over to a new position during the async operation
198
- // above
202
+ const { staticBlocks, bpPerPx } = view;
203
+ // continually generate the vc pairing, set and rerender if any
204
+ // new values seen
205
+ if (colorBy === null || colorBy === void 0 ? void 0 : colorBy.tag) {
206
+ self.updateColorTagMap(await getUniqueTagValues(self, colorBy, staticBlocks));
207
+ }
208
+ if ((colorBy === null || colorBy === void 0 ? void 0 : colorBy.type) === 'modifications') {
209
+ const adapter = getConf(parentTrack, ['adapter']);
210
+ self.updateModificationColorMap(await getUniqueModificationValues(self, adapter, colorBy, staticBlocks));
211
+ }
212
+ if (sortedBy) {
213
+ const { pos, refName, assemblyName } = sortedBy;
214
+ // render just the sorted region first
199
215
  // @ts-ignore
200
- if (self.featureIdUnderMouse === feature.uniqueId) {
201
- // @ts-ignore
202
- self.setFeatureUnderMouse(new SimpleFeature(feature));
203
- }
216
+ await self.rendererType.renderInClient(rpcManager, {
217
+ assemblyName,
218
+ regions: [
219
+ {
220
+ start: pos,
221
+ end: pos + 1,
222
+ refName,
223
+ assemblyName,
224
+ },
225
+ ],
226
+ adapterConfig: adapterConfig,
227
+ rendererType: rendererType.name,
228
+ sessionId: getRpcSessionId(self),
229
+ layoutId: view.id,
230
+ timeout: 1000000,
231
+ ...self.renderProps(),
232
+ });
233
+ self.setReady(true);
234
+ self.setCurrSortBpPerPx(bpPerPx);
235
+ }
236
+ else {
237
+ self.setReady(true);
204
238
  }
205
239
  }
206
- }
207
- catch (e) {
208
- console.error(e);
209
- session.notify(`${e}`, 'error');
210
- }
211
- }));
212
- },
213
- selectFeature(feature) {
214
- const session = getSession(self);
215
- if (isSessionModelWithWidgets(session)) {
216
- const featureWidget = session.addWidget('AlignmentsFeatureWidget', 'alignmentFeature', { featureData: feature.toJSON(), view: getContainingView(self) });
217
- session.showWidget(featureWidget);
218
- }
219
- session.setSelection(feature);
220
- },
221
- clearSelected() {
222
- self.sortedBy = undefined;
223
- },
224
- // uses copy-to-clipboard and generates notification
225
- copyFeatureToClipboard(feature) {
226
- const { uniqueId, ...rest } = feature.toJSON();
227
- const session = getSession(self);
228
- copy(JSON.stringify(rest, null, 4));
229
- session.notify('Copied to clipboard', 'success');
230
- },
231
- toggleSoftClipping() {
232
- self.showSoftClipping = !self.showSoftClipping;
233
- },
234
- toggleMismatchAlpha() {
235
- self.mismatchAlpha = !self.mismatchAlpha;
236
- },
237
- setConfig(configuration) {
238
- self.configuration = configuration;
239
- },
240
- setSortedBy(type, tag) {
241
- const { centerLineInfo } = getContainingView(self);
242
- if (!centerLineInfo) {
243
- return;
244
- }
245
- const { refName, assemblyName, offset } = centerLineInfo;
246
- const centerBp = Math.round(offset) + 1;
247
- if (centerBp < 0 || !refName) {
248
- return;
249
- }
250
- self.sortedBy = {
251
- type,
252
- pos: centerBp,
253
- refName,
254
- assemblyName,
255
- tag,
256
- };
257
- self.ready = false;
258
- },
259
- setFilterBy(filter) {
260
- self.filterBy = cast(filter);
261
- },
262
- }))
263
- .actions(self => {
264
- // resets the sort object and refresh whole display on reload
265
- const superReload = self.reload;
266
- return {
267
- reload() {
268
- self.clearSelected();
269
- superReload();
270
- },
271
- };
272
- })
273
- .views(self => ({
274
- get maxHeight() {
275
- const conf = getConf(self, ['renderers', self.rendererTypeName]) || {};
276
- return self.trackMaxHeight !== undefined
277
- ? self.trackMaxHeight
278
- : conf.maxHeight;
279
- },
280
- get rendererConfig() {
281
- const configBlob = getConf(self, ['renderers', self.rendererTypeName]) || {};
282
- return self.rendererType.configSchema.create({
283
- ...configBlob,
284
- height: self.featureHeight,
285
- noSpacing: self.noSpacing,
286
- maxHeight: this.maxHeight,
287
- mismatchAlpha: self.mismatchAlpha,
288
- }, getEnv(self));
289
- },
290
- get featureHeightSetting() {
291
- return (self.featureHeight || readConfObject(this.rendererConfig, 'height'));
292
- },
293
- get mismatchAlphaSetting() {
294
- return self.mismatchAlpha !== undefined
295
- ? self.mismatchAlpha
296
- : readConfObject(this.rendererConfig, 'mismatchAlpha');
297
- },
298
- get featureUnderMouse() {
299
- return self.featureUnderMouseVolatile;
300
- },
301
- }))
302
- .views(self => {
303
- const { trackMenuItems: superTrackMenuItems, renderProps: superRenderProps, } = self;
304
- return {
305
- get rendererTypeName() {
306
- const viewName = getConf(self, 'defaultRendering');
307
- const rendererType = rendererTypes.get(viewName);
308
- if (!rendererType) {
309
- throw new Error(`unknown alignments view name ${viewName}`);
310
- }
311
- return rendererType;
312
- },
313
- contextMenuItems() {
314
- const feat = self.contextMenuFeature;
315
- const contextMenuItems = feat
316
- ? [
317
- {
318
- label: 'Open feature details',
319
- icon: MenuOpenIcon,
320
- onClick: () => {
321
- self.clearFeatureSelection();
322
- if (feat) {
323
- self.selectFeature(feat);
324
- }
325
- },
326
- },
327
- {
328
- label: 'Copy info to clipboard',
329
- icon: ContentCopyIcon,
330
- onClick: () => {
331
- if (feat) {
332
- self.copyFeatureToClipboard(feat);
333
- }
334
- },
335
- },
336
- ]
337
- : [];
338
- return contextMenuItems;
339
- },
340
- get DisplayBlurb() {
341
- return LinearPileupDisplayBlurb;
342
- },
343
- renderProps() {
344
- const view = getContainingView(self);
345
- const { colorTagMap, modificationTagMap, sortedBy, colorBy, filterBy, rpcDriverName, currBpPerPx, ready, } = self;
346
- const superProps = superRenderProps();
347
- return {
348
- ...superProps,
349
- notReady: superProps.notReady ||
350
- !ready ||
351
- (sortedBy && currBpPerPx !== view.bpPerPx),
352
- rpcDriverName,
353
- displayModel: self,
354
- sortedBy,
355
- colorBy,
356
- filterBy: JSON.parse(JSON.stringify(filterBy)),
357
- colorTagMap: Object.fromEntries(colorTagMap.toJSON()),
358
- modificationTagMap: Object.fromEntries(modificationTagMap.toJSON()),
359
- showSoftClip: self.showSoftClipping,
360
- config: self.rendererConfig,
361
- async onFeatureClick(_, featureId) {
362
- const session = getSession(self);
363
- const { rpcManager } = session;
364
- try {
365
- const f = featureId || self.featureIdUnderMouse;
366
- if (!f) {
367
- self.clearFeatureSelection();
240
+ catch (e) {
241
+ console.error(e);
242
+ self.setError(e);
243
+ }
244
+ }, { delay: 1000 }));
245
+ // autorun synchronizes featureUnderMouse with featureIdUnderMouse
246
+ // asynchronously. this is needed due to how we do not serialize all
247
+ // features from the BAM/CRAM over the rpc
248
+ addDisposer(self, autorun(async () => {
249
+ var _a;
250
+ const session = getSession(self);
251
+ try {
252
+ const featureId = self.featureIdUnderMouse;
253
+ if (((_a = self.featureUnderMouse) === null || _a === void 0 ? void 0 : _a.id()) !== featureId) {
254
+ if (!featureId) {
255
+ self.setFeatureUnderMouse(undefined);
368
256
  }
369
257
  else {
370
258
  const sessionId = getRpcSessionId(self);
371
- const { feature } = (await rpcManager.call(sessionId, 'CoreGetFeatureDetails', {
372
- featureId: f,
259
+ const view = getContainingView(self);
260
+ const { feature } = (await session.rpcManager.call(sessionId, 'CoreGetFeatureDetails', {
261
+ featureId,
373
262
  sessionId,
374
- layoutId: getContainingView(self).id,
263
+ layoutId: view.id,
375
264
  rendererType: 'PileupRenderer',
376
265
  }));
377
- if (feature) {
266
+ // check featureIdUnderMouse is still the same as the
267
+ // feature.id that was returned e.g. that the user hasn't
268
+ // moused over to a new position during the async operation
269
+ // above
270
+ // @ts-ignore
271
+ if (self.featureIdUnderMouse === feature.uniqueId) {
378
272
  // @ts-ignore
379
- self.selectFeature(new SimpleFeature(feature));
273
+ self.setFeatureUnderMouse(new SimpleFeature(feature));
380
274
  }
381
275
  }
382
276
  }
383
- catch (e) {
384
- console.error(e);
385
- session.notify(`${e}`);
386
- }
387
- },
388
- onClick() {
389
- self.clearFeatureSelection();
390
- },
391
- // similar to click but opens a menu with further options
392
- async onFeatureContextMenu(_, featureId) {
393
- const session = getSession(self);
394
- const { rpcManager } = session;
395
- try {
396
- const f = featureId || self.featureIdUnderMouse;
397
- if (!f) {
398
- self.clearFeatureSelection();
399
- }
400
- else {
401
- const sessionId = getRpcSessionId(self);
402
- const { feature } = (await rpcManager.call(sessionId, 'CoreGetFeatureDetails', {
403
- featureId: f,
404
- sessionId,
405
- layoutId: getContainingView(self).id,
406
- rendererType: 'PileupRenderer',
407
- }));
408
- if (feature) {
409
- self.setContextMenuFeature(new SimpleFeature(feature));
410
- }
411
- }
412
- }
413
- catch (e) {
414
- console.error(e);
415
- session.notify(`${e}`);
416
- }
417
- },
277
+ }
278
+ catch (e) {
279
+ console.error(e);
280
+ session.notify(`${e}`, 'error');
281
+ }
282
+ }));
283
+ },
284
+ /**
285
+ * #action
286
+ */
287
+ selectFeature(feature) {
288
+ const session = getSession(self);
289
+ if (isSessionModelWithWidgets(session)) {
290
+ const featureWidget = session.addWidget('AlignmentsFeatureWidget', 'alignmentFeature', { featureData: feature.toJSON(), view: getContainingView(self) });
291
+ session.showWidget(featureWidget);
292
+ }
293
+ session.setSelection(feature);
294
+ },
295
+ /**
296
+ * #action
297
+ */
298
+ clearSelected() {
299
+ self.sortedBy = undefined;
300
+ },
301
+ /**
302
+ * #action
303
+ * uses copy-to-clipboard and generates notification
304
+ */
305
+ copyFeatureToClipboard(feature) {
306
+ const { uniqueId, ...rest } = feature.toJSON();
307
+ const session = getSession(self);
308
+ copy(JSON.stringify(rest, null, 4));
309
+ session.notify('Copied to clipboard', 'success');
310
+ },
311
+ /**
312
+ * #action
313
+ */
314
+ toggleSoftClipping() {
315
+ self.showSoftClipping = !self.showSoftClipping;
316
+ },
317
+ /**
318
+ * #action
319
+ */
320
+ toggleMismatchAlpha() {
321
+ self.mismatchAlpha = !self.mismatchAlpha;
322
+ },
323
+ /**
324
+ * #action
325
+ */
326
+ setConfig(configuration) {
327
+ self.configuration = configuration;
328
+ },
329
+ /**
330
+ * #action
331
+ */
332
+ setSortedBy(type, tag) {
333
+ const { centerLineInfo } = getContainingView(self);
334
+ if (!centerLineInfo) {
335
+ return;
336
+ }
337
+ const { refName, assemblyName, offset } = centerLineInfo;
338
+ const centerBp = Math.round(offset) + 1;
339
+ if (centerBp < 0 || !refName) {
340
+ return;
341
+ }
342
+ self.sortedBy = {
343
+ type,
344
+ pos: centerBp,
345
+ refName,
346
+ assemblyName,
347
+ tag,
418
348
  };
349
+ self.ready = false;
419
350
  },
420
- trackMenuItems() {
421
- return [
422
- ...superTrackMenuItems(),
423
- {
424
- label: 'Show soft clipping',
425
- icon: VisibilityIcon,
426
- type: 'checkbox',
427
- checked: self.showSoftClipping,
428
- onClick: () => {
429
- self.toggleSoftClipping();
430
- // if toggling from off to on, will break sort for this track
431
- // so clear it
432
- if (self.showSoftClipping) {
433
- self.clearSelected();
434
- }
435
- },
436
- },
437
- {
438
- label: 'Sort by',
439
- icon: SortIcon,
440
- disabled: self.showSoftClipping,
441
- subMenu: [
442
- ...['Start location', 'Read strand', 'Base pair'].map(option => ({
443
- label: option,
444
- onClick: () => self.setSortedBy(option),
445
- })),
351
+ setFilterBy(filter) {
352
+ self.filterBy = cast(filter);
353
+ },
354
+ }))
355
+ .actions(self => {
356
+ // resets the sort object and refresh whole display on reload
357
+ const superReload = self.reload;
358
+ return {
359
+ /**
360
+ * #action
361
+ */
362
+ reload() {
363
+ self.clearSelected();
364
+ superReload();
365
+ },
366
+ };
367
+ })
368
+ .views(self => ({
369
+ /**
370
+ * #getter
371
+ */
372
+ get maxHeight() {
373
+ const conf = getConf(self, ['renderers', self.rendererTypeName]) || {};
374
+ return self.trackMaxHeight !== undefined
375
+ ? self.trackMaxHeight
376
+ : conf.maxHeight;
377
+ },
378
+ /**
379
+ * #getter
380
+ */
381
+ get rendererConfig() {
382
+ const configBlob = getConf(self, ['renderers', self.rendererTypeName]) || {};
383
+ return self.rendererType.configSchema.create({
384
+ ...configBlob,
385
+ height: self.featureHeight,
386
+ noSpacing: self.noSpacing,
387
+ maxHeight: this.maxHeight,
388
+ mismatchAlpha: self.mismatchAlpha,
389
+ }, getEnv(self));
390
+ },
391
+ /**
392
+ * #getter
393
+ */
394
+ get featureHeightSetting() {
395
+ return (self.featureHeight || readConfObject(this.rendererConfig, 'height'));
396
+ },
397
+ /**
398
+ * #getter
399
+ */
400
+ get mismatchAlphaSetting() {
401
+ return self.mismatchAlpha !== undefined
402
+ ? self.mismatchAlpha
403
+ : readConfObject(this.rendererConfig, 'mismatchAlpha');
404
+ },
405
+ /**
406
+ * #getter
407
+ */
408
+ get featureUnderMouse() {
409
+ return self.featureUnderMouseVolatile;
410
+ },
411
+ }))
412
+ .views(self => {
413
+ const { trackMenuItems: superTrackMenuItems, renderProps: superRenderProps, } = self;
414
+ return {
415
+ /**
416
+ * #getter
417
+ */
418
+ get rendererTypeName() {
419
+ const viewName = getConf(self, 'defaultRendering');
420
+ const rendererType = rendererTypes.get(viewName);
421
+ if (!rendererType) {
422
+ throw new Error(`unknown alignments view name ${viewName}`);
423
+ }
424
+ return rendererType;
425
+ },
426
+ /**
427
+ * #method
428
+ */
429
+ contextMenuItems() {
430
+ const feat = self.contextMenuFeature;
431
+ const contextMenuItems = feat
432
+ ? [
446
433
  {
447
- label: 'Sort by tag...',
434
+ label: 'Open feature details',
435
+ icon: MenuOpenIcon,
448
436
  onClick: () => {
449
- getSession(self).queueDialog(handleClose => [
450
- SortByTagDlg,
451
- { model: self, handleClose },
452
- ]);
437
+ self.clearFeatureSelection();
438
+ if (feat) {
439
+ self.selectFeature(feat);
440
+ }
453
441
  },
454
442
  },
455
443
  {
456
- label: 'Clear sort',
457
- onClick: () => self.clearSelected(),
458
- },
459
- ],
460
- },
461
- {
462
- label: 'Color scheme',
463
- icon: PaletteIcon,
464
- subMenu: [
465
- {
466
- label: 'Normal',
444
+ label: 'Copy info to clipboard',
445
+ icon: ContentCopyIcon,
467
446
  onClick: () => {
468
- self.setColorScheme({ type: 'normal' });
447
+ if (feat) {
448
+ self.copyFeatureToClipboard(feat);
449
+ }
469
450
  },
470
451
  },
471
- {
472
- label: 'Mapping quality',
473
- onClick: () => {
474
- self.setColorScheme({ type: 'mappingQuality' });
475
- },
452
+ ]
453
+ : [];
454
+ return contextMenuItems;
455
+ },
456
+ /**
457
+ * #getter
458
+ */
459
+ get DisplayBlurb() {
460
+ return LinearPileupDisplayBlurb;
461
+ },
462
+ /**
463
+ * #method
464
+ */
465
+ renderProps() {
466
+ const view = getContainingView(self);
467
+ const { colorTagMap, modificationTagMap, sortedBy, colorBy, filterBy, rpcDriverName, currSortBpPerPx, ready, } = self;
468
+ const superProps = superRenderProps();
469
+ return {
470
+ ...superProps,
471
+ notReady: superProps.notReady ||
472
+ !ready ||
473
+ (sortedBy && currSortBpPerPx !== view.bpPerPx),
474
+ rpcDriverName,
475
+ displayModel: self,
476
+ sortedBy,
477
+ colorBy,
478
+ filterBy: JSON.parse(JSON.stringify(filterBy)),
479
+ colorTagMap: Object.fromEntries(colorTagMap.toJSON()),
480
+ modificationTagMap: Object.fromEntries(modificationTagMap.toJSON()),
481
+ showSoftClip: self.showSoftClipping,
482
+ config: self.rendererConfig,
483
+ async onFeatureClick(_, featureId) {
484
+ const session = getSession(self);
485
+ const { rpcManager } = session;
486
+ try {
487
+ const f = featureId || self.featureIdUnderMouse;
488
+ if (!f) {
489
+ self.clearFeatureSelection();
490
+ }
491
+ else {
492
+ const sessionId = getRpcSessionId(self);
493
+ const { feature } = (await rpcManager.call(sessionId, 'CoreGetFeatureDetails', {
494
+ featureId: f,
495
+ sessionId,
496
+ layoutId: getContainingView(self).id,
497
+ rendererType: 'PileupRenderer',
498
+ }));
499
+ if (feature) {
500
+ // @ts-ignore
501
+ self.selectFeature(new SimpleFeature(feature));
502
+ }
503
+ }
504
+ }
505
+ catch (e) {
506
+ console.error(e);
507
+ session.notify(`${e}`);
508
+ }
509
+ },
510
+ onClick() {
511
+ self.clearFeatureSelection();
512
+ },
513
+ // similar to click but opens a menu with further options
514
+ async onFeatureContextMenu(_, featureId) {
515
+ const session = getSession(self);
516
+ const { rpcManager } = session;
517
+ try {
518
+ const f = featureId || self.featureIdUnderMouse;
519
+ if (!f) {
520
+ self.clearFeatureSelection();
521
+ }
522
+ else {
523
+ const sessionId = getRpcSessionId(self);
524
+ const { feature } = (await rpcManager.call(sessionId, 'CoreGetFeatureDetails', {
525
+ featureId: f,
526
+ sessionId,
527
+ layoutId: getContainingView(self).id,
528
+ rendererType: 'PileupRenderer',
529
+ }));
530
+ if (feature) {
531
+ self.setContextMenuFeature(new SimpleFeature(feature));
532
+ }
533
+ }
534
+ }
535
+ catch (e) {
536
+ console.error(e);
537
+ session.notify(`${e}`);
538
+ }
539
+ },
540
+ };
541
+ },
542
+ /**
543
+ * #method
544
+ */
545
+ trackMenuItems() {
546
+ return [
547
+ ...superTrackMenuItems(),
548
+ {
549
+ label: 'Show soft clipping',
550
+ icon: VisibilityIcon,
551
+ type: 'checkbox',
552
+ checked: self.showSoftClipping,
553
+ onClick: () => {
554
+ self.toggleSoftClipping();
555
+ // if toggling from off to on, will break sort for this track
556
+ // so clear it
557
+ if (self.showSoftClipping) {
558
+ self.clearSelected();
559
+ }
476
560
  },
477
- {
478
- label: 'Strand',
479
- onClick: () => {
480
- self.setColorScheme({ type: 'strand' });
561
+ },
562
+ {
563
+ label: 'Sort by',
564
+ icon: SortIcon,
565
+ disabled: self.showSoftClipping,
566
+ subMenu: [
567
+ ...['Start location', 'Read strand', 'Base pair'].map(option => ({
568
+ label: option,
569
+ onClick: () => self.setSortedBy(option),
570
+ })),
571
+ {
572
+ label: 'Sort by tag...',
573
+ onClick: () => {
574
+ getSession(self).queueDialog(handleClose => [
575
+ SortByTagDlg,
576
+ { model: self, handleClose },
577
+ ]);
578
+ },
481
579
  },
482
- },
483
- {
484
- label: 'Pair orientation',
485
- onClick: () => {
486
- self.setColorScheme({ type: 'pairOrientation' });
580
+ {
581
+ label: 'Clear sort',
582
+ onClick: () => self.clearSelected(),
487
583
  },
488
- },
489
- {
490
- label: 'Per-base quality',
491
- onClick: () => {
492
- self.setColorScheme({ type: 'perBaseQuality' });
584
+ ],
585
+ },
586
+ {
587
+ label: 'Color scheme',
588
+ icon: PaletteIcon,
589
+ subMenu: [
590
+ {
591
+ label: 'Normal',
592
+ onClick: () => self.setColorScheme({ type: 'normal' }),
493
593
  },
494
- },
495
- {
496
- label: 'Per-base lettering',
497
- onClick: () => {
498
- self.setColorScheme({ type: 'perBaseLettering' });
594
+ {
595
+ label: 'Mapping quality',
596
+ onClick: () => self.setColorScheme({ type: 'mappingQuality' }),
499
597
  },
500
- },
501
- {
502
- label: 'Modifications or methylation',
503
- onClick: () => {
504
- getSession(self).queueDialog(doneCallback => [
505
- ModificationsDlg,
506
- { model: self, handleClose: doneCallback },
507
- ]);
598
+ {
599
+ label: 'Strand',
600
+ onClick: () => self.setColorScheme({ type: 'strand' }),
508
601
  },
509
- },
510
- {
511
- label: 'Insert size',
512
- onClick: () => {
513
- self.setColorScheme({ type: 'insertSize' });
602
+ {
603
+ label: 'Pair orientation',
604
+ onClick: () => self.setColorScheme({ type: 'pairOrientation' }),
514
605
  },
515
- },
516
- {
517
- label: 'Stranded paired-end',
518
- onClick: () => {
519
- self.setColorScheme({ type: 'reverseTemplate' });
606
+ {
607
+ label: 'Per-base quality',
608
+ onClick: () => self.setColorScheme({ type: 'perBaseQuality' }),
520
609
  },
521
- },
522
- {
523
- label: 'Color by tag...',
524
- onClick: () => {
525
- getSession(self).queueDialog(doneCallback => [
526
- ColorByTagDlg,
527
- { model: self, handleClose: doneCallback },
528
- ]);
610
+ {
611
+ label: 'Per-base lettering',
612
+ onClick: () => self.setColorScheme({ type: 'perBaseLettering' }),
613
+ },
614
+ {
615
+ label: 'Modifications or methylation',
616
+ onClick: () => {
617
+ getSession(self).queueDialog(doneCallback => [
618
+ ModificationsDlg,
619
+ { model: self, handleClose: doneCallback },
620
+ ]);
621
+ },
529
622
  },
623
+ {
624
+ label: 'Insert size',
625
+ onClick: () => self.setColorScheme({ type: 'insertSize' }),
626
+ },
627
+ {
628
+ label: 'Stranded paired-end',
629
+ onClick: () => self.setColorScheme({ type: 'reverseTemplate' }),
630
+ },
631
+ {
632
+ label: 'Color by tag...',
633
+ onClick: () => {
634
+ getSession(self).queueDialog(doneCallback => [
635
+ ColorByTagDlg,
636
+ { model: self, handleClose: doneCallback },
637
+ ]);
638
+ },
639
+ },
640
+ ],
641
+ },
642
+ {
643
+ label: 'Filter by',
644
+ icon: FilterListIcon,
645
+ onClick: () => {
646
+ getSession(self).queueDialog(doneCallback => [
647
+ FilterByTagDlg,
648
+ { model: self, handleClose: doneCallback },
649
+ ]);
530
650
  },
531
- ],
532
- },
533
- {
534
- label: 'Filter by',
535
- icon: FilterListIcon,
536
- onClick: () => {
537
- getSession(self).queueDialog(doneCallback => [
538
- FilterByTagDlg,
539
- { model: self, handleClose: doneCallback },
540
- ]);
541
651
  },
542
- },
543
- {
544
- label: 'Set feature height',
545
- onClick: () => {
546
- getSession(self).queueDialog(doneCallback => [
547
- SetFeatureHeightDlg,
548
- { model: self, handleClose: doneCallback },
549
- ]);
652
+ {
653
+ label: 'Set feature height',
654
+ onClick: () => {
655
+ getSession(self).queueDialog(doneCallback => [
656
+ SetFeatureHeightDlg,
657
+ { model: self, handleClose: doneCallback },
658
+ ]);
659
+ },
550
660
  },
551
- },
552
- {
553
- label: 'Set max height',
554
- onClick: () => {
555
- getSession(self).queueDialog(doneCallback => [
556
- SetMaxHeightDlg,
557
- { model: self, handleClose: doneCallback },
558
- ]);
661
+ {
662
+ label: 'Set max height',
663
+ onClick: () => {
664
+ getSession(self).queueDialog(doneCallback => [
665
+ SetMaxHeightDlg,
666
+ { model: self, handleClose: doneCallback },
667
+ ]);
668
+ },
559
669
  },
560
- },
561
- {
562
- label: 'Fade mismatches by quality',
563
- type: 'checkbox',
564
- checked: self.mismatchAlphaSetting,
565
- onClick: () => {
566
- self.toggleMismatchAlpha();
670
+ {
671
+ label: 'Fade mismatches by quality',
672
+ type: 'checkbox',
673
+ checked: self.mismatchAlphaSetting,
674
+ onClick: () => self.toggleMismatchAlpha(),
567
675
  },
568
- },
569
- ];
570
- },
571
- };
572
- });
676
+ ];
677
+ },
678
+ };
679
+ });
680
+ }
573
681
  export default stateModelFactory;
574
682
  //# sourceMappingURL=model.js.map