From 5066638782035c4301ff22a4d46034a7ec4d8c3b Mon Sep 17 00:00:00 2001 From: Nalvazhuthi Date: Mon, 14 Apr 2025 18:09:36 +0530 Subject: [PATCH 1/4] bug fix --- .../ui/inputs/MultiLevelDropDown.tsx | 6 +- app/src/modules/scene/scene.tsx | 2 +- app/src/modules/visualization/DisplayZone.tsx | 11 +- .../visualization/RealTimeVisulization.tsx | 134 +++++++---- .../charts/BarGraphComponent.tsx | 188 +++++++-------- .../charts/LineGraphComponent.tsx | 186 +++++++-------- .../charts/PieGraphComponent.tsx | 180 +++++++-------- .../functions}/zoneCameraTarget.tsx | 0 .../widgets/2d/DraggableWidget.tsx | 36 +-- .../widgets/3d/cards/ReturnOfInvestment.tsx | 2 +- .../floating/DroppedFloatingWidgets.tsx | 8 +- .../cards/FleetEfficiencyComponent.tsx | 214 +++++++++--------- .../widgets/panel/AddButtons.tsx | 31 ++- app/src/styles/components/input.scss | 39 ++++ .../visualization/floating/common.scss | 3 + 15 files changed, 568 insertions(+), 472 deletions(-) rename app/src/{components/ui => modules/visualization}/charts/BarGraphComponent.tsx (95%) rename app/src/{components/ui => modules/visualization}/charts/LineGraphComponent.tsx (95%) rename app/src/{components/ui => modules/visualization}/charts/PieGraphComponent.tsx (95%) rename app/src/{components/ui/componets => modules/visualization/functions}/zoneCameraTarget.tsx (100%) diff --git a/app/src/components/ui/inputs/MultiLevelDropDown.tsx b/app/src/components/ui/inputs/MultiLevelDropDown.tsx index 50f7fc8..378313c 100644 --- a/app/src/components/ui/inputs/MultiLevelDropDown.tsx +++ b/app/src/components/ui/inputs/MultiLevelDropDown.tsx @@ -258,7 +258,11 @@ const MultiLevelDropdown = ({ {open && (
-
+
+ {/* loading list */} + + {/*
*/} + {/* Unselect Option */} {/* Nested Dropdown Items */} diff --git a/app/src/modules/scene/scene.tsx b/app/src/modules/scene/scene.tsx index b26dca9..941616c 100644 --- a/app/src/modules/scene/scene.tsx +++ b/app/src/modules/scene/scene.tsx @@ -17,7 +17,7 @@ import MeasurementTool from "./tools/measurementTool"; import Simulation from "../simulation/simulation"; // import Simulation from "./simulationtemp/simulation"; -import ZoneCentreTarget from "../../components/ui/componets/zoneCameraTarget"; +import ZoneCentreTarget from "../visualization/functions/zoneCameraTarget"; import Dropped3dWidgets from "../../modules/visualization/widgets/3d/Dropped3dWidget"; import ZoneAssets from "../visualization/zoneAssets"; diff --git a/app/src/modules/visualization/DisplayZone.tsx b/app/src/modules/visualization/DisplayZone.tsx index f4033f9..dfe68f6 100644 --- a/app/src/modules/visualization/DisplayZone.tsx +++ b/app/src/modules/visualization/DisplayZone.tsx @@ -97,11 +97,16 @@ const DisplayZone: React.FC = ({ if (container) { const isOverflowing = container.scrollWidth > container.clientWidth; const canScrollLeft = container.scrollLeft > 0; - const canScrollRight = - container.scrollLeft + container.clientWidth < container.scrollWidth; + const canScrollRight = + container.scrollLeft + container.clientWidth + 1 < + container.scrollWidth; setShowLeftArrow(isOverflowing && canScrollLeft); setShowRightArrow(isOverflowing && canScrollRight); + + console.log('canScrollRight: ', canScrollRight); + console.log('isOverflowing: ', isOverflowing); + } }, []); @@ -166,7 +171,7 @@ const DisplayZone: React.FC = ({ if (selectedZone?.zoneId === zoneId) { return; } - setSelectedChartId(null); + // setSelectedChartId(null); const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; let response = await getSelect2dZoneData(zoneId, organization); diff --git a/app/src/modules/visualization/RealTimeVisulization.tsx b/app/src/modules/visualization/RealTimeVisulization.tsx index 6a5145f..b6569c3 100644 --- a/app/src/modules/visualization/RealTimeVisulization.tsx +++ b/app/src/modules/visualization/RealTimeVisulization.tsx @@ -34,6 +34,7 @@ import { import Dropped3dWidgets from "./widgets/3d/Dropped3dWidget"; import OuterClick from "../../utils/outerClick"; import { useWidgetStore } from "../../store/useWidgetStore"; +import { getActiveProperties } from "./functions/getActiveProperties"; type Side = "top" | "bottom" | "left" | "right"; @@ -166,60 +167,65 @@ const RealTimeVisulization: React.FC = () => { const canvasElement = document.getElementById("real-time-vis-canvas"); if (!canvasElement) throw new Error("Canvas element not found"); - // Get canvas dimensions and mouse position const rect = canvasElement.getBoundingClientRect(); - let relativeX = (event.clientX - rect.left) ; - let relativeY = event.clientY - rect.top; + const relativeX = event.clientX - rect.left; + const relativeY = event.clientY - rect.top; - // Widget dimensions (with defaults) - const widgetWidth = droppedData.width || 125; // 250/2 as default - const widgetHeight = droppedData.height || 100; // 83/2 as default + // Widget dimensions + const widgetWidth = droppedData.width || 125; + const widgetHeight = droppedData.height || 100; - // Clamp to ensure widget stays fully inside canvas - const clampedX = Math.max( - 0, // Prevent going beyond left edge - Math.min( - relativeX, - rect.width - widgetWidth // Prevent going beyond right edge - ) - ); - - console.log('clampedX: ', clampedX); - const clampedY = Math.max( - 0, // Prevent going beyond top edge - Math.min( - relativeY, - rect.height - widgetHeight // Prevent going beyond bottom edge - ) - ); + // Center the widget at cursor + const centerOffsetX = widgetWidth / 2; + const centerOffsetY = widgetHeight / 2; - // Debug logging (optional) - console.log("Drop coordinates:", { - rawX: relativeX, - rawY: relativeY, - clampedX, - clampedY, - canvasWidth: rect.width, - canvasHeight: rect.height, - widgetWidth, - widgetHeight - }); + const adjustedX = relativeX - centerOffsetX; + const adjustedY = relativeY - centerOffsetY; - const finalPosition = determinePosition(rect, clampedX, clampedY); + const finalPosition = determinePosition(rect, adjustedX, adjustedY); + const [activeProp1, activeProp2] = getActiveProperties(finalPosition); + + let finalY = 0; + let finalX = 0; + + if (activeProp1 === "top") { + finalY = adjustedY; + } else { + finalY = rect.height - (adjustedY + widgetHeight); + } + + if (activeProp2 === "left") { + finalX = adjustedX; + } else { + finalX = rect.width - (adjustedX + widgetWidth); + } + + // Clamp to boundaries + finalX = Math.max(0, Math.min(rect.width - widgetWidth, finalX)); + finalY = Math.max(0, Math.min(rect.height - widgetHeight, finalY)); + + const boundedPosition = { + ...finalPosition, + [activeProp1]: finalY, + [activeProp2]: finalX, + [activeProp1 === "top" ? "bottom" : "top"]: "auto", + [activeProp2 === "left" ? "right" : "left"]: "auto", + }; const newObject = { ...droppedData, id: generateUniqueId(), - position: finalPosition, + position: boundedPosition, }; - // Zone management - const existingZone = useDroppedObjectsStore.getState().zones[selectedZone.zoneName]; + const existingZone = + useDroppedObjectsStore.getState().zones[selectedZone.zoneName]; if (!existingZone) { - useDroppedObjectsStore.getState().setZone(selectedZone.zoneName, selectedZone.zoneId); + useDroppedObjectsStore + .getState() + .setZone(selectedZone.zoneName, selectedZone.zoneId); } - // Socket emission const addFloatingWidget = { organization, widget: newObject, @@ -230,25 +236,27 @@ const RealTimeVisulization: React.FC = () => { visualizationSocket.emit("v2:viz-float:add", addFloatingWidget); } - // Store update - useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, newObject); + useDroppedObjectsStore + .getState() + .addObject(selectedZone.zoneName, newObject); - // Post-drop verification const droppedObjectsStore = useDroppedObjectsStore.getState(); const currentZone = droppedObjectsStore.zones[selectedZone.zoneName]; if (currentZone && currentZone.zoneId === selectedZone.zoneId) { - console.log(`Objects for Zone ${selectedZone.zoneId}:`, currentZone.objects); + console.log( + `Objects for Zone ${selectedZone.zoneId}:`, + currentZone.objects + ); setFloatingWidget(currentZone.objects); } else { console.warn("Zone not found or zoneId mismatch"); } - } catch (error) { console.error("Error in handleDrop:", error); - // Consider adding user feedback here (e.g., toast notification) } }; + useEffect(() => { const handleClickOutside = (event: MouseEvent) => { @@ -270,8 +278,42 @@ const RealTimeVisulization: React.FC = () => { }; }, [setRightClickSelected]); + const [canvasDimensions, setCanvasDimensions] = useState({ + width: 0, + height: 0, + }); + useEffect(() => { + const canvas = document.getElementById("real-time-vis-canvas"); + if (!canvas) return; + + const updateCanvasDimensions = () => { + const rect = canvas.getBoundingClientRect(); + setCanvasDimensions({ + width: rect.width, + height: rect.height, + }); + }; + + updateCanvasDimensions(); + const resizeObserver = new ResizeObserver(updateCanvasDimensions); + resizeObserver.observe(canvas); + + return () => resizeObserver.unobserve(canvas); + }, []); + + return ( <> +
{ - // Memoize Font Weight Mapping - const chartFontWeightMap = useMemo( - () => ({ - Light: "lighter" as const, - Regular: "normal" as const, - Bold: "bold" as const, - }), - [] - ); - - // Parse and Memoize Font Size - const fontSizeValue = useMemo( - () => (fontSize ? parseInt(fontSize) : 12), - [fontSize] - ); - - // Determine and Memoize Font Weight - const fontWeightValue = useMemo( - () => chartFontWeightMap[fontWeight], - [fontWeight, chartFontWeightMap] - ); - - // Memoize Chart Font Style - const chartFontStyle = useMemo( - () => ({ - family: fontFamily || "Arial", - size: fontSizeValue, - weight: fontWeightValue, - }), - [fontFamily, fontSizeValue, fontWeightValue] - ); - - const options = useMemo( - () => ({ - responsive: true, - maintainAspectRatio: false, - plugins: { - title: { - display: true, - text: title, - font: chartFontStyle, - }, - legend: { - display: false, - }, - }, - scales: { - x: { - ticks: { - display: false, // This hides the x-axis labels - }, - }, - }, - }), - [title, chartFontStyle] - ); - - const chartData = { - labels: ["January", "February", "March", "April", "May", "June", "July"], - datasets: [ - { - label: "My First Dataset", - data: [65, 59, 80, 81, 56, 55, 40], - backgroundColor: "#6f42c1", - borderColor: "#ffffff", - borderWidth: 2, - fill: false, - }, - ], - }; - - return ; -}; - -export default LineGraphComponent; +import { useMemo } from "react"; + +import { Bar } from "react-chartjs-2"; + +interface ChartComponentProps { + type: any; + title: string; + fontFamily?: string; + fontSize?: string; + fontWeight?: "Light" | "Regular" | "Bold"; + data: any; +} + +const LineGraphComponent = ({ + title, + fontFamily, + fontSize, + fontWeight = "Regular", +}: ChartComponentProps) => { + // Memoize Font Weight Mapping + const chartFontWeightMap = useMemo( + () => ({ + Light: "lighter" as const, + Regular: "normal" as const, + Bold: "bold" as const, + }), + [] + ); + + // Parse and Memoize Font Size + const fontSizeValue = useMemo( + () => (fontSize ? parseInt(fontSize) : 12), + [fontSize] + ); + + // Determine and Memoize Font Weight + const fontWeightValue = useMemo( + () => chartFontWeightMap[fontWeight], + [fontWeight, chartFontWeightMap] + ); + + // Memoize Chart Font Style + const chartFontStyle = useMemo( + () => ({ + family: fontFamily || "Arial", + size: fontSizeValue, + weight: fontWeightValue, + }), + [fontFamily, fontSizeValue, fontWeightValue] + ); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + plugins: { + title: { + display: true, + text: title, + font: chartFontStyle, + }, + legend: { + display: false, + }, + }, + scales: { + x: { + ticks: { + display: false, // This hides the x-axis labels + }, + }, + }, + }), + [title, chartFontStyle] + ); + + const chartData = { + labels: ["January", "February", "March", "April", "May", "June", "July"], + datasets: [ + { + label: "My First Dataset", + data: [65, 59, 80, 81, 56, 55, 40], + backgroundColor: "#6f42c1", + borderColor: "#ffffff", + borderWidth: 2, + fill: false, + }, + ], + }; + + return ; +}; + +export default LineGraphComponent; diff --git a/app/src/components/ui/charts/LineGraphComponent.tsx b/app/src/modules/visualization/charts/LineGraphComponent.tsx similarity index 95% rename from app/src/components/ui/charts/LineGraphComponent.tsx rename to app/src/modules/visualization/charts/LineGraphComponent.tsx index 7f420d7..cf1a47f 100644 --- a/app/src/components/ui/charts/LineGraphComponent.tsx +++ b/app/src/modules/visualization/charts/LineGraphComponent.tsx @@ -1,93 +1,93 @@ -import { useMemo } from "react"; -import { Line } from "react-chartjs-2"; - -interface ChartComponentProps { - type: any; - title: string; - fontFamily?: string; - fontSize?: string; - fontWeight?: "Light" | "Regular" | "Bold"; - data: any; -} - -const LineGraphComponent = ({ - title, - fontFamily, - fontSize, - fontWeight = "Regular", -}: ChartComponentProps) => { - // Memoize Font Weight Mapping - const chartFontWeightMap = useMemo( - () => ({ - Light: "lighter" as const, - Regular: "normal" as const, - Bold: "bold" as const, - }), - [] - ); - - // Parse and Memoize Font Size - const fontSizeValue = useMemo( - () => (fontSize ? parseInt(fontSize) : 12), - [fontSize] - ); - - // Determine and Memoize Font Weight - const fontWeightValue = useMemo( - () => chartFontWeightMap[fontWeight], - [fontWeight, chartFontWeightMap] - ); - - // Memoize Chart Font Style - const chartFontStyle = useMemo( - () => ({ - family: fontFamily || "Arial", - size: fontSizeValue, - weight: fontWeightValue, - }), - [fontFamily, fontSizeValue, fontWeightValue] - ); - - const options = useMemo( - () => ({ - responsive: true, - maintainAspectRatio: false, - plugins: { - title: { - display: true, - text: title, - font: chartFontStyle, - }, - legend: { - display: false, - }, - }, - scales: { - x: { - ticks: { - display: false, // This hides the x-axis labels - }, - }, - }, - }), - [title, chartFontStyle] - ); - - const chartData = { - labels: ["January", "February", "March", "April", "May", "June", "July"], - datasets: [ - { - label: "My First Dataset", - data: [65, 59, 80, 81, 56, 55, 40], - backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple) - borderColor: "#ffffff", // Keeping border color white - borderWidth: 2, - fill: false, - }, - ], - }; - - return ; -}; - -export default LineGraphComponent; +import { useMemo } from "react"; +import { Line } from "react-chartjs-2"; + +interface ChartComponentProps { + type: any; + title: string; + fontFamily?: string; + fontSize?: string; + fontWeight?: "Light" | "Regular" | "Bold"; + data: any; +} + +const LineGraphComponent = ({ + title, + fontFamily, + fontSize, + fontWeight = "Regular", +}: ChartComponentProps) => { + // Memoize Font Weight Mapping + const chartFontWeightMap = useMemo( + () => ({ + Light: "lighter" as const, + Regular: "normal" as const, + Bold: "bold" as const, + }), + [] + ); + + // Parse and Memoize Font Size + const fontSizeValue = useMemo( + () => (fontSize ? parseInt(fontSize) : 12), + [fontSize] + ); + + // Determine and Memoize Font Weight + const fontWeightValue = useMemo( + () => chartFontWeightMap[fontWeight], + [fontWeight, chartFontWeightMap] + ); + + // Memoize Chart Font Style + const chartFontStyle = useMemo( + () => ({ + family: fontFamily || "Arial", + size: fontSizeValue, + weight: fontWeightValue, + }), + [fontFamily, fontSizeValue, fontWeightValue] + ); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + plugins: { + title: { + display: true, + text: title, + font: chartFontStyle, + }, + legend: { + display: false, + }, + }, + scales: { + x: { + ticks: { + display: false, // This hides the x-axis labels + }, + }, + }, + }), + [title, chartFontStyle] + ); + + const chartData = { + labels: ["January", "February", "March", "April", "May", "June", "July"], + datasets: [ + { + label: "My First Dataset", + data: [65, 59, 80, 81, 56, 55, 40], + backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple) + borderColor: "#ffffff", // Keeping border color white + borderWidth: 2, + fill: false, + }, + ], + }; + + return ; +}; + +export default LineGraphComponent; diff --git a/app/src/components/ui/charts/PieGraphComponent.tsx b/app/src/modules/visualization/charts/PieGraphComponent.tsx similarity index 95% rename from app/src/components/ui/charts/PieGraphComponent.tsx rename to app/src/modules/visualization/charts/PieGraphComponent.tsx index 7c8bb1d..912cbc3 100644 --- a/app/src/components/ui/charts/PieGraphComponent.tsx +++ b/app/src/modules/visualization/charts/PieGraphComponent.tsx @@ -1,90 +1,90 @@ -import { useMemo } from "react"; -import { Pie } from "react-chartjs-2"; - -interface ChartComponentProps { - type: any; - title: string; - fontFamily?: string; - fontSize?: string; - fontWeight?: "Light" | "Regular" | "Bold"; - data: any; -} - -const PieChartComponent = ({ - title, - fontFamily, - fontSize, - fontWeight = "Regular", -}: ChartComponentProps) => { - // Memoize Font Weight Mapping - const chartFontWeightMap = useMemo( - () => ({ - Light: "lighter" as const, - Regular: "normal" as const, - Bold: "bold" as const, - }), - [] - ); - - // Parse and Memoize Font Size - const fontSizeValue = useMemo( - () => (fontSize ? parseInt(fontSize) : 12), - [fontSize] - ); - - // Determine and Memoize Font Weight - const fontWeightValue = useMemo( - () => chartFontWeightMap[fontWeight], - [fontWeight, chartFontWeightMap] - ); - - // Memoize Chart Font Style - const chartFontStyle = useMemo( - () => ({ - family: fontFamily || "Arial", - size: fontSizeValue, - weight: fontWeightValue, - }), - [fontFamily, fontSizeValue, fontWeightValue] - ); - - // Access the CSS variable for the primary accent color - const accentColor = getComputedStyle(document.documentElement) - .getPropertyValue("--accent-color") - .trim(); - - const options = useMemo( - () => ({ - responsive: true, - maintainAspectRatio: false, - plugins: { - title: { - display: true, - text: title, - font: chartFontStyle, - }, - legend: { - display: false, - }, - }, - }), - [title, chartFontStyle] - ); - - const chartData = { - labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"], - datasets: [ - { - label: "Dataset", - data: [12, 19, 3, 5, 2, 3], - backgroundColor: ["#6f42c1"], - borderColor: "#ffffff", - borderWidth: 2, - }, - ], - }; - - return ; -}; - -export default PieChartComponent; +import { useMemo } from "react"; +import { Pie } from "react-chartjs-2"; + +interface ChartComponentProps { + type: any; + title: string; + fontFamily?: string; + fontSize?: string; + fontWeight?: "Light" | "Regular" | "Bold"; + data: any; +} + +const PieChartComponent = ({ + title, + fontFamily, + fontSize, + fontWeight = "Regular", +}: ChartComponentProps) => { + // Memoize Font Weight Mapping + const chartFontWeightMap = useMemo( + () => ({ + Light: "lighter" as const, + Regular: "normal" as const, + Bold: "bold" as const, + }), + [] + ); + + // Parse and Memoize Font Size + const fontSizeValue = useMemo( + () => (fontSize ? parseInt(fontSize) : 12), + [fontSize] + ); + + // Determine and Memoize Font Weight + const fontWeightValue = useMemo( + () => chartFontWeightMap[fontWeight], + [fontWeight, chartFontWeightMap] + ); + + // Memoize Chart Font Style + const chartFontStyle = useMemo( + () => ({ + family: fontFamily || "Arial", + size: fontSizeValue, + weight: fontWeightValue, + }), + [fontFamily, fontSizeValue, fontWeightValue] + ); + + // Access the CSS variable for the primary accent color + const accentColor = getComputedStyle(document.documentElement) + .getPropertyValue("--accent-color") + .trim(); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + plugins: { + title: { + display: true, + text: title, + font: chartFontStyle, + }, + legend: { + display: false, + }, + }, + }), + [title, chartFontStyle] + ); + + const chartData = { + labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"], + datasets: [ + { + label: "Dataset", + data: [12, 19, 3, 5, 2, 3], + backgroundColor: ["#6f42c1"], + borderColor: "#ffffff", + borderWidth: 2, + }, + ], + }; + + return ; +}; + +export default PieChartComponent; diff --git a/app/src/components/ui/componets/zoneCameraTarget.tsx b/app/src/modules/visualization/functions/zoneCameraTarget.tsx similarity index 100% rename from app/src/components/ui/componets/zoneCameraTarget.tsx rename to app/src/modules/visualization/functions/zoneCameraTarget.tsx diff --git a/app/src/modules/visualization/widgets/2d/DraggableWidget.tsx b/app/src/modules/visualization/widgets/2d/DraggableWidget.tsx index 3b9e8d7..7e6ad6d 100644 --- a/app/src/modules/visualization/widgets/2d/DraggableWidget.tsx +++ b/app/src/modules/visualization/widgets/2d/DraggableWidget.tsx @@ -89,9 +89,7 @@ export const DraggableWidget = ({ width: 0, height: 0, }); - useEffect(() => { - console.log("changes loggggg", measurements, duration, name); - }, [measurements, duration, name]) + useEffect(() => {}, [measurements, duration, name]); const handlePointerDown = () => { if (selectedChartId?.id !== widget.id) { setSelectedChartId(widget); @@ -148,7 +146,7 @@ export const DraggableWidget = ({ const getCurrentWidgetCount = (panel: Side) => selectedZone.widgets.filter((w) => w.panel === panel).length; // Calculate panel capacity - + const calculatePanelCapacity = (panel: Side) => { const CHART_WIDTH = panelSize; const CHART_HEIGHT = panelSize; @@ -167,25 +165,22 @@ export const DraggableWidget = ({ const currentWidgetCount = getCurrentWidgetCount(panel); const panelCapacity = calculatePanelCapacity(panel); - return currentWidgetCount > panelCapacity; + return currentWidgetCount > panelCapacity; }; const duplicateWidget = async () => { try { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; - console.log("widget data sent", widget); - const duplicatedWidget: Widget = { ...widget, Data: { duration: duration, - measurements: { ...measurements } + measurements: { ...measurements }, }, id: `${widget.id}-copy-${Date.now()}`, }; - console.log("duplicatedWidget: ", duplicatedWidget); let duplicateWidget = { organization: organization, @@ -193,8 +188,6 @@ export const DraggableWidget = ({ widget: duplicatedWidget, }; if (visualizationSocket) { - console.log("duplecate widget", duplicateWidget); - visualizationSocket.emit("v2:viz-widget:add", duplicateWidget); } setSelectedZone((prevZone: any) => ({ @@ -293,20 +286,12 @@ export const DraggableWidget = ({ return ( <> -
diff --git a/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx b/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx index a4c04ca..5a975f1 100644 --- a/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx @@ -238,7 +238,7 @@ const ReturnOfInvestment: React.FC = ({ rotation={rotation} scale={[0.5, 0.5, 0.5]} transform - zIndexRange={[1, 0]} + sprite={false} // style={{ // transform: transformStyle.transform, diff --git a/app/src/modules/visualization/widgets/floating/DroppedFloatingWidgets.tsx b/app/src/modules/visualization/widgets/floating/DroppedFloatingWidgets.tsx index de48ef6..62c1de7 100644 --- a/app/src/modules/visualization/widgets/floating/DroppedFloatingWidgets.tsx +++ b/app/src/modules/visualization/widgets/floating/DroppedFloatingWidgets.tsx @@ -121,10 +121,12 @@ const DroppedObjects: React.FC = () => { function handleDuplicate(zoneName: string, index: number) { setOpenKebabId(null); duplicateObject(zoneName, index); // Call the duplicateObject method from the store + setSelectedChartId(null); } async function handleDelete(zoneName: string, id: string) { try { + setSelectedChartId(null); const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; @@ -532,7 +534,7 @@ const DroppedObjects: React.FC = () => { typeof obj.position.left === "number" ? `calc(${obj.position.left}px + ${ isPlaying && selectedZone.activeSides.includes("left") - ? `${widthMultiplier - 100}px` + ? `${widthMultiplier - 150}px` : "0px" })` : "auto"; @@ -541,11 +543,10 @@ const DroppedObjects: React.FC = () => { typeof obj.position.right === "number" ? `calc(${obj.position.right}px + ${ isPlaying && selectedZone.activeSides.includes("right") - ? `${widthMultiplier - 100}px` + ? `${widthMultiplier - 150}px` : "0px" })` : "auto"; - const bottomPosition = typeof obj.position.bottom === "number" ? `calc(${obj.position.bottom}px + ${ @@ -663,4 +664,3 @@ const DroppedObjects: React.FC = () => { }; export default DroppedObjects; - diff --git a/app/src/modules/visualization/widgets/floating/cards/FleetEfficiencyComponent.tsx b/app/src/modules/visualization/widgets/floating/cards/FleetEfficiencyComponent.tsx index 6799dcb..f50bec9 100644 --- a/app/src/modules/visualization/widgets/floating/cards/FleetEfficiencyComponent.tsx +++ b/app/src/modules/visualization/widgets/floating/cards/FleetEfficiencyComponent.tsx @@ -1,113 +1,117 @@ -import React, { useState, useEffect } from 'react' -import { Line } from 'react-chartjs-2' -import useChartStore from '../../../../../store/useChartStore'; -import { useWidgetStore } from '../../../../../store/useWidgetStore'; -import axios from 'axios'; +import React, { useState, useEffect } from "react"; +import { Line } from "react-chartjs-2"; +import useChartStore from "../../../../../store/useChartStore"; +import { useWidgetStore } from "../../../../../store/useWidgetStore"; +import axios from "axios"; import io from "socket.io-client"; +import { usePlayButtonStore } from "../../../../../store/usePlayButtonStore"; -const FleetEfficiencyComponent = ({object}: any) => { - const [ progress, setProgress ] = useState(0) - const [measurements, setmeasurements] = useState({}); - const [duration, setDuration] = useState("1h") - const [name, setName] = useState(object.header ? object.header : '') - const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0] - const { header, flotingDuration, flotingMeasurements } = useChartStore(); - const { selectedChartId } = useWidgetStore(); +const FleetEfficiencyComponent = ({ object }: any) => { + const [progress, setProgress] = useState(0); + const [measurements, setmeasurements] = useState({}); + const [duration, setDuration] = useState("1h"); + const [name, setName] = useState(object.header ? object.header : ""); + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + const { header, flotingDuration, flotingMeasurements } = useChartStore(); + const { selectedChartId } = useWidgetStore(); + const { isPlaying } = usePlayButtonStore(); - const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; - // Calculate the rotation angle for the progress bar - const rotationAngle = 45 + progress * 1.8; + // Calculate the rotation angle for the progress bar + const rotationAngle = 45 + progress * 1.8; + useEffect(() => { + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) + return; - useEffect(() => { - if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; - - const socket = io(`http://${iotApiUrl}`); - - const inputData = { - measurements, - duration, - interval: 1000, - }; - - - const startStream = () => { - socket.emit("lastInput", inputData); - }; - - socket.on("connect", startStream); - - socket.on("lastOutput", (response) => { - const responseData = response.input1; - // console.log(responseData); - - if (typeof responseData === "number") { - console.log("It's a number!"); - setProgress(responseData); - } - }); - - return () => { - socket.off("lastOutput"); - socket.emit("stop_stream"); // Stop streaming when component unmounts - socket.disconnect(); - }; - }, [measurements, duration, iotApiUrl]); - - const fetchSavedInputes = async() => { - - if (object?.id !== "") { - try { - const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${object?.id}/${organization}`); - if (response.status === 200) { - setmeasurements(response.data.Data.measurements) - setDuration(response.data.Data.duration) - setName(response.data.header) - } else { - console.log("Unexpected response:", response); - } - } catch (error) { - console.error("There was an error!", error); - } - } + const socket = io(`http://${iotApiUrl}`); + + const inputData = { + measurements, + duration, + interval: 1000, + }; + + const startStream = () => { + socket.emit("lastInput", inputData); + }; + + socket.on("connect", startStream); + + socket.on("lastOutput", (response) => { + const responseData = response.input1; + // console.log(responseData); + + if (typeof responseData === "number") { + console.log("It's a number!"); + setProgress(responseData); } - - useEffect(() => { - fetchSavedInputes(); - }, []); - - useEffect(() => { - if (selectedChartId?.id === object?.id) { - fetchSavedInputes(); - } - } - ,[header, flotingDuration, flotingMeasurements]) - - return ( - <> -

{name}

-
-
-
-
-
-
-
-
- 0% -
-
{progress}%
-
Optimal
-
- 100% -
- - ) -} + }); -export default FleetEfficiencyComponent \ No newline at end of file + return () => { + socket.off("lastOutput"); + socket.emit("stop_stream"); // Stop streaming when component unmounts + socket.disconnect(); + }; + }, [measurements, duration, iotApiUrl]); + + const fetchSavedInputes = async () => { + if (object?.id !== "") { + try { + const response = await axios.get( + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${object?.id}/${organization}` + ); + if (response.status === 200) { + setmeasurements(response.data.Data.measurements); + setDuration(response.data.Data.duration); + setName(response.data.header); + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + }; + + useEffect(() => { + fetchSavedInputes(); + }, []); + + useEffect(() => { + if (selectedChartId?.id === object?.id) { + fetchSavedInputes(); + } + }, [header, flotingDuration, flotingMeasurements]); + + return ( + <> +

{name}

+
+
+
+
+
+
+
+
+ 0% +
+
{progress}%
+
Optimal
+
+ 100% +
+ + ); +}; + +export default FleetEfficiencyComponent; diff --git a/app/src/modules/visualization/widgets/panel/AddButtons.tsx b/app/src/modules/visualization/widgets/panel/AddButtons.tsx index 5469ffa..5d45d3f 100644 --- a/app/src/modules/visualization/widgets/panel/AddButtons.tsx +++ b/app/src/modules/visualization/widgets/panel/AddButtons.tsx @@ -128,6 +128,12 @@ const AddButtons: React.FC = ({ const cleanPanel = async (side: Side) => { //add api // console.log('side: ', side); + if ( + hiddenPanels[selectedZone.zoneId]?.includes(side) || + selectedZone.lockedPanels.includes(side) + ) + return; + const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value @@ -197,13 +203,12 @@ const AddButtons: React.FC = ({ } setSelectedZone(updatedZone); - - if (hiddenPanels[selectedZone.zoneId]?.includes(side)) { - - setHiddenPanels(prev => ({ + setHiddenPanels((prev) => ({ ...prev, - [selectedZone.zoneId]: prev[selectedZone.zoneId].filter(s => s !== side) + [selectedZone.zoneId]: prev[selectedZone.zoneId].filter( + (s) => s !== side + ), })); } @@ -284,10 +289,11 @@ const AddButtons: React.FC = ({
{/* Hide Panel */}
= ({ className="icon" title="Clean Panel" onClick={() => cleanPanel(side)} + style={{ + cursor: + hiddenPanels[selectedZone.zoneId]?.includes(side) || + selectedZone.lockedPanels.includes(side) + ? "not-allowed" + : "pointer", + }} >
diff --git a/app/src/styles/components/input.scss b/app/src/styles/components/input.scss index 990d243..0c89cc5 100644 --- a/app/src/styles/components/input.scss +++ b/app/src/styles/components/input.scss @@ -344,6 +344,45 @@ input { padding: 10px; } + + .loading { + position: absolute; + bottom: 0; + left: 0; + height: 2px; + /* slim progress bar */ + width: 100%; + overflow: hidden; + background: rgba(0, 0, 0, 0.05); + /* optional track background */ + } + + .loading::before { + content: ""; + position: absolute; + top: 0; + left: -50%; + height: 100%; + width: 50%; + background: linear-gradient(to right, + var(--accent-color), + transparent); + animation: loadingAnimation 1.2s linear infinite; + border-radius: 4px; + } + + @keyframes loadingAnimation { + 0% { + left: -50%; + } + + 100% { + left: 100%; + } + } + + + .dropdown-item { display: block; padding: 5px 10px; diff --git a/app/src/styles/components/visualization/floating/common.scss b/app/src/styles/components/visualization/floating/common.scss index d4afa7a..d138959 100644 --- a/app/src/styles/components/visualization/floating/common.scss +++ b/app/src/styles/components/visualization/floating/common.scss @@ -480,3 +480,6 @@ } // progress should be progress {progress} + + + From 7b2d77e273d064b74e5dd065a905aa20d6171c9f Mon Sep 17 00:00:00 2001 From: Nalvazhuthi Date: Mon, 14 Apr 2025 18:14:40 +0530 Subject: [PATCH 2/4] updated donut chart --- .../ui/inputs/MultiLevelDropDown.tsx | 2 +- .../visualization/RealTimeVisulization.tsx | 43 +++++++++---------- .../2d/charts/DoughnutGraphComponent.tsx | 22 +++++----- 3 files changed, 32 insertions(+), 35 deletions(-) diff --git a/app/src/components/ui/inputs/MultiLevelDropDown.tsx b/app/src/components/ui/inputs/MultiLevelDropDown.tsx index 378313c..f2be121 100644 --- a/app/src/components/ui/inputs/MultiLevelDropDown.tsx +++ b/app/src/components/ui/inputs/MultiLevelDropDown.tsx @@ -259,8 +259,8 @@ const MultiLevelDropdown = ({ {open && (
- {/* loading list */} + {/* loading list */} {/*
*/} {/* Unselect Option */} diff --git a/app/src/modules/visualization/RealTimeVisulization.tsx b/app/src/modules/visualization/RealTimeVisulization.tsx index b6569c3..e039592 100644 --- a/app/src/modules/visualization/RealTimeVisulization.tsx +++ b/app/src/modules/visualization/RealTimeVisulization.tsx @@ -93,6 +93,7 @@ const RealTimeVisulization: React.FC = () => { "sidebar-right-wrapper", "card", "dropdown-menu", + "dropdown-options", ], setMenuVisible: () => setSelectedChartId(null), }); @@ -158,52 +159,52 @@ const RealTimeVisulization: React.FC = () => { try { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; - + const data = event.dataTransfer.getData("text/plain"); if (widgetSubOption === "3D") return; if (!data || selectedZone.zoneName === "") return; - + const droppedData = JSON.parse(data); const canvasElement = document.getElementById("real-time-vis-canvas"); if (!canvasElement) throw new Error("Canvas element not found"); - + const rect = canvasElement.getBoundingClientRect(); const relativeX = event.clientX - rect.left; const relativeY = event.clientY - rect.top; - + // Widget dimensions const widgetWidth = droppedData.width || 125; const widgetHeight = droppedData.height || 100; - + // Center the widget at cursor const centerOffsetX = widgetWidth / 2; const centerOffsetY = widgetHeight / 2; - + const adjustedX = relativeX - centerOffsetX; const adjustedY = relativeY - centerOffsetY; - + const finalPosition = determinePosition(rect, adjustedX, adjustedY); const [activeProp1, activeProp2] = getActiveProperties(finalPosition); - + let finalY = 0; let finalX = 0; - + if (activeProp1 === "top") { finalY = adjustedY; } else { finalY = rect.height - (adjustedY + widgetHeight); } - + if (activeProp2 === "left") { finalX = adjustedX; } else { finalX = rect.width - (adjustedX + widgetWidth); } - + // Clamp to boundaries finalX = Math.max(0, Math.min(rect.width - widgetWidth, finalX)); finalY = Math.max(0, Math.min(rect.height - widgetHeight, finalY)); - + const boundedPosition = { ...finalPosition, [activeProp1]: finalY, @@ -211,13 +212,13 @@ const RealTimeVisulization: React.FC = () => { [activeProp1 === "top" ? "bottom" : "top"]: "auto", [activeProp2 === "left" ? "right" : "left"]: "auto", }; - + const newObject = { ...droppedData, id: generateUniqueId(), position: boundedPosition, }; - + const existingZone = useDroppedObjectsStore.getState().zones[selectedZone.zoneName]; if (!existingZone) { @@ -225,24 +226,24 @@ const RealTimeVisulization: React.FC = () => { .getState() .setZone(selectedZone.zoneName, selectedZone.zoneId); } - + const addFloatingWidget = { organization, widget: newObject, zoneId: selectedZone.zoneId, }; - + if (visualizationSocket) { visualizationSocket.emit("v2:viz-float:add", addFloatingWidget); } - + useDroppedObjectsStore .getState() .addObject(selectedZone.zoneName, newObject); - + const droppedObjectsStore = useDroppedObjectsStore.getState(); const currentZone = droppedObjectsStore.zones[selectedZone.zoneName]; - + if (currentZone && currentZone.zoneId === selectedZone.zoneId) { console.log( `Objects for Zone ${selectedZone.zoneId}:`, @@ -256,7 +257,6 @@ const RealTimeVisulization: React.FC = () => { console.error("Error in handleDrop:", error); } }; - useEffect(() => { const handleClickOutside = (event: MouseEvent) => { @@ -301,10 +301,9 @@ const RealTimeVisulization: React.FC = () => { return () => resizeObserver.unobserve(canvas); }, []); - return ( <> -