ngx-image-drawing
Version:
Angular module to draw on images
2 lines • 16.2 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@angular/common"),require("@angular/core"),require("fabric"),require("rxjs"),require("rxjs/operators")):"function"==typeof define&&define.amd?define("ngx-image-drawing",["exports","@angular/common","@angular/core","fabric","rxjs","rxjs/operators"],t):t((e=e||self)["ngx-image-drawing"]={},e.ng.common,e.ng.core,e.fabric,e.rxjs,e.rxjs.operators)}(this,(function(e,t,o,n,i,r){"use strict";function a(e,t,o,n){var i,r=arguments.length,a=r<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,o):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,o,n);else for(var s=e.length-1;s>=0;s--)(i=e[s])&&(a=(r<3?i(a):r>3?i(t,o,a):i(t,o))||a);return r>3&&a&&Object.defineProperty(t,o,a),a}function s(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}function l(e,t){var o="function"==typeof Symbol&&e[Symbol.iterator];if(!o)return e;var n,i,r=o.call(e),a=[];try{for(;(void 0===t||t-- >0)&&!(n=r.next()).done;)a.push(n.value)}catch(e){i={error:e}}finally{try{n&&!n.done&&(o=r.return)&&o.call(r)}finally{if(i)throw i.error}}return a}var c={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"},undo:"Undo",redo:"Redo",clear:"Clear",colors:{black:"Black",white:"White",yellow:"Yellow",red:"Red",green:"Green",blue:"Blue",purple:"Purple"},tools:{brush:"Brush"}},d={fr:{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"}},en:c},h=function(){function e(){this.forceSizeCanvas=!0,this.forceSizeExport=!1,this.enableRemoveImage=!1,this.enableLoadAnotherImage=!1,this.enableTooltip=!0,this.showCancelButton=!0,this.locale="en",this.saveBtnText="Save",this.cancelBtnText="Cancel",this.loadingText="Loading…",this.errorText="Error loading %@",this.outputMimeType="image/jpeg",this.outputQuality=.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 o.EventEmitter,this.cancel=new o.EventEmitter,this.currentTool="brush",this.currentSize="medium",this.currentColor="black",this.i18n=c,this.canUndo=!1,this.canRedo=!1,this.isLoading=!1,this.hasError=!1,this.errorMessage="",this.stack=[],this.colorsName=[],this.drawingSizesName=[]}return e.prototype.ngOnInit=function(){var e=this;if(this.colorsName=Object.keys(this.colors),this.drawingSizesName=Object.keys(this.drawingSizes),this.canvas=new n.fabric.Canvas("canvas",{hoverCursor:"pointer",isDrawingMode:!0}),this.canvas.backgroundColor="white",this.src)this.importPhotoFromSrc(this.src);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("path:created",(function(){e.stack=[],e.setUndoRedo()})),this.selectTool(this.currentTool),this.selectColor(this.currentColor),this.selectDrawingSize(this.currentSize),this.locale&&d[this.locale.toLowerCase()]&&(this.i18n=d[this.locale.toLowerCase()]),this.saveBtnText&&(this.i18n.saveBtn=this.saveBtnText),this.cancelBtnText&&(this.i18n.cancelBtn=this.cancelBtnText),this.loadingText&&(this.i18n.loading=this.loadingText),this.errorText&&(this.i18n.loadError=this.errorText)},e.prototype.selectTool=function(e){this.currentTool=e},e.prototype.selectDrawingSize=function(e){this.currentSize=e,this.canvas&&(this.canvas.freeDrawingBrush.width=this.drawingSizes[e])},e.prototype.selectColor=function(e){this.currentColor=e,this.canvas&&(this.canvas.freeDrawingBrush.color=this.colors[e])},e.prototype.undo=function(){if(this.canUndo){var e=this.canvas.getObjects().length-1,t=this.canvas.getObjects()[e];this.stack.push(t),this.canvas.remove(t),this.setUndoRedo()}},e.prototype.redo=function(){if(this.canRedo){var e=this.stack.splice(-1,1)[0];e&&this.canvas.insertAt(e,this.canvas.getObjects().length-1,!1),this.setUndoRedo()}},e.prototype.clearCanvas=function(){var e;this.canvas&&((e=this.canvas).remove.apply(e,function(){for(var e=[],t=0;t<arguments.length;t++)e=e.concat(l(arguments[t]));return e}(this.canvas.getObjects())),this.setUndoRedo())},e.prototype.saveImage=function(){var e=this;if(!this.forceSizeExport||this.forceSizeExport&&this.width&&this.height){var t=document.createElement("canvas"),o=new n.fabric.Canvas(t);o.backgroundColor="white",new i.Observable((function(t){e.imageUsed?e.forceSizeExport?(o.setWidth(e.width),o.setHeight(e.height),e.imageUsed.cloneAsImage((function(n){n.scaleToWidth(e.width,!1),n.scaleToHeight(e.height,!1),o.setBackgroundImage(n,(function(e){e||t.error(new Error("Impossible to draw the image on the temporary canvas")),t.next(o),t.complete()}),{crossOrigin:"anonymous",originX:"left",originY:"top"})}))):o.setBackgroundImage(e.imageUsed,(function(e){e||t.error(new Error("Impossible to draw the image on the temporary canvas")),o.setWidth(e.width),o.setHeight(e.height),t.next(o),t.complete()}),{crossOrigin:"anonymous",originX:"left",originY:"top"}):(o.setWidth(e.width),o.setHeight(e.height))})).pipe(r.switchMap((function(){var t=i.of(o);if(e.canvas.getObjects().length>0){var n=o.getWidth()/e.canvas.getWidth(),a=o.getHeight()/e.canvas.getHeight();e.canvas.getObjects().forEach((function(e,s){t=t.pipe(r.switchMap((function(){return new i.Observable((function(t){e.clone((function(i){i.set("left",e.left*n),i.set("top",e.top*a),i.scaleToWidth(e.width*n),i.scaleToHeight(e.height*a),o.insertAt(i,s,!1),o.renderAll(),t.next(o),t.complete()}))}))})))}))}return t}))).subscribe((function(){o.renderAll(),o.getElement().toBlob((function(t){e.save.emit(t)}),e.outputMimeType,e.outputQuality)}))}else this.canvas.getElement().toBlob((function(t){e.save.emit(t)}),this.outputMimeType,this.outputQuality)},e.prototype.cancelAction=function(){this.cancel.emit()},e.prototype.getTextTranslated=function(e){var t=e.split(".").reduce((function(e,t){return e[t]}),this.i18n);if(this.i18nUser)try{var o=e.split(".").reduce((function(e,t){return e[t]}),this.i18nUser);o&&(t=o)}catch(e){}return t||console.error(e+" translation not found !"),t},e.prototype.getTooltipTranslated=function(e){return this.enableTooltip?this.getTextTranslated(e):""},e.prototype.setUndoRedo=function(){this.canUndo=this.canvas.getObjects().length>0,this.canRedo=this.stack.length>0,this.canvas.renderAll()},e.prototype.importPhotoFromFile=function(e){if(e.target.files&&e.target.files.length>0){var t=e.target.files[0];if(!t.type.match("image.*"))throw new Error("Not an image !");this.importPhotoFromBlob(t)}},e.prototype.removeImage=function(){this.imageUsed&&(this.imageUsed.dispose(),this.imageUsed=null),this.canvas.backgroundImage=null,this.width&&this.height&&(this.canvas.setWidth(this.width),this.canvas.setHeight(this.height)),this.canvas.renderAll()},Object.defineProperty(e.prototype,"hasImage",{get:function(){return!!this.canvas.backgroundImage},enumerable:!0,configurable:!0}),e.prototype.importPhotoFromSrc=function(e){var t=this;this.isLoading=!0;var o=!0,i=new Image;i.setAttribute("crossOrigin","anonymous"),i.src=e,i.onerror=function(){o?(i.src="https://cors-anywhere.herokuapp.com/"+t.src,o=!1):(t.isLoading=!1,t.hasError=!0,t.errorMessage=t.getTextTranslated("loadError").replace("%@",t.src))},i.onload=function(){t.isLoading=!1,t.imageUsed=new n.fabric.Image(i),t.imageUsed.cloneAsImage((function(e){var o=i.width,n=i.height;t.width&&(o=t.width),t.height&&(n=t.height),e.scaleToWidth(o,!1),e.scaleToHeight(n,!1),t.canvas.setBackgroundImage(e,(function(i){i&&(t.forceSizeCanvas?(t.canvas.setWidth(o),t.canvas.setHeight(n)):(t.canvas.setWidth(e.getScaledWidth()),t.canvas.setHeight(e.getScaledHeight())))}),{crossOrigin:"anonymous",originX:"left",originY:"top"})}))}},e.prototype.importPhotoFromBlob=function(e){var t=this,o=new FileReader;o.readAsDataURL(e),o.onload=function(e){e.target.readyState==FileReader.DONE&&t.importPhotoFromSrc(e.target.result)}},e.prototype.importPhotoFromUrl=function(){var e=prompt(this.getTooltipTranslated("loadImageUrl"));e&&this.importPhotoFromSrc(e)},e.prototype.ngOnChanges=function(e){e.src&&!e.src.firstChange&&e.src.currentValue&&("string"==typeof e.src.currentValue?this.importPhotoFromSrc(e.src.currentValue):e.src.currentValue instanceof Blob&&this.importPhotoFromBlob(e.src.currentValue))},a([o.Input(),s("design:type",String)],e.prototype,"src",void 0),a([o.Input(),s("design:type",Number)],e.prototype,"width",void 0),a([o.Input(),s("design:type",Number)],e.prototype,"height",void 0),a([o.Input(),s("design:type",Object)],e.prototype,"forceSizeCanvas",void 0),a([o.Input(),s("design:type",Object)],e.prototype,"forceSizeExport",void 0),a([o.Input(),s("design:type",Object)],e.prototype,"enableRemoveImage",void 0),a([o.Input(),s("design:type",Object)],e.prototype,"enableLoadAnotherImage",void 0),a([o.Input(),s("design:type",Object)],e.prototype,"enableTooltip",void 0),a([o.Input(),s("design:type",Object)],e.prototype,"showCancelButton",void 0),a([o.Input("i18n"),s("design:type",Object)],e.prototype,"i18nUser",void 0),a([o.Input(),s("design:type",String)],e.prototype,"locale",void 0),a([o.Input(),s("design:type",Object)],e.prototype,"saveBtnText",void 0),a([o.Input(),s("design:type",Object)],e.prototype,"cancelBtnText",void 0),a([o.Input(),s("design:type",Object)],e.prototype,"loadingText",void 0),a([o.Input(),s("design:type",Object)],e.prototype,"errorText",void 0),a([o.Input(),s("design:type",o.TemplateRef)],e.prototype,"loadingTemplate",void 0),a([o.Input(),s("design:type",o.TemplateRef)],e.prototype,"errorTemplate",void 0),a([o.Input(),s("design:type",Object)],e.prototype,"outputMimeType",void 0),a([o.Input(),s("design:type",Object)],e.prototype,"outputQuality",void 0),a([o.Input(),s("design:type",String)],e.prototype,"borderCss",void 0),a([o.Input(),s("design:type",Object)],e.prototype,"drawingSizes",void 0),a([o.Input(),s("design:type",Object)],e.prototype,"colors",void 0),a([o.Output(),s("design:type",o.EventEmitter)],e.prototype,"save",void 0),a([o.Output(),s("design:type",o.EventEmitter)],e.prototype,"cancel",void 0),e=a([o.Component({selector:"image-drawing",template:'<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />\n\n<div class="loading" *ngIf="isLoading">\n <ng-container *ngTemplateOutlet="loadingTemplate ? loadingTemplate : defaultLoading"></ng-container>\n</div>\n<div class="error" *ngIf="hasError">\n <ng-container *ngTemplateOutlet="errorTemplate ? errorTemplate : defaultError"></ng-container>\n</div>\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<div class="toolbar" *ngIf="!isLoading">\n <div class="tools">\n <div class="row">\n <i class="material-icons btn" [class.selected]="currentTool == \'brush\'" (click)="selectTool(\'brush\')"\n [title]="getTooltipTranslated(\'tools.brush\')">brush</i>\n <span *ngFor="let drawingSizeName of drawingSizesName" class="size btn"\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 <i class="material-icons btn" *ngIf="enableLoadAnotherImage && !hasImage" (click)="fileInput.click();"\n [title]="getTooltipTranslated(\'loadImage\')">attach_file</i>\n <i class="material-icons btn" *ngIf="enableLoadAnotherImage && !hasImage" (click)="importPhotoFromUrl()"\n [title]="getTooltipTranslated(\'loadImageUrl\')">insert_drive_file</i>\n <i class="material-icons btn" *ngIf="enableRemoveImage && hasImage" (click)="removeImage()"\n [title]="getTooltipTranslated(\'removeImage\')">clear</i>\n\n <i class="material-icons btn" [class.disabled]="!canUndo" (click)="undo()"\n [title]="getTooltipTranslated(\'undo\')">undo</i>\n <i class="material-icons btn" [class.disabled]="!canRedo" (click)="redo()"\n [title]="getTooltipTranslated(\'redo\')">redo</i>\n <i class="material-icons btn" (click)="clearCanvas()" [title]="getTooltipTranslated(\'clear\')">delete</i>\n </div>\n <div class="row">\n <div *ngFor="let colorName of colorsName" [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 </div>\n </div>\n <div class="buttons">\n <a href="#" class="button btn-primary"\n (click)="saveImage(); $event.preventDefault()">{{ getTextTranslated(\'saveBtn\') }}</a>\n <a href="#" class="button btn-light" *ngIf="showCancelButton"\n (click)="cancelAction(); $event.preventDefault()">{{ getTextTranslated(\'cancelBtn\') }}</a>\n </div>\n \x3c!-- Any additional toolbar buttons to be projected by the consuming app --\x3e\n <ng-content></ng-content>\n</div>\n',styles:[':host{display:flex;flex-direction:column;align-items:center}:host .toolbar{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap}:host .tools{display:inline-flex;flex-direction:column;padding:20px;margin:10px;background:#fff;border-radius:6px;box-shadow:0 3px 10px rgba(0,0,0,.4)}:host .row{display:flex;width:300px;justify-content:space-around;align-items:center}:host .row:first-child{margin-bottom:10px}:host .btn{cursor:pointer}:host .btn.selected{color:#bdbdbd}:host .btn.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{margin:10px;display:flex;flex-direction:column}: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 280ms 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:rgba(239,95,39,.8)}:host .button.btn-light{color:#ef5f27}:host .button.btn-light:hover{background-color:rgba(239,95,39,.1)}']}),s("design:paramtypes",[])],e)}(),p=function(){function e(){}return e=a([o.NgModule({declarations:[h],exports:[h],imports:[t.CommonModule]})],e)}();e.ImageDrawingComponent=h,e.ImageDrawingModule=p,Object.defineProperty(e,"__esModule",{value:!0})}));
//# sourceMappingURL=ngx-image-drawing.umd.min.js.map