- 有一个需求实现类似于企查查之类的企业图谱功能。调研了几个工具后,决定使用g6绘图来实现。
具体使用方式查看G6官网文档
下面附上写的一个demo代码。涵盖了节点位置,文字,颜色,节点事件等。
父组件
register-edge.js
export default G6 => {
G6.registerEdge("kaimo-line", {
/**
* 绘制边,包含文本
* @param {Object} cfg 边的配置项
* @param {G.Group} group 图形分组,边中的图形对象的容器
* @return {G.Shape} 绘制的图形,通过 node.get('keyShape') 可以获取到
*/
draw(cfg, group) {
const startPoint = cfg.startPoint;
const endPoint = cfg.endPoint;
const target = cfg.targetNode.getModel()
const source = cfg.sourceNode.getModel()
let shape;
shape = group.addShape("path", {
//线条
attrs: {
stroke: "#E4E7ED",
path: [
["M", startPoint.x, startPoint.y],
["L", endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y],
["L", endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y],
["L", endPoint.x, endPoint.y],
],
endArrow: {
path: G6.Arrow.triangle(5, 5, 0), // 使用内置箭头路径函数,参数为箭头的 宽度、长度、偏移量(默认为 0,与 d 对应)
d: 0,
fill: "#E4E7ED",
opacity: 0.5,
lineWidth: 1,
},
},
// must be assigned in G6 3.3 and later versions. it can be any value you want
name: "path-shape",
});
// 关系描述
if (target.edgesLabel) {
group.addShape('text', {
attrs: {
x: endPoint.x + 10,
y: endPoint.y,
fontSize: 12,
text: target.edgesLabel,
fill: '#666'
}
})
}
return shape;
},
});
}
register-node.js
import G6 from '@antv/g6'
// 文本超出隐藏 (字段, 最大长度, 字体大小)
const fittingString = (str, maxWidth, fontSize) => {
const ellipsis = "..."
const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0]
let currentWidth = 0
let res = str
const pattern = new RegExp("[\u4E00-\u9FA5]+")
str.split("").forEach((letter, i) => {
if (currentWidth > maxWidth - ellipsisLength) return
if (pattern.test(letter)) {
currentWidth += fontSize
} else {
currentWidth += G6.Util.getLetterWidth(letter, fontSize)
}
if (currentWidth > maxWidth - ellipsisLength) {
res = `${str.substr(0, i)}${ellipsis}`
}
})
return res
};
// 获取文本的长度
const getTextSize = (str, maxWidth, fontSize) => {
let width = G6.Util.getTextSize(str, fontSize)[0]
return width > maxWidth ? maxWidth : width
}
const getItemBakColor = (str) => {
if (str === '股东') return '#FD924E'
if (str === '高管') return '#7685E4'
if (str === '客户') return '#3FCDC1'
if (str === '对外投资') return '#F3AF17'
if (str === '供应商') return '#FA9B2D'
if (str === '实控人') return '#FA7370'
}
const register = G6 => {
G6.registerNode("tree-node", {
draw(cfg, group) {
let rect;
if (cfg.depth === 0) {
rect = group.addShape("circle", {
attrs: {
x: 100, // x 轴移动距离
y: 20, // y 轴移动距离
r: 40,
fill: "#0D85EE",
stroke: "#0D85EE", // 边框色
},
name: "big-circle-shape",
});
group.addShape("image", {
attrs: {
x: 75, // x 轴移动距离
y: -8, // y 轴移动距离
width: 50,
height: 50,
img: require('@/assets/img/fangzi.png'),
},
name: "big-image-shape",
});
group.addShape("text", {
attrs: {
text: fittingString(cfg.label, 90, 16),
x: 100,
// x: getTextSize(cfg.label, 90, 16) + 35,
y: 90,
fontSize: 18,
textAlign: "center",
fontWeight: 700,
textBaseline: "middle",
fill: "#0D85EE",
},
name: "text-shape",
});
group.addShape("text", {
attrs: {
text: `[${cfg.companyCode}]`,
x: 100,
y: 110,
fontSize: 18,
textAlign: "center",
fontWeight: 700,
textBaseline: "middle",
fill: "#0D85EE",
},
name: "text-shape",
});
}
if (cfg.location === "left") {
if (cfg.depth === 1) {
rect = group.addShape("circle", {
attrs: {
x: 160, // x 轴移动距离
y: 20, // y 轴移动距离
r: 35,
fill: getItemBakColor(cfg.label),
stroke: getItemBakColor(cfg.label), // 边框色
},
name: "first-circle-shape",
});
if (cfg.label === '对外投资') {
group.addShape("text", {
attrs: {
text: '对外',
x: 160,
y: 12,
fontSize: 18,
textAlign: "center",
textBaseline: "middle",
fill: "#fff",
},
name: "text-shape",
});
group.addShape("text", {
attrs: {
text: '投资',
x: 160,
y: 32,
fontSize: 18,
textAlign: "center",
textBaseline: "middle",
fill: "#fff",
},
name: "text-shape",
});
} else {
group.addShape("text", {
attrs: {
text: cfg.label,
x: 160,
y: 20,
fontSize: 18,
textAlign: "center",
textBaseline: "middle",
fill: "#fff",
},
name: "text-shape",
});
}
} else {
if (cfg.label.indexOf('更多') > -1) {
rect = group.addShape("rect", {
attrs: {
x: cfg.post ? 160 - getTextSize(cfg.label, 210, 18) - getTextSize(cfg.post, 210, 18) + 50 : 160 - getTextSize(cfg.label, 210, 18) + 50, // x 轴移动距离
y: 0, // y 轴移动距离
width: cfg.post ? getTextSize(cfg.label, 210, 18) + getTextSize(cfg.post, 210, 18) + 30 : getTextSize(cfg.label, 210, 18) + 30, // 宽
height: 40, // 高
fontSize: 18,
radius: 4,
},
name: "big-rect-shape",
});
group.addShape("text", {
attrs: {
text: fittingString(cfg.label, 210, 18),
x: 160 - getTextSize(cfg.label, 210, 18) + 80,
y: 20,
fontSize: 18,
textAlign: "left",
textBaseline: "middle",
fill: '#0D85EE',
cursor: 'pointer'
},
name: "text-shape",
});
} else {
rect = group.addShape("rect", {
attrs: {
x: cfg.post ? 160 - getTextSize(cfg.label, 210, 18) - getTextSize(cfg.post, 210, 18) + 50 : 160 - getTextSize(cfg.label, 210, 18) + 50, // x 轴移动距离
y: 0, // y 轴移动距离
width: cfg.post ? getTextSize(cfg.label, 210, 18) + getTextSize(cfg.post, 210, 18) + 30 : getTextSize(cfg.label, 210, 18) + 30, // 宽
height: 40, // 高
fontSize: 18,
// stroke: "#666",
// fontWeight: 600,
radius: 4,
},
name: "big-rect-shape",
});
// 左文本点
group.addShape("text", {
attrs: {
text: fittingString(cfg.label, 210, 18),
x: cfg.post ? 160 - getTextSize(cfg.label, 210, 18) + 50 : 160 - getTextSize(cfg.label, 210, 18) + 80,
y: 20,
fontSize: 18,
textAlign: "left",
textBaseline: "middle",
fill: document.body.className.indexOf('custom-f4c46d')>-1?'#fff' :'#333',
},
name: "text-shape",
});
if (cfg.post) {
group.addShape("text", {
attrs: {
text: `[${cfg.post}]`,
x: 195 + getTextSize(cfg.post, 210, 18),
y: 20,
fontSize: 18,
textAlign: "left",
textBaseline: "middle",
fill: '#666',
},
name: "text-shape",
});
}
}
}
}
if (cfg.location === "right") {
if (cfg.depth === 1) {
rect = group.addShape("circle", {
attrs: {
x: 35, // x 轴移动距离
y: 20, // y 轴移动距离
r: 35,
fill: getItemBakColor(cfg.label),
stroke: getItemBakColor(cfg.label), // 边框色
},
name: "first-circle-shape",
});
group.addShape("text", {
attrs: {
text: cfg.label,
x: 35,
y: 20,
fontSize: 18,
textAlign: "center",
textBaseline: "middle",
fill: "#fff",
},
name: "text-shape",
});
} else {
if (cfg.label.indexOf('更多') > -1) {
rect = group.addShape("text", {
attrs: {
text: fittingString(cfg.label, 210, 18),
x: 10,
y: 20,
fontSize: 18,
textAlign: "left",
textBaseline: "middle",
fill: '#0D85EE',
cursor: 'pointer'
},
name: "text-shape",
});
} else {
rect = group.addShape("text", {
attrs: {
text: cfg.companyType === '高管' ? cfg.label : fittingString(cfg.label, 210, 18),
x: 10,
y: 20,
fontSize: 18,
textAlign: "left",
textBaseline: "middle",
fill: document.body.className.indexOf('custom-f4c46d')>-1?'#fff' :'#333',
},
name: "text-shape",
});
if (cfg.post) {
group.addShape("text", {
attrs: {
text: `[${cfg.post}]`,
x: getTextSize(cfg.label, 210, 18) + 15,
y: 20,
fontSize: 18,
textAlign: "left",
textBaseline: "middle",
fill: '#666',
},
name: "text-shape",
});
}
}
}
}
return rect
}
})
}
export { register }