@jbrowse/plugin-breakpoint-split-view 2.6.1 → 2.6.2

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 (84) hide show
  1. package/dist/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.js +0 -1
  2. package/dist/BreakpointAlignmentsFeatureDetail/index.js +0 -1
  3. package/dist/BreakpointSplitView/BreakpointSplitView.js +0 -1
  4. package/dist/BreakpointSplitView/components/AlignmentConnections.js +0 -1
  5. package/dist/BreakpointSplitView/components/Breakends.js +0 -1
  6. package/dist/BreakpointSplitView/components/BreakpointSplitView.js +0 -1
  7. package/dist/BreakpointSplitView/components/ExportSvgDialog.js +0 -1
  8. package/dist/BreakpointSplitView/components/Overlay.js +0 -1
  9. package/dist/BreakpointSplitView/components/Translocations.js +0 -1
  10. package/dist/BreakpointSplitView/components/util.js +0 -1
  11. package/dist/BreakpointSplitView/index.js +0 -1
  12. package/dist/BreakpointSplitView/model.d.ts +1 -1
  13. package/dist/BreakpointSplitView/model.js +3 -3
  14. package/dist/BreakpointSplitView/svgcomponents/SVGBackground.js +0 -1
  15. package/dist/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.js +0 -1
  16. package/dist/BreakpointSplitView/util.js +0 -1
  17. package/dist/index.js +0 -1
  18. package/esm/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.js +0 -1
  19. package/esm/BreakpointAlignmentsFeatureDetail/index.js +0 -1
  20. package/esm/BreakpointSplitView/BreakpointSplitView.js +0 -1
  21. package/esm/BreakpointSplitView/components/AlignmentConnections.js +0 -1
  22. package/esm/BreakpointSplitView/components/Breakends.js +0 -1
  23. package/esm/BreakpointSplitView/components/BreakpointSplitView.js +0 -1
  24. package/esm/BreakpointSplitView/components/ExportSvgDialog.js +0 -1
  25. package/esm/BreakpointSplitView/components/Overlay.js +0 -1
  26. package/esm/BreakpointSplitView/components/Translocations.js +0 -1
  27. package/esm/BreakpointSplitView/components/util.js +0 -1
  28. package/esm/BreakpointSplitView/index.js +0 -1
  29. package/esm/BreakpointSplitView/model.d.ts +1 -1
  30. package/esm/BreakpointSplitView/model.js +3 -3
  31. package/esm/BreakpointSplitView/svgcomponents/SVGBackground.js +0 -1
  32. package/esm/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.js +0 -1
  33. package/esm/BreakpointSplitView/util.js +0 -1
  34. package/esm/index.js +0 -1
  35. package/package.json +3 -4
  36. package/dist/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.js.map +0 -1
  37. package/dist/BreakpointAlignmentsFeatureDetail/index.js.map +0 -1
  38. package/dist/BreakpointSplitView/BreakpointSplitView.js.map +0 -1
  39. package/dist/BreakpointSplitView/components/AlignmentConnections.js.map +0 -1
  40. package/dist/BreakpointSplitView/components/Breakends.js.map +0 -1
  41. package/dist/BreakpointSplitView/components/BreakpointSplitView.js.map +0 -1
  42. package/dist/BreakpointSplitView/components/ExportSvgDialog.js.map +0 -1
  43. package/dist/BreakpointSplitView/components/Overlay.js.map +0 -1
  44. package/dist/BreakpointSplitView/components/Translocations.js.map +0 -1
  45. package/dist/BreakpointSplitView/components/util.js.map +0 -1
  46. package/dist/BreakpointSplitView/index.js.map +0 -1
  47. package/dist/BreakpointSplitView/model.js.map +0 -1
  48. package/dist/BreakpointSplitView/svgcomponents/SVGBackground.js.map +0 -1
  49. package/dist/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.js.map +0 -1
  50. package/dist/BreakpointSplitView/util.js.map +0 -1
  51. package/dist/index.js.map +0 -1
  52. package/esm/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.js.map +0 -1
  53. package/esm/BreakpointAlignmentsFeatureDetail/index.js.map +0 -1
  54. package/esm/BreakpointSplitView/BreakpointSplitView.js.map +0 -1
  55. package/esm/BreakpointSplitView/components/AlignmentConnections.js.map +0 -1
  56. package/esm/BreakpointSplitView/components/Breakends.js.map +0 -1
  57. package/esm/BreakpointSplitView/components/BreakpointSplitView.js.map +0 -1
  58. package/esm/BreakpointSplitView/components/ExportSvgDialog.js.map +0 -1
  59. package/esm/BreakpointSplitView/components/Overlay.js.map +0 -1
  60. package/esm/BreakpointSplitView/components/Translocations.js.map +0 -1
  61. package/esm/BreakpointSplitView/components/util.js.map +0 -1
  62. package/esm/BreakpointSplitView/index.js.map +0 -1
  63. package/esm/BreakpointSplitView/model.js.map +0 -1
  64. package/esm/BreakpointSplitView/svgcomponents/SVGBackground.js.map +0 -1
  65. package/esm/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.js.map +0 -1
  66. package/esm/BreakpointSplitView/util.js.map +0 -1
  67. package/esm/index.js.map +0 -1
  68. package/src/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.tsx +0 -24
  69. package/src/BreakpointAlignmentsFeatureDetail/index.ts +0 -35
  70. package/src/BreakpointSplitView/BreakpointSplitView.ts +0 -100
  71. package/src/BreakpointSplitView/components/AlignmentConnections.tsx +0 -166
  72. package/src/BreakpointSplitView/components/Breakends.tsx +0 -141
  73. package/src/BreakpointSplitView/components/BreakpointSplitView.tsx +0 -95
  74. package/src/BreakpointSplitView/components/ExportSvgDialog.tsx +0 -149
  75. package/src/BreakpointSplitView/components/Overlay.tsx +0 -29
  76. package/src/BreakpointSplitView/components/Translocations.tsx +0 -147
  77. package/src/BreakpointSplitView/components/util.ts +0 -127
  78. package/src/BreakpointSplitView/index.ts +0 -17
  79. package/src/BreakpointSplitView/model.ts +0 -333
  80. package/src/BreakpointSplitView/svgcomponents/SVGBackground.tsx +0 -21
  81. package/src/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.tsx +0 -179
  82. package/src/BreakpointSplitView/util.ts +0 -89
  83. package/src/index.test.ts +0 -3
  84. package/src/index.ts +0 -15
