feat: Create examples directory and add some examples
* Add svg plugins for vite & rollup update: more bundle stuff
This commit is contained in:
-38
@@ -1,38 +0,0 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<h1>Revue Flow</h1>
|
||||
<Basic style="height: 75vh; background: #1a192b" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import Basic from './Basic';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'App',
|
||||
components: {
|
||||
Basic
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
elements: [
|
||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true }
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
margin-top: 60px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,87 +0,0 @@
|
||||
import { Connection, Edge, Elements, FlowElement, Node, OnLoadParams } from './types';
|
||||
import { addEdge, isNode, removeElements } from './utils/graph';
|
||||
import RevueFlow from './container/RevueFlow';
|
||||
import { MiniMap, Controls, Background } from './additional-components';
|
||||
import { defineComponent, ref } from 'vue';
|
||||
|
||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
||||
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element);
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true },
|
||||
{ id: 'e1-3', source: '1', target: '3' }
|
||||
];
|
||||
|
||||
const BasicFlow = defineComponent({
|
||||
components: { RevueFlow, MiniMap, Controls, Background },
|
||||
setup() {
|
||||
const elements = ref<Elements>(initialElements);
|
||||
const rfInstance = ref<OnLoadParams | null>(null);
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value));
|
||||
const onConnect = (params: Edge | Connection) => (elements.value = addEdge(params, elements.value));
|
||||
const onLoad = (revueFlowInstance: OnLoadParams) => (rfInstance.value = revueFlowInstance);
|
||||
|
||||
const updatePos = () => {
|
||||
elements.value = elements.value.map((el) => {
|
||||
if (isNode(el)) {
|
||||
el.position = {
|
||||
x: Math.random() * 400,
|
||||
y: Math.random() * 400
|
||||
};
|
||||
}
|
||||
|
||||
return el;
|
||||
});
|
||||
};
|
||||
|
||||
const logToObject = () => console.log(rfInstance.value?.toObject());
|
||||
const resetTransform = () => rfInstance.value?.setTransform({ x: 0, y: 0, zoom: 1 });
|
||||
|
||||
const toggleClassnames = () => {
|
||||
elements.value = elements.value.map((el) => {
|
||||
if (isNode(el)) {
|
||||
el.className = el.className === 'light' ? 'dark' : 'light';
|
||||
}
|
||||
|
||||
return el;
|
||||
});
|
||||
};
|
||||
|
||||
return () => (
|
||||
<RevueFlow
|
||||
elements={elements.value}
|
||||
onLoad={onLoad}
|
||||
onElementClick={onElementClick}
|
||||
onElementsRemove={onElementsRemove}
|
||||
onConnect={onConnect}
|
||||
onNodeDragStop={onNodeDragStop}
|
||||
class="revue-flow-basic-example"
|
||||
defaultZoom={1.5}
|
||||
minZoom={0.2}
|
||||
maxZoom={4}
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
<Background color="#aaa" gap={16} />
|
||||
<div style={{ position: 'absolute', right: '10px', top: '10px', zIndex: 4 }}>
|
||||
<button onClick={resetTransform} style={{ marginRight: '5px' }}>
|
||||
reset transform
|
||||
</button>
|
||||
<button onClick={updatePos} style={{ marginRight: '5px' }}>
|
||||
change pos
|
||||
</button>
|
||||
<button onClick={toggleClassnames} style={{ marginRight: '5px' }}>
|
||||
toggle classnames
|
||||
</button>
|
||||
<button onClick={logToObject}>toObject</button>
|
||||
</div>
|
||||
</RevueFlow>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default BasicFlow;
|
||||
@@ -1,7 +1,12 @@
|
||||
import { defineComponent, HTMLAttributes, onMounted, PropType, ref } from 'vue';
|
||||
import useZoomPanHelper from '../../hooks/useZoomPanHelper';
|
||||
import { FitViewParams } from '../../types';
|
||||
import { defineComponent, HTMLAttributes, onMounted, PropType, ref } from 'vue';
|
||||
import store from '../../store';
|
||||
import PlusIcon from '../../../assets/icons/plus.svg';
|
||||
import MinusIcon from '../../../assets/icons/minus.svg';
|
||||
import Fitview from '../../../assets/icons/fitview.svg';
|
||||
import Lock from '../../../assets/icons/lock.svg';
|
||||
import Unlock from '../../../assets/icons/unlock.svg';
|
||||
|
||||
export interface ControlProps extends HTMLAttributes {
|
||||
showZoom?: boolean;
|
||||
@@ -123,25 +128,21 @@ const Controls = defineComponent({
|
||||
{props.showZoom && (
|
||||
<>
|
||||
<ControlButton onClick={onZoomInHandler} class="revue-flow__controls-zoomin">
|
||||
<img src={'../../../assets/icons/plus.svg'} alt="Plus" />
|
||||
<PlusIcon />
|
||||
</ControlButton>
|
||||
<ControlButton onClick={onZoomOutHandler} class="revue-flow__controls-zoomout">
|
||||
<img src={'../../../assets/icons/minus.svg'} alt="Minus" />
|
||||
<MinusIcon />
|
||||
</ControlButton>
|
||||
</>
|
||||
)}
|
||||
{props.showFitView && (
|
||||
<ControlButton class="revue-flow__controls-fitview" onClick={onFitViewHandler}>
|
||||
<img src={'../../../assets/icons/fitview.svg'} alt="FitView" />
|
||||
<Fitview />
|
||||
</ControlButton>
|
||||
)}
|
||||
{props.showInteractive && (
|
||||
<ControlButton class="revue-flow__controls-interactive" onClick={onInteractiveChangeHandler}>
|
||||
{isInteractive ? (
|
||||
<img src={'../../../assets/icons/unlock.svg'} alt="Unlock" />
|
||||
) : (
|
||||
<img src={'../../../assets/icons/lock.svg'} alt="Lock" />
|
||||
)}
|
||||
{isInteractive ? <Unlock /> : <Lock />}
|
||||
</ControlButton>
|
||||
)}
|
||||
{slots.default ? slots.default() : ''}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
|
||||
interface MiniMapNodeProps {
|
||||
x: number;
|
||||
@@ -62,19 +62,19 @@ const MiniMapNode = defineComponent({
|
||||
}
|
||||
},
|
||||
setup(props, { attrs }: { attrs: Record<string, any> }) {
|
||||
const { background, backgroundColor } = attrs.style || {};
|
||||
const fill = (props.color || background || backgroundColor) as string;
|
||||
const styles = attrs.style || {};
|
||||
const fill = computed(() => (props.color || styles.value.background || styles.value.backgroundColor) as string);
|
||||
|
||||
return () => (
|
||||
<rect
|
||||
class={['revue-flow__minimap-node']}
|
||||
class="revue-flow__minimap-node"
|
||||
x={props.x}
|
||||
y={props.y}
|
||||
rx={props.borderRadius}
|
||||
ry={props.borderRadius}
|
||||
width={props.width}
|
||||
height={props.height}
|
||||
fill={fill}
|
||||
fill={fill.value}
|
||||
stroke={props.strokeColor}
|
||||
stroke-width={props.strokeWidth}
|
||||
shape-rendering={props.shapeRendering}
|
||||
|
||||
@@ -24,17 +24,17 @@ const MiniMap = defineComponent({
|
||||
name: 'MiniMap',
|
||||
props: {
|
||||
nodeStrokeColor: {
|
||||
type: (String || Function) as PropType<MiniMapProps['nodeStrokeColor']>,
|
||||
type: [String, Function] as PropType<MiniMapProps['nodeStrokeColor']>,
|
||||
required: false,
|
||||
default: '#555'
|
||||
},
|
||||
nodeColor: {
|
||||
type: (String || Function) as PropType<MiniMapProps['nodeColor']>,
|
||||
type: [String, Function] as PropType<MiniMapProps['nodeColor']>,
|
||||
required: false,
|
||||
default: '#fff'
|
||||
},
|
||||
nodeClassName: {
|
||||
type: (String || Function) as PropType<MiniMapProps['nodeClassName']>,
|
||||
type: [String, Function] as PropType<MiniMapProps['nodeClassName']>,
|
||||
required: false,
|
||||
default: ''
|
||||
},
|
||||
@@ -57,17 +57,15 @@ const MiniMap = defineComponent({
|
||||
setup(props, { attrs }: { attrs: Record<string, any> }) {
|
||||
const pinia = store();
|
||||
const transform = computed(() => pinia.transform);
|
||||
|
||||
const mapClasses = ['revue-flow__minimap'];
|
||||
const elementWidth = computed(() => (attrs.style?.width || defaultWidth)! as number);
|
||||
const elementHeight = computed(() => (attrs.style?.height || defaultHeight)! as number);
|
||||
const nodeColorFunc = (props.nodeColor instanceof Function ? props.nodeColor : () => props.nodeColor) as StringFunc;
|
||||
const nodeStrokeColorFunc = (
|
||||
props.nodeStrokeColor instanceof Function ? props.nodeStrokeColor : () => props.nodeStrokeColor
|
||||
) as StringFunc;
|
||||
const nodeClassNameFunc = (
|
||||
props.nodeClassName instanceof Function ? props.nodeClassName : () => props.nodeClassName
|
||||
) as StringFunc;
|
||||
const nodeColorFunc = computed(() => (props.nodeColor instanceof Function ? props.nodeColor : () => props.nodeColor) as StringFunc);
|
||||
const nodeStrokeColorFunc = computed(
|
||||
() => (props.nodeStrokeColor instanceof Function ? props.nodeStrokeColor : () => props.nodeStrokeColor) as StringFunc
|
||||
);
|
||||
const nodeClassNameFunc = computed(
|
||||
() => (props.nodeClassName instanceof Function ? props.nodeClassName : () => props.nodeClassName) as StringFunc
|
||||
);
|
||||
const hasNodes = computed(() => pinia.nodes && pinia.nodes.length);
|
||||
const bb = computed(() => getRectOfNodes(pinia.nodes));
|
||||
const viewBB = computed<Rect>(() => ({
|
||||
@@ -94,7 +92,7 @@ const MiniMap = defineComponent({
|
||||
width={elementWidth.value}
|
||||
height={elementHeight.value}
|
||||
viewBox={`${x.value} ${y.value} ${width.value} ${height.value}`}
|
||||
class={mapClasses}
|
||||
class="revue-flow__minimap"
|
||||
>
|
||||
{pinia.nodes
|
||||
.filter((node) => !node.isHidden)
|
||||
@@ -106,10 +104,10 @@ const MiniMap = defineComponent({
|
||||
width={node.__rf.width}
|
||||
height={node.__rf.height}
|
||||
style={node.style}
|
||||
class={nodeClassNameFunc(node)}
|
||||
color={nodeColorFunc(node)}
|
||||
class={nodeClassNameFunc.value(node)}
|
||||
color={nodeColorFunc.value(node)}
|
||||
borderRadius={props.nodeBorderRadius}
|
||||
strokeColor={nodeStrokeColorFunc(node)}
|
||||
strokeColor={nodeStrokeColorFunc.value(node)}
|
||||
strokeWidth={props.nodeStrokeWidth}
|
||||
shapeRendering={shapeRendering}
|
||||
/>
|
||||
|
||||
@@ -35,10 +35,13 @@ export function getBezierPath({
|
||||
let path = `M${sourceX},${sourceY} C${sourceX},${cY} ${targetX},${cY} ${targetX},${targetY}`;
|
||||
|
||||
if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
|
||||
console.log('foo');
|
||||
path = `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}`;
|
||||
} else if (leftAndRight.includes(targetPosition)) {
|
||||
console.log('bar');
|
||||
path = `M${sourceX},${sourceY} C${sourceX},${targetY} ${sourceX},${targetY} ${targetX},${targetY}`;
|
||||
} else if (leftAndRight.includes(sourcePosition)) {
|
||||
console.log('baz');
|
||||
path = `M${sourceX},${sourceY} C${targetX},${sourceY} ${targetX},${sourceY} ${targetX},${targetY}`;
|
||||
}
|
||||
|
||||
@@ -82,9 +85,9 @@ const BezierEdge = defineComponent({
|
||||
required: true
|
||||
},
|
||||
labelStyle: {
|
||||
type: Object as PropType<any>,
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({})
|
||||
default: undefined
|
||||
},
|
||||
labelShowBg: {
|
||||
type: Boolean,
|
||||
@@ -153,11 +156,11 @@ const BezierEdge = defineComponent({
|
||||
/>
|
||||
) : null;
|
||||
|
||||
const markerEnd = getMarkerEnd(props.arrowHeadType, props.markerEndId);
|
||||
const markerEnd = computed(() => getMarkerEnd(props.arrowHeadType, props.markerEndId));
|
||||
|
||||
return () => (
|
||||
<>
|
||||
<path style={props.style} d={path.value} class="revue-flow__edge-path" marker-end={markerEnd} />
|
||||
<path style={props.style} d={path.value} class="revue-flow__edge-path" marker-end={markerEnd.value} />
|
||||
{text}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Position } from '../../types';
|
||||
import { defineComponent, HTMLAttributes, PropType } from 'vue';
|
||||
import { computed, defineComponent, HTMLAttributes, PropType } from 'vue';
|
||||
|
||||
const shiftX = (x: number, shift: number, position: Position): number => {
|
||||
if (position === Position.Left) return x - shift;
|
||||
@@ -41,13 +41,13 @@ export const EdgeAnchor = defineComponent({
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const radius = props.radius || 10;
|
||||
const radius = computed(() => props.radius || 10);
|
||||
return () => (
|
||||
<circle
|
||||
class="revue-flow__edgeupdater"
|
||||
cx={shiftX(props.centerX, radius, props.position)}
|
||||
cy={shiftY(props.centerY, radius, props.position)}
|
||||
r={radius}
|
||||
cx={shiftX(props.centerX, radius.value, props.position)}
|
||||
cy={shiftY(props.centerY, radius.value, props.position)}
|
||||
r={radius.value}
|
||||
stroke="transparent"
|
||||
fill="transparent"
|
||||
/>
|
||||
|
||||
@@ -28,8 +28,7 @@ const EdgeText = defineComponent({
|
||||
default: () => ({})
|
||||
},
|
||||
labelBgPadding: {
|
||||
/* @ts-ignore */
|
||||
type: Array as PropType<[number, number]>,
|
||||
type: Array as unknown as PropType<[number, number]>,
|
||||
default: () => [2, 4]
|
||||
},
|
||||
labelBgBorderRadius: {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, computed, defineComponent, ref } from 'vue';
|
||||
import { Component, computed, defineComponent, PropType, ref } from 'vue';
|
||||
|
||||
import store from '../../store';
|
||||
import { Edge, EdgeProps, Position, WrapEdgeProps } from '../../types';
|
||||
@@ -8,11 +8,188 @@ import { EdgeAnchor } from './EdgeAnchor';
|
||||
export default (EdgeComponent: any): Component<EdgeProps> => {
|
||||
return defineComponent({
|
||||
components: { EdgeComponent },
|
||||
props: WrapEdgeProps,
|
||||
props: {
|
||||
id: {
|
||||
type: String as PropType<WrapEdgeProps['id']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
type: {
|
||||
type: String as PropType<WrapEdgeProps['type']>,
|
||||
required: true
|
||||
},
|
||||
data: {
|
||||
type: String as PropType<WrapEdgeProps['data']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
onClick: {
|
||||
type: Function as unknown as PropType<WrapEdgeProps['onClick']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
onEdgeDoubleClick: {
|
||||
type: Function as unknown as PropType<WrapEdgeProps['onEdgeDoubleClick']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
selected: {
|
||||
type: Boolean as PropType<WrapEdgeProps['selected']>,
|
||||
required: true,
|
||||
default: false
|
||||
},
|
||||
animated: {
|
||||
type: Boolean as PropType<WrapEdgeProps['animated']>,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
label: {
|
||||
type: Object as PropType<WrapEdgeProps['label']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
labelStyle: {
|
||||
type: Object as PropType<WrapEdgeProps['labelStyle']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
labelShowBg: {
|
||||
type: Boolean as PropType<WrapEdgeProps['labelShowBg']>,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
labelBgStyle: {
|
||||
type: Object as PropType<WrapEdgeProps['labelBgStyle']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
labelBgPadding: {
|
||||
type: Array as unknown as PropType<WrapEdgeProps['labelBgPadding']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
labelBgBorderRadius: {
|
||||
type: Number as PropType<WrapEdgeProps['labelBgBorderRadius']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
style: {
|
||||
type: Object as PropType<WrapEdgeProps['style']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
arrowHeadType: {
|
||||
type: String as PropType<WrapEdgeProps['arrowHeadType']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
source: {
|
||||
type: String as PropType<WrapEdgeProps['source']>,
|
||||
required: true
|
||||
},
|
||||
target: {
|
||||
type: String as PropType<WrapEdgeProps['target']>,
|
||||
required: true
|
||||
},
|
||||
sourceHandleId: {
|
||||
type: String as PropType<WrapEdgeProps['sourceHandleId']>,
|
||||
required: true,
|
||||
default: null
|
||||
},
|
||||
targetHandleId: {
|
||||
type: String as PropType<WrapEdgeProps['targetHandleId']>,
|
||||
required: true,
|
||||
default: null
|
||||
},
|
||||
sourceX: {
|
||||
type: Number as PropType<WrapEdgeProps['sourceX']>,
|
||||
required: true
|
||||
},
|
||||
sourceY: {
|
||||
type: Number as PropType<WrapEdgeProps['sourceY']>,
|
||||
required: true
|
||||
},
|
||||
targetX: {
|
||||
type: Number as PropType<WrapEdgeProps['targetX']>,
|
||||
required: true
|
||||
},
|
||||
targetY: {
|
||||
type: Number as PropType<WrapEdgeProps['targetY']>,
|
||||
required: true
|
||||
},
|
||||
sourcePosition: {
|
||||
type: String as PropType<WrapEdgeProps['sourcePosition']>,
|
||||
required: true
|
||||
},
|
||||
targetPosition: {
|
||||
type: String as PropType<WrapEdgeProps['targetPosition']>,
|
||||
required: true
|
||||
},
|
||||
elementsSelectable: {
|
||||
type: Boolean as PropType<WrapEdgeProps['elementsSelectable']>,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
markerEndId: {
|
||||
type: String as PropType<WrapEdgeProps['markerEndId']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
isHidden: {
|
||||
type: Boolean as PropType<WrapEdgeProps['isHidden']>,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
handleEdgeUpdate: {
|
||||
type: Boolean as PropType<WrapEdgeProps['handleEdgeUpdate']>,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
onConnectEdge: {
|
||||
type: Function as PropType<WrapEdgeProps['onConnectEdge']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
onContextMenu: {
|
||||
type: Function as unknown as PropType<WrapEdgeProps['onContextMenu']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
onMouseEnter: {
|
||||
type: Function as unknown as PropType<WrapEdgeProps['onMouseEnter']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
onMouseMove: {
|
||||
type: Function as unknown as PropType<WrapEdgeProps['onMouseMove']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
onMouseLeave: {
|
||||
type: Function as unknown as PropType<WrapEdgeProps['onMouseLeave']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
edgeUpdaterRadius: {
|
||||
type: Number as PropType<WrapEdgeProps['edgeUpdaterRadius']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
onEdgeUpdateStart: {
|
||||
type: Function as unknown as PropType<WrapEdgeProps['onEdgeUpdateStart']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
onEdgeUpdateEnd: {
|
||||
type: Function as unknown as PropType<WrapEdgeProps['onEdgeUpdateEnd']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const pinia = store();
|
||||
const updating = ref<boolean>(false);
|
||||
const inactive = !props.elementsSelectable && !props.onClick;
|
||||
const inactive = computed(() => !props.elementsSelectable && !props.onClick);
|
||||
const edgeClasses = computed(() => [
|
||||
'revue-flow__edge',
|
||||
`revue-flow__edge-${props.type}`,
|
||||
@@ -21,9 +198,9 @@ export default (EdgeComponent: any): Component<EdgeProps> => {
|
||||
|
||||
const edgeElement = computed<Edge>(() => {
|
||||
const el: Edge = {
|
||||
id: props.id || '',
|
||||
source: props.source || '',
|
||||
target: props.target || '',
|
||||
id: props.id as string,
|
||||
source: props.source,
|
||||
target: props.target,
|
||||
type: props.type
|
||||
};
|
||||
|
||||
@@ -48,23 +225,23 @@ export default (EdgeComponent: any): Component<EdgeProps> => {
|
||||
pinia.addSelectedElements(edgeElement.value as any);
|
||||
}
|
||||
|
||||
if (props.onClick) props.onClick?.(event, edgeElement.value);
|
||||
if (typeof props.onClick === 'function') props.onClick(event, edgeElement.value);
|
||||
};
|
||||
|
||||
const onEdgeContextMenu = (event: MouseEvent) => {
|
||||
if (typeof props.onContextMenu === 'function') props.onContextMenu?.(event, edgeElement.value);
|
||||
if (typeof props.onContextMenu === 'function') props.onContextMenu(event, edgeElement.value);
|
||||
};
|
||||
|
||||
const onEdgeMouseEnter = (event: MouseEvent) => {
|
||||
if (typeof props.onMouseEnter === 'function') props.onMouseEnter?.(event, edgeElement.value);
|
||||
if (typeof props.onMouseEnter === 'function') props.onMouseEnter(event, edgeElement.value);
|
||||
};
|
||||
|
||||
const onEdgeMouseMove = (event: MouseEvent) => {
|
||||
if (typeof props.onMouseMove === 'function') props.onMouseMove?.(event, edgeElement.value);
|
||||
if (typeof props.onMouseMove === 'function') props.onMouseMove(event, edgeElement.value);
|
||||
};
|
||||
|
||||
const onEdgeMouseLeave = (event: MouseEvent) => {
|
||||
if (typeof props.onMouseLeave === 'function') props.onMouseLeave?.(event, edgeElement.value);
|
||||
if (typeof props.onMouseLeave === 'function') props.onMouseLeave(event, edgeElement.value);
|
||||
};
|
||||
|
||||
const handleEdgeUpdater = (event: MouseEvent, isSourceHandle: boolean) => {
|
||||
@@ -84,7 +261,7 @@ export default (EdgeComponent: any): Component<EdgeProps> => {
|
||||
onMouseDown(
|
||||
event,
|
||||
handleId,
|
||||
nodeId || '',
|
||||
nodeId,
|
||||
pinia.setConnectionNodeId,
|
||||
pinia.setConnectionPosition,
|
||||
props.onConnectEdge as any,
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
} from '../../types';
|
||||
import { computed, CSSProperties, defineComponent, PropType } from 'vue';
|
||||
import store from '../../store';
|
||||
import MarkerDefinitions from './MarkerDefinitions';
|
||||
|
||||
interface EdgeRendererProps {
|
||||
edgeTypes: any;
|
||||
@@ -101,8 +102,6 @@ const EdgeCmp = defineComponent({
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const sourceHandleId = computed(() => props.edge.sourceHandle || null);
|
||||
const targetHandleId = computed(() => props.edge.targetHandle || null);
|
||||
const nodes = computed(() => getSourceTargetNodes(props.edge, props.nodes));
|
||||
|
||||
const onConnectEdge = (connection: Connection) => {
|
||||
@@ -119,20 +118,20 @@ const EdgeCmp = defineComponent({
|
||||
return () => null;
|
||||
}
|
||||
|
||||
const edgeType = props.edge.type || 'default';
|
||||
const EdgeComponent: any = props.props.edgeTypes[edgeType] || props.props.edgeTypes.default;
|
||||
const targetNodeBounds = nodes.value.targetNode.__rf.handleBounds;
|
||||
const EdgeComponent: any = props.props.edgeTypes[props.edge.type as string] || props.props.edgeTypes.default;
|
||||
const targetNodeBounds = computed(() => nodes.value.targetNode?.__rf.handleBounds);
|
||||
// when connection type is loose we can define all handles as sources
|
||||
const targetNodeHandles =
|
||||
const targetNodeHandles = computed(() =>
|
||||
props.connectionMode === ConnectionMode.Strict
|
||||
? targetNodeBounds.target
|
||||
: targetNodeBounds.target || targetNodeBounds.source;
|
||||
const sourceHandle = computed(
|
||||
() => nodes.value.sourceNode && getHandle(nodes.value.sourceNode.__rf.handleBounds.source, sourceHandleId.value)
|
||||
? targetNodeBounds.value?.target
|
||||
: targetNodeBounds.value?.target || targetNodeBounds.value?.source
|
||||
);
|
||||
const targetHandle = computed(() => getHandle(targetNodeHandles, targetHandleId.value));
|
||||
const sourcePosition = sourceHandle.value ? sourceHandle.value.position : Position.Bottom;
|
||||
const targetPosition = targetHandle.value ? targetHandle.value.position : Position.Top;
|
||||
const sourceHandle = computed(
|
||||
() => nodes.value.sourceNode && getHandle(nodes.value.sourceNode.__rf.handleBounds.source, props.edge.sourceHandle || null)
|
||||
);
|
||||
const targetHandle = computed(() => getHandle(targetNodeHandles.value, props.edge.targetHandle || null));
|
||||
const sourcePosition = computed(() => (sourceHandle.value ? sourceHandle.value.position : Position.Bottom));
|
||||
const targetPosition = computed(() => (targetHandle.value ? targetHandle.value.position : Position.Top));
|
||||
|
||||
const edgePositions = computed(() => {
|
||||
return (
|
||||
@@ -140,11 +139,11 @@ const EdgeCmp = defineComponent({
|
||||
nodes.value.targetNode &&
|
||||
getEdgePositions(
|
||||
nodes.value.sourceNode,
|
||||
sourceHandle,
|
||||
sourcePosition,
|
||||
sourceHandle.value,
|
||||
sourcePosition.value,
|
||||
nodes.value.targetNode,
|
||||
targetHandle,
|
||||
targetPosition
|
||||
targetHandle.value,
|
||||
targetPosition.value
|
||||
)
|
||||
);
|
||||
});
|
||||
@@ -188,8 +187,8 @@ const EdgeCmp = defineComponent({
|
||||
arrowHeadType={props.edge.arrowHeadType}
|
||||
source={props.edge.source}
|
||||
target={props.edge.target}
|
||||
sourceHandleId={sourceHandleId}
|
||||
targetHandleId={targetHandleId}
|
||||
sourceHandleId={props.edge.sourceHandle}
|
||||
targetHandleId={props.edge.targetHandle}
|
||||
sourceX={edgePositions.value?.sourceX}
|
||||
sourceY={edgePositions.value?.sourceY}
|
||||
targetX={edgePositions.value?.targetX}
|
||||
@@ -218,7 +217,8 @@ const EdgeRenderer = defineComponent({
|
||||
name: 'EdgeRenderer',
|
||||
components: {
|
||||
EdgeCmp,
|
||||
ConnectionLine
|
||||
ConnectionLine,
|
||||
MarkerDefinitions
|
||||
},
|
||||
props: {
|
||||
edgeTypes: {
|
||||
@@ -247,12 +247,12 @@ const EdgeRenderer = defineComponent({
|
||||
default: undefined
|
||||
},
|
||||
onElementClick: {
|
||||
type: Function() as PropType<EdgeRendererProps['onElementClick']>,
|
||||
type: Function as unknown as PropType<EdgeRendererProps['onElementClick']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
onEdgeDoubleClick: {
|
||||
type: Function() as PropType<EdgeRendererProps['onEdgeDoubleClick']>,
|
||||
type: Function as unknown as PropType<EdgeRendererProps['onEdgeDoubleClick']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
@@ -272,37 +272,37 @@ const EdgeRenderer = defineComponent({
|
||||
default: undefined
|
||||
},
|
||||
onEdgeUpdate: {
|
||||
type: Function() as PropType<EdgeRendererProps['onEdgeUpdate']>,
|
||||
type: Function as unknown as PropType<EdgeRendererProps['onEdgeUpdate']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
onEdgeContextMenu: {
|
||||
type: Function() as PropType<EdgeRendererProps['onEdgeContextMenu']>,
|
||||
type: Function as unknown as PropType<EdgeRendererProps['onEdgeContextMenu']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
onEdgeMouseEnter: {
|
||||
type: Function() as PropType<EdgeRendererProps['onEdgeMouseEnter']>,
|
||||
type: Function as unknown as PropType<EdgeRendererProps['onEdgeMouseEnter']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
onEdgeMouseMove: {
|
||||
type: Function() as PropType<EdgeRendererProps['onEdgeMouseMove']>,
|
||||
type: Function as unknown as PropType<EdgeRendererProps['onEdgeMouseMove']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
onEdgeMouseLeave: {
|
||||
type: Function() as PropType<EdgeRendererProps['onEdgeMouseLeave']>,
|
||||
type: Function as unknown as PropType<EdgeRendererProps['onEdgeMouseLeave']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
onEdgeUpdateStart: {
|
||||
type: Function() as PropType<EdgeRendererProps['onEdgeUpdateStart']>,
|
||||
type: Function as unknown as PropType<EdgeRendererProps['onEdgeUpdateStart']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
onEdgeUpdateEnd: {
|
||||
type: Function() as PropType<EdgeRendererProps['onEdgeUpdateEnd']>,
|
||||
type: Function as unknown as PropType<EdgeRendererProps['onEdgeUpdateEnd']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
@@ -314,11 +314,15 @@ const EdgeRenderer = defineComponent({
|
||||
},
|
||||
setup(props) {
|
||||
const pinia = store();
|
||||
const transformStyle = computed(() => `translate(${pinia.transform[0]},${pinia.transform[1]}) scale(${pinia.transform[2]})`);
|
||||
const transform = computed(() => pinia.transform);
|
||||
const transformStyle = computed(() => {
|
||||
return `translate(${transform.value[0]},${transform.value[1]}) scale(${transform.value[2]})`;
|
||||
});
|
||||
const renderConnectionLine = computed(() => pinia.connectionNodeId && pinia.connectionHandleType);
|
||||
|
||||
return () => (
|
||||
<svg width={pinia.width} height={pinia.height} class="revue-flow__edges">
|
||||
<MarkerDefinitions color={props.arrowHeadColor || ''} />
|
||||
<g transform={transformStyle.value}>
|
||||
{pinia.edges.map((edge: Edge) => (
|
||||
<EdgeCmp
|
||||
|
||||
@@ -34,6 +34,7 @@ export function getHandlePosition(position: Position, node: Node, handle: any |
|
||||
const width = handle?.width || node.__rf.width;
|
||||
const height = handle?.height || node.__rf.height;
|
||||
|
||||
console.log(handle?.x, handle?.y);
|
||||
switch (position) {
|
||||
case Position.Top:
|
||||
return {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { computed, CSSProperties, defineComponent, HTMLAttributes, onUpdated, PropType } from 'vue';
|
||||
import { computed, CSSProperties, defineComponent, HTMLAttributes, onBeforeUnmount, onUpdated, PropType } from 'vue';
|
||||
import GraphView from '../GraphView';
|
||||
import DefaultNode from '../../components/Nodes/DefaultNode';
|
||||
import InputNode from '../../components/Nodes/InputNode';
|
||||
@@ -27,7 +27,6 @@ import {
|
||||
OnEdgeUpdateFunc,
|
||||
NodeExtent
|
||||
} from '../../types';
|
||||
|
||||
import '../../style.css';
|
||||
import '../../theme-default.css';
|
||||
import store from '../../store';
|
||||
@@ -259,7 +258,7 @@ const RevueFlow = defineComponent({
|
||||
connectionLineStyle: {
|
||||
type: Object as PropType<RevueFlowProps['connectionLineStyle']>,
|
||||
required: false,
|
||||
default: () => ({} as CSSProperties)
|
||||
default: undefined
|
||||
},
|
||||
connectionLineComponent: {
|
||||
type: Object as PropType<RevueFlowProps['connectionLineComponent']>,
|
||||
@@ -459,12 +458,15 @@ const RevueFlow = defineComponent({
|
||||
pinia.setElements(props.elements);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
pinia.setElements([]);
|
||||
});
|
||||
|
||||
const nodeTypesParsed = computed(() => props.nodeTypes && createNodeTypes(props.nodeTypes));
|
||||
const edgeTypesParsed = computed(() => props.edgeTypes && createEdgeTypes(props.edgeTypes));
|
||||
const reactFlowClasses = ['revue-flow'];
|
||||
|
||||
return () => (
|
||||
<div class={reactFlowClasses}>
|
||||
<div class="revue-flow">
|
||||
<GraphView
|
||||
onLoad={props.onLoad}
|
||||
onMove={props.onMove}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
|
||||
const app = createApp(App);
|
||||
app.config.performance = true;
|
||||
app.mount('#app');
|
||||
Vendored
+6
@@ -4,3 +4,9 @@ declare module '*.vue' {
|
||||
const component: DefineComponent<{}, {}, any>;
|
||||
export default component;
|
||||
}
|
||||
|
||||
declare namespace JSX {
|
||||
export interface IntrinsicElements {
|
||||
[key: string]: any;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { setActivePinia, createPinia, defineStore, StoreDefinition } from 'pinia';
|
||||
import { setActivePinia, createPinia, defineStore, StoreDefinition, Pinia } from 'pinia';
|
||||
import { inject } from 'vue';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { Edge, Node, NodeDiffUpdate, ReactFlowState, RevueFlowActionsTree, XYPosition } from '../types';
|
||||
import { getConnectedEdges, getNodesInside, getRectOfNodes, isEdge, isNode, parseEdge, parseNode } from '../utils/graph';
|
||||
@@ -10,12 +11,12 @@ type NextElements = {
|
||||
nextEdges: Edge[];
|
||||
};
|
||||
|
||||
const pinia = createPinia();
|
||||
setActivePinia(pinia);
|
||||
|
||||
export default function configureStore(
|
||||
preloadedState: ReactFlowState
|
||||
): StoreDefinition<'revue-flow', ReactFlowState, any, RevueFlowActionsTree> {
|
||||
const pinia = inject<Pinia>(Symbol('pinia')) ?? createPinia();
|
||||
setActivePinia(pinia);
|
||||
|
||||
return defineStore({
|
||||
id: 'revue-flow',
|
||||
state: () => preloadedState,
|
||||
|
||||
+1
-1
@@ -58,6 +58,6 @@ export const initialState: ReactFlowState = {
|
||||
|
||||
const store = configureStore(initialState);
|
||||
|
||||
export type ReactFlowDispatch = RevueFlowActionsTree;
|
||||
export type RevueFlowDispatch = RevueFlowActionsTree;
|
||||
|
||||
export default store;
|
||||
|
||||
Vendored
+1
@@ -1 +1,2 @@
|
||||
/// <reference types="vite/client" />
|
||||
/// <reference types="vite-svg-loader" />
|
||||
|
||||
Reference in New Issue
Block a user