ngx-image-drawing-zone
Version:

1,330 lines • 66.5 kB
JavaScript
import { NgTemplateOutlet, NgStyle, NgClass, CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { EventEmitter, Component, Input, Output, NgModule } from '@angular/core';
import { fabric } from 'fabric';
import { Observable, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { MatIconModule } from '@angular/material/icon';
const I18nFr = {
saveBtn: 'Enregistrer',
cancelBtn: 'Annuler',
loadImage: 'Charger une image depuis votre PC',
loadImageUrl: 'Charger une image depuis une URL',
loading: 'Chargement',
loadError: 'Erreur de chargement %@',
removeImage: 'Supprimer l\'image',
sizes: {
small: 'Petit',
medium: 'Moyen',
large: 'Gros'
},
undo: 'Annuler',
redo: 'Répter',
clear: 'Effacer',
colors: {
black: 'Noir',
white: 'Blanc',
yellow: 'Jaune',
red: 'Rouge',
green: 'Vert',
blue: 'Blue',
purple: 'Violet'
},
tools: {
brush: 'Pinceau'
}
};
const I18nEn = {
saveBtn: 'Save',
cancelBtn: 'Cancel',
loadImage: 'Load image',
loadImageUrl: 'Load image from URL',
loading: 'Loading',
loadError: 'Error loading %@',
removeImage: 'Remove image',
sizes: {
small: 'Small',
medium: 'Medium',
large: 'Large'
},
resize: "Resize",
undo: 'Undo',
redo: 'Redo',
clear: 'Clear',
crop: 'Crop',
mask: "Mask",
rotate: "Rotate",
colors: {
black: 'Black',
white: 'White',
yellow: 'Yellow',
red: 'Red',
green: 'Green',
blue: 'Blue',
purple: 'Purple',
},
tools: {
brush: 'Brush'
}
};
const I18nHe = {
saveBtn: 'שמירה',
cancelBtn: 'ביטול',
loadImage: 'טוען תמונה',
loadImageUrl: 'טוען תמונה מנתיב',
loading: 'בטעינה',
loadError: 'שגיאה בטעינה',
removeImage: 'הסרת תמונה',
sizes: {
small: 'קטן',
medium: 'בינוני',
large: 'גדול'
},
rotate: "הפיכת תמונה",
resize: "שנה גודל",
undo: 'ביטול',
redo: 'שחזור',
clear: 'ניקןי',
crop: 'חיתוך תמונה',
mask: 'ריבוע בחירה',
colors: {
black: 'שחור',
white: 'לבן',
yellow: 'צהוב',
red: 'אדום',
green: 'ירוק',
blue: 'כחול',
purple: 'סגול',
},
tools: {
brush: 'מברשת'
}
};
const i18nLanguages = {
fr: I18nFr,
en: I18nEn,
he: I18nHe
};
class ImageDrawingComponent {
constructor(zone) {
this.zone = zone;
this.saveBtnClass = "button btn-primary";
this.cancelBtnClass = "button btn-light";
this.forceSizeCanvas = true;
this.forceSizeExport = false;
this.enableRemoveImage = false;
this.enableLoadAnotherImage = false;
this.enableTooltip = true;
this.showCancelButton = true;
this.locale = 'en';
/* @deprecated Use i18n.saveBtn */
this.saveBtnText = 'Save';
/* @deprecated Use i18n.cancelBtn */
this.cancelBtnText = 'Cancel';
/* @deprecated Use i18n.loading */
this.loadingText = 'Loading…';
/* @deprecated Use i18n.loadError */
this.errorText = 'Error loading %@';
this.outputMimeType = 'image/jpeg';
this.outputQuality = 0.8;
this.borderCss = 'none';
this.drawingSizes = {
small: 5,
medium: 10,
large: 25,
};
this.colors = {
black: '#000',
white: '#fff',
yellow: '#ffeb3b',
red: '#f44336',
blue: '#2196f3',
green: '#4caf50',
purple: '#7a08af',
};
this.save = new EventEmitter();
this.cancel = new EventEmitter();
this.currentTool = '';
this.currentSize = 'medium';
this.currentColor = 'black';
this.i18n = I18nEn;
this.shapesNames = [
{ shape: 'rectangle', icon: 'rectangle' },
{ shape: 'circle', icon: 'circle' },
{ shape: 'line', icon: ' horizontal_rule' },
{ shape: 'arrow', icon: 'arrow_back' }
];
this.canUndo = false;
this.canRedo = false;
this.isShapeMode = false;
this.shapeType = '';
this.isLoading = false;
this.hasError = false;
this.errorMessage = '';
this.shapedone = false;
this.stack = [];
this.stackUndo = [];
this.stackUndoLocation = [];
this.stackRedoLocation = [];
this.colorsName = [];
this.drawingSizesName = [];
this.isCrop = false;
this.pos = [0, 0];
this.mousex = 0;
this.mousey = 0;
this.disabled = true;
this.lastSelectedPicture = null;
this.isInsertingCropRectangle = false;
this.done = false;
}
get commons() {
return {
originX: 'center',
originY: 'center',
stroke: this.currentColor,
strokeWidth: this.drawingSizes[this.currentSize]
};
}
get commons1() {
return {
stroke: this.currentColor,
strokeWidth: this.drawingSizes[this.currentSize]
};
}
ngOnInit() {
this.colorsName = Object.keys(this.colors);
this.drawingSizesName = Object.keys(this.drawingSizes);
this.initClipPath();
this.canvas = new fabric.Canvas('canvas', {
hoverCursor: 'pointer',
selection: true,
preserveObjectStacking: true,
//clipPath:clipPath
//isDrawingMode: true,
});
this.canvas.backgroundColor = 'white';
if (this.src) {
this.importPhotoFromSrc(this.src);
this.r = document.getElementById('canvas').getBoundingClientRect();
this.pos[0] = this.r.left;
this.pos[1] = this.r.top;
}
else {
if (!this.width || !this.height) {
throw new Error('No width or hight given !');
}
this.canvas.setWidth(this.width);
this.canvas.setHeight(this.height);
}
//this.canvas.on('')
this.canvas.on('path:created', () => {
this.stack = [];
this.setUndoRedo();
});
this.canvas.on('object:added', (e) => {
});
this.canvas.on('object:modified', (e) => {
if (this.currentTool === 'resize') {
const newWidth = e.target.width * e.target.scaleX;
const newHeight = e.target.height * e.target.scaleY;
e.target.set({ opacity: 1 });
debugger;
//var newWidth = (Math.round(e.target.width/ canvasGrid)) * canvasGrid;
//var newHeight = (Math.round(e.target.height / canvasGrid)) * canvasGrid;
if (e.target.width !== newWidth) {
//e.target.set({ width: newWidth, height: newHeight, scaleX: 1, scaleY: 1, });
}
this.imageUsed.scaleToWidth(e.target.width * e.target.scaleX);
this.imageUsed.scaleToHeight(e.target.height * e.target.scaleY);
this.canvas.setWidth(e.target.width * e.target.scaleX);
this.canvas.setHeight(e.target.height * e.target.scaleY);
e.target.setCoords();
this.canvas.renderAll();
const imageStr = this.canvas.toDataURL({
format: 'jpeg'
});
this.canvas.remove(this.imageUsed);
this.canvas.getObjects().forEach(e => e.opacity = 0);
this.selectTool('');
//this.canvas.getObjects()[0].opacity=1
this.importPhotoFromSrc(imageStr, false, true);
}
//this.setUndoRedo()
});
this.canvas.on('mouse:down', (o) => {
if (this.isInsertingCropRectangle == true) {
console.log('mouse down done = ' + this.done);
if (this.done) {
this.canvas.renderAll();
return;
}
this.isDown = true;
var pointer = this.canvas.getPointer(o.e);
this.origX = pointer.x;
this.origY = pointer.y;
this.crop_rect = new fabric.Rect({
left: this.origX,
top: this.origY,
width: pointer.x - this.origX,
height: pointer.y - this.origY,
opacity: .3,
transparentCorners: false,
selectable: true,
//id: 'mask'
});
this.mask = this.crop_rect;
this.canvas.add(this.crop_rect);
this.setUndoRedo();
this.canvas.renderAll();
}
else if (this.isShapeMode === true) {
this.isDown = true;
if (this.shapeType === 'rectangle') {
this.shapePoint = this.canvas.getPointer(o.e);
this.shape_rect = new fabric.Rect({
...this.commons,
left: this.shapePoint.x,
top: this.shapePoint.y,
fill: 'transparent',
width: this.shapePoint.x - this.shapePoint.x,
height: this.shapePoint.y - this.shapePoint.y,
//centeredRotation:true,
//centeredScaling:true,
selectable: true,
});
this.canvas.add(this.shape_rect);
//this.setUndoRedo();
this.canvas.renderAll();
}
else if (this.shapeType === 'circle') {
this.shapePoint = this.canvas.getPointer(o.e);
this.shape_circle = new fabric.Circle({
...this.commons,
left: this.shapePoint.x,
top: this.shapePoint.y,
fill: 'transparent',
radius: this.shapePoint.x - this.shapePoint.x,
selectable: true,
});
this.canvas.add(this.shape_circle);
//this.setUndoRedo();
this.canvas.renderAll();
}
else if (this.shapeType === 'line') {
this.shapePoint = this.canvas.getPointer(o.e);
this.shape_line = new fabric.Line([this.shapePoint.x, this.shapePoint.y, this.shapePoint.x, this.shapePoint.y], this.commons);
this.canvas.add(this.shape_line);
this.canvas.renderAll();
}
else if (this.shapeType === 'arrow') {
this.shapePoint = this.canvas.getPointer(o.e);
var angle = Math.atan2(this.shapePoint.y - this.shapePoint.y, this.shapePoint.x - this.shapePoint.x);
angle *= 180 / Math.PI;
angle += 90;
this.shape_line = new fabric.Line([this.shapePoint.x, this.shapePoint.y, this.shapePoint.x, this.shapePoint.y], this.commons);
this.shape_arrow = new fabric.Triangle({
...this.commons,
angle: angle,
top: this.shape_line.y2,
left: this.shape_line.x2,
width: 10,
height: 10
});
this.shape_line_copy = new fabric.Line([this.shapePoint.x, this.shapePoint.y, this.shapePoint.x, this.shapePoint.y], this.commons);
this.shape_arrow_copy = new fabric.Triangle({
...this.commons,
angle: angle,
top: this.shape_line.y2,
left: this.shape_line.x2,
width: 10,
height: 10
});
this.canvas.add(this.shape_line);
this.canvas.add(this.shape_arrow);
this.canvas.renderAll();
}
}
});
this.canvas.on('mouse:move', (o) => {
if (this.isInsertingCropRectangle == true) {
console.log('mouse move done = ' + this.done);
if (this.done) {
this.canvas.renderAll();
return;
}
if (!this.isDown)
return;
var pointer = this.canvas.getPointer(o.e);
if (this.origX > pointer.x) {
this.crop_rect.set({
left: Math.abs(pointer.x)
});
}
if (this.origY > pointer.y) {
this.crop_rect.set({
top: Math.abs(pointer.y)
});
}
this.crop_rect.set({
width: Math.abs(this.origX - pointer.x)
});
this.crop_rect.set({
height: Math.abs(this.origY - pointer.y)
});
this.crop_rect.setCoords();
this.canvas.renderAll();
}
else if (this.isShapeMode === true) {
if (!this.isDown)
return;
if (this.shapeType === 'rectangle') {
var pointer = this.canvas.getPointer(o.e);
if (this.shapePoint.x > pointer.x) {
this.shape_rect.set({
left: Math.abs(pointer.x)
});
}
if (this.shapePoint.y > pointer.y) {
this.shape_rect.set({
top: Math.abs(pointer.y)
});
}
this.shape_rect.set({
width: Math.abs(this.shapePoint.x - pointer.x)
});
this.shape_rect.set({
height: Math.abs(this.shapePoint.y - pointer.y)
});
this.shape_rect.setCoords();
this.canvas.renderAll();
}
else if (this.shapeType === 'circle') {
var pointer = this.canvas.getPointer(o.e);
if (this.shapePoint.x > pointer.x) {
this.shape_circle.set({
left: Math.abs(pointer.x)
});
}
if (this.shapePoint.y > pointer.y) {
this.shape_circle.set({
top: Math.abs(pointer.y)
});
}
this.shape_circle.set({
radius: Math.abs(this.shapePoint.x - pointer.x) / 2
});
// this.shape_circle.set({
// height: Math.abs(this.shapePoint.y - pointer.y)
//});
this.shape_circle.setCoords();
this.canvas.renderAll();
}
else if (this.shapeType === 'line') {
var pointer = this.canvas.getPointer(o.e);
if (this.shapePoint.x > pointer.x) {
this.shape_line.set({
left: Math.abs(pointer.x)
});
}
if (this.shapePoint.y > pointer.y) {
this.shape_line.set({
top: Math.abs(pointer.y)
});
}
this.shape_line.set({
x2: pointer.x,
y2: pointer.y
});
this.shape_line.setCoords();
this.canvas.renderAll();
}
else if (this.shapeType === 'arrow') {
var pointer = this.canvas.getPointer(o.e);
console.log(pointer);
console.log(this.shapePoint);
const py = pointer.y - this.shapePoint.y;
const px = pointer.x - this.shapePoint.x;
this.shape_line.set({
x2: pointer.x,
y2: pointer.y
});
this.shape_line_copy.set({
x2: pointer.x,
y2: pointer.y
});
this.shape_line.setCoords();
var angle = Math.atan2(py, px);
angle *= 180 / Math.PI;
angle += 90;
let pointX;
let pointY;
if (pointer.x > this.shapePoint.x) {
pointX = pointer.x + 15;
}
else if (pointer.x < this.shapePoint.x) {
pointX = pointer.x - 15;
}
else {
pointX = pointer.x;
}
if (pointer.y > this.shapePoint.y) {
pointY = pointer.y + 7;
}
else if (pointer.y < this.shapePoint.y) {
pointY = pointer.y - 7;
}
else {
pointY = pointer.y;
}
this.shape_arrow.set({
angle: angle,
top: pointer.y,
left: pointer.x
});
this.shape_arrow_copy.set({
angle: angle,
top: pointer.y,
left: pointer.x
});
console.log(this.shape_arrow);
console.log(this.shape_line);
this.shape_arrow.setCoords();
this.canvas.renderAll();
}
}
});
this.canvas.on('mouse:up', (o) => {
if (this.isInsertingCropRectangle == true) {
console.log('mouse up done = ' + this.done);
if (this.done) {
this.canvas.renderAll();
return;
}
this.isDown = false;
this.crop_rect.set({
selectable: true
});
this.done = true;
}
else if (this.isShapeMode === true) {
if (this.shapedone)
return;
if (this.shapeType === 'arrow') {
debugger;
const line = new fabric.Line([this.shape_line.x1, this.shape_line.y1, this.shape_line.x2, this.shape_line.y2], this.commons1);
line.set({
x1: this.shape_line.x1,
y1: this.shape_line.y1,
x2: this.shape_line.x2,
y2: this.shape_line.y2
});
const arrow = new fabric.Triangle({
...this.commons1,
angle: this.shape_arrow.angle,
top: this.shape_arrow.top,
left: this.shape_arrow.left,
width: 10,
height: 10
});
line.setCoords();
arrow.setCoords();
var obj = [this.shape_arrow_copy, this.shape_line_copy];
let myShape = new fabric.Group(obj, {
left: Math.min(this.shape_line_copy.x1, this.shape_line_copy.x2),
top: Math.min(this.shape_line_copy.y1, this.shape_line_copy.y2)
});
myShape.setCoords();
console.log(myShape);
this.canvas.add(myShape);
this.canvas.renderAll();
this.canvas.remove(this.shape_line);
this.canvas.remove(this.shape_arrow);
this.canvas.renderAll();
this.shapedone = true;
//this.isDown = false;
//this.shapeType=''
//this.isShapeMode=false;
this.selectTool('');
this.setUndoRedo();
this.canvas.renderAll();
}
else {
//this.isDown = false;
//this.shapeType=''
//this.isShapeMode=false;
this.selectTool('');
this.setUndoRedo();
this.canvas.renderAll();
}
}
});
this.canvas.on('selection:created', (event) => {
console.log("canvas.on('selection:created'");
this.selectionChanged(event);
});
this.canvas.on('selection:updated', (event) => {
console.log("canvas.on('selection:updated'");
this.selectionChanged(event);
});
this.selectColor(this.currentColor);
this.selectDrawingSize(this.currentSize);
if (this.locale && i18nLanguages[this.locale.toLowerCase()]) {
this.i18n = i18nLanguages[this.locale.toLowerCase()];
}
// FIXME remove after a while because properties are now deprecated
if (this.saveBtnText) {
this.i18n.saveBtn = this.saveBtnText;
}
if (this.cancelBtnText) {
this.i18n.cancelBtn = this.cancelBtnText;
}
if (this.loadingText) {
this.i18n.loading = this.loadingText;
}
if (this.errorText) {
this.i18n.loadError = this.errorText;
}
}
selectionChanged(event) {
console.log("selectionChanged");
console.log("selectionChanged type = " + event.target?.type);
switch (event.target?.type) {
case 'textbox':
break;
case 'image':
this.lastSelectedPicture = event.target;
break;
case 'rect':
break;
case 'group':
break;
default:
break;
}
}
rotate(degrees, undo = true) {
this.selectTool('rotate');
//this.canvas.setWidth(this.canvas.width+500)
//this.canvas.setHeight(this.canvas.height+500)
this.canvas.renderAll();
if (undo) {
this.stackUndoLocation.push({ type: 'rotate', loc: this.canvas.getObjects().length });
this.stackUndo.push(this.imageUsed);
this.setUndoRedo();
}
const w = this.canvas.width;
const h = this.canvas.height;
this.canvas.setWidth(h);
this.canvas.setHeight(w);
let i = 0;
this.canvas.getObjects().forEach((value) => {
console.log(value);
const t = value.top;
const l = value.left;
console.log("T L", value.top, value.left);
//const dd=(value?.angle+degrees)
//const de=( (dd % 360)* Math.PI) / 180
value.centeredRotation = true;
if (i > 0) {
this.canvas.setActiveObject(value);
}
value.rotate(value?.angle + degrees).setCoords();
console.log("T1 L1", value.top, value.left);
const w1 = value.width > this.canvas.width && value.width !== this.canvas.height ? this.canvas.width : value.width;
;
const h1 = value.height > this.canvas.height && value.height !== this.canvas.width ? this.canvas.height : value.height;
//value.originX='left'
//value.originY='top'
console.log("w1 h1 ", w1, h1);
//value.or
let pref = Math.abs(w1 / 2 - h1 / 2);
console.log("pref ", pref);
// value.originX='left'
// value.originY='top'
console.log("i ", i);
if (i === 0) {
if ((value.angle % 360 === 90 || value.angle % 360 === 270)) {
if (h > w) {
pref = pref * -1;
}
const t1 = t - value.top;
const l1 = h1 - value.left;
console.log(t1, l1);
value.top = value.top + pref;
value.left = value.left - pref;
}
// if(value.angle%360===270){
// const t1=t-value.top;
// const l1=l-value.left;
// console.log(t1,l1)
// value.top=value.top+pref;
// value.left=value.left-pref;
// }
if (value.angle % 360 === 180 || value.angle % 360 === 0) {
if (h < w) {
pref = pref * -1;
}
const t1 = h1 + value.top;
const l1 = l - value.left;
console.log(t1, l1);
value.top = value.top - pref;
value.left = value.left + pref;
}
// if(value.angle%360===0){
// const t1=h1-value.top;
// const l1=l-value.left;
// console.log(t1,l1)
// value.top=value.top-pref;
// value.left=value.left+pref;
// }
}
else {
// if(value.angle%360===0){
// value.top=300;
// value.left=300;
// console.log("TT LL",value.top,value.left)
// }else{
value.top = l;
value.left = this.canvas.width - t;
console.log("TT LL", value.top, value.left);
//}
}
i = i + 1;
console.log(value);
});
//imageR.rotate(Math.PI / 2)
// imageR.snapAngle =90;
this.canvas.renderAll();
}
shape(shapeT) {
this.selectTool('shape');
this.shapedone = false;
this.isShapeMode = true;
this.shapeType = shapeT;
}
rescaleMask(target, mask) {
mask.scaleX = 1;
mask.scaleY = 1;
mask.scaleX /= target.scaleX;
mask.scaleY /= target.scaleY;
const targetCenterX = target.width * target.scaleX / 2;
const targetCenterY = target.height * target.scaleY / 2;
const maskOverlapX = mask.left - target.left;
const maskOverlapY = mask.top - target.top;
let centerBasedX = maskOverlapX - targetCenterX;
let centerBasedY = maskOverlapY - targetCenterY;
if (maskOverlapX >= targetCenterX) {
centerBasedX = (maskOverlapX - targetCenterX) / target.scaleX;
}
else {
centerBasedX = (-(targetCenterX) + maskOverlapX) / target.scaleX;
}
if (maskOverlapY >= targetCenterY) {
centerBasedY = (maskOverlapY - targetCenterY) / target.scaleY;
}
else {
centerBasedY = (-(targetCenterY) + maskOverlapY) / target.scaleY;
}
console.log('targetleft = ' + target.left);
console.log('targettop = ' + target.top);
console.log('targetCenterX = ' + targetCenterX);
console.log('targetCenterY = ' + targetCenterY);
console.log('maskleft = ' + mask.left);
console.log('masktop = ' + mask.top);
console.log('maskOverlapX = ' + maskOverlapX);
console.log('maskOverlapY = ' + maskOverlapY);
console.log('centerBasedX = ' + centerBasedX);
console.log('centerBasedY = ' + centerBasedY);
mask.left = centerBasedX;
mask.top = centerBasedY;
mask.originX = 'left';
mask.originY = 'top';
mask.setCoords();
mask.dirty = true;
this.canvas.renderAll();
//var newMask = mask;
return (mask);
}
initClipPath() {
this.clipPath = new fabric.Rect({
//left: 100,
//top: 100,
fill: 'transparent',
originX: 'left',
originY: 'top',
stroke: '#ccc',
strokeDashArray: [2, 2],
opacity: 1,
width: 1,
height: 1
});
}
// Tools
selectTool(tool) {
this.currentTool = tool;
if (this.currentTool === 'brush') {
this.canvas.isDrawingMode = true;
}
else {
this.canvas.isDrawingMode = false;
}
if (this.currentTool !== 'shape') {
this.isDown = false;
this.shapeType = '';
this.isShapeMode = false;
}
}
selectDrawingSize(size) {
this.currentSize = size;
if (this.canvas) {
this.canvas.freeDrawingBrush.width = this.drawingSizes[size];
}
}
selectColor(color) {
this.currentColor = color;
if (this.canvas) {
this.canvas.freeDrawingBrush.color = this.colors[color];
}
}
maskC() {
this.isInsertingCropRectangle = true;
this.selectTool('mask');
this.canvas.discardActiveObject();
this.target.selectable = false;
this.target.setCoords();
this.target.dirty = true;
//this.lastSelectedPicture.selectable = false;
//this.lastSelectedPicture.setCoords();
//this.lastSelectedPicture.dirty = true;
this.canvas.renderAll();
this.setUndoRedo();
this.canvas.discardActiveObject();
this.canvas.isDrawingMode = false;
}
// Actions
crop() {
if (this.target !== null && this.mask !== null && this.done) {
this.selectTool('crop');
this.target.setCoords();
// Re-scale mask
//this.mask = this.rescaleMask(this.target, this.mask);
this.mask.setCoords();
// Do the crop
//this.target.clipPath = this.mask;
//this.target.clipPath.setCoords();
//this.target.dirty=true;
//this.canvas.setActiveObject(this.target);
//this.canvas.bringToFront(this.target);
//this.target.clipPath.selectable = true;
this.setUndoRedo();
//this.stackUndoLocation.push(this.canvas.getObjects().length-2)
//this.stackUndo.push(this.mask);
this.canvas.remove(this.mask);
this.canvas.renderAll();
this.stackUndoLocation.push({ type: '', loc: this.canvas.getObjects().length - 1 });
this.stackUndo.push(this.imageUsed);
this.setUndoRedo();
const scale2 = Math.min(this.canvas.getWidth() / this.crop_rect.width, this.canvas.getHeight() / this.crop_rect.height);
const imageStr = this.canvas.toDataURL({
width: this.crop_rect.width, //this.target.clipPath.width,
height: this.crop_rect.height,
left: this.crop_rect.left, //+this.canvas.width/2,
top: this.crop_rect.top, //+this.canvas.height/2,
quality: 1,
multiplier: scale2,
format: 'jpeg'
});
this.canvas.remove(this.imageUsed);
this.canvas.getObjects().forEach(e => e.opacity = 0);
//this.canvas.getObjects()[0].opacity=1
this.importPhotoFromSrc(imageStr);
this.imageUsed.sendToBack();
this.canvas.renderAll();
this.setUndoRedo();
console.log(this.target);
this.isInsertingCropRectangle = false;
this.done = false;
this.selectTool('');
}
//this.disabled=false;
}
resize() {
this.selectTool('resize');
this.stackUndoLocation.push({ type: '', loc: this.canvas.getObjects().length - 1 });
this.stackUndo.push(this.imageUsed);
this.setUndoRedo();
const imageStr = this.canvas.toDataURL({
format: 'jpeg'
});
this.canvas.remove(this.imageUsed);
this.canvas.getObjects().forEach(e => e.opacity = 0);
//this.canvas.getObjects()[0].opacity=1
this.importPhotoFromSrc(imageStr, true);
//this.canvas.setWidth(this.canvas.width+500)
//this.canvas.setHeight(this.canvas.height+500)
this.canvas.renderAll();
}
undo() {
if (this.canUndo) {
debugger;
if (this.stackUndo.length > 0) {
if (this.stackUndoLocation[this.stackUndoLocation.length - 1].type === 'rotate') {
const ob = this.stackUndo.pop();
const l = this.stackUndoLocation.pop().loc;
this.setUndoRedo();
this.rotate(-90, false);
this.stack.push('rotate');
this.stackRedoLocation.push({ type: 'rotate', loc: this.canvas.getObjects().length });
this.setUndoRedo();
}
else if (this.canvas.getObjects().length - this.stackUndoLocation[this.stackUndoLocation.length - 1].loc > 1) {
const lastId = this.canvas.getObjects().length - 1;
const lastObj = this.canvas.getObjects()[lastId];
this.done = false;
this.stack.push(lastObj);
this.canvas.remove(lastObj);
this.setUndoRedo();
this.canvas.renderAll();
}
else {
const ob = this.stackUndo.pop();
const l = this.stackUndoLocation.pop().loc;
if (ob instanceof fabric.Image) {
this.stack.push(this.imageUsed);
for (var i = l; i >= 0; i--) {
this.canvas.getObjects()[i].opacity = 1;
}
this.setUndoRedo();
this.canvas.remove(this.imageUsed);
this.importPhotoFromSrc(ob.getSrc());
debugger;
}
else {
this.canvas.add(ob);
}
this.canvas.renderAll();
}
}
else {
const lastId = this.canvas.getObjects().length - 1;
const lastObj = this.canvas.getObjects()[lastId];
this.done = false;
this.stack.push(lastObj);
this.canvas.remove(lastObj);
this.setUndoRedo();
this.canvas.renderAll();
}
}
}
redo() {
if (this.canRedo) {
const firstInStack = this.stack.splice(-1, 1)[0];
if (firstInStack) {
if (firstInStack instanceof fabric.Image) {
this.stackUndoLocation.push({ type: '', loc: this.canvas.getObjects().length - 1 });
this.stackUndo.push(this.imageUsed);
this.canvas.remove(this.imageUsed);
this.importPhotoFromSrc(firstInStack.getSrc());
this.setUndoRedo();
}
else if (firstInStack === 'rotate') {
this.rotate(90);
}
else {
this.canvas.insertAt(firstInStack, this.canvas.getObjects().length, false);
this.setUndoRedo();
}
}
}
}
clearCanvas() {
if (this.canvas) {
this.canvas.clipPath = null;
this.canvas.remove(...this.canvas.getObjects());
//this.canvas.clear()
this.setUndoRedo();
}
}
saveImage() {
if (!this.forceSizeExport || (this.forceSizeExport && this.width && this.height)) {
const canvasScaledElement = document.createElement('canvas');
const canvasScaled = new fabric.Canvas(canvasScaledElement);
canvasScaled.backgroundColor = 'white';
let imageStr = null;
new Observable(observer => {
if (this.imageUsed) {
if (this.target.clipPath) {
debugger;
imageStr = this.canvas.toDataURL({
width: this.target.clipPath.width,
height: this.target.clipPath.height,
left: this.target.clipPath.left + this.canvas.width / 2,
top: this.target.clipPath.top + this.canvas.height / 2,
format: 'jpeg'
});
console.log(imageStr);
}
if (this.forceSizeExport) {
canvasScaled.setWidth(this.width);
canvasScaled.setHeight(this.height);
this.imageUsed.cloneAsImage(imageCloned => {
imageCloned.scaleToWidth(this.width, false);
imageCloned.scaleToHeight(this.height, false);
canvasScaled.setBackgroundImage(imageCloned, (img) => {
if (!img) {
observer.error(new Error('Impossible to draw the image on the temporary canvas'));
}
observer.next(canvasScaled);
observer.complete();
}, {
crossOrigin: 'anonymous',
originX: 'left',
originY: 'top'
});
});
}
else {
//canvasScaled.clipPath=this.mask
canvasScaled.setBackgroundImage(this.target, (img) => {
if (!img) {
observer.error(new Error('Impossible to draw the image on the temporary canvas'));
}
//canvasScaled.clipPath=this.clipPath
//(canvasScaled.backgroundImage as fabric.Image).clipPath=(this.canvas.backgroundImage as fabric.Image).clipPath
console.log(this.canvas.width);
if (img.angle % 360 === 90 || img.angle % 360 === 270) {
canvasScaled.setWidth(img.height * this.imageUsed.scaleX);
canvasScaled.setHeight(img.width * this.imageUsed.scaleY);
}
else {
canvasScaled.setWidth(img.width * this.imageUsed.scaleX);
canvasScaled.setHeight(img.height * this.imageUsed.scaleY);
}
observer.next(canvasScaled);
observer.complete();
}, {
crossOrigin: 'anonymous',
originX: 'left',
originY: 'top'
});
//(canvasScaled.backgroundImage as fabric.Image).clipPath=this.clipPath
}
}
else {
canvasScaled.setWidth(this.width);
canvasScaled.setHeight(this.height);
}
}).pipe(switchMap(() => {
let process = of(canvasScaled);
if (this.canvas.getObjects().length > 1) {
this.canvas.remove(this.imageUsed);
const ratioX = canvasScaled.getWidth() / this.canvas.getWidth();
const ratioY = canvasScaled.getHeight() / this.canvas.getHeight();
this.canvas.getObjects().forEach((originalObject, i) => {
process = process.pipe(switchMap(() => {
return new Observable(observerObject => {
originalObject.clone((clonedObject) => {
clonedObject.set('left', originalObject.left * ratioX);
clonedObject.set('top', originalObject.top * ratioY);
clonedObject.scaleToWidth(originalObject.width * ratioX);
clonedObject.scaleToHeight(originalObject.height * ratioY);
canvasScaled.insertAt(clonedObject, i, false);
canvasScaled.renderAll();
observerObject.next(canvasScaled);
observerObject.complete();
});
});
}));
});
}
return process;
})).subscribe(() => {
canvasScaled.renderAll();
// console.log(
// canvasScaled.toDataURL(
// {width:this.clipPath.width,
// height:this.clipPath.height,
// left:(this.canvas.backgroundImage as fabric.Image).clipPath.left,
// top:(this.canvas.backgroundImage as fabric.Image).clipPath.top,
// format:'jpeg'
// }))
const im = canvasScaled.toDataURL({
format: 'jpeg'
});
console.log(im);
canvasScaled.getElement().toBlob((data) => this.zone.run(() => {
this.save.emit(data);
}), this.outputMimeType, this.outputQuality);
});
}
else {
this.canvas.getElement().toBlob((data) => this.zone.run(() => {
this.save.emit(data);
}), this.outputMimeType, this.outputQuality);
}
}
cancelAction() {
this.cancel.emit();
}
getTextTranslated(name) {
let strOk = name.split('.').reduce((o, i) => o[i], this.i18n);
if (this.i18nUser) {
try {
const str = name.split('.').reduce((o, i) => o[i], this.i18nUser);
if (str) {
strOk = str;
}
}
catch (e) {
// if we pass here, ignored
}
}
if (!strOk) {
console.error(name + ' translation not found !');
}
return strOk;
}
getTooltipTranslated(name) {
if (this.enableTooltip) {
return this.getTextTranslated(name);
}
else {
return '';
}
}
setUndoRedo() {
this.canUndo = this.canvas.getObjects().length > 1 || this.stackUndo.length > 0;
this.canRedo = this.stack.length > 0;
// this.canvas.renderAll();
}
importPhotoFromFile(event) {
if (event.target.files && event.target.files.length > 0) {
const file = event.target.files[0];
if (file.type.match('image.*')) {
this.importPhotoFromBlob(file);
}
else {
throw new Error('Not an image !');
}
}
}
removeImage() {
if (this.imageUsed) {
this.imageUsed.dispose();
this.imageUsed = null;
}
this.canvas.backgroundImage = null;
if (this.width && this.height) {
this.canvas.setWidth(this.width);
this.canvas.setHeight(this.height);
}
this.canvas.renderAll();
}
get hasImage() {
return !!this.canvas.backgroundImage;
}
importPhotoFromSrc(src, select = false, stackundo = false) {
this.isLoading = true;
let isFirstTry = true;
const imgEl = new Image();
imgEl.setAttribute('crossorigin', 'anonymous');
imgEl.crossOrigin = "anonymous";
imgEl.src = src;
imgEl.onerror = () => {
// Retry with cors proxy
/* if (isFirstTry) {
imgEl.src = 'https://cors-anywhere.herokuapp.com/' + this.src;
isFirstTry = false;
}
else */
{
this.isLoading = false;
this.hasError = true;
this.errorMessage = this.getTextTranslated('loadError').replace('%@', this.src);
}
};
console.log(imgEl);
const scaleWidth = this.canvas.getWidth() / imgEl.width;
const scaleHeight = this.canvas.getHeight() / imgEl.height;
const scale = Math.min(scaleWidth, scaleHeight);
console.log(scale);
imgEl.onload = () => {
this.isLoading = false;
this.imageUsed = new fabric.Image(imgEl, {
selectable: false,
width: imgEl.width,
height: imgEl.height,
});
this.canvas.insertAt(this.imageUsed, 0, false);
//this.canvas.sendToBack(this.imageUsed)
this.canvas.width = imgEl.width;
this.canvas.height = imgEl.height;
//this.canvas.setActiveObject(this.imageUsed)
console.log(this.imageUsed);
this.imageUsed.cloneAsImage(image => {
let width = imgEl.width;
let height = imgEl.height;
if (this.width && this.width < width) {
width = this.width;
}
if (this.height && this.height < height) {
height = this.height;
}
this.imageUsed.scaleToWidth(width);
this.imageUsed.scaleToHeight(height);
image.scaleToWidth(width, false);
image.scaleToHeight(height, false);
console.log(image, width, height);
// this.canvas.setBackgroundImage(image, ((img: HTMLImageElement) => {
// if (img) {
if (this.forceSizeCanvas) {
this.canvas.setWidth(width);
this.canvas.setHeight(height);
}
else {
this.canvas.setWidth(image.getScaledWidth());
this.canvas.setHeight(image.getScaledHeight());
}
// }
// }), {
// crossOrigin: 'Anonymous',
// originX: 'left',
// originY: 'top'
//});
this.target = this.imageUsed;
this.target.selectable = select;
if (select) {
this.target.lockMovementX = true;
this.target.lockMovementY = true;
this.canvas.setWidth(width + 500);
this.canvas.setHeight(height + 500);
}
if (stackundo) {
this.stackUndoLocation.push({ type: '', loc: this.canvas.getObjects().length - 1 });
this.stackUndo.push(this.imageUsed);
this.setUndoRedo();
}
});
};
}
importPhotoFromBlob(file) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (evtReader) => {
if (evtReader.target.readyState == FileReader.DONE) {
this.importPhotoFromSrc(evtReader.target.result);
}
};
}
importPhotoFromUrl() {
const url = prompt(this.getTooltipTranslated('loadImageUrl'));
if (url) {
this.importPhotoFromSrc(url);
}
}
ngOnChanges(changes) {
if (changes.src && !changes.src.firstChange && changes.src.currentValue) {
if (typeof changes.src.currentValue === 'string') {
this.importPhotoFromSrc(changes.src.currentValue);
}
else if (changes.src.currentValue) {
this.importPhotoFromBlob(changes.src.currentValue);
}
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ImageDrawingComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: ImageDrawingComponent, isStandalone: true, selector: "image-drawing", inputs: { src: "src", width: "width", height: "height", saveBtnClass: "saveBtnClass", cancelBtnClass: "cancelBtnClass", forceSizeCanvas: "forceSizeCanvas", forceSizeExport: "forceSizeExport", enableRemoveImage: "enableRemoveImage", enableLoadAnotherImage: "enableLoadAnotherImage", enableTooltip: "enableTooltip", showCancelButton: "showCancelButton", i18nUser: ["i18n", "i18nUser"], locale: "locale", saveBtnText: "saveBtnText", cancelBtnText: "cancelBtnText", loadingText: "loadingText", errorText: "errorText", loadingTemplate: "loadingTemplate", errorTemplate: "errorTemplate", outputMimeType: "outputMimeType", outputQuality: "outputQuality", borderCss: "borderCss", drawingSizes: "drawingSizes", colors: "colors" }, outputs: { save: "save", cancel: "cancel" }, usesOnChanges: true, ngImport: i0, template: "\n\n@if (isLoading) {\n <div class=\"loading\">\n <ng-container *ngTemplateOutlet=\"loadingTemplate ? loadingTemplate : defaultLoading\"></ng-container>\n </div>\n}\n@if (hasError) {\n <div class=\"error\">\n <ng-container *ngTemplateOutlet=\"errorTemplate ? errorTemplate : defaultError\"></ng-container>\n </div>\n}\n\n<ng-template #defaultLoading><p>{{ getTextTranslated('loading') }}</p></ng-template>\n<ng-template #defaultError> <p>{{ errorMessage }}</p> </ng-template>\n\n<div [ngStyle]=\"{ border: borderCss }\">\n <canvas id=\"canvas\"></canvas>\n</div>\n@if (!isLoading) {\n <div class=\"toolbar\">\n <div class=\"tools\">\n <div class=\"row1\">\n <i class=\"material-icons btn1\" [class.selected]=\"currentTool === 'brush'\" (click)=\"selectTool('brush')\"\n [title]=\"getTooltipTranslated('tools.brush')\">brush</i>\n @for (drawingSizeName of drawingSizesName; track drawingSizeName) {\n <span class=\"size btn1\"\n [style.width.px]=\"drawingSizes[drawingSizeName] * 0.8 + 8\"\n [style.height.px]=\"drawingSizes[drawingSizeName] * 0.8 + 8\"\n [style.borderRadius.px]=\"drawingSizes[drawingSizeName] * 0.4 + 4\"\n [class.selected]=\"currentSize == drawingSizeName\"\n [title]=\"getTooltipTranslated('sizes.' + drawingSizeName)\"\n (click)=\"selectDrawingSize(drawingSizeName)\">\n </span>\n }\n <input style=\"display: none\" type=\"file\" #fileInput (change)=\"importPhotoFromFile($event)\"\n accept=\"image/*\"/>\n @if (enableLoadAnotherImage && !hasImage) {\n <i class=\"material-icons btn1\" (click)=\"fileInput.click();\"\n [title]=\"getTooltipTranslated('loadImage')\">attach_file</i>\n }\n @if (enableLoadAnotherImage && !hasImage) {\n <i class=\"material-icons btn1\" (click)=\"importPhotoFromUrl()\"\n [title]=\"getTooltipTranslated('loadImageUrl')\">insert_drive_file</i>\n }\n @if (enableRemoveImage && hasImage) {\n <i class=\"material-icons btn1\" (click)=\"removeImage()\"\n [title]=\"getTooltipTranslated('removeImage')\">clear</i>\n }\n <i class=\"material-icons btn1\" [class.selected]=\"currentTool === 'crop' || done===false\" (click)=\"crop()\"\n [title]=\"getTooltipTranslated('crop')\">crop</i>\n <i class=\"material-icons btn1\" [class.selected]=\"currentTool === 'mask'\" (click)=\"maskC()\"\n [title]=\"getTooltipTranslated('mask')\">crop_free</i>\n <i class=\"material-icons btn1\" [class.selected]=\"currentTool === 'resize'\" (click)=\"resize()\"\n [title]=\"getTooltipTranslated('resize')\">expand</i>\n <i class=\"material-icons btn1\" [class.disabled]=\"!canUndo\" (click)=\"undo()\"\n [title]=\"getTooltipTranslated('undo')\">undo</i>\n <i class=\"material-icons btn1\" [class.disabled]=\"!canRedo\" (click)=\"redo()\"\n [title]=\"getTooltipTranslated('redo')\">redo</i>\n <!-- <i class=\"material-icons btn1\" (click)=\"clearCanvas()\" [title]=\"getTooltipTranslated('clear')\">delete</i> -->\n </div>\n <div class=\"row1\">\n @for (shapeName of shapesNames; track shapeName) {\n <div class=\"material-icons-outlined btn1\" (click)=\"shape(shapeName.shape)\">\n {{shapeName.icon}}\n </div>\n }\n <div class=\"material-icons btn1\" (click)=\"rotate(90)\">\n rotate_right\n </div>\n </div>\n <div class=\"row1\">\n @for (colorName of colorsName; track colorName) {\n <div [class.selected]=\"currentColor === colorName\" class=\"color\"\n [ngClass]=\"colorName\"\n [style.background]=\"colors[colorName]\" [title]=\"getTooltipTranslated('colors.' + colorName)\"\n (click)=\"selectColor(colorName)\">\n </div>\n }\n </div>\n </div>\n <!-- Any additional toolbar buttons to be projected by the consuming app -->\n <ng-content></ng-content>\n </div>\n }\n @if (!isLoading) {\n <div class=\"buttons\">\n @if (showCancelButton) {\n <a href=\"#\" [class]=\"cancelBtnClass\"\n (click)=\"cancelAction(); $event.preventDefault()\">{{ getTextTranslated('cancelBtn') }}</a>\n }\n <button [class]=\"saveBtnClass\"\n (click)=\"saveImage()\">{{ getTextTranslated('saveBtn') }}</button>\n </div>\n }\n", styles: [":host{display:flex;flex-direction:column;align-items:center}:host .toolbar{display:flex;flex-direction:column;justify-content:space-between;align-items:center}:host .tools{display:inline-flex;flex-direction:column;padding:20px;margin:10px;background:#fff;border-radius:6px;box-shadow:0 3px 10px #0006}:host .row1{display:flex;width:300px;justify-content:space-around;align-items:center;margin-bottom:10px}:host .row1:last-child{margin-bottom:0}:host .btn1{cursor:pointer}:host .btn1.selected{color:#bdbdbd}:host .btn1.disabled{cursor:initial;color:#bdbdbd}:host .size{background-color:#000}:host .size.selected{background-color:#bdbdbd}:host .color{width:28px;height:28px;border-radius:14px;cursor:pointer;display:flex;align-items:center;justify-content:center}:host .color.selected:after{content:\"\";width:10px;height:10px;background:#000;display:flex;border-radius:5px}:host .color.black{background-color:#000}:host .color.black.selected:after{background:#fff}:host .color.white{border:1px solid #a7a7a7}:host .buttons{width:80%;margin:10px;display:flex;flex-direction:row;justify-content:flex-end}:host .button{cursor:pointer;outline:0;border:none;white-space:nowrap;text-decoration:none;vertical-align:baseline;text-align:center;min-width:64px;line-height:36px;padding:3px 16px;border-radius:4px;overflow:visible;transition:background .4s cubic-bezier(.25,.8,.25,1),box-shadow .28s cubic-bezier(.4,0,.2,1);margin:10px}:host .button:hover{text-decoration:none!important}:host .button.btn-primary{background-color:#ef5f27;color:#fff}:host .button.btn-primary:hover{background-color:#ef5f27cc}:host .button.btn-light{color:#ef5f27}:host .button.btn-light:hover{background-color:#ef5f271a}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ImageDrawingComponent, decorators: [{
type: Component,
args: [{ selector: 'image-drawing', standalone: true, imports: [NgTemplateOutlet, NgStyle, NgClass], template: "\n\n@if (isLoading) {\n <div class=\"loading\">\n <ng-container *ngTemplateOutlet=\"loadingTemplate ? loadingTemplate : defaultLoading\"></ng-container>\n </div>\n}\n@if (hasError) {\n <div class=\"error\">\n <ng-container *ngTemplateOutlet=\"errorTemplate ? errorTemplate : defaultError\"></ng-container>\n </div>\n}\n\n<ng-template #defaultLoading><p>{{ getTextTranslated('loading') }}</p></ng-template>\n<ng-template #defaultError> <p>{{ errorMessage }}</p> </ng-template>\n\n<div [ngStyle]=\"{ border: borderCss }\">\n <canvas id=\"canvas\"></canvas>\n</div>\n@if (!isLoading) {\n <div class=\"toolbar\">\n <div class=\"tools\">\n <div class=\"row1\">\n <i class=\"material-icons btn1\" [class.selected]=\"currentTool === 'brush'\" (click)=\"selectTool('brush')\"\n [title]=\"getTooltipTranslated('tools.brush')\">brush</i>\n @for (drawingSizeName of drawingSizesName; track drawingSizeName) {\n <span class=\"size btn1\"\n [style.width.px]=\"drawingSizes[drawingSizeName] * 0.8 + 8\"\n [style.height.px]=\"drawingSizes[drawingSizeName] * 0.8 + 8\"\n [style.borderRadius.px]=\"drawingSizes[drawingSizeName] * 0.4 + 4\"\n [class.selected]=\"currentSize == drawingSizeName\"\n [title]=\"getTooltipTranslated('sizes.' + drawingSizeName)\"\n (click)=\"selectDrawingSize(drawingSizeName)\">\n </span>\n }\n <input style=\"display: none\" type=\"file\" #fileInput (change)=\"importPhotoFromFile($event)\"\n accept=\"image/*\"/>\n @if (enableLoadAnotherImage && !hasImage) {\n <i class=\"material-icons btn1\" (click)=\"fileInput.click();\"\n [title]=\"getTooltipTranslated('loadImage')\">attach_file</i>\n }\n @if (enableLoadAnotherImage && !hasImage) {\n <i class=\"material-icons btn1\" (click)=\"importPhotoFromUrl()\"\n [title]=\"getTooltipTranslated('loadImageUrl')\">insert_drive_file</i>\n }\n @if (enableRemoveImage && hasImage) {\n <i class=\"material-icons btn1\" (click)=\"removeImage()\"\n [title]=\"getTooltipTranslated('removeImage')\">clear</i>\n }\n <i class=\"material-icons btn1\" [class.selected]=\"currentTool === 'crop' || done===false\" (click)=\"crop()\"\n [title]=\"getTooltipTranslated('crop')\">crop</i>\n <i class=\"material-icons btn1\" [class.selected]=\"currentTool === 'mask'\" (click)=\"maskC()\"\n [title]=\"getTooltipTranslated('mask')\">crop_free</i>\n <i class=\"material-icons btn1\" [class.selected]=\"currentTool === 'resize'\" (click)=\"resize()\"\n [title]=\"getTooltipTranslated('resize')\">expand</i>\n <i class=\"material-icons btn1\" [class.disabled]=\"!canUndo\" (click)=\"undo()\"\n [title]=\"getTooltipTranslated('undo')\">undo</i>\n <i class=\"material-icons btn1\" [class.disabled]=\"!canRedo\" (click)=\"redo()\"\n [title]=\"getTooltipTranslated('redo')\">redo</i>\n <!-- <i class=\"material-icons btn1\" (click)=\"clearCanvas()\" [title]=\"getTooltipTranslated('clear')\">delete</i> -->\n </div>\n <div class=\"row1\">\n @for (shapeName of shapesNames; track shapeName) {\n <div class=\"material-icons-outlined btn1\" (click)=\"shape(shapeName.shape)\">\n {{shapeName.icon}}\n </div>\n }\n <div class=\"material-icons btn1\" (click)=\"rotate(90)\">\n rotate_right\n </div>\n </div>\n <div class=\"row1\">\n @for (colorName of colorsName; track colorName) {\n <div [class.selected]=\"currentColor === colorName\" class=\"color\"\n [ngClass]=\"colorName\"\n [style.background]=\"colors[colorName]\" [title]=\"getTooltipTranslated('colors.' + colorName)\"\n (click)=\"selectColor(colorName)\">\n </div>\n }\n </div>\n </div>\n <!-- Any additional toolbar buttons to be projected by the consuming app -->\n <ng-content></ng-content>\n </div>\n }\n @if (!isLoading) {\n <div class=\"buttons\">\n @if (showCancelButton) {\n <a href=\"#\" [class]=\"cancelBtnClass\"\n (click)=\"cancelAction(); $event.preventDefault()\">{{ getTextTranslated('cancelBtn') }}</a>\n }\n <button [class]=\"saveBtnClass\"\n (click)=\"saveImage()\">{{ getTextTranslated('saveBtn') }}</button>\n </div>\n }\n", styles: [":host{display:flex;flex-direction:column;align-items:center}:host .toolbar{display:flex;flex-direction:column;justify-content:space-between;align-items:center}:host .tools{display:inline-flex;flex-direction:column;padding:20px;margin:10px;background:#fff;border-radius:6px;box-shadow:0 3px 10px #0006}:host .row1{display:flex;width:300px;justify-content:space-around;align-items:center;margin-bottom:10px}:host .row1:last-child{margin-bottom:0}:host .btn1{cursor:pointer}:host .btn1.selected{color:#bdbdbd}:host .btn1.disabled{cursor:initial;color:#bdbdbd}:host .size{background-color:#000}:host .size.selected{background-color:#bdbdbd}:host .color{width:28px;height:28px;border-radius:14px;cursor:pointer;display:flex;align-items:center;justify-content:center}:host .color.selected:after{content:\"\";width:10px;height:10px;background:#000;display:flex;border-radius:5px}:host .color.black{background-color:#000}:host .color.black.selected:after{background:#fff}:host .color.white{border:1px solid #a7a7a7}:host .buttons{width:80%;margin:10px;display:flex;flex-direction:row;justify-content:flex-end}:host .button{cursor:pointer;outline:0;border:none;white-space:nowrap;text-decoration:none;vertical-align:baseline;text-align:center;min-width:64px;line-height:36px;padding:3px 16px;border-radius:4px;overflow:visible;transition:background .4s cubic-bezier(.25,.8,.25,1),box-shadow .28s cubic-bezier(.4,0,.2,1);margin:10px}:host .button:hover{text-decoration:none!important}:host .button.btn-primary{background-color:#ef5f27;color:#fff}:host .button.btn-primary:hover{background-color:#ef5f27cc}:host .button.btn-light{color:#ef5f27}:host .button.btn-light:hover{background-color:#ef5f271a}\n"] }]
}], ctorParameters: () => [{ type: i0.NgZone }], propDecorators: { src: [{
type: Input
}], width: [{
type: Input
}], height: [{
type: Input
}], saveBtnClass: [{
type: Input
}], cancelBtnClass: [{
type: Input
}], forceSizeCanvas: [{
type: Input
}], forceSizeExport: [{
type: Input
}], enableRemoveImage: [{
type: Input
}], enableLoadAnotherImage: [{
type: Input
}], enableTooltip: [{
type: Input
}], showCancelButton: [{
type: Input
}], i18nUser: [{
type: Input,
args: ['i18n']
}], locale: [{
type: Input
}], saveBtnText: [{
type: Input
}], cancelBtnText: [{
type: Input
}], loadingText: [{
type: Input
}], errorText: [{
type: Input
}], loadingTemplate: [{
type: Input
}], errorTemplate: [{
type: Input
}], outputMimeType: [{
type: Input
}], outputQuality: [{
type: Input
}], borderCss: [{
type: Input
}], drawingSizes: [{
type: Input
}], colors: [{
type: Input
}], save: [{
type: Output
}], cancel: [{
type: Output
}] } });
class ImageDrawingModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ImageDrawingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: ImageDrawingModule, imports: [CommonModule,
MatIconModule,
ImageDrawingComponent], exports: [ImageDrawingComponent] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ImageDrawingModule, imports: [CommonModule,
MatIconModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ImageDrawingModule, decorators: [{
type: NgModule,
args: [{
exports: [
ImageDrawingComponent,
],
imports: [
CommonModule,
MatIconModule,
ImageDrawingComponent
]
}]
}] });
/*
* Public API Surface of ngx-image-drawing-zone
*/
/**
* Generated bundle index. Do not edit.
*/
export { I18nEn, I18nFr, I18nHe, ImageDrawingComponent, ImageDrawingModule, i18nLanguages };
//# sourceMappingURL=ngx-image-drawing-zone.mjs.map