- 前言
近期有一个项目需求,需要在使用uniapp在小程序端进行树状图的绘制,并且能够点击跳转。 需求并不难,在掘金也很快找到了对应的框架——antv-F6)。 如何在小程序绘制树状图
这篇文章已经把小程序的使用示例说得很清楚了,且文章末尾附上了gitbub地址及文档地址,虽然没在文章中写出来,但能找到对应的uniapp示例 uniapp示例(antv-F6) antv-F6文档
下面是我在uniapp中参考官方示例项目进行引入的参考。
1、到antv-F6的uniapp示例中下载如图两个文件夹,分别为示例组件canvas和antv-F6的源码
2、在自己的uniapp项目中,创建components文件夹,粘贴所下载的源码,可删除.map文件
3、创建页面,在页面中引入和使用 关于所需样式的问题,可以查看antv-F6的文档,建议先选择好想要的图的类型,再进行样式和交互的调整。树状图要比普通的图多引入一个treeGraph,文档里没有示例,要自己注意下。 如果有一些不明白的且实在找不到的样式属性,不妨参考下G6的文档(我就是这么干的😭)。
效果图:
页面示例代码如下:
<template>
<f6-canvas :width="width" :height="height" :pixelRatio="pixelRatio" @onInit="onCanvasInit" @onTouchEvent="onTouchEvent"/>
</template>
<script>
import F6Canvas from '@/components/antv-F6/canvas/canvas.vue';
import F6 from '@/components/antv-F6/f6';
import TreeGraph from '@/components/antv-F6/f6/extends/graph/treeGraph';
export default {
name: "chainTree",
props: {},
components: {
'f6-canvas': F6Canvas,
},
created() {
F6.registerGraph('TreeGraph', TreeGraph);
},
methods: {
//打开产业选择框
openSelect() {
this.show = true
},
//产业选择框确认事件
confirm(e) {
this.show = false
this.selectValue = e.value[0].label
},
onTouchEvent(e) {
this.graph && this.graph.emitEvent(e);
},
onCanvasInit({
ctx,
rect,
container,
renderer
}) {
// console.log('canvas init ready', ctx, rect, container, renderer);
const {
width,
height,
pixelRatio
} = this;
this.graph = new F6.TreeGraph({
container: container,
context: ctx,
renderer,
width,
height,
pixelRatio,
fitView: true,
layout: {
type: 'compactBox',
direction: 'TB', // H / V / LR / RL / TB / BT
getId: function getId(d) {
return d.id;
},
getHeight: function getHeight() {
return 85;
},
getWidth: function getWidth() {
return 50;
},
//每个节点的垂直间隙
getVGap: function getVGap() {
return 10;
},
//每个节点的水平间隙
getHGap: function getHGap() {
return 16;
},
},
//统一配置节点样式
defaultNode: {
type: 'rect',
//矩形宽高
size: [75, 40],
style: {
fill: '#fff',
// lineWidth: 1,
stroke: '#fff',
radius: 10
},
//节点连接点样式
linkPoints: {
top: true,
fill: '#fff',
stroke: '#364c6b'
},
},
//边样式
defaultEdge: {
style: {
stroke: '#364c6b',
lineWidth: 1,
}
},
nodeStateStyles: {
//被选择节点样式
tap: {
fill: '#25b3f9',
lineWidth: 0,
'text-shape': {
fill: "#ffffff"
}
},
},
modes: {
default: ['drag-canvas', 'zoom-canvas']
},
});
const anchorPoints = [
[0.5, 0],
[0.5, 1]
]
const data = {
id: 'node-main', // String,该节点存在则必须,节点的唯一标识
size: [120, 30],
x: 150, // Number,可选,节点位置的 x 值
y: 200, // Number,可选,节点位置的 y 值
type: 'rect',
label: '光电子信息',
anchorPoints: anchorPoints,
style: {
stroke: '#e2e2e2',
lineWidth: 2
},
labelCfg: {
style: {
fontWeight: 500,
fontSize: 16,
},
},
linkPoints: {
top: false,
bottom: true
},
children: [{
id: 'node1-1', // String,该节点存在则必须,节点的唯一标识
label: '数据驱动',
anchorPoints: anchorPoints,
children: [{
id: 'node1-2',
label: '网络化',
anchorPoints: anchorPoints,
children: [{
id: 'node1-3',
label: '电话通信网',
anchorPoints: anchorPoints
},
],
},
],
},
{
id: 'node2-1',
label: '支撑要素',
anchorPoints: anchorPoints,
children: [{
id: 'node2-2',
label: '数字化',
anchorPoints: anchorPoints,
},
],
},
],
};
const graph = this.graph
graph.data(data);
graph.render();
graph.on('node:tap', (evt) => {
const node = evt.item;
const hasActived = node._cfg.states.length;
// 当节点没有被点击过时
if (hasActived == 0) {
// 激活该节点的 tap状态
graph.setItemState(node, 'tap', true);
//点击后跳转,根节点不跳转
if (node._cfg.id != "node-main") {
setTimeout(() => {
graph.setItemState(node, 'tap', false);
}, 500)
}
} else {
graph.setItemState(node, 'tap', false);
}
});
graph.fitView();
}
},
}
</script>