diff --git a/chart.go b/chart.go index 874e620..a7e4385 100644 --- a/chart.go +++ b/chart.go @@ -122,6 +122,8 @@ type Range struct { InvNorm func(float64) float64 // Inverse of Norm() Data2Screen func(float64) int // Function to map data value to screen position Screen2Data func(int) float64 // Inverse of Data2Screen + + AlignTrans bool // alignment translation of the axis: false: axis location left/bottom, true: axis location right/top } // Fixed is a helper (just reduces typing) functions which turns of autoscaling @@ -674,8 +676,12 @@ type LayoutData struct { NumXtics, NumYtics int // suggested numer of tics for both axis } -// Layout graph data area on screen and place key. func layout(g Graphics, title, xlabel, ylabel string, hidextics, hideytics bool, key *Key) (ld LayoutData) { + return layoutWithAlign(g, title, xlabel, ylabel, hidextics, hideytics, key, false, false) +} + +// Layout graph data area on screen and place key. +func layoutWithAlign(g Graphics, title, xlabel, ylabel string, hidextics, hideytics bool, key *Key, xalign bool, yalign bool) (ld LayoutData) { fw, fh, _ := g.FontMetrics(Font{}) w, h := g.Dimensions() @@ -684,6 +690,9 @@ func layout(g Graphics, title, xlabel, ylabel string, hidextics, hideytics bool, } width, leftm, height, topm := w-int(6*fw), int(2*fw), h-2*fh, fh + if yalign { + leftm = int(4 * fw) + } xlabsep, ylabsep := fh, int(3*fw) if title != "" { topm += (5 * fh) / 2 @@ -697,11 +706,15 @@ func layout(g Graphics, title, xlabel, ylabel string, hidextics, hideytics bool, xlabsep += (3 * fh) / 2 } if ylabel != "" { - leftm += 2 * fh + if !yalign { + leftm += 2 * fh + } width -= 2 * fh } if !hideytics { - leftm += int(6 * fw) + if !yalign { + leftm += int(6 * fw) + } width -= int(6 * fw) ylabsep += int(6 * fw) } diff --git a/example/bestof.png b/example/bestof.png index 5ce7f41..b25ef80 100644 Binary files a/example/bestof.png and b/example/bestof.png differ diff --git a/example/samplecharts.go b/example/samplecharts.go index c742b3e..9a985f2 100644 --- a/example/samplecharts.go +++ b/example/samplecharts.go @@ -15,10 +15,10 @@ import ( "time" "github.com/ajstarks/svgo" - "github.com/vdobler/chart" - "github.com/vdobler/chart/imgg" - "github.com/vdobler/chart/svgg" - "github.com/vdobler/chart/txtg" + "github.com/yyonghe/chart" + "github.com/yyonghe/chart/imgg" + "github.com/yyonghe/chart/svgg" + "github.com/yyonghe/chart/txtg" ) var ( @@ -278,6 +278,7 @@ func scatterChart() { pl.XRange.TicSetting.Grid = 1 pl.XRange.Label = "X-Range" pl.YRange.Label = "Y-Range" + pl.YRange.AlignTrans = true pl.Key.Cols = 2 pl.Key.Pos = "orb" diff --git a/go.mod b/go.mod index 06a3e05..937e464 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/vdobler/chart +module github.com/yyonghe/chart require ( github.com/ajstarks/svgo v0.0.0-20181006003313-6ce6a3bcf6cd diff --git a/go.sum b/go.sum index 3e457b4..9ce9740 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,7 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGw github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/llgcode/draw2d v0.0.0-20180825133448-f52c8a71aff0 h1:2vp6ESimuT8pCuZHThVyV0hlfa9oPL06HnGCL9pbUgc= github.com/llgcode/draw2d v0.0.0-20180825133448-f52c8a71aff0/go.mod h1:mVa0dA29Db2S4LVqDYLlsePDzRJLDfdhVZiI15uY0FA= +github.com/llgcode/ps v0.0.0-20150911083025-f1443b32eedb h1:61ndUreYSlWFeCY44JxDDkngVoI7/1MVhEl98Nm0KOk= github.com/llgcode/ps v0.0.0-20150911083025-f1443b32eedb/go.mod h1:1l8ky+Ew27CMX29uG+a2hNOKpeNYEQjjtiALiBlFQbY= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20181030002151-69cc3646b96e h1:LpHV5J9Rec5OYn+RZFfNenrW109yUVSoKjGOgmKKhxE= diff --git a/graphics.go b/graphics.go index 322584d..fa1b7a3 100644 --- a/graphics.go +++ b/graphics.go @@ -278,14 +278,28 @@ func drawYTics(bg BasicGraphics, rng Range, x, xm, ticLen int, options PlotOptio y := rng.Data2Screen(tic.Pos) ly := rng.Data2Screen(tic.LabelPos) + ox := x + oxm := xm + if rng.AlignTrans { + ox = xm // origin to right + oxm = x // mirror to right + } // Tics switch rng.TicSetting.Tics { case 0: - bg.Line(x-ticLen, y, x+ticLen, y, ticstyle) + bg.Line(ox-ticLen, y, ox+ticLen, y, ticstyle) case 1: - bg.Line(x, y, x+ticLen, y, ticstyle) + if rng.AlignTrans { + bg.Line(ox, y, ox-ticLen, y, ticstyle) + } else { + bg.Line(ox, y, ox+ticLen, y, ticstyle) + } case 2: - bg.Line(x-ticLen, y, x, y, ticstyle) + if rng.AlignTrans { + bg.Line(ox+ticLen, y, ox, y, ticstyle) + } else { + bg.Line(ox-ticLen, y, ox, y, ticstyle) + } default: } @@ -293,11 +307,19 @@ func drawYTics(bg BasicGraphics, rng Range, x, xm, ticLen int, options PlotOptio if rng.TicSetting.Mirror >= 2 { switch rng.TicSetting.Tics { case 0: - bg.Line(xm-ticLen, y, xm+ticLen, y, ticstyle) + bg.Line(oxm-ticLen, y, oxm+ticLen, y, ticstyle) case 1: - bg.Line(xm-ticLen, y, xm, y, ticstyle) + if rng.AlignTrans { + bg.Line(oxm+ticLen, y, oxm, y, ticstyle) + } else { + bg.Line(oxm-ticLen, y, oxm, y, ticstyle) + } case 2: - bg.Line(xm, y, xm+ticLen, y, ticstyle) + if rng.AlignTrans { + bg.Line(oxm, y, oxm-ticLen, y, ticstyle) + } else { + bg.Line(oxm, y, oxm+ticLen, y, ticstyle) + } default: } } @@ -305,10 +327,14 @@ func drawYTics(bg BasicGraphics, rng Range, x, xm, ticLen int, options PlotOptio if !rng.TicSetting.HideLabels { // Label if rng.Time && tic.Align == 0 { // centered tic - bg.Line(x-2*ticLen, y, x+ticLen, y, ticstyle) - bg.Text(x-ticLen, ly, tic.Label, "cr", 0, ticfont) + bg.Line(ox-2*ticLen, y, ox+ticLen, y, ticstyle) + bg.Text(ox-ticLen, ly, tic.Label, "cr", 0, ticfont) } else { - bg.Text(x-2*ticLen, ly, tic.Label, "cr", 0, ticfont) + if rng.AlignTrans { + bg.Text(ox+2*ticLen, ly, tic.Label, "cl", 0, ticfont) + } else { + bg.Text(ox-2*ticLen, ly, tic.Label, "cr", 0, ticfont) + } } } } @@ -319,7 +345,7 @@ func drawYTics(bg BasicGraphics, rng Range, x, xm, ticLen int, options PlotOptio // The y.axis and the mirrord y-axis are drawn at x and ym respectively. func GenericYAxis(bg BasicGraphics, rng Range, x, xm int, options PlotOptions) { font := elementStyle(options, MajorAxisElement).Font - _, fontheight, _ := bg.FontMetrics(font) + fw, fontheight, _ := bg.FontMetrics(font) var ticLen int = 0 if !rng.TicSetting.Hide { ticLen = imin(10, imax(4, fontheight/2)) @@ -342,7 +368,11 @@ func GenericYAxis(bg BasicGraphics, rng Range, x, xm int, options PlotOptions) { } if rng.Label != "" { y := (ya + ye) / 2 - bg.Text(alx, y, rng.Label, "bc", 90, font) + if rng.AlignTrans { + bg.Text(xm+alx+int(6*fw), y, rng.Label, "bc", 90, font) + } else { + bg.Text(alx, y, rng.Label, "bc", 90, font) + } } if !rng.TicSetting.Hide { @@ -350,9 +380,15 @@ func GenericYAxis(bg BasicGraphics, rng Range, x, xm int, options PlotOptions) { } // Axis itself, mirrord axis and zero - bg.Line(x, ya, x, ye, elementStyle(options, MajorAxisElement)) + ox := x + oxm := xm + if rng.AlignTrans { + ox = xm + oxm = x + } + bg.Line(ox, ya, ox, ye, elementStyle(options, MajorAxisElement)) if rng.TicSetting.Mirror >= 1 { - bg.Line(xm, ya, xm, ye, elementStyle(options, MinorAxisElement)) + bg.Line(oxm, ya, oxm, ye, elementStyle(options, MinorAxisElement)) } if rng.ShowZero && rng.Min < 0 && rng.Max > 0 { z := rng.Data2Screen(0) diff --git a/imgg/image.go b/imgg/image.go index b5eaa34..85d69c8 100644 --- a/imgg/image.go +++ b/imgg/image.go @@ -10,7 +10,7 @@ import ( "github.com/golang/freetype/truetype" "github.com/llgcode/draw2d" "github.com/llgcode/draw2d/draw2dimg" - "github.com/vdobler/chart" + "github.com/yyonghe/chart" "golang.org/x/image/draw" "golang.org/x/image/math/f64" "golang.org/x/image/math/fixed" diff --git a/imgg/image_test.go b/imgg/image_test.go index 889ac31..eded6d8 100644 --- a/imgg/image_test.go +++ b/imgg/image_test.go @@ -1,7 +1,7 @@ package imgg import ( - "github.com/vdobler/chart" + "github.com/yyonghe/chart" "image" "image/color" "image/png" diff --git a/scatter.go b/scatter.go index 45ae8a9..9ae083b 100644 --- a/scatter.go +++ b/scatter.go @@ -127,10 +127,10 @@ func (c *ScatterChart) Reset() { // Plot outputs the scatter chart to the graphic output g. func (c *ScatterChart) Plot(g Graphics) { - layout := layout(g, c.Title, c.XRange.Label, c.YRange.Label, + layout := layoutWithAlign(g, c.Title, c.XRange.Label, c.YRange.Label, c.XRange.TicSetting.Hide || c.XRange.TicSetting.HideLabels, c.YRange.TicSetting.Hide || c.YRange.TicSetting.HideLabels, - &c.Key) + &c.Key, c.XRange.AlignTrans, c.YRange.AlignTrans) width, height := layout.Width, layout.Height topm, leftm := layout.Top, layout.Left diff --git a/svgg/svg.go b/svgg/svg.go index 0723de2..a982bdc 100644 --- a/svgg/svg.go +++ b/svgg/svg.go @@ -6,7 +6,7 @@ import ( "math" "github.com/ajstarks/svgo" - "github.com/vdobler/chart" + "github.com/yyonghe/chart" ) // SvgGraphics implements BasicGraphics and uses the generic implementations @@ -399,9 +399,11 @@ func (sg *SvgGraphics) Rings(wedges []chart.Wedgeinfo, x, y, ro, ri int) { d += fmt.Sprintf("L %d,%d ", int(rf*cphi+0.5+dx)+x, int(rf*sphi+0.5+dy)+y) dx, dy = p*math.Cos(w.Psi-math.Pi/2), p*math.Sin(w.Psi-math.Pi/2) - if math.Abs(w.Phi-w.Psi)>math.Pi { - d += fmt.Sprintf("A %d,%d 0 1 1 %d,%d ", ro, ro, int(rf*cpsi+0.5+dx)+x, int(rf*spsi+0.5+dy)+y) } else { - d += fmt.Sprintf("A %d,%d 0 0 1 %d,%d ", ro, ro, int(rf*cpsi+0.5+dx)+x, int(rf*spsi+0.5+dy)+y) } + if math.Abs(w.Phi-w.Psi) > math.Pi { + d += fmt.Sprintf("A %d,%d 0 1 1 %d,%d ", ro, ro, int(rf*cpsi+0.5+dx)+x, int(rf*spsi+0.5+dy)+y) + } else { + d += fmt.Sprintf("A %d,%d 0 0 1 %d,%d ", ro, ro, int(rf*cpsi+0.5+dx)+x, int(rf*spsi+0.5+dy)+y) + } d += fmt.Sprintf("z") } else { // ring drawn as inner radius -> outer radius -> outer arc -> inner radius -> inner arc @@ -412,13 +414,17 @@ func (sg *SvgGraphics) Rings(wedges []chart.Wedgeinfo, x, y, ro, ri int) { d += fmt.Sprintf("L %d,%d ", int(rof*cphi+0.5+dx)+x, int(rof*sphi+0.5+dy)+y) dx, dy = p*math.Cos(w.Psi-math.Pi/2), p*math.Sin(w.Psi-math.Pi/2) - if math.Abs(w.Phi-w.Psi)>math.Pi { - d += fmt.Sprintf("A %d,%d 0 1 1 %d,%d ", ro, ro, int(rof*cpsi+0.5+dx)+x, int(rof*spsi+0.5+dy)+y) } else { - d += fmt.Sprintf("A %d,%d 0 0 1 %d,%d ", ro, ro, int(rof*cpsi+0.5+dx)+x, int(rof*spsi+0.5+dy)+y) } + if math.Abs(w.Phi-w.Psi) > math.Pi { + d += fmt.Sprintf("A %d,%d 0 1 1 %d,%d ", ro, ro, int(rof*cpsi+0.5+dx)+x, int(rof*spsi+0.5+dy)+y) + } else { + d += fmt.Sprintf("A %d,%d 0 0 1 %d,%d ", ro, ro, int(rof*cpsi+0.5+dx)+x, int(rof*spsi+0.5+dy)+y) + } d += fmt.Sprintf("L %d,%d ", int(rif*cpsi+0.5+dx)+x, int(rif*spsi+0.5+dy)+y) - if math.Abs(w.Phi-w.Psi)>math.Pi { - d += fmt.Sprintf("A %d,%d 0 1 0 %d,%d ", ri, ri, a, b) } else { - d += fmt.Sprintf("A %d,%d 0 0 0 %d,%d ", ri, ri, a, b) } + if math.Abs(w.Phi-w.Psi) > math.Pi { + d += fmt.Sprintf("A %d,%d 0 1 0 %d,%d ", ri, ri, a, b) + } else { + d += fmt.Sprintf("A %d,%d 0 0 0 %d,%d ", ri, ri, a, b) + } d += fmt.Sprintf("z") } diff --git a/txtg/text.go b/txtg/text.go index 19ca0c1..755dea7 100644 --- a/txtg/text.go +++ b/txtg/text.go @@ -2,7 +2,7 @@ package txtg import ( "fmt" - "github.com/vdobler/chart" + "github.com/yyonghe/chart" "math" )