@jbrowse/plugin-circular-view 2.1.6 → 2.2.0
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/dist/BaseChordDisplay/models/BaseChordDisplayModel.d.ts +26 -0
- package/dist/BaseChordDisplay/models/BaseChordDisplayModel.js +199 -159
- package/dist/BaseChordDisplay/models/BaseChordDisplayModel.js.map +1 -1
- package/dist/BaseChordDisplay/models/baseChordDisplayConfig.js +13 -1
- package/dist/BaseChordDisplay/models/baseChordDisplayConfig.js.map +1 -1
- package/dist/CircularView/components/ImportForm.js +1 -1
- package/dist/CircularView/components/ImportForm.js.map +1 -1
- package/dist/CircularView/models/CircularView.d.ts +149 -8
- package/dist/CircularView/models/CircularView.js +176 -10
- package/dist/CircularView/models/CircularView.js.map +1 -1
- package/esm/BaseChordDisplay/models/BaseChordDisplayModel.d.ts +26 -0
- package/esm/BaseChordDisplay/models/BaseChordDisplayModel.js +199 -159
- package/esm/BaseChordDisplay/models/BaseChordDisplayModel.js.map +1 -1
- package/esm/BaseChordDisplay/models/baseChordDisplayConfig.js +13 -1
- package/esm/BaseChordDisplay/models/baseChordDisplayConfig.js.map +1 -1
- package/esm/CircularView/components/ImportForm.js +1 -1
- package/esm/CircularView/components/ImportForm.js.map +1 -1
- package/esm/CircularView/models/CircularView.d.ts +149 -8
- package/esm/CircularView/models/CircularView.js +176 -9
- package/esm/CircularView/models/CircularView.js.map +1 -1
- package/package.json +2 -2
- package/src/BaseChordDisplay/models/BaseChordDisplayModel.ts +236 -194
- package/src/BaseChordDisplay/models/baseChordDisplayConfig.ts +14 -1
- package/src/CircularView/components/ImportForm.tsx +1 -1
- package/src/CircularView/models/CircularView.ts +180 -11
|
@@ -25,7 +25,11 @@ import { calculateStaticSlices, sliceIsVisible } from './slices'
|
|
|
25
25
|
|
|
26
26
|
import { viewportVisibleSection } from './viewportVisibleRegion'
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
* #stateModel CircularView
|
|
30
|
+
* extends `BaseViewModel`
|
|
31
|
+
*/
|
|
32
|
+
function stateModelFactory(pluginManager: PluginManager) {
|
|
29
33
|
const minHeight = 40
|
|
30
34
|
const minWidth = 100
|
|
31
35
|
const defaultHeight = 400
|
|
@@ -33,41 +37,86 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
33
37
|
BaseViewModel,
|
|
34
38
|
types
|
|
35
39
|
.model('CircularView', {
|
|
40
|
+
/**
|
|
41
|
+
* #property
|
|
42
|
+
*/
|
|
36
43
|
type: types.literal('CircularView'),
|
|
44
|
+
/**
|
|
45
|
+
* #property
|
|
46
|
+
* similar to offsetPx in linear genome view
|
|
47
|
+
*/
|
|
37
48
|
offsetRadians: -Math.PI / 2,
|
|
49
|
+
/**
|
|
50
|
+
* #property
|
|
51
|
+
*/
|
|
38
52
|
bpPerPx: 2000000,
|
|
53
|
+
/**
|
|
54
|
+
* #property
|
|
55
|
+
*/
|
|
39
56
|
tracks: types.array(
|
|
40
57
|
pluginManager.pluggableMstType('track', 'stateModel'),
|
|
41
58
|
),
|
|
42
59
|
|
|
60
|
+
/**
|
|
61
|
+
* #property
|
|
62
|
+
*/
|
|
43
63
|
hideVerticalResizeHandle: false,
|
|
64
|
+
/**
|
|
65
|
+
* #property
|
|
66
|
+
*/
|
|
44
67
|
hideTrackSelectorButton: false,
|
|
68
|
+
/**
|
|
69
|
+
* #property
|
|
70
|
+
*/
|
|
45
71
|
lockedFitToWindow: true,
|
|
72
|
+
/**
|
|
73
|
+
* #property
|
|
74
|
+
*/
|
|
46
75
|
disableImportForm: false,
|
|
47
76
|
|
|
77
|
+
/**
|
|
78
|
+
* #property
|
|
79
|
+
*/
|
|
48
80
|
height: types.optional(
|
|
49
81
|
types.refinement('trackHeight', types.number, n => n >= minHeight),
|
|
50
82
|
defaultHeight,
|
|
51
83
|
),
|
|
84
|
+
/**
|
|
85
|
+
* #property
|
|
86
|
+
*/
|
|
87
|
+
displayedRegions: types.array(Region),
|
|
88
|
+
/**
|
|
89
|
+
* #property
|
|
90
|
+
*/
|
|
91
|
+
scrollX: 0,
|
|
92
|
+
/**
|
|
93
|
+
* #property
|
|
94
|
+
*/
|
|
95
|
+
scrollY: 0,
|
|
96
|
+
|
|
52
97
|
minimumRadiusPx: 25,
|
|
53
98
|
spacingPx: 10,
|
|
54
99
|
paddingPx: 80,
|
|
55
100
|
lockedPaddingPx: 100,
|
|
56
101
|
minVisibleWidth: 6,
|
|
57
102
|
minimumBlockWidth: 20,
|
|
58
|
-
|
|
59
|
-
scrollX: 0,
|
|
60
|
-
scrollY: 0,
|
|
103
|
+
|
|
61
104
|
trackSelectorType: 'hierarchical',
|
|
62
105
|
})
|
|
63
106
|
.volatile(() => ({
|
|
64
107
|
width: 0,
|
|
65
108
|
}))
|
|
66
109
|
.views(self => ({
|
|
110
|
+
/**
|
|
111
|
+
* #getter
|
|
112
|
+
*/
|
|
67
113
|
get staticSlices() {
|
|
68
114
|
return calculateStaticSlices(self)
|
|
69
115
|
},
|
|
70
116
|
|
|
117
|
+
/**
|
|
118
|
+
* #getter
|
|
119
|
+
*/
|
|
71
120
|
get visibleSection() {
|
|
72
121
|
return viewportVisibleSection(
|
|
73
122
|
[
|
|
@@ -80,6 +129,9 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
80
129
|
this.radiusPx,
|
|
81
130
|
)
|
|
82
131
|
},
|
|
132
|
+
/**
|
|
133
|
+
* #getter
|
|
134
|
+
*/
|
|
83
135
|
get circumferencePx() {
|
|
84
136
|
let elidedBp = 0
|
|
85
137
|
for (const r of this.elidedRegions) {
|
|
@@ -89,21 +141,36 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
89
141
|
elidedBp / self.bpPerPx + self.spacingPx * this.elidedRegions.length
|
|
90
142
|
)
|
|
91
143
|
},
|
|
144
|
+
/**
|
|
145
|
+
* #getter
|
|
146
|
+
*/
|
|
92
147
|
get radiusPx() {
|
|
93
148
|
return this.circumferencePx / (2 * Math.PI)
|
|
94
149
|
},
|
|
150
|
+
/**
|
|
151
|
+
* #getter
|
|
152
|
+
*/
|
|
95
153
|
get bpPerRadian() {
|
|
96
154
|
return self.bpPerPx * this.radiusPx
|
|
97
155
|
},
|
|
156
|
+
/**
|
|
157
|
+
* #getter
|
|
158
|
+
*/
|
|
98
159
|
get pxPerRadian() {
|
|
99
160
|
return this.radiusPx
|
|
100
161
|
},
|
|
162
|
+
/**
|
|
163
|
+
* #getter
|
|
164
|
+
*/
|
|
101
165
|
get centerXY(): [number, number] {
|
|
102
166
|
return [
|
|
103
167
|
this.radiusPx + self.paddingPx,
|
|
104
168
|
this.radiusPx + self.paddingPx,
|
|
105
169
|
]
|
|
106
170
|
},
|
|
171
|
+
/**
|
|
172
|
+
* #getter
|
|
173
|
+
*/
|
|
107
174
|
get totalBp() {
|
|
108
175
|
let total = 0
|
|
109
176
|
for (const region of self.displayedRegions) {
|
|
@@ -111,15 +178,24 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
111
178
|
}
|
|
112
179
|
return total
|
|
113
180
|
},
|
|
181
|
+
/**
|
|
182
|
+
* #getter
|
|
183
|
+
*/
|
|
114
184
|
get maximumRadiusPx() {
|
|
115
185
|
return self.lockedFitToWindow
|
|
116
186
|
? Math.min(self.width, self.height) / 2 - self.lockedPaddingPx
|
|
117
187
|
: 1000000
|
|
118
188
|
},
|
|
189
|
+
/**
|
|
190
|
+
* #getter
|
|
191
|
+
*/
|
|
119
192
|
get maxBpPerPx() {
|
|
120
193
|
const minCircumferencePx = 2 * Math.PI * self.minimumRadiusPx
|
|
121
194
|
return this.totalBp / minCircumferencePx
|
|
122
195
|
},
|
|
196
|
+
/**
|
|
197
|
+
* #getter
|
|
198
|
+
*/
|
|
123
199
|
get minBpPerPx() {
|
|
124
200
|
// min depends on window dimensions, clamp between old min(0.01) and max
|
|
125
201
|
const maxCircumferencePx = 2 * Math.PI * this.maximumRadiusPx
|
|
@@ -129,29 +205,50 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
129
205
|
this.maxBpPerPx,
|
|
130
206
|
)
|
|
131
207
|
},
|
|
208
|
+
/**
|
|
209
|
+
* #getter
|
|
210
|
+
*/
|
|
132
211
|
get atMaxBpPerPx() {
|
|
133
212
|
return self.bpPerPx >= this.maxBpPerPx
|
|
134
213
|
},
|
|
214
|
+
/**
|
|
215
|
+
* #getter
|
|
216
|
+
*/
|
|
135
217
|
get atMinBpPerPx() {
|
|
136
218
|
return self.bpPerPx <= this.minBpPerPx
|
|
137
219
|
},
|
|
220
|
+
/**
|
|
221
|
+
* #getter
|
|
222
|
+
*/
|
|
138
223
|
get tooSmallToLock() {
|
|
139
224
|
return this.minBpPerPx <= 0.0000000001
|
|
140
225
|
},
|
|
226
|
+
/**
|
|
227
|
+
* #getter
|
|
228
|
+
*/
|
|
141
229
|
get figureDimensions(): [number, number] {
|
|
142
230
|
return [
|
|
143
231
|
this.radiusPx * 2 + 2 * self.paddingPx,
|
|
144
232
|
this.radiusPx * 2 + 2 * self.paddingPx,
|
|
145
233
|
]
|
|
146
234
|
},
|
|
235
|
+
/**
|
|
236
|
+
* #getter
|
|
237
|
+
*/
|
|
147
238
|
get figureWidth() {
|
|
148
239
|
return this.figureDimensions[0]
|
|
149
240
|
},
|
|
241
|
+
/**
|
|
242
|
+
* #getter
|
|
243
|
+
*/
|
|
150
244
|
get figureHeight() {
|
|
151
245
|
return this.figureDimensions[1]
|
|
152
246
|
},
|
|
153
|
-
|
|
154
|
-
|
|
247
|
+
/**
|
|
248
|
+
* #getter
|
|
249
|
+
* this is displayedRegions, post-processed to
|
|
250
|
+
* elide regions that are too small to see reasonably
|
|
251
|
+
*/
|
|
155
252
|
get elidedRegions() {
|
|
156
253
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
157
254
|
const visible: any[] = []
|
|
@@ -187,7 +284,9 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
187
284
|
}
|
|
188
285
|
return visible
|
|
189
286
|
},
|
|
190
|
-
|
|
287
|
+
/**
|
|
288
|
+
* #getter
|
|
289
|
+
*/
|
|
191
290
|
get assemblyNames() {
|
|
192
291
|
const assemblyNames: string[] = []
|
|
193
292
|
self.displayedRegions.forEach(displayedRegion => {
|
|
@@ -197,6 +296,9 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
197
296
|
})
|
|
198
297
|
return assemblyNames
|
|
199
298
|
},
|
|
299
|
+
/**
|
|
300
|
+
* #getter
|
|
301
|
+
*/
|
|
200
302
|
get initialized() {
|
|
201
303
|
const { assemblyManager } = getSession(self)
|
|
202
304
|
return this.assemblyNames.every(
|
|
@@ -205,6 +307,9 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
205
307
|
},
|
|
206
308
|
}))
|
|
207
309
|
.views(self => ({
|
|
310
|
+
/**
|
|
311
|
+
* #getter
|
|
312
|
+
*/
|
|
208
313
|
get visibleStaticSlices() {
|
|
209
314
|
return self.staticSlices.filter(s => sliceIsVisible(self, s))
|
|
210
315
|
},
|
|
@@ -213,66 +318,107 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
213
318
|
error: undefined as unknown,
|
|
214
319
|
}))
|
|
215
320
|
.actions(self => ({
|
|
216
|
-
|
|
321
|
+
/**
|
|
322
|
+
* #action
|
|
323
|
+
*/
|
|
217
324
|
setWidth(newWidth: number) {
|
|
218
325
|
self.width = Math.max(newWidth, minWidth)
|
|
219
326
|
return self.width
|
|
220
327
|
},
|
|
328
|
+
/**
|
|
329
|
+
* #action
|
|
330
|
+
*/
|
|
221
331
|
setHeight(newHeight: number) {
|
|
222
332
|
self.height = Math.max(newHeight, minHeight)
|
|
223
333
|
return self.height
|
|
224
334
|
},
|
|
335
|
+
/**
|
|
336
|
+
* #action
|
|
337
|
+
*/
|
|
225
338
|
resizeHeight(distance: number) {
|
|
226
339
|
const oldHeight = self.height
|
|
227
340
|
const newHeight = this.setHeight(self.height + distance)
|
|
228
341
|
this.setModelViewWhenAdjust(!self.tooSmallToLock)
|
|
229
342
|
return newHeight - oldHeight
|
|
230
343
|
},
|
|
344
|
+
/**
|
|
345
|
+
* #action
|
|
346
|
+
*/
|
|
231
347
|
resizeWidth(distance: number) {
|
|
232
348
|
const oldWidth = self.width
|
|
233
349
|
const newWidth = this.setWidth(self.width + distance)
|
|
234
350
|
this.setModelViewWhenAdjust(!self.tooSmallToLock)
|
|
235
351
|
return newWidth - oldWidth
|
|
236
352
|
},
|
|
353
|
+
/**
|
|
354
|
+
* #action
|
|
355
|
+
*/
|
|
237
356
|
rotateClockwiseButton() {
|
|
238
357
|
this.rotateClockwise(Math.PI / 6)
|
|
239
358
|
},
|
|
240
359
|
|
|
360
|
+
/**
|
|
361
|
+
* #action
|
|
362
|
+
*/
|
|
241
363
|
rotateCounterClockwiseButton() {
|
|
242
364
|
this.rotateCounterClockwise(Math.PI / 6)
|
|
243
365
|
},
|
|
244
366
|
|
|
367
|
+
/**
|
|
368
|
+
* #action
|
|
369
|
+
*/
|
|
245
370
|
rotateClockwise(distance = 0.17) {
|
|
246
371
|
self.offsetRadians += distance
|
|
247
372
|
},
|
|
248
373
|
|
|
374
|
+
/**
|
|
375
|
+
* #action
|
|
376
|
+
*/
|
|
249
377
|
rotateCounterClockwise(distance = 0.17) {
|
|
250
378
|
self.offsetRadians -= distance
|
|
251
379
|
},
|
|
252
380
|
|
|
381
|
+
/**
|
|
382
|
+
* #action
|
|
383
|
+
*/
|
|
253
384
|
zoomInButton() {
|
|
254
385
|
this.setBpPerPx(self.bpPerPx / 1.4)
|
|
255
386
|
},
|
|
256
387
|
|
|
388
|
+
/**
|
|
389
|
+
* #action
|
|
390
|
+
*/
|
|
257
391
|
zoomOutButton() {
|
|
258
392
|
this.setBpPerPx(self.bpPerPx * 1.4)
|
|
259
393
|
},
|
|
260
394
|
|
|
395
|
+
/**
|
|
396
|
+
* #action
|
|
397
|
+
*/
|
|
261
398
|
setBpPerPx(newVal: number) {
|
|
262
399
|
self.bpPerPx = clamp(newVal, self.minBpPerPx, self.maxBpPerPx)
|
|
263
400
|
},
|
|
264
401
|
|
|
402
|
+
/**
|
|
403
|
+
* #action
|
|
404
|
+
*/
|
|
265
405
|
setModelViewWhenAdjust(secondCondition: boolean) {
|
|
266
406
|
if (self.lockedFitToWindow && secondCondition) {
|
|
267
407
|
this.setBpPerPx(self.minBpPerPx)
|
|
268
408
|
}
|
|
269
409
|
},
|
|
270
410
|
|
|
411
|
+
/**
|
|
412
|
+
* #action
|
|
413
|
+
*/
|
|
271
414
|
closeView() {
|
|
272
415
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
273
416
|
getParent<any>(self, 2).removeView(self)
|
|
274
417
|
},
|
|
275
418
|
|
|
419
|
+
/**
|
|
420
|
+
* #action
|
|
421
|
+
*/
|
|
276
422
|
setDisplayedRegions(regions: SnapshotOrInstance<typeof Region>[]) {
|
|
277
423
|
const previouslyEmpty = self.displayedRegions.length === 0
|
|
278
424
|
self.displayedRegions = cast(regions)
|
|
@@ -284,6 +430,9 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
284
430
|
}
|
|
285
431
|
},
|
|
286
432
|
|
|
433
|
+
/**
|
|
434
|
+
* #action
|
|
435
|
+
*/
|
|
287
436
|
activateTrackSelector() {
|
|
288
437
|
if (self.trackSelectorType === 'hierarchical') {
|
|
289
438
|
const session = getSession(self)
|
|
@@ -302,6 +451,9 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
302
451
|
)
|
|
303
452
|
},
|
|
304
453
|
|
|
454
|
+
/**
|
|
455
|
+
* #action
|
|
456
|
+
*/
|
|
305
457
|
toggleTrack(trackId: string) {
|
|
306
458
|
// if we have any tracks with that configuration, turn them off
|
|
307
459
|
const hiddenCount = this.hideTrack(trackId)
|
|
@@ -311,11 +463,17 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
311
463
|
}
|
|
312
464
|
},
|
|
313
465
|
|
|
466
|
+
/**
|
|
467
|
+
* #action
|
|
468
|
+
*/
|
|
314
469
|
setError(error: unknown) {
|
|
315
470
|
console.error(error)
|
|
316
471
|
self.error = error
|
|
317
472
|
},
|
|
318
473
|
|
|
474
|
+
/**
|
|
475
|
+
* #action
|
|
476
|
+
*/
|
|
319
477
|
showTrack(trackId: string, initialSnapshot = {}) {
|
|
320
478
|
const schema = pluginManager.pluggableConfigSchemaType('track')
|
|
321
479
|
const conf = resolveIdentifier(schema, getRoot(self), trackId)
|
|
@@ -337,6 +495,9 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
337
495
|
self.tracks.push(track)
|
|
338
496
|
},
|
|
339
497
|
|
|
498
|
+
/**
|
|
499
|
+
* #action
|
|
500
|
+
*/
|
|
340
501
|
addTrackConf(
|
|
341
502
|
configuration: AnyConfigurationModel,
|
|
342
503
|
initialSnapshot = {},
|
|
@@ -362,6 +523,9 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
362
523
|
self.tracks.push(track)
|
|
363
524
|
},
|
|
364
525
|
|
|
526
|
+
/**
|
|
527
|
+
* #action
|
|
528
|
+
*/
|
|
365
529
|
hideTrack(trackId: string) {
|
|
366
530
|
const schema = pluginManager.pluggableConfigSchemaType('track')
|
|
367
531
|
const conf = resolveIdentifier(schema, getRoot(self), trackId)
|
|
@@ -370,9 +534,12 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
370
534
|
return t.length
|
|
371
535
|
},
|
|
372
536
|
|
|
537
|
+
/**
|
|
538
|
+
* #action
|
|
539
|
+
*/
|
|
373
540
|
toggleFitToWindowLock() {
|
|
374
|
-
self.lockedFitToWindow = !self.lockedFitToWindow
|
|
375
541
|
// when going unlocked -> locked and circle is cut off, set to the locked minBpPerPx
|
|
542
|
+
self.lockedFitToWindow = !self.lockedFitToWindow
|
|
376
543
|
this.setModelViewWhenAdjust(self.atMinBpPerPx)
|
|
377
544
|
return self.lockedFitToWindow
|
|
378
545
|
},
|
|
@@ -380,10 +547,10 @@ export default function CircularView(pluginManager: PluginManager) {
|
|
|
380
547
|
)
|
|
381
548
|
}
|
|
382
549
|
|
|
383
|
-
export type CircularViewStateModel = ReturnType<typeof
|
|
550
|
+
export type CircularViewStateModel = ReturnType<typeof stateModelFactory>
|
|
384
551
|
export type CircularViewModel = Instance<CircularViewStateModel>
|
|
385
552
|
|
|
386
|
-
|
|
553
|
+
/**
|
|
387
554
|
PLANS
|
|
388
555
|
|
|
389
556
|
- tracks
|
|
@@ -391,3 +558,5 @@ PLANS
|
|
|
391
558
|
- set viewport scroll from state snapshot
|
|
392
559
|
|
|
393
560
|
*/
|
|
561
|
+
|
|
562
|
+
export default stateModelFactory
|