M cmd/orgchart/main.go +39 -15
@@ 1,8 1,9 @@
package main
-// TODO: Addl attrs in boxes (title, etc.)
+// TODO: Report-to (e.g., show anchor person's superior)
+// TODO: Highlight filtered person boxes
+// TODO: Support for ordering
// TODO: Max-depth (e.g., show only X levels below anchor person)
-// TODO: Report-to (e.g., show anchor person's superior)
// TODO: Dotted lines
import (
@@ 19,19 20,19 @@ import (
* Constants & global variables *
**************************************************************************/
const (
- boxW = 170
- gapW = 30
- marginW = 20
- boxH = 30
- gapH = 100
- marginH = 20
- textPX = 5
- textPY = 20
- _id = "person"
- _ref = "#person"
+ boxW = 190
+ gapW = 30
+ marginW = 20
+ gapH = 100
+ marginH = 20
+ textPX = 5
+ textPY = 5
+ textSize = 12
+ _id = "person"
+ _ref = "#person"
)
-var pageWidth int
+var boxH int
/**************************************************************************
* Main *
@@ 39,6 40,9 @@ var pageWidth int
func main() {
c := flag.String("c", "", "CSV input file")
o := flag.String("f", "", "Filter for these people's organization (regex)")
+ t := flag.Int("t", -1, "Title column (if not specified, omitted)")
+ s1 := flag.Int("s1", -1, "Subtext #1 column (if not specified, omitted)")
+ s2 := flag.Int("s2", -1, "Subtext #2 column (if not specified, omitted)")
flag.Parse()
if *c == "" {
fmt.Println("CSV is required")
@@ 51,7 55,7 @@ func main() {
fmt.Println(e.Error())
os.Exit(1)
}
- ps, e := makePeople(f)
+ ps, e := makePeople(f, *t, *s1, *s2)
if e != nil {
fmt.Println(e.Error())
os.Exit(1)
@@ 60,6 64,17 @@ func main() {
ps = filter(ps, *o)
}
rs := rank(ps)
+ boxH = 30
+ ty := textSize + textPY
+ if *t > -1 {
+ boxH += ty
+ }
+ if *s1 > -1 {
+ boxH += ty
+ }
+ if *s2 > -1 {
+ boxH += ty
+ }
renderSVG(os.Stdout, rs)
}
@@ 100,7 115,7 @@ func matches(p *Person, re *regexp.Regex
// Parses a CSV data stream, producing a map of people indexed by the person
// name. Returns an error if a non-EOF read error is encountered
-func makePeople(f io.Reader) (map[string]*Person, error) {
+func makePeople(f io.Reader, t, s1, s2 int) (map[string]*Person, error) {
r := csv.NewReader(f)
r.LazyQuotes = true
r.TrailingComma = true
@@ 128,6 143,15 @@ func makePeople(f io.Reader) (map[string
if strings.Contains(l[2], "Contractor") {
p.Contractor = true
}
+ if t > -1 {
+ p.Title = l[t]
+ }
+ if s1 > -1 {
+ p.Subtext1 = l[s1]
+ }
+ if s2 > -1 {
+ p.Subtext2 = l[s2]
+ }
ps[name] = p
}
if e == io.EOF {
M cmd/orgchart/person.go +3 -0
@@ 7,6 7,9 @@ import "fmt"
**************************************************************************/
type Person struct {
Name string
+ Title string
+ Subtext1 string
+ Subtext2 string
Manager *Person
Reports []*Person
Contractor bool
M cmd/orgchart/svg.go +20 -5
@@ 6,6 6,8 @@ import (
"github.com/ajstarks/svgo"
)
+var pageWidth int
+
/**************************************************************************
* SVG generating code *
**************************************************************************/
@@ 77,19 79,32 @@ func drawPerson(canvas *svg.SVG, x, y, i
if !leaf {
x += (person.Width() - (boxW + (gapH / 2))) / 2
}
- drawBox(canvas, x, y, person.Name, person.Contractor)
+ drawBox(canvas, x, y, person)
boxes[person.Name] = Box{X: x, Y: y, Leaf: leaf}
}
-func drawBox(c *svg.SVG, x, y int, n string, yn bool) {
+func drawBox(c *svg.SVG, x, y int, p *Person) {
c.Use(x+2, y+3, _ref, `filter="url(#blur)"`)
fill := "fill: white"
- if yn {
+ if p.Contractor {
fill = "fill: yellow"
}
c.Use(x, y, _ref, fill)
- toff := x + ((boxW - textPX) / 2) + textPX
- c.Text(toff, y+textPY, n, "text-anchor: middle;")
+ toff := x + (boxW / 2)
+ toffY := y + textSize + textPY
+ if p.Title != "" {
+ c.Text(toff, y+textSize+textPY, p.Title, "text-anchor: middle; font-size: smaller;")
+ toffY += textSize + textPY
+ }
+ c.Text(toff, toffY, p.Name, "text-anchor: middle; font-weight: bold;")
+ toffY += textSize + textPY
+ if p.Subtext1 != "" {
+ c.Text(toff, toffY, p.Subtext1, "text-anchor: middle; font-size: smaller;")
+ toffY += textSize + textPY
+ }
+ if p.Subtext2 != "" {
+ c.Text(toff, toffY, p.Subtext2, "text-anchor: middle; font-size: smaller;")
+ }
}
func connectBoxes(c *svg.SVG, ps Rank, bs map[string]Box) {