1. g6有combo,x6有 parent.addChild(child),实现combo效果,即node外面的框子;
2. g6有tooltip插件,x6用 删除 node,removeNode(node.id),新增 node graph.addNode(node),实现
共同的:er图布局,必须经过计算(暂未实现)

下面是在 X6 官网调试的demo 代码

import { Graph } from ‘@antv/x6’
import dagre from ‘dagre’
import { DagreLayout } from ‘@antv/layout’

const LINE_HEIGHT = 24
const NODE_WIDTH = 150

let nodes = [
{
id: 1,
shape: “er-rect”,
width: 60,
height: 40,
label: Child - 1,
zIndex: 1,
attrs: {
body: {
stroke: ‘none’,
fill: #211,
cursor: “auto”,
},
label: {
fill: ‘#fff’,
fontSize: 12,
cursor: “auto”,
},
},
},
{
id: 2,
shape: “er-rect”,
width: 60,
height: 40,
label: Child - 2,
zIndex: 1,
attrs: {
body: {
stroke: ‘none’,
fill: #422,
cursor: “auto”,
},
label: {
fill: ‘#fff’,
fontSize: 12,
cursor: “auto”,
},
},
},
{
id: 3,
shape: “er-rect”,
width: 60,
height: 40,
label: Child - 3,
zIndex: 1,
attrs: {
body: {
stroke: ‘none’,
fill: #633,
cursor: “auto”,
},
label: {
fill: ‘#fff’,
fontSize: 12,
cursor: “auto”,
},
},
},
{
id: 4,
shape: “er-rect”,
width: 60,
height: 40,
label: Child - 4,
zIndex: 1,
attrs: {
body: {
stroke: ‘none’,
fill: #844,
cursor: “auto”,
},
label: {
fill: ‘#fff’,
fontSize: 12,
cursor: “auto”,
},
},
},
{
id: 5,
shape: “er-rect”,
width: 60,
height: 40,
label: Child - 5,
zIndex: 1,
attrs: {
body: {
stroke: ‘none’,
fill: #1055,
cursor: “auto”,
},
label: {
fill: ‘#fff’,
fontSize: 12,
cursor: “auto”,
},
},
},
{
id: 6,
shape: “er-rect”,
width: 60,
height: 40,
label: Child - 6,
zIndex: 1,
attrs: {
body: {
stroke: ‘none’,
fill: #1266,
cursor: “auto”,
},
label: {
fill: ‘#fff’,
fontSize: 12,
cursor: “auto”,
},
},
},
{
id: 7,
shape: “er-rect”,
width: 60,
height: 40,
label: Child - 7,
zIndex: 1,
attrs: {
body: {
stroke: ‘none’,
fill: #1477,
cursor: “auto”,
},
label: {
fill: ‘#fff’,
fontSize: 12,
cursor: “auto”,
},
},
},
{
id: 8,
shape: “er-rect”,
width: 60,
height: 40,
label: Child - 8,
zIndex: 1,
attrs: {
body: {
stroke: ‘none’,
fill: #1688,
cursor: “auto”,
},
label: {
fill: ‘#fff’,
fontSize: 12,
cursor: “auto”,
},
},
},
{
id: 9,
shape: “er-rect”,
width: 60,
height: 40,
label: Child - 9,
zIndex: 1,
attrs: {
body: {
stroke: ‘none’,
fill: #1899,
cursor: “auto”,
},
label: {
fill: ‘#fff’,
fontSize: 12,
cursor: “auto”,
},
},
}
]

