added fit to page button for canvas

This commit is contained in:
Kilian Schüttler 2025-03-25 18:13:47 +01:00
parent fcfa06f691
commit 5227c0acea
2 changed files with 58 additions and 31 deletions

View File

@ -1,35 +1,45 @@
<script lang="ts"> <script lang="ts">
import { import {
ZoomInOutline, ZoomInOutline,
ZoomOutOutline, ZoomOutOutline,
RefreshOutline, RefreshOutline,
} from "flowbite-svelte-icons"; MinimizeOutline
} from 'flowbite-svelte-icons';
let { let {
scale, scale,
onZoomIn, onZoomIn,
onZoomOut, onZoomOut,
resetZoom, resetZoom,
}: { fit,
scale: number; showFit
onZoomIn: () => void; }: {
onZoomOut: () => void; scale: number;
resetZoom: () => void; onZoomIn: () => void;
} = $props(); onZoomOut: () => void;
resetZoom: () => void;
fit: () => void;
showFit: boolean;
} = $props();
</script> </script>
<div class="controls"> <div class="controls">
<span class="zoom-level">{(scale * 100).toFixed(0)}%</span> <span class="zoom-level">{(scale * 100).toFixed(0)}%</span>
<button class="control-button" onclick={onZoomIn}> {#if showFit}
<ZoomInOutline /> <button class="control-button" onclick={fit}>
</button> <MinimizeOutline />
<button class="control-button" onclick={onZoomOut}> </button>
<ZoomOutOutline /> {/if}
</button> <button class="control-button" onclick={onZoomIn}>
<button class="control-button" onclick={resetZoom}> <ZoomInOutline />
<RefreshOutline /> </button>
</button> <button class="control-button" onclick={onZoomOut}>
<ZoomOutOutline />
</button>
<button class="control-button" onclick={resetZoom}>
<RefreshOutline />
</button>
</div> </div>
<style lang="postcss"> <style lang="postcss">

View File

@ -1,6 +1,5 @@
<script lang="ts"> <script lang="ts">
import ZoomControls from '../components/ZoomControls.svelte'; import ZoomControls from '../components/ZoomControls.svelte';
import { onMount } from 'svelte';
type ZoomableProps = { type ZoomableProps = {
minZoom?: number; minZoom?: number;
@ -12,7 +11,7 @@
}; };
let { let {
minZoom = 0.5, minZoom = 0.1,
maxZoom = 10, maxZoom = 10,
zoomStep = 0.1, zoomStep = 0.1,
imgUrl, imgUrl,
@ -21,6 +20,8 @@
}: ZoomableProps = $props(); }: ZoomableProps = $props();
let currentImgUrl = $state(imgUrl); let currentImgUrl = $state(imgUrl);
let image: HTMLImageElement | undefined = $state(undefined);
let container = $state<HTMLDivElement>();
type ViewState = { type ViewState = {
x: number; x: number;
@ -35,7 +36,6 @@
}); });
// DOM refs // DOM refs
let container = $state<HTMLElement>();
// Drag state // Drag state
type DragState = { type DragState = {
@ -94,6 +94,20 @@
dragState = undefined; dragState = undefined;
} }
function fitCanvasToPage() {
if (!canvas || !container) return;
const w = canvas.width;
const h = canvas.height;
const targetWidth = container.offsetWidth;
const targetHeight = container.offsetHeight;
const wScale = targetWidth / w;
const hScale = targetHeight / h;
viewState.scale = Math.min(maxZoom, Math.max(minZoom, Math.min(wScale, hScale)));
viewState.x = 0;
viewState.y = 0;
}
function resetZoom() { function resetZoom() {
viewState.scale = 1; viewState.scale = 1;
if (container) { if (container) {
@ -122,9 +136,11 @@
<div class="relative w-full h-full"> <div class="relative w-full h-full">
<ZoomControls <ZoomControls
scale={viewState.scale} scale={viewState.scale}
onZoomIn={() => (viewState.scale = Math.min(viewState.scale + zoomStep, maxZoom))} onZoomIn={() => (viewState.scale = Math.min(viewState.scale + (zoomStep * viewState.scale), maxZoom))}
onZoomOut={() => (viewState.scale = Math.max(viewState.scale - zoomStep, minZoom))} onZoomOut={() => (viewState.scale = Math.max(viewState.scale - (zoomStep * viewState.scale), minZoom))}
{resetZoom} {resetZoom}
fit={fitCanvasToPage}
showFit={!image}
/> />
<div <div
class="container" class="container"
@ -140,6 +156,7 @@
{#if imgUrl} {#if imgUrl}
<img <img
class="zoomimage" class="zoomimage"
bind:this={image}
alt="rendered-page" alt="rendered-page"
src={currentImgUrl} src={currentImgUrl}
style:transform="translate({viewState.x}px, {viewState.y}px) scale({viewState.scale})" style:transform="translate({viewState.x}px, {viewState.y}px) scale({viewState.scale})"