G6-定制不同节点的参数 --组合图

本文介绍了如何使用 G6 图形库在 Angular 应用中创建具有动画效果的图表,包括边动画、节点拖拽、缩放和平移交互。示例代码展示了自定义边类型 'circle-running' 的实现,通过添加小球沿边移动的动画。此外,还讨论了图的适配问题,即图无法随屏幕尺寸变化自动调整大小。
摘要由CSDN通过智能技术生成

前言

G6官方地址:https://antv-g6.gitee.io/zh/examples/gallery

参考的G6案例有: 图表决策边动画定制不同节点的参数

实现的效果:动画、放大、缩小、拖拽、移动、点击交互等

有两版代码:一个是可以在G6官网里运行的。一个是在angular里运行的

我暂时未处理的问题:图的适配问题,不能随着屏幕大小变化而变化

请添加图片描述
变形
在这里插入图片描述
改变连接节点就行

代码

可直接在官网上运行的代码:
ps:随便找一个案例,替换掉里面的代码就行

import G6 from '@antv/g6';

G6.registerEdge(
  'circle-running',
  {
    afterDraw(cfg, group) {
      // 得到组中的第一个形状,它是边的路径在这里
      const shape = group.get('children')[0];
      // 边缘路径的起始位置
      const startPoint = shape.getPoint(0);

      // 添加一个在线上运动的圆球
      const circle = group.addShape('circle', {
        attrs: {
          x: startPoint.x,
          y: startPoint.y,
          fill: '#1890ff',
          r: 3,
        },
        name: 'circle-shape',
      });

      // 小球的动画
      circle.animate(
        (ratio) => {
          // 每个帧的操作。比率范围从0到1,表示动画的进度。返回修改后的配置
          // 根据比例得到边缘的位置
          const tmpPoint = shape.getPoint(ratio);
          // 这里返回修改后的配置,这里是x和y
          return {
            x: tmpPoint.x,
            y: tmpPoint.y,
          };
        },
        {
          repeat: true, // 是否重复执行动画
          duration: 3000, // 执行一次的持续时间
        },
      );
    },
  },
  'line', // 扩展内置边'cubic'
);

const lightColors = [
  '#8FE9FF',
  '#87EAEF',
  '#FFC9E3',
  '#A7C2FF',
  '#FFA1E3',
  '#FFE269',
  '#BFCFEE',
  '#FFA0C5',
  '#D5FF86',
];
const darkColors = [
  '#7DA8FF',
  '#44E6C1',
  '#FF68A7',
  '#7F86FF',
  '#AE6CFF',
  '#FF5A34',
  '#5D7092',
  '#FF6565',
  '#6BFFDE',
];
const uLightColors = [
  '#CFF6FF',
  '#BCFCFF',
  '#FFECF5',
  '#ECFBFF',
  '#EAD9FF',
  '#FFF8DA',
  '#DCE2EE',
  '#FFE7F0',
  '#EEFFCE',
];
const uDarkColors = [
  '#CADBFF',
  '#A9FFEB',
  '#FFC4DD',
  '#CACDFF',
  '#FFD4F2',
  '#FFD3C9',
  '#EBF2FF',
  '#FFCBCB',
  '#CAFFF3',
];

const gColors = [];
const unlightColorMap = new Map();


const container = document.getElementById('container');
const width = container.scrollWidth;
const height = container.scrollHeight || 500;
const graph = new G6.Graph({
  container: 'container',
  width,
  height,
  defaultEdge: {
    type: 'circle-running',
    style: {
      lineWidth: 2,
      stroke: '#bae7ff',
    },
  },
  defaultNode: {
    type: 'circle', // 'bubble'
    size: 95,
    labelCfg: {
      position: 'center',
      style: {
        fill: 'white',
        fontStyle: 'bold',
      },
    },
  },
  animate: true,
  layout: {
    type: 'force',
    preventOverlap: true,
    linkDistance: (d) => {
      if (d.source.id === 'node0') {
        return 200;
      }
      return 30;
    },
    nodeStrength: (d) => {
      if (d.isLeaf) {
        return -200;
      }
      return -100;
    },
  },
  defaultNode: {
    color: '#5B8FF9',
  },
  // 整个图可以拖动、放大缩小
    modes: {
      default: ['drag-canvas', 'zoom-canvas'],
    },
});

