@libs-ui/components-image-editor 0.2.190 → 0.2.192
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +253 -2
- package/demo/image-editor-demo.component.d.ts +48 -0
- package/esm2022/demo/image-editor-demo.component.mjs +154 -0
- package/esm2022/image-editor.component.mjs +23 -9
- package/esm2022/index.mjs +2 -1
- package/fesm2022/libs-ui-components-image-editor.mjs +174 -10
- package/fesm2022/libs-ui-components-image-editor.mjs.map +1 -1
- package/image-editor.component.d.ts +1 -1
- package/index.d.ts +1 -0
- package/package.json +9 -9
package/esm2022/index.mjs
CHANGED
|
@@ -2,4 +2,5 @@ export * from './image-editor.component';
|
|
|
2
2
|
export * from './interfaces/image-editor.interface';
|
|
3
3
|
export * from './interfaces/function-control-event.interface';
|
|
4
4
|
export * from './resize/resize.component';
|
|
5
|
-
|
|
5
|
+
export * from './demo/image-editor-demo.component';
|
|
6
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9saWJzLXVpL2NvbXBvbmVudHMvaW1hZ2UtZWRpdG9yL3NyYy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLDBCQUEwQixDQUFDO0FBQ3pDLGNBQWMscUNBQXFDLENBQUM7QUFDcEQsY0FBYywrQ0FBK0MsQ0FBQztBQUM5RCxjQUFjLDJCQUEyQixDQUFDO0FBQzFDLGNBQWMsb0NBQW9DLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tICcuL2ltYWdlLWVkaXRvci5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9pbnRlcmZhY2VzL2ltYWdlLWVkaXRvci5pbnRlcmZhY2UnO1xuZXhwb3J0ICogZnJvbSAnLi9pbnRlcmZhY2VzL2Z1bmN0aW9uLWNvbnRyb2wtZXZlbnQuaW50ZXJmYWNlJztcbmV4cG9ydCAqIGZyb20gJy4vcmVzaXplL3Jlc2l6ZS5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9kZW1vL2ltYWdlLWVkaXRvci1kZW1vLmNvbXBvbmVudCc7Il19
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NgTemplateOutlet } from '@angular/common';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { EventEmitter, Output, Input, Component, signal, input, model, viewChild, output, inject, Optional, Inject, ChangeDetectionStrategy } from '@angular/core';
|
|
3
|
+
import { EventEmitter, Output, Input, Component, signal, input, model, viewChild, output, inject, Optional, Inject, ChangeDetectionStrategy, ViewChild } from '@angular/core';
|
|
4
4
|
import { LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';
|
|
5
5
|
import { LibsUiComponentsInputsValidComponent } from '@libs-ui/components-inputs-valid';
|
|
6
6
|
import { LibsUiComponentsModalComponent } from '@libs-ui/components-modal';
|
|
@@ -331,7 +331,7 @@ class LibsUiComponentsImageEditorComponent {
|
|
|
331
331
|
initMouseEvent() {
|
|
332
332
|
const mouseUp = this.initEvent({ nativeElement: document }, 'mouseup', { callStopPropagation: true, callPreventDefault: true }, undefined, () => this.handlerMouseup());
|
|
333
333
|
const mouseMove = this.initEvent({ nativeElement: document }, 'mousemove', { callStopPropagation: true, callPreventDefault: true }).pipe(takeUntil(mouseUp));
|
|
334
|
-
this.initEvent(
|
|
334
|
+
this.initEvent(this.imageEditorContainer(), 'wheel', { callStopPropagation: true }, undefined, (e) => this.handlerMousewheel(e)).subscribe();
|
|
335
335
|
this.initEvent({ nativeElement: window }, 'resize', {}, undefined, () => this.updateModalSize()).subscribe();
|
|
336
336
|
this.initEvent(this.imageContainer(), 'mousedown', { callStopPropagation: true, callPreventDefault: true }, mouseMove, (e) => this.handlerImageContainerMousedown(e)).subscribe((e) => this.handlerMousemove(e));
|
|
337
337
|
this.initEvent(this.cropTL(), 'mousedown', { callStopPropagation: true, callPreventDefault: true }, mouseMove, (e) => { this.handlerCropResize(e, 'TL'); }).subscribe((e) => this.handlerMousemove(e));
|
|
@@ -649,12 +649,24 @@ class LibsUiComponentsImageEditorComponent {
|
|
|
649
649
|
const [currWidth, currHeight, currTop, currLeft] = getStylesOfElement(this.imageOrigin().nativeElement, ['offsetWidth', 'offsetHeight', 'style.top', 'style.left']);
|
|
650
650
|
const width = Math.max(currWidth * scale, 50);
|
|
651
651
|
const height = this.imageOrigin().nativeElement.offsetHeight * width / this.imageOrigin().nativeElement.offsetWidth;
|
|
652
|
-
|
|
653
|
-
const
|
|
652
|
+
// Calculate the center point of the current view
|
|
653
|
+
const centerX = currLeft + currWidth / 2;
|
|
654
|
+
const centerY = currTop + currHeight / 2;
|
|
655
|
+
// Calculate new position to maintain center point
|
|
656
|
+
const top = centerY - height / 2;
|
|
657
|
+
const left = centerX - width / 2;
|
|
658
|
+
// Get current crop area dimensions and position
|
|
654
659
|
let [cropWidth, cropHeight] = getStylesOfElement(this.cropArea().nativeElement, ['offsetWidth', 'offsetHeight']);
|
|
655
660
|
const [cropTop, cropLeft] = getStylesOfElement(this.cropArea().nativeElement, ['style.top', 'style.left']);
|
|
656
|
-
|
|
657
|
-
|
|
661
|
+
// Scale crop area dimensions proportionally
|
|
662
|
+
cropWidth = cropWidth * scale;
|
|
663
|
+
cropHeight = cropHeight * scale;
|
|
664
|
+
// Calculate new crop area position relative to the image
|
|
665
|
+
const cropTopNew = top + (cropTop - currTop) * scale;
|
|
666
|
+
const cropLeftNew = left + (cropLeft - currLeft) * scale;
|
|
667
|
+
// Ensure crop area stays within bounds
|
|
668
|
+
const maxCropWidth = width;
|
|
669
|
+
const maxCropHeight = height;
|
|
658
670
|
const minWidth = 20;
|
|
659
671
|
const minHeight = 20;
|
|
660
672
|
cropWidth = Math.min(cropWidth, maxCropWidth);
|
|
@@ -668,9 +680,10 @@ class LibsUiComponentsImageEditorComponent {
|
|
|
668
680
|
cropHeight = Math.max(cropHeight, minHeight);
|
|
669
681
|
cropWidth = cropHeight * this.ratioValue();
|
|
670
682
|
}
|
|
683
|
+
// Update clipping rectangle
|
|
671
684
|
this.rectClip.update(rect => {
|
|
672
|
-
const rectTop =
|
|
673
|
-
const rectLeft =
|
|
685
|
+
const rectTop = cropTopNew - top;
|
|
686
|
+
const rectLeft = cropLeftNew - left;
|
|
674
687
|
return {
|
|
675
688
|
...rect,
|
|
676
689
|
top: rectTop,
|
|
@@ -680,7 +693,8 @@ class LibsUiComponentsImageEditorComponent {
|
|
|
680
693
|
};
|
|
681
694
|
});
|
|
682
695
|
const clip = `rect(${this.rectClip().top}px, ${this.rectClip().right}px, ${this.rectClip().bottom}px, ${this.rectClip().left}px)`;
|
|
683
|
-
|
|
696
|
+
// Update all elements with new positions and dimensions
|
|
697
|
+
this.setStylesElements(this.cropArea(), { top: cropTopNew, left: cropLeftNew, width: cropWidth, height: cropHeight });
|
|
684
698
|
this.setStylesElements(this.imageOrigin(), { top, left, width, height });
|
|
685
699
|
this.setCirclePosition({ top, left, width, height });
|
|
686
700
|
this.setStylesElements(this.imageClip(), { clip, top, left, width, height });
|
|
@@ -970,9 +984,159 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
970
984
|
args: [LINK_IMAGE_ERROR_TOKEN_INJECT]
|
|
971
985
|
}] }] });
|
|
972
986
|
|
|
987
|
+
class LibsUiComponentsImageEditorDemoComponent {
|
|
988
|
+
imageFileInput;
|
|
989
|
+
imageSource = '';
|
|
990
|
+
showEditor = false;
|
|
991
|
+
editedImageUrl = '';
|
|
992
|
+
selectedFile = null;
|
|
993
|
+
imageName = '';
|
|
994
|
+
// Documentation data as regular properties
|
|
995
|
+
inputsDoc = [
|
|
996
|
+
{ name: 'imgSrc', type: 'string', default: 'Bắt buộc', description: 'Đường dẫn hoặc base64 của hình ảnh cần chỉnh sửa' },
|
|
997
|
+
{ name: 'originUrl', type: 'string', default: '-', description: 'URL gốc của hình ảnh' },
|
|
998
|
+
{ name: 'nameFile', type: 'string', default: '-', description: 'Tên file khi lưu' },
|
|
999
|
+
{ name: 'modeShowButton', type: '\'save-file\' | \'save-api\'', default: '\'save-file\'', description: 'Chế độ nút lưu' },
|
|
1000
|
+
{ name: 'mimetype', type: 'string', default: '-', description: 'Định dạng của hình ảnh' },
|
|
1001
|
+
{ name: 'zIndex', type: 'number', default: '1200', description: 'z-index của component' },
|
|
1002
|
+
{ name: 'hasZoom', type: 'boolean', default: 'false', description: 'Cho phép phóng to/thu nhỏ hình ảnh' },
|
|
1003
|
+
{ name: 'aspectRatio', type: 'IAspectRatio', default: '-', description: 'Tỷ lệ khung hình mặc định' },
|
|
1004
|
+
{ name: 'requiredCropFollowRatio', type: 'boolean', default: 'false', description: 'Bắt buộc cắt theo tỷ lệ đã chọn' }
|
|
1005
|
+
];
|
|
1006
|
+
outputsDoc = [
|
|
1007
|
+
{ name: 'outClose', type: '{isClickButtonClose: boolean}', description: 'Sự kiện khi đóng trình chỉnh sửa' },
|
|
1008
|
+
{ name: 'outSaveFile', type: 'ISaveFile', description: 'Sự kiện khi lưu file' },
|
|
1009
|
+
{ name: 'outFunctionsControl', type: 'IImageEditorFunctionControlEvent', description: 'Sự kiện để kiểm soát các chức năng' }
|
|
1010
|
+
];
|
|
1011
|
+
interfacesDoc = [
|
|
1012
|
+
{
|
|
1013
|
+
name: 'ISaveFile',
|
|
1014
|
+
code: 'export interface ISaveFile {\n file: Blob;\n url: string;\n mode: \'save-file\' | \'save-api\' | \'save-api-as-new-file\';\n}',
|
|
1015
|
+
description: 'Interface định nghĩa dữ liệu khi lưu file.'
|
|
1016
|
+
},
|
|
1017
|
+
{
|
|
1018
|
+
name: 'IImageEditorFunctionControlEvent',
|
|
1019
|
+
code: 'export interface IImageEditorFunctionControlEvent {\n cropImage: () => Promise<string>;\n setLoadingState: (loading: boolean) => void;\n}',
|
|
1020
|
+
description: 'Interface định nghĩa các hàm điều khiển có thể được gọi từ bên ngoài component.'
|
|
1021
|
+
},
|
|
1022
|
+
{
|
|
1023
|
+
name: 'IAspectRatio',
|
|
1024
|
+
code: 'export interface IAspectRatio {\n key: string;\n value: number;\n}',
|
|
1025
|
+
description: 'Interface định nghĩa tỷ lệ khung hình.'
|
|
1026
|
+
}
|
|
1027
|
+
];
|
|
1028
|
+
features = [
|
|
1029
|
+
{
|
|
1030
|
+
id: 1,
|
|
1031
|
+
icon: '✂️',
|
|
1032
|
+
title: 'Cắt ảnh',
|
|
1033
|
+
description: 'Cắt hình ảnh theo khu vực tùy chỉnh hoặc dựa trên tỷ lệ định trước (1:1, 4:3, 16:9, v.v.).'
|
|
1034
|
+
},
|
|
1035
|
+
{
|
|
1036
|
+
id: 2,
|
|
1037
|
+
icon: '🔄',
|
|
1038
|
+
title: 'Xoay và lật',
|
|
1039
|
+
description: 'Xoay hình ảnh theo các góc khác nhau hoặc lật theo chiều ngang/dọc.'
|
|
1040
|
+
},
|
|
1041
|
+
{
|
|
1042
|
+
id: 3,
|
|
1043
|
+
icon: '📏',
|
|
1044
|
+
title: 'Thay đổi kích thước',
|
|
1045
|
+
description: 'Thay đổi kích thước hình ảnh theo tỷ lệ phần trăm hoặc kích thước cụ thể.'
|
|
1046
|
+
},
|
|
1047
|
+
{
|
|
1048
|
+
id: 4,
|
|
1049
|
+
icon: '💾',
|
|
1050
|
+
title: 'Nhiều chế độ lưu',
|
|
1051
|
+
description: 'Hỗ trợ nhiều chế độ lưu: tải xuống trực tiếp hoặc gửi đến API.'
|
|
1052
|
+
},
|
|
1053
|
+
{
|
|
1054
|
+
id: 5,
|
|
1055
|
+
icon: '🔍',
|
|
1056
|
+
title: 'Phóng to/thu nhỏ',
|
|
1057
|
+
description: 'Tính năng phóng to/thu nhỏ để xem chi tiết hình ảnh khi cần thiết.'
|
|
1058
|
+
}
|
|
1059
|
+
];
|
|
1060
|
+
codeExamples = [
|
|
1061
|
+
{
|
|
1062
|
+
id: 1,
|
|
1063
|
+
title: 'Sử dụng cơ bản',
|
|
1064
|
+
code: `import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\n\n@Component({\n selector: 'app-example',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n template: \`\n <libs_ui-components-image_editor\n [(imgSrc)]="imageSource"\n [modeShowButton]="'save-file'"\n [nameFile]="'image.jpg'"\n (outSaveFile)="onSaveFile($event)"\n (outClose)="onClose($event)">\n </libs_ui-components-image_editor>\n \`\n})\nexport class ExampleComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n\n onSaveFile(data: {file: Blob, url: string, mode: string}) {\n console.log('File đã được lưu:', data);\n }\n\n onClose(data: {isClickButtonClose: boolean}) {\n console.log('Đã đóng trình chỉnh sửa ảnh');\n }\n}`
|
|
1065
|
+
},
|
|
1066
|
+
{
|
|
1067
|
+
id: 2,
|
|
1068
|
+
title: 'Sử dụng với tỷ lệ cố định',
|
|
1069
|
+
code: `import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\nimport { IAspectRatio } from '@libs-ui/interfaces-types';\n\n@Component({\n selector: 'app-example',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n template: \`\n <libs_ui-components-image_editor\n [(imgSrc)]="imageSource"\n [aspectRatio]="aspectRatio"\n [requiredCropFollowRatio]="true"\n (outSaveFile)="onSaveFile($event)">\n </libs_ui-components-image_editor>\n \`\n})\nexport class ExampleComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n aspectRatio: IAspectRatio = {\n key: '1:1',\n value: 1\n };\n\n onSaveFile(data: any) {\n console.log('Đã lưu hình ảnh với tỷ lệ 1:1');\n }\n}`
|
|
1070
|
+
},
|
|
1071
|
+
{
|
|
1072
|
+
id: 3,
|
|
1073
|
+
title: 'Sử dụng với phần điều khiển bên ngoài',
|
|
1074
|
+
code: `import { Component, ViewChild } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent, IImageEditorFunctionControlEvent } from '@libs-ui/components-image-editor';\n\n@Component({\n selector: 'app-example',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n template: \`\n <button (click)="cropAndSave()">Cắt và lưu ngay</button>\n <libs_ui-components-image_editor\n [(imgSrc)]="imageSource"\n (outFunctionsControl)="onFunctionsControl($event)">\n </libs_ui-components-image_editor>\n \`\n})\nexport class ExampleComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n editorFunctions!: IImageEditorFunctionControlEvent;\n\n onFunctionsControl(event: IImageEditorFunctionControlEvent) {\n this.editorFunctions = event;\n }\n\n async cropAndSave() {\n if (this.editorFunctions) {\n this.editorFunctions.setLoadingState(true);\n try {\n const dataUrl = await this.editorFunctions.cropImage();\n console.log('Hình ảnh đã được cắt:', dataUrl);\n } finally {\n this.editorFunctions.setLoadingState(false);\n }\n }\n }\n}`
|
|
1075
|
+
}
|
|
1076
|
+
];
|
|
1077
|
+
copyToClipboard(text) {
|
|
1078
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
1079
|
+
alert('Đã sao chép vào clipboard');
|
|
1080
|
+
}).catch(err => {
|
|
1081
|
+
console.error('Không thể sao chép: ', err);
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
onFileSelected(event) {
|
|
1085
|
+
const input = event.target;
|
|
1086
|
+
if (input.files && input.files.length > 0) {
|
|
1087
|
+
this.selectedFile = input.files[0];
|
|
1088
|
+
this.imageName = this.selectedFile.name;
|
|
1089
|
+
console.log('File selected:', this.selectedFile.name);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
uploadAndEdit() {
|
|
1093
|
+
if (!this.selectedFile) {
|
|
1094
|
+
alert('Vui lòng chọn một file hình ảnh trước');
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
const reader = new FileReader();
|
|
1098
|
+
reader.onload = (e) => {
|
|
1099
|
+
if (e.target?.result) {
|
|
1100
|
+
this.imageSource = e.target.result;
|
|
1101
|
+
this.showEditor = true;
|
|
1102
|
+
}
|
|
1103
|
+
};
|
|
1104
|
+
reader.readAsDataURL(this.selectedFile);
|
|
1105
|
+
}
|
|
1106
|
+
onSaveImage(data) {
|
|
1107
|
+
console.log('Image saved:', data);
|
|
1108
|
+
this.editedImageUrl = data.url;
|
|
1109
|
+
this.showEditor = false;
|
|
1110
|
+
}
|
|
1111
|
+
onCloseEditor(data) {
|
|
1112
|
+
console.log('Editor closed:', data);
|
|
1113
|
+
this.showEditor = false;
|
|
1114
|
+
}
|
|
1115
|
+
downloadImage() {
|
|
1116
|
+
if (this.editedImageUrl) {
|
|
1117
|
+
const link = document.createElement('a');
|
|
1118
|
+
link.href = this.editedImageUrl;
|
|
1119
|
+
link.download = this.imageName || 'edited-image.jpg';
|
|
1120
|
+
link.click();
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LibsUiComponentsImageEditorDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1124
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: LibsUiComponentsImageEditorDemoComponent, isStandalone: true, selector: "lib-image-editor-demo", viewQueries: [{ propertyName: "imageFileInput", first: true, predicate: ["imageFileInput"], descendants: true }], ngImport: i0, template: "<div class=\"max-w-6xl mx-auto p-5 font-sans text-gray-800\">\n <header class=\"text-center py-10 bg-white rounded-lg mb-8 shadow-sm\">\n <h1 class=\"text-4xl font-bold text-gray-800 mb-2\">Demo Tr\u00ECnh Ch\u1EC9nh S\u1EEDa H\u00ECnh \u1EA2nh</h1>\n <p class=\"text-xl text-gray-500\">Th\u01B0 vi\u1EC7n component cho Angular \u0111\u1EC3 ch\u1EC9nh s\u1EEDa h\u00ECnh \u1EA3nh</p>\n </header>\n\n <main>\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">Gi\u1EDBi thi\u1EC7u</h2>\n <p>\n <code class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">@libs-ui/components-image-editor</code> l\u00E0 m\u1ED9t\n component Angular m\u1EA1nh m\u1EBD cho ph\u00E9p ng\u01B0\u1EDDi d\u00F9ng th\u1EF1c hi\u1EC7n c\u00E1c thao t\u00E1c ch\u1EC9nh s\u1EEDa h\u00ECnh \u1EA3nh nh\u01B0 c\u1EAFt, thay \u0111\u1ED5i k\u00EDch\n th\u01B0\u1EDBc, xoay, l\u1EADt v\u00E0 \u00E1p d\u1EE5ng t\u1EF7 l\u1EC7 c\u1ED1 \u0111\u1ECBnh.\n </p>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">C\u00E0i \u0111\u1EB7t</h2>\n\n <div class=\"mb-6\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-3\">Y\u00EAu c\u1EA7u</h3>\n <ul class=\"list-disc pl-5 space-y-2 text-gray-600\">\n <li><span class=\"font-semibold\">Angular</span>: 18.0.0 tr\u1EDF l\u00EAn</li>\n <li><span class=\"font-semibold\">Tailwind CSS</span>: 3.3.0 tr\u1EDF l\u00EAn</li>\n </ul>\n </div>\n\n <p class=\"mb-4\">\u0110\u1EC3 c\u00E0i \u0111\u1EB7t th\u01B0 vi\u1EC7n, s\u1EED d\u1EE5ng npm ho\u1EB7c yarn:</p>\n\n <div class=\"flex items-center bg-gray-100 p-4 rounded-lg mb-6\">\n <pre class=\"flex-1 text-sm overflow-x-auto\"><code>npm install @libs-ui/components-image-editor</code></pre>\n <button class=\"ml-4 px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors\"\n (click)=\"copyToClipboard('npm install @libs-ui/components-image-editor')\">\n Sao ch\u00E9p\n </button>\n </div>\n\n <p class=\"mb-4\">Ho\u1EB7c v\u1EDBi yarn:</p>\n\n <div class=\"flex items-center bg-gray-100 p-4 rounded-lg mb-6\">\n <pre class=\"flex-1 text-sm overflow-x-auto\"><code>yarn add @libs-ui/components-image-editor</code></pre>\n <button class=\"ml-4 px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors\"\n (click)=\"copyToClipboard('yarn add @libs-ui/components-image-editor')\">\n Sao ch\u00E9p\n </button>\n </div>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">Demo tr\u1EF1c ti\u1EBFp</h2>\n <div>\n <p class=\"mb-4\">T\u1EA3i l\u00EAn h\u00ECnh \u1EA3nh v\u00E0 ch\u1EC9nh s\u1EEDa ngay tr\u00EAn tr\u00ECnh duy\u1EC7t:</p>\n <div class=\"flex flex-wrap items-center gap-4 mb-8\">\n <input type=\"file\"\n #imageFileInput\n accept=\"image/*\"\n class=\"border border-gray-300 rounded px-3 py-2\"\n (change)=\"onFileSelected($event)\" />\n <libs_ui-components-buttons-button label=\"T\u1EA3i l\u00EAn v\u00E0 ch\u1EC9nh s\u1EEDa\"\n (click)=\"uploadAndEdit()\">\n </libs_ui-components-buttons-button>\n </div>\n\n @if (editedImageUrl) {\n <div class=\"mt-8 p-6 bg-gray-50 rounded-lg\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">K\u1EBFt qu\u1EA3</h3>\n <div class=\"max-w-xl mx-auto mb-4 border border-gray-200 rounded-lg overflow-hidden shadow-md\">\n <img [src]=\"editedImageUrl\"\n alt=\"H\u00ECnh \u1EA3nh \u0111\u00E3 ch\u1EC9nh s\u1EEDa\"\n class=\"w-full h-auto\" />\n </div>\n <div class=\"flex justify-center\">\n <libs_ui-components-buttons-button label=\"T\u1EA3i xu\u1ED1ng h\u00ECnh \u1EA3nh\"\n (click)=\"downloadImage()\">\n </libs_ui-components-buttons-button>\n </div>\n </div>\n }\n </div>\n </section>\n\n @if (showEditor) {\n <div class=\"fixed inset-0 z-50\">\n <libs_ui-components-image_editor [(imgSrc)]=\"imageSource\"\n [nameFile]=\"imageName || 'demo-image.jpg'\"\n [modeShowButton]=\"'save-file'\"\n [hasZoom]=\"true\"\n (outSaveFile)=\"onSaveImage($event)\"\n (outClose)=\"onCloseEditor($event)\" />\n </div>\n }\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">C\u00E1ch s\u1EED d\u1EE5ng</h2>\n\n <div class=\"mb-8\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">C\u00E1ch 1: S\u1EED d\u1EE5ng file HTML ri\u00EAng bi\u1EC7t</h3>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-4\">\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">HTML (example.component.html)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code><libs_ui-components-image_editor\n [(imgSrc)]=\"imageSource\"\n [nameFile]=\"'image.jpg'\"\n [modeShowButton]=\"'save-file'\"\n (outSaveFile)=\"onSaveFile($event)\"\n (outClose)=\"onClose($event)\">\n</libs_ui-components-image_editor></code></pre>\n </div>\n\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">TypeScript (example.component.ts)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code>import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\n\n@Component({\n selector: 'app-example',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n templateUrl: './example.component.html'\n})\nexport class ExampleComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n\n onSaveFile(data: {file: Blob, url: string, mode: string}) {\n console.log('File \u0111\u00E3 \u0111\u01B0\u1EE3c l\u01B0u:', data);\n }\n\n onClose(data: {isClickButtonClose: boolean}) {\n console.log('\u0110\u00E3 \u0111\u00F3ng tr\u00ECnh ch\u1EC9nh s\u1EEDa \u1EA3nh');\n }\n}</code></pre>\n </div>\n </div>\n </div>\n\n <div class=\"mb-8\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">C\u00E1ch 2: V\u1EDBi tr\u00ECnh ch\u1EC9nh s\u1EEDa c\u00F3 th\u1EC3 \u0111\u00F3ng/m\u1EDF</h3>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-4\">\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">HTML (toggle-editor.component.html)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code><button (click)=\"openEditor()\" class=\"px-4 py-2 bg-blue-500 text-white rounded\">\n M\u1EDF tr\u00ECnh ch\u1EC9nh s\u1EEDa \u1EA3nh\n</button>\n\n@if (showEditor) {\n <libs_ui-components-image_editor\n [(imgSrc)]=\"imageSource\"\n [nameFile]=\"'my-image.jpg'\"\n (outSaveFile)=\"onSaveFile($event)\"\n (outClose)=\"onCloseEditor($event)\">\n </libs_ui-components-image_editor>\n}\n\n@if (editedImageUrl) {\n <div class=\"mt-4\">\n <h3 class=\"text-lg font-semibold\">H\u00ECnh \u1EA3nh \u0111\u00E3 ch\u1EC9nh s\u1EEDa:</h3>\n <img [src]=\"editedImageUrl\" alt=\"H\u00ECnh \u1EA3nh \u0111\u00E3 ch\u1EC9nh s\u1EEDa\" class=\"mt-2 max-w-full h-auto\" />\n </div>\n}</code></pre>\n </div>\n\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">TypeScript (toggle-editor.component.ts)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code>import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\nimport { ISaveFile } from '@libs-ui/components-image-editor';\n\n@Component({\n selector: 'app-toggle-editor',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n templateUrl: './toggle-editor.component.html'\n})\nexport class ToggleEditorComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n showEditor = false;\n editedImageUrl = '';\n\n openEditor() {\n this.showEditor = true;\n }\n\n onSaveFile(data: ISaveFile) {\n this.editedImageUrl = data.url;\n this.showEditor = false;\n console.log('\u0110\u00E3 l\u01B0u file:', data.file);\n }\n\n onCloseEditor(data: {isClickButtonClose: boolean}) {\n this.showEditor = false;\n }\n}</code></pre>\n </div>\n </div>\n </div>\n\n <div class=\"mb-8\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">C\u00E1ch 3: V\u1EDBi t\u1EF7 l\u1EC7 khung h\u00ECnh c\u1ED1 \u0111\u1ECBnh</h3>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-4\">\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">HTML (fixed-ratio.component.html)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code><libs_ui-components-image_editor\n [(imgSrc)]=\"imageSource\"\n [aspectRatio]=\"aspectRatio\"\n [requiredCropFollowRatio]=\"true\"\n (outSaveFile)=\"onSaveFile($event)\">\n</libs_ui-components-image_editor></code></pre>\n </div>\n\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">TypeScript (fixed-ratio.component.ts)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code>import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\nimport { IAspectRatio } from '@libs-ui/interfaces-types';\n\n@Component({\n selector: 'app-fixed-ratio',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n templateUrl: './fixed-ratio.component.html'\n})\nexport class FixedRatioComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n aspectRatio: IAspectRatio = {\n key: '1:1',\n value: 1\n };\n\n onSaveFile(data: any) {\n console.log('\u0110\u00E3 l\u01B0u h\u00ECnh \u1EA3nh v\u1EDBi t\u1EF7 l\u1EC7 1:1');\n }\n}</code></pre>\n </div>\n </div>\n </div>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">T\u00E0i li\u1EC7u API</h2>\n\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">Inputs</h3>\n <div class=\"overflow-x-auto mb-8\">\n <table class=\"min-w-full bg-white border border-gray-200\">\n <thead>\n <tr>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">T\u00EAn</th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">Ki\u1EC3u d\u1EEF\n li\u1EC7u\n </th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">M\u1EB7c \u0111\u1ECBnh\n </th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">M\u00F4 t\u1EA3\n </th>\n </tr>\n </thead>\n <tbody>\n @for (input of inputsDoc; track input.name) {\n <tr>\n <td class=\"py-2 px-4 border-b border-gray-200\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ input.name }}</code></td>\n <td class=\"py-2 px-4 border-b border-gray-200\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ input.type }}</code></td>\n <td class=\"py-2 px-4 border-b border-gray-200\">{{ input.default }}</td>\n <td class=\"py-2 px-4 border-b border-gray-200\">{{ input.description }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">Outputs</h3>\n <div class=\"overflow-x-auto mb-8\">\n <table class=\"min-w-full bg-white border border-gray-200\">\n <thead>\n <tr>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">T\u00EAn</th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">Ki\u1EC3u d\u1EEF\n li\u1EC7u\n </th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">M\u00F4 t\u1EA3\n </th>\n </tr>\n </thead>\n <tbody>\n @for (output of outputsDoc; track output.name) {\n <tr>\n <td class=\"py-2 px-4 border-b border-gray-200\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ output.name }}</code></td>\n <td class=\"py-2 px-4 border-b border-gray-200\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ output.type }}</code></td>\n <td class=\"py-2 px-4 border-b border-gray-200\">{{ output.description }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">Interfaces</h3>\n <div class=\"space-y-6\">\n @for (interfaceItem of interfacesDoc; track interfaceItem.name) {\n <div class=\"bg-gray-50 p-6 rounded-lg\">\n <h4 class=\"text-lg font-semibold text-gray-700 mb-3\">{{ interfaceItem.name }}</h4>\n <pre\n class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm mb-3\"><code>{{ interfaceItem.code }}</code></pre>\n <p class=\"text-gray-600\">{{ interfaceItem.description }}</p>\n </div>\n }\n </div>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">T\u00EDnh n\u0103ng</h2>\n <ul class=\"space-y-6\">\n @for (feature of features; track feature.id) {\n <li class=\"flex items-start\">\n <span class=\"text-2xl text-blue-500 mr-4\">{{ feature.icon }}</span>\n <div>\n <h3 class=\"text-lg font-semibold text-gray-700 mb-1\">{{ feature.title }}</h3>\n <p class=\"text-gray-600\">{{ feature.description }}</p>\n </div>\n </li>\n }\n </ul>\n </section>\n </main>\n</div>\n", styles: ["pre code{@apply font-mono;}.hover\\:bg-blue-600{transition:background-color .2s ease-in-out}.overflow-x-auto{-webkit-overflow-scrolling:touch}pre::-webkit-scrollbar{@apply h-1.5 bg-gray-100;}pre::-webkit-scrollbar-thumb{@apply bg-gray-300 rounded;}button:focus,input:focus{@apply outline-none ring-2 ring-blue-400 ring-opacity-50;}input[type=file]{@apply text-sm text-gray-600;}\n"], dependencies: [{ kind: "component", type: LibsUiComponentsButtonsButtonComponent, selector: "libs_ui-components-buttons-button", inputs: ["flagMouse", "type", "buttonCustom", "sizeButton", "label", "disable", "isPending", "imageLeft", "classInclude", "classIconLeft", "classIconRight", "classLabel", "iconOnlyType", "popover", "ignoreStopPropagationEvent", "zIndex", "widthLabelPopover", "styleIconLeft", "styleButton", "ignoreFocusWhenInputTab", "ignoreSetClickWhenShowPopover", "ignorePointerEvent", "isActive", "isHandlerEnterDocumentClickButton"], outputs: ["outClick", "outPopoverEvent", "outFunctionsControl"] }, { kind: "component", type: LibsUiComponentsImageEditorComponent, selector: "libs_ui-components-image_editor", inputs: ["modeShowButton", "mimetype", "zIndex", "imgSrc", "originUrl", "nameFile", "hasZoom", "aspectRatio", "requiredCropFollowRatio"], outputs: ["imgSrcChange", "outClose", "outSaveFile", "outFunctionsControl"] }] });
|
|
1125
|
+
}
|
|
1126
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LibsUiComponentsImageEditorDemoComponent, decorators: [{
|
|
1127
|
+
type: Component,
|
|
1128
|
+
args: [{ selector: 'lib-image-editor-demo', standalone: true, imports: [
|
|
1129
|
+
LibsUiComponentsButtonsButtonComponent,
|
|
1130
|
+
LibsUiComponentsImageEditorComponent
|
|
1131
|
+
], template: "<div class=\"max-w-6xl mx-auto p-5 font-sans text-gray-800\">\n <header class=\"text-center py-10 bg-white rounded-lg mb-8 shadow-sm\">\n <h1 class=\"text-4xl font-bold text-gray-800 mb-2\">Demo Tr\u00ECnh Ch\u1EC9nh S\u1EEDa H\u00ECnh \u1EA2nh</h1>\n <p class=\"text-xl text-gray-500\">Th\u01B0 vi\u1EC7n component cho Angular \u0111\u1EC3 ch\u1EC9nh s\u1EEDa h\u00ECnh \u1EA3nh</p>\n </header>\n\n <main>\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">Gi\u1EDBi thi\u1EC7u</h2>\n <p>\n <code class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">@libs-ui/components-image-editor</code> l\u00E0 m\u1ED9t\n component Angular m\u1EA1nh m\u1EBD cho ph\u00E9p ng\u01B0\u1EDDi d\u00F9ng th\u1EF1c hi\u1EC7n c\u00E1c thao t\u00E1c ch\u1EC9nh s\u1EEDa h\u00ECnh \u1EA3nh nh\u01B0 c\u1EAFt, thay \u0111\u1ED5i k\u00EDch\n th\u01B0\u1EDBc, xoay, l\u1EADt v\u00E0 \u00E1p d\u1EE5ng t\u1EF7 l\u1EC7 c\u1ED1 \u0111\u1ECBnh.\n </p>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">C\u00E0i \u0111\u1EB7t</h2>\n\n <div class=\"mb-6\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-3\">Y\u00EAu c\u1EA7u</h3>\n <ul class=\"list-disc pl-5 space-y-2 text-gray-600\">\n <li><span class=\"font-semibold\">Angular</span>: 18.0.0 tr\u1EDF l\u00EAn</li>\n <li><span class=\"font-semibold\">Tailwind CSS</span>: 3.3.0 tr\u1EDF l\u00EAn</li>\n </ul>\n </div>\n\n <p class=\"mb-4\">\u0110\u1EC3 c\u00E0i \u0111\u1EB7t th\u01B0 vi\u1EC7n, s\u1EED d\u1EE5ng npm ho\u1EB7c yarn:</p>\n\n <div class=\"flex items-center bg-gray-100 p-4 rounded-lg mb-6\">\n <pre class=\"flex-1 text-sm overflow-x-auto\"><code>npm install @libs-ui/components-image-editor</code></pre>\n <button class=\"ml-4 px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors\"\n (click)=\"copyToClipboard('npm install @libs-ui/components-image-editor')\">\n Sao ch\u00E9p\n </button>\n </div>\n\n <p class=\"mb-4\">Ho\u1EB7c v\u1EDBi yarn:</p>\n\n <div class=\"flex items-center bg-gray-100 p-4 rounded-lg mb-6\">\n <pre class=\"flex-1 text-sm overflow-x-auto\"><code>yarn add @libs-ui/components-image-editor</code></pre>\n <button class=\"ml-4 px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors\"\n (click)=\"copyToClipboard('yarn add @libs-ui/components-image-editor')\">\n Sao ch\u00E9p\n </button>\n </div>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">Demo tr\u1EF1c ti\u1EBFp</h2>\n <div>\n <p class=\"mb-4\">T\u1EA3i l\u00EAn h\u00ECnh \u1EA3nh v\u00E0 ch\u1EC9nh s\u1EEDa ngay tr\u00EAn tr\u00ECnh duy\u1EC7t:</p>\n <div class=\"flex flex-wrap items-center gap-4 mb-8\">\n <input type=\"file\"\n #imageFileInput\n accept=\"image/*\"\n class=\"border border-gray-300 rounded px-3 py-2\"\n (change)=\"onFileSelected($event)\" />\n <libs_ui-components-buttons-button label=\"T\u1EA3i l\u00EAn v\u00E0 ch\u1EC9nh s\u1EEDa\"\n (click)=\"uploadAndEdit()\">\n </libs_ui-components-buttons-button>\n </div>\n\n @if (editedImageUrl) {\n <div class=\"mt-8 p-6 bg-gray-50 rounded-lg\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">K\u1EBFt qu\u1EA3</h3>\n <div class=\"max-w-xl mx-auto mb-4 border border-gray-200 rounded-lg overflow-hidden shadow-md\">\n <img [src]=\"editedImageUrl\"\n alt=\"H\u00ECnh \u1EA3nh \u0111\u00E3 ch\u1EC9nh s\u1EEDa\"\n class=\"w-full h-auto\" />\n </div>\n <div class=\"flex justify-center\">\n <libs_ui-components-buttons-button label=\"T\u1EA3i xu\u1ED1ng h\u00ECnh \u1EA3nh\"\n (click)=\"downloadImage()\">\n </libs_ui-components-buttons-button>\n </div>\n </div>\n }\n </div>\n </section>\n\n @if (showEditor) {\n <div class=\"fixed inset-0 z-50\">\n <libs_ui-components-image_editor [(imgSrc)]=\"imageSource\"\n [nameFile]=\"imageName || 'demo-image.jpg'\"\n [modeShowButton]=\"'save-file'\"\n [hasZoom]=\"true\"\n (outSaveFile)=\"onSaveImage($event)\"\n (outClose)=\"onCloseEditor($event)\" />\n </div>\n }\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">C\u00E1ch s\u1EED d\u1EE5ng</h2>\n\n <div class=\"mb-8\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">C\u00E1ch 1: S\u1EED d\u1EE5ng file HTML ri\u00EAng bi\u1EC7t</h3>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-4\">\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">HTML (example.component.html)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code><libs_ui-components-image_editor\n [(imgSrc)]=\"imageSource\"\n [nameFile]=\"'image.jpg'\"\n [modeShowButton]=\"'save-file'\"\n (outSaveFile)=\"onSaveFile($event)\"\n (outClose)=\"onClose($event)\">\n</libs_ui-components-image_editor></code></pre>\n </div>\n\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">TypeScript (example.component.ts)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code>import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\n\n@Component({\n selector: 'app-example',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n templateUrl: './example.component.html'\n})\nexport class ExampleComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n\n onSaveFile(data: {file: Blob, url: string, mode: string}) {\n console.log('File \u0111\u00E3 \u0111\u01B0\u1EE3c l\u01B0u:', data);\n }\n\n onClose(data: {isClickButtonClose: boolean}) {\n console.log('\u0110\u00E3 \u0111\u00F3ng tr\u00ECnh ch\u1EC9nh s\u1EEDa \u1EA3nh');\n }\n}</code></pre>\n </div>\n </div>\n </div>\n\n <div class=\"mb-8\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">C\u00E1ch 2: V\u1EDBi tr\u00ECnh ch\u1EC9nh s\u1EEDa c\u00F3 th\u1EC3 \u0111\u00F3ng/m\u1EDF</h3>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-4\">\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">HTML (toggle-editor.component.html)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code><button (click)=\"openEditor()\" class=\"px-4 py-2 bg-blue-500 text-white rounded\">\n M\u1EDF tr\u00ECnh ch\u1EC9nh s\u1EEDa \u1EA3nh\n</button>\n\n@if (showEditor) {\n <libs_ui-components-image_editor\n [(imgSrc)]=\"imageSource\"\n [nameFile]=\"'my-image.jpg'\"\n (outSaveFile)=\"onSaveFile($event)\"\n (outClose)=\"onCloseEditor($event)\">\n </libs_ui-components-image_editor>\n}\n\n@if (editedImageUrl) {\n <div class=\"mt-4\">\n <h3 class=\"text-lg font-semibold\">H\u00ECnh \u1EA3nh \u0111\u00E3 ch\u1EC9nh s\u1EEDa:</h3>\n <img [src]=\"editedImageUrl\" alt=\"H\u00ECnh \u1EA3nh \u0111\u00E3 ch\u1EC9nh s\u1EEDa\" class=\"mt-2 max-w-full h-auto\" />\n </div>\n}</code></pre>\n </div>\n\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">TypeScript (toggle-editor.component.ts)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code>import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\nimport { ISaveFile } from '@libs-ui/components-image-editor';\n\n@Component({\n selector: 'app-toggle-editor',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n templateUrl: './toggle-editor.component.html'\n})\nexport class ToggleEditorComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n showEditor = false;\n editedImageUrl = '';\n\n openEditor() {\n this.showEditor = true;\n }\n\n onSaveFile(data: ISaveFile) {\n this.editedImageUrl = data.url;\n this.showEditor = false;\n console.log('\u0110\u00E3 l\u01B0u file:', data.file);\n }\n\n onCloseEditor(data: {isClickButtonClose: boolean}) {\n this.showEditor = false;\n }\n}</code></pre>\n </div>\n </div>\n </div>\n\n <div class=\"mb-8\">\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">C\u00E1ch 3: V\u1EDBi t\u1EF7 l\u1EC7 khung h\u00ECnh c\u1ED1 \u0111\u1ECBnh</h3>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-4\">\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">HTML (fixed-ratio.component.html)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code><libs_ui-components-image_editor\n [(imgSrc)]=\"imageSource\"\n [aspectRatio]=\"aspectRatio\"\n [requiredCropFollowRatio]=\"true\"\n (outSaveFile)=\"onSaveFile($event)\">\n</libs_ui-components-image_editor></code></pre>\n </div>\n\n <div>\n <h4 class=\"font-semibold mb-2 text-gray-700\">TypeScript (fixed-ratio.component.ts)</h4>\n <pre class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm\"><code>import { Component } from '@angular/core';\nimport { LibsUiComponentsImageEditorComponent } from '@libs-ui/components-image-editor';\nimport { IAspectRatio } from '@libs-ui/interfaces-types';\n\n@Component({\n selector: 'app-fixed-ratio',\n standalone: true,\n imports: [LibsUiComponentsImageEditorComponent],\n templateUrl: './fixed-ratio.component.html'\n})\nexport class FixedRatioComponent {\n imageSource = 'https://example.com/path/to/image.jpg';\n aspectRatio: IAspectRatio = {\n key: '1:1',\n value: 1\n };\n\n onSaveFile(data: any) {\n console.log('\u0110\u00E3 l\u01B0u h\u00ECnh \u1EA3nh v\u1EDBi t\u1EF7 l\u1EC7 1:1');\n }\n}</code></pre>\n </div>\n </div>\n </div>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">T\u00E0i li\u1EC7u API</h2>\n\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">Inputs</h3>\n <div class=\"overflow-x-auto mb-8\">\n <table class=\"min-w-full bg-white border border-gray-200\">\n <thead>\n <tr>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">T\u00EAn</th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">Ki\u1EC3u d\u1EEF\n li\u1EC7u\n </th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">M\u1EB7c \u0111\u1ECBnh\n </th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">M\u00F4 t\u1EA3\n </th>\n </tr>\n </thead>\n <tbody>\n @for (input of inputsDoc; track input.name) {\n <tr>\n <td class=\"py-2 px-4 border-b border-gray-200\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ input.name }}</code></td>\n <td class=\"py-2 px-4 border-b border-gray-200\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ input.type }}</code></td>\n <td class=\"py-2 px-4 border-b border-gray-200\">{{ input.default }}</td>\n <td class=\"py-2 px-4 border-b border-gray-200\">{{ input.description }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">Outputs</h3>\n <div class=\"overflow-x-auto mb-8\">\n <table class=\"min-w-full bg-white border border-gray-200\">\n <thead>\n <tr>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">T\u00EAn</th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">Ki\u1EC3u d\u1EEF\n li\u1EC7u\n </th>\n <th class=\"py-3 px-4 border-b border-gray-200 bg-gray-100 text-left font-semibold text-gray-700\">M\u00F4 t\u1EA3\n </th>\n </tr>\n </thead>\n <tbody>\n @for (output of outputsDoc; track output.name) {\n <tr>\n <td class=\"py-2 px-4 border-b border-gray-200\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ output.name }}</code></td>\n <td class=\"py-2 px-4 border-b border-gray-200\"><code\n class=\"text-sm bg-gray-100 px-1.5 py-0.5 rounded\">{{ output.type }}</code></td>\n <td class=\"py-2 px-4 border-b border-gray-200\">{{ output.description }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n <h3 class=\"text-xl font-semibold text-gray-700 mb-4\">Interfaces</h3>\n <div class=\"space-y-6\">\n @for (interfaceItem of interfacesDoc; track interfaceItem.name) {\n <div class=\"bg-gray-50 p-6 rounded-lg\">\n <h4 class=\"text-lg font-semibold text-gray-700 mb-3\">{{ interfaceItem.name }}</h4>\n <pre\n class=\"bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm mb-3\"><code>{{ interfaceItem.code }}</code></pre>\n <p class=\"text-gray-600\">{{ interfaceItem.description }}</p>\n </div>\n }\n </div>\n </section>\n\n <section class=\"bg-white rounded-lg p-8 mb-8 shadow-sm\">\n <h2 class=\"text-2xl font-bold text-gray-800 mb-5 pb-3 border-b border-gray-200\">T\u00EDnh n\u0103ng</h2>\n <ul class=\"space-y-6\">\n @for (feature of features; track feature.id) {\n <li class=\"flex items-start\">\n <span class=\"text-2xl text-blue-500 mr-4\">{{ feature.icon }}</span>\n <div>\n <h3 class=\"text-lg font-semibold text-gray-700 mb-1\">{{ feature.title }}</h3>\n <p class=\"text-gray-600\">{{ feature.description }}</p>\n </div>\n </li>\n }\n </ul>\n </section>\n </main>\n</div>\n", styles: ["pre code{@apply font-mono;}.hover\\:bg-blue-600{transition:background-color .2s ease-in-out}.overflow-x-auto{-webkit-overflow-scrolling:touch}pre::-webkit-scrollbar{@apply h-1.5 bg-gray-100;}pre::-webkit-scrollbar-thumb{@apply bg-gray-300 rounded;}button:focus,input:focus{@apply outline-none ring-2 ring-blue-400 ring-opacity-50;}input[type=file]{@apply text-sm text-gray-600;}\n"] }]
|
|
1132
|
+
}], propDecorators: { imageFileInput: [{
|
|
1133
|
+
type: ViewChild,
|
|
1134
|
+
args: ['imageFileInput']
|
|
1135
|
+
}] } });
|
|
1136
|
+
|
|
973
1137
|
/**
|
|
974
1138
|
* Generated bundle index. Do not edit.
|
|
975
1139
|
*/
|
|
976
1140
|
|
|
977
|
-
export { LibsUiComponentsImageEditorComponent, LibsUiComponentsImageEditorResizeComponent };
|
|
1141
|
+
export { LibsUiComponentsImageEditorComponent, LibsUiComponentsImageEditorDemoComponent, LibsUiComponentsImageEditorResizeComponent };
|
|
978
1142
|
//# sourceMappingURL=libs-ui-components-image-editor.mjs.map
|