树形流程图-G6

前几天接到了个需求,做一个树形的流程图,大概形状类似于antV-G6里面的自定义树图

antv-G6自定义树图链接:定制树图元素样式 | G6

树形流程图-G6_第1张图片

但是需求:父节点和子节点能够展开和关闭,还要有这个功能

树形流程图-G6_第2张图片

emmm..对于每接触过G6的小白来说...真的难哭了

我在网上一顿找..发现并没有合适的可以直接用的..只能自己去改造,但是改造的前提的我得先学G6,所以这篇是我对G6给的树图的学习--大家可以参考 

首先肯定是要下载G6了--官网

 npm install --save @antv/g6

注意:下载之后启动,如果报错core.js的问题,可以下载一下他的相对最新版

npm install [email protected]

下面就是对G6各个配置项的学习注释了

import G6 from '@antv/g6'

// 折叠图标函数
const COLLAPSE_ICON = function COLLAPSE_ICON (x, y, r) {
  return [
    ['M', x - r, y - r],
    ['a', r, r, 0, 1, 0, r * 2, 0],
    ['a', r, r, 0, 1, 0, -r * 2, 0],
    ['M', x + 2 - r, y - r],
    ['L', x + r - 2, y - r]
  ]
}
// 展开图标函数
const EXPAND_ICON = function EXPAND_ICON (x, y, r) {
  return [
    ['M', x - r, y - r],
    ['a', r, r, 0, 1, 0, r * 2, 0],
    ['a', r, r, 0, 1, 0, -r * 2, 0],
    ['M', x + 2 - r, y - r],
    ['L', x + r - 2, y - r],
    ['M', x, y - 2 * r + 2],
    ['L', x, y - 2]
  ]
}
// 树形图数据
const data = {
  id: 'root',
  label: 'root',
  children: [
    {
      id: 'c1',
      label: 'c1',
      children: [
        {
          id: 'c1-1',
          label: 'c1-1'
        },
        {
          id: 'c1-2',
          label: 'c1-2',
          children: [
            {
              id: 'c1-2-1',
              label: 'c1-2-1'
            },
            {
              id: 'c1-2-2',
              label: 'c1-2-2'
            }
          ]
        }
      ]
    },
    {
      id: 'c2',
      label: 'c2'
    },
    {
      id: 'c3',
      label: 'c3',
      children: [
        {
          id: 'c3-1',
          label: 'c3-1'
        },
        {
          id: 'c3-2',
          label: 'c3-2',
          children: [
            {
              id: 'c3-2-1',
              label: 'c3-2-1'
            },
            {
              id: 'c3-2-2',
              label: 'c3-2-2'
            },
            {
              id: 'c3-2-3',
              label: 'c3-2-3'
            }
          ]
        },
        {
          id: 'c3-3',
          label: 'c3-3'
        }
      ]
    }
  ]
}
// 深度优先遍历树数据 从根到子
G6.Util.traverseTree(data, (d) => {
  d.leftIcon = {
    style: {
      fill: '#e6fffb',
      stroke: '#e6fffb'
    },
    img: 'https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*Q_FQT6nwEC8AAAAAAAAAAABkARQnAQ'
  }
  return true
})

