123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- 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
- }
|