Vue3使用AntV | X6绘制流程图:开箱即用

news2024/11/24 18:33:53

x6官方地址X6·图编辑引擎 | AntV

官方文档仔细地介绍了很多丰富的功能,这里的demo可以满足基本的使用,具体拓展还需要仔细看文档内容

先上效果图

1、安装

通过 npm 或 yarn 命令安装 X6。

# npm
npm install @antv/x6 --save

# yarn
yarn add @antv/x6

初始化画布

<div id="container"></div>
import { Graph } from '@antv/x6'

const graph = new Graph({
  container: document.getElementById('container'),
  width: 800,
  height: 600,
  background: {
    color: '#F2F7FA',
  },
})

使用插件

import { Snapline } from '@antv/x6-plugin-snapline'

graph.use(
  new Snapline({
    enabled: true,
  }),
)

数据导出

graph.toJSON()

具体依赖package.json

{
  "@antv/x6": "^2.0.0",
  "@antv/x6-plugin-clipboard": "^2.0.0", // 如果使用剪切板功能,需要安装此包
  "@antv/x6-plugin-history": "^2.0.0", // 如果使用撤销重做功能,需要安装此包
  "@antv/x6-plugin-keyboard": "^2.0.0", // 如果使用快捷键功能,需要安装此包
  "@antv/x6-plugin-minimap": "^2.0.0", // 如果使用小地图功能,需要安装此包
  "@antv/x6-plugin-scroller": "^2.0.0", // 如果使用滚动画布功能,需要安装此包
  "@antv/x6-plugin-selection": "^2.0.0", // 如果使用框选功能,需要安装此包
  "@antv/x6-plugin-snapline": "^2.0.0", // 如果使用对齐线功能,需要安装此包
  "@antv/x6-plugin-dnd": "^2.0.0", // 如果使用 dnd 功能,需要安装此包
  "@antv/x6-plugin-stencil": "^2.0.0", // 如果使用 stencil 功能,需要安装此包
  "@antv/x6-plugin-transform": "^2.0.0", // 如果使用图形变换功能,需要安装此包
  "@antv/x6-plugin-export": "^2.0.0", // 如果使用图片导出功能,需要安装此包
  "@antv/x6-react-components": "^2.0.0", // 如果使用配套 UI 组件,需要安装此包
  "@antv/x6-react-shape": "^2.0.0", // 如果使用 react 渲染功能,需要安装此包
  "@antv/x6-vue-shape": "^2.0.0" // 如果使用 vue 渲染功能,需要安装此包
}

本文依赖

"dependencies": {
    "@element-plus/icons-vue": "^2.3.1",
    "element-plus": "^2.7.6",
    "pinia": "^2.1.7",
    "vue": "^3.4.29",
    "vue-router": "^4.3.3",
    "@antv/x6": "latest",
    "@antv/x6-plugin-clipboard": "latest",
    "@antv/x6-plugin-history": "latest",
    "@antv/x6-plugin-keyboard": "latest",
    "@antv/x6-plugin-selection": "latest",
    "@antv/x6-plugin-snapline": "latest",
    "@antv/x6-plugin-stencil": "latest",
    "@antv/x6-plugin-transform": "latest",
    "@antv/x6-plugin-node-editor": "latest",
    "insert-css": "latest"
  },

完整代码,开箱即用

<template>
  <div id="container">
    <div id="stencil"></div>
    <div id="graph-container"></div>
  </div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { Graph, Shape } from '@antv/x6'
import { Stencil } from '@antv/x6-plugin-stencil'
import { Transform } from '@antv/x6-plugin-transform'
import { Selection } from '@antv/x6-plugin-selection'
import { Snapline } from '@antv/x6-plugin-snapline'
import { Keyboard } from '@antv/x6-plugin-keyboard'
import { Clipboard } from '@antv/x6-plugin-clipboard'
import { History } from '@antv/x6-plugin-history'
// import { NodeEditor } from '@antv/x6-plugin-node-editor'
import insertCss from 'insert-css'

