Time
from the time
package and spits out an SVG of a clock with all the hands - hour, minute and second - pointing in the right direction. How hard can that be?x1
and y1
for this line) is the same for each hand of the clock. The numbers that need to change for each hand of the clock - the parameters to whatever builds the SVG - are the x2
and y2
attributes. We'll need an X and a Y for each of the hands of the clock.text/template
package, or we could just send bytes into a bytes.Buffer
or a writer. But we know we'll need those numbers, so let's focus on testing something that creates them.Point
where the tip of the second hand should go, and a function to get it.SecondHand
:(360 / 60 ) * 37 = 222
, but it's easier just to remember that it's 37/60
of a complete rotation.0, 0
.sin
and cos
.math
math
package has both, with one small snag we'll need to get our heads around; if we look at the description of math.Cos
:Cos returns the cosine of the radian argument x.
clockface
package; they may never get exported, and they may get deleted (or moved) once I have a better grip on what's going on.math
package! If a full turn of a circle is 2π radians, we know that halfway round should just be π radians. math.Pi
provides us with a value for π.testName
converts a time into a digital watch format (HH:MM:SS), and simpleTime
constructs a time.Time
using only the parts we actually care about (again, hours, minutes and seconds).[^1] Here they are:float64
) and we should now have all the tests passing...secondsInRadians
function. By dividing math.Pi
by 30 and then by multiplying it by 30 we've ended up with a number that's no longer the same as math.Pi
.t.Second()
+Inf
(infinity). Dividing by +Inf seems to result in zero and we can see this with the following:Rat
from the math/big
package. But given the objective is to draw an SVG and not land on the moon landings I think we can live with a bit of fuzziness.Points
- they'll work if the X and Y elements are within 0.0000001 of each other. That's still pretty accurate.clockface
package directory, called (confusingly), clockface
. In there we'll put the main
package that will create the binary that will build an SVG:main.go
, you'll start with this code but change the import for the clockface package to point at your own version:os.Stdout
- one string at a time.SecondHand
function is super tied to being an SVG... without mentioning SVGs or actually producing an SVG...SVGWriter
contain things that look like the sort of SVG tag we're expecting for a particular time. For instance:xml.Unmarshal
takes a []byte
of XML data, and a pointer to a struct for it to get unmarshalled in to.zek
a program that will automate all of that hard work for us. Even better, there's an online version at https://www.onlinetool.io/xmltogo/. Just paste the SVG from the top of the file into one box and - bam - out pops:SVG
) but it's definitely good enough to start us off. Paste the struct into the clockface_test
file and let's write a test with it:clockface.SVGWriter
to a bytes.Buffer
and then Unmarshal
it into an Svg
. We then look at each Line
in the Svg
to see if any of them have the expected X2
and Y2
values. If we get a match we return early (passing the test); if not we fail with a (hopefully) informative message.SVGWriter
...%f
format directive is printing our coordinates to the default level of precision - six decimal places. We should be explicit as to what level of precision we're expecting for the coordinates. Let's say three decimal places.main
function:x1
values, for instance?x1
etc. aren't really strings
are they? They're numbers!style
of the hand? Or, for that matter, the empty Text
node that's been generated by zak
?Svg
struct, and the tests, to sharpen everything up.Line
and the Circle
float64
s instead of string
s.Style
and Text
Svg
to SVG
because it's the right thing to do.