BiNgoViewer 2.3.4__tar.gz → 2.4.0__tar.gz
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.
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/BiNgoViewer.egg-info/PKG-INFO +4 -2
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/BiNgoViewer.egg-info/SOURCES.txt +1 -1
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/PKG-INFO +4 -2
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/README.md +1 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/__init__.py +1 -1
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/cli.py +18 -4
- bingoviewer-2.3.4/bingoviewer/frontend_dist/assets/index-Dbtbm6Rs.js → bingoviewer-2.4.0/bingoviewer/frontend_dist/assets/index-v6csp4Bc.js +1 -1
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/frontend_dist/index.html +1 -1
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/api/genome.py +4 -1
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/api/tracks.py +6 -2
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/main.py +1 -1
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/readers/bam_reader.py +43 -27
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/pyproject.toml +3 -2
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/BiNgoViewer.egg-info/dependency_links.txt +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/BiNgoViewer.egg-info/entry_points.txt +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/BiNgoViewer.egg-info/requires.txt +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/BiNgoViewer.egg-info/top_level.txt +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/__main__.py +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/icon.py +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/install_shortcut.py +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/__init__.py +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/api/__init__.py +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/api/data.py +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/readers/__init__.py +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/readers/annotation_reader.py +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/readers/bigwig_reader.py +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/readers/genbank_reader.py +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/readers/genome_reader.py +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/readers/vcf_reader.py +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/state.py +0 -0
- {bingoviewer-2.3.4 → bingoviewer-2.4.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: BiNgoViewer
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: BiNgo Genome Viewer — a lightweight browser-based genomics viewer
|
|
5
5
|
Author-email: Billy M Ngo <billy.ngo0108@gmail.com>
|
|
6
6
|
License: Proprietary
|
|
@@ -11,13 +11,14 @@ Classifier: Development Status :: 4 - Beta
|
|
|
11
11
|
Classifier: Intended Audience :: Science/Research
|
|
12
12
|
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
15
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
19
|
Classifier: Programming Language :: Python :: 3.14
|
|
19
20
|
Classifier: Operating System :: OS Independent
|
|
20
|
-
Requires-Python: >=3.
|
|
21
|
+
Requires-Python: >=3.9
|
|
21
22
|
Description-Content-Type: text/markdown
|
|
22
23
|
Requires-Dist: fastapi<1.0,>=0.111.0
|
|
23
24
|
Requires-Dist: uvicorn<1.0,>=0.29.0
|
|
@@ -101,6 +102,7 @@ Then open [http://localhost:8000](http://localhost:8000).
|
|
|
101
102
|
| Problem | Solution |
|
|
102
103
|
|---------|----------|
|
|
103
104
|
| `python` not found | Install Python 3.10+ and check **Add to PATH** during setup |
|
|
105
|
+
| "No matching distribution" | Your Python is too old — BiNgo requires **Python 3.10+**. Check with `python --version` |
|
|
104
106
|
| pip install fails | Try `pip install --user BiNgoViewer` or use a virtual environment |
|
|
105
107
|
| Port 8000 in use | Run `bingo --port 9000` (or any free port) |
|
|
106
108
|
| Browser doesn't open | Visit `http://localhost:8000` manually |
|
|
@@ -12,7 +12,7 @@ bingoviewer/cli.py
|
|
|
12
12
|
bingoviewer/icon.py
|
|
13
13
|
bingoviewer/install_shortcut.py
|
|
14
14
|
bingoviewer/frontend_dist/index.html
|
|
15
|
-
bingoviewer/frontend_dist/assets/index-
|
|
15
|
+
bingoviewer/frontend_dist/assets/index-v6csp4Bc.js
|
|
16
16
|
bingoviewer/server/__init__.py
|
|
17
17
|
bingoviewer/server/main.py
|
|
18
18
|
bingoviewer/server/state.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: BiNgoViewer
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: BiNgo Genome Viewer — a lightweight browser-based genomics viewer
|
|
5
5
|
Author-email: Billy M Ngo <billy.ngo0108@gmail.com>
|
|
6
6
|
License: Proprietary
|
|
@@ -11,13 +11,14 @@ Classifier: Development Status :: 4 - Beta
|
|
|
11
11
|
Classifier: Intended Audience :: Science/Research
|
|
12
12
|
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
15
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
19
|
Classifier: Programming Language :: Python :: 3.14
|
|
19
20
|
Classifier: Operating System :: OS Independent
|
|
20
|
-
Requires-Python: >=3.
|
|
21
|
+
Requires-Python: >=3.9
|
|
21
22
|
Description-Content-Type: text/markdown
|
|
22
23
|
Requires-Dist: fastapi<1.0,>=0.111.0
|
|
23
24
|
Requires-Dist: uvicorn<1.0,>=0.29.0
|
|
@@ -101,6 +102,7 @@ Then open [http://localhost:8000](http://localhost:8000).
|
|
|
101
102
|
| Problem | Solution |
|
|
102
103
|
|---------|----------|
|
|
103
104
|
| `python` not found | Install Python 3.10+ and check **Add to PATH** during setup |
|
|
105
|
+
| "No matching distribution" | Your Python is too old — BiNgo requires **Python 3.10+**. Check with `python --version` |
|
|
104
106
|
| pip install fails | Try `pip install --user BiNgoViewer` or use a virtual environment |
|
|
105
107
|
| Port 8000 in use | Run `bingo --port 9000` (or any free port) |
|
|
106
108
|
| Browser doesn't open | Visit `http://localhost:8000` manually |
|
|
@@ -73,6 +73,7 @@ Then open [http://localhost:8000](http://localhost:8000).
|
|
|
73
73
|
| Problem | Solution |
|
|
74
74
|
|---------|----------|
|
|
75
75
|
| `python` not found | Install Python 3.10+ and check **Add to PATH** during setup |
|
|
76
|
+
| "No matching distribution" | Your Python is too old — BiNgo requires **Python 3.10+**. Check with `python --version` |
|
|
76
77
|
| pip install fails | Try `pip install --user BiNgoViewer` or use a virtual environment |
|
|
77
78
|
| Port 8000 in use | Run `bingo --port 9000` (or any free port) |
|
|
78
79
|
| Browser doesn't open | Visit `http://localhost:8000` manually |
|
|
@@ -376,8 +376,16 @@ def _offer_shortcut_install():
|
|
|
376
376
|
try:
|
|
377
377
|
answer = input(" Create a desktop shortcut? [Y/n]: ").strip()
|
|
378
378
|
if answer.lower() != 'n':
|
|
379
|
-
|
|
380
|
-
|
|
379
|
+
try:
|
|
380
|
+
from bingoviewer.install_shortcut import main as install_main
|
|
381
|
+
install_main()
|
|
382
|
+
except ImportError:
|
|
383
|
+
print(" Shortcut creation requires tkinter.")
|
|
384
|
+
print(" Install it with: conda install tk (or) sudo apt install python3-tk")
|
|
385
|
+
print(" You can create a shortcut later with: bingo --install")
|
|
386
|
+
except Exception as e:
|
|
387
|
+
print(f" Shortcut creation failed: {e}")
|
|
388
|
+
print(" You can try again later with: bingo --install")
|
|
381
389
|
return
|
|
382
390
|
except (EOFError, OSError):
|
|
383
391
|
pass
|
|
@@ -437,8 +445,14 @@ def main():
|
|
|
437
445
|
return 0
|
|
438
446
|
|
|
439
447
|
if args.install:
|
|
440
|
-
|
|
441
|
-
|
|
448
|
+
try:
|
|
449
|
+
from bingoviewer.install_shortcut import main as install_main
|
|
450
|
+
install_main()
|
|
451
|
+
except ImportError:
|
|
452
|
+
print(" Shortcut creation requires tkinter.")
|
|
453
|
+
print(" Install it with: conda install tk (or) sudo apt install python3-tk")
|
|
454
|
+
except Exception as e:
|
|
455
|
+
print(f" Shortcut creation failed: {e}")
|
|
442
456
|
return 0
|
|
443
457
|
|
|
444
458
|
# ── Manual update command ────────────────────────────────────
|
|
@@ -94,4 +94,4 @@ ${z.join(`
|
|
|
94
94
|
`)}
|
|
95
95
|
|
|
96
96
|
Tip: If files were moved, re-add them using the 📂 Path button.`):(x("Session restored"),setTimeout(()=>{x(null),e()},1200))}catch(Y){f(Y.message)}finally{m(!1)}}const A=jc(),R=ky(c);return s.jsx("div",{style:R.overlay,onClick:U=>{U.target===U.currentTarget&&e()},children:s.jsxs("div",{style:R.panel,children:[s.jsxs("div",{style:R.header,children:[s.jsx("span",{style:R.title,children:"Session"}),s.jsx("button",{style:R.closeBtn,onClick:e,children:"✕"})]}),s.jsxs("div",{style:R.body,children:[s.jsxs("div",{style:R.section,children:[s.jsx("div",{style:R.sectionTitle,children:"Save"}),s.jsx("div",{style:{display:"flex",gap:8,flexWrap:"wrap"},children:s.jsx("button",{style:R.btn,onClick:b,disabled:!r||p,children:"Save to file"})}),s.jsx("div",{style:{fontSize:10,color:c.textTertiary,marginTop:4},children:"Session is also auto-saved to browser storage."})]}),s.jsxs("div",{style:R.section,children:[s.jsx("div",{style:R.sectionTitle,children:"Restore"}),s.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap"},children:[s.jsx("button",{style:R.btn,onClick:j,disabled:p,children:"Load from file"}),A&&s.jsx("button",{style:R.btn,onClick:E,disabled:p,children:"Restore last session"})]}),s.jsx("input",{ref:w,type:"file",accept:".json",style:{display:"none"},onChange:S}),A&&s.jsxs("div",{style:{fontSize:10,color:c.textTertiary,marginTop:4},children:["Last auto-save: ",new Date(A.savedAt).toLocaleString(),A.genome&&` — ${A.genome.name}`,A.tracks&&` — ${A.tracks.length} tracks`]})]}),v&&s.jsx("div",{style:{padding:"4px 16px",fontSize:11,color:"#81c784"},children:v}),y&&s.jsx("div",{style:{padding:"4px 16px",fontSize:11,color:"#ef9a9a",whiteSpace:"pre-wrap"},children:y})]}),s.jsx("div",{style:R.footer,children:s.jsx("button",{style:R.btn,onClick:e,children:"Close"})})]})})}function ky(e){return{overlay:{position:"fixed",inset:0,background:e.overlayBg,display:"flex",alignItems:"center",justifyContent:"center",zIndex:1e3},panel:{background:e.panelBg,border:`1px solid ${e.borderAccent}`,borderRadius:8,padding:0,minWidth:380,maxWidth:480,maxHeight:"80vh",display:"flex",flexDirection:"column",boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},header:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"10px 16px",borderBottom:`1px solid ${e.border}`},title:{fontSize:14,fontWeight:700,color:e.textPrimary},closeBtn:{background:"none",border:"none",color:e.textSecondary,cursor:"pointer",fontSize:18,lineHeight:1,padding:"0 4px"},body:{padding:"8px 0",overflowY:"auto",flex:1},section:{padding:"8px 16px"},sectionTitle:{fontSize:11,color:e.textSecondary,textTransform:"uppercase",letterSpacing:1,marginBottom:6},btn:{background:e.btnBg,border:"none",borderRadius:4,color:e.btnText,padding:"5px 14px",cursor:"pointer",fontSize:12,fontWeight:600},footer:{display:"flex",justifyContent:"flex-end",padding:"10px 16px",borderTop:`1px solid ${e.border}`}}}const ye=e=>s.jsx("strong",{children:e}),ue=({children:e})=>s.jsxs("div",{style:{display:"flex",gap:6,marginTop:4},children:[s.jsx("span",{style:{opacity:.5},children:"•"}),s.jsx("span",{children:e})]}),Rc=({children:e})=>s.jsx("span",{style:{background:"rgba(255,255,255,0.1)",borderRadius:3,padding:"0 4px",fontSize:11,fontFamily:"monospace"},children:e}),Cn=[{target:"file-loader",title:"Load Files",description:s.jsxs(s.Fragment,{children:["Upload genome and track files via:",s.jsxs(ue,{children:[ye("File picker"),' — click "Choose Files"']}),s.jsxs(ue,{children:[ye("Drag & drop")," — drop files anywhere on the app"]}),s.jsxs(ue,{children:[ye("Local path")," — paste a file path (best for large files)"]}),s.jsx("div",{style:{marginTop:8,opacity:.7},children:"Supported: FASTA, GenBank, BAM, BigWig, WIG, BedGraph, VCF, BED, GTF, GFF"})]}),position:"bottom"},{target:"nav-bar",title:"Navigation",description:s.jsxs(s.Fragment,{children:[s.jsxs(ue,{children:[ye("Chromosome selector")," — switch between chromosomes"]}),s.jsxs(ue,{children:[ye("Coordinate input")," — type ",s.jsx(Rc,{children:"chr1:1000-5000"})," and press Go"]}),s.jsxs(ue,{children:[ye("- +")," — zoom out / zoom in"]}),s.jsxs(ue,{children:[ye("◀ ▶")," — pan left / pan right"]}),s.jsxs(ue,{children:[ye("Blue scrubber bar")," — click or drag to jump across the chromosome"]})]}),position:"bottom"},{target:"track-area",title:"Track Interaction",description:s.jsxs(s.Fragment,{children:[s.jsxs(ue,{children:[ye("Left-click drag")," — pan the viewport"]}),s.jsxs(ue,{children:[ye("Scroll wheel")," — zoom in/out at cursor position"]}),s.jsxs(ue,{children:[ye("Right-click drag")," — select a region (hover for stats)"]}),s.jsxs(ue,{children:[ye("Double-click gene")," — zoom to fit that gene with context"]}),s.jsxs(ue,{children:[ye("Hover features")," — view detailed tooltips"]})]}),position:"inside"},{target:"skeleton-track-label",title:"Track Labels",description:s.jsxs(s.Fragment,{children:[s.jsxs(ue,{children:[ye("≡ Drag handle")," — reorder tracks by dragging"]}),s.jsxs(ue,{children:[ye("Color swatch")," — click to pick a color"]}),s.jsxs(ue,{children:[ye("× Button")," — remove the track"]}),s.jsxs(ue,{children:[ye("Bottom edge")," — drag to resize track height"]})]}),position:"right"},{target:"btn-settings",title:"Track Settings",description:s.jsxs(s.Fragment,{children:["Select one or more tracks to adjust:",s.jsx(ue,{children:"Height, visibility, and fill color"}),s.jsx(ue,{children:"Bar width, peak outline trace + smoothness"}),s.jsxs(ue,{children:["Y-axis scale (auto / manual / log","₂",")"]}),s.jsx(ue,{children:"Annotation colors per feature type"}),s.jsx(ue,{children:"Read appearance — strand colors, arrow style & size"}),s.jsx(ue,{children:"Nucleotide display with mismatch highlighting"}),s.jsx("div",{style:{marginTop:6,opacity:.7},children:"The panel is draggable — adjust settings while viewing your data."})]}),position:"bottom",action:"open-settings"},{target:"header-btns",title:"Themes",description:s.jsxs(s.Fragment,{children:[s.jsxs(ue,{children:[ye("5 built-in themes")," — Dark, Light, Colorblind, Soft, High Contrast"]}),s.jsxs(ue,{children:[ye("Custom themes")," — clone any preset and edit every color"]}),s.jsx("div",{style:{marginTop:6,opacity:.7},children:"Theme preferences persist across sessions."})]}),position:"bottom",action:"open-theme"},{target:"btn-export",title:"Export Image",description:s.jsxs(s.Fragment,{children:["Export the current view as ",ye("SVG")," or ",ye("PNG"),".",s.jsx(ue,{children:"Background, bars, outlines, and labels are separate SVG groups"}),s.jsx(ue,{children:"All track settings (colors, outlines, visibility) are respected"}),s.jsx(ue,{children:"Edit exported SVGs in Illustrator, Inkscape, or Figma"})]}),position:"bottom"},{target:"header-btns",title:"Sessions",description:s.jsxs(s.Fragment,{children:[s.jsxs(ue,{children:[ye("Save to file")," — exports genome, tracks, region, zoom, colors, and all settings as JSON"]}),s.jsxs(ue,{children:[ye("Restore")," — reload a saved session or the last auto-save"]}),s.jsxs(ue,{children:[ye("Auto-save")," — your session saves to the browser automatically"]}),s.jsx("div",{style:{marginTop:6,opacity:.7},children:"An exit guard warns you before closing with unsaved work."})]}),position:"bottom"},{target:"file-loader",title:"Tips",description:s.jsxs(s.Fragment,{children:[s.jsxs(ue,{children:[ye("Large BAM files")," — use the ",s.jsxs(Rc,{children:["📂"," Path"]})," button to load by file path (no upload needed)"]}),s.jsxs(ue,{children:[ye("Large WIG files")," — convert to BigWig for instant loading"]}),s.jsxs(ue,{children:[ye("BAM + BAI")," — select both together, or load by path (index auto-discovered)"]}),s.jsxs(ue,{children:[ye("Updates")," — the app checks for updates automatically on launch"]})]}),position:"bottom"}],Tn=8,jn=14,Et=340,Cy=230,zr="rgba(0,0,0,0.55)";function Ty({onClose:e,theme:t,onAction:n}){const[r,o]=C.useState(0),[l,i]=C.useState(null),[a,u]=C.useState(Cy),c=C.useRef(null),h=Cn[r],d=r===0,g=r===Cn.length-1;C.useEffect(()=>{var S;const j=(S=Cn[r])==null?void 0:S.action;j&&n&&n(j)},[r,n]);const T=C.useCallback(j=>{var E;((E=Cn[j])==null?void 0:E.action)&&n&&n(null)},[n]),v=C.useCallback(()=>{T(r),r<Cn.length-1?o(j=>j+1):e()},[r,e,T]),x=C.useCallback(()=>{T(r),r>0&&o(j=>j-1)},[r,T]);C.useEffect(()=>{function j(S){S.key==="Escape"?e():S.key==="ArrowRight"||S.key==="Enter"?v():S.key==="ArrowLeft"&&x()}return window.addEventListener("keydown",j),()=>window.removeEventListener("keydown",j)},[e,v,x]),C.useEffect(()=>{function j(){const S=document.querySelector(`[data-tour="${h.target}"]`);if(S){const E=S.getBoundingClientRect();i({top:E.top,left:E.left,width:E.width,height:E.height})}else i(null)}return j(),window.addEventListener("resize",j),window.addEventListener("scroll",j,!0),()=>{window.removeEventListener("resize",j),window.removeEventListener("scroll",j,!0)}},[h.target]),C.useEffect(()=>{c.current&&u(c.current.getBoundingClientRect().height)});const y=l?{top:l.top-Tn,left:l.left-Tn,width:l.width+Tn*2,height:l.height+Tn*2}:null;let f,p,m=null,w=Et/2;if(!l)f=(window.innerHeight-a)/2,p=(window.innerWidth-Et)/2;else{const j=h.position||"bottom",S=l.top+l.height+Tn,E=l.top-Tn,$=l.left+l.width+Tn,A=l.left+l.width/2;j==="inside"?(f=l.top+Math.max(20,(l.height-a)/2),p=l.left+Math.max(16,(l.width-Et)/2)):j==="right"?(f=l.top+l.height/2-a/2,p=$+jn,m="left",w=a/2,p+Et>window.innerWidth-12&&(f=S+jn,p=A-Et/2,m="up",w=Math.max(20,Math.min(Et-20,A-p)))):(S+jn+a<=window.innerHeight?(f=S+jn,m="up"):E-jn-a>=0?(f=E-jn-a,m="down"):(f=S+jn,m="up"),l.width<200?(p=Math.max(12,l.left+l.width-Et),p<12&&(p=12)):p=A-Et/2,w=Math.max(20,Math.min(Et-20,A-p))),p=Math.max(12,Math.min(window.innerWidth-Et-12,p)),f=Math.max(12,Math.min(window.innerHeight-a-12,f))}const b={card:{position:"fixed",top:f,left:p,width:Et,zIndex:10002,background:t.panelBg,border:`1px solid ${t.borderAccent}`,borderRadius:10,padding:"20px 24px 16px",color:t.textPrimary,boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},stepCounter:{fontSize:11,fontWeight:600,color:t.textTertiary,textTransform:"uppercase",letterSpacing:1.2,marginBottom:10},title:{fontSize:16,fontWeight:700,marginBottom:6,color:t.textPrimary},description:{fontSize:13,lineHeight:1.6,color:t.textSecondary,marginBottom:20},dots:{display:"flex",justifyContent:"center",gap:8,marginBottom:14},dot:j=>({width:7,height:7,borderRadius:"50%",background:j?"#42a5f5":t.borderStrong,cursor:"pointer"}),nav:{display:"flex",alignItems:"center",justifyContent:"space-between"},btnPrimary:{background:"#1976d2",border:"none",borderRadius:5,color:"#fff",padding:"6px 18px",cursor:"pointer",fontSize:12,fontWeight:600},btnSecondary:{background:t.btnBg,border:`1px solid ${t.borderStrong}`,borderRadius:5,color:t.btnText,padding:"6px 14px",cursor:"pointer",fontSize:12,fontWeight:600},btnDisabled:{background:t.btnBg,border:`1px solid ${t.border}`,borderRadius:5,color:t.textMuted,padding:"6px 14px",fontSize:12,fontWeight:600,cursor:"default",opacity:.5},skip:{background:"none",border:"none",color:t.textTertiary,fontSize:11,cursor:"pointer",textDecoration:"underline",padding:0},arrowUp:{position:"absolute",top:-7,left:w-7,width:0,height:0,borderLeft:"7px solid transparent",borderRight:"7px solid transparent",borderBottom:`7px solid ${t.panelBg}`},arrowDown:{position:"absolute",bottom:-7,left:w-7,width:0,height:0,borderLeft:"7px solid transparent",borderRight:"7px solid transparent",borderTop:`7px solid ${t.panelBg}`},arrowLeft:{position:"absolute",left:-7,top:w-7,width:0,height:0,borderTop:"7px solid transparent",borderBottom:"7px solid transparent",borderRight:`7px solid ${t.panelBg}`}};return s.jsxs(s.Fragment,{children:[s.jsx("div",{style:{position:"fixed",inset:0,zIndex:1e4},onClick:e}),y?s.jsxs(s.Fragment,{children:[s.jsx("div",{style:{position:"fixed",top:0,left:0,right:0,height:Math.max(0,y.top),background:zr,zIndex:10001,pointerEvents:"none"}}),s.jsx("div",{style:{position:"fixed",top:y.top+y.height,left:0,right:0,bottom:0,background:zr,zIndex:10001,pointerEvents:"none"}}),s.jsx("div",{style:{position:"fixed",top:y.top,left:0,width:Math.max(0,y.left),height:y.height,background:zr,zIndex:10001,pointerEvents:"none"}}),s.jsx("div",{style:{position:"fixed",top:y.top,left:y.left+y.width,right:0,height:y.height,background:zr,zIndex:10001,pointerEvents:"none"}}),s.jsx("div",{style:{position:"fixed",top:y.top,left:y.left,width:y.width,height:y.height,borderRadius:6,border:"2px solid rgba(255,255,255,0.22)",zIndex:10001,pointerEvents:"none",boxSizing:"border-box"}})]}):s.jsx("div",{style:{position:"fixed",inset:0,background:zr,zIndex:10001,pointerEvents:"none"}}),s.jsxs("div",{ref:c,style:b.card,onClick:j=>j.stopPropagation(),children:[m==="up"&&s.jsx("div",{style:b.arrowUp}),m==="down"&&s.jsx("div",{style:b.arrowDown}),m==="left"&&s.jsx("div",{style:b.arrowLeft}),s.jsxs("div",{style:b.stepCounter,children:["Step ",r+1," of ",Cn.length]}),s.jsx("div",{style:b.title,children:h.title}),s.jsx("div",{style:b.description,children:h.description}),s.jsx("div",{style:b.dots,children:Cn.map((j,S)=>s.jsx("div",{style:b.dot(S===r),onClick:()=>o(S)},S))}),s.jsxs("div",{style:b.nav,children:[s.jsx("button",{style:b.skip,onClick:e,children:"Skip Tour"}),s.jsxs("div",{style:{display:"flex",gap:8},children:[s.jsx("button",{style:d?b.btnDisabled:b.btnSecondary,onClick:x,disabled:d,children:"Previous"}),s.jsx("button",{style:b.btnPrimary,onClick:v,children:g?"Finish":"Next"})]})]})]})]})}function jy(){const{theme:e}=Xe(),{genome:t,region:n,navigateTo:r,zoom:o,pan:l}=at(),[i,a]=C.useState(""),u=C.useRef(null),c=C.useRef(!1),h=C.useMemo(()=>{if(!t)return{toShort:{},toLong:{}};const w={},b={};return t.chromosomes.forEach((j,S)=>{const E=`chr${S+1}`;w[j.name]=E,b[E.toLowerCase()]=j.name,b[j.name.toLowerCase()]=j.name}),{toShort:w,toLong:b}},[t]);C.useEffect(()=>{if(n){const w=h.toShort[n.chrom]||n.chrom;a(`${w}:${n.start.toLocaleString()}-${n.end.toLocaleString()}`)}},[n,h]);const d=C.useMemo(()=>{if(!t||!n)return 0;const w=t.chromosomes.find(b=>b.name===n.chrom);return w?w.length:0},[t,n==null?void 0:n.chrom]),g=C.useCallback(w=>{if(!u.current||!n||!d)return;const b=u.current.getBoundingClientRect(),j=Math.max(0,Math.min(1,(w-b.left)/b.width)),S=n.end-n.start,E=j*d;r(n.chrom,E-S/2,E+S/2)},[n,d,r]),T=C.useCallback(w=>{w.preventDefault(),c.current=!0,g(w.clientX);function b(S){c.current&&g(S.clientX)}function j(){c.current=!1,window.removeEventListener("mousemove",b),window.removeEventListener("mouseup",j),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="grabbing",document.body.style.userSelect="none",window.addEventListener("mousemove",b),window.addEventListener("mouseup",j)},[g]),v={bar:{background:e.headerBg,borderBottom:`1px solid ${e.border}`,padding:"6px 12px",display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},select:{background:e.inputBg,border:`1px solid ${e.borderAccent}`,borderRadius:4,color:e.textPrimary,padding:"4px 6px",fontSize:12},coordInput:{background:e.inputBg,border:`1px solid ${e.borderAccent}`,borderRadius:4,color:e.textPrimary,padding:"4px 8px",fontSize:12,width:220,fontFamily:"monospace"},btn:{background:e.btnBg,border:"none",borderRadius:4,color:e.btnText,padding:"4px 10px",cursor:"pointer",fontSize:13},info:{color:e.textSecondary,fontSize:11,marginLeft:8},scrubberWrap:{flex:1,minWidth:120,height:14,position:"relative",background:e.inputBg,borderRadius:7,border:`1px solid ${e.borderAccent}`,cursor:"pointer",overflow:"hidden"}};function x(w){if(!t)return;const b=t.chromosomes.find(j=>j.name===w.target.value);b&&r(b.name,0,Math.min(b.length,5e4))}function y(w){w.preventDefault();const j=i.replace(/,/g,"").trim().match(/^(\S+):(\d+)-(\d+)$/);if(j){const S=h.toLong[j[1].toLowerCase()]||j[1];r(S,parseInt(j[2]),parseInt(j[3]))}}if(!t)return s.jsx("div",{style:{...v.bar,opacity:.4},"data-tour":"nav-bar",children:s.jsx("span",{style:{fontSize:12,color:e.textMuted,fontStyle:"italic"},children:"Load a genome to enable navigation"})});const f=n?n.end-n.start:0;let p=0,m=100;return n&&d>0&&(p=n.start/d*100,m=Math.max(1,f/d*100)),s.jsxs("div",{style:v.bar,"data-tour":"nav-bar",children:[s.jsx("select",{style:v.select,value:(n==null?void 0:n.chrom)||"",onChange:x,children:t.chromosomes.map((w,b)=>s.jsxs("option",{value:w.name,children:["chr",b+1," ","—"," ",w.name," (",(w.length/1e3).toFixed(0)," kbp)"]},w.name))}),s.jsxs("form",{onSubmit:y,style:{display:"flex",gap:4},children:[s.jsx("input",{style:v.coordInput,value:i,onChange:w=>a(w.target.value),placeholder:"chr1:start-end"}),s.jsx("button",{style:v.btn,type:"submit",children:"Go"})]}),s.jsx("button",{style:v.btn,onClick:()=>o(2),title:"Zoom out",children:"-"}),s.jsx("button",{style:v.btn,onClick:()=>o(.5),title:"Zoom in",children:"+"}),s.jsx("button",{style:v.btn,onClick:()=>l(-f*.5),title:"Pan left",children:"◀"}),s.jsx("button",{style:v.btn,onClick:()=>l(f*.5),title:"Pan right",children:"▶"}),n&&d>0&&s.jsx("div",{ref:u,style:v.scrubberWrap,onMouseDown:T,title:"Drag to scroll across the chromosome",children:s.jsx("div",{style:{position:"absolute",left:`${p}%`,width:`${m}%`,top:1,bottom:1,background:"#42a5f5",borderRadius:6,minWidth:8,opacity:.7,transition:c.current?"none":"left 0.1s ease"}})}),n&&s.jsxs("span",{style:v.info,children:[f.toLocaleString()," bp"]})]})}function Pp(e){const{region:t,zoom:n,navigateTo:r,setSelection:o,clearSelection:l}=at(),i=C.useRef(null),a=C.useRef(null),u=C.useRef(t);u.current=t,C.useEffect(()=>{const c=e.current;if(!c)return;function h(x){const y=u.current;if(y){if(x.button===2){x.preventDefault();const f=c.getBoundingClientRect(),p=(x.clientX-f.left)/f.width,m=y.start+p*(y.end-y.start);a.current={startX:x.clientX,startBp:m,region:{...y},containerWidth:f.width};return}x.button===0&&(l(),i.current={x:x.clientX,startRegion:{...y},containerWidth:c.offsetWidth||c.clientWidth||1})}}function d(x){if(a.current){const j=a.current,S=c.getBoundingClientRect(),E=Math.max(0,Math.min(1,(x.clientX-S.left)/S.width)),$=j.region.start+E*(j.region.end-j.region.start),A=Math.min(j.startBp,$),R=Math.max(j.startBp,$);Math.abs(R-A)>=1&&o({chrom:j.region.chrom,start:Math.floor(A),end:Math.ceil(R)});return}if(!i.current)return;const y=x.clientX-i.current.x,{chrom:f,start:p,end:m}=i.current.startRegion,w=(m-p)/i.current.containerWidth,b=-y*w;r(f,p+b,m+b)}function g(x){if(a.current){a.current=null;return}i.current=null}function T(x){x.preventDefault()}function v(x){x.preventDefault();const y=c.getBoundingClientRect(),f=(x.clientX-y.left)/y.width,p=x.deltaY>0?1.4:.7;n(p,f)}return c.addEventListener("mousedown",h),c.addEventListener("contextmenu",T),window.addEventListener("mousemove",d),window.addEventListener("mouseup",g),c.addEventListener("wheel",v,{passive:!1}),()=>{c.removeEventListener("mousedown",h),c.removeEventListener("contextmenu",T),window.removeEventListener("mousemove",d),window.removeEventListener("mouseup",g),c.removeEventListener("wheel",v)}},[n,r,o,l,e])}const En=30;function Ey({width:e}){const t=C.useRef(null),n=C.useRef(null),{region:r,selection:o}=at(),{theme:l}=Xe();return Pp(t),C.useEffect(()=>{const i=n.current;if(!i||!r)return;const a=window.devicePixelRatio||1;i.width=e*a,i.height=En*a;const u=i.getContext("2d");u.scale(a,a);const{start:c,end:h}=r,d=h-c;if(u.clearRect(0,0,e,En),u.fillStyle=l.canvasBg,u.fillRect(0,0,e,En),o&&o.chrom===r.chrom){const p=(o.start-c)/d,m=(o.end-c)/d,w=Math.max(0,p*e),b=Math.min(e,m*e);b-w>=1&&(u.fillStyle="rgba(100, 181, 246, 0.25)",u.fillRect(w,0,b-w,En),u.strokeStyle="rgba(100, 181, 246, 0.6)",u.lineWidth=1,u.beginPath(),u.moveTo(w,0),u.lineTo(w,En),u.moveTo(b,0),u.lineTo(b,En),u.stroke())}const g=Math.min(10,Math.floor(e/80)),T=d/g,v=Math.pow(10,Math.floor(Math.log10(T))),x=[1,2,5,10].map(p=>p*v),y=x.find(p=>p>=T)||x[x.length-1],f=Math.ceil(c/y)*y;u.strokeStyle=l.rulerTick,u.fillStyle=l.rulerLabel,u.font="10px Arial, Helvetica, sans-serif",u.textAlign="center",u.beginPath(),u.moveTo(0,20),u.lineTo(e,20),u.lineWidth=1,u.stroke();for(let p=f;p<=h;p+=y){const m=(p-c)/d*e;u.beginPath(),u.moveTo(m,14),u.lineTo(m,20),u.stroke(),u.fillText(Ry(p),m,11)}},[r,o,e,l]),s.jsx("div",{ref:t,style:{position:"relative"},children:s.jsx("canvas",{ref:n,style:{display:"block",width:"100%",height:En}})})}function Ry(e){return e>=1e6?`${(e/1e6).toFixed(2)}M`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function $i(e,t){if(t<=0||e.length===0)return e;const n=new Array(e.length);for(let r=0;r<e.length;r++){let o=0,l=0;const i=Math.max(0,r-t),a=Math.min(e.length-1,r+t);for(let u=i;u<=a;u++)o+=e[u],l++;n[r]=o/l}return n}function Xn(e,t){return e<=0||t<=0?0:Math.log2(e+1)/Math.log2(t+1)}function Py({track:e,width:t,height:n,onWarning:r}){const o=C.useRef(null),{region:l}=at(),{theme:i}=Xe(),{data:a,loading:u,error:c}=ei(e,l,t);return C.useEffect(()=>{var Y,I;const h=o.current;if(!h)return;const d=window.devicePixelRatio||1;h.width=t*d,h.height=n*d;const g=h.getContext("2d");if(g.scale(d,d),g.clearRect(0,0,t,n),g.fillStyle=i.canvasBg,g.fillRect(0,0,t,n),u&&!((Y=a==null?void 0:a.bins)!=null&&Y.length)){g.fillStyle=i.textTertiary,g.font="11px Arial, Helvetica, sans-serif",g.fillText("Loading…",8,n/2+4),r&&r(null);return}if(c){g.fillStyle="#ef9a9a",g.font="11px Arial, Helvetica, sans-serif",g.fillText(typeof c=="string"?c:JSON.stringify(c),8,n/2+4),r&&r(null);return}if(!((I=a==null?void 0:a.bins)!=null&&I.length)){r&&r(null);return}const T=a.max_value||0,v=a.min_value||0,x=v<0,y=l.start,f=l.end-l.start,p=e.color||"#78909c",m=e.scaleMax!=null?e.scaleMax:null,w=e.scaleMin!=null?e.scaleMin:null,b=e.logScale===!0,j=e.barAutoWidth!==!1,S=e.barWidth||2,E=e.showOutline===!0,$=e.outlineColor||null,A=e.outlineSmooth||0,R=e.showBars!==!1,U=p,P=_y(p,-40),W=t/f;function O(L){return j?W>=1?Math.max(1,Math.min(W,L)):Math.max(1,L):Math.min(S,L)}if(x){const N=Math.round(n/2),D=N-12/2,z=n-N-12/2,F=m??(T||1),V=w??(Math.abs(v)||1);if(g.strokeStyle=i.centerLine,g.lineWidth=1,g.beginPath(),g.moveTo(0,N),g.lineTo(t,N),g.stroke(),R)for(const k of a.bins){const Q=(k.end-k.start)/f*t,ee=O(Q),ce=(k.start-y)/f*t,he=k.forward!=null?k.forward:Math.max(0,k.value),pe=k.reverse!=null?k.reverse:Math.min(0,k.value);if(he>0){const ae=b?Xn(he,F):he/F;g.fillStyle=U,g.fillRect(ce,N-ae*D,ee,ae*D)}if(pe<0){const ae=b?Xn(Math.abs(pe),V):Math.abs(pe)/V;g.fillStyle=P,g.fillRect(ce,N,ee,ae*z)}}if(E&&a.bins.length>0){const k=$||i.textPrimary||"#fff",Q=$||i.textPrimary||"#fff",ee=a.bins.map(ie=>{const ne=ie.forward!=null?ie.forward:Math.max(0,ie.value);return ne>0?b?Xn(ne,F):ne/F:0}),ce=a.bins.map(ie=>{const ne=ie.reverse!=null?ie.reverse:Math.min(0,ie.value);return ne<0?b?Xn(Math.abs(ne),V):Math.abs(ne)/V:0}),he=$i(ee,A),pe=$i(ce,A),ae=a.bins.map(ie=>((ie.start+ie.end)/2-y)/f*t);Ni(g,ae,he.map(ie=>N-ie*D),k,A>0),Ni(g,ae,pe.map(ie=>N+ie*z),Q,A>0)}const M=b?" log₂":"";$r(g,`+${F.toFixed(1)}${M}`,2,2,i),$r(g,`−${V.toFixed(1)}${M}`,2,n-12,i),$r(g,"0",2,N-6,i,!0)}else{const L=m??(T||1);if(R){g.fillStyle=U;for(const D of a.bins){const z=(D.end-D.start)/f*t,F=O(z),V=(D.start-y)/f*t,k=(b?Xn(D.value,L):D.value/L)*(n-14);g.fillRect(V,n-k-2,F,k)}}if(E&&a.bins.length>0){const D=a.bins.map(M=>b?Xn(M.value,L):M.value/L),z=$i(D,A),F=a.bins.map(M=>((M.start+M.end)/2-y)/f*t),V=z.map(M=>n-M*(n-14)-2);Ni(g,F,V,$||i.textPrimary||"#fff",A>0)}const N=b?" log₂":"";$r(g,`${L.toFixed(1)}${N}`,2,2,i),$r(g,"0",2,n-12,i,!0)}if(r){const L=[];m!=null&&T>m&&L.push(`Bars clipped: max value ${T.toFixed(1)} exceeds scale ${m.toFixed(1)}`),x&&w!=null&&Math.abs(v)>w&&L.push(`Negative bars clipped: min value ${Math.abs(v).toFixed(1)} exceeds scale ${w.toFixed(1)}`),r(L.length>0?L.join(`
|
|
97
|
-
`):null)}},[a,u,c,t,n,l,e.color,e.scaleMax,e.scaleMin,e.logScale,e.barAutoWidth,e.barWidth,e.showOutline,e.outlineColor,e.outlineSmooth,e.showBars,i]),s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function Ni(e,t,n,r,o){if(!(t.length<2)){if(e.beginPath(),e.moveTo(t[0],n[0]),o){for(let l=0;l<t.length-1;l++){const i=(t[l]+t[l+1])/2,a=(n[l]+n[l+1])/2;e.quadraticCurveTo(t[l],n[l],i,a)}e.lineTo(t[t.length-1],n[n.length-1])}else for(let l=0;l<t.length;l++)e.lineTo(t[l],n[l]);e.strokeStyle=r,e.lineWidth=1.5,e.stroke()}}function $r(e,t,n,r,o,l=!1){e.font="10px Arial, Helvetica, sans-serif",e.textAlign="left",e.textBaseline="top";const i=e.measureText(t),a=2,u=i.width+a*2,c=12;e.fillStyle=o.canvasBg||"#1e1e1e",e.globalAlpha=.75,e.fillRect(n,r,u,c),e.globalAlpha=1,e.fillStyle=l?o.textTertiary||"#666":o.textSecondary||"#aaa",e.fillText(t,n+a,r+1),e.textBaseline="alphabetic"}function _y(e,t){const n=e.match(/^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i);if(!n)return e;const r=o=>Math.max(0,Math.min(255,o+t));return`rgb(${r(parseInt(n[1],16))},${r(parseInt(n[2],16))},${r(parseInt(n[3],16))})`}const Pc=6,Oi=8,Fi=14,Ii=2,Ly="#9c27b0",Vo=10,My={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"},By="#ffeb3b";function _c(e,t){return e<=0||t<=0?0:Math.log2(e+1)/Math.log2(t+1)}function Ay({track:e,width:t,height:n,onWarning:r}){const o=C.useRef(null),{region:l}=at(),{theme:i}=Xe(),{data:a,loading:u}=ei(e,l,t),[c,h]=C.useState(null),d=C.useRef(null),[g,T]=C.useState(0),v=C.useRef(null),x=e.showNucleotides!==!1,y=e.useArrows!==!1,f=e.logScale===!0,p=e.fwdColor||"#90a4ae",m=e.revColor||"#f06292",w=e.arrowStyle||"pointed",b=e.arrowSize||4,j=C.useRef(null);C.useEffect(()=>{if(l&&j.current){const $=j.current;($.chrom!==l.chrom||Math.abs($.start-l.start)>$.end-$.start)&&T(0)}j.current=l},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end]),C.useEffect(()=>{if(!l||!x){h(null);return}const $=l.end-l.start;if(t/$<Pc||$>2e3){h(null);return}if(c&&c.chrom===l.chrom&&c.start<=l.start&&c.end>=l.end)return;const R=Math.max(0,l.start-500),U=l.end+500,P=`${l.chrom}:${R}-${U}`;d.current!==P&&(d.current=P,yn.sequence(l.chrom,R,U).then(W=>h({chrom:l.chrom,start:R,end:U,sequence:W.data.sequence})).catch(()=>{}))},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end,t,x]);const S=C.useCallback($=>{var W;if(!((W=a==null?void 0:a.reads)!=null&&W.length)||!$.shiftKey&&Math.abs($.deltaX)>Math.abs($.deltaY))return;const A=x&&c?Fi:Oi,R=Math.max(0,...a.reads.map(O=>O.row)),U=Math.floor(n/(A+Ii)),P=Math.max(0,R-U+2);P<=0||($.preventDefault(),$.stopPropagation(),T(O=>Math.max(0,Math.min(P,O+Math.sign($.deltaY)*3))))},[a,n,x,c]);C.useEffect(()=>{var k;const $=o.current;if(!$)return;const A=window.devicePixelRatio||1;$.width=t*A,$.height=n*A;const R=$.getContext("2d");if(R.scale(A,A),R.clearRect(0,0,t,n),R.fillStyle=i.canvasBg,R.fillRect(0,0,t,n),u&&!a){R.fillStyle=i.textTertiary,R.font="11px Arial, Helvetica, sans-serif",R.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!a){r&&r(null);return}const U=l.start,P=l.end-l.start;if(a.bins){const Q=a.max_value||1,ee=e.scaleMax!=null?e.scaleMax:Q,ce=e.color||"#78909c",he=e.barAutoWidth!==!1,pe=e.barWidth||2,ae=t/P;if(e.showBars!==!1){R.fillStyle=ce;for(const ne of a.bins){const xe=(ne.end-ne.start)/P*t,Me=he?ae>=1?Math.max(1,Math.min(ae,xe)):Math.max(1,xe):Math.min(pe,xe),ve=(ne.start-U)/P*t,et=(f?_c(ne.value,ee):Math.min(1,ne.value/ee))*(n-14);R.fillRect(ve,n-et-2,Me,et)}}if(e.showOutline&&a.bins.length>0){const ne=e.outlineSmooth||0,xe=a.bins.map(me=>f?_c(me.value,ee):Math.min(1,me.value/ee)),Me=$y(xe,ne),ve=a.bins.map(me=>((me.start+me.end)/2-U)/P*t),Fe=Me.map(me=>n-me*(n-14)-2),et=e.outlineColor||i.textPrimary||"#fff";if(R.beginPath(),R.moveTo(ve[0],Fe[0]),ne>0){for(let me=0;me<ve.length-1;me++)R.quadraticCurveTo(ve[me],Fe[me],(ve[me]+ve[me+1])/2,(Fe[me]+Fe[me+1])/2);R.lineTo(ve[ve.length-1],Fe[Fe.length-1])}else for(let me=0;me<ve.length;me++)R.lineTo(ve[me],Fe[me]);R.strokeStyle=et,R.lineWidth=1.5,R.stroke()}const ie=f?" log₂":"";Lc(R,`${ee.toFixed(1)}${ie}`,2,2,i),Lc(R,"0",2,n-12,i,!0),R.fillStyle="#ffb74d",R.font="10px Arial, Helvetica, sans-serif",R.textAlign="right",R.fillText("zoom in for reads",t-4,10),r&&r(e.scaleMax!=null&&Q>e.scaleMax?`Bars clipped: max value ${Q.toFixed(1)} exceeds scale ${e.scaleMax.toFixed(1)}`:null);return}if(!((k=a.reads)!=null&&k.length)){R.fillStyle=i.textTertiary,R.font="11px Arial, Helvetica, sans-serif",R.fillText("No reads in region",8,n/2+4),r&&r(null);return}const W=Q=>(Q-U)/P*t,O=t/P,Y=x&&O>=Pc&&c!=null,I=Y?Fi:Oi,L=Ii,D=Math.max(0,...a.reads.map(Q=>Q.row))+1,z=Math.floor(n/(I+L)),F=D>z,V=Math.min(g,Math.max(0,D-z+1));let M=0;for(const Q of a.reads){const ee=(Q.row-V)*(I+L)+2;if(ee+I<0||ee>n){M++;continue}const ce=Q.strand==="+"?p:m,he=Q.segments;if(he&&he.length>0){const pe=W(Q.start),ae=W(Q.end);R.strokeStyle=ce,R.lineWidth=1,R.beginPath(),R.moveTo(pe,ee+I/2),R.lineTo(ae,ee+I/2),R.stroke();let ie=0;for(const ne of he)if(ne.type==="M"){const xe=W(ne.start),Me=Math.max(1,W(ne.end)-xe);if(R.fillStyle=ce,R.fillRect(xe,ee,Me,I),Y&&Q.sequence){const ve=ne.end-ne.start;for(let Fe=0;Fe<ve;Fe++){const et=ne.start+Fe,me=W(et),gt=W(et+1)-me,G=(Q.sequence[ie+Fe]||"").toUpperCase();let J="";c&&et>=c.start&&et<c.end&&(J=(c.sequence[et-c.start]||"").toUpperCase());const te=J&&G&&G!==J&&G!=="N";te&&(R.fillStyle=By,R.fillRect(me,ee,gt,I)),gt>=6&&(R.fillStyle=te?"#000":My[G]||"#999",R.font=`bold ${Math.min(11,gt-1)}px monospace`,R.textAlign="center",R.textBaseline="middle",R.fillText(G,me+gt/2,ee+I/2))}ie+=ve}}else if(ne.type==="D"){const xe=W(ne.start),Me=W(ne.end)-xe;Me>=1&&(R.strokeStyle=ce,R.lineWidth=1,R.beginPath(),R.moveTo(xe,ee+I/2),R.lineTo(xe+Me,ee+I/2),R.stroke())}else if(ne.type==="N"){const xe=W(ne.start),Me=W(ne.end)-xe;Me>=2&&(R.setLineDash([2,2]),R.strokeStyle=ce,R.lineWidth=1,R.beginPath(),R.moveTo(xe,ee+I/2),R.lineTo(xe+Me,ee+I/2),R.stroke(),R.setLineDash([]))}else ne.type==="I"?(R.fillStyle=Ly,R.fillRect(W(ne.pos)-1,ee-1,2,I+2),Y&&(ie+=ne.length)):ne.type==="S"&&Y&&(ie+=ne.length)}else{const pe=W(Q.start),ae=Math.max(2,W(Q.end)-pe);R.fillStyle=Q.strand==="+"?p:m,R.fillRect(pe,ee,ae,I)}if(y&&w!=="flat"){const pe=W(Q.start),ae=Math.max(2,W(Q.end)-pe),ie=Math.min(b,ae/2);ie>=2&&zy(R,w,Q.strand,pe,ee,ae,I,ie,ce,i.canvasBg)}if(!Y&&!x){const pe=W(Q.start);Math.max(2,W(Q.end)-pe)>60&&(R.fillStyle=i.canvasBg,R.font="8px Arial, Helvetica, sans-serif",R.textAlign="left",R.fillText(Q.name.slice(0,20),pe+2,ee+I-1))}}if(F){const Q=t-Vo;R.fillStyle=i.inputBg||"#2a2a2a",R.fillRect(Q,0,Vo,n);const ee=z/D,ce=Math.max(20,ee*n),pe=(D>z?V/(D-z):0)*(n-ce);R.fillStyle="#555",R.fillRect(Q+1,pe,Vo-2,ce)}r&&(M>0&&!F?r(`${M} read${M>1?"s":""} hidden — increase track height to show all`):r(F?`${D} rows · Shift+scroll or drag scrollbar to navigate`:null))},[a,u,t,n,l,c,g,e.color,e.scaleMax,e.scaleMin,e.barAutoWidth,e.barWidth,e.showOutline,e.outlineColor,e.outlineSmooth,e.showBars,e.showNucleotides,e.useArrows,e.logScale,e.fwdColor,e.revColor,e.arrowStyle,e.arrowSize,i]);const E=C.useCallback($=>{var D;if(!((D=a==null?void 0:a.reads)!=null&&D.length))return;const A=o.current;if(!A)return;const R=A.getBoundingClientRect();if(($.clientX-R.left)*(t/R.width)<t-Vo)return;const P=x&&c?Fi:Oi,O=Math.max(0,...a.reads.map(z=>z.row))+1,Y=Math.floor(n/(P+Ii)),I=Math.max(0,O-Y+1);if(I<=0)return;$.preventDefault(),v.current={maxScroll:I,startY:$.clientY,startRow:g};function L(z){if(!v.current)return;const F=z.clientY-v.current.startY,V=Math.round(F/n*v.current.maxScroll);T(Math.max(0,Math.min(v.current.maxScroll,v.current.startRow+V)))}function N(){v.current=null,window.removeEventListener("mousemove",L),window.removeEventListener("mouseup",N)}window.addEventListener("mousemove",L),window.addEventListener("mouseup",N)},[a,t,n,g,x,c]);return s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n},onWheel:S,onMouseDown:E})}function zy(e,t,n,r,o,l,i,a,u,c){const h=n==="+";if(t==="pointed")e.fillStyle=c,h?(e.beginPath(),e.moveTo(r+l,o+i/2),e.lineTo(r+l-a,o),e.lineTo(r+l-a,o+i),e.fill()):(e.beginPath(),e.moveTo(r,o+i/2),e.lineTo(r+a,o),e.lineTo(r+a,o+i),e.fill());else if(t==="chevron")e.strokeStyle=c,e.lineWidth=1.5,h?(e.beginPath(),e.moveTo(r+l-a,o),e.lineTo(r+l,o+i/2),e.lineTo(r+l-a,o+i),e.stroke()):(e.beginPath(),e.moveTo(r+a,o),e.lineTo(r,o+i/2),e.lineTo(r+a,o+i),e.stroke());else if(t==="fade")if(h){const d=e.createLinearGradient(r+l-a*2,0,r+l,0);d.addColorStop(0,"rgba(0,0,0,0)"),d.addColorStop(1,c),e.fillStyle=d,e.fillRect(r+l-a*2,o,a*2,i)}else{const d=e.createLinearGradient(r,0,r+a*2,0);d.addColorStop(0,c),d.addColorStop(1,"rgba(0,0,0,0)"),e.fillStyle=d,e.fillRect(r,o,a*2,i)}}function $y(e,t){if(t<=0||e.length===0)return e;const n=new Array(e.length);for(let r=0;r<e.length;r++){let o=0,l=0;const i=Math.max(0,r-t),a=Math.min(e.length-1,r+t);for(let u=i;u<=a;u++)o+=e[u],l++;n[r]=o/l}return n}function Lc(e,t,n,r,o,l=!1){e.font="10px Arial, Helvetica, sans-serif",e.textAlign="left",e.textBaseline="top";const i=2,a=e.measureText(t).width+i*2;e.fillStyle=o.canvasBg||"#1e1e1e",e.globalAlpha=.75,e.fillRect(n,r,a,12),e.globalAlpha=1,e.fillStyle=l?o.textTertiary||"#666":o.textSecondary||"#aaa",e.fillText(t,n+i,r+1),e.textBaseline="alphabetic"}const Ny=16,Oy=22,Fy=4,_p=8,Mc=6,Bc={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"};function Iy({track:e,width:t,height:n,onWarning:r}){var $,A,R,U;const o=C.useRef(null),{region:l,navigateTo:i}=at(),{tracks:a}=Jt(),{theme:u}=Xe(),{data:c,loading:h,error:d}=ei(e,l,t),g=e.useArrows!==!1,T=e.showNucleotides!==!1,v=C.useRef([]),[x,y]=C.useState(null),[f,p]=C.useState(null),m=C.useRef(null);C.useEffect(()=>{if(!l||!T){p(null);return}const P=l.end-l.start;if(t/P<Mc||P>2e3){p(null);return}if(f&&f.chrom===l.chrom&&f.start<=l.start&&f.end>=l.end)return;const O=Math.max(0,l.start-500),Y=l.end+500,I=`${l.chrom}:${O}-${Y}`;m.current!==I&&(m.current=I,yn.sequence(l.chrom,O,Y).then(L=>p({chrom:l.chrom,start:O,end:Y,sequence:L.data.sequence})).catch(()=>{}))},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end,t,T]),C.useEffect(()=>{var V,M;const P=o.current;if(!P)return;const W=window.devicePixelRatio||1;P.width=t*W,P.height=n*W;const O=P.getContext("2d");if(O.scale(W,W),O.clearRect(0,0,t,n),O.fillStyle=u.canvasBg,O.fillRect(0,0,t,n),v.current=[],h&&!((V=c==null?void 0:c.features)!=null&&V.length)){O.fillStyle=u.textTertiary,O.font="11px Arial, Helvetica, sans-serif",O.fillText("Loading…",8,n/2+4),r&&r(null);return}if(d){O.fillStyle="#ef9a9a",O.font="11px Arial, Helvetica, sans-serif",O.fillText(typeof d=="string"?d:JSON.stringify(d),8,n/2+4),r&&r(null);return}if(!((M=c==null?void 0:c.features)!=null&&M.length)){c&&(O.fillStyle=u.textTertiary,O.font="11px Arial, Helvetica, sans-serif",O.fillText("No features in region",8,n/2+4)),r&&r(null);return}const Y=l.end-l.start,I=t/Y,L=T&&I>=Mc&&f!=null,N=L?Oy:Ny,D=[],z=[];let F=0;if(L){const Q=n-14;O.fillStyle=u.canvasBg,O.fillRect(0,Q,t,14),O.strokeStyle=u.border||"#333",O.lineWidth=.5,O.beginPath(),O.moveTo(0,Q),O.lineTo(t,Q),O.stroke();const ee=Math.min(10,I-1);if(ee>=5){O.font=`bold ${ee}px monospace`,O.textAlign="center",O.textBaseline="middle";for(let ce=Math.floor(l.start);ce<Math.ceil(l.end);ce++)if(f&&ce>=f.start&&ce<f.end){const he=(f.sequence[ce-f.start]||"").toUpperCase(),pe=(ce-l.start)/Y*t;O.fillStyle=Bc[he]||"#999",O.fillText(he,pe+I/2,Q+14/2)}}}for(const k of c.features){let Q=D.findIndex(ae=>k.start>=ae);Q===-1&&(Q=D.length),D[Q]=k.end;const ee=(k.start-l.start)/Y*t,ce=Math.max(2,(k.end-k.start)/Y*t),he=Q*(N+Fy)+2;if(he+N>n){F++;continue}const pe=zc(k.feature_type,e,u);if(k.sub_features&&k.sub_features.length>0){O.fillStyle=pe+"66",O.fillRect(ee,he+N/2-1,ce,2);for(const ae of k.sub_features){const ie=(ae.start-l.start)/Y*t,ne=Math.max(1,(ae.end-ae.start)/Y*t),xe=zc(ae.feature_type,e,u),Me=ae.feature_type==="CDS"?N:N-6,ve=ae.feature_type==="CDS"?he:he+3;g?Ac(O,xe,ie,ve,ne,Me,ae.strand||k.strand):(O.fillStyle=xe,O.fillRect(ie,ve,ne,Me))}}else g?Ac(O,pe,ee,he,ce,N,k.strand):(O.fillStyle=pe,O.fillRect(ee,he,ce,N));if(L){const ae=Math.max(k.start,l.start),ie=Math.min(k.end,l.end);for(let ne=ae;ne<ie;ne++)if(f&&ne>=f.start&&ne<f.end){const xe=(f.sequence[ne-f.start]||"").toUpperCase(),Me=(ne-l.start)/Y*t,ve=I;ve>=6&&(O.fillStyle=Bc[xe]||"#999",O.font=`bold ${Math.min(10,ve-1)}px monospace`,O.textAlign="center",O.textBaseline="middle",O.fillText(xe,Me+ve/2,he+N/2))}}else if(ce>20){O.fillStyle="#fff",O.font="10px Arial, Helvetica, sans-serif",O.textAlign="left",O.textBaseline="alphabetic";const ae=k.name||k.feature_type,ie=Math.floor((ce-(g?_p:0)-4)/6);ie>0&&O.fillText(ae.slice(0,ie),ee+3,he+N-4)}z.push({feat:k,x:ee,y:he,w:ce,h:N})}v.current=z,r&&r(F>0?`${F} feature${F>1?"s":""} hidden — increase track height to show all`:null)},[c,h,d,t,n,l,f,e.color,e.annotationColors,g,e.showNucleotides,u]);const w=C.useCallback(P=>{const W=o.current;if(!W)return;const O=W.getBoundingClientRect(),Y=(P.clientX-O.left)*(t/O.width),I=(P.clientY-O.top)*(n/O.height);for(const L of v.current)if(Y>=L.x&&Y<=L.x+L.w&&I>=L.y&&I<=L.y+L.h){const N=Math.min(P.clientX+14,window.innerWidth-300),D=Math.min(P.clientY+14,window.innerHeight-260);y({feat:L.feat,x:Math.max(4,N),y:Math.max(4,D)});return}y(null)},[t,n]),b=C.useCallback(()=>y(null),[]),j=C.useCallback(P=>{const W=o.current;if(!W||!l)return;const O=W.getBoundingClientRect(),Y=(P.clientX-O.left)*(t/O.width),I=(P.clientY-O.top)*(n/O.height);for(const L of v.current)if(Y>=L.x&&Y<=L.x+L.w&&I>=L.y&&I<=L.y+L.h){const N=L.feat,z=(N.end-N.start)*.15/(1-.3),F=N.start-z,V=N.end+z;i(l.chrom,F,V),y(null);return}},[t,n,l,i]),S=x?Dy(x.feat,a,l==null?void 0:l.chrom):[],E=x?Wn.createPortal(s.jsxs("div",{style:{position:"fixed",left:x.x,top:x.y,background:u.tooltipBg,border:`1px solid ${u.tooltipBorder}`,borderRadius:4,padding:"6px 10px",color:u.textPrimary,fontSize:11,lineHeight:1.5,maxWidth:280,zIndex:1e4,pointerEvents:"none",boxShadow:"0 4px 12px rgba(0,0,0,0.5)",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:[s.jsx("div",{style:{fontWeight:700,fontSize:12,marginBottom:2},children:x.feat.name||x.feat.feature_type}),s.jsx(en,{label:"Type",value:x.feat.feature_type}),s.jsx(en,{label:"Strand",value:x.feat.strand||"."}),s.jsx(en,{label:"Location",value:`${x.feat.start.toLocaleString()}–${x.feat.end.toLocaleString()}`}),s.jsx(en,{label:"Length",value:`${(x.feat.end-x.feat.start).toLocaleString()} bp`}),(($=x.feat.attributes)==null?void 0:$.gene)&&x.feat.attributes.gene!==x.feat.name&&s.jsx(en,{label:"Gene",value:x.feat.attributes.gene}),((A=x.feat.attributes)==null?void 0:A.locus_tag)&&s.jsx(en,{label:"Locus",value:x.feat.attributes.locus_tag}),((R=x.feat.attributes)==null?void 0:R.product)&&s.jsx(en,{label:"Product",value:x.feat.attributes.product}),((U=x.feat.attributes)==null?void 0:U.note)&&s.jsx(en,{label:"Note",value:String(x.feat.attributes.note).slice(0,120)}),S.length>0&&s.jsxs(s.Fragment,{children:[s.jsx("div",{style:{borderTop:`1px solid ${u.tooltipBorder}`,margin:"4px 0",paddingTop:4},children:s.jsx("span",{style:{color:u.textSecondary,fontWeight:600,fontSize:10,textTransform:"uppercase"},children:"Track totals in gene"})}),S.map(P=>s.jsxs("div",{style:{display:"flex",justifyContent:"space-between",gap:8},children:[s.jsx("span",{style:{color:u.textSecondary,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",flex:1},children:P.name}),s.jsx("span",{style:{color:u.textPrimary,fontWeight:600,flexShrink:0},children:P.total.toFixed(1)})]},P.trackId))]})]}),document.body):null;return s.jsxs("div",{style:{position:"relative",width:"100%",height:n},children:[s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n},onMouseMove:w,onMouseLeave:b,onDoubleClick:j}),E]})}function en({label:e,value:t}){return t?s.jsxs("div",{style:{display:"flex",gap:6},children:[s.jsxs("span",{style:{opacity:.6,flexShrink:0},children:[e,":"]}),s.jsx("span",{children:t})]}):null}function Dy(e,t,n){var o;if(!e||!n)return[];const r=[];for(const l of t){if(l.track_type!=="coverage"&&l.track_type!=="reads")continue;const i=ly(l.id,n);if(!((o=i==null?void 0:i.bins)!=null&&o.length))continue;let a=0;for(const u of i.bins){if(u.end<=e.start||u.start>=e.end)continue;const c=u.forward!=null?u.forward:Math.max(0,u.value||0),h=u.reverse!=null?Math.abs(u.reverse):Math.abs(Math.min(0,u.value||0));a+=c+h}a>0&&r.push({trackId:l.id,name:l.name,total:a})}return r}function Ac(e,t,n,r,o,l,i){e.fillStyle=t;const a=Math.min(_p,o*.4);e.beginPath(),i==="+"?(e.moveTo(n,r),e.lineTo(n+o-a,r),e.lineTo(n+o,r+l/2),e.lineTo(n+o-a,r+l),e.lineTo(n,r+l),e.closePath()):i==="-"?(e.moveTo(n+a,r),e.lineTo(n+o,r),e.lineTo(n+o,r+l),e.lineTo(n+a,r+l),e.lineTo(n,r+l/2),e.closePath()):e.rect(n,r,o,l),e.fill(),e.strokeStyle="rgba(0,0,0,0.25)",e.lineWidth=.5,e.stroke()}function zc(e,t,n){const r=t.annotationColors;switch(e==null?void 0:e.toLowerCase()){case"cds":return(r==null?void 0:r.cds)||(n==null?void 0:n.geneCds)||"#66bb6a";case"exon":return(r==null?void 0:r.exon)||(n==null?void 0:n.geneExon)||"#42a5f5";case"gene":return(r==null?void 0:r.gene)||(n==null?void 0:n.geneGene)||"#7e57c2";case"mrna":case"transcript":return(r==null?void 0:r.transcript)||(n==null?void 0:n.geneTranscript)||"#ab47bc";case"utr":case"3utr":case"5utr":return(r==null?void 0:r.utr)||(n==null?void 0:n.geneUtr)||"#26c6da";case"rrna":return(r==null?void 0:r.rrna)||(n==null?void 0:n.geneRrna)||"#ffa726";case"trna":return(r==null?void 0:r.trna)||(n==null?void 0:n.geneTrna)||"#ef5350";case"repeat_region":return(r==null?void 0:r.repeat)||(n==null?void 0:n.geneRepeat)||"#8d6e63";default:return(r==null?void 0:r.default)||t.color||(n==null?void 0:n.geneDefault)||"#80cbc4"}}function Uy({track:e,width:t,height:n,onWarning:r}){const o=C.useRef(null),{region:l}=at(),{theme:i}=Xe(),{data:a,loading:u}=ei(e,l,t);return C.useEffect(()=>{var f,p;const c=o.current;if(!c)return;const h=window.devicePixelRatio||1;c.width=t*h,c.height=n*h;const d=c.getContext("2d");if(d.scale(h,h),d.clearRect(0,0,t,n),d.fillStyle=i.canvasBg,d.fillRect(0,0,t,n),u&&!((f=a==null?void 0:a.variants)!=null&&f.length)){d.fillStyle=i.textTertiary,d.font="11px Arial, Helvetica, sans-serif",d.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!((p=a==null?void 0:a.variants)!=null&&p.length)){a&&(d.fillStyle=i.textTertiary,d.font="11px Arial, Helvetica, sans-serif",d.fillText("No variants in region",8,n/2+4)),r&&r(null);return}const g=l.end-l.start,T=e.barAutoWidth!==!1,v=e.barWidth||2,x=T?1:Math.max(.5,v),y=T?5:Math.max(2,v*2);for(const m of a.variants){const w=(m.pos-l.start)/g*t,b=Wy(m.ref,m.alt);d.strokeStyle=b,d.lineWidth=x,d.beginPath(),d.moveTo(w,n-4),d.lineTo(w,14),d.stroke(),d.fillStyle=b,d.beginPath(),d.arc(w,10,y,0,Math.PI*2),d.fill(),g<5e3&&(d.fillStyle=i.textPrimary,d.font="9px Arial, Helvetica, sans-serif",d.textAlign="center",d.fillText(`${m.ref}>${m.alt[0]||"?"}`,w,n-6))}if(r){const m=a.variants.filter(w=>w.pos>=l.start&&w.pos<=l.end).length;r(m>50?`${m} variants overlapping — zoom in for detail`:null)}},[a,u,t,n,l,e.color,e.barAutoWidth,e.barWidth,i]),s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function Wy(e,t){const n=t[0]||"";return e.length===1&&n.length===1?"#ffb74d":n.length>e.length?"#81c784":n.length<e.length?"#e57373":"#b0bec5"}function Hy({message:e,theme:t}){const[n,r]=C.useState(!1),o=C.useRef(null),l=o.current?o.current.getBoundingClientRect():null;return s.jsxs(s.Fragment,{children:[s.jsx("span",{ref:o,onMouseEnter:()=>r(!0),onMouseLeave:()=>r(!1),style:{display:"inline-flex",alignItems:"center",justifyContent:"center",width:12,height:12,borderRadius:"50%",background:"rgba(229, 57, 53, 0.85)",color:"#fff",fontSize:9,fontWeight:800,lineHeight:1,cursor:"default",flexShrink:0,fontFamily:"Arial, Helvetica, sans-serif"},children:"!"}),n&&l&&Wn.createPortal(s.jsx("div",{style:{position:"fixed",left:Math.min(l.right+6,window.innerWidth-220),top:l.top-4,background:t.tooltipBg||"#333",border:`1px solid ${t.tooltipBorder||"#555"}`,borderRadius:4,padding:"4px 8px",color:t.textPrimary||"#e0e0e0",fontSize:11,lineHeight:1.4,maxWidth:200,zIndex:10001,pointerEvents:"none",boxShadow:"0 3px 10px rgba(0,0,0,0.5)",whiteSpace:"pre-wrap",fontFamily:"Arial, Helvetica, sans-serif"},children:e}),document.body)]})}function Vy({width:e,height:t,trackData:n,trackType:r}){const{region:o,selection:l,clearSelection:i}=at(),{theme:a}=Xe(),[u,c]=C.useState(!1),[h,d]=C.useState({x:0,y:0}),g=C.useRef(null),T=C.useCallback(A=>{d({x:A.clientX,y:A.clientY}),c(!0)},[]),v=C.useCallback(()=>c(!1),[]);if(!l||!o||l.chrom!==o.chrom)return null;const x=o.end-o.start;if(x<=0)return null;const y=(l.start-o.start)/x,f=(l.end-o.start)/x,p=Math.max(0,y*e),w=Math.min(e,f*e)-p;if(w<1)return null;const b=Gy(l,n,r),j=l.end-l.start,S=260,E=Math.min(h.x+14,window.innerWidth-S-10),$=Math.min(h.y+14,window.innerHeight-200);return s.jsxs("div",{ref:g,style:{position:"absolute",top:0,left:0,width:e,height:t,pointerEvents:"none"},children:[s.jsx("div",{style:{position:"absolute",left:p,top:0,width:w,height:"100%",background:"rgba(100, 181, 246, 0.2)",borderLeft:"1px solid rgba(100, 181, 246, 0.6)",borderRight:"1px solid rgba(100, 181, 246, 0.6)",pointerEvents:"auto",cursor:"crosshair"},onMouseMove:T,onMouseLeave:v,onClick:A=>{A.stopPropagation(),i()}}),u&&Wn.createPortal(s.jsxs("div",{style:{position:"fixed",left:E,top:$,background:a.panelBg,border:`1px solid ${a.borderAccent}`,borderRadius:6,padding:"8px 12px",fontSize:11,color:a.textPrimary,lineHeight:1.6,pointerEvents:"none",zIndex:1e4,boxShadow:"0 4px 16px rgba(0,0,0,0.4)",minWidth:180,maxWidth:S},children:[s.jsx("div",{style:{fontWeight:700,marginBottom:4,fontSize:12},children:"Selected Region"}),s.jsxs("div",{children:[s.jsx("span",{style:{color:a.textSecondary},children:"Region:"})," ",l.chrom,":",l.start.toLocaleString(),"-",l.end.toLocaleString()]}),s.jsxs("div",{children:[s.jsx("span",{style:{color:a.textSecondary},children:"Length:"})," ",j.toLocaleString()," bp"]}),b.map((A,R)=>s.jsxs("div",{children:[s.jsxs("span",{style:{color:a.textSecondary},children:[A.label,":"]})," ",A.value]},R)),s.jsx("div",{style:{fontSize:9,color:a.textTertiary,marginTop:4},children:"Click to dismiss"})]}),document.body)]})}function Gy(e,t,n){const r=[];if(!t)return r;if(n==="reads"&&t.reads){const o=t.reads.filter(i=>i.end>e.start&&i.start<e.end);r.push({label:"Reads in region",value:o.length.toLocaleString()});let l=0;for(const i of o)if(i.cigar){const a=i.cigar.match(/(\d+)I/g);if(a)for(const u of a)l+=parseInt(u)}if(l>0&&r.push({label:"Insertion bases",value:l.toLocaleString()}),o.length>0){const i=o.reduce((a,u)=>a+(u.mapq||0),0)/o.length;r.push({label:"Avg MAPQ",value:i.toFixed(1)})}}if((n==="coverage"||n==="reads")&&t.bins){const o=t.bins.filter(l=>l.end>e.start&&l.start<e.end);if(o.length>0){const l=o.map(c=>c.value),i=l.reduce((c,h)=>c+h,0)/l.length,a=Math.max(...l),u=Math.min(...l);r.push({label:"Avg coverage",value:i.toFixed(1)}),r.push({label:"Max coverage",value:a.toFixed(1)}),u!==a&&r.push({label:"Min coverage",value:u.toFixed(1)})}}if(n==="variants"&&t.variants){const o=t.variants.filter(l=>l.pos>=e.start&&l.pos<e.end);r.push({label:"Variants in region",value:o.length.toLocaleString()})}if((n==="annotations"||n==="genome_annotations")&&t.features){const o=t.features.filter(l=>l.end>e.start&&l.start<e.end);r.push({label:"Features in region",value:o.length.toLocaleString()})}return r}class Yy extends C.Component{constructor(t){super(t),this.state={hasError:!1,error:null}}static getDerivedStateFromError(t){return{hasError:!0,error:t}}render(){var t;return this.state.hasError?s.jsxs("div",{style:{padding:8,color:"#ef9a9a",fontSize:11},children:["Track error: ",((t=this.state.error)==null?void 0:t.message)||"Unknown error"]}):this.props.children}}function Qy({track:e,containerWidth:t,labelWidth:n=140,onLabelResizeStart:r,isDragging:o,isDropTarget:l,onDragStart:i,onDragOver:a,onDrop:u,onDragEnd:c}){const{theme:h}=Xe(),{updateTrack:d,removeTrack:g}=Jt(),T=C.useRef(null),v=C.useRef(null),[x,y]=C.useState(!1),[f,p]=C.useState(!1),[m,w]=C.useState(null),b=C.useRef(null),j=C.useRef(null),S=e.track_type==="annotations"||e.track_type==="genome_annotations";Pp(T);const E=["#f44336","#ef5350","#e57373","#ff5722","#ff8a65","#ff9800","#ffa726","#ffb74d","#ffc107","#fff176","#4caf50","#66bb6a","#81c784","#aed581","#009688","#26c6da","#80cbc4","#2196f3","#42a5f5","#64b5f6","#7e57c2","#9575cd","#9c27b0","#ab47bc","#ce93d8","#e91e63","#f06292","#795548","#8d6e63","#607d8b","#78909c"],$=t-n,A={row:{display:"flex",borderBottom:`1px solid ${h.border}`,minHeight:40},label:{width:n,minWidth:n,background:h.panelBg,borderRight:`1px solid ${h.border}`,display:"flex",flexDirection:"column",justifyContent:"center",padding:"4px 8px",overflow:"hidden",position:"relative"},trackName:{fontSize:11,color:h.trackName,fontWeight:600,whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},trackType:{fontSize:10,color:h.textTertiary,marginTop:2},trackArea:{flex:1,overflow:"hidden",position:"relative"}},R=C.useCallback(P=>{P.preventDefault(),P.stopPropagation();const W=P.clientY,O=e.height;function Y(L){const N=Math.max(30,Math.min(500,O+(L.clientY-W)));d(e.id,{height:N})}function I(){window.removeEventListener("mousemove",Y),window.removeEventListener("mouseup",I),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="ns-resize",document.body.style.userSelect="none",window.addEventListener("mousemove",Y),window.addEventListener("mouseup",I)},[e.id,e.height,d]);function U(){const P={track:e,width:$,height:e.height,onWarning:w};switch(e.track_type){case"reads":return s.jsx(Ay,{...P});case"coverage":return s.jsx(Py,{...P});case"variants":return s.jsx(Uy,{...P});case"annotations":case"genome_annotations":return s.jsx(Iy,{...P});default:return s.jsx("div",{style:{padding:8,color:h.textTertiary,fontSize:11},children:"Unknown track type"})}}return s.jsxs("div",{style:{...A.row,height:e.height,position:"relative",opacity:o?.4:1,borderTop:l?"2px solid #888":void 0},onDragOver:P=>{P.preventDefault(),P.dataTransfer.dropEffect="move",a==null||a()},onDrop:P=>{P.preventDefault(),u==null||u()},onDragEnd:c,children:[s.jsxs("div",{style:A.label,children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[s.jsx("div",{draggable:!0,onDragStart:P=>{P.dataTransfer.effectAllowed="move",P.dataTransfer.setData("text/plain",e.id),i==null||i()},style:{cursor:"grab",color:h.textMuted,fontSize:14,lineHeight:1,userSelect:"none",flexShrink:0,padding:"0 2px"},title:"Drag to reorder tracks",children:"≡"}),s.jsx("div",{ref:b,children:S?s.jsxs(s.Fragment,{children:[s.jsx("span",{style:{display:"inline-block",width:10,height:10,borderRadius:2,background:"#888",cursor:"pointer",verticalAlign:"middle",border:"1px solid rgba(255,255,255,0.2)",backgroundImage:"linear-gradient(135deg, #ef5350 25%, #66bb6a 25%, #66bb6a 50%, #42a5f5 50%, #42a5f5 75%, #ffa726 75%)"},title:"Click to customize annotation colors",onMouseDown:P=>{P.stopPropagation(),p(W=>!W)}}),f&&Wn.createPortal(s.jsx(Jy,{track:e,theme:h,anchorRef:b,onClose:()=>p(!1),onChange:(P,W)=>{const O={...e.annotationColors||{},[P]:W};d(e.id,{annotationColors:O})},onReset:()=>d(e.id,{annotationColors:null})}),document.body)]}):s.jsxs(s.Fragment,{children:[s.jsx("span",{style:{display:"inline-block",width:10,height:10,borderRadius:2,background:e.color,cursor:"pointer",verticalAlign:"middle",border:"1px solid rgba(255,255,255,0.2)"},title:"Click to pick color, double-click for full palette",onMouseDown:P=>{P.stopPropagation(),y(!0)},onDoubleClick:P=>{var W;P.stopPropagation(),y(!1),(W=j.current)==null||W.click()}}),s.jsx("input",{ref:j,type:"color",value:e.color||"#78909c",onChange:P=>d(e.id,{color:P.target.value}),style:{position:"absolute",left:-9999,top:-9999,opacity:0,width:0,height:0}}),x&&Wn.createPortal(s.jsx("div",{style:{position:"fixed",left:b.current?b.current.getBoundingClientRect().left:0,top:b.current?b.current.getBoundingClientRect().bottom+4:0,zIndex:10001,background:h.panelBg,border:`1px solid ${h.borderAccent}`,borderRadius:4,padding:6,boxShadow:"0 4px 12px rgba(0,0,0,0.5)",display:"grid",gridTemplateColumns:"repeat(5, 18px)",gap:3},onMouseLeave:()=>y(!1),children:E.map(P=>s.jsx("span",{style:{width:18,height:18,borderRadius:3,background:P,cursor:"pointer",border:P===e.color?`2px solid ${h.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onMouseUp:()=>{d(e.id,{color:P}),y(!1)}},P))}),document.body)]})}),s.jsx("div",{style:{...A.trackName,flex:1},title:e.name,children:e.name}),s.jsx("span",{title:"Remove track",onClick:P=>{P.stopPropagation(),g(e.id)},style:{color:"#e53935",fontSize:13,fontWeight:700,cursor:"pointer",lineHeight:1,flexShrink:0,padding:"0 2px",opacity:.7,transition:"opacity 0.15s"},onMouseEnter:P=>P.currentTarget.style.opacity="1",onMouseLeave:P=>P.currentTarget.style.opacity="0.7",children:"×"})]}),s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[s.jsxs("div",{style:A.trackType,children:[e.file_format," · ",e.track_type]}),m&&s.jsx(Hy,{message:m,theme:h})]}),r&&s.jsx("div",{onMouseDown:r,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:P=>P.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:P=>P.currentTarget.style.background="transparent"})]}),s.jsxs("div",{style:A.trackArea,ref:T,children:[s.jsx(Yy,{children:U()}),s.jsx(Vy,{width:$,height:e.height,trackData:jp(e.id),trackType:e.track_type})]}),s.jsx("div",{ref:v,onMouseDown:R,title:"Drag to resize track height",style:{position:"absolute",left:0,right:0,bottom:-2,height:5,cursor:"ns-resize",zIndex:10,background:"transparent"},onMouseEnter:P=>P.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:P=>P.currentTarget.style.background="transparent"})]})}const Xy=[{key:"cds",label:"CDS"},{key:"exon",label:"Exon"},{key:"gene",label:"Gene"},{key:"transcript",label:"Transcript"},{key:"utr",label:"UTR"},{key:"rrna",label:"rRNA"},{key:"trna",label:"tRNA"},{key:"repeat",label:"Repeat"},{key:"default",label:"Other"}],Ky=["#f44336","#ef5350","#e57373","#ff5722","#ff8a65","#ff9800","#ffa726","#ffb74d","#ffc107","#fff176","#4caf50","#66bb6a","#81c784","#aed581","#009688","#26c6da","#80cbc4","#2196f3","#42a5f5","#64b5f6","#7e57c2","#9575cd","#9c27b0","#ab47bc","#ce93d8","#e91e63","#f06292","#795548","#8d6e63","#607d8b","#78909c"],qy={cds:"geneCds",exon:"geneExon",gene:"geneGene",transcript:"geneTranscript",utr:"geneUtr",rrna:"geneRrna",trna:"geneTrna",repeat:"geneRepeat",default:"geneDefault"};function Jy({track:e,theme:t,anchorRef:n,onClose:r,onChange:o,onReset:l}){var x;const[i,a]=C.useState(null),u=C.useRef(null),[c,h]=C.useState(null),d=e.annotationColors||{},g=(x=n.current)==null?void 0:x.getBoundingClientRect();function T(y){return d[y]||t[qy[y]]||Sp[y]}function v(y){h(y),u.current&&(u.current.value=T(y),u.current.click())}return s.jsxs("div",{style:{position:"fixed",left:g?Math.min(g.left,window.innerWidth-220):0,top:g?g.bottom+4:0,zIndex:10001,background:t.panelBg,border:`1px solid ${t.borderAccent}`,borderRadius:6,padding:"8px 0",boxShadow:"0 6px 20px rgba(0,0,0,0.5)",width:210,maxHeight:340,overflowY:"auto"},onMouseLeave:r,children:[s.jsx("div",{style:{fontSize:10,fontWeight:700,color:t.textSecondary,textTransform:"uppercase",letterSpacing:1,padding:"0 10px 6px",borderBottom:`1px solid ${t.border}`,marginBottom:4},children:"Annotation Colors"}),Xy.map(({key:y,label:f})=>{const p=T(y);return s.jsxs("div",{children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"4px 10px",cursor:"pointer",fontSize:11,color:t.textPrimary},onMouseEnter:m=>m.currentTarget.style.background=t.selectedRow,onMouseLeave:m=>m.currentTarget.style.background="transparent",onClick:()=>a(i===y?null:y),children:[s.jsx("span",{style:{display:"inline-block",width:14,height:14,borderRadius:3,background:p,border:"1px solid rgba(255,255,255,0.15)",flexShrink:0,cursor:"pointer"},onDoubleClick:m=>{m.stopPropagation(),v(y)},title:"Click to expand, double-click for full picker"}),s.jsx("span",{style:{flex:1},children:f}),s.jsx("span",{style:{fontSize:9,color:t.textTertiary},children:i===y?"▲":"▼"})]}),i===y&&s.jsx("div",{style:{padding:"4px 10px 6px 32px",display:"grid",gridTemplateColumns:"repeat(5, 18px)",gap:3},children:Ky.map(m=>s.jsx("span",{style:{width:18,height:18,borderRadius:3,background:m,cursor:"pointer",border:m===p?`2px solid ${t.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onClick:()=>{o(y,m),a(null)}},m))})]},y)}),s.jsx("div",{style:{borderTop:`1px solid ${t.border}`,marginTop:4,paddingTop:4},children:s.jsx("div",{style:{padding:"4px 10px",fontSize:10,color:t.textTertiary,cursor:"pointer",textAlign:"center"},onMouseEnter:y=>{y.currentTarget.style.color=t.textPrimary},onMouseLeave:y=>{y.currentTarget.style.color=t.textTertiary},onClick:l,children:"Reset to defaults"})}),s.jsx("input",{ref:u,type:"color",style:{position:"absolute",left:-9999,top:-9999,opacity:0,width:0,height:0},onChange:y=>{c&&o(c,y.target.value)}})]})}function Zy({labelWidth:e}){const{genome:t,region:n}=at(),{tracks:r}=Jt(),{theme:o,themeName:l,customTheme:i}=Xe(),[a,u]=C.useState(!1),[c,h]=C.useState(!1),d=!!t;C.useEffect(()=>{if(!d)return;function x(y){y.preventDefault(),y.returnValue=""}return window.addEventListener("beforeunload",x),()=>window.removeEventListener("beforeunload",x)},[d]),C.useEffect(()=>{if(!d)return;function x(y){(y.ctrlKey||y.metaKey)&&y.key==="w"&&(y.preventDefault(),u(!0))}return window.addEventListener("keydown",x),()=>window.removeEventListener("keydown",x)},[d]);const g=C.useCallback(()=>u(!1),[]),T=C.useCallback(()=>{window.onbeforeunload=null,window.close(),window.location.href="about:blank"},[]),v=C.useCallback(()=>{h(!0);try{const x=Da(t,n,r,l,i,e);Ua(x),Rp(x)}catch{}h(!1),window.onbeforeunload=null,window.close(),window.location.href="about:blank"},[t,n,r,l,i,e]);return a?s.jsx("div",{style:{position:"fixed",inset:0,zIndex:1e4,background:"rgba(0,0,0,0.5)",display:"flex",alignItems:"center",justifyContent:"center"},onClick:g,children:s.jsxs("div",{style:{background:o.panelBg,border:`1px solid ${o.borderAccent}`,borderRadius:8,padding:"24px 28px",maxWidth:400,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.6)"},onClick:x=>x.stopPropagation(),children:[s.jsx("div",{style:{fontSize:16,fontWeight:700,color:o.textPrimary,marginBottom:8},children:"Leave BiNgo Genome Viewer?"}),s.jsxs("div",{style:{fontSize:12,color:o.textSecondary,lineHeight:1.7,marginBottom:20},children:["You have an active session with"," ",s.jsxs("strong",{style:{color:o.textPrimary},children:[r.length," track",r.length!==1?"s":""]})," loaded. Unsaved changes will be lost."]}),s.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:8},children:[s.jsx("button",{onClick:g,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:"Return to App"}),s.jsx("button",{onClick:v,disabled:c,style:{background:o.btnBg,border:`1px solid ${o.borderStrong}`,borderRadius:4,color:o.btnText,padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:c?"Saving...":"Save Session & Exit"}),s.jsx("button",{onClick:T,style:{background:"transparent",border:`1px solid ${o.border}`,borderRadius:4,color:"#e57373",padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:"Exit Without Saving"})]})]})}):null}const $c="2.3.4";let ex=0;function Nc({size:e=32}){const[t]=Hs.useState(()=>`blogo${++ex}`);return s.jsxs("svg",{width:e,height:e,viewBox:"0 0 100 100",style:{flexShrink:0},xmlns:"http://www.w3.org/2000/svg",children:[s.jsxs("defs",{children:[s.jsxs("radialGradient",{id:`${t}_bg`,cx:"35%",cy:"30%",r:"65%",children:[s.jsx("stop",{offset:"0%",stopColor:"#5eb8ff"}),s.jsx("stop",{offset:"50%",stopColor:"#1976d2"}),s.jsx("stop",{offset:"100%",stopColor:"#0d47a1"})]}),s.jsxs("radialGradient",{id:`${t}_sh`,cx:"30%",cy:"25%",r:"30%",children:[s.jsx("stop",{offset:"0%",stopColor:"#ffffff",stopOpacity:"0.7"}),s.jsx("stop",{offset:"100%",stopColor:"#ffffff",stopOpacity:"0"})]})]}),s.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_bg)`}),s.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"white"}),s.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"none",stroke:"#1565c0",strokeWidth:"2.5"}),s.jsx("text",{x:"50",y:"39",textAnchor:"middle",fontSize:"13",fontWeight:"800",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"BN"}),s.jsx("text",{x:"50",y:"64",textAnchor:"middle",fontSize:"30",fontWeight:"900",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"1"}),s.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_sh)`})]})}function tx({theme:e,labelWidth:t}){return s.jsxs("div",{style:{display:"flex",borderBottom:`1px solid ${e.border}`,height:60,opacity:.45},children:[s.jsx("div",{"data-tour":"skeleton-track-label",style:{width:t,minWidth:t,background:e.panelBg,borderRight:`1px solid ${e.border}`,padding:"6px 8px",display:"flex",flexDirection:"column",justifyContent:"center",gap:4},children:s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6},children:[s.jsx("span",{style:{fontSize:14,color:e.textTertiary,userSelect:"none",lineHeight:1},children:"≡"}),s.jsx("span",{style:{width:10,height:10,borderRadius:2,background:"#78909c",flexShrink:0}}),s.jsx("span",{style:{fontSize:11,fontWeight:600,color:e.textSecondary,flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:"Track Name"}),s.jsx("span",{style:{fontSize:13,color:e.textTertiary,lineHeight:1,padding:"0 2px"},children:"×"})]})}),s.jsx("div",{style:{flex:1,background:e.canvasBg}})]})}function nx(){const{theme:e}=Xe(),{genome:t,region:n,setGenome:r,navigateTo:o}=at(),{tracks:l,reorderTracks:i,addTrack:a,uploadTrack:u,commitTrack:c,discardTrack:h,addGenomeAnnotationTrack:d,restoreAnnotationTracks:g}=Jt(),T=C.useRef(null),[v,x]=C.useState(800),[y,f]=C.useState(!1),[p,m]=C.useState(!1),[w,b]=C.useState(!1),[j,S]=C.useState(!1),[E,$]=C.useState(!1),[A,R]=C.useState(!1),[U,P]=C.useState(140),[W,O]=C.useState(null),[Y,I]=C.useState(null),[L,N]=C.useState(!1),[D,z]=C.useState(null),[F,V]=C.useState(null),[M,k]=C.useState(null),Q=C.useRef(0);Sy(U),C.useEffect(()=>{const B=()=>fetch("/api/heartbeat").catch(()=>{});B();const q=setInterval(B,1e4);return()=>clearInterval(q)},[]);const ee=C.useRef(n==null?void 0:n.chrom);C.useEffect(()=>{n!=null&&n.chrom&&n.chrom!==ee.current&&(ee.current=n.chrom,g())},[n==null?void 0:n.chrom,g]);const ce=new Set([".gb",".gbk",".genbank",".fasta",".fa"]),he=new Set([".bam",".bw",".bigwig",".wig",".bedgraph",".bdg",".vcf",".bed",".gtf",".gff",".gff2",".gff3"]),pe=new Set([".bai"]);function ae(B){if(!B)return"";if(B.toLowerCase().endsWith(".vcf.gz"))return".vcf.gz";const q=B.lastIndexOf(".");return q>=0?B.slice(q).toLowerCase():""}const ie=C.useCallback(B=>{var q,X;B.preventDefault(),B.stopPropagation(),(X=(q=B.dataTransfer)==null?void 0:q.types)!=null&&X.includes("Files")&&(Q.current++,Q.current===1&&N(!0))},[]),ne=C.useCallback(B=>{var q,X;B.preventDefault(),B.stopPropagation(),(X=(q=B.dataTransfer)==null?void 0:q.types)!=null&&X.includes("Files")&&(Q.current--,Q.current<=0&&(Q.current=0,N(!1)))},[]),xe=C.useCallback(B=>{B.preventDefault(),B.stopPropagation()},[]);function Me(B){const q=B==null?void 0:B.compatibility;return q&&q.status!=="ok"&&q.status!=="no_genome"}const ve=C.useCallback(async B=>{var Ie,ut,Wa,Ha,Va;if(B.preventDefault(),B.stopPropagation(),Q.current=0,N(!1),!((ut=(Ie=B.dataTransfer)==null?void 0:Ie.types)!=null&&ut.includes("Files")))return;const q=Array.from(B.dataTransfer.files);if(!q.length)return;const X=[],Z=[],le=[],oe=[];for(const Re of q){const Be=ae(Re.name),yt=Re.name.toLowerCase();ce.has(Be)?X.push(Re):he.has(Be)||Be===".vcf.gz"?Z.push(Re):pe.has(Be)||yt.endsWith(".bam.bai")?le.push(Re):oe.push(Re)}const fe=Z.filter(Re=>Re.name.toLowerCase().endsWith(".bam")&&Re.size>50*1024*1024),we=le.filter(Re=>Re.size>10*1024*1024);if(fe.length||we.length){const Re=[...fe,...we].map(yt=>yt.name).join(", "),Be=[...fe,...we].reduce((yt,jo)=>yt+jo.size,0)/(1024*1024);z({error:`${Re} (${Be.toFixed(0)} MB) — large files load faster via the Path button. Click 📂 Path in the toolbar and paste the file path instead of uploading.`}),setTimeout(()=>z(null),1e4);return}if(oe.length&&!X.length&&!Z.length&&!le.length){z({error:`Unsupported file${oe.length>1?"s":""}: ${oe.map(Re=>Re.name).join(", ")}`}),setTimeout(()=>z(null),4e3);return}try{if(X.length>0&&!t){z({msg:`Loading genome: ${X[0].name}...`});const Be=(await yn.load(X[0])).data;if(Be.name&&(Be.name=Ft(Be.name)),r(Be),((Wa=Be.chromosomes)==null?void 0:Wa.length)>0){const yt=Be.chromosomes[0];o(yt.name,0,Math.min(yt.length,5e4))}Be.is_annotated&&d({id:"genome_annotations",name:`${Be.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:Be.annotated_chromosomes||null})}else X.length>0&&t&&V({files:X});if(Z.length>0){if(!t&&X.length===0){z({error:"Load a genome file first (.fasta, .gb, .genbank)"}),setTimeout(()=>z(null),4e3);return}z({msg:`Loading ${Z.length} track${Z.length>1?"s":""}...`});const Re=[],Be=[],yt=[];for(const jo of Z)try{const kn=await u(jo,void 0);Me(kn)?Be.push(kn):(c(kn),Re.push(kn))}catch(kn){yt.push(`${jo.name}: ${((Va=(Ha=kn.response)==null?void 0:Ha.data)==null?void 0:Va.detail)||kn.message}`)}if(yt.length){z({error:yt.join("; ")}),setTimeout(()=>z(null),5e3);return}Be.length>0&&k({tracks:Be})}oe.length?(z({error:`Skipped unsupported: ${oe.map(Re=>Re.name).join(", ")}`}),setTimeout(()=>z(null),4e3)):(z({msg:"Files loaded"}),setTimeout(()=>z(null),2e3))}catch(Re){z({error:Re.message||"Drop failed"}),setTimeout(()=>z(null),5e3)}},[t,r,o,a,d]),Fe=C.useCallback(async()=>{var q,X;if(!F)return;const B=F.files;V(null);try{const Z=[];for(const le of B){z({msg:`Adding chromosomes from ${le.name}...`});try{const fe=(await yn.addChromosomes(le)).data;fe.name&&(fe.name=Ft(fe.name)),r(fe),fe.is_annotated&&d({id:"genome_annotations",name:`${fe.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:fe.annotated_chromosomes||null})}catch(oe){Z.push(`${le.name}: ${((X=(q=oe.response)==null?void 0:q.data)==null?void 0:X.detail)||oe.message}`)}}Z.length?(z({error:Z.join("; ")}),setTimeout(()=>z(null),5e3)):(z({msg:`Added chromosomes from ${B.length} file${B.length>1?"s":""}`}),setTimeout(()=>z(null),3e3))}catch(Z){z({error:Z.message||"Failed to add chromosomes"}),setTimeout(()=>z(null),5e3)}},[F,r,d]),et=C.useCallback(async()=>{var q,X;if(!F)return;const B=F.files;V(null);try{z({msg:`Loading ${B.length} track${B.length>1?"s":""}...`});const Z=[];for(const le of B)try{await a(le,void 0)}catch(oe){Z.push(`${le.name}: ${((X=(q=oe.response)==null?void 0:q.data)==null?void 0:X.detail)||oe.message}`)}Z.length?(z({error:Z.join("; ")}),setTimeout(()=>z(null),5e3)):(z({msg:`Added ${B.length} track${B.length>1?"s":""}`}),setTimeout(()=>z(null),3e3))}catch(Z){z({error:Z.message||"Failed to load tracks"}),setTimeout(()=>z(null),5e3)}},[F,a]),me=C.useCallback(async()=>{if(M){for(const B of M.tracks)await h(B.id);k(null)}},[M,h]),gt=C.useCallback(()=>{if(M){for(const B of M.tracks)c(B);k(null),z({msg:`Added ${M.tracks.length} track${M.tracks.length>1?"s":""}`}),setTimeout(()=>z(null),3e3)}},[M,c]),G=C.useCallback(B=>{B.preventDefault();const q=B.clientX,X=U;function Z(oe){P(Math.max(60,Math.min(400,X+(oe.clientX-q))))}function le(){window.removeEventListener("mousemove",Z),window.removeEventListener("mouseup",le),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="ew-resize",document.body.style.userSelect="none",window.addEventListener("mousemove",Z),window.addEventListener("mouseup",le)},[U]);C.useEffect(()=>{if(!T.current)return;const B=new ResizeObserver(q=>{for(const X of q)x(X.contentRect.width)});return B.observe(T.current),()=>B.disconnect()},[]);const J=C.useCallback(B=>B.visible?!B.targetChromosomes||!(n!=null&&n.chrom)?!0:B.targetChromosomes.includes(n.chrom):!1,[n==null?void 0:n.chrom]),te={app:{display:"flex",flexDirection:"column",height:"100vh",background:e.appBg,color:e.textPrimary},header:{background:e.headerBg,borderBottom:`2px solid ${e.borderAccent}`,padding:"8px 16px",display:"flex",alignItems:"center",justifyContent:"space-between"},headerLeft:{display:"flex",alignItems:"center",gap:12},title:{fontSize:18,fontWeight:700,color:e.textPrimary,letterSpacing:1},subtitle:{fontSize:11,color:e.textTertiary},headerBtns:{display:"flex",gap:8},btn:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 14px",cursor:"pointer",fontSize:12,fontWeight:600,display:"flex",alignItems:"center",gap:6},trackArea:{flex:1,overflowY:"auto",overflowX:"hidden",display:"flex",flexDirection:"column"},emptyState:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",flex:1,color:e.textMuted,gap:12},emptyTitle:{fontSize:22,fontWeight:300},emptyHint:{fontSize:13}};return s.jsxs("div",{style:te.app,onDragEnter:ie,onDragLeave:ne,onDragOver:xe,onDrop:ve,children:[s.jsxs("div",{style:te.header,children:[s.jsxs("div",{style:te.headerLeft,children:[s.jsx(Nc,{size:34}),s.jsxs("div",{children:[s.jsx("div",{style:te.title,children:"BiNgo Genome Viewer"}),t&&s.jsxs("div",{style:te.subtitle,children:[t.name," · ",t.chromosomes.length," chr"]})]}),s.jsxs("button",{onClick:()=>$(!0),title:"About / References",style:{background:"none",border:`1px solid ${e.border}`,borderRadius:10,padding:"2px 8px",display:"flex",alignItems:"center",gap:4,cursor:"pointer",color:e.textSecondary,fontSize:11,fontWeight:600,lineHeight:1,flexShrink:0},onMouseEnter:B=>{B.currentTarget.style.color=e.textPrimary,B.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:B=>{B.currentTarget.style.color=e.textSecondary,B.currentTarget.style.borderColor=e.border},children:[s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"currentColor",style:{flexShrink:0},children:[s.jsx("path",{d:"M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"}),s.jsx("circle",{cx:"8",cy:"4.5",r:"1.2"}),s.jsx("rect",{x:"7",y:"6.5",width:"2",height:"5.5",rx:"0.8"})]}),"Info"]}),s.jsxs("button",{onClick:()=>R(!0),title:"Guided Tour",style:{background:"none",border:`1px solid ${e.border}`,borderRadius:10,padding:"2px 8px",display:"flex",alignItems:"center",gap:4,cursor:"pointer",color:e.textSecondary,fontSize:11,fontWeight:600,lineHeight:1,flexShrink:0},onMouseEnter:B=>{B.currentTarget.style.color=e.textPrimary,B.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:B=>{B.currentTarget.style.color=e.textSecondary,B.currentTarget.style.borderColor=e.border},children:[s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"currentColor",style:{flexShrink:0},children:[s.jsx("path",{d:"M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"}),s.jsx("path",{d:"M5.255 5.786a.237.237 0 0 0 .241.247h.825c.138 0 .248-.113.266-.25.09-.656.54-1.134 1.342-1.134.686 0 1.314.343 1.314 1.168 0 .635-.374.927-.965 1.371-.673.489-1.206 1.06-1.168 1.987l.003.217a.25.25 0 0 0 .25.246h.811a.25.25 0 0 0 .25-.25v-.105c0-.718.273-.927 1.01-1.486.609-.463 1.244-.977 1.244-2.056 0-1.511-1.276-2.241-2.673-2.241-1.267 0-2.655.59-2.75 2.286zM8 13.5a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"})]}),"Help"]})]}),s.jsxs("div",{style:te.headerBtns,"data-tour":"header-btns",children:[s.jsxs("button",{style:te.btn,onClick:()=>S(!0),title:"Save or restore a session",children:[s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",stroke:"currentColor",strokeWidth:"1.3",strokeLinecap:"round",strokeLinejoin:"round",style:{flexShrink:0},children:[s.jsx("path",{d:"M2 2h8v8H2z"}),s.jsx("path",{d:"M4 2v4h4V2"}),s.jsx("path",{d:"M5 3h2"})]}),"Save Session"]}),s.jsxs("button",{style:te.btn,onClick:()=>m(!0),title:"Customize color theme",children:[s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 12 12",style:{flexShrink:0},children:[s.jsx("rect",{x:"0",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#66bb6a"}),s.jsx("rect",{x:"6.5",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#42a5f5"}),s.jsx("rect",{x:"0",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ffa726"}),s.jsx("rect",{x:"6.5",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ab47bc"})]}),"Theme"]}),s.jsxs("button",{"data-tour":"btn-export",style:{...te.btn,...n&&l.length>0?{}:{opacity:.35,cursor:"default"}},onClick:()=>{n&&l.length>0&&b(!0)},title:"Export current view as SVG or PNG",children:[s.jsx("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",style:{flexShrink:0},children:s.jsx("path",{d:"M6 1v7M3 5.5L6 8.5 9 5.5M2 11h8"})}),"Export Image"]}),s.jsxs("button",{"data-tour":"btn-settings",style:{...te.btn,...l.length===0?{opacity:.35,cursor:"default"}:{}},onClick:()=>{l.length>0&&f(!0)},title:"Adjust height, scale, color, and bar width for tracks",children:["⚙"," Track Settings"]})]})]}),s.jsx(W0,{}),s.jsx(jy,{}),s.jsxs("div",{style:te.trackArea,ref:T,"data-tour":"track-area",children:[l.filter(J).length===0&&s.jsx(tx,{theme:e,labelWidth:U}),t?n?s.jsxs(s.Fragment,{children:[s.jsxs("div",{style:{display:"flex"},children:[s.jsx("div",{style:{width:U,minWidth:U,background:e.panelBg,borderRight:`1px solid ${e.border}`,position:"relative"},children:s.jsx("div",{onMouseDown:G,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:B=>B.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:B=>B.currentTarget.style.background="transparent"})}),s.jsx(Ey,{width:v-U})]}),l.filter(J).map(B=>s.jsx(Qy,{track:B,containerWidth:v,labelWidth:U,onLabelResizeStart:G,isDragging:W===B.id,isDropTarget:Y===B.id,onDragStart:()=>O(B.id),onDragOver:()=>I(B.id),onDrop:()=>{W&&W!==B.id&&i(W,B.id),O(null),I(null)},onDragEnd:()=>{O(null),I(null)}},B.id)),l.length===0&&s.jsx("div",{style:{padding:24,color:e.textMuted,fontSize:13},children:"Add tracks above — BAM, VCF, BigWig, BED, GTF, GFF, WIG..."})]}):s.jsx("div",{style:te.emptyState,children:s.jsx("div",{style:te.emptyHint,children:"Select a chromosome to begin"})}):s.jsxs("div",{style:te.emptyState,children:[s.jsx("div",{style:te.emptyTitle,children:"No genome loaded"}),s.jsx("div",{style:te.emptyHint,children:"Load a FASTA or GenBank file above to get started"})]})]}),y&&s.jsx(Q0,{onClose:()=>f(!1)}),p&&s.jsx(Z0,{onClose:()=>m(!1)}),w&&s.jsx(ay,{onClose:()=>b(!1)}),j&&s.jsx(by,{onClose:()=>S(!1),labelWidth:U,setLabelWidth:P}),A&&s.jsx(Ty,{onClose:()=>{R(!1),f(!1),m(!1)},theme:e,onAction:B=>{B==="open-settings"?(f(!0),m(!1)):B==="open-theme"?(m(!0),f(!1)):(f(!1),m(!1))}}),E&&s.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.6)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},onClick:()=>$(!1),children:s.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.border}`,borderRadius:8,padding:"28px 36px",maxWidth:520,maxHeight:"85vh",overflowY:"auto",color:e.textPrimary,lineHeight:1.7},onClick:B=>B.stopPropagation(),children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,marginBottom:16},children:[s.jsx(Nc,{size:44}),s.jsx("div",{style:{fontSize:20,fontWeight:700},children:"BiNgo Genome Viewer"})]}),s.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[s.jsx("strong",{style:{color:e.textPrimary},children:"Version:"})," ",$c]}),s.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[s.jsx("strong",{style:{color:e.textPrimary},children:"Publisher:"})," Billy M Ngo"]}),s.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:20},children:[s.jsx("strong",{style:{color:e.textPrimary},children:"Published:"})," April 2026"]}),s.jsxs("div",{style:{fontSize:12,color:e.textSecondary,background:e.canvasBg,border:`1px solid ${e.border}`,borderRadius:4,padding:"10px 14px",fontFamily:"monospace",lineHeight:1.6,marginBottom:20,userSelect:"all"},children:["Ngo, B.M. (2026). BiNgo Genome Viewer (v",$c,") [Software]."]}),s.jsxs("details",{style:{marginBottom:20},children:[s.jsx("summary",{style:{cursor:"pointer",fontSize:13,fontWeight:600,color:e.textPrimary,marginBottom:8},children:"References & Acknowledgments"}),s.jsxs("div",{style:{fontSize:11,color:e.textSecondary,lineHeight:1.8,paddingTop:8},children:[s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginBottom:4},children:"Software Dependencies"}),s.jsxs("div",{children:[s.jsx("strong",{children:"FastAPI"})," ","—"," Ram","í","rez, S. (2018). A modern web framework for building APIs with Python."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"Uvicorn"})," ","—"," Encode OSS. ASGI server implementation for Python."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"BioPython"})," ","—"," Cock, P.J.A. et al. (2009). ",s.jsx("em",{children:"Bioinformatics"}),", 25(11), 1422","–","1423."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"pyfaidx"})," ","—"," Shirley, M.D. et al. (2015). ",s.jsx("em",{children:"PeerJ PrePrints"}),", 3:e1196."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"bamnostic"})," ","—"," Sherman, M.A. & Mills, R.E. (2019). Pure Python BAM parser."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"React"})," ","—"," Meta Platforms, Inc. JavaScript UI library."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"Vite"})," ","—"," You, E. (2020). Next generation frontend tooling."]}),s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"File Format Specifications"}),s.jsxs("div",{children:[s.jsx("strong",{children:"SAM/BAM"})," ","—"," Li, H. et al. (2009). ",s.jsx("em",{children:"Bioinformatics"}),", 25(16), 2078","–","2079."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"VCF"})," ","—"," Danecek, P. et al. (2011). ",s.jsx("em",{children:"Bioinformatics"}),", 27(15), 2156","–","2158."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"BigWig/WIG"})," ","—"," Kent, W.J. et al. (2010). ",s.jsx("em",{children:"Bioinformatics"}),", 26(17), 2204","–","2207."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"BED"})," ","—"," UCSC Genome Browser, UC Santa Cruz."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"GFF3"})," ","—"," Sequence Ontology Project."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"GTF"})," ","—"," Ensembl genome database project."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"GenBank"})," ","—"," Benson, D.A. et al. (2013). ",s.jsx("em",{children:"Nucleic Acids Res."}),", 41(D1), D36","–","D42."]}),s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Inspiration"}),s.jsxs("div",{children:[s.jsx("strong",{children:"IGV"})," ","—"," Robinson, J.T. et al. (2011). ",s.jsx("em",{children:"Nature Biotechnology"}),", 29(1), 24","–","26."]}),s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Acknowledgments"}),s.jsx("div",{children:"Early version testing and feedback:"}),s.jsx("div",{children:"Amanda Antoch, Isaac Poarch, Otto Chipashvili, Jake Colautti"})]})]}),s.jsx("div",{style:{textAlign:"right"},children:s.jsx("button",{onClick:()=>$(!1),style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 18px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Close"})})]})}),F&&(()=>{const B=F.files.length>1,q=F.files.map(X=>X.name).join(", ");return s.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:s.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.borderAccent}`,borderRadius:8,padding:"20px 24px",maxWidth:440,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},onClick:X=>X.stopPropagation(),children:[s.jsxs("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:["Genome file",B?"s":""," detected"]}),s.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[s.jsx("strong",{style:{color:e.textPrimary},children:q}),B?" appear to be genome files. A genome is already loaded.":" appears to be a genome file. A genome is already loaded.",s.jsx("br",{}),"How would you like to handle ",B?"them":"it","?"]}),s.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[s.jsx("button",{onClick:()=>V(null),style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Skip"}),s.jsxs("button",{onClick:et,style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:["Add as Track",B?"s":""]}),s.jsxs("button",{onClick:Fe,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:["Add as Chromosome",B?"s":""]})]})]})})})(),M&&s.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:s.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.borderAccent}`,borderRadius:8,padding:"20px 24px",maxWidth:480,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},onClick:B=>B.stopPropagation(),children:[s.jsx("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:"Track compatibility warning"}),s.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[M.tracks.map(B=>{var q;return s.jsxs("div",{style:{marginBottom:6},children:[s.jsx("strong",{style:{color:e.textPrimary},children:B.name})," — ",((q=B.compatibility)==null?void 0:q.message)||"Possible mismatch with loaded genome"]},B.id)}),s.jsx("div",{style:{marginTop:8},children:M.tracks.length>1?"These tracks may not match the loaded genome.":"This track may not match the loaded genome."})]}),s.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[s.jsx("button",{onClick:me,style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Skip"}),s.jsx("button",{onClick:gt,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Load Anyway"})]})]})}),L&&s.jsx("div",{style:{position:"fixed",inset:0,zIndex:9998,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"none"},children:s.jsxs("div",{style:{border:`3px dashed ${e.textSecondary}`,borderRadius:16,padding:"40px 60px",textAlign:"center"},children:[s.jsx("div",{style:{fontSize:28,fontWeight:300,color:e.textPrimary,marginBottom:8},children:"Drop files here"}),s.jsx("div",{style:{fontSize:13,color:e.textSecondary},children:"Genome (.gb, .fasta) or track files (.bam, .bw, .wig, .vcf, .bed, .gff, .gtf)"})]})}),D&&s.jsx("div",{style:{position:"fixed",bottom:20,left:"50%",transform:"translateX(-50%)",zIndex:10001,padding:"8px 20px",borderRadius:6,background:D.error?"#c62828":e.panelBg,border:`1px solid ${D.error?"#e53935":e.borderAccent}`,color:D.error?"#fff":"#81c784",fontSize:12,fontWeight:600,boxShadow:"0 4px 16px rgba(0,0,0,0.5)"},children:D.error||D.msg}),t&&s.jsx(Zy,{labelWidth:U})]})}function rx(){return s.jsx(F0,{children:s.jsx(rg,{children:s.jsx($0,{children:s.jsx(nx,{})})})})}Di.createRoot(document.getElementById("root")).render(s.jsx(Hs.StrictMode,{children:s.jsx(rx,{})}));
|
|
97
|
+
`):null)}},[a,u,c,t,n,l,e.color,e.scaleMax,e.scaleMin,e.logScale,e.barAutoWidth,e.barWidth,e.showOutline,e.outlineColor,e.outlineSmooth,e.showBars,i]),s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function Ni(e,t,n,r,o){if(!(t.length<2)){if(e.beginPath(),e.moveTo(t[0],n[0]),o){for(let l=0;l<t.length-1;l++){const i=(t[l]+t[l+1])/2,a=(n[l]+n[l+1])/2;e.quadraticCurveTo(t[l],n[l],i,a)}e.lineTo(t[t.length-1],n[n.length-1])}else for(let l=0;l<t.length;l++)e.lineTo(t[l],n[l]);e.strokeStyle=r,e.lineWidth=1.5,e.stroke()}}function $r(e,t,n,r,o,l=!1){e.font="10px Arial, Helvetica, sans-serif",e.textAlign="left",e.textBaseline="top";const i=e.measureText(t),a=2,u=i.width+a*2,c=12;e.fillStyle=o.canvasBg||"#1e1e1e",e.globalAlpha=.75,e.fillRect(n,r,u,c),e.globalAlpha=1,e.fillStyle=l?o.textTertiary||"#666":o.textSecondary||"#aaa",e.fillText(t,n+a,r+1),e.textBaseline="alphabetic"}function _y(e,t){const n=e.match(/^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i);if(!n)return e;const r=o=>Math.max(0,Math.min(255,o+t));return`rgb(${r(parseInt(n[1],16))},${r(parseInt(n[2],16))},${r(parseInt(n[3],16))})`}const Pc=6,Oi=8,Fi=14,Ii=2,Ly="#9c27b0",Vo=10,My={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"},By="#ffeb3b";function _c(e,t){return e<=0||t<=0?0:Math.log2(e+1)/Math.log2(t+1)}function Ay({track:e,width:t,height:n,onWarning:r}){const o=C.useRef(null),{region:l}=at(),{theme:i}=Xe(),{data:a,loading:u}=ei(e,l,t),[c,h]=C.useState(null),d=C.useRef(null),[g,T]=C.useState(0),v=C.useRef(null),x=e.showNucleotides!==!1,y=e.useArrows!==!1,f=e.logScale===!0,p=e.fwdColor||"#90a4ae",m=e.revColor||"#f06292",w=e.arrowStyle||"pointed",b=e.arrowSize||4,j=C.useRef(null);C.useEffect(()=>{if(l&&j.current){const $=j.current;($.chrom!==l.chrom||Math.abs($.start-l.start)>$.end-$.start)&&T(0)}j.current=l},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end]),C.useEffect(()=>{if(!l||!x){h(null);return}const $=l.end-l.start;if(t/$<Pc||$>2e3){h(null);return}if(c&&c.chrom===l.chrom&&c.start<=l.start&&c.end>=l.end)return;const R=Math.max(0,l.start-500),U=l.end+500,P=`${l.chrom}:${R}-${U}`;d.current!==P&&(d.current=P,yn.sequence(l.chrom,R,U).then(W=>h({chrom:l.chrom,start:R,end:U,sequence:W.data.sequence})).catch(()=>{}))},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end,t,x]);const S=C.useCallback($=>{var W;if(!((W=a==null?void 0:a.reads)!=null&&W.length)||!$.shiftKey&&Math.abs($.deltaX)>Math.abs($.deltaY))return;const A=x&&c?Fi:Oi,R=Math.max(0,...a.reads.map(O=>O.row)),U=Math.floor(n/(A+Ii)),P=Math.max(0,R-U+2);P<=0||($.preventDefault(),$.stopPropagation(),T(O=>Math.max(0,Math.min(P,O+Math.sign($.deltaY)*3))))},[a,n,x,c]);C.useEffect(()=>{var k;const $=o.current;if(!$)return;const A=window.devicePixelRatio||1;$.width=t*A,$.height=n*A;const R=$.getContext("2d");if(R.scale(A,A),R.clearRect(0,0,t,n),R.fillStyle=i.canvasBg,R.fillRect(0,0,t,n),u&&!a){R.fillStyle=i.textTertiary,R.font="11px Arial, Helvetica, sans-serif",R.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!a){r&&r(null);return}const U=l.start,P=l.end-l.start;if(a.bins){const Q=a.max_value||1,ee=e.scaleMax!=null?e.scaleMax:Q,ce=e.color||"#78909c",he=e.barAutoWidth!==!1,pe=e.barWidth||2,ae=t/P;if(e.showBars!==!1){R.fillStyle=ce;for(const ne of a.bins){const xe=(ne.end-ne.start)/P*t,Me=he?ae>=1?Math.max(1,Math.min(ae,xe)):Math.max(1,xe):Math.min(pe,xe),ve=(ne.start-U)/P*t,et=(f?_c(ne.value,ee):Math.min(1,ne.value/ee))*(n-14);R.fillRect(ve,n-et-2,Me,et)}}if(e.showOutline&&a.bins.length>0){const ne=e.outlineSmooth||0,xe=a.bins.map(me=>f?_c(me.value,ee):Math.min(1,me.value/ee)),Me=$y(xe,ne),ve=a.bins.map(me=>((me.start+me.end)/2-U)/P*t),Fe=Me.map(me=>n-me*(n-14)-2),et=e.outlineColor||i.textPrimary||"#fff";if(R.beginPath(),R.moveTo(ve[0],Fe[0]),ne>0){for(let me=0;me<ve.length-1;me++)R.quadraticCurveTo(ve[me],Fe[me],(ve[me]+ve[me+1])/2,(Fe[me]+Fe[me+1])/2);R.lineTo(ve[ve.length-1],Fe[Fe.length-1])}else for(let me=0;me<ve.length;me++)R.lineTo(ve[me],Fe[me]);R.strokeStyle=et,R.lineWidth=1.5,R.stroke()}const ie=f?" log₂":"";Lc(R,`${ee.toFixed(1)}${ie}`,2,2,i),Lc(R,"0",2,n-12,i,!0),R.fillStyle="#ffb74d",R.font="10px Arial, Helvetica, sans-serif",R.textAlign="right",R.fillText("zoom in for reads",t-4,10),r&&r(e.scaleMax!=null&&Q>e.scaleMax?`Bars clipped: max value ${Q.toFixed(1)} exceeds scale ${e.scaleMax.toFixed(1)}`:null);return}if(!((k=a.reads)!=null&&k.length)){R.fillStyle=i.textTertiary,R.font="11px Arial, Helvetica, sans-serif",R.fillText("No reads in region",8,n/2+4),r&&r(null);return}const W=Q=>(Q-U)/P*t,O=t/P,Y=x&&O>=Pc&&c!=null,I=Y?Fi:Oi,L=Ii,D=Math.max(0,...a.reads.map(Q=>Q.row))+1,z=Math.floor(n/(I+L)),F=D>z,V=Math.min(g,Math.max(0,D-z+1));let M=0;for(const Q of a.reads){const ee=(Q.row-V)*(I+L)+2;if(ee+I<0||ee>n){M++;continue}const ce=Q.strand==="+"?p:m,he=Q.segments;if(he&&he.length>0){const pe=W(Q.start),ae=W(Q.end);R.strokeStyle=ce,R.lineWidth=1,R.beginPath(),R.moveTo(pe,ee+I/2),R.lineTo(ae,ee+I/2),R.stroke();let ie=0;for(const ne of he)if(ne.type==="M"){const xe=W(ne.start),Me=Math.max(1,W(ne.end)-xe);if(R.fillStyle=ce,R.fillRect(xe,ee,Me,I),Y&&Q.sequence){const ve=ne.end-ne.start;for(let Fe=0;Fe<ve;Fe++){const et=ne.start+Fe,me=W(et),gt=W(et+1)-me,G=(Q.sequence[ie+Fe]||"").toUpperCase();let J="";c&&et>=c.start&&et<c.end&&(J=(c.sequence[et-c.start]||"").toUpperCase());const te=J&&G&&G!==J&&G!=="N";te&&(R.fillStyle=By,R.fillRect(me,ee,gt,I)),gt>=6&&(R.fillStyle=te?"#000":My[G]||"#999",R.font=`bold ${Math.min(11,gt-1)}px monospace`,R.textAlign="center",R.textBaseline="middle",R.fillText(G,me+gt/2,ee+I/2))}ie+=ve}}else if(ne.type==="D"){const xe=W(ne.start),Me=W(ne.end)-xe;Me>=1&&(R.strokeStyle=ce,R.lineWidth=1,R.beginPath(),R.moveTo(xe,ee+I/2),R.lineTo(xe+Me,ee+I/2),R.stroke())}else if(ne.type==="N"){const xe=W(ne.start),Me=W(ne.end)-xe;Me>=2&&(R.setLineDash([2,2]),R.strokeStyle=ce,R.lineWidth=1,R.beginPath(),R.moveTo(xe,ee+I/2),R.lineTo(xe+Me,ee+I/2),R.stroke(),R.setLineDash([]))}else ne.type==="I"?(R.fillStyle=Ly,R.fillRect(W(ne.pos)-1,ee-1,2,I+2),Y&&(ie+=ne.length)):ne.type==="S"&&Y&&(ie+=ne.length)}else{const pe=W(Q.start),ae=Math.max(2,W(Q.end)-pe);R.fillStyle=Q.strand==="+"?p:m,R.fillRect(pe,ee,ae,I)}if(y&&w!=="flat"){const pe=W(Q.start),ae=Math.max(2,W(Q.end)-pe),ie=Math.min(b,ae/2);ie>=2&&zy(R,w,Q.strand,pe,ee,ae,I,ie,ce,i.canvasBg)}if(!Y&&!x){const pe=W(Q.start);Math.max(2,W(Q.end)-pe)>60&&(R.fillStyle=i.canvasBg,R.font="8px Arial, Helvetica, sans-serif",R.textAlign="left",R.fillText(Q.name.slice(0,20),pe+2,ee+I-1))}}if(F){const Q=t-Vo;R.fillStyle=i.inputBg||"#2a2a2a",R.fillRect(Q,0,Vo,n);const ee=z/D,ce=Math.max(20,ee*n),pe=(D>z?V/(D-z):0)*(n-ce);R.fillStyle="#555",R.fillRect(Q+1,pe,Vo-2,ce)}r&&(M>0&&!F?r(`${M} read${M>1?"s":""} hidden — increase track height to show all`):r(F?`${D} rows · Shift+scroll or drag scrollbar to navigate`:null))},[a,u,t,n,l,c,g,e.color,e.scaleMax,e.scaleMin,e.barAutoWidth,e.barWidth,e.showOutline,e.outlineColor,e.outlineSmooth,e.showBars,e.showNucleotides,e.useArrows,e.logScale,e.fwdColor,e.revColor,e.arrowStyle,e.arrowSize,i]);const E=C.useCallback($=>{var D;if(!((D=a==null?void 0:a.reads)!=null&&D.length))return;const A=o.current;if(!A)return;const R=A.getBoundingClientRect();if(($.clientX-R.left)*(t/R.width)<t-Vo)return;const P=x&&c?Fi:Oi,O=Math.max(0,...a.reads.map(z=>z.row))+1,Y=Math.floor(n/(P+Ii)),I=Math.max(0,O-Y+1);if(I<=0)return;$.preventDefault(),v.current={maxScroll:I,startY:$.clientY,startRow:g};function L(z){if(!v.current)return;const F=z.clientY-v.current.startY,V=Math.round(F/n*v.current.maxScroll);T(Math.max(0,Math.min(v.current.maxScroll,v.current.startRow+V)))}function N(){v.current=null,window.removeEventListener("mousemove",L),window.removeEventListener("mouseup",N)}window.addEventListener("mousemove",L),window.addEventListener("mouseup",N)},[a,t,n,g,x,c]);return s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n},onWheel:S,onMouseDown:E})}function zy(e,t,n,r,o,l,i,a,u,c){const h=n==="+";if(t==="pointed")e.fillStyle=c,h?(e.beginPath(),e.moveTo(r+l,o+i/2),e.lineTo(r+l-a,o),e.lineTo(r+l-a,o+i),e.fill()):(e.beginPath(),e.moveTo(r,o+i/2),e.lineTo(r+a,o),e.lineTo(r+a,o+i),e.fill());else if(t==="chevron")e.strokeStyle=c,e.lineWidth=1.5,h?(e.beginPath(),e.moveTo(r+l-a,o),e.lineTo(r+l,o+i/2),e.lineTo(r+l-a,o+i),e.stroke()):(e.beginPath(),e.moveTo(r+a,o),e.lineTo(r,o+i/2),e.lineTo(r+a,o+i),e.stroke());else if(t==="fade")if(h){const d=e.createLinearGradient(r+l-a*2,0,r+l,0);d.addColorStop(0,"rgba(0,0,0,0)"),d.addColorStop(1,c),e.fillStyle=d,e.fillRect(r+l-a*2,o,a*2,i)}else{const d=e.createLinearGradient(r,0,r+a*2,0);d.addColorStop(0,c),d.addColorStop(1,"rgba(0,0,0,0)"),e.fillStyle=d,e.fillRect(r,o,a*2,i)}}function $y(e,t){if(t<=0||e.length===0)return e;const n=new Array(e.length);for(let r=0;r<e.length;r++){let o=0,l=0;const i=Math.max(0,r-t),a=Math.min(e.length-1,r+t);for(let u=i;u<=a;u++)o+=e[u],l++;n[r]=o/l}return n}function Lc(e,t,n,r,o,l=!1){e.font="10px Arial, Helvetica, sans-serif",e.textAlign="left",e.textBaseline="top";const i=2,a=e.measureText(t).width+i*2;e.fillStyle=o.canvasBg||"#1e1e1e",e.globalAlpha=.75,e.fillRect(n,r,a,12),e.globalAlpha=1,e.fillStyle=l?o.textTertiary||"#666":o.textSecondary||"#aaa",e.fillText(t,n+i,r+1),e.textBaseline="alphabetic"}const Ny=16,Oy=22,Fy=4,_p=8,Mc=6,Bc={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"};function Iy({track:e,width:t,height:n,onWarning:r}){var $,A,R,U;const o=C.useRef(null),{region:l,navigateTo:i}=at(),{tracks:a}=Jt(),{theme:u}=Xe(),{data:c,loading:h,error:d}=ei(e,l,t),g=e.useArrows!==!1,T=e.showNucleotides!==!1,v=C.useRef([]),[x,y]=C.useState(null),[f,p]=C.useState(null),m=C.useRef(null);C.useEffect(()=>{if(!l||!T){p(null);return}const P=l.end-l.start;if(t/P<Mc||P>2e3){p(null);return}if(f&&f.chrom===l.chrom&&f.start<=l.start&&f.end>=l.end)return;const O=Math.max(0,l.start-500),Y=l.end+500,I=`${l.chrom}:${O}-${Y}`;m.current!==I&&(m.current=I,yn.sequence(l.chrom,O,Y).then(L=>p({chrom:l.chrom,start:O,end:Y,sequence:L.data.sequence})).catch(()=>{}))},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end,t,T]),C.useEffect(()=>{var V,M;const P=o.current;if(!P)return;const W=window.devicePixelRatio||1;P.width=t*W,P.height=n*W;const O=P.getContext("2d");if(O.scale(W,W),O.clearRect(0,0,t,n),O.fillStyle=u.canvasBg,O.fillRect(0,0,t,n),v.current=[],h&&!((V=c==null?void 0:c.features)!=null&&V.length)){O.fillStyle=u.textTertiary,O.font="11px Arial, Helvetica, sans-serif",O.fillText("Loading…",8,n/2+4),r&&r(null);return}if(d){O.fillStyle="#ef9a9a",O.font="11px Arial, Helvetica, sans-serif",O.fillText(typeof d=="string"?d:JSON.stringify(d),8,n/2+4),r&&r(null);return}if(!((M=c==null?void 0:c.features)!=null&&M.length)){c&&(O.fillStyle=u.textTertiary,O.font="11px Arial, Helvetica, sans-serif",O.fillText("No features in region",8,n/2+4)),r&&r(null);return}const Y=l.end-l.start,I=t/Y,L=T&&I>=Mc&&f!=null,N=L?Oy:Ny,D=[],z=[];let F=0;if(L){const Q=n-14;O.fillStyle=u.canvasBg,O.fillRect(0,Q,t,14),O.strokeStyle=u.border||"#333",O.lineWidth=.5,O.beginPath(),O.moveTo(0,Q),O.lineTo(t,Q),O.stroke();const ee=Math.min(10,I-1);if(ee>=5){O.font=`bold ${ee}px monospace`,O.textAlign="center",O.textBaseline="middle";for(let ce=Math.floor(l.start);ce<Math.ceil(l.end);ce++)if(f&&ce>=f.start&&ce<f.end){const he=(f.sequence[ce-f.start]||"").toUpperCase(),pe=(ce-l.start)/Y*t;O.fillStyle=Bc[he]||"#999",O.fillText(he,pe+I/2,Q+14/2)}}}for(const k of c.features){let Q=D.findIndex(ae=>k.start>=ae);Q===-1&&(Q=D.length),D[Q]=k.end;const ee=(k.start-l.start)/Y*t,ce=Math.max(2,(k.end-k.start)/Y*t),he=Q*(N+Fy)+2;if(he+N>n){F++;continue}const pe=zc(k.feature_type,e,u);if(k.sub_features&&k.sub_features.length>0){O.fillStyle=pe+"66",O.fillRect(ee,he+N/2-1,ce,2);for(const ae of k.sub_features){const ie=(ae.start-l.start)/Y*t,ne=Math.max(1,(ae.end-ae.start)/Y*t),xe=zc(ae.feature_type,e,u),Me=ae.feature_type==="CDS"?N:N-6,ve=ae.feature_type==="CDS"?he:he+3;g?Ac(O,xe,ie,ve,ne,Me,ae.strand||k.strand):(O.fillStyle=xe,O.fillRect(ie,ve,ne,Me))}}else g?Ac(O,pe,ee,he,ce,N,k.strand):(O.fillStyle=pe,O.fillRect(ee,he,ce,N));if(L){const ae=Math.max(k.start,l.start),ie=Math.min(k.end,l.end);for(let ne=ae;ne<ie;ne++)if(f&&ne>=f.start&&ne<f.end){const xe=(f.sequence[ne-f.start]||"").toUpperCase(),Me=(ne-l.start)/Y*t,ve=I;ve>=6&&(O.fillStyle=Bc[xe]||"#999",O.font=`bold ${Math.min(10,ve-1)}px monospace`,O.textAlign="center",O.textBaseline="middle",O.fillText(xe,Me+ve/2,he+N/2))}}else if(ce>20){O.fillStyle="#fff",O.font="10px Arial, Helvetica, sans-serif",O.textAlign="left",O.textBaseline="alphabetic";const ae=k.name||k.feature_type,ie=Math.floor((ce-(g?_p:0)-4)/6);ie>0&&O.fillText(ae.slice(0,ie),ee+3,he+N-4)}z.push({feat:k,x:ee,y:he,w:ce,h:N})}v.current=z,r&&r(F>0?`${F} feature${F>1?"s":""} hidden — increase track height to show all`:null)},[c,h,d,t,n,l,f,e.color,e.annotationColors,g,e.showNucleotides,u]);const w=C.useCallback(P=>{const W=o.current;if(!W)return;const O=W.getBoundingClientRect(),Y=(P.clientX-O.left)*(t/O.width),I=(P.clientY-O.top)*(n/O.height);for(const L of v.current)if(Y>=L.x&&Y<=L.x+L.w&&I>=L.y&&I<=L.y+L.h){const N=Math.min(P.clientX+14,window.innerWidth-300),D=Math.min(P.clientY+14,window.innerHeight-260);y({feat:L.feat,x:Math.max(4,N),y:Math.max(4,D)});return}y(null)},[t,n]),b=C.useCallback(()=>y(null),[]),j=C.useCallback(P=>{const W=o.current;if(!W||!l)return;const O=W.getBoundingClientRect(),Y=(P.clientX-O.left)*(t/O.width),I=(P.clientY-O.top)*(n/O.height);for(const L of v.current)if(Y>=L.x&&Y<=L.x+L.w&&I>=L.y&&I<=L.y+L.h){const N=L.feat,z=(N.end-N.start)*.15/(1-.3),F=N.start-z,V=N.end+z;i(l.chrom,F,V),y(null);return}},[t,n,l,i]),S=x?Dy(x.feat,a,l==null?void 0:l.chrom):[],E=x?Wn.createPortal(s.jsxs("div",{style:{position:"fixed",left:x.x,top:x.y,background:u.tooltipBg,border:`1px solid ${u.tooltipBorder}`,borderRadius:4,padding:"6px 10px",color:u.textPrimary,fontSize:11,lineHeight:1.5,maxWidth:280,zIndex:1e4,pointerEvents:"none",boxShadow:"0 4px 12px rgba(0,0,0,0.5)",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:[s.jsx("div",{style:{fontWeight:700,fontSize:12,marginBottom:2},children:x.feat.name||x.feat.feature_type}),s.jsx(en,{label:"Type",value:x.feat.feature_type}),s.jsx(en,{label:"Strand",value:x.feat.strand||"."}),s.jsx(en,{label:"Location",value:`${x.feat.start.toLocaleString()}–${x.feat.end.toLocaleString()}`}),s.jsx(en,{label:"Length",value:`${(x.feat.end-x.feat.start).toLocaleString()} bp`}),(($=x.feat.attributes)==null?void 0:$.gene)&&x.feat.attributes.gene!==x.feat.name&&s.jsx(en,{label:"Gene",value:x.feat.attributes.gene}),((A=x.feat.attributes)==null?void 0:A.locus_tag)&&s.jsx(en,{label:"Locus",value:x.feat.attributes.locus_tag}),((R=x.feat.attributes)==null?void 0:R.product)&&s.jsx(en,{label:"Product",value:x.feat.attributes.product}),((U=x.feat.attributes)==null?void 0:U.note)&&s.jsx(en,{label:"Note",value:String(x.feat.attributes.note).slice(0,120)}),S.length>0&&s.jsxs(s.Fragment,{children:[s.jsx("div",{style:{borderTop:`1px solid ${u.tooltipBorder}`,margin:"4px 0",paddingTop:4},children:s.jsx("span",{style:{color:u.textSecondary,fontWeight:600,fontSize:10,textTransform:"uppercase"},children:"Track totals in gene"})}),S.map(P=>s.jsxs("div",{style:{display:"flex",justifyContent:"space-between",gap:8},children:[s.jsx("span",{style:{color:u.textSecondary,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",flex:1},children:P.name}),s.jsx("span",{style:{color:u.textPrimary,fontWeight:600,flexShrink:0},children:P.total.toFixed(1)})]},P.trackId))]})]}),document.body):null;return s.jsxs("div",{style:{position:"relative",width:"100%",height:n},children:[s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n},onMouseMove:w,onMouseLeave:b,onDoubleClick:j}),E]})}function en({label:e,value:t}){return t?s.jsxs("div",{style:{display:"flex",gap:6},children:[s.jsxs("span",{style:{opacity:.6,flexShrink:0},children:[e,":"]}),s.jsx("span",{children:t})]}):null}function Dy(e,t,n){var o;if(!e||!n)return[];const r=[];for(const l of t){if(l.track_type!=="coverage"&&l.track_type!=="reads")continue;const i=ly(l.id,n);if(!((o=i==null?void 0:i.bins)!=null&&o.length))continue;let a=0;for(const u of i.bins){if(u.end<=e.start||u.start>=e.end)continue;const c=u.forward!=null?u.forward:Math.max(0,u.value||0),h=u.reverse!=null?Math.abs(u.reverse):Math.abs(Math.min(0,u.value||0));a+=c+h}a>0&&r.push({trackId:l.id,name:l.name,total:a})}return r}function Ac(e,t,n,r,o,l,i){e.fillStyle=t;const a=Math.min(_p,o*.4);e.beginPath(),i==="+"?(e.moveTo(n,r),e.lineTo(n+o-a,r),e.lineTo(n+o,r+l/2),e.lineTo(n+o-a,r+l),e.lineTo(n,r+l),e.closePath()):i==="-"?(e.moveTo(n+a,r),e.lineTo(n+o,r),e.lineTo(n+o,r+l),e.lineTo(n+a,r+l),e.lineTo(n,r+l/2),e.closePath()):e.rect(n,r,o,l),e.fill(),e.strokeStyle="rgba(0,0,0,0.25)",e.lineWidth=.5,e.stroke()}function zc(e,t,n){const r=t.annotationColors;switch(e==null?void 0:e.toLowerCase()){case"cds":return(r==null?void 0:r.cds)||(n==null?void 0:n.geneCds)||"#66bb6a";case"exon":return(r==null?void 0:r.exon)||(n==null?void 0:n.geneExon)||"#42a5f5";case"gene":return(r==null?void 0:r.gene)||(n==null?void 0:n.geneGene)||"#7e57c2";case"mrna":case"transcript":return(r==null?void 0:r.transcript)||(n==null?void 0:n.geneTranscript)||"#ab47bc";case"utr":case"3utr":case"5utr":return(r==null?void 0:r.utr)||(n==null?void 0:n.geneUtr)||"#26c6da";case"rrna":return(r==null?void 0:r.rrna)||(n==null?void 0:n.geneRrna)||"#ffa726";case"trna":return(r==null?void 0:r.trna)||(n==null?void 0:n.geneTrna)||"#ef5350";case"repeat_region":return(r==null?void 0:r.repeat)||(n==null?void 0:n.geneRepeat)||"#8d6e63";default:return(r==null?void 0:r.default)||t.color||(n==null?void 0:n.geneDefault)||"#80cbc4"}}function Uy({track:e,width:t,height:n,onWarning:r}){const o=C.useRef(null),{region:l}=at(),{theme:i}=Xe(),{data:a,loading:u}=ei(e,l,t);return C.useEffect(()=>{var f,p;const c=o.current;if(!c)return;const h=window.devicePixelRatio||1;c.width=t*h,c.height=n*h;const d=c.getContext("2d");if(d.scale(h,h),d.clearRect(0,0,t,n),d.fillStyle=i.canvasBg,d.fillRect(0,0,t,n),u&&!((f=a==null?void 0:a.variants)!=null&&f.length)){d.fillStyle=i.textTertiary,d.font="11px Arial, Helvetica, sans-serif",d.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!((p=a==null?void 0:a.variants)!=null&&p.length)){a&&(d.fillStyle=i.textTertiary,d.font="11px Arial, Helvetica, sans-serif",d.fillText("No variants in region",8,n/2+4)),r&&r(null);return}const g=l.end-l.start,T=e.barAutoWidth!==!1,v=e.barWidth||2,x=T?1:Math.max(.5,v),y=T?5:Math.max(2,v*2);for(const m of a.variants){const w=(m.pos-l.start)/g*t,b=Wy(m.ref,m.alt);d.strokeStyle=b,d.lineWidth=x,d.beginPath(),d.moveTo(w,n-4),d.lineTo(w,14),d.stroke(),d.fillStyle=b,d.beginPath(),d.arc(w,10,y,0,Math.PI*2),d.fill(),g<5e3&&(d.fillStyle=i.textPrimary,d.font="9px Arial, Helvetica, sans-serif",d.textAlign="center",d.fillText(`${m.ref}>${m.alt[0]||"?"}`,w,n-6))}if(r){const m=a.variants.filter(w=>w.pos>=l.start&&w.pos<=l.end).length;r(m>50?`${m} variants overlapping — zoom in for detail`:null)}},[a,u,t,n,l,e.color,e.barAutoWidth,e.barWidth,i]),s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function Wy(e,t){const n=t[0]||"";return e.length===1&&n.length===1?"#ffb74d":n.length>e.length?"#81c784":n.length<e.length?"#e57373":"#b0bec5"}function Hy({message:e,theme:t}){const[n,r]=C.useState(!1),o=C.useRef(null),l=o.current?o.current.getBoundingClientRect():null;return s.jsxs(s.Fragment,{children:[s.jsx("span",{ref:o,onMouseEnter:()=>r(!0),onMouseLeave:()=>r(!1),style:{display:"inline-flex",alignItems:"center",justifyContent:"center",width:12,height:12,borderRadius:"50%",background:"rgba(229, 57, 53, 0.85)",color:"#fff",fontSize:9,fontWeight:800,lineHeight:1,cursor:"default",flexShrink:0,fontFamily:"Arial, Helvetica, sans-serif"},children:"!"}),n&&l&&Wn.createPortal(s.jsx("div",{style:{position:"fixed",left:Math.min(l.right+6,window.innerWidth-220),top:l.top-4,background:t.tooltipBg||"#333",border:`1px solid ${t.tooltipBorder||"#555"}`,borderRadius:4,padding:"4px 8px",color:t.textPrimary||"#e0e0e0",fontSize:11,lineHeight:1.4,maxWidth:200,zIndex:10001,pointerEvents:"none",boxShadow:"0 3px 10px rgba(0,0,0,0.5)",whiteSpace:"pre-wrap",fontFamily:"Arial, Helvetica, sans-serif"},children:e}),document.body)]})}function Vy({width:e,height:t,trackData:n,trackType:r}){const{region:o,selection:l,clearSelection:i}=at(),{theme:a}=Xe(),[u,c]=C.useState(!1),[h,d]=C.useState({x:0,y:0}),g=C.useRef(null),T=C.useCallback(A=>{d({x:A.clientX,y:A.clientY}),c(!0)},[]),v=C.useCallback(()=>c(!1),[]);if(!l||!o||l.chrom!==o.chrom)return null;const x=o.end-o.start;if(x<=0)return null;const y=(l.start-o.start)/x,f=(l.end-o.start)/x,p=Math.max(0,y*e),w=Math.min(e,f*e)-p;if(w<1)return null;const b=Gy(l,n,r),j=l.end-l.start,S=260,E=Math.min(h.x+14,window.innerWidth-S-10),$=Math.min(h.y+14,window.innerHeight-200);return s.jsxs("div",{ref:g,style:{position:"absolute",top:0,left:0,width:e,height:t,pointerEvents:"none"},children:[s.jsx("div",{style:{position:"absolute",left:p,top:0,width:w,height:"100%",background:"rgba(100, 181, 246, 0.2)",borderLeft:"1px solid rgba(100, 181, 246, 0.6)",borderRight:"1px solid rgba(100, 181, 246, 0.6)",pointerEvents:"auto",cursor:"crosshair"},onMouseMove:T,onMouseLeave:v,onClick:A=>{A.stopPropagation(),i()}}),u&&Wn.createPortal(s.jsxs("div",{style:{position:"fixed",left:E,top:$,background:a.panelBg,border:`1px solid ${a.borderAccent}`,borderRadius:6,padding:"8px 12px",fontSize:11,color:a.textPrimary,lineHeight:1.6,pointerEvents:"none",zIndex:1e4,boxShadow:"0 4px 16px rgba(0,0,0,0.4)",minWidth:180,maxWidth:S},children:[s.jsx("div",{style:{fontWeight:700,marginBottom:4,fontSize:12},children:"Selected Region"}),s.jsxs("div",{children:[s.jsx("span",{style:{color:a.textSecondary},children:"Region:"})," ",l.chrom,":",l.start.toLocaleString(),"-",l.end.toLocaleString()]}),s.jsxs("div",{children:[s.jsx("span",{style:{color:a.textSecondary},children:"Length:"})," ",j.toLocaleString()," bp"]}),b.map((A,R)=>s.jsxs("div",{children:[s.jsxs("span",{style:{color:a.textSecondary},children:[A.label,":"]})," ",A.value]},R)),s.jsx("div",{style:{fontSize:9,color:a.textTertiary,marginTop:4},children:"Click to dismiss"})]}),document.body)]})}function Gy(e,t,n){const r=[];if(!t)return r;if(n==="reads"&&t.reads){const o=t.reads.filter(i=>i.end>e.start&&i.start<e.end);r.push({label:"Reads in region",value:o.length.toLocaleString()});let l=0;for(const i of o)if(i.cigar){const a=i.cigar.match(/(\d+)I/g);if(a)for(const u of a)l+=parseInt(u)}if(l>0&&r.push({label:"Insertion bases",value:l.toLocaleString()}),o.length>0){const i=o.reduce((a,u)=>a+(u.mapq||0),0)/o.length;r.push({label:"Avg MAPQ",value:i.toFixed(1)})}}if((n==="coverage"||n==="reads")&&t.bins){const o=t.bins.filter(l=>l.end>e.start&&l.start<e.end);if(o.length>0){const l=o.map(c=>c.value),i=l.reduce((c,h)=>c+h,0)/l.length,a=Math.max(...l),u=Math.min(...l);r.push({label:"Avg coverage",value:i.toFixed(1)}),r.push({label:"Max coverage",value:a.toFixed(1)}),u!==a&&r.push({label:"Min coverage",value:u.toFixed(1)})}}if(n==="variants"&&t.variants){const o=t.variants.filter(l=>l.pos>=e.start&&l.pos<e.end);r.push({label:"Variants in region",value:o.length.toLocaleString()})}if((n==="annotations"||n==="genome_annotations")&&t.features){const o=t.features.filter(l=>l.end>e.start&&l.start<e.end);r.push({label:"Features in region",value:o.length.toLocaleString()})}return r}class Yy extends C.Component{constructor(t){super(t),this.state={hasError:!1,error:null}}static getDerivedStateFromError(t){return{hasError:!0,error:t}}render(){var t;return this.state.hasError?s.jsxs("div",{style:{padding:8,color:"#ef9a9a",fontSize:11},children:["Track error: ",((t=this.state.error)==null?void 0:t.message)||"Unknown error"]}):this.props.children}}function Qy({track:e,containerWidth:t,labelWidth:n=140,onLabelResizeStart:r,isDragging:o,isDropTarget:l,onDragStart:i,onDragOver:a,onDrop:u,onDragEnd:c}){const{theme:h}=Xe(),{updateTrack:d,removeTrack:g}=Jt(),T=C.useRef(null),v=C.useRef(null),[x,y]=C.useState(!1),[f,p]=C.useState(!1),[m,w]=C.useState(null),b=C.useRef(null),j=C.useRef(null),S=e.track_type==="annotations"||e.track_type==="genome_annotations";Pp(T);const E=["#f44336","#ef5350","#e57373","#ff5722","#ff8a65","#ff9800","#ffa726","#ffb74d","#ffc107","#fff176","#4caf50","#66bb6a","#81c784","#aed581","#009688","#26c6da","#80cbc4","#2196f3","#42a5f5","#64b5f6","#7e57c2","#9575cd","#9c27b0","#ab47bc","#ce93d8","#e91e63","#f06292","#795548","#8d6e63","#607d8b","#78909c"],$=t-n,A={row:{display:"flex",borderBottom:`1px solid ${h.border}`,minHeight:40},label:{width:n,minWidth:n,background:h.panelBg,borderRight:`1px solid ${h.border}`,display:"flex",flexDirection:"column",justifyContent:"center",padding:"4px 8px",overflow:"hidden",position:"relative"},trackName:{fontSize:11,color:h.trackName,fontWeight:600,whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},trackType:{fontSize:10,color:h.textTertiary,marginTop:2},trackArea:{flex:1,overflow:"hidden",position:"relative"}},R=C.useCallback(P=>{P.preventDefault(),P.stopPropagation();const W=P.clientY,O=e.height;function Y(L){const N=Math.max(30,Math.min(500,O+(L.clientY-W)));d(e.id,{height:N})}function I(){window.removeEventListener("mousemove",Y),window.removeEventListener("mouseup",I),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="ns-resize",document.body.style.userSelect="none",window.addEventListener("mousemove",Y),window.addEventListener("mouseup",I)},[e.id,e.height,d]);function U(){const P={track:e,width:$,height:e.height,onWarning:w};switch(e.track_type){case"reads":return s.jsx(Ay,{...P});case"coverage":return s.jsx(Py,{...P});case"variants":return s.jsx(Uy,{...P});case"annotations":case"genome_annotations":return s.jsx(Iy,{...P});default:return s.jsx("div",{style:{padding:8,color:h.textTertiary,fontSize:11},children:"Unknown track type"})}}return s.jsxs("div",{style:{...A.row,height:e.height,position:"relative",opacity:o?.4:1,borderTop:l?"2px solid #888":void 0},onDragOver:P=>{P.preventDefault(),P.dataTransfer.dropEffect="move",a==null||a()},onDrop:P=>{P.preventDefault(),u==null||u()},onDragEnd:c,children:[s.jsxs("div",{style:A.label,children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[s.jsx("div",{draggable:!0,onDragStart:P=>{P.dataTransfer.effectAllowed="move",P.dataTransfer.setData("text/plain",e.id),i==null||i()},style:{cursor:"grab",color:h.textMuted,fontSize:14,lineHeight:1,userSelect:"none",flexShrink:0,padding:"0 2px"},title:"Drag to reorder tracks",children:"≡"}),s.jsx("div",{ref:b,children:S?s.jsxs(s.Fragment,{children:[s.jsx("span",{style:{display:"inline-block",width:10,height:10,borderRadius:2,background:"#888",cursor:"pointer",verticalAlign:"middle",border:"1px solid rgba(255,255,255,0.2)",backgroundImage:"linear-gradient(135deg, #ef5350 25%, #66bb6a 25%, #66bb6a 50%, #42a5f5 50%, #42a5f5 75%, #ffa726 75%)"},title:"Click to customize annotation colors",onMouseDown:P=>{P.stopPropagation(),p(W=>!W)}}),f&&Wn.createPortal(s.jsx(Jy,{track:e,theme:h,anchorRef:b,onClose:()=>p(!1),onChange:(P,W)=>{const O={...e.annotationColors||{},[P]:W};d(e.id,{annotationColors:O})},onReset:()=>d(e.id,{annotationColors:null})}),document.body)]}):s.jsxs(s.Fragment,{children:[s.jsx("span",{style:{display:"inline-block",width:10,height:10,borderRadius:2,background:e.color,cursor:"pointer",verticalAlign:"middle",border:"1px solid rgba(255,255,255,0.2)"},title:"Click to pick color, double-click for full palette",onMouseDown:P=>{P.stopPropagation(),y(!0)},onDoubleClick:P=>{var W;P.stopPropagation(),y(!1),(W=j.current)==null||W.click()}}),s.jsx("input",{ref:j,type:"color",value:e.color||"#78909c",onChange:P=>d(e.id,{color:P.target.value}),style:{position:"absolute",left:-9999,top:-9999,opacity:0,width:0,height:0}}),x&&Wn.createPortal(s.jsx("div",{style:{position:"fixed",left:b.current?b.current.getBoundingClientRect().left:0,top:b.current?b.current.getBoundingClientRect().bottom+4:0,zIndex:10001,background:h.panelBg,border:`1px solid ${h.borderAccent}`,borderRadius:4,padding:6,boxShadow:"0 4px 12px rgba(0,0,0,0.5)",display:"grid",gridTemplateColumns:"repeat(5, 18px)",gap:3},onMouseLeave:()=>y(!1),children:E.map(P=>s.jsx("span",{style:{width:18,height:18,borderRadius:3,background:P,cursor:"pointer",border:P===e.color?`2px solid ${h.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onMouseUp:()=>{d(e.id,{color:P}),y(!1)}},P))}),document.body)]})}),s.jsx("div",{style:{...A.trackName,flex:1},title:e.name,children:e.name}),s.jsx("span",{title:"Remove track",onClick:P=>{P.stopPropagation(),g(e.id)},style:{color:"#e53935",fontSize:13,fontWeight:700,cursor:"pointer",lineHeight:1,flexShrink:0,padding:"0 2px",opacity:.7,transition:"opacity 0.15s"},onMouseEnter:P=>P.currentTarget.style.opacity="1",onMouseLeave:P=>P.currentTarget.style.opacity="0.7",children:"×"})]}),s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[s.jsxs("div",{style:A.trackType,children:[e.file_format," · ",e.track_type]}),m&&s.jsx(Hy,{message:m,theme:h})]}),r&&s.jsx("div",{onMouseDown:r,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:P=>P.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:P=>P.currentTarget.style.background="transparent"})]}),s.jsxs("div",{style:A.trackArea,ref:T,children:[s.jsx(Yy,{children:U()}),s.jsx(Vy,{width:$,height:e.height,trackData:jp(e.id),trackType:e.track_type})]}),s.jsx("div",{ref:v,onMouseDown:R,title:"Drag to resize track height",style:{position:"absolute",left:0,right:0,bottom:-2,height:5,cursor:"ns-resize",zIndex:10,background:"transparent"},onMouseEnter:P=>P.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:P=>P.currentTarget.style.background="transparent"})]})}const Xy=[{key:"cds",label:"CDS"},{key:"exon",label:"Exon"},{key:"gene",label:"Gene"},{key:"transcript",label:"Transcript"},{key:"utr",label:"UTR"},{key:"rrna",label:"rRNA"},{key:"trna",label:"tRNA"},{key:"repeat",label:"Repeat"},{key:"default",label:"Other"}],Ky=["#f44336","#ef5350","#e57373","#ff5722","#ff8a65","#ff9800","#ffa726","#ffb74d","#ffc107","#fff176","#4caf50","#66bb6a","#81c784","#aed581","#009688","#26c6da","#80cbc4","#2196f3","#42a5f5","#64b5f6","#7e57c2","#9575cd","#9c27b0","#ab47bc","#ce93d8","#e91e63","#f06292","#795548","#8d6e63","#607d8b","#78909c"],qy={cds:"geneCds",exon:"geneExon",gene:"geneGene",transcript:"geneTranscript",utr:"geneUtr",rrna:"geneRrna",trna:"geneTrna",repeat:"geneRepeat",default:"geneDefault"};function Jy({track:e,theme:t,anchorRef:n,onClose:r,onChange:o,onReset:l}){var x;const[i,a]=C.useState(null),u=C.useRef(null),[c,h]=C.useState(null),d=e.annotationColors||{},g=(x=n.current)==null?void 0:x.getBoundingClientRect();function T(y){return d[y]||t[qy[y]]||Sp[y]}function v(y){h(y),u.current&&(u.current.value=T(y),u.current.click())}return s.jsxs("div",{style:{position:"fixed",left:g?Math.min(g.left,window.innerWidth-220):0,top:g?g.bottom+4:0,zIndex:10001,background:t.panelBg,border:`1px solid ${t.borderAccent}`,borderRadius:6,padding:"8px 0",boxShadow:"0 6px 20px rgba(0,0,0,0.5)",width:210,maxHeight:340,overflowY:"auto"},onMouseLeave:r,children:[s.jsx("div",{style:{fontSize:10,fontWeight:700,color:t.textSecondary,textTransform:"uppercase",letterSpacing:1,padding:"0 10px 6px",borderBottom:`1px solid ${t.border}`,marginBottom:4},children:"Annotation Colors"}),Xy.map(({key:y,label:f})=>{const p=T(y);return s.jsxs("div",{children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"4px 10px",cursor:"pointer",fontSize:11,color:t.textPrimary},onMouseEnter:m=>m.currentTarget.style.background=t.selectedRow,onMouseLeave:m=>m.currentTarget.style.background="transparent",onClick:()=>a(i===y?null:y),children:[s.jsx("span",{style:{display:"inline-block",width:14,height:14,borderRadius:3,background:p,border:"1px solid rgba(255,255,255,0.15)",flexShrink:0,cursor:"pointer"},onDoubleClick:m=>{m.stopPropagation(),v(y)},title:"Click to expand, double-click for full picker"}),s.jsx("span",{style:{flex:1},children:f}),s.jsx("span",{style:{fontSize:9,color:t.textTertiary},children:i===y?"▲":"▼"})]}),i===y&&s.jsx("div",{style:{padding:"4px 10px 6px 32px",display:"grid",gridTemplateColumns:"repeat(5, 18px)",gap:3},children:Ky.map(m=>s.jsx("span",{style:{width:18,height:18,borderRadius:3,background:m,cursor:"pointer",border:m===p?`2px solid ${t.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onClick:()=>{o(y,m),a(null)}},m))})]},y)}),s.jsx("div",{style:{borderTop:`1px solid ${t.border}`,marginTop:4,paddingTop:4},children:s.jsx("div",{style:{padding:"4px 10px",fontSize:10,color:t.textTertiary,cursor:"pointer",textAlign:"center"},onMouseEnter:y=>{y.currentTarget.style.color=t.textPrimary},onMouseLeave:y=>{y.currentTarget.style.color=t.textTertiary},onClick:l,children:"Reset to defaults"})}),s.jsx("input",{ref:u,type:"color",style:{position:"absolute",left:-9999,top:-9999,opacity:0,width:0,height:0},onChange:y=>{c&&o(c,y.target.value)}})]})}function Zy({labelWidth:e}){const{genome:t,region:n}=at(),{tracks:r}=Jt(),{theme:o,themeName:l,customTheme:i}=Xe(),[a,u]=C.useState(!1),[c,h]=C.useState(!1),d=!!t;C.useEffect(()=>{if(!d)return;function x(y){y.preventDefault(),y.returnValue=""}return window.addEventListener("beforeunload",x),()=>window.removeEventListener("beforeunload",x)},[d]),C.useEffect(()=>{if(!d)return;function x(y){(y.ctrlKey||y.metaKey)&&y.key==="w"&&(y.preventDefault(),u(!0))}return window.addEventListener("keydown",x),()=>window.removeEventListener("keydown",x)},[d]);const g=C.useCallback(()=>u(!1),[]),T=C.useCallback(()=>{window.onbeforeunload=null,window.close(),window.location.href="about:blank"},[]),v=C.useCallback(()=>{h(!0);try{const x=Da(t,n,r,l,i,e);Ua(x),Rp(x)}catch{}h(!1),window.onbeforeunload=null,window.close(),window.location.href="about:blank"},[t,n,r,l,i,e]);return a?s.jsx("div",{style:{position:"fixed",inset:0,zIndex:1e4,background:"rgba(0,0,0,0.5)",display:"flex",alignItems:"center",justifyContent:"center"},onClick:g,children:s.jsxs("div",{style:{background:o.panelBg,border:`1px solid ${o.borderAccent}`,borderRadius:8,padding:"24px 28px",maxWidth:400,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.6)"},onClick:x=>x.stopPropagation(),children:[s.jsx("div",{style:{fontSize:16,fontWeight:700,color:o.textPrimary,marginBottom:8},children:"Leave BiNgo Genome Viewer?"}),s.jsxs("div",{style:{fontSize:12,color:o.textSecondary,lineHeight:1.7,marginBottom:20},children:["You have an active session with"," ",s.jsxs("strong",{style:{color:o.textPrimary},children:[r.length," track",r.length!==1?"s":""]})," loaded. Unsaved changes will be lost."]}),s.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:8},children:[s.jsx("button",{onClick:g,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:"Return to App"}),s.jsx("button",{onClick:v,disabled:c,style:{background:o.btnBg,border:`1px solid ${o.borderStrong}`,borderRadius:4,color:o.btnText,padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:c?"Saving...":"Save Session & Exit"}),s.jsx("button",{onClick:T,style:{background:"transparent",border:`1px solid ${o.border}`,borderRadius:4,color:"#e57373",padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:"Exit Without Saving"})]})]})}):null}const $c="2.4.0";let ex=0;function Nc({size:e=32}){const[t]=Hs.useState(()=>`blogo${++ex}`);return s.jsxs("svg",{width:e,height:e,viewBox:"0 0 100 100",style:{flexShrink:0},xmlns:"http://www.w3.org/2000/svg",children:[s.jsxs("defs",{children:[s.jsxs("radialGradient",{id:`${t}_bg`,cx:"35%",cy:"30%",r:"65%",children:[s.jsx("stop",{offset:"0%",stopColor:"#5eb8ff"}),s.jsx("stop",{offset:"50%",stopColor:"#1976d2"}),s.jsx("stop",{offset:"100%",stopColor:"#0d47a1"})]}),s.jsxs("radialGradient",{id:`${t}_sh`,cx:"30%",cy:"25%",r:"30%",children:[s.jsx("stop",{offset:"0%",stopColor:"#ffffff",stopOpacity:"0.7"}),s.jsx("stop",{offset:"100%",stopColor:"#ffffff",stopOpacity:"0"})]})]}),s.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_bg)`}),s.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"white"}),s.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"none",stroke:"#1565c0",strokeWidth:"2.5"}),s.jsx("text",{x:"50",y:"39",textAnchor:"middle",fontSize:"13",fontWeight:"800",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"BN"}),s.jsx("text",{x:"50",y:"64",textAnchor:"middle",fontSize:"30",fontWeight:"900",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"1"}),s.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_sh)`})]})}function tx({theme:e,labelWidth:t}){return s.jsxs("div",{style:{display:"flex",borderBottom:`1px solid ${e.border}`,height:60,opacity:.45},children:[s.jsx("div",{"data-tour":"skeleton-track-label",style:{width:t,minWidth:t,background:e.panelBg,borderRight:`1px solid ${e.border}`,padding:"6px 8px",display:"flex",flexDirection:"column",justifyContent:"center",gap:4},children:s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6},children:[s.jsx("span",{style:{fontSize:14,color:e.textTertiary,userSelect:"none",lineHeight:1},children:"≡"}),s.jsx("span",{style:{width:10,height:10,borderRadius:2,background:"#78909c",flexShrink:0}}),s.jsx("span",{style:{fontSize:11,fontWeight:600,color:e.textSecondary,flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:"Track Name"}),s.jsx("span",{style:{fontSize:13,color:e.textTertiary,lineHeight:1,padding:"0 2px"},children:"×"})]})}),s.jsx("div",{style:{flex:1,background:e.canvasBg}})]})}function nx(){const{theme:e}=Xe(),{genome:t,region:n,setGenome:r,navigateTo:o}=at(),{tracks:l,reorderTracks:i,addTrack:a,uploadTrack:u,commitTrack:c,discardTrack:h,addGenomeAnnotationTrack:d,restoreAnnotationTracks:g}=Jt(),T=C.useRef(null),[v,x]=C.useState(800),[y,f]=C.useState(!1),[p,m]=C.useState(!1),[w,b]=C.useState(!1),[j,S]=C.useState(!1),[E,$]=C.useState(!1),[A,R]=C.useState(!1),[U,P]=C.useState(140),[W,O]=C.useState(null),[Y,I]=C.useState(null),[L,N]=C.useState(!1),[D,z]=C.useState(null),[F,V]=C.useState(null),[M,k]=C.useState(null),Q=C.useRef(0);Sy(U),C.useEffect(()=>{const B=()=>fetch("/api/heartbeat").catch(()=>{});B();const q=setInterval(B,1e4);return()=>clearInterval(q)},[]);const ee=C.useRef(n==null?void 0:n.chrom);C.useEffect(()=>{n!=null&&n.chrom&&n.chrom!==ee.current&&(ee.current=n.chrom,g())},[n==null?void 0:n.chrom,g]);const ce=new Set([".gb",".gbk",".genbank",".fasta",".fa"]),he=new Set([".bam",".bw",".bigwig",".wig",".bedgraph",".bdg",".vcf",".bed",".gtf",".gff",".gff2",".gff3"]),pe=new Set([".bai"]);function ae(B){if(!B)return"";if(B.toLowerCase().endsWith(".vcf.gz"))return".vcf.gz";const q=B.lastIndexOf(".");return q>=0?B.slice(q).toLowerCase():""}const ie=C.useCallback(B=>{var q,X;B.preventDefault(),B.stopPropagation(),(X=(q=B.dataTransfer)==null?void 0:q.types)!=null&&X.includes("Files")&&(Q.current++,Q.current===1&&N(!0))},[]),ne=C.useCallback(B=>{var q,X;B.preventDefault(),B.stopPropagation(),(X=(q=B.dataTransfer)==null?void 0:q.types)!=null&&X.includes("Files")&&(Q.current--,Q.current<=0&&(Q.current=0,N(!1)))},[]),xe=C.useCallback(B=>{B.preventDefault(),B.stopPropagation()},[]);function Me(B){const q=B==null?void 0:B.compatibility;return q&&q.status!=="ok"&&q.status!=="no_genome"}const ve=C.useCallback(async B=>{var Ie,ut,Wa,Ha,Va;if(B.preventDefault(),B.stopPropagation(),Q.current=0,N(!1),!((ut=(Ie=B.dataTransfer)==null?void 0:Ie.types)!=null&&ut.includes("Files")))return;const q=Array.from(B.dataTransfer.files);if(!q.length)return;const X=[],Z=[],le=[],oe=[];for(const Re of q){const Be=ae(Re.name),yt=Re.name.toLowerCase();ce.has(Be)?X.push(Re):he.has(Be)||Be===".vcf.gz"?Z.push(Re):pe.has(Be)||yt.endsWith(".bam.bai")?le.push(Re):oe.push(Re)}const fe=Z.filter(Re=>Re.name.toLowerCase().endsWith(".bam")&&Re.size>50*1024*1024),we=le.filter(Re=>Re.size>10*1024*1024);if(fe.length||we.length){const Re=[...fe,...we].map(yt=>yt.name).join(", "),Be=[...fe,...we].reduce((yt,jo)=>yt+jo.size,0)/(1024*1024);z({error:`${Re} (${Be.toFixed(0)} MB) — large files load faster via the Path button. Click 📂 Path in the toolbar and paste the file path instead of uploading.`}),setTimeout(()=>z(null),1e4);return}if(oe.length&&!X.length&&!Z.length&&!le.length){z({error:`Unsupported file${oe.length>1?"s":""}: ${oe.map(Re=>Re.name).join(", ")}`}),setTimeout(()=>z(null),4e3);return}try{if(X.length>0&&!t){z({msg:`Loading genome: ${X[0].name}...`});const Be=(await yn.load(X[0])).data;if(Be.name&&(Be.name=Ft(Be.name)),r(Be),((Wa=Be.chromosomes)==null?void 0:Wa.length)>0){const yt=Be.chromosomes[0];o(yt.name,0,Math.min(yt.length,5e4))}Be.is_annotated&&d({id:"genome_annotations",name:`${Be.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:Be.annotated_chromosomes||null})}else X.length>0&&t&&V({files:X});if(Z.length>0){if(!t&&X.length===0){z({error:"Load a genome file first (.fasta, .gb, .genbank)"}),setTimeout(()=>z(null),4e3);return}z({msg:`Loading ${Z.length} track${Z.length>1?"s":""}...`});const Re=[],Be=[],yt=[];for(const jo of Z)try{const kn=await u(jo,void 0);Me(kn)?Be.push(kn):(c(kn),Re.push(kn))}catch(kn){yt.push(`${jo.name}: ${((Va=(Ha=kn.response)==null?void 0:Ha.data)==null?void 0:Va.detail)||kn.message}`)}if(yt.length){z({error:yt.join("; ")}),setTimeout(()=>z(null),5e3);return}Be.length>0&&k({tracks:Be})}oe.length?(z({error:`Skipped unsupported: ${oe.map(Re=>Re.name).join(", ")}`}),setTimeout(()=>z(null),4e3)):(z({msg:"Files loaded"}),setTimeout(()=>z(null),2e3))}catch(Re){z({error:Re.message||"Drop failed"}),setTimeout(()=>z(null),5e3)}},[t,r,o,a,d]),Fe=C.useCallback(async()=>{var q,X;if(!F)return;const B=F.files;V(null);try{const Z=[];for(const le of B){z({msg:`Adding chromosomes from ${le.name}...`});try{const fe=(await yn.addChromosomes(le)).data;fe.name&&(fe.name=Ft(fe.name)),r(fe),fe.is_annotated&&d({id:"genome_annotations",name:`${fe.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:fe.annotated_chromosomes||null})}catch(oe){Z.push(`${le.name}: ${((X=(q=oe.response)==null?void 0:q.data)==null?void 0:X.detail)||oe.message}`)}}Z.length?(z({error:Z.join("; ")}),setTimeout(()=>z(null),5e3)):(z({msg:`Added chromosomes from ${B.length} file${B.length>1?"s":""}`}),setTimeout(()=>z(null),3e3))}catch(Z){z({error:Z.message||"Failed to add chromosomes"}),setTimeout(()=>z(null),5e3)}},[F,r,d]),et=C.useCallback(async()=>{var q,X;if(!F)return;const B=F.files;V(null);try{z({msg:`Loading ${B.length} track${B.length>1?"s":""}...`});const Z=[];for(const le of B)try{await a(le,void 0)}catch(oe){Z.push(`${le.name}: ${((X=(q=oe.response)==null?void 0:q.data)==null?void 0:X.detail)||oe.message}`)}Z.length?(z({error:Z.join("; ")}),setTimeout(()=>z(null),5e3)):(z({msg:`Added ${B.length} track${B.length>1?"s":""}`}),setTimeout(()=>z(null),3e3))}catch(Z){z({error:Z.message||"Failed to load tracks"}),setTimeout(()=>z(null),5e3)}},[F,a]),me=C.useCallback(async()=>{if(M){for(const B of M.tracks)await h(B.id);k(null)}},[M,h]),gt=C.useCallback(()=>{if(M){for(const B of M.tracks)c(B);k(null),z({msg:`Added ${M.tracks.length} track${M.tracks.length>1?"s":""}`}),setTimeout(()=>z(null),3e3)}},[M,c]),G=C.useCallback(B=>{B.preventDefault();const q=B.clientX,X=U;function Z(oe){P(Math.max(60,Math.min(400,X+(oe.clientX-q))))}function le(){window.removeEventListener("mousemove",Z),window.removeEventListener("mouseup",le),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="ew-resize",document.body.style.userSelect="none",window.addEventListener("mousemove",Z),window.addEventListener("mouseup",le)},[U]);C.useEffect(()=>{if(!T.current)return;const B=new ResizeObserver(q=>{for(const X of q)x(X.contentRect.width)});return B.observe(T.current),()=>B.disconnect()},[]);const J=C.useCallback(B=>B.visible?!B.targetChromosomes||!(n!=null&&n.chrom)?!0:B.targetChromosomes.includes(n.chrom):!1,[n==null?void 0:n.chrom]),te={app:{display:"flex",flexDirection:"column",height:"100vh",background:e.appBg,color:e.textPrimary},header:{background:e.headerBg,borderBottom:`2px solid ${e.borderAccent}`,padding:"8px 16px",display:"flex",alignItems:"center",justifyContent:"space-between"},headerLeft:{display:"flex",alignItems:"center",gap:12},title:{fontSize:18,fontWeight:700,color:e.textPrimary,letterSpacing:1},subtitle:{fontSize:11,color:e.textTertiary},headerBtns:{display:"flex",gap:8},btn:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 14px",cursor:"pointer",fontSize:12,fontWeight:600,display:"flex",alignItems:"center",gap:6},trackArea:{flex:1,overflowY:"auto",overflowX:"hidden",display:"flex",flexDirection:"column"},emptyState:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",flex:1,color:e.textMuted,gap:12},emptyTitle:{fontSize:22,fontWeight:300},emptyHint:{fontSize:13}};return s.jsxs("div",{style:te.app,onDragEnter:ie,onDragLeave:ne,onDragOver:xe,onDrop:ve,children:[s.jsxs("div",{style:te.header,children:[s.jsxs("div",{style:te.headerLeft,children:[s.jsx(Nc,{size:34}),s.jsxs("div",{children:[s.jsx("div",{style:te.title,children:"BiNgo Genome Viewer"}),t&&s.jsxs("div",{style:te.subtitle,children:[t.name," · ",t.chromosomes.length," chr"]})]}),s.jsxs("button",{onClick:()=>$(!0),title:"About / References",style:{background:"none",border:`1px solid ${e.border}`,borderRadius:10,padding:"2px 8px",display:"flex",alignItems:"center",gap:4,cursor:"pointer",color:e.textSecondary,fontSize:11,fontWeight:600,lineHeight:1,flexShrink:0},onMouseEnter:B=>{B.currentTarget.style.color=e.textPrimary,B.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:B=>{B.currentTarget.style.color=e.textSecondary,B.currentTarget.style.borderColor=e.border},children:[s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"currentColor",style:{flexShrink:0},children:[s.jsx("path",{d:"M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"}),s.jsx("circle",{cx:"8",cy:"4.5",r:"1.2"}),s.jsx("rect",{x:"7",y:"6.5",width:"2",height:"5.5",rx:"0.8"})]}),"Info"]}),s.jsxs("button",{onClick:()=>R(!0),title:"Guided Tour",style:{background:"none",border:`1px solid ${e.border}`,borderRadius:10,padding:"2px 8px",display:"flex",alignItems:"center",gap:4,cursor:"pointer",color:e.textSecondary,fontSize:11,fontWeight:600,lineHeight:1,flexShrink:0},onMouseEnter:B=>{B.currentTarget.style.color=e.textPrimary,B.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:B=>{B.currentTarget.style.color=e.textSecondary,B.currentTarget.style.borderColor=e.border},children:[s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"currentColor",style:{flexShrink:0},children:[s.jsx("path",{d:"M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"}),s.jsx("path",{d:"M5.255 5.786a.237.237 0 0 0 .241.247h.825c.138 0 .248-.113.266-.25.09-.656.54-1.134 1.342-1.134.686 0 1.314.343 1.314 1.168 0 .635-.374.927-.965 1.371-.673.489-1.206 1.06-1.168 1.987l.003.217a.25.25 0 0 0 .25.246h.811a.25.25 0 0 0 .25-.25v-.105c0-.718.273-.927 1.01-1.486.609-.463 1.244-.977 1.244-2.056 0-1.511-1.276-2.241-2.673-2.241-1.267 0-2.655.59-2.75 2.286zM8 13.5a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"})]}),"Help"]})]}),s.jsxs("div",{style:te.headerBtns,"data-tour":"header-btns",children:[s.jsxs("button",{style:te.btn,onClick:()=>S(!0),title:"Save or restore a session",children:[s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",stroke:"currentColor",strokeWidth:"1.3",strokeLinecap:"round",strokeLinejoin:"round",style:{flexShrink:0},children:[s.jsx("path",{d:"M2 2h8v8H2z"}),s.jsx("path",{d:"M4 2v4h4V2"}),s.jsx("path",{d:"M5 3h2"})]}),"Save Session"]}),s.jsxs("button",{style:te.btn,onClick:()=>m(!0),title:"Customize color theme",children:[s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 12 12",style:{flexShrink:0},children:[s.jsx("rect",{x:"0",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#66bb6a"}),s.jsx("rect",{x:"6.5",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#42a5f5"}),s.jsx("rect",{x:"0",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ffa726"}),s.jsx("rect",{x:"6.5",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ab47bc"})]}),"Theme"]}),s.jsxs("button",{"data-tour":"btn-export",style:{...te.btn,...n&&l.length>0?{}:{opacity:.35,cursor:"default"}},onClick:()=>{n&&l.length>0&&b(!0)},title:"Export current view as SVG or PNG",children:[s.jsx("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",style:{flexShrink:0},children:s.jsx("path",{d:"M6 1v7M3 5.5L6 8.5 9 5.5M2 11h8"})}),"Export Image"]}),s.jsxs("button",{"data-tour":"btn-settings",style:{...te.btn,...l.length===0?{opacity:.35,cursor:"default"}:{}},onClick:()=>{l.length>0&&f(!0)},title:"Adjust height, scale, color, and bar width for tracks",children:["⚙"," Track Settings"]})]})]}),s.jsx(W0,{}),s.jsx(jy,{}),s.jsxs("div",{style:te.trackArea,ref:T,"data-tour":"track-area",children:[l.filter(J).length===0&&s.jsx(tx,{theme:e,labelWidth:U}),t?n?s.jsxs(s.Fragment,{children:[s.jsxs("div",{style:{display:"flex"},children:[s.jsx("div",{style:{width:U,minWidth:U,background:e.panelBg,borderRight:`1px solid ${e.border}`,position:"relative"},children:s.jsx("div",{onMouseDown:G,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:B=>B.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:B=>B.currentTarget.style.background="transparent"})}),s.jsx(Ey,{width:v-U})]}),l.filter(J).map(B=>s.jsx(Qy,{track:B,containerWidth:v,labelWidth:U,onLabelResizeStart:G,isDragging:W===B.id,isDropTarget:Y===B.id,onDragStart:()=>O(B.id),onDragOver:()=>I(B.id),onDrop:()=>{W&&W!==B.id&&i(W,B.id),O(null),I(null)},onDragEnd:()=>{O(null),I(null)}},B.id)),l.length===0&&s.jsx("div",{style:{padding:24,color:e.textMuted,fontSize:13},children:"Add tracks above — BAM, VCF, BigWig, BED, GTF, GFF, WIG..."})]}):s.jsx("div",{style:te.emptyState,children:s.jsx("div",{style:te.emptyHint,children:"Select a chromosome to begin"})}):s.jsxs("div",{style:te.emptyState,children:[s.jsx("div",{style:te.emptyTitle,children:"No genome loaded"}),s.jsx("div",{style:te.emptyHint,children:"Load a FASTA or GenBank file above to get started"})]})]}),y&&s.jsx(Q0,{onClose:()=>f(!1)}),p&&s.jsx(Z0,{onClose:()=>m(!1)}),w&&s.jsx(ay,{onClose:()=>b(!1)}),j&&s.jsx(by,{onClose:()=>S(!1),labelWidth:U,setLabelWidth:P}),A&&s.jsx(Ty,{onClose:()=>{R(!1),f(!1),m(!1)},theme:e,onAction:B=>{B==="open-settings"?(f(!0),m(!1)):B==="open-theme"?(m(!0),f(!1)):(f(!1),m(!1))}}),E&&s.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.6)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},onClick:()=>$(!1),children:s.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.border}`,borderRadius:8,padding:"28px 36px",maxWidth:520,maxHeight:"85vh",overflowY:"auto",color:e.textPrimary,lineHeight:1.7},onClick:B=>B.stopPropagation(),children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,marginBottom:16},children:[s.jsx(Nc,{size:44}),s.jsx("div",{style:{fontSize:20,fontWeight:700},children:"BiNgo Genome Viewer"})]}),s.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[s.jsx("strong",{style:{color:e.textPrimary},children:"Version:"})," ",$c]}),s.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[s.jsx("strong",{style:{color:e.textPrimary},children:"Publisher:"})," Billy M Ngo"]}),s.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:20},children:[s.jsx("strong",{style:{color:e.textPrimary},children:"Published:"})," April 2026"]}),s.jsxs("div",{style:{fontSize:12,color:e.textSecondary,background:e.canvasBg,border:`1px solid ${e.border}`,borderRadius:4,padding:"10px 14px",fontFamily:"monospace",lineHeight:1.6,marginBottom:20,userSelect:"all"},children:["Ngo, B.M. (2026). BiNgo Genome Viewer (v",$c,") [Software]."]}),s.jsxs("details",{style:{marginBottom:20},children:[s.jsx("summary",{style:{cursor:"pointer",fontSize:13,fontWeight:600,color:e.textPrimary,marginBottom:8},children:"References & Acknowledgments"}),s.jsxs("div",{style:{fontSize:11,color:e.textSecondary,lineHeight:1.8,paddingTop:8},children:[s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginBottom:4},children:"Software Dependencies"}),s.jsxs("div",{children:[s.jsx("strong",{children:"FastAPI"})," ","—"," Ram","í","rez, S. (2018). A modern web framework for building APIs with Python."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"Uvicorn"})," ","—"," Encode OSS. ASGI server implementation for Python."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"BioPython"})," ","—"," Cock, P.J.A. et al. (2009). ",s.jsx("em",{children:"Bioinformatics"}),", 25(11), 1422","–","1423."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"pyfaidx"})," ","—"," Shirley, M.D. et al. (2015). ",s.jsx("em",{children:"PeerJ PrePrints"}),", 3:e1196."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"bamnostic"})," ","—"," Sherman, M.A. & Mills, R.E. (2019). Pure Python BAM parser."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"React"})," ","—"," Meta Platforms, Inc. JavaScript UI library."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"Vite"})," ","—"," You, E. (2020). Next generation frontend tooling."]}),s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"File Format Specifications"}),s.jsxs("div",{children:[s.jsx("strong",{children:"SAM/BAM"})," ","—"," Li, H. et al. (2009). ",s.jsx("em",{children:"Bioinformatics"}),", 25(16), 2078","–","2079."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"VCF"})," ","—"," Danecek, P. et al. (2011). ",s.jsx("em",{children:"Bioinformatics"}),", 27(15), 2156","–","2158."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"BigWig/WIG"})," ","—"," Kent, W.J. et al. (2010). ",s.jsx("em",{children:"Bioinformatics"}),", 26(17), 2204","–","2207."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"BED"})," ","—"," UCSC Genome Browser, UC Santa Cruz."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"GFF3"})," ","—"," Sequence Ontology Project."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"GTF"})," ","—"," Ensembl genome database project."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"GenBank"})," ","—"," Benson, D.A. et al. (2013). ",s.jsx("em",{children:"Nucleic Acids Res."}),", 41(D1), D36","–","D42."]}),s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Inspiration"}),s.jsxs("div",{children:[s.jsx("strong",{children:"IGV"})," ","—"," Robinson, J.T. et al. (2011). ",s.jsx("em",{children:"Nature Biotechnology"}),", 29(1), 24","–","26."]}),s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Acknowledgments"}),s.jsx("div",{children:"Early version testing and feedback:"}),s.jsx("div",{children:"Amanda Antoch, Isaac Poarch, Otto Chipashvili, Jake Colautti"})]})]}),s.jsx("div",{style:{textAlign:"right"},children:s.jsx("button",{onClick:()=>$(!1),style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 18px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Close"})})]})}),F&&(()=>{const B=F.files.length>1,q=F.files.map(X=>X.name).join(", ");return s.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:s.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.borderAccent}`,borderRadius:8,padding:"20px 24px",maxWidth:440,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},onClick:X=>X.stopPropagation(),children:[s.jsxs("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:["Genome file",B?"s":""," detected"]}),s.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[s.jsx("strong",{style:{color:e.textPrimary},children:q}),B?" appear to be genome files. A genome is already loaded.":" appears to be a genome file. A genome is already loaded.",s.jsx("br",{}),"How would you like to handle ",B?"them":"it","?"]}),s.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[s.jsx("button",{onClick:()=>V(null),style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Skip"}),s.jsxs("button",{onClick:et,style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:["Add as Track",B?"s":""]}),s.jsxs("button",{onClick:Fe,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:["Add as Chromosome",B?"s":""]})]})]})})})(),M&&s.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:s.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.borderAccent}`,borderRadius:8,padding:"20px 24px",maxWidth:480,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},onClick:B=>B.stopPropagation(),children:[s.jsx("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:"Track compatibility warning"}),s.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[M.tracks.map(B=>{var q;return s.jsxs("div",{style:{marginBottom:6},children:[s.jsx("strong",{style:{color:e.textPrimary},children:B.name})," — ",((q=B.compatibility)==null?void 0:q.message)||"Possible mismatch with loaded genome"]},B.id)}),s.jsx("div",{style:{marginTop:8},children:M.tracks.length>1?"These tracks may not match the loaded genome.":"This track may not match the loaded genome."})]}),s.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[s.jsx("button",{onClick:me,style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Skip"}),s.jsx("button",{onClick:gt,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Load Anyway"})]})]})}),L&&s.jsx("div",{style:{position:"fixed",inset:0,zIndex:9998,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"none"},children:s.jsxs("div",{style:{border:`3px dashed ${e.textSecondary}`,borderRadius:16,padding:"40px 60px",textAlign:"center"},children:[s.jsx("div",{style:{fontSize:28,fontWeight:300,color:e.textPrimary,marginBottom:8},children:"Drop files here"}),s.jsx("div",{style:{fontSize:13,color:e.textSecondary},children:"Genome (.gb, .fasta) or track files (.bam, .bw, .wig, .vcf, .bed, .gff, .gtf)"})]})}),D&&s.jsx("div",{style:{position:"fixed",bottom:20,left:"50%",transform:"translateX(-50%)",zIndex:10001,padding:"8px 20px",borderRadius:6,background:D.error?"#c62828":e.panelBg,border:`1px solid ${D.error?"#e53935":e.borderAccent}`,color:D.error?"#fff":"#81c784",fontSize:12,fontWeight:600,boxShadow:"0 4px 16px rgba(0,0,0,0.5)"},children:D.error||D.msg}),t&&s.jsx(Zy,{labelWidth:U})]})}function rx(){return s.jsx(F0,{children:s.jsx(rg,{children:s.jsx($0,{children:s.jsx(nx,{})})})})}Di.createRoot(document.getElementById("root")).render(s.jsx(Hs.StrictMode,{children:s.jsx(rx,{})}));
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
body { font-family: Arial, Helvetica, sans-serif; background: #1a1a1a; color: #e0e0e0; height: 100vh; overflow: hidden; }
|
|
11
11
|
#root { height: 100vh; display: flex; flex-direction: column; }
|
|
12
12
|
</style>
|
|
13
|
-
<script type="module" crossorigin src="/assets/index-
|
|
13
|
+
<script type="module" crossorigin src="/assets/index-v6csp4Bc.js"></script>
|
|
14
14
|
</head>
|
|
15
15
|
<body>
|
|
16
16
|
<div id="root"></div>
|
|
@@ -73,7 +73,10 @@ async def add_chromosomes(file: UploadFile = File(...)):
|
|
|
73
73
|
async def load_genome_from_path(path: str = Form(...)):
|
|
74
74
|
"""Load genome from a local file path."""
|
|
75
75
|
from pathlib import Path as P
|
|
76
|
-
path = path.strip()
|
|
76
|
+
path = path.strip()
|
|
77
|
+
for q in ('"', "'", '`'):
|
|
78
|
+
path = path.strip(q)
|
|
79
|
+
path = path.strip().replace('\\ ', ' ')
|
|
77
80
|
p = P(path).expanduser()
|
|
78
81
|
if not p.exists() and not p.resolve().exists():
|
|
79
82
|
parent = p.parent
|
|
@@ -94,8 +94,12 @@ async def load_track_from_path(path: str = Form(...), name: str = Form("")):
|
|
|
94
94
|
"""Load track from a local file path (no upload needed)."""
|
|
95
95
|
from pathlib import Path as P
|
|
96
96
|
|
|
97
|
-
# Clean up the path: strip whitespace,
|
|
98
|
-
path = path.strip()
|
|
97
|
+
# Clean up the path: strip whitespace, all quote types, shell escapes
|
|
98
|
+
path = path.strip()
|
|
99
|
+
# Strip matching or trailing quotes (handles '/path', "/path", `/path`, path')
|
|
100
|
+
for q in ('"', "'", '`'):
|
|
101
|
+
path = path.strip(q)
|
|
102
|
+
path = path.strip()
|
|
99
103
|
# Remove shell-escaped spaces (e.g., /path/to/Sequencing\ Results/ → /path/to/Sequencing Results/)
|
|
100
104
|
path = path.replace('\\ ', ' ')
|
|
101
105
|
if path.lower().endswith('.bai'):
|
|
@@ -24,7 +24,7 @@ from api.genome import router as genome_router
|
|
|
24
24
|
from api.tracks import router as tracks_router
|
|
25
25
|
from api.data import router as data_router
|
|
26
26
|
|
|
27
|
-
app = FastAPI(title="BiNgo Genome Viewer API", version="2.
|
|
27
|
+
app = FastAPI(title="BiNgo Genome Viewer API", version="2.4.0")
|
|
28
28
|
|
|
29
29
|
app.add_middleware(
|
|
30
30
|
CORSMiddleware,
|
|
@@ -5,17 +5,19 @@ CRAM is not supported by bamnostic; use BAM instead.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from pathlib import Path
|
|
8
|
+
from typing import Optional
|
|
8
9
|
|
|
9
10
|
import bamnostic as bam
|
|
10
11
|
|
|
11
12
|
MAX_READS_RETURNED = 5000
|
|
13
|
+
MAX_COVERAGE_READS = 500_000 # cap reads iterated for coverage computation
|
|
12
14
|
READ_DETAIL_THRESHOLD = 50_000 # bp
|
|
13
15
|
|
|
14
16
|
# Standard index naming conventions: file.bam.bai and file.bai
|
|
15
17
|
_INDEX_SUFFIXES = (".bam.bai", ".bai")
|
|
16
18
|
|
|
17
19
|
|
|
18
|
-
def _find_index(bam_path: str) -> str
|
|
20
|
+
def _find_index(bam_path: str) -> Optional[str]:
|
|
19
21
|
"""Locate a .bai index for the given BAM file.
|
|
20
22
|
|
|
21
23
|
Checks both naming conventions (.bam.bai and .bai) in the same
|
|
@@ -96,8 +98,10 @@ class BamReader:
|
|
|
96
98
|
def get_coverage(self, chrom: str, start: int, end: int, bins: int = 1000) -> list[dict]:
|
|
97
99
|
"""Return binned coverage by piling up fetched reads.
|
|
98
100
|
|
|
99
|
-
For
|
|
100
|
-
|
|
101
|
+
For large regions, splits into sub-regions (50kb chunks) to ensure
|
|
102
|
+
bamnostic's index-based fetch covers the entire span reliably.
|
|
103
|
+
Large BAM files can fail to return all reads from a single huge
|
|
104
|
+
fetch spanning millions of bases.
|
|
101
105
|
"""
|
|
102
106
|
chrom = self._resolve_chrom(chrom)
|
|
103
107
|
region_len = end - start
|
|
@@ -106,33 +110,45 @@ class BamReader:
|
|
|
106
110
|
|
|
107
111
|
n_bins = min(bins, region_len)
|
|
108
112
|
bin_size = region_len / n_bins
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
counts = [0.0] * n_bins
|
|
114
|
+
|
|
115
|
+
# Split large regions into chunks for reliable index traversal
|
|
116
|
+
CHUNK_SIZE = 50_000
|
|
117
|
+
total_reads = 0
|
|
118
|
+
|
|
111
119
|
try:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
120
|
+
chunk_start = start
|
|
121
|
+
while chunk_start < end:
|
|
122
|
+
chunk_end = min(chunk_start + CHUNK_SIZE, end)
|
|
123
|
+
for read in self._aln.fetch(chrom, chunk_start, chunk_end):
|
|
124
|
+
if read.is_unmapped:
|
|
125
|
+
continue
|
|
126
|
+
rs = read.reference_start
|
|
127
|
+
re = read.reference_end if read.reference_end else rs + 1
|
|
128
|
+
rs = max(rs, start)
|
|
129
|
+
re = min(re, end)
|
|
130
|
+
if rs >= re:
|
|
131
|
+
continue
|
|
132
|
+
bi_start = int((rs - start) / bin_size)
|
|
133
|
+
bi_end = int((re - 1 - start) / bin_size) + 1
|
|
134
|
+
bi_start = max(0, min(bi_start, n_bins - 1))
|
|
135
|
+
bi_end = max(1, min(bi_end, n_bins))
|
|
136
|
+
for bi in range(bi_start, bi_end):
|
|
137
|
+
b_lo = start + bi * bin_size
|
|
138
|
+
b_hi = start + (bi + 1) * bin_size
|
|
139
|
+
overlap = min(re, b_hi) - max(rs, b_lo)
|
|
140
|
+
if overlap > 0:
|
|
141
|
+
counts[bi] += overlap / (b_hi - b_lo)
|
|
142
|
+
total_reads += 1
|
|
143
|
+
if total_reads >= MAX_COVERAGE_READS:
|
|
144
|
+
break
|
|
145
|
+
if total_reads >= MAX_COVERAGE_READS:
|
|
146
|
+
break
|
|
147
|
+
chunk_start = chunk_end
|
|
134
148
|
except KeyError:
|
|
135
149
|
return []
|
|
150
|
+
except Exception:
|
|
151
|
+
pass
|
|
136
152
|
|
|
137
153
|
result = []
|
|
138
154
|
for i in range(n_bins):
|
|
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "BiNgoViewer"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.4.0"
|
|
8
8
|
description = "BiNgo Genome Viewer — a lightweight browser-based genomics viewer"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "Proprietary"}
|
|
11
|
-
requires-python = ">=3.
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
12
|
authors = [
|
|
13
13
|
{name = "Billy M Ngo", email = "billy.ngo0108@gmail.com"},
|
|
14
14
|
]
|
|
@@ -18,6 +18,7 @@ classifiers = [
|
|
|
18
18
|
"Intended Audience :: Science/Research",
|
|
19
19
|
"Topic :: Scientific/Engineering :: Bio-Informatics",
|
|
20
20
|
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.9",
|
|
21
22
|
"Programming Language :: Python :: 3.10",
|
|
22
23
|
"Programming Language :: Python :: 3.11",
|
|
23
24
|
"Programming Language :: Python :: 3.12",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|