Giter Club home page Giter Club logo

g6's Introduction

English | 简体中文

G6:图可视分析引擎

G6 5.0 beta 版本已经发布,还有不少的细节体验问题,欢迎试用和反馈,线上产品暂时谨慎使用,6.6 发布正式版本!

npm Version Build Status Coverage Status npm Download typescript npm License

介绍案例教程API

G6 是一个图可视化引擎。它提供了图的绘制、布局、分析、交互、动画、主题、插件等图可视化和分析的基础能力。基于 G6,用户可以快速搭建自己的图可视化分析应用,让关系数据变得简单,透明,有意义。

✨ 特性

G6 作为一款专业的图可视化引擎,具有以下特性:

  • 丰富的元素:内置丰富的节点、边、Combo UI 元素,样式配置丰富,支持数据回调,且具备有灵活扩展自定义元素的机制。
  • 可控的交互:内置 10+ 交互行为,且提供丰富的各类事件,便于扩展自定义的交互行为。
  • 高性能布局:内置 10+ 常用的图布局,部分基于 GPU、Rust 并行计算提升性能,支持自定义布局。
  • 便捷的组件:优化内置组件功能及性能,且有灵活的扩展性,便于业务实现定制能力。
  • 多主题色板:提供了亮色、暗色两套内置主题,在 AntV 新色板前提下,融入 20+ 常用社区色板。
  • 多环境渲染:发挥 G 能力, 支持 Canvas、SVG 以及 WebGL,和 Node.js 服务端渲染;基于 WebGL 提供强大 3D 渲染和空间交互的插件包。
  • React 体系:利用 React 前端生态,支持 React 节点,大大丰富 G6 的节点呈现样式。

🔨 开始使用

可以通过 NPM 或 Yarn 等包管理器来安装。

$ npm install @antv/g6@next
$ yarn add @antv/g6@next

成功安装之后,可以通过 import 导入 Graph 对象。

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

// 准备数据
const data = {
  nodes: [/* your nodes data */],
  edges: [/* your edges data */],
};

// 初始化图表实例
const graph = new Graph({
  container: 'container',
  autoFit: 'view',
  data,
  node: {
    palette: {
      type: 'group',
      field: 'cluster',
    }
  },
  layout: {
    type: 'force',
  },
  behaviors: ['drag-canvas', 'drag-node'],
});

// 渲染可视化
graph.render();

一切顺利,你可以得到下面的力导图!

🌍 生态

  • Ant Design Charts: React 图表库,基于 G2、G6、X6、L7。
  • Graphin:基于 G6 的 React 简单封装,以及图可视化应用研发的 SDK。

更多生态开源项目,欢迎 PR 收录进来。

📮 贡献

  • 问题反馈:使用过程遇到的 G6 的问题,欢迎提交 Issue,并附上可以复现问题的最小案例代码。
  • 贡献指南:如何参与到 G6 的开发和贡献
  • 想法讨论:在 GitHub Discussion 上或者钉钉群里面讨论。

📄 License

MIT.

g6's People

Contributors

aarebecca avatar afc163 avatar albertaz1992 avatar anderson-liu avatar baizn avatar bzhangzju avatar chenluli avatar chenpeng-yiyu avatar colinchen2 avatar dependabot-preview[bot] avatar deturium avatar elaine1234 avatar fisherllcy avatar hustcc avatar k644606347 avatar lxfu1 avatar mxz96102 avatar openwayne avatar pomelo-nwu avatar songhn233 avatar spengjie avatar tomhuangcn avatar vellengs avatar wunaidage avatar xiaoiver avatar yanyan-wang avatar yvonneyx avatar zhanba avatar zqqcee avatar zxc0328 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

g6's Issues

动画

在更新 添加 删除 数据模型的时候 能不能 提供个动画 接口啊

例如 : graph.update(item, model,animate = true)

关于 group 和 shape 的 api

在示例中看到如下的用法

nameGroup.addShape('text', {
  attrs:{
    x: x,
    y: y + 20 * i,
    text: field.name,
    fill: '#333',
    textBaseline: 'top'
  }
});

