lsgraphics-cropper
v1.0.26
Published
Image and video cropper component with crop and tile modes
Maintainers
Readme
Cropper Component Library
Гибкая библиотека для кадрирования изображений и видео с поддержкой двух режимов: Crop и Tile.
📦 Установка
npm install lsgraphics-cropper
# или
yarn add lsgraphics-cropper🚀 Быстрый старт

import {Cropper, CropperProvider} from "lsgraphics-cropper"
function App() {
return (
<CropperProvider>
<Cropper
materialIndex={0}
showFileInput={true}
showZoom={true}
showSizeInputs={true}
showFileSizeAlert={true}
showModeSwitcher={true}
showMuteControl={true}
showVideoControls={true}
showProcessingControls={true}
canvasWidth={550}
canvasHeight={550}
/>
</CropperProvider>
)
}📚 Основные компоненты и хуки
CropperProvider
Контекстный провайдер для управления состоянием. Обязательно оборачивайте все Cropper компоненты.
import {CropperProvider} from "lsgraphics-cropper"
function App() {
return (
<CropperProvider>
{/* Все Cropper компоненты и хуки должны быть внутри */}
<YourComponents />
</CropperProvider>
)
}⚠️ Все хуки работают только внутри <CropperProvider>!
Cropper
Главный компонент с готовым UI.
Props
| Prop | Type | Default | Описание |
| ------------------------ | --------------------- | ------------ | ------------------------------------------ |
| materialIndex | number | required | Уникальный индекс материала |
| canvasWidth | number | 250 | Ширина холста (canvas) |
| canvasHeight | number | 250 | Высота холста (canvas) |
| showFileInput | boolean | false | Показать input для загрузки файла |
| showSizeInputs | boolean | false | Показать поля для изменения размеров |
| showModeSwitcher | boolean | false | Показать переключатель режимов (Crop/Tile) |
| showZoom | boolean | false | Показать слайдер зума |
| showVideoControls | boolean | false | Показать кнопку Play/Pause для видео |
| showProcessingControls | boolean | false | Показать кнопку обработки видео |
| showMuteControl | boolean | false | Показать чекбокс Mute |
| showFileSizeAlert | boolean | false | Показать предупреждение о размере файла |
| className | string | | CSS класс для контейнера |
| cropFrameClassName | string | | CSS класс для canvas |
| zoomSliderClassName | string | | CSS класс для слайдера |
| controlsClassName | string | | CSS класс для контролов |
| style | React.CSSProperties | | Inline стили |
🎣 Headless Хуки
Для создания кастомного UI используйте хуки.
useCropperLogic
Главный хук для управления всей логикой кроппинга.
import {useCropperLogic} from "lsgraphics-cropper"
const {
// Состояние
imageState,
cropState,
mode,
cropParams,
isProcessing,
downloadUrl,
uploadProgress,
canvasSize,
// Действия
handleImageUpload,
handleZoomChange,
handleDimensionChange,
handleModeSwitch,
handleDragStart,
handleDrag,
handleDragEnd,
handleMouseLeave,
processVideo,
downloadProcessedVideo,
// Ссылки
mainCanvasRef,
// Конфигурация
minZoom,
maxZoom,
step,
} = useCropperLogic(materialIndex, canvasWidth?, canvasHeight?)⚠️ Важно: Если вы используете одновременно useCropperLogic и компонент для одного материала, вы должны передавать одинаковые размеры canvasWidth и canvasHeight в оба места:
// ❌ Неправильно - размеры не синхронизированы const cropperLogic = useCropperLogic(0) // Дефолтные 250x250 // 500x350
// ✅ Правильно - одинаковые размеры const cropperLogic = useCropperLogic(0, 500, 350) // 500x350 // 500x350
Параметры
| Параметр | Type | Описание |
| --------------- | -------- | --------------------------- |
| materialIndex | number | Уникальный индекс материала |
| canvasWidth | number | Ширина холста (опционально) |
| canvasHeight | number | Высота холста (опционально) |
Возвращаемые значения
| Свойство | Type | Описание |
| ------------------------ | ------------------------------------------------- | ---------------------------------------------------------------- |
| Состояние |
| imageState | ImageState | Состояние изображения (status, position, zoom, dimensions, file) |
| cropState | CropState | Состояние кадрирования (dimensions, isDragging) |
| mode | 'crop' \| 'tile' | Текущий режим |
| cropParams | CropParams \| null | Параметры для обработки на бэкенде/Three.js |
| isProcessing | boolean | Идет ли обработка видео |
| downloadUrl | string \| null | URL обработанного видео |
| uploadProgress | number | Прогресс загрузки (0-100) |
| canvasSize | {width: number, height: number} | Текущий размер холста |
| Действия |
| handleImageUpload | (file: File) => void | Загрузить изображение/видео |
| handleZoomChange | (zoom: number) => void | Изменить зум |
| handleDimensionChange | (dim: 'width'\|'height', value: string) => void | Изменить размеры |
| handleModeSwitch | (mode: 'crop'\|'tile') => void | Переключить режим |
| handleDragStart | (e: React.MouseEvent) => void | Начать перетаскивание |
| handleDrag | (e: React.MouseEvent) => void | Перетаскивание |
| handleDragEnd | () => void | Завершить перетаскивание |
| handleMouseLeave | () => void | Мышь покинула canvas |
| processVideo | () => Promise<void> | Обработать видео на сервере |
| downloadProcessedVideo | (url: string) => void | Скачать обработанное видео |
| setCanvasSize | (size: {width: number, height: number}) => void | Изменить размер холста |
| Ссылки |
| mainCanvasRef | RefObject<HTMLCanvasElement> | Ref для canvas элемента |
| Конфигурация |
| minZoom | number | Минимальный зум |
| maxZoom | number | Максимальный зум |
| step | number | Шаг изменения зума |
Пример кастомного UI
import {
useCropperLogic,
useVideoControls,
CropperProvider,
} from "lsgraphics-cropper"
function CustomCropper() {
const {
imageState,
cropState,
cropParams,
handleImageUpload,
handleModeSwitch,
handleZoomChange,
handleDimensionChange,
handleDragStart,
handleDrag,
handleDragEnd,
handleMouseLeave,
processVideo,
isProcessing,
uploadProgress,
mainCanvasRef,
minZoom,
maxZoom,
step,
canvasSize,
setCanvasSize,
} = useCropperLogic(0, 400, 300) // ← Передаем размеры
const {isVideoPlaying, isMuted, toggleVideoPlaying, toggleMute} =
useVideoControls(0)
// Видео автоматически скачивается после обработки на сервере.
return (
<div>
{/* File Input */}
<input
type="file"
accept="image/*,video/*"
onChange={(e) => {
const file = e.target.files?.[0]
if (file) handleImageUpload(file)
}}
/>
{/* Изменение размера холста */}
<button onClick={() => setCanvasSize({width: 800, height: 600})}>
Увеличить холст
</button>
{imageState.status === "loaded" && (
<>
{/* Mode Switcher */}
{!imageState.videoUrl && (
<div>
<button onClick={() => handleModeSwitch("crop")}>
Crop Mode
</button>
<button onClick={() => handleModeSwitch("tile")}>
Tile Mode
</button>
</div>
)}
{/* Canvas */}
<canvas
ref={mainCanvasRef}
onMouseDown={handleDragStart}
onMouseMove={handleDrag}
onMouseUp={handleDragEnd}
onMouseLeave={handleMouseLeave}
width={canvasSize.width}
height={canvasSize.height}
/>
{/* Zoom Slider */}
<input
type="range"
value={imageState.zoom}
min={minZoom}
max={maxZoom}
step={step}
onChange={(e) =>
handleZoomChange(Number(e.target.value))
}
/>
<span>Zoom: {imageState.zoom}%</span>
{/* Size Inputs */}
<div>
<label>
Width:
<input
type="number"
value={cropState.dimensions.width}
onChange={(e) =>
handleDimensionChange(
"width",
e.target.value
)
}
/>
</label>
<label>
Height:
<input
type="number"
value={cropState.dimensions.height}
onChange={(e) =>
handleDimensionChange(
"height",
e.target.value
)
}
/>
</label>
</div>
{/* Video Controls */}
{imageState.videoUrl && (
<>
<label>
<input
type="checkbox"
checked={isMuted}
onChange={toggleMute}
/>
Mute sound
</label>
<button onClick={toggleVideoPlaying}>
{isVideoPlaying ? "Pause" : "Play"}
</button>
<button
onClick={processVideo}
disabled={isProcessing}
>
{isProcessing
? "Processing..."
: "Process Video"}
</button>
{isProcessing && (
<div
style={{
width: "100%",
height: "4px",
background: "#e5e7eb",
}}
>
<div
style={{
width: `${uploadProgress}%`,
height: "100%",
background: "#3b82f6",
transition: "width 0.3s",
}}
/>
</div>
)}
</>
)}
{/* Crop Params */}
{cropParams && (
<pre>{JSON.stringify(cropParams, null, 2)}</pre>
)}
</>
)}
</div>
)
}
// Обязательно оборните в Provider
function App() {
return (
<CropperProvider>
<CustomCropper />
</CropperProvider>
)
}useVideoControls
Хук для управления видео (play/pause/mute).
import {useVideoControls} from "lsgraphics-cropper"
const {
isVideoPlaying,
isMuted,
toggleVideoPlaying,
toggleMute,
isVideoDisabled,
} = useVideoControls(materialIndex)Параметры
| Параметр | Type | Описание |
| --------------- | -------- | ---------------- |
| materialIndex | number | Индекс материала |
Возвращаемые значения
| Свойство | Type | Описание |
| -------------------- | ------------------------------ | ---------------------------- |
| isVideoPlaying | boolean | Играет ли видео |
| isMuted | boolean | Выключен ли звук |
| toggleVideoPlaying | () => void | Переключить play/pause |
| toggleMute | () => void | Переключить mute |
| isVideoDisabled | (imageState: any) => boolean | Проверить disabled состояние |
Пример
function VideoControls() {
const {imageState} = useCropperLogic(0)
const {
isVideoPlaying,
isMuted,
toggleVideoPlaying,
toggleMute,
isVideoDisabled,
} = useVideoControls(0)
if (!imageState.videoUrl) return null
const disabled = isVideoDisabled(imageState)
return (
<div>
<button onClick={toggleVideoPlaying}>
{isVideoPlaying ? "Pause" : "Play"}
</button>
<label>
<input
type="checkbox"
checked={isMuted}
onChange={toggleMute}
/>
Mute
</label>
<p>Interface disabled: {disabled ? "Yes" : "No"}</p>
</div>
)
}getVideoElements
Утилита для получения всех видео элементов из кропперов. Полезна когда нужно управлять всеми видео одновременно с кешированием для производительности.
import {getVideoElements} from "lsgraphics-cropper"Возвращаемое значение
| Тип | Описание |
| ------------------------------------ | ---------------------------------------------------- |
| HTMLCollectionOf<HTMLVideoElement> | Коллекция всех видео элементов с классом cropVideo |
syncVideoWithTimeline
Утилита для синхронизации текущего времени всех видео с прогрессом таймлайна. Используется при ручной перемотке.
import {syncVideoWithTimeline} from "lsgraphics-cropper"
// При перемотке ползунка таймлайна
syncVideoWithTimeline(0.5) // Устанавливает видео на 50% их длительностиПараметры
| Параметр | Type | Описание |
| ---------- | -------- | ------------------------ |
| progress | number | Прогресс таймлайна (0-1) |
Пример
import {syncVideoWithTimeline} from "lsgraphics-cropper"
function handleSliderChange(value: number) {
const progress = value / 100 // 0-1
syncVideoWithTimeline(progress)
}⚠️ Использовать только для ручной перемотки, не для воспроизведения! При play/pause видео должно играть само через .play()/.pause()
useCropper
Низкоуровневый хук для прямого доступа к Context.
import {useCropper} from "lsgraphics-cropper"
const cropper = useCropper(materialIndex)
// Прямое управление состоянием
cropper?.setImageState({zoom: 150})
cropper?.setCropState({dimensions: {width: 3000, height: 2000}})
cropper?.setMode("tile")
cropper?.setCanvasSize({width: 800, height: 600}) // ← Изменить размер холста⚠️ Используйте только если useCropperLogic или useImageCrop недостаточно!
⚠️ Может вернуть null если материал не инициализирован!
useCropperReset
Хук для сброса состояния материалов (полезно при смене 3D модели).
import {useCropperReset} from "lsgraphics-cropper"
const {resetAllMaterials, resetMaterial} = useCropperReset()
// Сбросить все материалы
resetAllMaterials()
// Сбросить конкретный материал
resetMaterial(0)Возвращаемые значения
| Свойство | Type | Описание |
| ------------------- | ------------------------- | ---------------------------- |
| resetAllMaterials | () => void | Сбросить все материалы |
| resetMaterial | (index: number) => void | Сбросить конкретный материал |
Пример
function SceneManager() {
const {resetAllMaterials} = useCropperReset()
useEffect(() => {
// При смене 3D модели сбрасываем все материалы
resetAllMaterials()
}, [modelId])
return null
}Доступные данные из cropper
const cropper = useCropper(materialIndex)
// Данные изображения
cropper.imageState.status // 'initial' | 'loaded'
cropper.imageState.file // File объект
cropper.imageState.imgUrl // Data URL (base64)
cropper.imageState.videoUrl // Для видео
cropper.imageState.dimensions // {width, height} в пикселях
cropper.imageState.position // {x, y} в canvas
cropper.imageState.zoom // 100-400
// Параметры обрезки для бэкенда/текстуры
cropper.cropParams.offsetX // 0-1
cropper.cropParams.offsetY // 0-1
cropper.cropParams.repeatX // 0-1
cropper.cropParams.repeatY // 0-1
cropper.cropParams.mode // 'crop' | 'tile'
cropper.cropParams.cropWidth // Целевая ширина
cropper.cropParams.cropHeight // Целевая высота
// Размеры области обрезки
cropper.cropState.dimensions // {width, height}
// Режим работы
cropper.mode // 'crop' | 'tile'