Antv/X6<圖編輯引擎>

1618558278291.jpg
  • 你可以直接查看???? 官方文檔 ????,文檔寫的很棒????;
  • 你也可以簡單聽我BBLL,順便告訴你我的親身經(jīng)歷,和常用參數(shù);

遇到問題:

當(dāng)你遇到下面這幾種圖形編輯時,你可能會想:
??這不是要專門搞一套js代碼嗎,canvas我也不熟練啊??,這工程量也太大了,放棄吧?。「习逭f這個需求做不了

2021-04-16 10-46-28.gif

當(dāng)然x1,起初我也是這么想的,而且我也嘗試了自己用canvas寫一個這個東西~
當(dāng)然x2,寫起來又是一碼事了,什么小問題各種層出不窮,然后果斷棄坑~
當(dāng)然x3,我可以百度找現(xiàn)成的代碼啊,網(wǎng)上那么多插件啥的,后來才發(fā)現(xiàn)魚目混雜,根本無從下手,萬一遇到問題找誰?
??♂???♂?所以,在最后朋友(朋友多還是有那么點用的,致敬 ??木兄)的推薦下,還是遇到了它 ------???? Antv/X6????!!

步入正題:

2021-04-16 10-32-55.gif

上圖是我結(jié)合自身項目需求+ Vue,制作的類似于一個工廠智能小車工作線路圖,沒聽懂的,也可以忽略這句話??~
???? 官方文檔入口 ????
常用參數(shù):

      //創(chuàng)建地圖
      this.graph = new Graph({
        snapline: true, //對齊線
        history: {
          enabled: true, //歷史記錄
          ignoreChange: true //ignoreChange 是否忽略屬性變化
        },
        panning: true, //支持平移拖拽
        container: document.getElementById('container'),
        width: window.innerWidth,
        height: window.innerHeight,
        background: {
          color: '#fffbe6' // 設(shè)置畫布背景顏色
        },
        grid: {
          size: 10, // 網(wǎng)格大小 10px
          visible: true // 渲染網(wǎng)格背景
        },
        connecting: {
          allowPort: true, //是否允許邊鏈接到鏈接樁
          allowEdge: false, //是否允許邊鏈接到另一個邊
          allowNode: false, //是否允許邊鏈接到節(jié)點(非節(jié)點上的鏈接樁)
          allowLoop: false, //是否允許創(chuàng)建循環(huán)連線,即邊的起始節(jié)點和終止節(jié)點為同一節(jié)點
          allowMulti: false, //是否允許在相同的起始節(jié)點和終止之間創(chuàng)建多條邊
          allowBlank: false, //是否允許連接到畫布空白位置的點
          // 自動吸附
          snap: {
            radius: 20
          }
        }
      })
//加載地圖數(shù)據(jù)
this.graph.fromJSON(this.data)

右上角工具欄:

image.png

自己寫的,主要包含 撤銷重做,創(chuàng)建節(jié)點,圖形放大,圖形縮小,重置視圖,數(shù)據(jù)導(dǎo)出;

//撤銷操作
this.graph.undo()
//重做
this.graph.redo()
//創(chuàng)建節(jié)點
 const rect = this.graph.addNode({
  shape: 'rect', // 指定使用何種圖形,默認值為 'rect'
  ...
})
//地圖放大縮小
 this.graph.zoom(0.1)
 this.graph.zoom(-0.1)
//重置視圖
this.graph.centerContent() //畫布居中
this.graph.zoom(0)
//序列化/反序列化 數(shù)據(jù)格式
// https://antv-x6.gitee.io/zh/docs/tutorial/intermediate/serialization
// graph.toJSON() 方法來導(dǎo)出圖中的節(jié)點和邊
this.graph.toJSON()
選中和工具Tools:

2021-04-16 11-13-07.gif

使用工具 Tools文檔
節(jié)點和邊選中代碼示例
節(jié)點和邊選中——事件屬性參考文檔

