canvas-scale.ts 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. export const MIN_CANVAS_SCALE = 0.1
  2. export const MAX_CANVAS_SCALE = 4
  3. export const CANVAS_SCALE_STEP = 0.1
  4. export type CanvasScaleDirection = 'in' | 'out'
  5. export interface FitCanvasOptions {
  6. viewportWidth: number
  7. viewportHeight: number
  8. canvasWidth: number
  9. canvasHeight: number
  10. padding?: Partial<{
  11. top: number
  12. right: number
  13. bottom: number
  14. left: number
  15. }>
  16. }
  17. export const normalizeCanvasScale = (scale: number) => {
  18. const safeScale = Number.isFinite(scale) ? scale : 1
  19. const clampedScale = Math.min(MAX_CANVAS_SCALE, Math.max(MIN_CANVAS_SCALE, safeScale))
  20. return Math.round(clampedScale * 100) / 100
  21. }
  22. export const stepCanvasScale = (scale: number, direction: CanvasScaleDirection) =>
  23. normalizeCanvasScale(scale + (direction === 'in' ? CANVAS_SCALE_STEP : -CANVAS_SCALE_STEP))
  24. export const calculateFitCanvas = ({
  25. viewportWidth,
  26. viewportHeight,
  27. canvasWidth,
  28. canvasHeight,
  29. padding
  30. }: FitCanvasOptions) => {
  31. const safePadding = {
  32. top: Math.max(0, padding?.top ?? 24),
  33. right: Math.max(0, padding?.right ?? 24),
  34. bottom: Math.max(0, padding?.bottom ?? 72),
  35. left: Math.max(0, padding?.left ?? 24)
  36. }
  37. const availableWidth = Math.max(1, viewportWidth - safePadding.left - safePadding.right)
  38. const availableHeight = Math.max(1, viewportHeight - safePadding.top - safePadding.bottom)
  39. const safeCanvasWidth = Math.max(1, canvasWidth)
  40. const safeCanvasHeight = Math.max(1, canvasHeight)
  41. const scale = normalizeCanvasScale(
  42. Math.min(availableWidth / safeCanvasWidth, availableHeight / safeCanvasHeight)
  43. )
  44. return {
  45. scale,
  46. transformOrigin: { x: 0, y: 0 },
  47. dragOffset: {
  48. x: Math.round(safePadding.left + (availableWidth - safeCanvasWidth * scale) / 2),
  49. y: Math.round(safePadding.top + (availableHeight - safeCanvasHeight * scale) / 2)
  50. }
  51. }
  52. }