feat(math6): полоса процента (Гл.2 §1) + фильтр множества (Гл.3 §1)

Math6Anim.barModel — полоса 0..100%, заполняется (easing) к проценту,
синхронно %↔десятичная↔дробь; вшита в §2.1 на тот же ползунок, что и сетка 100.
Math6Anim.setFilter — числа 1..12 по очереди проходят сквозь «фильтр свойства»
(чётные/кратные 3/больше 6), подходящие падают в множество; кнопки смены свойства;
вшита в §3.1. Теперь во ВСЕХ 6 главах есть canvas-анимации + stepPlayer везде.
Headless-safe. Тесты math6: 20/20.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-02 22:00:57 +03:00
parent 97966ba2df
commit 302b062649
4 changed files with 78 additions and 3 deletions
+4 -3
View File
@@ -129,7 +129,7 @@ function buildP1(){
h+='<div class="wg" id="p1-iv1"><div class="wg-header"><span class="wg-badge">Интерактив 1</span><div class="wg-title">Процент наглядно</div></div>'
+'<div class="wg-help">Двигай ползунок — закрашенные клетки из 100 показывают процент.</div>'
+'<div class="sliders"><label>Процент = <b id="p1-pv">35</b>%<input type="range" id="p1-p" min="0" max="100" value="35"></label></div>'
+'<div id="p1-fig"></div><div id="p1-out" class="qbox"></div></div>';
+'<div id="p1-fig"></div><div id="p1-bar" style="margin:8px 0"></div><div id="p1-out" class="qbox"></div></div>';
h+='<div class="wg" id="p1-iv2"><div class="wg-header"><span class="wg-badge">Интерактив 2</span><div class="wg-title">Переводи проценты</div></div>'
+'<div class="wg-help">Переведи между процентами и десятичной дробью. Ответ — число.</div>'
+'<div class="score-display"><span>Вопрос <b id="p1-i">1</b> / 6</span><span>Очки: <b id="p1-s">0</b> / 6</span></div>'
@@ -140,9 +140,10 @@ function buildP1(){
box.innerHTML=h; renderMath(box);
(function(){
var sl=document.getElementById('p1-p'), fig=document.getElementById('p1-fig'), out=document.getElementById('p1-out');
var sl=document.getElementById('p1-p'), fig=document.getElementById('p1-fig'), out=document.getElementById('p1-out'), bar=null;
function render(){ var p=+sl.value; document.getElementById('p1-pv').textContent=p; fig.innerHTML=grid100(p);
out.innerHTML='<div style="font-size:1.2rem;font-weight:800;color:var(--pri2)">$'+p+'\\% = \\dfrac{'+p+'}{100} = '+_kf(p/100)+'$</div>'; renderMath(out); }
out.innerHTML='<div style="font-size:1.2rem;font-weight:800;color:var(--pri2)">$'+p+'\\% = \\dfrac{'+p+'}{100} = '+_kf(p/100)+'$</div>'; renderMath(out);
if(window.Math6Anim){ if(!bar) bar=Math6Anim.barModel(document.getElementById('p1-bar'),{percent:p}); else bar.set(p); } }
sl.oninput=render; render();
})();
+9
View File
@@ -137,9 +137,18 @@ function buildP1(){
+'<div id="p1-sv3-chips" style="display:flex;gap:8px;justify-content:center;flex-wrap:wrap;margin:10px 0"></div>'
+'<div style="display:flex;gap:10px;justify-content:center"><button class="btn primary" id="p1-sv3-go">Проверить</button><button class="btn" id="p1-sv3-next">Следующее</button></div>'
+'<div class="feedback" id="p1-sv3-fb"></div></div>';
h+='<div class="wg" id="p1-filter"><div class="wg-header"><span class="wg-badge">Анимация</span><div class="wg-title">Фильтр множества</div></div>'
+'<div class="wg-help">Выбери свойство — числа $1\\ldots12$ по очереди проходят через фильтр; подходящие падают в множество, остальные отсеиваются.</div>'
+'<div style="display:flex;gap:8px;justify-content:center;flex-wrap:wrap;margin-bottom:8px"><button class="btn primary" data-f="even">чётные</button><button class="btn" data-f="mul3">кратные 3</button><button class="btn" data-f="gt6">больше 6</button></div>'
+'<div id="p1-filterfig"></div></div>';
h+=secNav(null,'p2')+readBtn('p1');
box.innerHTML=h; renderMath(box);
(function(){ if(!window.Math6Anim) return; var ctrl=Math6Anim.setFilter(document.getElementById('p1-filterfig'),{label:'чётные',test:function(n){return n%2===0;}});
var F={even:['чётные',function(n){return n%2===0;}],mul3:['кратные 3',function(n){return n%3===0;}],gt6:['больше 6',function(n){return n>6;}]};
document.querySelectorAll('#p1-filter [data-f]').forEach(function(b){ b.addEventListener('click',function(){ document.querySelectorAll('#p1-filter [data-f]').forEach(function(x){x.classList.remove('primary');}); b.classList.add('primary'); var f=F[b.getAttribute('data-f')]; ctrl.set(f[0],f[1]); }); });
})();
(function(){
var i=0,score=0,cur=null;
function gen(){ var A=_distinct(_ri(3,5),1,9), inside=_pick([true,false]); var e; if(inside)e=_pick(A); else { do{e=_ri(1,9);}while(A.indexOf(e)>=0); } cur={A:A,e:e,in:A.indexOf(e)>=0}; }