onMounted(() => {
  // 初始化画布
  //- `Graph` 对象用于初始化流程图画布,`container` 指向 HTML 中 `graph-container` 这个 DOM 元素。流程图支持缩放、连线、拖拽等功能。
  const graph = new Graph({
    container: document.getElementById('graph-container'),
    grid: true,
    mousewheel: {
      enabled: true,
      zoomAtMousePosition: true,
      modifiers: 'ctrl',
      minScale: 0.5,
      maxScale: 3
    },
    connecting: {
      router: 'manhattan',
      connector: {
        name: 'rounded',
        args: { radius: 8 }
      },
      anchor: 'center',
      connectionPoint: 'anchor',
      allowBlank: false,
      snap: { radius: 20 },
      createEdge() {
        return new Shape.Edge({
          attrs: {
            line: {
              stroke: '#A2B1C3',
              strokeWidth: 2,
              targetMarker: {
                name: 'block',
                width: 12,
                height: 8
              }
            }
          },
          zIndex: 0
        })
      },
      validateConnection({ targetMagnet }) {
        return !!targetMagnet
      }
    },
    highlighting: {
      magnetAdsorbed: {
        name: 'stroke',
        args: { attrs: { fill: '#5F95FF', stroke: '#5F95FF' } }
      }
    }
  })

  // 插件配置
  //- 通过 `.use()` 方法注册了多个插件,包括 `Transform`(支持调整大小、旋转)、`Selection`(选择功能)、`Snapline`(自动对齐线)、`Keyboard`(键盘支持)等。

  graph
    .use(new Transform({ resizing: true, rotating: true }))
    .use(new Selection({ rubberband: true, showNodeSelectionBox: true }))
    .use(new Snapline())
    .use(new Keyboard())
    .use(new Clipboard())
    .use(new History())

  // 初始化 stencil
  //- `Stencil` 是用于提供左侧工具栏的组件,用户可以从工具栏中拖拽图形到画布中。支持基本图形和系统设计图的两类分组
  const stencil = new Stencil({
    title: '流程图',
    target: graph,
    stencilGraphWidth: 200,
    stencilGraphHeight: 180,
    collapsable: true,
    groups: [
      { title: '基础流程图', name: 'group1' },
      { title: '系统设计图', name: 'group2', graphHeight: 250, layoutOptions: { rowHeight: 70 } }
    ],
    layoutOptions: { columns: 2, columnWidth: 80, rowHeight: 55 }
  })

  document.getElementById('stencil')?.appendChild(stencil.container)
  // #region 快捷键与事件
  graph.bindKey(['meta+c', 'ctrl+c'], () => {
    const cells = graph.getSelectedCells()
    if (cells.length) {
      graph.copy(cells)
    }
    return false
  })
  graph.bindKey(['meta+x', 'ctrl+x'], () => {
    const cells = graph.getSelectedCells()
    if (cells.length) {
      graph.cut(cells)
    }
    return false
  })
  graph.bindKey(['meta+v', 'ctrl+v'], () => {
    if (!graph.isClipboardEmpty()) {
      const cells = graph.paste({ offset: 32 })
      graph.cleanSelection()
      graph.select(cells)
    }
    return false
  })

  // undo redo
  graph.bindKey(['meta+z', 'ctrl+z'], () => {
    if (graph.canUndo()) {
      graph.undo()
    }
    return false
  })
  graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
    if (graph.canRedo()) {
      graph.redo()
    }
    return false
  })

  // select all
  graph.bindKey(['meta+a', 'ctrl+a'], () => {
    const nodes = graph.getNodes()
    if (nodes) {
      graph.select(nodes)
    }
  })

  // delete
  graph.bindKey('backspace', () => {
    const cells = graph.getSelectedCells()
    if (cells.length) {
      graph.removeCells(cells)
    }
  })

  // zoom
  graph.bindKey(['ctrl+1', 'meta+1'], () => {
    const zoom = graph.zoom()
    if (zoom < 1.5) {
      graph.zoom(0.1)
    }
  })
  graph.bindKey(['ctrl+2', 'meta+2'], () => {
    const zoom = graph.zoom()
    if (zoom > 0.5) {
      graph.zoom(-0.1)
    }
  })

  // 控制连接桩显示/隐藏
  const showPorts = (ports: NodeListOf<SVGElement>, show: boolean) => {
    for (let i = 0, len = ports.length; i < len; i += 1) {
      ports[i].style.visibility = show ? 'visible' : 'hidden'
    }
  }
  graph.on('node:mouseenter', () => {
    const container = document.getElementById('graph-container')!
    const ports = container.querySelectorAll('.x6-port-body') as NodeListOf<SVGElement>
    showPorts(ports, true)
  })
  graph.on('node:mouseleave', () => {
    const container = document.getElementById('graph-container')!
    const ports = container.querySelectorAll('.x6-port-body') as NodeListOf<SVGElement>
    showPorts(ports, false)
  })
  // 注册自定义节点
  //- 通过 `Graph.registerNode` 注册了不同形状(矩形、圆形、多边形等)的自定义节点,并且定义了连接桩的位置和样式。
  const ports = {
    groups: {
      top: {
        position: 'top',
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: '#5F95FF',
            strokeWidth: 1,
            fill: '#fff',
            style: { visibility: 'hidden' }
          }
        }
      },
      right: {
        position: 'right',
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: '#5F95FF',
            strokeWidth: 1,
            fill: '#fff',
            style: { visibility: 'hidden' }
          }
        }
      },
      bottom: {
        position: 'bottom',
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: '#5F95FF',
            strokeWidth: 1,
            fill: '#fff',
            style: { visibility: 'hidden' }
          }
        }
      },
      left: {
        position: 'left',
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: '#5F95FF',
            strokeWidth: 1,
            fill: '#fff',
            style: { visibility: 'hidden' }
          }
        }
      }
    },
    items: [{ group: 'top' }, { group: 'right' }, { group: 'bottom' }, { group: 'left' }]
  }

  // 注册不同形状的自定义节点
  Graph.registerNode('custom-rect', {
    inherit: 'rect',
    width: 66,
    height: 36,
    attrs: {
      body: { strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF' },
      text: { fontSize: 12, fill: '#262626' }
    },
    ports: { ...ports },
    //支持文字编辑
    tools: [
      {
        name: 'node-editor',
        args: {
          attrs: {
            backgroundColor: '#EFF4FF'
          }
        }
      }
    ]
  })

  Graph.registerNode('custom-polygon', {
    inherit: 'polygon',
    width: 66,
    height: 36,
    attrs: {
      body: { strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF' },
      text: { fontSize: 12, fill: '#262626' }
    },
    ports: { ...ports, items: [{ group: 'top' }, { group: 'bottom' }] },
    //支持文字编辑
    tools: [
      {
        name: 'node-editor',
        args: {
          attrs: {
            backgroundColor: '#EFF4FF'
          }
        }
      }
    ]
  })

  Graph.registerNode('custom-circle', {
    inherit: 'circle',
    width: 45,
    height: 45,
    attrs: {
      body: { strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF' },
      text: { fontSize: 12, fill: '#262626' }
    },
    ports: { ...ports },
    //支持文字编辑
    tools: [
      {
        name: 'node-editor',
        args: {
          attrs: {
            backgroundColor: '#EFF4FF'
          }
        }
      }
    ]
  })

  // 加载图形节点到 stencil
  const r1 = graph.createNode({
    shape: 'custom-rect',
    label: '开始',
    attrs: { body: { rx: 20, ry: 26 } }
  })
  const r2 = graph.createNode({ shape: 'custom-rect', label: '过程' })
  const r3 = graph.createNode({
    shape: 'custom-rect',
    label: '可选过程',
    attrs: { body: { rx: 6, ry: 6 } }
  })
  const r4 = graph.createNode({
    shape: 'custom-polygon',
    label: '决策',
    attrs: { body: { refPoints: '0,10 10,0 20,10 10,20' } }
  })
  const r5 = graph.createNode({
    shape: 'custom-polygon',
    label: '数据',
    attrs: { body: { refPoints: '10,0 40,0 30,20 0,20' } }
  })
  const r6 = graph.createNode({ shape: 'custom-circle', label: '连接' })

  stencil.load([r1, r2, r3, r4, r5, r6], 'group1')
  //------------------------------------------文字编辑--------------------
  //   const source = graph.addNode({
  //     x: 180,
  //     y: 60,
  //     width: 100,
  //     height: 40,
  //     attrs: {
  //       body: {
  //         stroke: '#5F95FF',
  //         fill: '#EFF4FF',
  //         strokeWidth: 1
  //       }
  //     },
  //     tools: [
  //       {
  //         name: 'node-editor',
  //         args: {
  //           attrs: {
  //             backgroundColor: '#EFF4FF'
  //           }
  //         }
  //       }
  //     ]
  //   })

  //   const target = graph.addNode({
  //     x: 320,
  //     y: 250,
  //     width: 100,
  //     height: 40,
  //     attrs: {
  //       body: {
  //         stroke: '#5F95FF',
  //         fill: '#EFF4FF',
  //         strokeWidth: 1
  //       }
  //     },
  //     tools: [
  //       {
  //         name: 'node-editor',
  //         args: {
  //           attrs: {
  //             backgroundColor: '#EFF4FF'
  //           }
  //         }
  //       }
  //     ]
  //   })

  //   graph.addEdge({
  //     source,
  //     target,
  //     attrs: {
  //       line: {
  //         stroke: '#A2B1C3',
  //         strokeWidth: 2
  //       }
  //     },
  //     tools: [
  //       {
  //         name: 'edge-editor',
  //         args: {
  //           attrs: {
  //             backgroundColor: '#fff'
  //           }
  //         }
  //       }
  //     ]
  //   })
  //-------------------------------------------------------
  // 加载图像节点
  const imageShapes = [
    {
      label: 'Client',
      image: 'https://gw.alipayobjects.com/zos/bmw-prod/687b6cb9-4b97-42a6-96d0-34b3099133ac.svg'
    },
    {
      label: 'Http',
      image: 'https://gw.alipayobjects.com/zos/bmw-prod/dc1ced06-417d-466f-927b-b4a4d3265791.svg'
    },
    {
      label: 'Api',
      image: 'https://gw.alipayobjects.com/zos/bmw-prod/c55d7ae1-8d20-4585-bd8f-ca23653a4489.svg'
    },
    {
      label: 'Sql',
      image: 'https://gw.alipayobjects.com/zos/bmw-prod/6eb71764-18ed-4149-b868-53ad1542c405.svg'
    },
    {
      label: 'Clound',
      image: 'https://gw.alipayobjects.com/zos/bmw-prod/c36fe7cb-dc24-4854-aeb5-88d8dc36d52e.svg'
    },
    {
      label: 'Mq',
      image: 'https://gw.alipayobjects.com/zos/bmw-prod/2010ac9f-40e7-49d4-8c4a-4fcf2f83033b.svg'
    }
  ]

  const imageNodes = imageShapes.map((item) =>
    graph.createNode({
      shape: 'custom-image',
      label: item.label,
      attrs: { image: { 'xlink:href': item.image } }
    })
  )
  //- `stencil.load()` 方法用于将自定义节点加载到 Stencil 中,用户可以从左侧拖拽这些节点到画布上。
  stencil.load(imageNodes, 'group2')

  // 添加 CSS 样式
  //- 使用 `insertCss()` 动态添加了样式,使得画布、工具栏以及选择框等元素的样式更加统一。
  insertCss(`
    #container {
      display: flex;
      border: 1px solid #dfe3e8;
    }
    #stencil {
      width: 180px;
      height: 100%;
      position: relative;
      border-right: 1px solid #dfe3e8;
    }
    #graph-container {
      width: calc(100% - 180px);
      height: 100%;
    }
    .x6-widget-stencil, .x6-widget-stencil-title, .x6-widget-stencil-group-title {
      background-color: #fff !important;
    }
    .x6-widget-transform

, .x6-widget-selection-box, .x6-widget-selection-inner {
      border: 1px solid #239edd;
    }
  `)
})
</script>
<style scoped lang="scss">
#container {
  display: flex;
  height: 50vh;
}
#stencil {
  width: 180px;
  height: 100%;
  border-right: 1px solid #dfe3e8;
}
#graph-container {
  flex-grow: 1;
  width: 800px;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2230498.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

