antv-x6 源码解析(2) - markup

上一章:antv-x6 源码解析(1) - x6 核心包解析

markup

markup 是视图的一部分,指定了渲染时使用的 SVG/HTML 片段。

定义

Markup 的定义如下:

ts 复制代码
export type Markup = string | Markup.JSONMarkup | Markup.JSONMarkup[]

export namespace Markup {
  export interface JSONMarkup {
    /**
     * The namespace URI of the element. It defaults to SVG namespace
     * `"http://www.w3.org/2000/svg"`.
     */
    ns?: string | null
    /**
     * The type of element to be created.
     */
    tagName: string
    /**
     * A unique selector for targeting the element within the `attr`
     * cell attribute.
     */
    selector?: string | null
    /**
     * A selector for targeting multiple elements within the `attr`
     * cell attribute. The group selector name must not be the same
     * as an existing selector name.
     */
    groupSelector?: string | string[] | null
    attrs?: Attr.SimpleAttrs
    style?: Record<string, string | number>
    className?: string | string[]
    children?: JSONMarkup[]
    textContent?: string
  }
}

markup 在渲染前会被 parseJSONMarkup 解析为 ParseResult, 它的定义如下:

ts 复制代码
export interface ParseResult {
    fragment: DocumentFragment
    selectors: Selectors
    groups: KeyValue<Element[]>
}

GraphView

我们从 GraphViewmarkup 入手来理解这两者间的关系,我们首先看它的定义:

ts 复制代码
  const prefixCls = `${Config.prefixCls}-graph` // `Config.prefixCls` 默认值是 `x6`,即它的值是 `x6-graph`

  export const markup: Markup.JSONMarkup[] = [
    {
      ns: Dom.ns.xhtml, // `http://www.w3.org/1999/xhtml`
      tagName: 'div',
      selector: 'background',
      className: `${prefixCls}-background`,
    },
    {
      ns: Dom.ns.xhtml,
      tagName: 'div',
      selector: 'grid',
      className: `${prefixCls}-grid`,
    },
    {
      ns: Dom.ns.svg, // http://www.w3.org/2000/svg
      tagName: 'svg',
      selector: 'svg',
      className: `${prefixCls}-svg`,
      attrs: {
        width: '100%',
        height: '100%',
        'xmlns:xlink': Dom.ns.xlink, // http://www.w3.org/1999/xlink
      },
      children: [
        {
          tagName: 'defs',
          selector: 'defs',
        },
        {
          tagName: 'g',
          selector: 'viewport',
          className: `${prefixCls}-svg-viewport`,
          children: [
            {
              tagName: 'g',
              selector: 'primer',
              className: `${prefixCls}-svg-primer`,
            },
            {
              tagName: 'g',
              selector: 'stage',
              className: `${prefixCls}-svg-stage`,
            },
            {
              tagName: 'g',
              selector: 'decorator',
              className: `${prefixCls}-svg-decorator`,
            },
            {
              tagName: 'g',
              selector: 'overlay',
              className: `${prefixCls}-svg-overlay`,
            },
          ],
        },
      ],
    },
  ]

它的渲染结果如下:

对于其中的 selector 字段,它所在的元素会被加入映射表 selectors 中,其 key 就是 selector 的值。

我们现在重新看 GraphView 的实现,如下:

ts 复制代码
export class GraphView extends View {
  public readonly container: HTMLElement
  public readonly background: HTMLDivElement
  public readonly grid: HTMLDivElement
  public readonly svg: SVGSVGElement
  public readonly defs: SVGDefsElement
  public readonly viewport: SVGGElement
  public readonly primer: SVGGElement
  public readonly stage: SVGGElement
  public readonly decorator: SVGGElement
  public readonly overlay: SVGGElement

  constructor(protected readonly graph: Graph) {
    super()

    const { selectors, fragment } = Markup.parseJSONMarkup(GraphView.markup)
    this.background = selectors.background as HTMLDivElement
    this.grid = selectors.grid as HTMLDivElement
    this.svg = selectors.svg as SVGSVGElement
    this.defs = selectors.defs as SVGDefsElement
    this.viewport = selectors.viewport as SVGGElement
    this.primer = selectors.primer as SVGGElement
    this.stage = selectors.stage as SVGGElement
    this.decorator = selectors.decorator as SVGGElement
    this.overlay = selectors.overlay as SVGGElement
    this.container = this.options.container
    this.restore = GraphView.snapshoot(this.container)

    Dom.addClass(this.container, this.prefixClassName('graph'))
    Dom.append(this.container, fragment)

    this.delegateEvents()
  }
}

GraphView.markup 被解析后生成了 selectors,它存储的是元素的映射表,GraphView 将其一一取出,作为自身的属性,这使得我们可以通过属性来直接访问它的 Dom 元素。

NodeView

我们再来看 NodeViewmarkup 是如何渲染的,NodeViewmarkuprenderMarkup 中渲染,如下:

ts 复制代码
  protected renderMarkup() {
    const markup = this.cell.markup
    if (markup) {
      if (typeof markup === 'string') {
        throw new TypeError('Not support string markup.')
      }

      return this.renderJSONMarkup(markup)
    }

    throw new TypeError('Invalid node markup.')
  }

  protected renderJSONMarkup(markup: Markup.JSONMarkup | Markup.JSONMarkup[]) {
    const ret = this.parseJSONMarkup(markup, this.container)
    this.selectors = ret.selectors
    this.container.appendChild(ret.fragment)
  }

它从 cell 中获取 markup, 然后将其解析为 selectorsfragment,最后 fragment 被添加到 container

EdgeViewmarkup 的渲染与 NodeView 一致,此处不再赘述。

相关推荐
2301_818732061 小时前
用layui表单,前端页面的样式正常显示,但是表格内无数据显示(数据库连接和获取数据无问题)——已经解决
java·前端·javascript·前端框架·layui·intellij idea
Komorebi゛1 小时前
【uniapp】获取上传视频的md5,适用于APP和H5
前端·javascript·uni-app
林涧泣1 小时前
【Uniapp-Vue3】动态设置页面导航条的样式
前端·javascript·uni-app
杰九2 小时前
【全栈】SprintBoot+vue3迷你商城(10)
开发语言·前端·javascript·vue.js·spring boot
Hopebearer_2 小时前
入门 Canvas:Web 绘图的强大工具
前端·javascript·es6·canva可画
ILUUSION_S2 小时前
Vue平台开发三——项目管理页面
javascript·vue.js
_pengliang4 小时前
react native i18n插值:跨组件trans
javascript·react native·react.js
Catherinemin4 小时前
剑指Offer|LCR 045.找树左下角的值
javascript·算法
CodeClimb4 小时前
【华为OD-E卷 - VLAN资源池 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
徐_三岁5 小时前
TypeScript 中的 object 和Object的区别
前端·javascript·typescript