feat(math6): Глава 2 — Проценты и пропорции (§1–§9 + финал)

§1 процент наглядно (сетка 100) + конвертер %↔дробь↔десятичная;
§2 три типа задач (классификатор + тренажёр % от числа);
§3 пропорция (найди член крест-накрест + проверка свойства);
§4 прямая/обратная зависимость (классификатор + таблица);
§5 решение пропорцией (прямые и обратные задачи);
§6 масштаб (карта↔местность); §7 круговые диаграммы (Math6.pie +
%↔градусы); §9 прикладной; финал — 5 боссов. Тесты math6: 15/15.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-02 19:58:48 +03:00
parent c5a7803e34
commit a7835659d5
3 changed files with 545 additions and 0 deletions
+24
View File
@@ -153,4 +153,28 @@ M.plane = function (opts) {
return M.box(S, S, s, { maxw: opts.maxw || S, bg: opts.bg });
};
/* === КРУГОВАЯ ДИАГРАММА ===
* segs: [{value,label,color}]. opts: {size, r}. Возвращает boxed SVG (проценты в секторах).
*/
M.pie = function (segs, opts) {
opts = opts || {};
var S = opts.size || 220, cx = S / 2, cy = S / 2, r = opts.r || (S / 2 - 8);
var total = segs.reduce(function (a, s) { return a + s.value; }, 0) || 1;
var palette = ['#4f46e5', '#0891b2', '#e11d48', '#059669', '#d97706', '#7c3aed', '#db2777'];
var ang = -Math.PI / 2, s = '';
segs.forEach(function (seg, i) {
var frac = seg.value / total, a2 = ang + frac * 2 * Math.PI;
var col = seg.color || palette[i % palette.length];
if (frac >= 0.999) { s += '<circle cx="' + cx + '" cy="' + cy + '" r="' + r + '" fill="' + col + '"/>'; }
else {
var x1 = cx + r * Math.cos(ang), y1 = cy + r * Math.sin(ang), x2 = cx + r * Math.cos(a2), y2 = cy + r * Math.sin(a2), large = frac > 0.5 ? 1 : 0;
s += '<path d="M ' + cx + ' ' + cy + ' L ' + x1 + ' ' + y1 + ' A ' + r + ' ' + r + ' 0 ' + large + ' 1 ' + x2 + ' ' + y2 + ' Z" fill="' + col + '" stroke="var(--card,#fff)" stroke-width="1.5"/>';
}
var mid = ang + frac * Math.PI, lx = cx + r * 0.62 * Math.cos(mid), ly = cy + r * 0.62 * Math.sin(mid);
if (frac > 0.05) s += '<text x="' + lx + '" y="' + (ly + 4) + '" text-anchor="middle" font-size="12" font-weight="700" fill="#fff">' + Math.round(frac * 100) + '%</text>';
ang = a2;
});
return M.box(S, S, s, { maxw: opts.maxw || S });
};
})();