~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/ajstarks/svgo/rr/rr.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// radar roadmap (via Ernst and Young)
 
2
package main
 
3
 
 
4
import (
 
5
        "encoding/xml"
 
6
        "flag"
 
7
        "fmt"
 
8
        "github.com/ajstarks/svgo"
 
9
        "io"
 
10
        "math"
 
11
        "os"
 
12
        "strings"
 
13
)
 
14
 
 
15
var (
 
16
        width, height, iscale, fontsize, margin int
 
17
        bgcolor, itemcolor, title               string
 
18
        opacity                                 float64
 
19
        showtitle                               bool
 
20
        gstyle                                  = "font-family:Calibri;font-size:%dpx;text-anchor:middle"
 
21
        canvas                                  = svg.New(os.Stdout)
 
22
)
 
23
 
 
24
// Roadmap XML structure:
 
25
// a roadmap consists of sections, which contain items, which indicate maturity and impact
 
26
type Roadmap struct {
 
27
        Title    string    `xml:"title,attr"`
 
28
        Duration int       `xml:"duration,attr"`
 
29
        Unit     string    `xml:"unit,attr"`
 
30
        Section  []section `xml:"section"`
 
31
}
 
32
 
 
33
type section struct {
 
34
        Name    string  `xml:"name,attr"`
 
35
        Spacing float64 `xml:"spacing,attr"`
 
36
        Item    []item  `xml:"item"`
 
37
}
 
38
 
 
39
type item struct {
 
40
        Impact int     `xml:"impact,attr"`
 
41
        Effort int     `xml:"effort,attr"`
 
42
        Begin  string  `xml:"begin,attr"`
 
43
        Age    float64 `xml:"age,attr"`
 
44
        Name   string  `xml:",chardata"`
 
45
        Desc   desc    `xml:"desc"`
 
46
}
 
47
 
 
48
type desc struct {
 
49
        Description string `xml:",chardata"`
 
50
}
 
51
 
 
52
// dorr does file i/o
 
53
func dorr(location string) {
 
54
        var f *os.File
 
55
        var err error
 
56
        if len(location) > 0 {
 
57
                f, err = os.Open(location)
 
58
        } else {
 
59
                f = os.Stdin
 
60
        }
 
61
        if err == nil {
 
62
                readrr(f)
 
63
                f.Close()
 
64
        } else {
 
65
                fmt.Fprintf(os.Stderr, "%v\n", err)
 
66
        }
 
67
}
 
68
 
 
69
// readrr reads and parses the XML specification
 
70
func readrr(r io.Reader) {
 
71
        var rm Roadmap
 
72
        if err := xml.NewDecoder(r).Decode(&rm); err == nil {
 
73
                drawrr(rm)
 
74
        } else {
 
75
                fmt.Fprintf(os.Stderr, "%v\n", err)
 
76
        }
 
77
}
 
78
 
 
79
// drawrr draws the roadmap
 
80
func drawrr(rm Roadmap) {
 
81
 
 
82
        if len(rm.Title) > 0 {
 
83
                title = rm.Title
 
84
        }
 
85
        canvas.Title(title)
 
86
        canvas.Gstyle(fmt.Sprintf(gstyle, fontsize))
 
87
        canvas.Rect(0, 0, width, height, "fill:"+bgcolor)
 
88
        duration := rm.Duration
 
89
        if duration <= 0 {
 
90
                duration = 3
 
91
        }
 
92
        ns := len(rm.Section)
 
93
        cx := (width / 2)
 
94
        cy := (height / 2)
 
95
        r := ((width - margin) / duration) / 2
 
96
        sr := r
 
97
        midsize := width / 100
 
98
 
 
99
        // for each unit of time, draw cencentric circles
 
100
        for i := 0; i < duration; i++ {
 
101
                canvas.Circle(cx, cy, sr, "fill:none;stroke:lightgray;stroke-dasharray:7,7")
 
102
                canvas.Text(cx, (cy - sr), fmt.Sprintf("%s %d", rm.Unit, i+1), "font-size:150%;fill:gray")
 
103
                sr += r
 
104
        }
 
105
        // for each section, define its boundaries and draw its label
 
106
        angle := 360.0 / float64(ns)
 
107
        a := angle
 
108
        a2 := a / 2
 
109
        for _, s := range rm.Section {
 
110
                drawseclines(cx, cy, float64(r*duration), a, a2, s.Name)
 
111
                spacing := s.Spacing
 
112
                if spacing == 0 {
 
113
                        spacing = (angle / float64(len(s.Item))) - 1
 
114
                }
 
115
                iangle := a + spacing
 
116
                // for each item in the section, place the marker and label
 
117
                for _, i := range s.Item {
 
118
                        itemx, itemy := dpolar(cx, cy, i.Age*float64(r), iangle)
 
119
                        drawitem(itemx, itemy, i.Impact*iscale, i.Effort, i.Name)
 
120
                        iangle += spacing
 
121
                }
 
122
                a += angle
 
123
        }
 
124
 
 
125
        canvas.Circle(cx, cy, midsize, "fill:red")
 
126
        canvas.Text(cx, cy, "READY", "baseline-shift:-25%")
 
127
        if showtitle {
 
128
                dotitle(title)
 
129
        }
 
130
        canvas.Gend()
 
131
}
 
