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 一致,此处不再赘述。

相关推荐
清灵xmf44 分钟前
TypeScript 类型进阶指南
javascript·typescript·泛型·t·infer
小白学大数据1 小时前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
qq_390161771 小时前
防抖函数--应用场景及示例
前端·javascript
334554321 小时前
element动态表头合并表格
开发语言·javascript·ecmascript
John.liu_Test1 小时前
js下载excel示例demo
前端·javascript·excel
PleaSure乐事2 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶2 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
理想不理想v2 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript
栈老师不回家3 小时前
Vue 计算属性和监听器
前端·javascript·vue.js
前端啊龙3 小时前
用vue3封装丶高仿element-plus里面的日期联级选择器,日期选择器
前端·javascript·vue.js