【Angular】使用Material Design的图像裁剪器修剪图标
引言
在本文中,创建像这里一样的剪裁图标对话框。

这里有一个例子。
安装软件包
安装@angular/material
$ ng add @angular/material
安装ngx-image-cropper
$ npm i ngx-image-cropper
将index.html文件添加到Material Icon生效。
<link
href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet"
/>
将style.scss添加到影响Material主题的部分。
@import '~@angular/material/prebuilt-themes/indigo-pink.css';
编码
图片裁剪对话框
图像裁剪对话框.ts
import { ChangeDetectorRef, Component, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import {
base64ToFile,
ImageCroppedEvent,
ImageTransform,
} from 'ngx-image-cropper';
@Component({
selector: 'image-cropper-dialog',
templateUrl: './image-cropper-dialog.html',
styleUrls: ['./image-cropper-dialog.scss'],
})
export class ImageCropperDialog {
imageChangedEvent: any = '';
croppedImage: any = '';
rotation: number = 0;
scale: number = 1;
showCropper: boolean = false;
containWithinAspectRatio: boolean = true;
transform: ImageTransform = {};
defaultWidth: number;
defaultHeight: number;
constructor(
@Inject(MAT_DIALOG_DATA) public data: any,
private readonly dialogRef: MatDialogRef<ImageCropperDialog>,
private readonly cd: ChangeDetectorRef
) {
this.fileChangeEvent(data.event);
}
fileChangeEvent(event: any): void {
this.imageChangedEvent = event;
}
applyIcon(): void {
console.log('Cropped Image!', this.croppedImage);
}
resetImage() {
this.scale = 1;
this.rotation = 0;
this.transform = {};
this._resetCropperPosition();
}
imageCropped(event: ImageCroppedEvent) {
this.croppedImage = base64ToFile(event.base64);
// or if you want to save as base64
// this.croppedImage = base64ToFile(event.base64);
}
imageLoaded() {
this.showCropper = true;
}
rotateLeft() {
this.rotation--;
this._flipAfterRotate();
}
rotateRight() {
this.rotation++;
this._flipAfterRotate();
}
flipHorizontal() {
this.transform = {
...this.transform,
flipH: !this.transform.flipH,
};
}
flipVertical() {
this.transform = {
...this.transform,
flipV: !this.transform.flipV,
};
}
changeScale(e) {
this.scale = e.value;
this.transform = {
...this.transform,
scale: this.scale,
};
}
zoomOut() {
this.scale -= 0.1;
this.transform = {
...this.transform,
scale: this.scale,
};
}
zoomIn() {
this.scale += 0.1;
this.transform = {
...this.transform,
scale: this.scale,
};
}
toggleContainWithinAspectRatio() {
this.containWithinAspectRatio = !this.containWithinAspectRatio;
}
closeEditIconDialog(): void {
this.dialogRef.close();
}
private _flipAfterRotate() {
const flippedH = this.transform.flipH;
const flippedV = this.transform.flipV;
this.transform = {
...this.transform,
flipH: flippedV,
flipV: flippedH,
};
}
private _resetCropperPosition(): void {
this.containWithinAspectRatio = false;
this.cd.detectChanges();
this.containWithinAspectRatio = true;
}
}
图片裁剪对话框.html
<ng-container>
<div class="mat-dialog-header">
<div class="flex-start">
<button mat-icon-button (click)="closeEditIconDialog()">
<mat-icon>arrow_back</mat-icon>
</button>
<h1 mat-dialog-title class="mb-0">Tim Icon</h1>
</div>
<div class="my-8 action-header flex-center">
<button mat-icon-button (click)="rotateLeft()">
<mat-icon>rotate_left</mat-icon>
</button>
<button mat-icon-button (click)="rotateRight()">
<mat-icon>rotate_right</mat-icon>
</button>
<button mat-icon-button (click)="flipHorizontal()">
<mat-icon>swap_horiz</mat-icon>
</button>
<button mat-icon-button (click)="flipVertical()">
<mat-icon>sync</mat-icon>
</button>
</div>
</div>
<mat-dialog-content>
<image-cropper
[imageChangedEvent]="imageChangedEvent"
[maintainAspectRatio]="true"
[containWithinAspectRatio]="containWithinAspectRatio"
[aspectRatio]="1"
[resizeToWidth]="256"
[cropperMinWidth]="128"
[onlyScaleDown]="true"
[roundCropper]="false"
[canvasRotation]="rotation"
[transform]="transform"
[alignImage]="'center'"
[style.display]="showCropper ? null : 'none'"
format="png"
(imageCropped)="imageCropped($event)"
(imageLoaded)="imageLoaded()"
></image-cropper>
</mat-dialog-content>
<div class="flex-center">
<button mat-icon-button (click)="zoomOut()">
<mat-icon>zoom_out</mat-icon>
</button>
<mat-slider
step="0.1"
min="1"
max="2"
[value]="scale"
(change)="changeScale($event)"
></mat-slider>
<button mat-icon-button (click)="zoomIn()">
<mat-icon>zoom_in</mat-icon>
</button>
</div>
<mat-dialog-actions class="flex-end">
<button mat-button (click)="resetImage()">Reset</button>
<button mat-button color="accent" (click)="applyIcon()">Apply</button>
</mat-dialog-actions>
</ng-container>
图像裁剪对话框.scss
:host {
.flex-start {
display: flex;
justify-content: start;
text-align: center;
}
.flex-center {
display: flex;
justify-content: center;
text-align: center;
}
.flex-end {
display: flex;
justify-content: end;
text-align: center;
}
.action-header {
background-color: #f5f5f5;
}
.mat-dialog-content {
.cropper-container {
width: 100%;
margin: 0 auto;
}
}
img {
width: 600px;
}
}
::ng-deep .ngx-ic-move {
border-radius: 50%;
outline: 1px solid #888;
}
使用剪裁器组件(例如:app.component)
app.component.ts 的原因是处理组件的逻辑和功能。
import { Component } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { ImageCropperDialog } from './image-cropper-dialog/image-cropper-dialog';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
constructor(private readonly dialog: MatDialog) {}
fileChangeEvent(event: any): void {
this.dialog.open(ImageCropperDialog, {
width: '600px',
data: event,
});
}
}
应用程序.component.html
<input type="file" (change)="fileChangeEvent($event)" />
应用程序.module.ts
导入模块
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
+ import { ImageCropperModule } from 'ngx-image-cropper';
+ import { ImageCropperDialog } from './image-cropper-dialog/image-cropper-dialog';
+ import { MatButtonModule } from '@angular/material/button';
+ import { MatIconModule } from '@angular/material/icon';
+ import { MatDialogModule } from '@angular/material/dialog';
+ import { MatSliderModule } from '@angular/material/slider';
+ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
imports: [
BrowserModule,
FormsModule,
+ MatButtonModule,
+ MatIconModule,
+ MatDialogModule,
+ MatSliderModule,
+ ImageCropperModule,
+ BrowserAnimationsModule,
],
declarations: [
AppComponent,
+ ImageCropperDialog
],
bootstrap: [AppComponent],
+ entryComponents: [ImageCropperDialog],
})
export class AppModule {}