let edges = [
{
“id”: “edge1”,
“shape”: “edge”,
“source”: {
“cell”: “1”,
},
“target”: {
“cell”: “2”,
},
“attrs”: {
“line”: {
“stroke”: “#A2B1C3”,
“strokeWidth”: 2
}
},
“zIndex”: 1
},
{
“id”: “edge2”,
“shape”: “edge”,
“source”: {
“cell”: “3”,
},
“target”: {
“cell”: “4”,
},
“attrs”: {
“line”: {
“stroke”: “#A2B1C3”,
“strokeWidth”: 2
}
},
“zIndex”: 1
},
{
“id”: “edge3”,
“shape”: “edge”,
“source”: {
“cell”: “5”,
},
“target”: {
“cell”: “4”,
},
“attrs”: {
“line”: {
“stroke”: “#A2B1C3”,
“strokeWidth”: 2
}
},
“zIndex”: 1
},
{
“id”: “edge4”,
“shape”: “edge”,
“source”: {
“cell”: “4”,
},
“target”: {
“cell”: “6”,
},
“attrs”: {
“line”: {
“stroke”: “#A2B1C3”,
“strokeWidth”: 2
}
},
“zIndex”: 1
},
{
“id”: “edge5”,
“shape”: “edge”,
“source”: {
“cell”: “6”,
},
“target”: {
“cell”: “7”,
},
“attrs”: {
“line”: {
“stroke”: “#A2B1C3”,
“strokeWidth”: 2
}
},
“zIndex”: 1
},
{
“id”: “edge6”,
“shape”: “edge”,
“source”: {
“cell”: “7”,
},
“target”: {
“cell”: “8”,
},
“attrs”: {
“line”: {
“stroke”: “#A2B1C3”,
“strokeWidth”: 2
}
},
“zIndex”: 1
},
{
“id”: “edge7”,
“shape”: “edge”,
“source”: {
“cell”: “7”,
},
“target”: {
“cell”: “9”,
},
“attrs”: {
“line”: {
“stroke”: “#A2B1C3”,
“strokeWidth”: 2
}
},
“zIndex”: 1
}
]

let parentNode = {
id: ‘parent’,
x: 10,
y: 10,
width: 20,
height: 20,
zIndex: 0,
label: ‘Parent’,
attrs: {
body: {
fill: ‘#fffbe6’,
stroke: ‘#ffe7ba’,
cursor: “pointer”,
},
label: {
fontSize: 12,
cursor: “pointer”,
},
text: {
refX: 25,
refY: 10,
},
},
}

Graph.registerPortLayout(
‘erPortPosition’,
(portsPositionArgs) => {
return portsPositionArgs.map((_, index) => {
return {
position: {
x: 0,
y: (index + 1) * LINE_HEIGHT,
},
angle: 0,
}
})
},
true,
)

Graph.registerNode(
‘er-rect’,
{
inherit: ‘rect’,
markup: [
{
tagName: ‘rect’,
selector: ‘body’,
},
{
tagName: ‘text’,
selector: ‘label’,
},
],
attrs: {
rect: {
strokeWidth: 1,
stroke: ‘#5F95FF’,
fill: ‘#5F95FF’,
},
label: {
fontWeight: ‘bold’,
fill: ‘#ffffff’,
fontSize: 12,
},
},
ports: {
groups: {
list: {
markup: [
{
tagName: ‘rect’,
selector: ‘portBody’,
},
{
tagName: ‘text’,
selector: ‘portNameLabel’,
},
{
tagName: ‘text’,
selector: ‘portTypeLabel’,
},
],
attrs: {
portBody: {
width: NODE_WIDTH,
height: LINE_HEIGHT,
strokeWidth: 1,
stroke: ‘#5F95FF’,
fill: ‘#EFF4FF’,
magnet: true,
},
portNameLabel: {
ref: ‘portBody’,
refX: 6,
refY: 6,
fontSize: 10,
},
portTypeLabel: {
ref: ‘portBody’,
refX: 95,
refY: 6,
fontSize: 10,
},
},
position: ‘erPortPosition’,
},
},
},
},
true,
)

Graph.registerNode(
“tooltip-node”,
{
width: 600,
height: 450,
x: 200,
y: 50,
attrs: {
body: {
stroke: “#5F95FF”,
strokeWidth: 1,
fill: “rgba(204,204,204,0.2)”,
refWidth: 1,
refHeight: 1,
},
title: {
text: “Node”,
refX: 40,
refY: 14,
fill: “rgba(0,0,0,0.85)”,
fontSize: 12,
“text-anchor”: “start”,
},
text: {
text: “this is content text”,
refX: 40,
refY: 38,
fontSize: 12,
fill: “rgba(0,0,0,0.6)”,
“text-anchor”: “start”,
},
},
markup: [
{
tagName: “rect”,
selector: “body”,
},
{
tagName: “text”,
selector: “title”,
},
{
tagName: “text”,
selector: “text”,
},
],
},
true
);

const graph = new Graph({
container: document.getElementById(‘container’),
// embedding: {
// enabled: true,
// },
highlighting: {
embedding: {
name: ‘stroke’,
args: {
padding: -1,
attrs: {
stroke: ‘#73d13d’,
},
},
},
},
})

