feat: add primer and useForeignObject option for react-shape

primer: basic svg shape for calc connection point, useForeignObject: support render react component
to svg `g` element
This commit is contained in:
bubkoo
2021-01-26 16:53:47 +08:00
parent d8ee2aea3d
commit ab6a06f1fe
3 changed files with 102 additions and 18 deletions

View File

@ -25,6 +25,7 @@ class MyComponent extends React.Component<{ node?: Node; text: string }> {
height: '100%',
textAlign: 'center',
lineHeight: '60px',
borderRadius: 30,
background: color,
}}
>
@ -46,9 +47,10 @@ export default class Example extends React.Component {
const source = graph.addNode({
shape: 'react-shape',
primer: 'circle',
x: 80,
y: 80,
width: 160,
width: 60,
height: 60,
data: {},
xxx: {},
@ -59,14 +61,31 @@ export default class Example extends React.Component {
shape: 'react-shape',
x: 320,
y: 320,
width: 160,
height: 60,
width: 120,
height: 48,
component: (node) => {
return <div>{node.attr('body/fill')}</div>
return (
<div style={{ lineHeight: '48px', textAlign: 'center' }}>
{node.attr('body/fill')}
</div>
)
},
// component: () => <Test text="target" />,
})
graph.addNode({
shape: 'react-shape',
primer: 'circle',
x: 80,
y: 320,
width: 60,
height: 60,
useForeignObject: false,
component: () => {
return <circle stroke="red" cx="30" cy="30" r="30"/>
},
})
graph.addEdge({
source,
target,

View File

@ -1,4 +1,4 @@
import { Node, Markup } from '@antv/x6'
import { Node, Markup, ObjectExt } from '@antv/x6'
import { Definition } from './registry'
export class ReactShape<
@ -35,27 +35,50 @@ export class ReactShape<
}
export namespace ReactShape {
export type Primer =
| 'rect'
| 'circle'
| 'path'
| 'ellipse'
| 'polygon'
| 'polyline'
export interface Properties extends Node.Properties {
primer?: Primer
useForeignObject?: boolean
component?: Definition | string
}
}
export namespace ReactShape {
ReactShape.config({
view: 'react-shape-view',
markup: [
function getMarkup(useForeignObject: boolean, primer: Primer = 'rect') {
const markup: Markup.JSONMarkup[] = [
{
tagName: 'rect',
tagName: primer,
selector: 'body',
},
{
...Markup.getForeignObjectMarkup(),
},
{
tagName: 'text',
selector: 'label',
},
],
]
if (useForeignObject) {
markup.push(Markup.getForeignObjectMarkup())
} else {
markup.push({
tagName: 'g',
selector: 'content',
})
}
markup.push({
tagName: 'text',
selector: 'label',
})
return markup
}
ReactShape.config<Properties>({
view: 'react-shape-view',
markup: getMarkup(true),
attrs: {
body: {
fill: 'none',
@ -76,6 +99,46 @@ export namespace ReactShape {
textVerticalAnchor: 'middle',
},
},
propHooks(metadata: Properties) {
if (metadata.markup == null) {
const primer = metadata.primer
const useForeignObject = metadata.useForeignObject
if (primer != null || useForeignObject != null) {
metadata.markup = getMarkup(useForeignObject !== false, primer)
if (primer) {
if (metadata.attrs == null) {
metadata.attrs = {}
}
let attrs = {}
if (primer === 'circle') {
attrs = {
refCx: '50%',
refCy: '50%',
refR: '50%',
}
} else if (primer === 'ellipse') {
attrs = {
refCx: '50%',
refCy: '50%',
refRx: '50%',
refRy: '50%',
}
}
if (primer !== 'rect') {
metadata.attrs = ObjectExt.merge({}, metadata.attrs, {
body: {
refWidth: null,
refHeight: null,
...attrs,
},
})
}
}
}
}
return metadata
},
})
Node.registry.register('react-shape', ReactShape, true)

View File

@ -14,7 +14,9 @@ export class ReactShapeView extends NodeView<ReactShape> {
}
getComponentContainer() {
return this.selectors.foContent as HTMLDivElement
return this.cell.prop('useForeignObject') === false
? (this.selectors.content as SVGElement)
: (this.selectors.foContent as HTMLDivElement)
}
confirmUpdate(flag: number) {