Mundarija (29)
- Bu darsda
- 1. Nega bu kerak?
- 2. Recharts g'oyasi: grafik — komponentlar
- 2.1 Ma'lumot va dataKey
- 2.2 Birinchi grafik: BarChart
- 2.3 Ichida nima bor
- 3. Grafik turlari
- 3.1 LineChart va AreaChart — vaqt bo'yicha o'zgarish
- 3.2 PieChart — ulush
- 3.3 Qachon qaysi biri
- 4. Tooltip, Legend va formatlash
- 4.1 Sonni formatlash: Intl'siz
- 4.2 O'z tooltip'ingiz va klaviatura
- 5. O'lcham: ResponsiveContainer va responsive
- 6. shadcn Charts
- 7. Grafik va accessibility
- 8. Vazifalar qadami: teglar grafigi (holat 04)
- 8.1 Avval — Recharts bilan o'lchov
- 8.2 Qaror: o'z SVG grafigi
- 8.3 Natija va narx
- 9. Ko'p uchraydigan xatolar
- 10. Mashqlar
- 1-mashq (oson): qaysi grafik, qaysi prop?
- 2-mashq (o'rta): osh va manti yonma-yon
- 3-mashq (qiyin): doira va uning matn muqobili
- 4-mashq: Vazifalar qadami
- 11. Real ishda
- Xulosa
- Manbalar
Recharts bilan React grafiklari: ustun, chiziq, maydon va doira diagrammalari
Qisqacha: Recharts — React komponentlaridan grafik yig'adigan kutubxona:
<BarChart data={…}>ichiga<XAxis>,<YAxis>,<Tooltip>va<Bar dataKey="osh">qo'yasiz — natija SVG. Ma'lumot oddiy obyektlar massivi,dataKeyesa qaysi maydon chizilishini aytadi. Tooltip, Legend, o'qlar formatlash va klaviatura bilan yurish tayyor keladi. Narxi bor:vazifalarda bitta grafik uchun +103.4 KB gzip va qattiq tsconfig'da 12 ta tsc xatosi. Shuning uchun kanon oxirida o'z SVG grafigini (+0.3 KB) tanladi.
Bu darsda
BarChart,LineChart,AreaChartvaPieChartni ma'lumot massividan chizasiz.Tooltip,Legend,tickFormatterbilan grafikni o'qiladigan qilasiz va o'z tooltip komponentingizni yozasiz.ResponsiveContainervaresponsivebilan grafikni konteyner eniga moslaysiz.- shadcn Charts nima ekanini va grafikning a11y talablarini bilasiz.
- Kutubxona narxini o'lchab, qachon o'z SVG grafigi yaxshiroq ekanini asoslaysiz.
Oldin bilishingiz kerak: i18n II: o'zbek lotin/kirill, URL va type-safe kalitlar, Jadvallar I: TanStack Table asoslari, shadcn/ui II: real ilovada asosiy komponentlar, lazy va code splitting, React'da accessibility asoslari.
1. Nega bu kerak?
Jasur aka «Bahor» admin panelini ochdi: «Haftada qaysi kuni ko'p osh sotdik?». Jadvalda raqamlar bor — 32, 41, 28, 45, 60. Lekin ko'z jadvaldan "juma — eng ko'p" degan xulosani darhol chiqara olmaydi. Ustunli grafikda esa eng baland ustun birinchi qarashda ko'rinadi.
Grafikni o'zingiz chizish mumkin: SVG'da har ustun — <rect>, balandligi qiymatga mutanosib. Lekin o'qlar, chiziqlar, sichqoncha ustiga kelganda chiqadigan izoh, ranglar izohi, eni o'zgarganda qayta hisoblash — har biri o'nlab qator kod. Recharts shularni tayyor komponentlar qilib beradi.
Hayotiy o'xshatish: Lego. Har bo'lak alohida: asos (BarChart), o'qlar, izoh, ustunlar. Kerakligini olib, bir-biriga ulaysiz. Keraksizini qo'ymaysiz.
Oldingi darsda statistika sahifasi to'rt tilda gapira boshladi. Bugun unga teglar grafigi qo'shamiz. Avval Recharts'ni o'rganamiz, keyin vazifalar da uni o'lchab ko'ramiz — va kutilmagan qarorga kelamiz.
2. Recharts g'oyasi: grafik — komponentlar
2.1 Ma'lumot va dataKey
Recharts ma'lumotni obyektlar massivi ko'rinishida oladi. Har obyekt — bitta nuqta (ustun, chiziq nuqtasi):
const sotuv = [
{ kun: "Du", osh: 32 },
{ kun: "Se", osh: 41 },
];Qaysi maydon nima bo'lishini dataKey aytadi: <XAxis dataKey="kun" /> — gorizontal o'qda kunlar, <Bar dataKey="osh" /> — ustun balandligi osh soni. Grafik ichidagi qismlar qanday bog'langan:
flowchart TB
D["data: [{kun, osh}, …]"] --> C["BarChart (o'lcham, ma'lumot)"]
C --> X["XAxis dataKey=kun"]
C --> Y["YAxis (son o'qi)"]
C --> G["CartesianGrid (to'r)"]
C --> T["Tooltip (izoh)"]
C --> L["Legend (ranglar izohi)"]
C --> B["Bar dataKey=osh"]
B --> S["SVG: rect, text, path"]Diagrammaga qarang: ma'lumot faqat tepada, BarChart ga beriladi. Ichki komponentlar uni Context orqali oladi — bu compound komponent naqshi. Shuning uchun tartibni o'zgartirish yoki bitta qismni olib tashlash oson: <Tooltip /> ni o'chirsangiz, faqat izoh yo'qoladi.
2.2 Birinchi grafik: BarChart
Ustunli diagramma (bar chart) — har qiymat bitta ustun, balandligi qiymatga mutanosib. Turli toifalarni (kunlar, taomlar) solishtirish uchun eng tushunarli grafik.
import { BarChart, Bar, XAxis, YAxis, Tooltip } from "recharts";
const sotuv = [
{ kun: "Du", osh: 32 },
{ kun: "Se", osh: 41 },
{ kun: "Ch", osh: 28 },
{ kun: "Pa", osh: 45 },
{ kun: "Ju", osh: 60 },
];
export default function App() {
return (
<BarChart width={340} height={220} data={sotuv}>
<XAxis dataKey="kun" />
<YAxis />
<Tooltip />
<Bar
dataKey="osh"
name="Osh (porsiya)"
fill="#1f6f4a"
onClick={(ustun) => console.log(ustun.payload)}
/>
</BarChart>
);
}Konsolda (birinchi ustun bosildi):
{kun: 'Du', osh: 32}«Ishga tushir» ni bosing: beshta yashil ustun, pastda kunlar, chapda 0 dan 60 gacha son o'qi. Juma ustuni eng baland. Sichqonchani ustun ustiga olib boring — Tooltip chiqadi: «Ju», «Osh (porsiya) : 60». Ustunni bossangiz, konsolda o'sha kunning asl obyekti chiqadi (payload). Undan foydalanib, masalan, o'sha kunning buyurtmalar sahifasiga o'tish mumkin.
Kodda uchta muhim narsa:
widthvaheight— piksel. Grafik o'z o'lchamini bilishi shart, aks holda o'qlarni hisoblay olmaydi. Konteyner eniga moslash — «O'lcham» bo'limida.name— Tooltip va Legend'dagi nom. Bo'lmasadataKeyning o'zi chiqadi (osh).- Animatsiya — ustunlar pastdan o'sib chiqadi. Recharts 3 da
isAnimationActivesukut bo'yicha"auto": foydalanuvchi tizimda "harakatni kamaytirish" (prefers-reduced-motion) ni yoqqan bo'lsa, animatsiya o'chadi. Buni Recharts manba kodidan tekshirdik (usePrefersReducedMotion).
Diqqat: Saytdagi natija oynasi Recharts'ni birinchi marta ishga tushirganda ~1 MB lik to'plamni yuklaydi (gzip ~230 KB, development build — o'lchandi). Sekin internetda bir necha soniya kuting. Bu — kutubxona og'irligining birinchi belgisi; quyida haqiqiy ilovada o'lchaymiz.
2.3 Ichida nima bor
Grafik — oddiy SVG va bir nechta div. Natija oynasida DevTools'ni ochsangiz (yoki tekshiruvchimiz jsdom'da ko'rganidek), Recharts 3.10.1 shuni chizadi:
| Element | Vazifasi |
|---|---|
div.recharts-wrapper |
o'lchamli o'ram, position: relative |
svg role="application" tabindex="0" |
grafikning o'zi, klaviatura bilan fokuslanadi |
div.recharts-tooltip-wrapper |
izoh: role="status", aria-live="assertive" |
ul.recharts-default-legend |
ranglar izohi (Legend bo'lsa) |
tabindex="0" va role="application" — Recharts 3 dagi accessibilityLayer, sukut bo'yicha yoqilgan. Bobur (faqat klaviatura) Tab bilan grafikka kiradi va strelkalar bilan ustundan ustunga yuradi — Tooltip shu ustun uchun chiqadi. Buni «Tooltip» bo'limida jonli ko'ramiz.
Tekshirib ko'ring:
<Bar dataKey="Osh" />deb yozildi (katta harf bilan). Nima bo'ladi?
Javob
Xato chiqmaydi, lekin ustunlar ham chiqmaydi — grafik bo'sh. Obyektlarda Osh maydoni yo'q, Recharts har nuqta uchun undefined oladi va hech narsa chizmaydi. JS obyekt kalitlari katta-kichik harfni farqlaydi. Bu jim xato: grafik "ishlayapti", faqat bo'm-bo'sh. Davosi — dataKey ni ma'lumotdagi kalit bilan solishtirish; TypeScript'da ma'lumot turini bersangiz, muharrir yordam beradi.
3. Grafik turlari
3.1 LineChart va AreaChart — vaqt bo'yicha o'zgarish
Chiziqli diagramma (line chart) — nuqtalar chiziq bilan ulanadi. Vaqt bo'yicha o'zgarishni ko'rsatadi: kunlar, oylar. Bir nechta <Line> — bir nechta seriya (osh va manti) bitta grafikda:
import {
LineChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
} from "recharts";
const hafta = [
{ kun: "Du", osh: 32, manti: 20 },
{ kun: "Se", osh: 41, manti: 18 },
{ kun: "Ch", osh: 28, manti: 25 },
{ kun: "Pa", osh: 45, manti: 22 },
];
export default function App() {
return (
<LineChart width={340} height={220} data={hafta}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="kun" />
<YAxis />
<Tooltip />
<Legend />
<Line dataKey="osh" name="Osh" stroke="#1f6f4a" />
<Line dataKey="manti" name="Manti" stroke="#b45309" />
</LineChart>
);
}CartesianGrid — fondagi to'r; strokeDasharray="3 3" uni uzuq chiziqqa aylantiradi. Ikki seriya — ikki rang, Legend ularni nomlaydi.
Maydonli diagramma (area chart) — chiziq ostini bo'yaydi. stackId bir xil bo'lsa, maydonlar ustma-ust qo'shiladi: tepasi — jami sotuv. Kod xuddi shunday, faqat Line → Area:
import { AreaChart, Area, XAxis, YAxis, Tooltip } from "recharts";
const hafta = [
{ kun: "Du", osh: 32, manti: 20 },
{ kun: "Se", osh: 41, manti: 18 },
{ kun: "Ch", osh: 28, manti: 25 },
];
export default function App() {
return (
<AreaChart width={340} height={220} data={hafta}>
<XAxis dataKey="kun" />
<YAxis />
<Tooltip />
<Area dataKey="osh" stackId="1" fill="#1f6f4a" />
<Area dataKey="manti" stackId="1" fill="#b45309" />
</AreaChart>
);
}Xuddi shu stackId Bar da ham ishlaydi — ustunlar ustma-ust "yig'iladi" (stacked bar). vazifalar dagi teglar grafigi aynan shunday: har teg uchun "bajarildi" va "qolgan".
3.2 PieChart — ulush
Doiraviy diagramma (pie chart) — butunning qismlari. «Bugun sotilgan taomlarning qancha qismi osh?» Har bo'lak rangini Cell beradi:
import { PieChart, Pie, Cell } from "recharts";
const ulush = [
{ nom: "Osh", soni: 42 },
{ nom: "Manti", soni: 25 },
{ nom: "Lag'mon", soni: 18 },
];
const RANGLAR = ["#1f6f4a", "#b45309", "#1d4ed8"];
export default function App() {
return (
<PieChart width={300} height={240}>
<Pie
data={ulush}
dataKey="soni"
nameKey="nom"
label
onClick={(b) => {
const foiz = Math.round(b.percent * 100);
console.log(b.nom, b.soni, `${foiz}%`);
}}
>
{ulush.map((b, i) => (
<Cell key={b.nom} fill={RANGLAR[i]} />
))}
</Pie>
</PieChart>
);
}Konsolda (birinchi bo'lak bosildi):
Osh 42 49%percent ni Recharts o'zi hisoblaydi: 42 / (42 + 25 + 18) ≈ 0.494. label — har bo'lak yonida qiymat.
3.3 Qachon qaysi biri
| Savol | Grafik |
|---|---|
| Qaysi toifa ko'p? (kunlar, taomlar) | BarChart |
| Vaqt bo'yicha qanday o'zgardi? | LineChart |
| Jami va uning tarkibi vaqt bo'yicha | AreaChart (stackId) |
| Butunning qismlari (3–5 bo'lak) | PieChart |
Doiraviy diagramma bilan ehtiyot bo'ling. Ko'z burchaklarni uzunlikdan yomonroq solishtiradi: 25 va 18 lik bo'laklar farqi doirada qiyin ko'rinadi, ustunda — aniq. Bo'lak beshtadan oshsa, ustunli grafik tanlang.
Tekshirib ko'ring: «Bahor» filiallari (Chilonzor, Yunusobod, Sergeli) bo'yicha oylik tushum 12 oy davomida. Qaysi grafik?
Javob
LineChart, uchta <Line> — har filial bitta chiziq. Savol "vaqt bo'yicha qanday o'zgardi" va filiallarni solishtirish. 12 nuqtali uchta chiziq bitta grafikda o'qiladi. BarChart da 36 ustun bo'lardi — tartibsiz. PieChart esa vaqtni umuman ko'rsatmaydi.
4. Tooltip, Legend va formatlash
4.1 Sonni formatlash: Intl'siz
Tooltip'da «60» emas, «2 100 000 so'm» chiqishi kerak. Oldingi darsdagi tuzoqni eslang: Chrome'da Intl.NumberFormat("uz") «35,000» chiqaradi, Node'da «35 000». O'zbekcha uchun o'z funksiyamiz:
function som(son) {
const guruhlar = String(son).replace(/\B(?=(\d{3})+(?!\d))/g, " ");
return `${guruhlar} so'm`;
}
console.log(som(35000)); // 35 000 so'm
console.log(som(2100000)); // 2 100 000 so'm
console.log(som(500)); // 500 so'mMuntazam ifoda har uch raqamli guruh oldiga bo'sh joy qo'yadi (Lookahead va lookbehind). Natija har brauzerda bir xil.
Recharts'da formatlash uchta joyda:
| Prop | Qayerda | Misol |
|---|---|---|
tickFormatter |
XAxis/YAxis — o'q yozuvlari |
(v) => \${v} ta`` |
formatter |
Tooltip, Legend — qiymat |
(v) => som(v) |
labelFormatter |
Tooltip — sarlavha |
(kun) => \Kun: ${kun}`` |
4.2 O'z tooltip'ingiz va klaviatura
Standart Tooltip «Osh : 32» ko'rinishida. O'zimiz chizmoqchi bo'lsak — content ga komponent beramiz. Recharts unga active (ko'rinadimi), payload (shu nuqtadagi seriyalar) va label (o'q qiymati) props'ini uzatadi.
Quyidagi misolni klaviatura bilan yuramiz: Tab — grafikka fokus, keyin → →. Har o'zgarishda tooltip matnini konsolga ham yozamiz — Bobur nimani "ko'rishini" kuzatish uchun:
import { useEffect } from "react";
import { LineChart, Line, XAxis, YAxis, Tooltip } from "recharts";
const NARX = { osh: 35000, manti: 30000 };
const hafta = [
{ kun: "Du", osh: 32, manti: 20 },
{ kun: "Se", osh: 41, manti: 18 },
{ kun: "Ch", osh: 28, manti: 25 },
];
function som(son) {
const guruhlar = String(son).replace(/\B(?=(\d{3})+(?!\d))/g, " ");
return `${guruhlar} so'm`;
}
function SavdoTooltip({ active, payload, label }) {
const qatorlar = active && payload?.length
? payload.map((q) => {
const tushum = som(q.value * NARX[q.dataKey]);
return `${q.name} ${tushum}`;
})
: [];
const matn = qatorlar.length
? `${label}: ${qatorlar.join(", ")}`
: "";
useEffect(() => {
if (matn) console.log(matn);
}, [matn]);
return matn ? <p className="savdo-tooltip">{matn}</p> : null;
}
export default function App() {
return (
<LineChart width={340} height={220} data={hafta}>
<XAxis dataKey="kun" />
<YAxis tickFormatter={(v) => `${v} ta`} />
<Tooltip content={<SavdoTooltip />} />
<Line dataKey="osh" name="Osh" stroke="#1f6f4a" />
<Line dataKey="manti" name="Manti" stroke="#b45309" />
</LineChart>
);
}Konsolda (Tab, →, →):
Du: Osh 1 120 000 so'm, Manti 600 000 so'm
Se: Osh 1 435 000 so'm, Manti 540 000 so'm
Ch: Osh 980 000 so'm, Manti 750 000 so'mUch qadam — uch kun. Tab grafikka kirdi va birinchi nuqtani faollashtirdi, har → keyingisiga o'tdi. Bu klaviatura yo'lini biz yozmadik — accessibilityLayer ning ishi. content={<SavdoTooltip />} — element beriladi: Recharts unga props qo'shib, oddiy komponent kabi chizadi, ichida hook (useEffect) ham ishlaydi. Real loyihada konsol qatori kerak emas — u faqat kuzatish uchun.
Chap o'qdagi «20 ta», «40 ta» — tickFormatter. Tooltip'da q.name («Osh») — <Line name> dan, q.dataKey («osh») — narxni topish uchun.
Maslahat:
Legendbandlarini Recharts 3 sukut bo'yicha nomi bo'yicha alifbo tartibida chizadi (itemSorter: "value"— manba kodida tekshirdik). «Osh, Manti» emas, «Manti, Osh» chiqsa — sabab shu. O'z tartibingiz kerak bo'lsa:<Legend itemSorter={null} />.
5. O'lcham: ResponsiveContainer va responsive
width={340} telefonda sig'adi, kompyuterda esa mitti. Grafik konteyner eniga moslashishi kerak. Buning ikki yo'li bor:
ResponsiveContainer— klassik o'ram: ota-elementning o'lchamini kuzatadi (ResizeObserver) va grafikka beradi.responsiveprop (Recharts 3.3 dan) — o'ramsiz: grafikning o'ziga CSS bilan o'lcham berasiz (width: 100%,aspectRatio).
Bu blok faqat saytda ishlaydi. Tekshiruvchimiz jsdom'da ishlaydi, u yerda sahifa joylashuvi (layout) hisoblanmaydi — har element eni 0. «Ishga tushir» ni bosib, brauzer oynasini toraytirib ko'ring:
import {
ResponsiveContainer,
BarChart,
Bar,
XAxis,
YAxis,
} from "recharts";
const sotuv = [
{ kun: "Du", osh: 32 },
{ kun: "Se", osh: 41 },
{ kun: "Ju", osh: 60 },
];
export default function App() {
return (
<>
<div style={{ width: "100%", height: 200 }}>
<ResponsiveContainer>
<BarChart data={sotuv}>
<XAxis dataKey="kun" />
<YAxis />
<Bar dataKey="osh" fill="#1f6f4a" />
</BarChart>
</ResponsiveContainer>
</div>
<BarChart
responsive
data={sotuv}
style={{ width: "100%", maxWidth: 480, aspectRatio: 1.6 }}
>
<XAxis dataKey="kun" />
<Bar dataKey="osh" fill="#b45309" />
</BarChart>
</>
);
}Ikkala grafik oyna eniga cho'ziladi. Birinchisi — balandligi 200 px, ikkinchisi — eniga nisbatan (aspectRatio: 1.6).
Eng ko'p uchraydigan xato: ResponsiveContainer ning ota-elementida balandlik yo'q. height: 100% "nimaning 100%?" — ota balandligi 0 bo'lsa, grafik ham 0. Recharts konsolga ogohlantirish yozadi. Uning haqiqiy matni (jsdom'da olindi — u yerda hamma o'lcham 0):
The width(0) and height(0) of chart should be greater than 0,
please check the style of container, or the props width(100%) and height(100%),
or add a minWidth(0) or minHeight(undefined) or use aspect(undefined) to control the
height and width.Tarjimasi: "Grafik eni va balandligi 0 dan katta bo'lishi kerak. Konteyner stilini yoki width/height props'ini tekshiring, yoki minWidth, minHeight, aspect qo'shing". Davosi — ota-elementga aniq balandlik (height: 200px) yoki aspect.
6. shadcn Charts
shadcn/ui II darsida aytganimizdek, shadcn'ning Chart komponenti — Recharts ustidagi ingichka qatlam. Grafikni Recharts'ning o'zi chizadi, shadcn uchta narsa qo'shadi:
const chartConfig = {
osh: { label: "Osh", color: "var(--chart-1)" },
manti: { label: "Manti", color: "var(--chart-2)" },
} satisfies ChartConfig;
<ChartContainer config={chartConfig} className="min-h-50 w-full">
<BarChart accessibilityLayer data={hafta}>
<CartesianGrid vertical={false} />
<XAxis dataKey="kun" tickLine={false} />
<ChartTooltip content={<ChartTooltipContent />} />
<ChartLegend content={<ChartLegendContent />} />
<Bar dataKey="osh" fill="var(--color-osh)" radius={4} />
<Bar dataKey="manti" fill="var(--color-manti)" radius={4} />
</BarChart>
</ChartContainer>ChartConfig— har seriya nomi va rangi bitta joyda.colorCSS o'zgaruvchisiga aylanadi:--color-osh. Tema tokenlari bilan ishlaydi — qorong'i temada rang o'zi almashadi.ChartContainer—ResponsiveContainero'rami + o'sha CSS o'zgaruvchilari.ChartTooltipContent,ChartLegendContent— Tailwind bilan bezalgan tayyor tooltip va legend.
Ikki halol eslatma. Birinchisi — versiya: shadcn reyestri chart uchun recharts@3.8.0 ni yozadi, kanon tajribasida 3.10.1 o'lchangan. CLI ishlatsangiz, qaysi versiya o'rnatilganini tekshiring (shadcn/ui I qoidasi). Ikkinchisi — xavfsizlik siyosati: chart.tsx dagi ChartStyle sahifaga o'z <style> tegini yozadi. vazifalar ning CSP'si bunday tegni to'sadi — Radix chuqur darsidagi saboq. Recharts'ning o'zi esa CSP ostida toza: kanon tajribasida 0 buzilish.
7. Grafik va accessibility
Malika grafikni ko'rmaydi. Unga nima beramiz?
- Matn muqobili. Eng ishonchli yo'l — o'sha raqamlar jadvalda (Jadvallar I). Kanon shunday qildi: grafik
aria-hidden="true", ekran o'quvchi yonidagiTeglarJadvalini o'qiydi. - Faqat rang emas. Ikki seriya faqat rang bilan farqlansa, ranglarni ajrata olmaydigan odam ularni adashtiradi. Legend, yozuv yoki shakl (uzuq chiziq) qo'shing.
- Kontrast. Grafik elementlari fonga nisbatan kamida 3:1 (WCAG 1.4.11). Kanon "qolgan" qism uchun
--color-chegarani sinab ko'rdi — 1.4:1, o'tmadi;--color-ikkinchiolindi. - Harakat.
prefers-reduced-motion— Recharts"auto"bilan o'zi hurmat qiladi; o'z animatsiyangizda — o'zingiz (UI animatsiya tamoyillari).
accessibilityLayer yaxshi qadam: klaviatura bilan yurish va aria-live tooltip. Lekin ekran o'quvchi grafik ichidagi o'q yozuvlarini (0, 15, 30…) ham birma-bir o'qishi mumkin. Shuning uchun jadval baribir kerak.
Tekshirib ko'ring: Nega kanon grafikka
aria-label="Teglar grafigi"qo'yib qo'ya qolmadi,aria-hiddenqildi?
Javob
aria-label faqat nom beradi — "Teglar grafigi". Malika grafik borligini biladi, lekin raqamlarni bilmaydi. Raqamlar esa yonidagi jadvalda allaqachon bor. Grafikni yashirish takrorni oldini oladi: ekran o'quvchi bir xil ma'lumotni ikki marta (grafik va jadval) o'qimaydi. Ko'radigan foydalanuvchi uchun grafik, ko'rmaydigan uchun jadval — har biri o'z vazifasini qiladi.
8. Vazifalar qadami: teglar grafigi (holat 04)
8.1 Avval — Recharts bilan o'lchov
Statistika panelida teglar jadvali bor (Jadvallar I). Endi o'sha raqamlar grafikda: har teg — gorizontal ustun, "bajarildi" va "qolgan" ustma-ust. Kanon avval Recharts 3.10.1 bilan yozdi (tajriba varianti, asosiy qismi):
export default function TeglarGrafigi({ teglar }: Props) {
const malumot = teglar.slice(0, ENG_KOPI).map((t) => ({
teg: t.teg,
bajarildi: t.bajarildi,
qolgan: t.jami - t.bajarildi,
}));
return (
<figure id="teglar-grafigi">
{/* responsive (Recharts 3.3+): kenglik — ota elementdan,
ResponsiveContainer o'rami kerak emas */}
<BarChart
responsive
data={malumot}
style={{ width: "100%", maxWidth: "36rem", aspectRatio: 1.6 }}
margin={{ top: 8, right: 8, bottom: 0, left: 0 }}
>
<CartesianGrid vertical={false} />
<XAxis dataKey="teg" />
<YAxis allowDecimals={false} width={32} />
<Tooltip />
<Legend />
<Bar
dataKey="bajarildi"
name="Bajarildi"
stackId="hammasi"
className="grafik-bajarildi"
isAnimationActive={false}
/>
<Bar
dataKey="qolgan"
name="Qolgan"
stackId="hammasi"
className="grafik-qolgan"
isAnimationActive={false}
/>
</BarChart>
<figcaption>Teglar: bajarilgan va qolgan vazifalar</figcaption>
</figure>
);
}Hammasi tanish: stackId, name, responsive, allowDecimals={false} (vazifa soni butun — o'qda «1.5» chiqmasin). Grafik BatafsilStatistika ichida, alohida chunk bo'lib kech yuklanadi. O'rnatish va o'lchov (kanon, 04-recharts/olchov.txt):
npm i -E recharts@3.10.1 react-is@19.3.0Natija ikki muammo berdi. Birinchisi — hajm: bitta grafik chunk'i 103.4 KB gzip (xom 362 KB). npm 35 ta paket qo'shdi, ular orasida @reduxjs/toolkit, immer, reselect. Recharts 3 ichki holatini Redux bilan boshqaradi — butun Redux ilovaga keladi.
Ikkinchisi — turlar. tsc -b (TypeScript 7.0.2) 12 ta xato berdi (6 xil, har biri ikki marta). Hammasi kutubxonaning tur faylida, birinchi uchtasi:
node_modules/@reduxjs/toolkit/dist/index.d.mts(994,146): error TS2344: Type '{ [K in keyof (ThunkApiConfig & Omit<CurriedThunkApiConfig, keyof ThunkApiConfig>)]: (ThunkApiConfig & Omit<...>)[K]; }' do
node_modules/@reduxjs/toolkit/dist/index.d.mts(1690,99): error TS2344: Type '{ [K in keyof (ThunkApiConfig & Omit<CurriedThunkApiConfig, keyof ThunkApiConfig>)]: (ThunkApiConfig & Omit<...>)[K]; }' do
node_modules/@reduxjs/toolkit/dist/index.d.mts(2064,15): error TS2420: Class 'TaskAbortError' incorrectly implements interface 'SerializedError'.(Qatorlar o'lchov faylida shunday kesilgan.) Oxirgisining tarjimasi: "TaskAbortError klassi SerializedError interfeysini noto'g'ri amalga oshiradi". Sabab — kanonning qattiq tsconfig'i: exactOptionalPropertyTypes: true (Strict bayroqlar oilasi). Bu bayroq x?: string ga undefined ni ochiq yozishni taqiqlaydi. Redux turlari bunga tayyor emas. Kanon tekshirdi: bayroq false bo'lsa — 0 xato.
Ikki yo'l bor edi, ikkalasi ham kanonni susaytiradi:
skipLibCheck: true—node_modulesdagi hamma tur fayllari tekshirilmaydi. Ko'p loyihalarda shunday (darsdagi tekshiruvchimiz ham shunday ishlaydi, shuning uchun bu xatolarni yuqoridagi bloklarda ko'rmadingiz).- Bayroqni o'chirish — o'z kodimizdagi himoyadan voz kechish.
8.2 Qaror: o'z SVG grafigi
Kanon qarori: Recharts kirmaydi. Bitta oddiy grafik — 8 ta gorizontal ustun — uchun 103 KB va tsconfig'ni bo'shatish qimmat. O'rniga TeglarGrafigi.tsx — 77 qatorlik (izohlari bilan) o'z SVG komponenti. Uning g'oyasi:
- har teg — bitta
<g>qator: chapda teg nomi (<text>), keyin ikki<rect>(bajarildi + qolgan), oxirida «2/3»; masshtab = (ENI - YORLIQ - 32) / engKatta— eng uzun ustun mavjud joyni to'ldiradi;viewBox— SVG o'zi eniga moslashadi (inline-size: 100%),ResizeObserverkerak emas;- ranglar — CSS tokenlaridan (
fill: var(--color-asosiy)), qorong'i temada o'zi almashadi; aria-hidden="true"— matn muqobili jadvalda.
Kanon komponenti — kod aynan, faqat tur va ma'lumot shu blokka ko'chirilgan. Ranglar va CSS natija oynasi uchun soddalashtirilgan (kanonda — tokenlar, asos.css):
type TegHisobi = {
readonly teg: string;
readonly jami: number;
readonly bajarildi: number;
};
type Props = {
teglar: readonly TegHisobi[];
};
/** Grafikda eng ko'p 8 ta teg (jadvaldagi tartibda) */
const ENG_KOPI = 8;
const QATOR = 28; // bitta ustun balandligi + oraliq (px, viewBox)
const YORLIQ = 96; // chapdagi teg nomi uchun joy
const ENI = 360;
export function TeglarGrafigi({ teglar }: Props) {
const qatorlar = teglar.slice(0, ENG_KOPI);
const engKatta = Math.max(1, ...qatorlar.map((t) => t.jami));
const masshtab = (ENI - YORLIQ - 32) / engKatta;
const balandlik = qatorlar.length * QATOR;
return (
<figure id="teglar-grafigi">
<svg
viewBox={`0 0 ${ENI} ${balandlik}`}
aria-hidden="true"
focusable="false"
>
{qatorlar.map((t, i) => {
const y = i * QATOR;
const bajarildi = t.bajarildi * masshtab;
const qolgan = (t.jami - t.bajarildi) * masshtab;
return (
<g key={t.teg} transform={`translate(0 ${y})`}>
<text
x={YORLIQ - 6}
y={QATOR / 2}
className="grafik-yorliq"
>
{t.teg}
</text>
<rect
x={YORLIQ}
y={4}
width={bajarildi}
height={QATOR - 8}
className="grafik-bajarildi"
/>
<rect
x={YORLIQ + bajarildi}
y={4}
width={qolgan}
height={QATOR - 8}
className="grafik-qolgan"
/>
<text
x={YORLIQ + bajarildi + qolgan + 4}
y={QATOR / 2}
className="grafik-son"
>
{`${t.bajarildi}/${t.jami}`}
</text>
</g>
);
})}
</svg>
<figcaption>
<span className="belgi-bajarildi" /> bajarildi,{" "}
<span className="belgi-qolgan" /> qolgan (son — bajarildi/jami)
</figcaption>
</figure>
);
}
const css = `
#teglar-grafigi { max-inline-size: 36rem; margin: 0; }
#teglar-grafigi svg { display: block; inline-size: 100%; }
#teglar-grafigi text {
font-size: 12px; dominant-baseline: central;
}
.grafik-yorliq { text-anchor: end; }
.grafik-bajarildi { fill: #1f6f4a; }
.grafik-qolgan { fill: #6b7280; }
figcaption span {
display: inline-block; inline-size: .75em; block-size: .75em;
}
.belgi-bajarildi { background: #1f6f4a; }
.belgi-qolgan { background: #6b7280; }
`;
export default function App() {
return (
<>
<style>{css}</style>
<TeglarGrafigi
teglar={[
{ teg: "#bozor", jami: 3, bajarildi: 2 },
{ teg: "#uy", jami: 2, bajarildi: 0 },
{ teg: "#maktab", jami: 1, bajarildi: 1 },
]}
/>
</>
);
}«Ishga tushir» — uch qator: «#bozor» uzun ustun (ikki yashil ulush + bir kulrang), «#uy» butunlay kulrang, «#maktab» qisqa yashil. Ustun uzunligi jami ga mutanosib, eng kattasi (3) joyni to'ldiradi. Tooltip, o'qlar va animatsiya yo'q — ular bu yerda kerak emas: son har qator oxirida yozilgan. Bitta mustaqil fayl, bog'liqliksiz.
8.3 Natija va narx
git switch -c feat/teglar-grafigiBatafsilStatistika.tsx ga ikki qator (kanon):
import { TeglarJadvali } from "./TeglarJadvali.tsx";
+import { TeglarGrafigi } from "./TeglarGrafigi.tsx";
...
{s.teglar.length > 0 && <TeglarJadvali teglar={s.teglar} />}
+ {/* 21/#04: o'sha raqamlar grafikda (o'z SVG —
+ TeglarGrafigi.tsx) */}
+ {s.teglar.length > 0 && <TeglarGrafigi teglar={s.teglar} />}Va asos.css ga 15 qator (ranglar tokenlardan). Tekshiruvlar (haqiqiy, holat 04):
npm test— node:test 221, Vitest 65;lint,format:check,tip,knip—exit 0.- axe — 0 buzilish. Statistika ko'rinishida 4 ta "qo'lda ko'rish kerak" (
color-contrast): axe SVG matni ortidagi fon rangini aniqlay olmadi — kontrast qo'lda tekshirilgan. - e2e-21 — 22 ta, grafikka oidlari:
✅ grafik: teglar, ustun uzunligi jamiga mutanosib, son: [["#bozor",155,77,"2/3"],["#maktab",0,77,"0/1"]]
✅ grafik ekran o'quvchidan yashirin (jadval — matn muqobili), jadval bor: ["true",true]
✅ ranglar tokenlardan (bajarildi — asosiy, qolgan — ikkinchi): [true,true]
✅ grafik: CSP buzilishi yo'q: []Birinchi qatorni o'qing: «#bozor» — bajarildi 155 px, qolgan 77 px (2:1), «#maktab» — 0 va 77 (0/1). Mutanosiblik o'lchab tekshirildi.
Endi narx — grafik turgan BatafsilStatistika chunk'i (gzip):
- grafiksiz (holat 03)13,8 KB
- o'z SVG (holat 04)+0.3 KB14,1 KB
- Recharts varianti14.0 + 103.4 KB117,4 KB
Manba: O'lchandi: holat 03 va 04, tekshiruv-03.txt, tekshiruv-04.txt, 04-recharts/olchov.txt, gzip -9, 2026-10-17
O'z SVG — +0.3 KB, Recharts — +103.4 KB, ya'ni 300 baravardan ko'p. Birinchi yuklash ikkala variantda ham ~219 KB — grafik kech chunk'da. CSS +0.17 KB.
git add -A
git commitCommit (kanon): feat: teglar grafigi — o'z SVG (Recharts o'lchandi: +103 KB, tsc xatolari).
Bu "Recharts yomon" degani emas. Dashboard'da o'nta grafik, tooltip, zoom, vaqt o'qi kerak bo'lsa — 103 KB o'n grafikka bo'linadi va o'z kodingizdan arzon tushadi. Bitta oddiy grafik uchun esa — qimmat. Qoida 20-qismdagidek: kutubxona narxini ishlatilishiga bo'lib o'lchang. Boshqa kutubxonalar (Chart.js, ECharts, visx) — keyingi darsda.
9. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
grafik ko'rinmaydi, konsolda width(0) and height(0) |
ResponsiveContainer otasida balandlik yo'q |
otaga height yoki aspect |
| ustunlar yo'q, xato ham yo'q | dataKey ma'lumotdagi kalitga mos emas |
kalitni tekshiring, ma'lumotga tur bering |
Tooltip/Legend'da osh (kichik harf) |
name berilmagan |
<Bar name="Osh" /> |
| Legend tartibi o'zgarib ketdi | sukut — alifbo (itemSorter: "value") |
itemSorter={null} |
| o'qda «1.5 ta vazifa» | o'q sonlarni kasr bilan bo'ladi | allowDecimals={false} |
| Chrome'da «35,000» | Intl.NumberFormat("uz") |
o'z som() funksiyasi |
tsc -b — @reduxjs/toolkit da TS2344 |
exactOptionalPropertyTypes |
skipLibCheck yoki boshqa yechim (yuqorida) |
10. Mashqlar
Mashqlar kurs/mashqlar/21/04-recharts/ da. Har yechimni «Ishga tushir» bilan sinang.
1-mashq (oson): qaysi grafik, qaysi prop?
To'ldiring:
- Haftaning har kuni qancha manti sotilgani —
- 12 oy davomida tushum o'zgarishi —
- O'q yozuviga «ta» qo'shuvchi prop —
- Ikki ustunni ustma-ust qo'yuvchi prop —
ResponsiveContainerishlashi uchun ota-elementga kerak narsa —
Yechim
- BarChart — toifalarni (kunlarni) solishtirish.
- LineChart — vaqt bo'yicha o'zgarish.
- tickFormatter —
XAxis/YAxisdagi har yozuvni funksiyadan o'tkazadi. - stackId — bir xil qiymatli
BaryokiArealar ustma-ust yig'iladi. - balandlik — eni odatda ota-elementdan keladi, balandlik esa 0 bo'lib qolishi mumkin.
2-mashq (o'rta): osh va manti yonma-yon
Haftaning uch kuni uchun osh va manti sotuvi: Du — 32 va 20, Se — 41 va 18, Ch — 28 va 25. Grafik:
BarChart, ikkiBaryonma-yon (stackId'siz), nomlari «Osh» va «Manti».YAxisyozuvlari «10 ta» ko'rinishida,Legendbor.- «Osh» ustuni bosilganda konsolga
Du: 32 ta oshko'rinishida yozilsin.
Ishora: «Birinchi grafik» bo'limidagi onClick va «Sonni formatlash» dagi tickFormatter.
Yechim
import { BarChart, Bar, XAxis, YAxis, Legend } from "recharts";
const sotuv = [
{ kun: "Du", osh: 32, manti: 20 },
{ kun: "Se", osh: 41, manti: 18 },
{ kun: "Ch", osh: 28, manti: 25 },
];
export default function App() {
return (
<BarChart width={340} height={240} data={sotuv}>
<XAxis dataKey="kun" />
<YAxis tickFormatter={(v) => `${v} ta`} />
<Legend />
<Bar
dataKey="osh"
name="Osh"
fill="#1f6f4a"
onClick={(u) => console.log(`${u.kun}: ${u.osh} ta osh`)}
/>
<Bar dataKey="manti" name="Manti" fill="#b45309" />
</BarChart>
);
}Konsolda:
Du: 32 ta oshonClick ga kelgan obyektda asl maydonlar ham bor (u.kun, u.osh) — u.payload orqali ham olsa bo'ladi. stackId yo'q — ustunlar yonma-yon turadi. Selektor birinchi uchraganni bosadi — bu «Osh» ning «Du» ustuni.
3-mashq (qiyin): doira va uning matn muqobili
«Bugungi taomlar»: Osh 42, Manti 25, Lag'mon 18. Kanon g'oyasini takrorlang:
PieChart(Cell ranglari bilan)aria-hidden="true"lidivichida.- Ostida
<table>: «Taom», «Soni», «Ulush» ustunlari; ulush — butun foiz (Math.round), ulushlarpercentdan emas, o'zingiz hisoblang. - Jadvalga
<caption>— «Bugungi taomlar».
Ishora: jami — reduce. Jadval — oddiy HTML (Jadvallar I dagi semantika).
Yechim
import { PieChart, Pie, Cell } from "recharts";
const taomlar = [
{ nom: "Osh", soni: 42 },
{ nom: "Manti", soni: 25 },
{ nom: "Lag'mon", soni: 18 },
];
const RANGLAR = ["#1f6f4a", "#b45309", "#1d4ed8"];
export default function App() {
const jami = taomlar.reduce((s, t) => s + t.soni, 0);
return (
<figure>
<div aria-hidden="true">
<PieChart width={240} height={200}>
<Pie data={taomlar} dataKey="soni" nameKey="nom">
{taomlar.map((t, i) => (
<Cell key={t.nom} fill={RANGLAR[i]} />
))}
</Pie>
</PieChart>
</div>
<table>
<caption>Bugungi taomlar</caption>
<thead>
<tr>
<th>Taom</th>
<th>Soni</th>
<th>Ulush</th>
</tr>
</thead>
<tbody>
{taomlar.map((t) => (
<tr key={t.nom}>
<td>{t.nom}</td>
<td>{t.soni}</td>
<td>{Math.round((t.soni / jami) * 100)}%</td>
</tr>
))}
</tbody>
</table>
</figure>
);
}Ekranda:
Bugungi taomlar
Taom Soni Ulush
Osh 42 49%
Manti 25 29%
Lag'mon 18 21%Ekranda faqat jadval matni — doirada yozuv yo'q (label bermadik). Diqqat qiling: 49 + 29 + 21 = 99%. Yaxlitlashda yo'qolgan foiz — normal holat; aniqlik kerak bo'lsa bitta kasr xona bering. Malika jadvalni o'qiydi, doirani esa eshitmaydi — aria-hidden takrorni yo'qotdi.
4-mashq: Vazifalar qadami
feat/teglar-grafigi branch'ida «Vazifalar qadami» bo'limidagi o'zgarishlarni qiling: TeglarGrafigi.tsx, uni BatafsilStatistika.tsx ga ulash, asos.css dagi ranglar. Ixtiyoriy tajriba: alohida branch'da Recharts variantini yozib, npm run build va npm run tip natijasini o'zingiz ko'ring — keyin o'chiring.
Yechim
Tekshiruv ro'yxati:
npm test— node 221, Vitest 65;npm run tip— 0 xato.- Statistika sahifasi: jadval ostida grafik, ustunlar jamiga mutanosib; qorong'i temada ranglar almashadi.
- DevTools:
svgdaaria-hidden="true"; Lighthouse/axe — buzilish yo'q. npm run build— birinchi yuklash ~219.6 KB,BatafsilStatistikachunk'i ~14.1 KB gzip.- Recharts tajribasida: chunk ~103 KB va
tsc -bda@reduxjs/toolkitTS2344 xatolari.
11. Real ishda
- Admin panellar va analitika — sotuv, foydalanuvchilar, buyurtmalar grafigi. React loyihalarida Recharts ko'p uchraydi; shadcn Charts orqali ham keladi.
- Kod ko'rigida birinchi savol: "bu grafik uchun qancha KB?" Bitta oddiy grafik — o'z SVG; ko'p interaktiv grafik — kutubxona.
- Intervyu savollari: "Bar va Line qachon?", "
ResponsiveContainernega ishlamayapti?", "grafikni ekran o'quvchiga qanday tushuntirasiz?", "kutubxona qo'shishdan oldin nimani o'lchaysiz?".
Xulosa
- Recharts — komponentlardan grafik:
BarChart+XAxis/YAxis+Tooltip/Legend+Bar dataKey. Ma'lumot — obyektlar massivi. LineChart— vaqt,BarChart— toifa,AreaChart+stackId— tarkib,PieChart— 3–5 bo'lakli ulush.- Formatlash —
tickFormatter,formatter, o'z tooltipcontent={<… />}. O'zbekcha son — o'z funksiya, Intl'ga ishonmang. - O'lcham:
ResponsiveContainer(otada balandlik!) yokiresponsive+ CSSaspectRatio. - A11y:
accessibilityLayerklaviatura beradi, lekin matn muqobili — jadval. Rang yolg'iz emas, kontrast ≥ 3:1. - Narx:
vazifalarda +103.4 KB va 12 tsc xatosi → kanon o'z SVG grafigini oldi (+0.3 KB).
Keyingi dars: Grafiklar II: Chart.js, ECharts, Nivo va moliya grafiklari — canvas va SVG farqi, katta ma'lumot, xavfsizlik siyosati ostida qaysi kutubxona ishlaydi (kanon 6 ta grafik kutubxonasini o'lchadi).
Manbalar
- Recharts: API va misollar — recharts.github.io (3.10.1); manba kodi:
Legend(itemSorter),usePrefersReducedMotion,accessibilityLayer - shadcn/ui: Chart — ui.shadcn.com/docs/components/chart (reyestr:
recharts@3.8.0) - WCAG 2.2: 1.4.11 Non-text Contrast; 1.4.1 Use of Color
- Kanon:
vazifalarholat 04,natijalar/tekshiruv-03.txt,tekshiruv-04.txt,tajriba/04-recharts/olchov.txt,brauzer-tekshiruv/natija-21-04.txt(2026-10-17)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!