Align returns a two-dimensional row-major array of Canvases which will produce tiled plots with DataCanvases that are evenly sized and spaced. The arguments to the function are a two-dimensional row-major array of plots, a tile configuration, and the canvas to which the tiled plots are to be drawn.
(plots [][]*Plot, t draw.Tiles, dc draw.Canvas)
| 18 | // of plots, a tile configuration, and the canvas to which the tiled |
| 19 | // plots are to be drawn. |
| 20 | func Align(plots [][]*Plot, t draw.Tiles, dc draw.Canvas) [][]draw.Canvas { |
| 21 | o := make([][]draw.Canvas, len(plots)) |
| 22 | |
| 23 | if len(plots) != t.Rows { |
| 24 | panic(fmt.Errorf("plot: plots rows (%d) != tiles rows (%d)", len(plots), t.Rows)) |
| 25 | } |
| 26 | |
| 27 | // Create the initial tiles. |
| 28 | for j := range t.Rows { |
| 29 | if len(plots[j]) != t.Cols { |
| 30 | panic(fmt.Errorf("plot: plots row %d columns (%d) != tiles columns (%d)", j, len(plots[j]), t.Rows)) |
| 31 | } |
| 32 | |
| 33 | o[j] = make([]draw.Canvas, len(plots[j])) |
| 34 | for i := range t.Cols { |
| 35 | o[j][i] = t.At(dc, i, j) |
| 36 | } |
| 37 | } |
| 38 | |
| 39 | type posNeg struct { |
| 40 | p, n float64 |
| 41 | } |
| 42 | xSpacing := make([]posNeg, t.Cols) |
| 43 | ySpacing := make([]posNeg, t.Rows) |
| 44 | |
| 45 | // Calculate the maximum spacing between data canvases |
| 46 | // for each row and column. |
| 47 | for j, row := range plots { |
| 48 | for i, p := range row { |
| 49 | if p == nil { |
| 50 | continue |
| 51 | } |
| 52 | c := o[j][i] |
| 53 | dataC := p.DataCanvas(o[j][i]) |
| 54 | xSpacing[i].n = math.Max(float64(dataC.Min.X-c.Min.X), xSpacing[i].n) |
| 55 | xSpacing[i].p = math.Max(float64(c.Max.X-dataC.Max.X), xSpacing[i].p) |
| 56 | ySpacing[j].n = math.Max(float64(dataC.Min.Y-c.Min.Y), ySpacing[j].n) |
| 57 | ySpacing[j].p = math.Max(float64(c.Max.Y-dataC.Max.Y), ySpacing[j].p) |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | // Calculate the total row and column spacing. |
| 62 | var xTotalSpace float64 |
| 63 | for _, s := range xSpacing { |
| 64 | xTotalSpace += s.n + s.p |
| 65 | } |
| 66 | xTotalSpace += float64(t.PadX)*float64(len(xSpacing)-1) + float64(t.PadLeft+t.PadRight) |
| 67 | var yTotalSpace float64 |
| 68 | for _, s := range ySpacing { |
| 69 | yTotalSpace += s.n + s.p |
| 70 | } |
| 71 | yTotalSpace += float64(t.PadY)*float64(len(ySpacing)-1) + float64(t.PadTop+t.PadBottom) |
| 72 | |
| 73 | avgWidth := vg.Length((float64(dc.Max.X-dc.Min.X) - xTotalSpace) / float64(t.Cols)) |
| 74 | avgHeight := vg.Length((float64(dc.Max.Y-dc.Min.Y) - yTotalSpace) / float64(t.Rows)) |
| 75 | |
| 76 | moveVertical := make([]vg.Length, t.Cols) |
| 77 | for j := t.Rows - 1; j >= 0; j-- { |