107 lines
2.8 KiB
TypeScript
107 lines
2.8 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import * as React from 'react';
|
||
|
|
import { ZoomIn, ZoomOut, Maximize2, ChevronsUpDown, ChevronsLeftRight } from 'lucide-react';
|
||
|
|
import { Button } from '@/components/ui/Button';
|
||
|
|
import { Slider } from '@/components/ui/Slider';
|
||
|
|
import { cn } from '@/lib/utils/cn';
|
||
|
|
|
||
|
|
export interface ZoomControlsProps {
|
||
|
|
zoom: number;
|
||
|
|
onZoomChange: (zoom: number) => void;
|
||
|
|
amplitudeScale: number;
|
||
|
|
onAmplitudeScaleChange: (scale: number) => void;
|
||
|
|
onZoomIn: () => void;
|
||
|
|
onZoomOut: () => void;
|
||
|
|
onFitToView: () => void;
|
||
|
|
className?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function ZoomControls({
|
||
|
|
zoom,
|
||
|
|
onZoomChange,
|
||
|
|
amplitudeScale,
|
||
|
|
onAmplitudeScaleChange,
|
||
|
|
onZoomIn,
|
||
|
|
onZoomOut,
|
||
|
|
onFitToView,
|
||
|
|
className,
|
||
|
|
}: ZoomControlsProps) {
|
||
|
|
return (
|
||
|
|
<div className={cn('space-y-4', className)}>
|
||
|
|
{/* Horizontal Zoom */}
|
||
|
|
<div className="space-y-2">
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<label className="text-sm font-medium text-foreground flex items-center gap-2">
|
||
|
|
<ChevronsLeftRight className="h-4 w-4" />
|
||
|
|
Horizontal Zoom
|
||
|
|
</label>
|
||
|
|
<span className="text-sm text-muted-foreground">{zoom.toFixed(1)}x</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Button
|
||
|
|
variant="outline"
|
||
|
|
size="icon"
|
||
|
|
onClick={onZoomOut}
|
||
|
|
disabled={zoom <= 1}
|
||
|
|
title="Zoom Out"
|
||
|
|
className="h-8 w-8"
|
||
|
|
>
|
||
|
|
<ZoomOut className="h-4 w-4" />
|
||
|
|
</Button>
|
||
|
|
|
||
|
|
<Slider
|
||
|
|
value={zoom}
|
||
|
|
onChange={onZoomChange}
|
||
|
|
min={1}
|
||
|
|
max={20}
|
||
|
|
step={0.5}
|
||
|
|
className="flex-1"
|
||
|
|
/>
|
||
|
|
|
||
|
|
<Button
|
||
|
|
variant="outline"
|
||
|
|
size="icon"
|
||
|
|
onClick={onZoomIn}
|
||
|
|
disabled={zoom >= 20}
|
||
|
|
title="Zoom In"
|
||
|
|
className="h-8 w-8"
|
||
|
|
>
|
||
|
|
<ZoomIn className="h-4 w-4" />
|
||
|
|
</Button>
|
||
|
|
|
||
|
|
<Button
|
||
|
|
variant="outline"
|
||
|
|
size="icon"
|
||
|
|
onClick={onFitToView}
|
||
|
|
title="Fit to View"
|
||
|
|
className="h-8 w-8"
|
||
|
|
>
|
||
|
|
<Maximize2 className="h-4 w-4" />
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Vertical (Amplitude) Zoom */}
|
||
|
|
<div className="space-y-2">
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<label className="text-sm font-medium text-foreground flex items-center gap-2">
|
||
|
|
<ChevronsUpDown className="h-4 w-4" />
|
||
|
|
Amplitude Zoom
|
||
|
|
</label>
|
||
|
|
<span className="text-sm text-muted-foreground">{amplitudeScale.toFixed(1)}x</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<Slider
|
||
|
|
value={amplitudeScale}
|
||
|
|
onChange={onAmplitudeScaleChange}
|
||
|
|
min={0.5}
|
||
|
|
max={5}
|
||
|
|
step={0.1}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|