splitLine = group.addShape('line', {
  attrs: {
    stroke: '#fff'
  }
});

关于 group 和 shape 的用法,比如支持哪些 attrs,在官网文档没有找到,可以补充一下吗。

如何动态修改一个节点样式?

我希望点击一个节点改变这个节点的一些样式 onClick事件里应该怎样写呢?是改变节点属性然后graph.refresh/update吗?
最开始我的想法是graph.edge().style('id', id => id === activeId ? 'custom-style': '')
但是发现我在onClick里面写什么都不会重新设置一遍style
现在有点蒙 不知道应该是具体用什么思路搞这件事

关于插入图片

定义的节点image只支持http开头的吗,我写本地的不好用

`
addImage.on('click',function(ev){
net.beginAdd('node',{
shape:'china.png'//这个位置如果换成加http的是好使得
}) })

`

在自定义节点里添加一个菱形会报错

G6.registNode("compositeNode", {
  draw: function(cfg, group) {
    var shape = group.addShape("rect", {
      attrs: {
        x: cfg.x - 60,
        y: cfg.y - 30,
        width: 120,
        height: 60,
        fill: "#fff",
        stroke: "lightblue"
      }
    });
    group.addShape("rhombus");
    group.addShape("text", {
      attrs: {
        x: cfg.x,
        y: cfg.y,
        fill: "black",
        text: "自定义图形",
        textAlign: "center"
      }
    });
    return shape;
  },
  getAnchorPoints: function() {
    return [[0.5, 0], [1, 0.5], [0.5, 1], [0, 0.5]];
  }
});

我想组合一个自定义节点里面有矩形和菱形。但是这样会报错

Uncaught TypeError: u[r] is not a constructor

把 group.addShape("rhombus"); 去掉就好了

codepen demo

updateAnchor怎么用

updateAnchor怎么用,在api里面没有看到相关讲解,我想控制指定某个锚点可连线和不可连线

如何重新布局?

你好,我参照官方示例进行布局,如下所示。但是我的需求会动态添加/删除一些 node 和 edge,请问一下如何触发重新布局呢?

var Layout = G6.Layout;
var margin = 60;
var height = 800 - 2 * margin;
var width = 500 - 2 * margin;
var nodes = data.nodes;
var edges = data.edges;
var layout = new Layout.Flow({
  nodes: nodes,
  edges: edges
});
nodes = layout.getNodes();
nodes.map(function(node) {
  var x = node.x * width + margin;
  var y = node.y * height + margin;
  node.x = y;
  node.y = x;
});

自定义图形,nodes里面的x,y失效?

安装的版本是:

npm install @antv/g6

我自定义了几个图标,代码大致如下:

// 注册一个路由器的图标
G6.registNode('router', {
  draw: function(cfg, group) {
    group.addShape('path', {
      attrs: {
        path: 'M0 12.3 V28.9 A 24.9 11.0 0 1 0 49.8 28.9 V12.3 Z',
        fill: '#dbdde1'
      }
    });
    group.addShape('ellipse', {
      attrs: {
        x: 24.9,
        y: 12.3,
        rx: 24.9,
        ry: 12.3,
        fill: '#e2e4e9'
      }
    });
    group.addShape('ellipse', {
      attrs: {
        x: 24.9,
        y: 12.3,
        rx: 23.5,
        ry: 11.6,
        fill: '#eeeff2'
      }
    });
    group.addShape('path', {
      attrs: {
        path: 'M2.3,10.1 L4.6,7.9 L16.5,9.6 L17.7,8.6 L20.5,11.7 L12.4,13.5 L13.6,12.2Z M24.8,10.0 L28.3,6.9 L26.4,6.4 L34.6,4.3 L34.1,7.6 L31.7,7.4 L27.9,11.1Z M28.0,12.7 L35.7,11.4 L34.6,12.5 L46.0,14.8 L43.8,16.9 L31.7,14.1 L29.6,16.2Z M20.7,13.9 L24.3,14.5 L20.0,18.5 L22.6,19.3 L14.6,20.8 L14.3,17.2 L16.5,17.7Z',
        fill: '#e85464'
      }
    });
    return group.addShape('rect', {
      attrs: {
        x: 0,
        y: 0,
        width: 49.8,
        height: 40
      }
    });
  },
  afterDraw: function(cfg, group, router) {
    cfg.size = 10
    group.addShape('text', {
      attrs: {
        x: 20,
        y: 51.3,
        fontFamily: '宋体',
        text: cfg.label,
        stroke: '#000',
        textAlign: 'center'
      }
    });
  },
  getAnchorPoints: function(cfg, group) {
    return [
      [0.5, 1], // 上面边的中点
      [1, 0.5], // 右边边的中点
      [0.5, 0], // 下边边的中点
      [0, 0.5] // 左边边的中点
    ]
  }
});

