Merge remote-tracking branch 'origin/rtViz' into simulation
This commit is contained in:
commit
a07bf917c5
|
@ -166,6 +166,7 @@ const ProductionCapacity: React.FC<ProductionCapacityProps> = ({
|
||||||
const response = await axios.get(
|
const response = await axios.get(
|
||||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`
|
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
setmeasurements(response.data.Data.measurements);
|
setmeasurements(response.data.Data.measurements);
|
||||||
setDuration(response.data.Data.duration);
|
setDuration(response.data.Data.duration);
|
||||||
|
|
|
@ -45,7 +45,7 @@ const Header: React.FC = () => {
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="user-profile"
|
className="user-profile"
|
||||||
style={{ background: getAvatarColor(index) }}
|
style={{ background: getAvatarColor(index, user.userName) }}
|
||||||
>
|
>
|
||||||
{user.userName[0]}
|
{user.userName[0]}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
|
||||||
import RenameInput from "../../../ui/inputs/RenameInput";
|
import RenameInput from "../../../ui/inputs/RenameInput";
|
||||||
import Vector3Input from "../customInput/Vector3Input";
|
import Vector3Input from "../customInput/Vector3Input";
|
||||||
import { useSelectedZoneStore } from "../../../../store/useZoneStore";
|
import { useSelectedZoneStore } from "../../../../store/useZoneStore";
|
||||||
import { useEditPosition, usezonePosition, usezoneTarget } from "../../../../store/store";
|
import { useEditPosition, usezonePosition, useZones, usezoneTarget } from "../../../../store/store";
|
||||||
import { zoneCameraUpdate } from "../../../../services/realTimeVisulization/zoneData/zoneCameraUpdation";
|
import { zoneCameraUpdate } from "../../../../services/realTimeVisulization/zoneData/zoneCameraUpdation";
|
||||||
|
|
||||||
const ZoneProperties: React.FC = () => {
|
const ZoneProperties: React.FC = () => {
|
||||||
|
@ -10,6 +10,7 @@ const ZoneProperties: React.FC = () => {
|
||||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||||
const { zonePosition, setZonePosition } = usezonePosition();
|
const { zonePosition, setZonePosition } = usezonePosition();
|
||||||
const { zoneTarget, setZoneTarget } = usezoneTarget();
|
const { zoneTarget, setZoneTarget } = usezoneTarget();
|
||||||
|
const { zones, setZones } = useZones();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setZonePosition(selectedZone.zoneViewPortPosition)
|
setZonePosition(selectedZone.zoneViewPortPosition)
|
||||||
|
@ -31,11 +32,11 @@ const ZoneProperties: React.FC = () => {
|
||||||
if (response.message === "updated successfully") {
|
if (response.message === "updated successfully") {
|
||||||
setEdit(false);
|
setEdit(false);
|
||||||
} else {
|
} else {
|
||||||
console.log("Not updated Camera Position and Target");
|
console.log(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error in handleSetView:", error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,17 +44,32 @@ const ZoneProperties: React.FC = () => {
|
||||||
setEdit(!Edit); // This will toggle the `Edit` state correctly
|
setEdit(!Edit); // This will toggle the `Edit` state correctly
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleZoneNameChange(newName: string) {
|
async function handleZoneNameChange(newName: string) {
|
||||||
setSelectedZone((prev) => ({ ...prev, zoneName: newName }));
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
|
const zonesdata = {
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
|
zoneName: newName
|
||||||
|
};
|
||||||
|
// Call your API to update the zone
|
||||||
|
let response = await zoneCameraUpdate(zonesdata, organization);
|
||||||
|
console.log('response: ', response);
|
||||||
|
if (response.message === "updated successfully") {
|
||||||
|
setZones((prevZones: any[]) =>
|
||||||
|
prevZones.map((zone) =>
|
||||||
|
zone.zoneId === selectedZone.zoneId
|
||||||
|
? { ...zone, zoneName: newName }
|
||||||
|
: zone
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}else{
|
||||||
|
console.log(response?.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleVectorChange(key: "zoneViewPortTarget" | "zoneViewPortPosition", newValue: [number, number, number]) {
|
function handleVectorChange(key: "zoneViewPortTarget" | "zoneViewPortPosition", newValue: [number, number, number]) {
|
||||||
setSelectedZone((prev) => ({ ...prev, [key]: newValue }));
|
setSelectedZone((prev) => ({ ...prev, [key]: newValue }));
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
|
|
||||||
}, [selectedZone]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="zone-properties-container">
|
<div className="zone-properties-container">
|
||||||
|
|
|
@ -7,13 +7,11 @@ import {
|
||||||
VisualizationIcon,
|
VisualizationIcon,
|
||||||
} from "../icons/ExportModuleIcons";
|
} from "../icons/ExportModuleIcons";
|
||||||
import useToggleStore from "../../store/useUIToggleStore";
|
import useToggleStore from "../../store/useUIToggleStore";
|
||||||
import { useSelectedZoneStore } from "../../store/useZoneStore";
|
|
||||||
|
|
||||||
const ModuleToggle: React.FC = () => {
|
const ModuleToggle: React.FC = () => {
|
||||||
const { activeModule, setActiveModule } = useModuleStore();
|
const { activeModule, setActiveModule } = useModuleStore();
|
||||||
const { setToggleUI } = useToggleStore();
|
const { setToggleUI } = useToggleStore();
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="module-toggle-container">
|
<div className="module-toggle-container">
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -31,6 +31,7 @@ import {
|
||||||
useToggleView,
|
useToggleView,
|
||||||
useToolMode,
|
useToolMode,
|
||||||
useTransformMode,
|
useTransformMode,
|
||||||
|
useActiveSubTool,
|
||||||
} from "../../store/store";
|
} from "../../store/store";
|
||||||
import useToggleStore from "../../store/useUIToggleStore";
|
import useToggleStore from "../../store/useUIToggleStore";
|
||||||
import {
|
import {
|
||||||
|
@ -41,7 +42,7 @@ import {
|
||||||
|
|
||||||
const Tools: React.FC = () => {
|
const Tools: React.FC = () => {
|
||||||
const { templates } = useTemplateStore();
|
const { templates } = useTemplateStore();
|
||||||
const [activeSubTool, setActiveSubTool] = useState("cursor");
|
const { activeSubTool, setActiveSubTool } = useActiveSubTool();
|
||||||
const { toggleThreeD, setToggleThreeD } = useThreeDStore();
|
const { toggleThreeD, setToggleThreeD } = useThreeDStore();
|
||||||
const { setToggleUI } = useToggleStore();
|
const { setToggleUI } = useToggleStore();
|
||||||
|
|
||||||
|
@ -56,8 +57,7 @@ const Tools: React.FC = () => {
|
||||||
|
|
||||||
const { widgets3D } = use3DWidget();
|
const { widgets3D } = use3DWidget();
|
||||||
|
|
||||||
const zones = useDroppedObjectsStore((state) => state.zones);
|
const zones = useDroppedObjectsStore((state) => state.zones);
|
||||||
|
|
||||||
|
|
||||||
// wall options
|
// wall options
|
||||||
const { toggleView, setToggleView } = useToggleView();
|
const { toggleView, setToggleView } = useToggleView();
|
||||||
|
|
|
@ -8,6 +8,8 @@ import { panelData } from "../../../services/realTimeVisulization/zoneData/panel
|
||||||
import { AddIcon } from "../../icons/ExportCommonIcons";
|
import { AddIcon } from "../../icons/ExportCommonIcons";
|
||||||
import { deletePanelApi } from "../../../services/realTimeVisulization/zoneData/deletePanel";
|
import { deletePanelApi } from "../../../services/realTimeVisulization/zoneData/deletePanel";
|
||||||
import { useSocketStore } from "../../../store/store";
|
import { useSocketStore } from "../../../store/store";
|
||||||
|
import { clearPanel } from "../../../services/realTimeVisulization/zoneData/clearPanel";
|
||||||
|
import { lockPanel } from "../../../services/realTimeVisulization/zoneData/lockPanel";
|
||||||
|
|
||||||
// Define the type for `Side`
|
// Define the type for `Side`
|
||||||
type Side = "top" | "bottom" | "left" | "right";
|
type Side = "top" | "bottom" | "left" | "right";
|
||||||
|
@ -64,8 +66,10 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
||||||
// Local state to track hidden panels
|
// Local state to track hidden panels
|
||||||
|
|
||||||
// Function to toggle lock/unlock a panel
|
// Function to toggle lock/unlock a panel
|
||||||
const toggleLockPanel = (side: Side) => {
|
const toggleLockPanel = async (side: Side) => {
|
||||||
console.log('side: ', side);
|
console.log('side: ', side);
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value
|
||||||
//add api
|
//add api
|
||||||
const newLockedPanels = selectedZone.lockedPanels.includes(side)
|
const newLockedPanels = selectedZone.lockedPanels.includes(side)
|
||||||
? selectedZone.lockedPanels.filter((panel) => panel !== side)
|
? selectedZone.lockedPanels.filter((panel) => panel !== side)
|
||||||
|
@ -76,12 +80,28 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
||||||
lockedPanels: newLockedPanels,
|
lockedPanels: newLockedPanels,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update the selectedZone state
|
let lockedPanel = {
|
||||||
|
organization: organization,
|
||||||
|
lockedPanel: newLockedPanels,
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
|
};
|
||||||
|
if (visualizationSocket) {
|
||||||
|
visualizationSocket.emit("v2:viz-panel:locked", lockedPanel);
|
||||||
|
}
|
||||||
|
|
||||||
setSelectedZone(updatedZone);
|
setSelectedZone(updatedZone);
|
||||||
|
// let response = await lockPanel(selectedZone.zoneId, organization, newLockedPanels)
|
||||||
|
// console.log('response: ', response);
|
||||||
|
// if (response.message === 'locked panel updated successfully') {
|
||||||
|
// // Update the selectedZone state
|
||||||
|
// setSelectedZone(updatedZone);
|
||||||
|
// }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to toggle visibility of a panel
|
// Function to toggle visibility of a panel
|
||||||
const toggleVisibility = (side: Side) => {
|
const toggleVisibility = (side: Side) => {
|
||||||
|
|
||||||
const isHidden = hiddenPanels.includes(side);
|
const isHidden = hiddenPanels.includes(side);
|
||||||
if (isHidden) {
|
if (isHidden) {
|
||||||
// If the panel is already hidden, remove it from the hiddenPanels array
|
// If the panel is already hidden, remove it from the hiddenPanels array
|
||||||
|
@ -93,19 +113,45 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to clean all widgets from a panel
|
// Function to clean all widgets from a panel
|
||||||
const cleanPanel = (side: Side) => {
|
const cleanPanel = async (side: Side) => {
|
||||||
//add api
|
//add api
|
||||||
console.log('side: ', side);
|
console.log('side: ', side);
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value
|
||||||
|
|
||||||
|
let clearPanel = {
|
||||||
|
organization: organization,
|
||||||
|
panelName: side,
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
|
};
|
||||||
|
if (visualizationSocket) {
|
||||||
|
visualizationSocket.emit("v2:viz-panel:clear", clearPanel);
|
||||||
|
}
|
||||||
const cleanedWidgets = selectedZone.widgets.filter(
|
const cleanedWidgets = selectedZone.widgets.filter(
|
||||||
(widget) => widget.panel !== side
|
(widget) => widget.panel !== side
|
||||||
);
|
);
|
||||||
|
|
||||||
const updatedZone = {
|
const updatedZone = {
|
||||||
...selectedZone,
|
...selectedZone,
|
||||||
widgets: cleanedWidgets,
|
widgets: cleanedWidgets,
|
||||||
};
|
};
|
||||||
// Update the selectedZone state
|
// Update the selectedZone state
|
||||||
|
console.log('updatedZone: ', updatedZone);
|
||||||
setSelectedZone(updatedZone);
|
setSelectedZone(updatedZone);
|
||||||
|
|
||||||
|
// let response = await clearPanel(selectedZone.zoneId, organization, side)
|
||||||
|
// console.log('response: ', response);
|
||||||
|
// if (response.message === 'PanelWidgets cleared successfully') {
|
||||||
|
|
||||||
|
// const cleanedWidgets = selectedZone.widgets.filter(
|
||||||
|
// (widget) => widget.panel !== side
|
||||||
|
// );
|
||||||
|
// const updatedZone = {
|
||||||
|
// ...selectedZone,
|
||||||
|
// widgets: cleanedWidgets,
|
||||||
|
// };
|
||||||
|
// // Update the selectedZone state
|
||||||
|
// setSelectedZone(updatedZone);
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to handle "+" button click
|
// Function to handle "+" button click
|
||||||
|
@ -185,7 +231,7 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
||||||
// } else {
|
// } else {
|
||||||
//
|
//
|
||||||
// }
|
// }
|
||||||
} catch (error) {}
|
} catch (error) { }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -196,9 +242,8 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
||||||
<div key={side} className={`side-button-container ${side}`}>
|
<div key={side} className={`side-button-container ${side}`}>
|
||||||
{/* "+" Button */}
|
{/* "+" Button */}
|
||||||
<button
|
<button
|
||||||
className={`side-button ${side}${
|
className={`side-button ${side}${selectedZone.activeSides.includes(side) ? " active" : ""
|
||||||
selectedZone.activeSides.includes(side) ? " active" : ""
|
}`}
|
||||||
}`}
|
|
||||||
onClick={() => handlePlusButtonClick(side)}
|
onClick={() => handlePlusButtonClick(side)}
|
||||||
title={
|
title={
|
||||||
selectedZone.activeSides.includes(side)
|
selectedZone.activeSides.includes(side)
|
||||||
|
@ -216,9 +261,8 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
||||||
<div className="extra-Bs">
|
<div className="extra-Bs">
|
||||||
{/* Hide Panel */}
|
{/* Hide Panel */}
|
||||||
<div
|
<div
|
||||||
className={`icon ${
|
className={`icon ${hiddenPanels.includes(side) ? "active" : ""
|
||||||
hiddenPanels.includes(side) ? "active" : ""
|
}`}
|
||||||
}`}
|
|
||||||
title={
|
title={
|
||||||
hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel"
|
hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel"
|
||||||
}
|
}
|
||||||
|
@ -244,9 +288,8 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
||||||
|
|
||||||
{/* Lock/Unlock Panel */}
|
{/* Lock/Unlock Panel */}
|
||||||
<div
|
<div
|
||||||
className={`icon ${
|
className={`icon ${selectedZone.lockedPanels.includes(side) ? "active" : ""
|
||||||
selectedZone.lockedPanels.includes(side) ? "active" : ""
|
}`}
|
||||||
}`}
|
|
||||||
title={
|
title={
|
||||||
selectedZone.lockedPanels.includes(side)
|
selectedZone.lockedPanels.includes(side)
|
||||||
? "Unlock Panel"
|
? "Unlock Panel"
|
||||||
|
|
|
@ -157,6 +157,7 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
let response = await getSelect2dZoneData(zoneId, organization);
|
let response = await getSelect2dZoneData(zoneId, organization);
|
||||||
|
|
||||||
|
|
||||||
let res = await getFloatingZoneData(zoneId, organization);
|
let res = await getFloatingZoneData(zoneId, organization);
|
||||||
|
|
||||||
setFloatingWidget(res);
|
setFloatingWidget(res);
|
||||||
|
|
|
@ -143,7 +143,7 @@ const DroppedObjects: React.FC = () => {
|
||||||
// if (res.message === "FloatingWidget deleted successfully") {
|
// if (res.message === "FloatingWidget deleted successfully") {
|
||||||
// deleteObject(zoneName, id, index); // Call the deleteObject method from the store
|
// deleteObject(zoneName, id, index); // Call the deleteObject method from the store
|
||||||
// }
|
// }
|
||||||
} catch (error) {}
|
} catch (error) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePointerDown = (event: React.PointerEvent, index: number) => {
|
const handlePointerDown = (event: React.PointerEvent, index: number) => {
|
||||||
|
@ -510,7 +510,6 @@ const DroppedObjects: React.FC = () => {
|
||||||
|
|
||||||
const widthMultiplier = parseFloat(containerWidth) * 0.13;
|
const widthMultiplier = parseFloat(containerWidth) * 0.13;
|
||||||
|
|
||||||
console.log("zone.objects: ", zone.objects);
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onPointerMove={handlePointerMove}
|
onPointerMove={handlePointerMove}
|
||||||
|
@ -520,46 +519,41 @@ const DroppedObjects: React.FC = () => {
|
||||||
{zone.objects.map((obj, index) => {
|
{zone.objects.map((obj, index) => {
|
||||||
const topPosition =
|
const topPosition =
|
||||||
typeof obj.position.top === "number"
|
typeof obj.position.top === "number"
|
||||||
? `calc(${obj.position.top}px + ${
|
? `calc(${obj.position.top}px + ${isPlaying && selectedZone.activeSides.includes("top")
|
||||||
isPlaying && selectedZone.activeSides.includes("top")
|
? `${heightMultiplier - 55}px`
|
||||||
? `${heightMultiplier - 55}px`
|
: "0px"
|
||||||
: "0px"
|
})`
|
||||||
})`
|
|
||||||
: "auto";
|
: "auto";
|
||||||
|
|
||||||
const leftPosition =
|
const leftPosition =
|
||||||
typeof obj.position.left === "number"
|
typeof obj.position.left === "number"
|
||||||
? `calc(${obj.position.left}px + ${
|
? `calc(${obj.position.left}px + ${isPlaying && selectedZone.activeSides.includes("left")
|
||||||
isPlaying && selectedZone.activeSides.includes("left")
|
? `${widthMultiplier - 100}px`
|
||||||
? `${widthMultiplier - 100}px`
|
: "0px"
|
||||||
: "0px"
|
})`
|
||||||
})`
|
|
||||||
: "auto";
|
: "auto";
|
||||||
|
|
||||||
const rightPosition =
|
const rightPosition =
|
||||||
typeof obj.position.right === "number"
|
typeof obj.position.right === "number"
|
||||||
? `calc(${obj.position.right}px + ${
|
? `calc(${obj.position.right}px + ${isPlaying && selectedZone.activeSides.includes("right")
|
||||||
isPlaying && selectedZone.activeSides.includes("right")
|
? `${widthMultiplier - 100}px`
|
||||||
? `${widthMultiplier - 100}px`
|
: "0px"
|
||||||
: "0px"
|
})`
|
||||||
})`
|
|
||||||
: "auto";
|
: "auto";
|
||||||
|
|
||||||
const bottomPosition =
|
const bottomPosition =
|
||||||
typeof obj.position.bottom === "number"
|
typeof obj.position.bottom === "number"
|
||||||
? `calc(${obj.position.bottom}px + ${
|
? `calc(${obj.position.bottom}px + ${isPlaying && selectedZone.activeSides.includes("bottom")
|
||||||
isPlaying && selectedZone.activeSides.includes("bottom")
|
? `${heightMultiplier - 55}px`
|
||||||
? `${heightMultiplier - 55}px`
|
: "0px"
|
||||||
: "0px"
|
})`
|
||||||
})`
|
|
||||||
: "auto";
|
: "auto";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={`${zoneName}-${index}`}
|
key={`${zoneName}-${index}`}
|
||||||
className={`${obj.className} ${
|
className={`${obj.className} ${selectedChartId?.id === obj.id && "activeChart"
|
||||||
selectedChartId?.id === obj.id && "activeChart"
|
}`}
|
||||||
}`}
|
|
||||||
ref={chartWidget}
|
ref={chartWidget}
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
|
|
|
@ -7,7 +7,7 @@ import DisplayZone from "./DisplayZone";
|
||||||
import Scene from "../../../modules/scene/scene";
|
import Scene from "../../../modules/scene/scene";
|
||||||
import useModuleStore from "../../../store/useModuleStore";
|
import useModuleStore from "../../../store/useModuleStore";
|
||||||
|
|
||||||
import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
|
import { useDroppedObjectsStore, useFloatingWidget } from "../../../store/useDroppedObjectsStore";
|
||||||
import {
|
import {
|
||||||
useAsset3dWidget,
|
useAsset3dWidget,
|
||||||
useSocketStore,
|
useSocketStore,
|
||||||
|
@ -68,7 +68,8 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
const { rightClickSelected, setRightClickSelected } = useRightClickSelected();
|
const { rightClickSelected, setRightClickSelected } = useRightClickSelected();
|
||||||
const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false);
|
const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false);
|
||||||
|
|
||||||
const [floatingWidgets, setFloatingWidgets] = useState<Record<string, { zoneName: string; zoneId: string; objects: any[] }>>({});
|
// const [floatingWidgets, setFloatingWidgets] = useState<Record<string, { zoneName: string; zoneId: string; objects: any[] }>>({});
|
||||||
|
const { floatingWidget, setFloatingWidget } = useFloatingWidget()
|
||||||
const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
|
const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
|
||||||
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
|
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
|
||||||
const { visualizationSocket } = useSocketStore();
|
const { visualizationSocket } = useSocketStore();
|
||||||
|
@ -129,7 +130,6 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
|
|
||||||
const handleDrop = async (event: React.DragEvent<HTMLDivElement>) => {
|
const handleDrop = async (event: React.DragEvent<HTMLDivElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") || "";
|
||||||
|
@ -175,6 +175,25 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
if (visualizationSocket) {
|
if (visualizationSocket) {
|
||||||
visualizationSocket.emit("v2:viz-float:add", addFloatingWidget);
|
visualizationSocket.emit("v2:viz-float:add", addFloatingWidget);
|
||||||
}
|
}
|
||||||
|
useDroppedObjectsStore
|
||||||
|
.getState()
|
||||||
|
.addObject(selectedZone.zoneName, newObject);
|
||||||
|
|
||||||
|
//I need to console here objects based on selectedZone.zoneId
|
||||||
|
// Console the objects after adding
|
||||||
|
const droppedObjectsStore = useDroppedObjectsStore.getState();
|
||||||
|
const currentZone = droppedObjectsStore.zones[selectedZone.zoneName];
|
||||||
|
|
||||||
|
if (currentZone && currentZone.zoneId === selectedZone.zoneId) {
|
||||||
|
console.log(
|
||||||
|
`Objects for Zone ID: ${selectedZone.zoneId}`,
|
||||||
|
currentZone.objects
|
||||||
|
);
|
||||||
|
setFloatingWidget(currentZone.objects)
|
||||||
|
} else {
|
||||||
|
console.warn("Zone not found or mismatched zoneId");
|
||||||
|
}
|
||||||
|
|
||||||
// let response = await addingFloatingWidgets(
|
// let response = await addingFloatingWidgets(
|
||||||
// selectedZone.zoneId,
|
// selectedZone.zoneId,
|
||||||
// organization,
|
// organization,
|
||||||
|
@ -182,23 +201,10 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
// );
|
// );
|
||||||
// Add the dropped object to the zone if the API call is successful
|
// Add the dropped object to the zone if the API call is successful
|
||||||
// if (response.message === "FloatWidget created successfully") {
|
// if (response.message === "FloatWidget created successfully") {
|
||||||
useDroppedObjectsStore
|
|
||||||
.getState()
|
|
||||||
.addObject(selectedZone.zoneName, newObject);
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// Update floating widgets state
|
// Update floating widgets state
|
||||||
setFloatingWidgets((prevWidgets) => ({
|
|
||||||
...prevWidgets,
|
|
||||||
[selectedZone.zoneName]: {
|
|
||||||
...prevWidgets[selectedZone.zoneName],
|
|
||||||
zoneName: selectedZone.zoneName,
|
|
||||||
zoneId: selectedZone.zoneId,
|
|
||||||
objects: [
|
|
||||||
...(prevWidgets[selectedZone.zoneName]?.objects || []),
|
|
||||||
newObject,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
} catch (error) { }
|
} catch (error) { }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,25 +12,66 @@ export default function ZoneAssets() {
|
||||||
if (!zoneAssetId) return
|
if (!zoneAssetId) return
|
||||||
console.log('zoneAssetId: ', zoneAssetId);
|
console.log('zoneAssetId: ', zoneAssetId);
|
||||||
let AssetMesh = scene.getObjectByProperty("uuid", zoneAssetId.id);
|
let AssetMesh = scene.getObjectByProperty("uuid", zoneAssetId.id);
|
||||||
if (!AssetMesh) return;
|
if (AssetMesh) {
|
||||||
|
const bbox = new THREE.Box3().setFromObject(AssetMesh);
|
||||||
|
const size = bbox.getSize(new THREE.Vector3());
|
||||||
|
const center = bbox.getCenter(new THREE.Vector3());
|
||||||
|
|
||||||
const bbox = new THREE.Box3().setFromObject(AssetMesh);
|
const front = new THREE.Vector3(0, 0, 1);
|
||||||
const size = bbox.getSize(new THREE.Vector3());
|
AssetMesh.localToWorld(front);
|
||||||
const center = bbox.getCenter(new THREE.Vector3());
|
front.sub(AssetMesh.position).normalize();
|
||||||
|
|
||||||
const front = new THREE.Vector3(0, 0, 1);
|
const distance = Math.max(size.x, size.y, size.z) * 2;
|
||||||
AssetMesh.localToWorld(front);
|
const newPosition = center.clone().addScaledVector(front, distance);
|
||||||
front.sub(AssetMesh.position).normalize();
|
|
||||||
|
|
||||||
const distance = Math.max(size.x, size.y, size.z) * 2;
|
controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true);
|
||||||
const newPosition = center.clone().addScaledVector(front, distance);
|
controls.setTarget(center.x, center.y, center.z, true);
|
||||||
|
controls.fitToBox(AssetMesh, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5, });
|
||||||
|
|
||||||
controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true);
|
setSelectedFloorItem(AssetMesh);
|
||||||
controls.setTarget(center.x, center.y, center.z, true);
|
} else {
|
||||||
controls.fitToBox(AssetMesh, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5, });
|
console.log('zoneAssetId: ', zoneAssetId)
|
||||||
|
if (Array.isArray(zoneAssetId.position) && zoneAssetId.position.length >= 3) {
|
||||||
|
let selectedAssetPosition = [
|
||||||
|
zoneAssetId.position[0],
|
||||||
|
10,
|
||||||
|
zoneAssetId.position[2]
|
||||||
|
];
|
||||||
|
console.log('selectedAssetPosition: ', selectedAssetPosition);
|
||||||
|
let selectedAssetTarget = [
|
||||||
|
zoneAssetId.position[0],
|
||||||
|
zoneAssetId.position[1],
|
||||||
|
zoneAssetId.position[2]
|
||||||
|
];
|
||||||
|
console.log('selectedAssetTarget: ', selectedAssetTarget);
|
||||||
|
const setCam = async () => {
|
||||||
|
await controls?.setLookAt(...selectedAssetPosition, ...selectedAssetTarget, true);
|
||||||
|
setTimeout(() => {
|
||||||
|
let AssetMesh = scene.getObjectByProperty("uuid", zoneAssetId.id);
|
||||||
|
if (AssetMesh) {
|
||||||
|
const bbox = new THREE.Box3().setFromObject(AssetMesh);
|
||||||
|
const size = bbox.getSize(new THREE.Vector3());
|
||||||
|
const center = bbox.getCenter(new THREE.Vector3());
|
||||||
|
|
||||||
setSelectedFloorItem(AssetMesh);
|
const front = new THREE.Vector3(0, 0, 1);
|
||||||
|
AssetMesh.localToWorld(front);
|
||||||
|
front.sub(AssetMesh.position).normalize();
|
||||||
|
|
||||||
|
const distance = Math.max(size.x, size.y, size.z) * 2;
|
||||||
|
const newPosition = center.clone().addScaledVector(front, distance);
|
||||||
|
|
||||||
|
controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true);
|
||||||
|
controls.setTarget(center.x, center.y, center.z, true);
|
||||||
|
controls.fitToBox(AssetMesh, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5, });
|
||||||
|
|
||||||
|
setSelectedFloorItem(AssetMesh);
|
||||||
|
}
|
||||||
|
}, 500)
|
||||||
|
|
||||||
|
};
|
||||||
|
setCam();
|
||||||
|
}
|
||||||
|
}
|
||||||
}, [zoneAssetId, scene, controls])
|
}, [zoneAssetId, scene, controls])
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { AddIcon, ArrowIcon, FocusIcon } from "../../icons/ExportCommonIcons";
|
||||||
import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect";
|
import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect";
|
||||||
import { useFloorItems, useZones } from "../../../store/store";
|
import { useFloorItems, useZones } from "../../../store/store";
|
||||||
import { useSelectedZoneStore } from "../../../store/useZoneStore";
|
import { useSelectedZoneStore } from "../../../store/useZoneStore";
|
||||||
|
import { getZone2dData } from "../../../services/realTimeVisulization/zoneData/getZoneData";
|
||||||
|
|
||||||
interface DropDownListProps {
|
interface DropDownListProps {
|
||||||
value?: string; // Value to display in the DropDownList
|
value?: string; // Value to display in the DropDownList
|
||||||
|
@ -55,7 +56,7 @@ const DropDownList: React.FC<DropDownListProps> = ({
|
||||||
assets: { id: string; name: string; position?: []; rotation?: {} }[];
|
assets: { id: string; name: string; position?: []; rotation?: {} }[];
|
||||||
}
|
}
|
||||||
const [zoneDataList, setZoneDataList] = useState<ZoneData[]>([]);
|
const [zoneDataList, setZoneDataList] = useState<ZoneData[]>([]);
|
||||||
const { floorItems, setFloorItems } = useFloorItems();
|
const { floorItems } = useFloorItems();
|
||||||
|
|
||||||
const isPointInsidePolygon = (point: [number, number], polygon: [number, number][]) => {
|
const isPointInsidePolygon = (point: [number, number], polygon: [number, number][]) => {
|
||||||
let inside = false;
|
let inside = false;
|
||||||
|
@ -72,8 +73,7 @@ const DropDownList: React.FC<DropDownListProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const updatedZoneList: ZoneData[] = zones?.map((zone: Zone) => {
|
||||||
const updatedZoneList: ZoneData[] = zones.map((zone: Zone) => {
|
|
||||||
const polygon2D = zone.points.map((p: [number, number, number]) => [p[0], p[2]]) as [number, number][];
|
const polygon2D = zone.points.map((p: [number, number, number]) => [p[0], p[2]]) as [number, number][];
|
||||||
|
|
||||||
const assetsInZone = floorItems
|
const assetsInZone = floorItems
|
||||||
|
|
|
@ -13,7 +13,9 @@ import {
|
||||||
RmoveIcon,
|
RmoveIcon,
|
||||||
} from "../../icons/ExportCommonIcons";
|
} from "../../icons/ExportCommonIcons";
|
||||||
import { useThree } from "@react-three/fiber";
|
import { useThree } from "@react-three/fiber";
|
||||||
import { useZoneAssetId } from "../../../store/store";
|
import { useFloorItems, useZoneAssetId } from "../../../store/store";
|
||||||
|
import { zoneCameraUpdate } from "../../../services/realTimeVisulization/zoneData/zoneCameraUpdation";
|
||||||
|
import { setFloorItemApi } from "../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
|
||||||
|
|
||||||
interface Asset {
|
interface Asset {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -38,11 +40,12 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||||
const { activeModule, setActiveModule } = useModuleStore();
|
const { activeModule, setActiveModule } = useModuleStore();
|
||||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||||
const { zoneAssetId, setZoneAssetId } = useZoneAssetId();
|
const { zoneAssetId, setZoneAssetId } = useZoneAssetId();
|
||||||
|
|
||||||
const { setSubModule } = useSubModuleStore();
|
const { setSubModule } = useSubModuleStore();
|
||||||
const [expandedZones, setExpandedZones] = useState<Record<string, boolean>>(
|
const [expandedZones, setExpandedZones] = useState<Record<string, boolean>>(
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
const { floorItems, setFloorItems } = useFloorItems();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
useSelectedZoneStore.getState().setSelectedZone({
|
useSelectedZoneStore.getState().setSelectedZone({
|
||||||
|
@ -67,7 +70,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||||
async function handleSelectZone(id: string) {
|
async function handleSelectZone(id: string) {
|
||||||
try {
|
try {
|
||||||
if (selectedZone?.zoneId === id) {
|
if (selectedZone?.zoneId === id) {
|
||||||
console.log("Zone is already selected:", selectedZone.zoneName);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,19 +92,52 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||||
zoneViewPortPosition: response?.viewPortposition || [],
|
zoneViewPortPosition: response?.viewPortposition || [],
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("Zone selected:", response?.zoneName);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error selecting zone:", error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function handleAssetClick(asset: Asset) {
|
function handleAssetClick(asset: Asset) {
|
||||||
setZoneAssetId(asset)
|
setZoneAssetId(asset)
|
||||||
}
|
}
|
||||||
|
async function handleZoneNameChange(newName: string) {
|
||||||
|
//zone apiiiiii
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
|
let zonesdata = {
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
|
zoneName: newName
|
||||||
|
};
|
||||||
|
let response = await zoneCameraUpdate(zonesdata, organization);
|
||||||
|
if (response.message === "updated successfully") {
|
||||||
|
setSelectedZone((prev) => ({ ...prev, zoneName: newName }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function handleZoneAssetName(newName: string) {
|
||||||
|
const email = localStorage.getItem("email") || "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
|
|
||||||
|
if (zoneAssetId?.id) {
|
||||||
|
let response = await setFloorItemApi(organization, zoneAssetId.id, newName)
|
||||||
|
console.log('response: ', response);
|
||||||
|
setFloorItems((prevFloorItems: any[]) =>
|
||||||
|
prevFloorItems.map((floorItems) =>
|
||||||
|
floorItems.modeluuid === zoneAssetId.id
|
||||||
|
? { ...floorItems, modelname: response.modelname }
|
||||||
|
: floorItems
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('newName: ', newName);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{items.length > 0 ? (
|
{items?.length > 0 ? (
|
||||||
<ul className="list-wrapper">
|
<ul className="list-wrapper">
|
||||||
{items.map((item) => (
|
{items?.map((item) => (
|
||||||
<React.Fragment key={`zone-${item.id}`}>
|
<React.Fragment key={`zone-${item.id}`}>
|
||||||
<li className="list-container">
|
<li className="list-container">
|
||||||
<div className="list-item">
|
<div className="list-item">
|
||||||
|
@ -110,7 +146,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||||
className="value"
|
className="value"
|
||||||
onClick={() => handleSelectZone(item.id)}
|
onClick={() => handleSelectZone(item.id)}
|
||||||
>
|
>
|
||||||
<RenameInput value={item.name} />
|
<RenameInput value={item.name} onRename={handleZoneNameChange} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="options-container">
|
<div className="options-container">
|
||||||
|
@ -147,8 +183,8 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||||
className="list-container asset-item"
|
className="list-container asset-item"
|
||||||
>
|
>
|
||||||
<div className="list-item">
|
<div className="list-item">
|
||||||
<div className="value" onClick={() => handleAssetClick(asset)}>
|
<div className="value" onClick={() => handleAssetClick(asset)} >
|
||||||
<RenameInput value={asset.name} />
|
<RenameInput value={asset.name} onRename={handleZoneAssetName} />
|
||||||
</div>
|
</div>
|
||||||
<div className="options-container">
|
<div className="options-container">
|
||||||
<div className="lock option">
|
<div className="lock option">
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { getLines } from "../../../../services/factoryBuilder/lines/getLinesApi";
|
import { getLines } from "../../../../../services/factoryBuilder/lines/getLinesApi";
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import {
|
import {
|
||||||
useActiveLayer,
|
useActiveLayer,
|
||||||
useDeletedLines,
|
useDeletedLines,
|
||||||
useNewLines,
|
useNewLines,
|
||||||
useToggleView,
|
useToggleView,
|
||||||
} from "../../../../store/store";
|
} from "../../../../../store/store";
|
||||||
import objectLinesToArray from "./lineConvertions/objectLinesToArray";
|
import objectLinesToArray from "../lineConvertions/objectLinesToArray";
|
||||||
import { Html } from "@react-three/drei";
|
import { Html } from "@react-three/drei";
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../../types/world/worldTypes";
|
||||||
|
|
||||||
const DistanceText = () => {
|
const DistanceText = () => {
|
||||||
const [lines, setLines] = useState<
|
const [lines, setLines] = useState<
|
||||||
|
@ -122,7 +122,7 @@ const DistanceText = () => {
|
||||||
wrapperClass="distance-text-wrapper"
|
wrapperClass="distance-text-wrapper"
|
||||||
className="distance-text"
|
className="distance-text"
|
||||||
// other
|
// other
|
||||||
zIndexRange={[100, 0]}
|
zIndexRange={[1, 0]}
|
||||||
prepend
|
prepend
|
||||||
sprite
|
sprite
|
||||||
>
|
>
|
|
@ -0,0 +1,71 @@
|
||||||
|
import * as THREE from "three";
|
||||||
|
import { Html } from "@react-three/drei";
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { useActiveLayer } from "../../../../../store/store";
|
||||||
|
|
||||||
|
const ReferenceDistanceText = ({ line }: { line: any }) => {
|
||||||
|
interface TextState {
|
||||||
|
distance: string;
|
||||||
|
position: THREE.Vector3;
|
||||||
|
userData: any;
|
||||||
|
layer: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [text, setTexts] = useState<TextState | null>(null);
|
||||||
|
const { activeLayer } = useActiveLayer();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (line) {
|
||||||
|
if (line.parent === null) {
|
||||||
|
setTexts(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const distance = line.userData.linePoints.cursorPosition.distanceTo(
|
||||||
|
line.userData.linePoints.startPoint
|
||||||
|
);
|
||||||
|
const midpoint = new THREE.Vector3()
|
||||||
|
.addVectors(
|
||||||
|
line.userData.linePoints.cursorPosition,
|
||||||
|
line.userData.linePoints.startPoint
|
||||||
|
)
|
||||||
|
.divideScalar(2);
|
||||||
|
const newTexts = {
|
||||||
|
distance: distance.toFixed(1),
|
||||||
|
position: midpoint,
|
||||||
|
userData: line,
|
||||||
|
layer: activeLayer,
|
||||||
|
};
|
||||||
|
setTexts(newTexts);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group name="Reference_Distance_Text">
|
||||||
|
<mesh>
|
||||||
|
{text !== null && (
|
||||||
|
<Html
|
||||||
|
// data
|
||||||
|
key={text.distance}
|
||||||
|
userData={text.userData}
|
||||||
|
position={[text.position.x, 1, text.position.z]}
|
||||||
|
// class
|
||||||
|
wrapperClass="distance-text-wrapper"
|
||||||
|
className="distance-text"
|
||||||
|
// other
|
||||||
|
zIndexRange={[1, 0]}
|
||||||
|
prepend
|
||||||
|
sprite
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`Reference_Distance line-${text.userData.userData}`}
|
||||||
|
>
|
||||||
|
{text.distance} m
|
||||||
|
</div>
|
||||||
|
</Html>
|
||||||
|
)}
|
||||||
|
</mesh>
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ReferenceDistanceText;
|
|
@ -1,48 +0,0 @@
|
||||||
import * as THREE from 'three';
|
|
||||||
import { Html } from '@react-three/drei';
|
|
||||||
import { useState, useEffect } from 'react';
|
|
||||||
import { useActiveLayer } from '../../../../store/store';
|
|
||||||
|
|
||||||
const ReferenceDistanceText = ({ line }: { line: any }) => {
|
|
||||||
interface TextState {
|
|
||||||
distance: string;
|
|
||||||
position: THREE.Vector3;
|
|
||||||
userData: any;
|
|
||||||
layer: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [text, setTexts] = useState<TextState | null>(null);
|
|
||||||
const { activeLayer } = useActiveLayer();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (line) {
|
|
||||||
if (line.parent === null) {
|
|
||||||
setTexts(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const distance = line.userData.linePoints.cursorPosition.distanceTo(line.userData.linePoints.startPoint);
|
|
||||||
const midpoint = new THREE.Vector3().addVectors(line.userData.linePoints.cursorPosition, line.userData.linePoints.startPoint).divideScalar(2);
|
|
||||||
const newTexts = {
|
|
||||||
distance: distance.toFixed(1),
|
|
||||||
position: midpoint,
|
|
||||||
userData: line,
|
|
||||||
layer: activeLayer
|
|
||||||
};
|
|
||||||
setTexts(newTexts);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<group name='Reference_Distance_Text'>
|
|
||||||
<mesh>
|
|
||||||
{text !== null &&
|
|
||||||
< Html transform sprite key={text.distance} userData={text.userData} scale={5} position={[text.position.x, 1, text.position.z]} style={{ pointerEvents: 'none' }}>
|
|
||||||
<div className={`Reference_Distance line-${text.userData.userData}`}>{text.distance} m</div>
|
|
||||||
</Html>
|
|
||||||
}
|
|
||||||
</mesh>
|
|
||||||
</group >
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ReferenceDistanceText;
|
|
|
@ -50,7 +50,7 @@ const ZoneGroup: React.FC = () => {
|
||||||
uColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) },
|
uColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) },
|
||||||
},
|
},
|
||||||
transparent: true,
|
transparent: true,
|
||||||
depthWrite: false
|
depthWrite: false,
|
||||||
}), []);
|
}), []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -185,10 +185,9 @@ const CamModelsGroup = () => {
|
||||||
position={[-0.015, 0, 0.7]}
|
position={[-0.015, 0, 0.7]}
|
||||||
>
|
>
|
||||||
<CollabUserIcon
|
<CollabUserIcon
|
||||||
userImage={""}
|
userImage={cam.userData.userImage ||""}
|
||||||
userName={cam.userData.userName}
|
userName={cam.userData.userName}
|
||||||
index={index}
|
color={getAvatarColor(index, cam.userData.userName)}
|
||||||
color={getAvatarColor(index)}
|
|
||||||
/>
|
/>
|
||||||
</Html>
|
</Html>
|
||||||
</primitive>
|
</primitive>
|
||||||
|
|
|
@ -4,14 +4,12 @@ import CustomAvatar from "./users/Avatar";
|
||||||
interface CollabUserIconProps {
|
interface CollabUserIconProps {
|
||||||
userName: string;
|
userName: string;
|
||||||
userImage?: string;
|
userImage?: string;
|
||||||
index?: number;
|
|
||||||
color: string;
|
color: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CollabUserIcon: React.FC<CollabUserIconProps> = ({
|
const CollabUserIcon: React.FC<CollabUserIconProps> = ({
|
||||||
userImage,
|
userImage,
|
||||||
userName,
|
userName,
|
||||||
index = 0,
|
|
||||||
color,
|
color,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
|
@ -20,24 +18,7 @@ const CollabUserIcon: React.FC<CollabUserIconProps> = ({
|
||||||
{userImage ? (
|
{userImage ? (
|
||||||
<img className="user-image" src={userImage} alt={userName} />
|
<img className="user-image" src={userImage} alt={userName} />
|
||||||
) : (
|
) : (
|
||||||
<CustomAvatar name={userName} index={index} color={color} />
|
<CustomAvatar name={userName} color={color} />
|
||||||
// <div
|
|
||||||
// className="user-image"
|
|
||||||
// style={{
|
|
||||||
// lineHeight: "30px",
|
|
||||||
// textTransform: "uppercase",
|
|
||||||
// textAlign: "center",
|
|
||||||
// fontSize: "16px",
|
|
||||||
// borderRadius: "50%",
|
|
||||||
// backgroundColor: color,
|
|
||||||
// overflow: "hidden",
|
|
||||||
// backgroundSize: "cover",
|
|
||||||
// backgroundPosition: "center",
|
|
||||||
// color: "white",
|
|
||||||
// fontWeight: "bold",
|
|
||||||
// }}>
|
|
||||||
// {userName[0]}
|
|
||||||
// </div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="user-name" style={{ backgroundColor: color }}>
|
<div className="user-name" style={{ backgroundColor: color }}>
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { getAvatarColor } from "./functions/getAvatarColor";
|
||||||
interface AvatarProps {
|
interface AvatarProps {
|
||||||
name: string; // Name can be a full name or initials
|
name: string; // Name can be a full name or initials
|
||||||
size?: number;
|
size?: number;
|
||||||
index?: number;
|
|
||||||
textColor?: string;
|
textColor?: string;
|
||||||
color?: string; // Optional color prop for future use
|
color?: string; // Optional color prop for future use
|
||||||
}
|
}
|
||||||
|
@ -13,7 +12,6 @@ interface AvatarProps {
|
||||||
const CustomAvatar: React.FC<AvatarProps> = ({
|
const CustomAvatar: React.FC<AvatarProps> = ({
|
||||||
name,
|
name,
|
||||||
size = 100,
|
size = 100,
|
||||||
index = 0,
|
|
||||||
textColor = "#ffffff",
|
textColor = "#ffffff",
|
||||||
color, // Optional color prop for future use
|
color, // Optional color prop for future use
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -28,7 +26,7 @@ const CustomAvatar: React.FC<AvatarProps> = ({
|
||||||
const initials = getInitials(name); // Convert name to initials if needed
|
const initials = getInitials(name); // Convert name to initials if needed
|
||||||
|
|
||||||
// Draw background
|
// Draw background
|
||||||
ctx.fillStyle = color || getAvatarColor(index); // Use color prop or generate color based on index
|
ctx.fillStyle = color || "#323232"; // Use color prop or generate color based on index
|
||||||
ctx.fillRect(0, 0, size, size);
|
ctx.fillRect(0, 0, size, size);
|
||||||
|
|
||||||
// Draw initials
|
// Draw initials
|
||||||
|
@ -42,7 +40,7 @@ const CustomAvatar: React.FC<AvatarProps> = ({
|
||||||
const dataURL = canvas.toDataURL("image/png");
|
const dataURL = canvas.toDataURL("image/png");
|
||||||
setImageSrc(dataURL);
|
setImageSrc(dataURL);
|
||||||
}
|
}
|
||||||
}, [name, size, textColor, index]);
|
}, [name, size, textColor]);
|
||||||
|
|
||||||
if (!imageSrc) {
|
if (!imageSrc) {
|
||||||
return null; // Return null while the image is being generated
|
return null; // Return null while the image is being generated
|
||||||
|
@ -55,18 +53,6 @@ const CustomAvatar: React.FC<AvatarProps> = ({
|
||||||
alt="User Avatar"
|
alt="User Avatar"
|
||||||
style={{ width: "100%", height: "100%" }}
|
style={{ width: "100%", height: "100%" }}
|
||||||
/>
|
/>
|
||||||
// <div
|
|
||||||
// className="user-image"
|
|
||||||
// style={{
|
|
||||||
// width: size,
|
|
||||||
// height: size,
|
|
||||||
// borderRadius: "50%",
|
|
||||||
// overflow: "hidden",
|
|
||||||
// backgroundSize: "cover",
|
|
||||||
// backgroundPosition: "center",
|
|
||||||
// }}>
|
|
||||||
// {name[0]}
|
|
||||||
// </div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,67 @@
|
||||||
const avatarColors: string[] = [
|
const avatarColors: string[] = [
|
||||||
"#FF5733", // Red Orange
|
"#FF5733", // Vivid Orange
|
||||||
"#48ac2a", // Leaf Green
|
"#48ac2a", // Leaf Green
|
||||||
"#0050eb", // Royal Blue
|
"#0050eb", // Bright Blue
|
||||||
"#FF33A1", // Hot Pink
|
"#FF33A1", // Hot Pink
|
||||||
"#FF8C33", // Deep Orange
|
"#FF8C33", // Sunset Orange
|
||||||
"#8C33FF", // Violet
|
"#8C33FF", // Violet Purple
|
||||||
"#FF3333", // Bright Red
|
"#FF3333", // Fiery Red
|
||||||
"#43c06d", // Emerald Green
|
"#43c06d", // Emerald Green
|
||||||
"#A133FF", // Amethyst Purple
|
"#A133FF", // Royal Purple
|
||||||
"#C70039", // Crimson
|
"#C70039", // Crimson Red
|
||||||
"#900C3F", // Maroon
|
"#900C3F", // Deep Burgundy
|
||||||
"#581845", // Plum
|
"#581845", // Plum Purple
|
||||||
"#3498DB", // Sky Blue
|
"#3859AD", // Steel Blue
|
||||||
"#2ECC71", // Green Mint
|
"#08873E", // Forest Green
|
||||||
"#E74C3C", // Tomato Red
|
"#E74C3C", // Cherry Red
|
||||||
"#00adff", // Azure
|
"#00adff", // Sky Blue
|
||||||
"#DBAD05", // Amber Yellow
|
"#DBAD05", // Golden Yellow
|
||||||
"#FF5733", // Red Orange
|
"#A13E31", // Brick Red
|
||||||
"#FF33A1", // Hot Pink
|
"#94C40E", // Lime Green
|
||||||
"#900C3F", // Maroon
|
"#060C47", // Midnight Blue
|
||||||
|
"#2FAFAF", // Teal
|
||||||
];
|
];
|
||||||
|
|
||||||
export function getAvatarColor(index: number): string {
|
export function getAvatarColor(index: number, name?: string): string {
|
||||||
|
// Check if the color is already stored in localStorage
|
||||||
|
const localStorageKey = "userAvatarColors";
|
||||||
|
// Helper function to check if local storage is available
|
||||||
|
function isLocalStorageAvailable(): boolean {
|
||||||
|
try {
|
||||||
|
const testKey = "__test__";
|
||||||
|
localStorage.setItem(testKey, "test");
|
||||||
|
localStorage.removeItem(testKey);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if local storage is available
|
||||||
|
if (isLocalStorageAvailable() && name) {
|
||||||
|
let userColors = JSON.parse(localStorage.getItem(localStorageKey) || "{}");
|
||||||
|
|
||||||
|
// Check if the user already has an assigned color
|
||||||
|
if (userColors[name]) {
|
||||||
|
return userColors[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find a new color not already assigned
|
||||||
|
const usedColors = Object.values(userColors);
|
||||||
|
const availableColors = avatarColors.filter(color => !usedColors.includes(color));
|
||||||
|
|
||||||
|
// Assign a new color
|
||||||
|
const assignedColor = availableColors.length > 0
|
||||||
|
? availableColors[0]
|
||||||
|
: avatarColors[index % avatarColors.length];
|
||||||
|
|
||||||
|
userColors[name] = assignedColor;
|
||||||
|
|
||||||
|
// Save back to local storage
|
||||||
|
localStorage.setItem(localStorageKey, JSON.stringify(userColors));
|
||||||
|
|
||||||
|
return assignedColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: Assign a color using the index if no name or local storage is unavailable
|
||||||
return avatarColors[index % avatarColors.length];
|
return avatarColors[index % avatarColors.length];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,190 +1,244 @@
|
||||||
import * as THREE from 'three';
|
import * as THREE from "three";
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { useThree, useFrame } from '@react-three/fiber';
|
import { useThree, useFrame } from "@react-three/fiber";
|
||||||
import { useToolMode } from '../../../store/store';
|
import { useToolMode } from "../../../store/store";
|
||||||
import { Html } from '@react-three/drei';
|
import { Html } from "@react-three/drei";
|
||||||
|
|
||||||
const MeasurementTool = () => {
|
const MeasurementTool = () => {
|
||||||
const { gl, raycaster, pointer, camera, scene } = useThree();
|
const { gl, raycaster, pointer, camera, scene } = useThree();
|
||||||
const { toolMode } = useToolMode();
|
const { toolMode } = useToolMode();
|
||||||
|
|
||||||
const [points, setPoints] = useState<THREE.Vector3[]>([]);
|
const [points, setPoints] = useState<THREE.Vector3[]>([]);
|
||||||
const [tubeGeometry, setTubeGeometry] = useState<THREE.TubeGeometry | null>(null);
|
const [tubeGeometry, setTubeGeometry] = useState<THREE.TubeGeometry | null>(
|
||||||
const groupRef = useRef<THREE.Group>(null);
|
null
|
||||||
const [startConePosition, setStartConePosition] = useState<THREE.Vector3 | null>(null);
|
);
|
||||||
const [endConePosition, setEndConePosition] = useState<THREE.Vector3 | null>(null);
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
const [startConeQuaternion, setStartConeQuaternion] = useState(new THREE.Quaternion());
|
const [startConePosition, setStartConePosition] =
|
||||||
const [endConeQuaternion, setEndConeQuaternion] = useState(new THREE.Quaternion());
|
useState<THREE.Vector3 | null>(null);
|
||||||
const [coneSize, setConeSize] = useState({ radius: 0.2, height: 0.5 });
|
const [endConePosition, setEndConePosition] = useState<THREE.Vector3 | null>(
|
||||||
|
null
|
||||||
|
);
|
||||||
|
const [startConeQuaternion, setStartConeQuaternion] = useState(
|
||||||
|
new THREE.Quaternion()
|
||||||
|
);
|
||||||
|
const [endConeQuaternion, setEndConeQuaternion] = useState(
|
||||||
|
new THREE.Quaternion()
|
||||||
|
);
|
||||||
|
const [coneSize, setConeSize] = useState({ radius: 0.2, height: 0.5 });
|
||||||
|
|
||||||
|
const MIN_RADIUS = 0.001,
|
||||||
|
MAX_RADIUS = 0.1;
|
||||||
|
const MIN_CONE_RADIUS = 0.01,
|
||||||
|
MAX_CONE_RADIUS = 0.4;
|
||||||
|
const MIN_CONE_HEIGHT = 0.035,
|
||||||
|
MAX_CONE_HEIGHT = 2.0;
|
||||||
|
|
||||||
const MIN_RADIUS = 0.001, MAX_RADIUS = 0.1;
|
useEffect(() => {
|
||||||
const MIN_CONE_RADIUS = 0.01, MAX_CONE_RADIUS = 0.4;
|
const canvasElement = gl.domElement;
|
||||||
const MIN_CONE_HEIGHT = 0.035, MAX_CONE_HEIGHT = 2.0;
|
let drag = false;
|
||||||
|
let isLeftMouseDown = false;
|
||||||
|
|
||||||
useEffect(() => {
|
const onMouseDown = () => {
|
||||||
const canvasElement = gl.domElement;
|
isLeftMouseDown = true;
|
||||||
let drag = false;
|
drag = false;
|
||||||
let isLeftMouseDown = false;
|
|
||||||
|
|
||||||
const onMouseDown = () => {
|
|
||||||
isLeftMouseDown = true;
|
|
||||||
drag = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMouseUp = (evt: any) => {
|
|
||||||
isLeftMouseDown = false;
|
|
||||||
if (evt.button === 0 && !drag) {
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
const intersects = raycaster.intersectObjects(scene.children, true).filter(intersect => !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !intersect.object.name.includes("agv-collider") && !(intersect.object.type === "GridHelper"));
|
|
||||||
|
|
||||||
if (intersects.length > 0) {
|
|
||||||
const intersectionPoint = intersects[0].point.clone();
|
|
||||||
if (points.length < 2) {
|
|
||||||
setPoints([...points, intersectionPoint]);
|
|
||||||
} else {
|
|
||||||
setPoints([intersectionPoint]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMouseMove = () => {
|
|
||||||
if (isLeftMouseDown) drag = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onContextMenu = (evt: any) => {
|
|
||||||
evt.preventDefault();
|
|
||||||
if (!drag) {
|
|
||||||
evt.preventDefault();
|
|
||||||
setPoints([]);
|
|
||||||
setTubeGeometry(null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (toolMode === "MeasurementScale") {
|
|
||||||
canvasElement.addEventListener("pointerdown", onMouseDown);
|
|
||||||
canvasElement.addEventListener("pointermove", onMouseMove);
|
|
||||||
canvasElement.addEventListener("pointerup", onMouseUp);
|
|
||||||
canvasElement.addEventListener("contextmenu", onContextMenu);
|
|
||||||
} else {
|
|
||||||
resetMeasurement();
|
|
||||||
setPoints([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
canvasElement.removeEventListener("pointerdown", onMouseDown);
|
|
||||||
canvasElement.removeEventListener("pointermove", onMouseMove);
|
|
||||||
canvasElement.removeEventListener("pointerup", onMouseUp);
|
|
||||||
canvasElement.removeEventListener("contextmenu", onContextMenu);
|
|
||||||
};
|
|
||||||
}, [toolMode, camera, raycaster, pointer, scene, points]);
|
|
||||||
|
|
||||||
useFrame(() => {
|
|
||||||
if (points.length === 1) {
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
const intersects = raycaster.intersectObjects(scene.children, true).filter(intersect => !intersect.object.name.includes("Roof") && !intersect.object.name.includes("MeasurementReference") && !intersect.object.name.includes("agv-collider") && !(intersect.object.type === "GridHelper"));
|
|
||||||
|
|
||||||
if (intersects.length > 0) {
|
|
||||||
updateMeasurement(points[0], intersects[0].point);
|
|
||||||
}
|
|
||||||
} else if (points.length === 2) {
|
|
||||||
updateMeasurement(points[0], points[1]);
|
|
||||||
} else {
|
|
||||||
resetMeasurement();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const updateMeasurement = (start: THREE.Vector3, end: THREE.Vector3) => {
|
|
||||||
const distance = start.distanceTo(end);
|
|
||||||
|
|
||||||
const radius = THREE.MathUtils.clamp(distance * 0.02, MIN_RADIUS, MAX_RADIUS);
|
|
||||||
const coneRadius = THREE.MathUtils.clamp(distance * 0.05, MIN_CONE_RADIUS, MAX_CONE_RADIUS);
|
|
||||||
const coneHeight = THREE.MathUtils.clamp(distance * 0.2, MIN_CONE_HEIGHT, MAX_CONE_HEIGHT);
|
|
||||||
|
|
||||||
setConeSize({ radius: coneRadius, height: coneHeight });
|
|
||||||
|
|
||||||
const direction = new THREE.Vector3().subVectors(end, start).normalize();
|
|
||||||
|
|
||||||
const offset = direction.clone().multiplyScalar(coneHeight * 0.5);
|
|
||||||
|
|
||||||
let tubeStart = start.clone().add(offset);
|
|
||||||
let tubeEnd = end.clone().sub(offset);
|
|
||||||
|
|
||||||
tubeStart.y = Math.max(tubeStart.y, 0);
|
|
||||||
tubeEnd.y = Math.max(tubeEnd.y, 0);
|
|
||||||
|
|
||||||
const curve = new THREE.CatmullRomCurve3([tubeStart, tubeEnd]);
|
|
||||||
setTubeGeometry(new THREE.TubeGeometry(curve, 20, radius, 8, false));
|
|
||||||
|
|
||||||
setStartConePosition(tubeStart);
|
|
||||||
setEndConePosition(tubeEnd);
|
|
||||||
setStartConeQuaternion(getArrowOrientation(start, end));
|
|
||||||
setEndConeQuaternion(getArrowOrientation(end, start));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const resetMeasurement = () => {
|
const onMouseUp = (evt: any) => {
|
||||||
|
isLeftMouseDown = false;
|
||||||
|
if (evt.button === 0 && !drag) {
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const intersects = raycaster
|
||||||
|
.intersectObjects(scene.children, true)
|
||||||
|
.filter(
|
||||||
|
(intersect) =>
|
||||||
|
!intersect.object.name.includes("Roof") &&
|
||||||
|
!intersect.object.name.includes("MeasurementReference") &&
|
||||||
|
!intersect.object.name.includes("agv-collider") &&
|
||||||
|
!(intersect.object.type === "GridHelper")
|
||||||
|
);
|
||||||
|
|
||||||
|
if (intersects.length > 0) {
|
||||||
|
const intersectionPoint = intersects[0].point.clone();
|
||||||
|
if (points.length < 2) {
|
||||||
|
setPoints([...points, intersectionPoint]);
|
||||||
|
} else {
|
||||||
|
setPoints([intersectionPoint]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMouseMove = () => {
|
||||||
|
if (isLeftMouseDown) drag = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onContextMenu = (evt: any) => {
|
||||||
|
evt.preventDefault();
|
||||||
|
if (!drag) {
|
||||||
|
evt.preventDefault();
|
||||||
|
setPoints([]);
|
||||||
setTubeGeometry(null);
|
setTubeGeometry(null);
|
||||||
setStartConePosition(null);
|
}
|
||||||
setEndConePosition(null);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getArrowOrientation = (start: THREE.Vector3, end: THREE.Vector3) => {
|
if (toolMode === "MeasurementScale") {
|
||||||
const direction = new THREE.Vector3().subVectors(end, start).normalize().negate();
|
canvasElement.addEventListener("pointerdown", onMouseDown);
|
||||||
const quaternion = new THREE.Quaternion();
|
canvasElement.addEventListener("pointermove", onMouseMove);
|
||||||
quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), direction);
|
canvasElement.addEventListener("pointerup", onMouseUp);
|
||||||
return quaternion;
|
canvasElement.addEventListener("contextmenu", onContextMenu);
|
||||||
|
} else {
|
||||||
|
resetMeasurement();
|
||||||
|
setPoints([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
canvasElement.removeEventListener("pointerdown", onMouseDown);
|
||||||
|
canvasElement.removeEventListener("pointermove", onMouseMove);
|
||||||
|
canvasElement.removeEventListener("pointerup", onMouseUp);
|
||||||
|
canvasElement.removeEventListener("contextmenu", onContextMenu);
|
||||||
};
|
};
|
||||||
|
}, [toolMode, camera, raycaster, pointer, scene, points]);
|
||||||
|
|
||||||
useEffect(() => {
|
useFrame(() => {
|
||||||
if (points.length === 2) {
|
if (points.length === 1) {
|
||||||
console.log(points[0].distanceTo(points[1]));
|
raycaster.setFromCamera(pointer, camera);
|
||||||
}
|
const intersects = raycaster
|
||||||
}, [points])
|
.intersectObjects(scene.children, true)
|
||||||
|
.filter(
|
||||||
|
(intersect) =>
|
||||||
|
!intersect.object.name.includes("Roof") &&
|
||||||
|
!intersect.object.name.includes("MeasurementReference") &&
|
||||||
|
!intersect.object.name.includes("agv-collider") &&
|
||||||
|
!(intersect.object.type === "GridHelper")
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
if (intersects.length > 0) {
|
||||||
<group ref={groupRef} name="MeasurementGroup">
|
updateMeasurement(points[0], intersects[0].point);
|
||||||
{startConePosition && (
|
}
|
||||||
<mesh name='MeasurementReference' position={startConePosition} quaternion={startConeQuaternion}>
|
} else if (points.length === 2) {
|
||||||
<coneGeometry args={[coneSize.radius, coneSize.height, 16]} />
|
updateMeasurement(points[0], points[1]);
|
||||||
<meshBasicMaterial color="yellow" />
|
} else {
|
||||||
</mesh>
|
resetMeasurement();
|
||||||
)}
|
}
|
||||||
{endConePosition && (
|
});
|
||||||
<mesh name='MeasurementReference' position={endConePosition} quaternion={endConeQuaternion}>
|
|
||||||
<coneGeometry args={[coneSize.radius, coneSize.height, 16]} />
|
|
||||||
<meshBasicMaterial color="yellow" />
|
|
||||||
</mesh>
|
|
||||||
)}
|
|
||||||
{tubeGeometry && (
|
|
||||||
<mesh name='MeasurementReference' geometry={tubeGeometry}>
|
|
||||||
<meshBasicMaterial color="yellow" />
|
|
||||||
</mesh>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{startConePosition && endConePosition && (
|
const updateMeasurement = (start: THREE.Vector3, end: THREE.Vector3) => {
|
||||||
<Html
|
const distance = start.distanceTo(end);
|
||||||
as="div"
|
|
||||||
center
|
const radius = THREE.MathUtils.clamp(
|
||||||
zIndexRange={[1, 0]}
|
distance * 0.02,
|
||||||
style={{
|
MIN_RADIUS,
|
||||||
padding: "10px",
|
MAX_RADIUS
|
||||||
color: "white",
|
);
|
||||||
borderRadius: "8px",
|
const coneRadius = THREE.MathUtils.clamp(
|
||||||
textAlign: "center",
|
distance * 0.05,
|
||||||
fontFamily: "Arial, sans-serif",
|
MIN_CONE_RADIUS,
|
||||||
}}
|
MAX_CONE_RADIUS
|
||||||
transform
|
);
|
||||||
sprite
|
const coneHeight = THREE.MathUtils.clamp(
|
||||||
scale={THREE.MathUtils.clamp(startConePosition.distanceTo(endConePosition) * 0.25, 0, 10)}
|
distance * 0.2,
|
||||||
position={[(startConePosition.x + endConePosition.x) / 2, (startConePosition.y + endConePosition.y) / 2, (startConePosition.z + endConePosition.z) / 2]}
|
MIN_CONE_HEIGHT,
|
||||||
>
|
MAX_CONE_HEIGHT
|
||||||
<div style={{ color: "black" }} >{startConePosition.distanceTo(endConePosition).toFixed(2)} m</div>
|
|
||||||
</Html>
|
|
||||||
)}
|
|
||||||
</group>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
setConeSize({ radius: coneRadius, height: coneHeight });
|
||||||
|
|
||||||
|
const direction = new THREE.Vector3().subVectors(end, start).normalize();
|
||||||
|
|
||||||
|
const offset = direction.clone().multiplyScalar(coneHeight * 0.5);
|
||||||
|
|
||||||
|
let tubeStart = start.clone().add(offset);
|
||||||
|
let tubeEnd = end.clone().sub(offset);
|
||||||
|
|
||||||
|
tubeStart.y = Math.max(tubeStart.y, 0);
|
||||||
|
tubeEnd.y = Math.max(tubeEnd.y, 0);
|
||||||
|
|
||||||
|
const curve = new THREE.CatmullRomCurve3([tubeStart, tubeEnd]);
|
||||||
|
setTubeGeometry(new THREE.TubeGeometry(curve, 20, radius, 8, false));
|
||||||
|
|
||||||
|
setStartConePosition(tubeStart);
|
||||||
|
setEndConePosition(tubeEnd);
|
||||||
|
setStartConeQuaternion(getArrowOrientation(start, end));
|
||||||
|
setEndConeQuaternion(getArrowOrientation(end, start));
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetMeasurement = () => {
|
||||||
|
setTubeGeometry(null);
|
||||||
|
setStartConePosition(null);
|
||||||
|
setEndConePosition(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getArrowOrientation = (start: THREE.Vector3, end: THREE.Vector3) => {
|
||||||
|
const direction = new THREE.Vector3()
|
||||||
|
.subVectors(end, start)
|
||||||
|
.normalize()
|
||||||
|
.negate();
|
||||||
|
const quaternion = new THREE.Quaternion();
|
||||||
|
quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), direction);
|
||||||
|
return quaternion;
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (points.length === 2) {
|
||||||
|
console.log(points[0].distanceTo(points[1]));
|
||||||
|
}
|
||||||
|
}, [points]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group ref={groupRef} name="MeasurementGroup">
|
||||||
|
{startConePosition && (
|
||||||
|
<mesh
|
||||||
|
name="MeasurementReference"
|
||||||
|
position={startConePosition}
|
||||||
|
quaternion={startConeQuaternion}
|
||||||
|
>
|
||||||
|
<coneGeometry args={[coneSize.radius, coneSize.height, 16]} />
|
||||||
|
<meshBasicMaterial color="yellow" />
|
||||||
|
</mesh>
|
||||||
|
)}
|
||||||
|
{endConePosition && (
|
||||||
|
<mesh
|
||||||
|
name="MeasurementReference"
|
||||||
|
position={endConePosition}
|
||||||
|
quaternion={endConeQuaternion}
|
||||||
|
>
|
||||||
|
<coneGeometry args={[coneSize.radius, coneSize.height, 16]} />
|
||||||
|
<meshBasicMaterial color="yellow" />
|
||||||
|
</mesh>
|
||||||
|
)}
|
||||||
|
{tubeGeometry && (
|
||||||
|
<mesh name="MeasurementReference" geometry={tubeGeometry}>
|
||||||
|
<meshBasicMaterial color="yellow" />
|
||||||
|
</mesh>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{startConePosition && endConePosition && (
|
||||||
|
<Html
|
||||||
|
scale={THREE.MathUtils.clamp(
|
||||||
|
startConePosition.distanceTo(endConePosition) * 0.25,
|
||||||
|
0,
|
||||||
|
10
|
||||||
|
)}
|
||||||
|
position={[
|
||||||
|
(startConePosition.x + endConePosition.x) / 2,
|
||||||
|
(startConePosition.y + endConePosition.y) / 2,
|
||||||
|
(startConePosition.z + endConePosition.z) / 2,
|
||||||
|
]}
|
||||||
|
// class
|
||||||
|
wrapperClass="distance-text-wrapper"
|
||||||
|
className="distance-text"
|
||||||
|
// other
|
||||||
|
zIndexRange={[1, 0]}
|
||||||
|
prepend
|
||||||
|
sprite
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
{startConePosition.distanceTo(endConePosition).toFixed(2)} m
|
||||||
|
</div>
|
||||||
|
</Html>
|
||||||
|
)}
|
||||||
|
</group>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MeasurementTool;
|
export default MeasurementTool;
|
||||||
|
|
|
@ -6,8 +6,8 @@ import { useThree, useFrame } from "@react-three/fiber";
|
||||||
|
|
||||||
////////// Component Imports //////////
|
////////// Component Imports //////////
|
||||||
|
|
||||||
import DistanceText from "../../builder/geomentries/lines/distanceText";
|
import DistanceText from "../../builder/geomentries/lines/distanceText/distanceText";
|
||||||
import ReferenceDistanceText from "../../builder/geomentries/lines/referenceDistanceText";
|
import ReferenceDistanceText from "../../builder/geomentries/lines/distanceText/referenceDistanceText";
|
||||||
|
|
||||||
////////// Assests Imports //////////
|
////////// Assests Imports //////////
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ export const handleSaveTemplate = async ({
|
||||||
templates = [],
|
templates = [],
|
||||||
visualizationSocket,
|
visualizationSocket,
|
||||||
}: HandleSaveTemplateProps): Promise<void> => {
|
}: HandleSaveTemplateProps): Promise<void> => {
|
||||||
|
console.log('floatingWidget: ', floatingWidget);
|
||||||
try {
|
try {
|
||||||
// Check if the selected zone has any widgets
|
// Check if the selected zone has any widgets
|
||||||
if (!selectedZone.panelOrder || selectedZone.panelOrder.length === 0) {
|
if (!selectedZone.panelOrder || selectedZone.panelOrder.length === 0) {
|
||||||
|
|
|
@ -15,22 +15,19 @@ type WidgetData = {
|
||||||
|
|
||||||
export default function SocketRealTimeViz() {
|
export default function SocketRealTimeViz() {
|
||||||
const { visualizationSocket } = useSocketStore();
|
const { visualizationSocket } = useSocketStore();
|
||||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
const { setSelectedZone } = useSelectedZoneStore();
|
||||||
const deleteObject = useDroppedObjectsStore((state) => state.deleteObject);
|
const deleteObject = useDroppedObjectsStore((state) => state.deleteObject);
|
||||||
const duplicateObject = useDroppedObjectsStore((state) => state.duplicateObject);
|
|
||||||
const updateObjectPosition = useDroppedObjectsStore((state) => state.updateObjectPosition);
|
const updateObjectPosition = useDroppedObjectsStore((state) => state.updateObjectPosition);
|
||||||
const { addWidget } = useZoneWidgetStore()
|
const { addWidget } = useZoneWidgetStore()
|
||||||
const { templates, removeTemplate } = useTemplateStore();
|
const { removeTemplate } = useTemplateStore();
|
||||||
const { setTemplates } = useTemplateStore();
|
const { setTemplates } = useTemplateStore();
|
||||||
const { zoneWidgetData, setZoneWidgetData, updateWidgetPosition, updateWidgetRotation } = useZoneWidgetStore();
|
const { zoneWidgetData, setZoneWidgetData, updateWidgetPosition, updateWidgetRotation } = useZoneWidgetStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const email = localStorage.getItem("email") || "";
|
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
|
||||||
if (visualizationSocket) {
|
if (visualizationSocket) {
|
||||||
//add panel response
|
//add panel response
|
||||||
visualizationSocket.on("viz-panel:response:updates", (addPanel: any) => {
|
visualizationSocket.on("viz-panel:response:updates", (addPanel: any) => {
|
||||||
console.log('addPanel: ', addPanel);
|
|
||||||
if (addPanel.success) {
|
if (addPanel.success) {
|
||||||
let addPanelData = addPanel.data.data
|
let addPanelData = addPanel.data.data
|
||||||
setSelectedZone(addPanelData)
|
setSelectedZone(addPanelData)
|
||||||
|
@ -38,15 +35,33 @@ export default function SocketRealTimeViz() {
|
||||||
})
|
})
|
||||||
//delete panel response
|
//delete panel response
|
||||||
visualizationSocket.on("viz-panel:response:delete", (deletePanel: any) => {
|
visualizationSocket.on("viz-panel:response:delete", (deletePanel: any) => {
|
||||||
console.log('deletePanel: ', deletePanel);
|
|
||||||
if (deletePanel.success) {
|
if (deletePanel.success) {
|
||||||
let deletePanelData = deletePanel.data.data
|
let deletePanelData = deletePanel.data.data
|
||||||
setSelectedZone(deletePanelData)
|
setSelectedZone(deletePanelData)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
//clear Panel response
|
||||||
|
visualizationSocket.on("viz-panel:response:clear", (clearPanel: any) => {
|
||||||
|
|
||||||
|
if (clearPanel.success && clearPanel.message === "PanelWidgets cleared successfully") {
|
||||||
|
|
||||||
|
let clearPanelData = clearPanel.data.data
|
||||||
|
setSelectedZone(clearPanelData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//lock Panel response
|
||||||
|
visualizationSocket.on("viz-panel:response:locked", (lockPanel: any) => {
|
||||||
|
|
||||||
|
if (lockPanel.success && lockPanel.message === "locked panel updated successfully") {
|
||||||
|
|
||||||
|
let lockPanelData = lockPanel.data.data
|
||||||
|
setSelectedZone(lockPanelData)
|
||||||
|
}
|
||||||
|
})
|
||||||
// add 2dWidget response
|
// add 2dWidget response
|
||||||
visualizationSocket.on("viz-widget:response:updates", (add2dWidget: any) => {
|
visualizationSocket.on("viz-widget:response:updates", (add2dWidget: any) => {
|
||||||
console.log('add2dWidget: ', add2dWidget);
|
|
||||||
|
|
||||||
if (add2dWidget.success && add2dWidget.data) {
|
if (add2dWidget.success && add2dWidget.data) {
|
||||||
setSelectedZone((prev) => {
|
setSelectedZone((prev) => {
|
||||||
|
@ -65,7 +80,7 @@ export default function SocketRealTimeViz() {
|
||||||
});
|
});
|
||||||
//delete 2D Widget response
|
//delete 2D Widget response
|
||||||
visualizationSocket.on("viz-widget:response:delete", (deleteWidget: any) => {
|
visualizationSocket.on("viz-widget:response:delete", (deleteWidget: any) => {
|
||||||
console.log('deleteWidget: ', deleteWidget);
|
|
||||||
|
|
||||||
if (deleteWidget?.success && deleteWidget.data) {
|
if (deleteWidget?.success && deleteWidget.data) {
|
||||||
setSelectedZone((prevZone: any) => ({
|
setSelectedZone((prevZone: any) => ({
|
||||||
|
@ -78,7 +93,7 @@ export default function SocketRealTimeViz() {
|
||||||
});
|
});
|
||||||
//add Floating Widget response
|
//add Floating Widget response
|
||||||
visualizationSocket.on("viz-float:response:updates", (addFloatingWidget: any) => {
|
visualizationSocket.on("viz-float:response:updates", (addFloatingWidget: any) => {
|
||||||
console.log('addFloatingWidget: ', addFloatingWidget);
|
|
||||||
|
|
||||||
if (addFloatingWidget.success) {
|
if (addFloatingWidget.success) {
|
||||||
if (addFloatingWidget.success && addFloatingWidget.message === "FloatWidget created successfully") {
|
if (addFloatingWidget.success && addFloatingWidget.message === "FloatWidget created successfully") {
|
||||||
|
@ -105,7 +120,7 @@ export default function SocketRealTimeViz() {
|
||||||
});
|
});
|
||||||
//duplicate Floating Widget response
|
//duplicate Floating Widget response
|
||||||
visualizationSocket.on("viz-float:response:addDuplicate", (duplicateFloatingWidget: any) => {
|
visualizationSocket.on("viz-float:response:addDuplicate", (duplicateFloatingWidget: any) => {
|
||||||
console.log('duplicateFloatingWidget: ', duplicateFloatingWidget);
|
|
||||||
|
|
||||||
if (duplicateFloatingWidget.success && duplicateFloatingWidget.message === "duplicate FloatWidget created successfully") {
|
if (duplicateFloatingWidget.success && duplicateFloatingWidget.message === "duplicate FloatWidget created successfully") {
|
||||||
useDroppedObjectsStore.setState((state) => {
|
useDroppedObjectsStore.setState((state) => {
|
||||||
|
@ -133,7 +148,7 @@ export default function SocketRealTimeViz() {
|
||||||
});
|
});
|
||||||
//delete Floating Widget response
|
//delete Floating Widget response
|
||||||
visualizationSocket.on("viz-float:response:delete", (deleteFloatingWidget: any) => {
|
visualizationSocket.on("viz-float:response:delete", (deleteFloatingWidget: any) => {
|
||||||
console.log('deleteFloatingWidget: ', deleteFloatingWidget);
|
|
||||||
|
|
||||||
if (deleteFloatingWidget.success) {
|
if (deleteFloatingWidget.success) {
|
||||||
deleteObject(deleteFloatingWidget.data.zoneName, deleteFloatingWidget.data.floatWidgetID);
|
deleteObject(deleteFloatingWidget.data.zoneName, deleteFloatingWidget.data.floatWidgetID);
|
||||||
|
@ -142,9 +157,9 @@ export default function SocketRealTimeViz() {
|
||||||
//add 3D Widget response
|
//add 3D Widget response
|
||||||
visualizationSocket.on("viz-widget3D:response:updates", (add3DWidget: any) => {
|
visualizationSocket.on("viz-widget3D:response:updates", (add3DWidget: any) => {
|
||||||
|
|
||||||
console.log('add3DWidget: ', add3DWidget);
|
|
||||||
if (add3DWidget.success) {
|
if (add3DWidget.success) {
|
||||||
console.log('add3DWidget: ', add3DWidget);
|
|
||||||
if (add3DWidget.message === "Widget created successfully") {
|
if (add3DWidget.message === "Widget created successfully") {
|
||||||
addWidget(add3DWidget.data.zoneId, add3DWidget.data.widget);
|
addWidget(add3DWidget.data.zoneId, add3DWidget.data.widget);
|
||||||
}
|
}
|
||||||
|
@ -152,7 +167,7 @@ export default function SocketRealTimeViz() {
|
||||||
});
|
});
|
||||||
//delete 3D Widget response
|
//delete 3D Widget response
|
||||||
visualizationSocket.on("viz-widget3D:response:delete", (delete3DWidget: any) => {
|
visualizationSocket.on("viz-widget3D:response:delete", (delete3DWidget: any) => {
|
||||||
console.log('delete3DWidget: ', delete3DWidget);
|
|
||||||
// "3DWidget delete unsuccessfull"
|
// "3DWidget delete unsuccessfull"
|
||||||
if (delete3DWidget.success && delete3DWidget.message === "3DWidget delete successfull") {
|
if (delete3DWidget.success && delete3DWidget.message === "3DWidget delete successfull") {
|
||||||
const activeZoneWidgets = zoneWidgetData[delete3DWidget.data.zoneId] || [];
|
const activeZoneWidgets = zoneWidgetData[delete3DWidget.data.zoneId] || [];
|
||||||
|
@ -164,16 +179,16 @@ export default function SocketRealTimeViz() {
|
||||||
});
|
});
|
||||||
//update3D widget response
|
//update3D widget response
|
||||||
visualizationSocket.on("viz-widget3D:response:modifyPositionRotation", (update3DWidget: any) => {
|
visualizationSocket.on("viz-widget3D:response:modifyPositionRotation", (update3DWidget: any) => {
|
||||||
console.log('update3DWidget: ', update3DWidget);
|
|
||||||
|
|
||||||
if (update3DWidget.success && update3DWidget.message==="widget update successfully") {
|
|
||||||
|
if (update3DWidget.success && update3DWidget.message === "widget update successfully") {
|
||||||
updateWidgetPosition(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.position);
|
updateWidgetPosition(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.position);
|
||||||
updateWidgetRotation(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.rotation);
|
updateWidgetRotation(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.rotation);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// add Template response
|
// add Template response
|
||||||
visualizationSocket.on("viz-template:response:add", (addingTemplate: any) => {
|
visualizationSocket.on("viz-template:response:add", (addingTemplate: any) => {
|
||||||
console.log('addingTemplate: ', addingTemplate);
|
|
||||||
|
|
||||||
if (addingTemplate.success) {
|
if (addingTemplate.success) {
|
||||||
if (addingTemplate.message === "Template saved successfully") {
|
if (addingTemplate.message === "Template saved successfully") {
|
||||||
|
@ -183,7 +198,7 @@ export default function SocketRealTimeViz() {
|
||||||
});
|
});
|
||||||
//load Template response
|
//load Template response
|
||||||
visualizationSocket.on("viz-template:response:addTemplateZone", (loadTemplate: any) => {
|
visualizationSocket.on("viz-template:response:addTemplateZone", (loadTemplate: any) => {
|
||||||
console.log('loadTemplate: ', loadTemplate);
|
|
||||||
|
|
||||||
if (loadTemplate.success) {
|
if (loadTemplate.success) {
|
||||||
if (loadTemplate.message === "Template placed in Zone") {
|
if (loadTemplate.message === "Template placed in Zone") {
|
||||||
|
@ -206,14 +221,12 @@ export default function SocketRealTimeViz() {
|
||||||
});
|
});
|
||||||
//delete Template response
|
//delete Template response
|
||||||
visualizationSocket.on("viz-template:response:delete", (deleteTemplate: any) => {
|
visualizationSocket.on("viz-template:response:delete", (deleteTemplate: any) => {
|
||||||
console.log('deleteTemplate: ', deleteTemplate);
|
|
||||||
|
|
||||||
if (deleteTemplate.success) {
|
if (deleteTemplate.success) {
|
||||||
if (deleteTemplate.message === 'Template deleted successfully') {
|
if (deleteTemplate.message === 'Template deleted successfully') {
|
||||||
removeTemplate(deleteTemplate.data);
|
removeTemplate(deleteTemplate.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,17 +22,17 @@ import LoadingPage from "../components/templates/LoadingPage";
|
||||||
import SimulationPlayer from "../components/ui/simulation/simulationPlayer";
|
import SimulationPlayer from "../components/ui/simulation/simulationPlayer";
|
||||||
import RenderOverlay from "../components/templates/Overlay";
|
import RenderOverlay from "../components/templates/Overlay";
|
||||||
import MenuBar from "../components/ui/menu/menu";
|
import MenuBar from "../components/ui/menu/menu";
|
||||||
|
import KeyPressListener from "../utils/shortcutkeys/handleShortcutKeys";
|
||||||
|
|
||||||
const Project: React.FC = () => {
|
const Project: React.FC = () => {
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { loadingProgress, setLoadingProgress } = useLoadingProgress();
|
const { loadingProgress } = useLoadingProgress();
|
||||||
const { setUserName } = useUserName();
|
const { setUserName } = useUserName();
|
||||||
const { setOrganization } = useOrganization();
|
const { setOrganization } = useOrganization();
|
||||||
const { setFloorItems } = useFloorItems();
|
const { setFloorItems } = useFloorItems();
|
||||||
const { setWallItems } = useWallItems();
|
const { setWallItems } = useWallItems();
|
||||||
const { setZones } = useZones();
|
const { setZones } = useZones();
|
||||||
const [openMenu, setOpenMenu] = useState<boolean>(true);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFloorItems([]);
|
setFloorItems([]);
|
||||||
|
@ -56,6 +56,7 @@ const Project: React.FC = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="project-main">
|
<div className="project-main">
|
||||||
|
<KeyPressListener />
|
||||||
{loadingProgress && <LoadingPage progress={loadingProgress} />}
|
{loadingProgress && <LoadingPage progress={loadingProgress} />}
|
||||||
{!isPlaying && (
|
{!isPlaying && (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
|
||||||
|
|
||||||
export const getFloorAssets = async (organization: string) => {
|
export const getFloorAssets = async (organization: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${url_Backend_dwinzo}/api/v2/floorAssets/${organization}`, {
|
const response = await fetch(`${url_Backend_dwinzo}/api/v2/floorAssets/${organization}`, {
|
||||||
|
@ -14,6 +15,7 @@ export const getFloorAssets = async (organization: string) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
|
||||||
export const setFloorItemApi = async (
|
export const setFloorItemApi = async (
|
||||||
organization: string,
|
organization: string,
|
||||||
modeluuid: string,
|
modeluuid?: string,
|
||||||
modelname: string,
|
modelname?: string,
|
||||||
modelfileID: string,
|
modelfileID?: string,
|
||||||
position: Object,
|
position?: Object,
|
||||||
rotation: Object,
|
rotation?: Object,
|
||||||
isLocked: boolean,
|
isLocked?: boolean,
|
||||||
isVisible: boolean,
|
isVisible?: boolean,
|
||||||
eventData?: any
|
eventData?: any
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
// let url_Backend_dwinzo = `http://192.168.0.102:5000`;
|
||||||
|
|
||||||
export const getZonesApi = async (organization: string) => {
|
export const getZonesApi = async (organization: string) => {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
let url_Backend_dwinzo = `http://192.168.0.102:5000`;
|
||||||
|
export const clearPanel = async (
|
||||||
|
zoneId: string,
|
||||||
|
organization: string,
|
||||||
|
panelName: string
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${url_Backend_dwinzo}/api/v2/clearpanel`, {
|
||||||
|
method: "PATCH",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ organization, zoneId, panelName }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to clearPanel in the zone");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(error.message);
|
||||||
|
} else {
|
||||||
|
throw new Error("An unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
// let url_Backend_dwinzo = `http://192.168.0.102:5000`;
|
||||||
|
export const lockPanel = async (
|
||||||
|
zoneId: string,
|
||||||
|
organization: string,
|
||||||
|
lockedPanel: any
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${url_Backend_dwinzo}/api/v2/zones/lockedPanels`, {
|
||||||
|
method: "PATCH",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ organization, zoneId, lockedPanel }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to Lock Panel in the zone");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(error.message);
|
||||||
|
} else {
|
||||||
|
throw new Error("An unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -9,20 +9,16 @@ export const update3dWidget = async (
|
||||||
console.log("organization: ", organization);
|
console.log("organization: ", organization);
|
||||||
console.log("zoneId: ", zoneId);
|
console.log("zoneId: ", zoneId);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(`${url_Backend_dwinzo}/api/v2/modifyPR/widget3D`, {
|
||||||
`${url_Backend_dwinzo}/api/v2/modifyPR/widget3D`,
|
method: "PATCH",
|
||||||
{
|
headers: { "Content-Type": "application/json", },
|
||||||
method: "PATCH",
|
body: JSON.stringify({
|
||||||
headers: {
|
organization,
|
||||||
"Content-Type": "application/json",
|
zoneId,
|
||||||
},
|
id,
|
||||||
body: JSON.stringify({
|
position,
|
||||||
organization,
|
}),
|
||||||
zoneId,
|
}
|
||||||
id,
|
|
||||||
position,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|
|
@ -252,6 +252,11 @@ export const useActiveTool = create<any>((set: any) => ({
|
||||||
setActiveTool: (x: any) => set({ activeTool: x }),
|
setActiveTool: (x: any) => set({ activeTool: x }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
export const useActiveSubTool = create<any>((set: any) => ({
|
||||||
|
activeSubTool: "cursor",
|
||||||
|
setActiveSubTool: (x: any) => set({ activeSubTool: x }),
|
||||||
|
}));
|
||||||
|
|
||||||
export const use2DUndoRedo = create<any>((set: any) => ({
|
export const use2DUndoRedo = create<any>((set: any) => ({
|
||||||
is2DUndoRedo: null,
|
is2DUndoRedo: null,
|
||||||
set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }),
|
set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }),
|
||||||
|
|
|
@ -146,5 +146,6 @@
|
||||||
font-size: var(--font-size-regulaar);
|
font-size: var(--font-size-regulaar);
|
||||||
font-weight: var(--font-size-regulaar);
|
font-weight: var(--font-size-regulaar);
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,16 +68,15 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 10px;
|
bottom: 0px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
max-width: 80%;
|
max-width: 80%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
max-width: calc(100% - 500px);
|
max-width: calc(100% - 500px);
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
transform: translate(-50%, -100%);
|
transform: translate(-50%, -10%);
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
}
|
}
|
||||||
.distance-text {
|
.distance-text {
|
||||||
pointer-events: none !important;
|
pointer-events: none !important;
|
||||||
.distance {
|
div {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
transform: translate(-50%, -50%) scale(.8);
|
transform: translate(-50%, -50%) scale(0.8);
|
||||||
pointer-events: none !important;
|
pointer-events: none !important;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
// style
|
// style
|
||||||
|
@ -22,6 +22,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.pointer-none{
|
.pointer-none {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,187 @@
|
||||||
|
// Importing React and useEffect from React library
|
||||||
|
import React, { useEffect } from "react";
|
||||||
|
// Importing the necessary hooks and types from React and TypeScript
|
||||||
|
import useModuleStore, { useThreeDStore } from "../../store/useModuleStore";
|
||||||
|
import useToggleStore from "../../store/useUIToggleStore";
|
||||||
|
import { useActiveSubTool, useActiveTool, useAddAction, useDeleteTool, useSelectedWallItem, useToggleView, useToolMode } from "../../store/store";
|
||||||
|
import { usePlayButtonStore } from "../../store/usePlayButtonStore";
|
||||||
|
|
||||||
|
const KeyPressListener: React.FC = () => {
|
||||||
|
// Function to detect if Shift, Ctrl, Alt, or combinations are pressed
|
||||||
|
const detectModifierKeys = (event: KeyboardEvent): string => {
|
||||||
|
const modifiers = [
|
||||||
|
event.ctrlKey ? "Ctrl" : "",
|
||||||
|
event.altKey ? "Alt" : "",
|
||||||
|
event.shiftKey ? "Shift" : "",
|
||||||
|
event.metaKey ? "Meta" : "" // Add support for Command/Win key
|
||||||
|
].filter(Boolean);
|
||||||
|
|
||||||
|
// Ignore modifier keys when they're pressed alone
|
||||||
|
const isModifierKey = [
|
||||||
|
"Control", "Shift", "Alt", "Meta",
|
||||||
|
"Ctrl", "AltGraph", "OS" // Additional modifier key aliases
|
||||||
|
].includes(event.key);
|
||||||
|
|
||||||
|
const mainKey = isModifierKey ? "" : event.key.toUpperCase();
|
||||||
|
|
||||||
|
// Handle special cases for keys with different representations
|
||||||
|
const normalizedKey = mainKey === " " ? "Space" : mainKey;
|
||||||
|
|
||||||
|
// Build the combination string
|
||||||
|
if (modifiers.length > 0 && normalizedKey) {
|
||||||
|
return `${modifiers.join("+")}+${normalizedKey}`;
|
||||||
|
} else if (modifiers.length > 0) {
|
||||||
|
return modifiers.join("+");
|
||||||
|
} else {
|
||||||
|
return normalizedKey;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Importing the necessary hooks from the store
|
||||||
|
const { activeModule, setActiveModule } = useModuleStore();
|
||||||
|
const { setActiveSubTool } = useActiveSubTool();
|
||||||
|
const { toggleUI, setToggleUI } = useToggleStore();
|
||||||
|
const { setToggleThreeD } = useThreeDStore();
|
||||||
|
const { setToolMode } = useToolMode();
|
||||||
|
const { setIsPlaying } = usePlayButtonStore();
|
||||||
|
|
||||||
|
// wall options
|
||||||
|
const { toggleView, setToggleView } = useToggleView();
|
||||||
|
const { setDeleteTool } = useDeleteTool();
|
||||||
|
const { setAddAction } = useAddAction();
|
||||||
|
const { setSelectedWallItem } = useSelectedWallItem();
|
||||||
|
const { setActiveTool } = useActiveTool();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Function to handle keydown events
|
||||||
|
const handleKeyPress = (event: KeyboardEvent) => {
|
||||||
|
// Allow default behavior for F5 and F12
|
||||||
|
const keyCombination = detectModifierKeys(event);
|
||||||
|
|
||||||
|
if (["F5", "F11", "F12"].includes(event.key) || keyCombination === "Ctrl+R") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent default action for the key press
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
// Detect the key combination pressed
|
||||||
|
if (keyCombination) {
|
||||||
|
// Check for specific key combinations to switch modules
|
||||||
|
if (keyCombination === "1" && !toggleView) {
|
||||||
|
setActiveTool("cursor");
|
||||||
|
setActiveSubTool("cursor");
|
||||||
|
setActiveModule("builder");
|
||||||
|
}
|
||||||
|
if (keyCombination === "2" && !toggleView) {
|
||||||
|
setActiveTool("cursor");
|
||||||
|
setActiveSubTool("cursor");
|
||||||
|
setActiveModule("simulation");
|
||||||
|
}
|
||||||
|
if (keyCombination === "3" && !toggleView) {
|
||||||
|
setActiveTool("cursor");
|
||||||
|
setActiveSubTool("cursor");
|
||||||
|
setActiveModule("visualization");
|
||||||
|
}
|
||||||
|
if (keyCombination === "4" && !toggleView) {
|
||||||
|
setActiveTool("cursor");
|
||||||
|
setActiveSubTool("cursor");
|
||||||
|
setToggleUI(false);
|
||||||
|
setActiveModule("market");
|
||||||
|
}
|
||||||
|
|
||||||
|
// sidebar toggle
|
||||||
|
if (keyCombination === "Ctrl+." && activeModule !== "market") {
|
||||||
|
setToggleUI(!toggleUI);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tools toggle
|
||||||
|
if (keyCombination === "V") {
|
||||||
|
setActiveTool("cursor");
|
||||||
|
setActiveSubTool("cursor");
|
||||||
|
}
|
||||||
|
if (keyCombination === "X") {
|
||||||
|
setActiveTool("delete");
|
||||||
|
setActiveSubTool("delete");
|
||||||
|
}
|
||||||
|
if (keyCombination === "H") {
|
||||||
|
setActiveTool("free-hand");
|
||||||
|
setActiveSubTool("free-hand");
|
||||||
|
}
|
||||||
|
|
||||||
|
// player toggle
|
||||||
|
if (keyCombination === "Ctrl+P" && !toggleView) {
|
||||||
|
setIsPlaying(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// builder key combination
|
||||||
|
if (activeModule === "builder") {
|
||||||
|
if (keyCombination === "TAB") {
|
||||||
|
if (toggleView) {
|
||||||
|
setToggleView(false);
|
||||||
|
setToggleThreeD(true);
|
||||||
|
setActiveTool("cursor");
|
||||||
|
} else {
|
||||||
|
setSelectedWallItem(null);
|
||||||
|
setDeleteTool(false);
|
||||||
|
setAddAction(null);
|
||||||
|
setToggleView(true);
|
||||||
|
setToggleThreeD(false);
|
||||||
|
setActiveTool("cursor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// builder tools
|
||||||
|
if (toggleView) {
|
||||||
|
if (keyCombination === "Q" || keyCombination === "6") {
|
||||||
|
setActiveTool("draw-wall");
|
||||||
|
setToolMode("Wall");
|
||||||
|
}
|
||||||
|
if (keyCombination === "R" || keyCombination === "7") {
|
||||||
|
setActiveTool("draw-aisle");
|
||||||
|
setToolMode("Aisle");
|
||||||
|
}
|
||||||
|
if (keyCombination === "E" || keyCombination === "8") {
|
||||||
|
setActiveTool("draw-zone");
|
||||||
|
setToolMode("Zone");
|
||||||
|
}
|
||||||
|
if (keyCombination === "T" || keyCombination === "9") {
|
||||||
|
setActiveTool("draw-floor");
|
||||||
|
setToolMode("Floor");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (keyCombination === "M") {
|
||||||
|
setActiveTool("measure");
|
||||||
|
setToolMode("MeasurementScale");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Undo redo
|
||||||
|
if (keyCombination === "Ctrl+Z") {
|
||||||
|
// Handle undo action here
|
||||||
|
}
|
||||||
|
if (keyCombination === "Ctrl+Y" || keyCombination === "Ctrl+Shift+Z") {
|
||||||
|
// Handle redo action here
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup function to remove event listener
|
||||||
|
if (keyCombination === "ESCAPE") {
|
||||||
|
setActiveTool("cursor");
|
||||||
|
setIsPlaying(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add event listener for keydown
|
||||||
|
window.addEventListener("keydown", handleKeyPress);
|
||||||
|
|
||||||
|
// Cleanup function to remove event listener
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("keydown", handleKeyPress);
|
||||||
|
};
|
||||||
|
}, [activeModule, toggleUI, toggleView]); // Empty dependency array ensures this runs only once
|
||||||
|
|
||||||
|
return null; // No UI component to render, so return null
|
||||||
|
};
|
||||||
|
|
||||||
|
export default KeyPressListener;
|
Loading…
Reference in New Issue