Skip to content

Commit abe9d36

Browse files
mattleibowCopilot
andcommitted
Comprehensive DeepZoom documentation overhaul
- Restructure overview (deep-zoom.md): architecture diagram, quick start, image source sections, programmatic navigation, events table - New deep-zoom-controller.md: full controller API, viewport coordinate system, zoom semantics, NativeZoom, SKDeepZoomImageSource/CollectionSource - New deep-zoom-caching.md: ISKDeepZoomTileCache interface, SKDeepZoomMemoryTileCache, tiered cache-aside pattern, custom cache examples, SKDeepZoomTileId docs - New deep-zoom-fetching.md: ISKDeepZoomTileFetcher, built-in fetchers, custom fetcher examples (app package, auth headers, pre-loaded) - Update deep-zoom-blazor.md: current API (IAsyncDisposable, DZC loading, custom cache, pan/zoom wiring) - Update deep-zoom-maui.md: current API, pan/zoom gestures, DZC loading - Add Deep Zoom section to toc.yml with all 6 sub-pages - Rewrite README.md: concise class reference table, minimal usage snippet, architecture notes, coordinate system explanation - Add XML doc comments to SKDeepZoomFileTileFetcher and SKDeepZoomTileRequest Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 51cfe8c commit abe9d36

File tree

10 files changed

+1081
-481
lines changed

10 files changed

+1081
-481
lines changed

docs/docs/deep-zoom-blazor.md

Lines changed: 98 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
# Deep Zoom for Blazor
22

3-
Use `SKDeepZoomController` with a plain `SKCanvasView` to render Deep Zoom images in Blazor WebAssembly. There is no custom component — the page wires the services directly to the canvas.
3+
Use `SKDeepZoomController` with a plain `SKCanvasView` in Blazor WebAssembly to render Deep Zoom images. There is no custom component — the page wires the services directly to the canvas, giving you full control over layout, interaction, and lifecycle.
44

55
## Quick Start
66

