# metricflow
**Repository Path**: huoyo/metricflow
## Basic Information
- **Project Name**: metricflow
- **Description**: MetricFlow是一个前端画图的javascript库,可用于构建流程图、网络图、知识图谱展示等
- **Primary Language**: JavaScript
- **License**: LGPL-2.1
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 227
- **Forks**: 58
- **Created**: 2021-09-05
- **Last Updated**: 2025-07-02
## Categories & Tags
**Categories**: charting-components
**Tags**: None
## README
# MetricFlow.js
[别拦我,我要支持作者](https://afdian.net/a/huoyo)
---
MetricFlow是一个前端画图的javascript库,可用于构建可拖拽、可灵活定义的流程图、网络图、知识图谱展示等
> python版本请移步[ndraw](https://gitee.com/huoyo/ndraw.git)
> 作者注:此项目是应用户要求从隔壁的[KoTime](https://gitee.com/huoyo/ko-time.git)家中抠出来的,我以为他们喜欢的是我的私生子KoTime,没想到只是问我要它脸上的BB霜,不知道是该难过还是该开心,因为都是我写的!
>
> 另外本人是后端,基本上不写前端,如果有什么bug请issue我(不可以骂我),如果喜欢本项目,可以给我Star,这样我应该有动力继续优化!
## 展示
[参考demo6.html](demo/demo6.html)

[参考demo15.html](demo/demo15.html)

[参考demo8.html](demo/demo8.html)

### 快速上手
#### 0.引入
* 原生引入
[下载](https://gitee.com/huoyo/metricflow/releases) 发行版本
```html
```
* npm安装
>npm install metricflow
```html
let MetricFlow = require("metricflow")
```
#### 1. 创建画布
创建画布只需要定义`div`标签即可,并声明画布的`width`和`height`
```html
```
#### 2. 创建节点
```javascript
/*在画布上创建图*/
let metricFlow = MetricFlow("graph")
/*定义节点数据*/
let nodeData= {
"id":"primaryKey",//id在全局中不能重复,否则会被覆盖
"title":{'name':"运行时间统计"},
"data":[
{'name':'方法:IndexController#method1'},
{'name':'平均耗时:0.333ms'},
]
};
/*在(20,200)坐标上创建一个节点*/
let node1 = metricFlow.createNode(nodeData,10,200);
/*或者直接在nodeData中定义位置x和y属性,然后*/
/*metricFlow.createNode(nodeData);*/
```
[创建节点demo1.html](demo/demo1.html)

#### 3. 创建连线
```javascript
let metricFlow = MetricFlow("graph")
let node1Data= {
"x":10,
"y":200,
"id":"node1",
"title":{'name':"运行时间统计"},
"data":[
{'name':'方法:IndexController#method1'},
{'name':'平均耗时:0.333ms'},
]
};
let node1 = metricFlow.createNode(node1Data);
let node2Data= {
"x":300,
"y":200,
"id":"node2",
"title":{'name':"运行时间统计"},
"data":[
{'name':'方法:IndexController#method1'},
{'name':'平均耗时:0.333ms'},
]
};
let node2 = metricFlow.createNode(node2Data);
/*连接两个节点 连线的起始位置在哪个位置无需关心,会自动判断 比如目标节点在
起始节点下方 那么连线从起始节点的下方开始到目标接线的上方位置
*/
metricFlow.createLink(node1,node2);
```
或者直接在末尾节点中指定`from`属性,无需`metricFlow.createLink(node1,node2);`
```javascript
let metricFlow = MetricFlow("graph")
let node1Data= {
"x":10,
"y":200,
"id":"node1",
"title":{'name':"运行时间统计"},
"data":[]
};
let node1 = metricFlow.createNode(node1Data);
let node2Data= {
"x":300,
"y":200,
"id":"node2",
"from":"node1",//from的值可以是string 也可以是数组
"title":{'name':"运行时间统计"},
"data":[]
};
let node2 = metricFlow.createNode(node2Data);
```
[创建连线demo(两个节点)-demo2.html](demo/demo2.html)

[创建连线demo(三个节点)-demo3.html](demo/demo3.html)

#### 4. 批量创建节点
批量创建节点有两种方式,第一种使用list创建,并在每个节点数据中指定`from`属性即可创建关系:
```javascript
let metricFlow = MetricFlow("graph")
/*定义节点数据*/
let node1Data= {
"x":20,
"y":200,
"id":"node1",
"title":{'name':"节点1"}
};
let node2Data= {
"x":300,
"y":50,
"id":"node2",
"from":"node1",
"title":{'name':"节点2"}
};
let node3Data= {
"x":300,
"y":300,
"id":"node3",
"from":"node1",
"title":{'name':"节点3"}
};
let node4Data= {
"x":500,
"y":200,
"id":"node4",
"from":['node2','node3'],
"title":{'name':"节点3"},
"data":[
{'name':"1.xxxx"},
{'name':"2.xxxx"},
]
};
let nodes = [node1Data,node2Data,node3Data,node4Data];
metricFlow.createNodes(nodes);
```
[批量创建节点-demo7.html](demo/demo7.html)


第二种使用children属性创建,根节点的x和y需指定,其余子节点默认会自动向右排列
```javascript
let nodes= {
"x":20,
"y":200,
...
"children":[
{
"id":"node3",
...
"children":[
{...}
]
},
]
};
metricFlow.createNodes(nodes);
```
[批量创建节点-demo9.html](demo/demo9.html)

自动创建的时候如果节点间距不合适,可调整
```javascript
let options = {
'node-distance-offsetx':5,//左右间距+5
'node-distance-offsety':-5//上下间距-5
};
let metricFlow = MetricFlow("graph",options)
```
如果需要自动向下排列,可调整
```javascript
let options = {
"flow":"vertical" //horizontal水平排列 vertical垂直排列
};
let metricFlow = MetricFlow("graph",options)
```
[垂直排列-demo12.html](demo/demo12.html)
自动创建的时候如果数据格式不匹配,又不想遍历处理,可传入函数调整
```javascript
function format(data){
data['title'] = {'name':"更改title的名字"};
return data;
}
metricFlow.createNodes(nodes,format);
```
[批量创建节点-demo9.html](demo/demo9.html)
### 样式定义
#### 1. 更改节点样式
在节点上添加`style`属性即可
```javascript
let node2Data= {
"id":"node2",
"style":{
"node-type": "circle",//节点类型{metric,circle,rectangle} 默认为metric v1.1.4新增
'node-width':'3px',//节点宽度 默认自适应,指定以后可固定 v1.1.3增加
'node-height':'3px',//节点高度 默认自适应,指定以后可固定 v1.1.3增加
'border-width':'3px',//边框厚度 v1.1.3增加
'border-color':'black',//边框颜色
'title-color':'black',//标题背景颜色
'title-font-color':'white',//标题字体颜色
'title-font-size':'13px',//标题字体大小
'data-color':'white',//数据背景颜色
'data-font-size':'13px',//数据字体大小
'data-font-color':'red',//数据字体颜色
},
"title":{'name':"运行时间统计"},
"data":[
{'name':'方法:IndexController#method1'},
{'name':'平均耗时:0.333ms'},
]
};
```
[样式定义demo-demo8.html](demo/demo8.html)
单个节点添加不方便可以批量
```javascript
metricFlow.createNodes(nodeList,addColors);
function addColors(data) {
data['style'] = {
'border-color':'black',//边框颜色
'title-color':'black',//标题背景颜色
'title-font-color':'white',//标题字体颜色
'title-font-size':'13px',//标题字体大小
'data-color':'white',//数据背景颜色
'data-font-size':'13px',//数据字体大小
'data-font-color':'red',//数据字体颜色
}
return data
}
```
[样式定义demo-demo7.html](demo/demo7.html)
### 连线配置
连线位置目前仅支持偏移量定义,可在创建`MetricFlow`时定义
连线分为起始点和终点,可设置全局的起始点的偏移位置,主要考虑前端框架使用较为复杂时css冲突所导致位置偏移的校正
```javascript
let options = {
'link-start-offsetx':1,//起始点向右偏移一个单位
'link-start-offsety':-1,//起始点向上偏移一个单位
'link-end-offsetx':-1,
'link-end-offsety':-1,
'link-width-offset':-1,//线段粗细减小1个单位
'link-color':"blue", //更改线段颜色
'node-distance-offsetx': -55,//自动向右排列时 两节点之间距离-55
'node-distance-offsety': -55,//自动向下排列时 两节点之间距离-55
};
let metricFlow = MetricFlow("graph",options)
```
[连线位置demo-demo5.html](demo/demo5.html)
### 禁止拖拽
```javascript
let options = {
'drag':false
};
let metricFlow = MetricFlow("graph",options)
```
### 节点事件
支持基本的鼠标事件,如`click`、`dblclick`、`mousedown`、`mouseup`等,与原生js一致,事件在对应节点身上配置即可:
```javascript
let node1Data= {
"id":"primaryKey",
"title":{'name':"双击"},
'click':"sinclick", //单击 sinclick为函数名
'dblclick':"doubleClick",//双击
"data":[
{'name':'方法:IndexController#method1'},
{'name':'平均耗时:0.333ms'},
]
};
```
[节点事件demo-demo11.html](demo/demo11.html)
[节点事件demo-demo14.html](demo/demo14.html)
### 主要api参考
```
创建节点:createNode(param, x, y)
批量创建节点:createNodes(params)
创建连接:createLink(sourceDom, targetDom)
清除所有节点:clearAll()
切换拖拽状态:switchDrag()
绑定连线事件:bindLinkEvent(startNodeId,endNodeId,eventName,funcName)
绑定节点事件:bindNodeEvent(nodeId,eventName,funcName)
根据节点事件获取节点id:getNodeId(e)
获取节点位置:getNodeXy(nodeId)
获取节点信息:getNodeInfo(nodeId)
设置节点颜色:setColor(nodeId,titleColor,borderColor)
设置连线颜色:setLinkColor(startNodeId,endNodeId,color)
设置标题:setTitle(nodeId,title)
清除连线:removeLink(startNodeId,endNodeId)
伸缩宽度(在原始基础上):stretchWidth(nodeId,nodeWidth)
```
## 版本说明
> V1.0.0:创建节点;连线;样式定义;鼠标事件
>
> V1.0.1:新增自动向下布局
## 版权说明
> 1.本项目版权属作者所有,并使用 LGPL-2.1进行开源;
>
> 2.您可以使用本项目进行学习,并且免费将本项目作为第三方库引入后闭源或者商用;
>
> 3.但不允许将本项目二次开发后后商用(除非得到作者授权);
>
> 4.其他内容请参考LGPL-2.1