如何在小程序上绘制树状图

5,685 阅读4分钟

前言

现有的移动端图可视化技术有Antv旗下的F2、F6。F2主要专注于数据分析的统计图,而F6专注与各种场景的关系图。两者各有侧重。F6 是一个简单、易用、完备的移动端图可视化引擎,它在高定制能力的基础上,提供了一系列设计优雅、便于使用的图可视化解决方案。能帮助开发者搭建属于自己的图可视化、图分析、或图编辑器应用。如果您希望将内容通过流程图、知识图谱、思维导图等形式进行输出,并希望可以方便的实现对图的操控,那么建议您一定要尝试一下F6。

欢迎star和提交issue

github.com/antvis/F6

什么是树图?

树图,表现形式如下,

具体原理可以参考 emr.cs.iit.edu/~reingold/t… ,由根节点不断的派生,形成一个树状结构,是一种可以很好表达层级关系的可视化方法。 举个例子: Kapture 2021-09-22 at 23.40.34.gif

什么场景下使用

名称应用
分解树在人口调查中,将人口样本分解为人口统计信息
关键质量特性树将顾客的需求转化为产品的可测量参数和过程特性
决策树或逻辑图绘制出思维过程以便于决策
树干图在产品的设计和开发阶段,用于识别产品的特性
故障树分析识别故障的潜在原因
装配图在制造过程中,描绘产品零部件的装配
方法-方法图解决问题
工作或任务分析识别一项工作或任务的要求
组织图识别管理和汇报间的关联水平
过程决策程序图确定潜在的问题和复杂计划中的对策
需求测量树确定顾客、需求以及对测量产品或服务的测量
原因一原因图或five whys识别问题的根本原因
生产分类结构(WBS)识别项目的所有方面,分解成具体工作包水平

可见树图在实际场景中有很多应用,不论是在日常生活中,还是在生产中都有多种用途。我们最熟悉的脑图(mind map)也是树图的一种形式,

F6中如何绘制

演示示例可以参考f6.antv.vision/zh/docs/exa… 本节代码已经开源,感兴趣可以查看

支付宝中

首先安装

npm install @antv/f6 @antv/f6-alipay -S

index.json

{
  "defaultTitle": "紧凑树",
  "usingComponents": {
    "f6-canvas": "@antv/f6-alipay/es/container/container"
  }
}

index.js

import F6 from '@antv/f6';
import TreeGraph from '@antv/f6/dist/extends/graph/treeGraph';

import data from './data.js';

/**
 * 紧凑树
 */

Page({
  canvas: null,
  ctx: null, // 延迟获取的2d context
  renderer: '', // mini、mini-native等,F6需要,标记环境
  isCanvasInit: false, // canvas是否准备好了
  graph: null,

  data: {
    width: 375,
    height: 600,
    pixelRatio: 2,
    forceMini: false,
  },

  onLoad() {
    // 注册自定义树,节点等
    F6.registerGraph('TreeGraph', TreeGraph);

    // 同步获取window的宽高
    const { windowWidth, windowHeight, pixelRatio } = my.getSystemInfoSync();

    this.setData({
      width: windowWidth,
      height: windowHeight,
      pixelRatio,
    });
  },

  /**
   * 初始化canvas回调,缓存获得的context
   * @param {*} ctx 绘图context
   * @param {*} rect 宽高信息
   * @param {*} canvas canvas对象,在render为mini时为null
   * @param {*} renderer 使用canvas 1.0还是canvas 2.0,mini | mini-native
   */
  handleInit(ctx, rect, canvas, renderer) {
    this.isCanvasInit = true;
    this.ctx = ctx;
    this.renderer = renderer;
    this.canvas = canvas;
    this.updateChart();
  },

  /**
   * canvas派发的事件,转派给graph实例
   */
  handleTouch(e) {
    this.graph && this.graph.emitEvent(e);
  },

  updateChart() {
    const { width, height, pixelRatio } = this.data;

    // 创建F6实例
    this.graph = new F6.TreeGraph({
      context: this.ctx,
      renderer: this.renderer,
      width,
      height,
      pixelRatio,
      fitView: true,
      modes: {
        default: [
          {
            type: 'collapse-expand',
            onChange: function onChange(item, collapsed) {
              const model = item.getModel();
              model.collapsed = collapsed;
              return true;
            },
          },
          'drag-canvas',
          'zoom-canvas',
        ],
      },
      defaultNode: {
        size: 26,
        anchorPoints: [
          [0, 0.5],
          [1, 0.5],
        ],
      },
      defaultEdge: {
        type: 'cubic-horizontal',
      },
      layout: {
        type: 'compactBox',
        direction: 'LR',
        getId: function getId(d) {
          return d.id;
        },
        getHeight: function getHeight() {
          return 16;
        },
        getWidth: function getWidth() {
          return 16;
        },
        getVGap: function getVGap() {
          return 10;
        },
        getHGap: function getHGap() {
          return 100;
        },
      },
    });

    this.graph.node(function(node) {
      return {
        label: node.id,
        labelCfg: {
          offset: 10,
          position: node.children && node.children.length > 0 ? 'left' : 'right',
        },
      };
    });

    this.graph.data(data);
    this.graph.render();
    this.graph.fitView();
  },
});

index.axml

<f6-canvas
  width="{{width}}"
  height="{{height}}"
  forceMini="{{forceMini}}"
  pixelRatio="{{pixelRatio}}"
  onTouchEvent="handleTouch"
  onInit="handleInit"
></f6-canvas>

微信中

首先安装

npm install @antv/f6-wx -S

@antv/f6-wx 由于微信对npm包不是很友好,所以我们封装了 @antv/f6-wx 帮助用户简化操作。 ​

index.json

{
  "defaultTitle": "紧凑树",
  "usingComponents": {
    "f6-canvas": "@antv/f6-wx/canvas/canvas"
  }
}

index.wxml

<f6-canvas
  width="{{width}}"
  height="{{height}}"
  forceMini="{{forceMini}}"
  pixelRatio="{{pixelRatio}}"
  bind:onTouchEvent="handleTouch"
  bind:onInit="handleInit"
></f6-canvas>

index.js

import F6 from '@antv/f6-wx';
import TreeGraph from '@antv/f6-wx/extends/graph/treeGraph';

import data from './data.js';
Page({
  canvas: null,
  ctx: null, // 延迟获取的2d context
  renderer: '', // mini、mini-native等,F6需要,标记环境
  isCanvasInit: false, // canvas是否准备好了
  graph: null,

  data: {
    width: 375,
    height: 600,
    pixelRatio: 2,
    forceMini: false,
  },

  onLoad() {
    // 注册自定义树,节点等
    F6.registerGraph('TreeGraph', TreeGraph);
    // 同步获取window的宽高
    const { windowWidth, windowHeight, pixelRatio } = wx.getSystemInfoSync();

    this.setData({
      width: windowWidth * pixelRatio,
      height: windowHeight * pixelRatio,
      pixelRatio,
    });
  },

  /**
   * 初始化canvas回调,缓存获得的context
   * @param {*} ctx 绘图context
   * @param {*} rect 宽高信息
   * @param {*} canvas canvas对象,在render为mini时为null
   * @param {*} renderer 使用canvas 1.0还是canvas 2.0,mini | mini-native
   */
  handleInit(event) {
    const { ctx, rect, canvas, renderer } = event.detail;
    this.isCanvasInit = true;
    this.ctx = ctx;
    this.renderer = renderer;
    this.canvas = canvas;
    this.updateChart();
  },

  /**
   * canvas派发的事件,转派给graph实例
   */
  handleTouch(e) {
    this.graph && this.graph.emitEvent(e.detail);
  },

  updateChart() {
    const { width, height, pixelRatio } = this.data;

    // 创建F6实例
    this.graph = new F6.TreeGraph({
      context: this.ctx,
      renderer: this.renderer,
      width,
      height,
      pixelRatio,
      fitView: true,
      modes: {
        default: [
          {
            type: 'collapse-expand', // 点击后展开/收缩
            onChange: function onChange(item, collapsed) {
              const model = item.getModel();
              model.collapsed = collapsed;
              return true;
            },
          },
          'drag-canvas',
          'zoom-canvas',
        ],
      },
      defaultNode: {
        size: 26,
        anchorPoints: [
          [0, 0.5],
          [1, 0.5],
        ],
      },
      defaultEdge: {
        type: 'cubic-horizontal',
      },
      layout: {
        type: 'compactBox',
        direction: 'LR',
        getId: function getId(d) {
          return d.id;
        },
        getHeight: function getHeight() {
          return 16;
        },
        getWidth: function getWidth() {
          return 16;
        },
        getVGap: function getVGap() {
          return 10;
        },
        getHGap: function getHGap() {
          return 100;
        },
      },
    });

    this.graph.node(function(node) {
      return {
        label: node.id,
        labelCfg: {
          offset: 10,
          position: node.children && node.children.length > 0 ? 'left' : 'right',
        },
      };
    });

    this.graph.data(data);
    this.graph.render();
    this.graph.fitView();
  },
});

要点回顾

欢迎加入我们

欢迎star和提交issue

github.com/antvis/F6

对于树图,或者图可视化感兴趣,可以添加我的微信 openwayne 进入我们的微信群。