docs: add editable node and edge demo (#572)
This commit is contained in:
@ -9,7 +9,7 @@
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*FgY8TJWw1TQAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "create.ts",
|
||||
"filename": "create.tsx",
|
||||
"title": {
|
||||
"zh": "手动创建连线",
|
||||
"en": "Create Edge Manually"
|
||||
|
@ -1,131 +0,0 @@
|
||||
import React from 'react'
|
||||
import ReactDom from 'react-dom'
|
||||
import { Dropdown, Menu, message } from 'antd'
|
||||
import { Graph } from '@antv/x6'
|
||||
|
||||
class Example extends React.Component {
|
||||
private container: HTMLDivElement
|
||||
private contextMenuAnchor: HTMLSpanElement
|
||||
|
||||
componentDidMount() {
|
||||
const graph = new Graph({
|
||||
container: this.container,
|
||||
grid: true,
|
||||
width: 780,
|
||||
height: 520,
|
||||
})
|
||||
|
||||
const source = graph.addNode({
|
||||
x: 180,
|
||||
y: 60,
|
||||
width: 100,
|
||||
height: 40,
|
||||
attrs: {
|
||||
body: {
|
||||
fill: '#f5f5f5',
|
||||
stroke: '#d9d9d9',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const target = graph.addNode({
|
||||
x: 320,
|
||||
y: 250,
|
||||
width: 100,
|
||||
height: 40,
|
||||
attrs: {
|
||||
body: {
|
||||
fill: '#f5f5f5',
|
||||
stroke: '#d9d9d9',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
graph.addEdge({
|
||||
source,
|
||||
target,
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: '#a0a0a0',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
graph.on('cell:contextmenu', ({ e }) => {
|
||||
const { x, y } = graph.clientToLocal(e.clientX, e.clientY)
|
||||
this.contextMenuAnchor.style.display = 'inline-block'
|
||||
this.contextMenuAnchor.style.left = `${x}px`
|
||||
this.contextMenuAnchor.style.top = `${y}px`
|
||||
const clickEvent = document.createEvent('HTMLEvents')
|
||||
clickEvent.initEvent('click', true, true)
|
||||
this.contextMenuAnchor.dispatchEvent(clickEvent)
|
||||
})
|
||||
}
|
||||
|
||||
renderContextMenu() {
|
||||
return (
|
||||
<Menu onClick={(e) => message.info(`select ${e.key}`)}>
|
||||
<Menu.Item key={0}>Menu Item 0</Menu.Item>
|
||||
<Menu.Item key={1}>Menu Item 1</Menu.Item>
|
||||
<Menu.Item key={2}>Menu Item 2</Menu.Item>
|
||||
<Menu.Item key={3}>Menu Item 3</Menu.Item>
|
||||
<Menu.Item key={4}>Menu Item 4</Menu.Item>
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
|
||||
handleContextMenuVisibleChange = (visible: boolean) => {
|
||||
if (!visible) {
|
||||
this.contextMenuAnchor.style.display = 'none'
|
||||
}
|
||||
}
|
||||
|
||||
refContainer = (container: HTMLDivElement) => {
|
||||
this.container = container
|
||||
}
|
||||
|
||||
refContextMenuAnchor = (anchor: HTMLSpanElement) => {
|
||||
this.contextMenuAnchor = anchor
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="x6-graph-wrap">
|
||||
<div ref={this.refContainer} />
|
||||
<Dropdown
|
||||
overlay={this.renderContextMenu()}
|
||||
trigger={['click']}
|
||||
onVisibleChange={this.handleContextMenuVisibleChange}
|
||||
>
|
||||
<span
|
||||
ref={this.refContextMenuAnchor}
|
||||
className="context-menu-anchor"
|
||||
/>
|
||||
</Dropdown>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ReactDom.render(<Example />, document.getElementById('container'))
|
||||
|
||||
// 我们用 insert-css 协助demo演示
|
||||
// 实际项目中只要将下面样式添加到样式文件中
|
||||
insertCss(`
|
||||
.x6-graph-wrap {
|
||||
position: relative;
|
||||
}
|
||||
.context-menu-anchor {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
display: none;
|
||||
cursor: default;
|
||||
font-size: 1px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
`)
|
175
sites/x6-sites/examples/node/tool/demo/editable.ts
Normal file
175
sites/x6-sites/examples/node/tool/demo/editable.ts
Normal file
@ -0,0 +1,175 @@
|
||||
import { Graph, ToolsView, EdgeView, Point } from '@antv/x6'
|
||||
import '../index.less'
|
||||
|
||||
class EditableCellTool extends ToolsView.ToolItem<
|
||||
EdgeView,
|
||||
EditableCellToolOptions
|
||||
> {
|
||||
private editorContent: HTMLDivElement
|
||||
|
||||
render() {
|
||||
super.render()
|
||||
const cell = this.cell
|
||||
let x = 0
|
||||
let y = 0
|
||||
let width = 0
|
||||
let height = 0
|
||||
|
||||
if (cell.isNode()) {
|
||||
const position = cell.position()
|
||||
const size = cell.size()
|
||||
x = position.x
|
||||
y = position.y
|
||||
width = size.width
|
||||
height = size.height
|
||||
} else {
|
||||
x = this.options.x - 40
|
||||
y = this.options.y - 20
|
||||
width = 80
|
||||
height = 40
|
||||
}
|
||||
|
||||
const editorParent = ToolsView.createElement('div', false) as HTMLDivElement
|
||||
editorParent.style.position = 'absolute'
|
||||
editorParent.style.left = `${x}px`
|
||||
editorParent.style.top = `${y}px`
|
||||
editorParent.style.width = `${width}px`
|
||||
editorParent.style.height = `${height}px`
|
||||
editorParent.style.display = 'flex'
|
||||
editorParent.style.alignItems = 'center'
|
||||
editorParent.style.textAlign = 'center'
|
||||
|
||||
this.editorContent = ToolsView.createElement('div', false) as HTMLDivElement
|
||||
this.editorContent.contentEditable = 'true'
|
||||
this.editorContent.style.width = '100%'
|
||||
this.editorContent.style.outline = 'none'
|
||||
this.editorContent.style.backgroundColor = cell.isEdge() ? '#fff' : ''
|
||||
this.editorContent.style.border = cell.isEdge() ? '1px solid #ccc' : 'none'
|
||||
editorParent.appendChild(this.editorContent)
|
||||
this.container.appendChild(editorParent)
|
||||
|
||||
this.init()
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
init = () => {
|
||||
const cell = this.cell
|
||||
if (cell.isNode()) {
|
||||
const value = cell.attr('text/text') as string
|
||||
if (value) {
|
||||
this.editorContent.innerHTML = value
|
||||
cell.attr('text/text', '')
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.editorContent.focus()
|
||||
})
|
||||
document.addEventListener('mousedown', this.onMouseDown)
|
||||
}
|
||||
|
||||
onMouseDown = (e: MouseEvent) => {
|
||||
if (e.target !== this.editorContent) {
|
||||
const cell = this.cell
|
||||
const value = this.editorContent.innerHTML
|
||||
cell.removeTools()
|
||||
if (cell.isNode()) {
|
||||
cell.attr('text/text', value)
|
||||
} else if (cell.isEdge()) {
|
||||
cell.appendLabel({
|
||||
attrs: {
|
||||
text: {
|
||||
text: value,
|
||||
}
|
||||
},
|
||||
position: {
|
||||
distance: this.getDistance(),
|
||||
}
|
||||
})
|
||||
}
|
||||
document.removeEventListener('mousedown', this.onMouseDown)
|
||||
}
|
||||
}
|
||||
|
||||
getDistance() {
|
||||
const cell = this.cell
|
||||
if (cell.isEdge()) {
|
||||
const targetPoint = cell.getTargetPoint()
|
||||
const cross = cell.getSourceNode()!.getBBox().intersectsWithLineFromCenterToPoint(targetPoint)!
|
||||
const p = new Point(this.options.x, this.options.y)
|
||||
return p.distance(cross)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
EditableCellTool.config({
|
||||
tagName: 'div',
|
||||
isSVGElement: false,
|
||||
})
|
||||
|
||||
export interface EditableCellToolOptions extends ToolsView.ToolItem.Options {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
|
||||
Graph.registerEdgeTool('editableCell', EditableCellTool, true)
|
||||
Graph.registerNodeTool('editableCell', EditableCellTool, true)
|
||||
|
||||
const container = document.getElementById('container')
|
||||
const graph = new Graph({
|
||||
container: container,
|
||||
grid: true,
|
||||
})
|
||||
|
||||
const source = graph.addNode({
|
||||
x: 180,
|
||||
y: 60,
|
||||
width: 100,
|
||||
height: 40,
|
||||
attrs: {
|
||||
body: {
|
||||
fill: '#f5f5f5',
|
||||
stroke: '#d9d9d9',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const target = graph.addNode({
|
||||
x: 320,
|
||||
y: 250,
|
||||
width: 100,
|
||||
height: 40,
|
||||
attrs: {
|
||||
body: {
|
||||
fill: '#f5f5f5',
|
||||
stroke: '#d9d9d9',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
graph.addEdge({
|
||||
source,
|
||||
target,
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: '#a0a0a0',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
graph.on('cell:dblclick', ({ cell, e }) => {
|
||||
const p = graph.clientToGraph(e.clientX, e.clientY)
|
||||
cell.addTools([
|
||||
{
|
||||
name: 'editableCell',
|
||||
args: {
|
||||
x: p.x,
|
||||
y: p.y,
|
||||
},
|
||||
},
|
||||
])
|
||||
})
|
@ -25,12 +25,12 @@
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*9jEGTak16UEAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "contextmenu.tsx",
|
||||
"filename": "editable.ts",
|
||||
"title": {
|
||||
"zh": "右键菜单",
|
||||
"en": "Context Menu"
|
||||
"zh": "文本编辑",
|
||||
"en": "Text Editor"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*cBHESINBs3MAAAAAAAAAAAAAARQnAQ"
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*XYwVTYkKcpwAAAAAAAAAAAAAARQnAQ"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Reference in New Issue
Block a user