天天看點

流程圖的渲染實作

效果圖如下:

流程圖的渲染實作

 流程節點類型:

1.普通節點

2.分支節點

難點:

1.資料結構定義

2.節點有序渲染

3.分支節點渲染

資料結構:

流程圖的渲染實作
流程圖的渲染實作

 flowNodesMap:節點映射對象;(以節點id為關鍵字存儲節點資料)

 startNodeId     :起始節點Id       ;(友善從映射對象中找出起始節點資料)  

節點資料中關鍵 :

  1. nextId:下一節點id(若後面無節點預設值為-1)
  2. preId :前一節點id(起始節點預設值為1)

 節點序列化渲染:

getSameLevelIds (flowNodesMap, startNodeId) {
    let ret = [startNodeId]
    let nextId = flowNodesMap[startNodeId].nextId
    while (nextId && nextId !== '-1') {
      ret.push(nextId)
      nextId = flowNodesMap[nextId].nextId
    }
    return ret
  },

 renderNodes (flowNodesMap, startNodeId) {
      const nodes = getSameLevelIds(flowNodesMap, startNodeId)
        .map((id) => {
          let data = {
            key: id,
            props: {
              node: flowNodesMap[id],
            },
            on: {
              delete: this.handleNodeDelete,
            },
          }
          return flowNodesMap[id].type === Enums.NODE_TYPE.BRANCH ? (
            <Branch
              {...data}
              flowNodesMap={flowNodesMap}
              renderNodes={this.renderNodes}
            ></Branch>
          ) : (
            <DealNode {...data} ></DealNode>
          )
        })
      return nodes
    },
           

getSameLevelIds:根據節點映射生成有序數組,

renderNodes:周遊渲染節點 (根據節點類型渲染不同節點)

分支節點渲染:

流程圖的渲染實作
 關鍵點:flowIds資料儲存該分支節點的所有一級條件節點id
const nodes = this.node.flowIds.map((id, index) => {
      let conditionNode = this.renderConditionNode(id)
      if (index === 0) {
        return (
          <div class="col-box">
            <div class="top-left-cover-line" />
            {conditionNode}
            <div class="bottom-left-cover-line" />
          </div>
        )
      } else if (index === this.node.flowIds.length - 1) {
        return (
          <div class="col-box">
            <div class="top-right-cover-line" />
            {conditionNode}
            <div class="bottom-right-cover-line" />
          </div>
        )
      }
      return (
        <div class="col-box">
          {conditionNode}
        </div>
      )
    })
           
renderConditionNode (id) {
      let ret = []
      ret.push(<ConditionNode node={this.flowNodesMap[id]} on-delete={this.handleConditionNodeDelete}></ConditionNode>)
//如果該條件節點存在下一節點,則重新判斷節點類型渲染節點  是普通節點還是分支節點
      if (this.flowNodesMap[id].nextId) {
        ret.push(...this.renderNodes(this.flowNodesMap,this.flowNodesMap[id].nextId))
      }
      if (ret.length === 1) {
        if (!ret[0].data.style) {
          ret[0].data.style = {}
        }
        ret[0].data.style['flex-grow'] = 1
      } else {
        if (!ret[ret.length - 1].data.style) {
          ret[ret.length - 1].data.style = {}
        }
        ret[ret.length - 1].data.style['flex-grow'] = 1
      }
      return ret
    },
           

元件樣式自定義

整體結構:節點塊 + 連結線

渲染思路總結:

根據節點映射排列縱向節點,渲染類型為分支節點時,根據flowIds渲染分支的同級條件節點。一條分支以條件節點開頭,渲染分支就以該頭部條件節點為起始節點循環調用renderNode,實作各分支渲染。

繼續閱讀