feat: Enhance arrow and trigger connection handling with backend updates and improved event management
This commit is contained in:
@@ -2,6 +2,11 @@ import * as THREE from "three";
|
|||||||
import { useMemo, useRef, useState } from "react";
|
import { useMemo, useRef, useState } from "react";
|
||||||
import { useThree } from "@react-three/fiber";
|
import { useThree } from "@react-three/fiber";
|
||||||
import { useToolMode } from "../../../../store/builder/store";
|
import { useToolMode } from "../../../../store/builder/store";
|
||||||
|
import { useSceneContext } from "../../../scene/sceneContext";
|
||||||
|
import { useVersionContext } from "../../../builder/version/versionContext";
|
||||||
|
import { useProductContext } from "../../products/productContext";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||||
|
|
||||||
interface ConnectionLine {
|
interface ConnectionLine {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -15,6 +20,28 @@ export function Arrows({ connections }: { readonly connections: ConnectionLine[]
|
|||||||
const groupRef = useRef<THREE.Group>(null);
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
const { toolMode } = useToolMode();
|
const { toolMode } = useToolMode();
|
||||||
|
const { eventStore, productStore } = useSceneContext();
|
||||||
|
const { removeTrigger } = productStore();
|
||||||
|
const { selectedVersionStore } = useVersionContext();
|
||||||
|
const { selectedVersion } = selectedVersionStore();
|
||||||
|
const { selectedProductStore } = useProductContext();
|
||||||
|
const { selectedProduct } = selectedProductStore();
|
||||||
|
const { projectId } = useParams();
|
||||||
|
|
||||||
|
const updateBackend = (
|
||||||
|
productName: string,
|
||||||
|
productUuid: string,
|
||||||
|
projectId: string,
|
||||||
|
eventData: EventsSchema
|
||||||
|
) => {
|
||||||
|
upsertProductOrEventApi({
|
||||||
|
productName: productName,
|
||||||
|
productUuid: productUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
eventDatas: eventData,
|
||||||
|
versionId: selectedVersion?.versionId || '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const getWorldPositionFromScene = (uuid: string): THREE.Vector3 | null => {
|
const getWorldPositionFromScene = (uuid: string): THREE.Vector3 | null => {
|
||||||
const obj = scene.getObjectByProperty("uuid", uuid);
|
const obj = scene.getObjectByProperty("uuid", uuid);
|
||||||
@@ -24,14 +51,20 @@ export function Arrows({ connections }: { readonly connections: ConnectionLine[]
|
|||||||
return pos;
|
return pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const processedArrows = new Set<string>();
|
||||||
|
|
||||||
const createArrow = (
|
const createArrow = (
|
||||||
key: string,
|
key: string,
|
||||||
fullCurve: THREE.QuadraticBezierCurve3,
|
fullCurve: THREE.QuadraticBezierCurve3,
|
||||||
centerT: number,
|
centerT: number,
|
||||||
segmentSize: number,
|
segmentSize: number,
|
||||||
scale: number,
|
scale: number,
|
||||||
reverse = false
|
reverse: boolean,
|
||||||
|
trigger: TriggerSchema
|
||||||
) => {
|
) => {
|
||||||
|
if (processedArrows.has(trigger.triggerUuid)) return [];
|
||||||
|
processedArrows.add(trigger.triggerUuid);
|
||||||
|
|
||||||
const t1 = Math.max(0, centerT - segmentSize / 2);
|
const t1 = Math.max(0, centerT - segmentSize / 2);
|
||||||
const t2 = Math.min(1, centerT + segmentSize / 2);
|
const t2 = Math.min(1, centerT + segmentSize / 2);
|
||||||
const subCurve = getSubCurve(fullCurve, t1, t2, reverse);
|
const subCurve = getSubCurve(fullCurve, t1, t2, reverse);
|
||||||
@@ -53,26 +86,41 @@ export function Arrows({ connections }: { readonly connections: ConnectionLine[]
|
|||||||
tangent
|
tangent
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const removeConnection = (trigger: TriggerSchema) => {
|
||||||
|
if (trigger.triggerUuid) {
|
||||||
|
const event = removeTrigger(selectedProduct.productUuid, trigger.triggerUuid);
|
||||||
|
if (event) {
|
||||||
|
updateBackend(
|
||||||
|
selectedProduct.productName,
|
||||||
|
selectedProduct.productUuid,
|
||||||
|
projectId || '',
|
||||||
|
event
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group key={key}>
|
<group
|
||||||
|
key={key}
|
||||||
|
onPointerOver={() => setHoveredLineKey(trigger.triggerUuid)}
|
||||||
|
onPointerOut={() => setHoveredLineKey(null)}
|
||||||
|
onClick={() => { removeConnection(trigger) }}
|
||||||
|
>
|
||||||
<mesh
|
<mesh
|
||||||
geometry={shaftGeometry}
|
geometry={shaftGeometry}
|
||||||
onPointerOver={() => setHoveredLineKey(key)}
|
|
||||||
onPointerOut={() => setHoveredLineKey(null)}
|
|
||||||
>
|
>
|
||||||
<meshStandardMaterial
|
<meshStandardMaterial
|
||||||
color={toolMode === '2D-Delete' && hoveredLineKey === key ? "red" : "#42a5f5"}
|
color={toolMode === '3D-Delete' && hoveredLineKey === trigger.triggerUuid ? "red" : "#42a5f5"}
|
||||||
/>
|
/>
|
||||||
</mesh>
|
</mesh>
|
||||||
<mesh
|
<mesh
|
||||||
position={end}
|
position={end}
|
||||||
quaternion={rotation}
|
quaternion={rotation}
|
||||||
geometry={headGeometry}
|
geometry={headGeometry}
|
||||||
onPointerOver={() => setHoveredLineKey(key)}
|
|
||||||
onPointerOut={() => setHoveredLineKey(null)}
|
|
||||||
>
|
>
|
||||||
<meshStandardMaterial
|
<meshStandardMaterial
|
||||||
color={toolMode === '2D-Delete' && hoveredLineKey === key ? "red" : "#42a5f5"}
|
color={toolMode === '3D-Delete' && hoveredLineKey === trigger.triggerUuid ? "red" : "#42a5f5"}
|
||||||
/>
|
/>
|
||||||
</mesh>
|
</mesh>
|
||||||
</group>
|
</group>
|
||||||
@@ -97,50 +145,29 @@ export function Arrows({ connections }: { readonly connections: ConnectionLine[]
|
|||||||
};
|
};
|
||||||
|
|
||||||
const arrowGroups = connections.flatMap((connection) => {
|
const arrowGroups = connections.flatMap((connection) => {
|
||||||
const start = getWorldPositionFromScene(connection.startPointUuid);
|
const { startPointUuid, endPointUuid } = connection;
|
||||||
const end = getWorldPositionFromScene(connection.endPointUuid);
|
const start = getWorldPositionFromScene(startPointUuid);
|
||||||
|
const end = getWorldPositionFromScene(endPointUuid);
|
||||||
if (!start || !end) return [];
|
if (!start || !end) return [];
|
||||||
|
|
||||||
const isBidirectional = connections.some(
|
const isBidirectional = connections.some((other) => other.startPointUuid === endPointUuid && other.endPointUuid === startPointUuid);
|
||||||
(other) =>
|
|
||||||
other.startPointUuid === connection.endPointUuid &&
|
|
||||||
other.endPointUuid === connection.startPointUuid
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isBidirectional && connection.startPointUuid < connection.endPointUuid) {
|
const distance = start.distanceTo(end);
|
||||||
const distance = start.distanceTo(end);
|
const heightFactor = Math.max(0.5, distance * 0.2);
|
||||||
const heightFactor = Math.max(0.5, distance * 0.2);
|
const control = new THREE.Vector3((start.x + end.x) / 2, Math.max(start.y, end.y) + heightFactor, (start.z + end.z) / 2);
|
||||||
const control = new THREE.Vector3(
|
const curve = new THREE.QuadraticBezierCurve3(start, control, end);
|
||||||
(start.x + end.x) / 2,
|
const scale = THREE.MathUtils.clamp(distance * 0.75, 0.5, 5);
|
||||||
Math.max(start.y, end.y) + heightFactor,
|
|
||||||
(start.z + end.z) / 2
|
|
||||||
);
|
|
||||||
const curve = new THREE.QuadraticBezierCurve3(start, control, end);
|
|
||||||
const scale = THREE.MathUtils.clamp(distance * 0.75, 0.5, 3);
|
|
||||||
|
|
||||||
|
if (isBidirectional) {
|
||||||
return [
|
return [
|
||||||
createArrow(connection.id + "-fwd", curve, 0.33, 0.25, scale, true),
|
createArrow(connection.id + "-fwd", curve, 0.33, 0.25, scale, true, connection.trigger),
|
||||||
createArrow(connection.id + "-bwd", curve, 0.66, 0.25, scale, false),
|
createArrow(connection.id + "-bwd", curve, 0.66, 0.25, scale, false, connection.trigger),
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return [
|
||||||
|
createArrow(connection.id, curve, 0.5, 0.3, scale, false, connection.trigger)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isBidirectional) {
|
|
||||||
const distance = start.distanceTo(end);
|
|
||||||
const heightFactor = Math.max(0.5, distance * 0.2);
|
|
||||||
const control = new THREE.Vector3(
|
|
||||||
(start.x + end.x) / 2,
|
|
||||||
Math.max(start.y, end.y) + heightFactor,
|
|
||||||
(start.z + end.z) / 2
|
|
||||||
);
|
|
||||||
const curve = new THREE.QuadraticBezierCurve3(start, control, end);
|
|
||||||
const scale = THREE.MathUtils.clamp(distance * 0.75, 0.5, 5);
|
|
||||||
|
|
||||||
return [
|
|
||||||
createArrow(connection.id, curve, 0.5, 0.3, scale)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return <group ref={groupRef} name="connectionArrows">{arrowGroups}</group>;
|
return <group ref={groupRef} name="connectionArrows">{arrowGroups}</group>;
|
||||||
|
|||||||
@@ -503,15 +503,15 @@ function TriggerConnector() {
|
|||||||
dashed={toolMode === '3D-Delete' && hoveredLineKey === connection.id ? false : true}
|
dashed={toolMode === '3D-Delete' && hoveredLineKey === connection.id ? false : true}
|
||||||
dashSize={0.75}
|
dashSize={0.75}
|
||||||
dashScale={20}
|
dashScale={20}
|
||||||
onPointerOver={() => setHoveredLineKey(connection.id)}
|
// onPointerOver={() => setHoveredLineKey(connection.id)}
|
||||||
onPointerOut={() => setHoveredLineKey(null)}
|
// onPointerOut={() => setHoveredLineKey(null)}
|
||||||
onClick={() => {
|
// onClick={() => {
|
||||||
if (toolMode === '3D-Delete') {
|
// if (toolMode === '3D-Delete') {
|
||||||
setHoveredLineKey(null);
|
// setHoveredLineKey(null);
|
||||||
setCurrentLine(null);
|
// setCurrentLine(null);
|
||||||
removeConnection(connection);
|
// removeConnection(connection);
|
||||||
}
|
// }
|
||||||
}}
|
// }}
|
||||||
userData={connection.trigger}
|
userData={connection.trigger}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user