阅读 6834

gojs 流程图框架-基础绘图(一)

gojs 是一款非常优秀的流程图绘制 js 框架, 该框架没有中文版 api, 并且网上可查阅的资料非常少, 本文旨在带领读者了解整个框架结构, 以及基本的绘制方法. 本文对技术细节不作过多描述, 并会附上 api 地址以供参考.

完成后的效果图:

源码地址: github.com/muzqi/sampl…

Step1 初始化画布

html

<div id="diagram" style="width: 1000px; height: 500px"></div>
复制代码

javascript

// [1]
const $ = go.GraphObject.make

// [2]
const diagram = $(go.Diagram, 'diagram', {
   // 令绘制的元素相对画布居中
  'initialContentAlignment': go.Spot.Center, 
  
  // 是否可撤销编辑
  'undoManager.isEnabled': true
})
复制代码

代码注释:

  1. gojs 有两种使用方法, 一种是使用原本的 go 对象, 第二种则是构造器方式创建, 即使用 go.GraphObject.make 对象创建,我们将该对象赋值给 $, 当然为了避免冲突也可以是其他符号
  2. $(go.Diagram, [selector], [options]), 该方法会执行 canvas 画布的初始化操作, 同时也提供了丰富的配置项使用, 详情参考Class Diagram

Step2 编写节点模板

所谓节点模板, 系指对节点建立一个统一的样式模板(集合); 如果用过 react 或 vue 等框架的童鞋自然很了解模板的意义, 在 gojs 中也一样, 我们建立好公用模板后, 只需要数据传参即可

gojs 一共有两种方式搭建节点模板 nodeTemplatenodeTemplateMap

这里只讲解 nodeTemplateMap, 它是一个节点模板集合, 里面可以自定义丰富的节点模板 它的使用方法类似 css 的类, 定义模板时定义类名, 调用时指定该类名即可

小试牛刀

// [1]
diagram.nodeTemplateMap.add('templateName',
  $(go.Node, go.Panel.Auto,
    $(go.TextBlock, 
    { text: 'test' },
    /*[2]*/new go.Binding('text', 'text'))
  )
)

// [3]
const nodeDataArray = [
  { category: 'templateName', key: 'check', text: '审核' }
]

// [4]
const linkDataArray = []

// [5]
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray)
复制代码

代码注释:

1.diagram.nodeTemplateMap.add([name], [node])

  • ES6 Set 方法非常类似, add 即添加一个模板的意思, 第一个参数是模板的名字, 第二个参数是具体模板的配置
  • 第二个参数必须传递一个 $(go.Node, [Panel], [Elements]) 构造器

2.new go.Binding([origin], [target], [filter = Func])

  • 这是 gojs 中的数据绑定, 使用该方法实现了模板与真实数据之间的传递
  • 该方法能在任意构造器中使用
    • origin: 该构造器中的属性名
    • target: 需要绑定到数据集中的属性名
    • filter: 过滤函数

3.定义一个节点数据集,

  • key 属性是必填的且具有唯一性, 它将运用到连接线数据集
  • category 属性即对应了节点模板中模板的名称, 若不填, 则会默认使用第一组模板
  • textnew go.Binding 绑定的数据

4.连接线数据集, 这里为空, 暂不讨论

5.diagram.model 决定了页面中呈现哪些元素, 我们创建一个普通连线实例 new go.GraphLinksModel 该构造函数接收两个参数, 即之前创建的 nodeDataArraylinkDataArray

实战演练

diagram.nodeTemplateMap.add('node1',
  $(go.Node, go.Panel.Position,
    // 规定该节点的宽高, 内容超出会被隐藏
    { width: 230, height: 240 },
    
    // 绑定节点的位置属性, 用来控制节点处于画布的哪个位置
    new go.Binding('position'),

    // 背景图片与图标
    $(/*[1]*/go.Panel, /*[2]*/go.Panel.Auto,
      { position: new go.Point(0, 72) },
      $(go.Picture,
        {
          width: 178, height: 168,
        },
        new go.Binding('source', 'bgSrc')),
      $(go.Picture,
        {
          width: 64, height: 64,
        },
        new go.Binding('source', 'iconSrc'))
    ),

    // 文字背景与文本信息
    $(go.Panel, go.Panel.Position,
      { position: new go.Point(50, 0) },

      $(go.Picture,
        { width: 178, height: 100 },
        new go.Binding('source', 'textBgSrc')),

      $(go.TextBlock,
        {
          stroke: '#FFF',
          font: 'normal bold 24px Serif',
          position: new go.Point(80, 20)
        },
        new go.Binding('text'))
    )
  )
)