@@ -1,149 +0,0 @@
1
- import React, { useState } from 'react'
2
- import {
3
- Button,
4
- Checkbox,
5
- CircularProgress,
6
- DialogActions,
7
- DialogContent,
8
- FormControlLabel,
9
- MenuItem,
10
- TextField,
11
- Typography,
12
- } from '@mui/material'
13
- import { Dialog, ErrorMessage } from '@jbrowse/core/ui'
14
- import { getSession, useLocalStorage } from '@jbrowse/core/util'
15
-
16
- // locals
17
- import { ExportSvgOptions } from '../model'
18
-
19
- function LoadingMessage() {
20
- return (
21
- <div>
22
- <CircularProgress size={20} style={{ marginRight: 20 }} />
23
- <Typography display="inline">Creating SVG</Typography>
24
- </div>
25
- )
26
- }
27
-
28
- function useSvgLocal<T>(key: string, val: T) {
29
- return useLocalStorage('svg-' + key, val)
30
- }
31
-
32
- export default function ExportSvgDlg({
33
- model,
34
- handleClose,
35
- }: {
36
- model: { exportSvg(opts: ExportSvgOptions): Promise<void> }
37
- handleClose: () => void
38
- }) {
39
- const session = getSession(model)
40
- const offscreenCanvas = typeof OffscreenCanvas !== 'undefined'
41
- const [rasterizeLayers, setRasterizeLayers] = useState(offscreenCanvas)
42
- const [loading, setLoading] = useState(false)
43
- const [error, setError] = useState<unknown>()
44
- const [filename, setFilename] = useSvgLocal('file', 'jbrowse.svg')
45
- const [trackLabels, setTrackLabels] = useSvgLocal('tracklabels', 'offset')
46
- const [themeName, setThemeName] = useSvgLocal(
47
- 'theme',
48
- session.themeName || 'default',
49
- )
50
- return (
51
- <Dialog open onClose={handleClose} title="Export SVG">
52
- <DialogContent>
53
- {error ? (
54
- <ErrorMessage error={error} />
55
- ) : loading ? (
56
- <LoadingMessage />
57
- ) : null}
58
- <TextField
59
- helperText="filename"
60
- value={filename}
61
- onChange={event => setFilename(event.target.value)}
62
- />
63
- <br />
64
- <TextField
65
- select
66
- label="Track label positioning"
67
- variant="outlined"
68
- style={{ width: 150 }}
69
- value={trackLabels}
70
- onChange={event => setTrackLabels(event.target.value)}
71
- >
72
- <MenuItem value="offset">Offset</MenuItem>
73
- <MenuItem value="overlay">Overlay</MenuItem>
74
- <MenuItem value="left">Left</MenuItem>
75
- <MenuItem value="none">None</MenuItem>
76
- </TextField>
77
- <br />
78
- {session.allThemes ? (
79
- <TextField
80
- select
81
- label="Theme"
82
- variant="outlined"
83
- value={themeName}
84
- onChange={event => setThemeName(event.target.value)}
85
- >
86
- {Object.entries(session.allThemes()).map(([key, val]) => (
87
- <MenuItem key={key} value={key}>
88
- {
89
- // @ts-expect-error
90
- val.name || '(Unknown name)'
91
- }
92
- </MenuItem>
93
- ))}
94
- </TextField>
95
- ) : null}
96
-
97
- {offscreenCanvas ? (
98
- <FormControlLabel
99
- control={
100
- <Checkbox
101
- checked={rasterizeLayers}
102
- onChange={() => setRasterizeLayers(val => !val)}
103
- />
104
- }
105
- label="Rasterize canvas based tracks? File may be much larger if this is turned off"
106
- />
107
- ) : (
108
- <Typography>
109
- Note: rasterizing layers not yet supported in this browser, so SVG
110
- size may be large
111
- </Typography>
112
- )}
113
- </DialogContent>
114
- <DialogActions>
115
- <Button
116
- variant="contained"
117
- color="secondary"
118
- onClick={() => handleClose()}
119
- >
120
- Cancel
121
- </Button>
122
- <Button
123
- variant="contained"
124
- color="primary"
125
- type="submit"
126
- onClick={async () => {
127
- setLoading(true)
128
- setError(undefined)
129
- try {
130
- await model.exportSvg({
131
- rasterizeLayers,
132
- filename,
133
- trackLabels,
134
- themeName,
135
- })
136
- handleClose()
137
- } catch (e) {
138
- console.error(e)
139
- setError(e)
140
- setLoading(false)
141
- }
142
- }}
143
- >
144
- Submit
145
- </Button>
146
- </DialogActions>
147
- </Dialog>
148
- )
149
- }
@@ -1,29 +0,0 @@
1
- import React from 'react'
2
- import { observer } from 'mobx-react'
3
-
4
- // locals
5
- import { BreakpointViewModel } from '../model'
6
- import AlignmentConnections from './AlignmentConnections'
7
- import Breakends from './Breakends'
8
- import Translocations from './Translocations'
9
-
10
- export default observer(function (props: {
11
- parentRef: React.RefObject<SVGSVGElement>
12
- model: BreakpointViewModel
13
- trackId: string
14
- getTrackYPosOverride?: (trackId: string, level: number) => number
15
- }) {
16
- const { model, trackId } = props
17
- const tracks = model.getMatchedTracks(trackId)
18
- if (tracks[0]?.type === 'AlignmentsTrack') {
19
- return <AlignmentConnections {...props} />
20
- }
21
- if (tracks[0]?.type === 'VariantTrack') {
22
- return model.hasTranslocations(trackId) ? (
23
- <Translocations {...props} />
24
- ) : (
25
- <Breakends {...props} />
26
- )
27
- }
28
- return null
29
- })
@@ -1,147 +0,0 @@
1
- import React, { useState, useMemo } from 'react'
2
- import { getSession } from '@jbrowse/core/util'
3
- import { observer } from 'mobx-react'
4
- import { getSnapshot } from 'mobx-state-tree'
5
-
6
- // locals
7
- import { getMatchedTranslocationFeatures } from './util'
8
- import { yPos, getPxFromCoordinate, useNextFrame } from '../util'
9
- import { BreakpointViewModel, LayoutRecord } from '../model'
10
-
11
- const [LEFT] = [0, 1, 2, 3]
12
-
13
- const Translocations = observer(function ({
14
- model,
15
- trackId,
16
- parentRef: ref,
17
- getTrackYPosOverride,
18
- }: {
19
- model: BreakpointViewModel
20
- trackId: string
21
- parentRef: React.RefObject<SVGSVGElement>
22
- getTrackYPosOverride?: (trackId: string, level: number) => number
23
- }) {
24
- const { views } = model
25
- const session = getSession(model)
26
- const { assemblyManager } = session
27
- const totalFeatures = model.getTrackFeatures(trackId)
28
- const layoutMatches = useMemo(
29
- () =>
30
- model.getMatchedFeaturesInLayout(
31
- trackId,
32
- getMatchedTranslocationFeatures(totalFeatures),
33
- ),
34
-
35
- [totalFeatures, trackId, model],
36
- )
37
-
38
- const [mouseoverElt, setMouseoverElt] = useState<string>()
39
- const snap = getSnapshot(model)
40
- useNextFrame(snap)
41
-
42
- const assembly = assemblyManager.get(views[0].assemblyNames[0])
43
- if (!assembly) {
44
- return null
45
- }
46
-
47
- let yOffset = 0
48
- if (ref.current) {
49
- const rect = ref.current.getBoundingClientRect()
50
- yOffset = rect.top
51
- }
52
-
53
- // we hardcode the TRA to go to the "other view" and if there is none, we
54
- // just return null here note: would need to do processing of the INFO
55
- // CHR2/END and see which view could contain those coordinates to really do
56
- // it properly
57
- if (views.length < 2) {
58
- return null
59
- }
60
- return (
61
- <g
62
- fill="none"
63
- stroke="green"
64
- strokeWidth={5}
65
- data-testid={layoutMatches.length ? `${trackId}-loaded` : trackId}
66
- >
67
- {layoutMatches.map(chunk => {
68
- // we follow a path in the list of chunks, not from top to bottom,
69
- // just in series following x1,y1 -> x2,y2
70
- const ret = []
71
- for (let i = 0; i < chunk.length; i += 1) {
72
- const { layout: c1, feature: f1, level: level1 } = chunk[i]
73
- const level2 = level1 === 0 ? 1 : 0
74
- const id = f1.id()
75
- if (!c1) {
76
- return null
77
- }
78
-
79
- const info = f1.get('INFO')
80
- const chr2 = info.CHR2[0]
81
- const end2 = info.END[0]
82
- const [myDirection, mateDirection] = info.STRANDS[0].split('')
83
-
84
- const r = getPxFromCoordinate(views[level2], chr2, end2)
85
- if (r) {
86
- const c2: LayoutRecord = [r, 0, r + 1, 0]
87
- const x1 = getPxFromCoordinate(
88
- views[level1],
89
- f1.get('refName'),
90
- c1[LEFT],
91
- )
92
- const x2 = r
93
- const reversed1 = views[level1].pxToBp(x1).reversed
94
- const reversed2 = views[level2].pxToBp(x2).reversed
95
-
96
- const tracks = views.map(v => v.getTrack(trackId))
97
- const y1 =
98
- yPos(trackId, level1, views, tracks, c1, getTrackYPosOverride) -
99
- yOffset
100
- const y2 =
101
- yPos(trackId, level2, views, tracks, c2, getTrackYPosOverride) -
102
- yOffset
103
-
104
- const path = [
105
- 'M', // move to
106
- x1 - 20 * (myDirection === '+' ? 1 : -1) * (reversed1 ? -1 : 1),
107
- y1,
108
- 'L', // line to
109
- x1,
110
- y1,
111
- 'L', // line to
112
- x2,
113
- y2,
114
- 'L', // line to
115
- x2 - 20 * (mateDirection === '+' ? 1 : -1) * (reversed2 ? -1 : 1),
116
- y2,
117
- ].join(' ')
118
- ret.push(
119
- <path
120
- d={path}
121
- key={JSON.stringify(path)}
122
- strokeWidth={id === mouseoverElt ? 10 : 5}
123
- onClick={() => {
124
- const featureWidget = session.addWidget?.(
125
- 'VariantFeatureWidget',
126
- 'variantFeature',
127
- {
128
- featureData: (
129
- totalFeatures.get(id) || { toJSON: () => {} }
130
- ).toJSON(),
131
- },
132
- )
133
- session.showWidget?.(featureWidget)
134
- }}
135
- onMouseOver={() => setMouseoverElt(id)}
136
- onMouseOut={() => setMouseoverElt(undefined)}
137
- />,
138
- )
139
- }
140
- }
141
- return ret
142
- })}
143
- </g>
144
- )
145
- })
146
-
147
- export default Translocations
@@ -1,127 +0,0 @@
1
- import { Feature, notEmpty } from '@jbrowse/core/util'
2
-
3
- import { parseBreakend } from '@gmod/vcf'
4
-
5
- // this finds candidate alignment features, aimed at plotting split reads from
6
- // BAM/CRAM files
7
- export function getBadlyPairedAlignments(features: Map<string, Feature>) {
8
- const candidates = new Map<string, Feature[]>()
9
- const alreadySeen = new Set<string>()
10
-
11
- // this finds candidate features that share the same name
12
- for (const feature of features.values()) {
13
- const flags = feature.get('flags')
14
- const id = feature.id()
15
- const unmapped = flags & 4
16
- const correctlyPaired = flags & 2
17
-
18
- if (!alreadySeen.has(id) && !correctlyPaired && !unmapped) {
19
- const n = feature.get('name')
20
- let val = candidates.get(n)
21
- if (!val) {
22
- val = []
23
- candidates.set(n, val)
24
- }
25
- val.push(feature)
26
- }
27
- alreadySeen.add(feature.id())
28
- }
29
-
30
- return [...candidates.values()].filter(v => v.length > 1)
31
- }
32
-
33
- function getTag(f: Feature, tag: string) {
34
- const tags = f.get('tags')
35
- return tags ? tags[tag] : f.get(tag)
36
- }
37
-
38
- // this finds candidate alignment features, aimed at plotting split reads from
39
- // BAM/CRAM files
40
- export function getMatchedAlignmentFeatures(features: Map<string, Feature>) {
41
- const candidates = new Map<string, Feature[]>()
42
- const alreadySeen = new Set<string>()
43
-
44
- // this finds candidate features that share the same name
45
- for (const feature of features.values()) {
46
- const id = feature.id()
47
- const unmapped = feature.get('flags') & 4
48
- const hasSA = !!getTag(feature, 'SA')
49
- if (!alreadySeen.has(id) && !unmapped && hasSA) {
50
- const n = feature.get('name')
51
- let val = candidates.get(n)
52
- if (!val) {
53
- val = []
54
- candidates.set(n, val)
55
- }
56
- val.push(feature)
57
- }
58
- alreadySeen.add(feature.id())
59
- }
60
-
61
- return [...candidates.values()].filter(v => v.length > 1)
62
- }
63
-
64
- export function hasPairedReads(features: Map<string, Feature>) {
65
- for (const f of features.values()) {
66
- if (f.get('flags') & 1) {
67
- return true
68
- }
69
- }
70
- return false
71
- }
72
-
73
- export function findMatchingAlt(feat1: Feature, feat2: Feature) {
74
- const alts = feat1.get('ALT') as string[] | undefined
75
- if (alts) {
76
- return new Map(
77
- alts
78
- ?.map(alt => parseBreakend(alt))
79
- .filter(notEmpty)
80
- .map(bnd => [bnd.MatePosition, bnd]),
81
- ).get(`${feat2.get('refName')}:${feat2.get('start') + 1}`)
82
- }
83
- return undefined
84
- }
85
-
86
- // Returns paired BND features across multiple views by inspecting the ALT
87
- // field to get exact coordinate matches
88
- export function getMatchedBreakendFeatures(feats: Map<string, Feature>) {
89
- const candidates = new Map<string, Feature[]>()
90
- const alreadySeen = new Set<string>()
91
-
92
- for (const f of feats.values()) {
93
- if (!alreadySeen.has(f.id()) && f.get('type') === 'breakend') {
94
- const alts = f.get('ALT') as string[] | undefined
95
- alts?.forEach(a => {
96
- const cur = `${f.get('refName')}:${f.get('start') + 1}`
97
- const bnd = parseBreakend(a)
98
- if (bnd) {
99
- const val = candidates.get(cur)
100
- if (!val) {
101
- candidates.set(bnd.MatePosition || 'none', [f])
102
- } else {
103
- val.push(f)
104
- }
105
- }
106
- })
107
- }
108
- alreadySeen.add(f.id())
109
- }
110
-
111
- return [...candidates.values()].filter(v => v.length > 1)
112
- }
113
-
114
- // Getting "matched" TRA means just return all TRA
115
- export function getMatchedTranslocationFeatures(feats: Map<string, Feature>) {
116
- const ret: Feature[][] = []
117
- const alreadySeen = new Set<string>()
118
-
119
- for (const f of feats.values()) {
120
- if (!alreadySeen.has(f.id()) && f.get('ALT')[0] === '<TRA>') {
121
- ret.push([f])
122
- }
123
- alreadySeen.add(f.id())
124
- }
125
-
126
- return ret
127
- }
@@ -1,17 +0,0 @@
1
- import { lazy } from 'react'
2
- import PluginManager from '@jbrowse/core/PluginManager'
3
-
4
- // locals
5
- import BreakpointSplitView from './BreakpointSplitView'
6
- import stateModelFactory from './model'
7
-
8
- export default (pluginManager: PluginManager) => {
9
- pluginManager.addViewType(() => {
10
- return new BreakpointSplitView({
11
- name: 'BreakpointSplitView',
12
- displayName: 'Breakpoint split view',
13
- stateModel: stateModelFactory(pluginManager),
14
- ReactComponent: lazy(() => import('./components/BreakpointSplitView')),
15
- })
16
- })
17
- }