Merge branch 'main' into realTimeVisulization

This commit is contained in:
Gomathi 2025-03-26 12:32:04 +05:30
commit 5cc3b83e43
17 changed files with 1025 additions and 20881 deletions

58
app/.gitignore vendored
View File

@ -1,29 +1,29 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies # dependencies
/node_modules /node_modules
/package-lock.json /package-lock.json
/.pnp /.pnp
.pnp.js .pnp.js
# testing # testing
/coverage /coverage
# production # production
/build /build
# misc # misc
.DS_Store .DS_Store
.env.local .env.local
.env.development.local .env.development.local
.env.test.local .env.test.local
.env.production.local .env.production.local
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
# remove zip # remove zip
*.zip *.zip
**/temp/ **/temp/

20174
app/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -107,7 +107,7 @@ export function StockIncreseIcon() {
fill="none" fill="none"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
> >
<g clip-path="url(#clip0_3050_69519)"> <g clipPath="url(#clip0_3050_69519)">
<path <path
d="M7.80766 6.99219H1.17811C0.752382 6.99219 0.407227 7.33734 0.407227 7.76307C0.407227 8.18879 0.752382 8.53395 1.17811 8.53395H7.80766C8.23339 8.53395 8.57854 8.18879 8.57854 7.76307C8.57854 7.33733 8.23339 6.99219 7.80766 6.99219Z" d="M7.80766 6.99219H1.17811C0.752382 6.99219 0.407227 7.33734 0.407227 7.76307C0.407227 8.18879 0.752382 8.53395 1.17811 8.53395H7.80766C8.23339 8.53395 8.57854 8.18879 8.57854 7.76307C8.57854 7.33733 8.23339 6.99219 7.80766 6.99219Z"
fill="white" fill="white"
@ -142,8 +142,8 @@ export function StockIncreseIcon() {
y2="8.53122" y2="8.53122"
gradientUnits="userSpaceOnUse" gradientUnits="userSpaceOnUse"
> >
<stop stop-color="#31B2B9" /> <stop stopColor="#31B2B9" />
<stop offset="1" stop-color="#FBD8B8" /> <stop offset="1" stopColor="#FBD8B8" />
</linearGradient> </linearGradient>
<clipPath id="clip0_3050_69519"> <clipPath id="clip0_3050_69519">
<rect <rect

View File

@ -3,9 +3,12 @@ import { ToggleSidebarIcon } from "../../icons/HeaderIcons";
import { LogoIcon } from "../../icons/Logo"; import { LogoIcon } from "../../icons/Logo";
import FileMenu from "../../ui/FileMenu"; import FileMenu from "../../ui/FileMenu";
import useToggleStore from "../../../store/useUIToggleStore"; import useToggleStore from "../../../store/useUIToggleStore";
import useModuleStore from "../../../store/useModuleStore";
const Header: React.FC = () => { const Header: React.FC = () => {
const { toggleUI, setToggleUI } = useToggleStore(); const { toggleUI, setToggleUI } = useToggleStore();
const { activeModule } = useModuleStore();
return ( return (
<div className="header-container"> <div className="header-container">
<div className="header-content"> <div className="header-content">
@ -19,7 +22,7 @@ const Header: React.FC = () => {
<div <div
className={`toggle-sidebar-ui-button ${!toggleUI ? "active" : ""}`} className={`toggle-sidebar-ui-button ${!toggleUI ? "active" : ""}`}
onClick={() => { onClick={() => {
setToggleUI(!toggleUI); if (activeModule !== "market") setToggleUI(!toggleUI);
}} }}
> >
<ToggleSidebarIcon /> <ToggleSidebarIcon />

View File

@ -1,6 +1,8 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Header from "./Header"; import Header from "./Header";
import useModuleStore, { useSubModuleStore } from "../../../store/useModuleStore"; import useModuleStore, {
useSubModuleStore,
} from "../../../store/useModuleStore";
import { import {
AnalysisIcon, AnalysisIcon,
MechanicsIcon, MechanicsIcon,
@ -15,6 +17,7 @@ import AsstePropertiies from "./properties/AssetProperties";
import Analysis from "./analysis/Analysis"; import Analysis from "./analysis/Analysis";
import Simulations from "./simulation/Simulations"; import Simulations from "./simulation/Simulations";
import { useSelectedActionSphere } from "../../../store/store"; import { useSelectedActionSphere } from "../../../store/store";
import ZoneProperties from "./properties/ZoneProperties";
const SideBarRight: React.FC = () => { const SideBarRight: React.FC = () => {
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
@ -24,7 +27,8 @@ const SideBarRight: React.FC = () => {
// Reset subModule whenever activeModule changes // Reset subModule whenever activeModule changes
useEffect(() => { useEffect(() => {
setSubModule("properties"); if (activeModule !== "simulation") setSubModule("properties");
if (activeModule === "simulation") setSubModule("mechanics");
}, [activeModule]); }, [activeModule]);
return ( return (
@ -32,32 +36,38 @@ const SideBarRight: React.FC = () => {
<Header /> <Header />
{toggleUI && ( {toggleUI && (
<div className="sidebar-actions-container"> <div className="sidebar-actions-container">
<div {/* {activeModule === "builder" && ( */}
className={`sidebar-action-list ${subModule === "properties" ? "active" : "" <div
className={`sidebar-action-list ${
subModule === "properties" ? "active" : ""
}`} }`}
onClick={() => setSubModule("properties")} onClick={() => setSubModule("properties")}
> >
<PropertiesIcon isActive={subModule === "properties"} /> <PropertiesIcon isActive={subModule === "properties"} />
</div> </div>
{/* )} */}
{activeModule === "simulation" && ( {activeModule === "simulation" && (
<> <>
<div <div
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : "" className={`sidebar-action-list ${
}`} subModule === "mechanics" ? "active" : ""
}`}
onClick={() => setSubModule("mechanics")} onClick={() => setSubModule("mechanics")}
> >
<MechanicsIcon isActive={subModule === "mechanics"} /> <MechanicsIcon isActive={subModule === "mechanics"} />
</div> </div>
<div <div
className={`sidebar-action-list ${subModule === "simulations" ? "active" : "" className={`sidebar-action-list ${
}`} subModule === "simulations" ? "active" : ""
}`}
onClick={() => setSubModule("simulations")} onClick={() => setSubModule("simulations")}
> >
<SimulationIcon isActive={subModule === "simulations"} /> <SimulationIcon isActive={subModule === "simulations"} />
</div> </div>
<div <div
className={`sidebar-action-list ${subModule === "analysis" ? "active" : "" className={`sidebar-action-list ${
}`} subModule === "analysis" ? "active" : ""
}`}
onClick={() => setSubModule("analysis")} onClick={() => setSubModule("analysis")}
> >
<AnalysisIcon isActive={subModule === "analysis"} /> <AnalysisIcon isActive={subModule === "analysis"} />
@ -73,6 +83,7 @@ const SideBarRight: React.FC = () => {
<div className="sidebar-right-container"> <div className="sidebar-right-container">
<div className="sidebar-right-content-container"> <div className="sidebar-right-content-container">
<GlobalProperties /> <GlobalProperties />
{/* <ZoneProperties /> */}
{/* <AsstePropertiies /> */} {/* <AsstePropertiies /> */}
</div> </div>
</div> </div>
@ -82,17 +93,17 @@ const SideBarRight: React.FC = () => {
{toggleUI && activeModule === "simulation" && ( {toggleUI && activeModule === "simulation" && (
<> <>
{(subModule === "mechanics" && selectedActionSphere) && ( {subModule === "mechanics" && selectedActionSphere && (
<div className="sidebar-right-container"> <div className="sidebar-right-container">
<div className="sidebar-right-content-container"> <div className="sidebar-right-content-container">
<MachineMechanics /> <MachineMechanics />
</div> </div>
</div> </div>
)} )}
{(subModule === "mechanics" && !selectedActionSphere) && ( {subModule === "mechanics" && !selectedActionSphere && (
<div className="sidebar-right-container"> <div className="sidebar-right-container">
<div className="sidebar-right-content-container"> <div className="sidebar-right-content-container">
{/* <MachineMechanics /> */} <MachineMechanics />
</div> </div>
</div> </div>
)} )}

View File

@ -0,0 +1,62 @@
import React from "react";
import { EyeDroperIcon } from "../../../icons/ExportCommonIcons";
interface PositionInputProps {
onChange: (value: string) => void; // Callback for value change
header: string;
placeholder?: string; // Optional placeholder
type?: string; // Input type (e.g., text, number, email)
}
const Vector3Input: React.FC<PositionInputProps> = ({
onChange,
header,
placeholder = "Enter value", // Default placeholder
type = "number", // Default type
}) => {
return (
<div className="custom-input-container">
<div className="header">
{header}{" "}
<div className="eyedrop-button">
<EyeDroperIcon isActive={false} />
</div>
</div>
<div className="inputs-container">
<div className="input-container">
<div className="custom-input-label">X : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
disabled
/>
</div>
<div className="input-container">
<div className="custom-input-label">Y : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
disabled
min={0}
/>
</div>
<div className="input-container">
<div className="custom-input-label">Z : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
disabled
/>
</div>
</div>
</div>
);
};
export default Vector3Input;

View File

@ -14,8 +14,8 @@ import EyeDropInput from "../../../ui/inputs/EyeDropInput";
import { useSelectedActionSphere } from "../../../../store/store"; import { useSelectedActionSphere } from "../../../../store/store";
const MachineMechanics: React.FC = () => { const MachineMechanics: React.FC = () => {
const { selectedActionSphere, setSelectedActionSphere } = useSelectedActionSphere(); const { selectedActionSphere } = useSelectedActionSphere();
console.log('selectedActionSphere: ', selectedActionSphere); console.log("selectedActionSphere: ", selectedActionSphere);
const [actionList, setActionList] = useState<string[]>([]); const [actionList, setActionList] = useState<string[]>([]);
const [triggerList, setTriggerList] = useState<string[]>([]); const [triggerList, setTriggerList] = useState<string[]>([]);
const [selectedItem, setSelectedItem] = useState<{ const [selectedItem, setSelectedItem] = useState<{
@ -71,7 +71,9 @@ const MachineMechanics: React.FC = () => {
return ( return (
<div className="machine-mechanics-container"> <div className="machine-mechanics-container">
<div className="machine-mechanics-header">{selectedActionSphere.path.modelName}</div> <div className="machine-mechanics-header">
{selectedActionSphere?.path?.modelName || "path name not found"}
</div>
{/* <div className="process-list-container"> {/* <div className="process-list-container">
<div className="label">Process:</div> <div className="label">Process:</div>
<RegularDropDown <RegularDropDown
@ -100,11 +102,12 @@ const MachineMechanics: React.FC = () => {
{actionList.map((action, index) => ( {actionList.map((action, index) => (
<div <div
key={index} key={index}
className={`list-item ${selectedItem?.type === "action" && className={`list-item ${
selectedItem?.type === "action" &&
selectedItem.name === action selectedItem.name === action
? "active" ? "active"
: "" : ""
}`} }`}
> >
<div <div
className="value" className="value"
@ -146,11 +149,12 @@ const MachineMechanics: React.FC = () => {
{triggerList.map((trigger, index) => ( {triggerList.map((trigger, index) => (
<div <div
key={index} key={index}
className={`list-item ${selectedItem?.type === "trigger" && className={`list-item ${
selectedItem?.type === "trigger" &&
selectedItem.name === trigger selectedItem.name === trigger
? "active" ? "active"
: "" : ""
}`} }`}
> >
<div <div
className="value" className="value"
@ -188,7 +192,7 @@ const MachineMechanics: React.FC = () => {
label="Speed" label="Speed"
value="" value=""
activeOption=".mm" activeOption=".mm"
onChange={() => { }} onChange={() => {}}
/> />
<EyeDropInput /> <EyeDropInput />
</> </>

View File

@ -0,0 +1,39 @@
import React, { useState } from "react";
import RenameInput from "../../../ui/inputs/RenameInput";
import Vector3Input from "../customInput/Vector3Input";
const ZoneProperties: React.FC = () => {
const [Edit, setEdit] = useState(false);
function handleSetView() {
setEdit(false);
}
function handleEditView() {
if (Edit) {
setEdit(false);
} else {
setEdit(true);
}
}
return (
<div className="zone-properties-container">
<div className="header">
<RenameInput value="Selected Zone Name" />
<div className="button" onClick={handleEditView}>
{Edit ? "Cancel" : "Edit"}
</div>
</div>
<Vector3Input onChange={() => {}} header="Viewport Target" />
<Vector3Input onChange={() => {}} header="Viewport Position" />
{Edit && (
<div className="button-save" onClick={handleSetView}>
Set View
</div>
)}
</div>
);
};
export default ZoneProperties;

View File

@ -28,7 +28,7 @@ const DropList: React.FC<DropListProps> = ({ val }) => {
}} }}
> >
{val.pathName} {val.pathName}
<div className="arrow-container"> <div className={`arrow-container${openDrop ? " active" : ""}`}>
<ArrowIcon /> <ArrowIcon />
</div> </div>
</div> </div>
@ -87,8 +87,9 @@ const Simulations: React.FC = () => {
{productsList.map((action, index) => ( {productsList.map((action, index) => (
<div <div
key={index} key={index}
className={`list-item ${selectedItem === action ? "active" : "" className={`list-item ${
}`} selectedItem === action ? "active" : ""
}`}
> >
<div <div
className="value" className="value"

View File

@ -6,15 +6,20 @@ import {
SimulationIcon, SimulationIcon,
VisualizationIcon, VisualizationIcon,
} from "../icons/ExportModuleIcons"; } from "../icons/ExportModuleIcons";
import useToggleStore from "../../store/useUIToggleStore";
const ModuleToggle: React.FC = () => { const ModuleToggle: React.FC = () => {
const { activeModule, setActiveModule } = useModuleStore(); const { activeModule, setActiveModule } = useModuleStore();
const { setToggleUI } = useToggleStore();
return ( return (
<div className="module-toggle-container"> <div className="module-toggle-container">
<div <div
className={`module-list ${activeModule === "builder" && "active"}`} className={`module-list ${activeModule === "builder" && "active"}`}
onClick={() => setActiveModule("builder")} onClick={() => {
setActiveModule("builder");
setToggleUI(true);
}}
> >
<div className="icon"> <div className="icon">
<BuilderIcon isActive={activeModule === "builder"} /> <BuilderIcon isActive={activeModule === "builder"} />
@ -23,7 +28,10 @@ const ModuleToggle: React.FC = () => {
</div> </div>
<div <div
className={`module-list ${activeModule === "simulation" && "active"}`} className={`module-list ${activeModule === "simulation" && "active"}`}
onClick={() => setActiveModule("simulation")} onClick={() => {
setActiveModule("simulation");
setToggleUI(true);
}}
> >
<div className="icon"> <div className="icon">
<SimulationIcon isActive={activeModule === "simulation"} /> <SimulationIcon isActive={activeModule === "simulation"} />
@ -34,7 +42,10 @@ const ModuleToggle: React.FC = () => {
className={`module-list ${ className={`module-list ${
activeModule === "visualization" && "active" activeModule === "visualization" && "active"
}`} }`}
onClick={() => setActiveModule("visualization")} onClick={() => {
setActiveModule("visualization");
setToggleUI(true);
}}
> >
<div className="icon"> <div className="icon">
<VisualizationIcon isActive={activeModule === "visualization"} /> <VisualizationIcon isActive={activeModule === "visualization"} />
@ -42,10 +53,11 @@ const ModuleToggle: React.FC = () => {
<div className="module">Visualization</div> <div className="module">Visualization</div>
</div> </div>
<div <div
className={`module-list ${ className={`module-list ${activeModule === "market" && "active"}`}
activeModule === "market" && "active" onClick={() => {
}`} setActiveModule("market");
onClick={() => setActiveModule("market")} setToggleUI(false);
}}
> >
<div className="icon"> <div className="icon">
<CartIcon isActive={activeModule === "market"} /> <CartIcon isActive={activeModule === "market"} />

View File

@ -5,6 +5,7 @@ import AddButtons from "./AddButtons";
import { useSelectedZoneStore } from "../../../store/useZoneStore"; import { useSelectedZoneStore } from "../../../store/useZoneStore";
import DisplayZone from "./DisplayZone"; import DisplayZone from "./DisplayZone";
import Scene from "../../../modules/scene/scene"; import Scene from "../../../modules/scene/scene";
import useModuleStore from "../../../store/useModuleStore";
import { getZonesApi } from "../../../services/realTimeVisulization/zoneData/getZones"; import { getZonesApi } from "../../../services/realTimeVisulization/zoneData/getZones";
@ -38,6 +39,8 @@ const RealTimeVisulization: React.FC = () => {
const [hiddenPanels, setHiddenPanels] = React.useState<Side[]>([]); const [hiddenPanels, setHiddenPanels] = React.useState<Side[]>([]);
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const { activeModule } = useModuleStore();
const [zonesData, setZonesData] = useState<FormattedZoneData>({}); const [zonesData, setZonesData] = useState<FormattedZoneData>({});
const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { selectedZone, setSelectedZone } = useSelectedZoneStore();
@ -98,34 +101,44 @@ const RealTimeVisulization: React.FC = () => {
id="real-time-vis-canvas" id="real-time-vis-canvas"
className={`realTime-viz canvas ${!isPlaying ? "playActiveFalse" : ""}`} className={`realTime-viz canvas ${!isPlaying ? "playActiveFalse" : ""}`}
style={{ style={{
height: isPlaying ? "100vh" : "", height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
left: isPlaying ? "0%" : "", width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
}} }}
> >
<div <div
className="scene-container" className="scene-container"
style={{ height: "100%", width: "100%" }} style={{
height: "100%",
width: "100%",
borderRadius: isPlaying || activeModule !== "visualization" ? "" : "6px",
}}
> >
<Scene /> <Scene />
</div> </div>
{!isPlaying && ( {activeModule === "visualization" && (
<AddButtons <>
hiddenPanels={hiddenPanels} <DisplayZone
setHiddenPanels={setHiddenPanels} zonesData={zonesData}
selectedZone={selectedZone} selectedZone={selectedZone}
setSelectedZone={setSelectedZone} setSelectedZone={setSelectedZone}
/> />
{!isPlaying && (
<AddButtons
hiddenPanels={hiddenPanels}
setHiddenPanels={setHiddenPanels}
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
)}
<Panel
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
</>
)} )}
<DisplayZone
zonesData={zonesData}
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
<Panel
selectedZone={selectedZone}
hiddenPanels={hiddenPanels}
setSelectedZone={setSelectedZone}
/>{" "}
</div> </div>
); );
}; };

View File

@ -1,466 +1,509 @@
import React, { useState, useEffect, useMemo, useRef } from "react"; import React, { useState, useEffect, useMemo, useRef } from "react";
import { Line, Sphere } from "@react-three/drei"; import { Line, Sphere } from "@react-three/drei";
import { useThree, useFrame } from "@react-three/fiber"; import { useThree, useFrame } from "@react-three/fiber";
import * as THREE from "three"; import * as THREE from "three";
import { useActiveLayer, useDeleteModels, useDeletePointOrLine, useMovePoint, useSocketStore, useToggleView, useToolMode, useRemovedLayer, useZones, useZonePoints } from "../../../store/store"; import { useActiveLayer, useDeleteModels, useDeletePointOrLine, useMovePoint, useSocketStore, useToggleView, useToolMode, useRemovedLayer, useZones, useZonePoints } from "../../../store/store";
// import { setZonesApi } from "../../../services/factoryBuilder/zones/setZonesApi"; // import { setZonesApi } from "../../../services/factoryBuilder/zones/setZonesApi";
// import { deleteZonesApi } from "../../../services/factoryBuilder/zones/deleteZoneApi"; // import { deleteZonesApi } from "../../../services/factoryBuilder/zones/deleteZoneApi";
import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi"; import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi";
import * as CONSTANTS from '../../../types/world/worldConstants'; import * as CONSTANTS from '../../../types/world/worldConstants';
const ZoneGroup: React.FC = () => { const ZoneGroup: React.FC = () => {
const { camera, pointer, gl, raycaster, scene, controls } = useThree(); const { camera, pointer, gl, raycaster, scene, controls } = useThree();
const [startPoint, setStartPoint] = useState<THREE.Vector3 | null>(null); const [startPoint, setStartPoint] = useState<THREE.Vector3 | null>(null);
const [endPoint, setEndPoint] = useState<THREE.Vector3 | null>(null); const [endPoint, setEndPoint] = useState<THREE.Vector3 | null>(null);
const { zones, setZones } = useZones(); const { zones, setZones } = useZones();
const { zonePoints, setZonePoints } = useZonePoints(); const { zonePoints, setZonePoints } = useZonePoints();
const [isDragging, setIsDragging] = useState(false); const [isDragging, setIsDragging] = useState(false);
const [draggedSphere, setDraggedSphere] = useState<THREE.Vector3 | null>(null); const [draggedSphere, setDraggedSphere] = useState<THREE.Vector3 | null>(null);
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const { toggleView } = useToggleView(); const { toggleView } = useToggleView();
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
const { removedLayer, setRemovedLayer } = useRemovedLayer(); const { removedLayer, setRemovedLayer } = useRemovedLayer();
const { toolMode, setToolMode } = useToolMode(); const { toolMode, setToolMode } = useToolMode();
const { movePoint, setMovePoint } = useMovePoint(); const { movePoint, setMovePoint } = useMovePoint();
const { deleteModels, setDeleteModels } = useDeleteModels(); const { deleteModels, setDeleteModels } = useDeleteModels();
const { activeLayer, setActiveLayer } = useActiveLayer(); const { activeLayer, setActiveLayer } = useActiveLayer();
const { socket } = useSocketStore(); const { socket } = useSocketStore();
const groupsRef = useRef<any>(); const groupsRef = useRef<any>();
const zoneMaterial = useMemo(() => new THREE.ShaderMaterial({ const zoneMaterial = useMemo(() => new THREE.ShaderMaterial({
side: THREE.DoubleSide, side: THREE.DoubleSide,
vertexShader: ` vertexShader: `
varying vec2 vUv; varying vec2 vUv;
void main(){ void main(){
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
vUv = uv; vUv = uv;
} }
`, `,
fragmentShader: ` fragmentShader: `
varying vec2 vUv; varying vec2 vUv;
uniform vec3 uColor; uniform vec3 uColor;
void main(){ void main(){
float alpha = 1.0 - vUv.y; float alpha = 1.0 - vUv.y;
gl_FragColor = vec4(uColor, alpha); gl_FragColor = vec4(uColor, alpha);
} }
`, `,
uniforms: { uniforms: {
uColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) }, uColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) },
}, },
transparent: true, transparent: true,
}), []); }), []);
useEffect(() => { useEffect(() => {
const fetchZones = async () => { const fetchZones = async () => {
const email = localStorage.getItem('email'); const email = localStorage.getItem('email');
if (!email) return; if (!email) return;
const organization = email.split("@")[1].split(".")[0]; const organization = email.split("@")[1].split(".")[0];
const data = await getZonesApi(organization); const data = await getZonesApi(organization);
if (data.data && data.data.length > 0) { if (data.data && data.data.length > 0) {
const fetchedZones = data.data.map((zone: any) => ({ const fetchedZones = data.data.map((zone: any) => ({
zoneId: zone.zoneId, zoneId: zone.zoneId,
zoneName: zone.zoneName, zoneName: zone.zoneName,
points: zone.points, points: zone.points,
layer: zone.layer layer: zone.layer
})); }));
setZones(fetchedZones); setZones(fetchedZones);
const fetchedPoints = data.data.flatMap((zone: any) => const fetchedPoints = data.data.flatMap((zone: any) =>
zone.points.slice(0, 4).map((point: [number, number, number]) => new THREE.Vector3(...point)) zone.points.slice(0, 4).map((point: [number, number, number]) => new THREE.Vector3(...point))
); );
setZonePoints(fetchedPoints); setZonePoints(fetchedPoints);
} }
}; };
fetchZones(); fetchZones();
}, []); }, []);
useEffect(() => { useEffect(() => {
localStorage.setItem('zones', JSON.stringify(zones)); localStorage.setItem('zones', JSON.stringify(zones));
}, [zones]) }, [zones])
useEffect(() => { useEffect(() => {
if (removedLayer) { if (removedLayer) {
const updatedZones = zones.filter((zone: any) => zone.layer !== removedLayer); const updatedZones = zones.filter((zone: any) => zone.layer !== removedLayer);
setZones(updatedZones); setZones(updatedZones);
const updatedzonePoints = zonePoints.filter((_: any, index: any) => { const updatedzonePoints = zonePoints.filter((_: any, index: any) => {
const zoneIndex = Math.floor(index / 4); const zoneIndex = Math.floor(index / 4);
return zones[zoneIndex]?.layer !== removedLayer; return zones[zoneIndex]?.layer !== removedLayer;
}); });
setZonePoints(updatedzonePoints); setZonePoints(updatedzonePoints);
zones.filter((zone: any) => zone.layer === removedLayer).forEach((zone: any) => { zones.filter((zone: any) => zone.layer === removedLayer).forEach((zone: any) => {
deleteZoneFromBackend(zone.zoneId); deleteZoneFromBackend(zone.zoneId);
}); });
setRemovedLayer(null); setRemovedLayer(null);
} }
}, [removedLayer]); }, [removedLayer]);
useEffect(() => { useEffect(() => {
if (toolMode !== "Zone") { if (toolMode !== "Zone") {
setStartPoint(null); setStartPoint(null);
setEndPoint(null); setEndPoint(null);
} else { } else {
setDeletePointOrLine(false); setDeletePointOrLine(false);
setMovePoint(false); setMovePoint(false);
setDeleteModels(false); setDeleteModels(false);
} }
if (!toggleView) { if (!toggleView) {
setStartPoint(null); setStartPoint(null);
setEndPoint(null); setEndPoint(null);
} }
}, [toolMode, toggleView]); }, [toolMode, toggleView]);
const addZoneToBackend = async (zone: { zoneId: string; zoneName: string; points: [number, number, number][]; layer: string }) => { const addZoneToBackend = async (zone: { zoneId: string; zoneName: string; points: [number, number, number][]; layer: string }) => {
const email = localStorage.getItem('email'); const email = localStorage.getItem('email');
const userId = localStorage.getItem('userId'); const userId = localStorage.getItem('userId');
const organization = (email!.split("@")[1]).split(".")[0]; const organization = (email!.split("@")[1]).split(".")[0];
const input = { const calculateCenter = (points: number[][]) => {
userId: userId, if (!points || points.length === 0) return null;
organization: organization,
zoneData: { let sumX = 0, sumY = 0, sumZ = 0;
zoneName: zone.zoneName, const numPoints = points.length;
zoneId: zone.zoneId,
points: zone.points, points.forEach(([x, y, z]) => {
layer: zone.layer sumX += x;
} sumY += y;
} sumZ += z;
});
socket.emit('v2:zone:set', input);
}; return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [number, number, number];
};
const updateZoneToBackend = async (zone: { zoneId: string; zoneName: string; points: [number, number, number][]; layer: string }) => {
const target: [number, number, number] | null = calculateCenter(zone.points);
const email = localStorage.getItem('email'); if (!target) return;
const userId = localStorage.getItem('userId'); const position = [target[0], 75, target[2]];
const organization = (email!.split("@")[1]).split(".")[0];
const input = {
const input = { userId: userId,
userId: userId, organization: organization,
organization: organization, zoneData: {
zoneData: { zoneName: zone.zoneName,
zoneName: zone.zoneName, zoneId: zone.zoneId,
zoneId: zone.zoneId, points: zone.points,
points: zone.points, viewPortCenter: target,
layer: zone.layer viewPortposition: position,
} layer: zone.layer
} }
}
socket.emit('v2:zone:set', input);
}; socket.emit('v2:zone:set', input);
};
const deleteZoneFromBackend = async (zoneId: string) => {
const updateZoneToBackend = async (zone: { zoneId: string; zoneName: string; points: [number, number, number][]; layer: string }) => {
const email = localStorage.getItem('email');
const userId = localStorage.getItem('userId'); const email = localStorage.getItem('email');
const organization = (email!.split("@")[1]).split(".")[0]; const userId = localStorage.getItem('userId');
const organization = (email!.split("@")[1]).split(".")[0];
const input = {
userId: userId, const calculateCenter = (points: number[][]) => {
organization: organization, if (!points || points.length === 0) return null;
zoneId: zoneId
} let sumX = 0, sumY = 0, sumZ = 0;
const numPoints = points.length;
socket.emit('v2:zone:delete', input);
}; points.forEach(([x, y, z]) => {
sumX += x;
const handleDeleteZone = (zoneId: string) => { sumY += y;
const updatedZones = zones.filter((zone: any) => zone.zoneId !== zoneId); sumZ += z;
setZones(updatedZones); });
const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === zoneId); return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [number, number, number];
if (zoneIndex !== -1) { };
const zonePointsToRemove = zonePoints.slice(zoneIndex * 4, zoneIndex * 4 + 4);
zonePointsToRemove.forEach((point: any) => groupsRef.current.remove(point)); const target: [number, number, number] | null = calculateCenter(zone.points);
const updatedzonePoints = zonePoints.filter((_: any, index: any) => index < zoneIndex * 4 || index >= zoneIndex * 4 + 4); if (!target) return;
setZonePoints(updatedzonePoints); const position = [target[0], 75, target[2]];
}
const input = {
deleteZoneFromBackend(zoneId); userId: userId,
}; organization: organization,
zoneData: {
useEffect(() => { zoneName: zone.zoneName,
if (!camera || !toggleView) return; zoneId: zone.zoneId,
const canvasElement = gl.domElement; points: zone.points,
viewPortCenter: target,
let drag = false; viewPortposition: position,
let isLeftMouseDown = false; layer: zone.layer
}
const onMouseDown = (evt: any) => { }
if (evt.button === 0) {
isLeftMouseDown = true; socket.emit('v2:zone:set', input);
drag = false; };
raycaster.setFromCamera(pointer, camera);
const intersects = raycaster.intersectObjects(groupsRef.current.children, true); const deleteZoneFromBackend = async (zoneId: string) => {
if (intersects.length > 0 && movePoint) { const email = localStorage.getItem('email');
const clickedObject = intersects[0].object; const userId = localStorage.getItem('userId');
const sphereIndex = zonePoints.findIndex((point: any) => point.equals(clickedObject.position)); const organization = (email!.split("@")[1]).split(".")[0];
if (sphereIndex !== -1) {
(controls as any).enabled = false; const input = {
setDraggedSphere(zonePoints[sphereIndex]); userId: userId,
setIsDragging(true); organization: organization,
} zoneId: zoneId
} }
}
}; socket.emit('v2:zone:delete', input);
};
const onMouseUp = (evt: any) => {
if (evt.button === 0 && !drag && !isDragging && !deletePointOrLine) { const handleDeleteZone = (zoneId: string) => {
isLeftMouseDown = false; const updatedZones = zones.filter((zone: any) => zone.zoneId !== zoneId);
setZones(updatedZones);
if (!startPoint && !movePoint) {
raycaster.setFromCamera(pointer, camera); const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === zoneId);
const intersectionPoint = new THREE.Vector3(); if (zoneIndex !== -1) {
const point = raycaster.ray.intersectPlane(plane, intersectionPoint); const zonePointsToRemove = zonePoints.slice(zoneIndex * 4, zoneIndex * 4 + 4);
if (point) { zonePointsToRemove.forEach((point: any) => groupsRef.current.remove(point));
setStartPoint(point); const updatedzonePoints = zonePoints.filter((_: any, index: any) => index < zoneIndex * 4 || index >= zoneIndex * 4 + 4);
setEndPoint(null); setZonePoints(updatedzonePoints);
} }
} else if (startPoint && !movePoint) {
raycaster.setFromCamera(pointer, camera); deleteZoneFromBackend(zoneId);
const intersectionPoint = new THREE.Vector3(); };
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (!point) return; useEffect(() => {
if (!camera || !toggleView) return;
const points = [ const canvasElement = gl.domElement;
[startPoint.x, 0.15, startPoint.z],
[point.x, 0.15, startPoint.z], let drag = false;
[point.x, 0.15, point.z], let isLeftMouseDown = false;
[startPoint.x, 0.15, point.z],
[startPoint.x, 0.15, startPoint.z], const onMouseDown = (evt: any) => {
] as [number, number, number][]; if (evt.button === 0) {
isLeftMouseDown = true;
const zoneName = `Zone ${zones.length + 1}`; drag = false;
const zoneId = THREE.MathUtils.generateUUID();
const newZone = { raycaster.setFromCamera(pointer, camera);
zoneId, const intersects = raycaster.intersectObjects(groupsRef.current.children, true);
zoneName,
points: points, if (intersects.length > 0 && movePoint) {
layer: activeLayer const clickedObject = intersects[0].object;
}; const sphereIndex = zonePoints.findIndex((point: any) => point.equals(clickedObject.position));
if (sphereIndex !== -1) {
const newZones = [...zones, newZone]; (controls as any).enabled = false;
setDraggedSphere(zonePoints[sphereIndex]);
setZones(newZones); setIsDragging(true);
}
const newzonePoints = [ }
new THREE.Vector3(startPoint.x, 0.15, startPoint.z), }
new THREE.Vector3(point.x, 0.15, startPoint.z), };
new THREE.Vector3(point.x, 0.15, point.z),
new THREE.Vector3(startPoint.x, 0.15, point.z), const onMouseUp = (evt: any) => {
]; if (evt.button === 0 && !drag && !isDragging && !deletePointOrLine) {
isLeftMouseDown = false;
const updatedZonePoints = [...zonePoints, ...newzonePoints];
setZonePoints(updatedZonePoints); if (!startPoint && !movePoint) {
raycaster.setFromCamera(pointer, camera);
addZoneToBackend(newZone); const intersectionPoint = new THREE.Vector3();
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
setStartPoint(null); if (point) {
setEndPoint(null); setStartPoint(point);
} setEndPoint(null);
} else if (evt.button === 0 && !drag && !isDragging && deletePointOrLine) { }
raycaster.setFromCamera(pointer, camera); } else if (startPoint && !movePoint) {
const intersects = raycaster.intersectObjects(groupsRef.current.children, true); raycaster.setFromCamera(pointer, camera);
const intersectionPoint = new THREE.Vector3();
if (intersects.length > 0) { const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
const clickedObject = intersects[0].object; if (!point) return;
const sphereIndex = zonePoints.findIndex((point: any) => point.equals(clickedObject.position)); const points = [
if (sphereIndex !== -1) { [startPoint.x, 0.15, startPoint.z],
const zoneIndex = Math.floor(sphereIndex / 4); [point.x, 0.15, startPoint.z],
const zoneId = zones[zoneIndex].zoneId; [point.x, 0.15, point.z],
handleDeleteZone(zoneId); [startPoint.x, 0.15, point.z],
return; [startPoint.x, 0.15, startPoint.z],
} ] as [number, number, number][];
}
} const zoneName = `Zone ${zones.length + 1}`;
const zoneId = THREE.MathUtils.generateUUID();
if (evt.button === 0) { const newZone = {
if (isDragging && draggedSphere) { zoneId,
setIsDragging(false); zoneName,
setDraggedSphere(null); points: points,
layer: activeLayer
const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere); };
if (sphereIndex !== -1) {
const zoneIndex = Math.floor(sphereIndex / 4); const newZones = [...zones, newZone];
if (zoneIndex !== -1 && zones[zoneIndex]) { setZones(newZones);
updateZoneToBackend(zones[zoneIndex]);
} const newzonePoints = [
} new THREE.Vector3(startPoint.x, 0.15, startPoint.z),
} new THREE.Vector3(point.x, 0.15, startPoint.z),
} new THREE.Vector3(point.x, 0.15, point.z),
}; new THREE.Vector3(startPoint.x, 0.15, point.z),
];
const onMouseMove = () => {
if (isLeftMouseDown) { const updatedZonePoints = [...zonePoints, ...newzonePoints];
drag = true; setZonePoints(updatedZonePoints);
}
raycaster.setFromCamera(pointer, camera); addZoneToBackend(newZone);
const intersects = raycaster.intersectObjects(groupsRef.current.children, true);
setStartPoint(null);
if (intersects.length > 0 && intersects[0].object.name.includes('point')) { setEndPoint(null);
gl.domElement.style.cursor = movePoint ? "pointer" : "default"; }
} else { } else if (evt.button === 0 && !drag && !isDragging && deletePointOrLine) {
gl.domElement.style.cursor = "default"; raycaster.setFromCamera(pointer, camera);
} const intersects = raycaster.intersectObjects(groupsRef.current.children, true);
if (isDragging && draggedSphere) {
raycaster.setFromCamera(pointer, camera); if (intersects.length > 0) {
const intersectionPoint = new THREE.Vector3(); const clickedObject = intersects[0].object;
const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (point) { const sphereIndex = zonePoints.findIndex((point: any) => point.equals(clickedObject.position));
draggedSphere.set(point.x, 0.15, point.z); if (sphereIndex !== -1) {
const zoneIndex = Math.floor(sphereIndex / 4);
const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere); const zoneId = zones[zoneIndex].zoneId;
if (sphereIndex !== -1) { handleDeleteZone(zoneId);
const zoneIndex = Math.floor(sphereIndex / 4); return;
const cornerIndex = sphereIndex % 4; }
}
const updatedZones = zones.map((zone: any, index: number) => { }
if (index === zoneIndex) {
const updatedPoints = [...zone.points]; if (evt.button === 0) {
updatedPoints[cornerIndex] = [point.x, 0.15, point.z]; if (isDragging && draggedSphere) {
updatedPoints[4] = updatedPoints[0]; setIsDragging(false);
return { ...zone, points: updatedPoints }; setDraggedSphere(null);
}
return zone; const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere);
}); if (sphereIndex !== -1) {
const zoneIndex = Math.floor(sphereIndex / 4);
setZones(updatedZones);
} if (zoneIndex !== -1 && zones[zoneIndex]) {
} updateZoneToBackend(zones[zoneIndex]);
} }
}; }
}
const onContext = (event: any) => { }
event.preventDefault(); };
setStartPoint(null);
setEndPoint(null); const onMouseMove = () => {
}; if (isLeftMouseDown) {
drag = true;
if (toolMode === 'Zone' || deletePointOrLine || movePoint) { }
canvasElement.addEventListener("mousedown", onMouseDown); raycaster.setFromCamera(pointer, camera);
canvasElement.addEventListener("mouseup", onMouseUp); const intersects = raycaster.intersectObjects(groupsRef.current.children, true);
canvasElement.addEventListener("mousemove", onMouseMove);
canvasElement.addEventListener("contextmenu", onContext); if (intersects.length > 0 && intersects[0].object.name.includes('point')) {
} gl.domElement.style.cursor = movePoint ? "pointer" : "default";
return () => { } else {
canvasElement.removeEventListener("mousedown", onMouseDown); gl.domElement.style.cursor = "default";
canvasElement.removeEventListener("mouseup", onMouseUp); }
canvasElement.removeEventListener("mousemove", onMouseMove); if (isDragging && draggedSphere) {
canvasElement.removeEventListener("contextmenu", onContext); raycaster.setFromCamera(pointer, camera);
}; const intersectionPoint = new THREE.Vector3();
}, [gl, camera, startPoint, toggleView, scene, toolMode, zones, isDragging, deletePointOrLine, zonePoints, draggedSphere, movePoint, activeLayer]); const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (point) {
useFrame(() => { draggedSphere.set(point.x, 0.15, point.z);
if (!startPoint) return;
raycaster.setFromCamera(pointer, camera); const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere);
const intersectionPoint = new THREE.Vector3(); if (sphereIndex !== -1) {
const point = raycaster.ray.intersectPlane(plane, intersectionPoint); const zoneIndex = Math.floor(sphereIndex / 4);
if (point) { const cornerIndex = sphereIndex % 4;
setEndPoint(point);
} const updatedZones = zones.map((zone: any, index: number) => {
}); if (index === zoneIndex) {
return ( const updatedPoints = [...zone.points];
<group ref={groupsRef} name='zoneGroup' > updatedPoints[cornerIndex] = [point.x, 0.15, point.z];
<group name="zones" visible={!toggleView}> updatedPoints[4] = updatedPoints[0];
{zones return { ...zone, points: updatedPoints };
.map((zone: any) => ( }
<group key={zone.zoneId} name={zone.zoneName}> return zone;
{zone.points.slice(0, -1).map((point: [number, number, number], index: number) => { });
const nextPoint = zone.points[index + 1];
setZones(updatedZones);
const point1 = new THREE.Vector3(point[0], point[1], point[2]); }
const point2 = new THREE.Vector3(nextPoint[0], nextPoint[1], nextPoint[2]); }
}
const planeWidth = point1.distanceTo(point2); };
const planeHeight = CONSTANTS.wallConfig.height;
const onContext = (event: any) => {
const midpoint = new THREE.Vector3((point1.x + point2.x) / 2, (CONSTANTS.wallConfig.height / 2) + ((zone.layer - 1) * CONSTANTS.wallConfig.height), (point1.z + point2.z) / 2); event.preventDefault();
setStartPoint(null);
const angle = Math.atan2(point2.z - point1.z, point2.x - point1.x); setEndPoint(null);
};
return (
<mesh if (toolMode === 'Zone' || deletePointOrLine || movePoint) {
key={index} canvasElement.addEventListener("mousedown", onMouseDown);
position={midpoint} canvasElement.addEventListener("mouseup", onMouseUp);
rotation={[0, -angle, 0]} canvasElement.addEventListener("mousemove", onMouseMove);
> canvasElement.addEventListener("contextmenu", onContext);
<planeGeometry args={[planeWidth, planeHeight]} /> }
<primitive return () => {
object={zoneMaterial.clone()} canvasElement.removeEventListener("mousedown", onMouseDown);
attach="material" canvasElement.removeEventListener("mouseup", onMouseUp);
/> canvasElement.removeEventListener("mousemove", onMouseMove);
</mesh> canvasElement.removeEventListener("contextmenu", onContext);
); };
})} }, [gl, camera, startPoint, toggleView, scene, toolMode, zones, isDragging, deletePointOrLine, zonePoints, draggedSphere, movePoint, activeLayer]);
</group>
))} useFrame(() => {
</group> if (!startPoint) return;
<group name='zoneLines' visible={toggleView}> raycaster.setFromCamera(pointer, camera);
{zones const intersectionPoint = new THREE.Vector3();
.filter((zone: any) => zone.layer === activeLayer) const point = raycaster.ray.intersectPlane(plane, intersectionPoint);
.map((zone: any) => ( if (point) {
<Line setEndPoint(point);
key={zone.zoneId} }
points={zone.points} });
color="#007BFF" return (
lineWidth={3} <group ref={groupsRef} name='zoneGroup' >
onClick={(e) => { <group name="zones" visible={!toggleView}>
e.stopPropagation(); {zones
if (deletePointOrLine) { .map((zone: any) => (
handleDeleteZone(zone.zoneId); <group key={zone.zoneId} name={zone.zoneName}>
} {zone.points.slice(0, -1).map((point: [number, number, number], index: number) => {
}} const nextPoint = zone.points[index + 1];
/>
))} const point1 = new THREE.Vector3(point[0], point[1], point[2]);
</group> const point2 = new THREE.Vector3(nextPoint[0], nextPoint[1], nextPoint[2]);
<group name="zonePoints" visible={toggleView}>
{zones.filter((zone: any) => zone.layer === activeLayer).flatMap((zone: any) => ( const planeWidth = point1.distanceTo(point2);
zone.points.slice(0, 4).map((point: any, pointIndex: number) => ( const planeHeight = CONSTANTS.wallConfig.height;
<Sphere
key={`${zone.zoneId}-point-${pointIndex}`} const midpoint = new THREE.Vector3((point1.x + point2.x) / 2, (CONSTANTS.wallConfig.height / 2) + ((zone.layer - 1) * CONSTANTS.wallConfig.height), (point1.z + point2.z) / 2);
position={new THREE.Vector3(...point)}
args={[0.3, 16, 16]} const angle = Math.atan2(point2.z - point1.z, point2.x - point1.x);
name={`point-${zone.zoneId}-${pointIndex}`}
> return (
<meshBasicMaterial color="red" /> <mesh
</Sphere> key={index}
)) position={midpoint}
))} rotation={[0, -angle, 0]}
</group> >
<group name="tempGroup" visible={toggleView}> <planeGeometry args={[planeWidth, planeHeight]} />
{startPoint && endPoint && ( <primitive
<Line object={zoneMaterial.clone()}
points={[ attach="material"
[startPoint.x, 0.15, startPoint.z], />
[endPoint.x, 0.15, startPoint.z], </mesh>
[endPoint.x, 0.15, endPoint.z], );
[startPoint.x, 0.15, endPoint.z], })}
[startPoint.x, 0.15, startPoint.z], </group>
]} ))}
color="#C164FF" </group>
lineWidth={3} <group name='zoneLines' visible={toggleView}>
/> {zones
)} .filter((zone: any) => zone.layer === activeLayer)
</group> .map((zone: any) => (
</group> <Line
); key={zone.zoneId}
}; points={zone.points}
color="#007BFF"
lineWidth={3}
onClick={(e) => {
e.stopPropagation();
if (deletePointOrLine) {
handleDeleteZone(zone.zoneId);
}
}}
/>
))}
</group>
<group name="zonePoints" visible={toggleView}>
{zones.filter((zone: any) => zone.layer === activeLayer).flatMap((zone: any) => (
zone.points.slice(0, 4).map((point: any, pointIndex: number) => (
<Sphere
key={`${zone.zoneId}-point-${pointIndex}`}
position={new THREE.Vector3(...point)}
args={[0.3, 16, 16]}
name={`point-${zone.zoneId}-${pointIndex}`}
>
<meshBasicMaterial color="red" />
</Sphere>
))
))}
</group>
<group name="tempGroup" visible={toggleView}>
{startPoint && endPoint && (
<Line
points={[
[startPoint.x, 0.15, startPoint.z],
[endPoint.x, 0.15, startPoint.z],
[endPoint.x, 0.15, endPoint.z],
[startPoint.x, 0.15, endPoint.z],
[startPoint.x, 0.15, startPoint.z],
]}
color="#C164FF"
lineWidth={3}
/>
)}
</group>
</group>
);
};
export default ZoneGroup; export default ZoneGroup;

View File

@ -22,8 +22,8 @@ const Project: React.FC = () => {
let navigate = useNavigate(); let navigate = useNavigate();
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
const { userName, setUserName } = useUserName(); const { setUserName } = useUserName();
const { organization, setOrganization } = useOrganization(); const { setOrganization } = useOrganization();
const { setFloorItems } = useFloorItems(); const { setFloorItems } = useFloorItems();
const { setWallItems } = useWallItems(); const { setWallItems } = useWallItems();
const { setZones } = useZones(); const { setZones } = useZones();
@ -50,21 +50,15 @@ const Project: React.FC = () => {
return ( return (
<div className="project-main"> <div className="project-main">
<ModuleToggle /> <ModuleToggle />
<SideBarLeft />
{!isPlaying && <SideBarLeft />} <SideBarRight />
{!isPlaying && <SideBarRight />} <RealTimeVisulization />
{activeModule === "visualization" && <RealTimeVisulization />} {activeModule !== "market" && <Tools />}
{/* {activeModule !== "visualization" && <Scene />} */}
<Tools />
{/* <Scene /> */}
{/* <SimulationUI /> */} {/* <SimulationUI /> */}
<div <div
className="canvas-container" className="canvas-container"
style={{ height: "100vh", width: "100vw" }} style={{ height: "100vh", width: "100vw" }}
> ></div>
{activeModule !== "visualization" && <Scene />}
</div>
</div> </div>
); );
}; };

View File

@ -141,7 +141,7 @@ const UserAuth: React.FC = () => {
</div> </div>
{!isSignIn && ( {!isSignIn && (
<div className="policy-checkbox"> <div className="policy-checkbox">
<input type="checkbox" name="" id="" /> <input type="checkbox" name="" id="" required/>
<div className="label"> <div className="label">
I have read and agree to the terms of service I have read and agree to the terms of service
</div> </div>

View File

@ -14,7 +14,7 @@
width: fit-content; width: fit-content;
transition: width 0.2s; transition: width 0.2s;
background-color: var(--background-color); background-color: var(--background-color);
z-index: #{$z-index-tools}; z-index: #{$z-index-default};
.split { .split {
height: 20px; height: 20px;
width: 2px; width: 2px;

View File

@ -662,16 +662,30 @@
.collapse-header-container { .collapse-header-container {
@include flex-space-between; @include flex-space-between;
padding-right: 12px; padding-right: 12px;
margin-top: 8px;
border-top: 1px solid var(--border-color);
border-bottom: 1px solid var(--border-color);
.header {
color: var(--accent-color);
}
} }
.process-container { .process-container {
padding: 0 12px;
margin: 6px 0;
.value { .value {
@include flex-space-between;
.arrow-container { .arrow-container {
height: 16px;
width: 16px;
} }
.active { .active {
rotate: 90deg;
} }
} }
.children-drop { .children-drop {
.value { .value {
padding: 6px;
border-left: 1px solid var(--border-color);
} }
} }
} }
@ -716,12 +730,17 @@
} }
.global-properties-container, .global-properties-container,
.analysis-main-container, .analysis-main-container,
.asset-properties-container { .asset-properties-container,
.zone-properties-container {
.header { .header {
@include flex-space-between;
padding: 8px 12px; padding: 8px 12px;
border-top: 1px solid var(--highlight-accent-color); border-top: 1px solid var(--highlight-accent-color);
border-bottom: 1px solid var(--highlight-accent-color); border-bottom: 1px solid var(--highlight-accent-color);
color: var(--accent-color); color: var(--accent-color);
.input-value {
color: inherit;
}
} }
.input-container { .input-container {
@include flex-center; @include flex-center;
@ -740,7 +759,8 @@
} }
} }
.optimize-button, .optimize-button,
.generate-report-button { .generate-report-button,
.button-save {
@include flex-center; @include flex-center;
background-color: var(--accent-color); background-color: var(--accent-color);
color: var(--primary-color); color: var(--primary-color);
@ -759,7 +779,11 @@
} }
.custom-input-container { .custom-input-container {
.header { .header {
@include flex-space-between;
border: none; border: none;
.eyedrop-button {
@include flex-center;
}
} }
.inputs-container { .inputs-container {
@include flex-space-between; @include flex-space-between;

View File

@ -1,35 +1,155 @@
@use "../abstracts/variables.scss" as *; @use "../abstracts/variables.scss" as *;
@use "../abstracts/mixins.scss" as *;
// Main Container // Main Container
.realTime-viz { .realTime-viz {
background-color: var(--background-color); background-color: var(--background-color);
border-radius: 20px; border-radius: 20px;
box-shadow: $box-shadow-medium; box-shadow: $box-shadow-medium;
width: 100%; width: calc(100% - (320px + 270px + 90px));
height: 100%; height: calc(100% - (200px + 80px));
position: absolute; position: absolute;
top: 0; top: 50%;
left: 0; left: calc(270px + 45px);
transform: scale(1); transform: translate(0, -50%);
border-radius: #{$border-radius-medium};
transition: all 0.2s;
z-index: #{$z-index-default};
.scene-container { .scene-container {
width: 100%; overflow: hidden;
height: 100%; }
canvas { .icon {
width: 100vw !important; display: flex;
height: 100% !important; align-items: center;
position: relative;
}
.icons-container {
.icon {
&:first-child {
&::after {
display: none;
}
}
} }
} }
// Panels
.zoon-wrapper {
display: flex;
background-color: var(--background-color);
position: absolute;
bottom: 10px;
left: 50%;
transform: translate(-50%, 0);
gap: 6px;
padding: 4px;
border-radius: 8px;
max-width: 80%;
overflow: auto;
max-width: calc(100% - 450px);
&::-webkit-scrollbar {
display: none;
}
.zone {
width: auto;
background-color: var(--background-color);
border-radius: 6px;
padding: 4px 8px;
white-space: nowrap;
font-size: $small;
}
.active {
background-color: var(--accent-color);
color: var(--background-color);
// color: #FCFDFD !important;
}
}
.zoon-wrapper.bottom {
bottom: 210px;
}
@media (max-width: 1024px) {
width: 80%; // Increase width to take more space on smaller screens
height: 500px; // Reduce height to fit smaller screens
left: 50%; // Center horizontally
.main-container {
margin: 0 15px; // Reduce margin for better spacing
}
.zoon-wrapper {
bottom: 5px; // Adjust position for smaller screens
&.bottom {
bottom: 150px; // Adjust for bottom placement
}
}
}
.content-container {
display: flex;
height: 100vh;
transition: all 0.3s ease;
}
.main-container {
position: relative;
flex: 1;
height: 600px;
background-color: rgb(235, 235, 235);
margin: 0 30px;
transition: height 0.3s ease, margin 0.3s ease;
.zoon-wrapper {
display: flex;
background-color: rgba(224, 223, 255, 0.5);
position: absolute;
bottom: 10px;
left: 50%;
transform: translate(-50%, 0);
gap: 6px;
padding: 4px;
border-radius: 8px;
max-width: 80%;
overflow: auto;
transition: transform 0.3s ease;
&::-webkit-scrollbar {
display: none;
}
.zone {
width: auto;
background-color: $background-color;
border-radius: 6px;
padding: 4px 8px;
white-space: nowrap;
cursor: pointer;
transition: background-color 0.3s ease;
&.active {
background-color: var(--primary-color);
color: var(--accent-color);
}
}
&.bottom {
bottom: 210px;
}
}
}
.panel { .panel {
position: absolute; position: absolute;
background: white; background: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease; transition: all 0.3s ease;
border-radius: 6px; border-radius: 6px;
overflow: hidden; overflow: visible !important;
.panel-content { .panel-content {
position: relative; position: relative;
@ -46,7 +166,7 @@
} }
.chart-container { .chart-container {
width: 229px; width: 100%;
height: 200px; height: 200px;
max-height: 100%; max-height: 100%;
border: 1px dotted #a9a9a9; border: 1px dotted #a9a9a9;
@ -66,125 +186,54 @@
color: var(--primary-color); color: var(--primary-color);
} }
} }
}
// Panels for each side &.top-panel,
.left-panel, &.bottom-panel {
.right-panel { left: 0;
.chart-container { right: 0;
padding: 10px;
width: 100% !important;
height: 250px !important;
} .fullScreen {
} background-color: red;
}
.top-panel, .panel-content {
.bottom-panel { display: flex;
.chart-container { flex-direction: row;
padding: 10px;
width: 300px !important;
height: 100% !important;
}
}
// Zone Wrapper .chart-container {
.zoon-wrapper { height: 100%;
display: flex; width: 200px;
background-color: var(--background-color); }
position: absolute; }
bottom: 10px;
left: 50%;
transform: translate(-50%, 0);
gap: 6px;
padding: 4px;
border-radius: 8px;
max-width: 80%;
overflow: auto;
max-width: calc(100% - 450px);
z-index: 11000000000;
&::-webkit-scrollbar {
display: none;
} }
.zone { &.top-panel {
width: auto; top: 0;
background-color: var(--background-color);
border-radius: 6px;
padding: 4px 8px;
white-space: nowrap;
font-size: $small;
} }
.active { &.bottom-panel {
background-color: var(--accent-color); bottom: 0;
color: var(--background-color);
} }
}
.zoon-wrapper.bottom { &.left-panel {
bottom: 250px; left: 0;
} top: 0;
bottom: 0;
.content-container { .chart-container {
display: flex; width: 100%;
height: 100vh; height: 180px;
transition: all 0.3s ease; }
} }
.main-container { &.right-panel {
position: relative; right: 0;
flex: 1; top: 0;
height: 600px; bottom: 0;
background-color: rgb(235, 235, 235); }
margin: 0 30px;
transition: height 0.3s ease, margin 0.3s ease;
} }
} }
.playActiveFalse {
position: absolute;
top: 50%;
left: calc(270px + 45px);
transform-origin: left;
transform: translate(0, -50%) scaleX(0.6) scaleY(0.65);
width: calc((100vw * 1.65) - (320px + 270px + 70px) / 0.6);
z-index: 100;
.scene-container {
width: 100%;
height: 100%;
canvas {
width: calc((100vw * 1.65) - (320px + 270px + 70px) / 0.6) !important;
height: 100% !important;
}
}
&.top {
transform: scale(1.5);
}
&.right {
transform: scale(1.5);
}
&.bottom {
transform: scale(1.5);
}
&.left {
transform: scale(1.5);
}
.zoon-wrapper {
transform: translate(-50%, 0) scale(1.5);
}
}
// Side Buttons // Side Buttons
.side-button-container { .side-button-container {
position: absolute; position: absolute;
@ -224,6 +273,7 @@
height: 18px; height: 18px;
display: flex; display: flex;
justify-content: center; justify-content: center;
// align-items: center;
background-color: var(--accent-color); background-color: var(--accent-color);
border: none; border: none;
color: var(--background-color); color: var(--background-color);
@ -231,54 +281,116 @@
} }
&.top { &.top {
top: -35px; top: -30px;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
flex-direction: row; flex-direction: row;
gap: 6px; gap: 6px;
transform: scale(1.5);
} }
&.right { &.right {
right: -35px; right: -30px;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
flex-direction: column; flex-direction: column;
gap: 6px; gap: 6px;
transform: scale(1.5);
} }
&.bottom { &.bottom {
bottom: -35px; bottom: -30px;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
flex-direction: row; flex-direction: row;
gap: 6px; gap: 6px;
transform: scale(1.5);
} }
&.left { &.left {
left: -35px; left: -30px;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
flex-direction: column; flex-direction: column;
gap: 6px; gap: 6px;
transform: scale(1.5);
} }
} }
.right.side-button-container, .right.side-button-container {
.extra-Bs {
flex-direction: column;
}
}
.left.side-button-container { .left.side-button-container {
.extra-Bs { .extra-Bs {
flex-direction: column; flex-direction: column;
} }
} }
.top-panel, // Theme Container
.bottom-panel { .theme-container {
.panel-content { width: 250px;
padding: 12px;
box-shadow: 1px -3px 4px 0px rgba(0, 0, 0, 0.11);
border-radius: 8px;
background-color: white;
position: absolute;
top: 20px;
right: -100%;
transform: translate(-0%, 0);
display: flex; h2 {
flex-direction: row !important; font-size: 12px;
margin-bottom: 8px;
color: #2b3344;
} }
}
.theme-preset-wrapper {
display: flex;
gap: 5px;
flex-wrap: wrap;
.theme-preset {
display: flex;
gap: 2px;
margin-bottom: 10px;
border: 1px solid $border-color;
padding: 5px 10px;
border-radius: 4px;
transition: border 0.3s ease;
&.active {
border: 1px solid var(--primary-color);
&::after {
content: "";
position: absolute;
top: 1px;
left: 1px;
width: 10px;
height: 10px;
background-color: var(--primary-color);
border-radius: 50%;
}
}
}
}
.custom-color {
display: flex;
justify-content: space-between;
.color-displayer {
display: flex;
gap: 5px;
align-items: center;
border: 1px solid var(--accent-color);
border-radius: 4px;
padding: 0 5px;
input {
border: none;
outline: none;
border-radius: 50%;
}
}
}
}