---
title: "HTML5 Canvas ile çizim: şekil, eğri, metin ve animasyon rehberi"
author: "Abdulaziz Akyol"
author_url: https://www.abdulazizakyol.com/hakkimda/
url: https://www.abdulazizakyol.com/blog/html-5-grafik-islemlericanvas/
language: tr
published: 2018-10-01
updated: 2026-09-25
categories: ["HTML5", "Yazılım geliştirme"]
tags: ["HTML5", "Canvas", "JavaScript", "requestAnimationFrame", "SVG", "devicePixelRatio"]
description: "HTML5 Canvas 2D ile çizgi, şekil, yay ve Bézier eğrisi, gradyan, metin, görsel ve animasyon; Retina bulanıklığı düzeltmesi ve Canvas–SVG karşılaştırması."
---

# HTML5 Canvas ile çizim: şekil, eğri, metin ve animasyon rehberi

Yazar: [Abdulaziz Akyol](https://www.abdulazizakyol.com/hakkimda/) · 2018-10-01

## Öne çıkanlar

- Canvas, JavaScript ile piksel tabanlı çizim yapılan bir HTML öğesidir; çizim getContext('2d') ile alınan bağlam nesnesi üzerinden yapılır ve koordinat başlangıcı sol üst köşedir.
- arc yöntemi açıları derece değil radyan cinsinden alır; tam daire 2π radyandır ve son parametre true verilirse yay saat yönünün tersine çizilir.
- Canvas'ın width ve height öznitelikleri çizim tamponunun piksel boyutunu, CSS ise ekrandaki boyutunu belirler; yüksek DPI ekranlarda tamponu devicePixelRatio ile çarpmak bulanıklığı giderir.
- Animasyon için setInterval yerine requestAnimationFrame kullanılmalı ve hareket, kareler arasındaki geçen süreye (delta time) göre hesaplanmalıdır.
- Çok sayıda nesne ve piksel işlemi gereken sahnelerde Canvas, ölçeklenmesi, erişilebilirliği ve tek tek öğe etkileşimi önemli grafiklerde SVG daha uygundur.

HTML5 Canvas, `<canvas>` öğesi üzerinde JavaScript ile piksel tabanlı çizim yapmayı sağlayan bir API'dir. Çizgi, şekil, eğri, metin ve görselleri kodla çizer, bunları saniyede onlarca kez yeniden çizerek animasyon, grafik ya da oyun oluşturursunuz.

Bu rehber, 2018'de yazdığım üç Canvas notunun (genel giriş, şekil çizimleri ve eğriler) birleştirilmiş ve düzeltilmiş hâlidir. Eski notlardaki kodlar akıllı tırnaklar yüzünden çalışmıyordu, bir yerde `getElementyId` yazım hatası, bir yerde 200 piksel denip `width="20"` verilmiş bir canvas vardı. Tüm örnekleri düz tırnaklarla, güncel JavaScript ile yeniden yazdım. Serinin çerçevesi için [HTML5 nedir?](https://www.abdulazizakyol.com/blog/html5-nedir/) yazısına bakabilirsiniz.

## Canvas nedir, nasıl başlanır?

```html
<canvas id="tuval" width="400" height="220">
  Bu grafik bir çizgi, bir üçgen ve bir daire gösterir.
</canvas>
<script>
  const canvas = document.getElementById("tuval");
  const ctx = canvas.getContext("2d");
</script>
```

Bilmeniz gereken dört temel nokta var:

1. **`width` ve `height` öznitelikleri çizim tamponunun piksel boyutudur.** Verilmezse varsayılan 300×150'dir. CSS ile verdiğiniz boyut yalnızca ekrandaki görüntüyü büyütür ya da küçültür; bu ikisi karıştırılınca çizim bulanıklaşır.
2. **Etiketin içindeki metin yedek içeriktir.** Ekran okuyucular ve canvas'ı çalıştıramayan ortamlar bu metni kullanır.
3. **Koordinat başlangıcı (0, 0) sol üst köşedir.** x sağa, y aşağı doğru artar; matematikteki eksenin tersine.
4. **Çizim, `getContext("2d")` ile alınan bağlam (context) nesnesiyle yapılır.** 3B için `webgl2` ya da WebGPU bağlamı kullanılır.

## Çizgi ve dikdörtgen nasıl çizilir?

Canvas'ta şekiller **yol (path)** olarak tanımlanır: `beginPath()` ile yeni bir yol başlatılır, `moveTo()` ile kalem kaldırılıp taşınır, `lineTo()` ile çizgi eklenir, sonunda `stroke()` kenarı çizer ya da `fill()` içini doldurur.

```javascript
// Kalın, yuvarlak uçlu gri çizgi
ctx.beginPath();
ctx.moveTo(50, 150);
ctx.lineTo(150, 50);
ctx.lineWidth = 10;
ctx.lineCap = "round";
ctx.strokeStyle = "#cccccc";
ctx.stroke();

// Üçgen: yolu kapatıp doldurmak
ctx.beginPath();
ctx.moveTo(200, 150);
ctx.lineTo(260, 50);
ctx.lineTo(320, 150);
ctx.closePath();
ctx.fillStyle = "#1d4ed8";
ctx.fill();

// Dikdörtgenler
ctx.fillStyle = "#16a34a";
ctx.fillRect(10, 10, 80, 40);         // dolu dikdörtgen
ctx.lineWidth = 1;
ctx.strokeStyle = "#000000";
ctx.strokeRect(10.5, 160.5, 80, 40);  // 1 px kenarlık, yarım piksele hizalı
ctx.clearRect(20, 20, 20, 20);        // alanı silip şeffaf yapar

// Yuvarlatılmış köşeli dikdörtgen
ctx.beginPath();
ctx.roundRect(340, 10, 50, 40, 8);
ctx.fill();
```

`strokeRect` satırındaki `.5` değerleri bilinçli: 1 piksellik çizgi tam sayı koordinata çizilirse iki piksel sütununa yarı yarıya yayılır ve gri, bulanık görünür. `roundRect()` [MDN'e göre](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/roundRect) Nisan 2023'ten beri tüm büyük tarayıcılarda çalışıyor.

`beginPath()` çağrısını unutmak en sık gördüğüm hatadır. Yeni yol başlatılmazsa sonraki `stroke()` önceki bütün alt yolları da yeniden çizer; renk değiştirdiğinizde eski şekiller de yeni renge boyanır.

## Yay ve eğriler: arc, quadratic ve Bézier

`arc(x, y, yarıçap, başlangıçAçısı, bitişAçısı, saatYönününTersi)` bir çember yayı ekler. Açılar **radyan** cinsindendir: 360° = 2π. Açı 0, merkezin tam sağındaki noktadır; y ekseni aşağı baktığı için π/2 aşağıyı, 3π/2 yukarıyı gösterir. Son parametre verilmezse ya da `false` ise yay saat yönünde, `true` ise saat yönünün tersine çizilir.

| Derece | Radyan | Ekrandaki yön |
| ------ | ------ | ------------- |
| 0°     | 0      | Sağ           |
| 90°    | π/2    | Aşağı         |
| 180°   | π      | Sol           |
| 270°   | 3π/2   | Yukarı        |
| 360°   | 2π     | Tam tur       |

```javascript
const derece = (d) => (d * Math.PI) / 180;

// Eski nottaki yay: 0'dan 1,2π'ye saat yönünde
ctx.beginPath();
ctx.arc(100, 100, 75, 0, 1.2 * Math.PI, false);
ctx.lineWidth = 10;
ctx.strokeStyle = "#000000";
ctx.stroke();

// Pasta dilimi: merkezden başla, yayı çiz, yolu kapat
ctx.beginPath();
ctx.moveTo(300, 110);
ctx.arc(300, 110, 60, derece(-90), derece(30));
ctx.closePath();
ctx.fillStyle = "#f97316";
ctx.fill();
```

Serbest eğriler için iki yöntem vardır. `quadraticCurveTo(kx, ky, x, y)` tek kontrol noktalı karesel eğri, `bezierCurveTo(k1x, k1y, k2x, k2y, x, y)` iki kontrol noktalı kübik Bézier eğrisi çizer. Eğri kontrol noktalarından geçmez; onlara doğru "çekilir". Elips için `ellipse()` kullanılır:

```javascript
ctx.lineWidth = 3;
ctx.strokeStyle = "#0b1f3a";

// Karesel eğri: bir kontrol noktası
ctx.beginPath();
ctx.moveTo(20, 200);
ctx.quadraticCurveTo(100, 20, 180, 200);
ctx.stroke();

// Kübik Bézier: iki kontrol noktası
ctx.beginPath();
ctx.moveTo(220, 200);
ctx.bezierCurveTo(240, 20, 360, 20, 380, 200);
ctx.stroke();

// Elips: merkez, iki yarıçap, dönüş açısı, başlangıç ve bitiş açısı
ctx.beginPath();
ctx.ellipse(200, 110, 80, 40, derece(15), 0, Math.PI * 2);
ctx.stroke();
```

## Renk, gradyan ve gölge

`fillStyle` ve `strokeStyle`, CSS'teki her renk biçimini kabul eder. Gradyanlar ayrı nesnelerdir ve renk durakları (`addColorStop`) ekledikten sonra stile atanır:

```javascript
const dogrusal = ctx.createLinearGradient(10, 0, 210, 0);
dogrusal.addColorStop(0, "#1d4ed8");
dogrusal.addColorStop(1, "#22d3ee");
ctx.fillStyle = dogrusal;
ctx.fillRect(10, 10, 200, 60);

const dairesel = ctx.createRadialGradient(300, 60, 5, 300, 60, 50);
dairesel.addColorStop(0, "#ffffff");
dairesel.addColorStop(1, "#f97316");
ctx.fillStyle = dairesel;
ctx.beginPath();
ctx.arc(300, 60, 50, 0, Math.PI * 2);
ctx.fill();

ctx.shadowColor = "rgba(0, 0, 0, 0.35)";
ctx.shadowBlur = 12;
ctx.shadowOffsetY = 4;
ctx.fillStyle = "#16a34a";
ctx.fillRect(10, 110, 120, 60);
ctx.shadowColor = "transparent"; // sonraki çizimler gölgesiz olsun
```

Dikkat: gradyan koordinatları şekle göre değil **canvas'a göre** verilir. Gradyanı 0–200 arasında tanımlayıp 300. pikselde bir kare doldurursanız kare tek renk görünür. Görselle dolgu için `createPattern(gorsel, "repeat")`, açısal renk geçişi için `createConicGradient()` de kullanılabilir.

## Canvas'a metin yazmak

```javascript
// Modül betiğinde: web fontunun yüklenmesini bekle, yoksa yedek fontla çizilir
await document.fonts.load("600 24px Inter");

ctx.font = "600 24px Inter, system-ui, sans-serif";
ctx.fillStyle = "#0b1f3a";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("Kişi sayısı: 42", 200, 40);

const olcu = ctx.measureText("Kişi sayısı: 42");
console.log(`Metin genişliği: ${olcu.width.toFixed(1)} px`);
```

`font` özelliği CSS `font` kısaltmasıyla aynı sözdizimini kullanır. `fillText()` dördüncü parametre olarak en büyük genişliği alabilir; metin sığmazsa sıkıştırılır. Canvas metni satır kaydırmaz; çok satırlı metin için `measureText()` ile kelimeleri ölçüp satırları kendiniz bölmeniz gerekir.

## Görsel çizmek ve CORS

`drawImage()` üç biçimde çağrılır: yalnızca konum, konum ve boyut, ya da kaynaktan kırpılacak dikdörtgen ile hedef dikdörtgen. Görsel, video karesi ya da başka bir canvas kaynak olabilir:

```javascript
const gorsel = new Image();
gorsel.crossOrigin = "anonymous"; // başka alan adındaysa ve sunucu CORS izni veriyorsa
gorsel.src = "/img/kamera-karesi.jpg";
await gorsel.decode();             // görsel çözülmeden çizmeyin

ctx.drawImage(gorsel, 0, 0, 400, 225);                    // ölçekleyerek çiz
ctx.drawImage(gorsel, 100, 50, 200, 200, 0, 0, 100, 100); // kaynaktan kırp, hedefe çiz

// Görsel üzerine tespit kutusu ve etiketi
ctx.strokeStyle = "#22c55e";
ctx.lineWidth = 3;
ctx.strokeRect(120, 60, 80, 140);
ctx.fillStyle = "#22c55e";
ctx.font = "14px system-ui, sans-serif";
ctx.textAlign = "left";
ctx.textBaseline = "alphabetic";
ctx.fillText("kişi 0,91", 122, 56);
```

Son blok, görüntü işleme arayüzlerinde yaygın bir desendir: model sunucuda çalışır, tarayıcı yalnızca gelen kutu koordinatlarını video karesinin üstüne çizer. Kameradan olaya uzanan zincirin tamamını [mevcut kameralarla görüntü analitiği](https://www.abdulazizakyol.com/blog/mevcut-kameralarla-goruntu-analitigi-rtsp-den-olaya/) yazısında anlattım.

Başka bir alan adından CORS izni olmadan çizilen görsel canvas'ı "kirletir" (tainted). Bundan sonra `getImageData()`, `toDataURL()` ve `toBlob()` çağrıları `SecurityError` fırlatır. Bu bir hata değil, kullanıcının başka sitelerdeki görsellerini okumayı engelleyen bir güvenlik kuralıdır.

## Dönüşümler: taşıma, döndürme, ölçekleme

```javascript
ctx.save();                 // mevcut durumu (dönüşüm ve stiller) kaydet
ctx.translate(200, 110);    // başlangıç noktasını merkeze taşı
ctx.rotate(derece(45));     // 45 derece döndür
ctx.fillStyle = "#7c3aed";
ctx.fillRect(-25, -25, 50, 50);
ctx.restore();              // kaydedilen duruma geri dön
```

Dönüşümler birikir: `rotate()`'i iki kez çağırırsanız açılar toplanır. Her dönüşümlü çizimi `save()` ve `restore()` arasına almak hataların çoğunu önler.

## requestAnimationFrame ile animasyon

Canvas'ta animasyon, her karede sahneyi silip yeniden çizmek demektir. Bunun için `setInterval` değil `requestAnimationFrame` kullanılır: tarayıcının ekran yenilemesiyle eşzamanlı çalışır ve arka plandaki sekmelerde durdurulur. Hareketi kare sayısına değil **geçen süreye** göre hesaplayın; aksi hâlde 120 Hz ekranda animasyon 60 Hz'dekinin iki katı hızlı akar:

```javascript
let onceki = performance.now();

function kare(simdi) {
  const dt = Math.min((simdi - onceki) / 1000, 0.05); // saniye; sekme dönüşünde sıçramayı sınırla
  onceki = simdi;
  guncelle(dt);   // konumları hız × dt ile ilerlet
  ciz();          // sahneyi baştan çiz
  requestAnimationFrame(kare);
}
requestAnimationFrame(kare);
```

Hareket hassasiyeti olan kullanıcılar için `prefers-reduced-motion` tercihini dikkate alın ve animasyonu durdurmak için bir düğme koyun. Aşağıdaki tam örnek ikisini de yapıyor.

## Yüksek DPI (Retina) ekranlarda bulanıklık nasıl giderilir?

Telefonlarda ve Retina ekranlarda bir CSS pikseli 2–3 fiziksel pikselle çizilir. Canvas tamponu CSS boyutunda bırakılırsa tarayıcı görüntüyü büyütür ve her şey bulanıklaşır. Çözüm, tamponu `devicePixelRatio` ile çarpmak ve bağlamı aynı oranda ölçeklemektir:

```javascript
function yuksekDpiAyarla(canvas, ctx) {
  const dpr = window.devicePixelRatio || 1;
  const { width, height } = canvas.getBoundingClientRect(); // CSS boyutu
  canvas.width = Math.round(width * dpr);
  canvas.height = Math.round(height * dpr);
  ctx.setTransform(dpr, 0, 0, dpr, 0, 0); // çizim koordinatları CSS pikseli olarak kalır
}
```

[MDN'in canvas iyileştirme rehberindeki](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas) örnekte `ctx.scale(dpr, dpr)` kullanılır; ben `setTransform` tercih ediyorum, çünkü işlev pencere her yeniden boyutlandığında çağrıldığında `scale` birikir, `setTransform` ise dönüşümü sıfırdan kurar. Canvas'ın `width` veya `height` değerini değiştirmek içeriği sildiği için ayardan sonra sahneyi yeniden çizmek gerekir.

## Tam örnek: çalışır bir canvas sayfası

Aşağıdaki dosyayı `canvas.html` olarak kaydedip tarayıcıda açabilirsiniz. Yüksek DPI ayarı, yeniden boyutlandırma, gradyan, yay, metin, delta time ile animasyon, hareket azaltma tercihi ve durdurma düğmesi bir arada:

```html
<!DOCTYPE html>
<html lang="tr">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Canvas animasyon örneği</title>
  <style>
    body { margin: 0; font-family: system-ui, sans-serif; background: #f4f6fa; }
    canvas { display: block; width: 100%; height: 320px; }
    button { margin: 12px 16px; padding: 8px 14px; font: inherit; }
  </style>
</head>
<body>
  <canvas id="sahne" role="img"
          aria-label="Mavi zemin üzerinde dönen sarı bir yükleme halkası ve kenarlardan seken turuncu bir top">
    Dönen bir yükleme halkası ve seken bir top animasyonu.
  </canvas>
  <button type="button" id="dugme">Animasyonu durdur</button>

  <script>
    const canvas = document.getElementById("sahne");
    const ctx = canvas.getContext("2d");
    const dugme = document.getElementById("dugme");
    const hareketAzalt = window.matchMedia("(prefers-reduced-motion: reduce)");

    const topVerisi = { x: 60, y: 160, r: 18, hizX: 180, hizY: 140 }; // piksel/saniye
    let genislik = 0;
    let yukseklik = 0;
    let aci = 0;
    let sonZaman = 0;
    let kareId = null;
    let calisiyor = false;

    function boyutla() {
      const dpr = window.devicePixelRatio || 1;
      const kutu = canvas.getBoundingClientRect();
      genislik = kutu.width;
      yukseklik = kutu.height;
      canvas.width = Math.round(kutu.width * dpr);
      canvas.height = Math.round(kutu.height * dpr);
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    }

    function arkaPlan() {
      const gradyan = ctx.createLinearGradient(0, 0, 0, yukseklik);
      gradyan.addColorStop(0, "#0b1f3a");
      gradyan.addColorStop(1, "#1d4ed8");
      ctx.fillStyle = gradyan;
      ctx.fillRect(0, 0, genislik, yukseklik);
    }

    function halka(cx, cy) {
      ctx.lineWidth = 8;
      ctx.lineCap = "round";
      ctx.strokeStyle = "rgba(255, 255, 255, 0.2)";
      ctx.beginPath();
      ctx.arc(cx, cy, 40, 0, Math.PI * 2);
      ctx.stroke();

      ctx.strokeStyle = "#fbbf24";
      ctx.beginPath();
      ctx.arc(cx, cy, 40, aci, aci + Math.PI * 1.2);
      ctx.stroke();
    }

    function topuCiz() {
      const { x, y, r } = topVerisi;
      const parlak = ctx.createRadialGradient(x - 6, y - 6, 2, x, y, r);
      parlak.addColorStop(0, "#ffffff");
      parlak.addColorStop(1, "#f97316");
      ctx.fillStyle = parlak;
      ctx.beginPath();
      ctx.arc(x, y, r, 0, Math.PI * 2);
      ctx.fill();
    }

    function yazi() {
      ctx.fillStyle = "#ffffff";
      ctx.font = "600 16px system-ui, sans-serif";
      ctx.textAlign = "left";
      ctx.textBaseline = "top";
      ctx.fillText("HTML5 Canvas + requestAnimationFrame", 16, 16);
    }

    function ciz() {
      arkaPlan();
      halka(genislik - 80, 80);
      topuCiz();
      yazi();
    }

    function guncelle(dt) {
      const t = topVerisi;
      aci += dt * Math.PI; // saniyede yarım tur
      t.x += t.hizX * dt;
      t.y += t.hizY * dt;
      if (t.x < t.r || t.x > genislik - t.r) t.hizX *= -1;
      if (t.y < t.r || t.y > yukseklik - t.r) t.hizY *= -1;
      t.x = Math.min(Math.max(t.x, t.r), genislik - t.r);
      t.y = Math.min(Math.max(t.y, t.r), yukseklik - t.r);
    }

    function dongu(zaman) {
      const dt = Math.min((zaman - sonZaman) / 1000, 0.05);
      sonZaman = zaman;
      guncelle(dt);
      ciz();
      kareId = requestAnimationFrame(dongu);
    }

    function baslat() {
      calisiyor = true;
      dugme.textContent = "Animasyonu durdur";
      kareId = requestAnimationFrame((zaman) => {
        sonZaman = zaman;
        dongu(zaman);
      });
    }

    function durdur() {
      calisiyor = false;
      dugme.textContent = "Animasyonu başlat";
      cancelAnimationFrame(kareId);
    }

    dugme.addEventListener("click", () => (calisiyor ? durdur() : baslat()));

    // Boyut değişince tamponu yeniden kur ve sahneyi çiz (boyut değişimi canvas'ı siler)
    new ResizeObserver(() => {
      boyutla();
      ciz();
    }).observe(canvas);

    boyutla();
    ciz();
    if (hareketAzalt.matches) {
      dugme.textContent = "Animasyonu başlat"; // hareket azaltma açıksa durağan başla
    } else {
      baslat();
    }
  </script>
</body>
</html>
```

Bir ayrıntı: top nesnesine `top` adını vermedim. Klasik bir `<script>` içinde en üst düzeyde `const top` tanımlamak, tarayıcının salt okunur `window.top` özelliğiyle çakışır ve `SyntaxError` verir.

## Canvas mı SVG mi?

| Ölçüt            | Canvas                                                       | SVG                                            |
| ---------------- | ------------------------------------------------------------ | ---------------------------------------------- |
| Model            | Piksel tabanlı, "çiz ve unut"                                | Vektör tabanlı, her şekil bir DOM öğesi        |
| Ölçekleme        | Büyütünce pikselleşir; DPI ayarı gerekir                     | Her boyutta keskin                             |
| Çok sayıda nesne | Binlerce nesnede hızlı                                       | DOM büyüdükçe yavaşlar                         |
| Etkileşim        | Tıklanan şekli kendiniz hesaplarsınız                        | Her şekle olay dinleyici eklenir               |
| Erişilebilirlik  | İçerik ekran okuyucuya görünmez; yedek metin ve ARIA gerekir | `<title>`, `<desc>` ve seçilebilir metin       |
| Biçimlendirme    | Yalnızca JavaScript                                          | CSS ile biçimlendirilir, animasyon yapılabilir |
| Dışa aktarma     | `toBlob()` ile PNG, JPEG, WebP                               | Doğrudan `.svg` dosyası                        |
| Tipik kullanım   | Oyun, parçacık, video üzerine çizim, piksel işleme           | Logo, ikon, diyagram, etkileşimli grafik       |

Kendi tercihim şu: nesne sayısı az ve her birinin tıklanması, okunması, taranması gerekiyorsa SVG; sahne her karede baştan çiziliyorsa Canvas. Daha ağır işler için Canvas'ı bir Web Worker'a taşıyan `OffscreenCanvas`, MDN'e göre Mart 2023'ten beri tüm büyük tarayıcılarda kullanılabiliyor. Katmanlı canvas'lar (arka plan ayrı, hareketli nesneler ayrı) ve `getContext("2d", { alpha: false })` de MDN'in önerdiği başlıca iyileştirmelerdir.

## Canvas erişilebilirliği

Canvas'a çizilen her şey ekran okuyucu için tek bir resimdir; metin seçilemez, aranamaz, arama motorlarınca okunamaz. Bu yüzden:

- Canvas'a `role="img"` ve içeriği anlatan bir `aria-label` verin ya da anlamlı yedek içerik yazın.
- Veri grafiğiyse aynı veriyi bir `<table>` ile de sunun.
- Canvas üzerinde düğme çizmek yerine gerçek `<button>` öğelerini canvas'ın yanına ya da üstüne yerleştirin; renk ve hız ayarları için `type="color"` ve `type="range"` alanlarını [HTML5 formlar rehberindeki](https://www.abdulazizakyol.com/blog/html-5-form/) gibi etiketleyin.

Anlamsal yapı ve alternatif içerik konusunu [HTML5 anlamsal etiketler rehberinde](https://www.abdulazizakyol.com/blog/html-5-anlamsal-web/), video karelerini canvas'a aktarmadan önce videonun kendisini doğru sunmayı [HTML5 video ve audio rehberinde](https://www.abdulazizakyol.com/blog/html5-medya-etiketleri/) anlattım.

## Kontrol listesi

- [ ] Canvas'ın `width`/`height` değerleri `devicePixelRatio` ile ayarlanıyor, ekran boyutu CSS'ten geliyor.
- [ ] Her yeni şekil `beginPath()` ile başlıyor; dönüşümler `save()`/`restore()` arasında.
- [ ] Açılar radyan cinsinden; derece dönüşümü için yardımcı işlev var.
- [ ] Animasyon `requestAnimationFrame` ve delta time ile çalışıyor; `prefers-reduced-motion` ve durdurma düğmesi var.
- [ ] Canvas'ın `role="img"` + `aria-label` ya da yedek içeriği var; başka alan adındaki görseller CORS ile yükleniyor.

## Sık sorulan sorular

### Canvas neden bulanık görünüyor?

Canvas'ın çizim tamponu CSS boyutuyla aynı piksel sayısında bırakıldığında, piksel yoğunluğu yüksek ekranlarda tarayıcı görüntüyü büyütür ve bulanıklaşır. Tamponu devicePixelRatio ile çarparak büyütün, bağlamı setTransform ile aynı oranda ölçekleyin ve ekrandaki boyutu CSS ile sabit tutun.

### Canvas mı SVG mi kullanmalıyım?

Binlerce nesnenin her karede yeniden çizildiği oyun, parçacık efekti, video üzerine çizim ve piksel işleme için Canvas uygundur. Logo, ikon, diyagram ve etkileşimli grafik gibi az sayıda, ölçeklenmesi ve erişilebilir olması gereken nesnelerde SVG daha iyi sonuç verir.

### Canvas'a çizdiğim görseli neden getImageData ile okuyamıyorum?

Başka bir alan adından CORS izni olmadan yüklenen görsel canvas'ı kirletir (tainted) ve tarayıcı güvenlik nedeniyle getImageData, toDataURL ve toBlob çağrılarında SecurityError fırlatır. Görseli crossOrigin anonymous ile yükleyin ve sunucunun Access-Control-Allow-Origin başlığı döndürdüğünden emin olun.

### Canvas animasyonunda setInterval mi requestAnimationFrame mi kullanılmalı?

requestAnimationFrame kullanılmalıdır. Tarayıcının ekran yenilemesiyle eşzamanlı çalışır, arka plandaki sekmelerde durdurulur ve pil tüketimini azaltır. Hareketi kare sayısına değil geçen süreye göre hesaplarsanız 60 Hz ve 120 Hz ekranlarda aynı hızda görünür.

## Kaynaklar

1. [WHATWG HTML Standard — The canvas element](https://html.spec.whatwg.org/multipage/canvas.html)
2. [MDN — Canvas tutorial](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial)
3. [MDN — Optimizing canvas](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas)
4. [MDN — Window.requestAnimationFrame()](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame)
5. [MDN — OffscreenCanvas](https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas)
6. [MDN — CanvasRenderingContext2D.roundRect()](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/roundRect)

---

Abdulaziz Akyol, CX Teknoloji'nin (yapay zekâ, görüntü işleme ve IoT) kurucusudur. Asıl sürüm: https://www.abdulazizakyol.com/blog/html-5-grafik-islemlericanvas/