day12:磁盘阵列

一&#xff0c;RAID概述 RAID&#xff08;Redundant Array of Independent Disks&#xff09;是一种数据存储虚拟化技术&#xff0c;起源于1980年代&#xff0c;旨在提高存储系统的性能和可靠性。最初&#xff0c;由加州大学伯克利分校的研究人员提出&#xff0c;RAID技术的核…

Chromium 中chrome.topSites扩展接口定义c++

一、chrome.topSites 使用 chrome.topSites API 访问新标签页上显示的热门网站&#xff08;即最常访问的网站&#xff09;。不包括用户自定义的快捷方式。 权限 topSites 您必须声明“topSites”扩展程序清单中授予使用此 API 的权限。 {"name": "My exten…

Qt自定义控件:汽车速度表

1、功能 制作一个汽车速度表 2、实现 从外到内进行绘制&#xff0c;初始化画布&#xff0c;画渐变色外圈&#xff0c;画刻度&#xff0c;写刻度文字&#xff0c;画指针&#xff0c;画扇形&#xff0c;画内圈渐变色&#xff0c;画黑色内圈&#xff0c;写当前值 3、效果 4、源…

​Java面试经典 150 题.P13. 罗马数字转整数(012)​

本题来自&#xff1a;力扣-面试经典 150 题 面试经典 150 题 - 学习计划 - 力扣&#xff08;LeetCode&#xff09;全球极客挚爱的技术成长平台https://leetcode.cn/studyplan/top-interview-150/ 题解&#xff1a; class Solution {public int romanToInt(String s) {int sum…

