<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
		<style>
			body {
				background: black;
				color: rgb(80, 80, 80);
			}
			body, pre, #legend span {
				font-family: Menlo, monospace;
				font-weight: bold;
			}
			#topbar {
				background: black;
				position: fixed;
				top: 0; left: 0; right: 0;
				height: 42px;
				border-bottom: 1px solid rgb(80, 80, 80);
			}
			#content {
				margin-top: 50px;
			}
			#nav, #legend {
				float: left;
				margin-left: 10px;
			}
			#legend {
				margin-top: 12px;
			}
			#nav {
				margin-top: 10px;
			}
			#legend span {
				margin: 0 5px;
			}
			.cov0 { color: rgb(192, 0, 0) }
.cov1 { color: rgb(128, 128, 128) }
.cov2 { color: rgb(116, 140, 131) }
.cov3 { color: rgb(104, 152, 134) }
.cov4 { color: rgb(92, 164, 137) }
.cov5 { color: rgb(80, 176, 140) }
.cov6 { color: rgb(68, 188, 143) }
.cov7 { color: rgb(56, 200, 146) }
.cov8 { color: rgb(44, 212, 149) }
.cov9 { color: rgb(32, 224, 152) }
.cov10 { color: rgb(20, 236, 155) }

		</style>
	</head>
	<body>
		<div id="topbar">
			<div id="nav">
				<select id="files">
				
				<option value="file0">github.com/wcharczuk/go-chart/annotation_series.go (77.8%)</option>
				
				<option value="file1">github.com/wcharczuk/go-chart/bar_chart.go (95.8%)</option>
				
				<option value="file2">github.com/wcharczuk/go-chart/bollinger_band_series.go (68.8%)</option>
				
				<option value="file3">github.com/wcharczuk/go-chart/box.go (82.5%)</option>
				
				<option value="file4">github.com/wcharczuk/go-chart/chart.go (71.8%)</option>
				
				<option value="file5">github.com/wcharczuk/go-chart/colors.go (100.0%)</option>
				
				<option value="file6">github.com/wcharczuk/go-chart/concat_series.go (65.0%)</option>
				
				<option value="file7">github.com/wcharczuk/go-chart/continuous_range.go (93.3%)</option>
				
				<option value="file8">github.com/wcharczuk/go-chart/continuous_series.go (100.0%)</option>
				
				<option value="file9">github.com/wcharczuk/go-chart/draw.go (57.4%)</option>
				
				<option value="file10">github.com/wcharczuk/go-chart/drawing/color.go (59.5%)</option>
				
				<option value="file11">github.com/wcharczuk/go-chart/drawing/curve.go (42.0%)</option>
				
				<option value="file12">github.com/wcharczuk/go-chart/drawing/dasher.go (0.0%)</option>
				
				<option value="file13">github.com/wcharczuk/go-chart/drawing/demux_flattener.go (0.0%)</option>
				
				<option value="file14">github.com/wcharczuk/go-chart/drawing/flattener.go (0.0%)</option>
				
				<option value="file15">github.com/wcharczuk/go-chart/drawing/free_type_path.go (0.0%)</option>
				
				<option value="file16">github.com/wcharczuk/go-chart/drawing/line.go (0.0%)</option>
				
				<option value="file17">github.com/wcharczuk/go-chart/drawing/matrix.go (0.0%)</option>
				
				<option value="file18">github.com/wcharczuk/go-chart/drawing/painter.go (0.0%)</option>
				
				<option value="file19">github.com/wcharczuk/go-chart/drawing/path.go (0.0%)</option>
				
				<option value="file20">github.com/wcharczuk/go-chart/drawing/raster_graphic_context.go (0.0%)</option>
				
				<option value="file21">github.com/wcharczuk/go-chart/drawing/stack_graphic_context.go (0.0%)</option>
				
				<option value="file22">github.com/wcharczuk/go-chart/drawing/stroker.go (0.0%)</option>
				
				<option value="file23">github.com/wcharczuk/go-chart/drawing/text.go (0.0%)</option>
				
				<option value="file24">github.com/wcharczuk/go-chart/drawing/transformer.go (0.0%)</option>
				
				<option value="file25">github.com/wcharczuk/go-chart/drawing/util.go (0.0%)</option>
				
				<option value="file26">github.com/wcharczuk/go-chart/ema_series.go (58.7%)</option>
				
				<option value="file27">github.com/wcharczuk/go-chart/first_value_annotation.go (77.8%)</option>
				
				<option value="file28">github.com/wcharczuk/go-chart/font.go (88.9%)</option>
				
				<option value="file29">github.com/wcharczuk/go-chart/grid_line.go (34.5%)</option>
				
				<option value="file30">github.com/wcharczuk/go-chart/histogram_series.go (35.3%)</option>
				
				<option value="file31">github.com/wcharczuk/go-chart/image_writer.go (0.0%)</option>
				
				<option value="file32">github.com/wcharczuk/go-chart/jet.go (0.0%)</option>
				
				<option value="file33">github.com/wcharczuk/go-chart/last_value_annotation.go (77.8%)</option>
				
				<option value="file34">github.com/wcharczuk/go-chart/legend.go (32.5%)</option>
				
				<option value="file35">github.com/wcharczuk/go-chart/linear_coefficient_provider.go (0.0%)</option>
				
				<option value="file36">github.com/wcharczuk/go-chart/linear_regression_series.go (64.3%)</option>
				
				<option value="file37">github.com/wcharczuk/go-chart/linear_series.go (0.0%)</option>
				
				<option value="file38">github.com/wcharczuk/go-chart/macd_series.go (49.5%)</option>
				
				<option value="file39">github.com/wcharczuk/go-chart/matrix/matrix.go (81.0%)</option>
				
				<option value="file40">github.com/wcharczuk/go-chart/matrix/regression.go (90.9%)</option>
				
				<option value="file41">github.com/wcharczuk/go-chart/matrix/util.go (58.3%)</option>
				
				<option value="file42">github.com/wcharczuk/go-chart/matrix/vector.go (0.0%)</option>
				
				<option value="file43">github.com/wcharczuk/go-chart/min_max_series.go (0.0%)</option>
				
				<option value="file44">github.com/wcharczuk/go-chart/pie_chart.go (70.6%)</option>
				
				<option value="file45">github.com/wcharczuk/go-chart/polynomial_regression_series.go (45.6%)</option>
				
				<option value="file46">github.com/wcharczuk/go-chart/raster_renderer.go (74.1%)</option>
				
				<option value="file47">github.com/wcharczuk/go-chart/seq/array.go (100.0%)</option>
				
				<option value="file48">github.com/wcharczuk/go-chart/seq/buffer.go (69.9%)</option>
				
				<option value="file49">github.com/wcharczuk/go-chart/seq/linear.go (94.7%)</option>
				
				<option value="file50">github.com/wcharczuk/go-chart/seq/random.go (44.0%)</option>
				
				<option value="file51">github.com/wcharczuk/go-chart/seq/seq.go (47.0%)</option>
				
				<option value="file52">github.com/wcharczuk/go-chart/seq/time.go (78.9%)</option>
				
				<option value="file53">github.com/wcharczuk/go-chart/seq/times.go (0.0%)</option>
				
				<option value="file54">github.com/wcharczuk/go-chart/seq/util.go (0.0%)</option>
				
				<option value="file55">github.com/wcharczuk/go-chart/sma_series.go (54.8%)</option>
				
				<option value="file56">github.com/wcharczuk/go-chart/stacked_bar_chart.go (0.0%)</option>
				
				<option value="file57">github.com/wcharczuk/go-chart/style.go (66.1%)</option>
				
				<option value="file58">github.com/wcharczuk/go-chart/text.go (87.9%)</option>
				
				<option value="file59">github.com/wcharczuk/go-chart/tick.go (78.9%)</option>
				
				<option value="file60">github.com/wcharczuk/go-chart/time_series.go (69.6%)</option>
				
				<option value="file61">github.com/wcharczuk/go-chart/util/date.go (60.9%)</option>
				
				<option value="file62">github.com/wcharczuk/go-chart/util/file_util.go (0.0%)</option>
				
				<option value="file63">github.com/wcharczuk/go-chart/util/math.go (50.5%)</option>
				
				<option value="file64">github.com/wcharczuk/go-chart/util/time.go (53.7%)</option>
				
				<option value="file65">github.com/wcharczuk/go-chart/value.go (100.0%)</option>
				
				<option value="file66">github.com/wcharczuk/go-chart/value_formatter.go (46.9%)</option>
				
				<option value="file67">github.com/wcharczuk/go-chart/vector_renderer.go (56.6%)</option>
				
				<option value="file68">github.com/wcharczuk/go-chart/viridis.go (0.0%)</option>
				
				<option value="file69">github.com/wcharczuk/go-chart/xaxis.go (60.4%)</option>
				
				<option value="file70">github.com/wcharczuk/go-chart/yaxis.go (63.1%)</option>
				
				</select>
			</div>
			<div id="legend">
				<span>not tracked</span>
			
				<span class="cov0">not covered</span>
				<span class="cov8">covered</span>
			
			</div>
		</div>
		<div id="content">
		
		<pre class="file" id="file0" style="display: none">package chart

import (
        "fmt"
        "math"

        util "github.com/wcharczuk/go-chart/util"
)

// Interface Assertions.
var (
        _ Series = (*AnnotationSeries)(nil)
)

// AnnotationSeries is a series of labels on the chart.
type AnnotationSeries struct {
        Name        string
        Style       Style
        YAxis       YAxisType
        Annotations []Value2
}

// GetName returns the name of the time series.
func (as AnnotationSeries) GetName() string <span class="cov0" title="0">{
        return as.Name
}</span>

// GetStyle returns the line style.
func (as AnnotationSeries) GetStyle() Style <span class="cov0" title="0">{
        return as.Style
}</span>

// GetYAxis returns which YAxis the series draws on.
func (as AnnotationSeries) GetYAxis() YAxisType <span class="cov0" title="0">{
        return as.YAxis
}</span>

func (as AnnotationSeries) annotationStyleDefaults(defaults Style) Style <span class="cov8" title="1">{
        return Style{
                FontColor:   DefaultTextColor,
                Font:        defaults.Font,
                FillColor:   DefaultAnnotationFillColor,
                FontSize:    DefaultAnnotationFontSize,
                StrokeColor: defaults.StrokeColor,
                StrokeWidth: defaults.StrokeWidth,
                Padding:     DefaultAnnotationPadding,
        }
}</span>

// Measure returns a bounds box of the series.
func (as AnnotationSeries) Measure(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) Box <span class="cov8" title="1">{
        box := Box{
                Top:    math.MaxInt32,
                Left:   math.MaxInt32,
                Right:  0,
                Bottom: 0,
        }
        if as.Style.IsZero() || as.Style.Show </span><span class="cov8" title="1">{
                seriesStyle := as.Style.InheritFrom(as.annotationStyleDefaults(defaults))
                for _, a := range as.Annotations </span><span class="cov8" title="1">{
                        style := a.Style.InheritFrom(seriesStyle)
                        lx := canvasBox.Left + xrange.Translate(a.XValue)
                        ly := canvasBox.Bottom - yrange.Translate(a.YValue)
                        ab := Draw.MeasureAnnotation(r, canvasBox, style, lx, ly, a.Label)
                        box.Top = util.Math.MinInt(box.Top, ab.Top)
                        box.Left = util.Math.MinInt(box.Left, ab.Left)
                        box.Right = util.Math.MaxInt(box.Right, ab.Right)
                        box.Bottom = util.Math.MaxInt(box.Bottom, ab.Bottom)
                }</span>
        }
        <span class="cov8" title="1">return box</span>
}

// Render draws the series.
func (as AnnotationSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) <span class="cov8" title="1">{
        if as.Style.IsZero() || as.Style.Show </span><span class="cov8" title="1">{
                seriesStyle := as.Style.InheritFrom(as.annotationStyleDefaults(defaults))
                for _, a := range as.Annotations </span><span class="cov8" title="1">{
                        style := a.Style.InheritFrom(seriesStyle)
                        lx := canvasBox.Left + xrange.Translate(a.XValue)
                        ly := canvasBox.Bottom - yrange.Translate(a.YValue)
                        Draw.Annotation(r, canvasBox, style, lx, ly, a.Label)
                }</span>
        }
}

// Validate validates the series.
func (as AnnotationSeries) Validate() error <span class="cov0" title="0">{
        if len(as.Annotations) == 0 </span><span class="cov0" title="0">{
                return fmt.Errorf("annotation series requires annotations to be set and not empty")
        }</span>
        <span class="cov0" title="0">return nil</span>
}
</pre>
		
		<pre class="file" id="file1" style="display: none">package chart

import (
        "errors"
        "fmt"
        "io"
        "math"

        "github.com/golang/freetype/truetype"
        util "github.com/wcharczuk/go-chart/util"
)

// BarChart is a chart that draws bars on a range.
type BarChart struct {
        Title      string
        TitleStyle Style

        ColorPalette ColorPalette

        Width  int
        Height int
        DPI    float64

        BarWidth int

        Background Style
        Canvas     Style

        XAxis Style
        YAxis YAxis

        BarSpacing int

        UseBaseValue bool
        BaseValue    float64

        Font        *truetype.Font
        defaultFont *truetype.Font

        Bars     []Value
        Elements []Renderable
}

// GetDPI returns the dpi for the chart.
func (bc BarChart) GetDPI() float64 <span class="cov8" title="1">{
        if bc.DPI == 0 </span><span class="cov8" title="1">{
                return DefaultDPI
        }</span>
        <span class="cov8" title="1">return bc.DPI</span>
}

// GetFont returns the text font.
func (bc BarChart) GetFont() *truetype.Font <span class="cov8" title="1">{
        if bc.Font == nil </span><span class="cov8" title="1">{
                return bc.defaultFont
        }</span>
        <span class="cov8" title="1">return bc.Font</span>
}

// GetWidth returns the chart width or the default value.
func (bc BarChart) GetWidth() int <span class="cov8" title="1">{
        if bc.Width == 0 </span><span class="cov8" title="1">{
                return DefaultChartWidth
        }</span>
        <span class="cov8" title="1">return bc.Width</span>
}

// GetHeight returns the chart height or the default value.
func (bc BarChart) GetHeight() int <span class="cov8" title="1">{
        if bc.Height == 0 </span><span class="cov8" title="1">{
                return DefaultChartHeight
        }</span>
        <span class="cov8" title="1">return bc.Height</span>
}

// GetBarSpacing returns the spacing between bars.
func (bc BarChart) GetBarSpacing() int <span class="cov8" title="1">{
        if bc.BarSpacing == 0 </span><span class="cov8" title="1">{
                return DefaultBarSpacing
        }</span>
        <span class="cov8" title="1">return bc.BarSpacing</span>
}

// GetBarWidth returns the default bar width.
func (bc BarChart) GetBarWidth() int <span class="cov8" title="1">{
        if bc.BarWidth == 0 </span><span class="cov8" title="1">{
                return DefaultBarWidth
        }</span>
        <span class="cov8" title="1">return bc.BarWidth</span>
}

// Render renders the chart with the given renderer to the given io.Writer.
func (bc BarChart) Render(rp RendererProvider, w io.Writer) error <span class="cov8" title="1">{
        if len(bc.Bars) == 0 </span><span class="cov8" title="1">{
                return errors.New("please provide at least one bar")
        }</span>

        <span class="cov8" title="1">r, err := rp(bc.GetWidth(), bc.GetHeight())
        if err != nil </span><span class="cov0" title="0">{
                return err
        }</span>

        <span class="cov8" title="1">if bc.Font == nil </span><span class="cov8" title="1">{
                defaultFont, err := GetDefaultFont()
                if err != nil </span><span class="cov0" title="0">{
                        return err
                }</span>
                <span class="cov8" title="1">bc.defaultFont = defaultFont</span>
        }
        <span class="cov8" title="1">r.SetDPI(bc.GetDPI())

        bc.drawBackground(r)

        var canvasBox Box
        var yt []Tick
        var yr Range
        var yf ValueFormatter

        canvasBox = bc.getDefaultCanvasBox()
        yr = bc.getRanges()
        if yr.GetMax()-yr.GetMin() == 0 </span><span class="cov8" title="1">{
                return fmt.Errorf("invalid data range; cannot be zero")
        }</span>
        <span class="cov8" title="1">yr = bc.setRangeDomains(canvasBox, yr)
        yf = bc.getValueFormatters()

        if bc.hasAxes() </span><span class="cov8" title="1">{
                yt = bc.getAxesTicks(r, yr, yf)
                canvasBox = bc.getAdjustedCanvasBox(r, canvasBox, yr, yt)
                yr = bc.setRangeDomains(canvasBox, yr)
        }</span>
        <span class="cov8" title="1">bc.drawCanvas(r, canvasBox)
        bc.drawBars(r, canvasBox, yr)
        bc.drawXAxis(r, canvasBox)
        bc.drawYAxis(r, canvasBox, yr, yt)

        bc.drawTitle(r)
        for _, a := range bc.Elements </span><span class="cov0" title="0">{
                a(r, canvasBox, bc.styleDefaultsElements())
        }</span>

        <span class="cov8" title="1">return r.Save(w)</span>
}

func (bc BarChart) drawCanvas(r Renderer, canvasBox Box) <span class="cov8" title="1">{
        Draw.Box(r, canvasBox, bc.getCanvasStyle())
}</span>

func (bc BarChart) getRanges() Range <span class="cov8" title="1">{
        var yrange Range
        if bc.YAxis.Range != nil &amp;&amp; !bc.YAxis.Range.IsZero() </span><span class="cov8" title="1">{
                yrange = bc.YAxis.Range
        }</span> else<span class="cov8" title="1"> {
                yrange = &amp;ContinuousRange{}
        }</span>

        <span class="cov8" title="1">if !yrange.IsZero() </span><span class="cov8" title="1">{
                return yrange
        }</span>

        <span class="cov8" title="1">if len(bc.YAxis.Ticks) &gt; 0 </span><span class="cov8" title="1">{
                tickMin, tickMax := math.MaxFloat64, -math.MaxFloat64
                for _, t := range bc.YAxis.Ticks </span><span class="cov8" title="1">{
                        tickMin = math.Min(tickMin, t.Value)
                        tickMax = math.Max(tickMax, t.Value)
                }</span>
                <span class="cov8" title="1">yrange.SetMin(tickMin)
                yrange.SetMax(tickMax)
                return yrange</span>
        }

        <span class="cov8" title="1">min, max := math.MaxFloat64, -math.MaxFloat64
        for _, b := range bc.Bars </span><span class="cov8" title="1">{
                min = math.Min(b.Value, min)
                max = math.Max(b.Value, max)
        }</span>

        <span class="cov8" title="1">yrange.SetMin(min)
        yrange.SetMax(max)

        return yrange</span>
}

func (bc BarChart) drawBackground(r Renderer) <span class="cov8" title="1">{
        Draw.Box(r, Box{
                Right:  bc.GetWidth(),
                Bottom: bc.GetHeight(),
        }, bc.getBackgroundStyle())
}</span>

func (bc BarChart) drawBars(r Renderer, canvasBox Box, yr Range) <span class="cov8" title="1">{
        xoffset := canvasBox.Left

        width, spacing, _ := bc.calculateScaledTotalWidth(canvasBox)
        bs2 := spacing &gt;&gt; 1

        var barBox Box
        var bxl, bxr, by int
        for index, bar := range bc.Bars </span><span class="cov8" title="1">{
                bxl = xoffset + bs2
                bxr = bxl + width

                by = canvasBox.Bottom - yr.Translate(bar.Value)

                if bc.UseBaseValue </span><span class="cov0" title="0">{
                        barBox = Box{
                                Top:    by,
                                Left:   bxl,
                                Right:  bxr,
                                Bottom: canvasBox.Bottom - yr.Translate(bc.BaseValue),
                        }
                }</span> else<span class="cov8" title="1"> {
                        barBox = Box{
                                Top:    by,
                                Left:   bxl,
                                Right:  bxr,
                                Bottom: canvasBox.Bottom,
                        }
                }</span>

                <span class="cov8" title="1">Draw.Box(r, barBox, bar.Style.InheritFrom(bc.styleDefaultsBar(index)))

                xoffset += width + spacing</span>
        }
}

func (bc BarChart) drawXAxis(r Renderer, canvasBox Box) <span class="cov8" title="1">{
        if bc.XAxis.Show </span><span class="cov8" title="1">{
                axisStyle := bc.XAxis.InheritFrom(bc.styleDefaultsAxes())
                axisStyle.WriteToRenderer(r)

                width, spacing, _ := bc.calculateScaledTotalWidth(canvasBox)

                r.MoveTo(canvasBox.Left, canvasBox.Bottom)
                r.LineTo(canvasBox.Right, canvasBox.Bottom)
                r.Stroke()

                r.MoveTo(canvasBox.Left, canvasBox.Bottom)
                r.LineTo(canvasBox.Left, canvasBox.Bottom+DefaultVerticalTickHeight)
                r.Stroke()

                cursor := canvasBox.Left
                for index, bar := range bc.Bars </span><span class="cov8" title="1">{
                        barLabelBox := Box{
                                Top:    canvasBox.Bottom + DefaultXAxisMargin,
                                Left:   cursor,
                                Right:  cursor + width + spacing,
                                Bottom: bc.GetHeight(),
                        }

                        if len(bar.Label) &gt; 0 </span><span class="cov8" title="1">{
                                Draw.TextWithin(r, bar.Label, barLabelBox, axisStyle)
                        }</span>

                        <span class="cov8" title="1">axisStyle.WriteToRenderer(r)
                        if index &lt; len(bc.Bars)-1 </span><span class="cov8" title="1">{
                                r.MoveTo(barLabelBox.Right, canvasBox.Bottom)
                                r.LineTo(barLabelBox.Right, canvasBox.Bottom+DefaultVerticalTickHeight)
                                r.Stroke()
                        }</span>
                        <span class="cov8" title="1">cursor += width + spacing</span>
                }
        }
}

func (bc BarChart) drawYAxis(r Renderer, canvasBox Box, yr Range, ticks []Tick) <span class="cov8" title="1">{
        if bc.YAxis.Style.Show </span><span class="cov8" title="1">{
                axisStyle := bc.YAxis.Style.InheritFrom(bc.styleDefaultsAxes())
                axisStyle.WriteToRenderer(r)

                r.MoveTo(canvasBox.Right, canvasBox.Top)
                r.LineTo(canvasBox.Right, canvasBox.Bottom)
                r.Stroke()

                r.MoveTo(canvasBox.Right, canvasBox.Bottom)
                r.LineTo(canvasBox.Right+DefaultHorizontalTickWidth, canvasBox.Bottom)
                r.Stroke()

                var ty int
                var tb Box
                for _, t := range ticks </span><span class="cov8" title="1">{
                        ty = canvasBox.Bottom - yr.Translate(t.Value)

                        axisStyle.GetStrokeOptions().WriteToRenderer(r)
                        r.MoveTo(canvasBox.Right, ty)
                        r.LineTo(canvasBox.Right+DefaultHorizontalTickWidth, ty)
                        r.Stroke()

                        axisStyle.GetTextOptions().WriteToRenderer(r)
                        tb = r.MeasureText(t.Label)
                        Draw.Text(r, t.Label, canvasBox.Right+DefaultYAxisMargin+5, ty+(tb.Height()&gt;&gt;1), axisStyle)
                }</span>

        }
}

func (bc BarChart) drawTitle(r Renderer) <span class="cov8" title="1">{
        if len(bc.Title) &gt; 0 &amp;&amp; bc.TitleStyle.Show </span><span class="cov8" title="1">{
                r.SetFont(bc.TitleStyle.GetFont(bc.GetFont()))
                r.SetFontColor(bc.TitleStyle.GetFontColor(bc.GetColorPalette().TextColor()))
                titleFontSize := bc.TitleStyle.GetFontSize(bc.getTitleFontSize())
                r.SetFontSize(titleFontSize)

                textBox := r.MeasureText(bc.Title)

                textWidth := textBox.Width()
                textHeight := textBox.Height()

                titleX := (bc.GetWidth() &gt;&gt; 1) - (textWidth &gt;&gt; 1)
                titleY := bc.TitleStyle.Padding.GetTop(DefaultTitleTop) + textHeight

                r.Text(bc.Title, titleX, titleY)
        }</span>
}

func (bc BarChart) getCanvasStyle() Style <span class="cov8" title="1">{
        return bc.Canvas.InheritFrom(bc.styleDefaultsCanvas())
}</span>

func (bc BarChart) styleDefaultsCanvas() Style <span class="cov8" title="1">{
        return Style{
                FillColor:   bc.GetColorPalette().CanvasColor(),
                StrokeColor: bc.GetColorPalette().CanvasStrokeColor(),
                StrokeWidth: DefaultCanvasStrokeWidth,
        }
}</span>

func (bc BarChart) hasAxes() bool <span class="cov8" title="1">{
        return bc.YAxis.Style.Show
}</span>

func (bc BarChart) setRangeDomains(canvasBox Box, yr Range) Range <span class="cov8" title="1">{
        yr.SetDomain(canvasBox.Height())
        return yr
}</span>

func (bc BarChart) getDefaultCanvasBox() Box <span class="cov8" title="1">{
        return bc.box()
}</span>

func (bc BarChart) getValueFormatters() ValueFormatter <span class="cov8" title="1">{
        if bc.YAxis.ValueFormatter != nil </span><span class="cov8" title="1">{
                return bc.YAxis.ValueFormatter
        }</span>
        <span class="cov8" title="1">return FloatValueFormatter</span>
}

func (bc BarChart) getAxesTicks(r Renderer, yr Range, yf ValueFormatter) (yticks []Tick) <span class="cov8" title="1">{
        if bc.YAxis.Style.Show </span><span class="cov8" title="1">{
                yticks = bc.YAxis.GetTicks(r, yr, bc.styleDefaultsAxes(), yf)
        }</span>
        <span class="cov8" title="1">return</span>
}

func (bc BarChart) calculateEffectiveBarSpacing(canvasBox Box) int <span class="cov8" title="1">{
        totalWithBaseSpacing := bc.calculateTotalBarWidth(bc.GetBarWidth(), bc.GetBarSpacing())
        if totalWithBaseSpacing &gt; canvasBox.Width() </span><span class="cov8" title="1">{
                lessBarWidths := canvasBox.Width() - (len(bc.Bars) * bc.GetBarWidth())
                if lessBarWidths &gt; 0 </span><span class="cov0" title="0">{
                        return int(math.Ceil(float64(lessBarWidths) / float64(len(bc.Bars))))
                }</span>
                <span class="cov8" title="1">return 0</span>
        }
        <span class="cov8" title="1">return bc.GetBarSpacing()</span>
}

func (bc BarChart) calculateEffectiveBarWidth(canvasBox Box, spacing int) int <span class="cov8" title="1">{
        totalWithBaseWidth := bc.calculateTotalBarWidth(bc.GetBarWidth(), spacing)
        if totalWithBaseWidth &gt; canvasBox.Width() </span><span class="cov8" title="1">{
                totalLessBarSpacings := canvasBox.Width() - (len(bc.Bars) * spacing)
                if totalLessBarSpacings &gt; 0 </span><span class="cov8" title="1">{
                        return int(math.Ceil(float64(totalLessBarSpacings) / float64(len(bc.Bars))))
                }</span>
                <span class="cov0" title="0">return 0</span>
        }
        <span class="cov8" title="1">return bc.GetBarWidth()</span>
}

func (bc BarChart) calculateTotalBarWidth(barWidth, spacing int) int <span class="cov8" title="1">{
        return len(bc.Bars) * (barWidth + spacing)
}</span>

func (bc BarChart) calculateScaledTotalWidth(canvasBox Box) (width, spacing, total int) <span class="cov8" title="1">{
        spacing = bc.calculateEffectiveBarSpacing(canvasBox)
        width = bc.calculateEffectiveBarWidth(canvasBox, spacing)
        total = bc.calculateTotalBarWidth(width, spacing)
        return
}</span>

func (bc BarChart) getAdjustedCanvasBox(r Renderer, canvasBox Box, yrange Range, yticks []Tick) Box <span class="cov8" title="1">{
        axesOuterBox := canvasBox.Clone()

        _, _, totalWidth := bc.calculateScaledTotalWidth(canvasBox)

        if bc.XAxis.Show </span><span class="cov8" title="1">{
                xaxisHeight := DefaultVerticalTickHeight

                axisStyle := bc.XAxis.InheritFrom(bc.styleDefaultsAxes())
                axisStyle.WriteToRenderer(r)

                cursor := canvasBox.Left
                for _, bar := range bc.Bars </span><span class="cov8" title="1">{
                        if len(bar.Label) &gt; 0 </span><span class="cov8" title="1">{
                                barLabelBox := Box{
                                        Top:    canvasBox.Bottom + DefaultXAxisMargin,
                                        Left:   cursor,
                                        Right:  cursor + bc.GetBarWidth() + bc.GetBarSpacing(),
                                        Bottom: bc.GetHeight(),
                                }
                                lines := Text.WrapFit(r, bar.Label, barLabelBox.Width(), axisStyle)
                                linesBox := Text.MeasureLines(r, lines, axisStyle)

                                xaxisHeight = util.Math.MinInt(linesBox.Height()+(2*DefaultXAxisMargin), xaxisHeight)
                        }</span>
                }

                <span class="cov8" title="1">xbox := Box{
                        Top:    canvasBox.Top,
                        Left:   canvasBox.Left,
                        Right:  canvasBox.Left + totalWidth,
                        Bottom: bc.GetHeight() - xaxisHeight,
                }

                axesOuterBox = axesOuterBox.Grow(xbox)</span>
        }

        <span class="cov8" title="1">if bc.YAxis.Style.Show </span><span class="cov8" title="1">{
                axesBounds := bc.YAxis.Measure(r, canvasBox, yrange, bc.styleDefaultsAxes(), yticks)
                axesOuterBox = axesOuterBox.Grow(axesBounds)
        }</span>

        <span class="cov8" title="1">return canvasBox.OuterConstrain(bc.box(), axesOuterBox)</span>
}

// box returns the chart bounds as a box.
func (bc BarChart) box() Box <span class="cov8" title="1">{
        dpr := bc.Background.Padding.GetRight(10)
        dpb := bc.Background.Padding.GetBottom(50)

        return Box{
                Top:    bc.Background.Padding.GetTop(20),
                Left:   bc.Background.Padding.GetLeft(20),
                Right:  bc.GetWidth() - dpr,
                Bottom: bc.GetHeight() - dpb,
        }
}</span>

func (bc BarChart) getBackgroundStyle() Style <span class="cov8" title="1">{
        return bc.Background.InheritFrom(bc.styleDefaultsBackground())
}</span>

func (bc BarChart) styleDefaultsBackground() Style <span class="cov8" title="1">{
        return Style{
                FillColor:   bc.GetColorPalette().BackgroundColor(),
                StrokeColor: bc.GetColorPalette().BackgroundStrokeColor(),
                StrokeWidth: DefaultStrokeWidth,
        }
}</span>

func (bc BarChart) styleDefaultsBar(index int) Style <span class="cov8" title="1">{
        return Style{
                StrokeColor: bc.GetColorPalette().GetSeriesColor(index),
                StrokeWidth: 3.0,
                FillColor:   bc.GetColorPalette().GetSeriesColor(index),
        }
}</span>

func (bc BarChart) styleDefaultsTitle() Style <span class="cov0" title="0">{
        return bc.TitleStyle.InheritFrom(Style{
                FontColor:           bc.GetColorPalette().TextColor(),
                Font:                bc.GetFont(),
                FontSize:            bc.getTitleFontSize(),
                TextHorizontalAlign: TextHorizontalAlignCenter,
                TextVerticalAlign:   TextVerticalAlignTop,
                TextWrap:            TextWrapWord,
        })
}</span>

func (bc BarChart) getTitleFontSize() float64 <span class="cov8" title="1">{
        effectiveDimension := util.Math.MinInt(bc.GetWidth(), bc.GetHeight())
        if effectiveDimension &gt;= 2048 </span><span class="cov8" title="1">{
                return 48
        }</span> else<span class="cov8" title="1"> if effectiveDimension &gt;= 1024 </span><span class="cov8" title="1">{
                return 24
        }</span> else<span class="cov8" title="1"> if effectiveDimension &gt;= 512 </span><span class="cov8" title="1">{
                return 18
        }</span> else<span class="cov8" title="1"> if effectiveDimension &gt;= 256 </span><span class="cov8" title="1">{
                return 12
        }</span>
        <span class="cov8" title="1">return 10</span>
}

func (bc BarChart) styleDefaultsAxes() Style <span class="cov8" title="1">{
        return Style{
                StrokeColor:         bc.GetColorPalette().AxisStrokeColor(),
                Font:                bc.GetFont(),
                FontSize:            DefaultAxisFontSize,
                FontColor:           bc.GetColorPalette().TextColor(),
                TextHorizontalAlign: TextHorizontalAlignCenter,
                TextVerticalAlign:   TextVerticalAlignTop,
                TextWrap:            TextWrapWord,
        }
}</span>

func (bc BarChart) styleDefaultsElements() Style <span class="cov0" title="0">{
        return Style{
                Font: bc.GetFont(),
        }
}</span>

// GetColorPalette returns the color palette for the chart.
func (bc BarChart) GetColorPalette() ColorPalette <span class="cov8" title="1">{
        if bc.ColorPalette != nil </span><span class="cov0" title="0">{
                return bc.ColorPalette
        }</span>
        <span class="cov8" title="1">return AlternateColorPalette</span>
}
</pre>
		
		<pre class="file" id="file2" style="display: none">package chart

import (
        "fmt"

        "github.com/wcharczuk/go-chart/seq"
)

// Interface Assertions.
var (
        _ Series = (*BollingerBandsSeries)(nil)
)

// BollingerBandsSeries draws bollinger bands for an inner series.
// Bollinger bands are defined by two lines, one at SMA+k*stddev, one at SMA-k*stdev.
type BollingerBandsSeries struct {
        Name  string
        Style Style
        YAxis YAxisType

        Period      int
        K           float64
        InnerSeries ValuesProvider

        valueBuffer *seq.Buffer
}

// GetName returns the name of the time series.
func (bbs BollingerBandsSeries) GetName() string <span class="cov0" title="0">{
        return bbs.Name
}</span>

// GetStyle returns the line style.
func (bbs BollingerBandsSeries) GetStyle() Style <span class="cov0" title="0">{
        return bbs.Style
}</span>

// GetYAxis returns which YAxis the series draws on.
func (bbs BollingerBandsSeries) GetYAxis() YAxisType <span class="cov0" title="0">{
        return bbs.YAxis
}</span>

// GetPeriod returns the window size.
func (bbs BollingerBandsSeries) GetPeriod() int <span class="cov8" title="1">{
        if bbs.Period == 0 </span><span class="cov8" title="1">{
                return DefaultSimpleMovingAveragePeriod
        }</span>
        <span class="cov0" title="0">return bbs.Period</span>
}

// GetK returns the K value, or the number of standard deviations above and below
// to band the simple moving average with.
// Typical K value is 2.0.
func (bbs BollingerBandsSeries) GetK(defaults ...float64) float64 <span class="cov8" title="1">{
        if bbs.K == 0 </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov0" title="0">{
                        return defaults[0]
                }</span>
                <span class="cov8" title="1">return 2.0</span>
        }
        <span class="cov0" title="0">return bbs.K</span>
}

// Len returns the number of elements in the series.
func (bbs BollingerBandsSeries) Len() int <span class="cov0" title="0">{
        return bbs.InnerSeries.Len()
}</span>

// GetBoundedValues gets the bounded value for the series.
func (bbs *BollingerBandsSeries) GetBoundedValues(index int) (x, y1, y2 float64) <span class="cov8" title="1">{
        if bbs.InnerSeries == nil </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov8" title="1">if bbs.valueBuffer == nil || index == 0 </span><span class="cov8" title="1">{
                bbs.valueBuffer = seq.NewBufferWithCapacity(bbs.GetPeriod())
        }</span>
        <span class="cov8" title="1">if bbs.valueBuffer.Len() &gt;= bbs.GetPeriod() </span><span class="cov8" title="1">{
                bbs.valueBuffer.Dequeue()
        }</span>
        <span class="cov8" title="1">px, py := bbs.InnerSeries.GetValues(index)
        bbs.valueBuffer.Enqueue(py)
        x = px

        ay := seq.New(bbs.valueBuffer).Average()
        std := seq.New(bbs.valueBuffer).StdDev()

        y1 = ay + (bbs.GetK() * std)
        y2 = ay - (bbs.GetK() * std)
        return</span>
}

// GetBoundedLastValues returns the last bounded value for the series.
func (bbs *BollingerBandsSeries) GetBoundedLastValues() (x, y1, y2 float64) <span class="cov8" title="1">{
        if bbs.InnerSeries == nil </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov8" title="1">period := bbs.GetPeriod()
        seriesLength := bbs.InnerSeries.Len()
        startAt := seriesLength - period
        if startAt &lt; 0 </span><span class="cov0" title="0">{
                startAt = 0
        }</span>

        <span class="cov8" title="1">vb := seq.NewBufferWithCapacity(period)
        for index := startAt; index &lt; seriesLength; index++ </span><span class="cov8" title="1">{
                xn, yn := bbs.InnerSeries.GetValues(index)
                vb.Enqueue(yn)
                x = xn
        }</span>

        <span class="cov8" title="1">ay := seq.Seq{Provider: vb}.Average()
        std := seq.Seq{Provider: vb}.StdDev()

        y1 = ay + (bbs.GetK() * std)
        y2 = ay - (bbs.GetK() * std)

        return</span>
}

// Render renders the series.
func (bbs *BollingerBandsSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) <span class="cov0" title="0">{
        s := bbs.Style.InheritFrom(defaults.InheritFrom(Style{
                StrokeWidth: 1.0,
                StrokeColor: DefaultAxisColor.WithAlpha(64),
                FillColor:   DefaultAxisColor.WithAlpha(32),
        }))

        Draw.BoundedSeries(r, canvasBox, xrange, yrange, s, bbs, bbs.GetPeriod())
}</span>

// Validate validates the series.
func (bbs BollingerBandsSeries) Validate() error <span class="cov0" title="0">{
        if bbs.InnerSeries == nil </span><span class="cov0" title="0">{
                return fmt.Errorf("bollinger bands series requires InnerSeries to be set")
        }</span>
        <span class="cov0" title="0">return nil</span>
}
</pre>
		
		<pre class="file" id="file3" style="display: none">package chart

import (
        "fmt"
        "math"

        util "github.com/wcharczuk/go-chart/util"
)

var (
        // BoxZero is a preset box that represents an intentional zero value.
        BoxZero = Box{IsSet: true}
)

// NewBox returns a new (set) box.
func NewBox(top, left, right, bottom int) Box <span class="cov8" title="1">{
        return Box{
                IsSet:  true,
                Top:    top,
                Left:   left,
                Right:  right,
                Bottom: bottom,
        }
}</span>

// Box represents the main 4 dimensions of a box.
type Box struct {
        Top    int
        Left   int
        Right  int
        Bottom int
        IsSet  bool
}

// IsZero returns if the box is set or not.
func (b Box) IsZero() bool <span class="cov8" title="1">{
        if b.IsSet </span><span class="cov8" title="1">{
                return false
        }</span>
        <span class="cov8" title="1">return b.Top == 0 &amp;&amp; b.Left == 0 &amp;&amp; b.Right == 0 &amp;&amp; b.Bottom == 0</span>
}

// String returns a string representation of the box.
func (b Box) String() string <span class="cov8" title="1">{
        return fmt.Sprintf("box(%d,%d,%d,%d)", b.Top, b.Left, b.Right, b.Bottom)
}</span>

// GetTop returns a coalesced value with a default.
func (b Box) GetTop(defaults ...int) int <span class="cov8" title="1">{
        if !b.IsSet &amp;&amp; b.Top == 0 </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov0" title="0">return 0</span>
        }
        <span class="cov8" title="1">return b.Top</span>
}

// GetLeft returns a coalesced value with a default.
func (b Box) GetLeft(defaults ...int) int <span class="cov8" title="1">{
        if !b.IsSet &amp;&amp; b.Left == 0 </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov0" title="0">return 0</span>
        }
        <span class="cov8" title="1">return b.Left</span>
}

// GetRight returns a coalesced value with a default.
func (b Box) GetRight(defaults ...int) int <span class="cov8" title="1">{
        if !b.IsSet &amp;&amp; b.Right == 0 </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov0" title="0">return 0</span>
        }
        <span class="cov8" title="1">return b.Right</span>
}

// GetBottom returns a coalesced value with a default.
func (b Box) GetBottom(defaults ...int) int <span class="cov8" title="1">{
        if !b.IsSet &amp;&amp; b.Bottom == 0 </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov0" title="0">return 0</span>
        }
        <span class="cov8" title="1">return b.Bottom</span>
}

// Width returns the width
func (b Box) Width() int <span class="cov8" title="1">{
        return util.Math.AbsInt(b.Right - b.Left)
}</span>

// Height returns the height
func (b Box) Height() int <span class="cov8" title="1">{
        return util.Math.AbsInt(b.Bottom - b.Top)
}</span>

// Center returns the center of the box
func (b Box) Center() (x, y int) <span class="cov8" title="1">{
        w2, h2 := b.Width()&gt;&gt;1, b.Height()&gt;&gt;1
        return b.Left + w2, b.Top + h2
}</span>

// Aspect returns the aspect ratio of the box.
func (b Box) Aspect() float64 <span class="cov8" title="1">{
        return float64(b.Width()) / float64(b.Height())
}</span>

// Clone returns a new copy of the box.
func (b Box) Clone() Box <span class="cov8" title="1">{
        return Box{
                IsSet:  b.IsSet,
                Top:    b.Top,
                Left:   b.Left,
                Right:  b.Right,
                Bottom: b.Bottom,
        }
}</span>

// IsBiggerThan returns if a box is bigger than another box.
func (b Box) IsBiggerThan(other Box) bool <span class="cov8" title="1">{
        return b.Top &lt; other.Top ||
                b.Bottom &gt; other.Bottom ||
                b.Left &lt; other.Left ||
                b.Right &gt; other.Right
}</span>

// IsSmallerThan returns if a box is smaller than another box.
func (b Box) IsSmallerThan(other Box) bool <span class="cov8" title="1">{
        return b.Top &gt; other.Top &amp;&amp;
                b.Bottom &lt; other.Bottom &amp;&amp;
                b.Left &gt; other.Left &amp;&amp;
                b.Right &lt; other.Right
}</span>

// Equals returns if the box equals another box.
func (b Box) Equals(other Box) bool <span class="cov8" title="1">{
        return b.Top == other.Top &amp;&amp;
                b.Left == other.Left &amp;&amp;
                b.Right == other.Right &amp;&amp;
                b.Bottom == other.Bottom
}</span>

// Grow grows a box based on another box.
func (b Box) Grow(other Box) Box <span class="cov8" title="1">{
        return Box{
                Top:    util.Math.MinInt(b.Top, other.Top),
                Left:   util.Math.MinInt(b.Left, other.Left),
                Right:  util.Math.MaxInt(b.Right, other.Right),
                Bottom: util.Math.MaxInt(b.Bottom, other.Bottom),
        }
}</span>

// Shift pushes a box by x,y.
func (b Box) Shift(x, y int) Box <span class="cov8" title="1">{
        return Box{
                Top:    b.Top + y,
                Left:   b.Left + x,
                Right:  b.Right + x,
                Bottom: b.Bottom + y,
        }
}</span>

// Corners returns the box as a set of corners.
func (b Box) Corners() BoxCorners <span class="cov0" title="0">{
        return BoxCorners{
                TopLeft:     Point{b.Left, b.Top},
                TopRight:    Point{b.Right, b.Top},
                BottomRight: Point{b.Right, b.Bottom},
                BottomLeft:  Point{b.Left, b.Bottom},
        }
}</span>

// Fit is functionally the inverse of grow.
// Fit maintains the original aspect ratio of the `other` box,
// but constrains it to the bounds of the target box.
func (b Box) Fit(other Box) Box <span class="cov8" title="1">{
        ba := b.Aspect()
        oa := other.Aspect()

        if oa == ba </span><span class="cov8" title="1">{
                return b.Clone()
        }</span>

        <span class="cov8" title="1">bw, bh := float64(b.Width()), float64(b.Height())
        bw2 := int(bw) &gt;&gt; 1
        bh2 := int(bh) &gt;&gt; 1
        if oa &gt; ba </span><span class="cov8" title="1">{ // ex. 16:9 vs. 4:3
                var noh2 int
                if oa &gt; 1.0 </span><span class="cov8" title="1">{
                        noh2 = int(bw/oa) &gt;&gt; 1
                }</span> else<span class="cov0" title="0"> {
                        noh2 = int(bh*oa) &gt;&gt; 1
                }</span>
                <span class="cov8" title="1">return Box{
                        Top:    (b.Top + bh2) - noh2,
                        Left:   b.Left,
                        Right:  b.Right,
                        Bottom: (b.Top + bh2) + noh2,
                }</span>
        }
        <span class="cov8" title="1">var now2 int
        if oa &gt; 1.0 </span><span class="cov0" title="0">{
                now2 = int(bh/oa) &gt;&gt; 1
        }</span> else<span class="cov8" title="1"> {
                now2 = int(bw*oa) &gt;&gt; 1
        }</span>
        <span class="cov8" title="1">return Box{
                Top:    b.Top,
                Left:   (b.Left + bw2) - now2,
                Right:  (b.Left + bw2) + now2,
                Bottom: b.Bottom,
        }</span>
}

// Constrain is similar to `Fit` except that it will work
// more literally like the opposite of grow.
func (b Box) Constrain(other Box) Box <span class="cov8" title="1">{
        newBox := b.Clone()

        newBox.Top = util.Math.MaxInt(newBox.Top, other.Top)
        newBox.Left = util.Math.MaxInt(newBox.Left, other.Left)
        newBox.Right = util.Math.MinInt(newBox.Right, other.Right)
        newBox.Bottom = util.Math.MinInt(newBox.Bottom, other.Bottom)

        return newBox
}</span>

// OuterConstrain is similar to `Constraint` with the difference
// that it applies corrections
func (b Box) OuterConstrain(bounds, other Box) Box <span class="cov8" title="1">{
        newBox := b.Clone()
        if other.Top &lt; bounds.Top </span><span class="cov8" title="1">{
                delta := bounds.Top - other.Top
                newBox.Top = b.Top + delta
        }</span>

        <span class="cov8" title="1">if other.Left &lt; bounds.Left </span><span class="cov8" title="1">{
                delta := bounds.Left - other.Left
                newBox.Left = b.Left + delta
        }</span>

        <span class="cov8" title="1">if other.Right &gt; bounds.Right </span><span class="cov8" title="1">{
                delta := other.Right - bounds.Right
                newBox.Right = b.Right - delta
        }</span>

        <span class="cov8" title="1">if other.Bottom &gt; bounds.Bottom </span><span class="cov8" title="1">{
                delta := other.Bottom - bounds.Bottom
                newBox.Bottom = b.Bottom - delta
        }</span>
        <span class="cov8" title="1">return newBox</span>
}

// BoxCorners is a box with independent corners.
type BoxCorners struct {
        TopLeft, TopRight, BottomRight, BottomLeft Point
}

// Box return the BoxCorners as a regular box.
func (bc BoxCorners) Box() Box <span class="cov0" title="0">{
        return Box{
                Top:    util.Math.MinInt(bc.TopLeft.Y, bc.TopRight.Y),
                Left:   util.Math.MinInt(bc.TopLeft.X, bc.BottomLeft.X),
                Right:  util.Math.MaxInt(bc.TopRight.X, bc.BottomRight.X),
                Bottom: util.Math.MaxInt(bc.BottomLeft.Y, bc.BottomRight.Y),
        }
}</span>

// Width returns the width
func (bc BoxCorners) Width() int <span class="cov0" title="0">{
        minLeft := util.Math.MinInt(bc.TopLeft.X, bc.BottomLeft.X)
        maxRight := util.Math.MaxInt(bc.TopRight.X, bc.BottomRight.X)
        return maxRight - minLeft
}</span>

// Height returns the height
func (bc BoxCorners) Height() int <span class="cov0" title="0">{
        minTop := util.Math.MinInt(bc.TopLeft.Y, bc.TopRight.Y)
        maxBottom := util.Math.MaxInt(bc.BottomLeft.Y, bc.BottomRight.Y)
        return maxBottom - minTop
}</span>

// Center returns the center of the box
func (bc BoxCorners) Center() (x, y int) <span class="cov8" title="1">{

        left := util.Math.MeanInt(bc.TopLeft.X, bc.BottomLeft.X)
        right := util.Math.MeanInt(bc.TopRight.X, bc.BottomRight.X)
        x = ((right - left) &gt;&gt; 1) + left

        top := util.Math.MeanInt(bc.TopLeft.Y, bc.TopRight.Y)
        bottom := util.Math.MeanInt(bc.BottomLeft.Y, bc.BottomRight.Y)
        y = ((bottom - top) &gt;&gt; 1) + top

        return
}</span>

// Rotate rotates the box.
func (bc BoxCorners) Rotate(thetaDegrees float64) BoxCorners <span class="cov8" title="1">{
        cx, cy := bc.Center()

        thetaRadians := util.Math.DegreesToRadians(thetaDegrees)

        tlx, tly := util.Math.RotateCoordinate(cx, cy, bc.TopLeft.X, bc.TopLeft.Y, thetaRadians)
        trx, try := util.Math.RotateCoordinate(cx, cy, bc.TopRight.X, bc.TopRight.Y, thetaRadians)
        brx, bry := util.Math.RotateCoordinate(cx, cy, bc.BottomRight.X, bc.BottomRight.Y, thetaRadians)
        blx, bly := util.Math.RotateCoordinate(cx, cy, bc.BottomLeft.X, bc.BottomLeft.Y, thetaRadians)

        return BoxCorners{
                TopLeft:     Point{tlx, tly},
                TopRight:    Point{trx, try},
                BottomRight: Point{brx, bry},
                BottomLeft:  Point{blx, bly},
        }
}</span>

// Equals returns if the box equals another box.
func (bc BoxCorners) Equals(other BoxCorners) bool <span class="cov0" title="0">{
        return bc.TopLeft.Equals(other.TopLeft) &amp;&amp;
                bc.TopRight.Equals(other.TopRight) &amp;&amp;
                bc.BottomRight.Equals(other.BottomRight) &amp;&amp;
                bc.BottomLeft.Equals(other.BottomLeft)
}</span>

func (bc BoxCorners) String() string <span class="cov8" title="1">{
        return fmt.Sprintf("BoxC{%s,%s,%s,%s}", bc.TopLeft.String(), bc.TopRight.String(), bc.BottomRight.String(), bc.BottomLeft.String())
}</span>

// Point is an X,Y pair
type Point struct {
        X, Y int
}

// DistanceTo calculates the distance to another point.
func (p Point) DistanceTo(other Point) float64 <span class="cov0" title="0">{
        dx := math.Pow(float64(p.X-other.X), 2)
        dy := math.Pow(float64(p.Y-other.Y), 2)
        return math.Pow(dx+dy, 0.5)
}</span>

// Equals returns if a point equals another point.
func (p Point) Equals(other Point) bool <span class="cov8" title="1">{
        return p.X == other.X &amp;&amp; p.Y == other.Y
}</span>

// String returns a string representation of the point.
func (p Point) String() string <span class="cov8" title="1">{
        return fmt.Sprintf("P{%d,%d}", p.X, p.Y)
}</span>
</pre>
		
		<pre class="file" id="file4" style="display: none">package chart

import (
        "errors"
        "fmt"
        "io"
        "math"

        "github.com/golang/freetype/truetype"
        util "github.com/wcharczuk/go-chart/util"
)

// Chart is what we're drawing.
type Chart struct {
        Title      string
        TitleStyle Style

        ColorPalette ColorPalette

        Width  int
        Height int
        DPI    float64

        Background Style
        Canvas     Style

        XAxis          XAxis
        YAxis          YAxis
        YAxisSecondary YAxis

        Font        *truetype.Font
        defaultFont *truetype.Font

        Series   []Series
        Elements []Renderable
}

// GetDPI returns the dpi for the chart.
func (c Chart) GetDPI(defaults ...float64) float64 <span class="cov8" title="1">{
        if c.DPI == 0 </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov8" title="1">return DefaultDPI</span>
        }
        <span class="cov8" title="1">return c.DPI</span>
}

// GetFont returns the text font.
func (c Chart) GetFont() *truetype.Font <span class="cov8" title="1">{
        if c.Font == nil </span><span class="cov8" title="1">{
                return c.defaultFont
        }</span>
        <span class="cov8" title="1">return c.Font</span>
}

// GetWidth returns the chart width or the default value.
func (c Chart) GetWidth() int <span class="cov8" title="1">{
        if c.Width == 0 </span><span class="cov8" title="1">{
                return DefaultChartWidth
        }</span>
        <span class="cov8" title="1">return c.Width</span>
}

// GetHeight returns the chart height or the default value.
func (c Chart) GetHeight() int <span class="cov8" title="1">{
        if c.Height == 0 </span><span class="cov8" title="1">{
                return DefaultChartHeight
        }</span>
        <span class="cov8" title="1">return c.Height</span>
}

// Render renders the chart with the given renderer to the given io.Writer.
func (c Chart) Render(rp RendererProvider, w io.Writer) error <span class="cov8" title="1">{
        if len(c.Series) == 0 </span><span class="cov0" title="0">{
                return errors.New("please provide at least one series")
        }</span>
        <span class="cov8" title="1">if visibleSeriesErr := c.checkHasVisibleSeries(); visibleSeriesErr != nil </span><span class="cov0" title="0">{
                return visibleSeriesErr
        }</span>

        <span class="cov8" title="1">c.YAxisSecondary.AxisType = YAxisSecondary

        r, err := rp(c.GetWidth(), c.GetHeight())
        if err != nil </span><span class="cov0" title="0">{
                return err
        }</span>

        <span class="cov8" title="1">if c.Font == nil </span><span class="cov8" title="1">{
                defaultFont, err := GetDefaultFont()
                if err != nil </span><span class="cov0" title="0">{
                        return err
                }</span>
                <span class="cov8" title="1">c.defaultFont = defaultFont</span>
        }
        <span class="cov8" title="1">r.SetDPI(c.GetDPI(DefaultDPI))

        c.drawBackground(r)

        var xt, yt, yta []Tick
        xr, yr, yra := c.getRanges()
        canvasBox := c.getDefaultCanvasBox()
        xf, yf, yfa := c.getValueFormatters()

        xr, yr, yra = c.setRangeDomains(canvasBox, xr, yr, yra)

        err = c.checkRanges(xr, yr, yra)
        if err != nil </span><span class="cov8" title="1">{
                r.Save(w)
                return err
        }</span>

        <span class="cov8" title="1">if c.hasAxes() </span><span class="cov8" title="1">{
                xt, yt, yta = c.getAxesTicks(r, xr, yr, yra, xf, yf, yfa)
                canvasBox = c.getAxesAdjustedCanvasBox(r, canvasBox, xr, yr, yra, xt, yt, yta)
                xr, yr, yra = c.setRangeDomains(canvasBox, xr, yr, yra)

                // do a second pass in case things haven't settled yet.
                xt, yt, yta = c.getAxesTicks(r, xr, yr, yra, xf, yf, yfa)
                canvasBox = c.getAxesAdjustedCanvasBox(r, canvasBox, xr, yr, yra, xt, yt, yta)
                xr, yr, yra = c.setRangeDomains(canvasBox, xr, yr, yra)
        }</span>

        <span class="cov8" title="1">if c.hasAnnotationSeries() </span><span class="cov0" title="0">{
                canvasBox = c.getAnnotationAdjustedCanvasBox(r, canvasBox, xr, yr, yra, xf, yf, yfa)
                xr, yr, yra = c.setRangeDomains(canvasBox, xr, yr, yra)
                xt, yt, yta = c.getAxesTicks(r, xr, yr, yra, xf, yf, yfa)
        }</span>

        <span class="cov8" title="1">c.drawCanvas(r, canvasBox)
        c.drawAxes(r, canvasBox, xr, yr, yra, xt, yt, yta)
        for index, series := range c.Series </span><span class="cov8" title="1">{
                c.drawSeries(r, canvasBox, xr, yr, yra, series, index)
        }</span>

        <span class="cov8" title="1">c.drawTitle(r)

        for _, a := range c.Elements </span><span class="cov8" title="1">{
                a(r, canvasBox, c.styleDefaultsElements())
        }</span>

        <span class="cov8" title="1">return r.Save(w)</span>
}

func (c Chart) checkHasVisibleSeries() error <span class="cov8" title="1">{
        hasVisibleSeries := false
        var style Style
        for _, s := range c.Series </span><span class="cov8" title="1">{
                style = s.GetStyle()
                hasVisibleSeries = hasVisibleSeries || (style.IsZero() || style.Show)
        }</span>
        <span class="cov8" title="1">if !hasVisibleSeries </span><span class="cov0" title="0">{
                return fmt.Errorf("must have (1) visible series; make sure if you set a style, you set .Show = true")
        }</span>
        <span class="cov8" title="1">return nil</span>
}

func (c Chart) validateSeries() error <span class="cov8" title="1">{
        var err error
        for _, s := range c.Series </span><span class="cov8" title="1">{
                err = s.Validate()
                if err != nil </span><span class="cov8" title="1">{
                        return err
                }</span>
        }
        <span class="cov8" title="1">return nil</span>
}

func (c Chart) getRanges() (xrange, yrange, yrangeAlt Range) <span class="cov8" title="1">{
        var minx, maxx float64 = math.MaxFloat64, -math.MaxFloat64
        var miny, maxy float64 = math.MaxFloat64, -math.MaxFloat64
        var minya, maxya float64 = math.MaxFloat64, -math.MaxFloat64

        seriesMappedToSecondaryAxis := false

        // note: a possible future optimization is to not scan the series values if
        // all axis are represented by either custom ticks or custom ranges.
        for _, s := range c.Series </span><span class="cov8" title="1">{
                if s.GetStyle().IsZero() || s.GetStyle().Show </span><span class="cov8" title="1">{
                        seriesAxis := s.GetYAxis()
                        if bvp, isBoundedValuesProvider := s.(BoundedValuesProvider); isBoundedValuesProvider </span><span class="cov0" title="0">{
                                seriesLength := bvp.Len()
                                for index := 0; index &lt; seriesLength; index++ </span><span class="cov0" title="0">{
                                        vx, vy1, vy2 := bvp.GetBoundedValues(index)

                                        minx = math.Min(minx, vx)
                                        maxx = math.Max(maxx, vx)

                                        if seriesAxis == YAxisPrimary </span><span class="cov0" title="0">{
                                                miny = math.Min(miny, vy1)
                                                miny = math.Min(miny, vy2)
                                                maxy = math.Max(maxy, vy1)
                                                maxy = math.Max(maxy, vy2)
                                        }</span> else<span class="cov0" title="0"> if seriesAxis == YAxisSecondary </span><span class="cov0" title="0">{
                                                minya = math.Min(minya, vy1)
                                                minya = math.Min(minya, vy2)
                                                maxya = math.Max(maxya, vy1)
                                                maxya = math.Max(maxya, vy2)
                                                seriesMappedToSecondaryAxis = true
                                        }</span>
                                }
                        } else<span class="cov8" title="1"> if vp, isValuesProvider := s.(ValuesProvider); isValuesProvider </span><span class="cov8" title="1">{
                                seriesLength := vp.Len()
                                for index := 0; index &lt; seriesLength; index++ </span><span class="cov8" title="1">{
                                        vx, vy := vp.GetValues(index)

                                        minx = math.Min(minx, vx)
                                        maxx = math.Max(maxx, vx)

                                        if seriesAxis == YAxisPrimary </span><span class="cov8" title="1">{
                                                miny = math.Min(miny, vy)
                                                maxy = math.Max(maxy, vy)
                                        }</span> else<span class="cov8" title="1"> if seriesAxis == YAxisSecondary </span><span class="cov8" title="1">{
                                                minya = math.Min(minya, vy)
                                                maxya = math.Max(maxya, vy)
                                                seriesMappedToSecondaryAxis = true
                                        }</span>
                                }
                        }
                }
        }

        <span class="cov8" title="1">if c.XAxis.Range == nil </span><span class="cov8" title="1">{
                xrange = &amp;ContinuousRange{}
        }</span> else<span class="cov8" title="1"> {
                xrange = c.XAxis.Range
        }</span>

        <span class="cov8" title="1">if c.YAxis.Range == nil </span><span class="cov8" title="1">{
                yrange = &amp;ContinuousRange{}
        }</span> else<span class="cov8" title="1"> {
                yrange = c.YAxis.Range
        }</span>

        <span class="cov8" title="1">if c.YAxisSecondary.Range == nil </span><span class="cov8" title="1">{
                yrangeAlt = &amp;ContinuousRange{}
        }</span> else<span class="cov8" title="1"> {
                yrangeAlt = c.YAxisSecondary.Range
        }</span>

        <span class="cov8" title="1">if len(c.XAxis.Ticks) &gt; 0 </span><span class="cov0" title="0">{
                tickMin, tickMax := math.MaxFloat64, -math.MaxFloat64
                for _, t := range c.XAxis.Ticks </span><span class="cov0" title="0">{
                        tickMin = math.Min(tickMin, t.Value)
                        tickMax = math.Max(tickMax, t.Value)
                }</span>
                <span class="cov0" title="0">xrange.SetMin(tickMin)
                xrange.SetMax(tickMax)</span>
        } else<span class="cov8" title="1"> if xrange.IsZero() </span><span class="cov8" title="1">{
                xrange.SetMin(minx)
                xrange.SetMax(maxx)
        }</span>

        <span class="cov8" title="1">if len(c.YAxis.Ticks) &gt; 0 </span><span class="cov8" title="1">{
                tickMin, tickMax := math.MaxFloat64, -math.MaxFloat64
                for _, t := range c.YAxis.Ticks </span><span class="cov8" title="1">{
                        tickMin = math.Min(tickMin, t.Value)
                        tickMax = math.Max(tickMax, t.Value)
                }</span>
                <span class="cov8" title="1">yrange.SetMin(tickMin)
                yrange.SetMax(tickMax)</span>
        } else<span class="cov8" title="1"> if yrange.IsZero() </span><span class="cov8" title="1">{
                yrange.SetMin(miny)
                yrange.SetMax(maxy)

                // only round if we're showing the axis
                if c.YAxis.Style.Show </span><span class="cov0" title="0">{
                        delta := yrange.GetDelta()
                        roundTo := util.Math.GetRoundToForDelta(delta)
                        rmin, rmax := util.Math.RoundDown(yrange.GetMin(), roundTo), util.Math.RoundUp(yrange.GetMax(), roundTo)

                        yrange.SetMin(rmin)
                        yrange.SetMax(rmax)
                }</span>
        }

        <span class="cov8" title="1">if len(c.YAxisSecondary.Ticks) &gt; 0 </span><span class="cov0" title="0">{
                tickMin, tickMax := math.MaxFloat64, -math.MaxFloat64
                for _, t := range c.YAxis.Ticks </span><span class="cov0" title="0">{
                        tickMin = math.Min(tickMin, t.Value)
                        tickMax = math.Max(tickMax, t.Value)
                }</span>
                <span class="cov0" title="0">yrangeAlt.SetMin(tickMin)
                yrangeAlt.SetMax(tickMax)</span>
        } else<span class="cov8" title="1"> if seriesMappedToSecondaryAxis &amp;&amp; yrangeAlt.IsZero() </span><span class="cov8" title="1">{
                yrangeAlt.SetMin(minya)
                yrangeAlt.SetMax(maxya)

                if c.YAxisSecondary.Style.Show </span><span class="cov0" title="0">{
                        delta := yrangeAlt.GetDelta()
                        roundTo := util.Math.GetRoundToForDelta(delta)
                        rmin, rmax := util.Math.RoundDown(yrangeAlt.GetMin(), roundTo), util.Math.RoundUp(yrangeAlt.GetMax(), roundTo)
                        yrangeAlt.SetMin(rmin)
                        yrangeAlt.SetMax(rmax)
                }</span>
        }

        <span class="cov8" title="1">return</span>
}

func (c Chart) checkRanges(xr, yr, yra Range) error <span class="cov8" title="1">{
        xDelta := xr.GetDelta()
        if math.IsInf(xDelta, 0) </span><span class="cov8" title="1">{
                return errors.New("infinite x-range delta")
        }</span>
        <span class="cov8" title="1">if math.IsNaN(xDelta) </span><span class="cov0" title="0">{
                return errors.New("nan x-range delta")
        }</span>
        <span class="cov8" title="1">if xDelta == 0 </span><span class="cov0" title="0">{
                return errors.New("zero x-range delta; there needs to be at least (2) values")
        }</span>

        <span class="cov8" title="1">yDelta := yr.GetDelta()
        if math.IsInf(yDelta, 0) </span><span class="cov8" title="1">{
                return errors.New("infinite y-range delta")
        }</span>
        <span class="cov8" title="1">if math.IsNaN(yDelta) </span><span class="cov0" title="0">{
                return errors.New("nan y-range delta")
        }</span>

        <span class="cov8" title="1">if c.hasSecondarySeries() </span><span class="cov0" title="0">{
                yraDelta := yra.GetDelta()
                if math.IsInf(yraDelta, 0) </span><span class="cov0" title="0">{
                        return errors.New("infinite secondary y-range delta")
                }</span>
                <span class="cov0" title="0">if math.IsNaN(yraDelta) </span><span class="cov0" title="0">{
                        return errors.New("nan secondary y-range delta")
                }</span>
        }

        <span class="cov8" title="1">return nil</span>
}

func (c Chart) getDefaultCanvasBox() Box <span class="cov8" title="1">{
        return c.Box()
}</span>

func (c Chart) getValueFormatters() (x, y, ya ValueFormatter) <span class="cov8" title="1">{
        for _, s := range c.Series </span><span class="cov8" title="1">{
                if vfp, isVfp := s.(ValueFormatterProvider); isVfp </span><span class="cov8" title="1">{
                        sx, sy := vfp.GetValueFormatters()
                        if s.GetYAxis() == YAxisPrimary </span><span class="cov8" title="1">{
                                x = sx
                                y = sy
                        }</span> else<span class="cov8" title="1"> if s.GetYAxis() == YAxisSecondary </span><span class="cov8" title="1">{
                                x = sx
                                ya = sy
                        }</span>
                }
        }
        <span class="cov8" title="1">if c.XAxis.ValueFormatter != nil </span><span class="cov0" title="0">{
                x = c.XAxis.GetValueFormatter()
        }</span>
        <span class="cov8" title="1">if c.YAxis.ValueFormatter != nil </span><span class="cov0" title="0">{
                y = c.YAxis.GetValueFormatter()
        }</span>
        <span class="cov8" title="1">if c.YAxisSecondary.ValueFormatter != nil </span><span class="cov0" title="0">{
                ya = c.YAxisSecondary.GetValueFormatter()
        }</span>
        <span class="cov8" title="1">return</span>
}

func (c Chart) hasAxes() bool <span class="cov8" title="1">{
        return c.XAxis.Style.Show || c.YAxis.Style.Show || c.YAxisSecondary.Style.Show
}</span>

func (c Chart) getAxesTicks(r Renderer, xr, yr, yar Range, xf, yf, yfa ValueFormatter) (xticks, yticks, yticksAlt []Tick) <span class="cov8" title="1">{
        if c.XAxis.Style.Show </span><span class="cov8" title="1">{
                xticks = c.XAxis.GetTicks(r, xr, c.styleDefaultsAxes(), xf)
        }</span>
        <span class="cov8" title="1">if c.YAxis.Style.Show </span><span class="cov8" title="1">{
                yticks = c.YAxis.GetTicks(r, yr, c.styleDefaultsAxes(), yf)
        }</span>
        <span class="cov8" title="1">if c.YAxisSecondary.Style.Show </span><span class="cov8" title="1">{
                yticksAlt = c.YAxisSecondary.GetTicks(r, yar, c.styleDefaultsAxes(), yfa)
        }</span>
        <span class="cov8" title="1">return</span>
}

func (c Chart) getAxesAdjustedCanvasBox(r Renderer, canvasBox Box, xr, yr, yra Range, xticks, yticks, yticksAlt []Tick) Box <span class="cov8" title="1">{
        axesOuterBox := canvasBox.Clone()
        if c.XAxis.Style.Show </span><span class="cov8" title="1">{
                axesBounds := c.XAxis.Measure(r, canvasBox, xr, c.styleDefaultsAxes(), xticks)
                axesOuterBox = axesOuterBox.Grow(axesBounds)
        }</span>
        <span class="cov8" title="1">if c.YAxis.Style.Show </span><span class="cov8" title="1">{
                axesBounds := c.YAxis.Measure(r, canvasBox, yr, c.styleDefaultsAxes(), yticks)
                axesOuterBox = axesOuterBox.Grow(axesBounds)
        }</span>
        <span class="cov8" title="1">if c.YAxisSecondary.Style.Show </span><span class="cov0" title="0">{
                axesBounds := c.YAxisSecondary.Measure(r, canvasBox, yra, c.styleDefaultsAxes(), yticksAlt)
                axesOuterBox = axesOuterBox.Grow(axesBounds)
        }</span>

        <span class="cov8" title="1">return canvasBox.OuterConstrain(c.Box(), axesOuterBox)</span>
}

func (c Chart) setRangeDomains(canvasBox Box, xr, yr, yra Range) (Range, Range, Range) <span class="cov8" title="1">{
        xr.SetDomain(canvasBox.Width())
        yr.SetDomain(canvasBox.Height())
        yra.SetDomain(canvasBox.Height())
        return xr, yr, yra
}</span>

func (c Chart) hasAnnotationSeries() bool <span class="cov8" title="1">{
        for _, s := range c.Series </span><span class="cov8" title="1">{
                if as, isAnnotationSeries := s.(AnnotationSeries); isAnnotationSeries </span><span class="cov0" title="0">{
                        if as.Style.IsZero() || as.Style.Show </span><span class="cov0" title="0">{
                                return true
                        }</span>
                }
        }
        <span class="cov8" title="1">return false</span>
}

func (c Chart) hasSecondarySeries() bool <span class="cov8" title="1">{
        for _, s := range c.Series </span><span class="cov8" title="1">{
                if s.GetYAxis() == YAxisSecondary </span><span class="cov0" title="0">{
                        return true
                }</span>
        }
        <span class="cov8" title="1">return false</span>
}

func (c Chart) getAnnotationAdjustedCanvasBox(r Renderer, canvasBox Box, xr, yr, yra Range, xf, yf, yfa ValueFormatter) Box <span class="cov0" title="0">{
        annotationSeriesBox := canvasBox.Clone()
        for seriesIndex, s := range c.Series </span><span class="cov0" title="0">{
                if as, isAnnotationSeries := s.(AnnotationSeries); isAnnotationSeries </span><span class="cov0" title="0">{
                        if as.Style.IsZero() || as.Style.Show </span><span class="cov0" title="0">{
                                style := c.styleDefaultsSeries(seriesIndex)
                                var annotationBounds Box
                                if as.YAxis == YAxisPrimary </span><span class="cov0" title="0">{
                                        annotationBounds = as.Measure(r, canvasBox, xr, yr, style)
                                }</span> else<span class="cov0" title="0"> if as.YAxis == YAxisSecondary </span><span class="cov0" title="0">{
                                        annotationBounds = as.Measure(r, canvasBox, xr, yra, style)
                                }</span>

                                <span class="cov0" title="0">annotationSeriesBox = annotationSeriesBox.Grow(annotationBounds)</span>
                        }
                }
        }

        <span class="cov0" title="0">return canvasBox.OuterConstrain(c.Box(), annotationSeriesBox)</span>
}

func (c Chart) getBackgroundStyle() Style <span class="cov8" title="1">{
        return c.Background.InheritFrom(c.styleDefaultsBackground())
}</span>

func (c Chart) drawBackground(r Renderer) <span class="cov8" title="1">{
        Draw.Box(r, Box{
                Right:  c.GetWidth(),
                Bottom: c.GetHeight(),
        }, c.getBackgroundStyle())
}</span>

func (c Chart) getCanvasStyle() Style <span class="cov8" title="1">{
        return c.Canvas.InheritFrom(c.styleDefaultsCanvas())
}</span>

func (c Chart) drawCanvas(r Renderer, canvasBox Box) <span class="cov8" title="1">{
        Draw.Box(r, canvasBox, c.getCanvasStyle())
}</span>

func (c Chart) drawAxes(r Renderer, canvasBox Box, xrange, yrange, yrangeAlt Range, xticks, yticks, yticksAlt []Tick) <span class="cov8" title="1">{
        if c.XAxis.Style.Show </span><span class="cov8" title="1">{
                c.XAxis.Render(r, canvasBox, xrange, c.styleDefaultsAxes(), xticks)
        }</span>
        <span class="cov8" title="1">if c.YAxis.Style.Show </span><span class="cov8" title="1">{
                c.YAxis.Render(r, canvasBox, yrange, c.styleDefaultsAxes(), yticks)
        }</span>
        <span class="cov8" title="1">if c.YAxisSecondary.Style.Show </span><span class="cov0" title="0">{
                c.YAxisSecondary.Render(r, canvasBox, yrangeAlt, c.styleDefaultsAxes(), yticksAlt)
        }</span>
}

func (c Chart) drawSeries(r Renderer, canvasBox Box, xrange, yrange, yrangeAlt Range, s Series, seriesIndex int) <span class="cov8" title="1">{
        if s.GetStyle().IsZero() || s.GetStyle().Show </span><span class="cov8" title="1">{
                if s.GetYAxis() == YAxisPrimary </span><span class="cov8" title="1">{
                        s.Render(r, canvasBox, xrange, yrange, c.styleDefaultsSeries(seriesIndex))
                }</span> else<span class="cov0" title="0"> if s.GetYAxis() == YAxisSecondary </span><span class="cov0" title="0">{
                        s.Render(r, canvasBox, xrange, yrangeAlt, c.styleDefaultsSeries(seriesIndex))
                }</span>
        }
}

func (c Chart) drawTitle(r Renderer) <span class="cov8" title="1">{
        if len(c.Title) &gt; 0 &amp;&amp; c.TitleStyle.Show </span><span class="cov8" title="1">{
                r.SetFont(c.TitleStyle.GetFont(c.GetFont()))
                r.SetFontColor(c.TitleStyle.GetFontColor(c.GetColorPalette().TextColor()))
                titleFontSize := c.TitleStyle.GetFontSize(DefaultTitleFontSize)
                r.SetFontSize(titleFontSize)

                textBox := r.MeasureText(c.Title)

                textWidth := textBox.Width()
                textHeight := textBox.Height()

                titleX := (c.GetWidth() &gt;&gt; 1) - (textWidth &gt;&gt; 1)
                titleY := c.TitleStyle.Padding.GetTop(DefaultTitleTop) + textHeight

                r.Text(c.Title, titleX, titleY)
        }</span>
}

func (c Chart) styleDefaultsBackground() Style <span class="cov8" title="1">{
        return Style{
                FillColor:   c.GetColorPalette().BackgroundColor(),
                StrokeColor: c.GetColorPalette().BackgroundStrokeColor(),
                StrokeWidth: DefaultBackgroundStrokeWidth,
        }
}</span>

func (c Chart) styleDefaultsCanvas() Style <span class="cov8" title="1">{
        return Style{
                FillColor:   c.GetColorPalette().CanvasColor(),
                StrokeColor: c.GetColorPalette().CanvasStrokeColor(),
                StrokeWidth: DefaultCanvasStrokeWidth,
        }
}</span>

func (c Chart) styleDefaultsSeries(seriesIndex int) Style <span class="cov8" title="1">{
        return Style{
                DotColor:    c.GetColorPalette().GetSeriesColor(seriesIndex),
                StrokeColor: c.GetColorPalette().GetSeriesColor(seriesIndex),
                StrokeWidth: DefaultSeriesLineWidth,
                Font:        c.GetFont(),
                FontSize:    DefaultFontSize,
        }
}</span>

func (c Chart) styleDefaultsAxes() Style <span class="cov8" title="1">{
        return Style{
                Font:        c.GetFont(),
                FontColor:   c.GetColorPalette().TextColor(),
                FontSize:    DefaultAxisFontSize,
                StrokeColor: c.GetColorPalette().AxisStrokeColor(),
                StrokeWidth: DefaultAxisLineWidth,
        }
}</span>

func (c Chart) styleDefaultsElements() Style <span class="cov8" title="1">{
        return Style{
                Font: c.GetFont(),
        }
}</span>

// GetColorPalette returns the color palette for the chart.
func (c Chart) GetColorPalette() ColorPalette <span class="cov8" title="1">{
        if c.ColorPalette != nil </span><span class="cov0" title="0">{
                return c.ColorPalette
        }</span>
        <span class="cov8" title="1">return DefaultColorPalette</span>
}

// Box returns the chart bounds as a box.
func (c Chart) Box() Box <span class="cov8" title="1">{
        dpr := c.Background.Padding.GetRight(DefaultBackgroundPadding.Right)
        dpb := c.Background.Padding.GetBottom(DefaultBackgroundPadding.Bottom)

        return Box{
                Top:    c.Background.Padding.GetTop(DefaultBackgroundPadding.Top),
                Left:   c.Background.Padding.GetLeft(DefaultBackgroundPadding.Left),
                Right:  c.GetWidth() - dpr,
                Bottom: c.GetHeight() - dpb,
        }
}</span>
</pre>
		
		<pre class="file" id="file5" style="display: none">package chart

import "github.com/wcharczuk/go-chart/drawing"

var (
        // ColorWhite is white.
        ColorWhite = drawing.Color{R: 255, G: 255, B: 255, A: 255}
        // ColorBlue is the basic theme blue color.
        ColorBlue = drawing.Color{R: 0, G: 116, B: 217, A: 255}
        // ColorCyan is the basic theme cyan color.
        ColorCyan = drawing.Color{R: 0, G: 217, B: 210, A: 255}
        // ColorGreen is the basic theme green color.
        ColorGreen = drawing.Color{R: 0, G: 217, B: 101, A: 255}
        // ColorRed is the basic theme red color.
        ColorRed = drawing.Color{R: 217, G: 0, B: 116, A: 255}
        // ColorOrange is the basic theme orange color.
        ColorOrange = drawing.Color{R: 217, G: 101, B: 0, A: 255}
        // ColorYellow is the basic theme yellow color.
        ColorYellow = drawing.Color{R: 217, G: 210, B: 0, A: 255}
        // ColorBlack is the basic theme black color.
        ColorBlack = drawing.Color{R: 51, G: 51, B: 51, A: 255}
        // ColorLightGray is the basic theme light gray color.
        ColorLightGray = drawing.Color{R: 239, G: 239, B: 239, A: 255}

        // ColorAlternateBlue is a alternate theme color.
        ColorAlternateBlue = drawing.Color{R: 106, G: 195, B: 203, A: 255}
        // ColorAlternateGreen is a alternate theme color.
        ColorAlternateGreen = drawing.Color{R: 42, G: 190, B: 137, A: 255}
        // ColorAlternateGray is a alternate theme color.
        ColorAlternateGray = drawing.Color{R: 110, G: 128, B: 139, A: 255}
        // ColorAlternateYellow is a alternate theme color.
        ColorAlternateYellow = drawing.Color{R: 240, G: 174, B: 90, A: 255}
        // ColorAlternateLightGray is a alternate theme color.
        ColorAlternateLightGray = drawing.Color{R: 187, G: 190, B: 191, A: 255}

        // ColorTransparent is a transparent (alpha zero) color.
        ColorTransparent = drawing.Color{R: 1, G: 1, B: 1, A: 0}
)

var (
        // DefaultBackgroundColor is the default chart background color.
        // It is equivalent to css color:white.
        DefaultBackgroundColor = ColorWhite
        // DefaultBackgroundStrokeColor is the default chart border color.
        // It is equivalent to color:white.
        DefaultBackgroundStrokeColor = ColorWhite
        // DefaultCanvasColor is the default chart canvas color.
        // It is equivalent to css color:white.
        DefaultCanvasColor = ColorWhite
        // DefaultCanvasStrokeColor is the default chart canvas stroke color.
        // It is equivalent to css color:white.
        DefaultCanvasStrokeColor = ColorWhite
        // DefaultTextColor is the default chart text color.
        // It is equivalent to #333333.
        DefaultTextColor = ColorBlack
        // DefaultAxisColor is the default chart axis line color.
        // It is equivalent to #333333.
        DefaultAxisColor = ColorBlack
        // DefaultStrokeColor is the default chart border color.
        // It is equivalent to #efefef.
        DefaultStrokeColor = ColorLightGray
        // DefaultFillColor is the default fill color.
        // It is equivalent to #0074d9.
        DefaultFillColor = ColorBlue
        // DefaultAnnotationFillColor is the default annotation background color.
        DefaultAnnotationFillColor = ColorWhite
        // DefaultGridLineColor is the default grid line color.
        DefaultGridLineColor = ColorLightGray
)

var (
        // DefaultColors are a couple default series colors.
        DefaultColors = []drawing.Color{
                ColorBlue,
                ColorGreen,
                ColorRed,
                ColorCyan,
                ColorOrange,
        }

        // DefaultAlternateColors are a couple alternate colors.
        DefaultAlternateColors = []drawing.Color{
                ColorAlternateBlue,
                ColorAlternateGreen,
                ColorAlternateGray,
                ColorAlternateYellow,
                ColorBlue,
                ColorGreen,
                ColorRed,
                ColorCyan,
                ColorOrange,
        }
)

// GetDefaultColor returns a color from the default list by index.
// NOTE: the index will wrap around (using a modulo).
func GetDefaultColor(index int) drawing.Color <span class="cov8" title="1">{
        finalIndex := index % len(DefaultColors)
        return DefaultColors[finalIndex]
}</span>

// GetAlternateColor returns a color from the default list by index.
// NOTE: the index will wrap around (using a modulo).
func GetAlternateColor(index int) drawing.Color <span class="cov8" title="1">{
        finalIndex := index % len(DefaultAlternateColors)
        return DefaultAlternateColors[finalIndex]
}</span>

// ColorPalette is a set of colors that.
type ColorPalette interface {
        BackgroundColor() drawing.Color
        BackgroundStrokeColor() drawing.Color
        CanvasColor() drawing.Color
        CanvasStrokeColor() drawing.Color
        AxisStrokeColor() drawing.Color
        TextColor() drawing.Color
        GetSeriesColor(index int) drawing.Color
}

// DefaultColorPalette represents the default palatte.
var DefaultColorPalette defaultColorPalette

type defaultColorPalette struct{}

func (dp defaultColorPalette) BackgroundColor() drawing.Color <span class="cov8" title="1">{
        return DefaultBackgroundColor
}</span>

func (dp defaultColorPalette) BackgroundStrokeColor() drawing.Color <span class="cov8" title="1">{
        return DefaultBackgroundStrokeColor
}</span>

func (dp defaultColorPalette) CanvasColor() drawing.Color <span class="cov8" title="1">{
        return DefaultCanvasColor
}</span>

func (dp defaultColorPalette) CanvasStrokeColor() drawing.Color <span class="cov8" title="1">{
        return DefaultCanvasStrokeColor
}</span>

func (dp defaultColorPalette) AxisStrokeColor() drawing.Color <span class="cov8" title="1">{
        return DefaultAxisColor
}</span>

func (dp defaultColorPalette) TextColor() drawing.Color <span class="cov8" title="1">{
        return DefaultTextColor
}</span>

func (dp defaultColorPalette) GetSeriesColor(index int) drawing.Color <span class="cov8" title="1">{
        return GetDefaultColor(index)
}</span>

// AlternateColorPalette represents the default palatte.
var AlternateColorPalette alternateColorPalette

type alternateColorPalette struct{}

func (ap alternateColorPalette) BackgroundColor() drawing.Color <span class="cov8" title="1">{
        return DefaultBackgroundColor
}</span>

func (ap alternateColorPalette) BackgroundStrokeColor() drawing.Color <span class="cov8" title="1">{
        return DefaultBackgroundStrokeColor
}</span>

func (ap alternateColorPalette) CanvasColor() drawing.Color <span class="cov8" title="1">{
        return DefaultCanvasColor
}</span>

func (ap alternateColorPalette) CanvasStrokeColor() drawing.Color <span class="cov8" title="1">{
        return DefaultCanvasStrokeColor
}</span>

func (ap alternateColorPalette) AxisStrokeColor() drawing.Color <span class="cov8" title="1">{
        return DefaultAxisColor
}</span>

func (ap alternateColorPalette) TextColor() drawing.Color <span class="cov8" title="1">{
        return DefaultTextColor
}</span>

func (ap alternateColorPalette) GetSeriesColor(index int) drawing.Color <span class="cov8" title="1">{
        return GetAlternateColor(index)
}</span>
</pre>
		
		<pre class="file" id="file6" style="display: none">package chart

// ConcatSeries is a special type of series that concatenates its `InnerSeries`.
type ConcatSeries []Series

// Len returns the length of the concatenated set of series.
func (cs ConcatSeries) Len() int <span class="cov8" title="1">{
        total := 0
        for _, s := range cs </span><span class="cov8" title="1">{
                if typed, isValuesProvider := s.(ValuesProvider); isValuesProvider </span><span class="cov8" title="1">{
                        total += typed.Len()
                }</span>
        }

        <span class="cov8" title="1">return total</span>
}

// GetValue returns the value at the (meta) index (i.e 0 =&gt; totalLen-1)
func (cs ConcatSeries) GetValue(index int) (x, y float64) <span class="cov8" title="1">{
        cursor := 0
        for _, s := range cs </span><span class="cov8" title="1">{
                if typed, isValuesProvider := s.(ValuesProvider); isValuesProvider </span><span class="cov8" title="1">{
                        len := typed.Len()
                        if index &lt; cursor+len </span><span class="cov8" title="1">{
                                x, y = typed.GetValues(index - cursor) //FENCEPOSTS.
                                return
                        }</span>
                        <span class="cov8" title="1">cursor += typed.Len()</span>
                }
        }
        <span class="cov0" title="0">return</span>
}

// Validate validates the series.
func (cs ConcatSeries) Validate() error <span class="cov0" title="0">{
        var err error
        for _, s := range cs </span><span class="cov0" title="0">{
                err = s.Validate()
                if err != nil </span><span class="cov0" title="0">{
                        return err
                }</span>
        }
        <span class="cov0" title="0">return nil</span>
}
</pre>
		
		<pre class="file" id="file7" style="display: none">package chart

import (
        "fmt"
        "math"
)

// ContinuousRange represents a boundary for a set of numbers.
type ContinuousRange struct {
        Min        float64
        Max        float64
        Domain     int
        Descending bool
}

// IsDescending returns if the range is descending.
func (r ContinuousRange) IsDescending() bool <span class="cov8" title="1">{
        return r.Descending
}</span>

// IsZero returns if the ContinuousRange has been set or not.
func (r ContinuousRange) IsZero() bool <span class="cov8" title="1">{
        return (r.Min == 0 || math.IsNaN(r.Min)) &amp;&amp;
                (r.Max == 0 || math.IsNaN(r.Max)) &amp;&amp;
                r.Domain == 0
}</span>

// GetMin gets the min value for the continuous range.
func (r ContinuousRange) GetMin() float64 <span class="cov8" title="1">{
        return r.Min
}</span>

// SetMin sets the min value for the continuous range.
func (r *ContinuousRange) SetMin(min float64) <span class="cov8" title="1">{
        r.Min = min
}</span>

// GetMax returns the max value for the continuous range.
func (r ContinuousRange) GetMax() float64 <span class="cov8" title="1">{
        return r.Max
}</span>

// SetMax sets the max value for the continuous range.
func (r *ContinuousRange) SetMax(max float64) <span class="cov8" title="1">{
        r.Max = max
}</span>

// GetDelta returns the difference between the min and max value.
func (r ContinuousRange) GetDelta() float64 <span class="cov8" title="1">{
        return r.Max - r.Min
}</span>

// GetDomain returns the range domain.
func (r ContinuousRange) GetDomain() int <span class="cov8" title="1">{
        return r.Domain
}</span>

// SetDomain sets the range domain.
func (r *ContinuousRange) SetDomain(domain int) <span class="cov8" title="1">{
        r.Domain = domain
}</span>

// String returns a simple string for the ContinuousRange.
func (r ContinuousRange) String() string <span class="cov8" title="1">{
        return fmt.Sprintf("ContinuousRange [%.2f,%.2f] =&gt; %d", r.Min, r.Max, r.Domain)
}</span>

// Translate maps a given value into the ContinuousRange space.
func (r ContinuousRange) Translate(value float64) int <span class="cov8" title="1">{
        normalized := value - r.Min
        ratio := normalized / r.GetDelta()

        if r.IsDescending() </span><span class="cov0" title="0">{
                return r.Domain - int(math.Ceil(ratio*float64(r.Domain)))
        }</span>

        <span class="cov8" title="1">return int(math.Ceil(ratio * float64(r.Domain)))</span>
}
</pre>
		
		<pre class="file" id="file8" style="display: none">package chart

import "fmt"

// Interface Assertions.
var (
        _ Series              = (*ContinuousSeries)(nil)
        _ FirstValuesProvider = (*ContinuousSeries)(nil)
        _ LastValuesProvider  = (*ContinuousSeries)(nil)
)

// ContinuousSeries represents a line on a chart.
type ContinuousSeries struct {
        Name  string
        Style Style

        YAxis YAxisType

        XValueFormatter ValueFormatter
        YValueFormatter ValueFormatter

        XValues []float64
        YValues []float64
}

// GetName returns the name of the time series.
func (cs ContinuousSeries) GetName() string <span class="cov8" title="1">{
        return cs.Name
}</span>

// GetStyle returns the line style.
func (cs ContinuousSeries) GetStyle() Style <span class="cov8" title="1">{
        return cs.Style
}</span>

// Len returns the number of elements in the series.
func (cs ContinuousSeries) Len() int <span class="cov8" title="1">{
        return len(cs.XValues)
}</span>

// GetValues gets the x,y values at a given index.
func (cs ContinuousSeries) GetValues(index int) (float64, float64) <span class="cov8" title="1">{
        return cs.XValues[index], cs.YValues[index]
}</span>

// GetFirstValues gets the first x,y values.
func (cs ContinuousSeries) GetFirstValues() (float64, float64) <span class="cov8" title="1">{
        return cs.XValues[0], cs.YValues[0]
}</span>

// GetLastValues gets the last x,y values.
func (cs ContinuousSeries) GetLastValues() (float64, float64) <span class="cov8" title="1">{
        return cs.XValues[len(cs.XValues)-1], cs.YValues[len(cs.YValues)-1]
}</span>

// GetValueFormatters returns value formatter defaults for the series.
func (cs ContinuousSeries) GetValueFormatters() (x, y ValueFormatter) <span class="cov8" title="1">{
        if cs.XValueFormatter != nil </span><span class="cov8" title="1">{
                x = cs.XValueFormatter
        }</span> else<span class="cov8" title="1"> {
                x = FloatValueFormatter
        }</span>
        <span class="cov8" title="1">if cs.YValueFormatter != nil </span><span class="cov8" title="1">{
                y = cs.YValueFormatter
        }</span> else<span class="cov8" title="1"> {
                y = FloatValueFormatter
        }</span>
        <span class="cov8" title="1">return</span>
}

// GetYAxis returns which YAxis the series draws on.
func (cs ContinuousSeries) GetYAxis() YAxisType <span class="cov8" title="1">{
        return cs.YAxis
}</span>

// Render renders the series.
func (cs ContinuousSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) <span class="cov8" title="1">{
        style := cs.Style.InheritFrom(defaults)
        Draw.LineSeries(r, canvasBox, xrange, yrange, style, cs)
}</span>

// Validate validates the series.
func (cs ContinuousSeries) Validate() error <span class="cov8" title="1">{
        if len(cs.XValues) == 0 </span><span class="cov8" title="1">{
                return fmt.Errorf("continuous series must have xvalues set")
        }</span>

        <span class="cov8" title="1">if len(cs.YValues) == 0 </span><span class="cov8" title="1">{
                return fmt.Errorf("continuous series must have yvalues set")
        }</span>
        <span class="cov8" title="1">return nil</span>
}
</pre>
		
		<pre class="file" id="file9" style="display: none">package chart

import (
        "math"

        util "github.com/wcharczuk/go-chart/util"
)

var (
        // Draw contains helpers for drawing common objects.
        Draw = &amp;draw{}
)

type draw struct{}

// LineSeries draws a line series with a renderer.
func (d draw) LineSeries(r Renderer, canvasBox Box, xrange, yrange Range, style Style, vs ValuesProvider) <span class="cov8" title="1">{
        if vs.Len() == 0 </span><span class="cov0" title="0">{
                return
        }</span>

        <span class="cov8" title="1">cb := canvasBox.Bottom
        cl := canvasBox.Left

        v0x, v0y := vs.GetValues(0)
        x0 := cl + xrange.Translate(v0x)
        y0 := cb - yrange.Translate(v0y)

        yv0 := yrange.Translate(0)

        var vx, vy float64
        var x, y int

        if style.ShouldDrawStroke() &amp;&amp; style.ShouldDrawFill() </span><span class="cov8" title="1">{
                style.GetFillOptions().WriteDrawingOptionsToRenderer(r)
                r.MoveTo(x0, y0)
                for i := 1; i &lt; vs.Len(); i++ </span><span class="cov8" title="1">{
                        vx, vy = vs.GetValues(i)
                        x = cl + xrange.Translate(vx)
                        y = cb - yrange.Translate(vy)
                        r.LineTo(x, y)
                }</span>
                <span class="cov8" title="1">r.LineTo(x, util.Math.MinInt(cb, cb-yv0))
                r.LineTo(x0, util.Math.MinInt(cb, cb-yv0))
                r.LineTo(x0, y0)
                r.Fill()</span>
        }

        <span class="cov8" title="1">if style.ShouldDrawStroke() </span><span class="cov8" title="1">{
                style.GetStrokeOptions().WriteDrawingOptionsToRenderer(r)

                r.MoveTo(x0, y0)
                for i := 1; i &lt; vs.Len(); i++ </span><span class="cov8" title="1">{
                        vx, vy = vs.GetValues(i)
                        x = cl + xrange.Translate(vx)
                        y = cb - yrange.Translate(vy)
                        r.LineTo(x, y)
                }</span>
                <span class="cov8" title="1">r.Stroke()</span>
        }

        <span class="cov8" title="1">if style.ShouldDrawDot() </span><span class="cov0" title="0">{
                defaultDotWidth := style.GetDotWidth()

                style.GetDotOptions().WriteDrawingOptionsToRenderer(r)
                for i := 0; i &lt; vs.Len(); i++ </span><span class="cov0" title="0">{
                        vx, vy = vs.GetValues(i)
                        x = cl + xrange.Translate(vx)
                        y = cb - yrange.Translate(vy)

                        dotWidth := defaultDotWidth
                        if style.DotWidthProvider != nil </span><span class="cov0" title="0">{
                                dotWidth = style.DotWidthProvider(xrange, yrange, i, vx, vy)
                        }</span>

                        <span class="cov0" title="0">if style.DotColorProvider != nil </span><span class="cov0" title="0">{
                                dotColor := style.DotColorProvider(xrange, yrange, i, vx, vy)

                                r.SetFillColor(dotColor)
                                r.SetStrokeColor(dotColor)
                        }</span>

                        <span class="cov0" title="0">r.Circle(dotWidth, x, y)
                        r.FillStroke()</span>
                }
        }
}

// BoundedSeries draws a series that implements BoundedValuesProvider.
func (d draw) BoundedSeries(r Renderer, canvasBox Box, xrange, yrange Range, style Style, bbs BoundedValuesProvider, drawOffsetIndexes ...int) <span class="cov0" title="0">{
        drawOffsetIndex := 0
        if len(drawOffsetIndexes) &gt; 0 </span><span class="cov0" title="0">{
                drawOffsetIndex = drawOffsetIndexes[0]
        }</span>

        <span class="cov0" title="0">cb := canvasBox.Bottom
        cl := canvasBox.Left

        v0x, v0y1, v0y2 := bbs.GetBoundedValues(0)
        x0 := cl + xrange.Translate(v0x)
        y0 := cb - yrange.Translate(v0y1)

        var vx, vy1, vy2 float64
        var x, y int

        xvalues := make([]float64, bbs.Len())
        xvalues[0] = v0x
        y2values := make([]float64, bbs.Len())
        y2values[0] = v0y2

        style.GetFillAndStrokeOptions().WriteToRenderer(r)
        r.MoveTo(x0, y0)
        for i := 1; i &lt; bbs.Len(); i++ </span><span class="cov0" title="0">{
                vx, vy1, vy2 = bbs.GetBoundedValues(i)

                xvalues[i] = vx
                y2values[i] = vy2

                x = cl + xrange.Translate(vx)
                y = cb - yrange.Translate(vy1)
                if i &gt; drawOffsetIndex </span><span class="cov0" title="0">{
                        r.LineTo(x, y)
                }</span> else<span class="cov0" title="0"> {
                        r.MoveTo(x, y)
                }</span>
        }
        <span class="cov0" title="0">y = cb - yrange.Translate(vy2)
        r.LineTo(x, y)
        for i := bbs.Len() - 1; i &gt;= drawOffsetIndex; i-- </span><span class="cov0" title="0">{
                vx, vy2 = xvalues[i], y2values[i]
                x = cl + xrange.Translate(vx)
                y = cb - yrange.Translate(vy2)
                r.LineTo(x, y)
        }</span>
        <span class="cov0" title="0">r.Close()
        r.FillStroke()</span>
}

// HistogramSeries draws a value provider as boxes from 0.
func (d draw) HistogramSeries(r Renderer, canvasBox Box, xrange, yrange Range, style Style, vs ValuesProvider, barWidths ...int) <span class="cov0" title="0">{
        if vs.Len() == 0 </span><span class="cov0" title="0">{
                return
        }</span>

        //calculate bar width?
        <span class="cov0" title="0">seriesLength := vs.Len()
        barWidth := int(math.Floor(float64(xrange.GetDomain()) / float64(seriesLength)))
        if len(barWidths) &gt; 0 </span><span class="cov0" title="0">{
                barWidth = barWidths[0]
        }</span>

        <span class="cov0" title="0">cb := canvasBox.Bottom
        cl := canvasBox.Left

        //foreach datapoint, draw a box.
        for index := 0; index &lt; seriesLength; index++ </span><span class="cov0" title="0">{
                vx, vy := vs.GetValues(index)
                y0 := yrange.Translate(0)
                x := cl + xrange.Translate(vx)
                y := yrange.Translate(vy)

                d.Box(r, Box{
                        Top:    cb - y0,
                        Left:   x - (barWidth &gt;&gt; 1),
                        Right:  x + (barWidth &gt;&gt; 1),
                        Bottom: cb - y,
                }, style)
        }</span>
}

// MeasureAnnotation measures how big an annotation would be.
func (d draw) MeasureAnnotation(r Renderer, canvasBox Box, style Style, lx, ly int, label string) Box <span class="cov8" title="1">{
        style.WriteToRenderer(r)
        defer r.ResetStyle()

        textBox := r.MeasureText(label)
        textWidth := textBox.Width()
        textHeight := textBox.Height()
        halfTextHeight := textHeight &gt;&gt; 1

        pt := style.Padding.GetTop(DefaultAnnotationPadding.Top)
        pl := style.Padding.GetLeft(DefaultAnnotationPadding.Left)
        pr := style.Padding.GetRight(DefaultAnnotationPadding.Right)
        pb := style.Padding.GetBottom(DefaultAnnotationPadding.Bottom)

        strokeWidth := style.GetStrokeWidth()

        top := ly - (pt + halfTextHeight)
        right := lx + pl + pr + textWidth + DefaultAnnotationDeltaWidth + int(strokeWidth)
        bottom := ly + (pb + halfTextHeight)

        return Box{
                Top:    top,
                Left:   lx,
                Right:  right,
                Bottom: bottom,
        }
}</span>

// Annotation draws an anotation with a renderer.
func (d draw) Annotation(r Renderer, canvasBox Box, style Style, lx, ly int, label string) <span class="cov8" title="1">{
        style.GetTextOptions().WriteToRenderer(r)
        defer r.ResetStyle()

        textBox := r.MeasureText(label)
        textWidth := textBox.Width()
        halfTextHeight := textBox.Height() &gt;&gt; 1

        style.GetFillAndStrokeOptions().WriteToRenderer(r)

        pt := style.Padding.GetTop(DefaultAnnotationPadding.Top)
        pl := style.Padding.GetLeft(DefaultAnnotationPadding.Left)
        pr := style.Padding.GetRight(DefaultAnnotationPadding.Right)
        pb := style.Padding.GetBottom(DefaultAnnotationPadding.Bottom)

        textX := lx + pl + DefaultAnnotationDeltaWidth
        textY := ly + halfTextHeight

        ltx := lx + DefaultAnnotationDeltaWidth
        lty := ly - (pt + halfTextHeight)

        rtx := lx + pl + pr + textWidth + DefaultAnnotationDeltaWidth
        rty := ly - (pt + halfTextHeight)

        rbx := lx + pl + pr + textWidth + DefaultAnnotationDeltaWidth
        rby := ly + (pb + halfTextHeight)

        lbx := lx + DefaultAnnotationDeltaWidth
        lby := ly + (pb + halfTextHeight)

        r.MoveTo(lx, ly)
        r.LineTo(ltx, lty)
        r.LineTo(rtx, rty)
        r.LineTo(rbx, rby)
        r.LineTo(lbx, lby)
        r.LineTo(lx, ly)
        r.Close()
        r.FillStroke()

        style.GetTextOptions().WriteToRenderer(r)
        r.Text(label, textX, textY)
}</span>

// Box draws a box with a given style.
func (d draw) Box(r Renderer, b Box, s Style) <span class="cov8" title="1">{
        s.GetFillAndStrokeOptions().WriteToRenderer(r)
        defer r.ResetStyle()

        r.MoveTo(b.Left, b.Top)
        r.LineTo(b.Right, b.Top)
        r.LineTo(b.Right, b.Bottom)
        r.LineTo(b.Left, b.Bottom)
        r.LineTo(b.Left, b.Top)
        r.FillStroke()
}</span>

func (d draw) BoxRotated(r Renderer, b Box, thetaDegrees float64, s Style) <span class="cov0" title="0">{
        d.BoxCorners(r, b.Corners().Rotate(thetaDegrees), s)
}</span>

func (d draw) BoxCorners(r Renderer, bc BoxCorners, s Style) <span class="cov0" title="0">{
        s.GetFillAndStrokeOptions().WriteToRenderer(r)
        defer r.ResetStyle()

        r.MoveTo(bc.TopLeft.X, bc.TopLeft.Y)
        r.LineTo(bc.TopRight.X, bc.TopRight.Y)
        r.LineTo(bc.BottomRight.X, bc.BottomRight.Y)
        r.LineTo(bc.BottomLeft.X, bc.BottomLeft.Y)
        r.Close()
        r.FillStroke()
}</span>

// DrawText draws text with a given style.
func (d draw) Text(r Renderer, text string, x, y int, style Style) <span class="cov8" title="1">{
        style.GetTextOptions().WriteToRenderer(r)
        defer r.ResetStyle()

        r.Text(text, x, y)
}</span>

func (d draw) MeasureText(r Renderer, text string, style Style) Box <span class="cov8" title="1">{
        style.GetTextOptions().WriteToRenderer(r)
        defer r.ResetStyle()

        return r.MeasureText(text)
}</span>

// TextWithin draws the text within a given box.
func (d draw) TextWithin(r Renderer, text string, box Box, style Style) <span class="cov8" title="1">{
        style.GetTextOptions().WriteToRenderer(r)
        defer r.ResetStyle()

        lines := Text.WrapFit(r, text, box.Width(), style)
        linesBox := Text.MeasureLines(r, lines, style)

        y := box.Top

        switch style.GetTextVerticalAlign() </span>{
        case TextVerticalAlignBottom, TextVerticalAlignBaseline:<span class="cov0" title="0"> // i have to build better baseline handling into measure text
                y = y - linesBox.Height()</span>
        case TextVerticalAlignMiddle, TextVerticalAlignMiddleBaseline:<span class="cov0" title="0">
                y = (y - linesBox.Height()) &gt;&gt; 1</span>
        }

        <span class="cov8" title="1">var tx, ty int
        for _, line := range lines </span><span class="cov8" title="1">{
                lineBox := r.MeasureText(line)
                switch style.GetTextHorizontalAlign() </span>{
                case TextHorizontalAlignCenter:<span class="cov8" title="1">
                        tx = box.Left + ((box.Width() - lineBox.Width()) &gt;&gt; 1)</span>
                case TextHorizontalAlignRight:<span class="cov0" title="0">
                        tx = box.Right - lineBox.Width()</span>
                default:<span class="cov0" title="0">
                        tx = box.Left</span>
                }
                <span class="cov8" title="1">if style.TextRotationDegrees == 0 </span><span class="cov8" title="1">{
                        ty = y + lineBox.Height()
                }</span> else<span class="cov0" title="0"> {
                        ty = y
                }</span>

                <span class="cov8" title="1">r.Text(line, tx, ty)
                y += lineBox.Height() + style.GetTextLineSpacing()</span>
        }
}
</pre>
		
		<pre class="file" id="file10" style="display: none">package drawing

import (
        "fmt"
        "strconv"
)

var (
        // ColorTransparent is a fully transparent color.
        ColorTransparent = Color{}

        // ColorWhite is white.
        ColorWhite = Color{R: 255, G: 255, B: 255, A: 255}

        // ColorBlack is black.
        ColorBlack = Color{R: 0, G: 0, B: 0, A: 255}

        // ColorRed is red.
        ColorRed = Color{R: 255, G: 0, B: 0, A: 255}

        // ColorGreen is green.
        ColorGreen = Color{R: 0, G: 255, B: 0, A: 255}

        // ColorBlue is blue.
        ColorBlue = Color{R: 0, G: 0, B: 255, A: 255}
)

func parseHex(hex string) uint8 <span class="cov8" title="1">{
        v, _ := strconv.ParseInt(hex, 16, 16)
        return uint8(v)
}</span>

// ColorFromHex returns a color from a css hex code.
func ColorFromHex(hex string) Color <span class="cov8" title="1">{
        var c Color
        if len(hex) == 3 </span><span class="cov8" title="1">{
                c.R = parseHex(string(hex[0])) * 0x11
                c.G = parseHex(string(hex[1])) * 0x11
                c.B = parseHex(string(hex[2])) * 0x11
        }</span> else<span class="cov8" title="1"> {
                c.R = parseHex(string(hex[0:2]))
                c.G = parseHex(string(hex[2:4]))
                c.B = parseHex(string(hex[4:6]))
        }</span>
        <span class="cov8" title="1">c.A = 255
        return c</span>
}

// ColorFromAlphaMixedRGBA returns the system alpha mixed rgba values.
func ColorFromAlphaMixedRGBA(r, g, b, a uint32) Color <span class="cov8" title="1">{
        fa := float64(a) / 255.0
        var c Color
        c.R = uint8(float64(r) / fa)
        c.G = uint8(float64(g) / fa)
        c.B = uint8(float64(b) / fa)
        c.A = uint8(a | (a &gt;&gt; 8))
        return c
}</span>

// ColorChannelFromFloat returns a normalized byte from a given float value.
func ColorChannelFromFloat(v float64) uint8 <span class="cov0" title="0">{
        return uint8(v * 255)
}</span>

// Color is our internal color type because color.Color is bullshit.
type Color struct {
        R, G, B, A uint8
}

// RGBA returns the color as a pre-alpha mixed color set.
func (c Color) RGBA() (r, g, b, a uint32) <span class="cov0" title="0">{
        fa := float64(c.A) / 255.0
        r = uint32(float64(uint32(c.R)) * fa)
        r |= r &lt;&lt; 8
        g = uint32(float64(uint32(c.G)) * fa)
        g |= g &lt;&lt; 8
        b = uint32(float64(uint32(c.B)) * fa)
        b |= b &lt;&lt; 8
        a = uint32(c.A)
        a |= a &lt;&lt; 8
        return
}</span>

// IsZero returns if the color has been set or not.
func (c Color) IsZero() bool <span class="cov0" title="0">{
        return c.R == 0 &amp;&amp; c.G == 0 &amp;&amp; c.B == 0 &amp;&amp; c.A == 0
}</span>

// IsTransparent returns if the colors alpha channel is zero.
func (c Color) IsTransparent() bool <span class="cov0" title="0">{
        return c.A == 0
}</span>

// WithAlpha returns a copy of the color with a given alpha.
func (c Color) WithAlpha(a uint8) Color <span class="cov0" title="0">{
        return Color{
                R: c.R,
                G: c.G,
                B: c.B,
                A: a,
        }
}</span>

// Equals returns true if the color equals another.
func (c Color) Equals(other Color) bool <span class="cov8" title="1">{
        return c.R == other.R &amp;&amp;
                c.G == other.G &amp;&amp;
                c.B == other.B &amp;&amp;
                c.A == other.A
}</span>

// AverageWith averages two colors.
func (c Color) AverageWith(other Color) Color <span class="cov0" title="0">{
        return Color{
                R: (c.R + other.R) &gt;&gt; 1,
                G: (c.G + other.G) &gt;&gt; 1,
                B: (c.B + other.B) &gt;&gt; 1,
                A: c.A,
        }
}</span>

// String returns a css string representation of the color.
func (c Color) String() string <span class="cov8" title="1">{
        fa := float64(c.A) / float64(255)
        return fmt.Sprintf("rgba(%v,%v,%v,%.1f)", c.R, c.G, c.B, fa)
}</span>
</pre>
		
		<pre class="file" id="file11" style="display: none">package drawing

import "math"

const (
        // CurveRecursionLimit represents the maximum recursion that is really necessary to subsivide a curve into straight lines
        CurveRecursionLimit = 32
)

// Cubic
//        x1, y1, cpx1, cpy1, cpx2, cpy2, x2, y2 float64

// SubdivideCubic a Bezier cubic curve in 2 equivalents Bezier cubic curves.
// c1 and c2 parameters are the resulting curves
func SubdivideCubic(c, c1, c2 []float64) <span class="cov0" title="0">{
        // First point of c is the first point of c1
        c1[0], c1[1] = c[0], c[1]
        // Last point of c is the last point of c2
        c2[6], c2[7] = c[6], c[7]

        // Subdivide segment using midpoints
        c1[2] = (c[0] + c[2]) / 2
        c1[3] = (c[1] + c[3]) / 2

        midX := (c[2] + c[4]) / 2
        midY := (c[3] + c[5]) / 2

        c2[4] = (c[4] + c[6]) / 2
        c2[5] = (c[5] + c[7]) / 2

        c1[4] = (c1[2] + midX) / 2
        c1[5] = (c1[3] + midY) / 2

        c2[2] = (midX + c2[4]) / 2
        c2[3] = (midY + c2[5]) / 2

        c1[6] = (c1[4] + c2[2]) / 2
        c1[7] = (c1[5] + c2[3]) / 2

        // Last Point of c1 is equal to the first point of c2
        c2[0], c2[1] = c1[6], c1[7]
}</span>

// TraceCubic generate lines subdividing the cubic curve using a Liner
// flattening_threshold helps determines the flattening expectation of the curve
func TraceCubic(t Liner, cubic []float64, flatteningThreshold float64) <span class="cov0" title="0">{
        // Allocation curves
        var curves [CurveRecursionLimit * 8]float64
        copy(curves[0:8], cubic[0:8])
        i := 0

        // current curve
        var c []float64

        var dx, dy, d2, d3 float64

        for i &gt;= 0 </span><span class="cov0" title="0">{
                c = curves[i*8:]
                dx = c[6] - c[0]
                dy = c[7] - c[1]

                d2 = math.Abs((c[2]-c[6])*dy - (c[3]-c[7])*dx)
                d3 = math.Abs((c[4]-c[6])*dy - (c[5]-c[7])*dx)

                // if it's flat then trace a line
                if (d2+d3)*(d2+d3) &lt; flatteningThreshold*(dx*dx+dy*dy) || i == len(curves)-1 </span><span class="cov0" title="0">{
                        t.LineTo(c[6], c[7])
                        i--
                }</span> else<span class="cov0" title="0"> {
                        // second half of bezier go lower onto the stack
                        SubdivideCubic(c, curves[(i+1)*8:], curves[i*8:])
                        i++
                }</span>
        }
}

// Quad
// x1, y1, cpx1, cpy2, x2, y2 float64

// SubdivideQuad a Bezier quad curve in 2 equivalents Bezier quad curves.
// c1 and c2 parameters are the resulting curves
func SubdivideQuad(c, c1, c2 []float64) <span class="cov8" title="1">{
        // First point of c is the first point of c1
        c1[0], c1[1] = c[0], c[1]
        // Last point of c is the last point of c2
        c2[4], c2[5] = c[4], c[5]

        // Subdivide segment using midpoints
        c1[2] = (c[0] + c[2]) / 2
        c1[3] = (c[1] + c[3]) / 2
        c2[2] = (c[2] + c[4]) / 2
        c2[3] = (c[3] + c[5]) / 2
        c1[4] = (c1[2] + c2[2]) / 2
        c1[5] = (c1[3] + c2[3]) / 2
        c2[0], c2[1] = c1[4], c1[5]
        return
}</span>

func traceWindowIndices(i int) (startAt, endAt int) <span class="cov8" title="1">{
        startAt = i * 6
        endAt = startAt + 6
        return
}</span>

func traceCalcDeltas(c []float64) (dx, dy, d float64) <span class="cov8" title="1">{
        dx = c[4] - c[0]
        dy = c[5] - c[1]
        d = math.Abs(((c[2]-c[4])*dy - (c[3]-c[5])*dx))
        return
}</span>

func traceIsFlat(dx, dy, d, threshold float64) bool <span class="cov8" title="1">{
        return (d * d) &lt; threshold*(dx*dx+dy*dy)
}</span>

func traceGetWindow(curves []float64, i int) []float64 <span class="cov8" title="1">{
        startAt, endAt := traceWindowIndices(i)
        return curves[startAt:endAt]
}</span>

// TraceQuad generate lines subdividing the curve using a Liner
// flattening_threshold helps determines the flattening expectation of the curve
func TraceQuad(t Liner, quad []float64, flatteningThreshold float64) <span class="cov8" title="1">{
        const curveLen = CurveRecursionLimit * 6
        const curveEndIndex = curveLen - 1
        const lastIteration = CurveRecursionLimit - 1

        // Allocates curves stack
        curves := make([]float64, curveLen)

        // copy 6 elements from the quad path to the stack
        copy(curves[0:6], quad[0:6])

        var i int
        var c []float64
        var dx, dy, d float64

        for i &gt;= 0 </span><span class="cov8" title="1">{
                c = traceGetWindow(curves, i)
                dx, dy, d = traceCalcDeltas(c)

                // bail early if the distance is 0
                if d == 0 </span><span class="cov0" title="0">{
                        return
                }</span>

                // if it's flat then trace a line
                <span class="cov8" title="1">if traceIsFlat(dx, dy, d, flatteningThreshold) || i == lastIteration </span><span class="cov8" title="1">{
                        t.LineTo(c[4], c[5])
                        i--
                }</span> else<span class="cov8" title="1"> {
                        SubdivideQuad(c, traceGetWindow(curves, i+1), traceGetWindow(curves, i))
                        i++
                }</span>
        }
}

// TraceArc trace an arc using a Liner
func TraceArc(t Liner, x, y, rx, ry, start, angle, scale float64) (lastX, lastY float64) <span class="cov0" title="0">{
        end := start + angle
        clockWise := true
        if angle &lt; 0 </span><span class="cov0" title="0">{
                clockWise = false
        }</span>
        <span class="cov0" title="0">ra := (math.Abs(rx) + math.Abs(ry)) / 2
        da := math.Acos(ra/(ra+0.125/scale)) * 2
        //normalize
        if !clockWise </span><span class="cov0" title="0">{
                da = -da
        }</span>
        <span class="cov0" title="0">angle = start + da
        var curX, curY float64
        for </span><span class="cov0" title="0">{
                if (angle &lt; end-da/4) != clockWise </span><span class="cov0" title="0">{
                        curX = x + math.Cos(end)*rx
                        curY = y + math.Sin(end)*ry
                        return curX, curY
                }</span>
                <span class="cov0" title="0">curX = x + math.Cos(angle)*rx
                curY = y + math.Sin(angle)*ry

                angle += da
                t.LineTo(curX, curY)</span>
        }
}
</pre>
		
		<pre class="file" id="file12" style="display: none">package drawing

// NewDashVertexConverter creates a new dash converter.
func NewDashVertexConverter(dash []float64, dashOffset float64, flattener Flattener) *DashVertexConverter <span class="cov0" title="0">{
        var dasher DashVertexConverter
        dasher.dash = dash
        dasher.currentDash = 0
        dasher.dashOffset = dashOffset
        dasher.next = flattener
        return &amp;dasher
}</span>

// DashVertexConverter is a converter for dash vertexes.
type DashVertexConverter struct {
        next           Flattener
        x, y, distance float64
        dash           []float64
        currentDash    int
        dashOffset     float64
}

// LineTo implements the pathbuilder interface.
func (dasher *DashVertexConverter) LineTo(x, y float64) <span class="cov0" title="0">{
        dasher.lineTo(x, y)
}</span>

// MoveTo implements the pathbuilder interface.
func (dasher *DashVertexConverter) MoveTo(x, y float64) <span class="cov0" title="0">{
        dasher.next.MoveTo(x, y)
        dasher.x, dasher.y = x, y
        dasher.distance = dasher.dashOffset
        dasher.currentDash = 0
}</span>

// LineJoin implements the pathbuilder interface.
func (dasher *DashVertexConverter) LineJoin() <span class="cov0" title="0">{
        dasher.next.LineJoin()
}</span>

// Close implements the pathbuilder interface.
func (dasher *DashVertexConverter) Close() <span class="cov0" title="0">{
        dasher.next.Close()
}</span>

// End implements the pathbuilder interface.
func (dasher *DashVertexConverter) End() <span class="cov0" title="0">{
        dasher.next.End()
}</span>

func (dasher *DashVertexConverter) lineTo(x, y float64) <span class="cov0" title="0">{
        rest := dasher.dash[dasher.currentDash] - dasher.distance
        for rest &lt; 0 </span><span class="cov0" title="0">{
                dasher.distance = dasher.distance - dasher.dash[dasher.currentDash]
                dasher.currentDash = (dasher.currentDash + 1) % len(dasher.dash)
                rest = dasher.dash[dasher.currentDash] - dasher.distance
        }</span>
        <span class="cov0" title="0">d := distance(dasher.x, dasher.y, x, y)
        for d &gt;= rest </span><span class="cov0" title="0">{
                k := rest / d
                lx := dasher.x + k*(x-dasher.x)
                ly := dasher.y + k*(y-dasher.y)
                if dasher.currentDash%2 == 0 </span><span class="cov0" title="0">{
                        // line
                        dasher.next.LineTo(lx, ly)
                }</span> else<span class="cov0" title="0"> {
                        // gap
                        dasher.next.End()
                        dasher.next.MoveTo(lx, ly)
                }</span>
                <span class="cov0" title="0">d = d - rest
                dasher.x, dasher.y = lx, ly
                dasher.currentDash = (dasher.currentDash + 1) % len(dasher.dash)
                rest = dasher.dash[dasher.currentDash]</span>
        }
        <span class="cov0" title="0">dasher.distance = d
        if dasher.currentDash%2 == 0 </span><span class="cov0" title="0">{
                // line
                dasher.next.LineTo(x, y)
        }</span> else<span class="cov0" title="0"> {
                // gap
                dasher.next.End()
                dasher.next.MoveTo(x, y)
        }</span>
        <span class="cov0" title="0">if dasher.distance &gt;= dasher.dash[dasher.currentDash] </span><span class="cov0" title="0">{
                dasher.distance = dasher.distance - dasher.dash[dasher.currentDash]
                dasher.currentDash = (dasher.currentDash + 1) % len(dasher.dash)
        }</span>
        <span class="cov0" title="0">dasher.x, dasher.y = x, y</span>
}
</pre>
		
		<pre class="file" id="file13" style="display: none">package drawing

// DemuxFlattener is a flattener
type DemuxFlattener struct {
        Flatteners []Flattener
}

// MoveTo implements the path builder interface.
func (dc DemuxFlattener) MoveTo(x, y float64) <span class="cov0" title="0">{
        for _, flattener := range dc.Flatteners </span><span class="cov0" title="0">{
                flattener.MoveTo(x, y)
        }</span>
}

// LineTo implements the path builder interface.
func (dc DemuxFlattener) LineTo(x, y float64) <span class="cov0" title="0">{
        for _, flattener := range dc.Flatteners </span><span class="cov0" title="0">{
                flattener.LineTo(x, y)
        }</span>
}

// LineJoin implements the path builder interface.
func (dc DemuxFlattener) LineJoin() <span class="cov0" title="0">{
        for _, flattener := range dc.Flatteners </span><span class="cov0" title="0">{
                flattener.LineJoin()
        }</span>
}

// Close implements the path builder interface.
func (dc DemuxFlattener) Close() <span class="cov0" title="0">{
        for _, flattener := range dc.Flatteners </span><span class="cov0" title="0">{
                flattener.Close()
        }</span>
}

// End implements the path builder interface.
func (dc DemuxFlattener) End() <span class="cov0" title="0">{
        for _, flattener := range dc.Flatteners </span><span class="cov0" title="0">{
                flattener.End()
        }</span>
}
</pre>
		
		<pre class="file" id="file14" style="display: none">package drawing

// Liner receive segment definition
type Liner interface {
        // LineTo Draw a line from the current position to the point (x, y)
        LineTo(x, y float64)
}

// Flattener receive segment definition
type Flattener interface {
        // MoveTo Start a New line from the point (x, y)
        MoveTo(x, y float64)
        // LineTo Draw a line from the current position to the point (x, y)
        LineTo(x, y float64)
        // LineJoin add the most recent starting point to close the path to create a polygon
        LineJoin()
        // Close add the most recent starting point to close the path to create a polygon
        Close()
        // End mark the current line as finished so we can draw caps
        End()
}

// Flatten convert curves into straight segments keeping join segments info
func Flatten(path *Path, flattener Flattener, scale float64) <span class="cov0" title="0">{
        // First Point
        var startX, startY float64
        // Current Point
        var x, y float64
        var i int
        for _, cmp := range path.Components </span><span class="cov0" title="0">{
                switch cmp </span>{
                case MoveToComponent:<span class="cov0" title="0">
                        x, y = path.Points[i], path.Points[i+1]
                        startX, startY = x, y
                        if i != 0 </span><span class="cov0" title="0">{
                                flattener.End()
                        }</span>
                        <span class="cov0" title="0">flattener.MoveTo(x, y)
                        i += 2</span>
                case LineToComponent:<span class="cov0" title="0">
                        x, y = path.Points[i], path.Points[i+1]
                        flattener.LineTo(x, y)
                        flattener.LineJoin()
                        i += 2</span>
                case QuadCurveToComponent:<span class="cov0" title="0">
                        // we include the previous point for the start of the curve
                        TraceQuad(flattener, path.Points[i-2:], 0.5)
                        x, y = path.Points[i+2], path.Points[i+3]
                        flattener.LineTo(x, y)
                        i += 4</span>
                case CubicCurveToComponent:<span class="cov0" title="0">
                        TraceCubic(flattener, path.Points[i-2:], 0.5)
                        x, y = path.Points[i+4], path.Points[i+5]
                        flattener.LineTo(x, y)
                        i += 6</span>
                case ArcToComponent:<span class="cov0" title="0">
                        x, y = TraceArc(flattener, path.Points[i], path.Points[i+1], path.Points[i+2], path.Points[i+3], path.Points[i+4], path.Points[i+5], scale)
                        flattener.LineTo(x, y)
                        i += 6</span>
                case CloseComponent:<span class="cov0" title="0">
                        flattener.LineTo(startX, startY)
                        flattener.Close()</span>
                }
        }
        <span class="cov0" title="0">flattener.End()</span>
}

// SegmentedPath is a path of disparate point sectinos.
type SegmentedPath struct {
        Points []float64
}

// MoveTo implements the path interface.
func (p *SegmentedPath) MoveTo(x, y float64) <span class="cov0" title="0">{
        p.Points = append(p.Points, x, y)
        // TODO need to mark this point as moveto
}</span>

// LineTo implements the path interface.
func (p *SegmentedPath) LineTo(x, y float64) <span class="cov0" title="0">{
        p.Points = append(p.Points, x, y)
}</span>

// LineJoin implements the path interface.
func (p *SegmentedPath) LineJoin() {<span class="cov0" title="0">
        // TODO need to mark the current point as linejoin
}</span>

// Close implements the path interface.
func (p *SegmentedPath) Close() {<span class="cov0" title="0">
        // TODO Close
}</span>

// End implements the path interface.
func (p *SegmentedPath) End() {<span class="cov0" title="0">
        // Nothing to do
}</span>
</pre>
		
		<pre class="file" id="file15" style="display: none">package drawing

import (
        "github.com/golang/freetype/raster"
        "golang.org/x/image/math/fixed"
)

// FtLineBuilder is a builder for freetype raster glyphs.
type FtLineBuilder struct {
        Adder raster.Adder
}

// MoveTo implements the path builder interface.
func (liner FtLineBuilder) MoveTo(x, y float64) <span class="cov0" title="0">{
        liner.Adder.Start(fixed.Point26_6{X: fixed.Int26_6(x * 64), Y: fixed.Int26_6(y * 64)})
}</span>

// LineTo implements the path builder interface.
func (liner FtLineBuilder) LineTo(x, y float64) <span class="cov0" title="0">{
        liner.Adder.Add1(fixed.Point26_6{X: fixed.Int26_6(x * 64), Y: fixed.Int26_6(y * 64)})
}</span>

// LineJoin implements the path builder interface.
func (liner FtLineBuilder) LineJoin() {<span class="cov0" title="0">}</span>

// Close implements the path builder interface.
func (liner FtLineBuilder) Close() {<span class="cov0" title="0">}</span>

// End implements the path builder interface.
func (liner FtLineBuilder) End() {<span class="cov0" title="0">}</span>
</pre>
		
		<pre class="file" id="file16" style="display: none">package drawing

import (
        "image/color"
        "image/draw"
)

// PolylineBresenham draws a polyline to an image
func PolylineBresenham(img draw.Image, c color.Color, s ...float64) <span class="cov0" title="0">{
        for i := 2; i &lt; len(s); i += 2 </span><span class="cov0" title="0">{
                Bresenham(img, c, int(s[i-2]+0.5), int(s[i-1]+0.5), int(s[i]+0.5), int(s[i+1]+0.5))
        }</span>
}

// Bresenham draws a line between (x0, y0) and (x1, y1)
func Bresenham(img draw.Image, color color.Color, x0, y0, x1, y1 int) <span class="cov0" title="0">{
        dx := abs(x1 - x0)
        dy := abs(y1 - y0)
        var sx, sy int
        if x0 &lt; x1 </span><span class="cov0" title="0">{
                sx = 1
        }</span> else<span class="cov0" title="0"> {
                sx = -1
        }</span>
        <span class="cov0" title="0">if y0 &lt; y1 </span><span class="cov0" title="0">{
                sy = 1
        }</span> else<span class="cov0" title="0"> {
                sy = -1
        }</span>
        <span class="cov0" title="0">err := dx - dy

        var e2 int
        for </span><span class="cov0" title="0">{
                img.Set(x0, y0, color)
                if x0 == x1 &amp;&amp; y0 == y1 </span><span class="cov0" title="0">{
                        return
                }</span>
                <span class="cov0" title="0">e2 = 2 * err
                if e2 &gt; -dy </span><span class="cov0" title="0">{
                        err = err - dy
                        x0 = x0 + sx
                }</span>
                <span class="cov0" title="0">if e2 &lt; dx </span><span class="cov0" title="0">{
                        err = err + dx
                        y0 = y0 + sy
                }</span>
        }
}
</pre>
		
		<pre class="file" id="file17" style="display: none">package drawing

import (
        "math"
)

// Matrix represents an affine transformation
type Matrix [6]float64

const (
        epsilon = 1e-6
)

// Determinant compute the determinant of the matrix
func (tr Matrix) Determinant() float64 <span class="cov0" title="0">{
        return tr[0]*tr[3] - tr[1]*tr[2]
}</span>

// Transform applies the transformation matrix to points. It modify the points passed in parameter.
func (tr Matrix) Transform(points []float64) <span class="cov0" title="0">{
        for i, j := 0, 1; j &lt; len(points); i, j = i+2, j+2 </span><span class="cov0" title="0">{
                x := points[i]
                y := points[j]
                points[i] = x*tr[0] + y*tr[2] + tr[4]
                points[j] = x*tr[1] + y*tr[3] + tr[5]
        }</span>
}

// TransformPoint applies the transformation matrix to point. It returns the point the transformed point.
func (tr Matrix) TransformPoint(x, y float64) (xres, yres float64) <span class="cov0" title="0">{
        xres = x*tr[0] + y*tr[2] + tr[4]
        yres = x*tr[1] + y*tr[3] + tr[5]
        return xres, yres
}</span>

func minMax(x, y float64) (min, max float64) <span class="cov0" title="0">{
        if x &gt; y </span><span class="cov0" title="0">{
                return y, x
        }</span>
        <span class="cov0" title="0">return x, y</span>
}

// TransformRectangle applies the transformation matrix to the rectangle represented by the min and the max point of the rectangle
func (tr Matrix) TransformRectangle(x0, y0, x2, y2 float64) (nx0, ny0, nx2, ny2 float64) <span class="cov0" title="0">{
        points := []float64{x0, y0, x2, y0, x2, y2, x0, y2}
        tr.Transform(points)
        points[0], points[2] = minMax(points[0], points[2])
        points[4], points[6] = minMax(points[4], points[6])
        points[1], points[3] = minMax(points[1], points[3])
        points[5], points[7] = minMax(points[5], points[7])

        nx0 = math.Min(points[0], points[4])
        ny0 = math.Min(points[1], points[5])
        nx2 = math.Max(points[2], points[6])
        ny2 = math.Max(points[3], points[7])
        return nx0, ny0, nx2, ny2
}</span>

// InverseTransform applies the transformation inverse matrix to the rectangle represented by the min and the max point of the rectangle
func (tr Matrix) InverseTransform(points []float64) <span class="cov0" title="0">{
        d := tr.Determinant() // matrix determinant
        for i, j := 0, 1; j &lt; len(points); i, j = i+2, j+2 </span><span class="cov0" title="0">{
                x := points[i]
                y := points[j]
                points[i] = ((x-tr[4])*tr[3] - (y-tr[5])*tr[2]) / d
                points[j] = ((y-tr[5])*tr[0] - (x-tr[4])*tr[1]) / d
        }</span>
}

// InverseTransformPoint applies the transformation inverse matrix to point. It returns the point the transformed point.
func (tr Matrix) InverseTransformPoint(x, y float64) (xres, yres float64) <span class="cov0" title="0">{
        d := tr.Determinant() // matrix determinant
        xres = ((x-tr[4])*tr[3] - (y-tr[5])*tr[2]) / d
        yres = ((y-tr[5])*tr[0] - (x-tr[4])*tr[1]) / d
        return xres, yres
}</span>

// VectorTransform applies the transformation matrix to points without using the translation parameter of the affine matrix.
// It modify the points passed in parameter.
func (tr Matrix) VectorTransform(points []float64) <span class="cov0" title="0">{
        for i, j := 0, 1; j &lt; len(points); i, j = i+2, j+2 </span><span class="cov0" title="0">{
                x := points[i]
                y := points[j]
                points[i] = x*tr[0] + y*tr[2]
                points[j] = x*tr[1] + y*tr[3]
        }</span>
}

// NewIdentityMatrix creates an identity transformation matrix.
func NewIdentityMatrix() Matrix <span class="cov0" title="0">{
        return Matrix{1, 0, 0, 1, 0, 0}
}</span>

// NewTranslationMatrix creates a transformation matrix with a translation tx and ty translation parameter
func NewTranslationMatrix(tx, ty float64) Matrix <span class="cov0" title="0">{
        return Matrix{1, 0, 0, 1, tx, ty}
}</span>

// NewScaleMatrix creates a transformation matrix with a sx, sy scale factor
func NewScaleMatrix(sx, sy float64) Matrix <span class="cov0" title="0">{
        return Matrix{sx, 0, 0, sy, 0, 0}
}</span>

// NewRotationMatrix creates a rotation transformation matrix. angle is in radian
func NewRotationMatrix(angle float64) Matrix <span class="cov0" title="0">{
        c := math.Cos(angle)
        s := math.Sin(angle)
        return Matrix{c, s, -s, c, 0, 0}
}</span>

// NewMatrixFromRects creates a transformation matrix, combining a scale and a translation, that transform rectangle1 into rectangle2.
func NewMatrixFromRects(rectangle1, rectangle2 [4]float64) Matrix <span class="cov0" title="0">{
        xScale := (rectangle2[2] - rectangle2[0]) / (rectangle1[2] - rectangle1[0])
        yScale := (rectangle2[3] - rectangle2[1]) / (rectangle1[3] - rectangle1[1])
        xOffset := rectangle2[0] - (rectangle1[0] * xScale)
        yOffset := rectangle2[1] - (rectangle1[1] * yScale)
        return Matrix{xScale, 0, 0, yScale, xOffset, yOffset}
}</span>

// Inverse computes the inverse matrix
func (tr *Matrix) Inverse() <span class="cov0" title="0">{
        d := tr.Determinant() // matrix determinant
        tr0, tr1, tr2, tr3, tr4, tr5 := tr[0], tr[1], tr[2], tr[3], tr[4], tr[5]
        tr[0] = tr3 / d
        tr[1] = -tr1 / d
        tr[2] = -tr2 / d
        tr[3] = tr0 / d
        tr[4] = (tr2*tr5 - tr3*tr4) / d
        tr[5] = (tr1*tr4 - tr0*tr5) / d
}</span>

// Copy copies the matrix.
func (tr Matrix) Copy() Matrix <span class="cov0" title="0">{
        var result Matrix
        copy(result[:], tr[:])
        return result
}</span>

// Compose multiplies trToConcat x tr
func (tr *Matrix) Compose(trToCompose Matrix) <span class="cov0" title="0">{
        tr0, tr1, tr2, tr3, tr4, tr5 := tr[0], tr[1], tr[2], tr[3], tr[4], tr[5]
        tr[0] = trToCompose[0]*tr0 + trToCompose[1]*tr2
        tr[1] = trToCompose[1]*tr3 + trToCompose[0]*tr1
        tr[2] = trToCompose[2]*tr0 + trToCompose[3]*tr2
        tr[3] = trToCompose[3]*tr3 + trToCompose[2]*tr1
        tr[4] = trToCompose[4]*tr0 + trToCompose[5]*tr2 + tr4
        tr[5] = trToCompose[5]*tr3 + trToCompose[4]*tr1 + tr5
}</span>

// Scale adds a scale to the matrix
func (tr *Matrix) Scale(sx, sy float64) <span class="cov0" title="0">{
        tr[0] = sx * tr[0]
        tr[1] = sx * tr[1]
        tr[2] = sy * tr[2]
        tr[3] = sy * tr[3]
}</span>

// Translate adds a translation to the matrix
func (tr *Matrix) Translate(tx, ty float64) <span class="cov0" title="0">{
        tr[4] = tx*tr[0] + ty*tr[2] + tr[4]
        tr[5] = ty*tr[3] + tx*tr[1] + tr[5]
}</span>

// Rotate adds a rotation to the matrix.
func (tr *Matrix) Rotate(radians float64) <span class="cov0" title="0">{
        c := math.Cos(radians)
        s := math.Sin(radians)
        t0 := c*tr[0] + s*tr[2]
        t1 := s*tr[3] + c*tr[1]
        t2 := c*tr[2] - s*tr[0]
        t3 := c*tr[3] - s*tr[1]
        tr[0] = t0
        tr[1] = t1
        tr[2] = t2
        tr[3] = t3
}</span>

// GetTranslation gets the matrix traslation.
func (tr Matrix) GetTranslation() (x, y float64) <span class="cov0" title="0">{
        return tr[4], tr[5]
}</span>

// GetScaling gets the matrix scaling.
func (tr Matrix) GetScaling() (x, y float64) <span class="cov0" title="0">{
        return tr[0], tr[3]
}</span>

// GetScale computes a scale for the matrix
func (tr Matrix) GetScale() float64 <span class="cov0" title="0">{
        x := 0.707106781*tr[0] + 0.707106781*tr[1]
        y := 0.707106781*tr[2] + 0.707106781*tr[3]
        return math.Sqrt(x*x + y*y)
}</span>

// ******************** Testing ********************

// Equals tests if a two transformation are equal. A tolerance is applied when comparing matrix elements.
func (tr Matrix) Equals(tr2 Matrix) bool <span class="cov0" title="0">{
        for i := 0; i &lt; 6; i = i + 1 </span><span class="cov0" title="0">{
                if !fequals(tr[i], tr2[i]) </span><span class="cov0" title="0">{
                        return false
                }</span>
        }
        <span class="cov0" title="0">return true</span>
}

// IsIdentity tests if a transformation is the identity transformation. A tolerance is applied when comparing matrix elements.
func (tr Matrix) IsIdentity() bool <span class="cov0" title="0">{
        return fequals(tr[4], 0) &amp;&amp; fequals(tr[5], 0) &amp;&amp; tr.IsTranslation()
}</span>

// IsTranslation tests if a transformation is is a pure translation. A tolerance is applied when comparing matrix elements.
func (tr Matrix) IsTranslation() bool <span class="cov0" title="0">{
        return fequals(tr[0], 1) &amp;&amp; fequals(tr[1], 0) &amp;&amp; fequals(tr[2], 0) &amp;&amp; fequals(tr[3], 1)
}</span>

// fequals compares two floats. return true if the distance between the two floats is less than epsilon, false otherwise
func fequals(float1, float2 float64) bool <span class="cov0" title="0">{
        return math.Abs(float1-float2) &lt;= epsilon
}</span>
</pre>
		
		<pre class="file" id="file18" style="display: none">package drawing

import (
        "image"
        "image/color"

        "golang.org/x/image/draw"
        "golang.org/x/image/math/f64"

        "github.com/golang/freetype/raster"
)

// Painter implements the freetype raster.Painter and has a SetColor method like the RGBAPainter
type Painter interface {
        raster.Painter
        SetColor(color color.Color)
}

// DrawImage draws an image into dest using an affine transformation matrix, an op and a filter
func DrawImage(src image.Image, dest draw.Image, tr Matrix, op draw.Op, filter ImageFilter) <span class="cov0" title="0">{
        var transformer draw.Transformer
        switch filter </span>{
        case LinearFilter:<span class="cov0" title="0">
                transformer = draw.NearestNeighbor</span>
        case BilinearFilter:<span class="cov0" title="0">
                transformer = draw.BiLinear</span>
        case BicubicFilter:<span class="cov0" title="0">
                transformer = draw.CatmullRom</span>
        }
        <span class="cov0" title="0">transformer.Transform(dest, f64.Aff3{tr[0], tr[1], tr[4], tr[2], tr[3], tr[5]}, src, src.Bounds(), op, nil)</span>
}
</pre>
		
		<pre class="file" id="file19" style="display: none">package drawing

import (
        "fmt"
        "math"
)

// PathBuilder describes the interface for path drawing.
type PathBuilder interface {
        // LastPoint returns the current point of the current sub path
        LastPoint() (x, y float64)
        // MoveTo creates a new subpath that start at the specified point
        MoveTo(x, y float64)
        // LineTo adds a line to the current subpath
        LineTo(x, y float64)
        // QuadCurveTo adds a quadratic Bézier curve to the current subpath
        QuadCurveTo(cx, cy, x, y float64)
        // CubicCurveTo adds a cubic Bézier curve to the current subpath
        CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64)
        // ArcTo adds an arc to the current subpath
        ArcTo(cx, cy, rx, ry, startAngle, angle float64)
        // Close creates a line from the current point to the last MoveTo
        // point (if not the same) and mark the path as closed so the
        // first and last lines join nicely.
        Close()
}

// PathComponent represents component of a path
type PathComponent int

const (
        // MoveToComponent is a MoveTo component in a Path
        MoveToComponent PathComponent = iota
        // LineToComponent is a LineTo component in a Path
        LineToComponent
        // QuadCurveToComponent is a QuadCurveTo component in a Path
        QuadCurveToComponent
        // CubicCurveToComponent is a CubicCurveTo component in a Path
        CubicCurveToComponent
        // ArcToComponent is a ArcTo component in a Path
        ArcToComponent
        // CloseComponent is a ArcTo component in a Path
        CloseComponent
)

// Path stores points
type Path struct {
        // Components is a slice of PathComponent in a Path and mark the role of each points in the Path
        Components []PathComponent
        // Points are combined with Components to have a specific role in the path
        Points []float64
        // Last Point of the Path
        x, y float64
}

func (p *Path) appendToPath(cmd PathComponent, points ...float64) <span class="cov0" title="0">{
        p.Components = append(p.Components, cmd)
        p.Points = append(p.Points, points...)
}</span>

// LastPoint returns the current point of the current path
func (p *Path) LastPoint() (x, y float64) <span class="cov0" title="0">{
        return p.x, p.y
}</span>

// MoveTo starts a new path at (x, y) position
func (p *Path) MoveTo(x, y float64) <span class="cov0" title="0">{
        p.appendToPath(MoveToComponent, x, y)
        p.x = x
        p.y = y
}</span>

// LineTo adds a line to the current path
func (p *Path) LineTo(x, y float64) <span class="cov0" title="0">{
        if len(p.Components) == 0 </span><span class="cov0" title="0">{ //special case when no move has been done
                p.MoveTo(0, 0)
        }</span>
        <span class="cov0" title="0">p.appendToPath(LineToComponent, x, y)
        p.x = x
        p.y = y</span>
}

// QuadCurveTo adds a quadratic bezier curve to the current path
func (p *Path) QuadCurveTo(cx, cy, x, y float64) <span class="cov0" title="0">{
        if len(p.Components) == 0 </span><span class="cov0" title="0">{ //special case when no move has been done
                p.MoveTo(0, 0)
        }</span>
        <span class="cov0" title="0">p.appendToPath(QuadCurveToComponent, cx, cy, x, y)
        p.x = x
        p.y = y</span>
}

// CubicCurveTo adds a cubic bezier curve to the current path
func (p *Path) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) <span class="cov0" title="0">{
        if len(p.Components) == 0 </span><span class="cov0" title="0">{ //special case when no move has been done
                p.MoveTo(0, 0)
        }</span>
        <span class="cov0" title="0">p.appendToPath(CubicCurveToComponent, cx1, cy1, cx2, cy2, x, y)
        p.x = x
        p.y = y</span>
}

// ArcTo adds an arc to the path
func (p *Path) ArcTo(cx, cy, rx, ry, startAngle, delta float64) <span class="cov0" title="0">{
        endAngle := startAngle + delta
        clockWise := true
        if delta &lt; 0 </span><span class="cov0" title="0">{
                clockWise = false
        }</span>
        // normalize
        <span class="cov0" title="0">if clockWise </span><span class="cov0" title="0">{
                for endAngle &lt; startAngle </span><span class="cov0" title="0">{
                        endAngle += math.Pi * 2.0
                }</span>
        } else<span class="cov0" title="0"> {
                for startAngle &lt; endAngle </span><span class="cov0" title="0">{
                        startAngle += math.Pi * 2.0
                }</span>
        }
        <span class="cov0" title="0">startX := cx + math.Cos(startAngle)*rx
        startY := cy + math.Sin(startAngle)*ry
        if len(p.Components) &gt; 0 </span><span class="cov0" title="0">{
                p.LineTo(startX, startY)
        }</span> else<span class="cov0" title="0"> {
                p.MoveTo(startX, startY)
        }</span>
        <span class="cov0" title="0">p.appendToPath(ArcToComponent, cx, cy, rx, ry, startAngle, delta)
        p.x = cx + math.Cos(endAngle)*rx
        p.y = cy + math.Sin(endAngle)*ry</span>
}

// Close closes the current path
func (p *Path) Close() <span class="cov0" title="0">{
        p.appendToPath(CloseComponent)
}</span>

// Copy make a clone of the current path and return it
func (p *Path) Copy() (dest *Path) <span class="cov0" title="0">{
        dest = new(Path)
        dest.Components = make([]PathComponent, len(p.Components))
        copy(dest.Components, p.Components)
        dest.Points = make([]float64, len(p.Points))
        copy(dest.Points, p.Points)
        dest.x, dest.y = p.x, p.y
        return dest
}</span>

// Clear reset the path
func (p *Path) Clear() <span class="cov0" title="0">{
        p.Components = p.Components[0:0]
        p.Points = p.Points[0:0]
        return
}</span>

// IsEmpty returns true if the path is empty
func (p *Path) IsEmpty() bool <span class="cov0" title="0">{
        return len(p.Components) == 0
}</span>

// String returns a debug text view of the path
func (p *Path) String() string <span class="cov0" title="0">{
        s := ""
        j := 0
        for _, cmd := range p.Components </span><span class="cov0" title="0">{
                switch cmd </span>{
                case MoveToComponent:<span class="cov0" title="0">
                        s += fmt.Sprintf("MoveTo: %f, %f\n", p.Points[j], p.Points[j+1])
                        j = j + 2</span>
                case LineToComponent:<span class="cov0" title="0">
                        s += fmt.Sprintf("LineTo: %f, %f\n", p.Points[j], p.Points[j+1])
                        j = j + 2</span>
                case QuadCurveToComponent:<span class="cov0" title="0">
                        s += fmt.Sprintf("QuadCurveTo: %f, %f, %f, %f\n", p.Points[j], p.Points[j+1], p.Points[j+2], p.Points[j+3])
                        j = j + 4</span>
                case CubicCurveToComponent:<span class="cov0" title="0">
                        s += fmt.Sprintf("CubicCurveTo: %f, %f, %f, %f, %f, %f\n", p.Points[j], p.Points[j+1], p.Points[j+2], p.Points[j+3], p.Points[j+4], p.Points[j+5])
                        j = j + 6</span>
                case ArcToComponent:<span class="cov0" title="0">
                        s += fmt.Sprintf("ArcTo: %f, %f, %f, %f, %f, %f\n", p.Points[j], p.Points[j+1], p.Points[j+2], p.Points[j+3], p.Points[j+4], p.Points[j+5])
                        j = j + 6</span>
                case CloseComponent:<span class="cov0" title="0">
                        s += "Close\n"</span>
                }
        }
        <span class="cov0" title="0">return s</span>
}
</pre>
		
		<pre class="file" id="file20" style="display: none">package drawing

import (
        "errors"
        "image"
        "image/color"
        "math"

        "github.com/golang/freetype/raster"
        "github.com/golang/freetype/truetype"
        "golang.org/x/image/draw"
        "golang.org/x/image/font"
        "golang.org/x/image/math/fixed"
)

// NewRasterGraphicContext creates a new Graphic context from an image.
func NewRasterGraphicContext(img draw.Image) (*RasterGraphicContext, error) <span class="cov0" title="0">{
        var painter Painter
        switch selectImage := img.(type) </span>{
        case *image.RGBA:<span class="cov0" title="0">
                painter = raster.NewRGBAPainter(selectImage)</span>
        default:<span class="cov0" title="0">
                return nil, errors.New("NewRasterGraphicContext() :: invalid image type")</span>
        }
        <span class="cov0" title="0">return NewRasterGraphicContextWithPainter(img, painter), nil</span>
}

// NewRasterGraphicContextWithPainter creates a new Graphic context from an image and a Painter (see Freetype-go)
func NewRasterGraphicContextWithPainter(img draw.Image, painter Painter) *RasterGraphicContext <span class="cov0" title="0">{
        width, height := img.Bounds().Dx(), img.Bounds().Dy()
        return &amp;RasterGraphicContext{
                NewStackGraphicContext(),
                img,
                painter,
                raster.NewRasterizer(width, height),
                raster.NewRasterizer(width, height),
                &amp;truetype.GlyphBuf{},
                DefaultDPI,
        }
}</span>

// RasterGraphicContext is the implementation of GraphicContext for a raster image
type RasterGraphicContext struct {
        *StackGraphicContext
        img              draw.Image
        painter          Painter
        fillRasterizer   *raster.Rasterizer
        strokeRasterizer *raster.Rasterizer
        glyphBuf         *truetype.GlyphBuf
        DPI              float64
}

// SetDPI sets the screen resolution in dots per inch.
func (rgc *RasterGraphicContext) SetDPI(dpi float64) <span class="cov0" title="0">{
        rgc.DPI = dpi
        rgc.recalc()
}</span>

// GetDPI returns the resolution of the Image GraphicContext
func (rgc *RasterGraphicContext) GetDPI() float64 <span class="cov0" title="0">{
        return rgc.DPI
}</span>

// Clear fills the current canvas with a default transparent color
func (rgc *RasterGraphicContext) Clear() <span class="cov0" title="0">{
        width, height := rgc.img.Bounds().Dx(), rgc.img.Bounds().Dy()
        rgc.ClearRect(0, 0, width, height)
}</span>

// ClearRect fills the current canvas with a default transparent color at the specified rectangle
func (rgc *RasterGraphicContext) ClearRect(x1, y1, x2, y2 int) <span class="cov0" title="0">{
        imageColor := image.NewUniform(rgc.current.FillColor)
        draw.Draw(rgc.img, image.Rect(x1, y1, x2, y2), imageColor, image.ZP, draw.Over)
}</span>

// DrawImage draws the raster image in the current canvas
func (rgc *RasterGraphicContext) DrawImage(img image.Image) <span class="cov0" title="0">{
        DrawImage(img, rgc.img, rgc.current.Tr, draw.Over, BilinearFilter)
}</span>

// FillString draws the text at point (0, 0)
func (rgc *RasterGraphicContext) FillString(text string) (cursor float64, err error) <span class="cov0" title="0">{
        cursor, err = rgc.FillStringAt(text, 0, 0)
        return
}</span>

// FillStringAt draws the text at the specified point (x, y)
func (rgc *RasterGraphicContext) FillStringAt(text string, x, y float64) (cursor float64, err error) <span class="cov0" title="0">{
        cursor, err = rgc.CreateStringPath(text, x, y)
        rgc.Fill()
        return
}</span>

// StrokeString draws the contour of the text at point (0, 0)
func (rgc *RasterGraphicContext) StrokeString(text string) (cursor float64, err error) <span class="cov0" title="0">{
        cursor, err = rgc.StrokeStringAt(text, 0, 0)
        return
}</span>

// StrokeStringAt draws the contour of the text at point (x, y)
func (rgc *RasterGraphicContext) StrokeStringAt(text string, x, y float64) (cursor float64, err error) <span class="cov0" title="0">{
        cursor, err = rgc.CreateStringPath(text, x, y)
        rgc.Stroke()
        return
}</span>

func (rgc *RasterGraphicContext) drawGlyph(glyph truetype.Index, dx, dy float64) error <span class="cov0" title="0">{
        if err := rgc.glyphBuf.Load(rgc.current.Font, fixed.Int26_6(rgc.current.Scale), glyph, font.HintingNone); err != nil </span><span class="cov0" title="0">{
                return err
        }</span>
        <span class="cov0" title="0">e0 := 0
        for _, e1 := range rgc.glyphBuf.Ends </span><span class="cov0" title="0">{
                DrawContour(rgc, rgc.glyphBuf.Points[e0:e1], dx, dy)
                e0 = e1
        }</span>
        <span class="cov0" title="0">return nil</span>
}

// CreateStringPath creates a path from the string s at x, y, and returns the string width.
// The text is placed so that the left edge of the em square of the first character of s
// and the baseline intersect at x, y. The majority of the affected pixels will be
// above and to the right of the point, but some may be below or to the left.
// For example, drawing a string that starts with a 'J' in an italic font may
// affect pixels below and left of the point.
func (rgc *RasterGraphicContext) CreateStringPath(s string, x, y float64) (cursor float64, err error) <span class="cov0" title="0">{
        f := rgc.GetFont()
        if f == nil </span><span class="cov0" title="0">{
                err = errors.New("No font loaded, cannot continue")
                return
        }</span>
        <span class="cov0" title="0">rgc.recalc()

        startx := x
        prev, hasPrev := truetype.Index(0), false
        for _, rc := range s </span><span class="cov0" title="0">{
                index := f.Index(rc)
                if hasPrev </span><span class="cov0" title="0">{
                        x += fUnitsToFloat64(f.Kern(fixed.Int26_6(rgc.current.Scale), prev, index))
                }</span>
                <span class="cov0" title="0">err = rgc.drawGlyph(index, x, y)
                if err != nil </span><span class="cov0" title="0">{
                        cursor = x - startx
                        return
                }</span>
                <span class="cov0" title="0">x += fUnitsToFloat64(f.HMetric(fixed.Int26_6(rgc.current.Scale), index).AdvanceWidth)
                prev, hasPrev = index, true</span>
        }
        <span class="cov0" title="0">cursor = x - startx
        return</span>
}

// GetStringBounds returns the approximate pixel bounds of a string.
func (rgc *RasterGraphicContext) GetStringBounds(s string) (left, top, right, bottom float64, err error) <span class="cov0" title="0">{
        f := rgc.GetFont()
        if f == nil </span><span class="cov0" title="0">{
                err = errors.New("No font loaded, cannot continue")
                return
        }</span>
        <span class="cov0" title="0">rgc.recalc()

        left = math.MaxFloat64
        top = math.MaxFloat64

        cursor := 0.0
        prev, hasPrev := truetype.Index(0), false
        for _, rc := range s </span><span class="cov0" title="0">{
                index := f.Index(rc)
                if hasPrev </span><span class="cov0" title="0">{
                        cursor += fUnitsToFloat64(f.Kern(fixed.Int26_6(rgc.current.Scale), prev, index))
                }</span>

                <span class="cov0" title="0">if err = rgc.glyphBuf.Load(rgc.current.Font, fixed.Int26_6(rgc.current.Scale), index, font.HintingNone); err != nil </span><span class="cov0" title="0">{
                        return
                }</span>
                <span class="cov0" title="0">e0 := 0
                for _, e1 := range rgc.glyphBuf.Ends </span><span class="cov0" title="0">{
                        ps := rgc.glyphBuf.Points[e0:e1]
                        for _, p := range ps </span><span class="cov0" title="0">{
                                x, y := pointToF64Point(p)
                                top = math.Min(top, y)
                                bottom = math.Max(bottom, y)
                                left = math.Min(left, x+cursor)
                                right = math.Max(right, x+cursor)
                        }</span>
                        <span class="cov0" title="0">e0 = e1</span>
                }
                <span class="cov0" title="0">cursor += fUnitsToFloat64(f.HMetric(fixed.Int26_6(rgc.current.Scale), index).AdvanceWidth)
                prev, hasPrev = index, true</span>
        }
        <span class="cov0" title="0">return</span>
}

// recalc recalculates scale and bounds values from the font size, screen
// resolution and font metrics, and invalidates the glyph cache.
func (rgc *RasterGraphicContext) recalc() <span class="cov0" title="0">{
        rgc.current.Scale = rgc.current.FontSizePoints * float64(rgc.DPI)
}</span>

// SetFont sets the font used to draw text.
func (rgc *RasterGraphicContext) SetFont(font *truetype.Font) <span class="cov0" title="0">{
        rgc.current.Font = font
}</span>

// GetFont returns the font used to draw text.
func (rgc *RasterGraphicContext) GetFont() *truetype.Font <span class="cov0" title="0">{
        return rgc.current.Font
}</span>

// SetFontSize sets the font size in points (as in ``a 12 point font'').
func (rgc *RasterGraphicContext) SetFontSize(fontSizePoints float64) <span class="cov0" title="0">{
        rgc.current.FontSizePoints = fontSizePoints
        rgc.recalc()
}</span>

func (rgc *RasterGraphicContext) paint(rasterizer *raster.Rasterizer, color color.Color) <span class="cov0" title="0">{
        rgc.painter.SetColor(color)
        rasterizer.Rasterize(rgc.painter)
        rasterizer.Clear()
        rgc.current.Path.Clear()
}</span>

// Stroke strokes the paths with the color specified by SetStrokeColor
func (rgc *RasterGraphicContext) Stroke(paths ...*Path) <span class="cov0" title="0">{
        paths = append(paths, rgc.current.Path)
        rgc.strokeRasterizer.UseNonZeroWinding = true

        stroker := NewLineStroker(rgc.current.Cap, rgc.current.Join, Transformer{Tr: rgc.current.Tr, Flattener: FtLineBuilder{Adder: rgc.strokeRasterizer}})
        stroker.HalfLineWidth = rgc.current.LineWidth / 2

        var liner Flattener
        if rgc.current.Dash != nil &amp;&amp; len(rgc.current.Dash) &gt; 0 </span><span class="cov0" title="0">{
                liner = NewDashVertexConverter(rgc.current.Dash, rgc.current.DashOffset, stroker)
        }</span> else<span class="cov0" title="0"> {
                liner = stroker
        }</span>
        <span class="cov0" title="0">for _, p := range paths </span><span class="cov0" title="0">{
                Flatten(p, liner, rgc.current.Tr.GetScale())
        }</span>

        <span class="cov0" title="0">rgc.paint(rgc.strokeRasterizer, rgc.current.StrokeColor)</span>
}

// Fill fills the paths with the color specified by SetFillColor
func (rgc *RasterGraphicContext) Fill(paths ...*Path) <span class="cov0" title="0">{
        paths = append(paths, rgc.current.Path)
        rgc.fillRasterizer.UseNonZeroWinding = rgc.current.FillRule == FillRuleWinding

        flattener := Transformer{Tr: rgc.current.Tr, Flattener: FtLineBuilder{Adder: rgc.fillRasterizer}}
        for _, p := range paths </span><span class="cov0" title="0">{
                Flatten(p, flattener, rgc.current.Tr.GetScale())
        }</span>

        <span class="cov0" title="0">rgc.paint(rgc.fillRasterizer, rgc.current.FillColor)</span>
}

// FillStroke first fills the paths and than strokes them
func (rgc *RasterGraphicContext) FillStroke(paths ...*Path) <span class="cov0" title="0">{
        paths = append(paths, rgc.current.Path)
        rgc.fillRasterizer.UseNonZeroWinding = rgc.current.FillRule == FillRuleWinding
        rgc.strokeRasterizer.UseNonZeroWinding = true

        flattener := Transformer{Tr: rgc.current.Tr, Flattener: FtLineBuilder{Adder: rgc.fillRasterizer}}

        stroker := NewLineStroker(rgc.current.Cap, rgc.current.Join, Transformer{Tr: rgc.current.Tr, Flattener: FtLineBuilder{Adder: rgc.strokeRasterizer}})
        stroker.HalfLineWidth = rgc.current.LineWidth / 2

        var liner Flattener
        if rgc.current.Dash != nil &amp;&amp; len(rgc.current.Dash) &gt; 0 </span><span class="cov0" title="0">{
                liner = NewDashVertexConverter(rgc.current.Dash, rgc.current.DashOffset, stroker)
        }</span> else<span class="cov0" title="0"> {
                liner = stroker
        }</span>

        <span class="cov0" title="0">demux := DemuxFlattener{Flatteners: []Flattener{flattener, liner}}
        for _, p := range paths </span><span class="cov0" title="0">{
                Flatten(p, demux, rgc.current.Tr.GetScale())
        }</span>

        // Fill
        <span class="cov0" title="0">rgc.paint(rgc.fillRasterizer, rgc.current.FillColor)
        // Stroke
        rgc.paint(rgc.strokeRasterizer, rgc.current.StrokeColor)</span>
}
</pre>
		
		<pre class="file" id="file21" style="display: none">package drawing

import (
        "image"
        "image/color"

        "github.com/golang/freetype/truetype"
)

// StackGraphicContext is a context that does thngs.
type StackGraphicContext struct {
        current *ContextStack
}

// ContextStack is a graphic context implementation.
type ContextStack struct {
        Tr          Matrix
        Path        *Path
        LineWidth   float64
        Dash        []float64
        DashOffset  float64
        StrokeColor color.Color
        FillColor   color.Color
        FillRule    FillRule
        Cap         LineCap
        Join        LineJoin

        FontSizePoints float64
        Font           *truetype.Font

        Scale float64

        Previous *ContextStack
}

// NewStackGraphicContext Create a new Graphic context from an image
func NewStackGraphicContext() *StackGraphicContext <span class="cov0" title="0">{
        gc := &amp;StackGraphicContext{}
        gc.current = new(ContextStack)
        gc.current.Tr = NewIdentityMatrix()
        gc.current.Path = new(Path)
        gc.current.LineWidth = 1.0
        gc.current.StrokeColor = image.Black
        gc.current.FillColor = image.White
        gc.current.Cap = RoundCap
        gc.current.FillRule = FillRuleEvenOdd
        gc.current.Join = RoundJoin
        gc.current.FontSizePoints = 10
        return gc
}</span>

// GetMatrixTransform returns the matrix transform.
func (gc *StackGraphicContext) GetMatrixTransform() Matrix <span class="cov0" title="0">{
        return gc.current.Tr
}</span>

// SetMatrixTransform sets the matrix transform.
func (gc *StackGraphicContext) SetMatrixTransform(tr Matrix) <span class="cov0" title="0">{
        gc.current.Tr = tr
}</span>

// ComposeMatrixTransform composes a transform into the current transform.
func (gc *StackGraphicContext) ComposeMatrixTransform(tr Matrix) <span class="cov0" title="0">{
        gc.current.Tr.Compose(tr)
}</span>

// Rotate rotates the matrix transform by an angle in degrees.
func (gc *StackGraphicContext) Rotate(angle float64) <span class="cov0" title="0">{
        gc.current.Tr.Rotate(angle)
}</span>

// Translate translates a transform.
func (gc *StackGraphicContext) Translate(tx, ty float64) <span class="cov0" title="0">{
        gc.current.Tr.Translate(tx, ty)
}</span>

// Scale scales a transform.
func (gc *StackGraphicContext) Scale(sx, sy float64) <span class="cov0" title="0">{
        gc.current.Tr.Scale(sx, sy)
}</span>

// SetStrokeColor sets the stroke color.
func (gc *StackGraphicContext) SetStrokeColor(c color.Color) <span class="cov0" title="0">{
        gc.current.StrokeColor = c
}</span>

// SetFillColor sets the fill color.
func (gc *StackGraphicContext) SetFillColor(c color.Color) <span class="cov0" title="0">{
        gc.current.FillColor = c
}</span>

// SetFillRule sets the fill rule.
func (gc *StackGraphicContext) SetFillRule(f FillRule) <span class="cov0" title="0">{
        gc.current.FillRule = f
}</span>

// SetLineWidth sets the line width.
func (gc *StackGraphicContext) SetLineWidth(lineWidth float64) <span class="cov0" title="0">{
        gc.current.LineWidth = lineWidth
}</span>

// SetLineCap sets the line cap.
func (gc *StackGraphicContext) SetLineCap(cap LineCap) <span class="cov0" title="0">{
        gc.current.Cap = cap
}</span>

// SetLineJoin sets the line join.
func (gc *StackGraphicContext) SetLineJoin(join LineJoin) <span class="cov0" title="0">{
        gc.current.Join = join
}</span>

// SetLineDash sets the line dash.
func (gc *StackGraphicContext) SetLineDash(dash []float64, dashOffset float64) <span class="cov0" title="0">{
        gc.current.Dash = dash
        gc.current.DashOffset = dashOffset
}</span>

// SetFontSize sets the font size.
func (gc *StackGraphicContext) SetFontSize(fontSizePoints float64) <span class="cov0" title="0">{
        gc.current.FontSizePoints = fontSizePoints
}</span>

// GetFontSize gets the font size.
func (gc *StackGraphicContext) GetFontSize() float64 <span class="cov0" title="0">{
        return gc.current.FontSizePoints
}</span>

// SetFont sets the current font.
func (gc *StackGraphicContext) SetFont(f *truetype.Font) <span class="cov0" title="0">{
        gc.current.Font = f
}</span>

// GetFont returns the font.
func (gc *StackGraphicContext) GetFont() *truetype.Font <span class="cov0" title="0">{
        return gc.current.Font
}</span>

// BeginPath starts a new path.
func (gc *StackGraphicContext) BeginPath() <span class="cov0" title="0">{
        gc.current.Path.Clear()
}</span>

// IsEmpty returns if the path is empty.
func (gc *StackGraphicContext) IsEmpty() bool <span class="cov0" title="0">{
        return gc.current.Path.IsEmpty()
}</span>

// LastPoint returns the last point on the path.
func (gc *StackGraphicContext) LastPoint() (x float64, y float64) <span class="cov0" title="0">{
        return gc.current.Path.LastPoint()
}</span>

// MoveTo moves the cursor for a path.
func (gc *StackGraphicContext) MoveTo(x, y float64) <span class="cov0" title="0">{
        gc.current.Path.MoveTo(x, y)
}</span>

// LineTo draws a line.
func (gc *StackGraphicContext) LineTo(x, y float64) <span class="cov0" title="0">{
        gc.current.Path.LineTo(x, y)
}</span>

// QuadCurveTo draws a quad curve.
func (gc *StackGraphicContext) QuadCurveTo(cx, cy, x, y float64) <span class="cov0" title="0">{
        gc.current.Path.QuadCurveTo(cx, cy, x, y)
}</span>

// CubicCurveTo draws a cubic curve.
func (gc *StackGraphicContext) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) <span class="cov0" title="0">{
        gc.current.Path.CubicCurveTo(cx1, cy1, cx2, cy2, x, y)
}</span>

// ArcTo draws an arc.
func (gc *StackGraphicContext) ArcTo(cx, cy, rx, ry, startAngle, delta float64) <span class="cov0" title="0">{
        gc.current.Path.ArcTo(cx, cy, rx, ry, startAngle, delta)
}</span>

// Close closes a path.
func (gc *StackGraphicContext) Close() <span class="cov0" title="0">{
        gc.current.Path.Close()
}</span>

// Save pushes a context onto the stack.
func (gc *StackGraphicContext) Save() <span class="cov0" title="0">{
        context := new(ContextStack)
        context.FontSizePoints = gc.current.FontSizePoints
        context.Font = gc.current.Font
        context.LineWidth = gc.current.LineWidth
        context.StrokeColor = gc.current.StrokeColor
        context.FillColor = gc.current.FillColor
        context.FillRule = gc.current.FillRule
        context.Dash = gc.current.Dash
        context.DashOffset = gc.current.DashOffset
        context.Cap = gc.current.Cap
        context.Join = gc.current.Join
        context.Path = gc.current.Path.Copy()
        context.Font = gc.current.Font
        context.Scale = gc.current.Scale
        copy(context.Tr[:], gc.current.Tr[:])
        context.Previous = gc.current
        gc.current = context
}</span>

// Restore restores the previous context.
func (gc *StackGraphicContext) Restore() <span class="cov0" title="0">{
        if gc.current.Previous != nil </span><span class="cov0" title="0">{
                oldContext := gc.current
                gc.current = gc.current.Previous
                oldContext.Previous = nil
        }</span>
}
</pre>
		
		<pre class="file" id="file22" style="display: none">// Copyright 2010 The draw2d Authors. All rights reserved.
// created: 13/12/2010 by Laurent Le Goff

package drawing

// NewLineStroker creates a new line stroker.
func NewLineStroker(c LineCap, j LineJoin, flattener Flattener) *LineStroker <span class="cov0" title="0">{
        l := new(LineStroker)
        l.Flattener = flattener
        l.HalfLineWidth = 0.5
        l.Cap = c
        l.Join = j
        return l
}</span>

// LineStroker draws the stroke portion of a line.
type LineStroker struct {
        Flattener     Flattener
        HalfLineWidth float64
        Cap           LineCap
        Join          LineJoin
        vertices      []float64
        rewind        []float64
        x, y, nx, ny  float64
}

// MoveTo implements the path builder interface.
func (l *LineStroker) MoveTo(x, y float64) <span class="cov0" title="0">{
        l.x, l.y = x, y
}</span>

// LineTo implements the path builder interface.
func (l *LineStroker) LineTo(x, y float64) <span class="cov0" title="0">{
        l.line(l.x, l.y, x, y)
}</span>

// LineJoin implements the path builder interface.
func (l *LineStroker) LineJoin() {<span class="cov0" title="0">}</span>

func (l *LineStroker) line(x1, y1, x2, y2 float64) <span class="cov0" title="0">{
        dx := (x2 - x1)
        dy := (y2 - y1)
        d := vectorDistance(dx, dy)
        if d != 0 </span><span class="cov0" title="0">{
                nx := dy * l.HalfLineWidth / d
                ny := -(dx * l.HalfLineWidth / d)
                l.appendVertex(x1+nx, y1+ny, x2+nx, y2+ny, x1-nx, y1-ny, x2-nx, y2-ny)
                l.x, l.y, l.nx, l.ny = x2, y2, nx, ny
        }</span>
}

// Close implements the path builder interface.
func (l *LineStroker) Close() <span class="cov0" title="0">{
        if len(l.vertices) &gt; 1 </span><span class="cov0" title="0">{
                l.appendVertex(l.vertices[0], l.vertices[1], l.rewind[0], l.rewind[1])
        }</span>
}

// End implements the path builder interface.
func (l *LineStroker) End() <span class="cov0" title="0">{
        if len(l.vertices) &gt; 1 </span><span class="cov0" title="0">{
                l.Flattener.MoveTo(l.vertices[0], l.vertices[1])
                for i, j := 2, 3; j &lt; len(l.vertices); i, j = i+2, j+2 </span><span class="cov0" title="0">{
                        l.Flattener.LineTo(l.vertices[i], l.vertices[j])
                }</span>
        }
        <span class="cov0" title="0">for i, j := len(l.rewind)-2, len(l.rewind)-1; j &gt; 0; i, j = i-2, j-2 </span><span class="cov0" title="0">{
                l.Flattener.LineTo(l.rewind[i], l.rewind[j])
        }</span>
        <span class="cov0" title="0">if len(l.vertices) &gt; 1 </span><span class="cov0" title="0">{
                l.Flattener.LineTo(l.vertices[0], l.vertices[1])
        }</span>
        <span class="cov0" title="0">l.Flattener.End()
        // reinit vertices
        l.vertices = l.vertices[0:0]
        l.rewind = l.rewind[0:0]
        l.x, l.y, l.nx, l.ny = 0, 0, 0, 0</span>

}

func (l *LineStroker) appendVertex(vertices ...float64) <span class="cov0" title="0">{
        s := len(vertices) / 2
        l.vertices = append(l.vertices, vertices[:s]...)
        l.rewind = append(l.rewind, vertices[s:]...)
}</span>
</pre>
		
		<pre class="file" id="file23" style="display: none">package drawing

import (
        "github.com/golang/freetype/truetype"
        "golang.org/x/image/math/fixed"
)

// DrawContour draws the given closed contour at the given sub-pixel offset.
func DrawContour(path PathBuilder, ps []truetype.Point, dx, dy float64) <span class="cov0" title="0">{
        if len(ps) == 0 </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov0" title="0">startX, startY := pointToF64Point(ps[0])
        path.MoveTo(startX+dx, startY+dy)
        q0X, q0Y, on0 := startX, startY, true
        for _, p := range ps[1:] </span><span class="cov0" title="0">{
                qX, qY := pointToF64Point(p)
                on := p.Flags&amp;0x01 != 0
                if on </span><span class="cov0" title="0">{
                        if on0 </span><span class="cov0" title="0">{
                                path.LineTo(qX+dx, qY+dy)
                        }</span> else<span class="cov0" title="0"> {
                                path.QuadCurveTo(q0X+dx, q0Y+dy, qX+dx, qY+dy)
                        }</span>
                } else<span class="cov0" title="0"> if !on0 </span><span class="cov0" title="0">{
                        midX := (q0X + qX) / 2
                        midY := (q0Y + qY) / 2
                        path.QuadCurveTo(q0X+dx, q0Y+dy, midX+dx, midY+dy)
                }</span>
                <span class="cov0" title="0">q0X, q0Y, on0 = qX, qY, on</span>
        }
        // Close the curve.
        <span class="cov0" title="0">if on0 </span><span class="cov0" title="0">{
                path.LineTo(startX+dx, startY+dy)
        }</span> else<span class="cov0" title="0"> {
                path.QuadCurveTo(q0X+dx, q0Y+dy, startX+dx, startY+dy)
        }</span>
}

// FontExtents contains font metric information.
type FontExtents struct {
        // Ascent is the distance that the text
        // extends above the baseline.
        Ascent float64

        // Descent is the distance that the text
        // extends below the baseline.  The descent
        // is given as a negative value.
        Descent float64

        // Height is the distance from the lowest
        // descending point to the highest ascending
        // point.
        Height float64
}

// Extents returns the FontExtents for a font.
// TODO needs to read this https://developer.apple.com/fonts/TrueType-Reference-Manual/RM02/Chap2.html#intro
func Extents(font *truetype.Font, size float64) FontExtents <span class="cov0" title="0">{
        bounds := font.Bounds(fixed.Int26_6(font.FUnitsPerEm()))
        scale := size / float64(font.FUnitsPerEm())
        return FontExtents{
                Ascent:  float64(bounds.Max.Y) * scale,
                Descent: float64(bounds.Min.Y) * scale,
                Height:  float64(bounds.Max.Y-bounds.Min.Y) * scale,
        }
}</span>
</pre>
		
		<pre class="file" id="file24" style="display: none">// Copyright 2010 The draw2d Authors. All rights reserved.
// created: 13/12/2010 by Laurent Le Goff

package drawing

// Transformer apply the Matrix transformation tr
type Transformer struct {
        Tr        Matrix
        Flattener Flattener
}

// MoveTo implements the path builder interface.
func (t Transformer) MoveTo(x, y float64) <span class="cov0" title="0">{
        u := x*t.Tr[0] + y*t.Tr[2] + t.Tr[4]
        v := x*t.Tr[1] + y*t.Tr[3] + t.Tr[5]
        t.Flattener.MoveTo(u, v)
}</span>

// LineTo implements the path builder interface.
func (t Transformer) LineTo(x, y float64) <span class="cov0" title="0">{
        u := x*t.Tr[0] + y*t.Tr[2] + t.Tr[4]
        v := x*t.Tr[1] + y*t.Tr[3] + t.Tr[5]
        t.Flattener.LineTo(u, v)
}</span>

// LineJoin implements the path builder interface.
func (t Transformer) LineJoin() <span class="cov0" title="0">{
        t.Flattener.LineJoin()
}</span>

// Close implements the path builder interface.
func (t Transformer) Close() <span class="cov0" title="0">{
        t.Flattener.Close()
}</span>

// End implements the path builder interface.
func (t Transformer) End() <span class="cov0" title="0">{
        t.Flattener.End()
}</span>
</pre>
		
		<pre class="file" id="file25" style="display: none">package drawing

import (
        "math"

        "golang.org/x/image/math/fixed"

        "github.com/golang/freetype/raster"
        "github.com/golang/freetype/truetype"
)

// PixelsToPoints returns the points for a given number of pixels at a DPI.
func PixelsToPoints(dpi, pixels float64) (points float64) <span class="cov0" title="0">{
        points = (pixels * 72.0) / dpi
        return
}</span>

// PointsToPixels returns the pixels for a given number of points at a DPI.
func PointsToPixels(dpi, points float64) (pixels float64) <span class="cov0" title="0">{
        pixels = (points * dpi) / 72.0
        return
}</span>

func abs(i int) int <span class="cov0" title="0">{
        if i &lt; 0 </span><span class="cov0" title="0">{
                return -i
        }</span>
        <span class="cov0" title="0">return i</span>
}

func distance(x1, y1, x2, y2 float64) float64 <span class="cov0" title="0">{
        return vectorDistance(x2-x1, y2-y1)
}</span>

func vectorDistance(dx, dy float64) float64 <span class="cov0" title="0">{
        return float64(math.Sqrt(dx*dx + dy*dy))
}</span>

func toFtCap(c LineCap) raster.Capper <span class="cov0" title="0">{
        switch c </span>{
        case RoundCap:<span class="cov0" title="0">
                return raster.RoundCapper</span>
        case ButtCap:<span class="cov0" title="0">
                return raster.ButtCapper</span>
        case SquareCap:<span class="cov0" title="0">
                return raster.SquareCapper</span>
        }
        <span class="cov0" title="0">return raster.RoundCapper</span>
}

func toFtJoin(j LineJoin) raster.Joiner <span class="cov0" title="0">{
        switch j </span>{
        case RoundJoin:<span class="cov0" title="0">
                return raster.RoundJoiner</span>
        case BevelJoin:<span class="cov0" title="0">
                return raster.BevelJoiner</span>
        }
        <span class="cov0" title="0">return raster.RoundJoiner</span>
}

func pointToF64Point(p truetype.Point) (x, y float64) <span class="cov0" title="0">{
        return fUnitsToFloat64(p.X), -fUnitsToFloat64(p.Y)
}</span>

func fUnitsToFloat64(x fixed.Int26_6) float64 <span class="cov0" title="0">{
        scaled := x &lt;&lt; 2
        return float64(scaled/256) + float64(scaled%256)/256.0
}</span>
</pre>
		
		<pre class="file" id="file26" style="display: none">package chart

import "fmt"

const (
        // DefaultEMAPeriod is the default EMA period used in the sigma calculation.
        DefaultEMAPeriod = 12
)

// Interface Assertions.
var (
        _ Series              = (*EMASeries)(nil)
        _ FirstValuesProvider = (*EMASeries)(nil)
        _ LastValuesProvider  = (*EMASeries)(nil)
)

// EMASeries is a computed series.
type EMASeries struct {
        Name  string
        Style Style
        YAxis YAxisType

        Period      int
        InnerSeries ValuesProvider

        cache []float64
}

// GetName returns the name of the time series.
func (ema EMASeries) GetName() string <span class="cov0" title="0">{
        return ema.Name
}</span>

// GetStyle returns the line style.
func (ema EMASeries) GetStyle() Style <span class="cov0" title="0">{
        return ema.Style
}</span>

// GetYAxis returns which YAxis the series draws on.
func (ema EMASeries) GetYAxis() YAxisType <span class="cov0" title="0">{
        return ema.YAxis
}</span>

// GetPeriod returns the window size.
func (ema EMASeries) GetPeriod() int <span class="cov8" title="1">{
        if ema.Period == 0 </span><span class="cov0" title="0">{
                return DefaultEMAPeriod
        }</span>
        <span class="cov8" title="1">return ema.Period</span>
}

// Len returns the number of elements in the series.
func (ema EMASeries) Len() int <span class="cov8" title="1">{
        return ema.InnerSeries.Len()
}</span>

// GetSigma returns the smoothing factor for the serise.
func (ema EMASeries) GetSigma() float64 <span class="cov8" title="1">{
        return 2.0 / (float64(ema.GetPeriod()) + 1)
}</span>

// GetValues gets a value at a given index.
func (ema *EMASeries) GetValues(index int) (x, y float64) <span class="cov8" title="1">{
        if ema.InnerSeries == nil </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov8" title="1">if len(ema.cache) == 0 </span><span class="cov8" title="1">{
                ema.ensureCachedValues()
        }</span>
        <span class="cov8" title="1">vx, _ := ema.InnerSeries.GetValues(index)
        x = vx
        y = ema.cache[index]
        return</span>
}

// GetFirstValues computes the first moving average value.
func (ema *EMASeries) GetFirstValues() (x, y float64) <span class="cov0" title="0">{
        if ema.InnerSeries == nil </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov0" title="0">if len(ema.cache) == 0 </span><span class="cov0" title="0">{
                ema.ensureCachedValues()
        }</span>
        <span class="cov0" title="0">x, _ = ema.InnerSeries.GetValues(0)
        y = ema.cache[0]
        return</span>
}

// GetLastValues computes the last moving average value but walking back window size samples,
// and recomputing the last moving average chunk.
func (ema *EMASeries) GetLastValues() (x, y float64) <span class="cov8" title="1">{
        if ema.InnerSeries == nil </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov8" title="1">if len(ema.cache) == 0 </span><span class="cov0" title="0">{
                ema.ensureCachedValues()
        }</span>
        <span class="cov8" title="1">lastIndex := ema.InnerSeries.Len() - 1
        x, _ = ema.InnerSeries.GetValues(lastIndex)
        y = ema.cache[lastIndex]
        return</span>
}

func (ema *EMASeries) ensureCachedValues() <span class="cov8" title="1">{
        seriesLength := ema.InnerSeries.Len()
        ema.cache = make([]float64, seriesLength)
        sigma := ema.GetSigma()
        for x := 0; x &lt; seriesLength; x++ </span><span class="cov8" title="1">{
                _, y := ema.InnerSeries.GetValues(x)
                if x == 0 </span><span class="cov8" title="1">{
                        ema.cache[x] = y
                        continue</span>
                }
                <span class="cov8" title="1">previousEMA := ema.cache[x-1]
                ema.cache[x] = ((y - previousEMA) * sigma) + previousEMA</span>
        }
}

// Render renders the series.
func (ema *EMASeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) <span class="cov0" title="0">{
        style := ema.Style.InheritFrom(defaults)
        Draw.LineSeries(r, canvasBox, xrange, yrange, style, ema)
}</span>

// Validate validates the series.
func (ema *EMASeries) Validate() error <span class="cov0" title="0">{
        if ema.InnerSeries == nil </span><span class="cov0" title="0">{
                return fmt.Errorf("ema series requires InnerSeries to be set")
        }</span>
        <span class="cov0" title="0">return nil</span>
}
</pre>
		
		<pre class="file" id="file27" style="display: none">package chart

import "fmt"

// FirstValueAnnotation returns an annotation series of just the first value of a value provider as an annotation.
func FirstValueAnnotation(innerSeries ValuesProvider, vfs ...ValueFormatter) AnnotationSeries <span class="cov8" title="1">{
        var vf ValueFormatter
        if len(vfs) &gt; 0 </span><span class="cov0" title="0">{
                vf = vfs[0]
        }</span> else<span class="cov8" title="1"> if typed, isTyped := innerSeries.(ValueFormatterProvider); isTyped </span><span class="cov8" title="1">{
                _, vf = typed.GetValueFormatters()
        }</span> else<span class="cov0" title="0"> {
                vf = FloatValueFormatter
        }</span>

        <span class="cov8" title="1">var firstValue Value2
        if typed, isTyped := innerSeries.(FirstValuesProvider); isTyped </span><span class="cov8" title="1">{
                firstValue.XValue, firstValue.YValue = typed.GetFirstValues()
                firstValue.Label = vf(firstValue.YValue)
        }</span> else<span class="cov0" title="0"> {
                firstValue.XValue, firstValue.YValue = innerSeries.GetValues(0)
                firstValue.Label = vf(firstValue.YValue)
        }</span>

        <span class="cov8" title="1">var seriesName string
        var seriesStyle Style
        if typed, isTyped := innerSeries.(Series); isTyped </span><span class="cov8" title="1">{
                seriesName = fmt.Sprintf("%s - First Value", typed.GetName())
                seriesStyle = typed.GetStyle()
        }</span>

        <span class="cov8" title="1">return AnnotationSeries{
                Name:        seriesName,
                Style:       seriesStyle,
                Annotations: []Value2{firstValue},
        }</span>
}
</pre>
		
		<pre class="file" id="file28" style="display: none">package chart

import (
        "sync"

        "github.com/golang/freetype/truetype"
        "github.com/wcharczuk/go-chart/roboto"
)

var (
        _defaultFontLock sync.Mutex
        _defaultFont     *truetype.Font
)

// GetDefaultFont returns the default font (Roboto-Medium).
func GetDefaultFont() (*truetype.Font, error) <span class="cov8" title="1">{
        if _defaultFont == nil </span><span class="cov8" title="1">{
                _defaultFontLock.Lock()
                defer _defaultFontLock.Unlock()
                if _defaultFont == nil </span><span class="cov8" title="1">{
                        font, err := truetype.Parse(roboto.Roboto)
                        if err != nil </span><span class="cov0" title="0">{
                                return nil, err
                        }</span>
                        <span class="cov8" title="1">_defaultFont = font</span>
                }
        }
        <span class="cov8" title="1">return _defaultFont, nil</span>
}
</pre>
		
		<pre class="file" id="file29" style="display: none">package chart

// GridLineProvider is a type that provides grid lines.
type GridLineProvider interface {
        GetGridLines(ticks []Tick, isVertical bool, majorStyle, minorStyle Style) []GridLine
}

// GridLine is a line on a graph canvas.
type GridLine struct {
        IsMinor bool
        Style   Style
        Value   float64
}

// Major returns if the gridline is a `major` line.
func (gl GridLine) Major() bool <span class="cov0" title="0">{
        return !gl.IsMinor
}</span>

// Minor returns if the gridline is a `minor` line.
func (gl GridLine) Minor() bool <span class="cov0" title="0">{
        return gl.IsMinor
}</span>

// Render renders the gridline
func (gl GridLine) Render(r Renderer, canvasBox Box, ra Range, isVertical bool, defaults Style) <span class="cov0" title="0">{
        r.SetStrokeColor(gl.Style.GetStrokeColor(defaults.GetStrokeColor()))
        r.SetStrokeWidth(gl.Style.GetStrokeWidth(defaults.GetStrokeWidth()))
        r.SetStrokeDashArray(gl.Style.GetStrokeDashArray(defaults.GetStrokeDashArray()))

        if isVertical </span><span class="cov0" title="0">{
                lineLeft := canvasBox.Left + ra.Translate(gl.Value)
                lineBottom := canvasBox.Bottom
                lineTop := canvasBox.Top

                r.MoveTo(lineLeft, lineBottom)
                r.LineTo(lineLeft, lineTop)
                r.Stroke()
        }</span> else<span class="cov0" title="0"> {
                lineLeft := canvasBox.Left
                lineRight := canvasBox.Right
                lineHeight := canvasBox.Bottom - ra.Translate(gl.Value)

                r.MoveTo(lineLeft, lineHeight)
                r.LineTo(lineRight, lineHeight)
                r.Stroke()
        }</span>
}

// GenerateGridLines generates grid lines.
func GenerateGridLines(ticks []Tick, majorStyle, minorStyle Style) []GridLine <span class="cov8" title="1">{
        var gl []GridLine
        isMinor := false

        if len(ticks) &lt; 3 </span><span class="cov0" title="0">{
                return gl
        }</span>

        <span class="cov8" title="1">for _, t := range ticks[1 : len(ticks)-1] </span><span class="cov8" title="1">{
                s := majorStyle
                if isMinor </span><span class="cov8" title="1">{
                        s = minorStyle
                }</span>
                <span class="cov8" title="1">gl = append(gl, GridLine{
                        Style:   s,
                        IsMinor: isMinor,
                        Value:   t.Value,
                })
                isMinor = !isMinor</span>
        }
        <span class="cov8" title="1">return gl</span>
}
</pre>
		
		<pre class="file" id="file30" style="display: none">package chart

import "fmt"

// HistogramSeries is a special type of series that draws as a histogram.
// Some peculiarities; it will always be lower bounded at 0 (at the very least).
// This may alter ranges a bit and generally you want to put a histogram series on it's own y-axis.
type HistogramSeries struct {
        Name        string
        Style       Style
        YAxis       YAxisType
        InnerSeries ValuesProvider
}

// GetName implements Series.GetName.
func (hs HistogramSeries) GetName() string <span class="cov0" title="0">{
        return hs.Name
}</span>

// GetStyle implements Series.GetStyle.
func (hs HistogramSeries) GetStyle() Style <span class="cov0" title="0">{
        return hs.Style
}</span>

// GetYAxis returns which yaxis the series is mapped to.
func (hs HistogramSeries) GetYAxis() YAxisType <span class="cov0" title="0">{
        return hs.YAxis
}</span>

// Len implements BoundedValuesProvider.Len.
func (hs HistogramSeries) Len() int <span class="cov8" title="1">{
        return hs.InnerSeries.Len()
}</span>

// GetValues implements ValuesProvider.GetValues.
func (hs HistogramSeries) GetValues(index int) (x, y float64) <span class="cov0" title="0">{
        return hs.InnerSeries.GetValues(index)
}</span>

// GetBoundedValues implements BoundedValuesProvider.GetBoundedValue
func (hs HistogramSeries) GetBoundedValues(index int) (x, y1, y2 float64) <span class="cov8" title="1">{
        vx, vy := hs.InnerSeries.GetValues(index)

        x = vx

        if vy &gt; 0 </span><span class="cov8" title="1">{
                y1 = vy
                return
        }</span>

        <span class="cov0" title="0">y2 = vy
        return</span>
}

// Render implements Series.Render.
func (hs HistogramSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) <span class="cov0" title="0">{
        style := hs.Style.InheritFrom(defaults)
        Draw.HistogramSeries(r, canvasBox, xrange, yrange, style, hs)
}</span>

// Validate validates the series.
func (hs HistogramSeries) Validate() error <span class="cov0" title="0">{
        if hs.InnerSeries == nil </span><span class="cov0" title="0">{
                return fmt.Errorf("histogram series requires InnerSeries to be set")
        }</span>
        <span class="cov0" title="0">return nil</span>
}
</pre>
		
		<pre class="file" id="file31" style="display: none">package chart

import (
        "bytes"
        "errors"
        "image"
        "image/png"
)

// RGBACollector is a render target for a chart.
type RGBACollector interface {
        SetRGBA(i *image.RGBA)
}

// ImageWriter is a special type of io.Writer that produces a final image.
type ImageWriter struct {
        rgba     *image.RGBA
        contents *bytes.Buffer
}

func (ir *ImageWriter) Write(buffer []byte) (int, error) <span class="cov0" title="0">{
        if ir.contents == nil </span><span class="cov0" title="0">{
                ir.contents = bytes.NewBuffer([]byte{})
        }</span>
        <span class="cov0" title="0">return ir.contents.Write(buffer)</span>
}

// SetRGBA sets a raw version of the image.
func (ir *ImageWriter) SetRGBA(i *image.RGBA) <span class="cov0" title="0">{
        ir.rgba = i
}</span>

// Image returns an *image.Image for the result.
func (ir *ImageWriter) Image() (image.Image, error) <span class="cov0" title="0">{
        if ir.rgba != nil </span><span class="cov0" title="0">{
                return ir.rgba, nil
        }</span>
        <span class="cov0" title="0">if ir.contents != nil &amp;&amp; ir.contents.Len() &gt; 0 </span><span class="cov0" title="0">{
                return png.Decode(ir.contents)
        }</span>
        <span class="cov0" title="0">return nil, errors.New("no valid sources for image data, cannot continue")</span>
}
</pre>
		
		<pre class="file" id="file32" style="display: none">package chart

import "github.com/wcharczuk/go-chart/drawing"

// Jet is a color map provider based on matlab's jet color map.
func Jet(v, vmin, vmax float64) drawing.Color <span class="cov0" title="0">{
        c := drawing.Color{R: 0xff, G: 0xff, B: 0xff, A: 0xff} // white
        var dv float64

        if v &lt; vmin </span><span class="cov0" title="0">{
                v = vmin
        }</span>
        <span class="cov0" title="0">if v &gt; vmax </span><span class="cov0" title="0">{
                v = vmax
        }</span>
        <span class="cov0" title="0">dv = vmax - vmin

        if v &lt; (vmin + 0.25*dv) </span><span class="cov0" title="0">{
                c.R = 0
                c.G = drawing.ColorChannelFromFloat(4 * (v - vmin) / dv)
        }</span> else<span class="cov0" title="0"> if v &lt; (vmin + 0.5*dv) </span><span class="cov0" title="0">{
                c.R = 0
                c.B = drawing.ColorChannelFromFloat(1 + 4*(vmin+0.25*dv-v)/dv)
        }</span> else<span class="cov0" title="0"> if v &lt; (vmin + 0.75*dv) </span><span class="cov0" title="0">{
                c.R = drawing.ColorChannelFromFloat(4 * (v - vmin - 0.5*dv) / dv)
                c.B = 0
        }</span> else<span class="cov0" title="0"> {
                c.G = drawing.ColorChannelFromFloat(1 + 4*(vmin+0.75*dv-v)/dv)
                c.B = 0
        }</span>

        <span class="cov0" title="0">return c</span>
}
</pre>
		
		<pre class="file" id="file33" style="display: none">package chart

import "fmt"

// LastValueAnnotation returns an annotation series of just the last value of a value provider.
func LastValueAnnotation(innerSeries ValuesProvider, vfs ...ValueFormatter) AnnotationSeries <span class="cov8" title="1">{
        var vf ValueFormatter
        if len(vfs) &gt; 0 </span><span class="cov0" title="0">{
                vf = vfs[0]
        }</span> else<span class="cov8" title="1"> if typed, isTyped := innerSeries.(ValueFormatterProvider); isTyped </span><span class="cov8" title="1">{
                _, vf = typed.GetValueFormatters()
        }</span> else<span class="cov0" title="0"> {
                vf = FloatValueFormatter
        }</span>

        <span class="cov8" title="1">var lastValue Value2
        if typed, isTyped := innerSeries.(LastValuesProvider); isTyped </span><span class="cov8" title="1">{
                lastValue.XValue, lastValue.YValue = typed.GetLastValues()
                lastValue.Label = vf(lastValue.YValue)
        }</span> else<span class="cov0" title="0"> {
                lastValue.XValue, lastValue.YValue = innerSeries.GetValues(innerSeries.Len() - 1)
                lastValue.Label = vf(lastValue.YValue)
        }</span>

        <span class="cov8" title="1">var seriesName string
        var seriesStyle Style
        if typed, isTyped := innerSeries.(Series); isTyped </span><span class="cov8" title="1">{
                seriesName = fmt.Sprintf("%s - Last Value", typed.GetName())
                seriesStyle = typed.GetStyle()
        }</span>

        <span class="cov8" title="1">return AnnotationSeries{
                Name:        seriesName,
                Style:       seriesStyle,
                Annotations: []Value2{lastValue},
        }</span>
}
</pre>
		
		<pre class="file" id="file34" style="display: none">package chart

import (
        "github.com/wcharczuk/go-chart/drawing"
        "github.com/wcharczuk/go-chart/util"
)

// Legend returns a legend renderable function.
func Legend(c *Chart, userDefaults ...Style) Renderable <span class="cov8" title="1">{
        return func(r Renderer, cb Box, chartDefaults Style) </span><span class="cov8" title="1">{
                legendDefaults := Style{
                        FillColor:   drawing.ColorWhite,
                        FontColor:   DefaultTextColor,
                        FontSize:    8.0,
                        StrokeColor: DefaultAxisColor,
                        StrokeWidth: DefaultAxisLineWidth,
                }

                var legendStyle Style
                if len(userDefaults) &gt; 0 </span><span class="cov0" title="0">{
                        legendStyle = userDefaults[0].InheritFrom(chartDefaults.InheritFrom(legendDefaults))
                }</span> else<span class="cov8" title="1"> {
                        legendStyle = chartDefaults.InheritFrom(legendDefaults)
                }</span>

                // DEFAULTS
                <span class="cov8" title="1">legendPadding := Box{
                        Top:    5,
                        Left:   5,
                        Right:  5,
                        Bottom: 5,
                }
                lineTextGap := 5
                lineLengthMinimum := 25

                var labels []string
                var lines []Style
                for index, s := range c.Series </span><span class="cov8" title="1">{
                        if s.GetStyle().IsZero() || s.GetStyle().Show </span><span class="cov8" title="1">{
                                if _, isAnnotationSeries := s.(AnnotationSeries); !isAnnotationSeries </span><span class="cov8" title="1">{
                                        labels = append(labels, s.GetName())
                                        lines = append(lines, s.GetStyle().InheritFrom(c.styleDefaultsSeries(index)))
                                }</span>
                        }
                }

                <span class="cov8" title="1">legend := Box{
                        Top:  cb.Top,
                        Left: cb.Left,
                        // bottom and right will be sized by the legend content + relevant padding.
                }

                legendContent := Box{
                        Top:    legend.Top + legendPadding.Top,
                        Left:   legend.Left + legendPadding.Left,
                        Right:  legend.Left + legendPadding.Left,
                        Bottom: legend.Top + legendPadding.Top,
                }

                legendStyle.GetTextOptions().WriteToRenderer(r)

                // measure
                labelCount := 0
                for x := 0; x &lt; len(labels); x++ </span><span class="cov8" title="1">{
                        if len(labels[x]) &gt; 0 </span><span class="cov8" title="1">{
                                tb := r.MeasureText(labels[x])
                                if labelCount &gt; 0 </span><span class="cov0" title="0">{
                                        legendContent.Bottom += DefaultMinimumTickVerticalSpacing
                                }</span>
                                <span class="cov8" title="1">legendContent.Bottom += tb.Height()
                                right := legendContent.Left + tb.Width() + lineTextGap + lineLengthMinimum
                                legendContent.Right = util.Math.MaxInt(legendContent.Right, right)
                                labelCount++</span>
                        }
                }

                <span class="cov8" title="1">legend = legend.Grow(legendContent)
                legend.Right = legendContent.Right + legendPadding.Right
                legend.Bottom = legendContent.Bottom + legendPadding.Bottom

                Draw.Box(r, legend, legendStyle)

                legendStyle.GetTextOptions().WriteToRenderer(r)

                ycursor := legendContent.Top
                tx := legendContent.Left
                legendCount := 0
                var label string
                for x := 0; x &lt; len(labels); x++ </span><span class="cov8" title="1">{
                        label = labels[x]
                        if len(label) &gt; 0 </span><span class="cov8" title="1">{
                                if legendCount &gt; 0 </span><span class="cov0" title="0">{
                                        ycursor += DefaultMinimumTickVerticalSpacing
                                }</span>

                                <span class="cov8" title="1">tb := r.MeasureText(label)

                                ty := ycursor + tb.Height()
                                r.Text(label, tx, ty)

                                th2 := tb.Height() &gt;&gt; 1

                                lx := tx + tb.Width() + lineTextGap
                                ly := ty - th2
                                lx2 := legendContent.Right - legendPadding.Right

                                r.SetStrokeColor(lines[x].GetStrokeColor())
                                r.SetStrokeWidth(lines[x].GetStrokeWidth())
                                r.SetStrokeDashArray(lines[x].GetStrokeDashArray())

                                r.MoveTo(lx, ly)
                                r.LineTo(lx2, ly)
                                r.Stroke()

                                ycursor += tb.Height()
                                legendCount++</span>
                        }
                }
        }
}

// LegendThin is a legend that doesn't obscure the chart area.
func LegendThin(c *Chart, userDefaults ...Style) Renderable <span class="cov0" title="0">{
        return func(r Renderer, cb Box, chartDefaults Style) </span><span class="cov0" title="0">{
                legendDefaults := Style{
                        FillColor:   drawing.ColorWhite,
                        FontColor:   DefaultTextColor,
                        FontSize:    8.0,
                        StrokeColor: DefaultAxisColor,
                        StrokeWidth: DefaultAxisLineWidth,
                        Padding: Box{
                                Top:    2,
                                Left:   7,
                                Right:  7,
                                Bottom: 5,
                        },
                }

                var legendStyle Style
                if len(userDefaults) &gt; 0 </span><span class="cov0" title="0">{
                        legendStyle = userDefaults[0].InheritFrom(chartDefaults.InheritFrom(legendDefaults))
                }</span> else<span class="cov0" title="0"> {
                        legendStyle = chartDefaults.InheritFrom(legendDefaults)
                }</span>

                <span class="cov0" title="0">r.SetFont(legendStyle.GetFont())
                r.SetFontColor(legendStyle.GetFontColor())
                r.SetFontSize(legendStyle.GetFontSize())

                var labels []string
                var lines []Style
                for index, s := range c.Series </span><span class="cov0" title="0">{
                        if s.GetStyle().IsZero() || s.GetStyle().Show </span><span class="cov0" title="0">{
                                if _, isAnnotationSeries := s.(AnnotationSeries); !isAnnotationSeries </span><span class="cov0" title="0">{
                                        labels = append(labels, s.GetName())
                                        lines = append(lines, s.GetStyle().InheritFrom(c.styleDefaultsSeries(index)))
                                }</span>
                        }
                }

                <span class="cov0" title="0">var textHeight int
                var textWidth int
                var textBox Box
                for x := 0; x &lt; len(labels); x++ </span><span class="cov0" title="0">{
                        if len(labels[x]) &gt; 0 </span><span class="cov0" title="0">{
                                textBox = r.MeasureText(labels[x])
                                textHeight = util.Math.MaxInt(textBox.Height(), textHeight)
                                textWidth = util.Math.MaxInt(textBox.Width(), textWidth)
                        }</span>
                }

                <span class="cov0" title="0">legendBoxHeight := textHeight + legendStyle.Padding.Top + legendStyle.Padding.Bottom
                chartPadding := cb.Top
                legendYMargin := (chartPadding - legendBoxHeight) &gt;&gt; 1

                legendBox := Box{
                        Left:   cb.Left,
                        Right:  cb.Right,
                        Top:    legendYMargin,
                        Bottom: legendYMargin + legendBoxHeight,
                }

                Draw.Box(r, legendBox, legendDefaults)

                r.SetFont(legendStyle.GetFont())
                r.SetFontColor(legendStyle.GetFontColor())
                r.SetFontSize(legendStyle.GetFontSize())

                lineTextGap := 5
                lineLengthMinimum := 25

                tx := legendBox.Left + legendStyle.Padding.Left
                ty := legendYMargin + legendStyle.Padding.Top + textHeight
                var label string
                var lx, ly int
                th2 := textHeight &gt;&gt; 1
                for index := range labels </span><span class="cov0" title="0">{
                        label = labels[index]
                        if len(label) &gt; 0 </span><span class="cov0" title="0">{
                                textBox = r.MeasureText(label)
                                r.Text(label, tx, ty)

                                lx = tx + textBox.Width() + lineTextGap
                                ly = ty - th2

                                r.SetStrokeColor(lines[index].GetStrokeColor())
                                r.SetStrokeWidth(lines[index].GetStrokeWidth())
                                r.SetStrokeDashArray(lines[index].GetStrokeDashArray())

                                r.MoveTo(lx, ly)
                                r.LineTo(lx+lineLengthMinimum, ly)
                                r.Stroke()

                                tx += textBox.Width() + DefaultMinimumTickHorizontalSpacing + lineTextGap + lineLengthMinimum
                        }</span>
                }
        }
}

// LegendLeft is a legend that is designed for longer series lists.
func LegendLeft(c *Chart, userDefaults ...Style) Renderable <span class="cov0" title="0">{
        return func(r Renderer, cb Box, chartDefaults Style) </span><span class="cov0" title="0">{
                legendDefaults := Style{
                        FillColor:   drawing.ColorWhite,
                        FontColor:   DefaultTextColor,
                        FontSize:    8.0,
                        StrokeColor: DefaultAxisColor,
                        StrokeWidth: DefaultAxisLineWidth,
                }

                var legendStyle Style
                if len(userDefaults) &gt; 0 </span><span class="cov0" title="0">{
                        legendStyle = userDefaults[0].InheritFrom(chartDefaults.InheritFrom(legendDefaults))
                }</span> else<span class="cov0" title="0"> {
                        legendStyle = chartDefaults.InheritFrom(legendDefaults)
                }</span>

                // DEFAULTS
                <span class="cov0" title="0">legendPadding := Box{
                        Top:    5,
                        Left:   5,
                        Right:  5,
                        Bottom: 5,
                }
                lineTextGap := 5
                lineLengthMinimum := 25

                var labels []string
                var lines []Style
                for index, s := range c.Series </span><span class="cov0" title="0">{
                        if s.GetStyle().IsZero() || s.GetStyle().Show </span><span class="cov0" title="0">{
                                if _, isAnnotationSeries := s.(AnnotationSeries); !isAnnotationSeries </span><span class="cov0" title="0">{
                                        labels = append(labels, s.GetName())
                                        lines = append(lines, s.GetStyle().InheritFrom(c.styleDefaultsSeries(index)))
                                }</span>
                        }
                }

                <span class="cov0" title="0">legend := Box{
                        Top:  5,
                        Left: 5,
                        // bottom and right will be sized by the legend content + relevant padding.
                }

                legendContent := Box{
                        Top:    legend.Top + legendPadding.Top,
                        Left:   legend.Left + legendPadding.Left,
                        Right:  legend.Left + legendPadding.Left,
                        Bottom: legend.Top + legendPadding.Top,
                }

                legendStyle.GetTextOptions().WriteToRenderer(r)

                // measure
                labelCount := 0
                for x := 0; x &lt; len(labels); x++ </span><span class="cov0" title="0">{
                        if len(labels[x]) &gt; 0 </span><span class="cov0" title="0">{
                                tb := r.MeasureText(labels[x])
                                if labelCount &gt; 0 </span><span class="cov0" title="0">{
                                        legendContent.Bottom += DefaultMinimumTickVerticalSpacing
                                }</span>
                                <span class="cov0" title="0">legendContent.Bottom += tb.Height()
                                right := legendContent.Left + tb.Width() + lineTextGap + lineLengthMinimum
                                legendContent.Right = util.Math.MaxInt(legendContent.Right, right)
                                labelCount++</span>
                        }
                }

                <span class="cov0" title="0">legend = legend.Grow(legendContent)
                legend.Right = legendContent.Right + legendPadding.Right
                legend.Bottom = legendContent.Bottom + legendPadding.Bottom

                Draw.Box(r, legend, legendStyle)

                legendStyle.GetTextOptions().WriteToRenderer(r)

                ycursor := legendContent.Top
                tx := legendContent.Left
                legendCount := 0
                var label string
                for x := 0; x &lt; len(labels); x++ </span><span class="cov0" title="0">{
                        label = labels[x]
                        if len(label) &gt; 0 </span><span class="cov0" title="0">{
                                if legendCount &gt; 0 </span><span class="cov0" title="0">{
                                        ycursor += DefaultMinimumTickVerticalSpacing
                                }</span>

                                <span class="cov0" title="0">tb := r.MeasureText(label)

                                ty := ycursor + tb.Height()
                                r.Text(label, tx, ty)

                                th2 := tb.Height() &gt;&gt; 1

                                lx := tx + tb.Width() + lineTextGap
                                ly := ty - th2
                                lx2 := legendContent.Right - legendPadding.Right

                                r.SetStrokeColor(lines[x].GetStrokeColor())
                                r.SetStrokeWidth(lines[x].GetStrokeWidth())
                                r.SetStrokeDashArray(lines[x].GetStrokeDashArray())

                                r.MoveTo(lx, ly)
                                r.LineTo(lx2, ly)
                                r.Stroke()

                                ycursor += tb.Height()
                                legendCount++</span>
                        }
                }
        }
}
</pre>
		
		<pre class="file" id="file35" style="display: none">package chart

// LinearCoefficientProvider is a type that returns linear cofficients.
type LinearCoefficientProvider interface {
        Coefficients() (m, b, stdev, avg float64)
}

// LinearCoefficients returns a fixed linear coefficient pair.
func LinearCoefficients(m, b float64) LinearCoefficientSet <span class="cov0" title="0">{
        return LinearCoefficientSet{
                M: m,
                B: b,
        }
}</span>

// NormalizedLinearCoefficients returns a fixed linear coefficient pair.
func NormalizedLinearCoefficients(m, b, stdev, avg float64) LinearCoefficientSet <span class="cov0" title="0">{
        return LinearCoefficientSet{
                M:      m,
                B:      b,
                StdDev: stdev,
                Avg:    avg,
        }
}</span>

// LinearCoefficientSet is the m and b values for the linear equation in the form:
// y = (m*x) + b
type LinearCoefficientSet struct {
        M      float64
        B      float64
        StdDev float64
        Avg    float64
}

// Coefficients returns the coefficients.
func (lcs LinearCoefficientSet) Coefficients() (m, b, stdev, avg float64) <span class="cov0" title="0">{
        m = lcs.M
        b = lcs.B
        stdev = lcs.StdDev
        avg = lcs.Avg
        return
}</span>
</pre>
		
		<pre class="file" id="file36" style="display: none">package chart

import (
        "fmt"

        "github.com/wcharczuk/go-chart/seq"
        util "github.com/wcharczuk/go-chart/util"
)

// Interface Assertions.
var (
        _ Series                    = (*LinearRegressionSeries)(nil)
        _ FirstValuesProvider       = (*LinearRegressionSeries)(nil)
        _ LastValuesProvider        = (*LinearRegressionSeries)(nil)
        _ LinearCoefficientProvider = (*LinearRegressionSeries)(nil)
)

// LinearRegressionSeries is a series that plots the n-nearest neighbors
// linear regression for the values.
type LinearRegressionSeries struct {
        Name  string
        Style Style
        YAxis YAxisType

        Limit       int
        Offset      int
        InnerSeries ValuesProvider

        m       float64
        b       float64
        avgx    float64
        stddevx float64
}

// Coefficients returns the linear coefficients for the series.
func (lrs LinearRegressionSeries) Coefficients() (m, b, stdev, avg float64) <span class="cov0" title="0">{
        if lrs.IsZero() </span><span class="cov0" title="0">{
                lrs.computeCoefficients()
        }</span>

        <span class="cov0" title="0">m = lrs.m
        b = lrs.b
        stdev = lrs.stddevx
        avg = lrs.avgx
        return</span>
}

// GetName returns the name of the time series.
func (lrs LinearRegressionSeries) GetName() string <span class="cov0" title="0">{
        return lrs.Name
}</span>

// GetStyle returns the line style.
func (lrs LinearRegressionSeries) GetStyle() Style <span class="cov0" title="0">{
        return lrs.Style
}</span>

// GetYAxis returns which YAxis the series draws on.
func (lrs LinearRegressionSeries) GetYAxis() YAxisType <span class="cov0" title="0">{
        return lrs.YAxis
}</span>

// Len returns the number of elements in the series.
func (lrs LinearRegressionSeries) Len() int <span class="cov8" title="1">{
        return util.Math.MinInt(lrs.GetLimit(), lrs.InnerSeries.Len()-lrs.GetOffset())
}</span>

// GetLimit returns the window size.
func (lrs LinearRegressionSeries) GetLimit() int <span class="cov8" title="1">{
        if lrs.Limit == 0 </span><span class="cov8" title="1">{
                return lrs.InnerSeries.Len()
        }</span>
        <span class="cov8" title="1">return lrs.Limit</span>
}

// GetEndIndex returns the effective limit end.
func (lrs LinearRegressionSeries) GetEndIndex() int <span class="cov8" title="1">{
        windowEnd := lrs.GetOffset() + lrs.GetLimit()
        innerSeriesLastIndex := lrs.InnerSeries.Len() - 1
        return util.Math.MinInt(windowEnd, innerSeriesLastIndex)
}</span>

// GetOffset returns the data offset.
func (lrs LinearRegressionSeries) GetOffset() int <span class="cov8" title="1">{
        if lrs.Offset == 0 </span><span class="cov8" title="1">{
                return 0
        }</span>
        <span class="cov8" title="1">return lrs.Offset</span>
}

// GetValues gets a value at a given index.
func (lrs *LinearRegressionSeries) GetValues(index int) (x, y float64) <span class="cov8" title="1">{
        if lrs.InnerSeries == nil || lrs.InnerSeries.Len() == 0 </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov8" title="1">if lrs.IsZero() </span><span class="cov8" title="1">{
                lrs.computeCoefficients()
        }</span>
        <span class="cov8" title="1">offset := lrs.GetOffset()
        effectiveIndex := util.Math.MinInt(index+offset, lrs.InnerSeries.Len())
        x, y = lrs.InnerSeries.GetValues(effectiveIndex)
        y = (lrs.m * lrs.normalize(x)) + lrs.b
        return</span>
}

// GetFirstValues computes the first linear regression value.
func (lrs *LinearRegressionSeries) GetFirstValues() (x, y float64) <span class="cov0" title="0">{
        if lrs.InnerSeries == nil || lrs.InnerSeries.Len() == 0 </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov0" title="0">if lrs.IsZero() </span><span class="cov0" title="0">{
                lrs.computeCoefficients()
        }</span>
        <span class="cov0" title="0">x, y = lrs.InnerSeries.GetValues(0)
        y = (lrs.m * lrs.normalize(x)) + lrs.b
        return</span>
}

// GetLastValues computes the last linear regression value.
func (lrs *LinearRegressionSeries) GetLastValues() (x, y float64) <span class="cov8" title="1">{
        if lrs.InnerSeries == nil || lrs.InnerSeries.Len() == 0 </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov8" title="1">if lrs.IsZero() </span><span class="cov0" title="0">{
                lrs.computeCoefficients()
        }</span>
        <span class="cov8" title="1">endIndex := lrs.GetEndIndex()
        x, y = lrs.InnerSeries.GetValues(endIndex)
        y = (lrs.m * lrs.normalize(x)) + lrs.b
        return</span>
}

// Render renders the series.
func (lrs *LinearRegressionSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) <span class="cov0" title="0">{
        style := lrs.Style.InheritFrom(defaults)
        Draw.LineSeries(r, canvasBox, xrange, yrange, style, lrs)
}</span>

// Validate validates the series.
func (lrs *LinearRegressionSeries) Validate() error <span class="cov0" title="0">{
        if lrs.InnerSeries == nil </span><span class="cov0" title="0">{
                return fmt.Errorf("linear regression series requires InnerSeries to be set")
        }</span>
        <span class="cov0" title="0">return nil</span>
}

// IsZero returns if we've computed the coefficients or not.
func (lrs *LinearRegressionSeries) IsZero() bool <span class="cov8" title="1">{
        return lrs.m == 0 &amp;&amp; lrs.b == 0
}</span>

//
// internal helpers
//

func (lrs *LinearRegressionSeries) normalize(xvalue float64) float64 <span class="cov8" title="1">{
        return (xvalue - lrs.avgx) / lrs.stddevx
}</span>

// computeCoefficients computes the `m` and `b` terms in the linear formula given by `y = mx+b`.
func (lrs *LinearRegressionSeries) computeCoefficients() <span class="cov8" title="1">{
        startIndex := lrs.GetOffset()
        endIndex := lrs.GetEndIndex()

        p := float64(endIndex - startIndex)

        xvalues := seq.NewBufferWithCapacity(lrs.Len())
        for index := startIndex; index &lt; endIndex; index++ </span><span class="cov8" title="1">{
                x, _ := lrs.InnerSeries.GetValues(index)
                xvalues.Enqueue(x)
        }</span>

        <span class="cov8" title="1">lrs.avgx = seq.Seq{Provider: xvalues}.Average()
        lrs.stddevx = seq.Seq{Provider: xvalues}.StdDev()

        var sumx, sumy, sumxx, sumxy float64
        for index := startIndex; index &lt; endIndex; index++ </span><span class="cov8" title="1">{
                x, y := lrs.InnerSeries.GetValues(index)

                x = lrs.normalize(x)

                sumx += x
                sumy += y
                sumxx += x * x
                sumxy += x * y
        }</span>

        <span class="cov8" title="1">lrs.m = (p*sumxy - sumx*sumy) / (p*sumxx - sumx*sumx)
        lrs.b = (sumy / p) - (lrs.m * sumx / p)</span>
}
</pre>
		
		<pre class="file" id="file37" style="display: none">package chart

import (
        "fmt"
)

// Interface Assertions.
var (
        _ Series              = (*LinearSeries)(nil)
        _ FirstValuesProvider = (*LinearSeries)(nil)
        _ LastValuesProvider  = (*LinearSeries)(nil)
)

// LinearSeries is a series that plots a line in a given domain.
type LinearSeries struct {
        Name  string
        Style Style
        YAxis YAxisType

        XValues     []float64
        InnerSeries LinearCoefficientProvider

        m     float64
        b     float64
        stdev float64
        avg   float64
}

// GetName returns the name of the time series.
func (ls LinearSeries) GetName() string <span class="cov0" title="0">{
        return ls.Name
}</span>

// GetStyle returns the line style.
func (ls LinearSeries) GetStyle() Style <span class="cov0" title="0">{
        return ls.Style
}</span>

// GetYAxis returns which YAxis the series draws on.
func (ls LinearSeries) GetYAxis() YAxisType <span class="cov0" title="0">{
        return ls.YAxis
}</span>

// Len returns the number of elements in the series.
func (ls LinearSeries) Len() int <span class="cov0" title="0">{
        return len(ls.XValues)
}</span>

// GetEndIndex returns the effective limit end.
func (ls LinearSeries) GetEndIndex() int <span class="cov0" title="0">{
        return len(ls.XValues) - 1
}</span>

// GetValues gets a value at a given index.
func (ls *LinearSeries) GetValues(index int) (x, y float64) <span class="cov0" title="0">{
        if ls.InnerSeries == nil || len(ls.XValues) == 0 </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov0" title="0">if ls.IsZero() </span><span class="cov0" title="0">{
                ls.computeCoefficients()
        }</span>
        <span class="cov0" title="0">x = ls.XValues[index]
        y = (ls.m * ls.normalize(x)) + ls.b
        return</span>
}

// GetFirstValues computes the first linear regression value.
func (ls *LinearSeries) GetFirstValues() (x, y float64) <span class="cov0" title="0">{
        if ls.InnerSeries == nil || len(ls.XValues) == 0 </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov0" title="0">if ls.IsZero() </span><span class="cov0" title="0">{
                ls.computeCoefficients()
        }</span>
        <span class="cov0" title="0">x, y = ls.GetValues(0)
        return</span>
}

// GetLastValues computes the last linear regression value.
func (ls *LinearSeries) GetLastValues() (x, y float64) <span class="cov0" title="0">{
        if ls.InnerSeries == nil || len(ls.XValues) == 0 </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov0" title="0">if ls.IsZero() </span><span class="cov0" title="0">{
                ls.computeCoefficients()
        }</span>
        <span class="cov0" title="0">x, y = ls.GetValues(ls.GetEndIndex())
        return</span>
}

// Render renders the series.
func (ls *LinearSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) <span class="cov0" title="0">{
        Draw.LineSeries(r, canvasBox, xrange, yrange, ls.Style.InheritFrom(defaults), ls)
}</span>

// Validate validates the series.
func (ls LinearSeries) Validate() error <span class="cov0" title="0">{
        if ls.InnerSeries == nil </span><span class="cov0" title="0">{
                return fmt.Errorf("linear regression series requires InnerSeries to be set")
        }</span>
        <span class="cov0" title="0">return nil</span>
}

// IsZero returns if the linear series has computed coefficients or not.
func (ls LinearSeries) IsZero() bool <span class="cov0" title="0">{
        return ls.m == 0 &amp;&amp; ls.b == 0
}</span>

// computeCoefficients computes the `m` and `b` terms in the linear formula given by `y = mx+b`.
func (ls *LinearSeries) computeCoefficients() <span class="cov0" title="0">{
        ls.m, ls.b, ls.stdev, ls.avg = ls.InnerSeries.Coefficients()
}</span>

func (ls *LinearSeries) normalize(xvalue float64) float64 <span class="cov0" title="0">{
        if ls.avg &gt; 0 &amp;&amp; ls.stdev &gt; 0 </span><span class="cov0" title="0">{
                return (xvalue - ls.avg) / ls.stdev
        }</span>
        <span class="cov0" title="0">return xvalue</span>
}
</pre>
		
		<pre class="file" id="file38" style="display: none">package chart

import "fmt"

const (
        // DefaultMACDPeriodPrimary is the long window.
        DefaultMACDPeriodPrimary = 26
        // DefaultMACDPeriodSecondary is the short window.
        DefaultMACDPeriodSecondary = 12
        // DefaultMACDSignalPeriod is the signal period to compute for the MACD.
        DefaultMACDSignalPeriod = 9
)

// MACDSeries computes the difference between the MACD line and the MACD Signal line.
// It is used in technical analysis and gives a lagging indicator of momentum.
type MACDSeries struct {
        Name        string
        Style       Style
        YAxis       YAxisType
        InnerSeries ValuesProvider

        PrimaryPeriod   int
        SecondaryPeriod int
        SignalPeriod    int

        signal *MACDSignalSeries
        macdl  *MACDLineSeries
}

// Validate validates the series.
func (macd MACDSeries) Validate() error <span class="cov0" title="0">{
        var err error
        if macd.signal != nil </span><span class="cov0" title="0">{
                err = macd.signal.Validate()
        }</span>
        <span class="cov0" title="0">if err != nil </span><span class="cov0" title="0">{
                return err
        }</span>
        <span class="cov0" title="0">if macd.macdl != nil </span><span class="cov0" title="0">{
                err = macd.macdl.Validate()
        }</span>
        <span class="cov0" title="0">if err != nil </span><span class="cov0" title="0">{
                return err
        }</span>
        <span class="cov0" title="0">return nil</span>
}

// GetPeriods returns the primary and secondary periods.
func (macd MACDSeries) GetPeriods() (w1, w2, sig int) <span class="cov8" title="1">{
        if macd.PrimaryPeriod == 0 </span><span class="cov8" title="1">{
                w1 = DefaultMACDPeriodPrimary
        }</span> else<span class="cov0" title="0"> {
                w1 = macd.PrimaryPeriod
        }</span>
        <span class="cov8" title="1">if macd.SecondaryPeriod == 0 </span><span class="cov8" title="1">{
                w2 = DefaultMACDPeriodSecondary
        }</span> else<span class="cov0" title="0"> {
                w2 = macd.SecondaryPeriod
        }</span>
        <span class="cov8" title="1">if macd.SignalPeriod == 0 </span><span class="cov8" title="1">{
                sig = DefaultMACDSignalPeriod
        }</span> else<span class="cov0" title="0"> {
                sig = macd.SignalPeriod
        }</span>
        <span class="cov8" title="1">return</span>
}

// GetName returns the name of the time series.
func (macd MACDSeries) GetName() string <span class="cov0" title="0">{
        return macd.Name
}</span>

// GetStyle returns the line style.
func (macd MACDSeries) GetStyle() Style <span class="cov0" title="0">{
        return macd.Style
}</span>

// GetYAxis returns which YAxis the series draws on.
func (macd MACDSeries) GetYAxis() YAxisType <span class="cov0" title="0">{
        return macd.YAxis
}</span>

// Len returns the number of elements in the series.
func (macd MACDSeries) Len() int <span class="cov8" title="1">{
        if macd.InnerSeries == nil </span><span class="cov0" title="0">{
                return 0
        }</span>

        <span class="cov8" title="1">return macd.InnerSeries.Len()</span>
}

// GetValues gets a value at a given index. For MACD it is the signal value.
func (macd *MACDSeries) GetValues(index int) (x float64, y float64) <span class="cov8" title="1">{
        if macd.InnerSeries == nil </span><span class="cov0" title="0">{
                return
        }</span>

        <span class="cov8" title="1">if macd.signal == nil || macd.macdl == nil </span><span class="cov8" title="1">{
                macd.ensureChildSeries()
        }</span>

        <span class="cov8" title="1">_, lv := macd.macdl.GetValues(index)
        _, sv := macd.signal.GetValues(index)

        x, _ = macd.InnerSeries.GetValues(index)
        y = lv - sv

        return</span>
}

func (macd *MACDSeries) ensureChildSeries() <span class="cov8" title="1">{
        w1, w2, sig := macd.GetPeriods()

        macd.signal = &amp;MACDSignalSeries{
                InnerSeries:     macd.InnerSeries,
                PrimaryPeriod:   w1,
                SecondaryPeriod: w2,
                SignalPeriod:    sig,
        }

        macd.macdl = &amp;MACDLineSeries{
                InnerSeries:     macd.InnerSeries,
                PrimaryPeriod:   w1,
                SecondaryPeriod: w2,
        }
}</span>

// MACDSignalSeries computes the EMA of the MACDLineSeries.
type MACDSignalSeries struct {
        Name        string
        Style       Style
        YAxis       YAxisType
        InnerSeries ValuesProvider

        PrimaryPeriod   int
        SecondaryPeriod int
        SignalPeriod    int

        signal *EMASeries
}

// Validate validates the series.
func (macds MACDSignalSeries) Validate() error <span class="cov0" title="0">{
        if macds.signal != nil </span><span class="cov0" title="0">{
                return macds.signal.Validate()
        }</span>
        <span class="cov0" title="0">return nil</span>
}

// GetPeriods returns the primary and secondary periods.
func (macds MACDSignalSeries) GetPeriods() (w1, w2, sig int) <span class="cov8" title="1">{
        if macds.PrimaryPeriod == 0 </span><span class="cov0" title="0">{
                w1 = DefaultMACDPeriodPrimary
        }</span> else<span class="cov8" title="1"> {
                w1 = macds.PrimaryPeriod
        }</span>
        <span class="cov8" title="1">if macds.SecondaryPeriod == 0 </span><span class="cov0" title="0">{
                w2 = DefaultMACDPeriodSecondary
        }</span> else<span class="cov8" title="1"> {
                w2 = macds.SecondaryPeriod
        }</span>
        <span class="cov8" title="1">if macds.SignalPeriod == 0 </span><span class="cov0" title="0">{
                sig = DefaultMACDSignalPeriod
        }</span> else<span class="cov8" title="1"> {
                sig = macds.SignalPeriod
        }</span>
        <span class="cov8" title="1">return</span>
}

// GetName returns the name of the time series.
func (macds MACDSignalSeries) GetName() string <span class="cov0" title="0">{
        return macds.Name
}</span>

// GetStyle returns the line style.
func (macds MACDSignalSeries) GetStyle() Style <span class="cov0" title="0">{
        return macds.Style
}</span>

// GetYAxis returns which YAxis the series draws on.
func (macds MACDSignalSeries) GetYAxis() YAxisType <span class="cov0" title="0">{
        return macds.YAxis
}</span>

// Len returns the number of elements in the series.
func (macds *MACDSignalSeries) Len() int <span class="cov0" title="0">{
        if macds.InnerSeries == nil </span><span class="cov0" title="0">{
                return 0
        }</span>

        <span class="cov0" title="0">return macds.InnerSeries.Len()</span>
}

// GetValues gets a value at a given index. For MACD it is the signal value.
func (macds *MACDSignalSeries) GetValues(index int) (x float64, y float64) <span class="cov8" title="1">{
        if macds.InnerSeries == nil </span><span class="cov0" title="0">{
                return
        }</span>

        <span class="cov8" title="1">if macds.signal == nil </span><span class="cov8" title="1">{
                macds.ensureSignal()
        }</span>
        <span class="cov8" title="1">x, _ = macds.InnerSeries.GetValues(index)
        _, y = macds.signal.GetValues(index)
        return</span>
}

func (macds *MACDSignalSeries) ensureSignal() <span class="cov8" title="1">{
        w1, w2, sig := macds.GetPeriods()

        macds.signal = &amp;EMASeries{
                InnerSeries: &amp;MACDLineSeries{
                        InnerSeries:     macds.InnerSeries,
                        PrimaryPeriod:   w1,
                        SecondaryPeriod: w2,
                },
                Period: sig,
        }
}</span>

// Render renders the series.
func (macds *MACDSignalSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) <span class="cov0" title="0">{
        style := macds.Style.InheritFrom(defaults)
        Draw.LineSeries(r, canvasBox, xrange, yrange, style, macds)
}</span>

// MACDLineSeries is a series that computes the inner ema1-ema2 value as a series.
type MACDLineSeries struct {
        Name        string
        Style       Style
        YAxis       YAxisType
        InnerSeries ValuesProvider

        PrimaryPeriod   int
        SecondaryPeriod int

        ema1 *EMASeries
        ema2 *EMASeries

        Sigma float64
}

// Validate validates the series.
func (macdl MACDLineSeries) Validate() error <span class="cov0" title="0">{
        var err error
        if macdl.ema1 != nil </span><span class="cov0" title="0">{
                err = macdl.ema1.Validate()
        }</span>
        <span class="cov0" title="0">if err != nil </span><span class="cov0" title="0">{
                return err
        }</span>
        <span class="cov0" title="0">if macdl.ema2 != nil </span><span class="cov0" title="0">{
                err = macdl.ema2.Validate()
        }</span>
        <span class="cov0" title="0">if err != nil </span><span class="cov0" title="0">{
                return err
        }</span>
        <span class="cov0" title="0">if macdl.InnerSeries == nil </span><span class="cov0" title="0">{
                return fmt.Errorf("MACDLineSeries: must provide an inner series")
        }</span>
        <span class="cov0" title="0">return nil</span>
}

// GetName returns the name of the time series.
func (macdl MACDLineSeries) GetName() string <span class="cov0" title="0">{
        return macdl.Name
}</span>

// GetStyle returns the line style.
func (macdl MACDLineSeries) GetStyle() Style <span class="cov0" title="0">{
        return macdl.Style
}</span>

// GetYAxis returns which YAxis the series draws on.
func (macdl MACDLineSeries) GetYAxis() YAxisType <span class="cov0" title="0">{
        return macdl.YAxis
}</span>

// GetPeriods returns the primary and secondary periods.
func (macdl MACDLineSeries) GetPeriods() (w1, w2 int) <span class="cov8" title="1">{
        if macdl.PrimaryPeriod == 0 </span><span class="cov0" title="0">{
                w1 = DefaultMACDPeriodPrimary
        }</span> else<span class="cov8" title="1"> {
                w1 = macdl.PrimaryPeriod
        }</span>
        <span class="cov8" title="1">if macdl.SecondaryPeriod == 0 </span><span class="cov0" title="0">{
                w2 = DefaultMACDPeriodSecondary
        }</span> else<span class="cov8" title="1"> {
                w2 = macdl.SecondaryPeriod
        }</span>
        <span class="cov8" title="1">return</span>
}

// Len returns the number of elements in the series.
func (macdl *MACDLineSeries) Len() int <span class="cov8" title="1">{
        if macdl.InnerSeries == nil </span><span class="cov0" title="0">{
                return 0
        }</span>

        <span class="cov8" title="1">return macdl.InnerSeries.Len()</span>
}

// GetValues gets a value at a given index. For MACD it is the signal value.
func (macdl *MACDLineSeries) GetValues(index int) (x float64, y float64) <span class="cov8" title="1">{
        if macdl.InnerSeries == nil </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov8" title="1">if macdl.ema1 == nil &amp;&amp; macdl.ema2 == nil </span><span class="cov8" title="1">{
                macdl.ensureEMASeries()
        }</span>

        <span class="cov8" title="1">x, _ = macdl.InnerSeries.GetValues(index)

        _, emav1 := macdl.ema1.GetValues(index)
        _, emav2 := macdl.ema2.GetValues(index)

        y = emav2 - emav1
        return</span>
}

func (macdl *MACDLineSeries) ensureEMASeries() <span class="cov8" title="1">{
        w1, w2 := macdl.GetPeriods()

        macdl.ema1 = &amp;EMASeries{
                InnerSeries: macdl.InnerSeries,
                Period:      w1,
        }
        macdl.ema2 = &amp;EMASeries{
                InnerSeries: macdl.InnerSeries,
                Period:      w2,
        }
}</span>

// Render renders the series.
func (macdl *MACDLineSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) <span class="cov0" title="0">{
        style := macdl.Style.InheritFrom(defaults)
        Draw.LineSeries(r, canvasBox, xrange, yrange, style, macdl)
}</span>
</pre>
		
		<pre class="file" id="file39" style="display: none">package matrix

import (
        "bytes"
        "errors"
        "fmt"
        "math"
)

const (
        // DefaultEpsilon represents the minimum precision for matrix math operations.
        DefaultEpsilon = 0.000001
)

var (
        // ErrDimensionMismatch is a typical error.
        ErrDimensionMismatch = errors.New("dimension mismatch")

        // ErrSingularValue is a typical error.
        ErrSingularValue = errors.New("singular value")
)

// New returns a new matrix.
func New(rows, cols int, values ...float64) *Matrix <span class="cov8" title="1">{
        if len(values) == 0 </span><span class="cov8" title="1">{
                return &amp;Matrix{
                        stride:   cols,
                        epsilon:  DefaultEpsilon,
                        elements: make([]float64, rows*cols),
                }
        }</span>
        <span class="cov8" title="1">elems := make([]float64, rows*cols)
        copy(elems, values)
        return &amp;Matrix{
                stride:   cols,
                epsilon:  DefaultEpsilon,
                elements: elems,
        }</span>
}

// Identity returns the identity matrix of a given order.
func Identity(order int) *Matrix <span class="cov8" title="1">{
        m := New(order, order)
        for i := 0; i &lt; order; i++ </span><span class="cov8" title="1">{
                m.Set(i, i, 1)
        }</span>
        <span class="cov8" title="1">return m</span>
}

// Zero returns a matrix of a given size zeroed.
func Zero(rows, cols int) *Matrix <span class="cov8" title="1">{
        return New(rows, cols)
}</span>

// Ones returns an matrix of ones.
func Ones(rows, cols int) *Matrix <span class="cov8" title="1">{
        ones := make([]float64, rows*cols)
        for i := 0; i &lt; (rows * cols); i++ </span><span class="cov8" title="1">{
                ones[i] = 1
        }</span>

        <span class="cov8" title="1">return &amp;Matrix{
                stride:   cols,
                epsilon:  DefaultEpsilon,
                elements: ones,
        }</span>
}

// Eye returns the eye matrix.
func Eye(n int) *Matrix <span class="cov0" title="0">{
        m := Zero(n, n)
        for i := 0; i &lt; len(m.elements); i += n + 1 </span><span class="cov0" title="0">{
                m.elements[i] = 1
        }</span>
        <span class="cov0" title="0">return m</span>
}

// NewFromArrays creates a matrix from a jagged array set.
func NewFromArrays(a [][]float64) *Matrix <span class="cov8" title="1">{
        rows := len(a)
        if rows == 0 </span><span class="cov0" title="0">{
                return nil
        }</span>
        <span class="cov8" title="1">cols := len(a[0])
        m := New(rows, cols)
        for row := 0; row &lt; rows; row++ </span><span class="cov8" title="1">{
                for col := 0; col &lt; cols; col++ </span><span class="cov8" title="1">{
                        m.Set(row, col, a[row][col])
                }</span>
        }
        <span class="cov8" title="1">return m</span>
}

// Matrix represents a 2d dense array of floats.
type Matrix struct {
        epsilon  float64
        elements []float64
        stride   int
}

// String returns a string representation of the matrix.
func (m *Matrix) String() string <span class="cov8" title="1">{
        buffer := bytes.NewBuffer(nil)
        rows, cols := m.Size()

        for row := 0; row &lt; rows; row++ </span><span class="cov8" title="1">{
                for col := 0; col &lt; cols; col++ </span><span class="cov8" title="1">{
                        buffer.WriteString(f64s(m.Get(row, col)))
                        buffer.WriteRune(' ')
                }</span>
                <span class="cov8" title="1">buffer.WriteRune('\n')</span>
        }
        <span class="cov8" title="1">return buffer.String()</span>
}

// Epsilon returns the maximum precision for math operations.
func (m *Matrix) Epsilon() float64 <span class="cov8" title="1">{
        return m.epsilon
}</span>

// WithEpsilon sets the epsilon on the matrix and returns a reference to the matrix.
func (m *Matrix) WithEpsilon(epsilon float64) *Matrix <span class="cov8" title="1">{
        m.epsilon = epsilon
        return m
}</span>

// Each applies the action to each element of the matrix in
// rows =&gt; cols order.
func (m *Matrix) Each(action func(row, col int, value float64)) <span class="cov0" title="0">{
        rows, cols := m.Size()
        for row := 0; row &lt; rows; row++ </span><span class="cov0" title="0">{
                for col := 0; col &lt; cols; col++ </span><span class="cov0" title="0">{
                        action(row, col, m.Get(row, col))
                }</span>
        }
}

// Round rounds all the values in a matrix to it epsilon,
// returning a reference to the original
func (m *Matrix) Round() *Matrix <span class="cov8" title="1">{
        rows, cols := m.Size()
        for row := 0; row &lt; rows; row++ </span><span class="cov8" title="1">{
                for col := 0; col &lt; cols; col++ </span><span class="cov8" title="1">{
                        m.Set(row, col, roundToEpsilon(m.Get(row, col), m.epsilon))
                }</span>
        }
        <span class="cov8" title="1">return m</span>
}

// Arrays returns the matrix as a two dimensional jagged array.
func (m *Matrix) Arrays() [][]float64 <span class="cov8" title="1">{
        rows, cols := m.Size()
        a := make([][]float64, rows)

        for row := 0; row &lt; rows; row++ </span><span class="cov8" title="1">{
                a[row] = make([]float64, cols)

                for col := 0; col &lt; cols; col++ </span><span class="cov8" title="1">{
                        a[row][col] = m.Get(row, col)
                }</span>
        }
        <span class="cov8" title="1">return a</span>
}

// Size returns the dimensions of the matrix.
func (m *Matrix) Size() (rows, cols int) <span class="cov8" title="1">{
        rows = len(m.elements) / m.stride
        cols = m.stride
        return
}</span>

// IsSquare returns if the row count is equal to the column count.
func (m *Matrix) IsSquare() bool <span class="cov8" title="1">{
        return m.stride == (len(m.elements) / m.stride)
}</span>

// IsSymmetric returns if the matrix is symmetric about its diagonal.
func (m *Matrix) IsSymmetric() bool <span class="cov8" title="1">{
        rows, cols := m.Size()

        if rows != cols </span><span class="cov8" title="1">{
                return false
        }</span>

        <span class="cov8" title="1">for i := 0; i &lt; rows; i++ </span><span class="cov8" title="1">{
                for j := 0; j &lt; i; j++ </span><span class="cov8" title="1">{
                        if m.Get(i, j) != m.Get(j, i) </span><span class="cov8" title="1">{
                                return false
                        }</span>
                }
        }
        <span class="cov8" title="1">return true</span>
}

// Get returns the element at the given row, col.
func (m *Matrix) Get(row, col int) float64 <span class="cov8" title="1">{
        index := (m.stride * row) + col
        return m.elements[index]
}</span>

// Set sets a value.
func (m *Matrix) Set(row, col int, val float64) <span class="cov8" title="1">{
        index := (m.stride * row) + col
        m.elements[index] = val
}</span>

// Col returns a column of the matrix as a vector.
func (m *Matrix) Col(col int) Vector <span class="cov8" title="1">{
        rows, _ := m.Size()
        values := make([]float64, rows)
        for row := 0; row &lt; rows; row++ </span><span class="cov8" title="1">{
                values[row] = m.Get(row, col)
        }</span>
        <span class="cov8" title="1">return Vector(values)</span>
}

// Row returns a row of the matrix as a vector.
func (m *Matrix) Row(row int) Vector <span class="cov8" title="1">{
        _, cols := m.Size()
        values := make([]float64, cols)
        for col := 0; col &lt; cols; col++ </span><span class="cov8" title="1">{
                values[col] = m.Get(row, col)
        }</span>
        <span class="cov8" title="1">return Vector(values)</span>
}

// SubMatrix returns a sub matrix from a given outer matrix.
func (m *Matrix) SubMatrix(i, j, rows, cols int) *Matrix <span class="cov0" title="0">{
        return &amp;Matrix{
                elements: m.elements[i*m.stride+j : i*m.stride+j+(rows-1)*m.stride+cols],
                stride:   m.stride,
                epsilon:  m.epsilon,
        }
}</span>

// ScaleRow applies a scale to an entire row.
func (m *Matrix) ScaleRow(row int, scale float64) <span class="cov0" title="0">{
        startIndex := row * m.stride
        for i := startIndex; i &lt; m.stride; i++ </span><span class="cov0" title="0">{
                m.elements[i] = m.elements[i] * scale
        }</span>
}

func (m *Matrix) scaleAddRow(rd int, rs int, f float64) <span class="cov0" title="0">{
        indexd := rd * m.stride
        indexs := rs * m.stride
        for col := 0; col &lt; m.stride; col++ </span><span class="cov0" title="0">{
                m.elements[indexd] += f * m.elements[indexs]
                indexd++
                indexs++
        }</span>
}

// SwapRows swaps a row in the matrix in place.
func (m *Matrix) SwapRows(i, j int) <span class="cov8" title="1">{
        var vi, vj float64
        for col := 0; col &lt; m.stride; col++ </span><span class="cov8" title="1">{
                vi = m.Get(i, col)
                vj = m.Get(j, col)
                m.Set(i, col, vj)
                m.Set(j, col, vi)
        }</span>
}

// Augment concatenates two matrices about the horizontal.
func (m *Matrix) Augment(m2 *Matrix) (*Matrix, error) <span class="cov0" title="0">{
        mr, mc := m.Size()
        m2r, m2c := m2.Size()
        if mr != m2r </span><span class="cov0" title="0">{
                return nil, ErrDimensionMismatch
        }</span>

        <span class="cov0" title="0">m3 := Zero(mr, mc+m2c)
        for row := 0; row &lt; mr; row++ </span><span class="cov0" title="0">{
                for col := 0; col &lt; mc; col++ </span><span class="cov0" title="0">{
                        m3.Set(row, col, m.Get(row, col))
                }</span>
                <span class="cov0" title="0">for col := 0; col &lt; m2c; col++ </span><span class="cov0" title="0">{
                        m3.Set(row, mc+col, m2.Get(row, col))
                }</span>
        }
        <span class="cov0" title="0">return m3, nil</span>
}

// Copy returns a duplicate of a given matrix.
func (m *Matrix) Copy() *Matrix <span class="cov8" title="1">{
        m2 := &amp;Matrix{stride: m.stride, epsilon: m.epsilon, elements: make([]float64, len(m.elements))}
        copy(m2.elements, m.elements)
        return m2
}</span>

// DiagonalVector returns a vector from the diagonal of a matrix.
func (m *Matrix) DiagonalVector() Vector <span class="cov8" title="1">{
        rows, cols := m.Size()
        rank := minInt(rows, cols)
        values := make([]float64, rank)

        for index := 0; index &lt; rank; index++ </span><span class="cov8" title="1">{
                values[index] = m.Get(index, index)
        }</span>
        <span class="cov8" title="1">return Vector(values)</span>
}

// Diagonal returns a matrix from the diagonal of a matrix.
func (m *Matrix) Diagonal() *Matrix <span class="cov8" title="1">{
        rows, cols := m.Size()
        rank := minInt(rows, cols)
        m2 := New(rank, rank)

        for index := 0; index &lt; rank; index++ </span><span class="cov8" title="1">{
                m2.Set(index, index, m.Get(index, index))
        }</span>
        <span class="cov8" title="1">return m2</span>
}

// Equals returns if a matrix equals another matrix.
func (m *Matrix) Equals(other *Matrix) bool <span class="cov8" title="1">{
        if other == nil &amp;&amp; m != nil </span><span class="cov8" title="1">{
                return false
        }</span> else<span class="cov8" title="1"> if other == nil </span><span class="cov8" title="1">{
                return true
        }</span>

        <span class="cov8" title="1">if m.stride != other.stride </span><span class="cov8" title="1">{
                return false
        }</span>

        <span class="cov8" title="1">msize := len(m.elements)
        m2size := len(other.elements)

        if msize != m2size </span><span class="cov0" title="0">{
                return false
        }</span>

        <span class="cov8" title="1">for i := 0; i &lt; msize; i++ </span><span class="cov8" title="1">{
                if m.elements[i] != other.elements[i] </span><span class="cov8" title="1">{
                        return false
                }</span>
        }
        <span class="cov8" title="1">return true</span>
}

// L returns the matrix with zeros below the diagonal.
func (m *Matrix) L() *Matrix <span class="cov8" title="1">{
        rows, cols := m.Size()
        m2 := New(rows, cols)
        for row := 0; row &lt; rows; row++ </span><span class="cov8" title="1">{
                for col := row; col &lt; cols; col++ </span><span class="cov8" title="1">{
                        m2.Set(row, col, m.Get(row, col))
                }</span>
        }
        <span class="cov8" title="1">return m2</span>
}

// U returns the matrix with zeros above the diagonal.
// Does not include the diagonal.
func (m *Matrix) U() *Matrix <span class="cov8" title="1">{
        rows, cols := m.Size()
        m2 := New(rows, cols)
        for row := 0; row &lt; rows; row++ </span><span class="cov8" title="1">{
                for col := 0; col &lt; row &amp;&amp; col &lt; cols; col++ </span><span class="cov8" title="1">{
                        m2.Set(row, col, m.Get(row, col))
                }</span>
        }
        <span class="cov8" title="1">return m2</span>
}

// math operations

// Multiply multiplies two matrices.
func (m *Matrix) Multiply(m2 *Matrix) (m3 *Matrix, err error) <span class="cov8" title="1">{
        if m.stride*m2.stride != len(m2.elements) </span><span class="cov0" title="0">{
                return nil, ErrDimensionMismatch
        }</span>

        <span class="cov8" title="1">m3 = &amp;Matrix{epsilon: m.epsilon, stride: m2.stride, elements: make([]float64, (len(m.elements)/m.stride)*m2.stride)}
        for m1c0, m3x := 0, 0; m1c0 &lt; len(m.elements); m1c0 += m.stride </span><span class="cov8" title="1">{
                for m2r0 := 0; m2r0 &lt; m2.stride; m2r0++ </span><span class="cov8" title="1">{
                        for m1x, m2x := m1c0, m2r0; m2x &lt; len(m2.elements); m2x += m2.stride </span><span class="cov8" title="1">{
                                m3.elements[m3x] += m.elements[m1x] * m2.elements[m2x]
                                m1x++
                        }</span>
                        <span class="cov8" title="1">m3x++</span>
                }
        }
        <span class="cov8" title="1">return</span>
}

// Pivotize does something i'm not sure what.
func (m *Matrix) Pivotize() *Matrix <span class="cov8" title="1">{
        pv := make([]int, m.stride)

        for i := range pv </span><span class="cov8" title="1">{
                pv[i] = i
        }</span>

        <span class="cov8" title="1">for j, dx := 0, 0; j &lt; m.stride; j++ </span><span class="cov8" title="1">{
                row := j
                max := m.elements[dx]
                for i, ixcj := j, dx; i &lt; m.stride; i++ </span><span class="cov8" title="1">{
                        if m.elements[ixcj] &gt; max </span><span class="cov8" title="1">{
                                max = m.elements[ixcj]
                                row = i
                        }</span>
                        <span class="cov8" title="1">ixcj += m.stride</span>
                }
                <span class="cov8" title="1">if j != row </span><span class="cov8" title="1">{
                        pv[row], pv[j] = pv[j], pv[row]
                }</span>
                <span class="cov8" title="1">dx += m.stride + 1</span>
        }
        <span class="cov8" title="1">p := Zero(m.stride, m.stride)
        for r, c := range pv </span><span class="cov8" title="1">{
                p.elements[r*m.stride+c] = 1
        }</span>
        <span class="cov8" title="1">return p</span>
}

// Times returns the product of a matrix and another.
func (m *Matrix) Times(m2 *Matrix) (*Matrix, error) <span class="cov8" title="1">{
        mr, mc := m.Size()
        m2r, m2c := m2.Size()

        if mc != m2r </span><span class="cov0" title="0">{
                return nil, fmt.Errorf("cannot multiply (%dx%d) and (%dx%d)", mr, mc, m2r, m2c)
                //return nil, ErrDimensionMismatch
        }</span>

        <span class="cov8" title="1">c := Zero(mr, m2c)

        for i := 0; i &lt; mr; i++ </span><span class="cov8" title="1">{
                sums := c.elements[i*c.stride : (i+1)*c.stride]
                for k, a := range m.elements[i*m.stride : i*m.stride+m.stride] </span><span class="cov8" title="1">{
                        for j, b := range m2.elements[k*m2.stride : k*m2.stride+m2.stride] </span><span class="cov8" title="1">{
                                sums[j] += a * b
                        }</span>
                }
        }

        <span class="cov8" title="1">return c, nil</span>
}

// Decompositions

// LU performs the LU decomposition.
func (m *Matrix) LU() (l, u, p *Matrix) <span class="cov8" title="1">{
        l = Zero(m.stride, m.stride)
        u = Zero(m.stride, m.stride)
        p = m.Pivotize()
        m, _ = p.Multiply(m)
        for j, jxc0 := 0, 0; j &lt; m.stride; j++ </span><span class="cov8" title="1">{
                l.elements[jxc0+j] = 1
                for i, ixc0 := 0, 0; ixc0 &lt;= jxc0; i++ </span><span class="cov8" title="1">{
                        sum := 0.
                        for k, kxcj := 0, j; k &lt; i; k++ </span><span class="cov8" title="1">{
                                sum += u.elements[kxcj] * l.elements[ixc0+k]
                                kxcj += m.stride
                        }</span>
                        <span class="cov8" title="1">u.elements[ixc0+j] = m.elements[ixc0+j] - sum
                        ixc0 += m.stride</span>
                }
                <span class="cov8" title="1">for ixc0 := jxc0; ixc0 &lt; len(m.elements); ixc0 += m.stride </span><span class="cov8" title="1">{
                        sum := 0.
                        for k, kxcj := 0, j; k &lt; j; k++ </span><span class="cov8" title="1">{
                                sum += u.elements[kxcj] * l.elements[ixc0+k]
                                kxcj += m.stride
                        }</span>
                        <span class="cov8" title="1">l.elements[ixc0+j] = (m.elements[ixc0+j] - sum) / u.elements[jxc0+j]</span>
                }
                <span class="cov8" title="1">jxc0 += m.stride</span>
        }
        <span class="cov8" title="1">return</span>
}

// QR performs the qr decomposition.
func (m *Matrix) QR() (q, r *Matrix) <span class="cov8" title="1">{
        defer func() </span><span class="cov8" title="1">{
                q = q.Round()
                r = r.Round()
        }</span>()

        <span class="cov8" title="1">rows, cols := m.Size()
        qr := m.Copy()
        q = New(rows, cols)
        r = New(rows, cols)

        var i, j, k int
        var norm, s float64

        for k = 0; k &lt; cols; k++ </span><span class="cov8" title="1">{
                norm = 0
                for i = k; i &lt; rows; i++ </span><span class="cov8" title="1">{
                        norm = math.Hypot(norm, qr.Get(i, k))
                }</span>

                <span class="cov8" title="1">if norm != 0 </span><span class="cov8" title="1">{
                        if qr.Get(k, k) &lt; 0 </span><span class="cov8" title="1">{
                                norm = -norm
                        }</span>

                        <span class="cov8" title="1">for i = k; i &lt; rows; i++ </span><span class="cov8" title="1">{
                                qr.Set(i, k, qr.Get(i, k)/norm)
                        }</span>
                        <span class="cov8" title="1">qr.Set(k, k, qr.Get(k, k)+1.0)

                        for j = k + 1; j &lt; cols; j++ </span><span class="cov8" title="1">{
                                s = 0
                                for i = k; i &lt; rows; i++ </span><span class="cov8" title="1">{
                                        s += qr.Get(i, k) * qr.Get(i, j)
                                }</span>
                                <span class="cov8" title="1">s = -s / qr.Get(k, k)
                                for i = k; i &lt; rows; i++ </span><span class="cov8" title="1">{
                                        qr.Set(i, j, qr.Get(i, j)+s*qr.Get(i, k))

                                        if i &lt; j </span><span class="cov8" title="1">{
                                                r.Set(i, j, qr.Get(i, j))
                                        }</span>
                                }

                        }
                }

                <span class="cov8" title="1">r.Set(k, k, -norm)</span>

        }

        //Q Matrix:
        <span class="cov8" title="1">i, j, k = 0, 0, 0

        for k = cols - 1; k &gt;= 0; k-- </span><span class="cov8" title="1">{
                q.Set(k, k, 1.0)
                for j = k; j &lt; cols; j++ </span><span class="cov8" title="1">{
                        if qr.Get(k, k) != 0 </span><span class="cov8" title="1">{
                                s = 0
                                for i = k; i &lt; rows; i++ </span><span class="cov8" title="1">{
                                        s += qr.Get(i, k) * q.Get(i, j)
                                }</span>
                                <span class="cov8" title="1">s = -s / qr.Get(k, k)
                                for i = k; i &lt; rows; i++ </span><span class="cov8" title="1">{
                                        q.Set(i, j, q.Get(i, j)+s*qr.Get(i, k))
                                }</span>
                        }
                }
        }

        <span class="cov8" title="1">return</span>
}

// Transpose flips a matrix about its diagonal, returning a new copy.
func (m *Matrix) Transpose() *Matrix <span class="cov8" title="1">{
        rows, cols := m.Size()
        m2 := Zero(cols, rows)
        for i := 0; i &lt; rows; i++ </span><span class="cov8" title="1">{
                for j := 0; j &lt; cols; j++ </span><span class="cov8" title="1">{
                        m2.Set(j, i, m.Get(i, j))
                }</span>
        }
        <span class="cov8" title="1">return m2</span>
}

// Inverse returns a matrix such that M*I==1.
func (m *Matrix) Inverse() (*Matrix, error) <span class="cov0" title="0">{
        if !m.IsSymmetric() </span><span class="cov0" title="0">{
                return nil, ErrDimensionMismatch
        }</span>

        <span class="cov0" title="0">rows, cols := m.Size()

        aug, _ := m.Augment(Eye(rows))
        for i := 0; i &lt; rows; i++ </span><span class="cov0" title="0">{
                j := i
                for k := i; k &lt; rows; k++ </span><span class="cov0" title="0">{
                        if math.Abs(aug.Get(k, i)) &gt; math.Abs(aug.Get(j, i)) </span><span class="cov0" title="0">{
                                j = k
                        }</span>
                }
                <span class="cov0" title="0">if j != i </span><span class="cov0" title="0">{
                        aug.SwapRows(i, j)
                }</span>
                <span class="cov0" title="0">if aug.Get(i, i) == 0 </span><span class="cov0" title="0">{
                        return nil, ErrSingularValue
                }</span>
                <span class="cov0" title="0">aug.ScaleRow(i, 1.0/aug.Get(i, i))
                for k := 0; k &lt; rows; k++ </span><span class="cov0" title="0">{
                        if k == i </span><span class="cov0" title="0">{
                                continue</span>
                        }
                        <span class="cov0" title="0">aug.scaleAddRow(k, i, -aug.Get(k, i))</span>
                }
        }
        <span class="cov0" title="0">return aug.SubMatrix(0, cols, rows, cols), nil</span>
}
</pre>
		
		<pre class="file" id="file40" style="display: none">package matrix

import "errors"

var (
        // ErrPolyRegArraysSameLength is a common error.
        ErrPolyRegArraysSameLength = errors.New("polynomial array inputs must be the same length")
)

// Poly returns the polynomial regress of a given degree over the given values.
func Poly(xvalues, yvalues []float64, degree int) ([]float64, error) <span class="cov8" title="1">{
        if len(xvalues) != len(yvalues) </span><span class="cov0" title="0">{
                return nil, ErrPolyRegArraysSameLength
        }</span>

        <span class="cov8" title="1">m := len(yvalues)
        n := degree + 1
        y := New(m, 1, yvalues...)
        x := Zero(m, n)

        for i := 0; i &lt; m; i++ </span><span class="cov8" title="1">{
                ip := float64(1)
                for j := 0; j &lt; n; j++ </span><span class="cov8" title="1">{
                        x.Set(i, j, ip)
                        ip *= xvalues[i]
                }</span>
        }

        <span class="cov8" title="1">q, r := x.QR()
        qty, err := q.Transpose().Times(y)
        if err != nil </span><span class="cov0" title="0">{
                return nil, err
        }</span>

        <span class="cov8" title="1">c := make([]float64, n)
        for i := n - 1; i &gt;= 0; i-- </span><span class="cov8" title="1">{
                c[i] = qty.Get(i, 0)
                for j := i + 1; j &lt; n; j++ </span><span class="cov8" title="1">{
                        c[i] -= c[j] * r.Get(i, j)
                }</span>
                <span class="cov8" title="1">c[i] /= r.Get(i, i)</span>
        }

        <span class="cov8" title="1">return c, nil</span>
}
</pre>
		
		<pre class="file" id="file41" style="display: none">package matrix

import (
        "math"
        "strconv"
)

func minInt(values ...int) int <span class="cov8" title="1">{
        min := math.MaxInt32

        for x := 0; x &lt; len(values); x++ </span><span class="cov8" title="1">{
                if values[x] &lt; min </span><span class="cov8" title="1">{
                        min = values[x]
                }</span>
        }
        <span class="cov8" title="1">return min</span>
}

func maxInt(values ...int) int <span class="cov0" title="0">{
        max := math.MinInt32

        for x := 0; x &lt; len(values); x++ </span><span class="cov0" title="0">{
                if values[x] &gt; max </span><span class="cov0" title="0">{
                        max = values[x]
                }</span>
        }
        <span class="cov0" title="0">return max</span>
}

func f64s(v float64) string <span class="cov8" title="1">{
        return strconv.FormatFloat(v, 'f', -1, 64)
}</span>

func roundToEpsilon(value, epsilon float64) float64 <span class="cov8" title="1">{
        return math.Nextafter(value, value)
}</span>
</pre>
		
		<pre class="file" id="file42" style="display: none">package matrix

// Vector is just an array of values.
type Vector []float64

// DotProduct returns the dot product of two vectors.
func (v Vector) DotProduct(v2 Vector) (result float64, err error) <span class="cov0" title="0">{
        if len(v) != len(v2) </span><span class="cov0" title="0">{
                err = ErrDimensionMismatch
                return
        }</span>

        <span class="cov0" title="0">for i := 0; i &lt; len(v); i++ </span><span class="cov0" title="0">{
                result = result + (v[i] * v2[i])
        }</span>
        <span class="cov0" title="0">return</span>
}
</pre>
		
		<pre class="file" id="file43" style="display: none">package chart

import (
        "fmt"
        "math"
)

// MinSeries draws a horizontal line at the minimum value of the inner series.
type MinSeries struct {
        Name        string
        Style       Style
        YAxis       YAxisType
        InnerSeries ValuesProvider

        minValue *float64
}

// GetName returns the name of the time series.
func (ms MinSeries) GetName() string <span class="cov0" title="0">{
        return ms.Name
}</span>

// GetStyle returns the line style.
func (ms MinSeries) GetStyle() Style <span class="cov0" title="0">{
        return ms.Style
}</span>

// GetYAxis returns which YAxis the series draws on.
func (ms MinSeries) GetYAxis() YAxisType <span class="cov0" title="0">{
        return ms.YAxis
}</span>

// Len returns the number of elements in the series.
func (ms MinSeries) Len() int <span class="cov0" title="0">{
        return ms.InnerSeries.Len()
}</span>

// GetValues gets a value at a given index.
func (ms *MinSeries) GetValues(index int) (x, y float64) <span class="cov0" title="0">{
        ms.ensureMinValue()
        x, _ = ms.InnerSeries.GetValues(index)
        y = *ms.minValue
        return
}</span>

// Render renders the series.
func (ms *MinSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) <span class="cov0" title="0">{
        style := ms.Style.InheritFrom(defaults)
        Draw.LineSeries(r, canvasBox, xrange, yrange, style, ms)
}</span>

func (ms *MinSeries) ensureMinValue() <span class="cov0" title="0">{
        if ms.minValue == nil </span><span class="cov0" title="0">{
                minValue := math.MaxFloat64
                var y float64
                for x := 0; x &lt; ms.InnerSeries.Len(); x++ </span><span class="cov0" title="0">{
                        _, y = ms.InnerSeries.GetValues(x)
                        if y &lt; minValue </span><span class="cov0" title="0">{
                                minValue = y
                        }</span>
                }
                <span class="cov0" title="0">ms.minValue = &amp;minValue</span>
        }
}

// Validate validates the series.
func (ms *MinSeries) Validate() error <span class="cov0" title="0">{
        if ms.InnerSeries == nil </span><span class="cov0" title="0">{
                return fmt.Errorf("min series requires InnerSeries to be set")
        }</span>
        <span class="cov0" title="0">return nil</span>
}

// MaxSeries draws a horizontal line at the maximum value of the inner series.
type MaxSeries struct {
        Name        string
        Style       Style
        YAxis       YAxisType
        InnerSeries ValuesProvider

        maxValue *float64
}

// GetName returns the name of the time series.
func (ms MaxSeries) GetName() string <span class="cov0" title="0">{
        return ms.Name
}</span>

// GetStyle returns the line style.
func (ms MaxSeries) GetStyle() Style <span class="cov0" title="0">{
        return ms.Style
}</span>

// GetYAxis returns which YAxis the series draws on.
func (ms MaxSeries) GetYAxis() YAxisType <span class="cov0" title="0">{
        return ms.YAxis
}</span>

// Len returns the number of elements in the series.
func (ms MaxSeries) Len() int <span class="cov0" title="0">{
        return ms.InnerSeries.Len()
}</span>

// GetValues gets a value at a given index.
func (ms *MaxSeries) GetValues(index int) (x, y float64) <span class="cov0" title="0">{
        ms.ensureMaxValue()
        x, _ = ms.InnerSeries.GetValues(index)
        y = *ms.maxValue
        return
}</span>

// Render renders the series.
func (ms *MaxSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) <span class="cov0" title="0">{
        style := ms.Style.InheritFrom(defaults)
        Draw.LineSeries(r, canvasBox, xrange, yrange, style, ms)
}</span>

func (ms *MaxSeries) ensureMaxValue() <span class="cov0" title="0">{
        if ms.maxValue == nil </span><span class="cov0" title="0">{
                maxValue := -math.MaxFloat64
                var y float64
                for x := 0; x &lt; ms.InnerSeries.Len(); x++ </span><span class="cov0" title="0">{
                        _, y = ms.InnerSeries.GetValues(x)
                        if y &gt; maxValue </span><span class="cov0" title="0">{
                                maxValue = y
                        }</span>
                }
                <span class="cov0" title="0">ms.maxValue = &amp;maxValue</span>
        }
}

// Validate validates the series.
func (ms *MaxSeries) Validate() error <span class="cov0" title="0">{
        if ms.InnerSeries == nil </span><span class="cov0" title="0">{
                return fmt.Errorf("max series requires InnerSeries to be set")
        }</span>
        <span class="cov0" title="0">return nil</span>
}
</pre>
		
		<pre class="file" id="file44" style="display: none">package chart

import (
        "errors"
        "fmt"
        "io"
        "math"

        "github.com/golang/freetype/truetype"
        "github.com/wcharczuk/go-chart/util"
)

const (
        _pi  = math.Pi
        _pi2 = math.Pi / 2.0
        _pi4 = math.Pi / 4.0
)

// PieChart is a chart that draws sections of a circle based on percentages.
type PieChart struct {
        Title      string
        TitleStyle Style

        ColorPalette ColorPalette

        Width  int
        Height int
        DPI    float64

        Background Style
        Canvas     Style
        SliceStyle Style

        Font        *truetype.Font
        defaultFont *truetype.Font

        Values   []Value
        Elements []Renderable
}

// GetDPI returns the dpi for the chart.
func (pc PieChart) GetDPI(defaults ...float64) float64 <span class="cov8" title="1">{
        if pc.DPI == 0 </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov0" title="0">return DefaultDPI</span>
        }
        <span class="cov0" title="0">return pc.DPI</span>
}

// GetFont returns the text font.
func (pc PieChart) GetFont() *truetype.Font <span class="cov8" title="1">{
        if pc.Font == nil </span><span class="cov8" title="1">{
                return pc.defaultFont
        }</span>
        <span class="cov0" title="0">return pc.Font</span>
}

// GetWidth returns the chart width or the default value.
func (pc PieChart) GetWidth() int <span class="cov8" title="1">{
        if pc.Width == 0 </span><span class="cov8" title="1">{
                return DefaultChartWidth
        }</span>
        <span class="cov0" title="0">return pc.Width</span>
}

// GetHeight returns the chart height or the default value.
func (pc PieChart) GetHeight() int <span class="cov8" title="1">{
        if pc.Height == 0 </span><span class="cov8" title="1">{
                return DefaultChartWidth
        }</span>
        <span class="cov0" title="0">return pc.Height</span>
}

// Render renders the chart with the given renderer to the given io.Writer.
func (pc PieChart) Render(rp RendererProvider, w io.Writer) error <span class="cov8" title="1">{
        if len(pc.Values) == 0 </span><span class="cov0" title="0">{
                return errors.New("please provide at least one value")
        }</span>

        <span class="cov8" title="1">r, err := rp(pc.GetWidth(), pc.GetHeight())
        if err != nil </span><span class="cov0" title="0">{
                return err
        }</span>

        <span class="cov8" title="1">if pc.Font == nil </span><span class="cov8" title="1">{
                defaultFont, err := GetDefaultFont()
                if err != nil </span><span class="cov0" title="0">{
                        return err
                }</span>
                <span class="cov8" title="1">pc.defaultFont = defaultFont</span>
        }
        <span class="cov8" title="1">r.SetDPI(pc.GetDPI(DefaultDPI))

        canvasBox := pc.getDefaultCanvasBox()
        canvasBox = pc.getCircleAdjustedCanvasBox(canvasBox)

        pc.drawBackground(r)
        pc.drawCanvas(r, canvasBox)

        finalValues, err := pc.finalizeValues(pc.Values)
        if err != nil </span><span class="cov8" title="1">{
                return err
        }</span>
        <span class="cov8" title="1">pc.drawSlices(r, canvasBox, finalValues)
        pc.drawTitle(r)
        for _, a := range pc.Elements </span><span class="cov0" title="0">{
                a(r, canvasBox, pc.styleDefaultsElements())
        }</span>

        <span class="cov8" title="1">return r.Save(w)</span>
}

func (pc PieChart) drawBackground(r Renderer) <span class="cov8" title="1">{
        Draw.Box(r, Box{
                Right:  pc.GetWidth(),
                Bottom: pc.GetHeight(),
        }, pc.getBackgroundStyle())
}</span>

func (pc PieChart) drawCanvas(r Renderer, canvasBox Box) <span class="cov8" title="1">{
        Draw.Box(r, canvasBox, pc.getCanvasStyle())
}</span>

func (pc PieChart) drawTitle(r Renderer) <span class="cov8" title="1">{
        if len(pc.Title) &gt; 0 &amp;&amp; pc.TitleStyle.Show </span><span class="cov0" title="0">{
                Draw.TextWithin(r, pc.Title, pc.Box(), pc.styleDefaultsTitle())
        }</span>
}

func (pc PieChart) drawSlices(r Renderer, canvasBox Box, values []Value) <span class="cov8" title="1">{
        cx, cy := canvasBox.Center()
        diameter := util.Math.MinInt(canvasBox.Width(), canvasBox.Height())
        radius := float64(diameter &gt;&gt; 1)
        labelRadius := (radius * 2.0) / 3.0

        // draw the pie slices
        var rads, delta, delta2, total float64
        var lx, ly int

        if len(values) == 1 </span><span class="cov0" title="0">{
                pc.stylePieChartValue(0).WriteToRenderer(r)
                r.MoveTo(cx, cy)
                r.Circle(radius, cx, cy)
        }</span> else<span class="cov8" title="1"> {
                for index, v := range values </span><span class="cov8" title="1">{
                        v.Style.InheritFrom(pc.stylePieChartValue(index)).WriteToRenderer(r)

                        r.MoveTo(cx, cy)
                        rads = util.Math.PercentToRadians(total)
                        delta = util.Math.PercentToRadians(v.Value)

                        r.ArcTo(cx, cy, radius, radius, rads, delta)

                        r.LineTo(cx, cy)
                        r.Close()
                        r.FillStroke()
                        total = total + v.Value
                }</span>
        }

        // draw the labels
        <span class="cov8" title="1">total = 0
        for index, v := range values </span><span class="cov8" title="1">{
                v.Style.InheritFrom(pc.stylePieChartValue(index)).WriteToRenderer(r)
                if len(v.Label) &gt; 0 </span><span class="cov8" title="1">{
                        delta2 = util.Math.PercentToRadians(total + (v.Value / 2.0))
                        delta2 = util.Math.RadianAdd(delta2, _pi2)
                        lx, ly = util.Math.CirclePoint(cx, cy, labelRadius, delta2)

                        tb := r.MeasureText(v.Label)
                        lx = lx - (tb.Width() &gt;&gt; 1)
                        ly = ly + (tb.Height() &gt;&gt; 1)

                        if lx &lt; 0 </span><span class="cov0" title="0">{
                                lx = 0
                        }</span>
                        <span class="cov8" title="1">if ly &lt; 0 </span><span class="cov0" title="0">{
                                lx = 0
                        }</span>

                        <span class="cov8" title="1">r.Text(v.Label, lx, ly)</span>
                }
                <span class="cov8" title="1">total = total + v.Value</span>
        }
}

func (pc PieChart) finalizeValues(values []Value) ([]Value, error) <span class="cov8" title="1">{
        finalValues := Values(values).Normalize()
        if len(finalValues) == 0 </span><span class="cov8" title="1">{
                return nil, fmt.Errorf("pie chart must contain at least (1) non-zero value")
        }</span>
        <span class="cov8" title="1">return finalValues, nil</span>
}

func (pc PieChart) getDefaultCanvasBox() Box <span class="cov8" title="1">{
        return pc.Box()
}</span>

func (pc PieChart) getCircleAdjustedCanvasBox(canvasBox Box) Box <span class="cov8" title="1">{
        circleDiameter := util.Math.MinInt(canvasBox.Width(), canvasBox.Height())

        square := Box{
                Right:  circleDiameter,
                Bottom: circleDiameter,
        }

        return canvasBox.Fit(square)
}</span>

func (pc PieChart) getBackgroundStyle() Style <span class="cov8" title="1">{
        return pc.Background.InheritFrom(pc.styleDefaultsBackground())
}</span>

func (pc PieChart) getCanvasStyle() Style <span class="cov8" title="1">{
        return pc.Canvas.InheritFrom(pc.styleDefaultsCanvas())
}</span>

func (pc PieChart) styleDefaultsCanvas() Style <span class="cov8" title="1">{
        return Style{
                FillColor:   pc.GetColorPalette().CanvasColor(),
                StrokeColor: pc.GetColorPalette().CanvasStrokeColor(),
                StrokeWidth: DefaultStrokeWidth,
        }
}</span>

func (pc PieChart) styleDefaultsPieChartValue() Style <span class="cov0" title="0">{
        return Style{
                StrokeColor: pc.GetColorPalette().TextColor(),
                StrokeWidth: 5.0,
                FillColor:   pc.GetColorPalette().TextColor(),
        }
}</span>

func (pc PieChart) stylePieChartValue(index int) Style <span class="cov8" title="1">{
        return pc.SliceStyle.InheritFrom(Style{
                StrokeColor: ColorWhite,
                StrokeWidth: 5.0,
                FillColor:   pc.GetColorPalette().GetSeriesColor(index),
                FontSize:    pc.getScaledFontSize(),
                FontColor:   pc.GetColorPalette().TextColor(),
                Font:        pc.GetFont(),
        })
}</span>

func (pc PieChart) getScaledFontSize() float64 <span class="cov8" title="1">{
        effectiveDimension := util.Math.MinInt(pc.GetWidth(), pc.GetHeight())
        if effectiveDimension &gt;= 2048 </span><span class="cov0" title="0">{
                return 48.0
        }</span> else<span class="cov8" title="1"> if effectiveDimension &gt;= 1024 </span><span class="cov8" title="1">{
                return 24.0
        }</span> else<span class="cov0" title="0"> if effectiveDimension &gt; 512 </span><span class="cov0" title="0">{
                return 18.0
        }</span> else<span class="cov0" title="0"> if effectiveDimension &gt; 256 </span><span class="cov0" title="0">{
                return 12.0
        }</span>
        <span class="cov0" title="0">return 10.0</span>
}

func (pc PieChart) styleDefaultsBackground() Style <span class="cov8" title="1">{
        return Style{
                FillColor:   pc.GetColorPalette().BackgroundColor(),
                StrokeColor: pc.GetColorPalette().BackgroundStrokeColor(),
                StrokeWidth: DefaultStrokeWidth,
        }
}</span>

func (pc PieChart) styleDefaultsElements() Style <span class="cov0" title="0">{
        return Style{
                Font: pc.GetFont(),
        }
}</span>

func (pc PieChart) styleDefaultsTitle() Style <span class="cov0" title="0">{
        return pc.TitleStyle.InheritFrom(Style{
                FontColor:           pc.GetColorPalette().TextColor(),
                Font:                pc.GetFont(),
                FontSize:            pc.getTitleFontSize(),
                TextHorizontalAlign: TextHorizontalAlignCenter,
                TextVerticalAlign:   TextVerticalAlignTop,
                TextWrap:            TextWrapWord,
        })
}</span>

func (pc PieChart) getTitleFontSize() float64 <span class="cov0" title="0">{
        effectiveDimension := util.Math.MinInt(pc.GetWidth(), pc.GetHeight())
        if effectiveDimension &gt;= 2048 </span><span class="cov0" title="0">{
                return 48
        }</span> else<span class="cov0" title="0"> if effectiveDimension &gt;= 1024 </span><span class="cov0" title="0">{
                return 24
        }</span> else<span class="cov0" title="0"> if effectiveDimension &gt;= 512 </span><span class="cov0" title="0">{
                return 18
        }</span> else<span class="cov0" title="0"> if effectiveDimension &gt;= 256 </span><span class="cov0" title="0">{
                return 12
        }</span>
        <span class="cov0" title="0">return 10</span>
}

// GetColorPalette returns the color palette for the chart.
func (pc PieChart) GetColorPalette() ColorPalette <span class="cov8" title="1">{
        if pc.ColorPalette != nil </span><span class="cov0" title="0">{
                return pc.ColorPalette
        }</span>
        <span class="cov8" title="1">return AlternateColorPalette</span>
}

// Box returns the chart bounds as a box.
func (pc PieChart) Box() Box <span class="cov8" title="1">{
        dpr := pc.Background.Padding.GetRight(DefaultBackgroundPadding.Right)
        dpb := pc.Background.Padding.GetBottom(DefaultBackgroundPadding.Bottom)

        return Box{
                Top:    pc.Background.Padding.GetTop(DefaultBackgroundPadding.Top),
                Left:   pc.Background.Padding.GetLeft(DefaultBackgroundPadding.Left),
                Right:  pc.GetWidth() - dpr,
                Bottom: pc.GetHeight() - dpb,
        }
}</span>
</pre>
		
		<pre class="file" id="file45" style="display: none">package chart

import (
        "fmt"
        "math"

        "github.com/wcharczuk/go-chart/matrix"
        util "github.com/wcharczuk/go-chart/util"
)

// Interface Assertions.
var (
        _ Series              = (*PolynomialRegressionSeries)(nil)
        _ FirstValuesProvider = (*PolynomialRegressionSeries)(nil)
        _ LastValuesProvider  = (*PolynomialRegressionSeries)(nil)
)

// PolynomialRegressionSeries implements a polynomial regression over a given
// inner series.
type PolynomialRegressionSeries struct {
        Name  string
        Style Style
        YAxis YAxisType

        Limit       int
        Offset      int
        Degree      int
        InnerSeries ValuesProvider

        coeffs []float64
}

// GetName returns the name of the time series.
func (prs PolynomialRegressionSeries) GetName() string <span class="cov0" title="0">{
        return prs.Name
}</span>

// GetStyle returns the line style.
func (prs PolynomialRegressionSeries) GetStyle() Style <span class="cov0" title="0">{
        return prs.Style
}</span>

// GetYAxis returns which YAxis the series draws on.
func (prs PolynomialRegressionSeries) GetYAxis() YAxisType <span class="cov0" title="0">{
        return prs.YAxis
}</span>

// Len returns the number of elements in the series.
func (prs PolynomialRegressionSeries) Len() int <span class="cov0" title="0">{
        return util.Math.MinInt(prs.GetLimit(), prs.InnerSeries.Len()-prs.GetOffset())
}</span>

// GetLimit returns the window size.
func (prs PolynomialRegressionSeries) GetLimit() int <span class="cov8" title="1">{
        if prs.Limit == 0 </span><span class="cov8" title="1">{
                return prs.InnerSeries.Len()
        }</span>
        <span class="cov0" title="0">return prs.Limit</span>
}

// GetEndIndex returns the effective limit end.
func (prs PolynomialRegressionSeries) GetEndIndex() int <span class="cov8" title="1">{
        windowEnd := prs.GetOffset() + prs.GetLimit()
        innerSeriesLastIndex := prs.InnerSeries.Len() - 1
        return util.Math.MinInt(windowEnd, innerSeriesLastIndex)
}</span>

// GetOffset returns the data offset.
func (prs PolynomialRegressionSeries) GetOffset() int <span class="cov8" title="1">{
        if prs.Offset == 0 </span><span class="cov8" title="1">{
                return 0
        }</span>
        <span class="cov0" title="0">return prs.Offset</span>
}

// Validate validates the series.
func (prs *PolynomialRegressionSeries) Validate() error <span class="cov0" title="0">{
        if prs.InnerSeries == nil </span><span class="cov0" title="0">{
                return fmt.Errorf("linear regression series requires InnerSeries to be set")
        }</span>

        <span class="cov0" title="0">endIndex := prs.GetEndIndex()
        if endIndex &gt;= prs.InnerSeries.Len() </span><span class="cov0" title="0">{
                return fmt.Errorf("invalid window; inner series has length %d but end index is %d", prs.InnerSeries.Len(), endIndex)
        }</span>

        <span class="cov0" title="0">return nil</span>
}

// GetValues returns the series value for a given index.
func (prs *PolynomialRegressionSeries) GetValues(index int) (x, y float64) <span class="cov8" title="1">{
        if prs.InnerSeries == nil || prs.InnerSeries.Len() == 0 </span><span class="cov0" title="0">{
                return
        }</span>

        <span class="cov8" title="1">if prs.coeffs == nil </span><span class="cov8" title="1">{
                coeffs, err := prs.computeCoefficients()
                if err != nil </span><span class="cov0" title="0">{
                        panic(err)</span>
                }
                <span class="cov8" title="1">prs.coeffs = coeffs</span>
        }

        <span class="cov8" title="1">offset := prs.GetOffset()
        effectiveIndex := util.Math.MinInt(index+offset, prs.InnerSeries.Len())
        x, y = prs.InnerSeries.GetValues(effectiveIndex)
        y = prs.apply(x)
        return</span>
}

// GetFirstValues computes the first poly regression value.
func (prs *PolynomialRegressionSeries) GetFirstValues() (x, y float64) <span class="cov0" title="0">{
        if prs.InnerSeries == nil || prs.InnerSeries.Len() == 0 </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov0" title="0">if prs.coeffs == nil </span><span class="cov0" title="0">{
                coeffs, err := prs.computeCoefficients()
                if err != nil </span><span class="cov0" title="0">{
                        panic(err)</span>
                }
                <span class="cov0" title="0">prs.coeffs = coeffs</span>
        }
        <span class="cov0" title="0">x, y = prs.InnerSeries.GetValues(0)
        y = prs.apply(x)
        return</span>
}

// GetLastValues computes the last poly regression value.
func (prs *PolynomialRegressionSeries) GetLastValues() (x, y float64) <span class="cov0" title="0">{
        if prs.InnerSeries == nil || prs.InnerSeries.Len() == 0 </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov0" title="0">if prs.coeffs == nil </span><span class="cov0" title="0">{
                coeffs, err := prs.computeCoefficients()
                if err != nil </span><span class="cov0" title="0">{
                        panic(err)</span>
                }
                <span class="cov0" title="0">prs.coeffs = coeffs</span>
        }
        <span class="cov0" title="0">endIndex := prs.GetEndIndex()
        x, y = prs.InnerSeries.GetValues(endIndex)
        y = prs.apply(x)
        return</span>
}

func (prs *PolynomialRegressionSeries) apply(v float64) (out float64) <span class="cov8" title="1">{
        for index, coeff := range prs.coeffs </span><span class="cov8" title="1">{
                out = out + (coeff * math.Pow(v, float64(index)))
        }</span>
        <span class="cov8" title="1">return</span>
}

func (prs *PolynomialRegressionSeries) computeCoefficients() ([]float64, error) <span class="cov8" title="1">{
        xvalues, yvalues := prs.values()
        return matrix.Poly(xvalues, yvalues, prs.Degree)
}</span>

func (prs *PolynomialRegressionSeries) values() (xvalues, yvalues []float64) <span class="cov8" title="1">{
        startIndex := prs.GetOffset()
        endIndex := prs.GetEndIndex()

        xvalues = make([]float64, endIndex-startIndex)
        yvalues = make([]float64, endIndex-startIndex)

        for index := startIndex; index &lt; endIndex; index++ </span><span class="cov8" title="1">{
                x, y := prs.InnerSeries.GetValues(index)
                xvalues[index-startIndex] = x
                yvalues[index-startIndex] = y
        }</span>

        <span class="cov8" title="1">return</span>
}

// Render renders the series.
func (prs *PolynomialRegressionSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) <span class="cov0" title="0">{
        style := prs.Style.InheritFrom(defaults)
        Draw.LineSeries(r, canvasBox, xrange, yrange, style, prs)
}</span>
</pre>
		
		<pre class="file" id="file46" style="display: none">package chart

import (
        "image"
        "image/png"
        "io"
        "math"

        "github.com/golang/freetype/truetype"
        "github.com/wcharczuk/go-chart/drawing"
        "github.com/wcharczuk/go-chart/util"
)

// PNG returns a new png/raster renderer.
func PNG(width, height int) (Renderer, error) <span class="cov8" title="1">{
        i := image.NewRGBA(image.Rect(0, 0, width, height))
        gc, err := drawing.NewRasterGraphicContext(i)
        if err == nil </span><span class="cov8" title="1">{
                return &amp;rasterRenderer{
                        i:  i,
                        gc: gc,
                }, nil
        }</span>
        <span class="cov0" title="0">return nil, err</span>
}

// rasterRenderer renders chart commands to a bitmap.
type rasterRenderer struct {
        i  *image.RGBA
        gc *drawing.RasterGraphicContext

        rotateRadians *float64

        s Style
}

func (rr *rasterRenderer) ResetStyle() <span class="cov8" title="1">{
        rr.s = Style{Font: rr.s.Font}
        rr.ClearTextRotation()
}</span>

// GetDPI returns the dpi.
func (rr *rasterRenderer) GetDPI() float64 <span class="cov0" title="0">{
        return rr.gc.GetDPI()
}</span>

// SetDPI implements the interface method.
func (rr *rasterRenderer) SetDPI(dpi float64) <span class="cov8" title="1">{
        rr.gc.SetDPI(dpi)
}</span>

// SetClassName implements the interface method. However, PNGs have no classes.
func (vr *rasterRenderer) SetClassName(_ string) {<span class="cov8" title="1">
}</span>

// SetStrokeColor implements the interface method.
func (rr *rasterRenderer) SetStrokeColor(c drawing.Color) <span class="cov8" title="1">{
        rr.s.StrokeColor = c
}</span>

// SetLineWidth implements the interface method.
func (rr *rasterRenderer) SetStrokeWidth(width float64) <span class="cov8" title="1">{
        rr.s.StrokeWidth = width
}</span>

// StrokeDashArray sets the stroke dash array.
func (rr *rasterRenderer) SetStrokeDashArray(dashArray []float64) <span class="cov8" title="1">{
        rr.s.StrokeDashArray = dashArray
}</span>

// SetFillColor implements the interface method.
func (rr *rasterRenderer) SetFillColor(c drawing.Color) <span class="cov8" title="1">{
        rr.s.FillColor = c
}</span>

// MoveTo implements the interface method.
func (rr *rasterRenderer) MoveTo(x, y int) <span class="cov8" title="1">{
        rr.gc.MoveTo(float64(x), float64(y))
}</span>

// LineTo implements the interface method.
func (rr *rasterRenderer) LineTo(x, y int) <span class="cov8" title="1">{
        rr.gc.LineTo(float64(x), float64(y))
}</span>

// QuadCurveTo implements the interface method.
func (rr *rasterRenderer) QuadCurveTo(cx, cy, x, y int) <span class="cov0" title="0">{
        rr.gc.QuadCurveTo(float64(cx), float64(cy), float64(x), float64(y))
}</span>

// ArcTo implements the interface method.
func (rr *rasterRenderer) ArcTo(cx, cy int, rx, ry, startAngle, delta float64) <span class="cov8" title="1">{
        rr.gc.ArcTo(float64(cx), float64(cy), rx, ry, startAngle, delta)
}</span>

// Close implements the interface method.
func (rr *rasterRenderer) Close() <span class="cov8" title="1">{
        rr.gc.Close()
}</span>

// Stroke implements the interface method.
func (rr *rasterRenderer) Stroke() <span class="cov8" title="1">{
        rr.gc.SetStrokeColor(rr.s.StrokeColor)
        rr.gc.SetLineWidth(rr.s.StrokeWidth)
        rr.gc.SetLineDash(rr.s.StrokeDashArray, 0)
        rr.gc.Stroke()
}</span>

// Fill implements the interface method.
func (rr *rasterRenderer) Fill() <span class="cov8" title="1">{
        rr.gc.SetFillColor(rr.s.FillColor)
        rr.gc.Fill()
}</span>

// FillStroke implements the interface method.
func (rr *rasterRenderer) FillStroke() <span class="cov8" title="1">{
        rr.gc.SetFillColor(rr.s.FillColor)
        rr.gc.SetStrokeColor(rr.s.StrokeColor)
        rr.gc.SetLineWidth(rr.s.StrokeWidth)
        rr.gc.SetLineDash(rr.s.StrokeDashArray, 0)
        rr.gc.FillStroke()
}</span>

// Circle fully draws a circle at a given point but does not apply the fill or stroke.
func (rr *rasterRenderer) Circle(radius float64, x, y int) <span class="cov0" title="0">{
        xf := float64(x)
        yf := float64(y)

        rr.gc.MoveTo(xf-radius, yf)                            //9
        rr.gc.QuadCurveTo(xf-radius, yf-radius, xf, yf-radius) //12
        rr.gc.QuadCurveTo(xf+radius, yf-radius, xf+radius, yf) //3
        rr.gc.QuadCurveTo(xf+radius, yf+radius, xf, yf+radius) //6
        rr.gc.QuadCurveTo(xf-radius, yf+radius, xf-radius, yf) //9
}</span>

// SetFont implements the interface method.
func (rr *rasterRenderer) SetFont(f *truetype.Font) <span class="cov8" title="1">{
        rr.s.Font = f
}</span>

// SetFontSize implements the interface method.
func (rr *rasterRenderer) SetFontSize(size float64) <span class="cov8" title="1">{
        rr.s.FontSize = size
}</span>

// SetFontColor implements the interface method.
func (rr *rasterRenderer) SetFontColor(c drawing.Color) <span class="cov8" title="1">{
        rr.s.FontColor = c
}</span>

// Text implements the interface method.
func (rr *rasterRenderer) Text(body string, x, y int) <span class="cov8" title="1">{
        xf, yf := rr.getCoords(x, y)
        rr.gc.SetFont(rr.s.Font)
        rr.gc.SetFontSize(rr.s.FontSize)
        rr.gc.SetFillColor(rr.s.FontColor)
        rr.gc.CreateStringPath(body, float64(xf), float64(yf))
        rr.gc.Fill()
}</span>

// MeasureText returns the height and width in pixels of a string.
func (rr *rasterRenderer) MeasureText(body string) Box <span class="cov8" title="1">{
        rr.gc.SetFont(rr.s.Font)
        rr.gc.SetFontSize(rr.s.FontSize)
        rr.gc.SetFillColor(rr.s.FontColor)
        l, t, r, b, err := rr.gc.GetStringBounds(body)
        if err != nil </span><span class="cov8" title="1">{
                return Box{}
        }</span>
        <span class="cov8" title="1">if l &lt; 0 </span><span class="cov0" title="0">{
                r = r - l // equivalent to r+(-1*l)
                l = 0
        }</span>
        <span class="cov8" title="1">if t &lt; 0 </span><span class="cov8" title="1">{
                b = b - t
                t = 0
        }</span>

        <span class="cov8" title="1">if l &gt; 0 </span><span class="cov8" title="1">{
                r = r + l
                l = 0
        }</span>

        <span class="cov8" title="1">if t &gt; 0 </span><span class="cov0" title="0">{
                b = b + t
                t = 0
        }</span>

        <span class="cov8" title="1">textBox := Box{
                Top:    int(math.Ceil(t)),
                Left:   int(math.Ceil(l)),
                Right:  int(math.Ceil(r)),
                Bottom: int(math.Ceil(b)),
        }
        if rr.rotateRadians == nil </span><span class="cov8" title="1">{
                return textBox
        }</span>

        <span class="cov0" title="0">return textBox.Corners().Rotate(util.Math.RadiansToDegrees(*rr.rotateRadians)).Box()</span>
}

// SetTextRotation sets a text rotation.
func (rr *rasterRenderer) SetTextRotation(radians float64) <span class="cov0" title="0">{
        rr.rotateRadians = &amp;radians
}</span>

func (rr *rasterRenderer) getCoords(x, y int) (xf, yf int) <span class="cov8" title="1">{
        if rr.rotateRadians == nil </span><span class="cov8" title="1">{
                xf = x
                yf = y
                return
        }</span>

        <span class="cov0" title="0">rr.gc.Translate(float64(x), float64(y))
        rr.gc.Rotate(*rr.rotateRadians)
        return</span>
}

// ClearTextRotation clears text rotation.
func (rr *rasterRenderer) ClearTextRotation() <span class="cov8" title="1">{
        rr.gc.SetMatrixTransform(drawing.NewIdentityMatrix())
        rr.rotateRadians = nil
}</span>

// Save implements the interface method.
func (rr *rasterRenderer) Save(w io.Writer) error <span class="cov8" title="1">{
        if typed, isTyped := w.(RGBACollector); isTyped </span><span class="cov0" title="0">{
                typed.SetRGBA(rr.i)
                return nil
        }</span>
        <span class="cov8" title="1">return png.Encode(w, rr.i)</span>
}
</pre>
		
		<pre class="file" id="file47" style="display: none">package seq

// NewArray creates a new array.
func NewArray(values ...float64) Array <span class="cov8" title="1">{
        return Array(values)
}</span>

// Array is a wrapper for an array of floats that implements `ValuesProvider`.
type Array []float64

// Len returns the value provider length.
func (a Array) Len() int <span class="cov8" title="1">{
        return len(a)
}</span>

// GetValue returns the value at a given index.
func (a Array) GetValue(index int) float64 <span class="cov8" title="1">{
        return a[index]
}</span>
</pre>
		
		<pre class="file" id="file48" style="display: none">package seq

import (
        "fmt"
        "strings"

        util "github.com/wcharczuk/go-chart/util"
)

const (
        bufferMinimumGrow     = 4
        bufferShrinkThreshold = 32
        bufferGrowFactor      = 200
        bufferDefaultCapacity = 4
)

var (
        emptyArray = make([]float64, 0)
)

// NewBuffer creates a new value buffer with an optional set of values.
func NewBuffer(values ...float64) *Buffer <span class="cov8" title="1">{
        var tail int
        array := make([]float64, util.Math.MaxInt(len(values), bufferDefaultCapacity))
        if len(values) &gt; 0 </span><span class="cov8" title="1">{
                copy(array, values)
                tail = len(values)
        }</span>
        <span class="cov8" title="1">return &amp;Buffer{
                array: array,
                head:  0,
                tail:  tail,
                size:  len(values),
        }</span>
}

// NewBufferWithCapacity creates a new ValueBuffer pre-allocated with the given capacity.
func NewBufferWithCapacity(capacity int) *Buffer <span class="cov0" title="0">{
        return &amp;Buffer{
                array: make([]float64, capacity),
                head:  0,
                tail:  0,
                size:  0,
        }
}</span>

// Buffer is a fifo datastructure that is backed by a pre-allocated array.
// Instead of allocating a whole new node object for each element, array elements are re-used (which saves GC churn).
// Enqueue can be O(n), Dequeue is generally O(1).
// Buffer implements `seq.Provider`
type Buffer struct {
        array []float64
        head  int
        tail  int
        size  int
}

// Len returns the length of the Buffer (as it is currently populated).
// Actual memory footprint may be different.
func (b *Buffer) Len() int <span class="cov8" title="1">{
        return b.size
}</span>

// GetValue implements seq provider.
func (b *Buffer) GetValue(index int) float64 <span class="cov0" title="0">{
        effectiveIndex := (b.head + index) % len(b.array)
        return b.array[effectiveIndex]
}</span>

// Capacity returns the total size of the Buffer, including empty elements.
func (b *Buffer) Capacity() int <span class="cov8" title="1">{
        return len(b.array)
}</span>

// SetCapacity sets the capacity of the Buffer.
func (b *Buffer) SetCapacity(capacity int) <span class="cov8" title="1">{
        newArray := make([]float64, capacity)
        if b.size &gt; 0 </span><span class="cov8" title="1">{
                if b.head &lt; b.tail </span><span class="cov8" title="1">{
                        arrayCopy(b.array, b.head, newArray, 0, b.size)
                }</span> else<span class="cov8" title="1"> {
                        arrayCopy(b.array, b.head, newArray, 0, len(b.array)-b.head)
                        arrayCopy(b.array, 0, newArray, len(b.array)-b.head, b.tail)
                }</span>
        }
        <span class="cov8" title="1">b.array = newArray
        b.head = 0
        if b.size == capacity </span><span class="cov0" title="0">{
                b.tail = 0
        }</span> else<span class="cov8" title="1"> {
                b.tail = b.size
        }</span>
}

// Clear removes all objects from the Buffer.
func (b *Buffer) Clear() <span class="cov8" title="1">{
        b.array = make([]float64, bufferDefaultCapacity)
        b.head = 0
        b.tail = 0
        b.size = 0
}</span>

// Enqueue adds an element to the "back" of the Buffer.
func (b *Buffer) Enqueue(value float64) <span class="cov8" title="1">{
        if b.size == len(b.array) </span><span class="cov8" title="1">{
                newCapacity := int(len(b.array) * int(bufferGrowFactor/100))
                if newCapacity &lt; (len(b.array) + bufferMinimumGrow) </span><span class="cov0" title="0">{
                        newCapacity = len(b.array) + bufferMinimumGrow
                }</span>
                <span class="cov8" title="1">b.SetCapacity(newCapacity)</span>
        }

        <span class="cov8" title="1">b.array[b.tail] = value
        b.tail = (b.tail + 1) % len(b.array)
        b.size++</span>
}

// Dequeue removes the first element from the RingBuffer.
func (b *Buffer) Dequeue() float64 <span class="cov8" title="1">{
        if b.size == 0 </span><span class="cov0" title="0">{
                return 0
        }</span>

        <span class="cov8" title="1">removed := b.array[b.head]
        b.head = (b.head + 1) % len(b.array)
        b.size--
        return removed</span>
}

// Peek returns but does not remove the first element.
func (b *Buffer) Peek() float64 <span class="cov8" title="1">{
        if b.size == 0 </span><span class="cov8" title="1">{
                return 0
        }</span>
        <span class="cov8" title="1">return b.array[b.head]</span>
}

// PeekBack returns but does not remove the last element.
func (b *Buffer) PeekBack() float64 <span class="cov8" title="1">{
        if b.size == 0 </span><span class="cov8" title="1">{
                return 0
        }</span>
        <span class="cov8" title="1">if b.tail == 0 </span><span class="cov8" title="1">{
                return b.array[len(b.array)-1]
        }</span>
        <span class="cov8" title="1">return b.array[b.tail-1]</span>
}

// TrimExcess resizes the capacity of the buffer to better fit the contents.
func (b *Buffer) TrimExcess() <span class="cov0" title="0">{
        threshold := float64(len(b.array)) * 0.9
        if b.size &lt; int(threshold) </span><span class="cov0" title="0">{
                b.SetCapacity(b.size)
        }</span>
}

// Array returns the ring buffer, in order, as an array.
func (b *Buffer) Array() Array <span class="cov8" title="1">{
        newArray := make([]float64, b.size)

        if b.size == 0 </span><span class="cov0" title="0">{
                return newArray
        }</span>

        <span class="cov8" title="1">if b.head &lt; b.tail </span><span class="cov8" title="1">{
                arrayCopy(b.array, b.head, newArray, 0, b.size)
        }</span> else<span class="cov0" title="0"> {
                arrayCopy(b.array, b.head, newArray, 0, len(b.array)-b.head)
                arrayCopy(b.array, 0, newArray, len(b.array)-b.head, b.tail)
        }</span>

        <span class="cov8" title="1">return Array(newArray)</span>
}

// Each calls the consumer for each element in the buffer.
func (b *Buffer) Each(mapfn func(int, float64)) <span class="cov8" title="1">{
        if b.size == 0 </span><span class="cov0" title="0">{
                return
        }</span>

        <span class="cov8" title="1">var index int
        if b.head &lt; b.tail </span><span class="cov0" title="0">{
                for cursor := b.head; cursor &lt; b.tail; cursor++ </span><span class="cov0" title="0">{
                        mapfn(index, b.array[cursor])
                        index++
                }</span>
        } else<span class="cov8" title="1"> {
                for cursor := b.head; cursor &lt; len(b.array); cursor++ </span><span class="cov8" title="1">{
                        mapfn(index, b.array[cursor])
                        index++
                }</span>
                <span class="cov8" title="1">for cursor := 0; cursor &lt; b.tail; cursor++ </span><span class="cov0" title="0">{
                        mapfn(index, b.array[cursor])
                        index++
                }</span>
        }
}

// String returns a string representation for value buffers.
func (b *Buffer) String() string <span class="cov0" title="0">{
        var values []string
        for _, elem := range b.Array() </span><span class="cov0" title="0">{
                values = append(values, fmt.Sprintf("%v", elem))
        }</span>
        <span class="cov0" title="0">return strings.Join(values, " &lt;= ")</span>
}

// --------------------------------------------------------------------------------
// Util methods
// --------------------------------------------------------------------------------

func arrayClear(source []float64, index, length int) <span class="cov0" title="0">{
        for x := 0; x &lt; length; x++ </span><span class="cov0" title="0">{
                absoluteIndex := x + index
                source[absoluteIndex] = 0
        }</span>
}

func arrayCopy(source []float64, sourceIndex int, destination []float64, destinationIndex, length int) <span class="cov8" title="1">{
        for x := 0; x &lt; length; x++ </span><span class="cov8" title="1">{
                from := sourceIndex + x
                to := destinationIndex + x

                destination[to] = source[from]
        }</span>
}
</pre>
		
		<pre class="file" id="file49" style="display: none">package seq

// Range returns the array values of a linear seq with a given start, end and optional step.
func Range(start, end float64) []float64 <span class="cov8" title="1">{
        return Seq{NewLinear().WithStart(start).WithEnd(end).WithStep(1.0)}.Array()
}</span>

// RangeWithStep returns the array values of a linear seq with a given start, end and optional step.
func RangeWithStep(start, end, step float64) []float64 <span class="cov8" title="1">{
        return Seq{NewLinear().WithStart(start).WithEnd(end).WithStep(step)}.Array()
}</span>

// NewLinear returns a new linear generator.
func NewLinear() *Linear <span class="cov8" title="1">{
        return &amp;Linear{step: 1.0}
}</span>

// Linear is a stepwise generator.
type Linear struct {
        start float64
        end   float64
        step  float64
}

// Start returns the start value.
func (lg Linear) Start() float64 <span class="cov8" title="1">{
        return lg.start
}</span>

// End returns the end value.
func (lg Linear) End() float64 <span class="cov8" title="1">{
        return lg.end
}</span>

// Step returns the step value.
func (lg Linear) Step() float64 <span class="cov0" title="0">{
        return lg.step
}</span>

// Len returns the number of elements in the seq.
func (lg Linear) Len() int <span class="cov8" title="1">{
        if lg.start &lt; lg.end </span><span class="cov8" title="1">{
                return int((lg.end-lg.start)/lg.step) + 1
        }</span>
        <span class="cov8" title="1">return int((lg.start-lg.end)/lg.step) + 1</span>
}

// GetValue returns the value at a given index.
func (lg Linear) GetValue(index int) float64 <span class="cov8" title="1">{
        fi := float64(index)
        if lg.start &lt; lg.end </span><span class="cov8" title="1">{
                return lg.start + (fi * lg.step)
        }</span>
        <span class="cov8" title="1">return lg.start - (fi * lg.step)</span>
}

// WithStart sets the start and returns the linear generator.
func (lg *Linear) WithStart(start float64) *Linear <span class="cov8" title="1">{
        lg.start = start
        return lg
}</span>

// WithEnd sets the end and returns the linear generator.
func (lg *Linear) WithEnd(end float64) *Linear <span class="cov8" title="1">{
        lg.end = end
        return lg
}</span>

// WithStep sets the step and returns the linear generator.
func (lg *Linear) WithStep(step float64) *Linear <span class="cov8" title="1">{
        lg.step = step
        return lg
}</span>
</pre>
		
		<pre class="file" id="file50" style="display: none">package seq

import (
        "math"
        "math/rand"
        "time"
)

// RandomValues returns an array of random values.
func RandomValues(count int) []float64 <span class="cov0" title="0">{
        return Seq{NewRandom().WithLen(count)}.Array()
}</span>

// RandomValuesWithMax returns an array of random values with a given average.
func RandomValuesWithMax(count int, max float64) []float64 <span class="cov0" title="0">{
        return Seq{NewRandom().WithMax(max).WithLen(count)}.Array()
}</span>

// NewRandom creates a new random seq.
func NewRandom() *Random <span class="cov8" title="1">{
        return &amp;Random{
                rnd: rand.New(rand.NewSource(time.Now().Unix())),
        }
}</span>

// Random is a random number seq generator.
type Random struct {
        rnd *rand.Rand
        max *float64
        min *float64
        len *int
}

// Len returns the number of elements that will be generated.
func (r *Random) Len() int <span class="cov8" title="1">{
        if r.len != nil </span><span class="cov8" title="1">{
                return *r.len
        }</span>
        <span class="cov0" title="0">return math.MaxInt32</span>
}

// GetValue returns the value.
func (r *Random) GetValue(_ int) float64 <span class="cov8" title="1">{
        if r.min != nil &amp;&amp; r.max != nil </span><span class="cov0" title="0">{
                var delta float64

                if *r.max &gt; *r.min </span><span class="cov0" title="0">{
                        delta = *r.max - *r.min
                }</span> else<span class="cov0" title="0"> {
                        delta = *r.min - *r.max
                }</span>

                <span class="cov0" title="0">return *r.min + (r.rnd.Float64() * delta)</span>
        } else<span class="cov8" title="1"> if r.max != nil </span><span class="cov8" title="1">{
                return r.rnd.Float64() * *r.max
        }</span> else<span class="cov0" title="0"> if r.min != nil </span><span class="cov0" title="0">{
                return *r.min + (r.rnd.Float64())
        }</span>
        <span class="cov0" title="0">return r.rnd.Float64()</span>
}

// WithLen sets a maximum len
func (r *Random) WithLen(length int) *Random <span class="cov8" title="1">{
        r.len = &amp;length
        return r
}</span>

// Min returns the minimum value.
func (r Random) Min() *float64 <span class="cov0" title="0">{
        return r.min
}</span>

// WithMin sets the scale and returns the Random.
func (r *Random) WithMin(min float64) *Random <span class="cov0" title="0">{
        r.min = &amp;min
        return r
}</span>

// Max returns the maximum value.
func (r Random) Max() *float64 <span class="cov8" title="1">{
        return r.max
}</span>

// WithMax sets the average and returns the Random.
func (r *Random) WithMax(max float64) *Random <span class="cov8" title="1">{
        r.max = &amp;max
        return r
}</span>
</pre>
		
		<pre class="file" id="file51" style="display: none">package seq

import (
        "math"
        "sort"
)

// New wraps a provider with a seq.
func New(provider Provider) Seq <span class="cov8" title="1">{
        return Seq{Provider: provider}
}</span>

// Values returns a new seq composed of a given set of values.
func Values(values ...float64) Seq <span class="cov8" title="1">{
        return Seq{Provider: Array(values)}
}</span>

// Provider is a provider for values for a seq.
type Provider interface {
        Len() int
        GetValue(int) float64
}

// Seq is a utility wrapper for seq providers.
type Seq struct {
        Provider
}

// Array enumerates the seq into a slice.
func (s Seq) Array() (output []float64) <span class="cov8" title="1">{
        if s.Len() == 0 </span><span class="cov0" title="0">{
                return
        }</span>

        <span class="cov8" title="1">output = make([]float64, s.Len())
        for i := 0; i &lt; s.Len(); i++ </span><span class="cov8" title="1">{
                output[i] = s.GetValue(i)
        }</span>
        <span class="cov8" title="1">return</span>
}

// Each applies the `mapfn` to all values in the value provider.
func (s Seq) Each(mapfn func(int, float64)) <span class="cov8" title="1">{
        for i := 0; i &lt; s.Len(); i++ </span><span class="cov8" title="1">{
                mapfn(i, s.GetValue(i))
        }</span>
}

// Map applies the `mapfn` to all values in the value provider,
// returning a new seq.
func (s Seq) Map(mapfn func(i int, v float64) float64) Seq <span class="cov8" title="1">{
        output := make([]float64, s.Len())
        for i := 0; i &lt; s.Len(); i++ </span><span class="cov8" title="1">{
                mapfn(i, s.GetValue(i))
        }</span>
        <span class="cov8" title="1">return Seq{Array(output)}</span>
}

// FoldLeft collapses a seq from left to right.
func (s Seq) FoldLeft(mapfn func(i int, v0, v float64) float64) (v0 float64) <span class="cov8" title="1">{
        if s.Len() == 0 </span><span class="cov0" title="0">{
                return 0
        }</span>

        <span class="cov8" title="1">if s.Len() == 1 </span><span class="cov0" title="0">{
                return s.GetValue(0)
        }</span>

        <span class="cov8" title="1">v0 = s.GetValue(0)
        for i := 1; i &lt; s.Len(); i++ </span><span class="cov8" title="1">{
                v0 = mapfn(i, v0, s.GetValue(i))
        }</span>
        <span class="cov8" title="1">return</span>
}

// FoldRight collapses a seq from right to left.
func (s Seq) FoldRight(mapfn func(i int, v0, v float64) float64) (v0 float64) <span class="cov8" title="1">{
        if s.Len() == 0 </span><span class="cov0" title="0">{
                return 0
        }</span>

        <span class="cov8" title="1">if s.Len() == 1 </span><span class="cov0" title="0">{
                return s.GetValue(0)
        }</span>

        <span class="cov8" title="1">v0 = s.GetValue(s.Len() - 1)
        for i := s.Len() - 2; i &gt;= 0; i-- </span><span class="cov8" title="1">{
                v0 = mapfn(i, v0, s.GetValue(i))
        }</span>
        <span class="cov8" title="1">return</span>
}

// Min returns the minimum value in the seq.
func (s Seq) Min() float64 <span class="cov0" title="0">{
        if s.Len() == 0 </span><span class="cov0" title="0">{
                return 0
        }</span>
        <span class="cov0" title="0">min := s.GetValue(0)
        var value float64
        for i := 1; i &lt; s.Len(); i++ </span><span class="cov0" title="0">{
                value = s.GetValue(i)
                if value &lt; min </span><span class="cov0" title="0">{
                        min = value
                }</span>
        }
        <span class="cov0" title="0">return min</span>
}

// Max returns the maximum value in the seq.
func (s Seq) Max() float64 <span class="cov0" title="0">{
        if s.Len() == 0 </span><span class="cov0" title="0">{
                return 0
        }</span>
        <span class="cov0" title="0">max := s.GetValue(0)
        var value float64
        for i := 1; i &lt; s.Len(); i++ </span><span class="cov0" title="0">{
                value = s.GetValue(i)
                if value &gt; max </span><span class="cov0" title="0">{
                        max = value
                }</span>
        }
        <span class="cov0" title="0">return max</span>
}

// MinMax returns the minimum and the maximum in one pass.
func (s Seq) MinMax() (min, max float64) <span class="cov8" title="1">{
        if s.Len() == 0 </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov8" title="1">min = s.GetValue(0)
        max = min
        var value float64
        for i := 1; i &lt; s.Len(); i++ </span><span class="cov8" title="1">{
                value = s.GetValue(i)
                if value &lt; min </span><span class="cov0" title="0">{
                        min = value
                }</span>
                <span class="cov8" title="1">if value &gt; max </span><span class="cov8" title="1">{
                        max = value
                }</span>
        }
        <span class="cov8" title="1">return</span>
}

// Sort returns the seq sorted in ascending order.
// This fully enumerates the seq.
func (s Seq) Sort() Seq <span class="cov0" title="0">{
        if s.Len() == 0 </span><span class="cov0" title="0">{
                return s
        }</span>
        <span class="cov0" title="0">values := s.Array()
        sort.Float64s(values)
        return Seq{Provider: Array(values)}</span>
}

// Median returns the median or middle value in the sorted seq.
func (s Seq) Median() (median float64) <span class="cov0" title="0">{
        l := s.Len()
        if l == 0 </span><span class="cov0" title="0">{
                return
        }</span>

        <span class="cov0" title="0">sorted := s.Sort()
        if l%2 == 0 </span><span class="cov0" title="0">{
                v0 := sorted.GetValue(l/2 - 1)
                v1 := sorted.GetValue(l/2 + 1)
                median = (v0 + v1) / 2
        }</span> else<span class="cov0" title="0"> {
                median = float64(sorted.GetValue(l &lt;&lt; 1))
        }</span>

        <span class="cov0" title="0">return</span>
}

// Sum adds all the elements of a series together.
func (s Seq) Sum() (accum float64) <span class="cov8" title="1">{
        if s.Len() == 0 </span><span class="cov0" title="0">{
                return 0
        }</span>

        <span class="cov8" title="1">for i := 0; i &lt; s.Len(); i++ </span><span class="cov8" title="1">{
                accum += s.GetValue(i)
        }</span>
        <span class="cov8" title="1">return</span>
}

// Average returns the float average of the values in the buffer.
func (s Seq) Average() float64 <span class="cov8" title="1">{
        if s.Len() == 0 </span><span class="cov0" title="0">{
                return 0
        }</span>

        <span class="cov8" title="1">return s.Sum() / float64(s.Len())</span>
}

// Variance computes the variance of the buffer.
func (s Seq) Variance() float64 <span class="cov8" title="1">{
        if s.Len() == 0 </span><span class="cov0" title="0">{
                return 0
        }</span>

        <span class="cov8" title="1">m := s.Average()
        var variance, v float64
        for i := 0; i &lt; s.Len(); i++ </span><span class="cov8" title="1">{
                v = s.GetValue(i)
                variance += (v - m) * (v - m)
        }</span>

        <span class="cov8" title="1">return variance / float64(s.Len())</span>
}

// StdDev returns the standard deviation.
func (s Seq) StdDev() float64 <span class="cov0" title="0">{
        if s.Len() == 0 </span><span class="cov0" title="0">{
                return 0
        }</span>

        <span class="cov0" title="0">return math.Pow(s.Variance(), 0.5)</span>
}

//Percentile finds the relative standing in a slice of floats.
// `percent` should be given on the interval [0,1.0).
func (s Seq) Percentile(percent float64) (percentile float64) <span class="cov0" title="0">{
        l := s.Len()
        if l == 0 </span><span class="cov0" title="0">{
                return 0
        }</span>

        <span class="cov0" title="0">if percent &lt; 0 || percent &gt; 1.0 </span><span class="cov0" title="0">{
                panic("percent out of range [0.0, 1.0)")</span>
        }

        <span class="cov0" title="0">sorted := s.Sort()
        index := percent * float64(l)
        if index == float64(int64(index)) </span><span class="cov0" title="0">{
                i := f64i(index)
                ci := sorted.GetValue(i - 1)
                c := sorted.GetValue(i)
                percentile = (ci + c) / 2.0
        }</span> else<span class="cov0" title="0"> {
                i := f64i(index)
                percentile = sorted.GetValue(i)
        }</span>

        <span class="cov0" title="0">return percentile</span>
}

// Normalize maps every value to the interval [0, 1.0].
func (s Seq) Normalize() Seq <span class="cov8" title="1">{
        min, max := s.MinMax()

        delta := max - min
        output := make([]float64, s.Len())
        for i := 0; i &lt; s.Len(); i++ </span><span class="cov8" title="1">{
                output[i] = (s.GetValue(i) - min) / delta
        }</span>

        <span class="cov8" title="1">return Seq{Provider: Array(output)}</span>
}
</pre>
		
		<pre class="file" id="file52" style="display: none">package seq

import (
        "time"

        "github.com/wcharczuk/go-chart/util"
)

// Time is a utility singleton with helper functions for time seq generation.
var Time timeSequence

type timeSequence struct{}

// Days generates a seq of timestamps by day, from -days to today.
func (ts timeSequence) Days(days int) []time.Time <span class="cov0" title="0">{
        var values []time.Time
        for day := days; day &gt;= 0; day-- </span><span class="cov0" title="0">{
                values = append(values, time.Now().AddDate(0, 0, -day))
        }</span>
        <span class="cov0" title="0">return values</span>
}

func (ts timeSequence) Hours(start time.Time, totalHours int) []time.Time <span class="cov8" title="1">{
        times := make([]time.Time, totalHours)

        last := start
        for i := 0; i &lt; totalHours; i++ </span><span class="cov8" title="1">{
                times[i] = last
                last = last.Add(time.Hour)
        }</span>

        <span class="cov8" title="1">return times</span>
}

// HoursFilled adds zero values for the data bounded by the start and end of the xdata array.
func (ts timeSequence) HoursFilled(xdata []time.Time, ydata []float64) ([]time.Time, []float64) <span class="cov8" title="1">{
        start, end := util.Time.StartAndEnd(xdata...)
        totalHours := util.Time.DiffHours(start, end)

        finalTimes := ts.Hours(start, totalHours+1)
        finalValues := make([]float64, totalHours+1)

        var hoursFromStart int
        for i, xd := range xdata </span><span class="cov8" title="1">{
                hoursFromStart = util.Time.DiffHours(start, xd)
                finalValues[hoursFromStart] = ydata[i]
        }</span>

        <span class="cov8" title="1">return finalTimes, finalValues</span>
}
</pre>
		
		<pre class="file" id="file53" style="display: none">package seq

import (
        "time"

        "github.com/wcharczuk/go-chart/util"
)

// Assert types implement interfaces.
var (
        _ Provider = (*Times)(nil)
)

// Times are an array of times.
// It wraps the array with methods that implement `seq.Provider`.
type Times []time.Time

// Array returns the times to an array.
func (t Times) Array() []time.Time <span class="cov0" title="0">{
        return []time.Time(t)
}</span>

// Len returns the length of the array.
func (t Times) Len() int <span class="cov0" title="0">{
        return len(t)
}</span>

// GetValue returns a value at an index as a time.
func (t Times) GetValue(index int) float64 <span class="cov0" title="0">{
        return util.Time.ToFloat64(t[index])
}</span>
</pre>
		
		<pre class="file" id="file54" style="display: none">package seq

import "math"

func round(input float64, places int) (rounded float64) <span class="cov0" title="0">{
        if math.IsNaN(input) </span><span class="cov0" title="0">{
                return 0.0
        }</span>

        <span class="cov0" title="0">sign := 1.0
        if input &lt; 0 </span><span class="cov0" title="0">{
                sign = -1
                input *= -1
        }</span>

        <span class="cov0" title="0">precision := math.Pow(10, float64(places))
        digit := input * precision
        _, decimal := math.Modf(digit)

        if decimal &gt;= 0.5 </span><span class="cov0" title="0">{
                rounded = math.Ceil(digit)
        }</span> else<span class="cov0" title="0"> {
                rounded = math.Floor(digit)
        }</span>

        <span class="cov0" title="0">return rounded / precision * sign</span>
}

func f64i(value float64) int <span class="cov0" title="0">{
        r := round(value, 0)
        return int(r)
}</span>
</pre>
		
		<pre class="file" id="file55" style="display: none">package chart

import (
        "fmt"

        util "github.com/wcharczuk/go-chart/util"
)

const (
        // DefaultSimpleMovingAveragePeriod is the default number of values to average.
        DefaultSimpleMovingAveragePeriod = 16
)

// Interface Assertions.
var (
        _ Series              = (*SMASeries)(nil)
        _ FirstValuesProvider = (*SMASeries)(nil)
        _ LastValuesProvider  = (*SMASeries)(nil)
)

// SMASeries is a computed series.
type SMASeries struct {
        Name  string
        Style Style
        YAxis YAxisType

        Period      int
        InnerSeries ValuesProvider
}

// GetName returns the name of the time series.
func (sma SMASeries) GetName() string <span class="cov0" title="0">{
        return sma.Name
}</span>

// GetStyle returns the line style.
func (sma SMASeries) GetStyle() Style <span class="cov0" title="0">{
        return sma.Style
}</span>

// GetYAxis returns which YAxis the series draws on.
func (sma SMASeries) GetYAxis() YAxisType <span class="cov0" title="0">{
        return sma.YAxis
}</span>

// Len returns the number of elements in the series.
func (sma SMASeries) Len() int <span class="cov8" title="1">{
        return sma.InnerSeries.Len()
}</span>

// GetPeriod returns the window size.
func (sma SMASeries) GetPeriod(defaults ...int) int <span class="cov8" title="1">{
        if sma.Period == 0 </span><span class="cov0" title="0">{
                if len(defaults) &gt; 0 </span><span class="cov0" title="0">{
                        return defaults[0]
                }</span>
                <span class="cov0" title="0">return DefaultSimpleMovingAveragePeriod</span>
        }
        <span class="cov8" title="1">return sma.Period</span>
}

// GetValues gets a value at a given index.
func (sma SMASeries) GetValues(index int) (x, y float64) <span class="cov8" title="1">{
        if sma.InnerSeries == nil || sma.InnerSeries.Len() == 0 </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov8" title="1">px, _ := sma.InnerSeries.GetValues(index)
        x = px
        y = sma.getAverage(index)
        return</span>
}

// GetFirstValues computes the first moving average value.
func (sma SMASeries) GetFirstValues() (x, y float64) <span class="cov0" title="0">{
        if sma.InnerSeries == nil || sma.InnerSeries.Len() == 0 </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov0" title="0">px, _ := sma.InnerSeries.GetValues(0)
        x = px
        y = sma.getAverage(0)
        return</span>
}

// GetLastValues computes the last moving average value but walking back window size samples,
// and recomputing the last moving average chunk.
func (sma SMASeries) GetLastValues() (x, y float64) <span class="cov8" title="1">{
        if sma.InnerSeries == nil || sma.InnerSeries.Len() == 0 </span><span class="cov0" title="0">{
                return
        }</span>
        <span class="cov8" title="1">seriesLen := sma.InnerSeries.Len()
        px, _ := sma.InnerSeries.GetValues(seriesLen - 1)
        x = px
        y = sma.getAverage(seriesLen - 1)
        return</span>
}

func (sma SMASeries) getAverage(index int) float64 <span class="cov8" title="1">{
        period := sma.GetPeriod()
        floor := util.Math.MaxInt(0, index-period)
        var accum float64
        var count float64
        for x := index; x &gt;= floor; x-- </span><span class="cov8" title="1">{
                _, vy := sma.InnerSeries.GetValues(x)
                accum += vy
                count += 1.0
        }</span>
        <span class="cov8" title="1">return accum / count</span>
}

// Render renders the series.
func (sma SMASeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) <span class="cov0" title="0">{
        style := sma.Style.InheritFrom(defaults)
        Draw.LineSeries(r, canvasBox, xrange, yrange, style, sma)
}</span>

// Validate validates the series.
func (sma SMASeries) Validate() error <span class="cov0" title="0">{
        if sma.InnerSeries == nil </span><span class="cov0" title="0">{
                return fmt.Errorf("sma series requires InnerSeries to be set")
        }</span>
        <span class="cov0" title="0">return nil</span>
}
</pre>
		
		<pre class="file" id="file56" style="display: none">package chart

import (
        "errors"
        "fmt"
        "io"
        "math"

        "github.com/golang/freetype/truetype"
        "github.com/wcharczuk/go-chart/seq"
        util "github.com/wcharczuk/go-chart/util"
)

// StackedBar is a bar within a StackedBarChart.
type StackedBar struct {
        Name   string
        Width  int
        Values []Value
}

// GetWidth returns the width of the bar.
func (sb StackedBar) GetWidth() int <span class="cov0" title="0">{
        if sb.Width == 0 </span><span class="cov0" title="0">{
                return 50
        }</span>
        <span class="cov0" title="0">return sb.Width</span>
}

// StackedBarChart is a chart that draws sections of a bar based on percentages.
type StackedBarChart struct {
        Title      string
        TitleStyle Style

        ColorPalette ColorPalette

        Width  int
        Height int
        DPI    float64

        Background Style
        Canvas     Style

        XAxis Style
        YAxis Style

        BarSpacing int

        Font        *truetype.Font
        defaultFont *truetype.Font

        Bars     []StackedBar
        Elements []Renderable
}

// GetDPI returns the dpi for the chart.
func (sbc StackedBarChart) GetDPI(defaults ...float64) float64 <span class="cov0" title="0">{
        if sbc.DPI == 0 </span><span class="cov0" title="0">{
                if len(defaults) &gt; 0 </span><span class="cov0" title="0">{
                        return defaults[0]
                }</span>
                <span class="cov0" title="0">return DefaultDPI</span>
        }
        <span class="cov0" title="0">return sbc.DPI</span>
}

// GetFont returns the text font.
func (sbc StackedBarChart) GetFont() *truetype.Font <span class="cov0" title="0">{
        if sbc.Font == nil </span><span class="cov0" title="0">{
                return sbc.defaultFont
        }</span>
        <span class="cov0" title="0">return sbc.Font</span>
}

// GetWidth returns the chart width or the default value.
func (sbc StackedBarChart) GetWidth() int <span class="cov0" title="0">{
        if sbc.Width == 0 </span><span class="cov0" title="0">{
                return DefaultChartWidth
        }</span>
        <span class="cov0" title="0">return sbc.Width</span>
}

// GetHeight returns the chart height or the default value.
func (sbc StackedBarChart) GetHeight() int <span class="cov0" title="0">{
        if sbc.Height == 0 </span><span class="cov0" title="0">{
                return DefaultChartWidth
        }</span>
        <span class="cov0" title="0">return sbc.Height</span>
}

// GetBarSpacing returns the spacing between bars.
func (sbc StackedBarChart) GetBarSpacing() int <span class="cov0" title="0">{
        if sbc.BarSpacing == 0 </span><span class="cov0" title="0">{
                return 100
        }</span>
        <span class="cov0" title="0">return sbc.BarSpacing</span>
}

// Render renders the chart with the given renderer to the given io.Writer.
func (sbc StackedBarChart) Render(rp RendererProvider, w io.Writer) error <span class="cov0" title="0">{
        if len(sbc.Bars) == 0 </span><span class="cov0" title="0">{
                return errors.New("please provide at least one bar")
        }</span>

        <span class="cov0" title="0">r, err := rp(sbc.GetWidth(), sbc.GetHeight())
        if err != nil </span><span class="cov0" title="0">{
                return err
        }</span>

        <span class="cov0" title="0">if sbc.Font == nil </span><span class="cov0" title="0">{
                defaultFont, err := GetDefaultFont()
                if err != nil </span><span class="cov0" title="0">{
                        return err
                }</span>
                <span class="cov0" title="0">sbc.defaultFont = defaultFont</span>
        }
        <span class="cov0" title="0">r.SetDPI(sbc.GetDPI(DefaultDPI))

        canvasBox := sbc.getAdjustedCanvasBox(r, sbc.getDefaultCanvasBox())
        sbc.drawCanvas(r, canvasBox)
        sbc.drawBars(r, canvasBox)
        sbc.drawXAxis(r, canvasBox)
        sbc.drawYAxis(r, canvasBox)

        sbc.drawTitle(r)
        for _, a := range sbc.Elements </span><span class="cov0" title="0">{
                a(r, canvasBox, sbc.styleDefaultsElements())
        }</span>

        <span class="cov0" title="0">return r.Save(w)</span>
}

func (sbc StackedBarChart) drawCanvas(r Renderer, canvasBox Box) <span class="cov0" title="0">{
        Draw.Box(r, canvasBox, sbc.getCanvasStyle())
}</span>

func (sbc StackedBarChart) drawBars(r Renderer, canvasBox Box) <span class="cov0" title="0">{
        xoffset := canvasBox.Left
        for _, bar := range sbc.Bars </span><span class="cov0" title="0">{
                sbc.drawBar(r, canvasBox, xoffset, bar)
                xoffset += (sbc.GetBarSpacing() + bar.GetWidth())
        }</span>
}

func (sbc StackedBarChart) drawBar(r Renderer, canvasBox Box, xoffset int, bar StackedBar) int <span class="cov0" title="0">{
        barSpacing2 := sbc.GetBarSpacing() &gt;&gt; 1
        bxl := xoffset + barSpacing2
        bxr := bxl + bar.GetWidth()

        normalizedBarComponents := Values(bar.Values).Normalize()
        yoffset := canvasBox.Top
        for index, bv := range normalizedBarComponents </span><span class="cov0" title="0">{
                barHeight := int(math.Ceil(bv.Value * float64(canvasBox.Height())))
                barBox := Box{
                        Top:    yoffset,
                        Left:   bxl,
                        Right:  bxr,
                        Bottom: util.Math.MinInt(yoffset+barHeight, canvasBox.Bottom-DefaultStrokeWidth),
                }
                Draw.Box(r, barBox, bv.Style.InheritFrom(sbc.styleDefaultsStackedBarValue(index)))
                yoffset += barHeight
        }</span>

        <span class="cov0" title="0">return bxr</span>
}

func (sbc StackedBarChart) drawXAxis(r Renderer, canvasBox Box) <span class="cov0" title="0">{
        if sbc.XAxis.Show </span><span class="cov0" title="0">{
                axisStyle := sbc.XAxis.InheritFrom(sbc.styleDefaultsAxes())
                axisStyle.WriteToRenderer(r)

                r.MoveTo(canvasBox.Left, canvasBox.Bottom)
                r.LineTo(canvasBox.Right, canvasBox.Bottom)
                r.Stroke()

                r.MoveTo(canvasBox.Left, canvasBox.Bottom)
                r.LineTo(canvasBox.Left, canvasBox.Bottom+DefaultVerticalTickHeight)
                r.Stroke()

                cursor := canvasBox.Left
                for _, bar := range sbc.Bars </span><span class="cov0" title="0">{

                        barLabelBox := Box{
                                Top:    canvasBox.Bottom + DefaultXAxisMargin,
                                Left:   cursor,
                                Right:  cursor + bar.GetWidth() + sbc.GetBarSpacing(),
                                Bottom: sbc.GetHeight(),
                        }
                        if len(bar.Name) &gt; 0 </span><span class="cov0" title="0">{
                                Draw.TextWithin(r, bar.Name, barLabelBox, axisStyle)
                        }</span>
                        <span class="cov0" title="0">axisStyle.WriteToRenderer(r)
                        r.MoveTo(barLabelBox.Right, canvasBox.Bottom)
                        r.LineTo(barLabelBox.Right, canvasBox.Bottom+DefaultVerticalTickHeight)
                        r.Stroke()
                        cursor += bar.GetWidth() + sbc.GetBarSpacing()</span>
                }
        }
}

func (sbc StackedBarChart) drawYAxis(r Renderer, canvasBox Box) <span class="cov0" title="0">{
        if sbc.YAxis.Show </span><span class="cov0" title="0">{
                axisStyle := sbc.YAxis.InheritFrom(sbc.styleDefaultsAxes())
                axisStyle.WriteToRenderer(r)
                r.MoveTo(canvasBox.Right, canvasBox.Top)
                r.LineTo(canvasBox.Right, canvasBox.Bottom)
                r.Stroke()

                r.MoveTo(canvasBox.Right, canvasBox.Bottom)
                r.LineTo(canvasBox.Right+DefaultHorizontalTickWidth, canvasBox.Bottom)
                r.Stroke()

                ticks := seq.RangeWithStep(0.0, 1.0, 0.2)
                for _, t := range ticks </span><span class="cov0" title="0">{
                        axisStyle.GetStrokeOptions().WriteToRenderer(r)
                        ty := canvasBox.Bottom - int(t*float64(canvasBox.Height()))
                        r.MoveTo(canvasBox.Right, ty)
                        r.LineTo(canvasBox.Right+DefaultHorizontalTickWidth, ty)
                        r.Stroke()

                        axisStyle.GetTextOptions().WriteToRenderer(r)
                        text := fmt.Sprintf("%0.0f%%", t*100)

                        tb := r.MeasureText(text)
                        Draw.Text(r, text, canvasBox.Right+DefaultYAxisMargin+5, ty+(tb.Height()&gt;&gt;1), axisStyle)
                }</span>

        }
}

func (sbc StackedBarChart) drawTitle(r Renderer) <span class="cov0" title="0">{
        if len(sbc.Title) &gt; 0 &amp;&amp; sbc.TitleStyle.Show </span><span class="cov0" title="0">{
                r.SetFont(sbc.TitleStyle.GetFont(sbc.GetFont()))
                r.SetFontColor(sbc.TitleStyle.GetFontColor(sbc.GetColorPalette().TextColor()))
                titleFontSize := sbc.TitleStyle.GetFontSize(DefaultTitleFontSize)
                r.SetFontSize(titleFontSize)

                textBox := r.MeasureText(sbc.Title)

                textWidth := textBox.Width()
                textHeight := textBox.Height()

                titleX := (sbc.GetWidth() &gt;&gt; 1) - (textWidth &gt;&gt; 1)
                titleY := sbc.TitleStyle.Padding.GetTop(DefaultTitleTop) + textHeight

                r.Text(sbc.Title, titleX, titleY)
        }</span>
}

func (sbc StackedBarChart) getCanvasStyle() Style <span class="cov0" title="0">{
        return sbc.Canvas.InheritFrom(sbc.styleDefaultsCanvas())
}</span>

func (sbc StackedBarChart) styleDefaultsCanvas() Style <span class="cov0" title="0">{
        return Style{
                FillColor:   sbc.GetColorPalette().CanvasColor(),
                StrokeColor: sbc.GetColorPalette().CanvasStrokeColor(),
                StrokeWidth: DefaultCanvasStrokeWidth,
        }
}</span>

// GetColorPalette returns the color palette for the chart.
func (sbc StackedBarChart) GetColorPalette() ColorPalette <span class="cov0" title="0">{
        if sbc.ColorPalette != nil </span><span class="cov0" title="0">{
                return sbc.ColorPalette
        }</span>
        <span class="cov0" title="0">return AlternateColorPalette</span>
}

func (sbc StackedBarChart) getDefaultCanvasBox() Box <span class="cov0" title="0">{
        return sbc.Box()
}</span>

func (sbc StackedBarChart) getAdjustedCanvasBox(r Renderer, canvasBox Box) Box <span class="cov0" title="0">{
        var totalWidth int
        for _, bar := range sbc.Bars </span><span class="cov0" title="0">{
                totalWidth += bar.GetWidth() + sbc.GetBarSpacing()
        }</span>

        <span class="cov0" title="0">if sbc.XAxis.Show </span><span class="cov0" title="0">{
                xaxisHeight := DefaultVerticalTickHeight

                axisStyle := sbc.XAxis.InheritFrom(sbc.styleDefaultsAxes())
                axisStyle.WriteToRenderer(r)

                cursor := canvasBox.Left
                for _, bar := range sbc.Bars </span><span class="cov0" title="0">{
                        if len(bar.Name) &gt; 0 </span><span class="cov0" title="0">{
                                barLabelBox := Box{
                                        Top:    canvasBox.Bottom + DefaultXAxisMargin,
                                        Left:   cursor,
                                        Right:  cursor + bar.GetWidth() + sbc.GetBarSpacing(),
                                        Bottom: sbc.GetHeight(),
                                }
                                lines := Text.WrapFit(r, bar.Name, barLabelBox.Width(), axisStyle)
                                linesBox := Text.MeasureLines(r, lines, axisStyle)

                                xaxisHeight = util.Math.MaxInt(linesBox.Height()+(2*DefaultXAxisMargin), xaxisHeight)
                        }</span>
                }
                <span class="cov0" title="0">return Box{
                        Top:    canvasBox.Top,
                        Left:   canvasBox.Left,
                        Right:  canvasBox.Left + totalWidth,
                        Bottom: sbc.GetHeight() - xaxisHeight,
                }</span>
        }
        <span class="cov0" title="0">return Box{
                Top:    canvasBox.Top,
                Left:   canvasBox.Left,
                Right:  canvasBox.Left + totalWidth,
                Bottom: canvasBox.Bottom,
        }</span>

}

// Box returns the chart bounds as a box.
func (sbc StackedBarChart) Box() Box <span class="cov0" title="0">{
        dpr := sbc.Background.Padding.GetRight(10)
        dpb := sbc.Background.Padding.GetBottom(50)

        return Box{
                Top:    sbc.Background.Padding.GetTop(20),
                Left:   sbc.Background.Padding.GetLeft(20),
                Right:  sbc.GetWidth() - dpr,
                Bottom: sbc.GetHeight() - dpb,
        }
}</span>

func (sbc StackedBarChart) styleDefaultsStackedBarValue(index int) Style <span class="cov0" title="0">{
        return Style{
                StrokeColor: sbc.GetColorPalette().GetSeriesColor(index),
                StrokeWidth: 3.0,
                FillColor:   sbc.GetColorPalette().GetSeriesColor(index),
        }
}</span>

func (sbc StackedBarChart) styleDefaultsTitle() Style <span class="cov0" title="0">{
        return sbc.TitleStyle.InheritFrom(Style{
                FontColor:           DefaultTextColor,
                Font:                sbc.GetFont(),
                FontSize:            sbc.getTitleFontSize(),
                TextHorizontalAlign: TextHorizontalAlignCenter,
                TextVerticalAlign:   TextVerticalAlignTop,
                TextWrap:            TextWrapWord,
        })
}</span>

func (sbc StackedBarChart) getTitleFontSize() float64 <span class="cov0" title="0">{
        effectiveDimension := util.Math.MinInt(sbc.GetWidth(), sbc.GetHeight())
        if effectiveDimension &gt;= 2048 </span><span class="cov0" title="0">{
                return 48
        }</span> else<span class="cov0" title="0"> if effectiveDimension &gt;= 1024 </span><span class="cov0" title="0">{
                return 24
        }</span> else<span class="cov0" title="0"> if effectiveDimension &gt;= 512 </span><span class="cov0" title="0">{
                return 18
        }</span> else<span class="cov0" title="0"> if effectiveDimension &gt;= 256 </span><span class="cov0" title="0">{
                return 12
        }</span>
        <span class="cov0" title="0">return 10</span>
}

func (sbc StackedBarChart) styleDefaultsAxes() Style <span class="cov0" title="0">{
        return Style{
                StrokeColor:         DefaultAxisColor,
                Font:                sbc.GetFont(),
                FontSize:            DefaultAxisFontSize,
                FontColor:           DefaultAxisColor,
                TextHorizontalAlign: TextHorizontalAlignCenter,
                TextVerticalAlign:   TextVerticalAlignTop,
                TextWrap:            TextWrapWord,
        }
}</span>
func (sbc StackedBarChart) styleDefaultsElements() Style <span class="cov0" title="0">{
        return Style{
                Font: sbc.GetFont(),
        }
}</span>
</pre>
		
		<pre class="file" id="file57" style="display: none">package chart

import (
        "fmt"
        "strings"

        "github.com/golang/freetype/truetype"
        "github.com/wcharczuk/go-chart/drawing"
        "github.com/wcharczuk/go-chart/util"
)

const (
        // Disabled indicates if the value should be interpreted as set intentionally to zero.
        // this is because golang optionals aren't here yet.
        Disabled = -1
)

// StyleShow is a prebuilt style with the `Show` property set to true.
func StyleShow() Style <span class="cov8" title="1">{
        return Style{
                Show: true,
        }
}</span>

// StyleTextDefaults returns a style for drawing outside a
// chart context.
func StyleTextDefaults() Style <span class="cov0" title="0">{
        font, _ := GetDefaultFont()
        return Style{
                Show:      true,
                Font:      font,
                FontColor: DefaultTextColor,
                FontSize:  DefaultTitleFontSize,
        }
}</span>

// Style is a simple style set.
type Style struct {
        Show    bool
        Padding Box

        ClassName string

        StrokeWidth     float64
        StrokeColor     drawing.Color
        StrokeDashArray []float64

        DotColor drawing.Color
        DotWidth float64

        DotWidthProvider SizeProvider
        DotColorProvider DotColorProvider

        FillColor drawing.Color

        FontSize  float64
        FontColor drawing.Color
        Font      *truetype.Font

        TextHorizontalAlign TextHorizontalAlign
        TextVerticalAlign   TextVerticalAlign
        TextWrap            TextWrap
        TextLineSpacing     int
        TextRotationDegrees float64 //0 is unset or normal
}

// IsZero returns if the object is set or not.
func (s Style) IsZero() bool <span class="cov8" title="1">{
        return s.StrokeColor.IsZero() &amp;&amp;
                s.StrokeWidth == 0 &amp;&amp;
                s.DotColor.IsZero() &amp;&amp;
                s.DotWidth == 0 &amp;&amp;
                s.FillColor.IsZero() &amp;&amp;
                s.FontColor.IsZero() &amp;&amp;
                s.FontSize == 0 &amp;&amp;
                s.Font == nil &amp;&amp;
                s.ClassName == ""
}</span>

// String returns a text representation of the style.
func (s Style) String() string <span class="cov0" title="0">{
        if s.IsZero() </span><span class="cov0" title="0">{
                return "{}"
        }</span>

        <span class="cov0" title="0">var output []string
        if s.Show </span><span class="cov0" title="0">{
                output = []string{"\"show\": true"}
        }</span> else<span class="cov0" title="0"> {
                output = []string{"\"show\": false"}
        }</span>

        <span class="cov0" title="0">if s.ClassName != "" </span><span class="cov0" title="0">{
                output = append(output, fmt.Sprintf("\"class_name\": %s", s.ClassName))
        }</span> else<span class="cov0" title="0"> {
                output = append(output, "\"class_name\": null")
        }</span>

        <span class="cov0" title="0">if !s.Padding.IsZero() </span><span class="cov0" title="0">{
                output = append(output, fmt.Sprintf("\"padding\": %s", s.Padding.String()))
        }</span> else<span class="cov0" title="0"> {
                output = append(output, "\"padding\": null")
        }</span>

        <span class="cov0" title="0">if s.StrokeWidth &gt;= 0 </span><span class="cov0" title="0">{
                output = append(output, fmt.Sprintf("\"stroke_width\": %0.2f", s.StrokeWidth))
        }</span> else<span class="cov0" title="0"> {
                output = append(output, "\"stroke_width\": null")
        }</span>

        <span class="cov0" title="0">if !s.StrokeColor.IsZero() </span><span class="cov0" title="0">{
                output = append(output, fmt.Sprintf("\"stroke_color\": %s", s.StrokeColor.String()))
        }</span> else<span class="cov0" title="0"> {
                output = append(output, "\"stroke_color\": null")
        }</span>

        <span class="cov0" title="0">if len(s.StrokeDashArray) &gt; 0 </span><span class="cov0" title="0">{
                var elements []string
                for _, v := range s.StrokeDashArray </span><span class="cov0" title="0">{
                        elements = append(elements, fmt.Sprintf("%.2f", v))
                }</span>
                <span class="cov0" title="0">dashArray := strings.Join(elements, ", ")
                output = append(output, fmt.Sprintf("\"stroke_dash_array\": [%s]", dashArray))</span>
        } else<span class="cov0" title="0"> {
                output = append(output, "\"stroke_dash_array\": null")
        }</span>

        <span class="cov0" title="0">if s.DotWidth &gt;= 0 </span><span class="cov0" title="0">{
                output = append(output, fmt.Sprintf("\"dot_width\": %0.2f", s.DotWidth))
        }</span> else<span class="cov0" title="0"> {
                output = append(output, "\"dot_width\": null")
        }</span>

        <span class="cov0" title="0">if !s.DotColor.IsZero() </span><span class="cov0" title="0">{
                output = append(output, fmt.Sprintf("\"dot_color\": %s", s.DotColor.String()))
        }</span> else<span class="cov0" title="0"> {
                output = append(output, "\"dot_color\": null")
        }</span>

        <span class="cov0" title="0">if !s.FillColor.IsZero() </span><span class="cov0" title="0">{
                output = append(output, fmt.Sprintf("\"fill_color\": %s", s.FillColor.String()))
        }</span> else<span class="cov0" title="0"> {
                output = append(output, "\"fill_color\": null")
        }</span>

        <span class="cov0" title="0">if s.FontSize != 0 </span><span class="cov0" title="0">{
                output = append(output, fmt.Sprintf("\"font_size\": \"%0.2fpt\"", s.FontSize))
        }</span> else<span class="cov0" title="0"> {
                output = append(output, "\"font_size\": null")
        }</span>

        <span class="cov0" title="0">if !s.FontColor.IsZero() </span><span class="cov0" title="0">{
                output = append(output, fmt.Sprintf("\"font_color\": %s", s.FontColor.String()))
        }</span> else<span class="cov0" title="0"> {
                output = append(output, "\"font_color\": null")
        }</span>

        <span class="cov0" title="0">if s.Font != nil </span><span class="cov0" title="0">{
                output = append(output, fmt.Sprintf("\"font\": \"%s\"", s.Font.Name(truetype.NameIDFontFamily)))
        }</span> else<span class="cov0" title="0"> {
                output = append(output, "\"font_color\": null")
        }</span>

        <span class="cov0" title="0">return "{" + strings.Join(output, ", ") + "}"</span>
}

func (s Style) GetClassName(defaults ...string) string <span class="cov8" title="1">{
        if s.ClassName == "" </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov8" title="1">return ""</span>
        }
        <span class="cov0" title="0">return s.ClassName</span>
}

// GetStrokeColor returns the stroke color.
func (s Style) GetStrokeColor(defaults ...drawing.Color) drawing.Color <span class="cov8" title="1">{
        if s.StrokeColor.IsZero() </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov8" title="1">return drawing.ColorTransparent</span>
        }
        <span class="cov8" title="1">return s.StrokeColor</span>
}

// GetFillColor returns the fill color.
func (s Style) GetFillColor(defaults ...drawing.Color) drawing.Color <span class="cov8" title="1">{
        if s.FillColor.IsZero() </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov8" title="1">return drawing.ColorTransparent</span>
        }
        <span class="cov8" title="1">return s.FillColor</span>
}

// GetDotColor returns the stroke color.
func (s Style) GetDotColor(defaults ...drawing.Color) drawing.Color <span class="cov8" title="1">{
        if s.DotColor.IsZero() </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov0" title="0">return drawing.ColorTransparent</span>
        }
        <span class="cov0" title="0">return s.DotColor</span>
}

// GetStrokeWidth returns the stroke width.
func (s Style) GetStrokeWidth(defaults ...float64) float64 <span class="cov8" title="1">{
        if s.StrokeWidth == 0 </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov8" title="1">return DefaultStrokeWidth</span>
        }
        <span class="cov8" title="1">return s.StrokeWidth</span>
}

// GetDotWidth returns the dot width for scatter plots.
func (s Style) GetDotWidth(defaults ...float64) float64 <span class="cov8" title="1">{
        if s.DotWidth == 0 </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov0" title="0">return DefaultDotWidth</span>
        }
        <span class="cov0" title="0">return s.DotWidth</span>
}

// GetStrokeDashArray returns the stroke dash array.
func (s Style) GetStrokeDashArray(defaults ...[]float64) []float64 <span class="cov8" title="1">{
        if len(s.StrokeDashArray) == 0 </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov8" title="1">return nil</span>
        }
        <span class="cov0" title="0">return s.StrokeDashArray</span>
}

// GetFontSize gets the font size.
func (s Style) GetFontSize(defaults ...float64) float64 <span class="cov8" title="1">{
        if s.FontSize == 0 </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov8" title="1">return DefaultFontSize</span>
        }
        <span class="cov8" title="1">return s.FontSize</span>
}

// GetFontColor gets the font size.
func (s Style) GetFontColor(defaults ...drawing.Color) drawing.Color <span class="cov8" title="1">{
        if s.FontColor.IsZero() </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov8" title="1">return drawing.ColorTransparent</span>
        }
        <span class="cov8" title="1">return s.FontColor</span>
}

// GetFont returns the font face.
func (s Style) GetFont(defaults ...*truetype.Font) *truetype.Font <span class="cov8" title="1">{
        if s.Font == nil </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov8" title="1">return nil</span>
        }
        <span class="cov8" title="1">return s.Font</span>
}

// GetPadding returns the padding.
func (s Style) GetPadding(defaults ...Box) Box <span class="cov8" title="1">{
        if s.Padding.IsZero() </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov8" title="1">return Box{}</span>
        }
        <span class="cov8" title="1">return s.Padding</span>
}

// GetTextHorizontalAlign returns the horizontal alignment.
func (s Style) GetTextHorizontalAlign(defaults ...TextHorizontalAlign) TextHorizontalAlign <span class="cov8" title="1">{
        if s.TextHorizontalAlign == TextHorizontalAlignUnset </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov0" title="0">return TextHorizontalAlignUnset</span>
        }
        <span class="cov8" title="1">return s.TextHorizontalAlign</span>
}

// GetTextVerticalAlign returns the vertical alignment.
func (s Style) GetTextVerticalAlign(defaults ...TextVerticalAlign) TextVerticalAlign <span class="cov8" title="1">{
        if s.TextVerticalAlign == TextVerticalAlignUnset </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov0" title="0">return TextVerticalAlignUnset</span>
        }
        <span class="cov8" title="1">return s.TextVerticalAlign</span>
}

// GetTextWrap returns the word wrap.
func (s Style) GetTextWrap(defaults ...TextWrap) TextWrap <span class="cov8" title="1">{
        if s.TextWrap == TextWrapUnset </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov0" title="0">return TextWrapUnset</span>
        }
        <span class="cov0" title="0">return s.TextWrap</span>
}

// GetTextLineSpacing returns the spacing in pixels between lines of text (vertically).
func (s Style) GetTextLineSpacing(defaults ...int) int <span class="cov8" title="1">{
        if s.TextLineSpacing == 0 </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
                <span class="cov8" title="1">return DefaultLineSpacing</span>
        }
        <span class="cov0" title="0">return s.TextLineSpacing</span>
}

// GetTextRotationDegrees returns the text rotation in degrees.
func (s Style) GetTextRotationDegrees(defaults ...float64) float64 <span class="cov8" title="1">{
        if s.TextRotationDegrees == 0 </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov8" title="1">{
                        return defaults[0]
                }</span>
        }
        <span class="cov8" title="1">return s.TextRotationDegrees</span>
}

// WriteToRenderer passes the style's options to a renderer.
func (s Style) WriteToRenderer(r Renderer) <span class="cov8" title="1">{
        r.SetClassName(s.GetClassName())
        r.SetStrokeColor(s.GetStrokeColor())
        r.SetStrokeWidth(s.GetStrokeWidth())
        r.SetStrokeDashArray(s.GetStrokeDashArray())
        r.SetFillColor(s.GetFillColor())
        r.SetFont(s.GetFont())
        r.SetFontColor(s.GetFontColor())
        r.SetFontSize(s.GetFontSize())

        r.ClearTextRotation()
        if s.GetTextRotationDegrees() != 0 </span><span class="cov0" title="0">{
                r.SetTextRotation(util.Math.DegreesToRadians(s.GetTextRotationDegrees()))
        }</span>
}

// WriteDrawingOptionsToRenderer passes just the drawing style options to a renderer.
func (s Style) WriteDrawingOptionsToRenderer(r Renderer) <span class="cov8" title="1">{
        r.SetClassName(s.GetClassName())
        r.SetStrokeColor(s.GetStrokeColor())
        r.SetStrokeWidth(s.GetStrokeWidth())
        r.SetStrokeDashArray(s.GetStrokeDashArray())
        r.SetFillColor(s.GetFillColor())
}</span>

// WriteTextOptionsToRenderer passes just the text style options to a renderer.
func (s Style) WriteTextOptionsToRenderer(r Renderer) <span class="cov8" title="1">{
        r.SetClassName(s.GetClassName())
        r.SetFont(s.GetFont())
        r.SetFontColor(s.GetFontColor())
        r.SetFontSize(s.GetFontSize())
}</span>

// InheritFrom coalesces two styles into a new style.
func (s Style) InheritFrom(defaults Style) (final Style) <span class="cov8" title="1">{
        final.ClassName = s.GetClassName(defaults.ClassName)

        final.StrokeColor = s.GetStrokeColor(defaults.StrokeColor)
        final.StrokeWidth = s.GetStrokeWidth(defaults.StrokeWidth)
        final.StrokeDashArray = s.GetStrokeDashArray(defaults.StrokeDashArray)

        final.DotColor = s.GetDotColor(defaults.DotColor)
        final.DotWidth = s.GetDotWidth(defaults.DotWidth)

        final.DotWidthProvider = s.DotWidthProvider
        final.DotColorProvider = s.DotColorProvider

        final.FillColor = s.GetFillColor(defaults.FillColor)
        final.FontColor = s.GetFontColor(defaults.FontColor)
        final.FontSize = s.GetFontSize(defaults.FontSize)
        final.Font = s.GetFont(defaults.Font)
        final.Padding = s.GetPadding(defaults.Padding)
        final.TextHorizontalAlign = s.GetTextHorizontalAlign(defaults.TextHorizontalAlign)
        final.TextVerticalAlign = s.GetTextVerticalAlign(defaults.TextVerticalAlign)
        final.TextWrap = s.GetTextWrap(defaults.TextWrap)
        final.TextLineSpacing = s.GetTextLineSpacing(defaults.TextLineSpacing)
        final.TextRotationDegrees = s.GetTextRotationDegrees(defaults.TextRotationDegrees)

        return
}</span>

// GetStrokeOptions returns the stroke components.
func (s Style) GetStrokeOptions() Style <span class="cov8" title="1">{
        return Style{
                ClassName:       s.ClassName,
                StrokeDashArray: s.StrokeDashArray,
                StrokeColor:     s.StrokeColor,
                StrokeWidth:     s.StrokeWidth,
        }
}</span>

// GetFillOptions returns the fill components.
func (s Style) GetFillOptions() Style <span class="cov8" title="1">{
        return Style{
                ClassName: s.ClassName,
                FillColor: s.FillColor,
        }
}</span>

// GetDotOptions returns the dot components.
func (s Style) GetDotOptions() Style <span class="cov0" title="0">{
        return Style{
                ClassName:       s.ClassName,
                StrokeDashArray: nil,
                FillColor:       s.DotColor,
                StrokeColor:     s.DotColor,
                StrokeWidth:     1.0,
        }
}</span>

// GetFillAndStrokeOptions returns the fill and stroke components.
func (s Style) GetFillAndStrokeOptions() Style <span class="cov8" title="1">{
        return Style{
                ClassName:       s.ClassName,
                StrokeDashArray: s.StrokeDashArray,
                FillColor:       s.FillColor,
                StrokeColor:     s.StrokeColor,
                StrokeWidth:     s.StrokeWidth,
        }
}</span>

// GetTextOptions returns just the text components of the style.
func (s Style) GetTextOptions() Style <span class="cov8" title="1">{
        return Style{
                ClassName:           s.ClassName,
                FontColor:           s.FontColor,
                FontSize:            s.FontSize,
                Font:                s.Font,
                TextHorizontalAlign: s.TextHorizontalAlign,
                TextVerticalAlign:   s.TextVerticalAlign,
                TextWrap:            s.TextWrap,
                TextLineSpacing:     s.TextLineSpacing,
                TextRotationDegrees: s.TextRotationDegrees,
        }
}</span>

// ShouldDrawStroke tells drawing functions if they should draw the stroke.
func (s Style) ShouldDrawStroke() bool <span class="cov8" title="1">{
        return !s.StrokeColor.IsZero() &amp;&amp; s.StrokeWidth &gt; 0
}</span>

// ShouldDrawDot tells drawing functions if they should draw the dot.
func (s Style) ShouldDrawDot() bool <span class="cov8" title="1">{
        return (!s.DotColor.IsZero() &amp;&amp; s.DotWidth &gt; 0) || s.DotColorProvider != nil || s.DotWidthProvider != nil
}</span>

// ShouldDrawFill tells drawing functions if they should draw the stroke.
func (s Style) ShouldDrawFill() bool <span class="cov8" title="1">{
        return !s.FillColor.IsZero()
}</span>
</pre>
		
		<pre class="file" id="file58" style="display: none">package chart

import (
        "strings"

        util "github.com/wcharczuk/go-chart/util"
)

// TextHorizontalAlign is an enum for the horizontal alignment options.
type TextHorizontalAlign int

const (
        // TextHorizontalAlignUnset is the unset state for text horizontal alignment.
        TextHorizontalAlignUnset TextHorizontalAlign = 0
        // TextHorizontalAlignLeft aligns a string horizontally so that it's left ligature starts at horizontal pixel 0.
        TextHorizontalAlignLeft TextHorizontalAlign = 1
        // TextHorizontalAlignCenter left aligns a string horizontally so that there are equal pixels
        // to the left and to the right of a string within a box.
        TextHorizontalAlignCenter TextHorizontalAlign = 2
        // TextHorizontalAlignRight right aligns a string horizontally so that the right ligature ends at the right-most pixel
        // of a box.
        TextHorizontalAlignRight TextHorizontalAlign = 3
)

// TextWrap is an enum for the word wrap options.
type TextWrap int

const (
        // TextWrapUnset is the unset state for text wrap options.
        TextWrapUnset TextWrap = 0
        // TextWrapNone will spill text past horizontal boundaries.
        TextWrapNone TextWrap = 1
        // TextWrapWord will split a string on words (i.e. spaces) to fit within a horizontal boundary.
        TextWrapWord TextWrap = 2
        // TextWrapRune will split a string on a rune (i.e. utf-8 codepage) to fit within a horizontal boundary.
        TextWrapRune TextWrap = 3
)

// TextVerticalAlign is an enum for the vertical alignment options.
type TextVerticalAlign int

const (
        // TextVerticalAlignUnset is the unset state for vertical alignment options.
        TextVerticalAlignUnset TextVerticalAlign = 0
        // TextVerticalAlignBaseline aligns text according to the "baseline" of the string, or where a normal ascender begins.
        TextVerticalAlignBaseline TextVerticalAlign = 1
        // TextVerticalAlignBottom aligns the text according to the lowers pixel of any of the ligatures (ex. g or q both extend below the baseline).
        TextVerticalAlignBottom TextVerticalAlign = 2
        // TextVerticalAlignMiddle aligns the text so that there is an equal amount of space above and below the top and bottom of the ligatures.
        TextVerticalAlignMiddle TextVerticalAlign = 3
        // TextVerticalAlignMiddleBaseline aligns the text veritcally so that there is an equal number of pixels above and below the baseline of the string.
        TextVerticalAlignMiddleBaseline TextVerticalAlign = 4
        // TextVerticalAlignTop alignts the text so that the top of the ligatures are at y-pixel 0 in the container.
        TextVerticalAlignTop TextVerticalAlign = 5
)

var (
        // Text contains utilities for text.
        Text = &amp;text{}
)

// TextStyle encapsulates text style options.
type TextStyle struct {
        HorizontalAlign TextHorizontalAlign
        VerticalAlign   TextVerticalAlign
        Wrap            TextWrap
}

type text struct{}

func (t text) WrapFit(r Renderer, value string, width int, style Style) []string <span class="cov8" title="1">{
        switch style.TextWrap </span>{
        case TextWrapRune:<span class="cov0" title="0">
                return t.WrapFitRune(r, value, width, style)</span>
        case TextWrapWord:<span class="cov8" title="1">
                return t.WrapFitWord(r, value, width, style)</span>
        }
        <span class="cov0" title="0">return []string{value}</span>
}

func (t text) WrapFitWord(r Renderer, value string, width int, style Style) []string <span class="cov8" title="1">{
        style.WriteToRenderer(r)

        var output []string
        var line string
        var word string

        var textBox Box

        for _, c := range value </span><span class="cov8" title="1">{
                if c == rune('\n') </span><span class="cov8" title="1">{ // commit the line to output
                        output = append(output, t.Trim(line+word))
                        line = ""
                        word = ""
                        continue</span>
                }

                <span class="cov8" title="1">textBox = r.MeasureText(line + word + string(c))

                if textBox.Width() &gt;= width </span><span class="cov8" title="1">{
                        output = append(output, t.Trim(line))
                        line = word
                        word = string(c)
                        continue</span>
                }

                <span class="cov8" title="1">if c == rune(' ') || c == rune('\t') </span><span class="cov8" title="1">{
                        line = line + word + string(c)
                        word = ""
                        continue</span>
                }
                <span class="cov8" title="1">word = word + string(c)</span>
        }

        <span class="cov8" title="1">return append(output, t.Trim(line+word))</span>
}

func (t text) WrapFitRune(r Renderer, value string, width int, style Style) []string <span class="cov8" title="1">{
        style.WriteToRenderer(r)

        var output []string
        var line string
        var textBox Box
        for _, c := range value </span><span class="cov8" title="1">{
                if c == rune('\n') </span><span class="cov0" title="0">{
                        output = append(output, line)
                        line = ""
                        continue</span>
                }

                <span class="cov8" title="1">textBox = r.MeasureText(line + string(c))

                if textBox.Width() &gt;= width </span><span class="cov8" title="1">{
                        output = append(output, line)
                        line = string(c)
                        continue</span>
                }
                <span class="cov8" title="1">line = line + string(c)</span>
        }
        <span class="cov8" title="1">return t.appendLast(output, line)</span>
}

func (t text) Trim(value string) string <span class="cov8" title="1">{
        return strings.Trim(value, " \t\n\r")
}</span>

func (t text) MeasureLines(r Renderer, lines []string, style Style) Box <span class="cov8" title="1">{
        style.WriteTextOptionsToRenderer(r)
        var output Box
        for index, line := range lines </span><span class="cov8" title="1">{
                lineBox := r.MeasureText(line)
                output.Right = util.Math.MaxInt(lineBox.Right, output.Right)
                output.Bottom += lineBox.Height()
                if index &lt; len(lines)-1 </span><span class="cov0" title="0">{
                        output.Bottom += +style.GetTextLineSpacing()
                }</span>
        }
        <span class="cov8" title="1">return output</span>
}

func (t text) appendLast(lines []string, text string) []string <span class="cov8" title="1">{
        if len(lines) == 0 </span><span class="cov0" title="0">{
                return []string{text}
        }</span>
        <span class="cov8" title="1">lastLine := lines[len(lines)-1]
        lines[len(lines)-1] = lastLine + text
        return lines</span>
}
</pre>
		
		<pre class="file" id="file59" style="display: none">package chart

import (
        "fmt"
        "math"
        "strings"

        util "github.com/wcharczuk/go-chart/util"
)

// TicksProvider is a type that provides ticks.
type TicksProvider interface {
        GetTicks(r Renderer, defaults Style, vf ValueFormatter) []Tick
}

// Tick represents a label on an axis.
type Tick struct {
        Value float64
        Label string
}

// Ticks is an array of ticks.
type Ticks []Tick

// Len returns the length of the ticks set.
func (t Ticks) Len() int <span class="cov0" title="0">{
        return len(t)
}</span>

// Swap swaps two elements.
func (t Ticks) Swap(i, j int) <span class="cov0" title="0">{
        t[i], t[j] = t[j], t[i]
}</span>

// Less returns if i's value is less than j's value.
func (t Ticks) Less(i, j int) bool <span class="cov0" title="0">{
        return t[i].Value &lt; t[j].Value
}</span>

// String returns a string representation of the set of ticks.
func (t Ticks) String() string <span class="cov0" title="0">{
        var values []string
        for i, tick := range t </span><span class="cov0" title="0">{
                values = append(values, fmt.Sprintf("[%d: %s]", i, tick.Label))
        }</span>
        <span class="cov0" title="0">return strings.Join(values, ", ")</span>
}

// GenerateContinuousTicks generates a set of ticks.
func GenerateContinuousTicks(r Renderer, ra Range, isVertical bool, style Style, vf ValueFormatter) []Tick <span class="cov8" title="1">{
        if vf == nil </span><span class="cov0" title="0">{
                vf = FloatValueFormatter
        }</span>

        <span class="cov8" title="1">var ticks []Tick
        min, max := ra.GetMin(), ra.GetMax()

        if ra.IsDescending() </span><span class="cov8" title="1">{
                ticks = append(ticks, Tick{
                        Value: max,
                        Label: vf(max),
                })
        }</span> else<span class="cov8" title="1"> {
                ticks = append(ticks, Tick{
                        Value: min,
                        Label: vf(min),
                })
        }</span>

        <span class="cov8" title="1">minLabel := vf(min)
        style.GetTextOptions().WriteToRenderer(r)
        labelBox := r.MeasureText(minLabel)

        var tickSize float64
        if isVertical </span><span class="cov8" title="1">{
                tickSize = float64(labelBox.Height() + DefaultMinimumTickVerticalSpacing)
        }</span> else<span class="cov8" title="1"> {
                tickSize = float64(labelBox.Width() + DefaultMinimumTickHorizontalSpacing)
        }</span>

        <span class="cov8" title="1">domain := float64(ra.GetDomain())
        domainRemainder := domain - (tickSize * 2)
        intermediateTickCount := int(math.Floor(float64(domainRemainder) / float64(tickSize)))

        rangeDelta := math.Abs(max - min)
        tickStep := rangeDelta / float64(intermediateTickCount)

        roundTo := util.Math.GetRoundToForDelta(rangeDelta) / 10
        intermediateTickCount = util.Math.MinInt(intermediateTickCount, DefaultTickCountSanityCheck)

        for x := 1; x &lt; intermediateTickCount; x++ </span><span class="cov8" title="1">{
                var tickValue float64
                if ra.IsDescending() </span><span class="cov8" title="1">{
                        tickValue = max - util.Math.RoundUp(tickStep*float64(x), roundTo)
                }</span> else<span class="cov8" title="1"> {
                        tickValue = min + util.Math.RoundUp(tickStep*float64(x), roundTo)
                }</span>
                <span class="cov8" title="1">ticks = append(ticks, Tick{
                        Value: tickValue,
                        Label: vf(tickValue),
                })</span>
        }

        <span class="cov8" title="1">if ra.IsDescending() </span><span class="cov8" title="1">{
                ticks = append(ticks, Tick{
                        Value: min,
                        Label: vf(min),
                })
        }</span> else<span class="cov8" title="1"> {
                ticks = append(ticks, Tick{
                        Value: max,
                        Label: vf(max),
                })
        }</span>

        <span class="cov8" title="1">return ticks</span>
}
</pre>
		
		<pre class="file" id="file60" style="display: none">package chart

import (
        "fmt"
        "time"

        util "github.com/wcharczuk/go-chart/util"
)

// Interface Assertions.
var (
        _ Series                 = (*TimeSeries)(nil)
        _ FirstValuesProvider    = (*TimeSeries)(nil)
        _ LastValuesProvider     = (*TimeSeries)(nil)
        _ ValueFormatterProvider = (*TimeSeries)(nil)
)

// TimeSeries is a line on a chart.
type TimeSeries struct {
        Name  string
        Style Style

        YAxis YAxisType

        XValues []time.Time
        YValues []float64
}

// GetName returns the name of the time series.
func (ts TimeSeries) GetName() string <span class="cov0" title="0">{
        return ts.Name
}</span>

// GetStyle returns the line style.
func (ts TimeSeries) GetStyle() Style <span class="cov8" title="1">{
        return ts.Style
}</span>

// Len returns the number of elements in the series.
func (ts TimeSeries) Len() int <span class="cov8" title="1">{
        return len(ts.XValues)
}</span>

// GetValues gets x, y values at a given index.
func (ts TimeSeries) GetValues(index int) (x, y float64) <span class="cov8" title="1">{
        x = util.Time.ToFloat64(ts.XValues[index])
        y = ts.YValues[index]
        return
}</span>

// GetFirstValues gets the first values.
func (ts TimeSeries) GetFirstValues() (x, y float64) <span class="cov0" title="0">{
        x = util.Time.ToFloat64(ts.XValues[0])
        y = ts.YValues[0]
        return
}</span>

// GetLastValues gets the last values.
func (ts TimeSeries) GetLastValues() (x, y float64) <span class="cov0" title="0">{
        x = util.Time.ToFloat64(ts.XValues[len(ts.XValues)-1])
        y = ts.YValues[len(ts.YValues)-1]
        return
}</span>

// GetValueFormatters returns value formatter defaults for the series.
func (ts TimeSeries) GetValueFormatters() (x, y ValueFormatter) <span class="cov8" title="1">{
        x = TimeValueFormatter
        y = FloatValueFormatter
        return
}</span>

// GetYAxis returns which YAxis the series draws on.
func (ts TimeSeries) GetYAxis() YAxisType <span class="cov8" title="1">{
        return ts.YAxis
}</span>

// Render renders the series.
func (ts TimeSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) <span class="cov8" title="1">{
        style := ts.Style.InheritFrom(defaults)
        Draw.LineSeries(r, canvasBox, xrange, yrange, style, ts)
}</span>

// Validate validates the series.
func (ts TimeSeries) Validate() error <span class="cov8" title="1">{
        if len(ts.XValues) == 0 </span><span class="cov8" title="1">{
                return fmt.Errorf("time series must have xvalues set")
        }</span>

        <span class="cov8" title="1">if len(ts.YValues) == 0 </span><span class="cov8" title="1">{
                return fmt.Errorf("time series must have yvalues set")
        }</span>
        <span class="cov8" title="1">return nil</span>
}
</pre>
		
		<pre class="file" id="file61" style="display: none">package util

import (
        "time"
)

const (
        // AllDaysMask is a bitmask of all the days of the week.
        AllDaysMask = 1&lt;&lt;uint(time.Sunday) | 1&lt;&lt;uint(time.Monday) | 1&lt;&lt;uint(time.Tuesday) | 1&lt;&lt;uint(time.Wednesday) | 1&lt;&lt;uint(time.Thursday) | 1&lt;&lt;uint(time.Friday) | 1&lt;&lt;uint(time.Saturday)
        // WeekDaysMask is a bitmask of all the weekdays of the week.
        WeekDaysMask = 1&lt;&lt;uint(time.Monday) | 1&lt;&lt;uint(time.Tuesday) | 1&lt;&lt;uint(time.Wednesday) | 1&lt;&lt;uint(time.Thursday) | 1&lt;&lt;uint(time.Friday)
        //WeekendDaysMask is a bitmask of the weekend days of the week.
        WeekendDaysMask = 1&lt;&lt;uint(time.Sunday) | 1&lt;&lt;uint(time.Saturday)
)

var (
        // DaysOfWeek are all the time.Weekday in an array for utility purposes.
        DaysOfWeek = []time.Weekday{
                time.Sunday,
                time.Monday,
                time.Tuesday,
                time.Wednesday,
                time.Thursday,
                time.Friday,
                time.Saturday,
        }

        // WeekDays are the business time.Weekday in an array.
        WeekDays = []time.Weekday{
                time.Monday,
                time.Tuesday,
                time.Wednesday,
                time.Thursday,
                time.Friday,
        }

        // WeekendDays are the weekend time.Weekday in an array.
        WeekendDays = []time.Weekday{
                time.Sunday,
                time.Saturday,
        }

        //Epoch is unix epoc saved for utility purposes.
        Epoch = time.Unix(0, 0)
)

// Date contains utility functions that operate on dates.
var Date date

type date struct{}

func (d date) MustEastern() *time.Location <span class="cov8" title="1">{
        if eastern, err := d.Eastern(); err != nil </span><span class="cov0" title="0">{
                panic(err)</span>
        } else<span class="cov8" title="1"> {
                return eastern
        }</span>
}

// Eastern returns the eastern timezone.
func (d date) Eastern() (*time.Location, error) <span class="cov8" title="1">{
        // Try POSIX
        est, err := time.LoadLocation("America/New_York")
        if err != nil </span><span class="cov0" title="0">{
                // Try Windows
                est, err = time.LoadLocation("EST")
                if err != nil </span><span class="cov0" title="0">{
                        return nil, err
                }</span>
        }
        <span class="cov8" title="1">return est, nil</span>
}

func (d date) MustPacific() *time.Location <span class="cov0" title="0">{
        if pst, err := d.Pacific(); err != nil </span><span class="cov0" title="0">{
                panic(err)</span>
        } else<span class="cov0" title="0"> {
                return pst
        }</span>
}

// Pacific returns the pacific timezone.
func (d date) Pacific() (*time.Location, error) <span class="cov0" title="0">{
        // Try POSIX
        pst, err := time.LoadLocation("America/Los_Angeles")
        if err != nil </span><span class="cov0" title="0">{
                // Try Windows
                pst, err = time.LoadLocation("PST")
                if err != nil </span><span class="cov0" title="0">{
                        return nil, err
                }</span>
        }
        <span class="cov0" title="0">return pst, nil</span>
}

// TimeUTC returns a new time.Time for the given clock components in UTC.
// It is meant to be used with the `OnDate` function.
func (d date) TimeUTC(hour, min, sec, nsec int) time.Time <span class="cov0" title="0">{
        return time.Date(0, 0, 0, hour, min, sec, nsec, time.UTC)
}</span>

// Time returns a new time.Time for the given clock components.
// It is meant to be used with the `OnDate` function.
func (d date) Time(hour, min, sec, nsec int, loc *time.Location) time.Time <span class="cov8" title="1">{
        return time.Date(0, 0, 0, hour, min, sec, nsec, loc)
}</span>

// DateUTC returns a new time.Time for the given date comonents at (noon) in UTC.
func (d date) DateUTC(year, month, day int) time.Time <span class="cov0" title="0">{
        return time.Date(year, time.Month(month), day, 12, 0, 0, 0, time.UTC)
}</span>

// DateUTC returns a new time.Time for the given date comonents at (noon) in a given location.
func (d date) Date(year, month, day int, loc *time.Location) time.Time <span class="cov8" title="1">{
        return time.Date(year, time.Month(month), day, 12, 0, 0, 0, loc)
}</span>

// OnDate returns the clock components of clock (hour,minute,second) on the date components of d.
func (d date) OnDate(clock, date time.Time) time.Time <span class="cov8" title="1">{
        tzAdjusted := date.In(clock.Location())
        return time.Date(tzAdjusted.Year(), tzAdjusted.Month(), tzAdjusted.Day(), clock.Hour(), clock.Minute(), clock.Second(), clock.Nanosecond(), clock.Location())
}</span>

// NoonOnDate is a shortcut for On(Time(12,0,0), cd) a.k.a. noon on a given date.
func (d date) NoonOnDate(cd time.Time) time.Time <span class="cov8" title="1">{
        return time.Date(cd.Year(), cd.Month(), cd.Day(), 12, 0, 0, 0, cd.Location())
}</span>

// IsWeekDay returns if the day is a monday-&gt;friday.
func (d date) IsWeekDay(day time.Weekday) bool <span class="cov0" title="0">{
        return !d.IsWeekendDay(day)
}</span>

// IsWeekendDay returns if the day is a monday-&gt;friday.
func (d date) IsWeekendDay(day time.Weekday) bool <span class="cov0" title="0">{
        return day == time.Saturday || day == time.Sunday
}</span>

// Before returns if a timestamp is strictly before another date (ignoring hours, minutes etc.)
func (d date) Before(before, reference time.Time) bool <span class="cov8" title="1">{
        tzAdjustedBefore := before.In(reference.Location())
        if tzAdjustedBefore.Year() &lt; reference.Year() </span><span class="cov8" title="1">{
                return true
        }</span>
        <span class="cov8" title="1">if tzAdjustedBefore.Month() &lt; reference.Month() </span><span class="cov8" title="1">{
                return true
        }</span>
        <span class="cov8" title="1">return tzAdjustedBefore.Year() == reference.Year() &amp;&amp; tzAdjustedBefore.Month() == reference.Month() &amp;&amp; tzAdjustedBefore.Day() &lt; reference.Day()</span>
}

const (
        _secondsPerHour = 60 * 60
        _secondsPerDay  = 60 * 60 * 24
)

// NextDay returns the timestamp advanced a day.
func (d date) NextDay(ts time.Time) time.Time <span class="cov0" title="0">{
        return ts.AddDate(0, 0, 1)
}</span>

// NextHour returns the next timestamp on the hour.
func (d date) NextHour(ts time.Time) time.Time <span class="cov8" title="1">{
        //advance a full hour ...
        advanced := ts.Add(time.Hour)
        minutes := time.Duration(advanced.Minute()) * time.Minute
        final := advanced.Add(-minutes)
        return time.Date(final.Year(), final.Month(), final.Day(), final.Hour(), 0, 0, 0, final.Location())
}</span>

// NextDayOfWeek returns the next instance of a given weekday after a given timestamp.
func (d date) NextDayOfWeek(after time.Time, dayOfWeek time.Weekday) time.Time <span class="cov8" title="1">{
        afterWeekday := after.Weekday()
        if afterWeekday == dayOfWeek </span><span class="cov8" title="1">{
                return after.AddDate(0, 0, 7)
        }</span>

        // 1 vs 5 ~ add 4 days
        <span class="cov8" title="1">if afterWeekday &lt; dayOfWeek </span><span class="cov8" title="1">{
                dayDelta := int(dayOfWeek - afterWeekday)
                return after.AddDate(0, 0, dayDelta)
        }</span>

        // 5 vs 1, add 7-(5-1) ~ 3 days
        <span class="cov8" title="1">dayDelta := 7 - int(afterWeekday-dayOfWeek)
        return after.AddDate(0, 0, dayDelta)</span>
}
</pre>
		
		<pre class="file" id="file62" style="display: none">package util

import (
        "bufio"
        "io"
        "os"
)

var (
        // File contains file utility functions
        File = fileUtil{}
)

type fileUtil struct{}

// ReadByLines reads a file and calls the handler for each line.
func (fu fileUtil) ReadByLines(filePath string, handler func(line string) error) error <span class="cov0" title="0">{
        var f *os.File
        var err error
        if f, err = os.Open(filePath); err == nil </span><span class="cov0" title="0">{
                defer f.Close()
                var line string
                scanner := bufio.NewScanner(f)
                for scanner.Scan() </span><span class="cov0" title="0">{
                        line = scanner.Text()
                        err = handler(line)
                        if err != nil </span><span class="cov0" title="0">{
                                return err
                        }</span>
                }
        }
        <span class="cov0" title="0">return err</span>

}

// ReadByChunks reads a file in `chunkSize` pieces, dispatched to the handler.
func (fu fileUtil) ReadByChunks(filePath string, chunkSize int, handler func(line []byte) error) error <span class="cov0" title="0">{
        var f *os.File
        var err error
        if f, err = os.Open(filePath); err == nil </span><span class="cov0" title="0">{
                defer f.Close()

                chunk := make([]byte, chunkSize)
                for </span><span class="cov0" title="0">{
                        readBytes, err := f.Read(chunk)
                        if err == io.EOF </span><span class="cov0" title="0">{
                                break</span>
                        }
                        <span class="cov0" title="0">readData := chunk[:readBytes]
                        err = handler(readData)
                        if err != nil </span><span class="cov0" title="0">{
                                return err
                        }</span>
                }
        }
        <span class="cov0" title="0">return err</span>
}
</pre>
		
		<pre class="file" id="file63" style="display: none">package util

import (
        "math"
)

const (
        _pi   = math.Pi
        _2pi  = 2 * math.Pi
        _3pi4 = (3 * math.Pi) / 4.0
        _4pi3 = (4 * math.Pi) / 3.0
        _3pi2 = (3 * math.Pi) / 2.0
        _5pi4 = (5 * math.Pi) / 4.0
        _7pi4 = (7 * math.Pi) / 4.0
        _pi2  = math.Pi / 2.0
        _pi4  = math.Pi / 4.0
        _d2r  = (math.Pi / 180.0)
        _r2d  = (180.0 / math.Pi)
)

var (
        // Math contains helper methods for common math operations.
        Math = &amp;mathUtil{}
)

type mathUtil struct{}

// Max returns the maximum value of a group of floats.
func (m mathUtil) Max(values ...float64) float64 <span class="cov0" title="0">{
        if len(values) == 0 </span><span class="cov0" title="0">{
                return 0
        }</span>
        <span class="cov0" title="0">max := values[0]
        for _, v := range values </span><span class="cov0" title="0">{
                if max &lt; v </span><span class="cov0" title="0">{
                        max = v
                }</span>
        }
        <span class="cov0" title="0">return max</span>
}

// MinAndMax returns both the min and max in one pass.
func (m mathUtil) MinAndMax(values ...float64) (min float64, max float64) <span class="cov8" title="1">{
        if len(values) == 0 </span><span class="cov8" title="1">{
                return
        }</span>
        <span class="cov8" title="1">min = values[0]
        max = values[0]
        for _, v := range values[1:] </span><span class="cov8" title="1">{
                if max &lt; v </span><span class="cov8" title="1">{
                        max = v
                }</span>
                <span class="cov8" title="1">if min &gt; v </span><span class="cov8" title="1">{
                        min = v
                }</span>
        }
        <span class="cov8" title="1">return</span>
}

// GetRoundToForDelta returns a `roundTo` value for a given delta.
func (m mathUtil) GetRoundToForDelta(delta float64) float64 <span class="cov8" title="1">{
        startingDeltaBound := math.Pow(10.0, 10.0)
        for cursor := startingDeltaBound; cursor &gt; 0; cursor /= 10.0 </span><span class="cov8" title="1">{
                if delta &gt; cursor </span><span class="cov8" title="1">{
                        return cursor / 10.0
                }</span>
        }

        <span class="cov0" title="0">return 0.0</span>
}

// RoundUp rounds up to a given roundTo value.
func (m mathUtil) RoundUp(value, roundTo float64) float64 <span class="cov8" title="1">{
        if roundTo &lt; 0.000000000000001 </span><span class="cov8" title="1">{
                return value
        }</span>
        <span class="cov8" title="1">d1 := math.Ceil(value / roundTo)
        return d1 * roundTo</span>
}

// RoundDown rounds down to a given roundTo value.
func (m mathUtil) RoundDown(value, roundTo float64) float64 <span class="cov8" title="1">{
        if roundTo &lt; 0.000000000000001 </span><span class="cov8" title="1">{
                return value
        }</span>
        <span class="cov8" title="1">d1 := math.Floor(value / roundTo)
        return d1 * roundTo</span>
}

// Normalize returns a set of numbers on the interval [0,1] for a given set of inputs.
// An example: 4,3,2,1 =&gt; 0.4, 0.3, 0.2, 0.1
// Caveat; the total may be &lt; 1.0; there are going to be issues with irrational numbers etc.
func (m mathUtil) Normalize(values ...float64) []float64 <span class="cov8" title="1">{
        var total float64
        for _, v := range values </span><span class="cov8" title="1">{
                total += v
        }</span>
        <span class="cov8" title="1">output := make([]float64, len(values))
        for x, v := range values </span><span class="cov8" title="1">{
                output[x] = m.RoundDown(v/total, 0.0001)
        }</span>
        <span class="cov8" title="1">return output</span>
}

// MinInt returns the minimum of a set of integers.
func (m mathUtil) MinInt(values ...int) int <span class="cov0" title="0">{
        min := math.MaxInt32
        for _, v := range values </span><span class="cov0" title="0">{
                if v &lt; min </span><span class="cov0" title="0">{
                        min = v
                }</span>
        }
        <span class="cov0" title="0">return min</span>
}

// MaxInt returns the maximum of a set of integers.
func (m mathUtil) MaxInt(values ...int) int <span class="cov0" title="0">{
        max := math.MinInt32
        for _, v := range values </span><span class="cov0" title="0">{
                if v &gt; max </span><span class="cov0" title="0">{
                        max = v
                }</span>
        }
        <span class="cov0" title="0">return max</span>
}

// AbsInt returns the absolute value of an integer.
func (m mathUtil) AbsInt(value int) int <span class="cov0" title="0">{
        if value &lt; 0 </span><span class="cov0" title="0">{
                return -value
        }</span>
        <span class="cov0" title="0">return value</span>
}

// AbsInt64 returns the absolute value of a long.
func (m mathUtil) AbsInt64(value int64) int64 <span class="cov0" title="0">{
        if value &lt; 0 </span><span class="cov0" title="0">{
                return -value
        }</span>
        <span class="cov0" title="0">return value</span>
}

// Mean returns the mean of a set of values
func (m mathUtil) Mean(values ...float64) float64 <span class="cov0" title="0">{
        return m.Sum(values...) / float64(len(values))
}</span>

// MeanInt returns the mean of a set of integer values.
func (m mathUtil) MeanInt(values ...int) int <span class="cov0" title="0">{
        return m.SumInt(values...) / len(values)
}</span>

// Sum sums a set of values.
func (m mathUtil) Sum(values ...float64) float64 <span class="cov0" title="0">{
        var total float64
        for _, v := range values </span><span class="cov0" title="0">{
                total += v
        }</span>
        <span class="cov0" title="0">return total</span>
}

// SumInt sums a set of values.
func (m mathUtil) SumInt(values ...int) int <span class="cov0" title="0">{
        var total int
        for _, v := range values </span><span class="cov0" title="0">{
                total += v
        }</span>
        <span class="cov0" title="0">return total</span>
}

// PercentDifference computes the percentage difference between two values.
// The formula is (v2-v1)/v1.
func (m mathUtil) PercentDifference(v1, v2 float64) float64 <span class="cov8" title="1">{
        if v1 == 0 </span><span class="cov0" title="0">{
                return 0
        }</span>
        <span class="cov8" title="1">return (v2 - v1) / v1</span>
}

// DegreesToRadians returns degrees as radians.
func (m mathUtil) DegreesToRadians(degrees float64) float64 <span class="cov8" title="1">{
        return degrees * _d2r
}</span>

// RadiansToDegrees translates a radian value to a degree value.
func (m mathUtil) RadiansToDegrees(value float64) float64 <span class="cov8" title="1">{
        return math.Mod(value, _2pi) * _r2d
}</span>

// PercentToRadians converts a normalized value (0,1) to radians.
func (m mathUtil) PercentToRadians(pct float64) float64 <span class="cov8" title="1">{
        return m.DegreesToRadians(360.0 * pct)
}</span>

// RadianAdd adds a delta to a base in radians.
func (m mathUtil) RadianAdd(base, delta float64) float64 <span class="cov8" title="1">{
        value := base + delta
        if value &gt; _2pi </span><span class="cov8" title="1">{
                return math.Mod(value, _2pi)
        }</span> else<span class="cov8" title="1"> if value &lt; 0 </span><span class="cov8" title="1">{
                return math.Mod(_2pi+value, _2pi)
        }</span>
        <span class="cov8" title="1">return value</span>
}

// DegreesAdd adds a delta to a base in radians.
func (m mathUtil) DegreesAdd(baseDegrees, deltaDegrees float64) float64 <span class="cov0" title="0">{
        value := baseDegrees + deltaDegrees
        if value &gt; _2pi </span><span class="cov0" title="0">{
                return math.Mod(value, 360.0)
        }</span> else<span class="cov0" title="0"> if value &lt; 0 </span><span class="cov0" title="0">{
                return math.Mod(360.0+value, 360.0)
        }</span>
        <span class="cov0" title="0">return value</span>
}

// DegreesToCompass returns the degree value in compass / clock orientation.
func (m mathUtil) DegreesToCompass(deg float64) float64 <span class="cov0" title="0">{
        return m.DegreesAdd(deg, -90.0)
}</span>

// CirclePoint returns the absolute position of a circle diameter point given
// by the radius and the theta.
func (m mathUtil) CirclePoint(cx, cy int, radius, thetaRadians float64) (x, y int) <span class="cov0" title="0">{
        x = cx + int(radius*math.Sin(thetaRadians))
        y = cy - int(radius*math.Cos(thetaRadians))
        return
}</span>

func (m mathUtil) RotateCoordinate(cx, cy, x, y int, thetaRadians float64) (rx, ry int) <span class="cov8" title="1">{
        tempX, tempY := float64(x-cx), float64(y-cy)
        rotatedX := tempX*math.Cos(thetaRadians) - tempY*math.Sin(thetaRadians)
        rotatedY := tempX*math.Sin(thetaRadians) + tempY*math.Cos(thetaRadians)
        rx = int(rotatedX) + cx
        ry = int(rotatedY) + cy
        return
}</span>
</pre>
		
		<pre class="file" id="file64" style="display: none">package util

import "time"

var (
        // Time contains time utility functions.
        Time = timeUtil{}
)

type timeUtil struct{}

// Millis returns the duration as milliseconds.
func (tu timeUtil) Millis(d time.Duration) float64 <span class="cov0" title="0">{
        return float64(d) / float64(time.Millisecond)
}</span>

// TimeToFloat64 returns a float64 representation of a time.
func (tu timeUtil) ToFloat64(t time.Time) float64 <span class="cov0" title="0">{
        return float64(t.UnixNano())
}</span>

// Float64ToTime returns a time from a float64.
func (tu timeUtil) FromFloat64(tf float64) time.Time <span class="cov0" title="0">{
        return time.Unix(0, int64(tf))
}</span>

func (tu timeUtil) DiffDays(t1, t2 time.Time) (days int) <span class="cov8" title="1">{
        t1n := t1.Unix()
        t2n := t2.Unix()
        var diff int64
        if t1n &gt; t2n </span><span class="cov0" title="0">{
                diff = t1n - t2n //yields seconds
        }</span> else<span class="cov8" title="1"> {
                diff = t2n - t1n //yields seconds
        }</span>
        <span class="cov8" title="1">return int(diff / (_secondsPerDay))</span>
}

func (tu timeUtil) DiffHours(t1, t2 time.Time) (hours int) <span class="cov8" title="1">{
        t1n := t1.Unix()
        t2n := t2.Unix()
        var diff int64
        if t1n &gt; t2n </span><span class="cov0" title="0">{
                diff = t1n - t2n
        }</span> else<span class="cov8" title="1"> {
                diff = t2n - t1n
        }</span>
        <span class="cov8" title="1">return int(diff / (_secondsPerHour))</span>
}

// Start returns the earliest (min) time in a list of times.
func (tu timeUtil) Start(times ...time.Time) time.Time <span class="cov0" title="0">{
        if len(times) == 0 </span><span class="cov0" title="0">{
                return time.Time{}
        }</span>

        <span class="cov0" title="0">start := times[0]
        for _, t := range times[1:] </span><span class="cov0" title="0">{
                if t.Before(start) </span><span class="cov0" title="0">{
                        start = t
                }</span>
        }
        <span class="cov0" title="0">return start</span>
}

// Start returns the earliest (min) time in a list of times.
func (tu timeUtil) End(times ...time.Time) time.Time <span class="cov0" title="0">{
        if len(times) == 0 </span><span class="cov0" title="0">{
                return time.Time{}
        }</span>

        <span class="cov0" title="0">end := times[0]
        for _, t := range times[1:] </span><span class="cov0" title="0">{
                if t.After(end) </span><span class="cov0" title="0">{
                        end = t
                }</span>
        }
        <span class="cov0" title="0">return end</span>
}

// StartAndEnd returns the start and end of a given set of time in one pass.
func (tu timeUtil) StartAndEnd(values ...time.Time) (start time.Time, end time.Time) <span class="cov8" title="1">{
        if len(values) == 0 </span><span class="cov8" title="1">{
                return
        }</span>

        <span class="cov8" title="1">start = values[0]
        end = values[0]

        for _, v := range values[1:] </span><span class="cov8" title="1">{
                if end.Before(v) </span><span class="cov8" title="1">{
                        end = v
                }</span>
                <span class="cov8" title="1">if start.After(v) </span><span class="cov8" title="1">{
                        start = v
                }</span>
        }
        <span class="cov8" title="1">return</span>
}
</pre>
		
		<pre class="file" id="file65" style="display: none">package chart

import util "github.com/wcharczuk/go-chart/util"

// Value is a chart value.
type Value struct {
        Style Style
        Label string
        Value float64
}

// Values is an array of Value.
type Values []Value

// Values returns the values.
func (vs Values) Values() []float64 <span class="cov8" title="1">{
        values := make([]float64, len(vs))
        for index, v := range vs </span><span class="cov8" title="1">{
                values[index] = v.Value
        }</span>
        <span class="cov8" title="1">return values</span>
}

// ValuesNormalized returns normalized values.
func (vs Values) ValuesNormalized() []float64 <span class="cov8" title="1">{
        return util.Math.Normalize(vs.Values()...)
}</span>

// Normalize returns the values normalized.
func (vs Values) Normalize() []Value <span class="cov8" title="1">{
        var output []Value
        var total float64

        for _, v := range vs </span><span class="cov8" title="1">{
                total += v.Value
        }</span>

        <span class="cov8" title="1">for _, v := range vs </span><span class="cov8" title="1">{
                if v.Value &gt; 0 </span><span class="cov8" title="1">{
                        output = append(output, Value{
                                Style: v.Style,
                                Label: v.Label,
                                Value: util.Math.RoundDown(v.Value/total, 0.0001),
                        })
                }</span>
        }
        <span class="cov8" title="1">return output</span>
}

// Value2 is a two axis value.
type Value2 struct {
        Style          Style
        Label          string
        XValue, YValue float64
}
</pre>
		
		<pre class="file" id="file66" style="display: none">package chart

import (
        "fmt"
        "strconv"
        "time"
)

// ValueFormatter is a function that takes a value and produces a string.
type ValueFormatter func(v interface{}) string

// TimeValueFormatter is a ValueFormatter for timestamps.
func TimeValueFormatter(v interface{}) string <span class="cov8" title="1">{
        return formatTime(v, DefaultDateFormat)
}</span>

// TimeHourValueFormatter is a ValueFormatter for timestamps.
func TimeHourValueFormatter(v interface{}) string <span class="cov0" title="0">{
        return formatTime(v, DefaultDateHourFormat)
}</span>

// TimeMinuteValueFormatter is a ValueFormatter for timestamps.
func TimeMinuteValueFormatter(v interface{}) string <span class="cov0" title="0">{
        return formatTime(v, DefaultDateMinuteFormat)
}</span>

// TimeDateValueFormatter is a ValueFormatter for timestamps.
func TimeDateValueFormatter(v interface{}) string <span class="cov0" title="0">{
        return formatTime(v, "2006-01-02")
}</span>

// TimeValueFormatterWithFormat returns a time formatter with a given format.
func TimeValueFormatterWithFormat(format string) ValueFormatter <span class="cov0" title="0">{
        return func(v interface{}) string </span><span class="cov0" title="0">{
                return formatTime(v, format)
        }</span>
}

// TimeValueFormatterWithFormat is a ValueFormatter for timestamps with a given format.
func formatTime(v interface{}, dateFormat string) string <span class="cov8" title="1">{
        if typed, isTyped := v.(time.Time); isTyped </span><span class="cov8" title="1">{
                return typed.Format(dateFormat)
        }</span>
        <span class="cov8" title="1">if typed, isTyped := v.(int64); isTyped </span><span class="cov0" title="0">{
                return time.Unix(0, typed).Format(dateFormat)
        }</span>
        <span class="cov8" title="1">if typed, isTyped := v.(float64); isTyped </span><span class="cov8" title="1">{
                return time.Unix(0, int64(typed)).Format(dateFormat)
        }</span>
        <span class="cov0" title="0">return ""</span>
}

// IntValueFormatter is a ValueFormatter for float64.
func IntValueFormatter(v interface{}) string <span class="cov0" title="0">{
        switch v.(type) </span>{
        case int:<span class="cov0" title="0">
                return strconv.Itoa(v.(int))</span>
        case int64:<span class="cov0" title="0">
                return strconv.FormatInt(v.(int64), 10)</span>
        case float32:<span class="cov0" title="0">
                return strconv.FormatInt(int64(v.(float32)), 10)</span>
        case float64:<span class="cov0" title="0">
                return strconv.FormatInt(int64(v.(float64)), 10)</span>
        default:<span class="cov0" title="0">
                return ""</span>
        }
}

// FloatValueFormatter is a ValueFormatter for float64.
func FloatValueFormatter(v interface{}) string <span class="cov8" title="1">{
        return FloatValueFormatterWithFormat(v, DefaultFloatFormat)
}</span>

// PercentValueFormatter is a formatter for percent values.
// NOTE: it normalizes the values, i.e. multiplies by 100.0.
func PercentValueFormatter(v interface{}) string <span class="cov0" title="0">{
        if typed, isTyped := v.(float64); isTyped </span><span class="cov0" title="0">{
                return FloatValueFormatterWithFormat(typed*100.0, DefaultPercentValueFormat)
        }</span>
        <span class="cov0" title="0">return ""</span>
}

// FloatValueFormatterWithFormat is a ValueFormatter for float64 with a given format.
func FloatValueFormatterWithFormat(v interface{}, floatFormat string) string <span class="cov8" title="1">{
        if typed, isTyped := v.(int); isTyped </span><span class="cov8" title="1">{
                return fmt.Sprintf(floatFormat, float64(typed))
        }</span>
        <span class="cov8" title="1">if typed, isTyped := v.(int64); isTyped </span><span class="cov8" title="1">{
                return fmt.Sprintf(floatFormat, float64(typed))
        }</span>
        <span class="cov8" title="1">if typed, isTyped := v.(float32); isTyped </span><span class="cov8" title="1">{
                return fmt.Sprintf(floatFormat, typed)
        }</span>
        <span class="cov8" title="1">if typed, isTyped := v.(float64); isTyped </span><span class="cov8" title="1">{
                return fmt.Sprintf(floatFormat, typed)
        }</span>
        <span class="cov0" title="0">return ""</span>
}
</pre>
		
		<pre class="file" id="file67" style="display: none">package chart

import (
        "bytes"
        "fmt"
        "io"
        "math"
        "strings"

        "golang.org/x/image/font"

        "github.com/golang/freetype/truetype"
        "github.com/wcharczuk/go-chart/drawing"
        "github.com/wcharczuk/go-chart/util"
)

// SVG returns a new png/raster renderer.
func SVG(width, height int) (Renderer, error) <span class="cov8" title="1">{
        buffer := bytes.NewBuffer([]byte{})
        canvas := newCanvas(buffer)
        canvas.Start(width, height)
        return &amp;vectorRenderer{
                b:   buffer,
                c:   canvas,
                s:   &amp;Style{},
                p:   []string{},
                dpi: DefaultDPI,
        }, nil
}</span>

// vectorRenderer renders chart commands to a bitmap.
type vectorRenderer struct {
        dpi float64
        b   *bytes.Buffer
        c   *canvas
        s   *Style
        p   []string
        fc  *font.Drawer
}

func (vr *vectorRenderer) ResetStyle() <span class="cov0" title="0">{
        vr.s = &amp;Style{Font: vr.s.Font}
        vr.fc = nil
}</span>

// GetDPI returns the dpi.
func (vr *vectorRenderer) GetDPI() float64 <span class="cov0" title="0">{
        return vr.dpi
}</span>

// SetDPI implements the interface method.
func (vr *vectorRenderer) SetDPI(dpi float64) <span class="cov8" title="1">{
        vr.dpi = dpi
        vr.c.dpi = dpi
}</span>

// SetClassName implements the interface method.
func (vr *vectorRenderer) SetClassName(classname string) <span class="cov0" title="0">{
        vr.s.ClassName = classname
}</span>

// SetStrokeColor implements the interface method.
func (vr *vectorRenderer) SetStrokeColor(c drawing.Color) <span class="cov0" title="0">{
        vr.s.StrokeColor = c
}</span>

// SetFillColor implements the interface method.
func (vr *vectorRenderer) SetFillColor(c drawing.Color) <span class="cov0" title="0">{
        vr.s.FillColor = c
}</span>

// SetLineWidth implements the interface method.
func (vr *vectorRenderer) SetStrokeWidth(width float64) <span class="cov0" title="0">{
        vr.s.StrokeWidth = width
}</span>

// StrokeDashArray sets the stroke dash array.
func (vr *vectorRenderer) SetStrokeDashArray(dashArray []float64) <span class="cov0" title="0">{
        vr.s.StrokeDashArray = dashArray
}</span>

// MoveTo implements the interface method.
func (vr *vectorRenderer) MoveTo(x, y int) <span class="cov8" title="1">{
        vr.p = append(vr.p, fmt.Sprintf("M %d %d", x, y))
}</span>

// LineTo implements the interface method.
func (vr *vectorRenderer) LineTo(x, y int) <span class="cov8" title="1">{
        vr.p = append(vr.p, fmt.Sprintf("L %d %d", x, y))
}</span>

// QuadCurveTo draws a quad curve.
func (vr *vectorRenderer) QuadCurveTo(cx, cy, x, y int) <span class="cov0" title="0">{
        vr.p = append(vr.p, fmt.Sprintf("Q%d,%d %d,%d", cx, cy, x, y))
}</span>

func (vr *vectorRenderer) ArcTo(cx, cy int, rx, ry, startAngle, delta float64) <span class="cov0" title="0">{
        startAngle = util.Math.RadianAdd(startAngle, _pi2)
        endAngle := util.Math.RadianAdd(startAngle, delta)

        startx := cx + int(rx*math.Sin(startAngle))
        starty := cy - int(ry*math.Cos(startAngle))

        if len(vr.p) &gt; 0 </span><span class="cov0" title="0">{
                vr.p = append(vr.p, fmt.Sprintf("L %d %d", startx, starty))
        }</span> else<span class="cov0" title="0"> {
                vr.p = append(vr.p, fmt.Sprintf("M %d %d", startx, starty))
        }</span>

        <span class="cov0" title="0">endx := cx + int(rx*math.Sin(endAngle))
        endy := cy - int(ry*math.Cos(endAngle))

        dd := util.Math.RadiansToDegrees(delta)

        largeArcFlag := 0
        if delta &gt; _pi </span><span class="cov0" title="0">{
                largeArcFlag = 1
        }</span>

        <span class="cov0" title="0">vr.p = append(vr.p, fmt.Sprintf("A %d %d %0.2f %d 1 %d %d", int(rx), int(ry), dd, largeArcFlag, endx, endy))</span>
}

// Close closes a shape.
func (vr *vectorRenderer) Close() <span class="cov8" title="1">{
        vr.p = append(vr.p, fmt.Sprintf("Z"))
}</span>

// Stroke draws the path with no fill.
func (vr *vectorRenderer) Stroke() <span class="cov0" title="0">{
        vr.drawPath(vr.s.GetStrokeOptions())
}</span>

// Fill draws the path with no stroke.
func (vr *vectorRenderer) Fill() <span class="cov0" title="0">{
        vr.drawPath(vr.s.GetFillOptions())
}</span>

// FillStroke draws the path with both fill and stroke.
func (vr *vectorRenderer) FillStroke() <span class="cov8" title="1">{
        vr.drawPath(vr.s.GetFillAndStrokeOptions())
}</span>

// drawPath draws a path.
func (vr *vectorRenderer) drawPath(s Style) <span class="cov8" title="1">{
        vr.c.Path(strings.Join(vr.p, "\n"), vr.s.GetFillAndStrokeOptions())
        vr.p = []string{} // clear the path
}</span>

// Circle implements the interface method.
func (vr *vectorRenderer) Circle(radius float64, x, y int) <span class="cov0" title="0">{
        vr.c.Circle(x, y, int(radius), vr.s.GetFillAndStrokeOptions())
}</span>

// SetFont implements the interface method.
func (vr *vectorRenderer) SetFont(f *truetype.Font) <span class="cov8" title="1">{
        vr.s.Font = f
}</span>

// SetFontColor implements the interface method.
func (vr *vectorRenderer) SetFontColor(c drawing.Color) <span class="cov0" title="0">{
        vr.s.FontColor = c
}</span>

// SetFontSize implements the interface method.
func (vr *vectorRenderer) SetFontSize(size float64) <span class="cov8" title="1">{
        vr.s.FontSize = size
}</span>

// Text draws a text blob.
func (vr *vectorRenderer) Text(body string, x, y int) <span class="cov0" title="0">{
        vr.c.Text(x, y, body, vr.s.GetTextOptions())
}</span>

// MeasureText uses the truetype font drawer to measure the width of text.
func (vr *vectorRenderer) MeasureText(body string) (box Box) <span class="cov8" title="1">{
        if vr.s.GetFont() != nil </span><span class="cov8" title="1">{
                vr.fc = &amp;font.Drawer{
                        Face: truetype.NewFace(vr.s.GetFont(), &amp;truetype.Options{
                                DPI:  vr.dpi,
                                Size: vr.s.FontSize,
                        }),
                }
                w := vr.fc.MeasureString(body).Ceil()

                box.Right = w
                box.Bottom = int(drawing.PointsToPixels(vr.dpi, vr.s.FontSize))
                if vr.c.textTheta == nil </span><span class="cov8" title="1">{
                        return
                }</span>
                <span class="cov0" title="0">box = box.Corners().Rotate(util.Math.RadiansToDegrees(*vr.c.textTheta)).Box()</span>
        }
        <span class="cov0" title="0">return</span>
}

// SetTextRotation sets the text rotation.
func (vr *vectorRenderer) SetTextRotation(radians float64) <span class="cov0" title="0">{
        vr.c.textTheta = &amp;radians
}</span>

// ClearTextRotation clears the text rotation.
func (vr *vectorRenderer) ClearTextRotation() <span class="cov0" title="0">{
        vr.c.textTheta = nil
}</span>

// Save saves the renderer's contents to a writer.
func (vr *vectorRenderer) Save(w io.Writer) error <span class="cov8" title="1">{
        vr.c.End()
        _, err := w.Write(vr.b.Bytes())
        return err
}</span>

func newCanvas(w io.Writer) *canvas <span class="cov8" title="1">{
        return &amp;canvas{
                w:   w,
                dpi: DefaultDPI,
        }
}</span>

type canvas struct {
        w         io.Writer
        dpi       float64
        textTheta *float64
        width     int
        height    int
}

func (c *canvas) Start(width, height int) <span class="cov8" title="1">{
        c.width = width
        c.height = height
        c.w.Write([]byte(fmt.Sprintf(`&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="%d" height="%d"&gt;\n`, c.width, c.height)))
}</span>

func (c *canvas) Path(d string, style Style) <span class="cov8" title="1">{
        var strokeDashArrayProperty string
        if len(style.StrokeDashArray) &gt; 0 </span><span class="cov0" title="0">{
                strokeDashArrayProperty = c.getStrokeDashArray(style)
        }</span>
        <span class="cov8" title="1">c.w.Write([]byte(fmt.Sprintf(`&lt;path %s d="%s" %s/&gt;`, strokeDashArrayProperty, d, c.styleAsSVG(style))))</span>
}

func (c *canvas) Text(x, y int, body string, style Style) <span class="cov0" title="0">{
        if c.textTheta == nil </span><span class="cov0" title="0">{
                c.w.Write([]byte(fmt.Sprintf(`&lt;text x="%d" y="%d" %s&gt;%s&lt;/text&gt;`, x, y, c.styleAsSVG(style), body)))
        }</span> else<span class="cov0" title="0"> {
                transform := fmt.Sprintf(` transform="rotate(%0.2f,%d,%d)"`, util.Math.RadiansToDegrees(*c.textTheta), x, y)
                c.w.Write([]byte(fmt.Sprintf(`&lt;text x="%d" y="%d" %s%s&gt;%s&lt;/text&gt;`, x, y, c.styleAsSVG(style), transform, body)))
        }</span>
}

func (c *canvas) Circle(x, y, r int, style Style) <span class="cov0" title="0">{
        c.w.Write([]byte(fmt.Sprintf(`&lt;circle cx="%d" cy="%d" r="%d" %s/&gt;`, x, y, r, c.styleAsSVG(style))))
}</span>

func (c *canvas) End() <span class="cov8" title="1">{
        c.w.Write([]byte("&lt;/svg&gt;"))
}</span>

// getStrokeDashArray returns the stroke-dasharray property of a style.
func (c *canvas) getStrokeDashArray(s Style) string <span class="cov0" title="0">{
        if len(s.StrokeDashArray) &gt; 0 </span><span class="cov0" title="0">{
                var values []string
                for _, v := range s.StrokeDashArray </span><span class="cov0" title="0">{
                        values = append(values, fmt.Sprintf("%0.1f", v))
                }</span>
                <span class="cov0" title="0">return "stroke-dasharray=\"" + strings.Join(values, ", ") + "\""</span>
        }
        <span class="cov0" title="0">return ""</span>
}

// GetFontFace returns the font face for the style.
func (c *canvas) getFontFace(s Style) string <span class="cov8" title="1">{
        family := "sans-serif"
        if s.GetFont() != nil </span><span class="cov8" title="1">{
                name := s.GetFont().Name(truetype.NameIDFontFamily)
                if len(name) != 0 </span><span class="cov8" title="1">{
                        family = fmt.Sprintf(`'%s',%s`, name, family)
                }</span>
        }
        <span class="cov8" title="1">return fmt.Sprintf("font-family:%s", family)</span>
}

// styleAsSVG returns the style as a svg style or class string.
func (c *canvas) styleAsSVG(s Style) string <span class="cov8" title="1">{
        if s.ClassName != "" </span><span class="cov8" title="1">{
                return fmt.Sprintf("class=\"%s\"", s.ClassName)
        }</span>
        <span class="cov8" title="1">sw := s.StrokeWidth
        sc := s.StrokeColor
        fc := s.FillColor
        fs := s.FontSize
        fnc := s.FontColor

        var pieces []string

        if sw != 0 </span><span class="cov8" title="1">{
                pieces = append(pieces, "stroke-width:"+fmt.Sprintf("%d", int(sw)))
        }</span> else<span class="cov8" title="1"> {
                pieces = append(pieces, "stroke-width:0")
        }</span>

        <span class="cov8" title="1">if !sc.IsZero() </span><span class="cov8" title="1">{
                pieces = append(pieces, "stroke:"+sc.String())
        }</span> else<span class="cov8" title="1"> {
                pieces = append(pieces, "stroke:none")
        }</span>

        <span class="cov8" title="1">if !fnc.IsZero() </span><span class="cov8" title="1">{
                pieces = append(pieces, "fill:"+fnc.String())
        }</span> else<span class="cov8" title="1"> if !fc.IsZero() </span><span class="cov0" title="0">{
                pieces = append(pieces, "fill:"+fc.String())
        }</span> else<span class="cov8" title="1"> {
                pieces = append(pieces, "fill:none")
        }</span>

        <span class="cov8" title="1">if fs != 0 </span><span class="cov0" title="0">{
                pieces = append(pieces, "font-size:"+fmt.Sprintf("%.1fpx", drawing.PointsToPixels(c.dpi, fs)))
        }</span>

        <span class="cov8" title="1">if s.Font != nil </span><span class="cov8" title="1">{
                pieces = append(pieces, c.getFontFace(s))
        }</span>
        <span class="cov8" title="1">return fmt.Sprintf("style=\"%s\"", strings.Join(pieces, ";"))</span>
}
</pre>
		
		<pre class="file" id="file68" style="display: none">package chart

import "github.com/wcharczuk/go-chart/drawing"

var viridisColors = [256]drawing.Color{
        drawing.Color{R: 0x44, G: 0x1, B: 0x54, A: 0xff},
        drawing.Color{R: 0x44, G: 0x2, B: 0x55, A: 0xff},
        drawing.Color{R: 0x45, G: 0x3, B: 0x57, A: 0xff},
        drawing.Color{R: 0x45, G: 0x5, B: 0x58, A: 0xff},
        drawing.Color{R: 0x45, G: 0x6, B: 0x5a, A: 0xff},
        drawing.Color{R: 0x46, G: 0x8, B: 0x5b, A: 0xff},
        drawing.Color{R: 0x46, G: 0x9, B: 0x5d, A: 0xff},
        drawing.Color{R: 0x46, G: 0xb, B: 0x5e, A: 0xff},
        drawing.Color{R: 0x46, G: 0xc, B: 0x60, A: 0xff},
        drawing.Color{R: 0x47, G: 0xe, B: 0x61, A: 0xff},
        drawing.Color{R: 0x47, G: 0xf, B: 0x62, A: 0xff},
        drawing.Color{R: 0x47, G: 0x11, B: 0x64, A: 0xff},
        drawing.Color{R: 0x47, G: 0x12, B: 0x65, A: 0xff},
        drawing.Color{R: 0x47, G: 0x14, B: 0x66, A: 0xff},
        drawing.Color{R: 0x48, G: 0x15, B: 0x68, A: 0xff},
        drawing.Color{R: 0x48, G: 0x16, B: 0x69, A: 0xff},
        drawing.Color{R: 0x48, G: 0x18, B: 0x6a, A: 0xff},
        drawing.Color{R: 0x48, G: 0x19, B: 0x6c, A: 0xff},
        drawing.Color{R: 0x48, G: 0x1a, B: 0x6d, A: 0xff},
        drawing.Color{R: 0x48, G: 0x1c, B: 0x6e, A: 0xff},
        drawing.Color{R: 0x48, G: 0x1d, B: 0x6f, A: 0xff},
        drawing.Color{R: 0x48, G: 0x1e, B: 0x70, A: 0xff},
        drawing.Color{R: 0x48, G: 0x20, B: 0x71, A: 0xff},
        drawing.Color{R: 0x48, G: 0x21, B: 0x73, A: 0xff},
        drawing.Color{R: 0x48, G: 0x22, B: 0x74, A: 0xff},
        drawing.Color{R: 0x48, G: 0x24, B: 0x75, A: 0xff},
        drawing.Color{R: 0x48, G: 0x25, B: 0x76, A: 0xff},
        drawing.Color{R: 0x48, G: 0x26, B: 0x77, A: 0xff},
        drawing.Color{R: 0x48, G: 0x27, B: 0x78, A: 0xff},
        drawing.Color{R: 0x47, G: 0x29, B: 0x79, A: 0xff},
        drawing.Color{R: 0x47, G: 0x2a, B: 0x79, A: 0xff},
        drawing.Color{R: 0x47, G: 0x2b, B: 0x7a, A: 0xff},
        drawing.Color{R: 0x47, G: 0x2c, B: 0x7b, A: 0xff},
        drawing.Color{R: 0x47, G: 0x2e, B: 0x7c, A: 0xff},
        drawing.Color{R: 0x46, G: 0x2f, B: 0x7d, A: 0xff},
        drawing.Color{R: 0x46, G: 0x30, B: 0x7e, A: 0xff},
        drawing.Color{R: 0x46, G: 0x31, B: 0x7e, A: 0xff},
        drawing.Color{R: 0x46, G: 0x33, B: 0x7f, A: 0xff},
        drawing.Color{R: 0x45, G: 0x34, B: 0x80, A: 0xff},
        drawing.Color{R: 0x45, G: 0x35, B: 0x81, A: 0xff},
        drawing.Color{R: 0x45, G: 0x36, B: 0x81, A: 0xff},
        drawing.Color{R: 0x44, G: 0x38, B: 0x82, A: 0xff},
        drawing.Color{R: 0x44, G: 0x39, B: 0x83, A: 0xff},
        drawing.Color{R: 0x44, G: 0x3a, B: 0x83, A: 0xff},
        drawing.Color{R: 0x43, G: 0x3b, B: 0x84, A: 0xff},
        drawing.Color{R: 0x43, G: 0x3c, B: 0x84, A: 0xff},
        drawing.Color{R: 0x43, G: 0x3e, B: 0x85, A: 0xff},
        drawing.Color{R: 0x42, G: 0x3f, B: 0x85, A: 0xff},
        drawing.Color{R: 0x42, G: 0x40, B: 0x86, A: 0xff},
        drawing.Color{R: 0x41, G: 0x41, B: 0x86, A: 0xff},
        drawing.Color{R: 0x41, G: 0x42, B: 0x87, A: 0xff},
        drawing.Color{R: 0x41, G: 0x43, B: 0x87, A: 0xff},
        drawing.Color{R: 0x40, G: 0x45, B: 0x88, A: 0xff},
        drawing.Color{R: 0x40, G: 0x46, B: 0x88, A: 0xff},
        drawing.Color{R: 0x3f, G: 0x47, B: 0x88, A: 0xff},
        drawing.Color{R: 0x3f, G: 0x48, B: 0x89, A: 0xff},
        drawing.Color{R: 0x3e, G: 0x49, B: 0x89, A: 0xff},
        drawing.Color{R: 0x3e, G: 0x4a, B: 0x89, A: 0xff},
        drawing.Color{R: 0x3d, G: 0x4b, B: 0x8a, A: 0xff},
        drawing.Color{R: 0x3d, G: 0x4d, B: 0x8a, A: 0xff},
        drawing.Color{R: 0x3c, G: 0x4e, B: 0x8a, A: 0xff},
        drawing.Color{R: 0x3c, G: 0x4f, B: 0x8a, A: 0xff},
        drawing.Color{R: 0x3b, G: 0x50, B: 0x8b, A: 0xff},
        drawing.Color{R: 0x3b, G: 0x51, B: 0x8b, A: 0xff},
        drawing.Color{R: 0x3a, G: 0x52, B: 0x8b, A: 0xff},
        drawing.Color{R: 0x3a, G: 0x53, B: 0x8b, A: 0xff},
        drawing.Color{R: 0x39, G: 0x54, B: 0x8c, A: 0xff},
        drawing.Color{R: 0x39, G: 0x55, B: 0x8c, A: 0xff},
        drawing.Color{R: 0x38, G: 0x56, B: 0x8c, A: 0xff},
        drawing.Color{R: 0x38, G: 0x57, B: 0x8c, A: 0xff},
        drawing.Color{R: 0x37, G: 0x58, B: 0x8c, A: 0xff},
        drawing.Color{R: 0x37, G: 0x59, B: 0x8c, A: 0xff},
        drawing.Color{R: 0x36, G: 0x5b, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x36, G: 0x5c, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x35, G: 0x5d, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x35, G: 0x5e, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x34, G: 0x5f, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x34, G: 0x60, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x33, G: 0x61, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x33, G: 0x62, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x33, G: 0x63, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x32, G: 0x64, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x32, G: 0x65, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x31, G: 0x66, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x31, G: 0x67, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x30, G: 0x68, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x30, G: 0x69, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x2f, G: 0x6a, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x2f, G: 0x6b, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x2f, G: 0x6c, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x2e, G: 0x6d, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x2e, G: 0x6e, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x2d, G: 0x6f, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x2d, G: 0x70, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x2d, G: 0x70, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x2c, G: 0x71, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x2c, G: 0x72, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x2b, G: 0x73, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x2b, G: 0x74, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x2b, G: 0x75, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x2a, G: 0x76, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x2a, G: 0x77, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x29, G: 0x78, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x29, G: 0x79, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x29, G: 0x7a, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x28, G: 0x7b, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x28, G: 0x7c, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x28, G: 0x7d, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x27, G: 0x7e, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x27, G: 0x7f, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x26, G: 0x80, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x26, G: 0x81, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x26, G: 0x82, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x25, G: 0x83, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x25, G: 0x83, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x25, G: 0x84, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x24, G: 0x85, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x24, G: 0x86, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x23, G: 0x87, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x23, G: 0x88, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x23, G: 0x89, B: 0x8e, A: 0xff},
        drawing.Color{R: 0x22, G: 0x8a, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x22, G: 0x8b, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x22, G: 0x8c, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x21, G: 0x8d, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x21, G: 0x8e, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x21, G: 0x8f, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x20, G: 0x90, B: 0x8d, A: 0xff},
        drawing.Color{R: 0x20, G: 0x91, B: 0x8c, A: 0xff},
        drawing.Color{R: 0x20, G: 0x92, B: 0x8c, A: 0xff},
        drawing.Color{R: 0x20, G: 0x93, B: 0x8c, A: 0xff},
        drawing.Color{R: 0x1f, G: 0x93, B: 0x8c, A: 0xff},
        drawing.Color{R: 0x1f, G: 0x94, B: 0x8c, A: 0xff},
        drawing.Color{R: 0x1f, G: 0x95, B: 0x8b, A: 0xff},
        drawing.Color{R: 0x1f, G: 0x96, B: 0x8b, A: 0xff},
        drawing.Color{R: 0x1f, G: 0x97, B: 0x8b, A: 0xff},
        drawing.Color{R: 0x1e, G: 0x98, B: 0x8b, A: 0xff},
        drawing.Color{R: 0x1e, G: 0x99, B: 0x8a, A: 0xff},
        drawing.Color{R: 0x1e, G: 0x9a, B: 0x8a, A: 0xff},
        drawing.Color{R: 0x1e, G: 0x9b, B: 0x8a, A: 0xff},
        drawing.Color{R: 0x1e, G: 0x9c, B: 0x89, A: 0xff},
        drawing.Color{R: 0x1e, G: 0x9d, B: 0x89, A: 0xff},
        drawing.Color{R: 0x1e, G: 0x9e, B: 0x89, A: 0xff},
        drawing.Color{R: 0x1e, G: 0x9f, B: 0x88, A: 0xff},
        drawing.Color{R: 0x1e, G: 0xa0, B: 0x88, A: 0xff},
        drawing.Color{R: 0x1f, G: 0xa1, B: 0x88, A: 0xff},
        drawing.Color{R: 0x1f, G: 0xa2, B: 0x87, A: 0xff},
        drawing.Color{R: 0x1f, G: 0xa3, B: 0x87, A: 0xff},
        drawing.Color{R: 0x1f, G: 0xa3, B: 0x86, A: 0xff},
        drawing.Color{R: 0x20, G: 0xa4, B: 0x86, A: 0xff},
        drawing.Color{R: 0x20, G: 0xa5, B: 0x86, A: 0xff},
        drawing.Color{R: 0x21, G: 0xa6, B: 0x85, A: 0xff},
        drawing.Color{R: 0x21, G: 0xa7, B: 0x85, A: 0xff},
        drawing.Color{R: 0x22, G: 0xa8, B: 0x84, A: 0xff},
        drawing.Color{R: 0x23, G: 0xa9, B: 0x83, A: 0xff},
        drawing.Color{R: 0x23, G: 0xaa, B: 0x83, A: 0xff},
        drawing.Color{R: 0x24, G: 0xab, B: 0x82, A: 0xff},
        drawing.Color{R: 0x25, G: 0xac, B: 0x82, A: 0xff},
        drawing.Color{R: 0x26, G: 0xad, B: 0x81, A: 0xff},
        drawing.Color{R: 0x27, G: 0xae, B: 0x81, A: 0xff},
        drawing.Color{R: 0x28, G: 0xaf, B: 0x80, A: 0xff},
        drawing.Color{R: 0x29, G: 0xaf, B: 0x7f, A: 0xff},
        drawing.Color{R: 0x2a, G: 0xb0, B: 0x7f, A: 0xff},
        drawing.Color{R: 0x2b, G: 0xb1, B: 0x7e, A: 0xff},
        drawing.Color{R: 0x2c, G: 0xb2, B: 0x7d, A: 0xff},
        drawing.Color{R: 0x2e, G: 0xb3, B: 0x7c, A: 0xff},
        drawing.Color{R: 0x2f, G: 0xb4, B: 0x7c, A: 0xff},
        drawing.Color{R: 0x30, G: 0xb5, B: 0x7b, A: 0xff},
        drawing.Color{R: 0x32, G: 0xb6, B: 0x7a, A: 0xff},
        drawing.Color{R: 0x33, G: 0xb7, B: 0x79, A: 0xff},
        drawing.Color{R: 0x35, G: 0xb7, B: 0x79, A: 0xff},
        drawing.Color{R: 0x36, G: 0xb8, B: 0x78, A: 0xff},
        drawing.Color{R: 0x38, G: 0xb9, B: 0x77, A: 0xff},
        drawing.Color{R: 0x39, G: 0xba, B: 0x76, A: 0xff},
        drawing.Color{R: 0x3b, G: 0xbb, B: 0x75, A: 0xff},
        drawing.Color{R: 0x3d, G: 0xbc, B: 0x74, A: 0xff},
        drawing.Color{R: 0x3e, G: 0xbd, B: 0x73, A: 0xff},
        drawing.Color{R: 0x40, G: 0xbe, B: 0x72, A: 0xff},
        drawing.Color{R: 0x42, G: 0xbe, B: 0x71, A: 0xff},
        drawing.Color{R: 0x44, G: 0xbf, B: 0x70, A: 0xff},
        drawing.Color{R: 0x46, G: 0xc0, B: 0x6f, A: 0xff},
        drawing.Color{R: 0x48, G: 0xc1, B: 0x6e, A: 0xff},
        drawing.Color{R: 0x49, G: 0xc2, B: 0x6d, A: 0xff},
        drawing.Color{R: 0x4b, G: 0xc2, B: 0x6c, A: 0xff},
        drawing.Color{R: 0x4d, G: 0xc3, B: 0x6b, A: 0xff},
        drawing.Color{R: 0x4f, G: 0xc4, B: 0x6a, A: 0xff},
        drawing.Color{R: 0x51, G: 0xc5, B: 0x69, A: 0xff},
        drawing.Color{R: 0x53, G: 0xc6, B: 0x68, A: 0xff},
        drawing.Color{R: 0x55, G: 0xc6, B: 0x66, A: 0xff},
        drawing.Color{R: 0x58, G: 0xc7, B: 0x65, A: 0xff},
        drawing.Color{R: 0x5a, G: 0xc8, B: 0x64, A: 0xff},
        drawing.Color{R: 0x5c, G: 0xc9, B: 0x63, A: 0xff},
        drawing.Color{R: 0x5e, G: 0xc9, B: 0x62, A: 0xff},
        drawing.Color{R: 0x60, G: 0xca, B: 0x60, A: 0xff},
        drawing.Color{R: 0x62, G: 0xcb, B: 0x5f, A: 0xff},
        drawing.Color{R: 0x65, G: 0xcc, B: 0x5e, A: 0xff},
        drawing.Color{R: 0x67, G: 0xcc, B: 0x5c, A: 0xff},
        drawing.Color{R: 0x69, G: 0xcd, B: 0x5b, A: 0xff},
        drawing.Color{R: 0x6c, G: 0xce, B: 0x5a, A: 0xff},
        drawing.Color{R: 0x6e, G: 0xce, B: 0x58, A: 0xff},
        drawing.Color{R: 0x70, G: 0xcf, B: 0x57, A: 0xff},
        drawing.Color{R: 0x73, G: 0xd0, B: 0x55, A: 0xff},
        drawing.Color{R: 0x75, G: 0xd0, B: 0x54, A: 0xff},
        drawing.Color{R: 0x77, G: 0xd1, B: 0x52, A: 0xff},
        drawing.Color{R: 0x7a, G: 0xd2, B: 0x51, A: 0xff},
        drawing.Color{R: 0x7c, G: 0xd2, B: 0x4f, A: 0xff},
        drawing.Color{R: 0x7f, G: 0xd3, B: 0x4e, A: 0xff},
        drawing.Color{R: 0x81, G: 0xd4, B: 0x4c, A: 0xff},
        drawing.Color{R: 0x84, G: 0xd4, B: 0x4b, A: 0xff},
        drawing.Color{R: 0x86, G: 0xd5, B: 0x49, A: 0xff},
        drawing.Color{R: 0x89, G: 0xd5, B: 0x48, A: 0xff},
        drawing.Color{R: 0x8b, G: 0xd6, B: 0x46, A: 0xff},
        drawing.Color{R: 0x8e, G: 0xd7, B: 0x44, A: 0xff},
        drawing.Color{R: 0x90, G: 0xd7, B: 0x43, A: 0xff},
        drawing.Color{R: 0x93, G: 0xd8, B: 0x41, A: 0xff},
        drawing.Color{R: 0x95, G: 0xd8, B: 0x3f, A: 0xff},
        drawing.Color{R: 0x98, G: 0xd9, B: 0x3e, A: 0xff},
        drawing.Color{R: 0x9b, G: 0xd9, B: 0x3c, A: 0xff},
        drawing.Color{R: 0x9d, G: 0xda, B: 0x3a, A: 0xff},
        drawing.Color{R: 0xa0, G: 0xda, B: 0x39, A: 0xff},
        drawing.Color{R: 0xa3, G: 0xdb, B: 0x37, A: 0xff},
        drawing.Color{R: 0xa5, G: 0xdb, B: 0x35, A: 0xff},
        drawing.Color{R: 0xa8, G: 0xdc, B: 0x33, A: 0xff},
        drawing.Color{R: 0xab, G: 0xdc, B: 0x32, A: 0xff},
        drawing.Color{R: 0xad, G: 0xdd, B: 0x30, A: 0xff},
        drawing.Color{R: 0xb0, G: 0xdd, B: 0x2e, A: 0xff},
        drawing.Color{R: 0xb3, G: 0xdd, B: 0x2d, A: 0xff},
        drawing.Color{R: 0xb5, G: 0xde, B: 0x2b, A: 0xff},
        drawing.Color{R: 0xb8, G: 0xde, B: 0x29, A: 0xff},
        drawing.Color{R: 0xbb, G: 0xdf, B: 0x27, A: 0xff},
        drawing.Color{R: 0xbd, G: 0xdf, B: 0x26, A: 0xff},
        drawing.Color{R: 0xc0, G: 0xdf, B: 0x24, A: 0xff},
        drawing.Color{R: 0xc3, G: 0xe0, B: 0x23, A: 0xff},
        drawing.Color{R: 0xc5, G: 0xe0, B: 0x21, A: 0xff},
        drawing.Color{R: 0xc8, G: 0xe1, B: 0x20, A: 0xff},
        drawing.Color{R: 0xcb, G: 0xe1, B: 0x1e, A: 0xff},
        drawing.Color{R: 0xcd, G: 0xe1, B: 0x1d, A: 0xff},
        drawing.Color{R: 0xd0, G: 0xe2, B: 0x1c, A: 0xff},
        drawing.Color{R: 0xd3, G: 0xe2, B: 0x1b, A: 0xff},
        drawing.Color{R: 0xd5, G: 0xe2, B: 0x1a, A: 0xff},
        drawing.Color{R: 0xd8, G: 0xe3, B: 0x19, A: 0xff},
        drawing.Color{R: 0xdb, G: 0xe3, B: 0x18, A: 0xff},
        drawing.Color{R: 0xdd, G: 0xe3, B: 0x18, A: 0xff},
        drawing.Color{R: 0xe0, G: 0xe4, B: 0x18, A: 0xff},
        drawing.Color{R: 0xe2, G: 0xe4, B: 0x18, A: 0xff},
        drawing.Color{R: 0xe5, G: 0xe4, B: 0x18, A: 0xff},
        drawing.Color{R: 0xe8, G: 0xe5, B: 0x19, A: 0xff},
        drawing.Color{R: 0xea, G: 0xe5, B: 0x19, A: 0xff},
        drawing.Color{R: 0xed, G: 0xe5, B: 0x1a, A: 0xff},
        drawing.Color{R: 0xef, G: 0xe6, B: 0x1b, A: 0xff},
        drawing.Color{R: 0xf2, G: 0xe6, B: 0x1c, A: 0xff},
        drawing.Color{R: 0xf4, G: 0xe6, B: 0x1e, A: 0xff},
        drawing.Color{R: 0xf7, G: 0xe6, B: 0x1f, A: 0xff},
        drawing.Color{R: 0xf9, G: 0xe7, B: 0x21, A: 0xff},
        drawing.Color{R: 0xfb, G: 0xe7, B: 0x23, A: 0xff},
        drawing.Color{R: 0xfe, G: 0xe7, B: 0x24, A: 0xff},
}

// Viridis creates a color map provider.
func Viridis(v, vmin, vmax float64) drawing.Color <span class="cov0" title="0">{
        normalized := (v - vmin) / (vmax - vmin)
        index := uint8(normalized * 255)
        return viridisColors[index]
}</span>
</pre>
		
		<pre class="file" id="file69" style="display: none">package chart

import (
        "math"

        util "github.com/wcharczuk/go-chart/util"
)

// XAxis represents the horizontal axis.
type XAxis struct {
        Name      string
        NameStyle Style

        Style          Style
        ValueFormatter ValueFormatter
        Range          Range

        TickStyle    Style
        Ticks        []Tick
        TickPosition TickPosition

        GridLines      []GridLine
        GridMajorStyle Style
        GridMinorStyle Style
}

// GetName returns the name.
func (xa XAxis) GetName() string <span class="cov0" title="0">{
        return xa.Name
}</span>

// GetStyle returns the style.
func (xa XAxis) GetStyle() Style <span class="cov0" title="0">{
        return xa.Style
}</span>

// GetValueFormatter returns the value formatter for the axis.
func (xa XAxis) GetValueFormatter() ValueFormatter <span class="cov0" title="0">{
        if xa.ValueFormatter != nil </span><span class="cov0" title="0">{
                return xa.ValueFormatter
        }</span>
        <span class="cov0" title="0">return FloatValueFormatter</span>
}

// GetTickPosition returns the tick position option for the axis.
func (xa XAxis) GetTickPosition(defaults ...TickPosition) TickPosition <span class="cov8" title="1">{
        if xa.TickPosition == TickPositionUnset </span><span class="cov8" title="1">{
                if len(defaults) &gt; 0 </span><span class="cov0" title="0">{
                        return defaults[0]
                }</span>
                <span class="cov8" title="1">return TickPositionUnderTick</span>
        }
        <span class="cov0" title="0">return xa.TickPosition</span>
}

// GetTicks returns the ticks for a series.
// The coalesce priority is:
//         - User Supplied Ticks (i.e. Ticks array on the axis itself).
//         - Range ticks (i.e. if the range provides ticks).
//        - Generating continuous ticks based on minimum spacing and canvas width.
func (xa XAxis) GetTicks(r Renderer, ra Range, defaults Style, vf ValueFormatter) []Tick <span class="cov8" title="1">{
        if len(xa.Ticks) &gt; 0 </span><span class="cov8" title="1">{
                return xa.Ticks
        }</span>
        <span class="cov8" title="1">if tp, isTickProvider := ra.(TicksProvider); isTickProvider </span><span class="cov0" title="0">{
                return tp.GetTicks(r, defaults, vf)
        }</span>
        <span class="cov8" title="1">tickStyle := xa.Style.InheritFrom(defaults)
        return GenerateContinuousTicks(r, ra, false, tickStyle, vf)</span>
}

// GetGridLines returns the gridlines for the axis.
func (xa XAxis) GetGridLines(ticks []Tick) []GridLine <span class="cov0" title="0">{
        if len(xa.GridLines) &gt; 0 </span><span class="cov0" title="0">{
                return xa.GridLines
        }</span>
        <span class="cov0" title="0">return GenerateGridLines(ticks, xa.GridMajorStyle, xa.GridMinorStyle)</span>
}

// Measure returns the bounds of the axis.
func (xa XAxis) Measure(r Renderer, canvasBox Box, ra Range, defaults Style, ticks []Tick) Box <span class="cov8" title="1">{
        tickStyle := xa.TickStyle.InheritFrom(xa.Style.InheritFrom(defaults))

        tp := xa.GetTickPosition()

        var ltx, rtx int
        var tx, ty int
        var left, right, bottom = math.MaxInt32, 0, 0
        for index, t := range ticks </span><span class="cov8" title="1">{
                v := t.Value
                tb := Draw.MeasureText(r, t.Label, tickStyle.GetTextOptions())

                tx = canvasBox.Left + ra.Translate(v)
                ty = canvasBox.Bottom + DefaultXAxisMargin + tb.Height()
                switch tp </span>{
                case TickPositionUnderTick, TickPositionUnset:<span class="cov8" title="1">
                        ltx = tx - tb.Width()&gt;&gt;1
                        rtx = tx + tb.Width()&gt;&gt;1
                        break</span>
                case TickPositionBetweenTicks:<span class="cov0" title="0">
                        if index &gt; 0 </span><span class="cov0" title="0">{
                                ltx = ra.Translate(ticks[index-1].Value)
                                rtx = tx
                        }</span>
                        <span class="cov0" title="0">break</span>
                }

                <span class="cov8" title="1">left = util.Math.MinInt(left, ltx)
                right = util.Math.MaxInt(right, rtx)
                bottom = util.Math.MaxInt(bottom, ty)</span>
        }

        <span class="cov8" title="1">if xa.NameStyle.Show &amp;&amp; len(xa.Name) &gt; 0 </span><span class="cov0" title="0">{
                tb := Draw.MeasureText(r, xa.Name, xa.NameStyle.InheritFrom(defaults))
                bottom += DefaultXAxisMargin + tb.Height()
        }</span>

        <span class="cov8" title="1">return Box{
                Top:    canvasBox.Bottom,
                Left:   left,
                Right:  right,
                Bottom: bottom,
        }</span>
}

// Render renders the axis
func (xa XAxis) Render(r Renderer, canvasBox Box, ra Range, defaults Style, ticks []Tick) <span class="cov8" title="1">{
        tickStyle := xa.TickStyle.InheritFrom(xa.Style.InheritFrom(defaults))

        tickStyle.GetStrokeOptions().WriteToRenderer(r)
        r.MoveTo(canvasBox.Left, canvasBox.Bottom)
        r.LineTo(canvasBox.Right, canvasBox.Bottom)
        r.Stroke()

        tp := xa.GetTickPosition()

        var tx, ty int
        var maxTextHeight int
        for index, t := range ticks </span><span class="cov8" title="1">{
                v := t.Value
                lx := ra.Translate(v)

                tx = canvasBox.Left + lx

                tickStyle.GetStrokeOptions().WriteToRenderer(r)
                r.MoveTo(tx, canvasBox.Bottom)
                r.LineTo(tx, canvasBox.Bottom+DefaultVerticalTickHeight)
                r.Stroke()

                tickWithAxisStyle := xa.TickStyle.InheritFrom(xa.Style.InheritFrom(defaults))
                tb := Draw.MeasureText(r, t.Label, tickWithAxisStyle)

                switch tp </span>{
                case TickPositionUnderTick, TickPositionUnset:<span class="cov8" title="1">
                        if tickStyle.TextRotationDegrees == 0 </span><span class="cov8" title="1">{
                                tx = tx - tb.Width()&gt;&gt;1
                                ty = canvasBox.Bottom + DefaultXAxisMargin + tb.Height()
                        }</span> else<span class="cov0" title="0"> {
                                ty = canvasBox.Bottom + (2 * DefaultXAxisMargin)
                        }</span>
                        <span class="cov8" title="1">Draw.Text(r, t.Label, tx, ty, tickWithAxisStyle)
                        maxTextHeight = util.Math.MaxInt(maxTextHeight, tb.Height())
                        break</span>
                case TickPositionBetweenTicks:<span class="cov0" title="0">
                        if index &gt; 0 </span><span class="cov0" title="0">{
                                llx := ra.Translate(ticks[index-1].Value)
                                ltx := canvasBox.Left + llx
                                finalTickStyle := tickWithAxisStyle.InheritFrom(Style{TextHorizontalAlign: TextHorizontalAlignCenter})

                                Draw.TextWithin(r, t.Label, Box{
                                        Left:   ltx,
                                        Right:  tx,
                                        Top:    canvasBox.Bottom + DefaultXAxisMargin,
                                        Bottom: canvasBox.Bottom + DefaultXAxisMargin,
                                }, finalTickStyle)

                                ftb := Text.MeasureLines(r, Text.WrapFit(r, t.Label, tx-ltx, finalTickStyle), finalTickStyle)
                                maxTextHeight = util.Math.MaxInt(maxTextHeight, ftb.Height())
                        }</span>
                        <span class="cov0" title="0">break</span>
                }
        }

        <span class="cov8" title="1">nameStyle := xa.NameStyle.InheritFrom(defaults)
        if xa.NameStyle.Show &amp;&amp; len(xa.Name) &gt; 0 </span><span class="cov0" title="0">{
                tb := Draw.MeasureText(r, xa.Name, nameStyle)
                tx := canvasBox.Right - (canvasBox.Width()&gt;&gt;1 + tb.Width()&gt;&gt;1)
                ty := canvasBox.Bottom + DefaultXAxisMargin + maxTextHeight + DefaultXAxisMargin + tb.Height()
                Draw.Text(r, xa.Name, tx, ty, nameStyle)
        }</span>

        <span class="cov8" title="1">if xa.GridMajorStyle.Show || xa.GridMinorStyle.Show </span><span class="cov0" title="0">{
                for _, gl := range xa.GetGridLines(ticks) </span><span class="cov0" title="0">{
                        if (gl.IsMinor &amp;&amp; xa.GridMinorStyle.Show) || (!gl.IsMinor &amp;&amp; xa.GridMajorStyle.Show) </span><span class="cov0" title="0">{
                                defaults := xa.GridMajorStyle
                                if gl.IsMinor </span><span class="cov0" title="0">{
                                        defaults = xa.GridMinorStyle
                                }</span>
                                <span class="cov0" title="0">gl.Render(r, canvasBox, ra, true, gl.Style.InheritFrom(defaults))</span>
                        }
                }
        }
}
</pre>
		
		<pre class="file" id="file70" style="display: none">package chart

import (
        "math"

        util "github.com/wcharczuk/go-chart/util"
)

// YAxis is a veritcal rule of the range.
// There can be (2) y-axes; a primary and secondary.
type YAxis struct {
        Name      string
        NameStyle Style

        Style Style

        Zero GridLine

        AxisType  YAxisType
        Ascending bool

        ValueFormatter ValueFormatter
        Range          Range

        TickStyle Style
        Ticks     []Tick

        GridLines      []GridLine
        GridMajorStyle Style
        GridMinorStyle Style
}

// GetName returns the name.
func (ya YAxis) GetName() string <span class="cov0" title="0">{
        return ya.Name
}</span>

// GetNameStyle returns the name style.
func (ya YAxis) GetNameStyle() Style <span class="cov0" title="0">{
        return ya.NameStyle
}</span>

// GetStyle returns the style.
func (ya YAxis) GetStyle() Style <span class="cov0" title="0">{
        return ya.Style
}</span>

// GetValueFormatter returns the value formatter for the axis.
func (ya YAxis) GetValueFormatter() ValueFormatter <span class="cov0" title="0">{
        if ya.ValueFormatter != nil </span><span class="cov0" title="0">{
                return ya.ValueFormatter
        }</span>
        <span class="cov0" title="0">return FloatValueFormatter</span>
}

// GetTickStyle returns the tick style.
func (ya YAxis) GetTickStyle() Style <span class="cov0" title="0">{
        return ya.TickStyle
}</span>

// GetTicks returns the ticks for a series.
// The coalesce priority is:
//         - User Supplied Ticks (i.e. Ticks array on the axis itself).
//         - Range ticks (i.e. if the range provides ticks).
//        - Generating continuous ticks based on minimum spacing and canvas width.
func (ya YAxis) GetTicks(r Renderer, ra Range, defaults Style, vf ValueFormatter) []Tick <span class="cov8" title="1">{
        if len(ya.Ticks) &gt; 0 </span><span class="cov8" title="1">{
                return ya.Ticks
        }</span>
        <span class="cov8" title="1">if tp, isTickProvider := ra.(TicksProvider); isTickProvider </span><span class="cov0" title="0">{
                return tp.GetTicks(r, defaults, vf)
        }</span>
        <span class="cov8" title="1">tickStyle := ya.Style.InheritFrom(defaults)
        return GenerateContinuousTicks(r, ra, true, tickStyle, vf)</span>
}

// GetGridLines returns the gridlines for the axis.
func (ya YAxis) GetGridLines(ticks []Tick) []GridLine <span class="cov0" title="0">{
        if len(ya.GridLines) &gt; 0 </span><span class="cov0" title="0">{
                return ya.GridLines
        }</span>
        <span class="cov0" title="0">return GenerateGridLines(ticks, ya.GridMajorStyle, ya.GridMinorStyle)</span>
}

// Measure returns the bounds of the axis.
func (ya YAxis) Measure(r Renderer, canvasBox Box, ra Range, defaults Style, ticks []Tick) Box <span class="cov8" title="1">{
        var tx int
        if ya.AxisType == YAxisPrimary </span><span class="cov8" title="1">{
                tx = canvasBox.Right + DefaultYAxisMargin
        }</span> else<span class="cov8" title="1"> if ya.AxisType == YAxisSecondary </span><span class="cov8" title="1">{
                tx = canvasBox.Left - DefaultYAxisMargin
        }</span>

        <span class="cov8" title="1">ya.TickStyle.InheritFrom(ya.Style.InheritFrom(defaults)).WriteToRenderer(r)
        var minx, maxx, miny, maxy = math.MaxInt32, 0, math.MaxInt32, 0
        var maxTextHeight int
        for _, t := range ticks </span><span class="cov8" title="1">{
                v := t.Value
                ly := canvasBox.Bottom - ra.Translate(v)

                tb := r.MeasureText(t.Label)
                tbh2 := tb.Height() &gt;&gt; 1
                finalTextX := tx
                if ya.AxisType == YAxisSecondary </span><span class="cov8" title="1">{
                        finalTextX = tx - tb.Width()
                }</span>

                <span class="cov8" title="1">maxTextHeight = util.Math.MaxInt(tb.Height(), maxTextHeight)

                if ya.AxisType == YAxisPrimary </span><span class="cov8" title="1">{
                        minx = canvasBox.Right
                        maxx = util.Math.MaxInt(maxx, tx+tb.Width())
                }</span> else<span class="cov8" title="1"> if ya.AxisType == YAxisSecondary </span><span class="cov8" title="1">{
                        minx = util.Math.MinInt(minx, finalTextX)
                        maxx = util.Math.MaxInt(maxx, tx)
                }</span>

                <span class="cov8" title="1">miny = util.Math.MinInt(miny, ly-tbh2)
                maxy = util.Math.MaxInt(maxy, ly+tbh2)</span>
        }

        <span class="cov8" title="1">if ya.NameStyle.Show &amp;&amp; len(ya.Name) &gt; 0 </span><span class="cov0" title="0">{
                maxx += (DefaultYAxisMargin + maxTextHeight)
        }</span>

        <span class="cov8" title="1">return Box{
                Top:    miny,
                Left:   minx,
                Right:  maxx,
                Bottom: maxy,
        }</span>
}

// Render renders the axis.
func (ya YAxis) Render(r Renderer, canvasBox Box, ra Range, defaults Style, ticks []Tick) <span class="cov8" title="1">{
        tickStyle := ya.TickStyle.InheritFrom(ya.Style.InheritFrom(defaults))
        tickStyle.WriteToRenderer(r)

        sw := tickStyle.GetStrokeWidth(defaults.StrokeWidth)

        var lx int
        var tx int
        if ya.AxisType == YAxisPrimary </span><span class="cov8" title="1">{
                lx = canvasBox.Right + int(sw)
                tx = lx + DefaultYAxisMargin
        }</span> else<span class="cov0" title="0"> if ya.AxisType == YAxisSecondary </span><span class="cov0" title="0">{
                lx = canvasBox.Left - int(sw)
                tx = lx - DefaultYAxisMargin
        }</span>

        <span class="cov8" title="1">r.MoveTo(lx, canvasBox.Bottom)
        r.LineTo(lx, canvasBox.Top)
        r.Stroke()

        var maxTextWidth int
        var finalTextX, finalTextY int
        for _, t := range ticks </span><span class="cov8" title="1">{
                v := t.Value
                ly := canvasBox.Bottom - ra.Translate(v)

                tb := Draw.MeasureText(r, t.Label, tickStyle)

                if tb.Width() &gt; maxTextWidth </span><span class="cov8" title="1">{
                        maxTextWidth = tb.Width()
                }</span>

                <span class="cov8" title="1">if ya.AxisType == YAxisSecondary </span><span class="cov0" title="0">{
                        finalTextX = tx - tb.Width()
                }</span> else<span class="cov8" title="1"> {
                        finalTextX = tx
                }</span>

                <span class="cov8" title="1">if tickStyle.TextRotationDegrees == 0 </span><span class="cov8" title="1">{
                        finalTextY = ly + tb.Height()&gt;&gt;1
                }</span> else<span class="cov0" title="0"> {
                        finalTextY = ly
                }</span>

                <span class="cov8" title="1">tickStyle.WriteToRenderer(r)

                r.MoveTo(lx, ly)
                if ya.AxisType == YAxisPrimary </span><span class="cov8" title="1">{
                        r.LineTo(lx+DefaultHorizontalTickWidth, ly)
                }</span> else<span class="cov0" title="0"> if ya.AxisType == YAxisSecondary </span><span class="cov0" title="0">{
                        r.LineTo(lx-DefaultHorizontalTickWidth, ly)
                }</span>
                <span class="cov8" title="1">r.Stroke()

                Draw.Text(r, t.Label, finalTextX, finalTextY, tickStyle)</span>
        }

        <span class="cov8" title="1">nameStyle := ya.NameStyle.InheritFrom(defaults.InheritFrom(Style{TextRotationDegrees: 90}))
        if ya.NameStyle.Show &amp;&amp; len(ya.Name) &gt; 0 </span><span class="cov0" title="0">{
                nameStyle.GetTextOptions().WriteToRenderer(r)
                tb := Draw.MeasureText(r, ya.Name, nameStyle)

                var tx int
                if ya.AxisType == YAxisPrimary </span><span class="cov0" title="0">{
                        tx = canvasBox.Right + int(sw) + DefaultYAxisMargin + maxTextWidth + DefaultYAxisMargin
                }</span> else<span class="cov0" title="0"> if ya.AxisType == YAxisSecondary </span><span class="cov0" title="0">{
                        tx = canvasBox.Left - (DefaultYAxisMargin + int(sw) + maxTextWidth + DefaultYAxisMargin)
                }</span>

                <span class="cov0" title="0">var ty int
                if nameStyle.TextRotationDegrees == 0 </span><span class="cov0" title="0">{
                        ty = canvasBox.Top + (canvasBox.Height()&gt;&gt;1 - tb.Width()&gt;&gt;1)
                }</span> else<span class="cov0" title="0"> {
                        ty = canvasBox.Top + (canvasBox.Height()&gt;&gt;1 - tb.Height()&gt;&gt;1)
                }</span>

                <span class="cov0" title="0">Draw.Text(r, ya.Name, tx, ty, nameStyle)</span>
        }

        <span class="cov8" title="1">if ya.Zero.Style.Show </span><span class="cov0" title="0">{
                ya.Zero.Render(r, canvasBox, ra, false, Style{})
        }</span>

        <span class="cov8" title="1">if ya.GridMajorStyle.Show || ya.GridMinorStyle.Show </span><span class="cov0" title="0">{
                for _, gl := range ya.GetGridLines(ticks) </span><span class="cov0" title="0">{
                        if (gl.IsMinor &amp;&amp; ya.GridMinorStyle.Show) || (!gl.IsMinor &amp;&amp; ya.GridMajorStyle.Show) </span><span class="cov0" title="0">{
                                defaults := ya.GridMajorStyle
                                if gl.IsMinor </span><span class="cov0" title="0">{
                                        defaults = ya.GridMinorStyle
                                }</span>
                                <span class="cov0" title="0">gl.Render(r, canvasBox, ra, false, gl.Style.InheritFrom(defaults))</span>
                        }
                }
        }
}
</pre>
		
		</div>
	</body>
	<script>
	(function() {
		var files = document.getElementById('files');
		var visible;
		files.addEventListener('change', onChange, false);
		function select(part) {
			if (visible)
				visible.style.display = 'none';
			visible = document.getElementById(part);
			if (!visible)
				return;
			files.value = part;
			visible.style.display = 'block';
			location.hash = part;
		}
		function onChange() {
			select(files.value);
			window.scrollTo(0, 0);
		}
		if (location.hash != "") {
			select(location.hash.substr(1));
		}
		if (!visible) {
			select("file0");
		}
	})();
	</script>
</html>