然后我渲染的数据如下:

var nodes = [
  {
    "id": "595b5e7e1d41c86f00adc371",
    "name": "switch_center",
    "host_id": "switch_center",
    "node_ip": "10.10.2.1",
    "node_type": "05401202",
    "linked": "1",
    "weight": 40,
    "y": 358.36920299208396,
    "x": 636.8554312518343,
    "shape": "router"
  },
  .....
]

结果是,这一类图标渲染出来的位置在坐标原点。

节点中可以存储节点

节点可以作为容器,可以为容器节点添加子节点,可以获取容器节点下的子节点数组,当容器节点移动时子节点一起移动,可以单独选择子节点。

撤销功能最多可以撤销几步

撤销功能是不是最多可以撤销4步,是否支持撤销到初始化状态,是否可以支持设置撤销几步,有没有这个打算

锚点连接问题

能不能处理以下两种情况
1,一个锚点连接过一次就不能进行第二次连接了
2,控制一个图形左侧的锚点不能和另外一个图形左侧的锚点进行连接

获得数据对象是不是应该更方便一点

graph.edge().color(dim, fun) 边颜色映射
graph.edge().size(dim, fun) 边大小映射
graph.edge().shape(dim, fun) 边形状映射
graph.edge().label(dim, fun) 边文本映射
graph.edge().style(dim, fun) 样式映射
graph.edge().tooltip(dim, fun) 提示信息映射

这一系列方法 参数是否应该直接是(edge) => {} ?node()同理,为什么不直接把对象暴露出来呢?

smoothArrow连接固定不变

image
针对自定义的图形,是不是在使用smoothArrow连接两个图形的锚点时,图形的位置发生改变,但是线的连接点连接的还是当初的锚点,不会跟着一起改变

关于removeBehaviour方法失效

hi
我的流程是这样的:
进入页面后,默认是complicated模式,点击“编辑”按钮后,切换到“edit”模式,我初始化net的时候,没有设置默认的“modes”字段。
现在的问题是:切换到“edit”模式后,双击画布报错,错误原因是“shortcut”这个行为。
我现在这样做:

function openEdit() {
  console.log('进入编辑模式');

  net.changeMode('edit');
  net.removeBehaviour('shortcut', 'edit');
  net.removeBehaviour('clickActive', 'edit');
}

但是双击画布以后还是会报错。
或者麻烦告诉我你们默认设置的“edit”模式都包括什么行为?我自定义一下“modes”字段。

G6 0.X -> G6 1.0 升级指南

概述

该文档是 G6 0.X -> G6 1.0 的升级指南文档,如果有你觉得描述的不够清晰的地方,升级有困难的话,敬请联系我们

原来的 Graph 既是现在的 Net

Graph 在 G6 1.0 中已经沉为抽象类,用户不应该直接实例化 Graph 使用。1.0 中 Net 基本含 0.X Graph 所有属性、方法。从 0.X 迁 1.X 的用户应将所有的 Graph 改为 Net。

新的锚点描述

锚点在关系图中无非是一个至关重要的概念,如果 0.X 中你使用了自定义锚点,应参看下文。