77
```razor
88
@page "/deepzoom"
9-
@implements IDisposable
9+
@implements IAsyncDisposable
1010
@inject HttpClient Http
1111
@using SkiaSharp.Extended.DeepZoom
1212
1313
<SKCanvasView @ref="_canvas"
1414
OnPaintSurface="OnPaintSurface"
15-
style="width: 100%; height: 600px; border: 1px solid #ccc;" />
15+
style="width: 100%; height: 600px; touch-action: none;" />
1616
1717
@code {
1818
private SKCanvasView? _canvas;
@@ -25,19 +25,16 @@ Use `SKDeepZoomController` with a plain `SKCanvasView` to render Deep Zoom image
2525
_controller = new SKDeepZoomController();
2626
_controller.InvalidateRequired += OnInvalidateRequired;
2727
28-
var xml = await Http.GetStringAsync("deepzoom/image.dzi");
29-
var baseUrl = new Uri(Http.BaseAddress!, "deepzoom/image_files/").ToString();
30-
var tileSource = SKDeepZoomImageSource.Parse(xml, baseUrl);
28+
var xml = await Http.GetStringAsync("deepzoom/image.dzi");
29+
var baseUrl = new Uri(Http.BaseAddress!, "deepzoom/image_files/").ToString();
30+
var source = SKDeepZoomImageSource.Parse(xml, baseUrl);
3131
32-
_controller.Load(tileSource, new SKDeepZoomHttpTileFetcher(new HttpClient()));
33-
34-
await InvokeAsync(StateHasChanged);
32+
_controller.Load(source, new SKDeepZoomHttpTileFetcher());
3533
}
3634
3735
private void OnPaintSurface(SKPaintSurfaceEventArgs e)
3836
{
3937
if (_controller == null) return;
40-
4138
_controller.SetControlSize(e.Info.Width, e.Info.Height);
4239
_controller.Update();
4340
_controller.Render(e.Surface.Canvas);
@@ -46,7 +43,7 @@ Use `SKDeepZoomController` with a plain `SKCanvasView` to render Deep Zoom image
4643
private void OnInvalidateRequired(object? sender, EventArgs e)
4744
=> InvokeAsync(() => _canvas?.Invalidate());
4845
49-
public void Dispose()
46+
public async ValueTask DisposeAsync()
5047
{
5148
if (_controller != null)
5249
{
@@ -59,7 +56,7 @@ Use `SKDeepZoomController` with a plain `SKCanvasView` to render Deep Zoom image
5956

6057
## Serving Tile Assets
6158

62-
Place `.dzi` and tile folder under `wwwroot`. In the project file, reference them as content:
59+
Place `.dzi` and tile folder under `wwwroot`. In the project file, mark them as content:
6360

6461
```xml
6562
<ItemGroup>
@@ -68,16 +65,98 @@ Place `.dzi` and tile folder under `wwwroot`. In the project file, reference the
6865
</ItemGroup>
6966
```
7067

71-
The `SKDeepZoomHttpTileFetcher` fetches each tile URL via `HttpClient`; tile URLs are constructed automatically from the base URL you supply to `SKDeepZoomImageSource.Parse`.
68+
The `SKDeepZoomHttpTileFetcher` fetches each tile via `HttpClient`; tile URLs are constructed automatically from the base URL you pass to `SKDeepZoomImageSource.Parse`.
69+
70+
## Pan and Zoom
71+
72+
Wire mouse and touch events to the controller's navigation methods:
73+
74+
```razor
75+
<SKCanvasView @ref="_canvas"
76+
OnPaintSurface="OnPaintSurface"
77+
@onmousedown="OnMouseDown"
78+
@onmousemove="OnMouseMove"
79+
@onmouseup="OnMouseUp"
80+
@onwheel="OnWheel"
81+
style="width: 100%; height: 600px; touch-action: none;" />
82+
83+
@code {
84+
private bool _dragging;
85+
private double _lastX, _lastY;
86+
87+
private void OnMouseDown(MouseEventArgs e)
88+
{
89+
_dragging = true;
90+
_lastX = e.ClientX;
91+
_lastY = e.ClientY;
92+
}
93+
94+
private void OnMouseMove(MouseEventArgs e)
95+
{
96+
if (!_dragging || _controller == null) return;
97+
_controller.Pan(e.ClientX - _lastX, e.ClientY - _lastY);
98+
_lastX = e.ClientX;
99+
_lastY = e.ClientY;
100+
_canvas?.Invalidate();
101+
}
102+
103+
private void OnMouseUp(MouseEventArgs e) => _dragging = false;
104+
105+
private void OnWheel(WheelEventArgs e)
106+
{
107+
if (_controller == null) return;
108+
double factor = e.DeltaY < 0 ? 1.15 : 1.0 / 1.15;
109+
_controller.ZoomAboutScreenPoint(factor, e.OffsetX, e.OffsetY);
110+
_canvas?.Invalidate();
111+
}
112+
}
113+
```
114+
115+
## Loading a DZC Collection
116+
117+
```csharp
118+
var xml = await Http.GetStringAsync("collection.dzc");
119+
var collection = SKDeepZoomCollectionSource.Parse(xml);
120+
collection.TilesBaseUri = Http.BaseAddress!.ToString();
121+
_controller!.Load(collection, new SKDeepZoomHttpTileFetcher());
122+
```
123+
124+
## Custom Cache
125+
126+
Pass a custom `ISKDeepZoomTileCache` to the controller for tiered caching or controlled experiments:
127+
128+
```csharp
129+
// Custom in-memory cache with explicit capacity
130+
var cache = new SKDeepZoomMemoryTileCache(maxEntries: 512);
131+
_controller = new SKDeepZoomController(cache: cache);
132+
```
133+
134+
See the [Caching docs](deep-zoom-caching.md) for implementing browser storage tiers, delay wrappers, and other custom strategies.
135+
136+
## Canvas Resize
137+
138+
When the Blazor page resizes, `SetControlSize` automatically picks up the new dimensions on the next paint. If you want to trigger a reset to fit the image after a resize:
139+
140+
```csharp
141+
// In a JS interop resize callback:
142+
[JSInvokable]
143+
public void OnCanvasResized()
144+
{
145+
_controller?.ResetView();
146+
InvokeAsync(() => _canvas?.Invalidate());
147+
}
148+
```
72149

73150
## Rendering Behaviour
74151

75-
- **Fit and center**: On load the controller calls `FitToView()` so the full image is visible and centered in the canvas. Neither cropping nor distortion occurs.
76-
- **Tile resolution**: `Update()` selects the pyramid level whose tile size best matches the physical pixel dimensions of the canvas. Only visible tiles are requested.
77-
- **Tile blending**: While high-resolution tiles are in-flight, parent-level tiles are upscaled and drawn as placeholders.
152+
- **Fit and center**: On load the controller calls `FitToView()` the full image is visible, centered horizontally and vertically, with aspect ratio preserved. No cropping or distortion.
153+
- **LOD blending**: While high-resolution tiles are in-flight, lower-resolution parent tiles are upscaled and composited as placeholders.
154+
- **Idle detection**: `controller.IsIdle` is `true` when no tiles are loading. You can pause periodic repaints when the view is idle.
78155

79156
## Related
80157

81-
- [Deep Zoom overview](deep-zoom.md) — architecture, services, and API reference
82-
- [Deep Zoom for MAUI](deep-zoom-maui.md) — .NET MAUI integration
83-
158+
- [Deep Zoom overview](deep-zoom.md)
159+
- [Controller & Viewport](deep-zoom-controller.md)
160+
- [Tile Fetching](deep-zoom-fetching.md)
161+
- [Caching](deep-zoom-caching.md)
162+
- [Deep Zoom for MAUI](deep-zoom-maui.md)

0 commit comments

Comments
 (0)