-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathgraph.go
More file actions
101 lines (86 loc) · 2.42 KB
/
Copy pathgraph.go
File metadata and controls
101 lines (86 loc) · 2.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package multistate
import (
"bytes"
"crypto/md5"
"encoding/binary"
"fmt"
"math"
"os"
"os/exec"
"runtime"
"strconv"
"github.com/tmc/dot"
)
func (m *Multistate) GetGraphSVG() string {
g := dot.NewGraph("Multistate")
nodes := map[uint64]*dot.Node{}
clusters := map[uint8]*dot.SubGraph{}
for _, cluster := range m.clusters {
c := dot.NewSubgraph(fmt.Sprintf("cluster_%d", cluster.id))
_ = c.Set("label", cluster.name)
clusters[cluster.id] = c
g.AddSubgraph(c)
}
for state := range m.statesActions {
var strFlags string
for i, flag := range m.GetStateFlags(state) {
if i > 0 {
strFlags += "<BR/>"
}
strFlags += fmt.Sprintf("<I>[% 2d]</I> %s", flag.Bit, flag.Caption)
}
if strFlags == "" {
strFlags = m.emptyStateName
}
if strFlags == "" {
strFlags = "EMPTY"
}
hs := md5.New()
_ = binary.Write(hs, binary.LittleEndian, state)
digestBuf := bytes.NewBuffer(hs.Sum(nil))
var c1, c2 uint32
_ = binary.Read(digestBuf, binary.LittleEndian, &c1)
_ = binary.Read(digestBuf, binary.LittleEndian, &c2)
color := fmt.Sprintf("%f %f %f", float64(c1)/float64(math.MaxUint32),
float64(c2)/float64(math.MaxUint32),
0.7)
n := dot.NewNode(strconv.FormatUint(state, 16))
_ = n.Set("shape", "plaintext")
_ = n.Set("label", fmt.Sprintf(`<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"><TR><TD><B>%d</B></TD><TD>%s</TD></TR></TABLE>>`, state, strFlags))
_ = n.Set("color", color)
_ = n.Set("fontcolor", color)
if c := m.stateClusterMap[state]; c != nil {
clusters[c.id].AddNode(n)
} else {
g.AddNode(n)
}
nodes[state] = n
}
for from, actions := range m.statesActions {
for action, to := range actions {
e := dot.NewEdge(nodes[from], nodes[to])
if m.actionsMap[action].availabler != nil {
_ = e.Set("label", fmt.Sprintf("%s\n(%s[%s])", m.actionsMap[action].caption, action, m.actionsMap[action].availabler.String()))
} else {
_ = e.Set("label", fmt.Sprintf("%s\n(%s)", m.actionsMap[action].caption, action))
}
color := nodes[from].Get("color")
_ = e.Set("color", color)
_ = e.Set("fontcolor", color)
g.AddEdge(e)
}
}
outBuf := &bytes.Buffer{}
pathToDot := "/usr/bin/dot"
if runtime.GOOS == "darwin" {
pathToDot = "/usr/local/bin/dot"
}
cmd := exec.Command(pathToDot, "-Tsvg")
cmd.Stdin = bytes.NewBuffer([]byte(g.String()))
cmd.Stdout = outBuf
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
panic(err)
}
return outBuf.String()
}