46 lines
1.9 KiB
Markdown
46 lines
1.9 KiB
Markdown
# 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
|
||
```
|