Skip to content

Commit

Permalink
feat: add graphin Behaviors
Browse files Browse the repository at this point in the history
  • Loading branch information
pomelo-nwu committed Oct 13, 2023
1 parent 3683a99 commit 4bacf75
Show file tree
Hide file tree
Showing 16 changed files with 482 additions and 24 deletions.
2 changes: 2 additions & 0 deletions packages/graphin/src/ExtendGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ export default extend(G6Graph, {
//@ts-ignore
'drag-canvas': Extensions.DragCanvas,
'drag-node': Extensions.DragNode,
'hover-activate': Extensions.HoverActivate,
'brush-select': Extensions.BrushSelect,
},
plugins: {
minimap: Extensions.Minimap,
Expand Down
15 changes: 10 additions & 5 deletions packages/graphin/src/Graphin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,12 @@ const Graphin: React.FunctionComponent<GraphinProps> = forwardRef((props, ref) =

const [state, setState] = useState<{
isReady: boolean;
graph: null | IGraph;
}>(() => ({
graph: IGraph;
}>({
isReady: false,
//@ts-ignore
graph: null,
}));
});
const { isReady, graph } = state;

if (dataRef.current !== data) {
Expand Down Expand Up @@ -109,7 +110,7 @@ const Graphin: React.FunctionComponent<GraphinProps> = forwardRef((props, ref) =
//@ts-ignore
edge,
// behaviors
modes = { default: ['zoom-canvas', 'drag-canvas', 'drag-node'] },
modes = { default: [], lasso: [] },
} = options;
const ContainerDOM = document.getElementById(container);

Expand Down Expand Up @@ -173,7 +174,11 @@ const Graphin: React.FunctionComponent<GraphinProps> = forwardRef((props, ref) =
</GraphinContext.Provider>
);
}
return <div id={container} style={containerStyle}></div>;
return (
<>
<div id={container} style={containerStyle}></div>
</>
);
});

export default memo(Graphin);
47 changes: 47 additions & 0 deletions packages/graphin/src/behaviors/ActivateRelations.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Extensions } from '@antv/g6';
import * as React from 'react';
import registerBehavior from './registerBehavior';
import useBehaviorHook from './useBehaviorHook';

const defaultConfig = {
/**
* @description 是否禁用该功能
* @default false
*/
disabled: false,
/**
* @description 可以是 mousenter,表示鼠标移入时触发;也可以是 click,鼠标点击时触发
* @default mouseenter
*/
trigger: 'mouseenter',
/**
* @description 活跃节点状态。当行为被触发,需要被突出显示的节点和边都会附带此状态,默认值为 active;可以与 graph 实例的 nodeStyle 和 edgeStyle 结合实现丰富的视觉效果。
* @default active
*/
activeState: 'active',
/**
* @description 非活跃节点状态。不需要被突出显示的节点和边都会附带此状态。默认值为 inactive。可以与 graph 实例的 nodeStyle 和 edgeStyle 结合实现丰富的视觉效果;
* @default inactive
*/
inactiveState: 'inactive',
/**
* @description 高亮相连节点时是否重置已经选中的节点,默认为 false,即选中的节点状态不会被 activate-relations 覆盖;
* @default false
*/
resetSelected: false,
};

export type ActivateRelationsProps = Partial<typeof defaultConfig>;

registerBehavior('activate-relations', Extensions.ActivateRelations);

const ActivateRelations: React.FunctionComponent<ActivateRelationsProps> = props => {
useBehaviorHook({
type: 'activate-relations',
userProps: props,
defaultConfig,
});
return null;
};

export default ActivateRelations;
41 changes: 41 additions & 0 deletions packages/graphin/src/behaviors/BrushSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as React from 'react';
import useBehaviorHook from './useBehaviorHook';

const DEFAULT_TRIGGER = 'shift';

const defaultConfig = {
/** 是否禁用该功能 */
disabled: false,
/** 拖动框选框的样式,包括 fill、fillOpacity、stroke 和 lineWidth 四个属性; */
brushStyle: {
fill: '#EEF6FF',
fillOpacity: 0.4,
stroke: '#DDEEFE',
lineWidth: 1,
},
/** 选中节点时的回调,参数 nodes 表示选中的节点; */
onSelect: () => {},
/** 取消选中节点时的回调,参数 nodes 表示取消选中的节点; */
onDeselect: () => {},
/** 选中的状态,默认值为 'selected' */
selectedState: 'selected',
/** 触发框选的动作,默认为 'shift',即用户按住 Shift 键拖动就可以进行框选操作,可配置的的选项为: 'shift'、'ctrl' / 'control'、'alt' 和 'drag' ,不区分大小写 */
trigger: DEFAULT_TRIGGER,
/** 框选过程中是否选中边,默认为 true,用户配置为 false 时,则不选中边; */
includeEdges: true,
/** Whether to include combos in the selection */
includeCombos: false,
};

