@jbrowse/plugin-circular-view 2.6.1 → 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.
- package/dist/BaseChordDisplay/components/BaseChordDisplay.js +0 -1
- package/dist/BaseChordDisplay/components/DisplayError.js +0 -1
- package/dist/BaseChordDisplay/components/Loading.js +0 -1
- package/dist/BaseChordDisplay/index.js +0 -1
- package/dist/BaseChordDisplay/models/configSchema.js +0 -1
- package/dist/BaseChordDisplay/models/model.js +0 -1
- package/dist/BaseChordDisplay/models/renderReaction.js +0 -1
- package/dist/CircularView/components/CircularView.js +0 -1
- package/dist/CircularView/components/Controls.js +0 -1
- package/dist/CircularView/components/ExportSvgDialog.js +0 -1
- package/dist/CircularView/components/ImportForm.js +0 -1
- package/dist/CircularView/components/Ruler.js +0 -1
- package/dist/CircularView/index.js +0 -1
- package/dist/CircularView/models/CircularView.js +0 -1
- package/dist/CircularView/models/slices.js +0 -1
- package/dist/CircularView/models/viewportVisibleRegion.js +0 -1
- package/dist/CircularView/svgcomponents/SVGBackground.js +2 -2
- package/dist/CircularView/svgcomponents/SVGCircularView.js +0 -1
- package/dist/LaunchCircularView/index.js +0 -1
- package/dist/index.js +0 -1
- package/esm/BaseChordDisplay/components/BaseChordDisplay.js +0 -1
- package/esm/BaseChordDisplay/components/DisplayError.js +0 -1
- package/esm/BaseChordDisplay/components/Loading.js +0 -1
- package/esm/BaseChordDisplay/index.js +0 -1
- package/esm/BaseChordDisplay/models/configSchema.js +0 -1
- package/esm/BaseChordDisplay/models/model.js +0 -1
- package/esm/BaseChordDisplay/models/renderReaction.js +0 -1
- package/esm/CircularView/components/CircularView.js +0 -1
- package/esm/CircularView/components/Controls.js +0 -1
- package/esm/CircularView/components/ExportSvgDialog.js +0 -1
- package/esm/CircularView/components/ImportForm.js +0 -1
- package/esm/CircularView/components/Ruler.js +0 -1
- package/esm/CircularView/index.js +0 -1
- package/esm/CircularView/models/CircularView.js +0 -1
- package/esm/CircularView/models/slices.js +0 -1
- package/esm/CircularView/models/viewportVisibleRegion.js +0 -1
- package/esm/CircularView/svgcomponents/SVGBackground.js +2 -2
- package/esm/CircularView/svgcomponents/SVGCircularView.js +0 -1
- package/esm/LaunchCircularView/index.js +0 -1
- package/esm/index.js +0 -1
- package/package.json +4 -4
- package/dist/BaseChordDisplay/components/BaseChordDisplay.js.map +0 -1
- package/dist/BaseChordDisplay/components/DisplayError.js.map +0 -1
- package/dist/BaseChordDisplay/components/Loading.js.map +0 -1
- package/dist/BaseChordDisplay/index.js.map +0 -1
- package/dist/BaseChordDisplay/models/configSchema.js.map +0 -1
- package/dist/BaseChordDisplay/models/model.js.map +0 -1
- package/dist/BaseChordDisplay/models/renderReaction.js.map +0 -1
- package/dist/CircularView/components/CircularView.js.map +0 -1
- package/dist/CircularView/components/Controls.js.map +0 -1
- package/dist/CircularView/components/ExportSvgDialog.js.map +0 -1
- package/dist/CircularView/components/ImportForm.js.map +0 -1
- package/dist/CircularView/components/Ruler.js.map +0 -1
- package/dist/CircularView/index.js.map +0 -1
- package/dist/CircularView/models/CircularView.js.map +0 -1
- package/dist/CircularView/models/slices.js.map +0 -1
- package/dist/CircularView/models/viewportVisibleRegion.js.map +0 -1
- package/dist/CircularView/svgcomponents/SVGBackground.js.map +0 -1
- package/dist/CircularView/svgcomponents/SVGCircularView.js.map +0 -1
- package/dist/LaunchCircularView/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/esm/BaseChordDisplay/components/BaseChordDisplay.js.map +0 -1
- package/esm/BaseChordDisplay/components/DisplayError.js.map +0 -1
- package/esm/BaseChordDisplay/components/Loading.js.map +0 -1
- package/esm/BaseChordDisplay/index.js.map +0 -1
- package/esm/BaseChordDisplay/models/configSchema.js.map +0 -1
- package/esm/BaseChordDisplay/models/model.js.map +0 -1
- package/esm/BaseChordDisplay/models/renderReaction.js.map +0 -1
- package/esm/CircularView/components/CircularView.js.map +0 -1
- package/esm/CircularView/components/Controls.js.map +0 -1
- package/esm/CircularView/components/ExportSvgDialog.js.map +0 -1
- package/esm/CircularView/components/ImportForm.js.map +0 -1
- package/esm/CircularView/components/Ruler.js.map +0 -1
- package/esm/CircularView/index.js.map +0 -1
- package/esm/CircularView/models/CircularView.js.map +0 -1
- package/esm/CircularView/models/slices.js.map +0 -1
- package/esm/CircularView/models/viewportVisibleRegion.js.map +0 -1
- package/esm/CircularView/svgcomponents/SVGBackground.js.map +0 -1
- package/esm/CircularView/svgcomponents/SVGCircularView.js.map +0 -1
- package/esm/LaunchCircularView/index.js.map +0 -1
- package/esm/index.js.map +0 -1
- package/src/BaseChordDisplay/components/BaseChordDisplay.tsx +0 -26
- package/src/BaseChordDisplay/components/DisplayError.tsx +0 -47
- package/src/BaseChordDisplay/components/Loading.tsx +0 -111
- package/src/BaseChordDisplay/index.ts +0 -3
- package/src/BaseChordDisplay/models/configSchema.ts +0 -30
- package/src/BaseChordDisplay/models/model.tsx +0 -314
- package/src/BaseChordDisplay/models/renderReaction.ts +0 -75
- package/src/CircularView/components/CircularView.tsx +0 -128
- package/src/CircularView/components/Controls.tsx +0 -119
- package/src/CircularView/components/ExportSvgDialog.tsx +0 -132
- package/src/CircularView/components/ImportForm.tsx +0 -68
- package/src/CircularView/components/Ruler.tsx +0 -265
- package/src/CircularView/index.ts +0 -16
- package/src/CircularView/models/CircularView.ts +0 -621
- package/src/CircularView/models/__snapshots__/slices.test.js.snap +0 -91
- package/src/CircularView/models/slices.test.js +0 -70
- package/src/CircularView/models/slices.ts +0 -101
- package/src/CircularView/models/viewportVisibleRegion.test.js +0 -168
- package/src/CircularView/models/viewportVisibleRegion.ts +0 -272
- package/src/CircularView/svgcomponents/SVGBackground.tsx +0 -21
- package/src/CircularView/svgcomponents/SVGCircularView.tsx +0 -58
- package/src/LaunchCircularView/index.ts +0 -48
- package/src/index.ts +0 -43
|
@@ -1,621 +0,0 @@
|
|
|
1
|
-
import React, { lazy } from 'react'
|
|
2
|
-
import PluginManager from '@jbrowse/core/PluginManager'
|
|
3
|
-
import {
|
|
4
|
-
cast,
|
|
5
|
-
getParent,
|
|
6
|
-
getRoot,
|
|
7
|
-
resolveIdentifier,
|
|
8
|
-
types,
|
|
9
|
-
SnapshotOrInstance,
|
|
10
|
-
Instance,
|
|
11
|
-
} from 'mobx-state-tree'
|
|
12
|
-
import { Region } from '@jbrowse/core/util/types/mst'
|
|
13
|
-
import { transaction } from 'mobx'
|
|
14
|
-
import { saveAs } from 'file-saver'
|
|
15
|
-
import {
|
|
16
|
-
AnyConfigurationModel,
|
|
17
|
-
readConfObject,
|
|
18
|
-
} from '@jbrowse/core/configuration'
|
|
19
|
-
import { MenuItem } from '@jbrowse/core/ui'
|
|
20
|
-
import {
|
|
21
|
-
getSession,
|
|
22
|
-
clamp,
|
|
23
|
-
isSessionModelWithWidgets,
|
|
24
|
-
} from '@jbrowse/core/util'
|
|
25
|
-
import { BaseViewModel } from '@jbrowse/core/pluggableElementTypes/models'
|
|
26
|
-
|
|
27
|
-
// icons
|
|
28
|
-
import { TrackSelector as TrackSelectorIcon } from '@jbrowse/core/ui/Icons'
|
|
29
|
-
import FolderOpenIcon from '@mui/icons-material/FolderOpen'
|
|
30
|
-
import PhotoCameraIcon from '@mui/icons-material/PhotoCamera'
|
|
31
|
-
|
|
32
|
-
// locals
|
|
33
|
-
import { calculateStaticSlices, sliceIsVisible, SliceRegion } from './slices'
|
|
34
|
-
import { viewportVisibleSection } from './viewportVisibleRegion'
|
|
35
|
-
|
|
36
|
-
// lazies
|
|
37
|
-
const ExportSvgDialog = lazy(() => import('../components/ExportSvgDialog'))
|
|
38
|
-
|
|
39
|
-
export interface ExportSvgOptions {
|
|
40
|
-
rasterizeLayers?: boolean
|
|
41
|
-
filename?: string
|
|
42
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
43
|
-
Wrapper?: React.FC<any>
|
|
44
|
-
themeName?: string
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* #stateModel CircularView
|
|
49
|
-
* extends `BaseViewModel`
|
|
50
|
-
*/
|
|
51
|
-
function stateModelFactory(pluginManager: PluginManager) {
|
|
52
|
-
const minHeight = 40
|
|
53
|
-
const minWidth = 100
|
|
54
|
-
const defaultHeight = 400
|
|
55
|
-
return types
|
|
56
|
-
.compose(
|
|
57
|
-
BaseViewModel,
|
|
58
|
-
types.model('CircularView', {
|
|
59
|
-
/**
|
|
60
|
-
* #property
|
|
61
|
-
*/
|
|
62
|
-
type: types.literal('CircularView'),
|
|
63
|
-
/**
|
|
64
|
-
* #property
|
|
65
|
-
* similar to offsetPx in linear genome view
|
|
66
|
-
*/
|
|
67
|
-
offsetRadians: -Math.PI / 2,
|
|
68
|
-
/**
|
|
69
|
-
* #property
|
|
70
|
-
*/
|
|
71
|
-
bpPerPx: 200,
|
|
72
|
-
/**
|
|
73
|
-
* #property
|
|
74
|
-
*/
|
|
75
|
-
tracks: types.array(
|
|
76
|
-
pluginManager.pluggableMstType('track', 'stateModel'),
|
|
77
|
-
),
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* #property
|
|
81
|
-
*/
|
|
82
|
-
hideVerticalResizeHandle: false,
|
|
83
|
-
/**
|
|
84
|
-
* #property
|
|
85
|
-
*/
|
|
86
|
-
hideTrackSelectorButton: false,
|
|
87
|
-
/**
|
|
88
|
-
* #property
|
|
89
|
-
*/
|
|
90
|
-
lockedFitToWindow: true,
|
|
91
|
-
/**
|
|
92
|
-
* #property
|
|
93
|
-
*/
|
|
94
|
-
disableImportForm: false,
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* #property
|
|
98
|
-
*/
|
|
99
|
-
height: types.optional(
|
|
100
|
-
types.refinement('trackHeight', types.number, n => n >= minHeight),
|
|
101
|
-
defaultHeight,
|
|
102
|
-
),
|
|
103
|
-
/**
|
|
104
|
-
* #property
|
|
105
|
-
*/
|
|
106
|
-
displayedRegions: types.array(Region),
|
|
107
|
-
/**
|
|
108
|
-
* #property
|
|
109
|
-
*/
|
|
110
|
-
scrollX: 0,
|
|
111
|
-
/**
|
|
112
|
-
* #property
|
|
113
|
-
*/
|
|
114
|
-
scrollY: 0,
|
|
115
|
-
|
|
116
|
-
minimumRadiusPx: 25,
|
|
117
|
-
spacingPx: 10,
|
|
118
|
-
paddingPx: 80,
|
|
119
|
-
lockedPaddingPx: 100,
|
|
120
|
-
minVisibleWidth: 6,
|
|
121
|
-
minimumBlockWidth: 20,
|
|
122
|
-
|
|
123
|
-
trackSelectorType: 'hierarchical',
|
|
124
|
-
}),
|
|
125
|
-
)
|
|
126
|
-
.volatile(() => ({
|
|
127
|
-
volatileWidth: undefined as number | undefined,
|
|
128
|
-
error: undefined as unknown,
|
|
129
|
-
}))
|
|
130
|
-
.views(self => ({
|
|
131
|
-
/**
|
|
132
|
-
* #getter
|
|
133
|
-
*/
|
|
134
|
-
get width() {
|
|
135
|
-
if (self.volatileWidth === undefined) {
|
|
136
|
-
throw new Error(
|
|
137
|
-
'wait for view to be initialized first before accessing width',
|
|
138
|
-
)
|
|
139
|
-
}
|
|
140
|
-
return self.volatileWidth
|
|
141
|
-
},
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* #getter
|
|
145
|
-
*/
|
|
146
|
-
get visibleSection() {
|
|
147
|
-
return viewportVisibleSection(
|
|
148
|
-
[
|
|
149
|
-
self.scrollX,
|
|
150
|
-
self.scrollX + self.width,
|
|
151
|
-
self.scrollY,
|
|
152
|
-
self.scrollY + self.height,
|
|
153
|
-
],
|
|
154
|
-
this.centerXY,
|
|
155
|
-
this.radiusPx,
|
|
156
|
-
)
|
|
157
|
-
},
|
|
158
|
-
/**
|
|
159
|
-
* #getter
|
|
160
|
-
*/
|
|
161
|
-
get circumferencePx() {
|
|
162
|
-
let elidedBp = 0
|
|
163
|
-
|
|
164
|
-
for (const r of this.elidedRegions) {
|
|
165
|
-
elidedBp += r.widthBp
|
|
166
|
-
}
|
|
167
|
-
return (
|
|
168
|
-
elidedBp / self.bpPerPx + self.spacingPx * this.elidedRegions.length
|
|
169
|
-
)
|
|
170
|
-
},
|
|
171
|
-
/**
|
|
172
|
-
* #getter
|
|
173
|
-
*/
|
|
174
|
-
get radiusPx() {
|
|
175
|
-
return this.circumferencePx / (2 * Math.PI)
|
|
176
|
-
},
|
|
177
|
-
/**
|
|
178
|
-
* #getter
|
|
179
|
-
*/
|
|
180
|
-
get bpPerRadian() {
|
|
181
|
-
return self.bpPerPx * this.radiusPx
|
|
182
|
-
},
|
|
183
|
-
/**
|
|
184
|
-
* #getter
|
|
185
|
-
*/
|
|
186
|
-
get pxPerRadian() {
|
|
187
|
-
return this.radiusPx
|
|
188
|
-
},
|
|
189
|
-
/**
|
|
190
|
-
* #getter
|
|
191
|
-
*/
|
|
192
|
-
get centerXY(): [number, number] {
|
|
193
|
-
return [this.radiusPx + self.paddingPx, this.radiusPx + self.paddingPx]
|
|
194
|
-
},
|
|
195
|
-
/**
|
|
196
|
-
* #getter
|
|
197
|
-
*/
|
|
198
|
-
get totalBp() {
|
|
199
|
-
let total = 0
|
|
200
|
-
for (const region of self.displayedRegions) {
|
|
201
|
-
total += region.end - region.start
|
|
202
|
-
}
|
|
203
|
-
return total
|
|
204
|
-
},
|
|
205
|
-
/**
|
|
206
|
-
* #getter
|
|
207
|
-
*/
|
|
208
|
-
get maximumRadiusPx() {
|
|
209
|
-
return self.lockedFitToWindow
|
|
210
|
-
? Math.min(self.width, self.height) / 2 - self.lockedPaddingPx
|
|
211
|
-
: 1000000
|
|
212
|
-
},
|
|
213
|
-
/**
|
|
214
|
-
* #getter
|
|
215
|
-
*/
|
|
216
|
-
get maxBpPerPx() {
|
|
217
|
-
const minCircumferencePx = 2 * Math.PI * self.minimumRadiusPx
|
|
218
|
-
return this.totalBp / minCircumferencePx
|
|
219
|
-
},
|
|
220
|
-
/**
|
|
221
|
-
* #getter
|
|
222
|
-
*/
|
|
223
|
-
get minBpPerPx() {
|
|
224
|
-
// min depends on window dimensions, clamp between old min(0.01) and max
|
|
225
|
-
const maxCircumferencePx = 2 * Math.PI * this.maximumRadiusPx
|
|
226
|
-
return clamp(
|
|
227
|
-
this.totalBp / maxCircumferencePx,
|
|
228
|
-
0.0000000001,
|
|
229
|
-
this.maxBpPerPx,
|
|
230
|
-
)
|
|
231
|
-
},
|
|
232
|
-
/**
|
|
233
|
-
* #getter
|
|
234
|
-
*/
|
|
235
|
-
get atMaxBpPerPx() {
|
|
236
|
-
return self.bpPerPx >= this.maxBpPerPx
|
|
237
|
-
},
|
|
238
|
-
/**
|
|
239
|
-
* #getter
|
|
240
|
-
*/
|
|
241
|
-
get atMinBpPerPx() {
|
|
242
|
-
return self.bpPerPx <= this.minBpPerPx
|
|
243
|
-
},
|
|
244
|
-
/**
|
|
245
|
-
* #getter
|
|
246
|
-
*/
|
|
247
|
-
get tooSmallToLock() {
|
|
248
|
-
return this.minBpPerPx <= 0.0000000001
|
|
249
|
-
},
|
|
250
|
-
/**
|
|
251
|
-
* #getter
|
|
252
|
-
*/
|
|
253
|
-
get figureDimensions(): [number, number] {
|
|
254
|
-
return [
|
|
255
|
-
this.radiusPx * 2 + 2 * self.paddingPx,
|
|
256
|
-
this.radiusPx * 2 + 2 * self.paddingPx,
|
|
257
|
-
]
|
|
258
|
-
},
|
|
259
|
-
/**
|
|
260
|
-
* #getter
|
|
261
|
-
*/
|
|
262
|
-
get figureWidth() {
|
|
263
|
-
return this.figureDimensions[0]
|
|
264
|
-
},
|
|
265
|
-
/**
|
|
266
|
-
* #getter
|
|
267
|
-
*/
|
|
268
|
-
get figureHeight() {
|
|
269
|
-
return this.figureDimensions[1]
|
|
270
|
-
},
|
|
271
|
-
/**
|
|
272
|
-
* #getter
|
|
273
|
-
* this is displayedRegions, post-processed to
|
|
274
|
-
* elide regions that are too small to see reasonably
|
|
275
|
-
*/
|
|
276
|
-
get elidedRegions() {
|
|
277
|
-
const visible: SliceRegion[] = []
|
|
278
|
-
self.displayedRegions.forEach(region => {
|
|
279
|
-
const widthBp = region.end - region.start
|
|
280
|
-
const widthPx = widthBp / self.bpPerPx
|
|
281
|
-
if (widthPx < self.minVisibleWidth) {
|
|
282
|
-
// too small to see, collapse into a single elision region
|
|
283
|
-
const lastVisible = visible.at(-1)
|
|
284
|
-
if (lastVisible?.elided) {
|
|
285
|
-
lastVisible.regions.push({ ...region })
|
|
286
|
-
lastVisible.widthBp += widthBp
|
|
287
|
-
} else {
|
|
288
|
-
visible.push({
|
|
289
|
-
elided: true,
|
|
290
|
-
widthBp,
|
|
291
|
-
regions: [{ ...region }],
|
|
292
|
-
})
|
|
293
|
-
}
|
|
294
|
-
} else {
|
|
295
|
-
// big enough to see, display it
|
|
296
|
-
visible.push({ ...region, widthBp, elided: false })
|
|
297
|
-
}
|
|
298
|
-
})
|
|
299
|
-
|
|
300
|
-
// remove any single-region elisions
|
|
301
|
-
for (let i = 0; i < visible.length; i += 1) {
|
|
302
|
-
const v = visible[i]
|
|
303
|
-
if (v.elided && v.regions.length === 1) {
|
|
304
|
-
visible[i] = { ...v, ...v.regions[0], elided: false }
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return visible
|
|
308
|
-
},
|
|
309
|
-
/**
|
|
310
|
-
* #getter
|
|
311
|
-
*/
|
|
312
|
-
get assemblyNames() {
|
|
313
|
-
const assemblyNames: string[] = []
|
|
314
|
-
self.displayedRegions.forEach(displayedRegion => {
|
|
315
|
-
if (!assemblyNames.includes(displayedRegion.assemblyName)) {
|
|
316
|
-
assemblyNames.push(displayedRegion.assemblyName)
|
|
317
|
-
}
|
|
318
|
-
})
|
|
319
|
-
return assemblyNames
|
|
320
|
-
},
|
|
321
|
-
/**
|
|
322
|
-
* #getter
|
|
323
|
-
*/
|
|
324
|
-
get initialized() {
|
|
325
|
-
const { assemblyManager } = getSession(self)
|
|
326
|
-
return (
|
|
327
|
-
self.volatileWidth !== undefined &&
|
|
328
|
-
this.assemblyNames.every(a => assemblyManager.get(a)?.initialized)
|
|
329
|
-
)
|
|
330
|
-
},
|
|
331
|
-
}))
|
|
332
|
-
.views(self => ({
|
|
333
|
-
/**
|
|
334
|
-
* #getter
|
|
335
|
-
*/
|
|
336
|
-
get staticSlices() {
|
|
337
|
-
return calculateStaticSlices(self)
|
|
338
|
-
},
|
|
339
|
-
}))
|
|
340
|
-
.views(self => ({
|
|
341
|
-
/**
|
|
342
|
-
* #getter
|
|
343
|
-
*/
|
|
344
|
-
get visibleStaticSlices() {
|
|
345
|
-
return self.staticSlices.filter(s => sliceIsVisible(self, s))
|
|
346
|
-
},
|
|
347
|
-
}))
|
|
348
|
-
|
|
349
|
-
.actions(self => ({
|
|
350
|
-
/**
|
|
351
|
-
* #action
|
|
352
|
-
*/
|
|
353
|
-
setWidth(newWidth: number) {
|
|
354
|
-
self.volatileWidth = Math.max(newWidth, minWidth)
|
|
355
|
-
return self.volatileWidth
|
|
356
|
-
},
|
|
357
|
-
/**
|
|
358
|
-
* #action
|
|
359
|
-
*/
|
|
360
|
-
setHeight(newHeight: number) {
|
|
361
|
-
self.height = Math.max(newHeight, minHeight)
|
|
362
|
-
return self.height
|
|
363
|
-
},
|
|
364
|
-
/**
|
|
365
|
-
* #action
|
|
366
|
-
*/
|
|
367
|
-
resizeHeight(distance: number) {
|
|
368
|
-
const oldHeight = self.height
|
|
369
|
-
const newHeight = this.setHeight(self.height + distance)
|
|
370
|
-
this.setModelViewWhenAdjust(!self.tooSmallToLock)
|
|
371
|
-
return newHeight - oldHeight
|
|
372
|
-
},
|
|
373
|
-
/**
|
|
374
|
-
* #action
|
|
375
|
-
*/
|
|
376
|
-
resizeWidth(distance: number) {
|
|
377
|
-
const oldWidth = self.width
|
|
378
|
-
const newWidth = this.setWidth(self.width + distance)
|
|
379
|
-
this.setModelViewWhenAdjust(!self.tooSmallToLock)
|
|
380
|
-
return newWidth - oldWidth
|
|
381
|
-
},
|
|
382
|
-
/**
|
|
383
|
-
* #action
|
|
384
|
-
*/
|
|
385
|
-
rotateClockwiseButton() {
|
|
386
|
-
this.rotateClockwise(Math.PI / 6)
|
|
387
|
-
},
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
* #action
|
|
391
|
-
*/
|
|
392
|
-
rotateCounterClockwiseButton() {
|
|
393
|
-
this.rotateCounterClockwise(Math.PI / 6)
|
|
394
|
-
},
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* #action
|
|
398
|
-
*/
|
|
399
|
-
rotateClockwise(distance = 0.17) {
|
|
400
|
-
self.offsetRadians += distance
|
|
401
|
-
},
|
|
402
|
-
|
|
403
|
-
/**
|
|
404
|
-
* #action
|
|
405
|
-
*/
|
|
406
|
-
rotateCounterClockwise(distance = 0.17) {
|
|
407
|
-
self.offsetRadians -= distance
|
|
408
|
-
},
|
|
409
|
-
|
|
410
|
-
/**
|
|
411
|
-
* #action
|
|
412
|
-
*/
|
|
413
|
-
zoomInButton() {
|
|
414
|
-
this.setBpPerPx(self.bpPerPx / 1.4)
|
|
415
|
-
},
|
|
416
|
-
|
|
417
|
-
/**
|
|
418
|
-
* #action
|
|
419
|
-
*/
|
|
420
|
-
zoomOutButton() {
|
|
421
|
-
this.setBpPerPx(self.bpPerPx * 1.4)
|
|
422
|
-
},
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* #action
|
|
426
|
-
*/
|
|
427
|
-
setBpPerPx(newVal: number) {
|
|
428
|
-
self.bpPerPx = clamp(newVal, self.minBpPerPx, self.maxBpPerPx)
|
|
429
|
-
},
|
|
430
|
-
|
|
431
|
-
/**
|
|
432
|
-
* #action
|
|
433
|
-
*/
|
|
434
|
-
setModelViewWhenAdjust(secondCondition: boolean) {
|
|
435
|
-
if (self.lockedFitToWindow && secondCondition) {
|
|
436
|
-
this.setBpPerPx(self.minBpPerPx)
|
|
437
|
-
}
|
|
438
|
-
},
|
|
439
|
-
|
|
440
|
-
/**
|
|
441
|
-
* #action
|
|
442
|
-
*/
|
|
443
|
-
closeView() {
|
|
444
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
445
|
-
getParent<any>(self, 2).removeView(self)
|
|
446
|
-
},
|
|
447
|
-
|
|
448
|
-
/**
|
|
449
|
-
* #action
|
|
450
|
-
*/
|
|
451
|
-
setDisplayedRegions(regions: SnapshotOrInstance<typeof Region>[]) {
|
|
452
|
-
const previouslyEmpty = self.displayedRegions.length === 0
|
|
453
|
-
self.displayedRegions = cast(regions)
|
|
454
|
-
|
|
455
|
-
if (previouslyEmpty) {
|
|
456
|
-
this.setBpPerPx(self.minBpPerPx)
|
|
457
|
-
} else {
|
|
458
|
-
this.setBpPerPx(self.bpPerPx)
|
|
459
|
-
}
|
|
460
|
-
},
|
|
461
|
-
|
|
462
|
-
/**
|
|
463
|
-
* #action
|
|
464
|
-
*/
|
|
465
|
-
activateTrackSelector() {
|
|
466
|
-
if (self.trackSelectorType === 'hierarchical') {
|
|
467
|
-
const session = getSession(self)
|
|
468
|
-
if (isSessionModelWithWidgets(session)) {
|
|
469
|
-
const selector = session.addWidget(
|
|
470
|
-
'HierarchicalTrackSelectorWidget',
|
|
471
|
-
'hierarchicalTrackSelector',
|
|
472
|
-
{ view: self },
|
|
473
|
-
)
|
|
474
|
-
session.showWidget(selector)
|
|
475
|
-
return selector
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
throw new Error(`invalid track selector type ${self.trackSelectorType}`)
|
|
479
|
-
},
|
|
480
|
-
|
|
481
|
-
/**
|
|
482
|
-
* #action
|
|
483
|
-
*/
|
|
484
|
-
toggleTrack(trackId: string) {
|
|
485
|
-
// if we have any tracks with that configuration, turn them off
|
|
486
|
-
const hiddenCount = this.hideTrack(trackId)
|
|
487
|
-
// if none had that configuration, turn one on
|
|
488
|
-
if (!hiddenCount) {
|
|
489
|
-
this.showTrack(trackId)
|
|
490
|
-
}
|
|
491
|
-
},
|
|
492
|
-
|
|
493
|
-
/**
|
|
494
|
-
* #action
|
|
495
|
-
*/
|
|
496
|
-
setError(error: unknown) {
|
|
497
|
-
self.error = error
|
|
498
|
-
},
|
|
499
|
-
|
|
500
|
-
/**
|
|
501
|
-
* #action
|
|
502
|
-
*/
|
|
503
|
-
showTrack(trackId: string, initialSnapshot = {}) {
|
|
504
|
-
const schema = pluginManager.pluggableConfigSchemaType('track')
|
|
505
|
-
const conf = resolveIdentifier(schema, getRoot(self), trackId)
|
|
506
|
-
const trackType = pluginManager.getTrackType(conf.type)
|
|
507
|
-
if (!trackType) {
|
|
508
|
-
throw new Error(`unknown track type ${conf.type}`)
|
|
509
|
-
}
|
|
510
|
-
const viewType = pluginManager.getViewType(self.type)
|
|
511
|
-
const supportedDisplays = new Set(
|
|
512
|
-
viewType.displayTypes.map(d => d.name),
|
|
513
|
-
)
|
|
514
|
-
const displayConf = conf.displays.find((d: AnyConfigurationModel) =>
|
|
515
|
-
supportedDisplays.has(d.type),
|
|
516
|
-
)
|
|
517
|
-
const track = trackType.stateModel.create({
|
|
518
|
-
...initialSnapshot,
|
|
519
|
-
type: conf.type,
|
|
520
|
-
configuration: conf,
|
|
521
|
-
displays: [{ type: displayConf.type, configuration: displayConf }],
|
|
522
|
-
})
|
|
523
|
-
self.tracks.push(track)
|
|
524
|
-
},
|
|
525
|
-
|
|
526
|
-
/**
|
|
527
|
-
* #action
|
|
528
|
-
*/
|
|
529
|
-
addTrackConf(configuration: AnyConfigurationModel, initialSnapshot = {}) {
|
|
530
|
-
const { type } = configuration
|
|
531
|
-
const name = readConfObject(configuration, 'name')
|
|
532
|
-
const trackType = pluginManager.getTrackType(type)
|
|
533
|
-
if (!trackType) {
|
|
534
|
-
throw new Error(`unknown track type ${type}`)
|
|
535
|
-
}
|
|
536
|
-
const viewType = pluginManager.getViewType(self.type)
|
|
537
|
-
const supportedDisplays = new Set(
|
|
538
|
-
viewType.displayTypes.map(d => d.name),
|
|
539
|
-
)
|
|
540
|
-
const displayConf = configuration.displays.find(
|
|
541
|
-
(d: AnyConfigurationModel) => supportedDisplays.has(d.type),
|
|
542
|
-
)
|
|
543
|
-
self.tracks.push(
|
|
544
|
-
trackType.stateModel.create({
|
|
545
|
-
...initialSnapshot,
|
|
546
|
-
name,
|
|
547
|
-
type,
|
|
548
|
-
configuration,
|
|
549
|
-
displays: [{ type: displayConf.type, configuration: displayConf }],
|
|
550
|
-
}),
|
|
551
|
-
)
|
|
552
|
-
},
|
|
553
|
-
|
|
554
|
-
/**
|
|
555
|
-
* #action
|
|
556
|
-
*/
|
|
557
|
-
hideTrack(trackId: string) {
|
|
558
|
-
const schema = pluginManager.pluggableConfigSchemaType('track')
|
|
559
|
-
const conf = resolveIdentifier(schema, getRoot(self), trackId)
|
|
560
|
-
const t = self.tracks.filter(t => t.configuration === conf)
|
|
561
|
-
transaction(() => t.forEach(t => self.tracks.remove(t)))
|
|
562
|
-
return t.length
|
|
563
|
-
},
|
|
564
|
-
|
|
565
|
-
/**
|
|
566
|
-
* #action
|
|
567
|
-
*/
|
|
568
|
-
toggleFitToWindowLock() {
|
|
569
|
-
// when going unlocked -> locked and circle is cut off, set to the
|
|
570
|
-
// locked minBpPerPx
|
|
571
|
-
self.lockedFitToWindow = !self.lockedFitToWindow
|
|
572
|
-
this.setModelViewWhenAdjust(self.atMinBpPerPx)
|
|
573
|
-
return self.lockedFitToWindow
|
|
574
|
-
},
|
|
575
|
-
/**
|
|
576
|
-
* #action
|
|
577
|
-
* creates an svg export and save using FileSaver
|
|
578
|
-
*/
|
|
579
|
-
async exportSvg(opts: ExportSvgOptions = {}) {
|
|
580
|
-
const { renderToSvg } = await import('../svgcomponents/SVGCircularView')
|
|
581
|
-
const html = await renderToSvg(self as CircularViewModel, opts)
|
|
582
|
-
const blob = new Blob([html], { type: 'image/svg+xml' })
|
|
583
|
-
saveAs(blob, opts.filename || 'image.svg')
|
|
584
|
-
},
|
|
585
|
-
}))
|
|
586
|
-
.views(self => ({
|
|
587
|
-
/**
|
|
588
|
-
* #method
|
|
589
|
-
* return the view menu items
|
|
590
|
-
*/
|
|
591
|
-
menuItems(): MenuItem[] {
|
|
592
|
-
return [
|
|
593
|
-
{
|
|
594
|
-
label: 'Return to import form',
|
|
595
|
-
onClick: () => self.setDisplayedRegions([]),
|
|
596
|
-
icon: FolderOpenIcon,
|
|
597
|
-
},
|
|
598
|
-
{
|
|
599
|
-
label: 'Export SVG',
|
|
600
|
-
icon: PhotoCameraIcon,
|
|
601
|
-
onClick: () => {
|
|
602
|
-
getSession(self).queueDialog(handleClose => [
|
|
603
|
-
ExportSvgDialog,
|
|
604
|
-
{ model: self, handleClose },
|
|
605
|
-
])
|
|
606
|
-
},
|
|
607
|
-
},
|
|
608
|
-
{
|
|
609
|
-
label: 'Open track selector',
|
|
610
|
-
onClick: self.activateTrackSelector,
|
|
611
|
-
icon: TrackSelectorIcon,
|
|
612
|
-
},
|
|
613
|
-
]
|
|
614
|
-
},
|
|
615
|
-
}))
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
export type CircularViewStateModel = ReturnType<typeof stateModelFactory>
|
|
619
|
-
export type CircularViewModel = Instance<CircularViewStateModel>
|
|
620
|
-
|
|
621
|
-
export default stateModelFactory
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`one slice 1`] = `
|
|
4
|
-
{
|
|
5
|
-
"bpPerRadian": 1591.5494309189535,
|
|
6
|
-
"endRadians": 6.283185307179586,
|
|
7
|
-
"flipped": false,
|
|
8
|
-
"key": "toast:1..10,000",
|
|
9
|
-
"offsetRadians": 0,
|
|
10
|
-
"radianWidth": 6.288185307179586,
|
|
11
|
-
"region": {
|
|
12
|
-
"end": 10000,
|
|
13
|
-
"refName": "toast",
|
|
14
|
-
"start": 0,
|
|
15
|
-
"widthBp": 10000,
|
|
16
|
-
},
|
|
17
|
-
"startRadians": 0,
|
|
18
|
-
}
|
|
19
|
-
`;
|
|
20
|
-
|
|
21
|
-
exports[`two slices 1`] = `
|
|
22
|
-
[
|
|
23
|
-
{
|
|
24
|
-
"bpPerRadian": 3183.098861837907,
|
|
25
|
-
"endRadians": 3.141592653589793,
|
|
26
|
-
"flipped": false,
|
|
27
|
-
"key": "toast:1..10,000",
|
|
28
|
-
"offsetRadians": 0,
|
|
29
|
-
"radianWidth": 3.146592653589793,
|
|
30
|
-
"region": {
|
|
31
|
-
"end": 10000,
|
|
32
|
-
"refName": "toast",
|
|
33
|
-
"start": 0,
|
|
34
|
-
"widthBp": 10000,
|
|
35
|
-
},
|
|
36
|
-
"startRadians": 0,
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"bpPerRadian": 3183.098861837907,
|
|
40
|
-
"endRadians": 6.288185307179586,
|
|
41
|
-
"flipped": false,
|
|
42
|
-
"key": "teest:1..10,000",
|
|
43
|
-
"offsetRadians": 3.146592653589793,
|
|
44
|
-
"radianWidth": 3.146592653589793,
|
|
45
|
-
"region": {
|
|
46
|
-
"end": 10000,
|
|
47
|
-
"refName": "teest",
|
|
48
|
-
"start": 0,
|
|
49
|
-
"widthBp": 10000,
|
|
50
|
-
},
|
|
51
|
-
"startRadians": 3.146592653589793,
|
|
52
|
-
},
|
|
53
|
-
]
|
|
54
|
-
`;
|
|
55
|
-
|
|
56
|
-
exports[`volvox 1`] = `
|
|
57
|
-
[
|
|
58
|
-
{
|
|
59
|
-
"bpPerRadian": 8925.40920859349,
|
|
60
|
-
"endRadians": 5.602096086738348,
|
|
61
|
-
"flipped": false,
|
|
62
|
-
"key": "{volvox}ctgA:1..50,001",
|
|
63
|
-
"offsetRadians": 0,
|
|
64
|
-
"radianWidth": 5.6070960867383475,
|
|
65
|
-
"region": {
|
|
66
|
-
"assemblyName": "volvox",
|
|
67
|
-
"end": 50001,
|
|
68
|
-
"refName": "ctgA",
|
|
69
|
-
"start": 0,
|
|
70
|
-
"widthBp": 50001,
|
|
71
|
-
},
|
|
72
|
-
"startRadians": 0,
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
"bpPerRadian": 8925.40920859349,
|
|
76
|
-
"endRadians": 6.288185307179587,
|
|
77
|
-
"flipped": false,
|
|
78
|
-
"key": "{volvox}ctgB:1..6,079",
|
|
79
|
-
"offsetRadians": 5.6070960867383475,
|
|
80
|
-
"radianWidth": 0.6860892204412394,
|
|
81
|
-
"region": {
|
|
82
|
-
"assemblyName": "volvox",
|
|
83
|
-
"end": 6079,
|
|
84
|
-
"refName": "ctgB",
|
|
85
|
-
"start": 0,
|
|
86
|
-
"widthBp": 6079,
|
|
87
|
-
},
|
|
88
|
-
"startRadians": 5.6070960867383475,
|
|
89
|
-
},
|
|
90
|
-
]
|
|
91
|
-
`;
|