@mark1505

Почему возникает TypeError: Illegal invocation при вызове drawImage у canvas'а?

В чём ошибка в typescript при использовании плагина react-image-crop?

import React, { FC, useState, useRef, useCallback } from 'react';
import ReactCrop, { Crop } from 'react-image-crop';
import 'react-image-crop/dist/ReactCrop.css';
import Icon from '../icon/Icon';
import Style from './CropImage.module.scss';

const CropImage: FC = () => {
  const imgRef = useRef<any>();
  const [crop, setCrop] = useState<Crop>({
    unit: 'px',
    x: 130,
    y: 36,
    width: 320,
    height: 320
  });
  const [imageSrc, setImageSrc] = useState<any>();
  const onSelectFile = (event: React.ChangeEvent<HTMLInputElement>) => {
    if (event.target.files && event.target.files.length > 0) {
      const reader = new FileReader();
      reader.addEventListener('load', () => setImageSrc(reader.result));
      reader.readAsDataURL(event.target.files[0]);
    }
  };

  const [image, setImage] = useState<HTMLImageElement>();
  const [result, setResult] = useState<any>();

  const onLoad = useCallback((img: any) => {
    setImage(img);
  }, []);

  const getCroppedImg = () => {
    if (image) {
      const canvas = document.createElement('canvas') as HTMLCanvasElement;
      const scaleX = image.naturalWidth / image.width;
      const scaleY = image.naturalHeight / image.height;
      canvas.width = crop.width;
      canvas.height = crop.height;
      const { drawImage } = canvas.getContext('2d') as CanvasRenderingContext2D;

      drawImage(
        image,
        crop.x * scaleX,
        crop.y * scaleY,
        crop.width * scaleX,
        crop.height * scaleY,
        0,
        0,
        crop.width,
        crop.height
      );
      const base64Image = canvas.toDataURL('image/jpeg');
      setResult(base64Image);
    }
  };

  return (
    <div>
      {!imageSrc ? (
        <label className={Style.inputImage}>
          <input type="file" accept="image/*" onChange={onSelectFile} />
          <Icon id="attach" width={24} height={22} />
          <span>Upload a photo</span>
        </label>
      ) : null}
      {imageSrc ? (
        <div className={Style.cropWrapper}>
          <ReactCrop crop={crop} onChange={(c) => setCrop(c)} aspect={1 / 1}>
            <img ref={imgRef} src={imageSrc} onLoad={onLoad} />
          </ReactCrop>
        </div>
      ) : null}
      <button onClick={getCroppedImg}>click</button>
      {result ? <img src={result} /> : null}
    </div>
  );
};

export default CropImage;

Ошибка появляется, когда хочу получить обрезанную картинку:

630865df3fac7009957653.jpeg
  • Вопрос задан
  • 158 просмотров
Решения вопроса 2
0xD34F
@0xD34F Куратор тега JavaScript
const { drawImage } = canvas.getContext('2d') as CanvasRenderingContext2D;

drawImage(
  ...

Откуда вы взяли, что методы контекста можно вызывать в отрыве от, м-м-м, КОНТЕКСТА?

Что у вас происходит, поясняю на пальцах:

const obj = {
  fucking_value: 666,
  fucking_method() {
    if (!this.hasOwnProperty('fucking_value')) {
      throw 'FUCK OFF';
    }

    console.log(this.fucking_value);
  },
};

const { fucking_method } = obj;
fucking_method();

Если вдруг не поняли, то...
...вот бы узнать - а какого хрена вы взялись за react (кстати, а при чём он здесь? да не при чём, как и ts), обладая нулевыми знаниями js?

Ключевое слово this - бегом гуглить, разбираться, что это, зачем, к каким значениям в каких случаях даёт доступ.
Ответ написан
@mark1505 Автор вопроса
import React, { FC, useState, useRef, useCallback } from 'react';
import ReactCrop, { Crop } from 'react-image-crop';
import 'react-image-crop/dist/ReactCrop.css';
import Icon from '../icon/Icon';
import Style from './CropImage.module.scss';

const CropImage: FC = () => {
  const imgRef = useRef();
  const [crop, setCrop] = useState<Crop>({
    unit: 'px',
    x: 130,
    y: 36,
    width: 320,
    height: 320
  });
  const [result, setResult] = useState('');
  const [imageSrc, setImageSrc] = useState<any>();
  const [image, setImage] = useState<HTMLImageElement>();
  const onSelectFile = (event: React.ChangeEvent<HTMLInputElement>) => {
    if (event.target.files && event.target.files.length > 0) {
      const reader = new FileReader();
      reader.addEventListener('load', () => setImageSrc(reader.result));
      reader.readAsDataURL(event.target.files[0]);
    }
  };

  const onLoad = useCallback((evt: any) => setImage(evt.target), []);

  const getCroppedImg = () => {
    if (image) {
      const canvas = document.createElement('canvas') as HTMLCanvasElement;
      const scaleX = image.naturalWidth / image.width;
      const scaleY = image.naturalHeight / image.height;
      canvas.width = crop.width;
      canvas.height = crop.height;

      canvas
        .getContext('2d')!
        .drawImage(
          image,
          crop.x * scaleX,
          crop.y * scaleY,
          crop.width * scaleX,
          crop.height * scaleY,
          0,
          0,
          crop.width,
          crop.height
        );
      const base64Image = canvas.toDataURL('image/jpeg');
      setResult(base64Image);
    }
  };

  return (
    <div>
      {!imageSrc ? (
        <label className={Style.inputImage}>
          <input type="file" accept="image/*" onChange={onSelectFile} />
          <Icon id="attach" width={24} height={22} />
          <span>Upload a photo</span>
        </label>
      ) : null}
      {imageSrc ? (
        <div className={Style.cropWrapper}>
          <ReactCrop crop={crop} onChange={(c) => setCrop(c)} aspect={1 / 1}>
            <img ref={imgRef} src={imageSrc} onLoad={onLoad} />
          </ReactCrop>
        </div>
      ) : null}
      {result ? (
        <a href={result} download>
          click
        </a>
      ) : null}
    </div>
  );
};

export default CropImage;
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы