1+ <!DOCTYPE html>
2+ < html lang ="en ">
3+ < head >
4+ < meta charset ="utf-8 ">
5+ < title > Orographer Plot</ title >
6+ < style >
7+ html , body {
8+ box-sizing : border-box;
9+ display : flow-root;
10+ height : 100% ;
11+ margin : 0 ;
12+ padding : 0 ;
13+ }
14+ </ style >
15+ < script src ="https://cdn.bokeh.org/bokeh/release/bokeh-3.9.0.min.js "> </ script >
16+ < script src ="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.9.0.min.js "> </ script >
17+ < script >
18+ Bokeh . set_log_level ( "info" ) ;
19+ </ script >
20+ </ head >
21+ < body >
22+ < div id ="dbc693e8-6d13-4a46-8f1f-88fdc58db67e " data-root-id ="p1249 " style ="display: contents; "> </ div >
23+
24+
25+ < script >
26+ ( function ( ) {
27+ const fn = function ( ) {
28+ Bokeh . safely ( function ( ) {
29+ ( function ( root ) {
30+ function embed_document ( root ) {
31+ // Load JSON data from external .json.gz file and decompress in browser
32+ const jsonFile = "chr2_130592001_130605000_bokeh.json.gz?v=1774040304" ;
33+ const headerBreakpoint = 825 ;
34+ const centerOffsetWide = 20 ;
35+ const centerOffsetNarrow = 0 ;
36+ const centerOffsetFullWidthAt = 1500 ;
37+
38+ function getScaledCenterOffset ( windowWidth ) {
39+ if ( windowWidth <= headerBreakpoint ) return centerOffsetNarrow ;
40+ if ( windowWidth >= centerOffsetFullWidthAt ) return centerOffsetWide ;
41+ const span = centerOffsetFullWidthAt - headerBreakpoint ;
42+ const ratio = ( windowWidth - headerBreakpoint ) / span ;
43+ return Math . round ( centerOffsetNarrow + ratio * ( centerOffsetWide - centerOffsetNarrow ) ) ;
44+ }
45+
46+ function updateResponsiveHeaderByModel ( ) {
47+ if ( ! root || ! root . Bokeh || ! root . Bokeh . documents ) return false ;
48+ const docs = root . Bokeh . documents ;
49+ const useWide = window . innerWidth > headerBreakpoint ;
50+ for ( let i = 0 ; i < docs . length ; i ++ ) {
51+ const doc = docs [ i ] ;
52+ const wide = doc . get_model_by_name ( "orographer_original_region_wide" ) ;
53+ const narrow = doc . get_model_by_name ( "orographer_original_region_narrow_row" ) ;
54+ const centerOffsetSpacer = doc . get_model_by_name ( "orographer_center_offset_spacer" ) ;
55+ if ( wide && narrow && centerOffsetSpacer ) {
56+ wide . visible = useWide ;
57+ narrow . visible = ! useWide ;
58+ centerOffsetSpacer . width = getScaledCenterOffset ( window . innerWidth ) ;
59+ wide . change . emit ( ) ;
60+ narrow . change . emit ( ) ;
61+ centerOffsetSpacer . change . emit ( ) ;
62+ return true ;
63+ }
64+ }
65+ return false ;
66+ }
67+
68+ ( async function ( ) {
69+ try {
70+ const response = await fetch ( jsonFile ) ;
71+ if ( ! response . ok ) {
72+ throw new Error (
73+ "Failed to load JSON file: " + response . status + " " + response . statusText
74+ ) ;
75+ }
76+ const stream = response . body . pipeThrough ( new DecompressionStream ( "gzip" ) ) ;
77+ const streamResponse = await new Response ( stream ) ;
78+ const data = await streamResponse . json ( ) ;
79+ const docs_json = data . docs_json ;
80+ const render_items = data . render_items ;
81+ root . Bokeh . embed . embed_items ( docs_json , render_items ) ;
82+ let tries = 0 ;
83+ const maxTries = 80 ;
84+ function tryUpdateHeader ( ) {
85+ tries += 1 ;
86+ if ( updateResponsiveHeaderByModel ( ) ) return ;
87+ if ( tries < maxTries ) setTimeout ( tryUpdateHeader , 100 ) ;
88+ }
89+ setTimeout ( tryUpdateHeader , 200 ) ;
90+ window . addEventListener ( "resize" , function ( ) {
91+ updateResponsiveHeaderByModel ( ) ;
92+ } ) ;
93+ } catch ( error ) {
94+ const errorDiv = document . createElement ( "div" ) ;
95+ errorDiv . style . cssText =
96+ "position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); " +
97+ "background: #f44336; color: white; padding: 20px; border-radius: 5px; " +
98+ "z-index: 10000; font-family: Arial, sans-serif; max-width: 500px;" ;
99+ errorDiv . innerHTML =
100+ "<h3 style=\"margin-top: 0;\">Error Loading Plot Data</h3>" +
101+ "<p style=\"margin: 10px 0;\">" + error . message + "</p>" +
102+ "<p style=\"font-size: 12px; margin-top: 10px;\">" +
103+ "Make sure you are serving files from a web server (not opening file:// directly).</p>" +
104+ "<p style=\"font-size: 12px;\">Try: <code>orographer deploy --output-dir ./output</code> " +
105+ "or any static file server.</p>" +
106+ "<p style=\"font-size: 12px; margin-top: 10px;\">" +
107+ "Then open: <code>http://localhost:8000/chr2_130592001_130605000_bokeh.html</code></p>" ;
108+ document . body . appendChild ( errorDiv ) ;
109+ console . error ( "Error loading JSON:" , error ) ;
110+ }
111+ } ) ( ) ;
112+
113+
114+ }
115+ if ( root . Bokeh !== undefined ) {
116+ embed_document ( root ) ;
117+ } else {
118+ let attempts = 0 ;
119+ const timer = setInterval ( function ( root ) {
120+ if ( root . Bokeh !== undefined ) {
121+ clearInterval ( timer ) ;
122+ embed_document ( root ) ;
123+ } else {
124+ attempts ++ ;
125+ if ( attempts > 100 ) {
126+ clearInterval ( timer ) ;
127+ console . log ( "Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing" ) ;
128+ }
129+ }
130+ } , 10 , root )
131+ }
132+ } ) ( window ) ;
133+ } ) ;
134+ } ;
135+ if ( document . readyState != "loading" ) fn ( ) ;
136+ else document . addEventListener ( "DOMContentLoaded" , fn ) ;
137+ } ) ( ) ;
138+ </ script >
139+
140+ <!-- Modal for details (alignments and variants) -->
141+ < div id ="alignmentModal " style ="display:none;position:fixed;z-index:1000;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:rgba(0,0,0,0.4);align-items:center;justify-content:center; ">
142+ < div id ="alignmentModalWrapper " style ="display:flex;align-items:center;justify-content:center;max-height:90vh; ">
143+ < div id ="alignmentModalDialog " style ="background:#fefefe;padding:20px;border:1px solid #888;width:400px; ">
144+ < span id ="closeModal " style ="color:#aaa;float:right;font-size:28px;font-weight:bold;cursor:pointer; "> ×</ span >
145+ < h2 style ="margin-top: 0; color: #333; "> Details</ h2 >
146+ < div id ="modalContent " style ="font-size: 14px; line-height: 1.8; "> </ div >
147+ </ div >
148+ </ div >
149+ </ div >
150+
151+ < script >
152+ // Modal close handlers and fitAlignmentModalToPlot
153+ const modal = document . getElementById ( "alignmentModal" ) ;
154+ const closeBtn = document . getElementById ( "closeModal" ) ;
155+ window . fitAlignmentModalToPlot = function ( ) {
156+ const wrapper = document . getElementById ( "alignmentModalWrapper" ) ;
157+ const dialog = document . getElementById ( "alignmentModalDialog" ) ;
158+ const root = document . querySelector ( ".bk-root" ) ;
159+ if ( ! wrapper || ! dialog ) return ;
160+ const maxH = root
161+ ? Math . max ( 120 , 0.9 * root . getBoundingClientRect ( ) . height )
162+ : 0.9 * window . innerHeight ;
163+ dialog . style . maxHeight = "" ;
164+ dialog . style . transform = "" ;
165+ const naturalH = dialog . scrollHeight ;
166+ const naturalW = dialog . offsetWidth || 400 ;
167+ if ( naturalH > maxH ) {
168+ if ( maxH > 0 ) {
169+ const scale = maxH / naturalH ;
170+ dialog . style . transform = "scale(" + scale + ")" ;
171+ dialog . style . transformOrigin = "top left" ;
172+ wrapper . style . width = naturalW * scale + "px" ;
173+ wrapper . style . height = naturalH * scale + "px" ;
174+ wrapper . style . overflow = "hidden" ;
175+ }
176+ } else {
177+ dialog . style . transformOrigin = "" ;
178+ wrapper . style . width = "" ;
179+ wrapper . style . height = "" ;
180+ wrapper . style . overflow = "" ;
181+ }
182+ } ;
183+ if ( closeBtn ) closeBtn . onclick = function ( ) { modal . style . display = "none" ; } ;
184+ window . onclick = function ( e ) {
185+ if ( e . target === modal ) modal . style . display = "none" ;
186+ } ;
187+ document . addEventListener ( "keydown" , function ( e ) {
188+ if ( e . key === "Escape" ) modal . style . display = "none" ;
189+ } ) ;
190+
191+ </ script >
192+ </ body >
193+ </ html >
0 commit comments