Compare commits

...

34 Commits

Author SHA1 Message Date
bc67848207 chore(release): 🚀 publish 2022-09-15 10:46:36 +08:00
12173bf500 feat: add scroller api
* docs: 📚️ add port connected demo

* feat:  add scroller api
2022-09-14 17:09:59 +08:00
8d645f980a chore(release): 🚀 publish 2022-09-13 22:10:15 +08:00
1701150042 fix: 🐛 fix type error in keyboard plugin (#2674) 2022-09-13 22:09:46 +08:00
6b8d7a4ef2 chore(release): 🚀 publish 2022-09-13 11:02:58 +08:00
8a17bfac81 fix: 🐛 change init method to public (#2671) 2022-09-13 10:59:30 +08:00
14ba132592 chore(release): 🚀 publish 2022-09-13 10:52:28 +08:00
f43e0a5417 feat: add trnsition methods for scroller plugin (#2670) 2022-09-13 10:51:44 +08:00
25b238fd0b feat: improve scroller plugin (#2667) 2022-09-13 10:25:00 +08:00
bf536778ca feat: add keyboard plugin (#2665)
* chore: 🔧 update yarn.lock

* feat:  add keyboard plugin
2022-09-10 19:51:53 +08:00
693e351957 chore(release): 🚀 publish 2022-09-08 19:55:38 +08:00
9a95594a72 chore(release): 🚀 publish 2022-09-08 19:54:42 +08:00
b7cef9edd2 chore: 🔧 remove release-it cmd (#2659)
* chore: 🔧 update x6-react-components version

* chore: 🔧 remove release-it cmd
2022-09-08 19:52:06 +08:00
f4c977759f chore: 🔧 unify the version of each package (#2658) 2022-09-08 19:11:46 +08:00
1f653d27d4 chore(release): 🚀 publish 2022-09-08 17:33:59 +08:00
27f27f1e75 chore: 🔧 update peerDeps for plugins (#2657) 2022-09-08 17:33:05 +08:00
cff8c126de chore(release): 🚀 publish 2022-09-08 15:52:46 +08:00
346c6a268a chore: 🔧 update yarn.lock (#2653) 2022-09-08 15:51:53 +08:00
f53f819043 chore: 🔧 update peerDeps for plugins (#2652) 2022-09-08 15:44:50 +08:00
f351284809 chore(release): 🚀 publish 2022-09-08 11:30:48 +08:00
12c67255ae feat: add onPortRendered options (#2649)
* chore: 🔧 set x6-next and x6-core to private

* feat:  add onPortRendered options
2022-09-08 11:29:15 +08:00
7e179844dc chore: 🔧 update peerdeps for some package (#2597) 2022-08-31 10:48:06 +08:00
bc5284c6fe chore(release): 🚀 publish 2022-08-31 10:37:48 +08:00
ad63046e89 feat: support inherit options for react-shape registry (#2596) 2022-08-31 10:29:44 +08:00
12f0345555 docs: 📚️ add react-shape demos (#2590) 2022-08-29 17:14:13 +08:00
5e0e2acde7 feat: add scroller plugin (#2580)
* feat:  support priority when find anchors

* feat:  add scroller plugin
2022-08-25 21:44:09 +08:00
a10dcdb29f chore: 🔧 change publish script (#2565) 2022-08-24 11:51:19 +08:00
394c945fa2 chore: update x6-next version (#2563)
* feat:  add built-in shapes

* chore: 🔧 change virtualRender option to virtual

* feat:  support mouseenter and mouseleave event

* chore: 🔧 update x6-next version
2022-08-24 10:57:33 +08:00
ecfd4263b1 feat: support mouseenter and mouseleave event (#2559)
* feat:  add built-in shapes

* chore: 🔧 change virtualRender option to virtual

* feat:  support mouseenter and mouseleave event

* chore: 🔧 add lerna publish cmd

* chore(release): 🚀 publish
2022-08-24 10:26:20 +08:00
6ce3980f86 chore: optimize some features (#2530)
* chore: 🔧 release @antv/x6-common@2.0.1-beta.5

* chore: 🔧 release @antv/x6-next@2.0.1-beta.5

* feat:  add built-in shapes

* fix: 🐛 remove transition:begin and transition:end event

* chore: 🔧 change virtualRender option to virtual
2022-08-17 23:14:15 +08:00
a09deaadd0 chore: 🔧 update x6-next version (#2416) 2022-07-25 16:06:11 +08:00
b8576ce96a chore: 🔧 release @antv/x6-next@2.0.1-beta.4 2022-07-24 20:06:09 +08:00
aafdab63ba chore: 🔧 release @antv/x6-geometry@2.0.1-beta.4 (#2414) 2022-07-24 20:00:53 +08:00
41f6b252ac chore: 🔧 update commit msg for release (#2413) 2022-07-24 19:42:09 +08:00
103 changed files with 3937 additions and 488 deletions

View File

@ -8,7 +8,6 @@
"pretty-quick": "^3.1.1",
"rimraf": "^3.0.2",
"ts-node": "^10.2.1",
"typescript": "^4.4.3",
"release-it": "^14.0.1"
"typescript": "^4.4.3"
}
}

View File

@ -7,7 +7,6 @@
"build": "umi build",
"postinstall": "umi generate tmp",
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
"test": "umi-test",
"lint": "umi-lint --eslint src/ -p.no-semi --prettier --fix",
"test:coverage": "umi-test --coverage"
},

View File

@ -7,7 +7,6 @@
"build": "umi build",
"postinstall": "umi generate tmp",
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
"test": "umi-test",
"test:coverage": "umi-test --coverage"
},
"gitHooks": {

View File

@ -1,7 +1,7 @@
{
"private": true,
"name": "@antv/x6-example-features",
"version": "1.2.2",
"version": "2.0.2-beta.0",
"scripts": {
"start": "umi dev",
"build": "umi build",
@ -10,8 +10,9 @@
},
"dependencies": {
"@antv/x6": "^1.30.2",
"@antv/x6-react-components": "^1.1.16",
"@antv/x6-react-shape": "^1.6.0",
"@antv/x6-next": "^2.0.6-beta.0",
"@antv/x6-react-components": "^2.0.6-beta.0",
"@antv/x6-react-shape": "^2.0.6-beta.0",
"@antv/x6-vector": "^1.3.0",
"antd": "^4.4.2",
"classnames": "^2.2.6",

View File

@ -5,12 +5,11 @@ import '../index.less'
class BallView extends NodeView {
protected speed: number = 0
protected angle: number = 0
protected timerId: number = 0
protected edge: Edge | null
protected init() {
this.timerId = this.cell.transition('attrs/label/opacity', 1, {
delay: (1 + Math.random()) * 3000,
this.cell.transition('attrs/label/opacity', 1, {
delay: 0,
duration: 3000,
timing: 'inout',
interp: function (a: number, b: number) {
@ -97,17 +96,13 @@ class BallView extends NodeView {
}
onMouseDown(e: JQuery.MouseDownEvent, x: number, y: number) {
console.log('mousedown1')
// Do not allow drag element while it's still in a transition.
if (this.cell.getTransitions().indexOf('position') > -1) {
console.log('mousedown2')
return
}
// Cancel displaying 'drag me!' if dragging already starts.
if (this.timerId) {
clearTimeout(this.timerId)
delete this.timerId
}
this.edge = this.graph.addEdge({
shape: 'edge',
source: this.cell.getBBox().getCenter(),

View File

@ -1,5 +1,7 @@
import React from 'react'
import { Graph, Cell, Point, Timing, Interp } from '@antv/x6'
import { Graph, Cell } from '@antv/x6-next'
import { Point } from '@antv/x6-geometry'
import { Timing, Interp } from '@antv/x6-common'
import '../index.less'
export default class Example extends React.Component {
@ -11,6 +13,9 @@ export default class Example extends React.Component {
width: 650,
height: 400,
grid: 1,
background: {
color: '#F2F7FA',
},
})
const ball = graph.addNode({
@ -23,9 +28,12 @@ export default class Example extends React.Component {
label: {
text: 'ball',
fontSize: 20,
stroke: '#8f8f8f',
},
body: {
fill: '#FFFFFF',
stroke: '#8f8f8f',
strokeWidth: 1,
},
},
})
@ -59,7 +67,6 @@ export default class Example extends React.Component {
{
delay: 5000,
duration: 2000,
easing: 'easeInBounce',
interp: (
start: { text: String; fontSize: number },
end: { text: String; fontSize: number },
@ -84,9 +91,12 @@ export default class Example extends React.Component {
label: {
text: 'u.f.o.',
fontSize: 10,
stroke: '8f8f8f',
},
body: {
fill: '#FFFFFF',
stroke: '#8f8f8f',
strokeWidth: 1,
},
},
})

View File

@ -1,5 +1,5 @@
import React from 'react'
import { Graph, Cell } from '@antv/x6'
import { Graph, Cell } from '@antv/x6-next'
import { Bus, Connector, Component, Fader, Aux } from './shapes'
import '../index.less'
import './index.less'
@ -12,9 +12,6 @@ export default class Example extends React.Component {
container: this.container,
width: 1000,
height: 800,
async: true,
frozen: true,
sorting: 'approx',
translating: {
restrict: true,
},
@ -206,8 +203,6 @@ export default class Example extends React.Component {
connector24,
connector25,
] as any)
graph.unfreeze()
}
refContainer = (container: HTMLDivElement) => {

View File

@ -1,4 +1,4 @@
import { Node, Shape } from '@antv/x6'
import { Node, Shape } from '@antv/x6-next'
export class Bus extends Shape.Edge {
static create(x: number, label: string, color: string) {

View File

@ -23,3 +23,9 @@
box-shadow: 0 0 10px 1px #e9e9e9;
margin: 0 auto;
}
.home {
width: 800px;
height: 100%;
margin: 0 auto;
}

View File

@ -1,9 +1,42 @@
import React from 'react'
import { Table } from 'antd'
import './index.less'
const dataSource = [
{
key: '1',
example: 'animation/transition',
description: 'transition 动画',
},
]
const columns = [
{
title: 'example',
dataIndex: 'example',
render(text: string) {
return (
<a href={`./${text}`} target="_blank">
{text}
</a>
)
},
},
{
title: 'description',
dataIndex: 'description',
},
]
export default function () {
return (
<div>
<h1>Feature List</h1>
<div className="home">
<Table
dataSource={dataSource}
columns={columns}
pagination={false}
size="small"
/>
</div>
)
}

View File

@ -1,5 +1,6 @@
import React from 'react'
import { Graph } from '@antv/x6'
import { Graph } from '@antv/x6-next'
import { Keyboard } from '@antv/x6-plugin-keyboard'
import '../index.less'
export default class Example extends React.Component {
@ -11,17 +12,28 @@ export default class Example extends React.Component {
width: 800,
height: 600,
grid: true,
selecting: {
// selecting: {
// enabled: true,
// showNodeSelectionBox: true,
// },
// clipboard: {
// enabled: true,
// },
// keyboard: {
// enabled: true,
// global: false,
// },
})
graph.use(
new Keyboard({
enabled: true,
showNodeSelectionBox: true,
},
clipboard: {
enabled: true,
},
keyboard: {
enabled: true,
global: false,
},
}),
)
const keyboard = graph.getPlugin('keyboard') as Keyboard
keyboard.bindKey('backspace', () => {
console.log('backspace')
})
graph.addNode({
@ -48,30 +60,30 @@ export default class Example extends React.Component {
attrs: { label: { text: 'C' } },
})
graph.bindKey('meta+c', () => {
const cells = graph.getSelectedCells()
if (cells.length) {
graph.copy(cells)
}
return false
})
// graph.bindKey('meta+c', () => {
// const cells = graph.getSelectedCells()
// if (cells.length) {
// graph.copy(cells)
// }
// return false
// })
graph.bindKey('meta+v', () => {
if (!graph.isClipboardEmpty()) {
const cells = graph.paste({ offset: 32 })
graph.resetSelection(cells)
}
console.log(graph.toJSON())
return false
})
// graph.bindKey('meta+v', () => {
// if (!graph.isClipboardEmpty()) {
// const cells = graph.paste({ offset: 32 })
// graph.resetSelection(cells)
// }
// console.log(graph.toJSON())
// return false
// })
graph.bindKey('backspace', () => {
graph.removeCells(graph.getSelectedCells())
})
// graph.bindKey('backspace', () => {
// graph.removeCells(graph.getSelectedCells())
// })
graph.on('selection:changed', ({ selected }) => {
console.log(selected)
})
// graph.on('selection:changed', ({ selected }) => {
// console.log(selected)
// })
}
refContainer = (container: HTMLDivElement) => {

View File

@ -0,0 +1,188 @@
import React from 'react'
import { Graph, Node } from '@antv/x6-next'
import { Path } from '@antv/x6-geometry'
import '../index.less'
Graph.registerConnector(
'ports-connected-connector',
(s, e) => {
const offset = 4
const deltaY = Math.abs(e.y - s.y)
const control = Math.floor((deltaY / 3) * 2)
const v1 = { x: s.x, y: s.y + offset + control }
const v2 = { x: e.x, y: e.y - offset - control }
return Path.normalize(
`M ${s.x} ${s.y}
L ${s.x} ${s.y + offset}
C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${e.x} ${e.y - offset}
L ${e.x} ${e.y}
`,
)
},
true,
)
Graph.registerNode(
'ports-connected-node',
{
width: 144,
height: 28,
markup: [
{
tagName: 'rect',
},
{
tagName: 'image',
},
{
tagName: 'text',
},
],
attrs: {
rect: {
rx: 14,
ry: 14,
refWidth: '100%',
refHeight: '100%',
fill: '#FFF',
stroke: '#5f95ff',
strokeWidth: 1,
},
image: {
x: 2,
y: 2,
width: 24,
height: 24,
xlinkHref:
'https://gw.alipayobjects.com/zos/bmw-prod/d9f3b597-3a2e-49c3-8469-64a1168ed779.svg',
},
text: {
x: 28,
y: 18,
text: '深度学习',
fontSize: 12,
fill: '#000000a6',
},
},
ports: {
groups: {
top: {
position: 'top',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#c5c5c5',
strokeWidth: 1,
fill: '#fff',
},
},
},
bottom: {
position: 'bottom',
attrs: {
circle: {
r: 4,
magnet: true,
stroke: '#c5c5c5',
strokeWidth: 1,
fill: '#fff',
},
},
},
},
},
},
true,
)
export default class Example extends React.Component {
private container: HTMLDivElement
componentDidMount() {
const graph = new Graph({
container: this.container,
width: 800,
height: 600,
connecting: {
connector: 'ports-connected-connector',
createEdge() {
return this.createEdge({
attrs: {
line: {
stroke: '#c5c5c5',
strokeWidth: 1,
targetMarker: null,
},
},
zIndex: -1,
})
},
},
})
graph.addNode({
shape: 'ports-connected-node',
width: 144,
height: 28,
x: 200,
y: 200,
ports: {
items: [
{
id: '1',
group: 'bottom',
},
{
id: '2',
group: 'bottom',
},
],
},
})
graph.addNode({
shape: 'ports-connected-node',
x: 200,
y: 400,
width: 144,
height: 28,
ports: {
items: [
{
id: '3',
group: 'top',
},
],
},
})
graph.on('edge:connected', ({ currentCell, currentPort }) => {
const node = currentCell as Node
node.setPortProp(currentPort as string, 'markup', [
{
tagName: 'path',
attrs: {
fill: '#808080',
d: 'M -1 1 L 7 1 L 3 5 L -1 1 Z',
style: 'transform: translateY(-1px)',
},
},
])
})
}
refContainer = (container: HTMLDivElement) => {
this.container = container
}
render() {
return (
<div className="x6-graph-wrap">
<div ref={this.refContainer} className="x6-graph" />
</div>
)
}
}

View File

@ -0,0 +1,77 @@
import React from 'react'
import { Graph, Node } from '@antv/x6-next'
import { ReactShape, register } from '@antv/x6-react-shape'
import '../index.less'
import './index.less'
class GroupNode extends ReactShape {
isGroup() {
return true
}
}
Graph.registerNode('group-node', GroupNode, true)
const NodeComponent = ({ node }: { node: Node }) => {
const data = node.getData()
return (
<div className="react-algo-node">
<img
src="https://gw.alipayobjects.com/zos/bmw-prod/d9f3b597-3a2e-49c3-8469-64a1168ed779.svg"
alt=""
/>
<span>{data.name}</span>
</div>
)
}
register(NodeComponent, {
shape: 'algo-node-3',
width: 144,
height: 28,
effect: ['data'],
inherit: 'group-node',
})
export default class Example extends React.Component {
private container: HTMLDivElement
private count = 0
componentDidMount() {
const graph = new Graph({
container: this.container,
width: 800,
height: 600,
})
const node = graph.createNode({
shape: 'algo-node-3',
x: 80,
y: 80,
data: {
name: '逻辑回归',
},
})
console.log(node.isGroup())
const update = () => {
node.setData({ name: `逻辑回归 ${(this.count += 1)}` })
setTimeout(update, 1000)
}
update()
}
refContainer = (container: HTMLDivElement) => {
this.container = container
}
render() {
return (
<div className="x6-graph-wrap">
<div ref={this.refContainer} className="x6-graph" />
</div>
)
}
}

View File

@ -0,0 +1,27 @@
.react-algo-node {
width: 100%;
height: 100%;
border: 1px solid #5f95ff;
border-radius: 14px;
display: flex;
align-items: center;
img {
width: 24px;
height: 24px;
}
span {
margin-left: 4px;
font-size: 12px;
color: #000000a6;
}
&.dark {
background-color: #141414;
span {
color: #fff;
}
}
}

View File

@ -1,42 +1,33 @@
import React from 'react'
import { Graph, Node, Color } from '@antv/x6'
import '@antv/x6-react-shape'
import { Graph, Node } from '@antv/x6-next'
import { register } from '@antv/x6-react-shape'
import '../index.less'
import './index.less'
class MyComponent extends React.Component<{ node?: Node; text: string }> {
shouldComponentUpdate() {
const node = this.props.node
if (node) {
if (node.hasChanged('data')) {
return true
}
}
const NodeComponent = ({ node }: { node: Node }) => {
const data = node.getData()
return false
}
render() {
const color = Color.randomHex()
return (
<div
style={{
color: Color.invert(color, true),
width: '100%',
height: '100%',
textAlign: 'center',
lineHeight: '60px',
borderRadius: 30,
background: color,
}}
>
{this.props.text}
</div>
)
}
return (
<div className="react-algo-node">
<img
src="https://gw.alipayobjects.com/zos/bmw-prod/d9f3b597-3a2e-49c3-8469-64a1168ed779.svg"
alt=""
/>
<span>{data.name}</span>
</div>
)
}
register(NodeComponent, {
shape: 'algo-node-1',
width: 144,
height: 28,
effect: ['data'],
})
export default class Example extends React.Component {
private container: HTMLDivElement
private count = 0
componentDidMount() {
const graph = new Graph({
@ -45,60 +36,21 @@ export default class Example extends React.Component {
height: 600,
})
const source = graph.addNode({
shape: 'react-shape',
primer: 'circle',
const node = graph.addNode({
shape: 'algo-node-1',
x: 80,
y: 80,
width: 60,
height: 60,
data: {},
xxx: {},
component: <MyComponent text="Source" />,
})
const target = graph.addNode({
shape: 'react-shape',
x: 320,
y: 320,
width: 120,
height: 48,
component: (node) => {
return (
<div style={{ lineHeight: '48px', textAlign: 'center' }}>
{node.attr('body/fill')}
</div>
)
data: {
name: '逻辑回归',
},
// 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,
})
const update = () => {
target.prop('attrs/body/fill', Color.randomHex())
node.setData({ name: `逻辑回归 ${(this.count += 1)}` })
setTimeout(update, 1000)
}
update()
console.log(graph.toJSON())
}
refContainer = (container: HTMLDivElement) => {

View File

@ -1,42 +1,41 @@
import React from 'react'
import { Graph, Node, Color } from '@antv/x6'
import { Portal } from '@antv/x6-react-shape'
import React, { useContext } from 'react'
import { Graph } from '@antv/x6-next'
import { register, Portal } from '@antv/x6-react-shape'
import { Button } from 'antd'
import '../index.less'
import './index.less'
class MyComponent extends React.Component<{ node?: Node; text: string }> {
shouldComponentUpdate() {
const node = this.props.node
if (node) {
if (node.hasChanged('data')) {
return true
}
}
const X6ReactPortalProvider = Portal.getProvider() // 注意,一个 graph 只能申明一个 portal provider
const ThemeContext = React.createContext('light')
return false
}
const NodeComponent = () => {
const theme = useContext(ThemeContext)
render() {
const color = Color.randomHex()
return (
<div
style={{
color: Color.invert(color, true),
width: '100%',
height: '100%',
textAlign: 'center',
lineHeight: '60px',
background: color,
}}
>
{this.props.text}
</div>
)
}
return (
<div className={`react-algo-node ${theme === 'light' ? 'light' : 'dark'}`}>
<img
src="https://gw.alipayobjects.com/zos/bmw-prod/d9f3b597-3a2e-49c3-8469-64a1168ed779.svg"
alt=""
/>
<span></span>
</div>
)
}
register(NodeComponent, {
shape: 'algo-node-2',
width: 144,
height: 28,
effect: [],
})
export default class Example extends React.Component {
private container: HTMLDivElement
state = {
theme: 'light',
}
componentDidMount() {
const graph = new Graph({
container: this.container,
@ -44,42 +43,20 @@ export default class Example extends React.Component {
height: 600,
})
const source = graph.addNode({
shape: 'react-shape',
graph.addNode({
shape: 'algo-node-2',
x: 80,
y: 80,
width: 160,
height: 60,
data: {},
xxx: {},
component: <MyComponent text="Source" />,
})
const target = graph.addNode({
shape: 'react-shape',
x: 320,
y: 320,
width: 160,
height: 60,
component: (node) => {
return <div>{node.attr('body/fill')}</div>
data: {
name: '逻辑回归',
},
// component: () => <Test text="target" />,
})
}
graph.addEdge({
source,
target,
changeTheme = () => {
this.setState({
theme: this.state.theme === 'light' ? 'dark' : 'light',
})
const update = () => {
target.prop('attrs/body/fill', Color.randomHex())
setTimeout(update, 1000)
}
update()
console.log(graph.toJSON())
}
refContainer = (container: HTMLDivElement) => {
@ -87,10 +64,16 @@ export default class Example extends React.Component {
}
render() {
const X6ReactPortalProvider = Portal.getProvider()
return (
<div className="x6-graph-wrap">
<X6ReactPortalProvider />
<ThemeContext.Provider value={this.state.theme}>
<X6ReactPortalProvider />
</ThemeContext.Provider>
<div className="x6-graph-tools">
<Button onClick={this.changeTheme}>
{this.state.theme === 'light' ? 'Light' : 'Dark'}
</Button>
</div>
<div ref={this.refContainer} className="x6-graph" />
</div>
)

View File

@ -0,0 +1,71 @@
import React from 'react'
import { Graph } from '@antv/x6-next'
import { Scroller } from '@antv/x6-plugin-scroller'
import '../index.less'
import './index.less'
export default class Example extends React.Component {
private graph: Graph
private graphContainer: HTMLDivElement
componentDidMount() {
const graph = new Graph({
container: this.graphContainer,
width: 800,
height: 500,
background: {
color: '#f5f5f5',
},
grid: {
visible: true,
},
mousewheel: {
enabled: true,
// fixed: false,
modifiers: ['ctrl', 'meta'],
minScale: 0.5,
maxScale: 2,
},
})
graph.use(
new Scroller({
enabled: true,
// width: 600,
// height: 400,
pageVisible: true,
pageBreak: true,
pannable: {
enabled: true,
eventTypes: ['leftMouseDown', 'rightMouseDown'],
},
}),
)
graph.addNode({
shape: 'rect',
x: 300,
y: 300,
width: 90,
height: 60,
attrs: {
rect: { fill: '#31D0C6', stroke: '#4B4A67', 'stroke-width': 2 },
text: { text: 'rect', fill: 'white' },
},
ports: [{}],
})
}
refContainer = (container: HTMLDivElement) => {
this.graphContainer = container
}
render() {
return (
<div className="x6-graph-wrap">
<h1>Scroller</h1>
<div ref={this.refContainer} className="x6-graph" />
</div>
)
}
}

View File

@ -6,7 +6,7 @@ import { generateData, parsePorts } from './data'
import { getPortsDefinition } from './port'
import { Component } from './component'
import './view'
import '../../index.less'
import '../index.less'
export default class Example extends React.Component {
private container: HTMLDivElement

View File

@ -1,33 +0,0 @@
import React from 'react'
import { SVG } from '@antv/x6-vector'
import '../index.less'
export default class Example extends React.Component {
private container: HTMLDivElement
componentDidMount() {
const svg = new SVG()
const rect = svg.rect(100, 100).node
svg.appendTo(this.container)
rect.animate(
[{ fill: '#000000' }, { fill: '#0000FF' }, { fill: '#00FFFF' }],
{
duration: 3000,
iterations: Infinity,
},
)
}
refContainer = (container: HTMLDivElement) => {
this.container = container
}
render() {
return (
<div className="x6-graph-wrap">
<h1>Default Settings</h1>
<div ref={this.refContainer} className="x6-graph" />
</div>
)
}
}

View File

@ -1,3 +0,0 @@
import { version } from '@antv/x6-vector'
console.log(version)

View File

@ -1,5 +1,5 @@
{
"version": "independent",
"version": "2.0.6-beta.6",
"npmClient": "yarn",
"useWorkspaces": true,
"command": {
@ -24,5 +24,12 @@
"pr(refactor)": ":100: Refactoring",
"pr(test)": ":white_check_mark: Test Case"
}
}
},
"packages": [
"packages/x6-common",
"packages/x6-geometry",
"packages/x6-next",
"packages/x6-react-shape",
"packages/x6-vue-shape"
]
}

View File

@ -26,7 +26,10 @@
"package:check": "yarn package-inherit check",
"package:inherit": "yarn package-inherit update",
"prepare": "is-ci || husky install configs/husky-config",
"precommit": "yarn lint-staged && lerna run --concurrency 1 --stream precommit"
"precommit": "yarn lint-staged && lerna run --concurrency 1 --stream precommit",
"version": "lerna version --no-private",
"publish:latest": "lerna publish from-package --no-private --ignore-scripts",
"publish:beta": "lerna publish from-package --no-private --ignore-scripts --canary --preid beta --dist-tag=beta"
},
"lint-staged": {
"**/*.{js,jsx,tsx,ts,less,md,json}": [

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-2022 Alipay.inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,6 +1,6 @@
{
"name": "@antv/x6-common",
"version": "2.0.1-beta.4",
"version": "2.0.6-beta.3",
"description": "Basic toolkit for x6.",
"main": "lib/index.js",
"module": "es/index.js",
@ -24,7 +24,7 @@
"clean": "run-p clean:build clean:coverage",
"lint": "eslint 'src/**/*.{js,ts}?(x)' --fix",
"build:esm": "tsc --module esnext --target es2015 --outDir ./es",
"build:cjs": "tsc --module commonjs --target es5 --outDir ./lib",
"build:cjs": "tsc --module commonjs --target es2015 --outDir ./lib",
"build:umd": "rollup -c",
"build:dev": "run-p build:cjs build:esm",
"build:watch": "yarn build:esm --w",
@ -36,21 +36,7 @@
"coveralls": "cat ./test/coverage/lcov.info | coveralls",
"pretest": "run-p clean:coverage",
"prepare": "run-s test build",
"precommit": "lint-staged",
"release": "release-it"
},
"release-it": {
"git": {
"commitMessage": "chore: release ${version}"
},
"github": {
"release": true
},
"hooks": {
"before:init": [
"yarn run build"
]
}
"precommit": "lint-staged"
},
"lint-staged": {
"src/**/*.ts": [
@ -136,5 +122,6 @@
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
}
},
"gitHead": "576fa342fa65a6867ead29f6801a30dcb31bcdb5"
}

View File

@ -0,0 +1,3 @@
import * as CssLoader from './loader'
export { CssLoader }

View File

@ -0,0 +1,44 @@
import { Platform } from '../platform'
interface CssModule {
name: string
styleElement: HTMLStyleElement | null
}
const cssModules: CssModule[] = []
export function ensure(name: string, content: string) {
const cssModule = cssModules.find((m) => m.name === name)
if (cssModule) {
return
}
if (!Platform.isApplyingHMR()) {
const styleElement = document.createElement('style')
styleElement.setAttribute('type', 'text/css')
styleElement.textContent = content
const head = document.querySelector('head') as HTMLHeadElement
if (head) {
head.insertBefore(styleElement, head.firstChild)
}
cssModules.push({
name,
styleElement,
})
}
}
export function clean(name: string) {
const index = cssModules.findIndex((m) => m.name === name)
if (index > -1) {
let styleElement = cssModules[index].styleElement
if (styleElement && styleElement.parentNode) {
styleElement.parentNode.removeChild(styleElement)
}
styleElement = null
cssModules.splice(index, 1)
}
}

View File

@ -201,6 +201,21 @@ export function before(
}
}
export function after(
elem: Element,
elems: Element | DocumentFragment | (Element | DocumentFragment)[],
) {
const parent = elem.parentNode
if (parent) {
const arr = Array.isArray(elems) ? elems : [elems]
arr.forEach((child) => {
if (child != null) {
parent.insertBefore(child, elem.nextSibling)
}
})
}
}
export function appendTo(elem: Element, target: Element) {
if (target != null) {
target.appendChild(elem)

View File

@ -3,6 +3,7 @@ import { EventHook } from './hook'
import { Store } from './store'
import { EventObject } from './object'
import { EventHandler } from './types'
import './special'
export namespace Core {
let triggered: string | undefined

View File

@ -1,4 +1,5 @@
import { EventHook } from './hook'
import { Util } from './util'
// Prevent triggered image.load events from bubbling to window.load
export namespace Special {
@ -19,3 +20,38 @@ export namespace Special {
},
})
}
// For mouseenter/leave call the handler if related is outside the target.
// NB: No relatedTarget if the mouse left/entered the browser window
export namespace Special {
EventHook.register('mouseenter', {
delegateType: 'mouseover',
bindType: 'mouseover',
handle(target, event) {
let ret
const related = event.relatedTarget
const handleObj = event.handleObj
if (!related || (related !== target && !Util.contains(target, related))) {
event.type = handleObj.originType
ret = handleObj.handler.call(target, event)
event.type = 'mouseover'
}
return ret
},
})
EventHook.register('mouseleave', {
delegateType: 'mouseout',
bindType: 'mouseout',
handle(target, event) {
let ret
const related = event.relatedTarget
const handleObj = event.handleObj
if (!related || (related !== target && !Util.contains(target, related))) {
event.type = handleObj.originType
ret = handleObj.handler.call(target, event)
event.type = 'mouseout'
}
return ret
},
})
}

View File

@ -173,3 +173,23 @@ export namespace Util {
return obj != null && obj === obj.window
}
}
export namespace Util {
export function contains(a: any, b: any) {
const adown = a.nodeType === 9 ? a.documentElement : a
const bup = b && b.parentNode
return (
a === bup ||
!!(
bup &&
bup.nodeType === 1 &&
// Support: IE 9 - 11+
// IE doesn't have `contains` on SVG.
(adown.contains
? adown.contains(bup)
: a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16)
)
)
}
}

View File

@ -7,6 +7,7 @@ export * from './prefix'
export * from './selection'
export * from './css'
export * from './data'
export * from './prop'
// svg
// ---

View File

@ -0,0 +1,45 @@
const propMap: Record<string, string> = {
/* GENERAL */
class: 'className',
contenteditable: 'contentEditable',
/* LABEL */
for: 'htmlFor',
/* INPUT */
readonly: 'readOnly',
maxlength: 'maxLength',
tabindex: 'tabIndex',
/* TABLE */
colspan: 'colSpan',
rowspan: 'rowSpan',
/* IMAGE */
usemap: 'useMap',
}
export function prop(elem: Element, props: string): any
export function prop(elem: Element, props: string, value: any): void
export function prop(elem: Element, props: Record<string, any>): void
export function prop(
elem: Element,
props: string | Record<string, any>,
value?: any,
) {
if (!props) {
return
}
if (typeof props === 'string') {
props = propMap[props] || props // eslint-disable-line
if (arguments.length < 3) {
return (elem as any)[props]
}
;(elem as any)[props] = value
return
}
// eslint-disable-next-line
for (const key in props) {
prop(elem, key, props[key])
}
}

View File

@ -21,4 +21,5 @@ export * from './dictionary'
export * from './registry'
export * from './modifier'
export * from './animation'
export * from './css-loader'
export * from './types'

View File

@ -1,3 +1,5 @@
import { Dom } from '../dom'
export type ModifierKey = 'alt' | 'ctrl' | 'meta' | 'shift'
// eslint-disable-next-line
@ -51,7 +53,7 @@ export namespace ModifierKey {
}
export function isMatch(
e: JQuery.TriggeredEvent | WheelEvent,
e: Dom.EventObject | WheelEvent,
modifiers?: string | ModifierKey[] | null,
strict?: boolean,
) {

21
packages/x6-core/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-2022 Alipay.inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,6 +1,7 @@
{
"private": true,
"name": "@antv/x6-core",
"version": "2.0.1-beta.3",
"version": "2.0.3-beta.0",
"description": "A lightweight graphic render library.",
"main": "lib/index.js",
"module": "es/index.js",
@ -24,7 +25,7 @@
"clean": "run-p clean:build clean:coverage",
"lint": "eslint 'src/**/*.{js,ts}?(x)' --fix",
"build:esm": "tsc --module esnext --target es2015 --outDir ./es",
"build:cjs": "tsc --module commonjs --target es5 --outDir ./lib",
"build:cjs": "tsc --module commonjs --target es2015 --outDir ./lib",
"build:umd": "rollup -c",
"build:dev": "run-p build:cjs build:esm",
"build:watch": "yarn build:esm --w",
@ -50,8 +51,8 @@
"@antv/x6-package-json/rollup.json"
],
"dependencies": {
"@antv/x6-common": "2.0.1-beta.3",
"@antv/x6-geometry": "2.0.1-beta.3"
"@antv/x6-common": "^2.0.6-beta.0",
"@antv/x6-geometry": "^2.0.6-beta.0"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^20.0.0",
@ -123,5 +124,6 @@
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
}
},
"gitHead": "576fa342fa65a6867ead29f6801a30dcb31bcdb5"
}

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-2022 Alipay.inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,5 +1,5 @@
{
"version": "2.0.1-beta.3",
"version": "2.0.6-beta.2",
"name": "@antv/x6-geometry",
"description": "Geometry operations for x6.",
"main": "lib/index.js",
@ -24,7 +24,7 @@
"clean": "run-p clean:build clean:coverage",
"lint": "eslint 'src/**/*.{js,ts}?(x)' --fix",
"build:esm": "tsc --module esnext --target es2015 --outDir ./es",
"build:cjs": "tsc --module commonjs --target es5 --outDir ./lib",
"build:cjs": "tsc --module commonjs --target es2015 --outDir ./lib",
"build:umd": "rollup -c",
"build:watch": "yarn build:esm --w",
"build:watch:esm": "yarn build:esm --w",
@ -36,27 +36,13 @@
"coveralls": "cat ./test/coverage/lcov.info | coveralls",
"pretest": "run-p clean:coverage",
"prepare": "run-s test build",
"precommit": "lint-staged",
"release": "release-it"
"precommit": "lint-staged"
},
"lint-staged": {
"src/**/*.ts": [
"eslint --fix"
]
},
"release-it": {
"git": {
"commitMessage": "chore: release ${version}"
},
"github": {
"release": true
},
"hooks": {
"before:init": [
"yarn run build"
]
}
},
"inherits": [
"@antv/x6-package-json/cli.json",
"@antv/x6-package-json/eslint.json",
@ -118,5 +104,6 @@
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
}
},
"gitHead": "576fa342fa65a6867ead29f6801a30dcb31bcdb5"
}

21
packages/x6-next/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-2022 Alipay.inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,9 +0,0 @@
import { version } from '../src'
describe('version', () => {
it('should match the `version` field of package.json', () => {
// eslint-disable-next-line
const expected = require('../package.json').version
expect(version).toBe(expected)
})
})

View File

@ -1,6 +1,6 @@
{
"name": "@antv/x6-next",
"version": "2.0.1-beta.3",
"version": "2.0.6-beta.6",
"description": "JavaScript diagramming library that uses SVG and HTML for rendering.",
"main": "lib/index.js",
"module": "es/index.js",
@ -32,7 +32,7 @@
"lint:style": "stylelint 'src/**/*.less' --syntax less --fix",
"lint": "run-s lint:ts lint:style",
"build:esm": "tsc --module esnext --target es2015 --outDir ./es",
"build:cjs": "tsc --module commonjs --target es5 --outDir ./lib",
"build:cjs": "tsc --module commonjs --target es2015 --outDir ./lib",
"build:umd": "rollup -c",
"build:less": "node ./scripts/style",
"build:readme": "node ./scripts/readme.js",
@ -41,14 +41,13 @@
"build:watch": "yarn build:esm --w",
"build:watch:esm": "yarn build:esm --w",
"build:watch:cjs": "yarn build:cjs --w",
"build": "run-p build:readme build:version build:dev build:umd",
"build": "run-p build:readme build:dev build:umd",
"prebuild": "run-s lint clean",
"test": "karma start",
"coveralls": "cat ./test/coverage/lcov.info | coveralls",
"pretest": "run-p clean:coverage",
"prepare": "run-s build:version test build",
"precommit": "lint-staged",
"release": "release-it"
"prepare": "run-s test build",
"precommit": "lint-staged"
},
"lint-staged": {
"src/**/*.less": [
@ -58,19 +57,6 @@
"eslint --fix"
]
},
"release-it": {
"git": {
"commitMessage": "chore: release ${version}"
},
"github": {
"release": true
},
"hooks": {
"before:init": [
"yarn run build"
]
}
},
"inherits": [
"@antv/x6-package-json/cli.json",
"@antv/x6-package-json/less.json",
@ -79,8 +65,8 @@
"@antv/x6-package-json/rollup.json"
],
"dependencies": {
"@antv/x6-common": "2.0.1-beta.3",
"@antv/x6-geometry": "2.0.1-beta.3"
"@antv/x6-common": "^2.0.6-beta.3",
"@antv/x6-geometry": "^2.0.6-beta.2"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^20.0.0",
@ -158,5 +144,6 @@
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
}
},
"gitHead": "576fa342fa65a6867ead29f6801a30dcb31bcdb5"
}

View File

@ -1,4 +1,4 @@
import { Platform } from '@antv/x6-common'
import { CssLoader } from '@antv/x6-common'
import { Config } from '../config'
import { content } from '../style/raw'
import { Base } from './base'
@ -6,43 +6,12 @@ import { Base } from './base'
export class CSSManager extends Base {
protected init() {
if (Config.autoInsertCSS) {
CSSManager.ensure()
CssLoader.ensure('core', content)
}
}
@CSSManager.dispose()
dispose() {
CSSManager.clean()
}
}
export namespace CSSManager {
let styleElement: HTMLStyleElement | null
let counter = 0
export function ensure() {
counter += 1
if (counter > 1) return
if (!Platform.isApplyingHMR()) {
styleElement = document.createElement('style')
styleElement.setAttribute('type', 'text/css')
styleElement.textContent = content
const head = document.querySelector('head') as HTMLHeadElement
if (head) {
head.insertBefore(styleElement, head.firstChild)
}
}
}
export function clean() {
counter -= 1
if (counter > 0) return
if (styleElement && styleElement.parentNode) {
styleElement.parentNode.removeChild(styleElement)
}
styleElement = null
CssLoader.clean('core')
}
}

View File

@ -20,6 +20,8 @@ import { HighlightManager as Highlight } from './highlight'
import { CellView } from '../view'
export class Graph extends Basecoat<EventArgs> {
private installedPlugins: Set<Graph.Plugin> = new Set()
public readonly options: GraphOptions.Definition
public readonly css: Css
public readonly model: Model
@ -663,6 +665,32 @@ export class Graph extends Basecoat<EventArgs> {
return this
}
/**
* Position the center of graph to the center of the viewport.
*/
center() {
return this.centerPoint()
}
/**
* Position the point (x,y) on the graph (in local coordinates) to the
* center of the viewport. If only one of the coordinates is specified,
* only center along the specified dimension and keep the other coordinate
* unchanged.
*/
centerPoint(x: number, y: null | number): this
centerPoint(x: null | number, y: number): this
centerPoint(): this
centerPoint(x?: number | null, y?: number | null) {
this.transform.centerPoint(x as number, y as number)
return this
}
centerContent(options?: Transform.PositionContentOptions) {
this.transform.centerContent(options)
return this
}
centerCell(cell: Cell) {
this.transform.centerCell(cell)
return this
@ -677,6 +705,24 @@ export class Graph extends Basecoat<EventArgs> {
return this
}
positionRect(rect: Rectangle.RectangleLike, direction: Transform.Direction) {
this.transform.positionRect(rect, direction)
return this
}
positionCell(cell: Cell, direction: Transform.Direction) {
this.transform.positionCell(cell, direction)
return this
}
positionContent(
pos: Transform.Direction,
options?: Transform.PositionContentOptions,
) {
this.transform.positionContent(pos, options)
return this
}
// #endregion
// #region coord
@ -1035,6 +1081,30 @@ export class Graph extends Basecoat<EventArgs> {
// #endregion
// #region plugin
use(plugin: Graph.Plugin, ...options: any[]) {
if (!this.installedPlugins.has(plugin)) {
this.installedPlugins.add(plugin)
plugin.init(this, ...options)
}
return this
}
getPlugin(pluginName: string) {
let result: Graph.Plugin | undefined
this.installedPlugins.forEach((plugin) => {
if (plugin.name === pluginName) {
result = plugin
}
})
return result
}
// #endregion
// #region dispose
@Basecoat.dispose()
@ -1053,6 +1123,10 @@ export class Graph extends Basecoat<EventArgs> {
this.panning.dispose()
this.view.dispose()
this.renderer.dispose()
this.installedPlugins.forEach((plugin) => {
plugin.dispose()
})
}
// #endregion
@ -1169,3 +1243,11 @@ export namespace Graph {
export const unregisterConnectionPoint =
Registry.ConnectionPoint.registry.unregister
}
export namespace Graph {
export type Plugin = {
name: string
init: (graph: Graph, ...options: any[]) => any
dispose: () => void
}
}

View File

@ -1 +1,5 @@
export * from './graph'
export * from './view'
export * from './events'
export * from './transform'
export * from './background'

View File

@ -8,7 +8,7 @@ import { PanningManager } from './panning'
import { MouseWheel } from './mousewheel'
import { Edge as StandardEdge } from '../shape'
import { Model, Cell, Node, Edge } from '../model'
import { View, CellView, NodeView, EdgeView } from '../view'
import { CellView, NodeView, EdgeView, Markup } from '../view'
import {
Router,
Connector,
@ -17,6 +17,7 @@ import {
ConnectionPoint,
} from '../registry'
import { HighlightManager } from './highlight'
import { PortManager } from '../model/port'
export namespace Options {
interface Common {
@ -45,15 +46,11 @@ export namespace Options {
preventDefaultBlankAction: boolean
interacting: CellView.Interacting
virtualRender?: boolean
virtual?: boolean
guard: (e: Dom.EventObject, view?: CellView | null) => boolean
onToolItemCreated: (args: {
name: string
cell: Cell
view: CellView
tool: View
}) => void
onPortRendered?: (args: OnPortRenderedArgs) => void
}
export interface ManualBooleans {
@ -367,6 +364,19 @@ export namespace Options {
}
}
export namespace Options {
export interface OnPortRenderedArgs {
node: Node
port: PortManager.Port
container: Element
selectors?: Markup.Selectors
labelContainer?: Element
labelSelectors?: Markup.Selectors | null
contentContainer: Element
contentSelectors?: Markup.Selectors
}
}
export namespace Options {
export const defaults: Partial<Definition> = {
x: 0,

View File

@ -594,4 +594,10 @@ export namespace TransformManager {
| 'bottom'
| 'bottom-left'
| 'left'
export interface CenterOptions {
padding?: NumberExt.SideOptions
}
export type PositionContentOptions = GetContentAreaOptions & CenterOptions
}

View File

@ -21,17 +21,17 @@ export class VirtualRenderManager extends Base {
}
enableVirtualRender() {
this.options.virtualRender = true
this.options.virtual = true
this.resetRenderArea()
}
disableVirtualRender() {
this.options.virtualRender = false
this.options.virtual = false
this.graph.renderer.setRenderArea(undefined)
}
resetRenderArea() {
if (this.options.virtualRender) {
if (this.options.virtual) {
const renderArea = this.graph.getGraphArea()
this.graph.renderer.setRenderArea(renderArea)
}

View File

@ -4,7 +4,7 @@ import * as Registry from './registry'
export * from './model'
export * from './view'
export * from './graph'
export * from './version'
export * from './config'
export * from './util'
export { Shape, Registry }

View File

@ -57,8 +57,6 @@ export class Animation {
}
if (progress === 1) {
// TODO: remove in the next major version
this.cell.notify('transition:end', this.getArgs<T>(key))
this.cell.notify('transition:complete', this.getArgs<T>(key))
options.complete && options.complete(this.getArgs<T>(key))
@ -73,8 +71,6 @@ export class Animation {
this.cache[key] = { startValue, targetValue, options: localOptions }
this.ids[key] = Dom.requestAnimationFrame(iterate)
// TODO: remove in the next major version
this.cell.notify('transition:begin', this.getArgs<T>(key))
this.cell.notify('transition:start', this.getArgs<T>(key))
options.start && options.start(this.getArgs<T>(key))
}, options.delay)

View File

@ -924,6 +924,7 @@ export namespace Edge {
export interface SetCellTerminalArgs extends SetTerminalCommonArgs {
port?: string
priority?: boolean
anchor?: string | NodeAnchor.NativeItem | NodeAnchor.ManaualItem
}

View File

@ -55,13 +55,6 @@ export class Segments extends ToolsView.ToolItem<EdgeView, Segments.Options> {
this.options.processHandle(handle)
}
this.graph.options.onToolItemCreated({
name: 'segments',
cell: this.cell,
view: this.cellView,
tool: handle,
})
this.updateHandle(handle, vertex, nextVertex)
this.container.appendChild(handle.container)
this.startHandleListening(handle)

View File

@ -69,13 +69,6 @@ export class Vertices extends ToolsView.ToolItem<EdgeView, Vertices.Options> {
processHandle(handle)
}
this.graph.options.onToolItemCreated({
name: 'vertices',
cell: this.cell,
view: this.cellView,
tool: handle,
})
handle.updatePosition(vertex.x, vertex.y)
this.stamp(handle.container)
this.container.appendChild(handle.container)

View File

@ -14,7 +14,6 @@ let isFlushPending = false
let scheduleId = 0
const queue: Job[] = []
const frameInterval = 33
let time = 0
let getCurrentTime: () => number
const hasPerformanceNow =
@ -80,10 +79,6 @@ export function clearJobs() {
cancelScheduleJob()
}
export function resetTimer() {
time = performance.now()
}
function flushJobs() {
isFlushPending = false
isFlushing = true
@ -106,8 +101,6 @@ function flushJobs() {
if (queue.length) {
queueFlush()
} else {
console.log('spend', performance.now() - time) // eslint-disable-line
}
}

View File

@ -2,13 +2,7 @@ import { KeyValue, Dom } from '@antv/x6-common'
import { Rectangle } from '@antv/x6-geometry'
import { Model, Cell } from '../model'
import { View, CellView, NodeView, EdgeView } from '../view'
import {
queueJob,
queueFlush,
clearJobs,
JOB_PRIORITY,
resetTimer,
} from './queueJob'
import { queueJob, queueFlush, clearJobs, JOB_PRIORITY } from './queueJob'
import { FlagManager } from '../view/flag'
import { Graph } from '../graph'
@ -181,7 +175,6 @@ export class Scheduler {
)
})
resetTimer()
queueFlush()
}
@ -222,7 +215,6 @@ export class Scheduler {
}
}
resetTimer()
queueFlush()
}

View File

@ -0,0 +1,11 @@
import { createShape } from './util'
export const Circle = createShape('circle', {
attrs: {
body: {
refCx: '50%',
refCy: '50%',
refR: '50%',
},
},
})

View File

@ -0,0 +1,12 @@
import { createShape } from './util'
export const Ellipse = createShape('ellipse', {
attrs: {
body: {
refCx: '50%',
refCy: '50%',
refRx: '50%',
refRy: '50%',
},
},
})

View File

@ -0,0 +1,17 @@
import { getImageUrlHook, createShape } from './util'
export const Image = createShape(
'image',
{
attrs: {
image: {
refWidth: '100%',
refHeight: '100%',
},
},
propHooks: getImageUrlHook(),
},
{
selector: 'image',
},
)

View File

@ -1,2 +1,11 @@
export * from './rect'
export * from './edge'
export * from './rect'
export * from './ellipse'
export * from './polygon'
export * from './polyline'
export * from './path'
export * from './text-block'
export * from './image'
export * from './edge'
export * from './circle'

View File

@ -0,0 +1,42 @@
import { ObjectExt } from '@antv/x6-common'
import { Base } from './base'
export const Path = Base.define({
shape: 'path',
markup: [
{
tagName: 'rect',
selector: 'bg',
},
{
tagName: 'path',
selector: 'body',
},
{
tagName: 'text',
selector: 'label',
},
],
attrs: {
bg: {
refWidth: '100%',
refHeight: '100%',
fill: 'none',
stroke: 'none',
pointerEvents: 'all',
},
body: {
fill: 'none',
stroke: '#000',
strokeWidth: 2,
},
},
propHooks(metadata) {
const { path, ...others } = metadata
if (path) {
ObjectExt.setByPath(others, 'attrs/body/refD', path)
}
return others
},
})

View File

@ -0,0 +1,69 @@
import { Point } from '@antv/x6-geometry'
import { ObjectExt } from '@antv/x6-common'
import { Base } from './base'
import { Node } from '../model/node'
export class Poly extends Base {
get points() {
return this.getPoints()
}
set points(pts: string | undefined | null) {
this.setPoints(pts)
}
getPoints() {
return this.getAttrByPath<string>('body/refPoints')
}
setPoints(
points?: string | Point.PointLike[] | Point.PointData[] | null,
options?: Node.SetOptions,
) {
if (points == null) {
this.removePoints()
} else {
this.setAttrByPath('body/refPoints', Poly.pointsToString(points), options)
}
return this
}
removePoints() {
this.removeAttrByPath('body/refPoints')
return this
}
}
export namespace Poly {
export function pointsToString(
points: Point.PointLike[] | Point.PointData[] | string,
) {
return typeof points === 'string'
? points
: (points as Point.PointLike[])
.map((p) => {
if (Array.isArray(p)) {
return p.join(',')
}
if (Point.isPointLike(p)) {
return `${p.x}, ${p.y}`
}
return ''
})
.join(' ')
}
Poly.config({
propHooks(metadata) {
const { points, ...others } = metadata
if (points) {
const data = pointsToString(points)
if (data) {
ObjectExt.setByPath(others, 'attrs/body/refPoints', data)
}
}
return others
},
})
}

View File

@ -0,0 +1,9 @@
import { Base } from './base'
import { Poly } from './poly'
import { createShape } from './util'
export const Polygon = createShape(
'polygon',
{},
{ parent: Poly as typeof Base },
)

View File

@ -0,0 +1,9 @@
import { Base } from './base'
import { Poly } from './poly'
import { createShape } from './util'
export const Polyline = createShape(
'polyline',
{},
{ parent: Poly as typeof Base },
)

View File

@ -0,0 +1,101 @@
import { Platform, Dom, FunctionExt, ObjectExt } from '@antv/x6-common'
import { Attr } from '../registry'
import { Base } from './base'
export const TextBlock = Base.define({
shape: 'text-block',
markup: [
{
tagName: 'rect',
selector: 'body',
},
Platform.SUPPORT_FOREIGNOBJECT
? {
tagName: 'foreignObject',
selector: 'foreignObject',
children: [
{
tagName: 'div',
ns: Dom.ns.xhtml,
selector: 'label',
style: {
width: '100%',
height: '100%',
position: 'static',
backgroundColor: 'transparent',
textAlign: 'center',
margin: 0,
padding: '0px 5px',
boxSizing: 'border-box',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
},
],
}
: {
tagName: 'text',
selector: 'label',
attrs: {
textAnchor: 'middle',
},
},
],
attrs: {
body: {
...Base.bodyAttr,
refWidth: '100%',
refHeight: '100%',
},
foreignObject: {
refWidth: '100%',
refHeight: '100%',
},
label: {
style: {
fontSize: 14,
},
},
},
propHooks(metadata) {
const { text, ...others } = metadata
if (text) {
ObjectExt.setByPath(others, 'attrs/label/text', text)
}
return others
},
attrHooks: {
text: {
set(text: string, { cell, view, refBBox, elem, attrs }) {
if (elem instanceof HTMLElement) {
elem.textContent = text
} else {
// No foreign object
const style = (attrs.style as Attr.SimpleAttrs) || {}
const wrapValue = { text, width: -5, height: '100%' }
const wrapAttrs = {
textVerticalAnchor: 'middle',
...style,
}
const textWrap = Attr.presets.textWrap as Attr.SetDefinition
FunctionExt.call(textWrap.set, this, wrapValue, {
cell,
view,
elem,
refBBox,
attrs: wrapAttrs,
})
return { fill: (style.color as string) || null }
}
},
position(text, { refBBox, elem }) {
if (elem instanceof SVGElement) {
return refBBox.getCenter()
}
},
},
},
})

View File

@ -1,5 +1,5 @@
import { ObjectExt } from '@antv/x6-common'
import { Node } from '../model'
import { Cell, Node } from '../model'
import { Markup } from '../view'
import { Base } from './base'
@ -16,6 +16,45 @@ export function getMarkup(tagName: string, selector = 'body'): Markup {
]
}
export function getImageUrlHook(attrName = 'xlink:href') {
const hook: Cell.PropHook = (metadata) => {
const { imageUrl, imageWidth, imageHeight, ...others } = metadata
if (imageUrl != null || imageWidth != null || imageHeight != null) {
const apply = () => {
if (others.attrs) {
const image = others.attrs.image
if (imageUrl != null) {
image[attrName] = imageUrl
}
if (imageWidth != null) {
image.width = imageWidth
}
if (imageHeight != null) {
image.height = imageHeight
}
others.attrs.image = image
}
}
if (others.attrs) {
if (others.attrs.image == null) {
others.attrs.image = {}
}
apply()
} else {
others.attrs = {
image: {},
}
apply()
}
}
return others
}
return hook
}
export function createShape(
shape: string,
config: Node.Config,

View File

@ -376,7 +376,9 @@ export namespace Util {
let tagName = node.tagName
if (typeof tagName !== 'string') return null
tagName = tagName.toUpperCase()
if (tagName === 'G') {
if (Dom.hasClass(node, 'x6-port')) {
node = node.nextElementSibling as Element
} else if (tagName === 'G') {
node = node.firstElementChild as Element
} else if (tagName === 'TITLE') {
node = node.nextElementSibling as Element

View File

@ -1,7 +0,0 @@
/* eslint-disable */
/**
* Auto generated version file, do not modify it!
*/
const version = '2.0.1-beta.3'
export { version }

View File

@ -533,70 +533,6 @@ export class CellView<
return magnet
}
// #region animate todo
// animate(elem: SVGElement | string, options: Dom.AnimationOptions) {
// const target = typeof elem === 'string' ? this.findOne(elem) : elem
// if (target == null) {
// throw new Error('Invalid animation element.')
// }
// const parent = target.parentNode
// const revert = () => {
// if (!parent) {
// Dom.remove(target)
// }
// }
// const vTarget = Vector.create(target as SVGElement)
// if (!parent) {
// vTarget.appendTo(this.graph.view.stage)
// }
// const onComplete = options.complete
// options.complete = (e: Event) => {
// revert()
// if (onComplete) {
// onComplete(e)
// }
// }
// return vTarget.animate(options)
// }
// animateTransform(elem: SVGElement | string, options: Dom.AnimationOptions) {
// const target = typeof elem === 'string' ? this.findOne(elem) : elem
// if (target == null) {
// throw new Error('Invalid animation element.')
// }
// const parent = target.parentNode
// const revert = () => {
// if (!parent) {
// Dom.remove(target)
// }
// }
// const vTarget = Vector.create(target as SVGElement)
// if (!parent) {
// vTarget.appendTo(this.graph.view.stage)
// }
// const onComplete = options.complete
// options.complete = (e: Event) => {
// revert()
// if (onComplete) {
// onComplete(e)
// }
// }
// return vTarget.animateTransform(options)
// }
// #endregion
// #region tools
protected tools: ToolsView | null

View File

@ -538,9 +538,23 @@ export class EdgeView<
}
protected findAnchors(vertices: Point.PointLike[]) {
const edge = this.cell
const source = edge.source as Edge.TerminalCellData
const target = edge.target as Edge.TerminalCellData
const firstVertex = vertices[0]
const lastVertex = vertices[vertices.length - 1]
if (target.priority && !source.priority) {
// Reversed order
return this.findAnchorsOrdered(
'target',
lastVertex,
'source',
firstVertex,
)
}
// Usual order
return this.findAnchorsOrdered('source', firstVertex, 'target', lastVertex)
}

View File

@ -333,17 +333,18 @@ export class NodeView<
portContentSelectors,
}
// todo
// this.graph.hook.onPortRendered({
// port,
// node: this.cell,
// container: portElement,
// selectors: portSelectors,
// labelContainer: portLabelElement,
// labelSelectors: portLabelSelectors,
// contentContainer: portContentElement,
// contentSelectors: portContentSelectors,
// })
if (this.graph.options.onPortRendered) {
this.graph.options.onPortRendered({
port,
node: this.cell,
container: portElement,
selectors: portSelectors,
labelContainer: portLabelElement,
labelSelectors: portLabelSelectors,
contentContainer: portContentElement,
contentSelectors: portContentSelectors,
})
}
return portElement
}

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-2022 Alipay.inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,5 @@
# `x6-plugin-keyboard`
> TODO: description
## Usage

View File

@ -0,0 +1 @@
export * from './src'

View File

@ -0,0 +1,113 @@
{
"name": "@antv/x6-plugin-keyboard",
"version": "2.0.6-beta.5",
"description": "keyboard plugin for X6.",
"main": "lib/index.js",
"module": "es/index.js",
"unpkg": "dist/x6-plugin-keyboard.js",
"jsdelivr": "dist/x6-plugin-keyboard.js",
"types": "lib/index.d.ts",
"files": [
"dist",
"es",
"lib"
],
"keywords": [
"plugin",
"keyboard",
"x6",
"antv"
],
"scripts": {
"clean:build": "rimraf dist es lib",
"clean:coverage": "rimraf ./test/coverage",
"clean": "run-p clean:build clean:coverage",
"lint": "eslint 'src/**/*.{js,ts}?(x)' --fix",
"build:esm": "tsc --module esnext --target es2015 --outDir ./es",
"build:cjs": "tsc --module commonjs --target es2015 --outDir ./lib",
"build:umd": "rollup -c",
"build:dev": "run-p build:cjs build:esm",
"build:watch": "yarn build:esm --w",
"build:watch:esm": "yarn build:esm --w",
"build:watch:cjs": "yarn build:cjs --w",
"build": "run-p build:dev build:umd",
"prebuild": "run-s lint clean",
"coveralls": "cat ./test/coverage/lcov.info | coveralls",
"pretest": "run-p clean:coverage",
"prepare": "run-s test build",
"precommit": "lint-staged"
},
"lint-staged": {
"src/**/*.ts": [
"eslint --fix"
]
},
"inherits": [
"@antv/x6-package-json/cli.json",
"@antv/x6-package-json/eslint.json",
"@antv/x6-package-json/rollup.json"
],
"dependencies": {
"mousetrap": "^1.6.5"
},
"peerDependencies": {
"@antv/x6-next": "2.0.6-beta.0"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^20.0.0",
"@rollup/plugin-node-resolve": "^13.0.4",
"@rollup/plugin-replace": "^3.0.0",
"@rollup/plugin-typescript": "^8.2.5",
"@types/mousetrap": "^1.6.5",
"@typescript-eslint/eslint-plugin": "^4.31.0",
"@typescript-eslint/parser": "^4.31.0",
"coveralls": "^3.1.1",
"eslint": "^7.32.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.24.2",
"eslint-plugin-jest": "^24.4.0",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-react": "^7.25.1",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-unicorn": "^36.0.0",
"less": "^4.1.1",
"lint-staged": "^11.1.2",
"npm-run-all": "^4.1.5",
"postcss": "^8.3.6",
"prettier": "^2.4.0",
"pretty-quick": "^3.1.1",
"rimraf": "^3.0.2",
"rollup": "^2.56.3",
"rollup-plugin-auto-external": "^2.0.0",
"rollup-plugin-filesize": "^9.1.1",
"rollup-plugin-postcss": "^4.0.1",
"rollup-plugin-progress": "^1.1.2",
"rollup-plugin-terser": "^7.0.2",
"ts-node": "^10.2.1",
"tslib": "^2.3.1",
"typescript": "^4.4.3"
},
"author": {
"name": "bubkoo",
"email": "bubkoo.wy@gmail.com"
},
"contributors": [],
"license": "MIT",
"homepage": "https://github.com/antvis/x6",
"bugs": {
"url": "https://github.com/antvis/x6/issues"
},
"repository": {
"type": "git",
"url": "ssh://git@github.com/antvis/x6.git",
"directory": "packages/x6-common"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
}
}

View File

@ -0,0 +1,17 @@
import config from '../../configs/rollup-config'
export default config({
output: [
{
name: 'X6PluginKeyboard',
format: 'umd',
file: 'dist/x6-plugin-keyboard.js',
sourcemap: true,
globals: {
'@antv/x6-next': 'X6',
'@antv/x6-common': 'X6Common',
},
},
],
external: ['@antv/x6-next', '@antv/x6-common'],
})

View File

@ -0,0 +1,69 @@
import { Disposable } from '@antv/x6-common'
import { Graph } from '@antv/x6-next'
import { KeyboardImpl } from './keyboard'
export class Keyboard extends Disposable {
public name = 'keyboard'
private keyboard: KeyboardImpl
constructor(public readonly options: KeyboardImpl.Options) {
super()
}
public init(graph: Graph) {
this.keyboard = new KeyboardImpl({
...this.options,
graph,
})
}
isKeyboardEnabled() {
return !this.keyboard.disabled
}
enableKeyboard() {
this.keyboard.enable()
return this
}
disableKeyboard() {
this.keyboard.disable()
return this
}
toggleKeyboard(enabled?: boolean) {
if (enabled != null) {
if (enabled !== this.isKeyboardEnabled()) {
if (enabled) {
this.enableKeyboard()
} else {
this.disableKeyboard()
}
}
} else if (this.isKeyboardEnabled()) {
this.disableKeyboard()
} else {
this.enableKeyboard()
}
return this
}
bindKey(
keys: string | string[],
callback: KeyboardImpl.Handler,
action?: KeyboardImpl.Action,
) {
this.keyboard.on(keys, callback, action)
return this
}
unbindKey(keys: string | string[], action?: KeyboardImpl.Action) {
this.keyboard.off(keys, action)
return this
}
@Disposable.dispose()
dispose() {
this.keyboard.dispose()
}
}

View File

@ -0,0 +1,189 @@
import Mousetrap from 'mousetrap'
import { Dom, FunctionExt, Disposable, IDisablable } from '@antv/x6-common'
import { Graph, EventArgs } from '@antv/x6-next'
export class KeyboardImpl extends Disposable implements IDisablable {
public readonly target: HTMLElement | Document
private readonly container: HTMLElement
private readonly mousetrap: Mousetrap.MousetrapInstance
private get graph() {
return this.options.graph
}
constructor(
private readonly options: KeyboardImpl.Options & { graph: Graph },
) {
super()
const scroller = this.graph.getPlugin('scroller') as any
this.container = scroller ? scroller.container : this.graph.container
if (options.global) {
this.target = document
} else {
this.target = this.container
if (!this.disabled) {
// ensure the container focusable
this.target.setAttribute('tabindex', '-1')
}
// change to mouseup eventprevent page stalling caused by focus
this.graph.on('cell:mouseup', this.focus, this)
this.graph.on('blank:mouseup', this.focus, this)
}
this.mousetrap = KeyboardImpl.createMousetrap(this)
}
get disabled() {
return this.options.enabled !== true
}
enable() {
if (this.disabled) {
this.options.enabled = true
if (this.target instanceof HTMLElement) {
this.target.setAttribute('tabindex', '-1')
}
}
}
disable() {
if (!this.disabled) {
this.options.enabled = false
if (this.target instanceof HTMLElement) {
this.target.removeAttribute('tabindex')
}
}
}
on(
keys: string | string[],
callback: KeyboardImpl.Handler,
action?: KeyboardImpl.Action,
) {
this.mousetrap.bind(this.getKeys(keys), callback, action)
}
off(keys: string | string[], action?: KeyboardImpl.Action) {
this.mousetrap.unbind(this.getKeys(keys), action)
}
private focus(e: EventArgs['node:mouseup']) {
const isInputEvent = this.isInputEvent(e.e)
if (isInputEvent) {
return
}
const target = this.target as HTMLElement
target.focus({
preventScroll: true,
})
}
private getKeys(keys: string | string[]) {
return (Array.isArray(keys) ? keys : [keys]).map((key) =>
this.formatkey(key),
)
}
protected formatkey(key: string) {
const formated = key
.toLowerCase()
.replace(/\s/g, '')
.replace('delete', 'del')
.replace('cmd', 'command')
const formatFn = this.options.format
if (formatFn) {
return FunctionExt.call(formatFn, this.graph, formated)
}
return formated
}
protected isGraphEvent(e: KeyboardEvent) {
const target = (e.srcElement || e.target) as Element
const currentTarget = e.currentTarget as Element
if (target) {
if (
target === this.target ||
currentTarget === this.target ||
target === document.body
) {
return true
}
return Dom.contains(this.container, target)
}
return false
}
isInputEvent(e: KeyboardEvent | JQuery.MouseUpEvent) {
const target = e.target as Element
const tagName = target?.tagName?.toLowerCase()
return ['input', 'textarea'].includes(tagName)
}
isEnabledForEvent(e: KeyboardEvent) {
const allowed = !this.disabled && this.isGraphEvent(e)
const isInputEvent = this.isInputEvent(e)
if (allowed) {
const code = e.keyCode || e.which
if (isInputEvent && (code === 8 || code === 46)) {
return false
}
if (this.options.guard) {
return FunctionExt.call(this.options.guard, this.graph, e)
}
}
return allowed
}
@Disposable.dispose()
dispose() {
this.mousetrap.reset()
}
}
export namespace KeyboardImpl {
export type Action = 'keypress' | 'keydown' | 'keyup'
export type Handler = (e: KeyboardEvent) => void
export interface Options {
enabled?: boolean
/**
* Specifies if keyboard event should bind on docuemnt or on container.
*
* Default is `false` that will bind keyboard event on the container.
*/
global?: boolean
format?: (this: Graph, key: string) => string
guard?: (this: Graph, e: KeyboardEvent) => boolean
}
}
export namespace KeyboardImpl {
export function createMousetrap(keyboard: KeyboardImpl) {
const mousetrap = new Mousetrap(keyboard.target as Element)
const stopCallback = mousetrap.stopCallback
mousetrap.stopCallback = (
e: KeyboardEvent,
elem: HTMLElement,
combo: string,
) => {
if (keyboard.isEnabledForEvent(e)) {
if (stopCallback) {
return stopCallback.call(mousetrap, e, elem, combo)
}
return false
}
return true
}
return mousetrap
}
}

View File

@ -0,0 +1,3 @@
{
"extends": "../../tsconfig.json"
}

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-2022 Alipay.inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,5 @@
# `x6-plugin-scroller`
> TODO: description
## Usage

View File

@ -0,0 +1 @@
export * from './src'

View File

@ -0,0 +1,110 @@
{
"name": "@antv/x6-plugin-scroller",
"version": "2.0.6-beta.6",
"description": "scroller plugin for X6.",
"main": "lib/index.js",
"module": "es/index.js",
"unpkg": "dist/x6-plugin-scroller.js",
"jsdelivr": "dist/x6-plugin-scroller.js",
"types": "lib/index.d.ts",
"files": [
"dist",
"es",
"lib"
],
"keywords": [
"plugin",
"scroller",
"x6",
"antv"
],
"scripts": {
"clean:build": "rimraf dist es lib",
"clean:coverage": "rimraf ./test/coverage",
"clean": "run-p clean:build clean:coverage",
"lint": "eslint 'src/**/*.{js,ts}?(x)' --fix",
"build:less": "node ./scripts/style",
"build:esm": "tsc --module esnext --target es2015 --outDir ./es",
"build:cjs": "tsc --module commonjs --target es2015 --outDir ./lib",
"build:umd": "rollup -c",
"build:dev": "run-p build:less build:cjs build:esm",
"build:watch": "yarn build:esm --w",
"build:watch:esm": "yarn build:esm --w",
"build:watch:cjs": "yarn build:cjs --w",
"build": "run-p build:dev build:umd",
"prebuild": "run-s lint clean",
"coveralls": "cat ./test/coverage/lcov.info | coveralls",
"pretest": "run-p clean:coverage",
"prepare": "run-s test build",
"precommit": "lint-staged"
},
"lint-staged": {
"src/**/*.ts": [
"eslint --fix"
]
},
"inherits": [
"@antv/x6-package-json/cli.json",
"@antv/x6-package-json/eslint.json",
"@antv/x6-package-json/rollup.json"
],
"peerDependencies": {
"@antv/x6-next": ">=2.0.6-beta.0"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^20.0.0",
"@rollup/plugin-node-resolve": "^13.0.4",
"@rollup/plugin-replace": "^3.0.0",
"@rollup/plugin-typescript": "^8.2.5",
"@typescript-eslint/eslint-plugin": "^4.31.0",
"@typescript-eslint/parser": "^4.31.0",
"coveralls": "^3.1.1",
"eslint": "^7.32.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.24.2",
"eslint-plugin-jest": "^24.4.0",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-react": "^7.25.1",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-unicorn": "^36.0.0",
"less": "^4.1.1",
"lint-staged": "^11.1.2",
"npm-run-all": "^4.1.5",
"postcss": "^8.3.6",
"prettier": "^2.4.0",
"pretty-quick": "^3.1.1",
"rimraf": "^3.0.2",
"rollup": "^2.56.3",
"rollup-plugin-auto-external": "^2.0.0",
"rollup-plugin-filesize": "^9.1.1",
"rollup-plugin-postcss": "^4.0.1",
"rollup-plugin-progress": "^1.1.2",
"rollup-plugin-terser": "^7.0.2",
"ts-node": "^10.2.1",
"tslib": "^2.3.1",
"typescript": "^4.4.3"
},
"author": {
"name": "bubkoo",
"email": "bubkoo.wy@gmail.com"
},
"contributors": [],
"license": "MIT",
"homepage": "https://github.com/antvis/x6",
"bugs": {
"url": "https://github.com/antvis/x6/issues"
},
"repository": {
"type": "git",
"url": "ssh://git@github.com/antvis/x6.git",
"directory": "packages/x6-common"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
}
}

View File

@ -0,0 +1,18 @@
import config from '../../configs/rollup-config'
export default config({
output: [
{
name: 'X6PluginScroller',
format: 'umd',
file: 'dist/x6-plugin-scroller.js',
sourcemap: true,
globals: {
'@antv/x6-next': 'X6',
'@antv/x6-common': 'X6Common',
'@antv/x6-geometry': 'X6Geometry',
},
},
],
external: ['@antv/x6-next', '@antv/x6-common', '@antv/x6-geometry'],
})

View File

@ -0,0 +1,85 @@
#!/usr/bin/env node
const fs = require('fs')
const os = require('os')
const path = require('path')
const fse = require('fs-extra')
const cp = require('child_process')
const cwd = process.cwd()
const es = path.join(cwd, 'es')
const lib = path.join(cwd, 'lib')
const src = path.join(cwd, 'src')
const dist = path.join(cwd, 'dist')
function compile(source, target) {
let cmd = './node_modules/.bin/lessc'
if (os.type() === 'Windows_NT') {
cmd = path.join(cwd, './node_modules/.bin/lessc.cmd')
}
cp.execFileSync(cmd, [source, target])
}
compile(path.join(src, 'index.less'), path.join(es, 'index.css'))
compile(path.join(src, 'index.less'), path.join(lib, 'index.css'))
compile(path.join(src, 'index.less'), path.join(dist, 'scroller.css'))
function toCSSPath(source) {
const dir = path.dirname(source)
const file = `${path.basename(source, '.less')}.css`
return path.join(dir, file)
}
// Copy less files
function processLessInDir(dir) {
const stat = fs.statSync(dir)
if (stat) {
if (stat.isDirectory()) {
fs.readdir(dir, (err, files) => {
files.forEach((file) => {
processLessInDir(path.join(dir, file))
})
})
} else {
const ext = path.extname(dir)
if (ext === '.less' || ext === '.css') {
fse.copySync(dir, path.join(es, path.relative(src, dir)))
fse.copySync(dir, path.join(lib, path.relative(src, dir)))
}
if (ext === '.less') {
let source = path.join(es, path.relative(src, dir))
let target = toCSSPath(source)
compile(dir, target)
source = path.join(lib, path.relative(src, dir))
target = toCSSPath(source)
compile(dir, target)
}
}
}
}
function makeStyleModule() {
const source = path.join(dist, 'scroller.css')
const target = path.join(src, 'style/raw.ts')
const content = fs.readFileSync(source, { encoding: 'utf8' })
const prev = fs.existsSync(target)
? fs.readFileSync(target, { encoding: 'utf8' })
: null
const curr = `/* eslint-disable */
/**
* Auto generated file, do not modify it!
*/
export const content = \`${content}\`
`
if (prev !== curr) {
fs.writeFileSync(target, curr)
}
}
processLessInDir(src)
makeStyleModule()

View File

@ -0,0 +1,76 @@
@scroller-prefix-cls: ~'x6-graph-scroller';
.@{scroller-prefix-cls} {
position: relative;
box-sizing: border-box;
overflow: scroll;
outline: none;
&-content {
position: relative;
}
&-background {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.x6-graph {
position: absolute;
display: inline-block;
margin: 0;
box-shadow: none;
> svg {
display: block;
}
}
&&-paged {
.x6-graph {
box-shadow: 0 0 4px 0 #eee;
}
}
&&-pannable[data-panning='false'] {
cursor: grab;
cursor: -moz-grab;
cursor: -webkit-grab;
}
&&-pannable[data-panning='true'] {
cursor: grabbing;
cursor: -moz-grabbing;
cursor: -webkit-grabbing;
user-select: none;
}
}
.x6-graph-pagebreak {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
&-vertical {
position: absolute;
top: 0;
bottom: 0;
box-sizing: border-box;
width: 1px;
border-left: 1px dashed #bdbdbd;
}
&-horizontal {
position: absolute;
right: 0;
left: 0;
box-sizing: border-box;
height: 1px;
border-top: 1px dashed #bdbdbd;
}
}

View File

@ -0,0 +1,371 @@
import { Dom, ModifierKey, Disposable, CssLoader } from '@antv/x6-common'
import {
Graph,
Config,
TransformManager,
Cell,
BackgroundManager,
} from '@antv/x6-next'
import { Rectangle, Point } from '@antv/x6-geometry'
import { ScrollerImpl } from './scroller'
import { content } from './style/raw'
export class Scroller extends Disposable {
public name = 'scroller'
private graph: Graph
private scrollerImpl: ScrollerImpl
private get pannable() {
if (this.options) {
if (typeof this.options.pannable === 'object') {
return this.options.pannable.enabled
}
return !!this.options.pannable
}
return false
}
constructor(public readonly options: Scroller.Options) {
super()
}
public init(graph: Graph) {
this.graph = graph
CssLoader.ensure('scroller', content)
this.scrollerImpl = new ScrollerImpl({
...this.options,
graph,
})
this.startListening()
this.updateClassName()
this.scrollerImpl.center()
}
private startListening() {
let eventTypes = []
const pannable = this.options.pannable
if (typeof pannable === 'object') {
eventTypes = pannable.eventTypes || []
} else {
eventTypes = ['leftMouseDown']
}
if (eventTypes.includes('leftMouseDown')) {
this.graph.on('blank:mousedown', this.preparePanning, this)
this.graph.on('node:unhandled:mousedown', this.preparePanning, this)
this.graph.on('edge:unhandled:mousedown', this.preparePanning, this)
}
if (eventTypes.includes('rightMouseDown')) {
this.onRightMouseDown = this.onRightMouseDown.bind(this)
Dom.Event.on(
this.scrollerImpl.container,
'mousedown',
this.onRightMouseDown,
)
}
}
private stopListening() {
let eventTypes = []
const pannable = this.options.pannable
if (typeof pannable === 'object') {
eventTypes = pannable.eventTypes || []
} else {
eventTypes = ['leftMouseDown']
}
if (eventTypes.includes('leftMouseDown')) {
this.graph.off('blank:mousedown', this.preparePanning, this)
this.graph.off('node:unhandled:mousedown', this.preparePanning, this)
this.graph.off('edge:unhandled:mousedown', this.preparePanning, this)
}
if (eventTypes.includes('rightMouseDown')) {
Dom.Event.off(
this.scrollerImpl.container,
'mousedown',
this.onRightMouseDown,
)
}
}
private onRightMouseDown(e: Dom.MouseDownEvent) {
if (e.button === 2 && this.allowPanning(e, true)) {
this.updateClassName(true)
this.scrollerImpl.startPanning(e)
this.scrollerImpl.once('pan:stop', () => this.updateClassName(false))
}
}
private preparePanning({ e }: { e: Dom.MouseDownEvent }) {
const allowPanning = this.allowPanning(e, true)
const selection = this.graph.getPlugin('selection') as any
const allowRubberband =
this.allowPanning(e) && selection && selection.allowRubberband(e, true)
if (allowPanning || !allowRubberband) {
this.updateClassName(true)
this.scrollerImpl.startPanning(e)
this.scrollerImpl.once('pan:stop', () => this.updateClassName(false))
}
}
private allowPanning(e: Dom.MouseDownEvent, strict?: boolean) {
return (
this.pannable && ModifierKey.isMatch(e, this.options.modifiers, strict)
)
}
private updateClassName(isPanning?: boolean) {
const container = this.scrollerImpl.container!
const pannable = Config.prefix('graph-scroller-pannable')
if (this.pannable) {
Dom.addClass(container, pannable)
container.dataset.panning = (!!isPanning).toString() // Use dataset to control scroller panning style to avoid reflow caused by changing classList
} else {
Dom.removeClass(container, pannable)
}
}
resize(width?: number, height?: number) {
this.scrollerImpl.resize(width, height)
}
zoom(): number
zoom(factor: number, options?: TransformManager.ZoomOptions): this
zoom(factor?: number, options?: TransformManager.ZoomOptions) {
if (typeof factor === 'undefined') {
return this.scrollerImpl.zoom()
}
this.scrollerImpl.zoom(factor, options)
return this
}
zoomTo(
factor: number,
options: Omit<TransformManager.ZoomOptions, 'absolute'> = {},
) {
this.scrollerImpl.zoom(factor, { ...options, absolute: true })
return this
}
zoomToRect(
rect: Rectangle.RectangleLike,
options: TransformManager.ScaleContentToFitOptions &
TransformManager.ScaleContentToFitOptions = {},
) {
this.scrollerImpl.zoomToRect(rect, options)
return this
}
zoomToFit(
options: TransformManager.GetContentAreaOptions &
TransformManager.ScaleContentToFitOptions = {},
) {
this.scrollerImpl.zoomToFit(options)
return this
}
center(optons?: ScrollerImpl.CenterOptions) {
return this.centerPoint(optons)
}
centerPoint(
x: number,
y: null | number,
options?: ScrollerImpl.CenterOptions,
): this
centerPoint(
x: null | number,
y: number,
options?: ScrollerImpl.CenterOptions,
): this
centerPoint(optons?: ScrollerImpl.CenterOptions): this
centerPoint(
x?: number | null | ScrollerImpl.CenterOptions,
y?: number | null,
options?: ScrollerImpl.CenterOptions,
) {
this.scrollerImpl.centerPoint(x as number, y as number, options)
return this
}
centerContent(options?: ScrollerImpl.PositionContentOptions) {
this.scrollerImpl.centerContent(options)
return this
}
centerCell(cell: Cell, options?: ScrollerImpl.CenterOptions) {
this.scrollerImpl.centerCell(cell, options)
return this
}
positionPoint(
point: Point.PointLike,
x: number | string,
y: number | string,
options: ScrollerImpl.CenterOptions = {},
) {
this.scrollerImpl.positionPoint(point, x, y, options)
return this
}
positionRect(
rect: Rectangle.RectangleLike,
direction: ScrollerImpl.Direction,
options?: ScrollerImpl.CenterOptions,
) {
this.scrollerImpl.positionRect(rect, direction, options)
return this
}
positionCell(
cell: Cell,
direction: ScrollerImpl.Direction,
options?: ScrollerImpl.CenterOptions,
) {
this.scrollerImpl.positionCell(cell, direction, options)
return this
}
positionContent(
pos: ScrollerImpl.Direction,
options?: ScrollerImpl.PositionContentOptions,
) {
this.scrollerImpl.positionContent(pos, options)
return this
}
drawBackground(options?: BackgroundManager.Options, onGraph?: boolean) {
if (this.graph.options.background == null || !onGraph) {
this.scrollerImpl.backgroundManager.draw(options)
}
return this
}
clearBackground(onGraph?: boolean) {
if (this.graph.options.background == null || !onGraph) {
this.scrollerImpl.backgroundManager.clear()
}
return this
}
isPannable() {
return this.pannable
}
enablePanning() {
if (!this.pannable) {
this.options.pannable = true
this.updateClassName()
}
}
disablePanning() {
if (this.pannable) {
this.options.pannable = false
this.updateClassName()
}
}
togglePanning(pannable?: boolean) {
if (pannable == null) {
if (this.isPannable()) {
this.disablePanning()
} else {
this.enablePanning()
}
} else if (pannable !== this.isPannable()) {
if (pannable) {
this.enablePanning()
} else {
this.disablePanning()
}
}
return this
}
lockScroller() {
this.scrollerImpl.lock()
}
unlockScroller() {
this.scrollerImpl.unlock()
}
updateScroller() {
this.scrollerImpl.update()
}
getScrollbarPosition() {
return this.scrollerImpl.scrollbarPosition()
}
setScrollbarPosition(left?: number, top?: number) {
this.scrollerImpl.scrollbarPosition(left, top)
return this
}
scrollToPoint(x: number | null | undefined, y: number | null | undefined) {
this.scrollerImpl.scrollToPoint(x, y)
return this
}
scrollToContent() {
this.scrollerImpl.scrollToContent()
return this
}
scrollToCell(cell: Cell) {
this.scrollerImpl.scrollToCell(cell)
return this
}
transitionToPoint(
p: Point.PointLike,
options?: ScrollerImpl.TransitionOptions,
): this
transitionToPoint(
x: number,
y: number,
options?: ScrollerImpl.TransitionOptions,
): this
transitionToPoint(
x: number | Point.PointLike,
y?: number | ScrollerImpl.TransitionOptions,
options?: ScrollerImpl.TransitionOptions,
) {
this.scrollerImpl.transitionToPoint(x as number, y as number, options)
return this
}
transitionToRect(
rect: Rectangle.RectangleLike,
options: ScrollerImpl.TransitionToRectOptions = {},
) {
this.scrollerImpl.transitionToRect(rect, options)
return this
}
enableAutoResize() {
this.scrollerImpl.enableAutoResize()
}
disableAutoResize() {
this.scrollerImpl.disableAutoResize()
}
@Disposable.dispose()
dispose() {
this.scrollerImpl.dispose()
this.stopListening()
CssLoader.clean('scroller')
}
}
export namespace Scroller {
type EventType = 'leftMouseDown' | 'rightMouseDown'
export interface Options extends ScrollerImpl.CommonOptions {
pannable?: boolean | { enabled: boolean; eventTypes: EventType[] }
modifiers?: string | ModifierKey[] | null // alt, ctrl, shift, meta
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,69 @@
/* eslint-disable */
/**
* Auto generated file, do not modify it!
*/
export const content = `.x6-graph-scroller {
position: relative;
box-sizing: border-box;
overflow: scroll;
outline: none;
}
.x6-graph-scroller-content {
position: relative;
}
.x6-graph-scroller-background {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.x6-graph-scroller .x6-graph {
position: absolute;
display: inline-block;
margin: 0;
box-shadow: none;
}
.x6-graph-scroller .x6-graph > svg {
display: block;
}
.x6-graph-scroller.x6-graph-scroller-paged .x6-graph {
box-shadow: 0 0 4px 0 #eee;
}
.x6-graph-scroller.x6-graph-scroller-pannable[data-panning='false'] {
cursor: grab;
cursor: -moz-grab;
cursor: -webkit-grab;
}
.x6-graph-scroller.x6-graph-scroller-pannable[data-panning='true'] {
cursor: grabbing;
cursor: -moz-grabbing;
cursor: -webkit-grabbing;
user-select: none;
}
.x6-graph-pagebreak {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.x6-graph-pagebreak-vertical {
position: absolute;
top: 0;
bottom: 0;
box-sizing: border-box;
width: 1px;
border-left: 1px dashed #bdbdbd;
}
.x6-graph-pagebreak-horizontal {
position: absolute;
right: 0;
left: 0;
box-sizing: border-box;
height: 1px;
border-top: 1px dashed #bdbdbd;
}
`

View File

@ -0,0 +1,3 @@
{
"extends": "../../tsconfig.json"
}

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-2022 Alipay.inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,6 +1,6 @@
{
"name": "@antv/x6-react-components",
"version": "1.1.16",
"version": "2.0.6-beta.2",
"description": "React components for building x6 editors",
"main": "lib/index.js",
"module": "es/index.js",
@ -22,7 +22,7 @@
"lint:ts": "eslint 'src/**/*.{js,ts}?(x)' --fix",
"lint:style": "stylelint 'src/**/*.less' --syntax less --fix",
"build:esm": "tsc --module esnext --target es2015 --outDir ./es",
"build:cjs": "tsc --module commonjs --target es5 --outDir ./lib",
"build:cjs": "tsc --module commonjs --target es2015 --outDir ./lib",
"build:umd": "rollup -c",
"build:watch": "yarn build:esm --w",
"build:watch:esm": "yarn build:esm --w",
@ -143,5 +143,6 @@
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
}
},
"gitHead": "576fa342fa65a6867ead29f6801a30dcb31bcdb5"
}

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-2022 Alipay.inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,6 +1,6 @@
{
"name": "@antv/x6-react-shape",
"version": "2.0.1-beta.3",
"version": "2.0.6-beta.2",
"description": "X6 shape for rendering react components.",
"main": "lib/index.js",
"module": "es/index.js",
@ -24,7 +24,7 @@
"lint": "eslint 'src/**/*.{js,ts}?(x)' --fix",
"watch": "watch 'yarn build' ./src",
"build:esm": "tsc --module esnext --target es2015 --outDir ./es",
"build:cjs": "tsc --module commonjs --target es5 --outDir ./lib",
"build:cjs": "tsc --module commonjs --target es2015 --outDir ./lib",
"build:umd": "rollup -c",
"build:watch": "yarn build:esm --w",
"build:watch:esm": "yarn build:esm --w",
@ -45,8 +45,8 @@
"@antv/x6-package-json/rollup.json"
],
"peerDependencies": {
"@antv/x6-next": "2.0.1-beta.3",
"@antv/x6-common": "2.0.1-beta.3",
"@antv/x6-common": ">=2.0.6-beta.0",
"@antv/x6-next": ">=2.0.6-beta.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
@ -109,5 +109,6 @@
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
}
},
"gitHead": "576fa342fa65a6867ead29f6801a30dcb31bcdb5"
}

View File

@ -4,6 +4,7 @@ import { Graph, Node } from '@antv/x6-next'
export type ReactShapeConfig = Node.Properties & {
shape: string
effect?: (keyof Node.Properties)[]
inherit?: string
}
export const shapeMaps: Record<
@ -18,7 +19,7 @@ export function register(
componentOrFC: React.ComponentType,
config: ReactShapeConfig,
) {
const { shape, effect, ...others } = config
const { shape, effect, inherit, ...others } = config
if (!shape) {
throw new Error('should specify shape in config')
}
@ -30,7 +31,7 @@ export function register(
Graph.registerNode(
shape,
{
inherit: 'react-shape',
inherit: inherit || 'react-shape',
...others,
},
true,

View File

@ -1,4 +1,5 @@
{
"private": true,
"version": "1.3.0",
"name": "@antv/x6-vector",
"description": "Lightweight library for manipulating and animating SVG.",

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-2022 Alipay.inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Some files were not shown because too many files have changed in this diff Show More