UNPKG

image-resizer-cropper

Version:

A simple image crop with resizing built for Angular 7, compatible with Angular Universal (SSR).

460 lines (454 loc) 16.8 kB
import { Component, Input, ElementRef, Renderer2, Inject, PLATFORM_ID, Output, EventEmitter, NgModule } from '@angular/core'; import { isPlatformBrowser, CommonModule } from '@angular/common'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ class ImageResizerCropperComponent { /** * @param {?} _el * @param {?} _renderer * @param {?} platformId */ constructor(_el, _renderer, platformId) { this._el = _el; this._renderer = _renderer; this.platformId = platformId; this.croppedImage = new EventEmitter(null); this.error = new EventEmitter(null); this.isDown = false; this.offSet = []; this.isBrowser = isPlatformBrowser(this.platformId); if (this.isBrowser) { this.canvasOne = this._renderer.createElement("canvas"); this.contextOne = this.canvasOne.getContext("2d"); this.canvasTwo = this._renderer.createElement("canvas"); this.contextTwo = this.canvasTwo.getContext("2d"); this.canvasThree = this._renderer.createElement("canvas"); this.contextThree = this.canvasThree.getContext("2d"); this.canvasFour = this._renderer.createElement("canvas"); this.contextFour = this.canvasFour.getContext("2d"); this.imgOne = this._renderer.createElement("img"); this.imgTwo = this._renderer.createElement("img"); } } /** * @return {?} */ get crContainer() { return this._el.nativeElement.querySelector(".cr-container"); } /** * @return {?} */ get crRange() { return this._el.nativeElement.querySelector("#cr-range"); } /** * @return {?} */ get crImage() { return this._el.nativeElement.querySelector("#cr-image"); } /** * @return {?} */ get crLens() { return this._el.nativeElement.querySelector("#cr-lens"); } /** * @return {?} */ get btn() { return this._el.nativeElement.querySelector("#crop"); } /** * @return {?} */ get testImg() { return this._el.nativeElement.querySelector("#test-img"); } /** * @return {?} */ get finalCrop() { return this._el.nativeElement.querySelector("#final-crop"); } /** * @return {?} */ get fileUpload() { return this._el.nativeElement.querySelector("#file-upload"); } /** * @return {?} */ ngOnInit() { if (this.sourceImage) { if (this.sourceImage.target && this.sourceImage.target.files) { this.parseFile(this.sourceImage); } } } /** * @return {?} */ ngAfterViewInit() { if (this.sourceImage) { if (this.imgOne) { this._renderer.setProperty(this.imgOne, "src", this.crImage.getAttribute("src")); } this.setUpListeners(); this.setUpConfigurations(); } } /** * @param {?} changes * @return {?} */ ngOnChanges(changes) { if (changes["sourceImage"] && !changes["sourceImage"].firstChange && changes["sourceImage"].currentValue) { this.clearImagePosition(); if (changes["sourceImage"].currentValue.target && changes["sourceImage"].currentValue.target.files) { this.parseFile(this.sourceImage); } else { if (this.imgOne) { this._renderer.setProperty(this.imgOne, "src", this.crImage.getAttribute("src")); this.setUpListeners(); this.setUpConfigurations(); } } } } /** * @return {?} */ setUpListeners() { if (this.isBrowser) { this._renderer.listen(this.crRange, "input", event => { this.linkImageToRangeInput(event.target.value); }); this._renderer.listen(this.crImage, "mousedown", event => { this.mouseDownOnImage(event); }); this._renderer.listen(this.crImage, "mouseup", event => { this.mouseUpOnImage(); if (this.autoCrop) { this.resizeAndCropImage(); } }); this._renderer.listen(this.crImage, "mousemove", event => { event.preventDefault(); this.mouseMoveOnImage(event); }); this._renderer.listen(this.crContainer, "mouseout", event => { this.keepMouseMoveInsideContainer(); }); this._renderer.listen(this.btn, "click", event => { this.resizeAndCropImage(); }); } } /** * @return {?} */ setUpConfigurations() { this.setBorderColor(); this.setBackgroundOpacity(); this.setLensHeightAndWidth(); } /** * @param {?} value * @return {?} */ linkImageToRangeInput(value) { /** @type {?} */ const val = value / 100; this.crImage.style.transform = `scale(${val})`; } /** * @param {?} event * @return {?} */ mouseDownOnImage(event) { this.isDown = true; this.offSet = [ event.target.offsetLeft - event.clientX, event.target.offsetTop - event.clientY ]; } /** * @return {?} */ mouseUpOnImage() { this.isDown = false; } /** * @param {?} event * @return {?} */ mouseMoveOnImage(event) { if (this.isDown) { /** @type {?} */ const mousePosition = { x: event.clientX, y: event.clientY }; this.crImage.style.left = mousePosition.x + this.offSet[0] + "px"; this.crImage.style.top = mousePosition.y + this.offSet[1] + "px"; } } /** * @return {?} */ keepMouseMoveInsideContainer() { this.isDown = false; } /** * @param {?} e1 * @param {?} e2 * @return {?} */ checkForOverlap(e1, e2) { if (e1.length && e1.length > 1) { e1 = e1[0]; } if (e2.length && e2.length > 1) { e2 = e2[0]; } /** @type {?} */ const rect1 = e1 instanceof Element ? e1.getBoundingClientRect() : false; /** @type {?} */ const rect2 = e2 instanceof Element ? e2.getBoundingClientRect() : false; /** @type {?} */ let overlap = null; if (rect1 && rect2) { overlap = !(rect1.right < rect2.left || rect1.left > rect2.right || rect1.bottom < rect2.top || rect1.top > rect2.bottom); return [overlap, rect1, rect2]; } else { return [overlap, rect1, rect2]; } } /** * @return {?} */ getResizeRatio() { /** @type {?} */ const transform = this.crImage.style.transform; /** @type {?} */ const matrix = transform .substring(transform.indexOf("(") + 1, transform.indexOf(")")) .split(","); return matrix.length > 0 ? matrix[0] : null; } /** * @return {?} */ drawImageResize() { /** @type {?} */ const ratio = this.getResizeRatio(); this.canvasTwo.width = this.imgOne.width; this.canvasTwo.height = this.imgOne.height; this.contextTwo.drawImage(this.imgOne, 0, 0); this.canvasOne.width = this.imgOne.width * ratio; this.canvasOne.height = this.imgOne.height * ratio; this.contextOne.drawImage(this.canvasTwo, 0, 0, this.canvasTwo.width, this.canvasTwo.height, 0, 0, this.canvasOne.width, this.canvasOne.height); /** @type {?} */ const i = this.canvasOne.toDataURL("image/png", 100); if (this.testImg) { this._renderer.setProperty(this.testImg, "src", i); } return i; } /** * @param {?} src * @return {?} */ drawImageCrop(src) { /** @type {?} */ const overlap = this.checkForOverlap(this.crLens, this.crImage); if (this.imgTwo) { this._renderer.setProperty(this.imgTwo, "src", src); return new Promise((resolve, reject) => { this._renderer.listen(this.imgTwo, "load", event => { this.canvasThree.width = event.target.width; this.canvasThree.height = event.target.height; this.contextThree.drawImage(this.imgTwo, 0, 0); this.canvasFour.width = this.lensWidth; this.canvasFour.height = this.lensHeight; if (overlap) { /** @type {?} */ const xCrop = overlap[1]["x"] - overlap[2]["x"]; /** @type {?} */ const yCrop = overlap[1]["y"] - overlap[2]["y"]; this.contextFour.drawImage(this.canvasThree, xCrop, yCrop, this.lensWidth, this.lensHeight, 0, 0, this.lensWidth, this.lensHeight); if (this.roundCrop) { this.contextFour.globalCompositeOperation = "destination-in"; this.contextFour.beginPath(); this.contextFour.arc(this.lensWidth / 2, this.lensHeight / 2, this.lensHeight / 2, 0, Math.PI * 2); this.contextFour.closePath(); this.contextFour.fill(); } /** @type {?} */ const b = this.canvasFour.toDataURL("image/png", 100); this.cropAvailable = true; setTimeout(() => { if (this.finalCrop) { this._renderer.setProperty(this.finalCrop, "src", b); } }); resolve(b); } }); }); } } /** * @return {?} */ resizeAndCropImage() { /** @type {?} */ const imgSrc = this.drawImageResize(); this.drawImageCrop(imgSrc).then(result => { this.croppedImage.emit(result); console.log(result); }); } /** * @return {?} */ setLensHeightAndWidth() { if (this.lensHeight && this.lensHeight !== 150) { this._renderer.setStyle(this.crLens, "height", this.lensHeight + "px"); } if (this.lensWidth && this.lensWidth !== 150) { this._renderer.setStyle(this.crLens, "width", this.lensWidth + "px"); } if (this.roundCrop) { this._renderer.addClass(this.crLens, "rounded"); } } /** * @return {?} */ setBorderColor() { if (this.borderColor) { this._renderer.setStyle(this.crContainer, "border-color", this.borderColor); this._renderer.setStyle(this.crLens, "border-color", this.borderColor); /** @type {?} */ const spans = this.crLens.querySelectorAll("span"); spans.forEach(element => { this._renderer.setStyle(element, "border-color", this.borderColor); }); } } /** * @return {?} */ setBackgroundOpacity() { if (this.backgroundOpacity && this.crLens) { this._renderer.setStyle(this.crLens, "box-shadow", "0 0 0 200000px rgba(0, 0, 0, " + this.backgroundOpacity + ")"); } } /** * @param {?} event * @return {?} */ parseFile(event) { /** @type {?} */ const file = event.target.files[0]; if (file.type === "image/png" || file.type === "image/jpeg" || file.type === "image/gif" || file.type === "image/tiff") { /** @type {?} */ const reader = new FileReader(); reader.readAsDataURL(file); reader.addEventListener("load", e => { /** @type {?} */ const val = reader.result.toString(); this._renderer.setProperty(this.crImage, "src", val); this.loadedSourceImage = this.crImage.getAttribute("src"); this._renderer.setProperty(this.imgOne, "src", this.crImage.getAttribute("src")); this.setUpListeners(); this.setUpConfigurations(); }); reader.onerror = function () { console.log("there are some problems"); }; } else { this.loadedSourceImage = null; if (this.crContainer) { this._renderer.addClass(this.crContainer, "error"); } this.errorMessage = "Invalid file type."; this.error.emit(this.errorMessage); } } /** * @return {?} */ clearImagePosition() { if (this.crImage) { this.crImage.style.left = "auto"; this.crImage.style.top = "auto"; } } } ImageResizerCropperComponent.decorators = [ { type: Component, args: [{ selector: "irc-image-resizer-cropper", template: "<ng-container *ngIf=\"sourceImage\">\n <div class=\"cr-container\">\n <div id=\"cr-lens\">\n <span></span>\n <span></span>\n <span></span>\n <span></span>\n </div>\n <img\n src=\"{{ loadedSourceImage }}\"\n style=\"transform: scale(1);\"\n draggable=\"false\"\n id=\"cr-image\"\n />\n <div *ngIf=\"errorMessage\" id=\"error-message\">{{ errorMessage }}</div>\n </div>\n <div class=\"cr-range-selector\">\n <input type=\"range\" id=\"cr-range\" min=\"10\" max=\"200\" />\n </div>\n <div class=\"text-center\">\n <button id=\"crop\" type=\"button\">Crop</button>\n </div>\n <div>\n <img src=\"#\" id=\"test-img\" style=\"display:none;\" />\n <img src=\"#\" *ngIf=\"previewCrop && cropAvailable\" id=\"final-crop\" />\n </div>\n</ng-container>\n", styles: [".text-center{text-align:center}.cr-container{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;-webkit-box-pack:center;justify-content:center;position:relative;min-height:300px;margin:0 auto;overflow:hidden;border:2px dashed #333}.cr-range-selector{margin:1rem 0;text-align:center}#cr-lens{height:150px;width:150px;border:2px solid #333;z-index:999999;box-shadow:0 0 0 200000px rgba(0,0,0,.2);position:relative}#cr-lens.rounded{border-radius:50%}#cr-lens span{position:absolute;width:15px;height:15px}#cr-lens span:nth-child(1){top:-17px;left:-17px;border-right:2px dashed #333;border-bottom:2px dashed #333}#cr-lens span:nth-child(2){top:-17px;right:-17px;border-left:2px dashed #333;border-bottom:2px dashed #333}#cr-lens span:nth-child(3){bottom:-17px;right:-17px;border-left:2px dashed #333;border-top:2px dashed #333}#cr-lens span:nth-child(4){bottom:-17px;left:-17px;border-right:2px dashed #333;border-top:2px dashed #333}#cr-image{display:block;position:absolute;-webkit-transform-origin:center center;transform-origin:center center;cursor:move}"] }] } ]; /** @nocollapse */ ImageResizerCropperComponent.ctorParameters = () => [ { type: ElementRef }, { type: Renderer2 }, { type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] } ]; ImageResizerCropperComponent.propDecorators = { sourceImage: [{ type: Input }], lensHeight: [{ type: Input }], lensWidth: [{ type: Input }], autoCrop: [{ type: Input }], previewCrop: [{ type: Input }], roundCrop: [{ type: Input }], borderColor: [{ type: Input }], backgroundOpacity: [{ type: Input }], croppedImage: [{ type: Output }], error: [{ type: Output }] }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ class ImageResizerCropperModule { } ImageResizerCropperModule.decorators = [ { type: NgModule, args: [{ imports: [CommonModule], declarations: [ImageResizerCropperComponent], exports: [ImageResizerCropperComponent] },] } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ export { ImageResizerCropperComponent, ImageResizerCropperModule }; //# sourceMappingURL=image-resizer-cropper.js.map