aico-image-editor
Version:
Combine multiple image into and create single combined image
341 lines (304 loc) • 12.3 kB
JavaScript
import Cropper from 'cropperjs';
const elementStore = Alpine.store('elements');
Alpine.store('uploadStore', {
uploadFilesToServer(uploadObj) {
const {files,action, type, imageType, originalFile,cropperData} = uploadObj;
const canvasStore = Alpine.store('canvas');
const formData = new FormData();
formData.append('configuratorId', canvasStore.configuratorId)
// append productId when configuratorId is null to first time save as create configurator endpoint
if(!canvasStore.configuratorId){
formData.append('productId', canvasStore.productId)
}
imageType && formData.append('imageType', imageType)
cropperData && formData.append('cropperData[]', JSON.stringify(cropperData));
originalFile && formData.append('originalFiles[]', originalFile);
for (const file of files) {
formData.append(type, file) // appending every file to formdata
}
//console.log(formData.get('backgrounds'))
if(type === 'hexCode') {
canvasStore.isColorBlockLoaderVisible = true;
} else {
canvasStore.isServerLoaderTabVisible = true;
}
return fetch(action, {
method: "POST",
body: formData,
// "timeout": 0,
headers: {
"Authorization": `Bearer ${canvasStore.apiConfig.apiToken}`,
},
redirect: 'follow'
})
.then((response) => {
return response.json()
})
.then((data) => {
canvasStore.isServerLoaderTabVisible = canvasStore.isColorBlockLoaderVisible = false;
canvasStore.configuratorId = data.data.configuratorId;
//console.log(data);
return data;
})
.catch((error) => {
canvasStore.isServerLoaderTabVisible = canvasStore.isColorBlockLoaderVisible = false;
console.error(error);
});
},
updateImageInServer(editUploadObj) {
const {files, action, type, cropperData} = editUploadObj;
const canvasStore = Alpine.store('canvas');
const formData = new FormData();
cropperData && formData.append('cropperData', JSON.stringify(cropperData));
for (const file of files) {
formData.append(type, file) // appending every file to formdata
}
canvasStore.isServerLoaderTabVisible = true;
return fetch(action, {
method: "POST",
body: formData,
// "timeout": 0,
headers: {
"Authorization": `Bearer ${canvasStore.apiConfig.apiToken}`,
},
redirect: 'follow'
})
.then((response) => {
return response.json()
})
.then((data) => {
canvasStore.isServerLoaderTabVisible = false;
//console.log(data);
return data;
})
.catch((error) => {
canvasStore.isServerLoaderTabVisible = false;
console.error(error);
});
},
uploadImageWithoutConfigurator(uploadObj) {
const canvasStore = Alpine.store('canvas');
const formData = new FormData();
const {files, action} = uploadObj;
for (const file of files) {
formData.append('layerFile', file)
}
canvasStore.isServerLoaderCanvasVisible = true;
return fetch(action, {
method: "POST",
body: formData,
// "timeout": 0,
headers: {
"Authorization": `Bearer ${canvasStore.apiConfig.apiToken}`,
},
redirect: 'follow'
})
.then((response) => {
if (!response.ok) {
throw new Error('Network response was not OK');
}
return response.json()
})
.then((data) => {
canvasStore.isServerLoaderCanvasVisible = false;
//console.log(data);
return data;
})
.catch((error) => {
canvasStore.isServerLoaderCanvasVisible = false;
console.error(error);
});
},
deleteFilesFromServer(id, type,fileName) {
const canvasStore = Alpine.store('canvas');
const formData = new FormData();
formData.append('productId', this.$store.canvas.buganoProductId)
formData.append('fileID', id)
formData.append('fileName', fileName)
formData.append('type', type)
canvasStore.isServerLoaderTabVisible = true;
return fetch('http://localhost:6288/delete', {
method: "DELETE",
body: formData,
})
.then((response) => {
return response.json()
})
.then((data) => {
canvasStore.isServerLoaderTabVisible = false;
//console.log(data);
return data;
})
.catch((error) => {
console.error(error);
});
}
})
Alpine.store('bgshapeCropperModalStore', {
cropBgImage: null,
cropperData: null,
originalBackgroundFile: null,
editingBackgroundId: null,
shouldPushRounded: false,
dataURLtoBlob(dataurl) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type:mime});
},
async getFileFromUrl(url, name, defaultType = 'image/jpeg') {
const response = await fetch(url);
const data = await response.blob();
return new File([data], name, {
type: data.type || defaultType,
});
},
async editExistingBackground(background) {
//const originalBackgroundFile = await this.getFileFromUrl(background.originalUrl);
this.editingBackgroundId = background.id;
const cropperInitObj = {
fileName: background.name,
url: background.cropperData.originalFileDataUrl,
//url: background.originalUrl,
cropperData: background.cropperData
}
this.displaySelectedBackground(cropperInitObj);
},
async displaySelectedBackground(cropperInitObj) {
const input = elementStore.backgroundUploadEL;
const img = document.createElement('img');
img.id = 'js-bgimg-cropper';
img.src = cropperInitObj.url;
img.alt = cropperInitObj.fileName;
const imgbgcrop = elementStore.imgBgCropEL;
imgbgcrop.innerHTML = '';
imgbgcrop.appendChild(img);
// this represents current background image element which was created from file above
this.cropBgImage = img;
this.cropperData = cropperInitObj.cropperData;
if(cropperInitObj.originalBackgroundFile) {
this.originalBackgroundFile = cropperInitObj.originalBackgroundFile;
}
// open modal if not open and if alreddy open then init background cropper
if (elementStore.cropbgModalEL.classList.contains('show')) {
this.initBackgroundCropper(img)
} else {
bootstrap.Modal.getOrCreateInstance(elementStore.cropbgModalEL).show()
}
},
initBackgroundCropper(img) {
let self = this;
const input = elementStore.backgroundUploadEL;
input.value = '';
this.aspectRatio = '1';
window.dispatchEvent(new CustomEvent('backgrounds-cleard'))
//destroy old cropper before initializing new one
this.destroyCropper()
new Cropper(img, {
crop: function (event) {
self.cropBoxWidth = Math.round(event.detail.width);
self.cropBoxHeight = Math.round(event.detail.height);
},
aspectRatio: 1,
autoCropArea: 1,
preview: elementStore.cropperBgPreviewEL,
ready: function () {
if(self.cropperData) {
this.cropper.setData(self.cropperData);
}
},
});
},
cropBoxWidth: 0,
cropBoxHeight: 0,
aspectRatio: '1',
clear() {
const cropperInstance = this.cropBgImage.cropper;
cropperInstance.clear()
},
destroyCropper() {
this.cropBgImage?.cropper?.destroy();
},
async crop() {
return new Promise((resolve, reject) => {
const cropperInstance = this.cropBgImage.cropper;
const input = elementStore.backgroundUploadEL;
let self = this;
const croppedCanvas = cropperInstance.getCroppedCanvas();
let finalCanvas = croppedCanvas;
if (self.shouldPushRounded) {
finalCanvas = self.getRoundedCanvas(croppedCanvas);
}
finalCanvas.toBlob(blob => {
if (blob) {
const dt = new DataTransfer();
dt.items.add(new File([blob], self.cropBgImage.alt, { type: blob.type }));
input.files = dt.files;
window.dispatchEvent(new CustomEvent('background-uploaded', {
detail: {
name: self.cropBgImage.alt,
label: self.cropBgImage.alt,
url: URL.createObjectURL(blob),
class: self.shouldPushRounded ? 'rounded' : '',
type: blob.type,
}
}));
resolve(dt.files);
} else {
reject("Failed to generate blob");
}
});
});
},
async processUpload($store) {
let self = this;
await this.crop();
const input = elementStore.backgroundUploadEL;
const cropperData = Object.assign({originalFileDataUrl: self.cropBgImage.src} ,self.cropBgImage?.cropper.getData());
if(input.files.length) {
const uploadObj = {
files: input.files,
action: `${$store.canvas.apiConfig.apiUrl}/api/v1/product-configurators/${$store.canvas.configuratorId || null}/images`,
type: 'backgrounds[]',
imageType: 'BACKGROUND',
originalFile: this.originalBackgroundFile,
cropperData: cropperData
}
const data = await $store.uploadStore.uploadFilesToServer(uploadObj);
data?.data?.images?.forEach((background) => {
window.dispatchEvent(new CustomEvent('backgrounds-added-from-api', {
detail: {
backgrounds: [background]
}
}));
});
//productBlockVisibleMobile = true;
}
},
async processUpdate($store) {
let self = this;
await this.crop();
const input = elementStore.backgroundUploadEL;
const cropperData = Object.assign({originalFileDataUrl: self.cropBgImage.src} ,self.cropBgImage?.cropper.getData());
if(input.files.length) {
const editUploadObj = {
files: input.files,
action: `${$store.canvas.apiConfig.apiUrl}/api/v1/product-configurators/images/${self.editingBackgroundId}`,
type: 'image',
cropperData: cropperData
}
const data = await $store.uploadStore.updateImageInServer(editUploadObj);
//here for update case background is directly returned as data.data and no further background property under that
if(data?.data) {
window.dispatchEvent(new CustomEvent('backgrounds-upated-from-api', {
detail: {
backgrounds: [data?.data]
}
}));
}
//productBlockVisibleMobile = true;
}
}
})