snapshot.
This commit is contained in:
parent
b78f2327aa
commit
8f56e5939b
10 changed files with 105 additions and 44 deletions
|
@ -14,13 +14,31 @@ func drawChart(res http.ResponseWriter, req *http.Request) {
|
|||
graph := chart.Chart{
|
||||
YAxis: chart.YAxis{
|
||||
Style: chart.Style{
|
||||
Show: true,
|
||||
TextRotationDegrees: 45.0,
|
||||
Show: true,
|
||||
},
|
||||
Range: &chart.ContinuousRange{
|
||||
Min: 0.0,
|
||||
Max: 4.0,
|
||||
},
|
||||
TickStyle: chart.Style{
|
||||
TextRotationDegrees: 45.0,
|
||||
},
|
||||
Ticks: []chart.Tick{
|
||||
{0.0, "0.00"},
|
||||
{2.0, "2.00"},
|
||||
{4.0, "4.00"},
|
||||
{6.0, "6.00"},
|
||||
{8.0, "Eight"},
|
||||
{10.0, "Ten"},
|
||||
},
|
||||
},
|
||||
XAxis: chart.XAxis{
|
||||
Style: chart.Style{
|
||||
Show: true,
|
||||
},
|
||||
TickStyle: chart.Style{
|
||||
TextRotationDegrees: 45.0,
|
||||
},
|
||||
Ticks: []chart.Tick{
|
||||
{0.0, "0.00"},
|
||||
{2.0, "2.00"},
|
||||
|
@ -39,6 +57,20 @@ func drawChart(res http.ResponseWriter, req *http.Request) {
|
|||
}
|
||||
|
||||
res.Header().Set("Content-Type", "image/png")
|
||||
graph.Elements = []chart.Renderable{
|
||||
func(r chart.Renderer, cb chart.Box, defaults chart.Style) {
|
||||
|
||||
b := chart.Box{50, 50, 90, 110}
|
||||
chart.Draw.Box(r, b, chart.Style{
|
||||
StrokeWidth: 2,
|
||||
StrokeColor: chart.ColorBlue,
|
||||
})
|
||||
chart.Draw.Box(r, b.Rotate(chart.Math.DegreesToRadians(45)), chart.Style{
|
||||
StrokeWidth: 2,
|
||||
StrokeColor: chart.ColorRed,
|
||||
})
|
||||
},
|
||||
}
|
||||
graph.Render(chart.PNG, res)
|
||||
}
|
||||
|
||||
|
|
6
box.go
6
box.go
|
@ -76,8 +76,8 @@ func (b Box) Height() int {
|
|||
|
||||
// Center returns the center of the box
|
||||
func (b Box) Center() (x, y int) {
|
||||
w, h := b.Width(), b.Height()
|
||||
return b.Left + w>>1, b.Top + h>>1
|
||||
w2, h2 := b.Width()>>1, b.Height()>>1
|
||||
return b.Left + w2, b.Top + h2
|
||||
}
|
||||
|
||||
// Aspect returns the aspect ratio of the box.
|
||||
|
@ -227,8 +227,8 @@ func (b Box) Rotate(radians float64) Box {
|
|||
ltx, lty := Math.RotateCoordinate(cx, cy, b.Left, b.Top, radians)
|
||||
rbx, rby := Math.RotateCoordinate(cx, cy, b.Right, b.Bottom, radians)
|
||||
return Box{
|
||||
Top: lty,
|
||||
Left: ltx,
|
||||
Top: lty,
|
||||
Right: rbx,
|
||||
Bottom: rby,
|
||||
}
|
||||
|
|
18
box_test.go
18
box_test.go
|
@ -144,6 +144,20 @@ func TestBoxShift(t *testing.T) {
|
|||
assert.Equal(12, shifted.Bottom)
|
||||
}
|
||||
|
||||
func TestBoxCenter(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
b := Box{
|
||||
Top: 10,
|
||||
Left: 10,
|
||||
Right: 20,
|
||||
Bottom: 30,
|
||||
}
|
||||
cx, cy := b.Center()
|
||||
assert.Equal(15, cx)
|
||||
assert.Equal(20, cy)
|
||||
}
|
||||
|
||||
func TestBoxRotate(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
|
@ -156,6 +170,6 @@ func TestBoxRotate(t *testing.T) {
|
|||
rotated := b.Rotate(Math.DegreesToRadians(45))
|
||||
assert.Equal(1, rotated.Top)
|
||||
assert.Equal(4, rotated.Left)
|
||||
assert.Equal(11, rotated.Right)
|
||||
assert.Equal(15, rotated.Bottom)
|
||||
assert.Equal(10, rotated.Right)
|
||||
assert.Equal(14, rotated.Bottom)
|
||||
}
|
||||
|
|
8
math.go
8
math.go
|
@ -223,9 +223,9 @@ func (m mathUtil) CirclePoint(cx, cy int, radius, thetaRadians float64) (x, y in
|
|||
|
||||
func (m mathUtil) RotateCoordinate(cx, cy, x, y int, thetaRadians float64) (rx, ry int) {
|
||||
tempX, tempY := float64(x-cx), float64(y-cy)
|
||||
rotatedX := int(math.Ceil(tempX*math.Cos(thetaRadians) - tempY*math.Sin(thetaRadians)))
|
||||
rotatedY := int(math.Ceil(tempX*math.Sin(thetaRadians) + tempY*math.Cos(thetaRadians)))
|
||||
rx = rotatedX + cy
|
||||
ry = rotatedY + cy
|
||||
rotatedX := tempX*math.Cos(thetaRadians) - tempY*math.Sin(thetaRadians)
|
||||
rotatedY := tempX*math.Sin(thetaRadians) + tempY*math.Cos(thetaRadians)
|
||||
rx = int(rotatedX) + cy
|
||||
ry = int(rotatedY) + cy
|
||||
return
|
||||
}
|
||||
|
|
19
math_test.go
19
math_test.go
|
@ -161,13 +161,24 @@ func TestRadianAdd(t *testing.T) {
|
|||
assert.Equal(_pi, Math.RadianAdd(_pi, -_2pi))
|
||||
}
|
||||
|
||||
func TestRotateCoordinate(t *testing.T) {
|
||||
func TestRotateCoordinate90(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
cx, cy := 10, 10
|
||||
x, y := 5, 5
|
||||
x, y := 5, 10
|
||||
|
||||
rx, ry := Math.RotateCoordinate(cx, cy, x, y, Math.DegreesToRadians(90))
|
||||
assert.Equal(10, rx)
|
||||
assert.Equal(5, ry)
|
||||
}
|
||||
|
||||
func TestRotateCoordinate45(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
cx, cy := 10, 10
|
||||
x, y := 5, 10
|
||||
|
||||
rx, ry := Math.RotateCoordinate(cx, cy, x, y, Math.DegreesToRadians(45))
|
||||
assert.Equal(10, rx)
|
||||
assert.Equal(3, ry)
|
||||
assert.Equal(7, rx)
|
||||
assert.Equal(7, ry)
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ type rasterRenderer struct {
|
|||
i *image.RGBA
|
||||
gc *drawing.RasterGraphicContext
|
||||
|
||||
rotateRadians float64
|
||||
rotateRadians *float64
|
||||
|
||||
s Style
|
||||
}
|
||||
|
@ -183,34 +183,34 @@ func (rr *rasterRenderer) MeasureText(body string) Box {
|
|||
Right: int(math.Ceil(r)),
|
||||
Bottom: int(math.Ceil(b)),
|
||||
}
|
||||
if rr.rotateRadians == 0 {
|
||||
if rr.rotateRadians == nil {
|
||||
return textBox
|
||||
}
|
||||
|
||||
return textBox.Rotate(rr.rotateRadians)
|
||||
return textBox.Rotate(*rr.rotateRadians)
|
||||
}
|
||||
|
||||
// SetTextRotation sets a text rotation.
|
||||
func (rr *rasterRenderer) SetTextRotation(radians float64) {
|
||||
rr.rotateRadians = radians
|
||||
rr.rotateRadians = &radians
|
||||
}
|
||||
|
||||
func (rr *rasterRenderer) getCoords(x, y int) (xf, yf int) {
|
||||
if rr.rotateRadians == 0 {
|
||||
if rr.rotateRadians == nil {
|
||||
xf = x
|
||||
yf = y
|
||||
return
|
||||
}
|
||||
|
||||
rr.gc.Translate(float64(x), float64(y))
|
||||
rr.gc.Rotate(rr.rotateRadians)
|
||||
rr.gc.Rotate(*rr.rotateRadians)
|
||||
return
|
||||
}
|
||||
|
||||
// ClearTextRotation clears text rotation.
|
||||
func (rr *rasterRenderer) ClearTextRotation() {
|
||||
rr.gc.SetMatrixTransform(drawing.NewIdentityMatrix())
|
||||
rr.rotateRadians = 0
|
||||
rr.rotateRadians = nil
|
||||
}
|
||||
|
||||
// Save implements the interface method.
|
||||
|
|
7
style.go
7
style.go
|
@ -33,7 +33,7 @@ type Style struct {
|
|||
TextVerticalAlign TextVerticalAlign
|
||||
TextWrap TextWrap
|
||||
TextLineSpacing int
|
||||
TextRotationDegrees float64
|
||||
TextRotationDegrees float64 //0 is unset or normal
|
||||
}
|
||||
|
||||
// IsZero returns if the object is set or not.
|
||||
|
@ -262,9 +262,8 @@ func (s Style) WriteToRenderer(r Renderer) {
|
|||
r.SetFontColor(s.GetFontColor())
|
||||
r.SetFontSize(s.GetFontSize())
|
||||
|
||||
if s.GetTextRotationDegrees() == 0 {
|
||||
r.ClearTextRotation()
|
||||
} else {
|
||||
r.ClearTextRotation()
|
||||
if s.GetTextRotationDegrees() != 0 {
|
||||
r.SetTextRotation(Math.DegreesToRadians(s.GetTextRotationDegrees()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ type vectorRenderer struct {
|
|||
b *bytes.Buffer
|
||||
c *canvas
|
||||
s *Style
|
||||
r float64
|
||||
p []string
|
||||
fc *font.Drawer
|
||||
}
|
||||
|
@ -168,18 +167,22 @@ func (vr *vectorRenderer) MeasureText(body string) (box Box) {
|
|||
|
||||
box.Right = w
|
||||
box.Bottom = int(drawing.PointsToPixels(vr.dpi, vr.s.FontSize))
|
||||
if vr.c.textTheta == nil {
|
||||
return
|
||||
}
|
||||
box = box.Rotate(*vr.c.textTheta)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetTextRotation sets the text rotation.
|
||||
func (vr *vectorRenderer) SetTextRotation(radians float64) {
|
||||
vr.c.r = radians
|
||||
vr.c.textTheta = &radians
|
||||
}
|
||||
|
||||
// ClearTextRotation clears the text rotation.
|
||||
func (vr *vectorRenderer) ClearTextRotation() {
|
||||
vr.c.r = 0
|
||||
vr.c.textTheta = nil
|
||||
}
|
||||
|
||||
// Save saves the renderer's contents to a writer.
|
||||
|
@ -196,11 +199,11 @@ func newCanvas(w io.Writer) *canvas {
|
|||
}
|
||||
|
||||
type canvas struct {
|
||||
w io.Writer
|
||||
dpi float64
|
||||
r float64
|
||||
width int
|
||||
height int
|
||||
w io.Writer
|
||||
dpi float64
|
||||
textTheta *float64
|
||||
width int
|
||||
height int
|
||||
}
|
||||
|
||||
func (c *canvas) Start(width, height int) {
|
||||
|
@ -218,10 +221,10 @@ func (c *canvas) Path(d string, style Style) {
|
|||
}
|
||||
|
||||
func (c *canvas) Text(x, y int, body string, style Style) {
|
||||
if c.r == 0 {
|
||||
if c.textTheta == nil {
|
||||
c.w.Write([]byte(fmt.Sprintf(`<text x="%d" y="%d" style="%s">%s</text>`, x, y, c.styleAsSVG(style), body)))
|
||||
} else {
|
||||
transform := fmt.Sprintf(` transform="rotate(%0.2f,%d,%d)"`, Math.RadiansToDegrees(c.r), x, y)
|
||||
transform := fmt.Sprintf(` transform="rotate(%0.2f,%d,%d)"`, Math.RadiansToDegrees(*c.textTheta), x, y)
|
||||
c.w.Write([]byte(fmt.Sprintf(`<text x="%d" y="%d" style="%s"%s>%s</text>`, x, y, c.styleAsSVG(style), transform, body)))
|
||||
}
|
||||
}
|
||||
|
|
10
xaxis.go
10
xaxis.go
|
@ -7,13 +7,15 @@ import (
|
|||
|
||||
// XAxis represents the horizontal axis.
|
||||
type XAxis struct {
|
||||
Name string
|
||||
NameStyle Style
|
||||
Name string
|
||||
NameStyle Style
|
||||
|
||||
Style Style
|
||||
ValueFormatter ValueFormatter
|
||||
Range Range
|
||||
Ticks []Tick
|
||||
|
||||
TickStyle Style
|
||||
Ticks []Tick
|
||||
TickPosition TickPosition
|
||||
|
||||
GridLines []GridLine
|
||||
|
@ -139,7 +141,7 @@ func (xa XAxis) Render(r Renderer, canvasBox Box, ra Range, defaults Style, tick
|
|||
r.LineTo(tx, canvasBox.Bottom+DefaultVerticalTickHeight)
|
||||
r.Stroke()
|
||||
|
||||
tickStyle.GetTextOptions().WriteToRenderer(r)
|
||||
xa.TickStyle.InheritFrom(xa.Style.InheritFrom(defaults)).WriteToRenderer(r)
|
||||
tb := r.MeasureText(t.Label)
|
||||
|
||||
switch tp {
|
||||
|
|
8
yaxis.go
8
yaxis.go
|
@ -22,8 +22,8 @@ type YAxis struct {
|
|||
|
||||
TickStyle Style
|
||||
Ticks []Tick
|
||||
GridLines []GridLine
|
||||
|
||||
GridLines []GridLine
|
||||
GridMajorStyle Style
|
||||
GridMinorStyle Style
|
||||
}
|
||||
|
@ -149,11 +149,10 @@ func (ya YAxis) Render(r Renderer, canvasBox Box, ra Range, defaults Style, tick
|
|||
|
||||
var maxTextWidth int
|
||||
for _, t := range ticks {
|
||||
ya.TickStyle.InheritFrom(ya.Style.InheritFrom(defaults)).WriteToRenderer(r)
|
||||
|
||||
v := t.Value
|
||||
ly := canvasBox.Bottom - ra.Translate(v)
|
||||
|
||||
ya.TickStyle.InheritFrom(ya.Style.InheritFrom(defaults)).WriteToRenderer(r)
|
||||
tb := r.MeasureText(t.Label)
|
||||
|
||||
if tb.Width() > maxTextWidth {
|
||||
|
@ -167,7 +166,8 @@ func (ya YAxis) Render(r Renderer, canvasBox Box, ra Range, defaults Style, tick
|
|||
}
|
||||
|
||||
r.Text(t.Label, finalTextX, finalTextY)
|
||||
r.ClearTextRotation()
|
||||
|
||||
ya.Style.InheritFrom(defaults).WriteToRenderer(r)
|
||||
|
||||
r.MoveTo(lx, ly)
|
||||
if ya.AxisType == YAxisPrimary {
|
||||
|
|
Loading…
Reference in a new issue