// Draw draws a plot to a draw.Canvas. // // Plotters are drawn in the order in which they were // added to the plot. Plotters that implement the // GlyphBoxer interface will have their GlyphBoxes // taken into account when padding the plot so that // none of their glyphs are clipped. func (p *Plot) Draw(c draw.Canvas) { if p.BackgroundColor != nil { c.SetColor(p.BackgroundColor) c.Fill(c.Rectangle.Path()) } if p.Title.Text != "" { c.FillText(p.Title.TextStyle, c.Center().X, c.Max.Y, -0.5, -1, p.Title.Text) c.Max.Y -= p.Title.Height(p.Title.Text) - p.Title.Font.Extents().Descent c.Max.Y -= p.Title.Padding } p.X.sanitizeRange() x := horizontalAxis{p.X} p.Y.sanitizeRange() y := verticalAxis{p.Y} ywidth := y.size() x.draw(padX(p, c.Crop(ywidth, 0, 0, 0))) xheight := x.size() y.draw(padY(p, c.Crop(0, xheight, 0, 0))) dataC := padY(p, padX(p, c.Crop(ywidth, xheight, 0, 0))) for _, data := range p.plotters { data.Plot(dataC, p) } p.Legend.draw(c.Crop(ywidth, 0, 0, 0).Crop(0, xheight, 0, 0)) }
// Thumbnail the thumbnail for the Line, // implementing the plot.Thumbnailer interface. func (pts *Line) Thumbnail(c *draw.Canvas) { if pts.ShadeColor != nil { points := []draw.Point{ {c.Min.X, c.Min.Y}, {c.Min.X, c.Max.Y}, {c.Max.X, c.Max.Y}, {c.Max.X, c.Min.Y}, } poly := c.ClipPolygonY(points) c.FillPolygon(*pts.ShadeColor, poly) points = append(points, draw.Point{c.Min.X, c.Min.Y}) } else { y := c.Center().Y c.StrokeLine2(pts.LineStyle, c.Min.X, y, c.Max.X, y) } }
// draw draws the axis along the left side of a draw.Canvas. func (a *verticalAxis) draw(c draw.Canvas) { x := c.Min.X if a.Label.Text != "" { x += a.Label.Height(a.Label.Text) c.Push() c.Rotate(math.Pi / 2) c.FillText(a.Label.TextStyle, c.Center().Y, -x, -0.5, 0, a.Label.Text) c.Pop() x += -a.Label.Font.Extents().Descent } marks := a.Tick.Marker.Ticks(a.Min, a.Max) if w := tickLabelWidth(a.Tick.Label, marks); len(marks) > 0 && w > 0 { x += w } major := false for _, t := range marks { y := c.Y(a.Norm(t.Value)) if !c.ContainsY(y) || t.IsMinor() { continue } c.FillText(a.Tick.Label, x, y, -1, -0.5, t.Label) major = true } if major { x += a.Tick.Label.Width(" ") } if a.drawTicks() && len(marks) > 0 { len := a.Tick.Length for _, t := range marks { y := c.Y(a.Norm(t.Value)) if !c.ContainsY(y) { continue } start := t.lengthOffset(len) c.StrokeLine2(a.Tick.LineStyle, x+start, y, x+len, y) } x += len } c.StrokeLine2(a.LineStyle, x, c.Min.Y, x, c.Max.Y) }
// draw draws the axis along the lower edge of a draw.Canvas. func (a *horizontalAxis) draw(c draw.Canvas) { y := c.Min.Y if a.Label.Text != "" { y -= a.Label.Font.Extents().Descent c.FillText(a.Label.TextStyle, c.Center().X, y, -0.5, 0, a.Label.Text) y += a.Label.Height(a.Label.Text) } marks := a.Tick.Marker.Ticks(a.Min, a.Max) for _, t := range marks { x := c.X(a.Norm(t.Value)) if !c.ContainsX(x) || t.IsMinor() { continue } c.FillText(a.Tick.Label, x, y, -0.5, 0, t.Label) } if len(marks) > 0 { y += tickLabelHeight(a.Tick.Label, marks) } else { y += a.Width / 2 } if len(marks) > 0 && a.drawTicks() { len := a.Tick.Length for _, t := range marks { x := c.X(a.Norm(t.Value)) if !c.ContainsX(x) { continue } start := t.lengthOffset(len) c.StrokeLine2(a.Tick.LineStyle, x, y+start, x, y+len) } y += len } c.StrokeLine2(a.LineStyle, c.Min.X, y, c.Max.X, y) }
// Thumbnail draws a line in the given style down the // center of a DrawArea as a thumbnail representation // of the LineStyle of the function. func (f Function) Thumbnail(c *draw.Canvas) { y := c.Center().Y c.StrokeLine2(f.LineStyle, c.Min.X, y, c.Max.X, y) }
// Thumbnail the thumbnail for the Scatter, // implementing the plot.Thumbnailer interface. func (pts *Scatter) Thumbnail(c *draw.Canvas) { c.DrawGlyph(pts.GlyphStyle, c.Center()) }