idiouf commited on
Commit
f6a88bc
·
verified ·
1 Parent(s): 7ef5dbf

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +42 -8
index.html CHANGED
@@ -424,11 +424,35 @@ document.getElementById('theme-toggle').addEventListener('click', e=>{
424
  if(cumChart) generate();
425
  if(detailChart) loadDetailChart(region);
426
  if(monthlyLoadedRegion) loadMonthlyClimate(region);
 
427
  });
428
  document.getElementById('lang-toggle').addEventListener('click', e=>{
429
  const btn = e.target.closest('.toggle-btn'); if(!btn) return;
430
  currentLang = btn.dataset.lang;
431
  applyI18n();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
432
  });
433
 
434
  /* ============================= CHART THEME COLORS ============================= */
@@ -743,11 +767,22 @@ async function fetchRecent30(region){
743
  }
744
  function dayOfYearOf(d){ const start=new Date(d.getFullYear(),0,1); let doy=Math.floor((d-start)/86400000)+1; return doy>365?365:doy; }
745
  function computeNormalForDates(byYear, dates, excludeYear){
 
 
 
 
746
  const years = Object.keys(byYear).map(Number).filter(y=>y!==excludeYear);
747
- return dates.map(d=>{
748
- const doy = dayOfYearOf(d);
749
- const vals = years.map(y=>byYear[y].precip[doy-1]).filter(v=>v!=null);
750
- return vals.length ? vals.reduce((a,b)=>a+b,0)/vals.length : 0;
 
 
 
 
 
 
 
751
  });
752
  }
753
  async function buildRain30(region){
@@ -760,10 +795,9 @@ async function buildRain30(region){
760
  const times = recent.time.slice(0,-1);
761
  const precs = recent.precipitation_sum.slice(0,-1).map(v=>v==null?0:v);
762
  const dates = times.map(s=>new Date(s+'T00:00:00'));
763
- const normalsDaily = computeNormalForDates(byYear, dates, new Date().getFullYear());
764
- let accA=0, accN=0;
765
  const actualCum = precs.map(v=>{ accA+=v; return accA; });
766
- const normalCum = normalsDaily.map(v=>{ accN+=v; return accN; });
767
  const above = actualCum.map((v,i)=>Math.max(v, normalCum[i]));
768
  const below = actualCum.map((v,i)=>Math.min(v, normalCum[i]));
769
  const months = MONTHS[currentLang];
@@ -1071,4 +1105,4 @@ applyI18n();
1071
  })();
1072
  </script>
1073
  </body>
1074
- </html>
 
424
  if(cumChart) generate();
425
  if(detailChart) loadDetailChart(region);
426
  if(monthlyLoadedRegion) loadMonthlyClimate(region);
427
+ if(window.parent !== window) window.parent.postMessage({type:'dashTheme', theme: currentTheme}, '*');
428
  });
429
  document.getElementById('lang-toggle').addEventListener('click', e=>{
430
  const btn = e.target.closest('.toggle-btn'); if(!btn) return;
431
  currentLang = btn.dataset.lang;
432
  applyI18n();
433
+ if(window.parent !== window) window.parent.postMessage({type:'dashLang', lang: currentLang}, '*');
434
+ });
435
+
436
+ /* ---- respond to lang/theme commands from a hosting portal page (if embedded in an iframe) ---- */
437
+ window.addEventListener('message', ev=>{
438
+ const msg = ev.data || {};
439
+ if(msg.type === 'setLang' && msg.lang && I18N[msg.lang] && msg.lang !== currentLang){
440
+ currentLang = msg.lang;
441
+ applyI18n();
442
+ }
443
+ if(msg.type === 'setTheme' && msg.theme){
444
+ // the portal supports 3 themes (navy/sky/light); this page only has light/dark — anything but "light" maps to dark
445
+ const mapped = msg.theme === 'light' ? 'light' : 'dark';
446
+ if(mapped !== currentTheme){
447
+ currentTheme = mapped;
448
+ document.documentElement.setAttribute('data-theme', currentTheme);
449
+ document.querySelectorAll('#theme-toggle .toggle-btn').forEach(b=>b.classList.toggle('active', b.dataset.themeVal===currentTheme));
450
+ const region = document.getElementById('sel-region').value;
451
+ if(cumChart) generate();
452
+ if(detailChart) loadDetailChart(region);
453
+ if(monthlyLoadedRegion) loadMonthlyClimate(region);
454
+ }
455
+ }
456
  });
457
 
458
  /* ============================= CHART THEME COLORS ============================= */
 
767
  }
768
  function dayOfYearOf(d){ const start=new Date(d.getFullYear(),0,1); let doy=Math.floor((d-start)/86400000)+1; return doy>365?365:doy; }
769
  function computeNormalForDates(byYear, dates, excludeYear){
770
+ // Uses the same method as the cumulative chart: for each reference year, sum precip over the
771
+ // matching calendar-day window, then take the MEDIAN of those yearly totals — not a day-by-day
772
+ // average, which uses a different statistic (mean) and can silently disagree in sign with the
773
+ // cumulative chart on skewed rainfall distributions.
774
  const years = Object.keys(byYear).map(Number).filter(y=>y!==excludeYear);
775
+ const doys = dates.map(d=>dayOfYearOf(d));
776
+ return doys.map((_, i)=>{
777
+ const yearlyTotals = years.map(y=>{
778
+ let total = 0;
779
+ for(let k=0;k<=i;k++){
780
+ const v = byYear[y].precip[doys[k]-1];
781
+ total += (v||0);
782
+ }
783
+ return total;
784
+ });
785
+ return percentile(yearlyTotals, 50) || 0;
786
  });
787
  }
788
  async function buildRain30(region){
 
795
  const times = recent.time.slice(0,-1);
796
  const precs = recent.precipitation_sum.slice(0,-1).map(v=>v==null?0:v);
797
  const dates = times.map(s=>new Date(s+'T00:00:00'));
798
+ const normalCum = computeNormalForDates(byYear, dates, new Date().getFullYear());
799
+ let accA=0;
800
  const actualCum = precs.map(v=>{ accA+=v; return accA; });
 
801
  const above = actualCum.map((v,i)=>Math.max(v, normalCum[i]));
802
  const below = actualCum.map((v,i)=>Math.min(v, normalCum[i]));
803
  const months = MONTHS[currentLang];
 
1105
  })();
1106
  </script>
1107
  </body>
1108
+ </html>