File size: 5,701 Bytes
31ae020
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140

<style>
  .wave-wrap { font-family: var(--font-sans); padding: 0.5rem 0 1rem; }
  .wave-controls { display: flex; gap: 20px; flex-wrap: wrap; align-items: center; margin-bottom: 12px; }
  .wave-label { font-size: 12px; color: var(--color-text-secondary); min-width: 120px; }
  .wave-val { font-size: 12px; font-weight: 500; color: var(--color-text-primary); min-width: 28px; }
  .panel-row { display: flex; gap: 12px; }
  .panel { flex: 1; background: var(--color-background-secondary); border-radius: 8px; padding: 10px 12px; }
  .panel-head { font-size: 12px; font-weight: 500; color: var(--color-text-primary); margin-bottom: 6px; }
  .panel-note { font-size: 11px; color: var(--color-text-secondary); margin-top: 4px; }
</style>
<div class="wave-wrap">
  <div class="wave-controls">
    <div style="display:flex;align-items:center;gap:8px">
      <span class="wave-label" style="color:#1D9E75;font-weight:500">pos (word index)</span>
      <input type="range" min="0" max="49" value="10" id="sl-pos" style="width:120px" oninput="update()">
      <span class="wave-val" id="lbl-pos">10</span>
    </div>
    <div style="display:flex;align-items:center;gap:8px">
      <span class="wave-label" style="color:#BA7517;font-weight:500">highlight dim i</span>
      <input type="range" min="0" max="255" value="0" id="sl-dim" style="width:120px" oninput="update()">
      <span class="wave-val" id="lbl-dim">0</span>
    </div>
  </div>

  <div class="panel-row" style="margin-bottom:10px">
    <div class="panel">
      <div class="panel-head">Looking <em>across</em> one row → (horizontal slice at selected pos)</div>
      <canvas id="hcv" style="width:100%;display:block"></canvas>
      <div class="panel-note" id="hnote"></div>
    </div>
    <div class="panel">
      <div class="panel-head">Looking <em>down</em> one column ↓ (vertical slice at selected dim i)</div>
      <canvas id="vcv" style="width:100%;display:block"></canvas>
      <div class="panel-note" id="vnote"></div>
    </div>
  </div>
</div>

<script>
const ROWS=50, COLS=256, D=512;
function pe(pos,i){
  const d=Math.pow(10000,(2*Math.floor(i/2))/D);
  return (i%2===0)?Math.sin(pos/d):Math.cos(pos/d);
}

const isDark = matchMedia('(prefers-color-scheme: dark)').matches;
const teal = '#1D9E75', amber = '#BA7517';
const textCol = isDark ? 'rgba(200,198,190,0.9)' : 'rgba(60,60,58,0.9)';
const gridCol = isDark ? 'rgba(255,255,255,0.07)' : 'rgba(0,0,0,0.07)';

function drawLine(cvs, data, color, hlIdx, xLabel, showFreq) {
  const dpr = window.devicePixelRatio||1;
  const w = cvs.offsetWidth||300;
  const h = 110;
  cvs.width = w*dpr; cvs.height = h*dpr;
  cvs.style.height = h+'px';
  const ctx = cvs.getContext('2d');
  ctx.scale(dpr, dpr);

  const pad = {l:6, r:6, t:10, b:20};
  const pw = w - pad.l - pad.r;
  const ph = h - pad.t - pad.b;
  const n = data.length;

  ctx.clearRect(0,0,w,h);

  // grid
  ctx.strokeStyle = gridCol; ctx.lineWidth = 0.5;
  [0.25, 0.5, 0.75].forEach(f => {
    const y = pad.t + f*ph;
    ctx.beginPath(); ctx.moveTo(pad.l, y); ctx.lineTo(pad.l+pw, y); ctx.stroke();
  });
  // zero line
  ctx.strokeStyle = isDark ? 'rgba(255,255,255,0.18)' : 'rgba(0,0,0,0.18)';
  ctx.lineWidth = 1;
  ctx.beginPath(); ctx.moveTo(pad.l, pad.t+ph/2); ctx.lineTo(pad.l+pw, pad.t+ph/2); ctx.stroke();

  // data path
  ctx.strokeStyle = color; ctx.lineWidth = 1.5; ctx.lineJoin = 'round';
  ctx.beginPath();
  data.forEach((v, i) => {
    const x = pad.l + (i/(n-1))*pw;
    const y = pad.t + (1-(v+1)/2)*ph;
    i===0 ? ctx.moveTo(x,y) : ctx.lineTo(x,y);
  });
  ctx.stroke();

  // highlight dot
  if (hlIdx >= 0 && hlIdx < n) {
    const x = pad.l + (hlIdx/(n-1))*pw;
    const y = pad.t + (1-(data[hlIdx]+1)/2)*ph;
    ctx.fillStyle = amber;
    ctx.beginPath(); ctx.arc(x,y,4,0,Math.PI*2); ctx.fill();
    // value label
    ctx.fillStyle = amber;
    ctx.font = `500 11px var(--font-sans)`;
    ctx.textAlign = 'center';
    ctx.fillText(data[hlIdx].toFixed(3), Math.min(Math.max(x,30),pw-20), y > pad.t+12 ? y-7 : y+14);
  }

  // x-axis ticks
  ctx.fillStyle = textCol; ctx.font = `10px var(--font-sans)`;
  ctx.textAlign = 'center';
  [0, Math.floor(n/2), n-1].forEach(i => {
    const x = pad.l + (i/(n-1))*pw;
    ctx.fillText(xLabel(i), x, h-4);
  });

  // y labels
  ctx.textAlign = 'right';
  ctx.fillText('+1', pad.l-1, pad.t+5);
  ctx.fillText('−1', pad.l-1, pad.t+ph+4);
}

function update() {
  const pos = +document.getElementById('sl-pos').value;
  const dim = +document.getElementById('sl-dim').value;
  document.getElementById('lbl-pos').textContent = pos;
  document.getElementById('lbl-dim').textContent = dim;

  // horizontal: values across dims for fixed pos
  const hdata = Array.from({length:COLS}, (_,i) => pe(pos,i));
  drawLine(document.getElementById('hcv'), hdata, teal, dim, i => i===0?'i=0':i===127?'128':i===255?'255':'', true);

  // vertical: values across positions for fixed dim
  const vdata = Array.from({length:ROWS}, (_,r) => pe(r,dim));
  drawLine(document.getElementById('vcv'), vdata, amber, pos, r => r===0?'pos=0':r===24?'24':r===49?'49':'', false);

  // notes
  const wl = (2*Math.PI*Math.pow(10000, dim/D)).toFixed(0);
  const speed = dim < 20 ? '⚡ very fast' : dim < 80 ? '⚡ fast' : dim < 160 ? '~ moderate' : '🐢 slow';
  document.getElementById('hnote').innerHTML = `Left = high-frequency oscillations. Right = nearly flat. Highlighted dot at <b>i=${dim}</b> = ${hdata[dim].toFixed(3)}.`;
  document.getElementById('vnote').innerHTML = `Dimension i=${dim} (${speed}, wavelength≈${wl}). Highlighted dot at <b>pos=${pos}</b> = ${vdata[pos].toFixed(3)}.`;
}

setTimeout(update, 60);
window.addEventListener('resize', update);
</script>