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