~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/ajstarks/svgo/pmap/pmap.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
// pmap percentage maps
 
2
// +build !appengine
 
3
 
 
4
package main
 
5
 
 
6
import (
 
7
        "encoding/xml"
 
8
        "flag"
 
9
        "fmt"
 
10
        "io"
 
11
        "os"
 
12
 
 
13
        "github.com/ajstarks/svgo"
 
14
)
 
15
 
 
16
// Pmap defines a porportional map
 
17
type Pmap struct {
 
18
        Top   int     `xml:"top,attr"`
 
19
        Left  int     `xml:"left,attr"`
 
20
        Title string  `xml:"title,attr"`
 
21
        Pdata []Pdata `xml:"pdata"`
 
22
}
 
23
 
 
24
// Pdata defines data with a portpotional map
 
25
type Pdata struct {
 
26
        Legend    string `xml:"legend,attr"`
 
27
        Stagger   string `xml:"stagger,attr"`
 
28
        Alternate string `xml:"alternate,attr"`
 
29
        Item      []Item `xml:"item"`
 
30
}
 
31
 
 
32
// Item defines an item with porpotional map data
 
33
type Item struct {
 
34
        Name  string  `xml:",chardata"`
 
35
        Value float64 `xml:"value,attr"`
 
36
}
 
37
 
 
38
var (
 
39
        width, height, fontsize, fontscale, round, gutter, pred, pgreen, pblue, oflen int
 
40
        bgcolor, olcolor, colorspec, title                                            string
 
41
        showpercent, showdata, alternate, showtitle, stagger, showlegend, showtotal   bool
 
42
        ofpct                                                                         float64
 
43
        leftmargin                                                                    = 40
 
44
        topmargin                                                                     = 40
 
45
        canvas                                                                        = svg.New(os.Stdout)
 
46
)
 
47
 
 
48
const (
 
49
        globalfmt   = "stroke-width:1;font-family:Calibri,sans-serif;text-anchor:middle;font-size:%dpt"
 
50
        legendstyle = "text-anchor:start;font-size:150%"
 
51
        linefmt     = "stroke:%s"
 
52
)
 
53
 
 
54
func dopmap(location string) {
 
55
        var f *os.File
 
56
        var err error
 
57
        if len(location) > 0 {
 
58
                f, err = os.Open(location)
 
59
        } else {
 
60
                f = os.Stdin
 
61
        }
 
62
        if err == nil {
 
63
                readpmap(f)
 
64
                f.Close()
 
65
        } else {
 
66
                fmt.Fprintf(os.Stderr, "%v\n", err)
 
67
        }
 
68
}
 
69
 
 
70
func readpmap(r io.Reader) {
 
71
        var pm Pmap
 
72
        if err := xml.NewDecoder(r).Decode(&pm); err == nil {
 
73
                drawpmap(pm)
 
74
        } else {
 
75
                fmt.Fprintf(os.Stderr, "Unable to parse pmap (%v)\n", err)
 
76
        }
 
77
}
 
78
 
 
79
func drawpmap(m Pmap) {
 
80
        fs := fontsize
 
81
        if m.Left > 0 {
 
82
                leftmargin = m.Left
 
83
        }
 
84
        if m.Top > 0 {
 
85
                topmargin = m.Top
 
86
        } else {
 
87
                topmargin = fs * fontscale
 
88
        }
 
89
        x := leftmargin
 
90
        y := topmargin
 
91
        if len(m.Title) > 0 {
 
92
                title = m.Title
 
93
        }
 
94
        canvas.Title(title)
 
95
        if showtitle {
 
96
                dotitle(title)
 
97
        }
 
98
        for _, p := range m.Pdata {
 
99
                pmap(x, y, fs, p)
 
100
                y += fs*fontscale + (gutter + fs*2)
 
101
        }
 
102
}
 