132
 
 
133
// radians converts degrees to radians
 
134
func radians(d float64) float64 {
 
135
        return d * (math.Pi / 180.0)
 
136
}
 
137
 
 
138
// dotitle places the title text
 
139
func dotitle(s string) {
 
140
        canvas.Text(width/2, height-10, s, "font-size:200%;text-anchor:middle")
 
141
}
 
142
 
 
143
// dpolar returns the cartesion coordinates given the center, size, and angle (in degrees)
 
144
func dpolar(cx, cy int, r, d float64) (int, int) {
 
145
        x := r * math.Cos(radians(d))
 
146
        y := r * math.Sin(radians(d))
 
147
        return cx + int(x), cy + int(y)
 
148
}
 
149
 
 
150
// drawseclines defines and labels the sections
 
151
func drawseclines(cx, cy int, size, a, h float64, s string) {
 
152
        fs := fontsize + (fontsize / 2)
 
153
        ix, iy := dpolar(cx, cy, size, a)
 
154
        ix2, iy2 := dpolar(cx, cy, size+50, a+h)
 
155
        canvas.Line(cx, cy, ix, iy, "stroke:lightgray")
 
156
        textlines(ix2, iy2, fs, fs+2, "middle", "black", strings.Split(s, "\\n"))
 
157
}
 
158
 
 
159
// drawitem draws a roadmap item
 
160
func drawitem(x, y, isize, ieffort int, s string) {
 
161
        var op float64
 
162
        if ieffort > 0 {
 
163
                op = opacity * (float64(ieffort) / 10.0)
 
164
        } else {
 
165
                op = opacity
 
166
        }
 
167
        style := fmt.Sprintf("fill:%s;fill-opacity:%.2f;stroke:white", itemcolor, op)
 
168
        canvas.Circle(x, y, isize/2, style)
 
169
        textlines(x-(isize/2)-2, y, fontsize, fontsize+2, "end", "black", strings.Split(s, "\\n"))
 
170
}
 
171
 
 
172
// textlines displays text at a specified size, leading, fill, and alignment
 
173
func textlines(x, y, fs, leading int, align, fill string, s []string) {
 
174
        canvas.Gstyle(fmt.Sprintf("font-size:%dpx;text-anchor:%s;fill:%s", fs, align, fill))
 
175
        for _, v := range s {
 
176
                canvas.Text(x, y, v)
 
177
                y += leading
 
178
        }
 
179
        canvas.Gend()
 
180
}
 
181
 
 
182
// init sets up the command flags
 
183
func init() {
 
184
        flag.StringVar(&bgcolor, "bg", "white", "background color")
 
185
        flag.StringVar(&itemcolor, "ic", "rgb(131,206,226)", "item color")
 
186
        flag.IntVar(&width, "w", 800, "width")
 
187
        flag.IntVar(&height, "h", 800, "height")
 
188
        flag.IntVar(&fontsize, "f", 12, "fontsize (px)")
 
189
        flag.IntVar(&iscale, "s", int(float64(width)*.009), "impact scale")
 
190
        flag.IntVar(&margin, "m", 150, "outside margin")
 
191
        flag.BoolVar(&showtitle, "showtitle", false, "show title")
 
192
        flag.StringVar(&title, "t", "Roadmap", "title")
 
193
        flag.Float64Var(&opacity, "o", 1.0, "opacity")
 
194
        flag.Parse()
 
195
}
 
196
 
 
197
// for every input file (or stdin), draw a roadmap as specified by command flags
 
198
func main() {
 
199
        canvas.Start(width, height)
 
200
        if len(flag.Args()) == 0 {
 
201
                dorr("")
 
202
        } else {
 
203
                for _, f := range flag.Args() {
 
204
                        dorr(f)
 
205
                }
 
206
        }
 
207
        canvas.End()
 
208
}