2024-09-23 14:49:29 +00:00
|
|
|
package clockface
|
|
|
|
|
|
|
|
import (
|
2024-09-23 15:24:40 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2024-09-23 14:49:29 +00:00
|
|
|
"math"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Point represents a two-dimentional Cartesian coordinate
|
|
|
|
type Point struct {
|
|
|
|
X float64
|
|
|
|
Y float64
|
|
|
|
}
|
|
|
|
|
2024-09-23 15:24:40 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2024-09-23 14:49:29 +00:00
|
|
|
// SecondHand is the unit vector of the second hand of an analogue clock at the time `t` represented as a Point
|
2024-09-23 15:24:40 +00:00
|
|
|
func SecondHand(w io.Writer, t time.Time) {
|
2024-09-23 14:49:29 +00:00
|
|
|
p := secondHandPoint(t)
|
2024-09-23 15:24:40 +00:00
|
|
|
p = Point{p.X * secondHandLength, p.Y * secondHandLength} // scale
|
|
|
|
p = Point{p.X, -p.Y} // flip
|
|
|
|
p = Point{p.X + clockCentreX, p.Y + clockCentreY} // translate
|
|
|
|
fmt.Fprintf(
|
|
|
|
w,
|
|
|
|
`<line x1="150" y1="150" x2="%f" y2="%f" style="fill:none;stroke:#f00;stroke-width:3px;"/>`,
|
|
|
|
p.X,
|
|
|
|
p.Y,
|
|
|
|
)
|
2024-09-23 14:49:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func secondsInRadians(t time.Time) float64 {
|
|
|
|
// XXX:Wanted 3.141592653589793 radians, but got 3.1415926535897936
|
|
|
|
// return float64(t.Second()) * (math.Pi / 30)
|
|
|
|
|
|
|
|
return math.Pi / (30 / float64(t.Second()))
|
|
|
|
}
|
|
|
|
|
|
|
|
func secondHandPoint(t time.Time) Point {
|
|
|
|
angle := secondsInRadians(t)
|
|
|
|
x := math.Sin(angle)
|
|
|
|
y := math.Cos(angle)
|
|
|
|
|
|
|
|
// XXX: Wanted {0 -1} Point, but got {1.2246467991473515e-16 -1}
|
|
|
|
return Point{x, y}
|
|
|
|
}
|