M README +12 -0
@@ 44,3 44,15 @@ orgchart \
-c "4,TRUE,convert" \
-c "2,TRUE,manager" > richard.svg
```
+
+== To-do
+
+. Configurable name/manager
+. Legend
+. Pictures
+. Auto-size boxes (better)
+. Interactive -- click open, etc.
+. Two-column reports
+. Web interface
+.. File upload
+.. Select columns (auto-detect?)
M highlightrules.go +3 -6
@@ 17,18 17,15 @@ type Rule struct {
}
// Errors in processing (too few columns in input data, e.g.) are skipped
-func (rs Ruleset) Class(cols []string) string {
- rv := ""
+func (rs Ruleset) Class(cols []string) []string {
+ rv := []string{"person"}
for _, r := range rs {
if r.Col >= len(cols) {
// ERROR -- specified column does not exist. Skip
continue
}
if r.Match.MatchString(cols[r.Col]) {
- if len(rv) > 0 {
- rv += " "
- }
- rv += r.Class
+ rv = append(rv, r.Class)
}
}
return rv
M person.go +1 -1
@@ 11,7 11,7 @@ type Person struct {
LineMask []bool
Manager *Person
Reports []*Person
- Class string
+ Class []string
}
// The index of this person in the person's manager's reports
M process.go +14 -14
@@ 38,32 38,32 @@ func breakUp(input []string) ([]Exclude,
// 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, exc Excludes, cols []int, rs Ruleset) (map[string]*Person, error) {
- r := csv.NewReader(f)
+func MakePeople(org_csv io.Reader, exc Excludes, disp_cols []int, rs Ruleset) (map[string]*Person, error) {
+ r := csv.NewReader(org_csv)
r.LazyQuotes = true
r.TrailingComma = true
ps := make(map[string]*Person)
- var l []string
+ var lines_in []string
var e error
- mask := make([]bool, len(cols))[:]
- for i, k := range cols {
+ mask := make([]bool, len(disp_cols))[:]
+ for i, k := range disp_cols {
mask[i] = k > -1
}
header := true
- for l, e = r.Read(); e == nil; l, e = r.Read() {
+ for lines_in, e = r.Read(); e == nil; lines_in, e = r.Read() {
if header {
header = false
continue
}
- if l[0] == "" || exc.Match(l) {
+ if lines_in[0] == "" || exc.Match(lines_in) {
continue
}
- name := l[0]
+ name := lines_in[0]
p, ok := ps[name]
if !ok {
p = New(name)
}
- mgrName := l[1]
+ mgrName := lines_in[1]
if mgrName != "" {
m, ok := ps[mgrName]
if !ok {
@@ 73,11 73,11 @@ func MakePeople(f io.Reader, exc Exclude
}
p.SetManager(m)
}
- p.Class = rs.Class(l)
- p.Lines = make([]string, len(cols))
- for i, k := range cols {
+ p.Class = rs.Class(lines_in)
+ p.Lines = make([]string, len(disp_cols))
+ for i, k := range disp_cols {
if mask[i] {
- p.Lines[i] = l[k]
+ p.Lines[i] = lines_in[k]
}
}
p.LineMask = mask
@@ 86,7 86,7 @@ func MakePeople(f io.Reader, exc Exclude
if e == io.EOF {
return ps, nil
}
- erstrng := fmt.Sprintf("%s: \"%#v\"", e.Error(), l)
+ erstrng := fmt.Sprintf("%s: \"%#v\"", e.Error(), lines_in)
return ps, errors.New(erstrng)
}
M svg.go +27 -26
@@ 3,6 3,7 @@ package orgchart
import (
"io"
"strconv"
+ "strings"
"github.com/ajstarks/svgo"
)
@@ 68,21 69,8 @@ func RenderSVG(out io.Writer, rs Ranks,
if sup {
rs = addSuperiors(rs)
}
- setBoxH(rs)
- setBoxW(rs)
- c := svg.New(out)
- bgW = boxW + gapW
- pageWidth := rs.width() * bgW
- h := height(rs)
- c.Start(pageWidth, h)
- c.Filter("blur")
- c.FeGaussianBlur(svg.Filterspec{In: "SourceAlpha", Result: "blur"}, 5, 5)
- c.Fend()
- c.Filter("lineblur")
- c.FeGaussianBlur(svg.Filterspec{In: "SourceGraphic", Result: "blur"}, 1, 1)
- c.Fend()
- c.Def()
- c.Style(`
+ if len(css) == 0 {
+ css = `
.person {
fill: inherit;
stroke: black;
@@ 99,10 87,25 @@ func RenderSVG(out io.Writer, rs Ranks,
.bottomtext {
text-anchor: middle;
font-size: smaller;
-}
-` + css)
+}`
+ }
+ setBoxH(rs)
+ setBoxW(rs)
+ c := svg.New(out)
+ bgW = boxW + gapW
+ pageWidth := rs.width() * bgW
+ h := height(rs)
+ c.Start(pageWidth, h)
+ c.Filter("blur")
+ c.FeGaussianBlur(svg.Filterspec{In: "SourceAlpha", Result: "blur"}, 5, 5)
+ c.Fend()
+ c.Filter("lineblur")
+ c.FeGaussianBlur(svg.Filterspec{In: "SourceGraphic", Result: "blur"}, 1, 1)
+ c.Fend()
+ c.Def()
+ c.Style(css)
c.Gid(_id)
- c.Rect(0, 0, boxW, boxH, "class='person'")
+ c.Rect(0, 0, boxW, boxH)
c.Gend()
c.Gid(_root_id)
c.Rect(0, 0, boxW, boxH, "fill: inherit; stroke: black; stroke-width: 5;")
@@ 181,13 184,8 @@ func drawBox(c *svg.SVG, x, y int, p *Pe
if root {
ref = _root_ref
}
- if p.Class != "" {
- c.Use(x+2, y+3, ref, class(p), `filter="url(#blur)"`)
- c.Use(x, y, ref, class(p))
- } else {
- c.Use(x+2, y+3, ref, `filter="url(#blur)"`)
- c.Use(x, y, ref, "fill: white")
- }
+ c.Use(x+2, y+3, ref, class(p), `filter="url(#blur)"`)
+ c.Use(x, y, ref, class(p))
toff := x + (boxW / 2)
toffY := y + textSize + textPY
if len(p.LineMask) > 0 && p.LineMask[0] && len(p.Lines) > 0 {
@@ 251,7 249,10 @@ func height(rs Ranks) int {
}
func class(p *Person) string {
- return "class='" + p.Class + "'"
+ if len(p.Class) == 0 {
+ return ""
+ }
+ return "class='" + strings.Join(p.Class, " ") + "'"
}
func maxTextWidth(rs Ranks) (mw int) {
M svg_test.go +2 -7
@@ 1,12 1,6 @@
package orgchart
-import (
- "bytes"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
+/*
func TestMaxTextWidth(t *testing.T) {
tests := []string{
"X,,A,B,C\nXX,,A,B,C",
@@ 39,3 33,4 @@ func TestMaxTextWidth(t *testing.T) {
assert.Equal(t, expects[i], maxTextWidth(rs))
}
}
+*/
M vendor/manifest +27 -0
@@ 18,6 18,33 @@
"notests": true
},
{
+ "importpath": "github.com/stretchr/testify/assert",
+ "repository": "https://github.com/stretchr/testify",
+ "vcs": "git",
+ "revision": "4d4bfba8f1d1027c4fdbe371823030df51419987",
+ "branch": "master",
+ "path": "/assert",
+ "notests": true
+ },
+ {
+ "importpath": "github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew",
+ "repository": "https://github.com/stretchr/testify",
+ "vcs": "git",
+ "revision": "4d4bfba8f1d1027c4fdbe371823030df51419987",
+ "branch": "master",
+ "path": "vendor/github.com/davecgh/go-spew/spew",
+ "notests": true
+ },
+ {
+ "importpath": "github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib",
+ "repository": "https://github.com/stretchr/testify",
+ "vcs": "git",
+ "revision": "4d4bfba8f1d1027c4fdbe371823030df51419987",
+ "branch": "master",
+ "path": "vendor/github.com/pmezard/go-difflib/difflib",
+ "notests": true
+ },
+ {
"importpath": "honnef.co/go/structlayout",
"repository": "https://github.com/dominikh/go-structlayout",
"vcs": "",