Skip to content

Commit

Permalink
#93 implement 3D Screenshot functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Salam-Dalloul committed Sep 26, 2024
1 parent 146220a commit 55866cd
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 5 deletions.
1 change: 1 addition & 0 deletions applications/visualizer/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"cytoscape-dagre": "^2.5.0",
"cytoscape-fcose": "^2.2.0",
"file-saver": "^2.0.5",
"html-to-image": "^1.11.11",
"html2canvas": "^1.4.1",
"ol": "^9.1.0",
"pako": "^2.1.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import * as htmlToImage from "html-to-image";

export function formatDate(d) {
return `${d.getFullYear()}${d.getMonth() + 1}${d.getDate()}-${pad(d.getHours(), 2)}${pad(d.getMinutes(), 2)}${pad(d.getSeconds(), 2)}`;
}

function pad(num, size) {
let s = num + "";
while (s.length < size) {
s = "0" + s;
}
return s;
}
function getOptions(htmlElement, targetResolution, quality, pixelRatio, filter) {
const resolution = getResolutionFixedRatio(htmlElement, targetResolution);
return {
quality: quality,
canvasWidth: resolution.width,
canvasHeight: resolution.height,
pixelRatio: pixelRatio,
filter: filter,
};
}

export function downloadScreenshot(
htmlElement,
quality = 0.95,
targetResolution = { width: 3840, height: 2160 },
pixelRatio = 1,
filter = () => true,
filename = `Canvas_${formatDate(new Date())}.png`,
) {
const options = getOptions(htmlElement, targetResolution, quality, pixelRatio, filter);

// Use `toBlob` to capture the canvas content as a blob
htmlToImage.toBlob(htmlElement, options).then((blob) => {
const link = document.createElement("a");
link.download = filename;
link.href = window.URL.createObjectURL(blob);
link.click();
});
}

function getResolutionFixedRatio(htmlElement, target) {
const current = {
height: htmlElement.clientHeight,
width: htmlElement.clientWidth,
};
// if height is closer
if ((Math.abs(target.width - current.width) * 9) / 16 > Math.abs(target.height - current.height)) {
return {
height: target.height,
width: Math.round((current.width * target.height) / current.height),
};
}
return {
height: Math.round((current.height * target.width) / current.width),
width: target.width,
};
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Box } from "@mui/system";
import { CameraControls, PerspectiveCamera } from "@react-three/drei";
import { Canvas } from "@react-three/fiber";
import { Suspense, useEffect, useMemo, useRef, useState } from "react";
import { Suspense, createRef, useEffect, useMemo, useRef, useState } from "react";
import { useSelectedWorkspace } from "../../../hooks/useSelectedWorkspace.ts";
import { ViewerType, getNeuronUrlForDataset } from "../../../models/models.ts";
import { type Dataset, OpenAPI } from "../../../rest";
Expand All @@ -19,6 +20,7 @@ import Gizmo from "./Gizmo.tsx";
import Loader from "./Loader.tsx";
import STLViewer from "./STLViewer.tsx";
import SceneControls from "./SceneControls.tsx";
import { downloadScreenshot } from "./Screenshoter.ts";

export interface Instance {
id: string;
Expand All @@ -37,6 +39,8 @@ function ThreeDViewer() {

const cameraControlRef = useRef<CameraControls | null>(null);

const ref = createRef<HTMLDivElement | null>();

// @ts-expect-error 'setShowNeurons' is declared but its value is never read.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [showNeurons, setShowNeurons] = useState<boolean>(true);
Expand Down Expand Up @@ -64,10 +68,16 @@ function ThreeDViewer() {
setInstances(newInstances);
}, [selectedDataset, workspace.availableNeurons, workspace.visibilities]);

const handleScreenshot = () => {
if (ref.current) {
// Use the Screenshoter utility functionthis.sceneRef.current && this.sceneRef.current.getElementsByTagName('canvas')[0]
downloadScreenshot(ref.current && ref.current.getElementsByTagName("canvas")[0], 0.95, { width: 3840, height: 2160 }, 1, () => true, "screenshot.png");
}
};
return (
<>
<Box ref={ref}>
<DatasetPicker datasets={dataSets} selectedDataset={selectedDataset} onDatasetChange={setSelectedDataset} />
<Canvas style={{ backgroundColor: SCENE_BACKGROUND }} frameloop={"demand"}>
<Canvas style={{ backgroundColor: SCENE_BACKGROUND }} gl={{ preserveDrawingBuffer: true }}>
<Suspense fallback={<Loader />}>
<PerspectiveCamera
makeDefault
Expand All @@ -87,8 +97,8 @@ function ThreeDViewer() {
<STLViewer instances={instances} isWireframe={isWireframe} />
</Suspense>
</Canvas>
<SceneControls cameraControlRef={cameraControlRef} isWireframe={isWireframe} setIsWireframe={setIsWireframe} />
</>
<SceneControls cameraControlRef={cameraControlRef} isWireframe={isWireframe} setIsWireframe={setIsWireframe} handleScreenshot={handleScreenshot} />
</Box>
);
}

Expand Down

0 comments on commit 55866cd

Please sign in to comment.