mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
fix(ui): do not rerender edges
This commit is contained in:
parent
1f194e3688
commit
c2e7f62701
@ -2,8 +2,9 @@ import { Badge, Flex } from '@chakra-ui/react';
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import { useChakraThemeTokens } from 'common/hooks/useChakraThemeTokens';
|
import { useChakraThemeTokens } from 'common/hooks/useChakraThemeTokens';
|
||||||
import { useMemo } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
BaseEdge,
|
BaseEdge,
|
||||||
EdgeLabelRenderer,
|
EdgeLabelRenderer,
|
||||||
@ -20,78 +21,165 @@ const makeEdgeSelector = (
|
|||||||
targetHandleId: string | null | undefined,
|
targetHandleId: string | null | undefined,
|
||||||
selected?: boolean
|
selected?: boolean
|
||||||
) =>
|
) =>
|
||||||
createSelector(stateSelector, ({ nodes }) => {
|
createSelector(
|
||||||
const sourceNode = nodes.nodes.find((node) => node.id === source);
|
stateSelector,
|
||||||
const targetNode = nodes.nodes.find((node) => node.id === target);
|
({ nodes }) => {
|
||||||
|
const sourceNode = nodes.nodes.find((node) => node.id === source);
|
||||||
|
const targetNode = nodes.nodes.find((node) => node.id === target);
|
||||||
|
|
||||||
const isInvocationToInvocationEdge =
|
const isInvocationToInvocationEdge =
|
||||||
isInvocationNode(sourceNode) && isInvocationNode(targetNode);
|
isInvocationNode(sourceNode) && isInvocationNode(targetNode);
|
||||||
|
|
||||||
const isSelected = sourceNode?.selected || targetNode?.selected || selected;
|
const isSelected =
|
||||||
const sourceType = isInvocationToInvocationEdge
|
sourceNode?.selected || targetNode?.selected || selected;
|
||||||
? sourceNode?.data?.outputs[sourceHandleId || '']?.type
|
const sourceType = isInvocationToInvocationEdge
|
||||||
: undefined;
|
? sourceNode?.data?.outputs[sourceHandleId || '']?.type
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const stroke =
|
const stroke =
|
||||||
sourceType && nodes.shouldColorEdges
|
sourceType && nodes.shouldColorEdges
|
||||||
? colorTokenToCssVar(FIELDS[sourceType].color)
|
? colorTokenToCssVar(FIELDS[sourceType].color)
|
||||||
: colorTokenToCssVar('base.500');
|
: colorTokenToCssVar('base.500');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isSelected,
|
isSelected,
|
||||||
shouldAnimate: nodes.shouldAnimateEdges && isSelected,
|
shouldAnimate: nodes.shouldAnimateEdges && isSelected,
|
||||||
stroke,
|
stroke,
|
||||||
};
|
};
|
||||||
});
|
},
|
||||||
|
defaultSelectorOptions
|
||||||
const CollapsedEdge = ({
|
|
||||||
sourceX,
|
|
||||||
sourceY,
|
|
||||||
targetX,
|
|
||||||
targetY,
|
|
||||||
sourcePosition,
|
|
||||||
targetPosition,
|
|
||||||
markerEnd,
|
|
||||||
data,
|
|
||||||
selected,
|
|
||||||
source,
|
|
||||||
target,
|
|
||||||
sourceHandleId,
|
|
||||||
targetHandleId,
|
|
||||||
}: EdgeProps<{ count: number }>) => {
|
|
||||||
const selector = useMemo(
|
|
||||||
() =>
|
|
||||||
makeEdgeSelector(
|
|
||||||
source,
|
|
||||||
sourceHandleId,
|
|
||||||
target,
|
|
||||||
targetHandleId,
|
|
||||||
selected
|
|
||||||
),
|
|
||||||
[selected, source, sourceHandleId, target, targetHandleId]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const { isSelected, shouldAnimate } = useAppSelector(selector);
|
const CollapsedEdge = memo(
|
||||||
|
({
|
||||||
const [edgePath, labelX, labelY] = getBezierPath({
|
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
sourcePosition,
|
|
||||||
targetX,
|
targetX,
|
||||||
targetY,
|
targetY,
|
||||||
|
sourcePosition,
|
||||||
targetPosition,
|
targetPosition,
|
||||||
});
|
markerEnd,
|
||||||
|
data,
|
||||||
|
selected,
|
||||||
|
source,
|
||||||
|
target,
|
||||||
|
sourceHandleId,
|
||||||
|
targetHandleId,
|
||||||
|
}: EdgeProps<{ count: number }>) => {
|
||||||
|
const selector = useMemo(
|
||||||
|
() =>
|
||||||
|
makeEdgeSelector(
|
||||||
|
source,
|
||||||
|
sourceHandleId,
|
||||||
|
target,
|
||||||
|
targetHandleId,
|
||||||
|
selected
|
||||||
|
),
|
||||||
|
[selected, source, sourceHandleId, target, targetHandleId]
|
||||||
|
);
|
||||||
|
|
||||||
const { base500 } = useChakraThemeTokens();
|
const { isSelected, shouldAnimate } = useAppSelector(selector);
|
||||||
|
|
||||||
return (
|
const [edgePath, labelX, labelY] = getBezierPath({
|
||||||
<>
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
sourcePosition,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
targetPosition,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { base500 } = useChakraThemeTokens();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BaseEdge
|
||||||
|
path={edgePath}
|
||||||
|
markerEnd={markerEnd}
|
||||||
|
style={{
|
||||||
|
strokeWidth: isSelected ? 3 : 2,
|
||||||
|
stroke: base500,
|
||||||
|
opacity: isSelected ? 0.8 : 0.5,
|
||||||
|
animation: shouldAnimate
|
||||||
|
? 'dashdraw 0.5s linear infinite'
|
||||||
|
: undefined,
|
||||||
|
strokeDasharray: shouldAnimate ? 5 : 'none',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{data?.count && data.count > 1 && (
|
||||||
|
<EdgeLabelRenderer>
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
|
||||||
|
}}
|
||||||
|
className="nodrag nopan"
|
||||||
|
>
|
||||||
|
<Badge
|
||||||
|
variant="solid"
|
||||||
|
sx={{
|
||||||
|
bg: 'base.500',
|
||||||
|
opacity: isSelected ? 0.8 : 0.5,
|
||||||
|
boxShadow: 'base',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{data.count}
|
||||||
|
</Badge>
|
||||||
|
</Flex>
|
||||||
|
</EdgeLabelRenderer>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
CollapsedEdge.displayName = 'CollapsedEdge';
|
||||||
|
|
||||||
|
const DefaultEdge = memo(
|
||||||
|
({
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
sourcePosition,
|
||||||
|
targetPosition,
|
||||||
|
markerEnd,
|
||||||
|
selected,
|
||||||
|
source,
|
||||||
|
target,
|
||||||
|
sourceHandleId,
|
||||||
|
targetHandleId,
|
||||||
|
}: EdgeProps) => {
|
||||||
|
const selector = useMemo(
|
||||||
|
() =>
|
||||||
|
makeEdgeSelector(
|
||||||
|
source,
|
||||||
|
sourceHandleId,
|
||||||
|
target,
|
||||||
|
targetHandleId,
|
||||||
|
selected
|
||||||
|
),
|
||||||
|
[source, sourceHandleId, target, targetHandleId, selected]
|
||||||
|
);
|
||||||
|
|
||||||
|
const { isSelected, shouldAnimate, stroke } = useAppSelector(selector);
|
||||||
|
|
||||||
|
const [edgePath] = getBezierPath({
|
||||||
|
sourceX,
|
||||||
|
sourceY,
|
||||||
|
sourcePosition,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
targetPosition,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
<BaseEdge
|
<BaseEdge
|
||||||
path={edgePath}
|
path={edgePath}
|
||||||
markerEnd={markerEnd}
|
markerEnd={markerEnd}
|
||||||
style={{
|
style={{
|
||||||
strokeWidth: isSelected ? 3 : 2,
|
strokeWidth: isSelected ? 3 : 2,
|
||||||
stroke: base500,
|
stroke,
|
||||||
opacity: isSelected ? 0.8 : 0.5,
|
opacity: isSelected ? 0.8 : 0.5,
|
||||||
animation: shouldAnimate
|
animation: shouldAnimate
|
||||||
? 'dashdraw 0.5s linear infinite'
|
? 'dashdraw 0.5s linear infinite'
|
||||||
@ -99,83 +187,11 @@ const CollapsedEdge = ({
|
|||||||
strokeDasharray: shouldAnimate ? 5 : 'none',
|
strokeDasharray: shouldAnimate ? 5 : 'none',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{data?.count && data.count > 1 && (
|
);
|
||||||
<EdgeLabelRenderer>
|
}
|
||||||
<Flex
|
);
|
||||||
sx={{
|
|
||||||
position: 'absolute',
|
|
||||||
transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
|
|
||||||
}}
|
|
||||||
className="nodrag nopan"
|
|
||||||
>
|
|
||||||
<Badge
|
|
||||||
variant="solid"
|
|
||||||
sx={{
|
|
||||||
bg: 'base.500',
|
|
||||||
opacity: isSelected ? 0.8 : 0.5,
|
|
||||||
boxShadow: 'base',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{data.count}
|
|
||||||
</Badge>
|
|
||||||
</Flex>
|
|
||||||
</EdgeLabelRenderer>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const DefaultEdge = ({
|
DefaultEdge.displayName = 'DefaultEdge';
|
||||||
sourceX,
|
|
||||||
sourceY,
|
|
||||||
targetX,
|
|
||||||
targetY,
|
|
||||||
sourcePosition,
|
|
||||||
targetPosition,
|
|
||||||
markerEnd,
|
|
||||||
selected,
|
|
||||||
source,
|
|
||||||
target,
|
|
||||||
sourceHandleId,
|
|
||||||
targetHandleId,
|
|
||||||
}: EdgeProps) => {
|
|
||||||
const selector = useMemo(
|
|
||||||
() =>
|
|
||||||
makeEdgeSelector(
|
|
||||||
source,
|
|
||||||
sourceHandleId,
|
|
||||||
target,
|
|
||||||
targetHandleId,
|
|
||||||
selected
|
|
||||||
),
|
|
||||||
[source, sourceHandleId, target, targetHandleId, selected]
|
|
||||||
);
|
|
||||||
|
|
||||||
const { isSelected, shouldAnimate, stroke } = useAppSelector(selector);
|
|
||||||
|
|
||||||
const [edgePath] = getBezierPath({
|
|
||||||
sourceX,
|
|
||||||
sourceY,
|
|
||||||
sourcePosition,
|
|
||||||
targetX,
|
|
||||||
targetY,
|
|
||||||
targetPosition,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<BaseEdge
|
|
||||||
path={edgePath}
|
|
||||||
markerEnd={markerEnd}
|
|
||||||
style={{
|
|
||||||
strokeWidth: isSelected ? 3 : 2,
|
|
||||||
stroke,
|
|
||||||
opacity: isSelected ? 0.8 : 0.5,
|
|
||||||
animation: shouldAnimate ? 'dashdraw 0.5s linear infinite' : undefined,
|
|
||||||
strokeDasharray: shouldAnimate ? 5 : 'none',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const edgeTypes = {
|
export const edgeTypes = {
|
||||||
collapsed: CollapsedEdge,
|
collapsed: CollapsedEdge,
|
||||||
|
Loading…
Reference in New Issue
Block a user