function getNodes(nodes) {
const parent = graph.addNode(parentNode)
nodes.forEach(item => {
if (item.shape !== ‘edge’) {
parent.addChild(graph.addNode(item))
}
})
}

function getEdges(edges) {
edges.forEach(item => {
if (item.shape == ‘edge’) {
if (item.source && item.target) {
graph.addEdge({
…item,
// source: item.source,
// target: item.target,
// attrs: item.attrs,
// normal 默认路由,原样返回路径点。
// orth 正交路由,由水平或垂直的正交线段组成。
// oneSide 受限正交路由,由受限的三段水平或垂直的正交线段组成。
// manhattan 智能正交路由,由水平或垂直的正交线段组成,并自动避开路径上的其他节点(障碍)。
// metro 智能地铁线路由,由水平或垂直的正交线段和斜角线段组成,类似地铁轨道图,并自动避开路径上的其他节点(障碍)。
// er 实体关系路由,由 Z 字形的斜角线段组成。
// router: “er”,
connector: {
// normal 简单连接器,用直线连接起点、路由点和终点。
// smooth 平滑连接器,用三次贝塞尔曲线线连接起点、路由点和终点。
// rounded 圆角连接器,用直线连接起点、路由点和终点,并在线段连接处用圆弧链接(倒圆角)。
// jumpover 跳线连接器,用直线连接起点、路由点和终点,并在边与边的交叉处用跳线符号链接。

        name: "normal",zIndex: 10000,},});}
}

})
}

// 布局方向
let dir = “LR”; // LR RL TB BT 竖排
// dir = ‘RL’ // LR RL TB BT 竖排
// dir = ‘TB’ // LR RL TB BT 横排
// dir = ‘BT’ // LR RL TB BT 横排
// 自动布局
function layout() {
const nodes = graph.getNodes();
const edges = graph.getEdges();
const g = new dagre.graphlib.Graph();
g.setGraph({ rankdir: dir, nodesep: 16, ranksep: 16 });
g.setDefaultEdgeLabel(() => ({}));
let width = 0;
let height = 0;
nodes.forEach((node, i) => {
if (node.id !== ‘parent’) {
width = 80;
height = 60;
g.setNode(node.id, { width, height });
}
});

edges.forEach((edge) => {
const source = edge.getSource();
const target = edge.getTarget();
g.setEdge(source.cell, target.cell);
});

dagre.layout(g);

graph.freeze();

g.nodes().forEach((id) => {
const node = graph.getCell(id);
if (node) {
const pos = g.node(id);
node.position(pos.x, pos.y);
}
});

edges.forEach((edge) => {
const source = edge.getSourceNode();
const target = edge.getTargetNode();
const sourceBBox = source.getBBox();
const targetBBox = target.getBBox();

if ((dir === "LR" || dir === "RL") && sourceBBox.y !== targetBBox.y) {const gap =dir === "LR"? targetBBox.x - sourceBBox.x - sourceBBox.width: -sourceBBox.x + targetBBox.x + targetBBox.width;const fix = dir === "LR" ? sourceBBox.width : 0;const x = sourceBBox.x + fix + gap / 2;edge.setVertices([{ x, y: sourceBBox.center.y },{ x, y: targetBBox.center.y },]);
} else if ((dir === "TB" || dir === "BT") && sourceBBox.x !== targetBBox.x) {const gap =dir === "TB"? targetBBox.y - sourceBBox.y - sourceBBox.height: -sourceBBox.y + targetBBox.y + targetBBox.height;const fix = dir === "TB" ? sourceBBox.height : 0;const y = sourceBBox.y + fix + gap / 2;edge.setVertices([{ x: sourceBBox.center.x, y },{ x: targetBBox.center.x, y },]);
} else {edge.setVertices([]);
}

});

graph.unfreeze();
}

getNodes(nodes);
getEdges(edges)
layout();

let ctrlPressed = false
const embedPadding = 20
let nodeId = [];

// 计算 parent node 的 width height
let flag = true;
if (flag) {
const nodes = graph.getNodes();
let x = 0;
let y = 0;
let parent = undefined;
nodes.forEach((node) => {
const element = node.getPosition();
if (element.x > x) {
x = element.x;
}
if (element.y > y) {
y = element.y;
}
if (node.id === “parent”) {
parent = node;
}
});

parent.prop(
{
size: { width: x + 100, height: y + 60 },
},
{ skipParentHandler: true }
);

flag = false;
}

