@jbrowse/plugin-circular-view 2.16.1 → 2.18.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/components/BaseChordDisplay.js +5 -4
- package/dist/BaseChordDisplay/components/Loading.js +1 -2
- package/dist/BaseChordDisplay/{models/configSchema.d.ts → configSchema.d.ts} +0 -3
- package/dist/BaseChordDisplay/{models/configSchema.js → configSchema.js} +1 -10
- package/dist/BaseChordDisplay/index.d.ts +2 -2
- package/dist/BaseChordDisplay/index.js +2 -2
- package/{esm/BaseChordDisplay/models → dist/BaseChordDisplay}/model.d.ts +11 -52
- package/dist/BaseChordDisplay/{models/model.js → model.js} +29 -89
- package/dist/BaseChordDisplay/renderReaction.d.ts +27 -0
- package/dist/BaseChordDisplay/{models/renderReaction.js → renderReaction.js} +5 -13
- package/dist/CircularView/components/CircularView.d.ts +1 -1
- package/dist/CircularView/components/CircularView.js +2 -3
- package/dist/CircularView/components/Controls.d.ts +1 -1
- package/dist/CircularView/components/Controls.js +11 -12
- package/dist/CircularView/components/ExportSvgDialog.d.ts +1 -1
- package/dist/CircularView/components/ExportSvgDialog.js +2 -4
- package/dist/CircularView/components/ImportForm.d.ts +1 -1
- package/dist/CircularView/components/ImportForm.js +3 -3
- package/dist/CircularView/components/Ruler.d.ts +2 -2
- package/dist/CircularView/components/Ruler.js +1 -7
- package/dist/CircularView/index.d.ts +1 -1
- package/dist/CircularView/index.js +1 -1
- package/dist/CircularView/{models/model.d.ts → model.d.ts} +9 -158
- package/dist/CircularView/{models/model.js → model.js} +8 -217
- package/dist/CircularView/{models/slices.d.ts → slices.d.ts} +1 -1
- package/dist/CircularView/svgcomponents/SVGBackground.js +1 -1
- package/dist/CircularView/svgcomponents/SVGCircularView.d.ts +1 -1
- package/dist/CircularView/svgcomponents/SVGCircularView.js +4 -9
- package/dist/CircularView/{models/viewportVisibleRegion.js → viewportVisibleRegion.js} +0 -70
- package/dist/LaunchCircularView/index.d.ts +1 -1
- package/dist/LaunchCircularView/index.js +1 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +5 -7
- package/esm/BaseChordDisplay/components/BaseChordDisplay.js +5 -4
- package/esm/BaseChordDisplay/components/Loading.js +2 -3
- package/esm/BaseChordDisplay/{models/configSchema.d.ts → configSchema.d.ts} +0 -3
- package/esm/BaseChordDisplay/{models/configSchema.js → configSchema.js} +1 -10
- package/esm/BaseChordDisplay/index.d.ts +2 -2
- package/esm/BaseChordDisplay/index.js +2 -2
- package/{dist/BaseChordDisplay/models → esm/BaseChordDisplay}/model.d.ts +11 -52
- package/esm/BaseChordDisplay/{models/model.js → model.js} +30 -90
- package/esm/BaseChordDisplay/renderReaction.d.ts +27 -0
- package/esm/BaseChordDisplay/{models/renderReaction.js → renderReaction.js} +5 -10
- package/esm/CircularView/components/CircularView.d.ts +1 -1
- package/esm/CircularView/components/CircularView.js +2 -3
- package/esm/CircularView/components/Controls.d.ts +1 -1
- package/esm/CircularView/components/Controls.js +11 -12
- package/esm/CircularView/components/ExportSvgDialog.d.ts +1 -1
- package/esm/CircularView/components/ExportSvgDialog.js +2 -4
- package/esm/CircularView/components/ImportForm.d.ts +1 -1
- package/esm/CircularView/components/ImportForm.js +3 -3
- package/esm/CircularView/components/Ruler.d.ts +2 -2
- package/esm/CircularView/components/Ruler.js +2 -8
- package/esm/CircularView/index.d.ts +1 -1
- package/esm/CircularView/index.js +1 -1
- package/esm/CircularView/{models/model.d.ts → model.d.ts} +9 -158
- package/esm/CircularView/{models/model.js → model.js} +9 -218
- package/esm/CircularView/{models/slices.d.ts → slices.d.ts} +1 -1
- package/esm/CircularView/{models/slices.js → slices.js} +1 -1
- package/esm/CircularView/svgcomponents/SVGBackground.js +1 -1
- package/esm/CircularView/svgcomponents/SVGCircularView.d.ts +1 -1
- package/esm/CircularView/svgcomponents/SVGCircularView.js +4 -9
- package/esm/CircularView/{models/viewportVisibleRegion.js → viewportVisibleRegion.js} +0 -70
- package/esm/LaunchCircularView/index.d.ts +1 -1
- package/esm/LaunchCircularView/index.js +1 -3
- package/esm/index.d.ts +3 -3
- package/esm/index.js +3 -5
- package/package.json +2 -3
- package/dist/BaseChordDisplay/models/renderReaction.d.ts +0 -45
- package/esm/BaseChordDisplay/models/renderReaction.d.ts +0 -45
- /package/dist/CircularView/{models/slices.js → slices.js} +0 -0
- /package/dist/CircularView/{models/viewportVisibleRegion.d.ts → viewportVisibleRegion.d.ts} +0 -0
- /package/esm/CircularView/{models/viewportVisibleRegion.d.ts → viewportVisibleRegion.d.ts} +0 -0
|
@@ -27,109 +27,42 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
const react_1 = require("react");
|
|
30
|
-
const mobx_state_tree_1 = require("mobx-state-tree");
|
|
31
|
-
const mst_1 = require("@jbrowse/core/util/types/mst");
|
|
32
|
-
const mobx_1 = require("mobx");
|
|
33
|
-
const file_saver_1 = require("file-saver");
|
|
34
30
|
const configuration_1 = require("@jbrowse/core/configuration");
|
|
35
|
-
const util_1 = require("@jbrowse/core/util");
|
|
36
31
|
const models_1 = require("@jbrowse/core/pluggableElementTypes/models");
|
|
37
|
-
// icons
|
|
38
32
|
const Icons_1 = require("@jbrowse/core/ui/Icons");
|
|
33
|
+
const util_1 = require("@jbrowse/core/util");
|
|
39
34
|
const FolderOpen_1 = __importDefault(require("@mui/icons-material/FolderOpen"));
|
|
40
35
|
const PhotoCamera_1 = __importDefault(require("@mui/icons-material/PhotoCamera"));
|
|
41
|
-
|
|
36
|
+
const file_saver_1 = require("file-saver");
|
|
37
|
+
const mobx_1 = require("mobx");
|
|
38
|
+
const mobx_state_tree_1 = require("mobx-state-tree");
|
|
42
39
|
const slices_1 = require("./slices");
|
|
43
40
|
const viewportVisibleRegion_1 = require("./viewportVisibleRegion");
|
|
44
|
-
|
|
45
|
-
const ExportSvgDialog = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('../components/ExportSvgDialog'))));
|
|
46
|
-
/**
|
|
47
|
-
* #stateModel CircularView
|
|
48
|
-
* extends
|
|
49
|
-
* - [BaseViewModel](../baseviewmodel)
|
|
50
|
-
*/
|
|
41
|
+
const ExportSvgDialog = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./components/ExportSvgDialog'))));
|
|
51
42
|
function stateModelFactory(pluginManager) {
|
|
52
43
|
const minHeight = 40;
|
|
53
44
|
const minWidth = 100;
|
|
54
45
|
const defaultHeight = 400;
|
|
55
46
|
return mobx_state_tree_1.types
|
|
56
47
|
.compose('CircularView', models_1.BaseViewModel, mobx_state_tree_1.types.model({
|
|
57
|
-
/**
|
|
58
|
-
* #property
|
|
59
|
-
*/
|
|
60
48
|
type: mobx_state_tree_1.types.literal('CircularView'),
|
|
61
|
-
/**
|
|
62
|
-
* #property
|
|
63
|
-
* similar to offsetPx in linear genome view
|
|
64
|
-
*/
|
|
65
49
|
offsetRadians: -Math.PI / 2,
|
|
66
|
-
/**
|
|
67
|
-
* #property
|
|
68
|
-
*/
|
|
69
50
|
bpPerPx: 200,
|
|
70
|
-
/**
|
|
71
|
-
* #property
|
|
72
|
-
*/
|
|
73
51
|
tracks: mobx_state_tree_1.types.array(pluginManager.pluggableMstType('track', 'stateModel')),
|
|
74
|
-
/**
|
|
75
|
-
* #property
|
|
76
|
-
*/
|
|
77
52
|
hideVerticalResizeHandle: false,
|
|
78
|
-
/**
|
|
79
|
-
* #property
|
|
80
|
-
*/
|
|
81
53
|
hideTrackSelectorButton: false,
|
|
82
|
-
/**
|
|
83
|
-
* #property
|
|
84
|
-
*/
|
|
85
54
|
lockedFitToWindow: true,
|
|
86
|
-
/**
|
|
87
|
-
* #property
|
|
88
|
-
*/
|
|
89
55
|
disableImportForm: false,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
*/
|
|
93
|
-
height: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.refinement('trackHeight', mobx_state_tree_1.types.number, n => n >= minHeight), defaultHeight),
|
|
94
|
-
/**
|
|
95
|
-
* #property
|
|
96
|
-
*/
|
|
97
|
-
displayedRegions: mobx_state_tree_1.types.array(mst_1.Region),
|
|
98
|
-
/**
|
|
99
|
-
* #property
|
|
100
|
-
*/
|
|
56
|
+
height: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.number, defaultHeight),
|
|
57
|
+
displayedRegions: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.frozen(), []),
|
|
101
58
|
scrollX: 0,
|
|
102
|
-
/**
|
|
103
|
-
* #property
|
|
104
|
-
*/
|
|
105
59
|
scrollY: 0,
|
|
106
|
-
/**
|
|
107
|
-
* #property
|
|
108
|
-
*/
|
|
109
60
|
minimumRadiusPx: 25,
|
|
110
|
-
/**
|
|
111
|
-
* #property
|
|
112
|
-
*/
|
|
113
61
|
spacingPx: 10,
|
|
114
|
-
/**
|
|
115
|
-
* #property
|
|
116
|
-
*/
|
|
117
62
|
paddingPx: 80,
|
|
118
|
-
/**
|
|
119
|
-
* #property
|
|
120
|
-
*/
|
|
121
63
|
lockedPaddingPx: 100,
|
|
122
|
-
/**
|
|
123
|
-
* #property
|
|
124
|
-
*/
|
|
125
64
|
minVisibleWidth: 6,
|
|
126
|
-
/**
|
|
127
|
-
* #property
|
|
128
|
-
*/
|
|
129
65
|
minimumBlockWidth: 20,
|
|
130
|
-
/**
|
|
131
|
-
* #property
|
|
132
|
-
*/
|
|
133
66
|
trackSelectorType: 'hierarchical',
|
|
134
67
|
}))
|
|
135
68
|
.volatile(() => ({
|
|
@@ -137,25 +70,16 @@ function stateModelFactory(pluginManager) {
|
|
|
137
70
|
error: undefined,
|
|
138
71
|
}))
|
|
139
72
|
.views(self => ({
|
|
140
|
-
/**
|
|
141
|
-
* #getter
|
|
142
|
-
*/
|
|
143
73
|
get width() {
|
|
144
74
|
if (self.volatileWidth === undefined) {
|
|
145
75
|
throw new Error('wait for view to be initialized first before accessing width');
|
|
146
76
|
}
|
|
147
77
|
return self.volatileWidth;
|
|
148
78
|
},
|
|
149
|
-
/**
|
|
150
|
-
* #getter
|
|
151
|
-
*/
|
|
152
79
|
get visibleSection() {
|
|
153
80
|
const { scrollX, scrollY, width, height } = self;
|
|
154
81
|
return (0, viewportVisibleRegion_1.viewportVisibleSection)([scrollX, scrollX + width, scrollY, scrollY + height], this.centerXY, this.radiusPx);
|
|
155
82
|
},
|
|
156
|
-
/**
|
|
157
|
-
* #getter
|
|
158
|
-
*/
|
|
159
83
|
get circumferencePx() {
|
|
160
84
|
let elidedBp = 0;
|
|
161
85
|
for (const r of this.elidedRegions) {
|
|
@@ -163,33 +87,18 @@ function stateModelFactory(pluginManager) {
|
|
|
163
87
|
}
|
|
164
88
|
return (elidedBp / self.bpPerPx + self.spacingPx * this.elidedRegions.length);
|
|
165
89
|
},
|
|
166
|
-
/**
|
|
167
|
-
* #getter
|
|
168
|
-
*/
|
|
169
90
|
get radiusPx() {
|
|
170
91
|
return this.circumferencePx / (2 * Math.PI);
|
|
171
92
|
},
|
|
172
|
-
/**
|
|
173
|
-
* #getter
|
|
174
|
-
*/
|
|
175
93
|
get bpPerRadian() {
|
|
176
94
|
return self.bpPerPx * this.radiusPx;
|
|
177
95
|
},
|
|
178
|
-
/**
|
|
179
|
-
* #getter
|
|
180
|
-
*/
|
|
181
96
|
get pxPerRadian() {
|
|
182
97
|
return this.radiusPx;
|
|
183
98
|
},
|
|
184
|
-
/**
|
|
185
|
-
* #getter
|
|
186
|
-
*/
|
|
187
99
|
get centerXY() {
|
|
188
100
|
return [this.radiusPx + self.paddingPx, this.radiusPx + self.paddingPx];
|
|
189
101
|
},
|
|
190
|
-
/**
|
|
191
|
-
* #getter
|
|
192
|
-
*/
|
|
193
102
|
get totalBp() {
|
|
194
103
|
let total = 0;
|
|
195
104
|
for (const region of self.displayedRegions) {
|
|
@@ -197,80 +106,46 @@ function stateModelFactory(pluginManager) {
|
|
|
197
106
|
}
|
|
198
107
|
return total;
|
|
199
108
|
},
|
|
200
|
-
/**
|
|
201
|
-
* #getter
|
|
202
|
-
*/
|
|
203
109
|
get maximumRadiusPx() {
|
|
204
110
|
return self.lockedFitToWindow
|
|
205
111
|
? Math.min(self.width, self.height) / 2 - self.lockedPaddingPx
|
|
206
112
|
: 1000000;
|
|
207
113
|
},
|
|
208
|
-
/**
|
|
209
|
-
* #getter
|
|
210
|
-
*/
|
|
211
114
|
get maxBpPerPx() {
|
|
212
115
|
const minCircumferencePx = 2 * Math.PI * self.minimumRadiusPx;
|
|
213
116
|
return this.totalBp / minCircumferencePx;
|
|
214
117
|
},
|
|
215
|
-
/**
|
|
216
|
-
* #getter
|
|
217
|
-
*/
|
|
218
118
|
get minBpPerPx() {
|
|
219
|
-
// min depends on window dimensions, clamp between old min(0.01) and max
|
|
220
119
|
const maxCircumferencePx = 2 * Math.PI * this.maximumRadiusPx;
|
|
221
120
|
return (0, util_1.clamp)(this.totalBp / maxCircumferencePx, 0.0000000001, this.maxBpPerPx);
|
|
222
121
|
},
|
|
223
|
-
/**
|
|
224
|
-
* #getter
|
|
225
|
-
*/
|
|
226
122
|
get atMaxBpPerPx() {
|
|
227
123
|
return self.bpPerPx >= this.maxBpPerPx;
|
|
228
124
|
},
|
|
229
|
-
/**
|
|
230
|
-
* #getter
|
|
231
|
-
*/
|
|
232
125
|
get atMinBpPerPx() {
|
|
233
126
|
return self.bpPerPx <= this.minBpPerPx;
|
|
234
127
|
},
|
|
235
|
-
/**
|
|
236
|
-
* #getter
|
|
237
|
-
*/
|
|
238
128
|
get tooSmallToLock() {
|
|
239
129
|
return this.minBpPerPx <= 0.0000000001;
|
|
240
130
|
},
|
|
241
|
-
/**
|
|
242
|
-
* #getter
|
|
243
|
-
*/
|
|
244
131
|
get figureDimensions() {
|
|
245
132
|
return [
|
|
246
133
|
this.radiusPx * 2 + 2 * self.paddingPx,
|
|
247
134
|
this.radiusPx * 2 + 2 * self.paddingPx,
|
|
248
135
|
];
|
|
249
136
|
},
|
|
250
|
-
/**
|
|
251
|
-
* #getter
|
|
252
|
-
*/
|
|
253
137
|
get figureWidth() {
|
|
254
138
|
return this.figureDimensions[0];
|
|
255
139
|
},
|
|
256
|
-
/**
|
|
257
|
-
* #getter
|
|
258
|
-
*/
|
|
259
140
|
get figureHeight() {
|
|
260
141
|
return this.figureDimensions[1];
|
|
261
142
|
},
|
|
262
|
-
/**
|
|
263
|
-
* #getter
|
|
264
|
-
* this is displayedRegions, post-processed to elide regions that are too
|
|
265
|
-
* small to see reasonably
|
|
266
|
-
*/
|
|
267
143
|
get elidedRegions() {
|
|
268
144
|
const visible = [];
|
|
269
145
|
self.displayedRegions.forEach(region => {
|
|
270
146
|
const widthBp = region.end - region.start;
|
|
271
147
|
const widthPx = widthBp / self.bpPerPx;
|
|
272
148
|
if (widthPx < self.minVisibleWidth) {
|
|
273
|
-
// too small to see, collapse into a single elision region
|
|
274
149
|
const lastVisible = visible.at(-1);
|
|
275
150
|
if (lastVisible === null || lastVisible === void 0 ? void 0 : lastVisible.elided) {
|
|
276
151
|
lastVisible.regions.push({ ...region });
|
|
@@ -285,11 +160,9 @@ function stateModelFactory(pluginManager) {
|
|
|
285
160
|
}
|
|
286
161
|
}
|
|
287
162
|
else {
|
|
288
|
-
// big enough to see, display it
|
|
289
163
|
visible.push({ ...region, widthBp, elided: false });
|
|
290
164
|
}
|
|
291
165
|
});
|
|
292
|
-
// remove any single-region elisions
|
|
293
166
|
for (let i = 0; i < visible.length; i += 1) {
|
|
294
167
|
const v = visible[i];
|
|
295
168
|
if (v.elided && v.regions.length === 1) {
|
|
@@ -298,9 +171,6 @@ function stateModelFactory(pluginManager) {
|
|
|
298
171
|
}
|
|
299
172
|
return visible;
|
|
300
173
|
},
|
|
301
|
-
/**
|
|
302
|
-
* #getter
|
|
303
|
-
*/
|
|
304
174
|
get assemblyNames() {
|
|
305
175
|
const assemblyNames = [];
|
|
306
176
|
self.displayedRegions.forEach(displayedRegion => {
|
|
@@ -310,9 +180,6 @@ function stateModelFactory(pluginManager) {
|
|
|
310
180
|
});
|
|
311
181
|
return assemblyNames;
|
|
312
182
|
},
|
|
313
|
-
/**
|
|
314
|
-
* #getter
|
|
315
|
-
*/
|
|
316
183
|
get initialized() {
|
|
317
184
|
const { assemblyManager } = (0, util_1.getSession)(self);
|
|
318
185
|
return (self.volatileWidth !== undefined &&
|
|
@@ -320,107 +187,62 @@ function stateModelFactory(pluginManager) {
|
|
|
320
187
|
},
|
|
321
188
|
}))
|
|
322
189
|
.views(self => ({
|
|
323
|
-
/**
|
|
324
|
-
* #getter
|
|
325
|
-
*/
|
|
326
190
|
get staticSlices() {
|
|
327
191
|
return (0, slices_1.calculateStaticSlices)(self);
|
|
328
192
|
},
|
|
329
193
|
}))
|
|
330
194
|
.views(self => ({
|
|
331
|
-
/**
|
|
332
|
-
* #getter
|
|
333
|
-
*/
|
|
334
195
|
get visibleStaticSlices() {
|
|
335
196
|
return self.staticSlices.filter(s => (0, slices_1.sliceIsVisible)(self, s));
|
|
336
197
|
},
|
|
337
198
|
}))
|
|
338
199
|
.actions(self => ({
|
|
339
|
-
/**
|
|
340
|
-
* #action
|
|
341
|
-
*/
|
|
342
200
|
setWidth(newWidth) {
|
|
343
201
|
self.volatileWidth = Math.max(newWidth, minWidth);
|
|
344
202
|
return self.volatileWidth;
|
|
345
203
|
},
|
|
346
|
-
/**
|
|
347
|
-
* #action
|
|
348
|
-
*/
|
|
349
204
|
setHeight(newHeight) {
|
|
350
205
|
self.height = Math.max(newHeight, minHeight);
|
|
351
206
|
return self.height;
|
|
352
207
|
},
|
|
353
|
-
/**
|
|
354
|
-
* #action
|
|
355
|
-
*/
|
|
356
208
|
resizeHeight(distance) {
|
|
357
209
|
const oldHeight = self.height;
|
|
358
210
|
const newHeight = this.setHeight(self.height + distance);
|
|
359
211
|
this.setModelViewWhenAdjust(!self.tooSmallToLock);
|
|
360
212
|
return newHeight - oldHeight;
|
|
361
213
|
},
|
|
362
|
-
/**
|
|
363
|
-
* #action
|
|
364
|
-
*/
|
|
365
214
|
resizeWidth(distance) {
|
|
366
215
|
const oldWidth = self.width;
|
|
367
216
|
const newWidth = this.setWidth(self.width + distance);
|
|
368
217
|
this.setModelViewWhenAdjust(!self.tooSmallToLock);
|
|
369
218
|
return newWidth - oldWidth;
|
|
370
219
|
},
|
|
371
|
-
/**
|
|
372
|
-
* #action
|
|
373
|
-
*/
|
|
374
220
|
rotateClockwiseButton() {
|
|
375
221
|
this.rotateClockwise(Math.PI / 6);
|
|
376
222
|
},
|
|
377
|
-
/**
|
|
378
|
-
* #action
|
|
379
|
-
*/
|
|
380
223
|
rotateCounterClockwiseButton() {
|
|
381
224
|
this.rotateCounterClockwise(Math.PI / 6);
|
|
382
225
|
},
|
|
383
|
-
/**
|
|
384
|
-
* #action
|
|
385
|
-
*/
|
|
386
226
|
rotateClockwise(distance = 0.17) {
|
|
387
227
|
self.offsetRadians += distance;
|
|
388
228
|
},
|
|
389
|
-
/**
|
|
390
|
-
* #action
|
|
391
|
-
*/
|
|
392
229
|
rotateCounterClockwise(distance = 0.17) {
|
|
393
230
|
self.offsetRadians -= distance;
|
|
394
231
|
},
|
|
395
|
-
/**
|
|
396
|
-
* #action
|
|
397
|
-
*/
|
|
398
232
|
zoomInButton() {
|
|
399
233
|
this.setBpPerPx(self.bpPerPx / 1.4);
|
|
400
234
|
},
|
|
401
|
-
/**
|
|
402
|
-
* #action
|
|
403
|
-
*/
|
|
404
235
|
zoomOutButton() {
|
|
405
236
|
this.setBpPerPx(self.bpPerPx * 1.4);
|
|
406
237
|
},
|
|
407
|
-
/**
|
|
408
|
-
* #action
|
|
409
|
-
*/
|
|
410
238
|
setBpPerPx(newVal) {
|
|
411
239
|
self.bpPerPx = (0, util_1.clamp)(newVal, self.minBpPerPx, self.maxBpPerPx);
|
|
412
240
|
},
|
|
413
|
-
/**
|
|
414
|
-
* #action
|
|
415
|
-
*/
|
|
416
241
|
setModelViewWhenAdjust(secondCondition) {
|
|
417
242
|
if (self.lockedFitToWindow && secondCondition) {
|
|
418
243
|
this.setBpPerPx(self.minBpPerPx);
|
|
419
244
|
}
|
|
420
245
|
},
|
|
421
|
-
/**
|
|
422
|
-
* #action
|
|
423
|
-
*/
|
|
424
246
|
setDisplayedRegions(regions) {
|
|
425
247
|
const previouslyEmpty = self.displayedRegions.length === 0;
|
|
426
248
|
self.displayedRegions = (0, mobx_state_tree_1.cast)(regions);
|
|
@@ -431,9 +253,6 @@ function stateModelFactory(pluginManager) {
|
|
|
431
253
|
this.setBpPerPx(self.bpPerPx);
|
|
432
254
|
}
|
|
433
255
|
},
|
|
434
|
-
/**
|
|
435
|
-
* #action
|
|
436
|
-
*/
|
|
437
256
|
activateTrackSelector() {
|
|
438
257
|
if (self.trackSelectorType === 'hierarchical') {
|
|
439
258
|
const session = (0, util_1.getSession)(self);
|
|
@@ -445,9 +264,6 @@ function stateModelFactory(pluginManager) {
|
|
|
445
264
|
}
|
|
446
265
|
throw new Error(`invalid track selector type ${self.trackSelectorType}`);
|
|
447
266
|
},
|
|
448
|
-
/**
|
|
449
|
-
* #action
|
|
450
|
-
*/
|
|
451
267
|
toggleTrack(trackId) {
|
|
452
268
|
const hiddenCount = this.hideTrack(trackId);
|
|
453
269
|
if (!hiddenCount) {
|
|
@@ -456,15 +272,9 @@ function stateModelFactory(pluginManager) {
|
|
|
456
272
|
}
|
|
457
273
|
return false;
|
|
458
274
|
},
|
|
459
|
-
/**
|
|
460
|
-
* #action
|
|
461
|
-
*/
|
|
462
275
|
setError(error) {
|
|
463
276
|
self.error = error;
|
|
464
277
|
},
|
|
465
|
-
/**
|
|
466
|
-
* #action
|
|
467
|
-
*/
|
|
468
278
|
showTrack(trackId, initialSnapshot = {}) {
|
|
469
279
|
const schema = pluginManager.pluggableConfigSchemaType('track');
|
|
470
280
|
const conf = (0, mobx_state_tree_1.resolveIdentifier)(schema, (0, mobx_state_tree_1.getRoot)(self), trackId);
|
|
@@ -483,9 +293,6 @@ function stateModelFactory(pluginManager) {
|
|
|
483
293
|
});
|
|
484
294
|
self.tracks.push(track);
|
|
485
295
|
},
|
|
486
|
-
/**
|
|
487
|
-
* #action
|
|
488
|
-
*/
|
|
489
296
|
addTrackConf(configuration, initialSnapshot = {}) {
|
|
490
297
|
const { type } = configuration;
|
|
491
298
|
const name = (0, configuration_1.readConfObject)(configuration, 'name');
|
|
@@ -504,9 +311,6 @@ function stateModelFactory(pluginManager) {
|
|
|
504
311
|
displays: [{ type: displayConf.type, configuration: displayConf }],
|
|
505
312
|
}));
|
|
506
313
|
},
|
|
507
|
-
/**
|
|
508
|
-
* #action
|
|
509
|
-
*/
|
|
510
314
|
hideTrack(trackId) {
|
|
511
315
|
const schema = pluginManager.pluggableConfigSchemaType('track');
|
|
512
316
|
const conf = (0, mobx_state_tree_1.resolveIdentifier)(schema, (0, mobx_state_tree_1.getRoot)(self), trackId);
|
|
@@ -516,32 +320,19 @@ function stateModelFactory(pluginManager) {
|
|
|
516
320
|
});
|
|
517
321
|
return t.length;
|
|
518
322
|
},
|
|
519
|
-
/**
|
|
520
|
-
* #action
|
|
521
|
-
*/
|
|
522
323
|
toggleFitToWindowLock() {
|
|
523
|
-
// when going unlocked -> locked and circle is cut off, set to the
|
|
524
|
-
// locked minBpPerPx
|
|
525
324
|
self.lockedFitToWindow = !self.lockedFitToWindow;
|
|
526
325
|
this.setModelViewWhenAdjust(self.atMinBpPerPx);
|
|
527
326
|
return self.lockedFitToWindow;
|
|
528
327
|
},
|
|
529
|
-
/**
|
|
530
|
-
* #action
|
|
531
|
-
* creates an svg export and save using FileSaver
|
|
532
|
-
*/
|
|
533
328
|
async exportSvg(opts = {}) {
|
|
534
|
-
const { renderToSvg } = await Promise.resolve().then(() => __importStar(require('
|
|
329
|
+
const { renderToSvg } = await Promise.resolve().then(() => __importStar(require('./svgcomponents/SVGCircularView')));
|
|
535
330
|
const html = await renderToSvg(self, opts);
|
|
536
331
|
const blob = new Blob([html], { type: 'image/svg+xml' });
|
|
537
332
|
(0, file_saver_1.saveAs)(blob, opts.filename || 'image.svg');
|
|
538
333
|
},
|
|
539
334
|
}))
|
|
540
335
|
.views(self => ({
|
|
541
|
-
/**
|
|
542
|
-
* #method
|
|
543
|
-
* return the view menu items
|
|
544
|
-
*/
|
|
545
336
|
menuItems() {
|
|
546
337
|
return [
|
|
547
338
|
{
|
|
@@ -5,8 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.default = SVGBackground;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
|
-
const material_1 = require("@mui/material");
|
|
9
8
|
const util_1 = require("@jbrowse/core/util");
|
|
9
|
+
const material_1 = require("@mui/material");
|
|
10
10
|
function SVGBackground({ width, height, shift, }) {
|
|
11
11
|
const theme = (0, material_1.useTheme)();
|
|
12
12
|
return (react_1.default.createElement("rect", { width: width + shift * 2, height: height, fill: (0, util_1.stripAlpha)(theme.palette.background.default) }));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { CircularViewModel, ExportSvgOptions } from '../model';
|
|
2
2
|
type CGV = CircularViewModel;
|
|
3
3
|
export declare function renderToSvg(model: CGV, opts: ExportSvgOptions): Promise<string>;
|
|
4
4
|
export {};
|
|
@@ -5,10 +5,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.renderToSvg = renderToSvg;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const ui_1 = require("@jbrowse/core/ui");
|
|
9
|
+
const util_1 = require("@jbrowse/core/util");
|
|
8
10
|
const material_1 = require("@mui/material");
|
|
9
11
|
const mobx_1 = require("mobx");
|
|
10
|
-
const util_1 = require("@jbrowse/core/util");
|
|
11
|
-
const ui_1 = require("@jbrowse/core/ui");
|
|
12
12
|
const mobx_state_tree_1 = require("mobx-state-tree");
|
|
13
13
|
const SVGBackground_1 = __importDefault(require("./SVGBackground"));
|
|
14
14
|
const Ruler_1 = __importDefault(require("../components/Ruler"));
|
|
@@ -28,16 +28,11 @@ async function renderToSvg(model, opts) {
|
|
|
28
28
|
}));
|
|
29
29
|
const { staticSlices, offsetRadians, centerXY } = model;
|
|
30
30
|
const deg = (0, util_1.radToDeg)(offsetRadians);
|
|
31
|
-
// the xlink namespace is used for rendering <image> tag
|
|
32
31
|
return (0, util_1.renderToStaticMarkup)(react_1.default.createElement(material_1.ThemeProvider, { theme: (0, ui_1.createJBrowseTheme)(theme) },
|
|
33
32
|
react_1.default.createElement(Wrapper, null,
|
|
34
33
|
react_1.default.createElement("svg", { width: width, height: height, xmlns: "http://www.w3.org/2000/svg", xmlnsXlink: "http://www.w3.org/1999/xlink", viewBox: [0, 0, width + shift * 2, height].toString() },
|
|
35
34
|
react_1.default.createElement(SVGBackground_1.default, { width: width, height: height, shift: shift }),
|
|
36
35
|
react_1.default.createElement("g", { transform: `translate(${centerXY}) rotate(${deg})` },
|
|
37
|
-
staticSlices.map((slice, i) => (
|
|
38
|
-
|
|
39
|
-
react_1.default.createElement(Ruler_1.default, { key: i, model: model, slice: slice }))),
|
|
40
|
-
displayResults.map(({ result }, i) => (
|
|
41
|
-
/* biome-ignore lint/suspicious/noArrayIndexKey: */
|
|
42
|
-
react_1.default.createElement(react_1.default.Fragment, { key: i }, result))))))), createRootFn);
|
|
36
|
+
staticSlices.map((slice, i) => (react_1.default.createElement(Ruler_1.default, { key: i, model: model, slice: slice }))),
|
|
37
|
+
displayResults.map(({ result }, i) => (react_1.default.createElement(react_1.default.Fragment, { key: i }, result))))))), createRootFn);
|
|
43
38
|
}
|
|
@@ -53,26 +53,21 @@ function thetaRangesOverlap(r1start, r1length, r2start, r2length) {
|
|
|
53
53
|
if (r1length + 0.0001 >= twoPi || r2length + 0.0001 >= twoPi) {
|
|
54
54
|
return true;
|
|
55
55
|
}
|
|
56
|
-
// put both range starts between 2π and 4π
|
|
57
56
|
r1start = (((r1start % twoPi) + twoPi) % twoPi) + twoPi;
|
|
58
57
|
r2start = (((r2start % twoPi) + twoPi) % twoPi) + twoPi;
|
|
59
58
|
if (r1start < r2start + r2length && r1start + r1length > r2start) {
|
|
60
59
|
return true;
|
|
61
60
|
}
|
|
62
|
-
// move r2 2π to the left and check
|
|
63
61
|
r2start -= twoPi;
|
|
64
62
|
if (r1start < r2start + r2length && r1start + r1length > r2start) {
|
|
65
63
|
return true;
|
|
66
64
|
}
|
|
67
|
-
// move it 2π to the right and check
|
|
68
65
|
r2start += twoPi + twoPi;
|
|
69
66
|
return r1start < r2start + r2length && r1start + r1length > r2start;
|
|
70
67
|
}
|
|
71
|
-
// return which arc range has any part of the circle visible in the viewport
|
|
72
68
|
function viewportVisibleSection(viewSides, circleCenter, circleRadius) {
|
|
73
69
|
let [viewL, viewR, viewT, viewB] = viewSides;
|
|
74
70
|
const [cx, cy] = circleCenter;
|
|
75
|
-
// transform coordinate system to center of circle
|
|
76
71
|
viewL -= cx;
|
|
77
72
|
viewR -= cx;
|
|
78
73
|
viewT -= cy;
|
|
@@ -97,61 +92,6 @@ function viewportVisibleSection(viewSides, circleCenter, circleRadius) {
|
|
|
97
92
|
theta: [0, 2 * Math.PI],
|
|
98
93
|
};
|
|
99
94
|
}
|
|
100
|
-
// const viewportCompletelyContainsCircle =
|
|
101
|
-
// circleCenter[0] - viewL >= circleRadius &&
|
|
102
|
-
// viewR - circleCenter[0] >= circleRadius &&
|
|
103
|
-
// circleCenter[1] - viewT >= circleRadius &&
|
|
104
|
-
// viewB - circleCenter[1] >= circleRadius
|
|
105
|
-
// if (viewportCompletelyContainsCircle) {
|
|
106
|
-
// return [0, 2 * Math.PI]
|
|
107
|
-
// }
|
|
108
|
-
// const distToCenterSquared = ([x, y]) => {
|
|
109
|
-
// const [cx, cy] = circleCenter
|
|
110
|
-
// const sq = n => n * n
|
|
111
|
-
// return sq(x - cx) + sq(y - cy)
|
|
112
|
-
// }
|
|
113
|
-
// const circleRadiusSquared = circleRadius * circleRadius
|
|
114
|
-
// const tlInside = distToCenterSquared([viewL, viewT]) <= circleRadiusSquared
|
|
115
|
-
// const trInside = distToCenterSquared([viewR, viewT]) <= circleRadiusSquared
|
|
116
|
-
// const blInside = distToCenterSquared([viewL, viewB]) <= circleRadiusSquared
|
|
117
|
-
// const brInside = distToCenterSquared([viewR, viewB]) <= circleRadiusSquared
|
|
118
|
-
// const noIntersection = !tlInside && !trInside && !blInside && !brInside
|
|
119
|
-
// if (noIntersection) return undefined
|
|
120
|
-
// const circleCompletelyContainsViewport =
|
|
121
|
-
// tlInside && trInside && blInside && brInside
|
|
122
|
-
// if (circleCompletelyContainsViewport) {
|
|
123
|
-
// // viewport is in the circle, but the center is not in it, so take max
|
|
124
|
-
// // and min of thetas to the center
|
|
125
|
-
// const thetas = [
|
|
126
|
-
// Math.atan(viewT / viewL),
|
|
127
|
-
// Math.atan(viewT / viewR),
|
|
128
|
-
// Math.atan(viewB / viewL),
|
|
129
|
-
// Math.atan(viewB / viewR),
|
|
130
|
-
// ]
|
|
131
|
-
// return [Math.min(...thetas), Math.max(...thetas)]
|
|
132
|
-
// }
|
|
133
|
-
// if we get here, the viewport is partly in, partly out of the circle
|
|
134
|
-
// const viewLIntersects = Math.abs(viewL - circleCenter[0]) <= circleRadius
|
|
135
|
-
// const viewRIntersects = Math.abs(viewR - circleCenter[0]) <= circleRadius
|
|
136
|
-
// const viewTIntersects = Math.abs(viewT - circleCenter[1]) <= circleRadius
|
|
137
|
-
// const viewBIntersects = Math.abs(viewB - circleCenter[1]) <= circleRadius
|
|
138
|
-
// const numIntersectingSides =
|
|
139
|
-
// Number(viewLIntersects) +
|
|
140
|
-
// Number(viewRIntersects) +
|
|
141
|
-
// Number(viewTIntersects) +
|
|
142
|
-
// Number(viewBIntersects)
|
|
143
|
-
// if (numIntersectingSides === 4) return [0, 2 * Math.PI]
|
|
144
|
-
// if (numIntersectingSides === 3) {
|
|
145
|
-
// // TODO calculate the thetas of the
|
|
146
|
-
// } else if (numIntersectingSides === 2) {
|
|
147
|
-
// // TODO calculate the thetas of the 2 intersection points
|
|
148
|
-
// } else if (numIntersectingSides === 1) {
|
|
149
|
-
// // TODO calculate the thetas of the 1-2 intersection points of the line, and the angle between
|
|
150
|
-
// }
|
|
151
|
-
// make a list of vertices-of-interest that lie inside both shapes to examine
|
|
152
|
-
// to determine the range covered by their intersection
|
|
153
|
-
// transform coordinates to have the circle as the origin and find the intersections
|
|
154
|
-
// of the circle and the view rectangle
|
|
155
95
|
const vertices = [
|
|
156
96
|
[viewL, viewT],
|
|
157
97
|
[viewR, viewT],
|
|
@@ -162,7 +102,6 @@ function viewportVisibleSection(viewSides, circleCenter, circleRadius) {
|
|
|
162
102
|
findCircleIntersectionY(viewR, 0, 0, circleRadius, vertices);
|
|
163
103
|
findCircleIntersectionX(viewT, 0, 0, circleRadius, vertices);
|
|
164
104
|
findCircleIntersectionX(viewB, 0, 0, circleRadius, vertices);
|
|
165
|
-
// for each edge, also look at the closest point to center if it is inside the circle
|
|
166
105
|
if (-viewL < circleRadius) {
|
|
167
106
|
vertices.push([viewL, 0]);
|
|
168
107
|
}
|
|
@@ -175,24 +114,15 @@ function viewportVisibleSection(viewSides, circleCenter, circleRadius) {
|
|
|
175
114
|
if (viewB < circleRadius) {
|
|
176
115
|
vertices.push([0, viewB]);
|
|
177
116
|
}
|
|
178
|
-
// const verticesOriginal = vertices.map(([x, y]) => [x + cx, y + cy])
|
|
179
|
-
// now convert them all to polar and take the max and min of rho and theta
|
|
180
|
-
// const viewportCenterTheta = cartesianToTheta(viewR + viewL, viewT + viewB)
|
|
181
117
|
const reflect = viewL >= 0 ? -1 : 1;
|
|
182
|
-
// viewportCenterTheta < Math.PI / 2 || viewportCenterTheta > 1.5 * Math.PI
|
|
183
|
-
// ? -1
|
|
184
|
-
// : 1
|
|
185
118
|
let rhoMin = Number.POSITIVE_INFINITY;
|
|
186
119
|
let rhoMax = Number.NEGATIVE_INFINITY;
|
|
187
120
|
let thetaMin = Number.POSITIVE_INFINITY;
|
|
188
121
|
let thetaMax = Number.NEGATIVE_INFINITY;
|
|
189
122
|
for (const [vx, vy] of vertices) {
|
|
190
|
-
// ignore vertex if outside the viewport
|
|
191
123
|
if (vx >= viewL && vx <= viewR && vy >= viewT && vy <= viewB) {
|
|
192
124
|
const [rho, theta] = cartesianToPolar(vx * reflect, vy * reflect);
|
|
193
|
-
// ignore vertex if outside the circle
|
|
194
125
|
if (rho <= circleRadius + 0.001) {
|
|
195
|
-
// ignore theta if rho is 0
|
|
196
126
|
if (theta < thetaMin && rho > 0.0001) {
|
|
197
127
|
thetaMin = theta;
|
|
198
128
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import PluginManager from '@jbrowse/core/PluginManager';
|
|
1
|
+
import type PluginManager from '@jbrowse/core/PluginManager';
|
|
2
2
|
export default function LaunchCircularViewF(pluginManager: PluginManager): void;
|
|
@@ -3,9 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.default = LaunchCircularViewF;
|
|
4
4
|
const mobx_1 = require("mobx");
|
|
5
5
|
function LaunchCircularViewF(pluginManager) {
|
|
6
|
-
pluginManager.addToExtensionPoint('LaunchView-CircularView',
|
|
7
|
-
// @ts-expect-error
|
|
8
|
-
async ({ session, assembly, tracks = [], }) => {
|
|
6
|
+
pluginManager.addToExtensionPoint('LaunchView-CircularView', async ({ session, assembly, tracks = [], }) => {
|
|
9
7
|
const { assemblyManager } = session;
|
|
10
8
|
const view = session.addView('CircularView', {});
|
|
11
9
|
await (0, mobx_1.when)(() => view.initialized);
|