export type IDragCanvasProps = Partial<typeof defaultConfig>;

const BrushSelect: React.FunctionComponent<IDragCanvasProps> = props => {
useBehaviorHook({
type: 'brush-select',
userProps: props,
defaultConfig,
});
return null;
};

export default BrushSelect;
35 changes: 35 additions & 0 deletions packages/graphin/src/behaviors/ClickSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import * as React from 'react';
import useBehaviorHook from './useBehaviorHook';

const DEFAULT_TRIGGER = 'shift';
// const ALLOW_EVENTS = ['shift', 'ctrl', 'alt', 'control'];

const defaultConfig = {
/** 是否禁用该功能 */
disabled: false,
/** 是否允许多选,默认为 true,当设置为 false,表示不允许多选,此时 trigger 参数无效; */
multiple: true,
/** 指定按住哪个键进行多选,默认为 shift,按住 Shift 键多选,用户可配置 shift、ctrl、alt; */
trigger: DEFAULT_TRIGGER,
/** 选中的样式,默认为 selected */
selectedState: 'selected',
/** Whether nodes can be selected */
selectNode: true,
/** Whether edges can be selected */
selectEdge: false,
/** Whether combos can be selected */
selectCombo: true,
};

export type IDragCanvasProps = Partial<typeof defaultConfig>;

const ClickSelect: React.FunctionComponent<IDragCanvasProps> = props => {
useBehaviorHook({
type: 'click-select',
userProps: props,
defaultConfig,
});
return null;
};

export default ClickSelect;
35 changes: 35 additions & 0 deletions packages/graphin/src/behaviors/DragCanvas.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import * as React from 'react';
import useBehaviorHook from './useBehaviorHook';

const defaultConfig = {
/** 允许拖拽方向,支持'x','y','both',默认方向为 'both'; */
direction: 'both',
/** 是否开启优化,开启后拖动画布过程中隐藏所有的边及节点上非 keyShape 部分,默认关闭; */
enableOptimize: false,
/**
* drag-canvas 可拖动的扩展范围,默认为 0,即最多可以拖动一屏的位置
* 当设置的值大于 0 时,即拖动可以超过一屏
* 当设置的值小于 0 时,相当于缩小了可拖动范围
* 具体实例可参考:https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*IFfoS67_HssAAAAAAAAAAAAAARQnAQ
*/
scalableRange: 0,
/** 是否允许触发该操作; */
shouldBegin: () => {
return true;
},
/** 是否禁用该功能 */
disabled: false,
};

export type IDragCanvasProps = Partial<typeof defaultConfig>;

const DragCanvas: React.FunctionComponent<IDragCanvasProps> = props => {
useBehaviorHook({
type: 'drag-canvas',
userProps: props,
defaultConfig,
});
return null;
};

export default DragCanvas;
30 changes: 30 additions & 0 deletions packages/graphin/src/behaviors/DragCombo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as React from 'react';
import useBehaviorHook from './useBehaviorHook';

const defaultConfig = {
/** 是否禁用该功能 */
disabled: false,
/** 拖动 Combo 时候是否开启图形代理 delegate,即拖动 Combo 时候 Combo 不会实时跟随变动,拖动过程中有临时生成一个 delegate 图形,拖动结束后才更新 Combo 位置,默认为 false,不开启 */
enableDelegate: false,
/** delegate 的样式 */
delegateStyle: {},
/** 拖动嵌套的 Combo 时,只改变父 Combo 的大小,不改变层级关系,默认为 false; */
onlyChangeComboSize: false,
/** 当拖动 Combo 时,父 Combo 或进入到的 Combo 的状态值,需要用户在实例化 Graph 时在 comboStateStyles 里面配置,默认为空; */
activeState: '',
/** 选中 Combo 的状态,默认为 selected,需要在 comboStateStyles 里面配置; */
selectedState: 'selected',
};

export type DragComboProps = Partial<typeof defaultConfig>;

const DragCombo: React.FunctionComponent<DragComboProps> = props => {
useBehaviorHook({
type: 'drag-combo',
userProps: props,
defaultConfig,
});
return null;
};

export default DragCombo;
53 changes: 53 additions & 0 deletions packages/graphin/src/behaviors/DragNode.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import * as React from 'react';
import useBehaviorHook from './useBehaviorHook';