过去的锚点,我们定义了上(0)右(1)下(2)左(3),四个边,然后在通过第二个参数确定锚点的位置,如左图所示。这样不仅理解起来复杂,而且还有一个硬伤 —— 锚点无法定义到图形上!在新的锚点机制里,我们以左上角为(0,0)点,将锚点的范围拓展至了整个图形的包围盒平面内,如右图所示:

这样我们不仅能把锚点定义到图形包围盒边上,还能定义到包围盒内图,以做到锚点跟图形精确关联,如下图所示:

再见无穷尽的xxxable

诸如:selectabledragablezoomable,在 1.0 后,应用行为模式的交互插拔机制实现,比如:

0.X 中

var graph = new Graph({
  zoomable: false
});

等于 1.X 中

var net = new Net();
net.removeBehaviour(['wheelZoom']);

行为、模式的插拔组装,参见Demo;

调整初始化视口应该用fitView

0.x 中有时我们会render结束后,调用autoZoom方法,让图适应画布。1.X 中这种方法被废弃,需要在初始化图时配置fitView,以决定初始化时画布的视口。Graph API,fitView 属性。

统一输入输出 save && read

在使用关系图开发的过程中,我们常常需要导出导入数据,以满足关系图的存储、分享、编辑的功能。0.X 中 graph.savegraph.srouce 并没有严格对照。 G6 1.0 后,我们对这部分的需求做了总结。在 Graph 定义了一对相互对照的接口,read <==> save,后面用户应该严格通过这两个该接口导入导出数据。

读入数据 -- read

/**
 * 导入数据
 * @param  {Object}  data   通过save导出的数据
 */
graph.read(data);

保存数据 -- save

/**
 * 导出数据
 * @return  {Object}  data  导出的数据
 */
graph.save();

关于g6 net数据大的问题

