事件驱动
x6 是通过事件进行驱动的,事件分为以下几类:
-
鼠标键盘事件
-
模型变更事件
-
自定义事件
鼠标键盘事件
鼠标键盘事件的入口在 GraphView。
GraphView.events 定义了事件和绑定的方法。它在 GraphView 初始化时作为 delegateEvents 的参数传递给了 View,然后将其绑定在了 graph.container 上。
模型变更事件
Cell 级的事件
首先观察 Cell 的 setup 方法以及 notify 方法,如下:
export class Cell<
Properties extends Cell.Properties = Cell.Properties,
> extends Basecoat<Cell.EventArgs> {
protected setup() {
this.store.on('change:*', (metadata) => {
const { key, current, previous, options } = metadata
this.notify('change:*', {
key,
options,
current,
previous,
cell: this,
})
this.notify(`change:${key}` as keyof Cell.EventArgs, {
options,
current,
previous,
cell: this,
})
const type = key as Edge.TerminalType
if (type === 'source' || type === 'target') {
this.notify(`change:terminal`, {
type,
current,
previous,
options,
cell: this,
})
}
})
this.store.on('changed', ({ options }) =>
this.notify('changed', { options, cell: this }),
)
}
notify<Key extends keyof Cell.EventArgs>(
name: Key,
args: Cell.EventArgs[Key],
): this
notify(name: Exclude<string, keyof Cell.EventArgs>, args: any): this
notify<Key extends keyof Cell.EventArgs>(
name: Key,
args: Cell.EventArgs[Key],
) {
this.trigger(name, args)
const model = this.model
if (model) {
model.notify(`cell:${name}`, args)
if (this.isNode()) {
model.notify(`node:${name}`, { ...args, node: this })
} else if (this.isEdge()) {
model.notify(`edge:${name}`, { ...args, edge: this })
}
}
return this
}
}
store 中存储的是 Cell 的 props, attrs 等元数据,当元数据发生变化时,首先会触发 change:* 事件,所有更改完成后会触发 changed 事件。Cell 监听了 store 的 change:* 和 changed 事件,并将其重新分发为 Cell 上的事件和 Model 上的事件。
Cell 有两种类型:Node 和 Edge。
Node 只在 updatePortData 增加了 ports:added 和 ports:removed 事件
Edge 在 onLabelsChanged 增加了 labels:added 和 labels:removed 事件,在 onVertexsChanged 增加了 vertexs:added 和 vertexs:removed 事件
Model 级的事件
现在,我们观察 Model 的 setup 方法及 notify 方法,如下:
export class Model extends Basecoat<Model.EventArgs> {
protected setup() {
const collection = this.collection
collection.on('sorted', () => this.notify('sorted', null))
collection.on('updated', (args) => this.notify('updated', args))
collection.on('cell:change:zIndex', () => this.sortOnChangeZ())
collection.on('added', ({ cell }) => {
this.onCellAdded(cell)
})
collection.on('removed', (args) => {
const cell = args.cell
this.onCellRemoved(cell, args.options)
// Should trigger remove-event manually after cell was removed.
this.notify('cell:removed', args)
if (cell.isNode()) {
this.notify('node:removed', { ...args, node: cell })
} else if (cell.isEdge()) {
this.notify('edge:removed', { ...args, edge: cell })
}
})
collection.on('reseted', (args) => {
this.onReset(args.current)
this.notify('reseted', args)
})
collection.on('edge:change:source', ({ edge }) =>
this.onEdgeTerminalChanged(edge, 'source'),
)
collection.on('edge:change:target', ({ edge }) => {
this.onEdgeTerminalChanged(edge, 'target')
})
}
notify<Key extends keyof Model.EventArgs>(
name: Key,
args: Model.EventArgs[Key],
): this
notify(name: Exclude<string, keyof Model.EventArgs>, args: any): this
notify<Key extends keyof Model.EventArgs>(
name: Key,
args: Model.EventArgs[Key],
) {
this.trigger(name, args)
const graph = this.graph
if (graph) {
if (name === 'sorted' || name === 'reseted' || name === 'updated') {
graph.trigger(`model:${name}`, args)
} else {
graph.trigger(name, args)
}
}
return this
}
}
Model 上的 collection 是存储 Cell 的容器,当 collection 中的 Cell 发生变更时(例如,增加,删除,排序等),它会触发事件,Model 监听这些事件并进行重新分发为 Model 上的事件和 Graph 上的事件。
注意,Cell 也调用了 Model 的 notify,因此,所有 Cell 上的事件加上前缀后同样也会在 Model 和 Graph 上出现。
监听事件
-
Graph上的功能组件通过监听事件来进行变更BackgroundManager监听scale和translate事件GridManager监听scale和translate事件HighlightManager监听cell:highlight和cell:unhighlight事件PanningManager监听blank:mousedown,node:unhandled:mousedown和edge:unhandled:mousedown事件VirtualRenderManager监听translate,scale和resize事件
-
注册表中的内置工具通过监听事件来进行变更,例如
jumpover,stroke,CellEditor,Segments和Vertices -
CellView视图中,观察CellView的setup,如下:export class CellView<Entity extends Cell = Cell, Options extends CellView.Options = CellView.Options> extends View<CellView.EventArgs> { protected setup() { this.cell.on('changed', ({ options }) => this.onAttrsChange(options)) } protected onAttrsChange(options: Cell.MutateOptions) { let flag = this.flag.getChangedFlag() if (options.updated || !flag) { return } if (options.dirty && this.hasAction(flag, 'update')) { flag |= this.getFlag('render') // eslint-disable-line no-bitwise } // tool changes should be sync render if (options.toolId) { options.async = false } if (this.graph != null) { this.graph.renderer.requestViewUpdate(this, flag, options) } } }当监听到
Cell上的changed事件时,请求视图更新。 -
渲染器的调度器中监听了
reseted,cell:added,cell:removed,cell:change:zIndex,cell:change:visible事件,然后请求视图更新。