updating UI
This commit is contained in:
commit
c8c0f9a9c0
|
@ -38,7 +38,7 @@ const Footer: React.FC = () => {
|
|||
<span className="log-message">{lastLog.message}</span>
|
||||
</>
|
||||
) : (
|
||||
"No logs yet."
|
||||
"There are no logs to display at the moment."
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -66,14 +66,13 @@ export function ProductionCapacityIcon() {
|
|||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g filter="url(#filter0_d_4173_2653)">
|
||||
<rect
|
||||
x="4"
|
||||
width="25"
|
||||
height="25"
|
||||
rx="12.5"
|
||||
fill="#6F42C1"
|
||||
shape-rendering="crispEdges"
|
||||
<rect width="25" height="25" rx="12.5" fill="#6F42C1" />
|
||||
<g clipPath="url(#clip0_4107_2562)">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M13.5167 7.88281H15.3741C15.668 7.88281 15.9053 8.09496 15.9053 8.35581V13.0575H9.079L9.00279 13.0583V8.35581C9.00279 8.09417 9.24007 7.88281 9.53393 7.88281H11.3921V10.251C11.3921 10.3138 11.4204 10.3735 11.4707 10.4183C11.5226 10.4633 11.5891 10.4879 11.6577 10.4875H13.2511C13.3201 10.4881 13.3868 10.4635 13.4389 10.4183C13.4625 10.3971 13.4815 10.3713 13.4949 10.3426C13.5082 10.3138 13.5157 10.2826 13.5167 10.251V7.88281ZM9.079 14.0389H15.921C16.4243 14.0491 16.9035 14.2561 17.2559 14.6157C17.6082 14.9752 17.8056 15.4585 17.8056 15.9619C17.8056 16.4653 17.6082 16.9486 17.2559 17.3082C16.9035 17.6677 16.4243 17.8748 15.921 17.885H9.079C8.82319 17.8901 8.56892 17.8442 8.33108 17.7499C8.09324 17.6556 7.87661 17.5147 7.69387 17.3357C7.51113 17.1566 7.36596 16.9428 7.26685 16.707C7.16775 16.4711 7.1167 16.2178 7.1167 15.9619C7.1167 15.7061 7.16775 15.4528 7.26685 15.2169C7.36596 14.981 7.51113 14.7673 7.69387 14.5882C7.87661 14.4091 8.09324 14.2683 8.33108 14.174C8.56892 14.0796 8.82319 14.0337 9.079 14.0389ZM10.4626 15.956C10.4626 16.1384 10.3902 16.3132 10.2613 16.4422C10.1323 16.5711 9.95748 16.6435 9.77514 16.6435C9.59281 16.6435 9.41794 16.5711 9.28901 16.4422C9.16008 16.3132 9.08764 16.1384 9.08764 15.956C9.08764 15.7737 9.16008 15.5988 9.28901 15.4699C9.41794 15.341 9.59281 15.2685 9.77514 15.2685C9.95748 15.2685 10.1323 15.341 10.2613 15.4699C10.3902 15.5988 10.4626 15.7737 10.4626 15.956ZM13.1914 15.956C13.1914 16.1384 13.119 16.3132 12.9901 16.4422C12.8611 16.5711 12.6863 16.6435 12.5039 16.6435C12.3216 16.6435 12.1467 16.5711 12.0178 16.4422C11.8889 16.3132 11.8164 16.1384 11.8164 15.956C11.8164 15.7737 11.8889 15.5988 12.0178 15.4699C12.1467 15.341 12.3216 15.2685 12.5039 15.2685C12.6863 15.2685 12.8611 15.341 12.9901 15.4699C13.119 15.5988 13.1914 15.7737 13.1914 15.956ZM15.2319 16.6427C15.4143 16.6427 15.5891 16.5703 15.7181 16.4414C15.847 16.3124 15.9194 16.1376 15.9194 15.9552C15.9194 15.7729 15.847 15.598 15.7181 15.4691C15.5891 15.3402 15.4143 15.2677 15.2319 15.2677C15.0496 15.2677 14.8747 15.3402 14.7458 15.4691C14.6169 15.598 14.5444 15.7729 14.5444 15.9552C14.5444 16.1376 14.6169 16.3124 14.7458 16.4414C14.8747 16.5703 15.0496 16.6427 15.2319 16.6427Z"
|
||||
fill="var(--text-color)"
|
||||
/>
|
||||
<g clip-path="url(#clip0_4173_2653)">
|
||||
<path
|
||||
|
@ -142,14 +141,10 @@ export function ROISummaryIcon() {
|
|||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect y="0.515625" width="25" height="25" rx="12.5" fill="#28B9F3" />
|
||||
<rect y="0.515625" width="25" height="25" rx="12.5" fill="#2676D7" />
|
||||
<path d="M6 7.51562V19.0974H19" stroke="white" strokeLinecap="round" />
|
||||
<path
|
||||
d="M6.00015 7.51562V19.0974H19.0002"
|
||||
stroke="white"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M6.50037 15.0553L10.3102 11.847C10.6984 11.52 11.2701 11.5358 11.6397 11.8837L15.0095 15.0553L19.5004 11.2734"
|
||||
d="M6.5 15.0553L10.3098 11.847C10.6981 11.52 11.2697 11.5358 11.6393 11.8837L15.0091 15.0553L19.5 11.2734"
|
||||
stroke="white"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import React from "react";
|
||||
|
||||
const SemiCircleProgress = ({ progress = 10 }) => {
|
||||
const SemiCircleProgress = ({ progress = 60, years = 4.02 }) => {
|
||||
const clampedProgress = Math.min(Math.max(progress, 0), 100);
|
||||
const radius = 80;
|
||||
const strokeWidth = 20;
|
||||
const strokeWidth = 26;
|
||||
const circumference = Math.PI * radius;
|
||||
const strokeDashoffset =
|
||||
circumference - (clampedProgress / 100) * circumference;
|
||||
|
@ -15,22 +13,36 @@ const SemiCircleProgress = ({ progress = 10 }) => {
|
|||
<path
|
||||
d="M20,100 A80,80 0 0,1 180,100"
|
||||
fill="none"
|
||||
stroke="lightgray"
|
||||
stroke="#6F6F7A"
|
||||
strokeWidth={strokeWidth}
|
||||
/>
|
||||
{/* Progress track */}
|
||||
<path
|
||||
d="M20,100 A80,80 0 0,1 180,100"
|
||||
fill="none"
|
||||
stroke="skyblue"
|
||||
stroke="url(#paint0_linear_4200_2273)"
|
||||
strokeWidth={strokeWidth}
|
||||
strokeDasharray={circumference}
|
||||
strokeDashoffset={strokeDashoffset}
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear_4200_2273"
|
||||
x1="26.7278"
|
||||
y1="279.417"
|
||||
x2="298.886"
|
||||
y2="65.0002"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#3D3795" />
|
||||
<stop offset="0.535019" stopColor="#2A9BCF" />
|
||||
<stop offset="1" stopColor="#0DB3F4" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<div className="label-wrapper">
|
||||
<div className="label">{clampedProgress}%</div>
|
||||
<div className="label">{years}</div>
|
||||
<div className="label-content">Years</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -23,6 +23,7 @@ const LogList: React.FC = () => {
|
|||
className="log-list-container"
|
||||
onClick={() => setIsLogListVisible(false)}
|
||||
>
|
||||
{/* eslint-disable-next-line */}
|
||||
<div
|
||||
className="log-list-wrapper"
|
||||
onClick={(e) => {
|
||||
|
@ -46,32 +47,41 @@ const LogList: React.FC = () => {
|
|||
</div>
|
||||
|
||||
{/* Tabs */}
|
||||
<div className="log-nav-wrapper">
|
||||
{["all", "info", "warning", "error"].map((type) => (
|
||||
<button
|
||||
title="log-type"
|
||||
key={type}
|
||||
className={`log-nav ${selectedTab === type ? "active" : ""}`}
|
||||
onClick={() => setSelectedTab(type as any)}
|
||||
>
|
||||
{`${type.charAt(0).toUpperCase() + type.slice(1)} Logs`}
|
||||
</button>
|
||||
))}
|
||||
<div className="log-nav-container">
|
||||
<div className="log-nav-wrapper">
|
||||
{["all", "info", "warning", "error"].map((type) => (
|
||||
<button
|
||||
title="log-type"
|
||||
key={type}
|
||||
className={`log-nav ${selectedTab === type ? "active" : ""}`}
|
||||
onClick={() => setSelectedTab(type as any)}
|
||||
>
|
||||
{`${type.charAt(0).toUpperCase() + type.slice(1)} Logs`}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<button title="clear-btn" className="clear-button" onClick={clear}>
|
||||
clear
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Log Entries */}
|
||||
<div className="log-entry-wrapper">
|
||||
{filteredLogs.map((log) => (
|
||||
<div key={log.id} className={`log-entry ${log.type}`}>
|
||||
<div className="log-icon">{GetLogIcon(log.type)}</div>
|
||||
<div className="log-entry-message-container">
|
||||
<div className="log-entry-message">{log.message}</div>
|
||||
<div className="message-time">
|
||||
{formatTimestamp(log.timestamp)}
|
||||
{filteredLogs.length > 0 ? (
|
||||
filteredLogs.map((log) => (
|
||||
<div key={log.id} className={`log-entry ${log.type}`}>
|
||||
<div className="log-icon">{GetLogIcon(log.type)}</div>
|
||||
<div className="log-entry-message-container">
|
||||
<div className="log-entry-message">{log.message}</div>
|
||||
<div className="message-time">
|
||||
{formatTimestamp(log.timestamp)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
))
|
||||
) : (
|
||||
<div className="no-log">There are no logs to display at the moment.</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
import React, {
|
||||
createContext,
|
||||
useContext,
|
||||
useState,
|
||||
useCallback,
|
||||
useMemo,
|
||||
} from "react";
|
||||
import React, { createContext, useContext, useState, useCallback, useMemo } from "react";
|
||||
import { MathUtils } from "three";
|
||||
|
||||
export type LogType = "log" | "info" | "warning" | "error" | "success";
|
||||
|
||||
|
@ -36,22 +31,17 @@ export const LoggerProvider: React.FC<{ children: React.ReactNode }> = ({
|
|||
const [logs, setLogs] = useState<LogEntry[]>([]);
|
||||
const [isLogListVisible, setIsLogListVisible] = useState<boolean>(false);
|
||||
|
||||
const generateId = useCallback(
|
||||
() => Math.random().toString(36).substring(2, 9),
|
||||
[]
|
||||
);
|
||||
|
||||
const addLog = useCallback(
|
||||
(type: LogType, message: string) => {
|
||||
const newLog: LogEntry = {
|
||||
id: generateId(),
|
||||
id: MathUtils.generateUUID(),
|
||||
type,
|
||||
message,
|
||||
timestamp: new Date(),
|
||||
};
|
||||
setLogs((prevLogs) => [...prevLogs, newLog]);
|
||||
},
|
||||
[generateId]
|
||||
[]
|
||||
);
|
||||
|
||||
const loggerMethods: LoggerContextValue = useMemo(
|
||||
|
|
|
@ -1,250 +1,272 @@
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
import * as THREE from "three";
|
||||
import { useEventsStore } from "../../../../../store/simulation/useEventsStore";
|
||||
import useModuleStore, { useSubModuleStore } from "../../../../../store/useModuleStore";
|
||||
import useModuleStore, {
|
||||
useSubModuleStore,
|
||||
} from "../../../../../store/useModuleStore";
|
||||
import { TransformControls } from "@react-three/drei";
|
||||
import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
|
||||
import {
|
||||
useSelectedEventSphere,
|
||||
useSelectedEventData,
|
||||
useSelectedEventSphere,
|
||||
useSelectedEventData,
|
||||
} from "../../../../../store/simulation/useSimulationStore";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
|
||||
function PointsCreator() {
|
||||
const { gl, raycaster, scene, pointer, camera } = useThree();
|
||||
const { subModule } = useSubModuleStore();
|
||||
const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const transformRef = useRef<any>(null);
|
||||
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
|
||||
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
||||
const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere, } = useSelectedEventSphere();
|
||||
const { selectedEventData, setSelectedEventData, clearSelectedEventData } = useSelectedEventData();
|
||||
const { gl, raycaster, scene, pointer, camera } = useThree();
|
||||
const { subModule } = useSubModuleStore();
|
||||
const { events, updatePoint, getPointByUuid, getEventByModelUuid } =
|
||||
useEventsStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const transformRef = useRef<any>(null);
|
||||
const [transformMode, setTransformMode] = useState<
|
||||
"translate" | "rotate" | null
|
||||
>(null);
|
||||
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
||||
const {
|
||||
selectedEventSphere,
|
||||
setSelectedEventSphere,
|
||||
clearSelectedEventSphere,
|
||||
} = useSelectedEventSphere();
|
||||
const { setSelectedEventData, clearSelectedEventData } =
|
||||
useSelectedEventData();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedEventSphere) {
|
||||
const eventData = getEventByModelUuid(
|
||||
selectedEventSphere.userData.modelUuid
|
||||
);
|
||||
useEffect(() => {
|
||||
if (selectedEventSphere) {
|
||||
const eventData = getEventByModelUuid(
|
||||
selectedEventSphere.userData.modelUuid
|
||||
);
|
||||
|
||||
if (eventData) {
|
||||
setSelectedEventData(eventData, selectedEventSphere.userData.pointUuid);
|
||||
} else {
|
||||
clearSelectedEventData();
|
||||
}
|
||||
} else {
|
||||
clearSelectedEventData();
|
||||
}
|
||||
}, [selectedEventSphere]);
|
||||
if (eventData) {
|
||||
setSelectedEventData(eventData, selectedEventSphere.userData.pointUuid);
|
||||
} else {
|
||||
clearSelectedEventData();
|
||||
}
|
||||
} else {
|
||||
clearSelectedEventData();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedEventSphere]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
const keyCombination = detectModifierKeys(e);
|
||||
if (!selectedEventSphere) return;
|
||||
if (keyCombination === "G") {
|
||||
setTransformMode((prev) => (prev === "translate" ? null : "translate"));
|
||||
}
|
||||
if (keyCombination === "R") {
|
||||
setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
||||
}, [selectedEventSphere]);
|
||||
|
||||
const updatePointToState = (selectedEventSphere: THREE.Mesh) => {
|
||||
let point = JSON.parse(
|
||||
JSON.stringify(getPointByUuid(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid))
|
||||
);
|
||||
if (point) {
|
||||
point.position = [selectedEventSphere.position.x, selectedEventSphere.position.y, selectedEventSphere.position.z,];
|
||||
updatePoint(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid, point);
|
||||
}
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
const keyCombination = detectModifierKeys(e);
|
||||
if (!selectedEventSphere) return;
|
||||
if (keyCombination === "G") {
|
||||
setTransformMode((prev) => (prev === "translate" ? null : "translate"));
|
||||
}
|
||||
if (keyCombination === "R") {
|
||||
setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
||||
}, [selectedEventSphere]);
|
||||
|
||||
let drag = false;
|
||||
let isMouseDown = false;
|
||||
|
||||
const onMouseDown = () => {
|
||||
isMouseDown = true;
|
||||
drag = false;
|
||||
};
|
||||
|
||||
const onMouseUp = () => {
|
||||
if (selectedEventSphere && !drag) {
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster
|
||||
.intersectObjects(scene.children, true)
|
||||
.filter(
|
||||
(intersect) =>
|
||||
intersect.object.name === ('Event-Sphere')
|
||||
);
|
||||
if (intersects.length === 0) {
|
||||
clearSelectedEventSphere();
|
||||
setTransformMode(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
if (subModule === 'mechanics') {
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
};
|
||||
|
||||
}, [gl, subModule, selectedEventSphere]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{activeModule === "simulation" && (
|
||||
<>
|
||||
<group name="EventPointsGroup">
|
||||
{events.map((event, i) => {
|
||||
if (event.type === "transfer") {
|
||||
return (
|
||||
<group
|
||||
key={i}
|
||||
position={new THREE.Vector3(...event.position)}
|
||||
>
|
||||
{event.points.map((point) => (
|
||||
<mesh
|
||||
name="Event-Sphere"
|
||||
uuid={point.uuid}
|
||||
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSelectedEventSphere(
|
||||
sphereRefs.current[point.uuid]
|
||||
);
|
||||
}}
|
||||
position={new THREE.Vector3(...point.position)}
|
||||
userData={{
|
||||
modelUuid: event.modelUuid,
|
||||
pointUuid: point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="orange" />
|
||||
</mesh>
|
||||
))}
|
||||
</group>
|
||||
);
|
||||
} else if (event.type === "vehicle") {
|
||||
return (
|
||||
<group
|
||||
key={i}
|
||||
position={new THREE.Vector3(...event.position)}
|
||||
>
|
||||
<mesh
|
||||
name="Event-Sphere"
|
||||
uuid={event.point.uuid}
|
||||
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSelectedEventSphere(
|
||||
sphereRefs.current[event.point.uuid]
|
||||
);
|
||||
}}
|
||||
position={new THREE.Vector3(...event.point.position)}
|
||||
userData={{
|
||||
modelUuid: event.modelUuid,
|
||||
pointUuid: event.point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="blue" />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
} else if (event.type === "roboticArm") {
|
||||
return (
|
||||
<group
|
||||
key={i}
|
||||
position={new THREE.Vector3(...event.position)}
|
||||
>
|
||||
<mesh
|
||||
name="Event-Sphere"
|
||||
uuid={event.point.uuid}
|
||||
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSelectedEventSphere(
|
||||
sphereRefs.current[event.point.uuid]
|
||||
);
|
||||
}}
|
||||
position={new THREE.Vector3(...event.point.position)}
|
||||
userData={{
|
||||
modelUuid: event.modelUuid,
|
||||
pointUuid: event.point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="green" />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
} else if (event.type === "machine") {
|
||||
return (
|
||||
<group
|
||||
key={i}
|
||||
position={new THREE.Vector3(...event.position)}
|
||||
>
|
||||
<mesh
|
||||
name="Event-Sphere"
|
||||
uuid={event.point.uuid}
|
||||
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSelectedEventSphere(
|
||||
sphereRefs.current[event.point.uuid]
|
||||
);
|
||||
}}
|
||||
position={new THREE.Vector3(...event.point.position)}
|
||||
userData={{
|
||||
modelUuid: event.modelUuid,
|
||||
pointUuid: event.point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="purple" />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})}
|
||||
</group>
|
||||
{selectedEventSphere && transformMode && (
|
||||
<TransformControls
|
||||
ref={transformRef}
|
||||
object={selectedEventSphere}
|
||||
mode={transformMode}
|
||||
onMouseUp={(e) => {
|
||||
updatePointToState(selectedEventSphere);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
const updatePointToState = (selectedEventSphere: THREE.Mesh) => {
|
||||
let point = JSON.parse(
|
||||
JSON.stringify(
|
||||
getPointByUuid(
|
||||
selectedEventSphere.userData.modelUuid,
|
||||
selectedEventSphere.userData.pointUuid
|
||||
)
|
||||
)
|
||||
);
|
||||
if (point) {
|
||||
point.position = [
|
||||
selectedEventSphere.position.x,
|
||||
selectedEventSphere.position.y,
|
||||
selectedEventSphere.position.z,
|
||||
];
|
||||
updatePoint(
|
||||
selectedEventSphere.userData.modelUuid,
|
||||
selectedEventSphere.userData.pointUuid,
|
||||
point
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
let drag = false;
|
||||
let isMouseDown = false;
|
||||
|
||||
const onMouseDown = () => {
|
||||
isMouseDown = true;
|
||||
drag = false;
|
||||
};
|
||||
|
||||
const onMouseUp = () => {
|
||||
if (selectedEventSphere && !drag) {
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster
|
||||
.intersectObjects(scene.children, true)
|
||||
.filter((intersect) => intersect.object.name === "Event-Sphere");
|
||||
if (intersects.length === 0) {
|
||||
clearSelectedEventSphere();
|
||||
setTransformMode(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isMouseDown) {
|
||||
drag = true;
|
||||
}
|
||||
};
|
||||
|
||||
if (subModule === "mechanics") {
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [gl, subModule, selectedEventSphere]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{activeModule === "simulation" && (
|
||||
<>
|
||||
<group name="EventPointsGroup">
|
||||
{events.map((event, index) => {
|
||||
if (event.type === "transfer") {
|
||||
return (
|
||||
<group
|
||||
key={`${index}-${event.modelUuid}`}
|
||||
position={new THREE.Vector3(...event.position)}
|
||||
>
|
||||
{event.points.map((point, i) => (
|
||||
<mesh
|
||||
key={`${i}-${point.uuid}`}
|
||||
name="Event-Sphere"
|
||||
uuid={point.uuid}
|
||||
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSelectedEventSphere(
|
||||
sphereRefs.current[point.uuid]
|
||||
);
|
||||
}}
|
||||
position={new THREE.Vector3(...point.position)}
|
||||
userData={{
|
||||
modelUuid: event.modelUuid,
|
||||
pointUuid: point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="orange" />
|
||||
</mesh>
|
||||
))}
|
||||
</group>
|
||||
);
|
||||
} else if (event.type === "vehicle") {
|
||||
return (
|
||||
<group
|
||||
key={`${index}-${event.modelUuid}`}
|
||||
position={new THREE.Vector3(...event.position)}
|
||||
>
|
||||
<mesh
|
||||
name="Event-Sphere"
|
||||
uuid={event.point.uuid}
|
||||
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSelectedEventSphere(
|
||||
sphereRefs.current[event.point.uuid]
|
||||
);
|
||||
}}
|
||||
position={new THREE.Vector3(...event.point.position)}
|
||||
userData={{
|
||||
modelUuid: event.modelUuid,
|
||||
pointUuid: event.point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="blue" />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
} else if (event.type === "roboticArm") {
|
||||
return (
|
||||
<group
|
||||
key={`${index}-${event.modelUuid}`}
|
||||
position={new THREE.Vector3(...event.position)}
|
||||
>
|
||||
<mesh
|
||||
name="Event-Sphere"
|
||||
uuid={event.point.uuid}
|
||||
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSelectedEventSphere(
|
||||
sphereRefs.current[event.point.uuid]
|
||||
);
|
||||
}}
|
||||
position={new THREE.Vector3(...event.point.position)}
|
||||
userData={{
|
||||
modelUuid: event.modelUuid,
|
||||
pointUuid: event.point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="green" />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
} else if (event.type === "machine") {
|
||||
return (
|
||||
<group
|
||||
key={`${index}-${event.modelUuid}`}
|
||||
position={new THREE.Vector3(...event.position)}
|
||||
>
|
||||
<mesh
|
||||
name="Event-Sphere"
|
||||
uuid={event.point.uuid}
|
||||
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSelectedEventSphere(
|
||||
sphereRefs.current[event.point.uuid]
|
||||
);
|
||||
}}
|
||||
position={new THREE.Vector3(...event.point.position)}
|
||||
userData={{
|
||||
modelUuid: event.modelUuid,
|
||||
pointUuid: event.point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="purple" />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})}
|
||||
</group>
|
||||
{selectedEventSphere && transformMode && (
|
||||
<TransformControls
|
||||
ref={transformRef}
|
||||
object={selectedEventSphere}
|
||||
mode={transformMode}
|
||||
onMouseUp={(e) => {
|
||||
updatePointToState(selectedEventSphere);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default PointsCreator;
|
||||
export default PointsCreator;
|
||||
|
|
|
@ -28,9 +28,9 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
.icon{
|
||||
.icon {
|
||||
@include flex-center;
|
||||
scale: .8;
|
||||
scale: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,24 +43,38 @@
|
|||
svg {
|
||||
scale: 1.6;
|
||||
}
|
||||
&:hover{
|
||||
&:hover {
|
||||
background: var(--background-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
.log-nav-container {
|
||||
@include flex-space-between;
|
||||
align-items: flex-end;
|
||||
.log-nav-wrapper {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
|
||||
.log-nav-wrapper {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
.log-nav {
|
||||
padding: 8px 16px;
|
||||
border-radius: 19px;
|
||||
}
|
||||
|
||||
.log-nav {
|
||||
padding: 8px 16px;
|
||||
border-radius: 19px;
|
||||
.log-nav.active {
|
||||
background-color: var(--background-color-accent);
|
||||
color: var(--text-button-color);
|
||||
}
|
||||
}
|
||||
|
||||
.log-nav.active {
|
||||
background-color: var(--background-color-accent);
|
||||
color: var(--text-button-color);
|
||||
.clear-button{
|
||||
margin: 0 6px;
|
||||
padding: 4px 12px;
|
||||
color: var(--text-disabled);
|
||||
border-radius: #{$border-radius-large};
|
||||
&:hover{
|
||||
font-weight: 300;
|
||||
color: var(--text-color);
|
||||
background: var(--background-color-solid-gradient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,7 +112,7 @@
|
|||
text-wrap: nowrap;
|
||||
height: 100%;
|
||||
}
|
||||
.log-entry-message{
|
||||
.log-entry-message {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
@ -108,5 +122,10 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.no-log{
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
color: var(--text-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,19 +11,12 @@
|
|||
width: 100%;
|
||||
height: 100vh;
|
||||
pointer-events: none;
|
||||
padding: 10px;
|
||||
z-index: 2;
|
||||
|
||||
.analysis-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.analysis-card {
|
||||
min-width: 333px;
|
||||
border-radius: 20px;
|
||||
padding: 8px;
|
||||
margin: 8px;
|
||||
pointer-events: all;
|
||||
|
||||
.analysis-card-wrapper {
|
||||
|
@ -50,6 +43,7 @@
|
|||
}
|
||||
|
||||
.sub-header {
|
||||
font-weight: 300;
|
||||
font-size: var(--font-size-tiny);
|
||||
color: var(--text-color);
|
||||
opacity: 0.8;
|
||||
|
@ -173,11 +167,13 @@
|
|||
background: var(--background-color-gray);
|
||||
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--background-color);
|
||||
border-radius: 6px;
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
outline: 1px solid var(--border-color);
|
||||
|
||||
&:first-child {
|
||||
width: 85%;
|
||||
|
@ -338,10 +334,11 @@
|
|||
flex-direction: column;
|
||||
gap: 3px;
|
||||
align-items: center;
|
||||
|
||||
font-weight: 300;
|
||||
.key {
|
||||
font-size: var(--font-size-xlarge);
|
||||
color: #28B9F3;
|
||||
font-weight: 500;
|
||||
font-size: var(--font-size-large);
|
||||
color: #28b9f3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -410,8 +407,10 @@
|
|||
.cost-breakdown {
|
||||
background: var(--background-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: #{$border-radius-extra-large};
|
||||
border-radius: #{$border-radius-large};
|
||||
max-height: 20vh;
|
||||
padding: 16px;
|
||||
overflow: auto;
|
||||
|
||||
.breakdown-header {
|
||||
display: flex;
|
||||
|
@ -472,7 +471,7 @@
|
|||
}
|
||||
|
||||
.tips-section {
|
||||
background-color: var(--background-color);
|
||||
background: var(--background-color);
|
||||
border-radius: #{$border-radius-large};
|
||||
outline: 1px solid var(--border-color);
|
||||
display: flex;
|
||||
|
@ -552,18 +551,17 @@
|
|||
.label-wrapper {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
bottom: 2px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.label {
|
||||
font-size: var(--font-size-xlarge);
|
||||
font-size: var(--font-size-xxlarge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.breakdown-table-wrapper {
|
||||
|
@ -589,4 +587,4 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Breakdown Table Open/Close Logic
|
||||
// Breakdown Table Open/Close Logic
|
||||
|
|
Loading…
Reference in New Issue