const data = {
  nodes: [
     { id: 'node0', label: `组织管理\n(12)`, size: 100 },
        { id: 'node1', label: '管理单位', size: 100 },
        { id: 'node2', label: '角色管理', size: 100 },
        { id: 'node3', label: '岗位管理', size: 100 },
        { id: 'node4', label: '岗位管理', size: 100 },
        { id: 'node5', label: '岗位管理', size: 100 },
  ],
  edges: [
   { source: 'node0', target: 'node1' },
        { source: 'node0', target: 'node2' },
        { source: 'node0', target: 'node3' },
        { source: 'node0', target: 'node4' },
        { source: 'node0', target: 'node5' },
  ],
};

lightColors.forEach((lcolor, i) => {
  gColors.push('l(0) 0:' + lcolor + ' 1:' + darkColors[i]);
  unlightColorMap.set(gColors[i], 'l(0) 0:' + uLightColors[i] + ' 1:' + uDarkColors[i]);
});
console.log(gColors);

for ( let i = 0; i < data.nodes.length; i++ ) {
  data.nodes[i].color = gColors[i];
  data.nodes[i].style = {
    fill: gColors[i],
    lineWidth: 0
  };
  data.nodes[i].labelCfg = {
    style: {
      fontSize: 20,
      fill: '#fff',
      fontWeight: 300,
    },
  };
}



const nodes = data.nodes;
graph.data({
  nodes,
  edges: data.edges.map(function (edge, i) {
    edge.id = 'edge' + i;
    return Object.assign({}, edge);
  }),
});
graph.render();

graph.on('node:dragstart', function (e) {
  graph.layout();
  refreshDragedNodePosition(e);
});
graph.on('node:drag', function (e) {
  refreshDragedNodePosition(e);
});
graph.on('node:dragend', function (e) {
  e.item.get('model').fx = null;
  e.item.get('model').fy = null;
});
graph.on('node:click', (evt) => {
    window.alert('点击了');
  });

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);
  };

function refreshDragedNodePosition(e) {
  const model = e.item.get('model');
  model.fx = e.x;
  model.fy = e.y;
}

我的代码

我是在angular11里使用的G6

<div #mountNodeLeft></div>
import { Component, OnInit, ViewChild } from '@angular/core';




