aboutsummaryrefslogtreecommitdiffstats
path: root/web_src/js/features/comp/Cropper.ts
blob: aaa169115238d649040b43a34fc9e22c80f824dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import {showElem, type DOMEvent} from '../../utils/dom.ts';

type CropperOpts = {
  container: HTMLElement,
  imageSource: HTMLImageElement,
  fileInput: HTMLInputElement,
}

async function initCompCropper({container, fileInput, imageSource}: CropperOpts) {
  const {default: Cropper} = await import(/* webpackChunkName: "cropperjs" */'cropperjs');
  let currentFileName = '';
  let currentFileLastModified = 0;
  const cropper = new Cropper(imageSource, {
    aspectRatio: 1,
    viewMode: 2,
    autoCrop: false,
    crop() {
      const canvas = cropper.getCroppedCanvas();
      canvas.toBlob((blob) => {
        const croppedFileName = currentFileName.replace(/\.[^.]{3,4}$/, '.png');
        const croppedFile = new File([blob], croppedFileName, {type: 'image/png', lastModified: currentFileLastModified});
        const dataTransfer = new DataTransfer();
        dataTransfer.items.add(croppedFile);
        fileInput.files = dataTransfer.files;
      });
    },
  });

  fileInput.addEventListener('input', (e: DOMEvent<Event, HTMLInputElement>) => {
    const files = e.target.files;
    if (files?.length > 0) {
      currentFileName = files[0].name;
      currentFileLastModified = files[0].lastModified;
      const fileURL = URL.createObjectURL(files[0]);
      imageSource.src = fileURL;
      cropper.replace(fileURL);
      showElem(container);
    }
  });
}

export async function initAvatarUploaderWithCropper(fileInput: HTMLInputElement) {
  const panel = fileInput.nextElementSibling as HTMLElement;
  if (!panel?.matches('.cropper-panel')) throw new Error('Missing cropper panel for avatar uploader');
  const imageSource = panel.querySelector<HTMLImageElement>('.cropper-source');
  await initCompCropper({container: panel, fileInput, imageSource});
}