// 自定义元素 G6.registerX
// 自定义节点-当内置节点不满足需求时,可以通过 G6.registerNode(nodeName, options, extendedNodeName) 方法自定义节点。
// nodeName 自定义节点的名称 唯一性  必须
// options,自定义节点的配置项是个对象 必须
// extendedNodeName 可以基于内置节点自定义节点
G6.registerNode(
  'icon-node',
  {
    options: {
      size: [60, 20], // 宽高
      stroke: '#91d5ff', // 变颜色
      fill: '#91d5ff'// 填充色
    },
    // draw是绘制后的附加操作-节点的配置项  图形分组,节点中图形对象的容器
    draw (cfg, group) {
      // 获取节点的配置
      const styles = this.getShapeStyle(cfg)
      // 解构赋值
      const { labelCfg = {} } = cfg

      const w = styles.width
      const h = styles.height
      // 向分组中添加新的图形 图形 配置 rect矩形 xy 代表左上角坐标 w h是宽高
      const keyShape = group.addShape('rect', {
        attrs: {
          ...styles,
          x: -w / 2,
          y: -h / 2
        }
      })

      console.log('cfg.leftIcon', cfg.leftIcon)
      // 如果有左侧图标 向分组中添加新的图形的配置
      if (cfg.leftIcon) {
        const { style, img } = cfg.leftIcon
        group.addShape('rect', {
          attrs: {
            x: 1 - w / 2,
            y: 1 - h / 2,
            width: 38,
            height: styles.height - 2,
            fill: '#8c8c8c',
            ...style
          }
        })

        group.addShape('image', {
          attrs: {
            x: 8 - w / 2,
            y: 8 - h / 2,
            width: 24,
            height: 24,
            img:
              img ||
              'https://g.alicdn.com/cm-design/arms-trace/1.0.155/styles/armsTrace/images/TAIR.png'
          },
          name: 'image-shape'
        })
      }

      // 如果不需要动态增加或删除元素,则不需要 add 这两个 marker
      group.addShape('marker', {
        attrs: {
          x: 40 - w / 2,
          y: 52 - h / 2,
          r: 6,
          stroke: '#73d13d',
          cursor: 'pointer',
          symbol: EXPAND_ICON
        },
        name: 'add-item'
      })

      group.addShape('marker', {
        attrs: {
          x: 80 - w / 2,
          y: 52 - h / 2,
          r: 6,
          stroke: '#ff4d4f',
          cursor: 'pointer',
          symbol: COLLAPSE_ICON
        },
        name: 'remove-item'
      })
      // 文本文字的配置
      if (cfg.label) {
        group.addShape('text', {
          attrs: {
            ...labelCfg.style,
            text: cfg.label,
            x: 50 - w / 2,
            y: 25 - h / 2
          }
        })
      }

      return keyShape
    },
    // 更新节点后的操作,一般同 afterDraw 配合使用
    update: undefined
  },
  'rect'
)

// 自定义边
// 参数1 自定义边的名称 参数2 自定义边时的配置项(对象) 参数3 自定义边时可基于内置边进行定义(选填)
G6.registerEdge('flow-line', {
// 绘制后的附加操作
  draw (cfg, group) {
    // 边两端与起始节点和结束节点的交点;
    const startPoint = cfg.startPoint
    const endPoint = cfg.endPoint
    // 边的配置
    const { style } = cfg
    const shape = group.addShape('path', {
      attrs: {
        stroke: style.stroke, // 边框的样式
        endArrow: style.endArrow, // 结束箭头
        // 路径
        path: [
          ['M', startPoint.x, startPoint.y],
          ['L', startPoint.x, (startPoint.y + endPoint.y) / 2],
          ['L', endPoint.x, (startPoint.y + endPoint.y) / 2],
          ['L', endPoint.x, endPoint.y]
        ]
      }
    })

    return shape
  }
})

// 默认的鼠标悬停会加粗,边框颜色改变
const defaultStateStyles = {
  hover: {
    stroke: '#1890ff',
    lineWidth: 2
  }
}

// 默认节点的颜色 边 圆角的配置
const defaultNodeStyle = {
  fill: '#91d5ff',
  stroke: '#40a9ff',
  radius: 5
}

// 默认边的颜色 末尾箭头
const defaultEdgeStyle = {
  stroke: '#91d5ff',
  endArrow: {
    path: 'M 0,0 L 12, 6 L 9,0 L 12, -6 Z',
    fill: '#91d5ff',
    d: -20
  }
}

// 默认布局
// compactBox 紧凑树布局
// 从根节点开始,同一深度的节点在同一层,并且布局时会将节点大小考虑进去。
const defaultLayout = {
  type: 'compactBox', // 布局类型树
  direction: 'TB', // TB 根节点在上,往下布局
  getId: function getId (d) { // 节点 id 的回调函数
    return d.id
  },
  getHeight: function getHeight () { // 节点高度的回调函数
    return 16
  },
  getWidth: function getWidth () { // 节点宽度的回调函数
    return 16
  },
  getVGap: function getVGap () { // 节点纵向间距的回调函数
    return 40
  },
  getHGap: function getHGap () { // 节点横向间距的回调函数
    return 70
  }
}

// 文本配置项
const defaultLabelCfg = {
  style: {
    fill: '#000',
    fontSize: 12
  }
}

// 获取容器
const container = document.getElementById('container')
// 获取容器的宽高
const width = container.scrollWidth
const height = container.scrollHeight || 500

