Advertisement
MrBartek

charts.lua

Apr 22nd, 2021
51
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.40 KB | None | 0 0
  1. local bit32 = require("bit32")
  2. local component = require("component")
  3.  
  4. local sides = {
  5. TOP = 1,
  6. BOTTOM = 2,
  7. LEFT = 3,
  8. RIGHT = 4,
  9. "TOP",
  10. "BOTTOM",
  11. "LEFT",
  12. "RIGHT"
  13. }
  14.  
  15. local function patch(base, head)
  16. for k, v in pairs(head) do
  17. if type(v) ~= "table" or type(base[k]) ~= "table" then
  18. base[k] = v
  19. else
  20. patch(base[k], v)
  21. end
  22. end
  23. end
  24.  
  25. local Histogram
  26.  
  27. do
  28. local characters = {" ", "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"}
  29. local meta = {}
  30. meta.__index = meta
  31.  
  32. local function calcHeight(height, perc)
  33. return math.floor(perc * height * 8)
  34. end
  35.  
  36. local function getBarChars(height, halfHeight, totalHeight)
  37. if height < 0 then
  38. height = -height
  39. local spaces = math.floor(height / 8)
  40. local part = characters[8 - (height - spaces * 8) + 1]
  41. if spaces * 8 == height then
  42. part = ""
  43. end
  44. local blocks = totalHeight - halfHeight
  45. return characters[9]:rep(blocks) .. characters[1]:rep(spaces) .. part
  46. end
  47. local blocks = math.floor(height / 8)
  48. local part = characters[height - blocks * 8 + 1]
  49. if blocks * 8 == height then
  50. part = ""
  51. end
  52. local spaces = halfHeight - blocks - (part ~= "" and 1 or 0)
  53. return characters[1]:rep(spaces) .. part .. characters[9]:rep(blocks)
  54. end
  55.  
  56. function meta:draw(container)
  57. if self.max == self.min and self.max == 0 then
  58. error("min and max are both 0!")
  59. end
  60. local loopStart, loopEnd = 1, container.width
  61. if self.align == sides.RIGHT then
  62. loopEnd = #self.values
  63. loopStart = loopEnd - container.width + 1
  64. end
  65. local max = self.max - self.min
  66. local min = 0
  67. local bar = 1
  68.  
  69. local levelY = self.level.y
  70. if levelY > 0 and levelY < 1 then
  71. levelY = levelY * container.height
  72. elseif levelY < 0 then
  73. levelY = container.height + levelY + 1
  74. end
  75. levelY = math.floor(levelY)
  76. if levelY > container.height then
  77. levelY = container.height
  78. end
  79.  
  80. local levelV = self.level.value or self.min
  81. if levelV < self.min or levelV > self.max then
  82. error("invalid level value set!")
  83. end
  84.  
  85. for i = loopStart, loopEnd do
  86. local value = self.values[i] or levelV
  87. if value < self.min or value > self.max then
  88. error("incorrect min/max values: min = " .. self.min .. ", max = " .. self.max .. ", v = " .. value)
  89. end
  90. local v = value - levelV
  91. local halfH = v < 0 and levelY or container.height - levelY
  92.  
  93. local perc
  94. if v < 0 then
  95. perc = (levelV + value) / (levelV - self.min)
  96. else
  97. perc = (value - levelV) / (self.max - levelV)
  98. end
  99. if v == 0 and max == 0 then
  100. perc = 1
  101. end
  102.  
  103. local height = calcHeight(halfH, perc)
  104. local chars = getBarChars(height, halfH, container.height)
  105.  
  106. local fg, bg = self.colorFunc(i, perc, value, self, container)
  107. fg = fg or container.fg
  108. bg = bg or container.bg
  109.  
  110. if v < 0 then
  111. fg, bg = bg, fg
  112. end
  113.  
  114. if container.gpu.getForeground() ~= fg then
  115. container.gpu.setForeground(fg)
  116. end
  117.  
  118. if container.gpu.getBackground() ~= bg then
  119. container.gpu.setBackground(bg)
  120. end
  121.  
  122. container.gpu.set(container:getX() + bar - 1,
  123. container:getY(),
  124. chars,
  125. true)
  126. bar = bar + 1
  127. end
  128. end
  129.  
  130. Histogram = function(tbl)
  131. local obj = {
  132. values = {},
  133. align = sides.LEFT,
  134. colorFunc = function() end,
  135. min = 0,
  136. max = 1,
  137. level = {
  138. y = 0,
  139. value = nil
  140. }
  141. }
  142. if tbl then
  143. patch(obj, tbl)
  144. end
  145. return setmetatable(obj, meta)
  146. end
  147. end
  148.  
  149. local ProgressBar
  150. do
  151. local meta = {}
  152. meta.__index = meta
  153. local charsV = {" ", "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"}
  154. local charsH = {" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█"}
  155.  
  156. local function calcLength(perc, max)
  157. return math.floor(perc * 8 * max), max * 8
  158. end
  159.  
  160. local function getChars(direction, len, max)
  161. if direction == sides.RIGHT then
  162. local blocks = math.floor(len / 8)
  163. local part = charsH[len - blocks * 8 + 1]
  164. if blocks * 8 == len then
  165. part = ""
  166. end
  167. local spaces = max / 8 - blocks - (part ~= "" and 1 or 0)
  168. return charsH[9]:rep(blocks) .. part .. charsH[1]:rep(spaces)
  169. elseif direction == sides.LEFT then
  170. local spaces = math.floor(len / 8)
  171. local part = charsH[9 - (len - spaces * 8)]
  172. if spaces * 8 == len then
  173. part = ""
  174. end
  175. local blocks = max / 8 - spaces - (part ~= "" and 1 or 0)
  176. return charsH[9]:rep(blocks) .. part .. charsH[1]:rep(spaces)
  177. elseif direction == sides.TOP then
  178. local blocks = math.floor(len / 8)
  179. local part = charsV[len - blocks * 8 + 1]
  180. if blocks * 8 == len then
  181. part = ""
  182. end
  183. local spaces = max / 8 - blocks - (part ~= "" and 1 or 0)
  184. return charsV[1]:rep(spaces) .. part .. charsV[9]:rep(blocks)
  185. elseif direction == sides.BOTTOM then
  186. local spaces = math.floor(len / 8)
  187. local part = charsV[9 - (len - spaces * 8)]
  188. if spaces * 8 == len then
  189. part = ""
  190. end
  191. local blocks = max / 8 - spaces - (part ~= "" and 1 or 0)
  192. return charsV[1]:rep(spaces) .. part .. charsV[9]:rep(blocks)
  193. end
  194. end
  195.  
  196. function meta:draw(container)
  197. local min = 0
  198. local max = self.max - self.min
  199. if min == max and min == 0 then
  200. error("min and max values are the same")
  201. end
  202. local value = self.value - self.min
  203. if not (value >= min and value <= max) then
  204. error("incorrect min/max values: min = " .. self.min .. ", max = " .. self.max .. ", v = " .. self.value)
  205. end
  206. local perc = value / max
  207. local maxLength = container.width
  208. if self.direction == sides.TOP or self.direction == sides.BOTTOM then
  209. maxLength = container.height
  210. end
  211. local chars = getChars(self.direction, calcLength(perc, maxLength))
  212. local fg, bg = self.colorFunc(self.value, perc, self, container)
  213. fg = fg or container.fg
  214. bg = bg or container.bg
  215. if self.direction == sides.LEFT or self.direction == sides.BOTTOM then
  216. fg, bg = bg, fg
  217. end
  218. if container.gpu.getForeground() ~= fg then
  219. container.gpu.setForeground(fg)
  220. end
  221. if container.gpu.getBackground() ~= bg then
  222. container.gpu.setBackground(bg)
  223. end
  224. if self.direction == sides.TOP or self.direction == sides.BOTTOM then
  225. for x = 1, container.width, 1 do
  226. container.gpu.set(container:getX() + x - 1, container:getY(), chars, true)
  227. end
  228. else
  229. for y = 1, container.height, 1 do
  230. container.gpu.set(container:getX(), container:getY() + y - 1, chars)
  231. end
  232. end
  233. end
  234.  
  235. ProgressBar = function(tbl)
  236. local obj = {
  237. direction = sides.RIGHT,
  238. min = 0,
  239. max = 1,
  240. value = 0,
  241. colorFunc = function(value, perc, prbar, container) end
  242. }
  243. if tbl then
  244. patch(obj, tbl)
  245. end
  246. return setmetatable(obj, meta)
  247. end
  248. end
  249.  
  250. local Container
  251. do
  252. local meta = {}
  253. meta.__index = meta
  254.  
  255. function meta:draw()
  256. if self.payload then
  257. local fg = self.gpu.getForeground()
  258. local bg = self.gpu.getBackground()
  259. if fg ~= self.fg then
  260. self.gpu.setForeground(self.fg)
  261. end
  262. if bg ~= self.bg then
  263. self.gpu.setBackground(self.bg)
  264. end
  265.  
  266. self.gpu.fill(self.x, self.y, self.width, self.height, " ")
  267. self.payload:draw(self)
  268.  
  269. if self.gpu.getForeground() ~= fg then
  270. self.gpu.setForeground(fg)
  271. end
  272. if self.gpu.getBackground() ~= bg then
  273. self.gpu.setBackground(bg)
  274. end
  275. end
  276. end
  277.  
  278. function meta:getX()
  279. return self.x + self.payloadX - 1
  280. end
  281.  
  282. function meta:getY()
  283. return self.y + self.payloadY - 1
  284. end
  285.  
  286. Container = function(tbl)
  287. local obj = {
  288. gpu = component.gpu,
  289. fg = 0xffffff,
  290. bg = 0x000000,
  291. x = 1,
  292. y = 1,
  293. payloadX = 1,
  294. payloadY = 1,
  295. width = 80,
  296. height = 25,
  297. payload = nil
  298. }
  299. if tbl then
  300. patch(obj, tbl)
  301. end
  302. return setmetatable(obj, meta)
  303. end
  304. end
  305.  
  306. return {
  307. sides = sides,
  308. Container = Container,
  309. Histogram = Histogram,
  310. ProgressBar = ProgressBar
  311. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement