(w, h int, logarithm bool)
| 26 | } |
| 27 | |
| 28 | func (s *Survey) SVG(w, h int, logarithm bool) *bytes.Buffer { |
| 29 | s.Lock() |
| 30 | defer s.Unlock() |
| 31 | |
| 32 | ret := &bytes.Buffer{} |
| 33 | ret.WriteString(fmt.Sprintf(`<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 %d %d">`, w, h)) |
| 34 | ret.WriteString(`<style>*{ font-family: "Lucida Console", Monaco, monospace; box-sizing: border-box; }</style>`) |
| 35 | ret.WriteString(`<defs>`) |
| 36 | id := strconv.FormatInt(time.Now().Unix(), 16) |
| 37 | ret.WriteString(`<linearGradient id="traffic-` + id + `-i" x1="0" x2="1" y1="0" y2="0"><stop offset="0%" stop-color="white" stop-opacity="0.7"/><stop offset="100%" stop-color="white" stop-opacity="0"/></linearGradient>`) |
| 38 | ret.WriteString(`<clipPath id="traffic-` + id + `-c"><rect width="100%" height="100%" fill="none" stroke="none"/></clipPath>`) |
| 39 | ret.WriteString(`</defs><g clip-path="url(#traffic-` + id + `-c)">`) |
| 40 | |
| 41 | wTick := float64(w) / float64(len(s.sent.data)-1) |
| 42 | s.sent.logarithm, s.recved.logarithm = logarithm, logarithm |
| 43 | _, savg, smax := s.sent.Range() |
| 44 | _, ravg, rmax := s.recved.Range() |
| 45 | margin := h / 10 |
| 46 | tick := 60 / s.sent.interval |
| 47 | minutes := len(s.sent.data) / tick |
| 48 | |
| 49 | for i := tick; i < len(s.sent.data); i += tick * 2 { |
| 50 | x := float64(i) * wTick |
| 51 | ret.WriteString(fmt.Sprintf(`<rect x="%f" y="0" width="%f" height="%d" fill="#f7f8f9"/>`, x-wTick, wTick*float64(tick), h)) |
| 52 | } |
| 53 | |
| 54 | for i, m := 0, 0; i < len(s.sent.data); i, m = i+tick*5, m+5 { |
| 55 | x := float64(i) * wTick |
| 56 | ret.WriteString(fmt.Sprintf(`<text x="%f" y="%d" font-size=".3em">-%d</text>`, x+1, h-2, minutes-m)) |
| 57 | } |
| 58 | |
| 59 | polybegin := func(c string) { |
| 60 | ret.WriteString(`<polyline stroke="` + c + `" fill="` + c + `" fill-opacity="0.5" stroke-width="0.5px" points="`) |
| 61 | } |
| 62 | |
| 63 | if delta := smax; delta > 0 { |
| 64 | if logarithm { |
| 65 | delta = s.sent.Log(smax) |
| 66 | margin = h/2 + 1 |
| 67 | } |
| 68 | |
| 69 | hScale := float64(h-margin) / delta |
| 70 | polybegin(`#F44336`) |
| 71 | |
| 72 | x := 0.0 |
| 73 | for i := len(s.sent.data) - 1; i >= 0; i-- { |
| 74 | f := int(s.sent.Get(i) * hScale) |
| 75 | |
| 76 | if x1, x2 := x-wTick/2, x+wTick/2; logarithm { |
| 77 | ret.WriteString(fmt.Sprintf(`%f,%d %f,%d `, x1, h/2-f, x2, h/2-f)) |
| 78 | } else { |
| 79 | ret.WriteString(fmt.Sprintf(`%f,%d %f,%d `, x1, f, x2, f)) |
| 80 | } |
| 81 | x += wTick |
| 82 | } |
| 83 | |
| 84 | if logarithm { |
| 85 | ret.WriteString(fmt.Sprintf(` %d,%d 0,%d"/>`, w, h/2, h/2)) |
no test coverage detected