diff --git a/app/src/components/icons/analysis.tsx b/app/src/components/icons/analysis.tsx
index c387003..7c36f20 100644
--- a/app/src/components/icons/analysis.tsx
+++ b/app/src/components/icons/analysis.tsx
@@ -28,10 +28,10 @@ export function ProductionCapacityIcon() {
xmlns="http://www.w3.org/2000/svg"
>
-
+
@@ -59,15 +59,11 @@ export function ROISummaryIcon() {
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
-
+
+
-
@@ -83,7 +79,7 @@ export function PowerIcon() {
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
-
+
);
@@ -147,8 +143,8 @@ export function SonarCrownIcon() {
);
@@ -166,9 +162,9 @@ export function CostBreakDownIcon() {
);
diff --git a/app/src/components/ui/analysis/SemiCircleProgress.tsx b/app/src/components/ui/analysis/SemiCircleProgress.tsx
index b2a3622..78422d3 100644
--- a/app/src/components/ui/analysis/SemiCircleProgress.tsx
+++ b/app/src/components/ui/analysis/SemiCircleProgress.tsx
@@ -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 }) => {
{/* Progress track */}
+
+
+
+
+
+
+
-
{clampedProgress}%
+
{years}
Years
diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx
index 94128ce..1252446 100644
--- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx
+++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx
@@ -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(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(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" && (
- <>
-
- {events.map((event, i) => {
- if (event.type === "transfer") {
- return (
-
- {event.points.map((point) => (
- (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,
- }}
- >
-
-
-
- ))}
-
- );
- } else if (event.type === "vehicle") {
- return (
-
- (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,
- }}
- >
-
-
-
-
- );
- } else if (event.type === "roboticArm") {
- return (
-
- (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,
- }}
- >
-
-
-
-
- );
- } else if (event.type === "machine") {
- return (
-
- (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,
- }}
- >
-
-
-
-
- );
- } else {
- return null;
- }
- })}
-
- {selectedEventSphere && transformMode && (
- {
- 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" && (
+ <>
+
+ {events.map((event, index) => {
+ if (event.type === "transfer") {
+ return (
+
+ {event.points.map((point, i) => (
+ (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,
+ }}
+ >
+
+
+
+ ))}
+
+ );
+ } else if (event.type === "vehicle") {
+ return (
+
+ (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,
+ }}
+ >
+
+
+
+
+ );
+ } else if (event.type === "roboticArm") {
+ return (
+
+ (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,
+ }}
+ >
+
+
+
+
+ );
+ } else if (event.type === "machine") {
+ return (
+
+ (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,
+ }}
+ >
+
+
+
+
+ );
+ } else {
+ return null;
+ }
+ })}
+
+ {selectedEventSphere && transformMode && (
+ {
+ updatePointToState(selectedEventSphere);
+ }}
+ />
+ )}
+ >
+ )}
+ >
+ );
}
-export default PointsCreator;
\ No newline at end of file
+export default PointsCreator;
diff --git a/app/src/styles/components/simulation/analysis.scss b/app/src/styles/components/simulation/analysis.scss
index f33fb46..7cf906e 100644
--- a/app/src/styles/components/simulation/analysis.scss
+++ b/app/src/styles/components/simulation/analysis.scss
@@ -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-button-color);
}
@@ -170,12 +164,13 @@
.footer-card {
width: 100%;
- background: var(--background-color-gray);
+ 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%;
@@ -326,10 +321,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;
}
}
}
@@ -376,8 +372,9 @@
gap: 6px;
.metric-item {
+ padding: 8px;
border-radius: #{$border-radius-large};
- background-color: var(--background-color);
+ background: var(--background-color);
border: 1px solid var(--border-color);
}
}
@@ -385,10 +382,12 @@
}
.cost-breakdown {
- background-color: var(--background-color);
+ 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;
@@ -448,7 +447,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;
@@ -510,18 +509,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 {
@@ -547,4 +545,4 @@
}
}
-// Breakdown Table Open/Close Logic
\ No newline at end of file
+// Breakdown Table Open/Close Logic