-
Notifications
You must be signed in to change notification settings - Fork 263
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(graphin):add graphin-line shape
- Loading branch information
1 parent
228f530
commit 8fc761b
Showing
1 changed file
with
160 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,123 +1,174 @@ | ||
import G6, { IGroup, IShape, IEdge } from '@antv/g6'; | ||
import { isString } from '@antv/util'; | ||
// @ts-nocheck | ||
import { Group } from '@antv/g-canvas'; | ||
import G6, { EdgeConfig, EdgeConfig } from '@antv/g6'; | ||
|
||
import { IUserEdge } from '../typings/type'; | ||
import { deepMix } from '@antv/util'; | ||
import { EdgeStyle } from '../typings/type'; | ||
import { setStatusStyle } from './utils'; | ||
|
||
export enum EnumNodeAndEdgeStatus { | ||
NORMAL = 'normal', | ||
SELECTED = 'selected', | ||
HOVERED = 'hovered', | ||
DISABLED = 'disabled', | ||
} | ||
|
||
export function removeDumpAttrs(attrs) { | ||
Object.keys(attrs).forEach(key => { | ||
if (attrs[key] === undefined) { | ||
delete attrs[key]; | ||
} | ||
}); | ||
return attrs; | ||
} | ||
export function parseLabel(json) { | ||
const { value, ...others } = json; | ||
const attrs = { | ||
id: 'label', | ||
x: 0, | ||
y: 0, | ||
text: value, | ||
...others, | ||
}; | ||
return removeDumpAttrs(attrs); | ||
} | ||
|
||
export function parseKeyShape(json) { | ||
const { ...others } = json; | ||
const attrs = { | ||
id: 'keyshape', | ||
...others, | ||
}; | ||
return removeDumpAttrs(attrs); | ||
} | ||
|
||
export function parseHalo(json) { | ||
const { ...others } = json; | ||
const attrs = { | ||
id: 'halo', | ||
...others, | ||
}; | ||
return removeDumpAttrs(attrs); | ||
} | ||
|
||
const parseAttr = (style, itemShapeName: string) => { | ||
if (itemShapeName === 'keyshape') { | ||
return parseKeyShape(style); | ||
} | ||
if (itemShapeName === 'halo') { | ||
return parseKeyShape(style); | ||
} | ||
if (itemShapeName === 'label') { | ||
return parseLabel(style); | ||
} | ||
return style; | ||
}; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export default () => { | ||
G6.registerEdge( | ||
'graphin-line', | ||
{ | ||
options: { | ||
style: { | ||
stroke: 'rgb(239, 244, 255)', | ||
opacity: 1, | ||
labelCfg: { | ||
fill: 'rgb(0, 0, 0)', | ||
fontSize: 12, | ||
}, | ||
}, | ||
status: { | ||
selected: { | ||
fill: 'rgb(239, 244, 255)', | ||
}, | ||
hover: { | ||
fill: 'rgb(239, 244, 255)', | ||
}, | ||
}, | ||
}, | ||
G6.registerEdge('graphin-line', { | ||
draw(cfg: EdgeConfig, group: Group) { | ||
try { | ||
const style = deepMix({}, cfg.style) as EdgeStyle; | ||
/** 将初始化样式存储在model中 */ | ||
|
||
// eslint-disable-next-line no-underscore-dangle | ||
cfg._initialStyle = { ...style }; | ||
|
||
const { label, halo, keyshape: keyShapeStyle } = style; | ||
|
||
afterDraw(cfg: IUserEdge, group: IGroup, keyShape: IShape) { | ||
const path = keyShape.attr('path'); | ||
const lineWidth = keyShape.attr('lineWidth'); | ||
const shape = group.addShape('path', { | ||
const hasLabel = label.value; | ||
const { startPoint, endPoint } = cfg; | ||
|
||
const d = (keyShapeStyle?.lineWidth || 1) + 1; | ||
// TODO:支持多边 | ||
const path = [ | ||
['M', startPoint.x, startPoint.y], | ||
['L', endPoint.x, endPoint.y], | ||
]; | ||
|
||
/** 光环 */ | ||
group.addShape('path', { | ||
attrs: { | ||
id: 'halo', | ||
path, | ||
lineWidth: lineWidth * 10, | ||
// opacity: 0.1, | ||
stroke: 'rgb(239, 244, 255)', | ||
lineWidth: keyShapeStyle.lineWidth + 10, | ||
...halo, | ||
}, | ||
name: 'external-shape', | ||
draggable: true, | ||
name: 'halo', | ||
visible: false, | ||
}); | ||
shape.toBack(); | ||
}, | ||
|
||
setState(name: string, value: string, item: IEdge) { | ||
const keyShape = item.getKeyShape(); | ||
const group = item.get('group'); | ||
const model = item.getModel() as IUserEdge; | ||
const children = group.get('children'); | ||
if (!model.status || !model.status[name]) return; | ||
|
||
const shape = children.find((element: any) => element.get('name') === 'external-shape'); | ||
if (value) { | ||
// selected 状态显示边上的 shape | ||
if (name === 'selected') { | ||
shape.show(); | ||
} | ||
|
||
// 是否有配置动画 | ||
const { animation, ...otherAttr } = model.status[name]; | ||
for (let key in otherAttr) { | ||
const value = (otherAttr as any)[key]; | ||
keyShape.attr(key, value); | ||
} | ||
/** 主路径 */ | ||
const key = group.addShape('path', { | ||
attrs: { | ||
id: 'keyshape', | ||
path, | ||
endArrow: { | ||
d: -d / 2, | ||
path: `M 0,0 L ${d},${d / 2} L ${d},-${d / 2} Z`, | ||
}, | ||
...keyShapeStyle, | ||
}, | ||
draggable: true, | ||
name: 'keyshape', | ||
}); | ||
|
||
if (animation) { | ||
const { delay = 0, duration = 3000, easing = 'easeLinear', repeat = true } = animation; | ||
let index = 0; | ||
keyShape.animate( | ||
() => { | ||
index++; | ||
if (index > 9) { | ||
index = 0; | ||
} | ||
|
||
const conf = { | ||
lineDash: [3, 3], | ||
lineDashOffset: -index, | ||
}; | ||
|
||
return conf; | ||
}, | ||
{ | ||
easing, | ||
delay, | ||
repeat, | ||
duration, | ||
}, | ||
); | ||
} | ||
} else { | ||
shape.hide(); | ||
keyShape.stopAnimate(); | ||
keyShape.attr('lineDash', null); | ||
|
||
// 恢复到原来的样式 | ||
const originStyle = item.getOriginStyle() as any; | ||
for (let key in originStyle) { | ||
const currentShape = children.find((element: any) => element.get('name') === key); | ||
if (currentShape) { | ||
for (let value in originStyle[key]) { | ||
const currentValue = originStyle[key][value]; | ||
if (isString(currentValue)) { | ||
currentShape.attr(value, currentValue); | ||
} | ||
} | ||
/** 标签 */ | ||
if (hasLabel) { | ||
const { value, ...others } = label; | ||
const labelShape = group.addShape('text', { | ||
attrs: { | ||
id: 'label', | ||
x: 0, | ||
y: 0, | ||
text: value, | ||
...others, | ||
}, | ||
draggable: true, | ||
name: 'label', | ||
}); | ||
/** 处理标签自动旋转问题 */ | ||
labelShape.rotate( | ||
endPoint.x - startPoint.x === 0 | ||
? Math.PI / 2 | ||
: Math.atan((endPoint.y - startPoint.y) / (endPoint.x - startPoint.x)), | ||
); | ||
labelShape.translate((startPoint.x + endPoint.x) / 2, (startPoint.y + endPoint.y) / 2); | ||
} | ||
return key; | ||
} catch (error) { | ||
console.error(error); | ||
} | ||
}, | ||
setState(name: EnumNodeAndEdgeStatus, value: string, item: EdgeConfig) { | ||
if (!name) return; | ||
const model = item.getModel() as EdgeConfig; | ||
const shapes = item.getContainer().get('children'); // 顺序根据 draw 时确定 | ||
const initStateStyle = deepMix({}, model.style.status); | ||
|
||
const initialStyle = item.getModel()._initialStyle as EdgeStyle; | ||
|
||
const status = item._cfg?.states || []; | ||
|
||
try { | ||
Object.keys(initStateStyle).forEach(statusKey => { | ||
if (name === statusKey) { | ||
if (value) { | ||
setStatusStyle(shapes, initStateStyle[statusKey], parseAttr); // 匹配到status就改变 | ||
} else { | ||
setStatusStyle(shapes, initialStyle, parseAttr); // 没匹配到就重置 | ||
status.forEach(key => { | ||
// 如果cfg.status中还有其他状态,那就重新设置回来 | ||
setStatusStyle(shapes, initStateStyle[key], parseAttr); | ||
}); | ||
} | ||
} | ||
} | ||
}, | ||
afterUpdate(cfg: IUserEdge, item: IEdge) { | ||
const keyShape = item.getKeyShape(); | ||
const group = item.get('group'); | ||
const shape = group.get('children').find((element: any) => element.get('name') === 'external-shape'); | ||
if (shape) { | ||
shape.attr('path', keyShape.attr('path')); | ||
} | ||
}, | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
} as any, | ||
'line', | ||
); | ||
}); | ||
} catch (error) { | ||
console.error(error); | ||
} | ||
}, | ||
}); | ||
}; |