slabOS/lib/basalt/objects/Graph.lua
2025-06-02 10:23:40 +03:00

171 lines
5.5 KiB
Lua

return function(name, basalt)
local base = basalt.getObject("ChangeableObject")(name, basalt)
local objectType = "Graph"
base:setZIndex(5)
base:setSize(30, 10)
local graphData = {}
local graphColor = colors.gray
local graphSymbol = "\7"
local graphSymbolCol = colors.black
local maxValue = 100
local minValue = 0
local graphType = "line"
local maxEntries = 10
local object = {
getType = function(self)
return objectType
end,
setGraphColor = function(self, color)
graphColor = color or graphColor
self:updateDraw()
return self
end,
setGraphSymbol = function(self, symbol, symbolcolor)
graphSymbol = symbol or graphSymbol
graphSymbolCol = symbolcolor or graphSymbolCol
self:updateDraw()
return self
end,
setGraphSymbolColor = function(self, symbolColor)
return self:setGraphSymbolColor(nil, symbolColor)
end,
getGraphSymbol = function(self)
return graphSymbol, graphSymbolCol
end,
getGraphSymbolColor = function(self)
return graphSymbolCol
end,
addDataPoint = function(self, value)
if value >= minValue and value <= maxValue then
table.insert(graphData, value)
self:updateDraw()
end
if(#graphData>100)then -- 100 is hard capped to prevent memory leaks
table.remove(graphData,1)
end
return self
end,
setMaxValue = function(self, value)
maxValue = value
self:updateDraw()
return self
end,
getMaxValue = function(self)
return maxValue
end,
setMinValue = function(self, value)
minValue = value
self:updateDraw()
return self
end,
getMinValue = function(self)
return minValue
end,
setGraphType = function(self, graph_type)
if graph_type == "scatter" or graph_type == "line" or graph_type == "bar" then
graphType = graph_type
self:updateDraw()
end
return self
end,
getGraphType = function(self)
return graphType
end,
setMaxEntries = function(self, value)
maxEntries = value
self:updateDraw()
return self
end,
getMaxEntries = function(self)
return maxEntries
end,
clear = function(self)
graphData = {}
self:updateDraw()
return self
end,
draw = function(self)
base.draw(self)
self:addDraw("graph", function()
local obx, oby = self:getPosition()
local w, h = self:getSize()
local bgCol, fgCol = self:getBackground(), self:getForeground()
local range = maxValue - minValue
local prev_x, prev_y
local startIndex = #graphData - maxEntries + 1
if startIndex < 1 then startIndex = 1 end
for i = startIndex, #graphData do
local data = graphData[i]
local x = math.floor(((w - 1) / (maxEntries - 1)) * (i - startIndex) + 1.5)
local y = math.floor((h - 1) - ((h - 1) / range) * (data - minValue) + 1.5)
if graphType == "scatter" then
self:addBackgroundBox(x, y, 1, 1, graphColor)
self:addForegroundBox(x, y, 1, 1, graphSymbolCol)
self:addTextBox(x, y, 1, 1, graphSymbol)
elseif graphType == "line" then
if prev_x and prev_y then
local dx = math.abs(x - prev_x)
local dy = math.abs(y - prev_y)
local sx = prev_x < x and 1 or -1
local sy = prev_y < y and 1 or -1
local err = dx - dy
while true do
self:addBackgroundBox(prev_x, prev_y, 1, 1, graphColor)
self:addForegroundBox(prev_x, prev_y, 1, 1, graphSymbolCol)
self:addTextBox(prev_x, prev_y, 1, 1, graphSymbol)
if prev_x == x and prev_y == y then
break
end
local e2 = 2 * err
if e2 > -dy then
err = err - dy
prev_x = prev_x + sx
end
if e2 < dx then
err = err + dx
prev_y = prev_y + sy
end
end
end
prev_x, prev_y = x, y
elseif graphType == "bar" then
self:addBackgroundBox(x - 1, y, 1, h - y, graphColor)
end
end
end)
end,
}
object.__index = object
return setmetatable(object, base)
end