npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

lsgraphics-cropper

v1.0.26

Published

Image and video cropper component with crop and tile modes

Readme

Cropper Component Library

Гибкая библиотека для кадрирования изображений и видео с поддержкой двух режимов: Crop и Tile.

📦 Установка

npm install lsgraphics-cropper
# или
yarn add lsgraphics-cropper

🚀 Быстрый старт

Cropper example

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'