mod_stat_minute.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // package mod_stat_minute -- статистика модуля за первые 60 мин
  2. package mod_stat_minute
  3. import (
  4. "bytes"
  5. "fmt"
  6. "math"
  7. "sync"
  8. "time"
  9. svg "github.com/ajstarks/svgo"
  10. )
  11. // ModStatMinutes -- статистика модуля за первые 60 мин
  12. type ModStatMinutes struct {
  13. sync.RWMutex
  14. lst []int // Список значений за последние 60 мин
  15. bufSvg *bytes.Buffer
  16. }
  17. // NewModStatMinute -- возвращает новую статистику модуля за последние 60 мин
  18. func NewModStatMinute() *ModStatMinutes {
  19. sf := &ModStatMinutes{
  20. lst: []int{},
  21. bufSvg: bytes.NewBufferString(""),
  22. }
  23. return sf
  24. }
  25. // Sum -- возвращает сумму элементов по требованию
  26. func (sf *ModStatMinutes) Sum() int {
  27. sf.RLock()
  28. defer sf.RUnlock()
  29. sum := 0
  30. for _, val := range sf.lst {
  31. sum += val
  32. }
  33. return sum
  34. }
  35. // Add -- добавляет значение в часовой срез
  36. func (sf *ModStatMinutes) Add(val int) {
  37. sf.Lock()
  38. defer sf.Unlock()
  39. for len(sf.lst) < 60 {
  40. sf.lst = append(sf.lst, math.MinInt64)
  41. }
  42. sf.lst = append(sf.lst, val)
  43. if len(sf.lst) > 60 {
  44. sf.lst = sf.lst[1:]
  45. }
  46. }
  47. // Svg -- возвращает сгенерированный SVG по часовому срезу
  48. func (sf *ModStatMinutes) Svg() string {
  49. sf.RLock()
  50. defer sf.RUnlock()
  51. sf.bufSvg.Reset()
  52. cnv := svg.New(sf.bufSvg)
  53. cnv.Start(480, 320)
  54. cnv.Title("Last 60 minute")
  55. cnv.Desc("Graphic of last 60 minute")
  56. cnv.Text(20, 20, "Last 60 minute", "")
  57. var (
  58. valMin = math.MaxInt64
  59. valMax = math.MinInt64
  60. )
  61. fnGetMinMax := func() { // Вычисляет максимальное и минимальное значение в графике
  62. for _, val := range sf.lst {
  63. if val < valMin {
  64. valMin = val
  65. }
  66. if val > valMax {
  67. valMax = val
  68. }
  69. }
  70. }
  71. fnGetMinMax()
  72. for i, val := range sf.lst {
  73. x1 := int(float32(i)*6) + 42
  74. y1 := int(240 * float32(valMax) / float32(val))
  75. cnv.Rect(x1, 280-y1, 5, y1, "fill:true;stroke:red;")
  76. }
  77. fnDrawNet := func() {
  78. // Метки величины
  79. if valMin == math.MaxInt64 || valMin == math.MinInt64 {
  80. valMin = 0
  81. }
  82. cnv.Text(25, 285, fmt.Sprint(valMin), "")
  83. if valMax == math.MinInt64 || valMax == math.MaxInt64 {
  84. valMax = 1
  85. }
  86. cnv.Text(25, 45, fmt.Sprint(valMax), "")
  87. // Метки времени
  88. timeNow := time.Now().Local()
  89. timeSub60 := timeNow.Add(-60 * time.Minute).Format("04")
  90. cnv.Text(40, 295, timeSub60, "")
  91. timeSub45 := timeNow.Add(-45 * time.Minute).Format("04")
  92. cnv.Text(128, 295, timeSub45, "")
  93. timeSub30 := timeNow.Add(-30 * time.Minute).Format("04")
  94. cnv.Text(216, 295, timeSub30, "")
  95. timeSub15 := timeNow.Add(-15 * time.Minute).Format("04")
  96. cnv.Text(304, 295, timeSub15, "")
  97. timeSub0 := time.Now().Format("04")
  98. cnv.Text(392, 295, timeSub0, "")
  99. cnv.Line(40, 280, 40, 38, "fill:true;stroke:black;stroke-width:4")
  100. cnv.Line(40, 280, 442, 280, "fill:true;stroke:black;stroke-width:4")
  101. count := 0
  102. for x := 40; x < 460; x += 20 {
  103. cnv.Line(x, 40, x, 280, "fill:true;stroke:gray")
  104. if count%5 == 0 {
  105. cnv.Text(x+3, 278, fmt.Sprint(x), "fill:white;stroke:gray")
  106. }
  107. count++
  108. }
  109. count = 0
  110. for y := 40; y < 300; y += 20 {
  111. cnv.Line(40, y, 440, y, "fill:true;stroke:gray")
  112. if count%5 == 0 {
  113. cnv.Text(43, y+12, fmt.Sprint(y), "fill:white;stroke:gray")
  114. }
  115. count++
  116. }
  117. }
  118. fnDrawNet()
  119. cnv.End()
  120. strOut := sf.bufSvg.String()
  121. return strOut
  122. }