在之前数据库表的基础上做了一个模拟数据,到1000张左右的时候 会比较卡,请问如何处理数据量大的问题呢?
`$(function () {

    var dataObj = {
        nodes: [],
        edges: [],
    };

    for (var i = 0; i < 1500; i++) {
        var nodesObj = {
            "shape": "table",
            "x": Math.floor(Math.random() * 9999),
            "y": Math.floor(Math.random() * 9999),
            "id": "d62q1519",
            "title": "Division",
            "type": "B",
            "fields": [
                {
                    "name": "Employee number",
                    "type": "Numberic(5)",
                    "key": "<pk>"
                },
                {
                    "name": "Emp_Employee number",
                    "type": "Numberic(5)",
                    "key": "<fk1>"
                },
                {
                    "name": "Division",
                    "type": "Numberic(5)",
                    "key": "<fk2>"
                },
                {
                    "name": "FirstName",
                    "type": "Chart(30)",
                    "key": ""
                }
            ]
        };
        var edgesObj = {
            "shape": "arrow",
            "source": "d62d1569",
            "id": "d6cb23c5",
            "target": "d62d1519",
            "controlPoints": [
                {
                    "x": Math.floor(Math.random() * 9999),
                    "y": Math.floor(Math.random() * 9999)
                },
                {
                    "x": Math.floor(Math.random() * 9999),
                    "y": Math.floor(Math.random() * 9999)
                },
                {
                    "x": Math.floor(Math.random() * 9999),
                    "y": Math.floor(Math.random() * 9999)
                }
            ],
            "relation": "service",
            "sourceAnchor": 2
        };
        edgesObj.source = edgesObj.target = nodesObj.id = Math.random().toString(36).substr(2);
        edgesObj.id = Math.random().toString(36).substr(2);

        dataObj.nodes.push(nodesObj);
        dataObj.edges.push(edgesObj);
    }

    var Util = G6.Util;
    G6.registNode('table', {
        draw: function (cfg, group) {
            var x = cfg.x;
            var y = cfg.y;
            var origin = cfg.origin;
            var fields = origin.fields;
            var backRect = group.addShape('rect', {
                attrs: {
                    stroke: 'blue',
                    fill: cfg.color
                }
            });
            var nameGroup = group.addGroup();
            var typeGroup = group.addGroup();
            var keyGroup = group.addGroup();
            var lineHeight = 20;
            var marginRight = 10;
            var padding = 6;
            var l = fields.length;
            var fontHeight;
            var anchorPoints = [];
            var title;
            var titleBox;
            var nameBox;
            var typeBox;
            var keyBox;
            var width;
            var height;
            var splitLine;
            title = group.addShape('text', {
                attrs: {
                    x: x,
                    y: y,
                    text: origin.title,
                    fill: '#333',
                    textBaseline: 'top',
                    textAlign: 'center'
                }
            });
            splitLine = group.addShape('line', {
                attrs: {
                    stroke: '#fff'
                }
            });
            Util.each(fields, function (field, i) {
                nameGroup.addShape('text', {
                    attrs: {
                        x: x,
                        y: y + 20 * i,
                        text: field.name,
                        fill: '#333',
                        textBaseline: 'top'
                    }
                });
                typeGroup.addShape('text', {
                    attrs: {
                        x: x,
                        y: y + 20 * i,
                        text: field.type,
                        fill: '#333',
                        textBaseline: 'top'
                    }
                });
                keyGroup.addShape('text', {
                    attrs: {
                        x: x,
                        y: y + 20 * i,
                        text: field.key,
                        fill: '#333',
                        textBaseline: 'top'
                    }
                });
            });
            titleBox = title.getBBox();
            nameBox = nameGroup.getBBox();
            typeBox = typeGroup.getBBox();
            keyBox = keyGroup.getBBox();
            width = nameBox.width + typeBox.width + keyBox.width + 3 * marginRight + 2 * padding;
            height = Math.max(nameBox.height, typeBox.height, keyBox.height) + 4 * padding + titleBox.height;
            fontHeight = nameGroup.get('children')[0].getBBox().height;
            title.translate(0, -height / 2 + padding);
            nameGroup.translate(-width / 2 + padding, -height / 2 + titleBox.height + 3 * padding);
            typeGroup.translate(-width / 2 + nameBox.width + marginRight + padding, -height / 2 + titleBox.height + 3 * padding);
            keyGroup.translate(-width / 2 + nameBox.width + typeBox.width + 2 * marginRight + padding, -height / 2 + titleBox.height + 3 * padding);
            splitLine.attr({
                x1: cfg.x - width / 2,
                y1: cfg.y - height / 2 + 2 * padding + titleBox.height,
                x2: cfg.x + width / 2,
                y2: cfg.y - height / 2 + 2 * padding + titleBox.height
            });
            backRect.attr({
                x: x - width / 2,
                y: y - height / 2,
                width: width,
                height: height,
                stroke: 'blue',
                fill: cfg.color
            });
            Util.each(fields, function (field, i) {
                var r = ( titleBox.height + i * (nameBox.height + lineHeight - fontHeight) / l + fontHeight / 2 + 3 * padding) / height;
                anchorPoints.push([0, r]);
                anchorPoints.push([1, r]);
            });
            group.set('anchorPoints', anchorPoints);
            return backRect;
        },
        getAnchorPoints: function (cfg, group) {
            var anchorPoints = group.get('anchorPoints');
            anchorPoints.unshift([0.5, 0]);   // 上中
            anchorPoints.push([0.5, 1]);      // 下中
            return anchorPoints;
        }
    });
    var net = new G6.Net({
        id: 'c1',            // 容器ID
        height: 900,         // 画布高
        fitView: 'autoZoom', // 自动缩放
        grid: {
            cell: 10           // 网格大小
        }
    });
    net.source(dataObj.nodes, dataObj.edges);
    net.node().color('type', function (val) {
        if (val === "B") {
            return G6.Global.colors[0];
        }
        if (val === "C") {
            return G6.Global.colors[1];
        }
    });
    net.edge().label('relation');
    net.render();
});`

如何添加节点内局部自定义事件

非常喜欢 G6 ,给项目组点赞。

我想要捕获节点的局部点击事件,请问一下如何实现呢?我们要实现一个自定义节点,捕获类似 tree 节点右侧的 "+" 号的点击事件。目前从文档和示例来看,只能获取到 node 和 edge 这个级别的事件。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.