rotation bug fixed
This commit is contained in:
@@ -1237,6 +1237,22 @@ ${linksYaml}`;
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getRotatableNodeHandleDirection = (node, handleId) => {
|
||||||
|
if (!node || !handleId) return null;
|
||||||
|
if (node.type !== 'rotatableNode' && !(!node.data?.elementType && node.data?.componentName)) return null;
|
||||||
|
const ports = node.data && node.data.ports;
|
||||||
|
if (!ports || !ports[handleId]) return null;
|
||||||
|
const boxSize = normalizeBoxSize({ box_size: node.data && node.data.boxSize }, DEFAULT_COMPONENT_BOX_SIZE);
|
||||||
|
const handles = buildPortHandles(ports, {
|
||||||
|
rotation: Number((node.data && node.data.rotation) || 0),
|
||||||
|
flip: Boolean(node.data && node.data.flip),
|
||||||
|
flop: Boolean(node.data && node.data.flop),
|
||||||
|
boxSize
|
||||||
|
});
|
||||||
|
const found = handles.find(handle => handle.name === handleId);
|
||||||
|
return found ? found.position : null;
|
||||||
|
};
|
||||||
|
|
||||||
// Backward-compatible alias for same-type route crossing validation.
|
// Backward-compatible alias for same-type route crossing validation.
|
||||||
const findSameFamilyRouteCrossing = findSameTypeRouteCrossing;
|
const findSameFamilyRouteCrossing = findSameTypeRouteCrossing;
|
||||||
|
|
||||||
@@ -1276,6 +1292,7 @@ ${linksYaml}`;
|
|||||||
createComponentSymbolMetrics,
|
createComponentSymbolMetrics,
|
||||||
transformPortInfo,
|
transformPortInfo,
|
||||||
getNodePortCanvasPoint,
|
getNodePortCanvasPoint,
|
||||||
|
getRotatableNodeHandleDirection,
|
||||||
buildPortHandles,
|
buildPortHandles,
|
||||||
buildElementPorts,
|
buildElementPorts,
|
||||||
buildElementPinEntries,
|
buildElementPinEntries,
|
||||||
|
|||||||
+30
-11
@@ -1566,6 +1566,7 @@ Organization : OptiHK Limited
|
|||||||
calculateLayoutBounds,
|
calculateLayoutBounds,
|
||||||
calculateCompositeBoxSize,
|
calculateCompositeBoxSize,
|
||||||
buildPortHandles,
|
buildPortHandles,
|
||||||
|
getRotatableNodeHandleDirection,
|
||||||
buildElementPorts,
|
buildElementPorts,
|
||||||
getElementPinName,
|
getElementPinName,
|
||||||
buildElementBoxSize,
|
buildElementBoxSize,
|
||||||
@@ -1698,8 +1699,10 @@ Organization : OptiHK Limited
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const transformKey = `${data.rotation || 0}:${data.flip ? 1 : 0}:${data.flop ? 1 : 0}`;
|
const transformKey = `${data.rotation || 0}:${data.flip ? 1 : 0}:${data.flop ? 1 : 0}`;
|
||||||
if (prevTransformRef.current !== transformKey) {
|
if (prevTransformRef.current !== transformKey) {
|
||||||
updateNodeInternalsRef.current(id);
|
|
||||||
prevTransformRef.current = transformKey;
|
prevTransformRef.current = transformKey;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
updateNodeInternalsRef.current(id);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [data.rotation, data.flip, data.flop, id]);
|
}, [data.rotation, data.flip, data.flop, id]);
|
||||||
|
|
||||||
@@ -1719,6 +1722,16 @@ Organization : OptiHK Limited
|
|||||||
top: Position.Top,
|
top: Position.Top,
|
||||||
bottom: Position.Bottom
|
bottom: Position.Bottom
|
||||||
};
|
};
|
||||||
|
const rotateHandleDirection = (dir, rot) => {
|
||||||
|
const norm = ((rot % 360) + 360) % 360;
|
||||||
|
const map = {
|
||||||
|
0: { right: 'right', left: 'left', top: 'top', bottom: 'bottom' },
|
||||||
|
90: { right: 'bottom', left: 'top', top: 'left', bottom: 'right' },
|
||||||
|
180: { right: 'left', left: 'right', top: 'bottom', bottom: 'top' },
|
||||||
|
270: { right: 'top', left: 'bottom', top: 'right', bottom: 'left' }
|
||||||
|
};
|
||||||
|
return (map[norm] || map[0])[dir] || dir;
|
||||||
|
};
|
||||||
const componentSize = normalizeBoxSize({ box_size: data.boxSize }, DEFAULT_COMPONENT_BOX_SIZE);
|
const componentSize = normalizeBoxSize({ box_size: data.boxSize }, DEFAULT_COMPONENT_BOX_SIZE);
|
||||||
const flippedPorts = useMemo(
|
const flippedPorts = useMemo(
|
||||||
() => {
|
() => {
|
||||||
@@ -1844,24 +1857,28 @@ Organization : OptiHK Limited
|
|||||||
transformOrigin: 'center center',
|
transformOrigin: 'center center',
|
||||||
pointerEvents: 'none'
|
pointerEvents: 'none'
|
||||||
}}>
|
}}>
|
||||||
{portHandles.map((portHandle) => (
|
{portHandles.map((portHandle) => {
|
||||||
|
const originalDir = portDirectionMap.get(portHandle.name) || portHandle.position;
|
||||||
|
const effectiveDir = rotateHandleDirection(originalDir, data.rotation || 0);
|
||||||
|
return (
|
||||||
<React.Fragment key={portHandle.name}>
|
<React.Fragment key={portHandle.name}>
|
||||||
<Handle
|
<Handle
|
||||||
type="source"
|
type="source"
|
||||||
position={handlePositionMap[portDirectionMap.get(portHandle.name) || portHandle.position]}
|
position={handlePositionMap[effectiveDir]}
|
||||||
id={portHandle.name}
|
id={portHandle.name}
|
||||||
title={portHandle.name}
|
title={portHandle.name}
|
||||||
style={{ ...baseHandleStyle, ...portHandle.style, zIndex: 10, pointerEvents: 'all' }}
|
style={{ ...baseHandleStyle, ...portHandle.style, zIndex: 10, pointerEvents: 'all' }}
|
||||||
/>
|
/>
|
||||||
<Handle
|
<Handle
|
||||||
type="target"
|
type="target"
|
||||||
position={handlePositionMap[portDirectionMap.get(portHandle.name) || portHandle.position]}
|
position={handlePositionMap[effectiveDir]}
|
||||||
id={portHandle.name}
|
id={portHandle.name}
|
||||||
title={portHandle.name}
|
title={portHandle.name}
|
||||||
style={{ ...baseHandleStyle, ...portHandle.style, zIndex: 5, pointerEvents: 'all' }}
|
style={{ ...baseHandleStyle, ...portHandle.style, zIndex: 5, pointerEvents: 'all' }}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
{portHandles.map((portHandle) => (
|
{portHandles.map((portHandle) => (
|
||||||
<span key={`label-${portHandle.name}`} className="port-name-label" style={portLabelStyle(portHandle)} title={portHandle.name}>
|
<span key={`label-${portHandle.name}`} className="port-name-label" style={portLabelStyle(portHandle)} title={portHandle.name}>
|
||||||
{portHandle.name}
|
{portHandle.name}
|
||||||
@@ -4007,8 +4024,10 @@ Organization : OptiHK Limited
|
|||||||
const targetEndpoint = `${edge.target}:${edge.targetHandle || ''}`;
|
const targetEndpoint = `${edge.target}:${edge.targetHandle || ''}`;
|
||||||
const key = [sourceEndpoint, targetEndpoint].sort().join('<>');
|
const key = [sourceEndpoint, targetEndpoint].sort().join('<>');
|
||||||
const group = groups.get(key) || [];
|
const group = groups.get(key) || [];
|
||||||
const sourceDirection = getAnchorHandleRouteDirection(nodeMap[edge.source], edge.sourceHandle);
|
const sourceDirection = getAnchorHandleRouteDirection(nodeMap[edge.source], edge.sourceHandle)
|
||||||
const targetDirection = getAnchorHandleRouteDirection(nodeMap[edge.target], edge.targetHandle);
|
|| getRotatableNodeHandleDirection(nodeMap[edge.source], edge.sourceHandle);
|
||||||
|
const targetDirection = getAnchorHandleRouteDirection(nodeMap[edge.target], edge.targetHandle)
|
||||||
|
|| getRotatableNodeHandleDirection(nodeMap[edge.target], edge.targetHandle);
|
||||||
const usesAnchorDirection = Boolean(sourceDirection || targetDirection);
|
const usesAnchorDirection = Boolean(sourceDirection || targetDirection);
|
||||||
const hasRoutePoints = edge.data && Array.isArray(edge.data.points) && edge.data.points.length >= 2;
|
const hasRoutePoints = edge.data && Array.isArray(edge.data.points) && edge.data.points.length >= 2;
|
||||||
const directionalEdge = usesAnchorDirection
|
const directionalEdge = usesAnchorDirection
|
||||||
@@ -4031,7 +4050,7 @@ Organization : OptiHK Limited
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
return [...separatedEdges, ...rulerEdges];
|
return [...separatedEdges, ...rulerEdges];
|
||||||
}, [currentEdges, currentNodes, getAnchorHandleRouteDirection, rulerEdges]);
|
}, [currentEdges, currentNodes, getAnchorHandleRouteDirection, getRotatableNodeHandleDirection, rulerEdges]);
|
||||||
|
|
||||||
const [projectCompositeMap, setProjectCompositeMap] = useState({});
|
const [projectCompositeMap, setProjectCompositeMap] = useState({});
|
||||||
const [standaloneComposites, setStandaloneComposites] = useState([]);
|
const [standaloneComposites, setStandaloneComposites] = useState([]);
|
||||||
@@ -6018,6 +6037,7 @@ Organization : OptiHK Limited
|
|||||||
const route = currentLinkRoute;
|
const route = currentLinkRoute;
|
||||||
const view = routeStyleForSettings(route, false);
|
const view = routeStyleForSettings(route, false);
|
||||||
const edgeId = `edge-${connection.source}-${connection.sourceHandle}-${connection.target}-${connection.targetHandle}-${Date.now()}`;
|
const edgeId = `edge-${connection.source}-${connection.sourceHandle}-${connection.target}-${connection.targetHandle}-${Date.now()}`;
|
||||||
|
const nodeMap = Object.fromEntries(activePage.nodes.map(node => [node.id, node]));
|
||||||
const candidate = {
|
const candidate = {
|
||||||
id: edgeId,
|
id: edgeId,
|
||||||
source: connection.source,
|
source: connection.source,
|
||||||
@@ -6027,9 +6047,8 @@ Organization : OptiHK Limited
|
|||||||
type: view.type,
|
type: view.type,
|
||||||
selectable: true,
|
selectable: true,
|
||||||
style: view.style,
|
style: view.style,
|
||||||
data: { route }
|
data: { route },
|
||||||
};
|
};
|
||||||
const nodeMap = Object.fromEntries(activePage.nodes.map(node => [node.id, node]));
|
|
||||||
const conflict = findSameTypeRouteCrossing(candidate, activePage.edges, nodeMap, technologyManifest);
|
const conflict = findSameTypeRouteCrossing(candidate, activePage.edges, nodeMap, technologyManifest);
|
||||||
if (conflict) {
|
if (conflict) {
|
||||||
const source = nodeMap[conflict.conflictEdge.source]?.data?.componentDisplayName || conflict.conflictEdge.source;
|
const source = nodeMap[conflict.conflictEdge.source]?.data?.componentDisplayName || conflict.conflictEdge.source;
|
||||||
@@ -6043,7 +6062,7 @@ Organization : OptiHK Limited
|
|||||||
: p
|
: p
|
||||||
)));
|
)));
|
||||||
addLog(`Connected ${connection.sourceHandle} to ${connection.targetHandle}.`);
|
addLog(`Connected ${connection.sourceHandle} to ${connection.targetHandle}.`);
|
||||||
}, [activePageId, activePage, rulerMode, currentLinkRoute, technologyManifest, addLog]);
|
}, [activePageId, activePage, rulerMode, currentLinkRoute, technologyManifest, addLog, getAnchorHandleRouteDirection]);
|
||||||
|
|
||||||
// Select custom route edges from their SVG hit target.
|
// Select custom route edges from their SVG hit target.
|
||||||
const handleRouteEdgeMouseDown = useCallback((event) => {
|
const handleRouteEdgeMouseDown = useCallback((event) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user