docs: 📚️ update org demo (#1581)
This commit is contained in:
@ -0,0 +1,67 @@
|
||||
import { Graph } from '@antv/x6'
|
||||
|
||||
const graph = new Graph({
|
||||
container: document.getElementById('container')!,
|
||||
grid: true,
|
||||
})
|
||||
|
||||
graph.addNode({
|
||||
shape: 'rect',
|
||||
x: 80,
|
||||
y: 210,
|
||||
width: 120,
|
||||
height: 50,
|
||||
attrs: {
|
||||
body: {
|
||||
stroke: '#9254de',
|
||||
fill: '#efdbff',
|
||||
},
|
||||
text: {
|
||||
textWrap: {
|
||||
text: '使用 textWrap 实现文本换行',
|
||||
width: -10, // 宽度减少 10px
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
graph.addNode({
|
||||
shape: 'html',
|
||||
x: 250,
|
||||
y: 200,
|
||||
width: 160,
|
||||
height: 60,
|
||||
html: () => {
|
||||
const wrap = document.createElement('div')
|
||||
wrap.style.width = '100%'
|
||||
wrap.style.height = '100%'
|
||||
wrap.style.border = '2px solid #9254de'
|
||||
wrap.style.background = '#efdbff'
|
||||
wrap.style.display = 'flex'
|
||||
wrap.style.justifyContent = 'center'
|
||||
wrap.style.alignItems = 'center'
|
||||
wrap.style.wordBreak = 'break-word'
|
||||
wrap.style.padding = '8px'
|
||||
wrap.innerText = '使用 HTML 节点实现文本换行'
|
||||
|
||||
return wrap
|
||||
},
|
||||
})
|
||||
|
||||
graph.addNode({
|
||||
shape: 'rect',
|
||||
x: 550,
|
||||
y: 230,
|
||||
attrs: {
|
||||
body: {
|
||||
ref: 'text',
|
||||
refWidth: 16,
|
||||
refHeight: 16,
|
||||
refX: -8,
|
||||
refY: -8,
|
||||
stroke: '#9254de',
|
||||
fill: '#efdbff',
|
||||
},
|
||||
},
|
||||
label: '根据文本的大小确定节点的宽高',
|
||||
})
|
@ -20,9 +20,9 @@ graph.addNode({
|
||||
textWrap: {
|
||||
text: '使用 textWrap 实现文本换行',
|
||||
width: -10, // 宽度减少 10px
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
graph.addNode({
|
||||
@ -61,7 +61,7 @@ graph.addNode({
|
||||
refY: -8,
|
||||
stroke: '#9254de',
|
||||
fill: '#efdbff',
|
||||
}
|
||||
},
|
||||
},
|
||||
label: '根据文本的大小确定节点的宽高'
|
||||
})
|
||||
label: '根据文本的大小确定节点的宽高',
|
||||
})
|
@ -0,0 +1,72 @@
|
||||
import { Graph, Edge, EdgeView, Shape } from '@antv/x6'
|
||||
|
||||
const graph = new Graph({
|
||||
container: document.getElementById('container')!,
|
||||
grid: true,
|
||||
connecting: {
|
||||
validateMagnet({ cell, magnet }) {
|
||||
let count = 0
|
||||
const connectionCount = magnet.getAttribute('connection-count')
|
||||
const max = connectionCount
|
||||
? parseInt(connectionCount, 10)
|
||||
: Number.MAX_SAFE_INTEGER
|
||||
const outgoingEdges = graph.getOutgoingEdges(cell)
|
||||
if (outgoingEdges) {
|
||||
outgoingEdges.forEach((edge: Edge) => {
|
||||
const edgeView = graph.findViewByCell(edge) as EdgeView
|
||||
if (edgeView.sourceMagnet === magnet) {
|
||||
count += 1
|
||||
}
|
||||
})
|
||||
}
|
||||
return count < max
|
||||
},
|
||||
createEdge() {
|
||||
return new Shape.Edge({
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: 'orange',
|
||||
},
|
||||
},
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
graph.addNode({
|
||||
shape: 'rect',
|
||||
x: 280,
|
||||
y: 280,
|
||||
width: 160,
|
||||
height: 60,
|
||||
ports: [
|
||||
{
|
||||
id: 'a',
|
||||
attrs: {
|
||||
circle: {
|
||||
magnet: true,
|
||||
connectionCount: 3, // 自定义属性,控制连接桩可连接多少条边
|
||||
},
|
||||
},
|
||||
position: 'top',
|
||||
},
|
||||
{
|
||||
id: 'b',
|
||||
attrs: {
|
||||
circle: {
|
||||
magnet: true,
|
||||
connectionCount: 0, // 自定义属性,控制连接桩可连接多少条边
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
attrs: {
|
||||
body: {
|
||||
fill: '#f5f5f5',
|
||||
stroke: '#d9d9d9',
|
||||
strokeWidth: 1,
|
||||
magnet: true,
|
||||
connectionCount: 2, // 自定义属性,控制节点可连接多少条边
|
||||
},
|
||||
},
|
||||
})
|
@ -1,36 +1,20 @@
|
||||
{
|
||||
"demos": [
|
||||
{
|
||||
"filename": "flex-image.ts",
|
||||
"title": {
|
||||
"zh": "根据图片大小缩放节点",
|
||||
"en": "Resize Node According to the Image Size"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*AhNyQ5453mEAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "change-mode.tsx",
|
||||
"title": {
|
||||
"zh": "切换交互模式",
|
||||
"en": "Switch Interacting"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*YmthRqMeb7AAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "validate-connection.ts",
|
||||
"title": {
|
||||
"zh": "限制连接边的数量",
|
||||
"en": "Limit Connected Edges"
|
||||
"zh": "链接桩验证/高亮/自动吸附",
|
||||
"en": "Validattion/Highlight/Absorb of Port"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*f_ztRpTun3AAAAAAAAAAAAAAARQnAQ"
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*Gi4OSoXvPzgAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "text-wrap.ts",
|
||||
"filename": "path-editor.ts",
|
||||
"title": {
|
||||
"zh": "文本换行",
|
||||
"en": "Text Wrap"
|
||||
"zh": "路径编辑器",
|
||||
"en": "Path Editor"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*-gIBRKiYraoAAAAAAAAAAAAAARQnAQ"
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*drmQQb_VAUsAAAAAAAAAAAAAARQnAQ"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ const container = document.getElementById('container')!
|
||||
|
||||
const graph = new Graph({
|
||||
container,
|
||||
grid: true,
|
||||
})
|
||||
|
||||
const init = (pos: { x: number; y: number }) => {
|
||||
@ -29,7 +28,7 @@ const init = (pos: { x: number; y: number }) => {
|
||||
attrs: {
|
||||
line: {
|
||||
targetMarker: null,
|
||||
stroke: '#A2B1C3',
|
||||
stroke: '#5F95FF',
|
||||
strokeWidth: 2,
|
||||
},
|
||||
},
|
@ -1,70 +1,257 @@
|
||||
import { Graph, Edge, EdgeView, Shape } from '@antv/x6'
|
||||
import { Graph, Edge, Shape, NodeView } from '@antv/x6'
|
||||
|
||||
// 定义节点
|
||||
class MyShape extends Shape.Rect {
|
||||
getInPorts() {
|
||||
return this.getPortsByGroup('in')
|
||||
}
|
||||
|
||||
getOutPorts() {
|
||||
return this.getPortsByGroup('out')
|
||||
}
|
||||
|
||||
getUsedInPorts(graph: Graph) {
|
||||
const incomingEdges = graph.getIncomingEdges(this) || []
|
||||
return incomingEdges.map((edge: Edge) => {
|
||||
const portId = edge.getTargetPortId()
|
||||
return this.getPort(portId!)
|
||||
})
|
||||
}
|
||||
|
||||
getNewInPorts(length: number) {
|
||||
return Array.from(
|
||||
{
|
||||
length,
|
||||
},
|
||||
() => {
|
||||
return {
|
||||
group: 'in',
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
updateInPorts(graph: Graph) {
|
||||
const minNumberOfPorts = 2
|
||||
const ports = this.getInPorts()
|
||||
const usedPorts = this.getUsedInPorts(graph)
|
||||
const newPorts = this.getNewInPorts(
|
||||
Math.max(minNumberOfPorts - usedPorts.length, 1),
|
||||
)
|
||||
|
||||
if (
|
||||
ports.length === minNumberOfPorts &&
|
||||
ports.length - usedPorts.length > 0
|
||||
) {
|
||||
// noop
|
||||
} else if (ports.length === usedPorts.length) {
|
||||
this.addPorts(newPorts)
|
||||
} else if (ports.length + 1 > usedPorts.length) {
|
||||
this.prop(
|
||||
['ports', 'items'],
|
||||
this.getOutPorts().concat(usedPorts).concat(newPorts),
|
||||
{
|
||||
rewrite: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
MyShape.config({
|
||||
attrs: {
|
||||
root: {
|
||||
magnet: false,
|
||||
},
|
||||
body: {
|
||||
fill: '#EFF4FF',
|
||||
stroke: '#5F95FF',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
ports: {
|
||||
items: [
|
||||
{
|
||||
group: 'out',
|
||||
},
|
||||
],
|
||||
groups: {
|
||||
in: {
|
||||
position: {
|
||||
name: 'top',
|
||||
},
|
||||
attrs: {
|
||||
portBody: {
|
||||
magnet: 'passive',
|
||||
r: 6,
|
||||
stroke: '#5F95FF',
|
||||
fill: '#fff',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
out: {
|
||||
position: {
|
||||
name: 'bottom',
|
||||
},
|
||||
attrs: {
|
||||
portBody: {
|
||||
magnet: true,
|
||||
r: 6,
|
||||
fill: '#fff',
|
||||
stroke: '#5F95FF',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
portMarkup: [
|
||||
{
|
||||
tagName: 'circle',
|
||||
selector: 'portBody',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// 高亮
|
||||
const magnetAvailabilityHighlighter = {
|
||||
name: 'stroke',
|
||||
args: {
|
||||
attrs: {
|
||||
fill: '#fff',
|
||||
stroke: '#47C769',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// 画布
|
||||
const graph = new Graph({
|
||||
container: document.getElementById('container')!,
|
||||
grid: true,
|
||||
highlighting: {
|
||||
magnetAvailable: magnetAvailabilityHighlighter,
|
||||
magnetAdsorbed: {
|
||||
name: 'stroke',
|
||||
args: {
|
||||
attrs: {
|
||||
fill: '#fff',
|
||||
stroke: '#31d0c6',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
connecting: {
|
||||
validateMagnet({ cell, magnet }) {
|
||||
let count = 0
|
||||
const connectionCount = magnet.getAttribute('connection-count')
|
||||
const max = connectionCount ? parseInt(connectionCount, 10) : Number.MAX_SAFE_INTEGER
|
||||
const outgoingEdges = graph.getOutgoingEdges(cell)
|
||||
if (outgoingEdges) {
|
||||
outgoingEdges.forEach((edge: Edge) => {
|
||||
const edgeView = graph.findViewByCell(edge) as EdgeView
|
||||
if (edgeView.sourceMagnet === magnet) {
|
||||
count += 1
|
||||
}
|
||||
})
|
||||
}
|
||||
return count < max
|
||||
snap: true,
|
||||
allowBlank: false,
|
||||
allowLoop: false,
|
||||
highlight: true,
|
||||
connector: 'rounded',
|
||||
connectionPoint: 'boundary',
|
||||
router: {
|
||||
name: 'er',
|
||||
args: {
|
||||
direction: 'V',
|
||||
},
|
||||
},
|
||||
createEdge() {
|
||||
return new Shape.Edge({
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: 'orange',
|
||||
line: {
|
||||
stroke: '#A2B1C3',
|
||||
strokeWidth: 1,
|
||||
targetMarker: {
|
||||
name: 'classic',
|
||||
size: 7,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
validateConnection({ sourceView, targetView, targetMagnet }) {
|
||||
if (!targetMagnet) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (targetMagnet.getAttribute('port-group') !== 'in') {
|
||||
return false
|
||||
}
|
||||
|
||||
if (targetView) {
|
||||
const node = targetView.cell
|
||||
if (node instanceof MyShape) {
|
||||
const portId = targetMagnet.getAttribute('port')
|
||||
const usedInPorts = node.getUsedInPorts(graph)
|
||||
if (usedInPorts.find((port) => port && port.id === portId)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
graph.addNode(
|
||||
new MyShape().resize(120, 40).position(200, 50).updateInPorts(graph),
|
||||
)
|
||||
|
||||
graph.addNode(
|
||||
new MyShape().resize(120, 40).position(400, 50).updateInPorts(graph),
|
||||
)
|
||||
|
||||
graph.addNode(
|
||||
new MyShape().resize(120, 40).position(300, 250).updateInPorts(graph),
|
||||
)
|
||||
|
||||
function update(view: NodeView) {
|
||||
const cell = view.cell
|
||||
if (cell instanceof MyShape) {
|
||||
cell.getInPorts().forEach((port) => {
|
||||
const portNode = view.findPortElem(port.id!, 'portBody')
|
||||
view.unhighlight(portNode, {
|
||||
highlighter: magnetAvailabilityHighlighter,
|
||||
})
|
||||
})
|
||||
cell.updateInPorts(graph)
|
||||
}
|
||||
}
|
||||
|
||||
graph.on('edge:connected', ({ previousView, currentView }) => {
|
||||
if (previousView) {
|
||||
update(previousView as NodeView)
|
||||
}
|
||||
if (currentView) {
|
||||
update(currentView as NodeView)
|
||||
}
|
||||
})
|
||||
|
||||
graph.addNode({
|
||||
shape: 'rect',
|
||||
x: 280,
|
||||
y: 280,
|
||||
width: 160,
|
||||
height: 60,
|
||||
ports: [
|
||||
graph.on('edge:removed', ({ edge, options }) => {
|
||||
if (!options.ui) {
|
||||
return
|
||||
}
|
||||
|
||||
const target = edge.getTargetCell()
|
||||
if (target instanceof MyShape) {
|
||||
target.updateInPorts(graph)
|
||||
}
|
||||
})
|
||||
|
||||
graph.on('edge:mouseenter', ({ edge }) => {
|
||||
edge.addTools([
|
||||
'source-arrowhead',
|
||||
'target-arrowhead',
|
||||
{
|
||||
id: 'a',
|
||||
attrs: {
|
||||
circle: {
|
||||
magnet: true,
|
||||
connectionCount: 3, // 自定义属性,控制连接桩可连接多少条边
|
||||
}
|
||||
name: 'button-remove',
|
||||
args: {
|
||||
distance: -30,
|
||||
},
|
||||
position: 'top'
|
||||
},
|
||||
{
|
||||
id: 'b',
|
||||
attrs: {
|
||||
circle: {
|
||||
magnet: true,
|
||||
connectionCount: 0, // 自定义属性,控制连接桩可连接多少条边
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
attrs: {
|
||||
body: {
|
||||
fill: '#f5f5f5',
|
||||
stroke: '#d9d9d9',
|
||||
strokeWidth: 1,
|
||||
magnet: true,
|
||||
connectionCount: 2, // 自定义属性,控制节点可连接多少条边
|
||||
},
|
||||
},
|
||||
})
|
||||
])
|
||||
})
|
||||
|
||||
graph.on('edge:mouseleave', ({ edge }) => {
|
||||
edge.removeTools()
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: FAQ
|
||||
title: Common Functions
|
||||
order: 20
|
||||
redirect_from:
|
||||
- /zh/examples/practices
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: 常见问题
|
||||
title: 常用功能
|
||||
order: 20
|
||||
redirect_from:
|
||||
- /zh/examples/practices
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Graph, Cell } from '@antv/x6'
|
||||
////import ELK, { ElkNode, ElkExtendedEdge, ElkEdge } from 'elkjs/lib/elk-api.js';
|
||||
import ELK, { ElkNode, ElkEdge, ElkExtendedEdge } from 'elkjs'
|
||||
|
||||
Graph.registerNode(
|
||||
@ -174,7 +173,7 @@ fetch('../data/elkdata.json')
|
||||
addEdges(res.edges || [])
|
||||
graph.resetCells(cells)
|
||||
graph.zoomToFit({
|
||||
padding: 10,
|
||||
padding: 20,
|
||||
maxScale: 1,
|
||||
})
|
||||
})
|
||||
|
@ -11,8 +11,8 @@
|
||||
{
|
||||
"filename": "dag.tsx",
|
||||
"title": {
|
||||
"zh": "人工智能建模流程",
|
||||
"en": "Flow for AI Model"
|
||||
"zh": "人工智能建模 DAG 图",
|
||||
"en": "DAG for AI Model"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*RPiGRaSus3UAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
@ -56,29 +56,13 @@
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*Z3ebTKy0w9cAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "validate-connection.ts",
|
||||
"title": {
|
||||
"zh": "链接桩验证/高亮/自动吸附",
|
||||
"en": "Validattion/Highlight/Absorb of Port"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*chF2SIucKCUAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "tree.ts",
|
||||
"title": {
|
||||
"zh": "展开/折叠树",
|
||||
"en": "Expand/Collapse the Tree"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*dJiNTJ2h3GAAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "org.ts",
|
||||
"title": {
|
||||
"zh": "组织架构图",
|
||||
"en": "Organizational Charts"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*mxDSTpxbMYYAAAAAAAAAAAAAARQnAQ"
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*FWx5SYDzLw4AAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "orgchart.ts",
|
||||
@ -86,15 +70,7 @@
|
||||
"zh": "组织架构图(自动布局)",
|
||||
"en": "Organizational Charts"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*w5SUSIvTxPAAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "path-editor.ts",
|
||||
"title": {
|
||||
"zh": "路径编辑器",
|
||||
"en": "Path Editor"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*dz6aS5gtapUAAAAAAAAAAAAAARQnAQ"
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*-1_wQ6zLmMYAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "class.ts",
|
||||
@ -103,6 +79,14 @@
|
||||
"en": "UML Class"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*OaCpR7t_mVoAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "tree.ts",
|
||||
"title": {
|
||||
"zh": "展开/折叠树",
|
||||
"en": "Expand/Collapse the Tree"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*XDnNRqnj4WkAAAAAAAAAAAAAARQnAQ"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ Graph.registerNode(
|
||||
'xlink:href':
|
||||
'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SYCuQ6HHs5cAAAAAAAAAAAAAARQnAQ',
|
||||
event: 'add:topic',
|
||||
class: 'topic-image',
|
||||
},
|
||||
label: {
|
||||
fontSize: 14,
|
||||
@ -379,11 +380,11 @@ graph.bindKey('tab', (e) => {
|
||||
render()
|
||||
|
||||
insertCss(`
|
||||
.x6-node image {
|
||||
.topic-image {
|
||||
visibility: hidden;
|
||||
cursor: pointer;
|
||||
}
|
||||
.x6-node:hover image {
|
||||
.x6-node:hover .topic-image {
|
||||
visibility: visible;
|
||||
}
|
||||
.x6-node-selected rect {
|
||||
|
@ -27,9 +27,9 @@ Graph.registerNode(
|
||||
body: {
|
||||
refWidth: '100%',
|
||||
refHeight: '100%',
|
||||
fill: '#FFFFFF',
|
||||
stroke: '#000000',
|
||||
strokeWidth: 2,
|
||||
fill: '#5F95FF',
|
||||
stroke: '#5F95FF',
|
||||
strokeWidth: 1,
|
||||
rx: 10,
|
||||
ry: 10,
|
||||
pointerEvents: 'visiblePainted',
|
||||
@ -43,6 +43,7 @@ Graph.registerNode(
|
||||
rank: {
|
||||
refX: 0.9,
|
||||
refY: 0.2,
|
||||
fill: '#fff',
|
||||
fontFamily: 'Courier New',
|
||||
fontSize: 14,
|
||||
textAnchor: 'end',
|
||||
@ -51,6 +52,7 @@ Graph.registerNode(
|
||||
name: {
|
||||
refX: 0.9,
|
||||
refY: 0.6,
|
||||
fill: '#fff',
|
||||
fontFamily: 'Courier New',
|
||||
fontSize: 14,
|
||||
fontWeight: '800',
|
||||
@ -69,8 +71,8 @@ Graph.registerEdge(
|
||||
line: {
|
||||
fill: 'none',
|
||||
strokeLinejoin: 'round',
|
||||
strokeWidth: '2',
|
||||
stroke: '#4b4a67',
|
||||
strokeWidth: 2,
|
||||
stroke: '#A2B1C3',
|
||||
sourceMarker: null,
|
||||
targetMarker: null,
|
||||
},
|
||||
@ -80,8 +82,7 @@ Graph.registerEdge(
|
||||
)
|
||||
|
||||
const graph = new Graph({
|
||||
container: document.getElementById('container'),
|
||||
grid: true,
|
||||
container: document.getElementById('container')!,
|
||||
connecting: {
|
||||
anchor: 'orth',
|
||||
},
|
||||
@ -93,31 +94,23 @@ function member(
|
||||
rank: string,
|
||||
name: string,
|
||||
image: string,
|
||||
background: string,
|
||||
textColor: string = '#000',
|
||||
) {
|
||||
return graph.addNode({
|
||||
x,
|
||||
y,
|
||||
shape: 'org-node',
|
||||
attrs: {
|
||||
body: {
|
||||
fill: background,
|
||||
stroke: 'none',
|
||||
},
|
||||
avatar: {
|
||||
opacity: 0.7,
|
||||
'xlink:href': image,
|
||||
},
|
||||
rank: {
|
||||
text: rank,
|
||||
fill: textColor,
|
||||
wordSpacing: '-5px',
|
||||
letterSpacing: 0,
|
||||
},
|
||||
name: {
|
||||
text: name,
|
||||
fill: textColor,
|
||||
fontSize: 13,
|
||||
fontFamily: 'Arial',
|
||||
letterSpacing: 0,
|
||||
@ -129,8 +122,12 @@ function member(
|
||||
function link(source: Node, target: Node, vertices: Point.PointLike[]) {
|
||||
return graph.addEdge({
|
||||
vertices,
|
||||
source: { cell: source },
|
||||
target: { cell: target },
|
||||
source: {
|
||||
cell: source,
|
||||
},
|
||||
target: {
|
||||
cell: target,
|
||||
},
|
||||
shape: 'org-edge',
|
||||
})
|
||||
}
|
||||
@ -140,47 +137,57 @@ const male =
|
||||
const female =
|
||||
'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*f6hhT75YjkIAAAAAAAAAAAAAARQnAQ'
|
||||
|
||||
const bart = member(300, 70, 'CEO', 'Bart Simpson', male, '#30d0c6')
|
||||
const homer = member(
|
||||
90,
|
||||
200,
|
||||
'VP Marketing',
|
||||
'Homer Simpson',
|
||||
male,
|
||||
'#7c68fd',
|
||||
'#f1f1f1',
|
||||
)
|
||||
const marge = member(
|
||||
300,
|
||||
200,
|
||||
'VP Sales',
|
||||
'Marge Simpson',
|
||||
female,
|
||||
'#7c68fd',
|
||||
'#f1f1f1',
|
||||
)
|
||||
const lisa = member(
|
||||
500,
|
||||
200,
|
||||
'VP Production',
|
||||
'Lisa Simpson',
|
||||
female,
|
||||
'#7c68fd',
|
||||
'#f1f1f1',
|
||||
)
|
||||
const maggie = member(400, 350, 'Manager', 'Maggie Simpson', female, '#feb563')
|
||||
const lenny = member(190, 350, 'Manager', 'Lenny Leonard', male, '#feb563')
|
||||
const carl = member(190, 500, 'Manager', 'Carl Carlson', male, '#feb563')
|
||||
const bart = member(300, 70, 'CEO', 'Bart Simpson', male)
|
||||
const homer = member(90, 200, 'VP Marketing', 'Homer Simpson', male)
|
||||
const marge = member(300, 200, 'VP Sales', 'Marge Simpson', female)
|
||||
const lisa = member(500, 200, 'VP Production', 'Lisa Simpson', female)
|
||||
const maggie = member(400, 350, 'Manager', 'Maggie Simpson', female)
|
||||
const lenny = member(190, 350, 'Manager', 'Lenny Leonard', male)
|
||||
const carl = member(190, 500, 'Manager', 'Carl Carlson', male)
|
||||
|
||||
link(bart, marge, [{ x: 385, y: 180 }])
|
||||
link(bart, marge, [
|
||||
{
|
||||
x: 385,
|
||||
y: 180,
|
||||
},
|
||||
])
|
||||
link(bart, homer, [
|
||||
{ x: 385, y: 180 },
|
||||
{ x: 175, y: 180 },
|
||||
{
|
||||
x: 385,
|
||||
y: 180,
|
||||
},
|
||||
{
|
||||
x: 175,
|
||||
y: 180,
|
||||
},
|
||||
])
|
||||
link(bart, lisa, [
|
||||
{ x: 385, y: 180 },
|
||||
{ x: 585, y: 180 },
|
||||
{
|
||||
x: 385,
|
||||
y: 180,
|
||||
},
|
||||
{
|
||||
x: 585,
|
||||
y: 180,
|
||||
},
|
||||
])
|
||||
link(homer, lenny, [{ x: 175, y: 380 }])
|
||||
link(homer, carl, [{ x: 175, y: 530 }])
|
||||
link(marge, maggie, [{ x: 385, y: 380 }])
|
||||
link(homer, lenny, [
|
||||
{
|
||||
x: 175,
|
||||
y: 380,
|
||||
},
|
||||
])
|
||||
link(homer, carl, [
|
||||
{
|
||||
x: 175,
|
||||
y: 530,
|
||||
},
|
||||
])
|
||||
link(marge, maggie, [
|
||||
{
|
||||
x: 385,
|
||||
y: 380,
|
||||
},
|
||||
])
|
||||
|
||||
graph.zoomToFit({ padding: 20, maxScale: 1 })
|
||||
|
@ -90,9 +90,9 @@ Graph.registerNode(
|
||||
ry: 10,
|
||||
refWidth: '100%',
|
||||
refHeight: '100%',
|
||||
fill: '#FFF',
|
||||
stroke: '#000',
|
||||
strokeWidth: 0,
|
||||
fill: '#5F95FF',
|
||||
stroke: '#5F95FF',
|
||||
strokeWidth: 1,
|
||||
pointerEvents: 'visiblePainted',
|
||||
},
|
||||
'.image': {
|
||||
@ -105,6 +105,7 @@ Graph.registerNode(
|
||||
'.rank': {
|
||||
refX: 0.95,
|
||||
refY: 0.5,
|
||||
fill: '#fff',
|
||||
fontFamily: 'Courier New',
|
||||
fontSize: 13,
|
||||
textAnchor: 'end',
|
||||
@ -113,6 +114,7 @@ Graph.registerNode(
|
||||
'.name': {
|
||||
refX: 0.95,
|
||||
refY: 0.7,
|
||||
fill: '#fff',
|
||||
fontFamily: 'Arial',
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
@ -131,13 +133,13 @@ Graph.registerNode(
|
||||
'.btn > circle': {
|
||||
r: 10,
|
||||
fill: 'transparent',
|
||||
stroke: '#333',
|
||||
stroke: '#fff',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
'.btn.add > text': {
|
||||
fontSize: 20,
|
||||
fontWeight: 800,
|
||||
stroke: '#000',
|
||||
fill: '#fff',
|
||||
x: -5.5,
|
||||
y: 7,
|
||||
fontFamily: 'Times New Roman',
|
||||
@ -146,7 +148,7 @@ Graph.registerNode(
|
||||
'.btn.del > text': {
|
||||
fontSize: 28,
|
||||
fontWeight: 500,
|
||||
stroke: '#000',
|
||||
fill: '#fff',
|
||||
x: -4.5,
|
||||
y: 6,
|
||||
fontFamily: 'Times New Roman',
|
||||
@ -164,8 +166,8 @@ Graph.registerEdge(
|
||||
zIndex: -1,
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: '#585858',
|
||||
strokeWidth: 3,
|
||||
strokeWidth: 2,
|
||||
stroke: '#A2B1C3',
|
||||
sourceMarker: null,
|
||||
targetMarker: null,
|
||||
},
|
||||
@ -183,10 +185,8 @@ const dir = 'LR' // LR RL TB BT
|
||||
|
||||
// 创建画布
|
||||
const graph = new Graph({
|
||||
container: document.getElementById('container'),
|
||||
grid: true,
|
||||
container: document.getElementById('container')!,
|
||||
scroller: true,
|
||||
snapline: true,
|
||||
interacting: false,
|
||||
})
|
||||
|
||||
@ -194,13 +194,10 @@ const graph = new Graph({
|
||||
function setup() {
|
||||
graph.on('node:add', ({ e, node }) => {
|
||||
e.stopPropagation()
|
||||
const bg = Color.randomHex()
|
||||
const member = createNode(
|
||||
'Employee',
|
||||
'New Employee',
|
||||
Math.random() < 0.5 ? male : female,
|
||||
bg,
|
||||
Color.invert(bg, true),
|
||||
)
|
||||
graph.freeze()
|
||||
graph.addCell([member, createEdge(node, member)])
|
||||
@ -288,28 +285,17 @@ function layout() {
|
||||
graph.unfreeze()
|
||||
}
|
||||
|
||||
function createNode(
|
||||
rank: string,
|
||||
name: string,
|
||||
image: string,
|
||||
background: string,
|
||||
textColor = '#000',
|
||||
) {
|
||||
function createNode(rank: string, name: string, image: string) {
|
||||
return graph.createNode({
|
||||
shape: 'org-node',
|
||||
attrs: {
|
||||
'.card': { fill: background },
|
||||
'.image': { xlinkHref: image },
|
||||
'.rank': {
|
||||
fill: textColor,
|
||||
text: Dom.breakText(rank, { width: 160, height: 45 }),
|
||||
},
|
||||
'.name': {
|
||||
fill: textColor,
|
||||
text: Dom.breakText(name, { width: 160, height: 45 }),
|
||||
},
|
||||
'.btn > circle': { stroke: textColor },
|
||||
'.btn > text': { fill: textColor, stroke: textColor },
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -323,27 +309,12 @@ function createEdge(source: Cell, target: Cell) {
|
||||
}
|
||||
|
||||
const nodes = [
|
||||
createNode('Founder & Chairman', 'Pierre Omidyar', male, '#31d0c6'),
|
||||
createNode('President & CEO', 'Margaret C. Whitman', female, '#31d0c6'),
|
||||
createNode('President, PayPal', 'Scott Thompson', male, '#7c68fc'),
|
||||
createNode(
|
||||
'President, Ebay Global Marketplaces',
|
||||
'Devin Wenig',
|
||||
male,
|
||||
'#7c68fc',
|
||||
),
|
||||
createNode(
|
||||
'Senior Vice President Human Resources',
|
||||
'Jeffrey S. Skoll',
|
||||
male,
|
||||
'#fe854f',
|
||||
),
|
||||
createNode(
|
||||
'Senior Vice President Controller',
|
||||
'Steven P. Westly',
|
||||
male,
|
||||
'#feb663',
|
||||
),
|
||||
createNode('Founder & Chairman', 'Pierre Omidyar', male),
|
||||
createNode('President & CEO', 'Margaret C. Whitman', female),
|
||||
createNode('President, PayPal', 'Scott Thompson', male),
|
||||
createNode('President, Ebay Global Marketplaces', 'Devin Wenig', male),
|
||||
createNode('Senior Vice President Human Resources', 'Jeffrey S. Skoll', male),
|
||||
createNode('Senior Vice President Controller', 'Steven P. Westly', male),
|
||||
]
|
||||
|
||||
const edges = [
|
||||
|
@ -73,8 +73,8 @@ TreeNode.config({
|
||||
refWidth: '100%',
|
||||
refHeight: '100%',
|
||||
strokeWidth: 1,
|
||||
fill: '#ffffff',
|
||||
stroke: '#a0a0a0',
|
||||
fill: '#EFF4FF',
|
||||
stroke: '#5F95FF',
|
||||
},
|
||||
label: {
|
||||
textWrap: {
|
||||
@ -92,7 +92,7 @@ TreeNode.config({
|
||||
refY: '50%',
|
||||
},
|
||||
button: {
|
||||
fill: '#4C65DD',
|
||||
fill: '#5F95FF',
|
||||
stroke: 'none',
|
||||
x: -10,
|
||||
y: -10,
|
||||
@ -124,7 +124,7 @@ TreeEdge.config({
|
||||
zIndex: 1,
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: '#a0a0a0',
|
||||
stroke: '#A2B1C3',
|
||||
strokeWidth: 1,
|
||||
targetMarker: null,
|
||||
},
|
||||
@ -138,15 +138,11 @@ Edge.registry.register('tree-edge', TreeEdge, true)
|
||||
// 初始化画布
|
||||
const graph = new Graph({
|
||||
container: document.getElementById('container')!,
|
||||
grid: 1,
|
||||
async: true,
|
||||
frozen: true,
|
||||
scroller: true,
|
||||
interacting: false,
|
||||
sorting: 'approx',
|
||||
background: {
|
||||
color: '#f5f5f5',
|
||||
},
|
||||
connecting: {
|
||||
anchor: 'orth',
|
||||
connector: 'rounded',
|
||||
|
@ -1,258 +0,0 @@
|
||||
import { Graph, Edge, Shape, NodeView } from '@antv/x6'
|
||||
|
||||
// 定义节点
|
||||
class MyShape extends Shape.Rect {
|
||||
getInPorts() {
|
||||
return this.getPortsByGroup('in')
|
||||
}
|
||||
|
||||
getOutPorts() {
|
||||
return this.getPortsByGroup('out')
|
||||
}
|
||||
|
||||
getUsedInPorts(graph: Graph) {
|
||||
const incomingEdges = graph.getIncomingEdges(this) || []
|
||||
return incomingEdges.map((edge: Edge) => {
|
||||
const portId = edge.getTargetPortId()
|
||||
return this.getPort(portId!)
|
||||
})
|
||||
}
|
||||
|
||||
getNewInPorts(length: number) {
|
||||
return Array.from(
|
||||
{
|
||||
length,
|
||||
},
|
||||
() => {
|
||||
return {
|
||||
group: 'in',
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
updateInPorts(graph: Graph) {
|
||||
const minNumberOfPorts = 2
|
||||
const ports = this.getInPorts()
|
||||
const usedPorts = this.getUsedInPorts(graph)
|
||||
const newPorts = this.getNewInPorts(
|
||||
Math.max(minNumberOfPorts - usedPorts.length, 1),
|
||||
)
|
||||
|
||||
if (
|
||||
ports.length === minNumberOfPorts &&
|
||||
ports.length - usedPorts.length > 0
|
||||
) {
|
||||
// noop
|
||||
} else if (ports.length === usedPorts.length) {
|
||||
this.addPorts(newPorts)
|
||||
} else if (ports.length + 1 > usedPorts.length) {
|
||||
this.prop(
|
||||
['ports', 'items'],
|
||||
this.getOutPorts().concat(usedPorts).concat(newPorts),
|
||||
{
|
||||
rewrite: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
MyShape.config({
|
||||
attrs: {
|
||||
root: {
|
||||
magnet: false,
|
||||
},
|
||||
body: {
|
||||
fill: '#f5f5f5',
|
||||
stroke: '#d9d9d9',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
ports: {
|
||||
items: [
|
||||
{
|
||||
group: 'out',
|
||||
},
|
||||
],
|
||||
groups: {
|
||||
in: {
|
||||
position: {
|
||||
name: 'top',
|
||||
},
|
||||
attrs: {
|
||||
portBody: {
|
||||
magnet: 'passive',
|
||||
r: 6,
|
||||
stroke: '#ffa940',
|
||||
fill: '#fff',
|
||||
strokeWidth: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
out: {
|
||||
position: {
|
||||
name: 'bottom',
|
||||
},
|
||||
attrs: {
|
||||
portBody: {
|
||||
magnet: true,
|
||||
r: 6,
|
||||
fill: '#fff',
|
||||
stroke: '#3199FF',
|
||||
strokeWidth: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
portMarkup: [
|
||||
{
|
||||
tagName: 'circle',
|
||||
selector: 'portBody',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// 高亮
|
||||
const magnetAvailabilityHighlighter = {
|
||||
name: 'stroke',
|
||||
args: {
|
||||
attrs: {
|
||||
fill: '#fff',
|
||||
stroke: '#47C769',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// 画布
|
||||
const graph = new Graph({
|
||||
grid: true,
|
||||
container: document.getElementById('container')!,
|
||||
highlighting: {
|
||||
magnetAvailable: magnetAvailabilityHighlighter,
|
||||
magnetAdsorbed: {
|
||||
name: 'stroke',
|
||||
args: {
|
||||
attrs: {
|
||||
fill: '#fff',
|
||||
stroke: '#31d0c6',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
connecting: {
|
||||
snap: true,
|
||||
allowBlank: false,
|
||||
allowLoop: false,
|
||||
highlight: true,
|
||||
connector: 'rounded',
|
||||
connectionPoint: 'boundary',
|
||||
router: {
|
||||
name: 'er',
|
||||
args: {
|
||||
direction: 'V',
|
||||
},
|
||||
},
|
||||
createEdge() {
|
||||
return new Shape.Edge({
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: '#a0a0a0',
|
||||
strokeWidth: 1,
|
||||
targetMarker: {
|
||||
name: 'classic',
|
||||
size: 7,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
},
|
||||
validateConnection({ sourceView, targetView, targetMagnet }) {
|
||||
if (!targetMagnet) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (targetMagnet.getAttribute('port-group') !== 'in') {
|
||||
return false
|
||||
}
|
||||
|
||||
if (targetView) {
|
||||
const node = targetView.cell
|
||||
if (node instanceof MyShape) {
|
||||
const portId = targetMagnet.getAttribute('port')
|
||||
const usedInPorts = node.getUsedInPorts(graph)
|
||||
if (usedInPorts.find((port) => port && port.id === portId)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
graph.addNode(
|
||||
new MyShape().resize(120, 40).position(200, 50).updateInPorts(graph),
|
||||
)
|
||||
|
||||
graph.addNode(
|
||||
new MyShape().resize(120, 40).position(400, 50).updateInPorts(graph),
|
||||
)
|
||||
|
||||
graph.addNode(
|
||||
new MyShape().resize(120, 40).position(300, 250).updateInPorts(graph),
|
||||
)
|
||||
|
||||
function update(view: NodeView) {
|
||||
const cell = view.cell
|
||||
if (cell instanceof MyShape) {
|
||||
cell.getInPorts().forEach((port) => {
|
||||
const portNode = view.findPortElem(port.id!, 'portBody')
|
||||
view.unhighlight(portNode, {
|
||||
highlighter: magnetAvailabilityHighlighter,
|
||||
})
|
||||
})
|
||||
cell.updateInPorts(graph)
|
||||
}
|
||||
}
|
||||
|
||||
graph.on('edge:connected', ({ previousView, currentView }) => {
|
||||
if (previousView) {
|
||||
update(previousView as NodeView)
|
||||
}
|
||||
if (currentView) {
|
||||
update(currentView as NodeView)
|
||||
}
|
||||
})
|
||||
|
||||
graph.on('edge:removed', ({ edge, options }) => {
|
||||
if (!options.ui) {
|
||||
return
|
||||
}
|
||||
|
||||
const target = edge.getTargetCell()
|
||||
if (target instanceof MyShape) {
|
||||
target.updateInPorts(graph)
|
||||
}
|
||||
})
|
||||
|
||||
graph.on('edge:mouseenter', ({ edge }) => {
|
||||
edge.addTools([
|
||||
'source-arrowhead',
|
||||
'target-arrowhead',
|
||||
{
|
||||
name: 'button-remove',
|
||||
args: {
|
||||
distance: -30,
|
||||
},
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
graph.on('edge:mouseleave', ({ edge }) => {
|
||||
edge.removeTools()
|
||||
})
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: 业务实践
|
||||
title: 业务场景
|
||||
order: 10
|
||||
redirect_from:
|
||||
- /zh/examples/practices
|
||||
|
Reference in New Issue
Block a user