stl_stack/queue

一.适配器 stack和queue实际上并不能算是一种容器&#xff0c;而是一种容器适配器。而适配器作为stl的6大组件之一&#xff0c;其实是一种设计模式。适配器模式其实就是将一个类的接口&#xff08;该接口无法直接满足客户的需求&#xff09;转换成客户希望的另一个接口&#x…

计算机网络:网络层 —— 虚拟专用网 VPN

文章目录 虚拟专用网 VPN 概述内联网 VPN外联网 VPN 虚拟专用网 VPN 概述 虚拟专用网&#xff08;Virtual Private Network&#xff0c;VPN&#xff09;&#xff1a;利用公用的因特网作为本机构各专用网之间的通信载体&#xff0c;这样形成的网络又称为虚拟专用网。 出于安全…

SSM酒店预订住宿管理系统-计算机毕业设计源码01085

摘要 随着互联网和移动技术的快速发展&#xff0c;酒店行业也面临着巨大的变革和机遇。传统的酒店管理方式存在着信息不透明、预订流程繁琐等问题&#xff0c;无法满足现代消费者对便捷、高效、个性化服务的需求。因此&#xff0c;开发酒店预订住宿管理系统具有重要的意义。本文…

STM32CubeMX学习(三) SPI+DMA通信

STM32CubeMX学习&#xff08;三&#xff09; SPIDMA通信 一、简介二、新建STM32CubeMX项目并使用外部时钟三、SPI3配置四、相关代码五、测试 一、简介 本文将基于STM32F103RCT芯片介绍如何在STM32CubeMXKEIL5开发环境下进行SPIDMA通信。 操作系统&#xff1a;WIN10 x64硬件电…

