Skip to content

Commit

Permalink
image rendered on drawing widget then saved and persisted to attattac…
Browse files Browse the repository at this point in the history
…hments
  • Loading branch information
jona42-ui committed Aug 31, 2023
1 parent 2c49e87 commit 4b0ca2f
Show file tree
Hide file tree
Showing 5 changed files with 295 additions and 114 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@carbon/react": "^1.33.0",
"@openmrs/esm-patient-common-lib": "^5.0.0",
"@openmrs/openmrs-form-engine-lib": "latest",
"canvas-to-image": "^2.0.3",
"canvg": "^4.0.1",
"html2canvas": "^1.4.1",
"lodash-es": "^4.17.21",
Expand Down
180 changes: 106 additions & 74 deletions src/components/drawing-widget/drawing-widget.component.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import React, { useState, useEffect, useCallback } from "react";
import React, { useState, useCallback } from "react";
import ReactImageAnnotate, { Annotation } from "react-image-annotate";
import { Add } from "@carbon/react/icons";
import { useTranslation } from "react-i18next";
import { CardHeader } from "@openmrs/esm-patient-common-lib";
import { Button } from "@carbon/react";
import { RegionClass, RegionTag } from "../../constants";
import { showToast } from "@openmrs/esm-framework";
import { createAttachment } from "../../attachments/attachments.resource";
import html2canvas from "html2canvas";
import { readFileAsString } from "../../utils";

interface RegionData {
type: string;
Expand All @@ -28,106 +32,134 @@ interface DrawingWidgetProps {
drawingWidgetRef: React.RefObject<HTMLDivElement>;
}

const sendAnnotatedImageUrl = (
callbackName: string,
annotatedImageUrl: string
): void => {
if (
callbackName &&
window.opener &&
typeof window.opener[callbackName] === "function"
) {
window.opener[callbackName](annotatedImageUrl);
}
};

const DrawingWidget: React.FC<DrawingWidgetProps> = ({ drawingWidgetRef }) => {
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const DrawingWidget: React.FC<DrawingWidgetProps> = ({
selectedImage,
imagesData,
drawingWidgetRef,
}) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [annotations, setAnnotations] = useState<Annotation[]>([]);
const [activeImage, setActiveImage] = useState<ImageData | null>(null);
const { t } = useTranslation();

useEffect(() => {
const urlSearchParams = new URLSearchParams(window.location.search);
const imageUrl = urlSearchParams.get("imageUrl");

if (imageUrl) {
const activeImage: ImageData = {
src: imageUrl,
name: "Image from URL",
regions: [],
};
setActiveImage(activeImage);
}
}, []);

const handleExit = useCallback(() => {
const handleExit = useCallback(async () => {
if (drawingWidgetRef.current) {
const canvas = drawingWidgetRef.current.querySelector("canvas");
if (canvas) {
const annotatedImageUrl = canvas.toDataURL("image/png");
const callbackName = new URLSearchParams(window.location.search).get(
"callback"
);
sendAnnotatedImageUrl(callbackName, annotatedImageUrl);
window.close();
} else {
console.error("Canvas element not found.");
try {
const annotatedCanvas = await html2canvas(drawingWidgetRef.current);

// Create a new canvas
const newCanvas = document.createElement("canvas");
newCanvas.width = annotatedCanvas.width;
newCanvas.height = annotatedCanvas.height;
const ctx = newCanvas.getContext("2d");

// Draw the annotated canvas onto the new canvas
ctx.drawImage(annotatedCanvas, 0, 0);

// Convert the new canvas content to a blob
newCanvas.toBlob(async (blob) => {
if (!blob) {
console.error("Failed to convert new canvas to blob");
return;
}

try {
const urlSearchParams = new URLSearchParams(window.location.search);
const patientUuid = urlSearchParams.get("patientUuid");

// Create a new File instance from the blob
const file = new File([blob], "annotated_image.png", {
type: "image/png",
lastModified: new Date().getTime(),
});

const fileDescription = "Annotated Image";

const base64Content = await readFileAsString(file);

await createAttachment(patientUuid, {
file,
fileDescription,
base64Content,
fileName: "",
fileType: "",
});

showToast({
description: t(
"createdAttachment",
"A new attachment was created"
),
title: t("createdRecord", "Record created"),
kind: "success",
critical: true,
});

window.close();
} catch (error) {
console.error("Error creating attachment:", error);
showToast({
description: t(
"errorSavingAttachment",
"Error saving attachment"
),
title: t("error", "Error"),
kind: "error",
critical: true,
});
}
}, "image/png");
} catch (error) {
console.error("Error capturing annotated canvas:", error);
// Handle the error as needed
}
}
}, [drawingWidgetRef]);
}, [drawingWidgetRef, t]);

const handleAnnotationChange = useCallback((newAnnotations: Annotation[]) => {
setAnnotations(newAnnotations);
}, []);
// const images: ImageData[] = selectedImage
// ? [
// {
// src: URL.createObjectURL(selectedImage),
// name: selectedImage.name,
// regions: [],
// },
// ]
// : [];

const images: ImageData[] = selectedFile
? [
{
src: URL.createObjectURL(selectedFile),
name: selectedFile.name,
regions: [],
},
]
: [];

const handleAddDiagram = () => {
if (selectedFile) {
const newDiagram: ImageData = {
src: URL.createObjectURL(selectedFile),
name: selectedFile.name,
regions: [],
};
setActiveImage(newDiagram);
setSelectedFile(null);
}
};
// const handleAddDiagram = () => {
// if (selectedFile) {
// const newDiagram: ImageData = {
// src: URL.createObjectURL(selectedFile),
// name: selectedFile.name,
// regions: [],
// };
// // setActiveImage();
// setSelectedFile(newDiagram);
// }
// };

return (
<div className="drawing-widget">
{activeImage || selectedFile ? (
{selectedImage || imagesData.length > 0 ? (
<ReactImageAnnotate
labelImages
regionClsList={Object.values(RegionClass)} // Use enum values
regionTagList={Object.values(RegionTag)} // Use enum values
images={images}
images={imagesData}
onExit={handleExit}
onChange={handleAnnotationChange}
allowComments={true}
/>
) : (
<div>No image to display.</div>
)}
) : null}
<CardHeader title={t("Add Diagram", "add diagram")}>
<input
type="file"
onChange={(e) => setSelectedFile(e.target.files?.[0] || null)}
/>
<input type="file" onChange={(e) => e.target.files?.[0] || null} />
<Button
kind="ghost"
renderIcon={Add}
iconDescription="Add diagram"
onClick={handleAddDiagram}
onClick={""}
>
{t("add", "Add")}
</Button>
Expand Down
Loading

0 comments on commit 4b0ca2f

Please sign in to comment.