updated folder structure
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import html2canvas from "html2canvas";
|
||||
|
||||
export const captureVisualization = async (): Promise<string | null> => {
|
||||
const container = document.getElementById("real-time-vis-canvas");
|
||||
if (!container) {
|
||||
console.error("Container element not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// Hide any elements you don't want in the screenshot
|
||||
const originalVisibility = container.style.visibility;
|
||||
container.style.visibility = 'visible';
|
||||
|
||||
const canvas = await html2canvas(container, {
|
||||
scale: 2, // Higher scale for better quality
|
||||
logging: false, // Disable console logging
|
||||
useCORS: true, // Handle cross-origin images
|
||||
allowTaint: true, // Allow tainted canvas
|
||||
backgroundColor: '#ffffff', // Set white background
|
||||
removeContainer: true // Clean up temporary containers
|
||||
});
|
||||
|
||||
// Restore original visibility
|
||||
container.style.visibility = originalVisibility;
|
||||
|
||||
// Convert to PNG with highest quality
|
||||
return canvas.toDataURL('image/png', 1.0);
|
||||
} catch (error) {
|
||||
console.error("Error capturing visualization:", error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
77
app/src/modules/visualization/functions/determinePosition.ts
Normal file
77
app/src/modules/visualization/functions/determinePosition.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
export function determinePosition(
|
||||
canvasRect: DOMRect,
|
||||
relativeX: number,
|
||||
relativeY: number
|
||||
): {
|
||||
top: number | "auto";
|
||||
left: number | "auto";
|
||||
right: number | "auto";
|
||||
bottom: number | "auto";
|
||||
} {
|
||||
const centerX = canvasRect.width / 2;
|
||||
const centerY = canvasRect.height / 2;
|
||||
|
||||
// Define a threshold for considering a point as "centered"
|
||||
const centerThreshold = 10; // Adjust this value as needed
|
||||
|
||||
// Check if the point is within the center threshold
|
||||
const isCenterX = Math.abs(relativeX - centerX) <= centerThreshold;
|
||||
const isCenterY = Math.abs(relativeY - centerY) <= centerThreshold;
|
||||
|
||||
// If the point is centered, return a special "centered" position
|
||||
if (isCenterX && isCenterY) {
|
||||
return {
|
||||
top: "auto",
|
||||
left: "auto",
|
||||
right: "auto",
|
||||
bottom: "auto",
|
||||
};
|
||||
}
|
||||
|
||||
let position: {
|
||||
top: number | "auto";
|
||||
left: number | "auto";
|
||||
right: number | "auto";
|
||||
bottom: number | "auto";
|
||||
};
|
||||
|
||||
if (relativeY < centerY) {
|
||||
if (relativeX < centerX) {
|
||||
// Top-left quadrant
|
||||
position = {
|
||||
top: relativeY - 41.5,
|
||||
left: relativeX - 125,
|
||||
right: "auto",
|
||||
bottom: "auto",
|
||||
};
|
||||
} else {
|
||||
// Top-right quadrant
|
||||
position = {
|
||||
top: relativeY - 41.5,
|
||||
right: canvasRect.width - relativeX - 125,
|
||||
left: "auto",
|
||||
bottom: "auto",
|
||||
};
|
||||
}
|
||||
} else {
|
||||
if (relativeX < centerX) {
|
||||
// Bottom-left quadrant
|
||||
position = {
|
||||
bottom: canvasRect.height - relativeY - 41.5,
|
||||
left: relativeX - 125,
|
||||
right: "auto",
|
||||
top: "auto",
|
||||
};
|
||||
} else {
|
||||
// Bottom-right quadrant
|
||||
position = {
|
||||
bottom: canvasRect.height - relativeY - 41.5,
|
||||
right: canvasRect.width - relativeX - 125,
|
||||
left: "auto",
|
||||
top: "auto",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export function getActiveProperties(position: any): [string, string] {
|
||||
if (position.top !== "auto" && position.left !== "auto") {
|
||||
return ["top", "left"]; // Top-left
|
||||
} else if (position.top !== "auto" && position.right !== "auto") {
|
||||
return ["top", "right"]; // Top-right
|
||||
} else if (position.bottom !== "auto" && position.left !== "auto") {
|
||||
return ["bottom", "left"]; // Bottom-left
|
||||
} else {
|
||||
return ["bottom", "right"]; // Bottom-right
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import { Template } from "../../../store/useTemplateStore";
|
||||
import { captureVisualization } from "./captureVisualization";
|
||||
|
||||
type HandleSaveTemplateProps = {
|
||||
addTemplate: (template: Template) => void;
|
||||
floatingWidget: []; // Updated type from `[]` to `any[]` for clarity
|
||||
widgets3D: []; // Updated type from `[]` to `any[]` for clarity
|
||||
selectedZone: {
|
||||
panelOrder: string[];
|
||||
widgets: any[];
|
||||
};
|
||||
templates?: Template[];
|
||||
visualizationSocket: any;
|
||||
};
|
||||
|
||||
// Generate a unique ID
|
||||
const generateUniqueId = (): string => {
|
||||
return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
|
||||
};
|
||||
|
||||
export const handleSaveTemplate = async ({
|
||||
addTemplate,
|
||||
floatingWidget,
|
||||
widgets3D,
|
||||
selectedZone,
|
||||
templates = [],
|
||||
visualizationSocket,
|
||||
}: HandleSaveTemplateProps): Promise<void> => {
|
||||
try {
|
||||
// Check if the selected zone has any widgets
|
||||
if (!selectedZone.panelOrder || selectedZone.panelOrder.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the template already exists
|
||||
const isDuplicate = templates.some(
|
||||
(template) =>
|
||||
JSON.stringify(template.panelOrder) ===
|
||||
JSON.stringify(selectedZone.panelOrder) &&
|
||||
JSON.stringify(template.widgets) ===
|
||||
JSON.stringify(selectedZone.widgets)
|
||||
);
|
||||
|
||||
if (isDuplicate) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Capture visualization snapshot
|
||||
const snapshot = await captureVisualization();
|
||||
|
||||
|
||||
if (!snapshot) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a new template
|
||||
const newTemplate: Template = {
|
||||
id: generateUniqueId(),
|
||||
name: `Template ${new Date().toISOString()}`, // Better name formatting
|
||||
panelOrder: selectedZone.panelOrder,
|
||||
widgets: selectedZone.widgets,
|
||||
snapshot,
|
||||
floatingWidget,
|
||||
widgets3D,
|
||||
};
|
||||
|
||||
// Extract organization from email
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email.includes("@")
|
||||
? email.split("@")[1]?.split(".")[0]
|
||||
: "";
|
||||
|
||||
if (!organization) {
|
||||
return;
|
||||
}
|
||||
let saveTemplate = {
|
||||
organization: organization,
|
||||
template: newTemplate,
|
||||
};
|
||||
if (visualizationSocket) {
|
||||
visualizationSocket.emit("v2:viz-template:add", saveTemplate);
|
||||
}
|
||||
|
||||
// Save the template
|
||||
try {
|
||||
addTemplate(newTemplate);
|
||||
// const response = await saveTemplateApi(organization, newTemplate);
|
||||
//
|
||||
|
||||
// Add template only if API call succeeds
|
||||
} catch (apiError) {
|
||||
//
|
||||
}
|
||||
} catch (error) {
|
||||
//
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import { useEffect } from "react";
|
||||
|
||||
export const useClickOutside = (
|
||||
ref: React.RefObject<HTMLElement>,
|
||||
callback: () => void
|
||||
) => {
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (ref.current && !event.composedPath().includes(ref.current)) {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, [ref, callback]);
|
||||
};
|
||||
Reference in New Issue
Block a user