LLaMA系列一直在假装开源...

伙伴们&#xff0c;很奇怪~ 关于LLM的开源与闭源模型的竞争又开始愈发激烈。 众所周知&#xff0c;开源模型以其开放性和社区驱动的特点受到一部分用户的青睐&#xff0c;而闭源模型则因其专业性和性能优化被广泛应用于商业领域。由于大模型最近2年的突然兴起&#xff0c;开源…

C语言 核心语法2

时间&#xff1a;2024.11.1 一、学习内容 1、计算机的存储规则 1.1存储规则 视频是图片和声音的结合体。 在计算机中&#xff0c;任意数据都是以二进制的形式进行存储的。 在计算机中&#xff0c;二进制可以表示万事万物。 1.2十进制 1.3二进制的运算过程 1.4文本存储 …

客户端与微服务之间的桥梁---网关

当我们创建好了N多个微服务或者微服务的实例之后&#xff0c;每个服务暴露出不同的端口地址&#xff0c;一般对于客户端请求&#xff0c;只需要请求一个端口&#xff0c;要隔离客户端和微服务的直接关系&#xff0c;保证微服务的安全性和灵活性&#xff0c;避免敏感信息的泄露。…

萤石设备视频接入平台EasyCVR私有化部署视频平台高速公路视频上云的高效解决方案