const defaultConfig = {
/**
* @description 是否禁用该功能
* @default false
*/
disabled: false,
/**
* @description 是否在拖拽节点时更新所有与之相连的边,默认为 true
* @default true
*/
updateEdge: true,
/**
* @description 节点拖拽时的绘图属性
* @default { strokeOpacity: 0.6, fillOpacity: 0.6 }
*/
delegateStyle: {},
/**
* @description 是否开启delegate
* @default false
*/
enableDelegate: false,
/**
* @description 拖动节点过程中是否只改变 Combo 的大小,而不改变其结构
* @default false
*/
onlyChangeComboSize: false,
/**
* @description 拖动过程中目标 combo 状态样式
* @default ''
*/
comboActiveState: '',
/**
* @description 选中样式
* @default selected
*/
selectedState: 'selected',
};

export type DragNodeProps = Partial<typeof defaultConfig>;

const DragNode: React.FunctionComponent<DragNodeProps> = props => {
useBehaviorHook({
type: 'drag-node',
userProps: props,
defaultConfig,
});
return null;
};

export default DragNode;
59 changes: 59 additions & 0 deletions packages/graphin/src/behaviors/Hoverable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { IG6GraphEvent } from '@antv/g6';
import * as React from 'react';
import { GraphinContext } from '../useGraphin';

export interface HoverableProps {
bindType?: 'node' | 'edge';
disabled?: boolean;
}

const Hoverable: React.FunctionComponent<HoverableProps> = props => {
const graphin = React.useContext(GraphinContext);
const { bindType = 'node', disabled } = props;
const { graph } = graphin;
React.useEffect(() => {
if (disabled) {
return;
}

const handleNodeMouseEnter = (evt: IG6GraphEvent & any) => {
graph.setItemState(evt.item, 'hover', true);
};

const handleNodeMouseLeave = (evt: IG6GraphEvent & any) => {
graph.setItemState(evt.item, 'hover', false);
};

const handleEdgeMouseEnter = (evt: IG6GraphEvent & any) => {
graph.setItemState(evt.item, 'hover', true);
};

const handleEdgeMouseLeave = (evt: IG6GraphEvent & any) => {
graph.setItemState(evt.item, 'hover', false);
};

if (bindType === 'node') {
graph.on('node:mouseenter', handleNodeMouseEnter);
graph.on('node:mouseleave', handleNodeMouseLeave);
}
if (bindType === 'edge') {
graph.on('edge:mouseenter', handleEdgeMouseEnter);
graph.on('edge:mouseleave', handleEdgeMouseLeave);
}

return () => {
if (bindType === 'node') {
graph.off('node:mouseenter', handleNodeMouseEnter);
graph.off('node:mouseleave', handleNodeMouseLeave);
}
if (bindType === 'edge') {
graph.off('edge:mouseenter', handleEdgeMouseEnter);
graph.off('edge:mouseleave', handleEdgeMouseLeave);
}
};
}, [graph, disabled]);

return null;
};

export default Hoverable;
45 changes: 45 additions & 0 deletions packages/graphin/src/behaviors/LassoSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Extensions } from '@antv/g6';
import * as React from 'react';
import registerBehavior from './registerBehavior';
import useBehaviorHook from './useBehaviorHook';

const DEFAULT_TRIGGER = 'shift';

const defaultConfig = {
mode: 'lasso',
/** 是否禁用该功能 */
disabled: false,
/** 拖动框选框的样式,包括 fill、fillOpacity、stroke 和 lineWidth 四个属性; */
delegateStyle: {
fill: '#EEF6FF',
fillOpacity: 0.4,
stroke: '#DDEEFE',
lineWidth: 1,
},
/** 选中节点时的回调,参数 nodes 表示选中的节点; */
onSelect: () => {},
/** 取消选中节点时的回调,参数 nodes 表示取消选中的节点; */
onDeselect: () => {},
/** 选中的状态,默认值为 'selected' */
selectedState: 'selected',
/** 触发框选的动作,默认为 'shift',即用户按住 Shift 键拖动就可以进行框选操作,可配置的的选项为: 'shift'、'ctrl' / 'control'、'alt' 和 'drag' ,不区分大小写 */
trigger: DEFAULT_TRIGGER,
/** 框选过程中是否选中边,默认为 true,用户配置为 false 时,则不选中边; */
includeEdges: true,
};

export type LassoSelectProps = Partial<typeof defaultConfig>;

registerBehavior('lasso-select', Extensions.LassoSelect);

const LassoSelect: React.FunctionComponent<LassoSelectProps> = props => {
useBehaviorHook({
type: 'lasso-select',
userProps: props,
defaultConfig,
mode: (props && props.mode) || 'lasso',
});
return null;
};

export default LassoSelect;
Loading

0 comments on commit 4bacf75

Please sign in to comment.