feat(alg9 ch2 wave2): §8 «Чётные/нечётные» + §9 «Сдвиги графиков»
This commit is contained in:
@@ -1118,38 +1118,686 @@ function buildP7(){
|
||||
}
|
||||
|
||||
function buildP8(){
|
||||
const root = document.getElementById('p8-body');
|
||||
root.innerHTML = `
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<span class="card-icon theory">${ICONS.theory}</span>
|
||||
<span class="card-title">В разработке</span>
|
||||
<span class="card-num">§ 8</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Содержание параграфа <b>«Чётные и нечётные функции»</b> будет добавлено в следующих обновлениях.</p>
|
||||
<p style="color:var(--muted);font-size:.9rem">Раздел Phase 1.</p>
|
||||
</div>
|
||||
</div>` + secNav('p7', 'p9') + readButton('p8');
|
||||
renderMath(root);
|
||||
const box = document.getElementById('p8-body');
|
||||
let html = '';
|
||||
|
||||
html += makeCard('theory', 'Определения', '8.1', `
|
||||
<p>Функция $y = f(x)$ называется <b>чётной</b>, если её область определения $D(f)$ симметрична относительно нуля и для всех $x \\in D(f)$ выполняется равенство:</p>
|
||||
<p style="text-align:center;font-size:1.05rem">$f(-x) = f(x)$</p>
|
||||
<p>Функция $y = f(x)$ называется <b>нечётной</b>, если её область определения $D(f)$ симметрична относительно нуля и для всех $x \\in D(f)$ выполняется равенство:</p>
|
||||
<p style="text-align:center;font-size:1.05rem">$f(-x) = -f(x)$</p>
|
||||
<p>Если ни одно из этих условий не выполняется — функцию называют <b>функцией общего вида</b>.</p>
|
||||
<details class="spoiler"><summary>Что значит «$D(f)$ симметрична относительно нуля»?</summary><div class="spoiler-body">
|
||||
Это значит: если $x \\in D(f)$, то и $-x \\in D(f)$. Например, $D(f) = [-3; 3]$ — симметрична, а $D(f) = [0; +\\infty)$ — нет.
|
||||
</div></details>`);
|
||||
|
||||
html += makeCard('rule', 'Графическая симметрия', '8.2', `
|
||||
<p>Свойство чётности или нечётности имеет наглядный геометрический смысл:</p>
|
||||
<ul style="padding-left:22px;line-height:1.9">
|
||||
<li>График <b>чётной</b> функции симметричен относительно <b>оси $Oy$</b> (зеркальное отражение).</li>
|
||||
<li>График <b>нечётной</b> функции симметричен относительно <b>начала координат</b> (центральная симметрия — точка $O$).</li>
|
||||
</ul>
|
||||
<p>Поэтому достаточно построить график на $[0; +\\infty)$ — а на $(-\\infty; 0]$ его можно восстановить отражением.</p>`);
|
||||
|
||||
html += makeCard('example', 'Примеры функций', '8.3', `
|
||||
<p><b>Чётные:</b> $y = x^2$, $y = x^4$, $y = |x|$, $y = \\cos x$, $y = x^2 + 1$.</p>
|
||||
<p><b>Нечётные:</b> $y = x$, $y = x^3$, $y = \\dfrac{1}{x}$, $y = \\sin x$, $y = x^5 - x$.</p>
|
||||
<p><b>Общего вида:</b></p>
|
||||
<ul style="padding-left:22px;line-height:1.9">
|
||||
<li>$y = x + 1$ — линейная без чётности;</li>
|
||||
<li>$y = x^2 + x$ — смесь чётной и нечётной части;</li>
|
||||
<li>$y = \\sqrt{x}$ — $D(f) = [0; +\\infty)$ не симметрична относительно нуля.</li>
|
||||
</ul>`);
|
||||
|
||||
/* INTERACTIVE 1 — симметрия графика */
|
||||
html += `<div class="wg" id="p8-iv1">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Симметрия графика</div></div>
|
||||
<div class="wg-help">Выбери функцию ползунком. На графике появятся линии симметрии: для чётной — относительно оси $Oy$, для нечётной — относительно точки $O$.</div>
|
||||
<div class="sliders">
|
||||
<label>Функция №<b id="p8-iv1-fi">1</b> / 6<input type="range" id="p8-iv1-fn" min="1" max="6" step="1" value="1"></label>
|
||||
</div>
|
||||
<div id="p8-iv1-formula" style="text-align:center;font-size:1.1rem;padding:10px;background:var(--card);border-radius:9px;margin-bottom:10px"></div>
|
||||
<div style="background:var(--card);border-radius:10px;padding:10px;overflow-x:auto">
|
||||
<svg id="p8-iv1-svg" viewBox="0 0 380 280" style="width:100%;max-width:500px;height:auto;display:block;margin:0 auto"></svg>
|
||||
</div>
|
||||
<div id="p8-iv1-out" style="margin-top:10px;padding:12px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.95rem;line-height:1.7"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 2 — квикфайр */
|
||||
html += `<div class="wg" id="p8-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">Задача: <b id="p8-iv2-idx">1</b> / 8 · Очки: <b id="p8-iv2-sc">0</b></div>
|
||||
<div id="p8-iv2-q" style="text-align:center;font-size:1.15rem;padding:14px;background:var(--card);border-radius:9px;margin-bottom:12px;min-height:60px"></div>
|
||||
<div class="actions" style="justify-content:center;flex-wrap:wrap">
|
||||
<button class="btn primary" id="p8-iv2-e">Чётная</button>
|
||||
<button class="btn" id="p8-iv2-o">Нечётная</button>
|
||||
<button class="btn" id="p8-iv2-g">Общая</button>
|
||||
</div>
|
||||
<div class="feedback" id="p8-iv2-fb"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 3 — подставь -x */
|
||||
html += `<div class="wg" id="p8-iv3">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Подставь $-x$</div></div>
|
||||
<div class="wg-help">Подставь в формулу $-x$ вместо $x$. Сравни с исходной: получилась $f(x)$? — чётная. Получилась $-f(x)$? — нечётная. Что-то другое? — общая.</div>
|
||||
<div class="score-display">Задача: <b id="p8-iv3-idx">1</b> / 6 · Очки: <b id="p8-iv3-sc">0</b></div>
|
||||
<div id="p8-iv3-q" style="text-align:center;font-size:1.05rem;padding:14px;background:var(--card);border-radius:9px;margin-bottom:12px;min-height:60px"></div>
|
||||
<div class="actions" style="justify-content:center;flex-wrap:wrap">
|
||||
<button class="btn primary" id="p8-iv3-a">$f(-x) = f(x)$</button>
|
||||
<button class="btn" id="p8-iv3-b">$f(-x) = -f(x)$</button>
|
||||
<button class="btn" id="p8-iv3-c">Другое</button>
|
||||
</div>
|
||||
<div class="feedback" id="p8-iv3-fb"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 4 — DnD сортер */
|
||||
html += `<div class="wg" id="p8-iv4">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Сортер: какой тип?</div></div>
|
||||
<div class="wg-help">Перетащи каждую функцию в подходящий ящик.</div>
|
||||
<div id="p8-iv4-pool"></div>
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px">
|
||||
<div class="drop-box"><h5>Чётная</h5><div class="drop-items" data-cat="even"></div></div>
|
||||
<div class="drop-box"><h5>Нечётная</h5><div class="drop-items" data-cat="odd"></div></div>
|
||||
<div class="drop-box"><h5>Общая</h5><div class="drop-items" data-cat="gen"></div></div>
|
||||
</div>
|
||||
<div class="actions"><button class="btn primary" id="p8-iv4-check">Проверить</button><button class="btn" id="p8-iv4-reset">Сбросить</button></div>
|
||||
<div class="feedback" id="p8-iv4-fb"></div>
|
||||
</div>`;
|
||||
|
||||
box.innerHTML = html + secNav('p7', 'p9') + readButton('p8');
|
||||
renderMath(box);
|
||||
|
||||
/* ===== IV1 wiring — симметрия графика ===== */
|
||||
(function(){
|
||||
const fns = [
|
||||
{ tex:'y = x^2', f:x=>x*x, type:'even', xmin:-4, xmax:4 },
|
||||
{ tex:'y = x^3', f:x=>x*x*x, type:'odd', xmin:-4, xmax:4 },
|
||||
{ tex:'y = |x|', f:x=>Math.abs(x),type:'even', xmin:-4, xmax:4 },
|
||||
{ tex:'y = x', f:x=>x, type:'odd', xmin:-4, xmax:4 },
|
||||
{ tex:'y = x^2 + x', f:x=>x*x+x, type:'gen', xmin:-4, xmax:4 },
|
||||
{ tex:'y = \\dfrac{1}{x}', f:x=>1/x, type:'odd', xmin:-4, xmax:4 }
|
||||
];
|
||||
const sl = document.getElementById('p8-iv1-fn');
|
||||
const fi = document.getElementById('p8-iv1-fi');
|
||||
const svg = document.getElementById('p8-iv1-svg');
|
||||
const formula = document.getElementById('p8-iv1-formula');
|
||||
const out = document.getElementById('p8-iv1-out');
|
||||
let bumped = false;
|
||||
|
||||
function redraw(){
|
||||
const idx = (+sl.value)-1;
|
||||
const fobj = fns[idx];
|
||||
fi.textContent = (idx+1);
|
||||
const ax = axes2D(380, 280, 28, -4, 4, -4, 4);
|
||||
let g = ax.content;
|
||||
|
||||
// линии симметрии под графиком
|
||||
if (fobj.type === 'even'){
|
||||
// подсветим ось Oy
|
||||
const x0 = ax.toX(0);
|
||||
g += '<line x1="'+x0+'" y1="'+ax.toY(-4)+'" x2="'+x0+'" y2="'+ax.toY(4)+'" stroke="#a855f7" stroke-width="2.5" stroke-dasharray="6 4" opacity=".7"/>';
|
||||
} else if (fobj.type === 'odd'){
|
||||
// выделим точку O маркером
|
||||
const cx = ax.toX(0), cy = ax.toY(0);
|
||||
g += '<circle cx="'+cx+'" cy="'+cy+'" r="10" fill="none" stroke="#a855f7" stroke-width="2.5" stroke-dasharray="4 3"/>';
|
||||
// диагонали через O
|
||||
g += '<line x1="'+ax.toX(-4)+'" y1="'+ax.toY(4)+'" x2="'+ax.toX(4)+'" y2="'+ax.toY(-4)+'" stroke="#a855f7" stroke-width="1" stroke-dasharray="3 5" opacity=".4"/>';
|
||||
g += '<line x1="'+ax.toX(-4)+'" y1="'+ax.toY(-4)+'" x2="'+ax.toX(4)+'" y2="'+ax.toY(4)+'" stroke="#a855f7" stroke-width="1" stroke-dasharray="3 5" opacity=".4"/>';
|
||||
}
|
||||
|
||||
// график
|
||||
if (fobj.type === 'odd' && fobj.tex.indexOf('1') !== -1 && fobj.tex.indexOf('x') !== -1 && fobj.tex.indexOf('dfrac') !== -1){
|
||||
// гипербола: рисуем две ветви
|
||||
g += plotFunc(fobj.f, -4, -0.05, ax.toX, ax.toY, '#059669', 200);
|
||||
g += plotFunc(fobj.f, 0.05, 4, ax.toX, ax.toY, '#059669', 200);
|
||||
} else {
|
||||
g += plotFunc(fobj.f, fobj.xmin, fobj.xmax, ax.toX, ax.toY, '#059669', 300);
|
||||
}
|
||||
|
||||
svg.innerHTML = g;
|
||||
formula.innerHTML = '$' + fobj.tex + '$';
|
||||
|
||||
// подсчёт f(-x)
|
||||
const xprobe = 1.5;
|
||||
let fnegX_tex = '';
|
||||
if (idx === 0) fnegX_tex = '(-x)^2 = x^2 = f(x)';
|
||||
else if (idx === 1) fnegX_tex = '(-x)^3 = -x^3 = -f(x)';
|
||||
else if (idx === 2) fnegX_tex = '|-x| = |x| = f(x)';
|
||||
else if (idx === 3) fnegX_tex = '-x = -f(x)';
|
||||
else if (idx === 4) fnegX_tex = '(-x)^2 + (-x) = x^2 - x \\ne \\pm f(x)';
|
||||
else if (idx === 5) fnegX_tex = '\\dfrac{1}{-x} = -\\dfrac{1}{x} = -f(x)';
|
||||
|
||||
const typeLabel = (fobj.type==='even')?'<b style="color:#059669">чётная</b>':(fobj.type==='odd')?'<b style="color:#2563eb">нечётная</b>':'<b style="color:#ef4444">общего вида</b>';
|
||||
const symLabel = (fobj.type==='even')?'ось $Oy$':(fobj.type==='odd')?'точка $O$ (начало координат)':'нет симметрии';
|
||||
|
||||
out.innerHTML =
|
||||
'<div>$f(-x) = ' + fnegX_tex + '$</div>' +
|
||||
'<div style="margin-top:6px">Тип: ' + typeLabel + '</div>' +
|
||||
'<div style="margin-top:4px">Симметрия: ' + symLabel + '</div>';
|
||||
renderMath(formula); renderMath(out);
|
||||
if (!bumped){ bumped = true; bumpProgress('p8', 15); addXp(10,'p8-iv1'); }
|
||||
}
|
||||
sl.addEventListener('input', redraw);
|
||||
redraw();
|
||||
})();
|
||||
|
||||
/* ===== IV2 wiring — квикфайр 8 ===== */
|
||||
(function(){
|
||||
const items = [
|
||||
{ q:'$f(x) = x^4$', ans:'even', hint:'$(-x)^4 = x^4$ — чётная.' },
|
||||
{ q:'$f(x) = x^5$', ans:'odd', hint:'$(-x)^5 = -x^5$ — нечётная.' },
|
||||
{ q:'$f(x) = x^2 + 3$', ans:'even', hint:'$(-x)^2 + 3 = x^2 + 3 = f(x)$ — чётная.' },
|
||||
{ q:'$f(x) = x^3 + x$', ans:'odd', hint:'$(-x)^3 + (-x) = -x^3 - x = -(x^3+x) = -f(x)$ — нечётная.' },
|
||||
{ q:'$f(x) = x^3 + 1$', ans:'gen', hint:'$(-x)^3 + 1 = -x^3 + 1$ — не равно ни $f(x)$, ни $-f(x)$. Общая.' },
|
||||
{ q:'$f(x) = |x| - 5$', ans:'even', hint:'$|-x| - 5 = |x| - 5 = f(x)$ — чётная.' },
|
||||
{ q:'$f(x) = \\dfrac{1}{x^2}$', ans:'even', hint:'$\\dfrac{1}{(-x)^2} = \\dfrac{1}{x^2} = f(x)$ — чётная.' },
|
||||
{ q:'$f(x) = \\dfrac{1}{x^3}$', ans:'odd', hint:'$\\dfrac{1}{(-x)^3} = -\\dfrac{1}{x^3} = -f(x)$ — нечётная.' }
|
||||
];
|
||||
let i = 0, sc = 0;
|
||||
const idxEl = document.getElementById('p8-iv2-idx');
|
||||
const scEl = document.getElementById('p8-iv2-sc');
|
||||
const qEl = document.getElementById('p8-iv2-q');
|
||||
const fb = document.getElementById('p8-iv2-fb');
|
||||
const eBtn = document.getElementById('p8-iv2-e');
|
||||
const oBtn = document.getElementById('p8-iv2-o');
|
||||
const gBtn = document.getElementById('p8-iv2-g');
|
||||
let bumped = false;
|
||||
function render(){
|
||||
idxEl.textContent = Math.min(i+1, items.length);
|
||||
scEl.textContent = sc;
|
||||
if (i >= items.length){
|
||||
qEl.innerHTML = '<b>Готово!</b> Результат: ' + sc + ' / ' + items.length;
|
||||
eBtn.disabled = true; oBtn.disabled = true; gBtn.disabled = true;
|
||||
eBtn.style.opacity = .5; oBtn.style.opacity = .5; gBtn.style.opacity = .5;
|
||||
if (!bumped){ bumped = true; bumpProgress('p8', 15); addXp(10,'p8-iv2'); }
|
||||
return;
|
||||
}
|
||||
qEl.innerHTML = items[i].q;
|
||||
fb.style.display = 'none';
|
||||
renderMath(qEl);
|
||||
}
|
||||
function answer(v){
|
||||
if (i >= items.length) return;
|
||||
const it = items[i];
|
||||
const ok = (v === it.ans);
|
||||
if (ok) sc++;
|
||||
feedback(fb, ok, (ok?'✓ Верно. ':'✗ Неверно. ') + it.hint);
|
||||
i++;
|
||||
setTimeout(render, 1000);
|
||||
}
|
||||
eBtn.addEventListener('click', ()=>answer('even'));
|
||||
oBtn.addEventListener('click', ()=>answer('odd'));
|
||||
gBtn.addEventListener('click', ()=>answer('gen'));
|
||||
render();
|
||||
})();
|
||||
|
||||
/* ===== IV3 wiring — подставь -x ===== */
|
||||
(function(){
|
||||
const items = [
|
||||
{ q:'$f(x) = 2x^2 - 7$', ans:'a', hint:'$f(-x) = 2(-x)^2 - 7 = 2x^2 - 7 = f(x)$. Чётная.' },
|
||||
{ q:'$f(x) = x^5 - 2x$', ans:'b', hint:'$f(-x) = -x^5 + 2x = -(x^5 - 2x) = -f(x)$. Нечётная.' },
|
||||
{ q:'$f(x) = x + 1$', ans:'c', hint:'$f(-x) = -x + 1$ — не равно ни $f(x)$, ни $-f(x)$. Общая.' },
|
||||
{ q:'$f(x) = -3x^2 + |x|$', ans:'a', hint:'$f(-x) = -3x^2 + |x| = f(x)$. Чётная.' },
|
||||
{ q:'$f(x) = x^3 - 3x$', ans:'b', hint:'$f(-x) = -x^3 + 3x = -(x^3 - 3x) = -f(x)$. Нечётная.' },
|
||||
{ q:'$f(x) = (x + 2)^2$', ans:'c', hint:'$f(-x) = (-x + 2)^2 = (x - 2)^2$ — не равно ни $f(x)$, ни $-f(x)$. Общая.' }
|
||||
];
|
||||
let i = 0, sc = 0;
|
||||
const idxEl = document.getElementById('p8-iv3-idx');
|
||||
const scEl = document.getElementById('p8-iv3-sc');
|
||||
const qEl = document.getElementById('p8-iv3-q');
|
||||
const fb = document.getElementById('p8-iv3-fb');
|
||||
const aBtn = document.getElementById('p8-iv3-a');
|
||||
const bBtn = document.getElementById('p8-iv3-b');
|
||||
const cBtn = document.getElementById('p8-iv3-c');
|
||||
let bumped = false;
|
||||
function render(){
|
||||
idxEl.textContent = Math.min(i+1, items.length);
|
||||
scEl.textContent = sc;
|
||||
if (i >= items.length){
|
||||
qEl.innerHTML = '<b>Готово!</b> Результат: ' + sc + ' / ' + items.length;
|
||||
aBtn.disabled = true; bBtn.disabled = true; cBtn.disabled = true;
|
||||
aBtn.style.opacity = .5; bBtn.style.opacity = .5; cBtn.style.opacity = .5;
|
||||
if (!bumped){ bumped = true; bumpProgress('p8', 25); addXp(15,'p8-iv3'); }
|
||||
return;
|
||||
}
|
||||
qEl.innerHTML = items[i].q;
|
||||
fb.style.display = 'none';
|
||||
renderMath(qEl);
|
||||
}
|
||||
function answer(v){
|
||||
if (i >= items.length) return;
|
||||
const it = items[i];
|
||||
const ok = (v === it.ans);
|
||||
if (ok) sc++;
|
||||
feedback(fb, ok, (ok?'✓ Верно. ':'✗ Неверно. ') + it.hint);
|
||||
i++;
|
||||
setTimeout(render, 1100);
|
||||
}
|
||||
aBtn.addEventListener('click', ()=>answer('a'));
|
||||
bBtn.addEventListener('click', ()=>answer('b'));
|
||||
cBtn.addEventListener('click', ()=>answer('c'));
|
||||
render();
|
||||
})();
|
||||
|
||||
/* ===== IV4 wiring — DnD сортер ===== */
|
||||
(function(){
|
||||
const items = [
|
||||
{ id:'a', html:'$y = 5x^2$', cat:'even' },
|
||||
{ id:'b', html:'$y = 7x^3$', cat:'odd' },
|
||||
{ id:'c', html:'$y = 4x + 1$', cat:'gen' },
|
||||
{ id:'d', html:'$y = x^2 - 9$', cat:'even' },
|
||||
{ id:'e', html:'$y = x^3 - 2x$', cat:'odd' },
|
||||
{ id:'f', html:'$y = \\sqrt{x}$', cat:'gen' }
|
||||
];
|
||||
const sorter = setupSorter({
|
||||
poolId: 'p8-iv4-pool',
|
||||
scopeSelector: '#p8-iv4',
|
||||
cats: ['even','odd','gen'],
|
||||
items: items
|
||||
});
|
||||
let bumped = false;
|
||||
document.getElementById('p8-iv4-check').addEventListener('click', ()=>{
|
||||
const fb = document.getElementById('p8-iv4-fb');
|
||||
const total = items.length;
|
||||
let correct = 0, placed = 0;
|
||||
items.forEach(it=>{ if(sorter.placed[it.id]){ placed++; if(sorter.placed[it.id]===it.cat) correct++; } });
|
||||
if (placed < total){ feedback(fb, false, 'Размещены не все: ' + placed + ' / ' + total + '.'); return; }
|
||||
const ok = (correct === total);
|
||||
feedback(fb, ok, ok ? '✓ Все верно! ' + correct + ' / ' + total : '✗ Правильно: ' + correct + ' / ' + total);
|
||||
if (ok && !bumped){ bumped = true; bumpProgress('p8', 25); addXp(15,'p8-iv4'); }
|
||||
});
|
||||
document.getElementById('p8-iv4-reset').addEventListener('click', ()=>{
|
||||
sorter.reset();
|
||||
const fb = document.getElementById('p8-iv4-fb'); fb.style.display='none';
|
||||
});
|
||||
})();
|
||||
|
||||
wireReadBtn('p8');
|
||||
}
|
||||
|
||||
function buildP9(){
|
||||
const root = document.getElementById('p9-body');
|
||||
root.innerHTML = `
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<span class="card-icon theory">${ICONS.theory}</span>
|
||||
<span class="card-title">В разработке</span>
|
||||
<span class="card-num">§ 9</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Содержание параграфа <b>«Сдвиги графиков»</b> будет добавлено в следующих обновлениях.</p>
|
||||
<p style="color:var(--muted);font-size:.9rem">Раздел Phase 1.</p>
|
||||
</div>
|
||||
</div>` + secNav('p8', 'final2') + readButton('p9');
|
||||
renderMath(root);
|
||||
const box = document.getElementById('p9-body');
|
||||
let html = '';
|
||||
|
||||
html += makeCard('theory', 'Вертикальный сдвиг $y = f(x) + b$', '9.1', `
|
||||
<p>График функции $y = f(x) + b$ получается из графика $y = f(x)$ <b>параллельным переносом</b> вдоль оси $Oy$:</p>
|
||||
<ul style="padding-left:22px;line-height:1.9">
|
||||
<li>если $b > 0$ — <b>вверх</b> на $b$ единиц;</li>
|
||||
<li>если $b < 0$ — <b>вниз</b> на $|b|$ единиц.</li>
|
||||
</ul>
|
||||
<p><b>Пример.</b> График $y = x^2 + 3$ — это парабола $y = x^2$, сдвинутая <b>вверх</b> на 3 единицы. Её вершина: $(0;\\ 3)$.</p>
|
||||
<details class="spoiler"><summary>Почему так?</summary><div class="spoiler-body">
|
||||
При том же $x$ значение $y$ увеличивается на $b$ — то есть каждая точка поднимается на $b$ вверх. Это и есть вертикальный перенос.
|
||||
</div></details>`);
|
||||
|
||||
html += makeCard('rule', 'Горизонтальный сдвиг $y = f(x \\pm a)$', '9.2', `
|
||||
<p>График функции $y = f(x - a)$ получается из графика $y = f(x)$ параллельным переносом вдоль оси $Ox$:</p>
|
||||
<ul style="padding-left:22px;line-height:1.9">
|
||||
<li>если $a > 0$ — <b>вправо</b> на $a$ единиц;</li>
|
||||
<li>если $a < 0$ — <b>влево</b> на $|a|$ единиц.</li>
|
||||
</ul>
|
||||
<p><b>Внимание!</b> Знак <b>минус</b> внутри аргумента — сдвиг <b>вправо</b>. Знак <b>плюс</b> (то есть $f(x + a)$) — сдвиг <b>влево</b>. Это самая частая ошибка!</p>
|
||||
<p><b>Пример.</b> График $y = (x - 2)^2$ — парабола $y = x^2$, сдвинутая <b>вправо</b> на 2. Её вершина: $(2;\\ 0)$.</p>
|
||||
<p>А $y = (x + 5)^2$ — сдвиг <b>влево</b> на 5. Вершина: $(-5;\\ 0)$.</p>`);
|
||||
|
||||
html += makeCard('example', 'Комбинированный сдвиг', '9.3', `
|
||||
<p>График $y = f(x - a) + b$ получается комбинацией двух переносов: сдвиг на $a$ по оси $Ox$ и на $b$ по оси $Oy$.</p>
|
||||
<ul style="padding-left:22px;line-height:1.9">
|
||||
<li>$y = (x - 1)^2 + 3$ — парабола с вершиной в $(1;\\ 3)$.</li>
|
||||
<li>$y = (x + 2)^2 - 4$ — парабола с вершиной в $(-2;\\ -4)$.</li>
|
||||
<li>$y = \\sqrt{x - 3} + 1$ — график $y = \\sqrt{x}$, сдвинутый вправо на 3 и вверх на 1.</li>
|
||||
<li>$y = |x + 1| - 2$ — график $y = |x|$, сдвинутый влево на 1 и вниз на 2.</li>
|
||||
</ul>
|
||||
<p><b>Лайфхак.</b> Для параболы $y = (x - a)^2 + b$ вершина всегда в точке $(a;\\ b)$.</p>`);
|
||||
|
||||
/* INTERACTIVE 1 — слайдер сдвигов */
|
||||
html += `<div class="wg" id="p9-iv1">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Слайдер сдвигов</div></div>
|
||||
<div class="wg-help">Выбери базовую функцию и крути ползунки $a$ и $b$. Синяя кривая — сдвинутый график $y = f(x - a) + b$, серая — исходный.</div>
|
||||
<div class="sliders">
|
||||
<label>Функция №<b id="p9-iv1-fi">1</b> / 4<input type="range" id="p9-iv1-fn" min="1" max="4" step="1" value="1"></label>
|
||||
<label>$a$ =<b id="p9-iv1-av">0</b><input type="range" id="p9-iv1-a" min="-4" max="4" step="1" value="0"></label>
|
||||
<label>$b$ =<b id="p9-iv1-bv">0</b><input type="range" id="p9-iv1-b" min="-4" max="4" step="1" value="0"></label>
|
||||
</div>
|
||||
<div id="p9-iv1-formula" style="text-align:center;font-size:1.1rem;padding:10px;background:var(--card);border-radius:9px;margin-bottom:10px"></div>
|
||||
<div style="background:var(--card);border-radius:10px;padding:10px;overflow-x:auto">
|
||||
<svg id="p9-iv1-svg" viewBox="0 0 420 320" style="width:100%;max-width:560px;height:auto;display:block;margin:0 auto"></svg>
|
||||
</div>
|
||||
<div id="p9-iv1-out" style="margin-top:10px;padding:12px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.95rem;line-height:1.7;text-align:center"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 2 — вершина параболы */
|
||||
html += `<div class="wg" id="p9-iv2">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Сдвиг и вершина параболы</div></div>
|
||||
<div class="wg-help">Для параболы $y = (x - a)^2 + b$ вершина — в точке $(a;\\ b)$. Введи <b>сумму</b> координат вершины: $a + b$.</div>
|
||||
<div class="score-display">Задача: <b id="p9-iv2-idx">1</b> / 6 · Очки: <b id="p9-iv2-sc">0</b></div>
|
||||
<div id="p9-iv2-q" style="text-align:center;font-size:1.1rem;padding:14px;background:var(--card);border-radius:9px;margin-bottom:12px"></div>
|
||||
<div style="display:flex;gap:10px;justify-content:center;flex-wrap:wrap;align-items:center">
|
||||
<span>$a + b$ =</span>
|
||||
<input type="number" id="p9-iv2-in" class="tinp" style="width:110px;text-align:center" step="1">
|
||||
<button class="btn primary" id="p9-iv2-go">Проверить</button>
|
||||
</div>
|
||||
<div class="feedback" id="p9-iv2-fb"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 3 — куда сдвиг */
|
||||
html += `<div class="wg" id="p9-iv3">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">В какую сторону сдвиг?</div></div>
|
||||
<div class="wg-help">Определи направление сдвига графика относительно исходной функции.</div>
|
||||
<div class="score-display">Задача: <b id="p9-iv3-idx">1</b> / 8 · Очки: <b id="p9-iv3-sc">0</b></div>
|
||||
<div id="p9-iv3-q" style="text-align:center;font-size:1.15rem;padding:14px;background:var(--card);border-radius:9px;margin-bottom:12px;min-height:60px"></div>
|
||||
<div class="actions" style="justify-content:center;flex-wrap:wrap">
|
||||
<button class="btn primary" id="p9-iv3-u">Вверх</button>
|
||||
<button class="btn" id="p9-iv3-d">Вниз</button>
|
||||
<button class="btn" id="p9-iv3-r">Вправо</button>
|
||||
<button class="btn" id="p9-iv3-l">Влево</button>
|
||||
</div>
|
||||
<div class="feedback" id="p9-iv3-fb"></div>
|
||||
</div>`;
|
||||
|
||||
/* INTERACTIVE 4 — конструктор формулы */
|
||||
html += `<div class="wg" id="p9-iv4">
|
||||
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Конструктор формулы по графику</div></div>
|
||||
<div class="wg-help">Для каждого описания выбери верную формулу из выпадающего списка. Нажми «Проверить» в конце.</div>
|
||||
<div id="p9-iv4-rows" style="display:flex;flex-direction:column;gap:12px"></div>
|
||||
<div class="actions"><button class="btn primary" id="p9-iv4-check">Проверить</button><button class="btn" id="p9-iv4-reset">Сбросить</button></div>
|
||||
<div class="feedback" id="p9-iv4-fb"></div>
|
||||
</div>`;
|
||||
|
||||
box.innerHTML = html + secNav('p8', 'final2') + readButton('p9');
|
||||
renderMath(box);
|
||||
|
||||
/* ===== IV1 wiring — слайдер сдвигов ===== */
|
||||
(function(){
|
||||
const fns = [
|
||||
{ tex:'x^2', f:x=>x*x, dom:[-6,6] },
|
||||
{ tex:'|x|', f:x=>Math.abs(x), dom:[-6,6] },
|
||||
{ tex:'\\sqrt{x}', f:x=>Math.sqrt(x), dom:[0,6], shiftDom:true },
|
||||
{ tex:'x^3', f:x=>x*x*x, dom:[-6,6] }
|
||||
];
|
||||
const fnSl = document.getElementById('p9-iv1-fn');
|
||||
const aSl = document.getElementById('p9-iv1-a');
|
||||
const bSl = document.getElementById('p9-iv1-b');
|
||||
const fi = document.getElementById('p9-iv1-fi');
|
||||
const av = document.getElementById('p9-iv1-av');
|
||||
const bv = document.getElementById('p9-iv1-bv');
|
||||
const svg = document.getElementById('p9-iv1-svg');
|
||||
const formula = document.getElementById('p9-iv1-formula');
|
||||
const out = document.getElementById('p9-iv1-out');
|
||||
let bumped = false;
|
||||
|
||||
function redraw(){
|
||||
const idx = (+fnSl.value)-1;
|
||||
const a = +aSl.value, b = +bSl.value;
|
||||
const fobj = fns[idx];
|
||||
fi.textContent = (idx+1);
|
||||
av.textContent = a;
|
||||
bv.textContent = b;
|
||||
|
||||
const ax = axes2D(420, 320, 30, -6, 6, -6, 6);
|
||||
let g = ax.content;
|
||||
|
||||
// исходная (серая)
|
||||
g += plotFunc(fobj.f, fobj.dom[0], fobj.dom[1], ax.toX, ax.toY, '#94a3b8', 250);
|
||||
// сдвинутая (синяя) — y = f(x - a) + b
|
||||
const shifted = x => fobj.f(x - a) + b;
|
||||
const xmin2 = fobj.dom[0] + a, xmax2 = fobj.dom[1] + a;
|
||||
g += plotFunc(shifted, Math.max(xmin2,-6), Math.min(xmax2,6), ax.toX, ax.toY, '#2563eb', 280);
|
||||
|
||||
// маркеры начальных точек
|
||||
// исходная: для x^2, |x|, x^3 — это (0;0); для sqrt — тоже (0;0)
|
||||
const ox = 0, oy = fobj.f(0);
|
||||
if (oy>=-6 && oy<=6){
|
||||
const cx = ax.toX(ox), cy = ax.toY(oy);
|
||||
g += '<circle cx="'+cx+'" cy="'+cy+'" r="4" fill="#94a3b8" stroke="#fff" stroke-width="1.5"/>';
|
||||
}
|
||||
// сдвинутая
|
||||
const sx = ox + a, sy = oy + b;
|
||||
if (sx>=-6 && sx<=6 && sy>=-6 && sy<=6){
|
||||
const cx = ax.toX(sx), cy = ax.toY(sy);
|
||||
g += '<circle cx="'+cx+'" cy="'+cy+'" r="5" fill="#2563eb" stroke="#fff" stroke-width="2"/>';
|
||||
// стрелка от (0;0) до (a;b)
|
||||
if (a !== 0 || b !== 0){
|
||||
const sx0 = ax.toX(ox), sy0 = ax.toY(oy);
|
||||
g += '<line x1="'+sx0+'" y1="'+sy0+'" x2="'+cx+'" y2="'+cy+'" stroke="#a855f7" stroke-width="1.6" stroke-dasharray="5 3" marker-end=""/>';
|
||||
}
|
||||
}
|
||||
|
||||
svg.innerHTML = g;
|
||||
|
||||
// формула
|
||||
const aStr = (a >= 0) ? ('- ' + a) : ('+ ' + (-a));
|
||||
const bStr = (b >= 0) ? ('+ ' + b) : ('- ' + (-b));
|
||||
let inner;
|
||||
if (a === 0) inner = fobj.tex;
|
||||
else if (fobj.tex === '\\sqrt{x}') inner = '\\sqrt{x ' + aStr + '}';
|
||||
else if (fobj.tex === '|x|') inner = '|x ' + aStr + '|';
|
||||
else if (fobj.tex === 'x^2') inner = '(x ' + aStr + ')^2';
|
||||
else if (fobj.tex === 'x^3') inner = '(x ' + aStr + ')^3';
|
||||
else inner = fobj.tex;
|
||||
let full = 'y = ' + inner;
|
||||
if (b !== 0) full += ' ' + bStr;
|
||||
formula.innerHTML = '$' + full + '$';
|
||||
|
||||
// направление
|
||||
let dir = [];
|
||||
if (a > 0) dir.push('вправо на ' + a);
|
||||
else if (a < 0) dir.push('влево на ' + (-a));
|
||||
if (b > 0) dir.push('вверх на ' + b);
|
||||
else if (b < 0) dir.push('вниз на ' + (-b));
|
||||
const dirText = dir.length ? 'Сдвиг: ' + dir.join(', ') + '.' : 'Сдвига нет — графики совпадают.';
|
||||
out.innerHTML = dirText;
|
||||
|
||||
renderMath(formula); renderMath(out);
|
||||
if (!bumped){ bumped = true; bumpProgress('p9', 15); addXp(10,'p9-iv1'); }
|
||||
}
|
||||
fnSl.addEventListener('input', redraw);
|
||||
aSl.addEventListener('input', redraw);
|
||||
bSl.addEventListener('input', redraw);
|
||||
redraw();
|
||||
})();
|
||||
|
||||
/* ===== IV2 wiring — вершина параболы ===== */
|
||||
(function(){
|
||||
const items = [
|
||||
{ q:'$y = (x - 2)^2 + 3$', ans:5, hint:'Вершина $(2;\\ 3)$, $a + b = 5$.' },
|
||||
{ q:'$y = (x + 1)^2 - 4$', ans:-5, hint:'Вершина $(-1;\\ -4)$, $a + b = -5$.' },
|
||||
{ q:'$y = (x - 5)^2$', ans:5, hint:'Вершина $(5;\\ 0)$, $a + b = 5$.' },
|
||||
{ q:'$y = x^2 + 7$', ans:7, hint:'Вершина $(0;\\ 7)$, $a + b = 7$.' },
|
||||
{ q:'$y = (x + 3)^2 + 2$', ans:-1, hint:'Вершина $(-3;\\ 2)$, $a + b = -1$.' },
|
||||
{ q:'$y = (x - 4)^2 - 6$', ans:-2, hint:'Вершина $(4;\\ -6)$, $a + b = -2$.' }
|
||||
];
|
||||
let i = 0, sc = 0;
|
||||
const idxEl = document.getElementById('p9-iv2-idx');
|
||||
const scEl = document.getElementById('p9-iv2-sc');
|
||||
const qEl = document.getElementById('p9-iv2-q');
|
||||
const inEl = document.getElementById('p9-iv2-in');
|
||||
const fb = document.getElementById('p9-iv2-fb');
|
||||
const goBtn = document.getElementById('p9-iv2-go');
|
||||
let bumped = false;
|
||||
function render(){
|
||||
idxEl.textContent = Math.min(i+1, items.length);
|
||||
scEl.textContent = sc;
|
||||
if (i >= items.length){
|
||||
qEl.innerHTML = '<b>Готово!</b> Результат: ' + sc + ' / ' + items.length;
|
||||
inEl.disabled = true; goBtn.disabled = true; goBtn.style.opacity = .5;
|
||||
if (!bumped){ bumped = true; bumpProgress('p9', 15); addXp(10,'p9-iv2'); }
|
||||
return;
|
||||
}
|
||||
qEl.innerHTML = items[i].q;
|
||||
inEl.value = '';
|
||||
fb.style.display = 'none';
|
||||
renderMath(qEl);
|
||||
inEl.focus();
|
||||
}
|
||||
function check(){
|
||||
if (i >= items.length) return;
|
||||
const v = +inEl.value;
|
||||
if (!Number.isFinite(v) || inEl.value === ''){ feedback(fb, false, 'Введи число.'); return; }
|
||||
const it = items[i];
|
||||
const ok = (v === it.ans);
|
||||
if (ok) sc++;
|
||||
feedback(fb, ok, (ok?'✓ Верно. ':'✗ Неверно. ') + it.hint);
|
||||
i++;
|
||||
setTimeout(render, 1100);
|
||||
}
|
||||
goBtn.addEventListener('click', check);
|
||||
inEl.addEventListener('keydown', e=>{ if (e.key === 'Enter') check(); });
|
||||
render();
|
||||
})();
|
||||
|
||||
/* ===== IV3 wiring — направление сдвига ===== */
|
||||
(function(){
|
||||
const items = [
|
||||
{ q:'$y = x^2 + 5$', ans:'u', hint:'$b = 5 > 0$ — вверх.' },
|
||||
{ q:'$y = x^2 - 3$', ans:'d', hint:'$b = -3 < 0$ — вниз.' },
|
||||
{ q:'$y = (x - 2)^2$', ans:'r', hint:'$x - 2$ → сдвиг вправо на 2.' },
|
||||
{ q:'$y = (x + 4)^2$', ans:'l', hint:'$x + 4$ → сдвиг влево на 4.' },
|
||||
{ q:'$y = |x| + 1$', ans:'u', hint:'$b = 1 > 0$ — вверх.' },
|
||||
{ q:'$y = |x - 7|$', ans:'r', hint:'$x - 7$ → сдвиг вправо на 7.' },
|
||||
{ q:'$y = \\sqrt{x + 2}$', ans:'l', hint:'$x + 2$ → сдвиг влево на 2.' },
|
||||
{ q:'$y = x^3 - 1$', ans:'d', hint:'$b = -1 < 0$ — вниз.' }
|
||||
];
|
||||
let i = 0, sc = 0;
|
||||
const idxEl = document.getElementById('p9-iv3-idx');
|
||||
const scEl = document.getElementById('p9-iv3-sc');
|
||||
const qEl = document.getElementById('p9-iv3-q');
|
||||
const fb = document.getElementById('p9-iv3-fb');
|
||||
const uBtn = document.getElementById('p9-iv3-u');
|
||||
const dBtn = document.getElementById('p9-iv3-d');
|
||||
const rBtn = document.getElementById('p9-iv3-r');
|
||||
const lBtn = document.getElementById('p9-iv3-l');
|
||||
let bumped = false;
|
||||
function render(){
|
||||
idxEl.textContent = Math.min(i+1, items.length);
|
||||
scEl.textContent = sc;
|
||||
if (i >= items.length){
|
||||
qEl.innerHTML = '<b>Готово!</b> Результат: ' + sc + ' / ' + items.length;
|
||||
[uBtn,dBtn,rBtn,lBtn].forEach(b=>{ b.disabled=true; b.style.opacity=.5; });
|
||||
if (!bumped){ bumped = true; bumpProgress('p9', 25); addXp(15,'p9-iv3'); }
|
||||
return;
|
||||
}
|
||||
qEl.innerHTML = items[i].q;
|
||||
fb.style.display = 'none';
|
||||
renderMath(qEl);
|
||||
}
|
||||
function answer(v){
|
||||
if (i >= items.length) return;
|
||||
const it = items[i];
|
||||
const ok = (v === it.ans);
|
||||
if (ok) sc++;
|
||||
feedback(fb, ok, (ok?'✓ Верно. ':'✗ Неверно. ') + it.hint);
|
||||
i++;
|
||||
setTimeout(render, 900);
|
||||
}
|
||||
uBtn.addEventListener('click', ()=>answer('u'));
|
||||
dBtn.addEventListener('click', ()=>answer('d'));
|
||||
rBtn.addEventListener('click', ()=>answer('r'));
|
||||
lBtn.addEventListener('click', ()=>answer('l'));
|
||||
render();
|
||||
})();
|
||||
|
||||
/* ===== IV4 wiring — конструктор формулы ===== */
|
||||
(function(){
|
||||
const tasks = [
|
||||
{
|
||||
desc: 'Парабола $y = x^2$ сдвинута на 2 <b>влево</b>',
|
||||
opts: [
|
||||
{ v:'a', tex:'y = (x - 2)^2' },
|
||||
{ v:'b', tex:'y = (x + 2)^2' },
|
||||
{ v:'c', tex:'y = x^2 + 2' },
|
||||
{ v:'d', tex:'y = x^2 - 2' }
|
||||
],
|
||||
ans: 'b'
|
||||
},
|
||||
{
|
||||
desc: '$y = |x|$ сдвинута на 4 <b>вверх</b>',
|
||||
opts: [
|
||||
{ v:'a', tex:'y = |x| + 4' },
|
||||
{ v:'b', tex:'y = |x| - 4' },
|
||||
{ v:'c', tex:'y = |x - 4|' },
|
||||
{ v:'d', tex:'y = |x + 4|' }
|
||||
],
|
||||
ans: 'a'
|
||||
},
|
||||
{
|
||||
desc: '$y = \\sqrt{x}$ сдвинута на 1 <b>вниз</b>',
|
||||
opts: [
|
||||
{ v:'a', tex:'y = \\sqrt{x} + 1' },
|
||||
{ v:'b', tex:'y = \\sqrt{x} - 1' },
|
||||
{ v:'c', tex:'y = \\sqrt{x - 1}' },
|
||||
{ v:'d', tex:'y = \\sqrt{x + 1}' }
|
||||
],
|
||||
ans: 'b'
|
||||
},
|
||||
{
|
||||
desc: '$y = x^2$ сдвинута на 3 <b>вправо</b> и 2 <b>вверх</b>',
|
||||
opts: [
|
||||
{ v:'a', tex:'y = (x + 3)^2 + 2' },
|
||||
{ v:'b', tex:'y = (x - 3)^2 - 2' },
|
||||
{ v:'c', tex:'y = (x - 3)^2 + 2' },
|
||||
{ v:'d', tex:'y = (x + 3)^2 - 2' }
|
||||
],
|
||||
ans: 'c'
|
||||
},
|
||||
{
|
||||
desc: '$y = x^3$ сдвинута на 5 <b>влево</b>',
|
||||
opts: [
|
||||
{ v:'a', tex:'y = (x - 5)^3' },
|
||||
{ v:'b', tex:'y = (x + 5)^3' },
|
||||
{ v:'c', tex:'y = x^3 + 5' },
|
||||
{ v:'d', tex:'y = x^3 - 5' }
|
||||
],
|
||||
ans: 'b'
|
||||
},
|
||||
{
|
||||
desc: '$y = |x|$ сдвинута на 1 <b>вправо</b> и 4 <b>вниз</b>',
|
||||
opts: [
|
||||
{ v:'a', tex:'y = |x - 1| - 4' },
|
||||
{ v:'b', tex:'y = |x + 1| - 4' },
|
||||
{ v:'c', tex:'y = |x - 1| + 4' },
|
||||
{ v:'d', tex:'y = |x + 1| + 4' }
|
||||
],
|
||||
ans: 'a'
|
||||
}
|
||||
];
|
||||
const rowsBox = document.getElementById('p9-iv4-rows');
|
||||
let rowsHtml = '';
|
||||
tasks.forEach((t, i)=>{
|
||||
let optsHtml = '<option value="">— выбери —</option>';
|
||||
t.opts.forEach(o=>{ optsHtml += '<option value="'+o.v+'">'+o.tex+'</option>'; });
|
||||
rowsHtml +=
|
||||
'<div style="background:var(--card);padding:10px 12px;border-radius:9px;display:flex;flex-direction:column;gap:8px">' +
|
||||
'<div style="font-size:.98rem"><b>'+(i+1)+'.</b> '+t.desc+'</div>' +
|
||||
'<select id="p9-iv4-s'+i+'" class="tinp" style="min-width:200px">'+optsHtml+'</select>' +
|
||||
'</div>';
|
||||
});
|
||||
rowsBox.innerHTML = rowsHtml;
|
||||
renderMath(rowsBox);
|
||||
let bumped = false;
|
||||
document.getElementById('p9-iv4-check').addEventListener('click', ()=>{
|
||||
const fb = document.getElementById('p9-iv4-fb');
|
||||
let correct = 0, answered = 0;
|
||||
tasks.forEach((t,i)=>{
|
||||
const v = document.getElementById('p9-iv4-s'+i).value;
|
||||
if (v) answered++;
|
||||
if (v === t.ans) correct++;
|
||||
});
|
||||
if (answered < tasks.length){
|
||||
feedback(fb, false, 'Отвечены не все: ' + answered + ' / ' + tasks.length + '.');
|
||||
return;
|
||||
}
|
||||
const ok = (correct === tasks.length);
|
||||
feedback(fb, ok, ok ? '✓ Все верно! ' + correct + ' / ' + tasks.length : '✗ Правильно: ' + correct + ' / ' + tasks.length);
|
||||
if (ok && !bumped){ bumped = true; bumpProgress('p9', 25); addXp(15,'p9-iv4'); }
|
||||
});
|
||||
document.getElementById('p9-iv4-reset').addEventListener('click', ()=>{
|
||||
tasks.forEach((t,i)=>{ document.getElementById('p9-iv4-s'+i).value = ''; });
|
||||
const fb = document.getElementById('p9-iv4-fb'); fb.style.display='none';
|
||||
});
|
||||
})();
|
||||
|
||||
wireReadBtn('p9');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user