// 递归往前找
function getPreEdges(id) {
edges.forEach(item => {
if (item.shape == ‘edge’) {
if (item.target.cell == id) {
item.attrs.line.stroke = ‘#0f0’;
getPreEdges(item.source.cell)
nodeId.push(item.source.cell)
}
}
})
}

// 递归往后找
function getNextEdges(id) {
edges.forEach(item => {
if (item.shape == ‘edge’) {
if (item.source.cell == id) {
item.attrs.line.stroke = ‘#0f0’;
getNextEdges(item.target.cell)
nodeId.push(item.target.cell)
}
}
})
}

graph.on(“edge:click”, ({ e, x, y, edge, view }) => {
// console.log(“edge:click”, edge.store.data);
const nodes = graph.getNodes();
nodes.forEach((node) => {
if (node.store.data.shape == “tooltip-node”) {
console.log(“node”, node.id, node.store.data.shape);
graph.removeNode(node.id);
}
});
graph.addNode({
x,
y: y > 330 ? 330 : y,
shape: “tooltip-node”,
});
});

graph.on(“node:click”, ({ e, x, y, node, view }) => {
if (node.store.data.id == “parent”) {
console.log(“node:click”, node.store.data);
} else {
node.store.data.attrs.body.fill = ‘#f00’;
// 从画布上删除点击的 node
// graph.removeNode(node.id)
// 递归改数据
nodeId.push(${node.id})
getPreEdges(node.id);
getNextEdges(node.id)
graph.clearCells(); // 清空画布所有的 node、edge
nodeId.forEach(ele => {
nodes.forEach(item => {
if (item.id == ele) {
item.attrs.body.fill = ‘#0f0’;
}
})
})
getNodes(nodes)
edges.forEach(item => {
graph.addEdge({
…item,
connector: {
name: “normal”,
},
});
})
// 重新布局
layout();
}
});

graph.on(‘node:change:size’, ({ node, options }) => {
if (options.skipParentHandler) {
return
}

const children = node.getChildren()
if (children && children.length) {
node.prop(‘originSize’, node.getSize())
}
})

graph.on(‘node:change:position’, ({ node, options }) => {
if (options.skipParentHandler || ctrlPressed) {
return
}

const children = node.getChildren()
if (children && children.length) {
node.prop(‘originPosition’, node.getPosition())
}

const parent = node.getParent()
if (parent && parent.isNode()) {
let originSize = parent.prop(‘originSize’)
if (originSize == null) {
originSize = parent.getSize()
parent.prop(‘originSize’, originSize)
}

let originPosition = parent.prop('originPosition')
if (originPosition == null) {originPosition = parent.getPosition()parent.prop('originPosition', originPosition)
}let x = originPosition.x
let y = originPosition.y
let cornerX = originPosition.x + originSize.width
let cornerY = originPosition.y + originSize.height
let hasChange = falseconst children = parent.getChildren()
if (children) {children.forEach((child) => {const bbox = child.getBBox().inflate(embedPadding)const corner = bbox.getCorner()if (bbox.x < x) {x = bbox.xhasChange = true}if (bbox.y < y) {y = bbox.yhasChange = true}if (corner.x > cornerX) {cornerX = corner.xhasChange = true}if (corner.y > cornerY) {cornerY = corner.yhasChange = true}})
}if (hasChange) {parent.prop({position: { x, y },size: { width: cornerX - x, height: cornerY - y },},{ skipParentHandler: true },)
}

}
})

