Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
143 lines
4.1 KiB
Plaintext
143 lines
4.1 KiB
Plaintext
import React, { useState, useRef } from 'react'
|
|
|
|
import ReactCrop, { centerCrop, makeAspectCrop, Crop, PixelCrop } from '..'
|
|
import { canvasPreview } from './canvasPreview'
|
|
import { useDebounceEffect } from './useDebounceEffect'
|
|
|
|
import '../ReactCrop.scss'
|
|
import './index.scss'
|
|
|
|
// This is to demonstate how to make and center a % aspect crop
|
|
// which is a bit trickier so we use some helper functions.
|
|
function centerAspectCrop(mediaWidth: number, mediaHeight: number, aspect: number) {
|
|
return centerCrop(
|
|
makeAspectCrop(
|
|
{
|
|
unit: '%',
|
|
width: 90,
|
|
},
|
|
aspect,
|
|
mediaWidth,
|
|
mediaHeight
|
|
),
|
|
mediaWidth,
|
|
mediaHeight
|
|
)
|
|
}
|
|
|
|
// const defaultAspect = 9 / 16
|
|
const defaultAspect = 16 / 9
|
|
|
|
export function Demo() {
|
|
const [imgSrc, setImgSrc] = useState('')
|
|
const previewCanvasRef = useRef<HTMLCanvasElement>(null)
|
|
const imgRef = useRef<HTMLImageElement>(null)
|
|
const [crop, setCrop] = useState<Crop>()
|
|
const [completedCrop, setCompletedCrop] = useState<PixelCrop>()
|
|
const [scale, setScale] = useState(1)
|
|
const [rotate, setRotate] = useState(0)
|
|
const [aspect, setAspect] = useState<number | undefined>(defaultAspect)
|
|
|
|
function onSelectFile(e: React.ChangeEvent<HTMLInputElement>) {
|
|
if (e.target.files && e.target.files.length > 0) {
|
|
setCrop(undefined) // Makes crop preview update between images.
|
|
const reader = new FileReader()
|
|
reader.addEventListener('load', () => setImgSrc(reader.result?.toString() || ''))
|
|
reader.readAsDataURL(e.target.files[0])
|
|
}
|
|
}
|
|
|
|
function onImageLoad(e: React.SyntheticEvent<HTMLImageElement>) {
|
|
if (aspect) {
|
|
const { width, height } = e.currentTarget
|
|
setCrop(centerAspectCrop(width, height, aspect))
|
|
}
|
|
}
|
|
|
|
useDebounceEffect(
|
|
async () => {
|
|
if (completedCrop?.width && completedCrop?.height && imgRef.current && previewCanvasRef.current) {
|
|
// We use canvasPreview as it's much faster than imgPreview.
|
|
canvasPreview(imgRef.current, previewCanvasRef.current, completedCrop, scale, rotate)
|
|
}
|
|
},
|
|
100,
|
|
[completedCrop, scale, rotate]
|
|
)
|
|
|
|
function handleToggleAspectClick() {
|
|
if (aspect) {
|
|
setAspect(undefined)
|
|
} else {
|
|
setAspect(defaultAspect)
|
|
if (imgRef.current) {
|
|
const { width, height } = imgRef.current
|
|
setCrop(centerAspectCrop(width, height, defaultAspect))
|
|
}
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="App">
|
|
<div className="Crop-Controls">
|
|
<input type="file" accept="image/*" onChange={onSelectFile} />
|
|
<div>
|
|
<label htmlFor="scale-input">Scale: </label>
|
|
<input
|
|
id="scale-input"
|
|
type="number"
|
|
step="0.1"
|
|
value={scale}
|
|
disabled={!imgSrc}
|
|
onChange={e => setScale(Number(e.target.value))}
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label htmlFor="rotate-input">Rotate: </label>
|
|
<input
|
|
id="rotate-input"
|
|
type="number"
|
|
value={rotate}
|
|
disabled={!imgSrc}
|
|
onChange={e => setRotate(Math.min(180, Math.max(-180, Number(e.target.value))))}
|
|
/>
|
|
</div>
|
|
<div>
|
|
<button onClick={handleToggleAspectClick}>Toggle aspect {aspect ? 'off' : 'on'}</button>
|
|
</div>
|
|
</div>
|
|
{!!imgSrc && (
|
|
<ReactCrop
|
|
crop={crop}
|
|
onChange={(_, percentCrop) => setCrop(percentCrop)}
|
|
onComplete={c => setCompletedCrop(c)}
|
|
aspect={aspect}
|
|
minWidth={400}
|
|
minHeight={200}
|
|
>
|
|
<img
|
|
ref={imgRef}
|
|
alt="Crop me"
|
|
src={imgSrc}
|
|
style={{ transform: `scale(${scale}) rotate(${rotate}deg)` }}
|
|
onLoad={onImageLoad}
|
|
/>
|
|
</ReactCrop>
|
|
)}
|
|
<div>
|
|
{!!completedCrop && (
|
|
<canvas
|
|
ref={previewCanvasRef}
|
|
style={{
|
|
border: '1px solid black',
|
|
objectFit: 'contain',
|
|
width: completedCrop.width,
|
|
height: completedCrop.height,
|
|
}}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|