//在創(chuàng)建節(jié)點的時候,直接加入刪除按鈕tools
  const rect = this.graph.addNode({
          shape: 'rect', // 指定使用何種圖形,默認值為 'rect'
          ...
          attrs: {
          ...
          },
         //使用工具
          tools: [
            {
              name: 'button-remove', // 工具名稱
              args: { x: 5, y: 5 } // 工具對應(yīng)的參數(shù)
            }
          ]})
案例代碼:
<template>
  <div>
    <span class="toolbar">
      <div class="tool" title="撤銷" @click="toUndo()">
        <i class="el-icon-refresh-left"></i>
      </div>
      <div class="tool" title="重做" @click="toRedo()">
        <i class="el-icon-refresh-right"></i>
      </div>
      <div class="tool" title="創(chuàng)建節(jié)點" @click="createNodes('rect')">
        <div class="rect"></div>
      </div>
      <div class="tool" @click="mapZoom('+')" title="放大視圖">
        <i class="el-icon-zoom-in"></i>
      </div>
      <div class="tool" @click="mapZoom('-')" title="縮小視圖">
        <i class="el-icon-zoom-out"></i>
      </div>
      <div class="tool" @click="mapZoom()" title="重置視圖">
        <i class="el-icon-full-screen"></i>
      </div>
      <div class="tool" @click="save()" title="保存">
        <i class="el-icon-cpu"></i>
      </div>
    </span>
    <div id="container"></div>
  </div>
</template>

