gojs 流程圖框架-基礎繪圖(一)

木子七發表於2018-05-25

gojs 是一款非常優秀的流程圖繪製 js 框架, 該框架沒有中文版 api, 並且網上可查閱的資料非常少, 本文旨在帶領讀者瞭解整個框架結構, 以及基本的繪製方法. 本文對技術細節不作過多描述, 並會附上 api 地址以供參考.

完成後的效果圖:

gojs 流程圖框架-基礎繪圖(一)

原始碼地址: 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

實戰演練

gojs 流程圖框架-基礎繪圖(一)

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 的編輯類别範本

(未完待續)

相關文章