clockface: xml
This commit is contained in:
parent
423c9e9567
commit
7b3fb0f91c
@ -1,6 +1,8 @@
|
|||||||
package clockface
|
package clockface
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -11,13 +13,43 @@ type Point struct {
|
|||||||
Y float64
|
Y float64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
secondHandLength = 90
|
||||||
|
clockCentreX = 150
|
||||||
|
clockCentreY = 150
|
||||||
|
)
|
||||||
|
|
||||||
|
const svgStart = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
viewBox="0 0 300 300"
|
||||||
|
version="2.0">`
|
||||||
|
|
||||||
|
const bezel = `<circle cx="150" cy="150" r="100" style="fill:#fff;stroke:#000;stroke-width:5px;"/>`
|
||||||
|
|
||||||
|
const svgEnd = `</svg>`
|
||||||
|
|
||||||
|
func SVGWriter(w io.Writer, t time.Time) {
|
||||||
|
io.WriteString(w, svgStart)
|
||||||
|
io.WriteString(w, bezel)
|
||||||
|
SecondHand(w, t)
|
||||||
|
io.WriteString(w, svgEnd)
|
||||||
|
}
|
||||||
|
|
||||||
// SecondHand is the unit vector of the second hand of an analogue clock at the time `t` represented as a Point
|
// SecondHand is the unit vector of the second hand of an analogue clock at the time `t` represented as a Point
|
||||||
func SecondHand(t time.Time) Point {
|
func SecondHand(w io.Writer, t time.Time) {
|
||||||
p := secondHandPoint(t)
|
p := secondHandPoint(t)
|
||||||
p = Point{p.X * 90, p.Y * 90} // scale
|
p = Point{p.X * secondHandLength, p.Y * secondHandLength} // scale
|
||||||
p = Point{p.X, -p.Y} // flip
|
p = Point{p.X, -p.Y} // flip
|
||||||
p = Point{p.X + 150, p.Y + 150} // translate
|
p = Point{p.X + clockCentreX, p.Y + clockCentreY} // translate
|
||||||
return p
|
fmt.Fprintf(
|
||||||
|
w,
|
||||||
|
`<line x1="150" y1="150" x2="%f" y2="%f" style="fill:none;stroke:#f00;stroke-width:3px;"/>`,
|
||||||
|
p.X,
|
||||||
|
p.Y,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func secondsInRadians(t time.Time) float64 {
|
func secondsInRadians(t time.Time) float64 {
|
||||||
|
@ -1,28 +1,81 @@
|
|||||||
package clockface
|
package clockface
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/xml"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSecondHandAtMidnight(t *testing.T) {
|
type Svg struct {
|
||||||
|
XMLName xml.Name `xml:"svg"`
|
||||||
|
Text string `xml:",chardata"`
|
||||||
|
Xmlns string `xml:"xmlns,attr"`
|
||||||
|
Width string `xml:"width,attr"`
|
||||||
|
Height string `xml:"height,attr"`
|
||||||
|
ViewBox string `xml:"viewBox,attr"`
|
||||||
|
Version string `xml:"version,attr"`
|
||||||
|
Circle struct {
|
||||||
|
Text string `xml:",chardata"`
|
||||||
|
Cx string `xml:"cx,attr"`
|
||||||
|
Cy string `xml:"cy,attr"`
|
||||||
|
R string `xml:"r,attr"`
|
||||||
|
Style string `xml:"style,attr"`
|
||||||
|
} `xml:"circle"`
|
||||||
|
Line []struct {
|
||||||
|
Text string `xml:",chardata"`
|
||||||
|
X1 string `xml:"x1,attr"`
|
||||||
|
Y1 string `xml:"y1,attr"`
|
||||||
|
X2 string `xml:"x2,attr"`
|
||||||
|
Y2 string `xml:"y2,attr"`
|
||||||
|
Style string `xml:"style,attr"`
|
||||||
|
} `xml:"line"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// func TestSecondHandAtMidnight(t *testing.T) {
|
||||||
|
// tm := time.Date(1337, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||||
|
//
|
||||||
|
// want := Point{X: 150, Y: 150 - 90}
|
||||||
|
// got := SecondHand(tm)
|
||||||
|
//
|
||||||
|
// if got != want {
|
||||||
|
// t.Errorf("Got %v, wanted %v", got, want)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func TestSecondHandAt30Seconds(t *testing.T) {
|
||||||
|
// tm := time.Date(1337, time.January, 1, 0, 0, 30, 0, time.UTC)
|
||||||
|
//
|
||||||
|
// want := Point{X: 150, Y: 150 + 90}
|
||||||
|
// got := SecondHand(tm)
|
||||||
|
//
|
||||||
|
// if got != want {
|
||||||
|
// t.Errorf("Got %v, wanted %v", got, want)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
func TestSVGWriterAtMidnight(t *testing.T) {
|
||||||
tm := time.Date(1337, time.January, 1, 0, 0, 0, 0, time.UTC)
|
tm := time.Date(1337, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||||
|
|
||||||
want := Point{X: 150, Y: 150 - 90}
|
b := bytes.Buffer{}
|
||||||
got := SecondHand(tm)
|
SVGWriter(&b, tm)
|
||||||
|
|
||||||
if got != want {
|
svg := Svg{}
|
||||||
t.Errorf("Got %v, wanted %v", got, want)
|
xml.Unmarshal(b.Bytes(), &svg)
|
||||||
|
|
||||||
|
x2 := "150.000000"
|
||||||
|
y2 := "60.000000"
|
||||||
|
|
||||||
|
for _, line := range svg.Line {
|
||||||
|
if line.X2 == x2 && line.Y2 == y2 {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSecondHandAt30Seconds(t *testing.T) {
|
t.Errorf(
|
||||||
tm := time.Date(1337, time.January, 1, 0, 0, 30, 0, time.UTC)
|
"Expected to find the second hand with x2 of %+v and y2 of %+v, in the SVG output %v",
|
||||||
|
x2,
|
||||||
want := Point{X: 150, Y: 150 + 90}
|
y2,
|
||||||
got := SecondHand(tm)
|
b.String(),
|
||||||
|
)
|
||||||
if got != want {
|
|
||||||
t.Errorf("Got %v, wanted %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
28
main.go
28
main.go
@ -1,9 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"gobytest/clockface"
|
"gobytest/clockface"
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -18,29 +16,5 @@ func main() {
|
|||||||
// clockface
|
// clockface
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
|
|
||||||
sh := clockface.SecondHand(t)
|
clockface.SVGWriter(os.Stdout, t)
|
||||||
io.WriteString(os.Stdout, svgStart)
|
|
||||||
io.WriteString(os.Stdout, bezel)
|
|
||||||
io.WriteString(os.Stdout, secondHandTag(sh))
|
|
||||||
io.WriteString(os.Stdout, svgEnd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func secondHandTag(p clockface.Point) string {
|
|
||||||
return fmt.Sprintf(
|
|
||||||
`<line x1="150" y1="150" x2="%f" y2="%f" style="fill:none;stroke:#f00;stroke-width:3px;"/>`,
|
|
||||||
p.X,
|
|
||||||
p.Y,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const svgStart = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
viewBox="0 0 300 300"
|
|
||||||
version="2.0">`
|
|
||||||
|
|
||||||
const bezel = `<circle cx="150" cy="150" r="100" style="fill:#fff;stroke:#000;stroke-width:5px;"/>`
|
|
||||||
|
|
||||||
const svgEnd = `</svg>`
|
|
||||||
|
Loading…
Reference in New Issue
Block a user