View

阅读时间约 6 分钟

配置

sorting

节点和边视图的排序方式。

原生 SVG 不支持 z-index 样式,所以我们在 x6 中通过代码的形式来支持节点和边的层级设置。创建节点和边时,可以通过 zIndex 选项来设置节点和边的层级;也可以拿到节点/边的实例后,通过 cell.setZIndex(z)cell.toFront()cell.toBack() 等方法来修改层级。

支持以下三种取值:

  • 'none' 时,不进行排序,节点和边的 zIndex 选项失效。
  • 'exact'zIndex 从低到高渲染,当 zIndex 相同时按照添加顺序渲染。
  • 'approx'zIndex 从低到高渲染,当 zIndex 相同时渲染顺序不确定,但渲染效率更高。

async

是否是异步渲染的画布。异步渲染不会阻塞 UI,对需要添加大量节点和边时的性能提升非常明显。但需要注意的是,一些同步操作可能会出现意外结果,比如获取某个节点的视图、获取节点/边的包围盒等,因为这些同步操作触发时异步渲染可能并没有完成,此时只能通过监听 render:done 事件来确保所有变更都已经生效,然后在事件回调中进行这些操作。

frozen

异步渲染的画布是否处于冻结状态,处于冻结状态的画布不会立即响应画布中节点和边的变更,直到调用 unfreeze(...) 方法来解除冻结并重新渲染画布。

const graph = new Graph({
  container: this.container,
  async: true,
  frozen: true,
})

// add many nodes and edges

graph.unfreeze()

checkView

(
  this: Graph,
  args: {
    view: CellView
    unmounted: boolean
  },
) => boolean

返回指定的视图是否应该渲染到 DOM 中。

magnetThreshold

鼠标移动多少次后才触发连线,或者设置为 'onleave' 时表示鼠标移出元素时才触发连线,默认为 0

moveThreshold

触发 'mousemove' 事件之前,允许鼠标移动的次数,默认为 0

clickThreshold

当鼠标移动次数超过指定的数字时,将不触发鼠标点击事件,默认为 0

preventDefaultContextMenu

是否禁用画布的默认右键,默认为 true

preventDefaultBlankAction

在画布空白位置响应鼠标事件时,是否禁用鼠标默认行为,默认为 true

guard

(e: JQuery.TriggeredEvent, view?: CellView | null) => boolean

是否应该忽略某个鼠标事件,返回 true 时忽略指定的鼠标事件,否则不忽略。

allowRubberband

(e: JQuery.MouseDownEvent) => boolean

返回是否响应框选事件,默认为 () => true

allowPanning

(e: JQuery.MouseDownEvent) => boolean

返回是否响应画布平移事件,默认为 () => true

getCellView

(this: Graph, cell: Cell) => null | undefined | typeof CellView | (new (...args: any[]) => CellView)

获取节点/边的视图类,默认为 () => null

createCellView

(this: Graph, cell: Cell) => CellView | null | undefined

创建节点/边的视图,默认自动根据节点和边的 view 选项创建对应的视图。

getHTMLComponent

(this: Graph, node: HTML) => HTMLElement | string | null | undefined

获取 HTML 节点的 HTML 元素,默认根据节点的 html 选项返回对应的 HTML 元素。更多细节请参考使用 HTML 节点教程

const graph = new Graph({
  getHTMLComponent(node) {
    const data = node.getData()
    if (data.flag) {
      return document.createElement('div')
    }
    return document.createElement('p')
  }
})

onPortRendered

(
  this: Graph, 
  args: {
    node: Node
    port: Port
    container: Element
    selectors?: Markup.Selectors
    labelContainer: Element
    labelSelectors?: Markup.Selectors
    contentContainer: Element
    contentSelectors?: Markup.Selectors
  },
) => void

当某个链接桩渲染完成时触发的回调。

args 参数

名称类型非空描述
nodeNode节点实例。
portPort链接桩选项。
containerElement链接桩的容器元素。
selectorsMarkup.Selectors链接桩 Markup 渲染后的选择器键值对。
labelContainerElement链接桩标签的容器元素。
labelSelectorsMarkup.Selectors链接桩标签 Markup 渲染后的选择器键值对。
contentContainerElement链接桩内容的容器元素。
contentSelectorsMarkup.Selectors链接桩内容 Markup 渲染后的选择器键值对。

使用

例如,我们可以渲染一个 React 类型的链接桩。

const graph = new Graph({
  container: this.container,
  onPortRendered(args) {
    const selectors = args.contentSelectors
    const container = selectors && selectors.foContent
    if (container) {
      ReactDOM.render(
        <Tooltip title="port">
          <div className="my-port" />
        </Tooltip>,
        container,
      )
    }
  },
})

onEdgeLabelRendered

(
  this: Graph, 
  args: {
    edge: Edge
    label: Edge.Label
    container: Element
    selectors: Markup.Selectors
  },
) => void

当边的文本标签渲染完成时触发的回调。

args 参数

名称类型非空描述
edgeEdge边实例。
labelEdge.Label文本标签选项。
containerElement文本标签容器。
selectorsMarkup.Selectors文本标签 Markup 渲染后的选择器键值对。

使用

例如,我们可以在标签上渲染任何想要的元素。