// 实例化 Grid 插件-小地图
const minimap = new G6.Minimap({
  size: [150, 100]
})
// 实例化 Menu 插件-右击
const menu = new G6.Menu({
  offsetX: 6,
  offsetY: 10,
  itemTypes: ['node'],
  getContent (e) {
    const outDiv = document.createElement('div')
    outDiv.style.width = '180px'
    outDiv.innerHTML = `
  • 测试01
  • 测试01
  • 测试01
  • 测试01
  • 测试01
` return outDiv } }) // Graph 是 G6 图表的载体-实例化 const graph = new G6.TreeGraph({ container: 'container', // 图的 DOM 容器 width, height, linkCenter: true, // 指定边是否连入节点的中心 plugins: [minimap, menu], // 插件 modes: { // 交互模式 // default 模式中包含点击选中节点行为和拖拽画布行为; default: ['drag-canvas', 'zoom-canvas'] }, // 默认状态下节点的配置 defaultNode: { type: 'icon-node', size: [120, 40], style: defaultNodeStyle, labelCfg: defaultLabelCfg }, // 默认状态下边的配置, defaultEdge: { type: 'flow-line', style: defaultEdgeStyle }, // 各个状态下节点的样式-,例如 hover、selected,3.1 版本新增。 nodeStateStyles: defaultStateStyles, // 各个状态下边的样式-,例如 hover、selected,3.1 版本新增。 edgeStateStyles: defaultStateStyles, // 布局配置项 layout: defaultLayout }) // 初始化的图数据,是一个包括 nodes 数组和 edges 数组的对象 graph.data(data) // 根据提供的数据渲染视图。 graph.render() // 让画布内容适应视口。 graph.fitView() // 改变视口的缩放比例,在当前画布比例下缩放,是相对比例。 graph.zoom(1) // 鼠标移入元素范围内触发 graph.on('node:mouseenter', (evt) => { const { item } = evt graph.setItemState(item, 'hover', true) }) // 鼠标移出目标元素后触发 graph.on('node:mouseleave', (evt) => { const { item } = evt// item表示触发元素 graph.setItemState(item, 'hover', false) }) // 单击鼠标左键或者按下回车键时触发 graph.on('node:click', (evt) => { // item: 事件的触发元素(节点/边/ Combo) // target: 事件的触发图形 Shape 或画布对象 const { item, target } = evt // type: 事件类型 // name: 事件名称 const targetType = target.get('type') const name = target.get('name') // 增加元素 if (targetType === 'marker') { const model = item.getModel() if (name === 'add-item') { if (!model.children) { model.children = [] } const id = `n-${Math.random()}` model.children.push({ id, label: id.substr(0, 8), leftIcon: { style: { fill: '#e6fffb', stroke: '#e6fffb' }, img: 'https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*Q_FQT6nwEC8AAAAAAAAAAABkARQnAQ' } }) graph.updateChild(model, model.id) } else if (name === 'remove-item') { // // 移除节点 graph.removeChild(model.id) } } }) if (typeof window !== 'undefined') { window.onresize = () => { if (!graph || graph.get('destroyed')) return if (!container || !container.scrollWidth || !container.scrollHeight) return graph.changeSize(container.scrollWidth, container.scrollHeight) } }

下面的是我根据G6树图的改造的 (在vue组件中写的)--效果图

树形流程图-G6_第3张图片

 树形流程图-G6_第4张图片





数据用的假数据 treedata.js

// 属性图的数据
export const treedata = {
  id: 'root',
  label: '根',
  children: [
    {
      id: '1',
      label: '一级',
      children: [
        {
          id: '1-1',
          label: '二级'
        },
        {
          id: '1-2',
          label: '二级',
          children: [
            {
              id: '1-2-1',
              label: '三级'
            },
            {
              id: '1-2-2',
              label: '三级'
            }
          ]
        }
      ]
    },
    {
      id: '2',
      label: '一级'
    },
    {
      id: '3',
      label: '一级',
      children: [
        {
          id: '3-1',
          label: '二级'
        },
        {
          id: '3-2',
          label: '二级',
          children: [
            {
              id: '3-2-1',
              label: '三级'
            },
            {
              id: '3-2-2',
              label: '三级'
            },
            {
              id: '3-2-3',
              label: '三级'
            }
          ]
        },
        {
          id: '3-3',
          label: '二级'
        }
      ]
    }
  ]
}

               哎,就是玩~    小白入手G6树第一步!

[添加,删除,修改,查看功能还没写~慢慢来]

你可能感兴趣的:(javascript,vue,npm,数据可视化)