<script>
import { Graph } from '@antv/x6'
export default {
  data() {
    return {
      graph_zoom: 0, //地圖縮放比例
      graph: null,
      //   data: {
      // 節(jié)點
      // nodes: [
      //   {
      //     id: 'node1', // String,可選,節(jié)點的唯一標識
      //     x: 40, // Number,必選,節(jié)點位置的 x 值
      //     y: 40, // Number,必選,節(jié)點位置的 y 值
      //     width: 60, // Number,可選,節(jié)點大小的 width 值
      //     height: 60, // Number,可選,節(jié)點大小的 height 值
      //     label: 'node1', // String,節(jié)點標簽
      //     tools: ['button-remove']
      //   },
      //   {
      //     id: 'node2', // String,節(jié)點的唯一標識
      //     x: 160, // Number,必選,節(jié)點位置的 x 值
      //     y: 180, // Number,必選,節(jié)點位置的 y 值
      //     width: 60, // Number,可選,節(jié)點大小的 width 值
      //     height: 60, // Number,可選,節(jié)點大小的 height 值
      //     label: 'node2' // String,節(jié)點標簽
      //   },
      //   {
      //     id: 'node3', // String,節(jié)點的唯一標識
      //     x: 40, // Number,必選,節(jié)點位置的 x 值
      //     y: 180, // Number,必選,節(jié)點位置的 y 值
      //     width: 60, // Number,可選,節(jié)點大小的 width 值
      //     height: 60, // Number,可選,節(jié)點大小的 height 值
      //     label: 'node3' // String,節(jié)點標簽
      //   }
      // ],
      // 邊
      // edges: [
      //   {
      //     source: 'node1', // String,必須,起始節(jié)點 id
      //     target: 'node2' // String,必須,目標節(jié)點 id
      //   }
      // ],
      //   }
      data: []
    }
  },
  mounted() {
    this.init()
  },
  methods: {
    //初始化地圖
    init() {
      //創(chuàng)建地圖
      this.graph = new Graph({
        snapline: true, //對齊線
        history: {
          enabled: true, //歷史記錄
          ignoreChange: true //ignoreChange 是否忽略屬性變化
        },
        panning: true, //支持平移拖拽
        container: document.getElementById('container'),
        width: window.innerWidth,
        height: window.innerHeight,
        background: {
          color: '#fffbe6' // 設(shè)置畫布背景顏色
        },
        grid: {
          size: 10, // 網(wǎng)格大小 10px
          visible: true // 渲染網(wǎng)格背景
        },
        connecting: {
          allowPort: true, //是否允許邊鏈接到鏈接樁
          allowEdge: false, //是否允許邊鏈接到另一個邊
          allowNode: false, //是否允許邊鏈接到節(jié)點(非節(jié)點上的鏈接樁)
          allowLoop: false, //是否允許創(chuàng)建循環(huán)連線,即邊的起始節(jié)點和終止節(jié)點為同一節(jié)點
          allowMulti: false, //是否允許在相同的起始節(jié)點和終止之間創(chuàng)建多條邊
          allowBlank: false, //是否允許連接到畫布空白位置的點
          // 自動吸附
          snap: {
            radius: 20
          },
          // createEdge() {
          //   //創(chuàng)建動畫虛線邊
          //   return new Shape.Edge({
          //     attrs: {
          //       line: {
          //         stroke: '#1890ff',
          //         strokeDasharray: 5,
          //         targetMarker: 'classic',
          //         style: {
          //           animation: 'ant-line 30s infinite linear'
          //         }
          //       }
          //     }
          //   })
          // }
        }
      })
      //加載地圖數(shù)據(jù)
      this.graph.fromJSON(this.data)
      this.graph.centerContent() //畫布居中
      //節(jié)點點擊事件
      this.graph.on('node:click', ({ e, x, y, node, view }) => {
        // console.log(node)
        this.selectReset()
        node.attr('body/stroke', 'orange')
      })
      //邊點擊事件
      this.graph.on('edge:click', ({ e, x, y, edge, view }) => {
        // console.log(edge)
        this.selectReset()
        edge.attr('line/stroke', 'orange')
        edge.prop('labels/0', {
          attrs: {
            body: {
              stroke: 'orange'
            }
          }
        })
      }),
        //節(jié)點雙擊事件
        this.graph.on('node:dblclick', ({ e, x, y, node, view }) => {
          alert('節(jié)點ID:' + node.id)
          console.log(node)
        })
      //邊雙擊事件
      this.graph.on('edge:dblclick', ({ e, x, y, edge, view }) => {
        console.log(edge)
        alert(
          `邊ID:${edge.id}, 起始節(jié)點: ${edge.source.cell},目標節(jié)點: ${edge.target.cell}`
        )
      })
    },
    //保存,獲取節(jié)點等數(shù)據(jù)
    save() {
      //序列化/反序列化 數(shù)據(jù)格式
      // https://antv-x6.gitee.io/zh/docs/tutorial/intermediate/serialization
      // graph.toJSON() 方法來導(dǎo)出圖中的節(jié)點和邊
      console.log(this.graph.toJSON())
    },
    //撤銷操作
    toUndo() {
      this.graph.undo()
    },
    //重做
    toRedo() {
      this.graph.redo()
      //   if (this.graph.isHistoryEnabled()) {
      //     this.graph.disableHistory()
      //   } else {
      //     this.graph.enableHistory()
      //   }
    },
    //地圖放大縮小
    mapZoom(type) {
      if (type == '+') {
        this.graph.zoom(0.1)
        this.graph_zoom += 0.1
      } else if (type == '-') {
        this.graph.zoom(-0.1)
        this.graph_zoom -= 0.1
      } else {
        this.graph.zoom(
          this.graph_zoom <= 0 ? Math.abs(this.graph_zoom) : -this.graph_zoom
        )
        this.graph.centerContent() //畫布居中
        this.graph_zoom = 0
      }
    },
    //創(chuàng)建節(jié)點
    createNodes(type) {
      if (type == 'rect') {
        const rect = this.graph.addNode({
          shape: 'rect', // 指定使用何種圖形,默認值為 'rect'
          x: 0,
          y: 0,
          width: 60,
          height: 60,
          angle: 0,
          attrs: {
            body: {
              fill: '#fff', // 背景顏色
              stroke: '#000' // 邊框顏色
            },
            label: {
              text: 'Node', // 文本
              fill: '#333', // 文字顏色
              fontSize: 13 // 文字大小
            }
          },
          tools: [
            {
              name: 'button-remove', // 工具名稱
              args: { x: 5, y: 5 } // 工具對應(yīng)的參數(shù)
            }
          ],
          //連接樁
          //   ports: [
          // {
          //   id: 'port1',
          //   attrs: {
          //     circle: {
          //       r: 6,
          //       //    magnet: true 這個特殊屬性,使鏈接樁在連線交互時可以被連接上
          //       magnet: true,
          //       stroke: '#31d0c6',
          //       strokeWidth: 2,
          //       fill: '#fff'
          //     }
          //   }
          // },
          // {
          //   id: 'port2',
          //   attrs: {
          //     circle: {
          //       r: 6,
          //       magnet: true,
          //       stroke: '#31d0c6',
          //       strokeWidth: 2,
          //       fill: '#fff'
          //     }
          //   }
          // }
          //   ]
          ports: {
            groups: {
              // 輸入鏈接樁群組定義
              left: {
                position: 'left',
                attrs: {
                  circle: {
                    r: 4,
                    magnet: true,
                    stroke: '#31d0c6',
                    strokeWidth: 2,
                    fill: '#fff'
                  }
                }
              },
              right: {
                position: 'right',
                attrs: {
                  circle: {
                    r: 4,
                    magnet: true,
                    stroke: '#31d0c6',
                    strokeWidth: 2,
                    fill: '#fff'
                  }
                }
              },
              top: {
                position: 'top',
                attrs: {
                  circle: {
                    r: 4,
                    magnet: true,
                    stroke: '#31d0c6',
                    strokeWidth: 2,
                    fill: '#fff'
                  }
                }
              },
              bottom: {
                position: 'bottom',
                attrs: {
                  circle: {
                    r: 4,
                    magnet: true,
                    stroke: '#31d0c6',
                    strokeWidth: 2,
                    fill: '#fff'
                  }
                }
              }
            },
            items: [
              {
                id: 'port1-1',
                group: 'left'
              },
              {
                id: 'port1-2',
                group: 'left',
                attrs: {
                  circle: {
                    stroke: '#e9352f'
                  }
                }
              },
              {
                id: 'port2-1',
                group: 'right',
                attrs: {
                  circle: {
                    stroke: '#e9352f'
                  }
                }
              },
              {
                id: 'port2-2',
                group: 'right'
              },
              {
                id: 'port3-1',
                group: 'top',
                attrs: {
                  circle: {
                    stroke: '#e9352f'
                  }
                }
              },
              {
                id: 'port3-2',
                group: 'top'
              },
              {
                id: 'port4-1',
                group: 'bottom'
              },
              {
                id: 'port4-2',
                group: 'bottom',
                attrs: {
                  circle: {
                    stroke: '#e9352f'
                  }
                }
              }
            ]
          }
        })
      }
      //   console.log(this.graph)
    },
    //創(chuàng)建邊
    createEdges(type) {
      const rect = this.graph.addEdge({
        shape: 'edge', // 指定使用何種圖形,默認值為 'edge'
        source: 'node1',
        target: 'node3'
      })
    },
    //選擇節(jié)點,邊時重置顏色
    selectReset() {
      //   this.graph.drawBackground({ color: '#fff' })
      const nodes = this.graph.getNodes()
      const edges = this.graph.getEdges()

      nodes.forEach(node => {
        node.attr('body/stroke', '#000')
      })

      edges.forEach(edge => {
        edge.attr('line/stroke', 'black')
        edge.prop('labels/0', {
          attrs: {
            body: {
              stroke: 'black'
            }
          }
        })
      })
    }
  }
}
</script>

<style lang="scss" scoped>
.toolbar {
  //   padding: 0 20px;
  box-sizing: border-box;
  height: 40px;
  background: white;
  box-shadow: 0 2px 6px #e1e1e1;
  position: fixed;
  right: 0;
  z-index: 999;
  display: flex;
  align-items: center;
  .tool {
    cursor: pointer;
    width: 40px;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    &:hover {
      background: #f1f1f1;
    }
  }
}
.rect {
  width: 10px;
  height: 10px;
  border: 1px solid #5a5a5a;
  //   color: #e9352f;
}
</style>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容