const graph = new Graph({
  container: this.container,
  onEdgeLabelRendered(args) {
    const { label, container, selectors } = args
    const data = label.data
    
    if (data) {
      // 在 Label 容器中渲染一个 foreignObject 来承载 HTML 元素和 React 组件
      const content = this.appendForeignObject(container)

      if (data === 1) {
        // 渲染一个 Div 元素
        const txt = document.createTextNode('text node')
        content.style.border = '1px solid #f0f0f0'
        content.style.borderRadius = '4px'
        content.appendChild(txt)
      } else if (data === 2) {
        // 渲染一个 HTML 按钮
        const btn = document.createElement('button')
        btn.appendChild(document.createTextNode('HTML Button'))
        btn.style.height = '30px'
        btn.style.lineHeight = '1'
        btn.addEventListener('click', () => {
          alert('clicked')
        })
        content.appendChild(btn)
      } else if (data === 3) {
        // 渲染一个 Atnd 的按钮
        ReactDOM.render(<Button size="small">Antd Button</Button>, content)
      }
    }
  },
})

我们也可以在定义 Label 的 Markup 时添加 <foreignObject> 元素来支持 HTML 和 React 的渲染能力。

const graph = new Graph({
  container: this.container,
  onEdgeLabelRendered: (args) => {
    const { selectors } = args
    const content = selectors.foContent as HTMLDivElement

    if (content) {
      content.style.display = 'flex'
      content.style.alignItems = 'center'
      content.style.justifyContent = 'center'
      ReactDOM.render(<Button size="small">Antd Button</Button>, content)
    }
  },
})

onToolItemCreated

(
  this: Graph, 
  args: {
    name: string
    cell: Cell
    view: CellView
    tool: View
  },
) => void

当工具项渲染完成时触发的回调。

args 参数

名称类型非空描述
cellCell节点/边实例。
viewCellView节点/边视图。
namestring工具项名称。
toolView工具视图。

使用

例如,我们为 vertices 工具设置间隔填充效果。

const graph = new Graph({
  container: this.container,
  grid: true,
  onToolItemCreated({ name, cell, tool }) {
    if (name === 'vertices' && cell === edge2) {
      const options = (tool as any).options
      if (options && options.index % 2 === 1) {
        tool.setAttrs({ fill: 'red' })
      }
    }
  },
})

方法

isAsync()

isAsync(): boolean

返回画布是否是异步渲染模式。异步渲染不会阻塞 UI,对需要添加大量节点和边时的性能提升非常明显,异步画布的使用细节请参考 async 选项。

isFrozen()

isFrozen(): boolean

返回异步画布是否处于冻结状态。处于冻结状态的画布不会立即响应画布中节点和边的变更,直到调用 unfreeze(...) 方法来解除冻结并重新渲染画布。

freeze(...)

freeze(options?: FreezeOptions): this

冻结异步画布,处于冻结状态的画布不会立即响应画布中节点和边的变更,直到调用 unfreeze(...) 方法来解除冻结并重新渲染画布。

参数

名称类型必选默认值描述
options.keystring-冻结状态的名称,当指定名称与当前冻结状态的名称不一致时,则不能用指定的名称冻结画布。

unfreeze(...)

unfreeze(options?: UnfreezeOptions): this

解除异步画布的冻结状态,并触发画布重新渲染,使画布中的变更生效。

参数

名称类型必选默认值描述
options.keystring-冻结状态的名称。
options.batchSizenumber1000每次异步进程中处理的节点和边视图的数量。
options.viewport(this: Graph, args: { view: CellView; unmounted: boolean }) => boolean-返回指定的视图是否应该渲染到 DOM 中。
options.before(this: Graph, graph: Graph) => void-开始异步更新前调用的函数。
options.after(this: Graph, graph: Graph) => void-完成异步更新时调用的函数。
options.progress(this: Graph, args: { done: boolean; processed: number; total: number }) => void-每次异步进程的进度回调函数。

findView(...)

findView(ref: Cell | JQuery | Element): CellView | null

根据节点/边或元素查找对应的视图。

findViewByCell(...)

findViewByCell(cellId: string | number): CellView | null
findViewByCell(cell: Cell | null): CellView | null

根据节点/边 ID 或实例查找对应的视图。

findViewByElem(...)

findViewByElem(elem: string | JQuery | Element | undefined | null): CellView | null

根据元素选择器或元素对象查找对应的视图。

findViewsFromPoint(...)

findViewsFromPoint(x: number, y: number): CellView[]
findViewsFromPoint(p: Point.PointLike): CellView[]

返回节点/边的包围盒包含指定点的视图。

findViewsInArea(...)

findViewsInArea(
  x: number,
  y: number,
  width: number,
  height: number,
  options?: FindViewsInAreaOptions,
): CellView[]
findViewsInArea(
  rect: Rectangle.RectangleLike,
  options?: FindViewsInAreaOptions,
): CellView[]

返回节点/边的包围盒与指定矩形相交的视图,当 options.stricttrue 时需要节点/边的包围盒完全包含指定的矩形。

findViews(...)

findViews(ref: Point.PointLike | Rectangle.RectangleLike): CellView[]

返回节点/边的包围盒包含指定的点或与指定的矩形相交的视图。

isViewMounted(...)

isViewMounted(view: CellView): boolean

返回指定的视图是否已经渲染到 DOM 中。

getMountedViews()

getMountedViews(): View[]

返回已经渲染到 DOM 的视图。

getUnmountedViews()

getUnmountedViews(): View[]

返回还没有渲染到 DOM 的视图。