fix(geom8): drag-интерактивы — pointermove/up на window + §7 индикатор равенства диагоналей

Drag (12 SVG-интерактивов): pointermove/pointerup/pointercancel слушались на
самом vertex-элементе. При выходе курсора за пределы маленького круга drag
обрывался — отсюда эффект 'нажал, чуть-чуть потянулось, и всё'. Перенесены
на window — теперь работают как нативный drag.

§7 (Прямоугольник): info-карточка показывала 'AC = BD' с одним значением.
Теперь две отдельные карточки AC и BD + индикатор равенства (зелёная плашка
'Диагонали равны' / красная 'Не равны' с Δ).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-05-28 08:53:57 +03:00
parent 2e37360dac
commit 640ca245ee
+33 -30
View File
@@ -959,10 +959,10 @@ function buildP1(){
verts[idx]={x:nx,y:ny};
redraw(); updateInfo();
}
function onUp(){ el.removeEventListener('pointermove',onMove);el.removeEventListener('pointerup',onUp);el.removeEventListener('pointercancel',onUp);el.style.cursor='grab'; }
el.addEventListener('pointermove',onMove);
el.addEventListener('pointerup',onUp);
el.addEventListener('pointercancel',onUp);
function onUp(){ window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp);el.style.cursor='grab'; }
window.addEventListener('pointermove',onMove);
window.addEventListener('pointerup',onUp);
window.addEventListener('pointercancel',onUp);
});
});
const statusEl=document.getElementById('p1-poly-status');
@@ -1746,10 +1746,10 @@ function buildP4(){
else if(vname==='D') D={x:nx,y:ny};
redraw(); updateInfo();
}
function onUp(){ el.removeEventListener('pointermove',onMove);el.removeEventListener('pointerup',onUp);el.removeEventListener('pointercancel',onUp); }
el.addEventListener('pointermove',onMove);
el.addEventListener('pointerup',onUp);
el.addEventListener('pointercancel',onUp);
function onUp(){ window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp); }
window.addEventListener('pointermove',onMove);
window.addEventListener('pointerup',onUp);
window.addEventListener('pointercancel',onUp);
});
});
updateInfo();
@@ -2033,8 +2033,8 @@ function buildP5(){
const vname=el.dataset.v;
try{el.setPointerCapture(ev.pointerId);}catch(e){}
function onMove(e){ const rect=svgEl.getBoundingClientRect(); const sx=W/rect.width,sy=H/rect.height; const nx=Math.max(10,Math.min(W-10,(e.clientX-rect.left)*sx)); const ny=Math.max(10,Math.min(H-10,(e.clientY-rect.top)*sy)); if(vname==='B') B={x:nx,y:ny}; else if(vname==='D') D={x:nx,y:ny}; redraw(); }
function onUp(){ el.removeEventListener('pointermove',onMove);el.removeEventListener('pointerup',onUp);el.removeEventListener('pointercancel',onUp); }
el.addEventListener('pointermove',onMove); el.addEventListener('pointerup',onUp); el.addEventListener('pointercancel',onUp);
function onUp(){ window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp); }
window.addEventListener('pointermove',onMove); window.addEventListener('pointerup',onUp); window.addEventListener('pointercancel',onUp);
});
});
const C2=getC(); const O2=intersect(A,C2,B,D);
@@ -2512,16 +2512,19 @@ function buildP7(){
if(ev.button!==undefined&&ev.button!==0)return;
try{el.setPointerCapture(ev.pointerId);}catch(e){}
function onMove(e){ const rect=svgEl.getBoundingClientRect(); const sx=W/rect.width,sy=H/rect.height; B={x:Math.max(A.x+30,Math.min(W-10,(e.clientX-rect.left)*sx)),y:Math.max(30,Math.min(H-10,(e.clientY-rect.top)*sy))}; redraw(); }
function onUp(){ el.removeEventListener('pointermove',onMove);el.removeEventListener('pointerup',onUp);el.removeEventListener('pointercancel',onUp); }
el.addEventListener('pointermove',onMove); el.addEventListener('pointerup',onUp); el.addEventListener('pointercancel',onUp);
function onUp(){ window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp); }
window.addEventListener('pointermove',onMove); window.addEventListener('pointerup',onUp); window.addEventListener('pointercancel',onUp);
});
});
const rr=getRect(); const ab=dist(rr.A,rr.B), bc=dist(rr.B,rr.C), ac=dist(rr.A,rr.C), bd=dist(rr.B,rr.D);
const eq=Math.abs(ac-bd)<0.05;
document.getElementById('p7-rect-info').innerHTML=`
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.85rem"><div style="color:var(--muted);font-size:.7rem;font-weight:700;text-transform:uppercase;margin-bottom:3px">AB</div><b>${ab.toFixed(1)}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.85rem"><div style="color:var(--muted);font-size:.7rem;font-weight:700;text-transform:uppercase;margin-bottom:3px">BC</div><b>${bc.toFixed(1)}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.85rem"><div style="color:var(--muted);font-size:.7rem;font-weight:700;text-transform:uppercase;margin-bottom:3px">AC = BD</div><b>${ac.toFixed(1)}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.85rem"><div style="color:var(--muted);font-size:.7rem;font-weight:700;text-transform:uppercase;margin-bottom:3px">Все углы</div><b>90°</b></div>`;
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.85rem"><div style="color:var(--muted);font-size:.7rem;font-weight:700;text-transform:uppercase;margin-bottom:3px">AC (диагональ)</div><b>${ac.toFixed(2)}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.85rem"><div style="color:var(--muted);font-size:.7rem;font-weight:700;text-transform:uppercase;margin-bottom:3px">BD (диагональ)</div><b>${bd.toFixed(2)}</b></div>
<div style="padding:8px 12px;background:${eq?'#d1fae5':'#fee2e2'};border-radius:8px;border:1.5px solid ${eq?'#10b981':'#dc2626'};font-size:.85rem;grid-column:span 2;text-align:center"><div style="color:${eq?'#047857':'#b91c1c'};font-size:.72rem;font-weight:800;text-transform:uppercase;margin-bottom:3px">${eq?'AC = BD':'AC ≠ BD'}</div><b style="color:${eq?'#047857':'#b91c1c'}">${eq?'Диагонали равны':'Не равны (Δ='+Math.abs(ac-bd).toFixed(2)+')'}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.85rem;grid-column:span 2;text-align:center"><div style="color:var(--muted);font-size:.7rem;font-weight:700;text-transform:uppercase;margin-bottom:3px">Все углы</div><b>90°</b></div>`;
}
redraw();
})();
@@ -2739,8 +2742,8 @@ function buildP8(){
if(ev.button!==undefined&&ev.button!==0)return;
try{el.setPointerCapture(ev.pointerId);}catch(e){}
function onMove(e){ const rect=svgEl.getBoundingClientRect(); const sx=W/rect.width,sy=H/rect.height; D={x:Math.max(10,Math.min(W-10,(e.clientX-rect.left)*sx)),y:Math.max(10,Math.min(H-10,(e.clientY-rect.top)*sy))}; redraw(); }
function onUp(){ el.removeEventListener('pointermove',onMove);el.removeEventListener('pointerup',onUp);el.removeEventListener('pointercancel',onUp); }
el.addEventListener('pointermove',onMove); el.addEventListener('pointerup',onUp); el.addEventListener('pointercancel',onUp);
function onUp(){ window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp); }
window.addEventListener('pointermove',onMove); window.addEventListener('pointerup',onUp); window.addEventListener('pointercancel',onUp);
});
});
const okCol=eq?'#10b981':'#94a3b8';
@@ -2984,8 +2987,8 @@ function buildP9(){
const vname=el.dataset.v;
try{el.setPointerCapture(ev.pointerId);}catch(e){}
function onMove(e){ const rect=svgEl.getBoundingClientRect(); const sx=W/rect.width,sy=H/rect.height; const nx=(e.clientX-rect.left)*sx; const ny=(e.clientY-rect.top)*sy; if(vname==='B'){ half2=Math.max(20,Math.min(H/2-10,cy-ny)); } else if(vname==='D'){ half2=Math.max(20,Math.min(H/2-10,ny-cy)); } else if(vname==='A'){ half1=Math.max(20,Math.min(W/2-10,cx-nx)); } else if(vname==='C'){ half1=Math.max(20,Math.min(W/2-10,nx-cx)); } redraw(); }
function onUp(){ el.removeEventListener('pointermove',onMove);el.removeEventListener('pointerup',onUp);el.removeEventListener('pointercancel',onUp); }
el.addEventListener('pointermove',onMove); el.addEventListener('pointerup',onUp); el.addEventListener('pointercancel',onUp);
function onUp(){ window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp); }
window.addEventListener('pointermove',onMove); window.addEventListener('pointerup',onUp); window.addEventListener('pointercancel',onUp);
});
});
const {A:A2,B:B2}=getVerts(half1,half2); const side2=dist(A2,B2);
@@ -3545,8 +3548,8 @@ function buildP11(){
else if(vname==='A1'){ A1x=Math.max(10,Math.min(W-10,nx)); A1y=Math.max(10,Math.min(H-10,ny)); }
drawThales();
}
function onUp(){ el.removeEventListener('pointermove',onMove); el.removeEventListener('pointerup',onUp); el.removeEventListener('pointercancel',onUp); }
el.addEventListener('pointermove',onMove); el.addEventListener('pointerup',onUp); el.addEventListener('pointercancel',onUp);
function onUp(){ window.removeEventListener('pointermove',onMove); window.removeEventListener('pointerup',onUp); window.removeEventListener('pointercancel',onUp); }
window.addEventListener('pointermove',onMove); window.addEventListener('pointerup',onUp); window.addEventListener('pointercancel',onUp);
});
});
@@ -3839,8 +3842,8 @@ function buildP12(){
else C={x:nx,y:ny};
redraw();
}
function onUp(){ el.removeEventListener('pointermove',onMove); el.removeEventListener('pointerup',onUp); el.removeEventListener('pointercancel',onUp); }
el.addEventListener('pointermove',onMove); el.addEventListener('pointerup',onUp); el.addEventListener('pointercancel',onUp);
function onUp(){ window.removeEventListener('pointermove',onMove); window.removeEventListener('pointerup',onUp); window.removeEventListener('pointercancel',onUp); }
window.addEventListener('pointermove',onMove); window.addEventListener('pointerup',onUp); window.addEventListener('pointercancel',onUp);
});
});
@@ -4093,8 +4096,8 @@ function buildP13(){
else C={x:nx,y:ny};
redraw();
}
function onUp(){ el.removeEventListener('pointermove',onMove); el.removeEventListener('pointerup',onUp); el.removeEventListener('pointercancel',onUp); }
el.addEventListener('pointermove',onMove); el.addEventListener('pointerup',onUp); el.addEventListener('pointercancel',onUp);
function onUp(){ window.removeEventListener('pointermove',onMove); window.removeEventListener('pointerup',onUp); window.removeEventListener('pointercancel',onUp); }
window.addEventListener('pointermove',onMove); window.addEventListener('pointerup',onUp); window.addEventListener('pointercancel',onUp);
});
});
const bc=dist(B,C), ac=dist(A,C), ab=dist(A,B);
@@ -4406,8 +4409,8 @@ function buildP14(){
else if(vname==='D'){ D={x:nx,y:ny}; C.y=ny; }
redraw();
}
function onUp(){ el.removeEventListener('pointermove',onMove); el.removeEventListener('pointerup',onUp); el.removeEventListener('pointercancel',onUp); }
el.addEventListener('pointermove',onMove); el.addEventListener('pointerup',onUp); el.addEventListener('pointercancel',onUp);
function onUp(){ window.removeEventListener('pointermove',onMove); window.removeEventListener('pointerup',onUp); window.removeEventListener('pointercancel',onUp); }
window.addEventListener('pointermove',onMove); window.addEventListener('pointerup',onUp); window.addEventListener('pointercancel',onUp);
});
});
const S=(a+b)/2*h;
@@ -4739,8 +4742,8 @@ function buildP15(){
else if(vname==='D'){ halfTop=Math.max(10, cx-nx); topY=ny; }
redraw();
}
function onUp(){ el.removeEventListener('pointermove',onMove); el.removeEventListener('pointerup',onUp); el.removeEventListener('pointercancel',onUp); }
el.addEventListener('pointermove',onMove); el.addEventListener('pointerup',onUp); el.addEventListener('pointercancel',onUp);
function onUp(){ window.removeEventListener('pointermove',onMove); window.removeEventListener('pointerup',onUp); window.removeEventListener('pointercancel',onUp); }
window.addEventListener('pointermove',onMove); window.addEventListener('pointerup',onUp); window.addEventListener('pointercancel',onUp);
});
});
const eq=(Math.abs(diag-dist(B,D))<0.5)?'<span style="color:var(--ok)">Равны!</span>':'не равны';
@@ -5057,8 +5060,8 @@ function buildP16(){
else if(vname==='D'){ D={x:nx,y:ny}; C.y=ny; }
redraw2();
}
function onUp(){ el.removeEventListener('pointermove',onMove); el.removeEventListener('pointerup',onUp); el.removeEventListener('pointercancel',onUp); }
el.addEventListener('pointermove',onMove); el.addEventListener('pointerup',onUp); el.addEventListener('pointercancel',onUp);
function onUp(){ window.removeEventListener('pointermove',onMove); window.removeEventListener('pointerup',onUp); window.removeEventListener('pointercancel',onUp); }
window.addEventListener('pointermove',onMove); window.addEventListener('pointerup',onUp); window.addEventListener('pointercancel',onUp);
});
});
const ind=document.getElementById('p16-sign2-ind');