308 lines
8.6 KiB
Go
308 lines
8.6 KiB
Go
package svg
|
||
|
||
import (
|
||
"bytes"
|
||
"encoding/json"
|
||
"fmt"
|
||
"html/template"
|
||
"strings"
|
||
|
||
"go-common/app/admin/main/aegis/model/net"
|
||
"go-common/library/log"
|
||
)
|
||
|
||
var tpl = `
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>流程网描述图</title>
|
||
|
||
<script src="https://cdn.bootcss.com/viz.js/2.1.1/viz.js"></script>
|
||
<script src="https://cdn.bootcss.com/viz.js/2.1.1/full.render.js"></script>
|
||
|
||
<script>
|
||
var json={{.ActionDesc}};
|
||
var actions = {{.Actions}};
|
||
window.onload = function () {
|
||
for( let i =0; i<actions.length; i++){
|
||
document.getElementById(actions[i]).onclick = function(e){
|
||
var x = e.clientX;
|
||
var y = e.clientY;
|
||
|
||
var content = document.getElementById("content");
|
||
|
||
var table = '<table bgcolor="LightSteelBlue" border="1">'
|
||
var data = JSON.parse(json[actions[i]]);
|
||
for (var key in data){
|
||
table +='<tr>'
|
||
table+='<td>'+key+'</td>'
|
||
table+='<td>'+data[key]+'</td>'
|
||
table +='</tr>'
|
||
}
|
||
table += '</table>'
|
||
|
||
content.innerHTML = table;
|
||
content.style.left = x+"px";
|
||
content.style.top = y+"px";
|
||
content.style.position="absolute";
|
||
content.style.display = "block";
|
||
content.disabled = true
|
||
console.log(content);
|
||
}
|
||
};
|
||
};
|
||
</script>
|
||
</head>
|
||
<body>
|
||
<label id="content" background-color="red"></label>
|
||
<script>
|
||
var viz = new Viz();
|
||
|
||
viz.renderSVGElement('DotCode')
|
||
.then(function(element) {
|
||
document.body.appendChild(element);
|
||
})
|
||
.catch(error => {
|
||
// Create a new Viz instance (@see Caveats page for more info)
|
||
viz = new Viz();
|
||
|
||
// Possibly display the error
|
||
console.error(error);
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|
||
`
|
||
|
||
var (
|
||
_labelFlow = `%s [label="%s",shape=circle]`
|
||
_labelTransition = `%s [label="%s",shape=box,color=lightgrey,style=filled;]`
|
||
_labelToken = `%d [label="%s",shape=Mdiamond]`
|
||
_labelDirection = `%s->%s`
|
||
)
|
||
|
||
//NetView .
|
||
type NetView struct {
|
||
*template.Template
|
||
Dot *Dot
|
||
Data struct {
|
||
NetDesc string
|
||
DotCode string
|
||
Actions []string
|
||
ActionDesc map[string]string
|
||
}
|
||
}
|
||
|
||
//NewNetView .
|
||
func NewNetView() *NetView {
|
||
return &NetView{}
|
||
}
|
||
|
||
//SetDot .
|
||
func (nv *NetView) SetDot(dot *Dot) {
|
||
nv.Dot = dot
|
||
nv.Data.DotCode = dot.String()
|
||
nv.Data.Actions = append(dot.nodes[:], dot.edges...)
|
||
nv.Data.ActionDesc = dot.mapactions
|
||
|
||
ntpl := strings.Replace(tpl, "DotCode", nv.Data.DotCode, 1)
|
||
nv.Template = template.New("流程网概览")
|
||
nv.Template, _ = nv.Template.Parse(ntpl)
|
||
}
|
||
|
||
/*
|
||
节点用record表示,节点绑定的令牌用在同一个record里面
|
||
变迁用diamond表示,若变迁绑定了令牌,则用图包含变迁和令牌
|
||
*/
|
||
//Dot .
|
||
type Dot struct {
|
||
*bytes.Buffer
|
||
nodes []string
|
||
edges []string
|
||
mapactions map[string]string
|
||
flows map[int64]*net.Flow
|
||
trans map[int64]*net.Transition
|
||
dirs map[int64]*net.Direction
|
||
tokens map[string][]*net.TokenBindDetail
|
||
}
|
||
|
||
//NewDot .
|
||
func NewDot() *Dot {
|
||
d := &Dot{
|
||
mapactions: make(map[string]string),
|
||
flows: make(map[int64]*net.Flow),
|
||
trans: make(map[int64]*net.Transition),
|
||
dirs: make(map[int64]*net.Direction),
|
||
tokens: make(map[string][]*net.TokenBindDetail),
|
||
}
|
||
return d
|
||
}
|
||
|
||
//StartDot .
|
||
func (d *Dot) StartDot() *Dot {
|
||
d.Buffer = bytes.NewBufferString(`digraph net{rankdir=LR;`)
|
||
return d
|
||
}
|
||
|
||
//End .
|
||
func (d *Dot) End() string {
|
||
d.WriteString("}")
|
||
return d.String()
|
||
}
|
||
|
||
//AddTokenBinds .
|
||
func (d *Dot) AddTokenBinds(tbs ...*net.TokenBindDetail) *Dot {
|
||
for _, tb := range tbs {
|
||
key := fmt.Sprintf("%d_%d", tb.Type, tb.ElementID)
|
||
if tks, ok := d.tokens[key]; ok {
|
||
d.tokens[key] = append(tks, tb)
|
||
} else {
|
||
d.tokens[key] = []*net.TokenBindDetail{tb}
|
||
}
|
||
}
|
||
return d
|
||
}
|
||
|
||
//AddFlow .
|
||
func (d *Dot) AddFlow(flows ...*net.Flow) *Dot {
|
||
for _, flow := range flows {
|
||
d.flows[flow.ID] = flow
|
||
node := fmt.Sprintf(_labelFlow, flow.Name, flow.ChName)
|
||
//
|
||
nodeid := fmt.Sprintf("node%d", len(d.nodes)+1)
|
||
d.nodes = append(d.nodes, nodeid)
|
||
bs, _ := json.Marshal(flow)
|
||
d.mapactions[nodeid] = string(bs)
|
||
|
||
//便利token,查找绑定
|
||
if tks, ok := d.tokens[fmt.Sprintf("1_%d", flow.ID)]; ok {
|
||
d.WriteString("subgraph cluster_" + flow.Name + " {")
|
||
d.WriteString(node + ";")
|
||
for _, tk := range tks {
|
||
node := fmt.Sprintf(_labelToken, tk.ID, tk.ChName)
|
||
d.WriteString(node + ";")
|
||
nodeid := fmt.Sprintf("node%d", len(d.nodes)+1)
|
||
d.nodes = append(d.nodes, nodeid)
|
||
bs, _ := json.Marshal(tk)
|
||
d.mapactions[nodeid] = string(bs)
|
||
}
|
||
d.WriteString("}")
|
||
} else {
|
||
d.WriteString(node + ";")
|
||
}
|
||
}
|
||
return d
|
||
}
|
||
|
||
//AddTransitions .
|
||
func (d *Dot) AddTransitions(trans ...*net.Transition) *Dot {
|
||
for _, tran := range trans {
|
||
d.trans[tran.ID] = tran
|
||
node := fmt.Sprintf(_labelTransition, tran.Name, tran.ChName)
|
||
nodeid := fmt.Sprintf("node%d", len(d.nodes)+1)
|
||
d.nodes = append(d.nodes, nodeid)
|
||
bs, _ := json.Marshal(tran)
|
||
d.mapactions[nodeid] = string(bs)
|
||
|
||
//便利token,查找绑定
|
||
if tks, ok := d.tokens[fmt.Sprintf("2_%d", tran.ID)]; ok {
|
||
d.WriteString("subgraph cluster_" + tran.Name + " {")
|
||
d.WriteString(node + ";")
|
||
for _, tk := range tks {
|
||
node := fmt.Sprintf(_labelToken, tk.ID, tk.ChName)
|
||
d.WriteString(node + ";")
|
||
nodeid := fmt.Sprintf("node%d", len(d.nodes)+1)
|
||
d.nodes = append(d.nodes, nodeid)
|
||
bs, _ := json.Marshal(tk)
|
||
d.mapactions[nodeid] = string(bs)
|
||
}
|
||
d.WriteString("}")
|
||
} else {
|
||
d.WriteString(node + ";")
|
||
}
|
||
}
|
||
return d
|
||
}
|
||
|
||
//AddDirections .
|
||
func (d *Dot) AddDirections(dirs ...*net.Direction) *Dot {
|
||
for _, dir := range dirs {
|
||
var (
|
||
start, end string
|
||
flow *net.Flow
|
||
trans *net.Transition
|
||
)
|
||
|
||
flow = d.flows[dir.FlowID]
|
||
trans = d.trans[dir.TransitionID]
|
||
|
||
if flow == nil || trans == nil {
|
||
log.Error("invalid direction(%+v)", dir)
|
||
continue
|
||
}
|
||
|
||
if dir.Direction == 1 {
|
||
start, end = flow.Name, trans.Name
|
||
}
|
||
if dir.Direction == 2 {
|
||
start, end = trans.Name, flow.Name
|
||
}
|
||
|
||
edge := fmt.Sprintf(_labelDirection, start, end)
|
||
d.WriteString(edge + ";")
|
||
edgeid := fmt.Sprintf("edge%d", len(d.edges)+1)
|
||
bs, _ := json.Marshal(dir)
|
||
d.mapactions[edgeid] = string(bs)
|
||
d.edges = append(d.edges, edgeid)
|
||
}
|
||
return d
|
||
}
|
||
|
||
var (
|
||
flow1 = &net.Flow{ID: 1, ChName: "节点1", Name: "flow1"}
|
||
flow2 = &net.Flow{ID: 2, ChName: "节点2", Name: "flow2"}
|
||
flow3 = &net.Flow{ID: 3, ChName: "节点3", Name: "flow3"}
|
||
flow4 = &net.Flow{ID: 4, ChName: "节点4", Name: "flow4"}
|
||
flow5 = &net.Flow{ID: 5, ChName: "节点5", Name: "flow5"}
|
||
flow6 = &net.Flow{ID: 6, ChName: "节点6", Name: "flow6"}
|
||
flow7 = &net.Flow{ID: 7, ChName: "节点7", Name: "flow7"}
|
||
tran1 = &net.Transition{ID: 1, ChName: "变迁1", Name: "tran1"}
|
||
tran2 = &net.Transition{ID: 2, ChName: "变迁2", Name: "tran2"}
|
||
tran3 = &net.Transition{ID: 3, ChName: "变迁3", Name: "tran3"}
|
||
dir1 = &net.Direction{ID: 1, FlowID: 1, TransitionID: 1, Direction: 1}
|
||
dir2 = &net.Direction{ID: 2, FlowID: 2, TransitionID: 1, Direction: 2}
|
||
dir3 = &net.Direction{ID: 3, FlowID: 2, TransitionID: 2, Direction: 1}
|
||
dir4 = &net.Direction{ID: 4, FlowID: 2, TransitionID: 3, Direction: 1}
|
||
dir5 = &net.Direction{ID: 5, FlowID: 3, TransitionID: 2, Direction: 2}
|
||
dir6 = &net.Direction{ID: 6, FlowID: 4, TransitionID: 2, Direction: 2}
|
||
dir7 = &net.Direction{ID: 7, FlowID: 5, TransitionID: 3, Direction: 2}
|
||
dir8 = &net.Direction{ID: 8, FlowID: 6, TransitionID: 2, Direction: 2}
|
||
dir9 = &net.Direction{ID: 9, FlowID: 7, TransitionID: 3, Direction: 2}
|
||
|
||
tk1 = &net.TokenBindDetail{
|
||
ID: 1,
|
||
Type: 1,
|
||
ElementID: 1,
|
||
ChName: "待审核",
|
||
}
|
||
tk2 = &net.TokenBindDetail{
|
||
ID: 2,
|
||
Type: 2,
|
||
ElementID: 1,
|
||
ChName: "通过",
|
||
}
|
||
)
|
||
|
||
func DebugSVG() (nv *NetView) {
|
||
dot := NewDot()
|
||
dot.StartDot().AddTokenBinds(tk1, tk2).
|
||
AddFlow(flow1, flow2, flow3, flow4, flow5, flow6, flow7).
|
||
AddTransitions(tran1, tran2, tran3).
|
||
AddDirections(dir1, dir2, dir3, dir4, dir5, dir6, dir7, dir8, dir9).
|
||
End()
|
||
nv = NewNetView()
|
||
nv.SetDot(dot)
|
||
return nv
|
||
}
|