高亮点击节点及其关联项:
const { ActivateRelations, DragCanvas, DragNode, ClickSelect } = Behaviors;
<ActivateRelations trigger="hover" resetSelected />//高亮行为组件
item.setState('selected', true);可以改变节点状态,然后走注册节点的setState周期
当使用ActivateRelations行为后,点击的节点及其相关项会graph.setItemState(item, 'active', true);
其他项会graph.setItemState(item, 'inactive', true);
点击画布时会触发相反的状态改变
基于此可以自定义样式:
setState(name, value, item) {
const group = item!.getContainer();
const header = group.find((e) => e.get('name') === 'rect-headGroup');
const content = group.find((e) => e.get('name') === 'rect-contentGroup');
const activeColor = '#CF1322';
if (value) {
if (name === 'active') {
header.attr({
shadowBlur: 20,
shadowColor: activeColor,
});
content.attr({
shadowBlur: 20,
shadowColor: activeColor,
});
} else if (name === 'inactive') {
group.attr({
opacity: 0.1,
});
}
} else {
header?.attr({
shadowColor: undefined,
});
content?.attr({
shadowColor: undefined,
});
group.attr({
opacity: 1,
});
}
},
提示框:
简单的做法,将需要触发toolTip的shape的name做一个标识:
maskGroup!.addShape('text', {
attrs: {
fill: '#fff',
fontSize: 14,
x: -55,
y: 0,
text: fittingString(id, 100, 14, 4),
textAlign: 'left',
textBaseline: 'middle',
opacity: 1,
},
name: 'mask-showToolTip-shape',
draggable: true,
});
然后注册:
export const tooltip = new G6.Tooltip({
offsetX: 20,
offsetY: 30,
itemTypes: ['node'],
getContent: (e) => {
const nodeName = ToolTipMap[e?.target.get('name')];
const model = e?.item?.getModel() as NodeCfg;
const text = JSON.stringify(model?.[nodeName]) ?? '';
return `${text}`;
},
shouldBegin: (e) => {
if (e?.target.get('name').includes('showToolTip')) {
return true;
}
return false;
},
});
根据model和name的映射关系来触发:
export const ToolTipMap = {
'text-code-showToolTip': 'id',
'text-dataType-showToolTip': 'nodeType',
'text-data-showToolTip': 'nodeData',
'mask-showToolTip-shape': 'id',
};
触屏双指滑动:
G6.registerBehavior('double-finger-drag-canvas', {
getEvents: function getEvents() {
return {
wheel: 'onWheel',
};
},
onWheel: function onWheel(ev: IG6GraphEvent) {
const graph = this.graph as Graph;
if (ev.ctrlKey) {
const canvas = graph.get('canvas');
const point = canvas.getPointByClient(ev.clientX, ev.clientY);
let ratio = graph.getZoom() as number;
if (ev.wheelDelta > 0) {
ratio = ratio + ratio * 0.05;
} else {
ratio = ratio - ratio * 0.05;
}
graph.zoomTo(ratio, {
x: point.x,
y: point.y,
});
} else {
const x = (ev.deltaX || ev.movementX) as number;
let y = (ev.deltaY || ev.movementY) as number;
if (!y && navigator.userAgent.indexOf('Firefox') > -1) y = (-ev.wheelDelta * 125) / 3;
graph.translate(-x, -y);
}
ev.preventDefault();
},
});
注意点:
onWheel为滚动事件,当函数被当做监听事件处理函数时, 其 this 指向触发该事件的元素 graph
navigator.userAgent可以获得当前浏览器的信息。
G6 中有三个坐标系:clientX/clientY、canvasX/canvasY、pointX/pointY。
clientX/clientY 坐标系的原点都在左上角
canvasX/canvsY 的原点在 Container DOM 的左上角
节点的 (x, y) 等都是与 pointX/pointY 坐标系相对应的。
超长文本的换行:
G6可以识别\n的换行
/**
* @description: 将当前一行的文本截取为对应行数的文本
* @param str 当前字符
* @param maxWidth 最大宽度
* @param fontSize 字体大小
* @param maxLine 需要转化为的行数
* @param iterateNum 迭代次数
*/
export const fittingString = (
str: string,
maxWidth: number,
fontSize: number,
maxLine: number,
iterateNum = 1,
) => {
let currentWidth = 0;
let res = str;
if (iterateNum >= maxLine) {
return truncate(str, { length: 16 });
}
const pattern = new RegExp('[\u4E00-\u9FA5]+');
str.split('').forEach((letter, i) => {
if (currentWidth > maxWidth) return;
if (pattern.test(letter)) {
currentWidth += fontSize;
} else {
currentWidth += G6.Util.getLetterWidth(letter, fontSize);
}
if (currentWidth > maxWidth) {
res = `${str.substring(0, i)}\n${fittingString(
str.substring(i),
maxWidth,
fontSize,
maxLine,
iterateNum + 1,
)}`;
}
});
return res;
};
全屏:
Element 中的方法
Element.requestFullscreen()
请求浏览器(user agent)将特定元素(甚至延伸到它的后代元素)置为全屏模式,隐去屏幕上的浏览器所有 UI 元素,以及其他应用。返回一个 Promise,并会在全屏模式被激活的时候变成 resolved 状态。
export const CardContext = createContext<HTMLDivElement | null>(null);
const cardRef = useRef<HTMLDivElement>();
<ProCard
ref={cardRef}
>
<CardContext.Provider value={cardRef.current}>
<GraphinShow
data={graphData}
/>
</CardContext.Provider>
将外层的dom元素传递进来,一般在Toolbar上添加全屏功能:
const cardRef = useContext(CardContext);
const handleFullscreen = () => {
cardRef!.requestFullscreen();
};
注意在全屏时相当于最外层元素是设置的全屏元素,对于select之类的下拉框之前是挂在body下的,需要更改容器,否则全屏下不可见:
<Select
getPopupContainer={() => cardRef!}
/>