const nodeDataArray = [
  {
    position: new go.Point(0, 0),
    category: 'node1',
    key: 'check',
    bgSrc: './images/circle_1.png',
    iconSrc: './images/icon-apply.png',
    textBgSrc: './images/text-bg-1.png',

    text: '申请'
  }
]
复制代码

代码注释:

1.这里使用的 $(go.Panel) 你可以理解成 html 中的 div, 参见以下代码:

diagram.nodeTemplateMap.add('node1',
  $(go.Node, go.Panel.Position,
    { width: 230, height: 240 },
    new go.Binding('position'),

    // 背景图片与图标
    $(go.Panel, go.Panel.Auto,
      { position: new go.Point(0, 72) },
      $(go.Picture,
        {
          width: 178, height: 168,
        },
        new go.Binding('source', 'bgSrc'))
    )
  )
)
复制代码

gojs 中的 node 模板可以 '翻译' 成以下结构(如果你恰好熟悉 JSX 语法, 那就更好理解了)

<Node 
    className="node1"
    layout="Position"
    style={{ width: 230, height: 240 }}
    position={position}>
    <Panel 
        layout="Auto"
        style={{ position: new go.Point(0, 72) }}>
        <Picture 
            source={bgSrc}
            style={{width: 178, height: 168}} />
    </Panel>
</Node>
复制代码

我们只需要严格按照 gojs 的语法规则, 逐一嵌套, 即可绘制出任意你想要的节点模型

2.go.Panel.Auto 布局方法, 允许将 Panel 中的子元素逐一居中显示在 Node 包裹容器正中(你也可以设置偏移), 更多的布局规则, 如 Position Vertical Spot 等等, 请移步 Panels, 官方文档已经做了很详细的解释了

以下是当前的三个节点效果 现在就差节点之间的连接线了!

node


Step3 编写连接线模板

还记得之前定义的 linkDataArray 数组么? 这个数组装载所有连接线的信息 值的注意的是, 要先有 node 再有 link

与节点模板一样, 连接线模板也分 linkTemplatelinkTemplateMap 这里我们只介绍 linkTemplateMap

实战演练

diagram.linkTemplateMap.add('link1',
  $(go.Link,  // [1]
    { routing: go.Link.Normal },
    new go.Binding('routing'),
    new go.Binding('fromSpot'),
    new go.Binding('toSpot'),

    // 线段模板
    $(go.Shape,  // [2]
      { strokeDashArray: [10, 20] },
      new go.Binding('stroke'),
      new go.Binding('strokeWidth')),

    // 箭头模板
    $(go.Shape,  // [2]
      { stroke: 'transparent', strokeWidth: 0 },
      new go.Binding('fromArrow'),
      new go.Binding('toArrow'),
      new go.Binding('scale', 'arrowScale'),
      new go.Binding('fill', 'arrowfill')),

    // 文字块
    $(go.Panel, go.Panel.Auto,  // [3]
      new go.Binding('alignmentFocus', 'textPos'),
      $(go.Shape, { fill: 'transparent' }, new go.Binding('stroke')),
      $(go.TextBlock, 
        { margin: 10 }, 
        new go.Binding('stroke'), 
        new go.Binding('text'))
    )
  )
)

const linkDataArray = [
  {
    category: 'link1',
    from: 'coor', to: 'apply',  // [4]

    routing: go.Link.Orthogonal,
    toArrow: 'Standard',
    arrowfill: 'orange',
    arrowScale: 2,
    fromSpot: new go.Spot(0, 0.42),
    toSpot: new go.Spot(0.42, 1),

    stroke: 'orange',
    strokeWidth: 2,

    text: '驳回',
    textPos: new go.Spot(0, 1, -100, 20)
  }
]
复制代码

代码注释:

1.go.Link 是连接线的包裹容器, 它全局为连接线定义一些属性

  • routing 定义连接线的连接方式, 直角或普通等等
  • fromSpot toSpot 定义连接线两端端头相对节点的位置
  • 还有许多可配置项, 参考Link

2.go.Link 容器中可以接收 go.Shape 构造器

  • 如果只设置该构造器 stroke 相关的属性, 则表示连接线的模板
  • 如果引入了 fromArrowtoArrow 则表示设置线段两端的箭头, 官方 figure 示例

3.同样, 我们可以在线段中添加 Picture TextBlock Shape Panel 等任何元素, 并且编写方式与节点模板是一致的, 只不过如果你想控制这些元素的偏移量, 你需要设置 alignmentFocus 属性

4.之前说过, nodeDataArray 中的 key 是必填的, 因为我们需要在 linkDataArray 中通过这个 key 来绝点各个节点的连接线如何相连

下期继续讲 gojs 的编辑类模板

(未完待续)

关注下面的标签,发现更多相似文章
评论