antv/G6和antv/X6相关推荐

  1. antv g6 禁止移动_antV G6流程图在Vue中的使用

    最近我司项目中需要加入流程图制作功能,于是乎百度各种找可视化绘制拓扑图的轮子,大部分都是国外的,看文档太吃力,不过好在最终让我发现了AntV G6流程图图表库,最新版为2.0,不过编辑器在2.0版本还 ...

  2. vue office在线编辑_VUE和Antv G6实现在线拓扑图编辑

    我使用的是G6 2.0,也可以使用 G6 3.0,3.0的拓扑图单独作为一个编辑器使用,使用更加方便.不过2.0的比较简单,容易上手. 1.首先在Antv官网上找到蚂蚁Antv G6插件,引入插件. ...

  3. antv g6 禁止移动_十 AntV

    ← Highcharts AntV 是蚂蚁金服全新一代数据可视化解决方案,致力于提供一套简单方便.专业可靠.无限可能的数据可视化最佳实践. AntV 包括以下解决方案: G2:可视化引擎 G2Plot ...

  4. vue中使用antv/g6 绘制关系图、结构图

    使用antv/g6绘制关系图 效果图 代码实现 npm install @antv/g6 --save <template><div id="app">&l ...

  5. 关系图 antv G6

    1.安装antv G6 npm install --save @antv/g6 # 或者 # pnpm install --save @antv/g6 2.引入antv G6 import G6 fr ...

  6. antv G6 + react umi(vue,ng) 实现节点红点(badges)

    在我们使用G6做知识图谱,topo图时,业务场景一般会涉及到告警的节点要有突出标识,所谓红点,因为G6内置是不自带此功能的(虽然Graphin是可以直接用的,但基于G6的react框架),这样我们可以 ...

  7. ANTV/G6 绘制网络拓扑图

    最近看其他项目绘制网络拓扑图用了vue-super-flow 绘制的不是太理想,所以自己研究了一下,尝试用antv/g6绘制了一下. 参看了官方api https://g6.antv.vision/z ...

  8. AntV G6将节点修改成图片

    1.在每个节点中添加图片 代码布局如下: 实现效果如下图: 主要代码: defaultNode: { // 节点样式修改type: 'image', // 设置节点为图片size: [40, 40] ...

  9. 关于antV G6中的on事件、util.each事件及update方法等的使用总结

    前言 antV G6相对而言是一个目前还处于较于不成熟的关系数据可视化引擎.因此在实习实现关系图的过程中遇到很大的坑.比如说高亮箭头及关联属性.关系图的缩放.以及由于G6是基于canvas原理所以无法 ...

  10. AntV G6 的坑之——从卡掉渣到满帧需要几步

    AntV G6 是一款图可视化与分析开源引擎.<AntV G6 的坑之--XXX>系列文章持续更新中,总结常见问题及神坑解决方案.任何问题可在 GitHub Issue 中提问,求 Git ...

最新文章

  1. Tensorflow object detection API 搭建物体识别模型
  2. 基于cocos2d-x的快速的游戏开发--回合制游戏
  3. 左神算法:在二叉树中找到累加和为指定值的最长路径长度(Java版)
  4. 算法题12 数组中所有的逆序对
  5. spring 注释_Spring@主要注释
  6. LeetCode 329. 矩阵中的最长递增路径(记忆化递归)
  7. 的优先级大小_如何评估需求的优先级?
  8. Java日历compareTo()方法与示例
  9. java实现同步的两种方式
  10. jinfo-jvm参数信息工具
  11. 评分 9.7!这本 Python 书彻底玩大了?程序员:满分!
  12. AcWing 145.超市(二叉堆)
  13. SpringBoot之注解
  14. php5.3.3以后php-fpm进程管理方式
  15. 5个冷门的MacOS快捷键,小众但好用
  16. linux下安装nginx1.10,Linux(RHEL7.0)下安装Nginx-1.10.2
  17. esp32实现万能红外遥控器 基于开源红外码库IREXT
  18. java后台模板_Java服务端后台常用模板
  19. HBase集群出现NotServingRegionException问题的排查及解决方法
  20. 高等数学学习笔记——第七十六讲——直角坐标系下二重积分的计算

热门文章

  1. 网贷黑名单查询,通过身份证号,或者手机号查询自己的网贷情况。
  2. 将雅虎《心香一脉》每天推荐的文章发到咱邮箱(Java版)
  3. 经常被问到的有深度有内涵的数据结构面试题
  4. 学术篇 | 面向分类的脑电接口Fuzzy-Rough特征选择
  5. 高德地图 删除marker(指定marker)
  6. 微信小程序-Testerhome
  7. 6.2.1.1UE maximum output power - EIRP and TRP——翻译
  8. 2020牛客暑期多校训练营(第九场)F.Groundhog Looking Dowdy
  9. 把ipa文件上传到App Store教程步骤
  10. 曾用心并深度参与的一款游戏今天发布了关服通知,回顾一下我最初的工作日报