2222< style >
2323 /* Edward Tufte–inspired theme: high data-ink ratio, restrained palette */
2424 * { margin : 0 ; padding : 0 ; box-sizing : border-box; }
25+
26+ /* Use a JS-set custom property for the true viewport height on mobile,
27+ falling back to 100dvh (dynamic viewport height) then 100vh. */
28+ : root { --vh : 1vh ; }
29+
2530 body {
2631 font-family : 'ET Book' , Palatino, 'Palatino Linotype' , 'Book Antiqua' , Georgia, serif;
2732 background : # fffff8 ;
2833 color : # 111 ;
2934 display : flex;
3035 flex-direction : column;
31- height : 100vh ;
36+ height : 100dvh ;
37+ height : calc (var (--vh , 1vh ) * 100 );
3238 overflow : hidden;
3339 }
3440 header {
5359 padding : 6px 28px ;
5460 border-bottom : 1px solid # eee ;
5561 flex-shrink : 0 ;
62+ line-height : 1.6 ;
5663 }
5764 .help kbd {
5865 background : # f0f0f0 ;
6269 font-size : 0.72rem ;
6370 font-family : monospace;
6471 }
72+ /* Show/hide desktop vs. touch hint rows */
73+ .help-desktop { display : block; }
74+ .help-touch { display : none; }
6575 # chart {
6676 flex : 1 ;
6777 min-height : 0 ;
8090 border-top : 1px solid # eee ;
8191 text-align : right;
8292 flex-shrink : 0 ;
93+ white-space : nowrap;
94+ overflow : hidden;
95+ text-overflow : ellipsis;
96+ }
97+
98+ /* ── Mobile styles ── */
99+ @media (max-width : 600px ) {
100+ header {
101+ padding : 10px 14px 7px ;
102+ }
103+ header h1 {
104+ font-size : 1rem ;
105+ }
106+ header p {
107+ font-size : 0.75rem ;
108+ }
109+ .help {
110+ padding : 5px 14px ;
111+ font-size : 0.7rem ;
112+ }
113+ .help kbd {
114+ font-size : 0.68rem ;
115+ }
116+ .stats {
117+ padding : 3px 14px ;
118+ font-size : 0.65rem ;
119+ }
120+ # fallback {
121+ padding : 20px ;
122+ font-size : 0.9rem ;
123+ }
124+ }
125+
126+ /* Show touch hints on true touch-primary devices */
127+ @media (hover : none) and (pointer : coarse) {
128+ .help-desktop { display : none; }
129+ .help-touch { display : block; }
83130 }
84131</ style >
85132</ head >
@@ -90,10 +137,18 @@ <h1>Quantum Metric sessions_archive Schema</h1>
90137 < p > Quantum Metric — BigQuery Schema Tree</ p >
91138</ header >
92139< div class ="help ">
93- < kbd > Click</ kbd > node to expand / collapse ·
94- < kbd > Scroll</ kbd > to zoom ·
95- < kbd > Drag</ kbd > to pan ·
96- < kbd > Right-click</ kbd > to reset view
140+ < span class ="help-desktop ">
141+ < kbd > Click</ kbd > node to expand / collapse ·
142+ < kbd > Scroll</ kbd > to zoom ·
143+ < kbd > Drag</ kbd > to pan ·
144+ < kbd > Right-click</ kbd > to reset view
145+ </ span >
146+ < span class ="help-touch ">
147+ < kbd > Tap</ kbd > node to expand / collapse ·
148+ < kbd > Pinch</ kbd > to zoom ·
149+ < kbd > Drag</ kbd > to pan ·
150+ < kbd > Double-tap</ kbd > to reset view
151+ </ span >
97152</ div >
98153< div id ="chart "> </ div >
99154< div id ="fallback "> Schema data is missing or invalid. See source comments for regeneration steps.</ div >
@@ -170,77 +225,109 @@ <h1>Quantum Metric sessions_archive Schema</h1>
170225 var chartDom = document . getElementById ( 'chart' ) ;
171226 var chart = echarts . init ( chartDom ) ;
172227
173- var option = {
174- tooltip : {
175- trigger : 'item' ,
176- triggerOn : 'mousemove' ,
177- formatter : function ( params ) {
178- var d = params . data ;
179- var parts = d . name . match ( / ^ ( .+ ?) \s * \( ( .+ ) \) $ / ) ;
180- if ( parts ) {
181- var childCount = d . children ? d . children . length : 0 ;
182- var tip = '<b>' + parts [ 1 ] + '</b><br/>Type: ' + parts [ 2 ] ;
183- if ( childCount > 0 ) tip += '<br/>Children: ' + childCount ;
184- return tip ;
185- }
186- return '<b>' + d . name + '</b>' ;
187- } ,
188- backgroundColor : '#fffff8' ,
189- borderColor : '#ccc' ,
190- textStyle : { color : '#333' , fontFamily : 'monospace' , fontSize : 12 }
191- } ,
192- series : [ {
193- type : 'tree' ,
194- data : [ SCHEMA_DATA ] ,
195- orient : 'LR' ,
196- top : 20 ,
197- bottom : 20 ,
198- left : 160 ,
199- right : 260 ,
200- symbolSize : 7 ,
201- edgeShape : 'polyline' ,
202- edgeForkPosition : '63%' ,
203- initialTreeDepth : - 1 , // we control collapse state manually
204- lineStyle : {
205- color : '#ccc' ,
206- width : 1
207- } ,
208- label : {
209- position : 'left' ,
210- verticalAlign : 'middle' ,
211- align : 'right' ,
212- fontSize : 11 ,
213- fontFamily : "'SF Mono', 'Menlo', 'Monaco', 'Consolas', monospace" ,
214- color : '#333'
228+ function isMobile ( ) { return window . innerWidth <= 600 ; }
229+
230+ function buildOption ( ) {
231+ var mobile = isMobile ( ) ;
232+ return {
233+ tooltip : {
234+ trigger : 'item' ,
235+ triggerOn : 'mousemove' ,
236+ formatter : function ( params ) {
237+ var d = params . data ;
238+ var parts = d . name . match ( / ^ ( .+ ?) \s * \( ( .+ ) \) $ / ) ;
239+ if ( parts ) {
240+ var childCount = d . children ? d . children . length : 0 ;
241+ var tip = '<b>' + parts [ 1 ] + '</b><br/>Type: ' + parts [ 2 ] ;
242+ if ( childCount > 0 ) tip += '<br/>Children: ' + childCount ;
243+ return tip ;
244+ }
245+ return '<b>' + d . name + '</b>' ;
246+ } ,
247+ backgroundColor : '#fffff8' ,
248+ borderColor : '#ccc' ,
249+ textStyle : { color : '#333' , fontFamily : 'monospace' , fontSize : 12 }
215250 } ,
216- leaves : {
251+ series : [ {
252+ type : 'tree' ,
253+ data : [ SCHEMA_DATA ] ,
254+ orient : 'LR' ,
255+ top : 20 ,
256+ bottom : 20 ,
257+ left : mobile ? 80 : 160 ,
258+ right : mobile ? 120 : 260 ,
259+ symbolSize : mobile ? 5 : 7 ,
260+ edgeShape : 'polyline' ,
261+ edgeForkPosition : '63%' ,
262+ initialTreeDepth : - 1 , // we control collapse state manually
263+ lineStyle : {
264+ color : '#ccc' ,
265+ width : 1
266+ } ,
217267 label : {
218- position : 'right ' ,
268+ position : 'left ' ,
219269 verticalAlign : 'middle' ,
220- align : 'left'
221- }
222- } ,
223- expandAndCollapse : true ,
224- animationDuration : 400 ,
225- animationDurationUpdate : 400 ,
226- roam : true ,
227- scaleLimit : { min : 0.3 , max : 3 }
228- } ]
229- } ;
270+ align : 'right' ,
271+ fontSize : mobile ? 9 : 11 ,
272+ fontFamily : "'SF Mono', 'Menlo', 'Monaco', 'Consolas', monospace" ,
273+ color : '#333'
274+ } ,
275+ leaves : {
276+ label : {
277+ position : 'right' ,
278+ verticalAlign : 'middle' ,
279+ align : 'left'
280+ }
281+ } ,
282+ expandAndCollapse : true ,
283+ animationDuration : 400 ,
284+ animationDurationUpdate : 400 ,
285+ roam : true ,
286+ scaleLimit : { min : mobile ? 0.2 : 0.3 , max : 3 }
287+ } ]
288+ } ;
289+ }
230290
231- chart . setOption ( option ) ;
291+ chart . setOption ( buildOption ( ) ) ;
232292
233293 // ── Right-click to reset view ──
234294 chartDom . addEventListener ( 'contextmenu' , function ( e ) {
235295 e . preventDefault ( ) ;
236296 chart . dispatchAction ( { type : 'restore' } ) ;
237297 } ) ;
238298
239- // ── Debounced resize ──
299+ // ── Double-tap to reset view (mobile) ──
300+ var DOUBLE_TAP_THRESHOLD_MS = 350 ;
301+ var lastTap = 0 ;
302+ chartDom . addEventListener ( 'touchend' , function ( e ) {
303+ var now = Date . now ( ) ;
304+ if ( now - lastTap < DOUBLE_TAP_THRESHOLD_MS ) {
305+ e . preventDefault ( ) ;
306+ chart . dispatchAction ( { type : 'restore' } ) ;
307+ }
308+ lastTap = now ;
309+ } , { passive : false } ) ;
310+
311+ // ── True viewport height for mobile browsers (hides/shows browser UI) ──
312+ function setVh ( ) {
313+ document . documentElement . style . setProperty ( '--vh' , window . innerHeight * 0.01 + 'px' ) ;
314+ }
315+ setVh ( ) ;
316+
317+ // ── Debounced resize: update vh, re-apply options (breakpoint may change), resize chart ──
240318 var resizeTimer ;
319+ var lastMobile = isMobile ( ) ;
241320 window . addEventListener ( 'resize' , function ( ) {
242321 clearTimeout ( resizeTimer ) ;
243- resizeTimer = setTimeout ( function ( ) { chart . resize ( ) ; } , 150 ) ;
322+ resizeTimer = setTimeout ( function ( ) {
323+ setVh ( ) ;
324+ var nowMobile = isMobile ( ) ;
325+ if ( nowMobile !== lastMobile ) {
326+ lastMobile = nowMobile ;
327+ chart . setOption ( buildOption ( ) ) ;
328+ }
329+ chart . resize ( ) ;
330+ } , 150 ) ;
244331 } ) ;
245332} ) ( ) ;
246333</ script >
0 commit comments