|
| 1 | +package svg |
| 2 | + |
| 3 | +import ( |
| 4 | + "encoding/xml" |
| 5 | + "fmt" |
| 6 | + "io" |
| 7 | + "time" |
| 8 | + |
| 9 | + "github.com/leetcode-golang-classroom/learn-golang-with-tests/clockface_sample/clockface" |
| 10 | +) |
| 11 | + |
| 12 | +type SVG struct { |
| 13 | + XMLName xml.Name `xml:"svg"` |
| 14 | + Xmlns string `xml:"xmlns,attr"` |
| 15 | + Width string `xml:"width,attr"` |
| 16 | + Height string `xml:"height,attr"` |
| 17 | + ViewBox string `xml:"viewBox,attr"` |
| 18 | + Version string `xml:"version,attr"` |
| 19 | + Circle Circle `xml:"circle"` |
| 20 | + Line []Line `xml:"line"` |
| 21 | +} |
| 22 | + |
| 23 | +type Circle struct { |
| 24 | + Cx float64 `xml:"cx,attr"` |
| 25 | + Cy float64 `xml:"cy,attr"` |
| 26 | + R float64 `xml:"r,attr"` |
| 27 | +} |
| 28 | + |
| 29 | +type Line struct { |
| 30 | + X1 float64 `xml:"x1,attr"` |
| 31 | + Y1 float64 `xml:"y1,attr"` |
| 32 | + X2 float64 `xml:"x2,attr"` |
| 33 | + Y2 float64 `xml:"y2,attr"` |
| 34 | +} |
| 35 | + |
| 36 | +const ( |
| 37 | + secondHandLength = 90 |
| 38 | + minuteHandLength = 80 |
| 39 | + hourHandLength = 50 |
| 40 | + clockCentreX = 150 |
| 41 | + clockCentreY = 150 |
| 42 | +) |
| 43 | + |
| 44 | +// Write writes an SVG representation of an analogue clock, showing the time t, to the writer w. |
| 45 | +func Write(w io.Writer, t time.Time) { |
| 46 | + io.WriteString(w, svgStart) |
| 47 | + io.WriteString(w, bezel) |
| 48 | + secondHand(w, t) |
| 49 | + minuteHand(w, t) |
| 50 | + hourHand(w, t) |
| 51 | + io.WriteString(w, svgEnd) |
| 52 | +} |
| 53 | + |
| 54 | +func secondHand(w io.Writer, t time.Time) { |
| 55 | + p := makeHand(clockface.SecondHandPoint(t), secondHandLength) |
| 56 | + fmt.Fprintf(w, `<line x1="150" y1="150" x2="%.3f" y2="%.3f" style="fill:none;stroke:#f00;stroke-width:3px;"/>`, p.X, p.Y) |
| 57 | +} |
| 58 | + |
| 59 | +func minuteHand(w io.Writer, t time.Time) { |
| 60 | + p := makeHand(clockface.MinuteHandPoint(t), minuteHandLength) |
| 61 | + fmt.Fprintf(w, `<line x1="150" y1="150" x2="%.3f" y2="%.3f" style="fill:none;stroke:#000;stroke-width:3px;"/>`, p.X, p.Y) |
| 62 | +} |
| 63 | + |
| 64 | +func makeHand(p clockface.Point, length float64) clockface.Point { |
| 65 | + p = clockface.Point{X: p.X * length, Y: p.Y * length} // scale |
| 66 | + p = clockface.Point{X: p.X, Y: -p.Y} // flip |
| 67 | + // transition |
| 68 | + return clockface.Point{X: p.X + clockCentreX, Y: p.Y + clockCentreY} |
| 69 | +} |
| 70 | + |
| 71 | +const svgStart = `<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
| 72 | +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> |
| 73 | +<svg xmlns="http://www.w3.org/2000/svg" |
| 74 | + width="100%" |
| 75 | + height="100%" |
| 76 | + viewBox="0 0 300 300" |
| 77 | + version="2.0">` |
| 78 | + |
| 79 | +const bezel = `<circle cx="150" cy="150" r="100" style="fill:#fff;stroke:#000;stroke-width:5px;"/>` |
| 80 | + |
| 81 | +const svgEnd = `</svg>` |
| 82 | + |
| 83 | +func hourHand(w io.Writer, t time.Time) { |
| 84 | + p := makeHand(clockface.HourHandPoint(t), hourHandLength) |
| 85 | + fmt.Fprintf(w, `<line x1="150" y1="150" x2="%.3f" y2="%.3f" style="fill:none;stroke:#000;stroke-width:3px;"/>`, p.X, p.Y) |
| 86 | +} |
0 commit comments