From 8a52b644d82bb12285d44cd45700d7960164f407 Mon Sep 17 00:00:00 2001 From: = Enea_Gore Date: Fri, 2 Aug 2024 20:33:51 +0200 Subject: [PATCH] crop and cut drag item from background --- .../drag-and-drop-question-edit.component.ts | 137 ++++++++++++++++-- 1 file changed, 127 insertions(+), 10 deletions(-) diff --git a/src/main/webapp/app/exercises/quiz/manage/drag-and-drop-question/drag-and-drop-question-edit.component.ts b/src/main/webapp/app/exercises/quiz/manage/drag-and-drop-question/drag-and-drop-question-edit.component.ts index fde9f929e280..16c00dda9ec0 100644 --- a/src/main/webapp/app/exercises/quiz/manage/drag-and-drop-question/drag-and-drop-question-edit.component.ts +++ b/src/main/webapp/app/exercises/quiz/manage/drag-and-drop-question/drag-and-drop-question-edit.component.ts @@ -43,6 +43,7 @@ import { faFont, faPencilAlt, faPlus, + faScissors, faTrash, faUndo, faUnlink, @@ -130,6 +131,7 @@ export class DragAndDropQuestionEditComponent implements OnInit, OnChanges, Afte faAngleRight = faAngleRight; faAngleDown = faAngleDown; faUpload = faUpload; + faScissors = faScissors; readonly MAX_POINTS = MAX_QUIZ_QUESTION_POINTS; @@ -276,16 +278,21 @@ export class DragAndDropQuestionEditComponent implements OnInit, OnChanges, Afte setBackgroundFile(event: any): void { const fileList: FileList = event.target.files as FileList; if (fileList.length) { - if (this.question.backgroundFilePath) { - this.removeFile.emit(this.question.backgroundFilePath); - } const file = fileList[0]; - const fileName = this.fileService.getUniqueFileName(this.fileService.getExtension(file.name), this.filePool); - this.question.backgroundFilePath = fileName; - this.filePreviewPaths.set(fileName, URL.createObjectURL(file)); - this.addNewFile.emit({ fileName, file }); - this.changeDetector.detectChanges(); + this.setBackgroundFileFromFile(file); + } + } + + setBackgroundFileFromFile(file: File) { + if (this.question.backgroundFilePath) { + this.removeFile.emit(this.question.backgroundFilePath); } + + const fileName = this.fileService.getUniqueFileName(this.fileService.getExtension(file.name), this.filePool); + this.question.backgroundFilePath = fileName; + this.filePreviewPaths.set(fileName, URL.createObjectURL(file)); + this.addNewFile.emit({ fileName, file }); + this.changeDetector.detectChanges(); } /** @@ -517,11 +524,15 @@ export class DragAndDropQuestionEditComponent implements OnInit, OnChanges, Afte /** * Add a Picture Drag Item with the selected file as its picture to the question */ - createImageDragItem(event: any): void { + createImageDragItem(event: any): DragItem | undefined { const dragItemFile = this.getFileFromEvent(event); if (!dragItemFile) { - return; + return undefined; } + return this.createImageDragItemFromFile(dragItemFile); + } + + createImageDragItemFromFile(dragItemFile: File) { const fileName = this.fileService.getUniqueFileName(this.fileService.getExtension(dragItemFile.name), this.filePool); this.addNewFile.emit({ fileName, file: dragItemFile }); this.filePreviewPaths.set(fileName, URL.createObjectURL(dragItemFile)); @@ -535,6 +546,7 @@ export class DragAndDropQuestionEditComponent implements OnInit, OnChanges, Afte this.question.dragItems.push(dragItem); this.questionUpdated.emit(); + return dragItem; } /** @@ -875,4 +887,109 @@ export class DragAndDropQuestionEditComponent implements OnInit, OnChanges, Afte this.cleanupQuestion(); this.markdownEditor.parse(); } + + /** + * Only using the first drop Location right now. + * @returns + */ + getImagesFromDropLocations() { + for (const someLocation of this.question.dropLocations!) { + const image = new Image(); + let dataUrl: string = ''; + let bgWidth; + let bgHeight; + image.onload = () => { + bgHeight = image.height; + bgWidth = image.width; + + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + + if (context) { + const scalarHeight = bgHeight / 200; + const scalarWidth = bgWidth / 200; + canvas.width = someLocation.width! * scalarWidth; + canvas.height = someLocation.height! * scalarHeight; + context.drawImage( + image, + someLocation.posX! * scalarWidth, + someLocation.posY! * scalarHeight, + someLocation.width! * scalarWidth, + someLocation.height! * scalarHeight, + 0, + 0, + someLocation.width! * scalarWidth, + someLocation.height! * scalarHeight, + ); + + dataUrl = canvas.toDataURL('image/png'); + const dragItemCreated = this.createImageDragItemFromFile(this.dataUrlToFile(dataUrl, 'placeholder' + someLocation.posX!))!; + const dndMapping = new DragAndDropMapping(dragItemCreated, someLocation); + this.question.correctMappings!.push(dndMapping); + } + }; + image.src = this.backgroundImage.src; + } + this.blankOutBackgroundImage(); + } + + blankOutBackgroundImage() { + const backGroundBlankingCanvas = document.createElement('canvas'); + const backGroundBlankingContext = backGroundBlankingCanvas.getContext('2d'); + const image = new Image(); + let bgWidth; + let bgHeight; + image.onload = () => { + bgHeight = image.height; + bgWidth = image.width; + + backGroundBlankingCanvas.width = bgWidth; + backGroundBlankingCanvas.height = bgHeight; + if (backGroundBlankingContext) { + const scalarHeight = bgHeight / 200; + const scalarWidth = bgWidth / 200; + + backGroundBlankingContext.drawImage(image, 0, 0); + backGroundBlankingContext.fillStyle = 'white'; + + for (const someLocation of this.question.dropLocations!) { + // Draw a white rectangle over the specified box location + backGroundBlankingContext.fillRect( + someLocation.posX! * scalarWidth, + someLocation.posY! * scalarHeight, + someLocation.width! * scalarWidth, + someLocation.height! * scalarHeight, + ); + } + const dataUrlCanvas = backGroundBlankingCanvas.toDataURL('image/png'); + this.setBackgroundFileFromFile(this.dataUrlToFile(dataUrlCanvas, 'backgorund')); + } + }; + image.src = this.backgroundImage.src; + } + + /** + * Turns a data url to a blob + * @param dataUrl + */ + dataUrlToBlob(dataUrl: string): Blob { + const byteString = atob(dataUrl.split(',')[1]); + const mimeString = dataUrl.split(',')[0].split(':')[1].split(';')[0]; + const ab = new ArrayBuffer(byteString.length); + const ia = new Uint8Array(ab); + for (let i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i); + } + return new Blob([ab], { type: mimeString }); + } + + /** + * Creates a File object from a blob given through a dataUrl + * @param dataUrl + * @param fileName + */ + dataUrlToFile(dataUrl: string, fileName: string): File { + const blob = this.dataUrlToBlob(dataUrl); + return new File([blob], fileName, { type: blob.type }); + } }