ng-cw-v12
Version:
Angular UI component library
437 lines (432 loc) • 24.7 kB
JavaScript
import * as i0 from '@angular/core';
import { EventEmitter, Component, Input, Output, NgModule } from '@angular/core';
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i2 from '@angular/forms';
import { FormsModule } from '@angular/forms';
import { __awaiter } from 'tslib';
class ImgClipComponent {
constructor(eleRef) {
this.eleRef = eleRef;
this.ncConfirm = new EventEmitter(); //确认裁剪回调
this.ncImgType = 'base64'; //裁剪回调返回图片格式
this.ncWidth = 300; //容器宽度
this.ncClipSize = 0.7; //默认裁剪框的尺寸占图片比例
this.ncClipMinWidth = 50; //裁剪框最小宽度
this.ncClipMinHeight = 50; //裁剪框最小高度
this.downloadMode = false;
this.toolMode = false;
this.uploadMode = false;
this.hasImage = false;
// 图片当前宽高
this.clipImageWidth = 0;
this.clipImageHeight = 0;
// 图片原始宽高
this.clipImageOriginWidth = 0;
this.clipImageOriginHeight = 0;
this.scale = 0; //缩放比例
this.clipWidth = 0; //裁剪框宽度
this.clipHeight = 0; //裁剪框高度
this.clipX = 0; //裁剪框x
this.clipY = 0; //裁剪框y
}
set ncUrl(value) {
setTimeout(() => {
//加延迟,防止其他传入参数未获取到
this.readImage(value);
});
}
;
//确认裁剪时是否下载图片
set ncDownload(value) {
this.downloadMode = value !== null && value !== undefined && value !== false && value !== 'false';
}
//调整工具栏
set ncTool(value) {
this.toolMode = value !== null && value !== undefined && value !== false && value !== 'false';
}
//上传
set ncUpload(value) {
this.uploadMode = value !== null && value !== undefined && value !== false && value !== 'false';
}
ngOnInit() {
this.clipImage = this.eleRef.nativeElement.querySelector('#clipImage');
this.clipPathImg = this.eleRef.nativeElement.querySelector('#clipPathImg');
this.clip = this.eleRef.nativeElement.querySelector('#clip');
if (this.uploadMode) {
setTimeout(() => {
this.file = this.eleRef.nativeElement.querySelector('#file');
// 监听上传状态 浏览图片
this.file.addEventListener('change', (e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
this.readImage(reader.result);
};
});
});
}
//裁剪框缩放、拖拽
this.clipBoxZoom();
this.clipBpxDrag();
}
//读取图片
readImage(url) {
// 读取到的图片数据
this.clipImage.src = url;
// 裁剪使用的图片
this.clipPathImg.src = url;
//获取当前图片的宽高
this.getClipImageSize(url).then((res) => {
// 初始化
this.init();
this.hasImage = true;
});
}
// 获取上传图片的当前尺寸和原始尺寸
getClipImageSize(dataurl) {
return __awaiter(this, void 0, void 0, function* () {
const data = yield new Promise((resolve) => {
this.clipImage.onload = () => {
resolve(this.clipImage);
};
});
// 获取图片当前宽高
this.clipImageWidth = data.width;
this.clipImageHeight = data.height;
const data_1 = yield new Promise((resolve_1) => {
// 获取图片原始宽高
let img = document.createElement('img');
img.src = dataurl;
img.onload = () => {
resolve_1(img);
};
});
// 获取图片原始宽高
this.clipImageOriginWidth = data_1.width;
this.clipImageOriginHeight = data_1.height;
return yield Promise.resolve();
});
}
// 初始化
init() {
// 显示裁剪框
this.clip.style.display = 'block';
// 缩放比例
this.scale = this.clipImageOriginWidth / this.clipImageWidth;
// 设置裁剪框的宽高
let clipWidth = Math.floor(this.clipImageWidth * this.ncClipSize);
let clipHeight = Math.floor(this.clipImageHeight * this.ncClipSize);
this.setClipSize(clipWidth, clipHeight);
// 设置裁剪框的位置
let x = Math.floor((this.clipImageWidth - clipWidth) / 2);
let y = Math.floor((this.clipImageHeight - clipHeight) / 2);
this.setClipPosition(x, y);
}
// 设置裁剪框的尺寸
setClipSize(clipWidth, clipHeight) {
this.clip.style.setProperty('--clipWidth', clipWidth + 'px');
this.clip.style.setProperty('--clipHeight', clipHeight + 'px');
this.clipWidth = clipWidth;
this.clipHeight = clipHeight;
}
// 设置裁剪框的位置
setClipPosition(x, y) {
this.clip.style.setProperty('--clipX', x + 'px');
this.clip.style.setProperty('--clipY', y + 'px');
this.clipX = x;
this.clipY = y;
// 设置裁剪阴影
this.setClipPath();
}
// 设置裁剪阴影
setClipPath() {
let lt = this.clip.offsetLeft + 'px' + ' ' + this.clip.offsetTop + 'px';
let rt = (this.clip.offsetLeft + this.clip.offsetWidth) + 'px' + ' ' + this.clip.offsetTop + 'px';
let rb = (this.clip.offsetLeft + this.clip.offsetWidth) + 'px' + ' ' + (this.clip.offsetTop + this.clip.offsetHeight) + 'px';
let lb = this.clip.offsetLeft + 'px' + ' ' + (this.clip.offsetTop + this.clip.offsetHeight) + 'px';
this.clipPathImg.style.setProperty('--clipPath', `polygon(${lt}, ${rt}, ${rb}, ${lb})`);
}
// 裁剪
clipImg(x, y, cutWidth, cutHeight, width, height) {
return __awaiter(this, void 0, void 0, function* () {
let canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').drawImage(this.clipImage, x, y, cutWidth, cutHeight, 0, 0, width, height);
//下载
if (this.downloadMode) {
const a = document.createElement('a');
a.download = '裁剪图片';
a.href = canvas.toDataURL('image/png');
a.click();
}
// 返回裁剪后的图片
return new Promise((resolve) => {
if (this.ncImgType == 'base64') {
resolve(canvas.toDataURL('image/png'));
}
else {
canvas.toBlob((blob) => {
resolve(new File([blob], 'clip.png', { type: 'image/png' }));
});
}
});
});
}
//确认裁剪
confirm() {
return __awaiter(this, void 0, void 0, function* () {
let res = yield this.clipImg(this.clip.offsetLeft * this.scale, this.clip.offsetTop * this.scale, this.clip.offsetWidth * this.scale, this.clip.offsetHeight * this.scale, this.clip.offsetWidth, this.clip.offsetHeight);
this.ncConfirm.emit(res);
});
}
//裁剪框的拖拽
clipBpxDrag() {
// 鼠标按下
this.clip.onmousedown = (e) => {
// 偏移量
let py = {
x: e.clientX - this.clip.offsetLeft,
y: e.clientY - this.clip.offsetTop
};
// 鼠标移动
window.onmousemove = (e) => {
// 鼠标移动的距离
let moveX = e.clientX - py.x;
let moveY = e.clientY - py.y;
// 裁剪框的位置
let left = moveX;
let top = moveY;
// 裁剪框的位置限制
if (left < 0) {
left = 0;
}
if (top < 0) {
top = 0;
}
if (left > this.clipImageWidth - this.clip.offsetWidth) {
left = this.clipImageWidth - this.clip.offsetWidth;
}
if (top > this.clipImageHeight - this.clip.offsetHeight) {
top = this.clipImageHeight - this.clip.offsetHeight;
}
// 设置裁剪框的位置
this.setClipPosition(left, top);
};
// 鼠标松开
window.onmouseup = () => {
window.onmouseup = null;
window.onmousemove = null;
};
};
}
//裁剪框缩放
clipBoxZoom() {
// 获取裁剪框的四个角
let zoomDom = {
lt: this.eleRef.nativeElement.querySelector('.lt'),
rt: this.eleRef.nativeElement.querySelector('.rt'),
rb: this.eleRef.nativeElement.querySelector('.rb'),
lb: this.eleRef.nativeElement.querySelector('.lb'),
};
// 鼠标按下时的位置
let zoomInfo = {
x: 0,
y: 0,
minWidth: this.ncClipMinWidth,
minHeight: this.ncClipMinHeight
};
// 鼠标按下时裁剪框的位置
for (let key in zoomDom) {
zoomDom[key].onmousedown = (e) => {
// 禁止冒泡
e.stopPropagation();
// 鼠标按下时的位置
zoomInfo.x = e.clientX;
zoomInfo.y = e.clientY;
// 鼠标移动
window.onmousemove = (e) => {
// 鼠标移动的距离
let moveX = e.clientX - zoomInfo.x;
let moveY = e.clientY - zoomInfo.y;
// 裁剪框的位置
let left = 0;
let top = 0;
// 裁剪框的尺寸
let width = 0;
let height = 0;
// 左上角
if (key === 'lt') {
// 裁剪框的位置
left = this.clip.offsetLeft + moveX;
top = this.clip.offsetTop + moveY;
// 裁剪框的尺寸
width = this.clip.offsetWidth - moveX;
height = this.clip.offsetHeight - moveY;
// 裁剪框的位置限制
if (left < 0) {
left = 0;
// 原来宽度+原来left
width = this.clip.offsetWidth + this.clip.offsetLeft;
}
if (top < 0) {
top = 0;
// 原来高度+原来top
height = this.clip.offsetHeight + this.clip.offsetTop;
}
}
// 右上角
if (key === 'rt') {
// 裁剪框的位置
top = this.clip.offsetTop + moveY;
left = this.clip.offsetLeft;
// 裁剪框的尺寸
width = this.clip.offsetWidth + moveX;
height = this.clip.offsetHeight - moveY;
// 裁剪框的位置限制
if (top < 0) {
top = 0;
// 原来高度+原来top
height = this.clip.offsetHeight + this.clip.offsetTop;
}
if (left + width > this.clipImageWidth) {
// 图片当前宽-原来left
width = this.clipImageWidth - left;
}
}
// 右下角
if (key === 'rb') {
// 裁剪框的尺寸
top = this.clip.offsetTop;
left = this.clip.offsetLeft;
width = this.clip.offsetWidth + moveX;
height = this.clip.offsetHeight + moveY;
// 裁剪框的位置限制
// 当前的left+当前的width>图片当前宽
if (this.clip.offsetLeft + width > this.clipImageWidth) {
width = this.clipImageWidth - left;
}
// 当前的top+当前的height>图片当前宽
if (this.clip.offsetTop + height > this.clipImageHeight) {
height = this.clipImageHeight - top;
}
}
// 左下角
if (key === 'lb') {
// 裁剪框的位置
left = this.clip.offsetLeft + moveX;
top = this.clip.offsetTop;
// 裁剪框的尺寸
width = this.clip.offsetWidth - moveX;
height = this.clip.offsetHeight + moveY;
// 裁剪框的位置限制
if (left < 0) {
left = 0;
width = this.clip.offsetWidth + this.clip.offsetLeft;
}
// 当前的top+当前的height>图片当前宽
if (this.clip.offsetTop + height > this.clipImageHeight) {
height = this.clipImageHeight - top;
}
}
// 裁剪框的限制
({ width, height, left, top } = this.ClipWidthPosition(zoomInfo, width, height, left, top));
// 设置裁剪框的位置
this.setClipPosition(left, top);
// 设置裁剪框的尺寸
this.setClipSize(width, height);
// 记录上一次的位置
zoomInfo.x = e.clientX;
zoomInfo.y = e.clientY;
};
// 鼠标松开
window.onmouseup = () => {
window.onmouseup = null;
window.onmousemove = null;
};
};
}
}
// 裁剪框的宽高限制以及位置限制
ClipWidthPosition(zoomInfo, w, h, l, t) {
let width = w; //裁剪框宽度
let height = h; //裁剪框的高度
let left = l; //裁剪框的left
let top = t; //裁剪框的top
if (w < zoomInfo.minWidth) {
width = zoomInfo.minWidth;
left = this.clip.offsetLeft;
}
if (h < zoomInfo.minHeight) {
height = zoomInfo.minHeight;
top = this.clip.offsetTop;
}
return { width, height, left, top };
}
//尺寸输入框变化
sizeInputChange() {
this.setClipSize(this.clipWidth, this.clipHeight);
this.setClipPosition(this.clipX, this.clipY);
}
}
ImgClipComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: ImgClipComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
ImgClipComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.1.5", type: ImgClipComponent, selector: "nc-img-clip", inputs: { ncUrl: "ncUrl", ncImgType: "ncImgType", ncWidth: "ncWidth", ncClipSize: "ncClipSize", ncClipMinWidth: "ncClipMinWidth", ncClipMinHeight: "ncClipMinHeight", ncDownload: "ncDownload", ncTool: "ncTool", ncUpload: "ncUpload" }, outputs: { ncConfirm: "ncConfirm" }, ngImport: i0, template: "<div class=\"clipContainer\" [ngStyle]=\"{'width': ncWidth + 'px'}\">\r\n <div class=\"clipBtnContainer\">\r\n <div *ngIf=\"uploadMode\" class=\"filebutton\">\r\n <div>\u4E0A\u4F20\u56FE\u7247</div>\r\n <input type=\"file\" id=\"file\" class=\"fileInput\" accept=\"image/*\">\r\n </div>\r\n <div *ngIf=\"hasImage\" class=\"confirmBtn\" (click)=\"confirm()\">\u786E\u5B9A</div>\r\n </div>\r\n <div class=\"clipImageCantainer\">\r\n <img id=\"clipImage\" src=\"\" crossorigin=\"anonymous\">\r\n <img id=\"clipPathImg\" src=\"\">\r\n <div id=\"clip\">\r\n <div class=\"corner lt\"></div>\r\n <div class=\"corner rt\"></div>\r\n <div class=\"corner rb\"></div>\r\n <div class=\"corner lb\"></div>\r\n </div>\r\n </div>\r\n <div class=\"bottomInputContainer\" *ngIf=\"hasImage && toolMode\">\r\n <div class=\"inputRow\">\r\n <div class=\"inputCol\">\r\n <div class=\"rowLabel\">\u5BBD\uFF1A</div>\r\n <input class=\"nc-input-number sizeInput\" type=\"number\" [(ngModel)]=\"clipWidth\" [min]=\"ncClipMinWidth\"\r\n [max]=\"clipImageWidth\" step=\"1\" (ngModelChange)=\"sizeInputChange()\">\r\n </div>\r\n <div class=\"inputCol\">\r\n <div class=\"rowLabel\">\u9AD8\uFF1A</div>\r\n <input class=\"nc-input-number sizeInput\" type=\"number\" [(ngModel)]=\"clipHeight\" [min]=\"ncClipMinHeight\"\r\n [max]=\"clipImageHeight\" step=\"1\" (ngModelChange)=\"sizeInputChange()\">\r\n </div>\r\n </div>\r\n <div class=\"inputRow\">\r\n <div class=\"inputCol\">\r\n <div class=\"rowLabel\">X\uFF1A</div>\r\n <input class=\"nc-input-number sizeInput\" type=\"number\" [(ngModel)]=\"clipX\" [min]=\"0\"\r\n [max]=\"clipImageWidth - clipWidth\" step=\"1\" (ngModelChange)=\"sizeInputChange()\">\r\n </div>\r\n <div class=\"inputCol\">\r\n <div class=\"rowLabel\">Y\uFF1A</div>\r\n <input class=\"nc-input-number sizeInput\" type=\"number\" [(ngModel)]=\"clipY\" [min]=\"0\"\r\n [max]=\"clipImageHeight - clipHeight\" step=\"1\" (ngModelChange)=\"sizeInputChange()\">\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [".clipContainer{margin:5px}.clipContainer .clipBtnContainer{display:flex;align-items:center;justify-content:space-between;margin-bottom:5px}.clipContainer .clipBtnContainer .filebutton{position:relative;display:inline-block;overflow:hidden}.clipContainer .clipBtnContainer .filebutton input{position:absolute;top:0;opacity:0;font-size:0;width:100%;height:100%;cursor:pointer}.clipContainer .clipBtnContainer .filebutton div{font-size:13px;background:#00aeff;color:#fff;padding:4px 8px;border-radius:3px}.clipContainer .clipBtnContainer .confirmBtn{font-size:13px;background:#00aeff;color:#fff;padding:4px 8px;border-radius:3px;cursor:pointer}.clipContainer .clipImageCantainer{width:100%;position:relative}.clipContainer .clipImageCantainer:after{content:\"\";position:absolute;width:100%;height:100%;top:0;left:0;background:rgba(0,0,0,.5);z-index:1}.clipContainer .clipImageCantainer img{width:100%;top:0;left:0;display:block}.clipContainer .clipImageCantainer #clipPathImg{position:absolute;top:0;left:0;width:100%;height:100%;z-index:2;clip-path:var(--clipPath)}.clipContainer .clipImageCantainer #clip{position:absolute;top:0;left:0;width:var(--clipWidth);height:var(--clipHeight);left:var(--clipX);top:var(--clipY);z-index:3;cursor:move;border:1px dashed white;display:none}.clipContainer .clipImageCantainer #clip .corner{position:absolute;width:10px;height:10px;background:#fff;border:1px solid #000}.clipContainer .clipImageCantainer #clip .lt{cursor:nw-resize;left:-5px;top:-5px}.clipContainer .clipImageCantainer #clip .rt{cursor:ne-resize;right:-5px;top:-5px}.clipContainer .clipImageCantainer #clip .lb{cursor:sw-resize;left:-5px;bottom:-5px}.clipContainer .clipImageCantainer #clip .rb{cursor:se-resize;right:-5px;bottom:-5px}.clipContainer .bottomInputContainer .inputRow{display:flex;align-items:center;margin-top:5px}.clipContainer .bottomInputContainer .inputRow .inputCol{display:flex;align-items:center;margin-right:10px}.clipContainer .bottomInputContainer .inputRow .inputCol .rowLabel{width:30px;display:flex;justify-content:flex-end;color:#b9b9b9;mix-blend-mode:difference}.clipContainer .bottomInputContainer .inputRow .inputCol .sizeInput{width:70px}\n"], directives: [{ type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: ImgClipComponent, decorators: [{
type: Component,
args: [{
selector: 'nc-img-clip',
templateUrl: './img-clip.component.html',
styleUrls: ['./img-clip.component.less']
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { ncUrl: [{
type: Input
}], ncConfirm: [{
type: Output
}], ncImgType: [{
type: Input
}], ncWidth: [{
type: Input
}], ncClipSize: [{
type: Input
}], ncClipMinWidth: [{
type: Input
}], ncClipMinHeight: [{
type: Input
}], ncDownload: [{
type: Input
}], ncTool: [{
type: Input
}], ncUpload: [{
type: Input
}] } });
class NcImgClipModule {
}
NcImgClipModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcImgClipModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
NcImgClipModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcImgClipModule, declarations: [ImgClipComponent], imports: [CommonModule,
FormsModule], exports: [ImgClipComponent] });
NcImgClipModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcImgClipModule, imports: [[
CommonModule,
FormsModule
]] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcImgClipModule, decorators: [{
type: NgModule,
args: [{
declarations: [
ImgClipComponent
],
imports: [
CommonModule,
FormsModule
],
exports: [
ImgClipComponent
]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { ImgClipComponent, NcImgClipModule };
//# sourceMappingURL=ng-cw-v12-img-clip.js.map