aico-image-editor
Version:
Combine multiple image into and create single combined image
230 lines (206 loc) • 9.15 kB
JavaScript
const loadCanvasFilterHTML = () => import(/* webpackMode: "eager" */'./canvasFilter.html');
import initStyles from '../../initStyles';
import initHTML from '../../initHTML';
initHTML('canvas-filter',loadCanvasFilterHTML);
import { hotReloadAlpineComponent } from '../../hotReloader';
import { setBubblePosition } from '../../utilities/bubbltPosition';
export default {
init() {
initStyles(this.$el.shadowRoot);
if(module.hot) {
module.hot.accept('./canvasFilter.html', function() {
hotReloadAlpineComponent(this.$el.getRootNode().host ,loadCanvasFilterHTML)
}.bind(this));
}
},
isWebglBackendEnabled: true,
setBubblePosition: setBubblePosition,
isObjectGrayScaleFilterActive: false,
isCanvasGrayScaleFilterActive: false,
objectBrightness: 0,
canvasBrightness: 0,
isCanvasBrightnessContrastEnabled: false,
resetFilterFromCanvas() {
const canvas = window.__canvas;
const ctx = canvas.getContext();
ctx.filter = 'none';
canvas.renderAll();
},
showWebglNotice: false,
toggleWebglNotice(activeObj) {
// indicate whether image original size is compatible with webgl texture size
this.showWebglNotice = ((activeObj.getOriginalSize().width > fabric.textureSize) || (activeObj.getOriginalSize().height > fabric.textureSize));
},
updateObjectGrayScale() {
const canvas = window.__canvas;
const activeObj = canvas.getActiveObject();
if(activeObj.type !== 'activeSelection') {
const objectGrayScaleFilter = new fabric.Image.filters.Grayscale();
const grayScaleFilterIndex = activeObj.filters.findIndex(filter => filter.type === 'Grayscale');
if(grayScaleFilterIndex === -1) {
if(this.isObjectGrayScaleFilterActive) {
activeObj.filters.push(objectGrayScaleFilter)
}
} else {
if(!this.isObjectGrayScaleFilterActive) {
// remove grayscale filter at that index
activeObj.filters.splice(grayScaleFilterIndex, 1)
}
}
// check compatibility with texture size
this.toggleWebglNotice(activeObj)
activeObj.applyFilters();
// undo redo neeeds to be done differently
canvas.fire('object:modified', {target: activeObj});
canvas.renderAll();
}
},
updateCanvasGrayScale() {
const canvas = window.__canvas;
const ctx = canvas.getContext();
const grayScaleRegex = /grayscale\s*\((\d+(?:\.\d+)?|\d+%)\)\s*/;
if (ctx) {
if(ctx.filter === 'none') {
if(this.isCanvasGrayScaleFilterActive) {
ctx.filter = `grayscale(1) `;
}
} else if(grayScaleRegex.test(ctx.filter)) {
if(!this.isCanvasGrayScaleFilterActive) {
if(ctx.filter.replace(grayScaleRegex, '') === '') {
ctx.filter = 'none'
} else {
ctx.filter = ctx.filter.replace(grayScaleRegex, '')
}
}
} else {
if(this.isCanvasGrayScaleFilterActive) {
ctx.filter += `grayscale(1) `;
}
}
canvas.renderAll();
} else {
console.log('canvas context not found');
}
},
updateObjectBrightness() {
const canvas = window.__canvas;
const activeObj = canvas.getActiveObject();
if(activeObj.type !== 'activeSelection') {
const objectBrightnessFilter = new fabric.Image.filters.Brightness({
brightness: this.objectBrightness/100
});
const brightnessFilterIndex = activeObj.filters.findIndex(filter => filter.brightness)
if(brightnessFilterIndex === -1) {
activeObj.filters.push(objectBrightnessFilter)
} else {
activeObj.filters[brightnessFilterIndex] = objectBrightnessFilter;
}
// check compatibility with texture size
this.toggleWebglNotice(activeObj);
activeObj.applyFilters();
canvas.fire('object:modified', {target: activeObj});
canvas.renderAll();
}
},
updateCanvasBrightness(brightness, isUpdatedFromApi) {
// we are sending the brightness filter value of canvas itself to server so in that case,
// it will be as is needed when updated from there so no need to increament by 1
if(!isUpdatedFromApi) {
brightness = brightness + 1;
}
const canvas = window.__canvas;
const ctx = canvas.getContext();
const brightnessRegex = /brightness\((\d+(\.\d+)?)\)\s*/;
if (ctx) {
// if no canvas filter present at all then assign filter directly equal to brightness filter
if(ctx.filter === 'none') {
ctx.filter = `brightness(${brightness}) `;
}
/// if brightness filter is present in space separated list of values then modify only that filter leaving others unchanged
else if(brightnessRegex.test(ctx.filter)) {
const currentBrightness = ctx.filter.match(brightnessRegex)[1];
const newBrightnessFilter = `brightness(${brightness}) `;
ctx.filter = ctx.filter.replace(brightnessRegex, newBrightnessFilter)
}
// and if it is not none and also not present at all then append it to current list
else {
ctx.filter += `brightness(${brightness}) `;
}
canvas.renderAll();
} else {
console.log('canvas context not found');
}
},
objectContrast: 0,
canvasContrast: 0,
updateObjectContrast() {
const canvas = window.__canvas;
const activeObj = canvas.getActiveObject();
if(activeObj.type !== 'activeSelection') {
const objectContrastFilter = new fabric.Image.filters.Contrast({
contrast: this.objectContrast/100
});
const contrastFilterIndex = activeObj.filters.findIndex(filter => filter.contrast)
if(contrastFilterIndex === -1) {
activeObj.filters.push(objectContrastFilter)
} else {
activeObj.filters[contrastFilterIndex] = objectContrastFilter;
}
// check compatibility with texture size
this.toggleWebglNotice(activeObj)
activeObj.applyFilters();
canvas.fire('object:modified', {target: activeObj});
canvas.renderAll();
}
},
updateCanvasContrast(contrast, isUpdatedFromApi) {
// we are sending the contrast filter value of canvas itself to server so in that case,
// it will be as is needed when updated from there so no need to increament by 1
if(!isUpdatedFromApi) {
contrast = contrast + 1;
}
const canvas = window.__canvas;
const ctx = canvas.getContext();
const contrastRegex = /contrast\((\d+(\.\d+)?)\)\s*/;
if (ctx) {
if(ctx.filter === 'none') {
ctx.filter = `contrast(${contrast}) `;
} else if (contrastRegex.test(ctx.filter)) {
const currentContrast = ctx.filter.match(contrastRegex)[1];
const newContrastFilter = `contrast(${contrast}) `;
ctx.filter = ctx.filter.replace(contrastRegex, newContrastFilter)
} else {
ctx.filter += `contrast(${contrast}) `;
}
canvas.renderAll();
} else {
console.log('canvas context not found.');
}
},
syncCanvasFilterFromApi(event) {
this.canvasBrightness = Math.round((Number.isFinite(event.detail.canvasBrightness) ? (event.detail.canvasBrightness - 1) : 0) * 100);
this.canvasContrast = Math.round((Number.isFinite(event.detail.canvasContrast) ? (event.detail.canvasContrast - 1) : 0) * 100)
this.isCanvasGrayScaleFilterActive = !!event.detail.canvasGrayScale;
if(Number.isFinite(event.detail.canvasBrightness)) {
this.updateCanvasBrightness(event.detail.canvasBrightness, true)
}
if(Number.isFinite(event.detail.canvasContrast)) {
this.updateCanvasContrast(event.detail.canvasContrast, true)
}
if(this.isCanvasGrayScaleFilterActive) {
this.updateCanvasGrayScale()
}
},
canvasBrightnessContrastTrigger: {
['@canvas-data-restored.window'](event) {
this.syncCanvasFilterFromApi(event)
},
['@canvas-data-viewed.window'](event) {
this.resetFilterFromCanvas();
this.syncCanvasFilterFromApi(event)
},
['@canvas-reset.window'](event) {
this.resetFilterFromCanvas();
}
}
}