@@ -82,6 +82,29 @@ function render({ model, el }) {
8282 return arr [ lo ] + t * ( arr [ lo + 1 ] - arr [ lo ] ) ;
8383 }
8484
85+ // ── b64 array decode helpers ─────────────────────────────────────────────
86+ // Convert a base-64 string (little-endian raw bytes) to a JS TypedArray.
87+ // TypedArrays support .length and [i] indexing so they are drop-in
88+ // replacements for plain arrays in all draw / hit-test functions.
89+ function _decodeF64 ( b64 ) {
90+ const bin = atob ( b64 ) ;
91+ const buf = new Uint8Array ( bin . length ) ;
92+ for ( let i = 0 ; i < bin . length ; i ++ ) buf [ i ] = bin . charCodeAt ( i ) ;
93+ return new Float64Array ( buf . buffer ) ;
94+ }
95+ function _decodeF32 ( b64 ) {
96+ const bin = atob ( b64 ) ;
97+ const buf = new Uint8Array ( bin . length ) ;
98+ for ( let i = 0 ; i < bin . length ; i ++ ) buf [ i ] = bin . charCodeAt ( i ) ;
99+ return new Float32Array ( buf . buffer ) ;
100+ }
101+ function _decodeI32 ( b64 ) {
102+ const bin = atob ( b64 ) ;
103+ const buf = new Uint8Array ( bin . length ) ;
104+ for ( let i = 0 ; i < bin . length ; i ++ ) buf [ i ] = bin . charCodeAt ( i ) ;
105+ return new Int32Array ( buf . buffer ) ;
106+ }
107+
85108 // ── per-panel frame timing ────────────────────────────────────────────────
86109 // Called at the entry of every draw function (draw2d / draw1d / draw3d /
87110 // drawBar). Records a high-resolution timestamp in a 60-entry rolling
@@ -1097,9 +1120,38 @@ function render({ model, el }) {
10971120 ctx . fillStyle = theme . bgPlot ;
10981121 ctx . fillRect ( 0 , 0 , pw , ph ) ;
10991122
1100- const verts = st . vertices || [ ] ;
1101- const faces = st . faces || [ ] ;
1102- const zVals = st . z_values || [ ] ;
1123+ // ── decode + cache b64 geometry (only when state changes) ──────────────
1124+ const vKey = st . vertices_b64 || '' ;
1125+ const fKey = st . faces_b64 || '' ;
1126+ const zKey = st . z_values_b64 || '' ;
1127+ if ( p . _3dVertsKey !== vKey ) {
1128+ p . _3dVertsKey = vKey ;
1129+ if ( vKey ) {
1130+ const vf = _decodeF32 ( vKey ) ;
1131+ const nv = vf . length / 3 ;
1132+ const arr = new Array ( nv ) ;
1133+ for ( let i = 0 ; i < nv ; i ++ ) arr [ i ] = [ vf [ i * 3 ] , vf [ i * 3 + 1 ] , vf [ i * 3 + 2 ] ] ;
1134+ p . _3dVerts = arr ;
1135+ } else { p . _3dVerts = st . vertices || [ ] ; }
1136+ }
1137+ if ( p . _3dFacesKey !== fKey ) {
1138+ p . _3dFacesKey = fKey ;
1139+ if ( fKey ) {
1140+ const ff = _decodeI32 ( fKey ) ;
1141+ const nf = ff . length / 3 ;
1142+ const arr = new Array ( nf ) ;
1143+ for ( let i = 0 ; i < nf ; i ++ ) arr [ i ] = [ ff [ i * 3 ] , ff [ i * 3 + 1 ] , ff [ i * 3 + 2 ] ] ;
1144+ p . _3dFaces = arr ;
1145+ } else { p . _3dFaces = st . faces || [ ] ; }
1146+ }
1147+ if ( p . _3dZKey !== zKey ) {
1148+ p . _3dZKey = zKey ;
1149+ p . _3dZVals = zKey ? _decodeF32 ( zKey ) : ( st . z_values || [ ] ) ;
1150+ }
1151+ const verts = p . _3dVerts || [ ] ;
1152+ const faces = p . _3dFaces || [ ] ;
1153+ const zVals = p . _3dZVals || [ ] ;
1154+
11031155 const lut = st . colormap_data || [ ] ;
11041156 const geom = st . geom_type || 'surface' ;
11051157 const bnds = st . data_bounds || { } ;
@@ -1381,7 +1433,22 @@ function render({ model, el }) {
13811433 _recordFrame ( p ) ;
13821434 const { pw, ph, plotCtx :ctx } = p ;
13831435 const r = _plotRect1d ( pw , ph ) ;
1384- const xArr = st . x_axis || [ ] , x0 = st . view_x0 || 0 , x1 = st . view_x1 || 1 ;
1436+
1437+ // ── decode + cache b64 arrays (keyed by b64 string; free on re-render) ──
1438+ const xKey = st . x_axis_b64 || '' ;
1439+ const dKey = st . data_b64 || '' ;
1440+ if ( p . _1dXKey !== xKey ) {
1441+ p . _1dXKey = xKey ;
1442+ p . _1dXArr = xKey ? _decodeF64 ( xKey ) : ( st . x_axis || [ ] ) ;
1443+ }
1444+ if ( p . _1dDKey !== dKey ) {
1445+ p . _1dDKey = dKey ;
1446+ p . _1dDArr = dKey ? _decodeF64 ( dKey ) : ( st . data || [ ] ) ;
1447+ }
1448+ const xArr = p . _1dXArr ; // Float64Array (or plain array fallback)
1449+ const yData = p . _1dDArr ; // Float64Array (or plain array fallback)
1450+
1451+ const x0 = st . view_x0 || 0 , x1 = st . view_x1 || 1 ;
13851452 const dMin = st . data_min , dMax = st . data_max ;
13861453 const units = st . units || '' , yUnits = st . y_units || '' ;
13871454
@@ -1522,13 +1589,15 @@ function render({ model, el }) {
15221589 ctx . restore ( ) ;
15231590 }
15241591
1525- _drawLine ( st . data , xArr ,
1592+ _drawLine ( yData , xArr ,
15261593 st . line_color || '#4fc3f7' , st . line_linewidth || 1.5 ,
15271594 st . line_linestyle || 'solid' ,
15281595 st . line_alpha != null ? st . line_alpha : 1.0 ,
15291596 st . line_marker || 'none' , st . line_markersize || 4 ) ;
15301597 for ( const ex of ( st . extra_lines || [ ] ) ) {
1531- _drawLine ( ex . data || [ ] , ex . x_axis || xArr ,
1598+ const exY = ex . data_b64 ? _decodeF64 ( ex . data_b64 ) : ( ex . data || [ ] ) ;
1599+ const exX = ex . x_axis_b64 ? _decodeF64 ( ex . x_axis_b64 ) : ( ex . x_axis ? ex . x_axis : xArr ) ;
1600+ _drawLine ( exY , exX ,
15321601 ex . color || ( theme . dark ? '#fff' : '#333' ) , ex . linewidth || 1.5 ,
15331602 ex . linestyle || 'solid' ,
15341603 ex . alpha != null ? ex . alpha : 1.0 ,
@@ -1613,7 +1682,8 @@ function render({ model, el }) {
16131682 const st = p . state ; if ( ! st ) return ;
16141683 const { pw, ph, ovCtx} = p ;
16151684 const r = _plotRect1d ( pw , ph ) ;
1616- const xArr = st . x_axis || [ ] , x0 = st . view_x0 || 0 , x1 = st . view_x1 || 1 ;
1685+ const xArr = p . _1dXArr || ( st . x_axis_b64 ? _decodeF64 ( st . x_axis_b64 ) : ( st . x_axis || [ ] ) ) ;
1686+ const x0 = st . view_x0 || 0 , x1 = st . view_x1 || 1 ;
16171687 const dMin = st . data_min , dMax = st . data_max ;
16181688 ovCtx . clearRect ( 0 , 0 , pw , ph ) ;
16191689 const widgets = st . overlay_widgets || [ ] ;
@@ -1668,9 +1738,10 @@ function render({ model, el }) {
16681738 const st = p . state ; if ( ! st ) return ;
16691739 const { pw, ph, mkCtx} = p ;
16701740 const r = _plotRect1d ( pw , ph ) ;
1671- const xArr = st . x_axis || [ ] , x0 = st . view_x0 || 0 , x1 = st . view_x1 || 1 ;
1672- const dMin = st . data_min , dMax = st . data_max ;
1673- const yData = st . data || [ ] ;
1741+ // Use cached decoded arrays from draw1d; fall back to inline decode if needed.
1742+ const xArr = p . _1dXArr || ( st . x_axis_b64 ? _decodeF64 ( st . x_axis_b64 ) : ( st . x_axis || [ ] ) ) ;
1743+ const yData = p . _1dDArr || ( st . data_b64 ? _decodeF64 ( st . data_b64 ) : ( st . data || [ ] ) ) ;
1744+ const x0 = st . view_x0 || 0 , x1 = st . view_x1 || 1 ;
16741745 mkCtx . clearRect ( 0 , 0 , pw , ph ) ;
16751746 const sets = st . markers || [ ] ;
16761747 if ( ! sets . length ) return ;
@@ -1745,7 +1816,8 @@ function render({ model, el }) {
17451816 const st = p . state ; if ( ! st ) return null ;
17461817 const r = _plotRect1d ( p . pw , p . ph ) ;
17471818 if ( mx < r . x || mx > r . x + r . w || my < r . y || my > r . y + r . h ) return null ;
1748- const xArr = st . x_axis || [ ] , x0 = st . view_x0 || 0 , x1 = st . view_x1 || 1 ;
1819+ const xArr = p . _1dXArr || ( st . x_axis_b64 ? _decodeF64 ( st . x_axis_b64 ) : ( st . x_axis || [ ] ) ) ;
1820+ const x0 = st . view_x0 || 0 , x1 = st . view_x1 || 1 ;
17491821 const dMin = st . data_min , dMax = st . data_max ;
17501822 const HIT = 6 ;
17511823
@@ -1776,10 +1848,13 @@ function render({ model, el }) {
17761848 // Check extra lines first (drawn on top), then primary
17771849 for ( let i = ( st . extra_lines || [ ] ) . length - 1 ; i >= 0 ; i -- ) {
17781850 const ex = st . extra_lines [ i ] ;
1779- const hit = _nearestOnLine ( ex . data , ex . x_axis || xArr , ex . id ) ;
1851+ const exY = ex . data_b64 ? _decodeF64 ( ex . data_b64 ) : ( ex . data || [ ] ) ;
1852+ const exX = ex . x_axis_b64 ? _decodeF64 ( ex . x_axis_b64 ) : ( ex . x_axis ? ex . x_axis : xArr ) ;
1853+ const hit = _nearestOnLine ( exY , exX , ex . id ) ;
17801854 if ( hit ) return hit ;
17811855 }
1782- return _nearestOnLine ( st . data , xArr , null ) ;
1856+ const primY = p . _1dDArr || ( st . data_b64 ? _decodeF64 ( st . data_b64 ) : ( st . data || [ ] ) ) ;
1857+ return _nearestOnLine ( primY , xArr , null ) ;
17831858 }
17841859
17851860 // ── marker hit-test helpers ────────────────────────────────────────────────
@@ -1858,7 +1933,9 @@ function render({ model, el }) {
18581933 function _markerHitTest1d ( mx , my , p ) {
18591934 const st = p . state ; if ( ! st ) return null ;
18601935 const r = _plotRect1d ( p . pw , p . ph ) ;
1861- const xArr = st . x_axis || [ ] , x0 = st . view_x0 || 0 , x1 = st . view_x1 || 1 ;
1936+ // Use cached decoded array from draw1d; fall back to inline decode if needed.
1937+ const xArr = p . _1dXArr || ( st . x_axis_b64 ? _decodeF64 ( st . x_axis_b64 ) : ( st . x_axis || [ ] ) ) ;
1938+ const x0 = st . view_x0 || 0 , x1 = st . view_x1 || 1 ;
18621939 const dMin = st . data_min , dMax = st . data_max ;
18631940 const sets = st . markers || [ ] ;
18641941 for ( let si = sets . length - 1 ; si >= 0 ; si -- ) {
@@ -2216,7 +2293,7 @@ function render({ model, el }) {
22162293 const regKeys = st . registered_keys || [ ] ;
22172294 if ( regKeys . includes ( e . key ) || regKeys . includes ( '*' ) ) {
22182295 const r = _plotRect1d ( p . pw , p . ph ) ;
2219- const xArr = st . x_axis || [ ] ;
2296+ const xArr = p . _1dXArr || ( st . x_axis_b64 ? _decodeF64 ( st . x_axis_b64 ) : ( st . x_axis || [ ] ) ) ;
22202297 const frac = _canvasXToFrac1d ( p . mouseX , st . view_x0 , st . view_x1 , r ) ;
22212298 const physX = xArr . length >= 2 ?_fracToX1d ( xArr , frac ) :frac ;
22222299 _emitEvent ( p . id , 'on_key' , null , {
@@ -2241,7 +2318,7 @@ function render({ model, el }) {
22412318 if ( p . _hoverSi !== - 1 ) { p . _hoverSi = - 1 ; p . _hoverI = - 1 ; drawMarkers1d ( p , null ) ; }
22422319 return ;
22432320 }
2244- const xArr = st . x_axis || [ ] ;
2321+ const xArr = p . _1dXArr || ( st . x_axis_b64 ? _decodeF64 ( st . x_axis_b64 ) : ( st . x_axis || [ ] ) ) ;
22452322 const frac = _canvasXToFrac1d ( mx , st . view_x0 , st . view_x1 , r ) ;
22462323 const phys = xArr . length >= 2 ?_fracToX1d ( xArr , frac ) :frac ;
22472324 p . statusBar . textContent = `x:${ fmtVal ( phys ) } ` ; p . statusBar . style . display = 'block' ;
@@ -2447,7 +2524,8 @@ function render({ model, el }) {
24472524 function _ovHitTest1d ( mx , my , p ) {
24482525 const st = p . state ; if ( ! st ) return null ;
24492526 const r = _plotRect1d ( p . pw , p . ph ) ;
2450- const xArr = st . x_axis || [ ] , x0 = st . view_x0 || 0 , x1 = st . view_x1 || 1 ;
2527+ const xArr = p . _1dXArr || ( st . x_axis_b64 ? _decodeF64 ( st . x_axis_b64 ) : ( st . x_axis || [ ] ) ) ;
2528+ const x0 = st . view_x0 || 0 , x1 = st . view_x1 || 1 ;
24512529 const widgets = st . overlay_widgets || [ ] ;
24522530 const HR = 7 ;
24532531 for ( let i = widgets . length - 1 ; i >= 0 ; i -- ) {
@@ -2480,7 +2558,8 @@ function render({ model, el }) {
24802558 const st = p . state ; if ( ! st ) return ;
24812559 const r = _plotRect1d ( p . pw , p . ph ) ;
24822560 const { mx, my :py } = _clientPos ( e , p . overlayCanvas , p . pw , p . ph ) ;
2483- const xArr = st . x_axis || [ ] , x0 = st . view_x0 || 0 , x1 = st . view_x1 || 1 ;
2561+ const xArr = p . _1dXArr || ( st . x_axis_b64 ? _decodeF64 ( st . x_axis_b64 ) : ( st . x_axis || [ ] ) ) ;
2562+ const x0 = st . view_x0 || 0 , x1 = st . view_x1 || 1 ;
24842563 const xUnit = xArr . length >= 2 ?_fracToX1d ( xArr , _canvasXToFrac1d ( mx , x0 , x1 , r ) ) :_canvasXToFrac1d ( mx , x0 , x1 , r ) ;
24852564 const widgets = st . overlay_widgets ;
24862565 const d = p . ovDrag , s = d . snapW , w = widgets [ d . idx ] ;
0 commit comments