经济的迅猛发展带来了高速公路使用频率的激增&#xff0c;其封闭、立交和高速的特性变得更加显著。然而&#xff0c;传统的人工巡查方式已不足以应对当前高速公路的监控挑战&#xff0c;监控盲点和响应速度慢成为突出问题。比如&#xff0c;非法占用紧急车道的情况屡见不鲜&…

【论文速读】| APILOT:通过避开过时API陷阱,引导大语言模型生成安全代码

基本信息 原文标题&#xff1a;APILOT: Navigating Large Language Models to Generate Secure Code by Sidestepping Outdated API Pitfalls 原文作者&#xff1a;Weiheng Bai, Keyang Xuan, Pengxiang Huang, Qiushi Wu, Jianing Wen, Jingjing Wu, Kangjie Lu 作者单位&a…

泡泡玛特行至巅峰,又顷刻“瓦解”?

今年&#xff0c;在海外“一呼百应”的LABUBU与“老妈”泡泡玛特一同步入了潮玩时代的全新阶段。 先是LABUBU获授“神奇泰国体验官”&#xff0c;首个LABUBU主题店也落地曼谷。随后泡泡玛特也在发布三季度财报后迎来股价新高&#xff08;10月24日收盘价75.85元/股&#xff0c;…

如何看待长周期项目?

有一个客户&#xff0c;想找你做一个软件项目。你大体评估了一下&#xff0c;项目成本300万&#xff0c;项目收入400万&#xff0c;有大概100万左右的毛利。但项目的周期&#xff0c;会比较长&#xff0c;大概是3年。 你会做吗&#xff1f; 我从自己的经验和直觉来看&#x…

Flutter仿微信,高度还原,开源

Flutter仿微信开源项目&#xff0c;持续更新中 Flutter仿微信项目&#xff0c;已开源&#x1f680;&#x1f680;&#x1f680;说明效果预览开发进度说明未来计划项目结构说明组件封装示例最后持续更新中... Flutter仿微信项目&#xff0c;已开源&#x1f680;&#x1f680;&am…

HBA:基于分层激光雷达集束调整的一致性建图

文章目录 前言一、介绍二、相关工作三、方法A. 概述B. 自底向上的分层BA&#xff08;Bundle Adjustment&#xff09;C. 自顶向下位姿图优化 四. 实验A. 精度分析 前言 代码&#xff1a;github 原文&#xff1a;原文 摘要——重建准确且一致的大规模LiDAR点云地图对机器人应用至…

Docker — 跨平台和环境部署

Docker 是一个开源的容器化平台&#xff0c;通过将应用程序和其依赖打包在一个轻量级、独立的容器中&#xff0c;能够跨平台和环境部署。 1. Docker 基本概念 镜像 (Image)&#xff1a;Docker 镜像是一个只读模板&#xff0c;包含运行应用程序所需的代码、库、依赖和环境配置。…

消息队列-Rabbitmq(消息发送,消息接收)

将来我们开发业务功能的时候&#xff0c;肯定不会在控制台收发消息&#xff0c;而是应该基于编程的方式。由于RabbitMQ采用了AMQP协议&#xff0c;因此它具备跨语言的特性。任何语言只要遵循AMQP协议收发消息&#xff0c;都可以与RabbitMQ交互。并且RabbitMQ官方也提供了各种不…

一机多控无人机集群飞行控制技术详解

一机多控无人机集群飞行控制技术是指通过单一控制端或多个协同工作的控制端&#xff0c;对多架无人机进行集群管理和控制的技术。这种技术结合了通信技术、路径规划、碰撞避免、分布式与集中式控制等多个方面&#xff0c;以实现无人机集群的协同作战或完成其他特定任务。以下是…