# ImajViewer — Pan Sınırlama & Zoom Merkezi Sorunu ✅ ÇÖZÜLDÜ

> **Tarih:** 2026-07-23  
> **Dosya:** `lib/widgets/image_canvas.dart`  
> **Durum:** ✅ Çözüldü

---

## Nihai Çözüm

### 1. Zoom — `Matrix4.copy(m)..translate..scale..translate`
Cursor merkezli zoomAroundPoint. Hem fill hem fit modunda çalışır çünkü `localPosition` her zaman Listener'a göre doğru koordinat verir. `_currentScale` listener'da güncellenir.

### 2. `_clampAfterZoom` — Image offset + sadece boundary clamp
**Kritik:** Fit modunda (BoxFit.contain) Image, Center widget içinde **ortalanır**. Offset hesaplanarak image'ın viewport'taki gerçek sınırları bulunur:

```dart
imgOffsetX = (viewportW - imageW) / 2  // fill modunda 0, fit modunda >0
imgLeft    = tx + imgOffsetX * scale
imgRight   = tx + (imgOffsetX + imageW) * scale
```

**SADECE** image viewport'tan büyükse clamp yapılır. Küçükse **dokunulmaz** — zoom-around-point merkezi korunur. Kullanıcı double-tap ile istediği zaman ortalamayı sıfırlayabilir (`Matrix4.identity()`).

### 3. `translate` — asla `setTranslationRaw` kullanma
`setTranslationRaw` matrisin translation sütununu ezer → zoom merkezini bozar. `translate(dx,dy)` ekleme yapar → zoom merkezi korunur.

### 4. Listener'da clamp YOK
Sadece `_currentScale` takip edilir. Pan → `boundaryMargin: EdgeInsets.zero`, Zoom → `_handleScroll` içinde `_clampAfterZoom`.

---

## Akış

```
Scroll → _handleScroll → zoomAroundPoint → _controller.value
                                            ↓
                               _clampAfterZoom()
                                 ├─ image > viewport → translate ile clamp
                                 └─ image ≤ viewport → dokunma

Pan   → InteractiveViewer → _controller.value (boundaryMargin sınırlar)
                                            ↓
                               _onTransformChanged → sadece _currentScale
```