@ViewChild('mountNodeLeft', { static: false }) mountNodeLeft!: any;
 constructor() { }

  ngOnInit(): void {
  }

  // tslint:disable-next-line:use-lifecycle-interface
  ngAfterViewInit(): void {
    setTimeout(() => { this.render(); }, 100);
  }

  // 下面两个函数是g6的图
  // tslint:disable-next-line:typedef
  render() {
    const lightColors = [
      '#8FE9FF',
      '#87EAEF',
      '#FFC9E3',
      '#A7C2FF',
      '#FFA1E3',
      '#FFE269',
      '#BFCFEE',
      '#FFA0C5',
      '#D5FF86',
    ];
    const darkColors = [
      '#7DA8FF',
      '#44E6C1',
      '#FF68A7',
      '#7F86FF',
      '#AE6CFF',
      '#FF5A34',
      '#5D7092',
      '#FF6565',
      '#6BFFDE',
    ];
    const uLightColors = [
      '#CFF6FF',
      '#BCFCFF',
      '#FFECF5',
      '#ECFBFF',
      '#EAD9FF',
      '#FFF8DA',
      '#DCE2EE',
      '#FFE7F0',
      '#EEFFCE',
    ];
    const uDarkColors = [
      '#CADBFF',
      '#A9FFEB',
      '#FFC4DD',
      '#CACDFF',
      '#FFD4F2',
      '#FFD3C9',
      '#EBF2FF',
      '#FFCBCB',
      '#CAFFF3',
    ];

    const gColors: any = [];
    const unlightColorMap = new Map();
    lightColors.forEach((lcolor, i) => {
      gColors.push('l(0) 0:' + lcolor + ' 1:' + darkColors[i]);
      unlightColorMap.set(gColors[i], 'l(0) 0:' + uLightColors[i] + ' 1:' + uDarkColors[i]);
    });

    G6.registerEdge(
      'circle-running',
      {
        // tslint:disable-next-line:typedef
        afterDraw(cfg, group: any) {
          // 得到组中的第一个形状,它是边的路径在这里
          const shape = group.get('children')[0];
          // 边缘路径的起始位置
          const startPoint = shape.getPoint(0);

          // 添加一个在线上运动的圆球
          const circle = group.addShape('circle', {
            attrs: {
              x: startPoint.x,
              y: startPoint.y,
              fill: '#1890ff',
              r: 3,
            },
            name: 'circle-shape',
          });

          // 小球的动画
          circle.animate(
            (ratio: any) => {
              // 每个帧的操作。比率范围从0到1,表示动画的进度。返回修改后的配置
              // 根据比例得到边缘的位置
              const tmpPoint = shape.getPoint(ratio);
              // 这里返回修改后的配置,这里是x和y
              return {
                x: tmpPoint.x,
                y: tmpPoint.y,
              };
            },
            {
              repeat: true, // 是否重复执行动画
              duration: 3000, // 执行一次的持续时间
            },
          );
        },
      },
      'line', // 扩展内置边'cubic'
    );

    const width = window.innerWidth / 2;
    const height = window.innerHeight - 300;
    const graph = new G6.Graph({
      container: this.mountNodeLeft.nativeElement,
      width,
      height,
      // 改变线的颜色 绑定动画
      defaultEdge: {
        type: 'circle-running',
        style: {
          lineWidth: 2,
          stroke: '#bae7ff',
        },
      },
      layout: {
        type: 'force',
        preventOverlap: true,
        linkDistance: (d: any) => {
          // if (d.source.id === 'node0') {
            // return 200;
          // }
          // return 30;
          return 200;
        },
        // nodeStrength: (d: any) => {
          // if (d.isLeaf) {
            // return -200;
          // }
         // return -100;
        },
      },
      defaultNode: {
        color: '#5B8FF9',
      },
      // 整个图可以拖动、放大缩小
      modes: {
        default: ['drag-canvas', 'zoom-canvas'],
      },
    });

    const data: any = {
      nodes: [
        { id: 'node0', label: `组织管理\n(12)`, size: 110 },
        { id: 'node1', label: '管理单位', size: 110 },
        { id: 'node2', label: '角色管理', size: 110 },
        { id: 'node3', label: '岗位管理', size: 110 },
        { id: 'node4', label: '岗位管理', size: 110 },
        { id: 'node5', label: '岗位管理', size: 110 },
      ],
      edges: [
        { source: 'node0', target: 'node1' },
        { source: 'node0', target: 'node2' },
        { source: 'node0', target: 'node3' },
        { source: 'node0', target: 'node4' },
        { source: 'node0', target: 'node5' },
      ],
    };
    // 修改图中的圆
    for (let i = 0; i < data.nodes.length; i++) {
      data.nodes[i].color = gColors[i];
      data.nodes[i].style = {
        fill: gColors[i],
        lineWidth: 0,
        cursor: 'pointer',
      };
      data.nodes[i].labelCfg = {
        style: {
          fontSize: 18,
          fill: '#fff',
          fontWeight: 300,
          cursor: 'pointer',
        },
      };
    }
    const nodes = data.nodes;
    graph.data({
      nodes,
      edges: data.edges.map((edge: any, i: any) => {
        edge.id = 'edge' + i;
        return Object.assign({}, edge);
      }),
    });
    graph.render();

    graph.on('node:dragstart', (e) => {
      graph.layout();
      this.refreshDragedNodePosition(e);
    });
    graph.on('node:drag', (e) => {
      this.refreshDragedNodePosition(e);
    });
    graph.on('node:dragend', (e: any) => {
      e.item.get('model').fx = null;
      e.item.get('model').fy = null;
    });
    graph.on('node:click', (evt) => {
      window.alert('点击了');
    });

  }
  // tslint:disable-next-line:typedef
  refreshDragedNodePosition(e: any) {
    const model = e.item.get('model');
    model.fx = e.x;
    model.fy = e.y;
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值