一、AntV G6

是阿里巴巴蚂蚁金服旗下 AntV 数据可视化团队开发的一款‌专注于关系数据的图可视化引擎‌,旨在帮助开发者高效构建专业的图可视化、图分析或图编辑器应用。

二、使用步骤

下面这个案例是创建一个垂直的树形图,且当叶子节点文本超过10时,文本会显示为省略号。且节点选中和未选中状态显示的填充色和文本颜色不一样。

1.引入库

注意:引入的g6库的版本必须和typescript版本相匹配,否则在项目中会报错,在这个案例中由于项目版本中ts的版本为4.0.2所以我安装的g6版本为3.8.5。

npm i @antv/g6@3.8.5

2.在项目中使用g6

1.在ts文件中引入

import G6 from '@antv/g6';

2.在html中创建一个有宽高的容器

 <div #orgElement class="echarts-width"></div>

3.在ts中获取这个dom节点,然后创建g6图例 

**注意:在创建graph图表前最好调需要创建的自定义节点、边,但事件需要在graph.render方法渲染后才调

    onInitGraph() {
        /**设置自定义边*/
        this.onRegisterEdge();
        /**设置自定义节点 */
        this.onSetNewNode();

        const container = this.orgElement.nativeElement;
        this.graph = new G6.TreeGraph({
            container: container,
            width: container.offsetWidth,
            height: container.offsetHeight,
            plugins: [this.onSetTooltip()], //显示tooltip
            fitView: true, //自适应
            linkCenter: true, //连接线从节点中心出发
            modes: { default: ['drag-canvas', 'zoom-canvas'] },// 支持画布拖拽,缩放
            defaultNode: {
                type: 'self-text-node', // 使用自定义节点
                size: [100, 40], // 宽度固定,高度动态
                clipCfg: { show: false } // 禁用裁剪
            },
            /**节点选中样式 */
            nodeStateStyles: {
                selected: {
                    // 选中状态样式
                    fill: '#3eaeff', // 蓝色背景
                    stroke: 'transparent', // 无边框
                    'text-shape': {
                        fill: '#fff' // 白色字体
                    }
                }
            },
            defaultEdge: {
                type: 'vertical-line',
                style: {
                    stroke: '#1890ff'
                }
            },
            layout: {
                type: 'dendrogram',
                direction: 'TB', // 从上到下布局(根节点在顶部)
                nodeSep: 200, // 节点间距
                rankSep: 100 // 层级间距,
            }
        });
        this.graph.data(this.graphDataIfy.data);
        this.graph.render();
        // 默认选中根节点
        const node = this.graph.findById(this.leftOrgIfy.activedNode.key);
        this.graph.setItemState(node, 'selected', true); //true表示启用选中状态
        this.onClickNode();
    }

4.创建图表使用的自定义方法、点击方法等

(1)设置自定义边

创建根节点与叶子结点的连接边,垂直显示

    /**自定义边,根节点和叶子结点的连接线 */
    onRegisterEdge() {
        G6.registerEdge('vertical-line', {
            draw(cfg, group) {
                /**由于设置了linkCenter所以都是从节点中心开始[0.5,0.5] */
                const { startPoint, endPoint } = cfg;
                /**M 移动到指定坐标,L 直线到指定坐标,从中心垂直向下后水平移动再垂直向下 */
                const 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 group.addShape('path', {
                    attrs: { path, stroke: '#1890ff' }
                });
            }
        });
    }

(2)创建自定义节点(包含超出范围用省略号显示、以及选中效果)

    /**设置新的节点 */
    onSetNewNode() {
        // // 在graph初始化前添加自定义节点类型
        G6.registerNode('self-text-node', {
            /**
             * @param cfg 节点配置项
             * @param group 节点容器
             */
            draw(cfg: any, group) {
                const { width, height } = this.calcSize(cfg);
                const rect = this.drawRect(group, width, height);
                this.drawText(cfg, group);
                return rect;
            },
            calcSize(cfg) {
                const mockCtx = document.createElement('canvas').getContext('2d');
                mockCtx.font = '12px sans-serif';
                // 截断文本(10个中文字符+省略号)
                const displayText =
                    cfg.label.length > 10 && cfg.depth !== 0
                        ? cfg.label.substr(0, 10) + '...'
                        : cfg.label;
                const metrics = mockCtx.measureText(displayText); //获取文本的宽度
                return {
                    width: Math.max(100, metrics.width + 20),
                    height: Math.max(40, 24)
                };
            },
            drawRect(group, w, h) {
                return group.addShape('rect', {
                    attrs: {
                        x: -w / 2,
                        y: -h / 2,
                        width: w,
                        height: h,
                        fill: '#f0f1f5',
                        radius: 4
                    },
                    name: 'node-rect'
                });
            },
            drawText(cfg, group) {
                // 保持与calcSize相同的截断逻辑
                const displayText =
                    cfg.label.length > 10 && cfg.depth !== 0
                        ? cfg.label.substr(0, 10) + '...'
                        : cfg.label;
                group.addShape('text', {
                    attrs: {
                        text: displayText,
                        x: 0,
                        y: 0,
                        fontSize: 12,
                        fill: '#3eaeff',
                        textAlign: 'center',
                        textBaseline: 'middle'
                    },
                    name: 'node-text'
                });
            },
            /**设置选中时的填充和文字颜色
             * @param name 状态名称 selected、hover
             * @param value 状态值 true为选中,false为未选中
             * @param item 节点实例对象
             */
            setState(name, value, item) {
                const group = item.get('group');
                ['node-rect', 'node-text'].forEach(key => {
                    const shape = group.find(e => e.get('name') === key);
                    if (shape)
                        shape.attr(
                            key.includes('text') ? 'fill' : 'fill',
                            value
                                ? key.includes('text')
                                    ? '#fff'
                                    : '#3eaeff'
                                : key.includes('text')
                                ? '#3eaeff'
                                : '#f0f1f5'
                        );
                });
            }
        });
    }

(3)点击节点事件实现选中效果和调取接口

    /**点击事件 */
    onClickNode() {
        this.graph.on('node:click', e => {
            const clickedNode = e.item;
            // 清除所有节点选中状态
            this.graph.getNodes().forEach(node => {
                if (node !== clickedNode) {
                    this.graph.setItemState(node, 'selected', false);
                }
            });
            this.graph.setItemState(clickedNode, 'selected', true);
            this.graphDataIfy.selectedNode = clickedNode;
            /**层级置于最顶层 */
            clickedNode.toFront();
           //...调接口
        });
    }

(4)设置超出文本10长度显示tootip文字提示

    /**设置tootip */
    onSetTooltip() {
        const tooltip = new G6.Tooltip({
            offsetX: 500, // 偏移量
            itemTypes: ['node'], // 仅节点生效
            container: this.orgElement.nativeElement,
            getContent: e => {
                return e.item.getModel().label; // 显示完整文本
            },
            shouldBegin: e => {
                const text = e.item.getModel().label;
                return text.length; // 仅超长文本触发
            }
        });
        return tooltip;
    }

三、最终效果图

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