103
 
 
104
func pmap(x, y, fs int, m Pdata) {
 
105
        var tfill, vfmt, oc string
 
106
        var up bool
 
107
        h := fs * fontscale
 
108
        fw := fs * 80
 
109
        slen := fs + (fs / 2)
 
110
        up = false
 
111
 
 
112
        sum := 0.0
 
113
        for _, v := range m.Item {
 
114
                sum += v.Value
 
115
        }
 
116
 
 
117
        if len(olcolor) > 0 {
 
118
                oc = olcolor
 
119
        } else {
 
120
                oc = bgcolor
 
121
        }
 
122
        loffset := (fs * fontscale) + fs
 
123
        gline := fmt.Sprintf(linefmt, "gray")
 
124
        wline := fmt.Sprintf(linefmt, oc)
 
125
        if len(m.Legend) > 0 && showlegend {
 
126
                if showtotal {
 
127
                        canvas.Text(x, y-fs, fmt.Sprintf("%s (total: "+floatfmt(sum)+")", m.Legend, sum), legendstyle)
 
128
                } else {
 
129
                        canvas.Text(x, y-fs, m.Legend, legendstyle)
 
130
                }
 
131
        }
 
132
        for i, p := range m.Item {
 
133
                k := p.Name
 
134
                v := p.Value
 
135
                if v == 0.0 {
 
136
                        continue
 
137
                }
 
138
                pct := v / sum
 
139
                pw := int(pct * float64(fw))
 
140
                xw := x + (pw / 2)
 
141
                yh := y + (h / 2)
 
142
                if pct >= .4 {
 
143
                        tfill = "fill:white"
 
144
                } else {
 
145
                        tfill = "fill:black"
 
146
                }
 
147
                if round > 0 {
 
148
                        canvas.Roundrect(x, y, pw, h, round, round, canvas.RGBA(pred, pgreen, pblue, pct))
 
149
                } else {
 
150
                        canvas.Rect(x, y, pw, h, canvas.RGBA(pred, pgreen, pblue, pct))
 
151
                }
 
152
 
 
153
                dy := yh + fs + (fs / 2)
 
154
                if pct <= ofpct || len(k) > oflen { // overflow label
 
155
                        if up {
 
156
                                dy -= loffset
 
157
                                yh -= loffset
 
158
                                canvas.Line(xw, y, xw, dy+(fs/2), gline)
 
159
                        } else {
 
160
                                dy += loffset
 
161
                                yh += loffset
 
162
                                canvas.Line(xw, y+h, xw, dy-(fs*3), gline)
 
163
                        }
 
164
                        if alternate {
 
165
                                up = !up
 
166
                                slen = fs * 2
 
167
                        } else {
 
168
                                slen = fs * 3
 
169
                        }
 
170
                        if stagger {
 
171
                                loffset += slen
 
172
                        }
 
173
                        tfill = "fill:black"
 
174
                }
 
175
                canvas.Text(xw, yh, k, tfill)
 
176
                dpfmt := tfill + ";font-size:75%"
 
177
                vfmt = floatfmt(v)
 
178
                switch {
 
179
                case showpercent && !showdata:
 
180
                        canvas.Text(xw, dy, fmt.Sprintf("%.1f%%", pct*100), dpfmt)
 
181
                case showpercent && showdata:
 
182
                        canvas.Text(xw, dy, fmt.Sprintf(vfmt+", %.1f%%", v, pct*100), dpfmt)
 
183
                case showdata && !showpercent:
 
184
                        canvas.Text(xw, dy, fmt.Sprintf(vfmt, v), dpfmt)
 
185
                }
 
186
                x += pw
 
187
                if i < len(m.Item) {
 
188
                        canvas.Line(x, y, x, y+h, wline)
 
189
                }
 
190
        }
 
191
}
 
192
 
 
193
func floatfmt(v float64) string {
 
194
        var vfmt = "%.1f"
 
195
        if v-float64(int(v)) == 0.0 {
 
196
                vfmt = "%.0f"
 
197
        }
 
198
        return vfmt
 
199
}
 
200
 
 
201
func dotitle(s string) {
 
202
        offset := 40
 
203
        canvas.Text(leftmargin, height-offset, s, "text-anchor:start;font-size:250%")
 
204
}
 
205
 
 
206
func init() {
 
207
        flag.IntVar(&width, "w", 1024, "width")
 
208
        flag.IntVar(&height, "h", 768, "height")
 
209
        flag.IntVar(&fontsize, "f", 12, "font size (pt)")
 
210
        flag.IntVar(&fontscale, "s", 5, "font scaling factor")
 
211
        flag.IntVar(&round, "r", 0, "rounded corner size")
 
212
        flag.IntVar(&gutter, "g", 100, "gutter")
 
213
        flag.IntVar(&oflen, "ol", 20, "overflow length")
 
214
        flag.StringVar(&bgcolor, "bg", "white", "background color")
 
215
        flag.StringVar(&olcolor, "oc", "", "outline color")
 
216
        flag.StringVar(&colorspec, "c", "0,0,0", "color (r,g,b)")
 
217
        flag.StringVar(&title, "t", "Proportions", "title")
 
218
        flag.BoolVar(&showpercent, "p", false, "show percentage")
 
219
        flag.BoolVar(&showdata, "d", false, "show data")
 
220
        flag.BoolVar(&alternate, "a", false, "alternate overflow labels")
 
221
        flag.BoolVar(&stagger, "stagger", false, "stagger labels")
 
222
        flag.BoolVar(&showlegend, "showlegend", true, "show the legend")
 
223
        flag.BoolVar(&showtitle, "showtitle", false, "show the title")
 
224
        flag.BoolVar(&showtotal, "showtotal", false, "show totals in the legend")
 
225
        flag.Float64Var(&ofpct, "op", 0.05, "overflow percentage")
 
226
        flag.Parse()
 
227
        fmt.Sscanf(colorspec, "%d,%d,%d", &pred, &pgreen, &pblue)
 
228
}
 
229
 
 
230
func main() {
 
231
        canvas.Start(width, height)
 
232
        canvas.Rect(0, 0, width, height, "fill:"+bgcolor)
 
233
        canvas.Gstyle(fmt.Sprintf(globalfmt, fontsize))
 
234
 
 
235
        if len(flag.Args()) == 0 {
 
236
                dopmap("")
 
237
        } else {
 
238
                for _, f := range flag.Args() {
 
239
                        dopmap(f)
 
240
                }
 
241
        }
 
242
        canvas.Gend()
 
243
        canvas.End()
 
244
}