Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CropperJS] Edit the cropper image #2380

Open
RehArk opened this issue Nov 15, 2024 · 1 comment
Open

[CropperJS] Edit the cropper image #2380

RehArk opened this issue Nov 15, 2024 · 1 comment
Labels

Comments

@RehArk
Copy link

RehArk commented Nov 15, 2024

Hi everyone, I need to crop my image based on my file input, but the cropper is not allowing me to edit the image. I want to know if it is possible to do something like this to update the cropper:

import { Controller } from '@hotwired/stimulus';
import Cropper from 'cropperjs';
import CropEvent = Cropper.CropEvent;

export default class CropperController extends Controller {
    declare readonly publicUrlValue: string;
    declare readonly optionsValue: object;
    declare img: HTMLImageElement;
    declare cropper: Cropper;

    static values = {
        publicUrl: String,
        options: Object,
        img: HTMLImageElement,
        cropper: Cropper
    };

    connect() {
        this.initializeCropper();
    }

    initializeCropper() {
        // Remove any existing cropper image and instance before initializing
        if (this.img) {
            this.img.remove();
        }
        if (this.cropper) {
            this.cropper.destroy();
        }

        // Create image view
        this.img = document.createElement('img');
        this.img.classList.add('cropperjs-image');
        this.img.src = this.publicUrlValue; // The current image URL value

        const parent = this.element.parentNode;
        if (!parent) {
            throw new Error('Missing parent node for Cropperjs');
        }

        parent.appendChild(this.img);

        // Options for the cropper instance
        const options = this.optionsValue;

        // Dispatch pre-connect event
        this.dispatchEvent('pre-connect', { options, img: this.img });

        // Build the cropper with the given image and options
        this.cropper = new Cropper(this.img, options);

        // Event listener to update the input value on crop
        this.img.addEventListener('crop', (event) => {
            (this.element as HTMLInputElement).value = JSON.stringify((event as CropEvent).detail);
        });

        // Dispatch connect event
        this.dispatchEvent('connect', { cropper: this.cropper, options, img: this.img });
    }

    // Method to update the image URL and reinitialize the cropper
    updateImage(newImageUrl) {
        this.img.src = newImageUrl; // Update the public URL value
        this.initializeCropper(); // Reinitialize the cropper with the new image
    }

    disconnect() {
        if (this.cropper) {
            this.cropper.destroy();
        }
        if (this.img) {
            this.img.remove();
        }
    }

    // Helper method to dispatch events
    private dispatchEvent(name: string, payload: any) {
        this.dispatch(name, { detail: payload, prefix: 'cropperjs' });
    }
}
@RehArk RehArk added the RFC label Nov 15, 2024
@smnandre smnandre changed the title Edit the cropper image [CropperJS] Edit the cropper image Nov 19, 2024
@smnandre
Copy link
Member

I’m not entirely sure about the expected behavior you’re aiming for.

The current CropperJS implementation is designed to crop an existing image, and adapting it to work with non-uploaded images would require quite a few changes to its code. :/

    // Method to update the image URL and reinitialize the cropper
    updateImage(newImageUrl) {
        this.img.src = newImageUrl; // Update the public URL value
        this.initializeCropper(); // Reinitialize the cropper with the new image
    }

This snippet wouldn’t work as expected because this.img gets reset right after the line // Create image view. I suppose you meant to reference this.publicUrl instead?

If you need this kind of behavior, one possible solution could be to set the initial HTML inside a <template> tag and dynamically create the <div> whenever you have a new imageUrl.

Alternatively, maybe consider a custom controller? You could use the various events dispatched by the UX controller?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants