Closed litewarp closed 9 months ago
+1
This also applies to the ReactFlow component being nested inside of a will-transform component like so:
import { motion } from 'framer-motion';
// ...
<motion.div whileHover={{ scale: 1.05 }}>
<ReactFlow />
</motion.div>
(The edges are mis-aligned exactly like the picture above even before a transform is made or set).
As an FYI, my workaround was just to recalculate the elements myself in a custom edge.
In order to get the correct edgePath, you could do something like the following:
import React from 'react'
import {
EdgeProps,
getSmoothStepPath,
getMarkerEnd,
useStoreState,
Position,
Node,
XYPosition,
getBezierPath
} from 'react-flow-renderer'
export type EdgeVariant = 'linear' | 'smoothstep' | 'bezier'
type CustomEdgeProps = EdgeProps<{
label?: string
variant: EdgeVariant
}>
type LinearEdgePathProps = {
sourceX: number
sourceY: number
targetX: number
targetY: number
}
type StepBezierEdgePathProps = LinearEdgePathProps & {
sourcePosition: Position
targetPosition: Position
}
type EdgePathCalculationProps = StepBezierEdgePathProps & {
variant: EdgeVariant
}
// copied from 'rf src/container/EdgeRenderer/utils.ts'
const getHandlePosition = (
position: Position,
node: Node,
handle: any | null = null
): XYPosition => {
const x = (handle?.x || 0) + node.__rf.position.x
const y = (handle?.y || 0) + node.__rf.position.y
const width = handle?.width || node.__rf.width
const height = handle?.height || node.__rf.height
switch (position) {
case Position.Top:
return {
x: x + width / 2,
y
}
case Position.Right:
return {
x: x + width,
y: y + height / 2
}
case Position.Bottom:
return {
x: x + width / 2,
y: y + height
}
case Position.Left:
return {
x,
y: y + height / 2
}
}
}
const getCustomEdgePath = ({
variant,
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition
}: EdgePathCalculationProps): string => {
switch (variant) {
case 'bezier':
return getBezierPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition
})
case 'smoothstep':
return getSmoothStepPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition
})
case 'linear':
return `M ${sourceX},${sourceY}L ${targetX},${targetY}`
}
}
const CustomEdge: React.FC<CustomEdgeProps> = ({
id,
style = {},
sourcePosition,
targetPosition,
data,
arrowHeadType,
markerEndId,
source,
target
}) => {
const nodes = useStoreState((state) => state.nodes)
const sourceNode = nodes.find((node) => node.id === source)
const sourceHandle = getHandlePosition(sourcePosition, sourceNode as Node, null)
const targetNode = nodes.find((node) => node.id === target)
const targetHandle = getHandlePosition(targetPosition, targetNode as Node, null)
const markerEnd = getMarkerEnd(arrowHeadType, markerEndId)
const edgePath = getCustomEdgePath({
sourceX: sourceHandle.x,
sourceY: sourceHandle.y,
sourcePosition,
targetX: targetHandle.x,
targetY: targetHandle.y,
targetPosition,
variant: data?.variant ?? 'bezier'
})
return (
<>
<path
id={id}
style={style}
className="react-flow__edge-path"
d={edgePath}
markerEnd={markerEnd}
/>
{data?.label ? (
<text>
<textPath
href={`#${id}`}
style={{ fontSize: '12px' }}
startOffset="50%"
textAnchor="middle"
>
{data.label}
</textPath>
</text>
) : null}
</>
)
}
Could you find a solution? If not, could you send a minimal example within a codesandbox?
The solution was just to recalculate the edges per the component above ☝🏾
I'm not sure what exactly happens when the EdgeRenderer calculates the nodes initially but if I do the calculation myself it mostly turns out ok. So I think there's some translation or transform happening.
I can try and put together a repro tomorrow.
Ok. Great that you could fix it! No need to rush with the repo but it seems to be an interesting issue.
If you just render the <TestFlow />
element, the edges are aligned. If you render it within the Spectacle Components, the edges are misaligned.
Even I am facing the same issue. Any update or help would be great .
I encountered a similar problem recently and found out it was the animation hadn't stopped when the node internal position was calculated. So I added a onAnimationEnd
handler and used the useUpdateNodeInternals
hook to recalculate node internals once the animation ended and the problem was solved.
I am sure the issue here is coming from some transform styles from Spectacle but I have no solution for this..
We faced the same problem, when we used React Flow component inside a modal, which had animation
css property.
Removing animation
property fixed the problem.
Thanks @pdambrauskas
For me, I just stopped using the "scale" from CSS attribte "transform". It then worked perfectly!
I encountered a similar problem recently and found out it was the animation hadn't stopped when the node internal position was calculated. So I added a
onAnimationEnd
handler and used theuseUpdateNodeInternals
hook to recalculate node internals once the animation ended and the problem was solved.
Thank you! This worked for me inside of a Spectacle slide as well:
import { FlexBox, Slide } from "spectacle";
import { useUpdateNodeInternals } from "reactflow";
// ...
<Slide>
<FlexBox onAnimationEnd={useUpdateNodeInternals}>
{/* ... */}
</FlexBox>
</Slide>
If you are doing an animation that changes the scale, you need to update the node internals via ]useUpdateNodeInternals
|(https://reactflow.dev/docs/api/hooks/use-update-node-internals/) to let React Flow re-measure the handle positions.
Having the same issue with vue-flow
I encountered a similar problem recently and found out it was the animation hadn't stopped when the node internal position was calculated. So I added a
onAnimationEnd
handler and used theuseUpdateNodeInternals
hook to recalculate node internals once the animation ended and the problem was solved.Thank you! This worked for me inside of a Spectacle slide as well:
import { FlexBox, Slide } from "spectacle"; import { useUpdateNodeInternals } from "reactflow"; // ... <Slide> <FlexBox onAnimationEnd={useUpdateNodeInternals}> {/* ... */} </FlexBox> </Slide>
I encountered kind of more or less similar situation but within MUI's Zoom component, and solved by delay mounting of reactflow, and the delayed wrapper
<Delayed>
{your_reactflow_component}
</Delayed>
Hi there. I've got an issue similar to #1075 and #1136 where the calculated edge path does not align with handles, and my use case may provide some insight onto why it's happening.
I use spectacle to create presentations and recently wanted to start using graphs created with react-flow in the slide. However, there is something strange happening when the slide is scaled down. The image below is from the graph rendered on a slide.
This one is the graph rendered outside of the Spectrum
<Slide>
component, but otherwise identical. The edges are correct.I can confirm that it has something to do with the scale transform based on the slide's height and width. If I change the size of the slide and reduce its dimensions (e.g., 1280x720 instead of 1920x1080) the misalignment is less severe but still present.
If you use the Spectacle print mode, the edges are more accurate, but still slightly off.
This may be too complex of a use case for a fix, especially if it is the result of a misconfiguration of Spectacle. But I figured that it at least gives you a reproducible example of the misalignment issue.
Any ideas on how prevent this from happening when you're working with a graph contained in a non-standard series of DOM elements?
Thanks in advance. Love the library!