Module:Bargraph

-- Filename: BarGraph.lua  Written by: dbanks  Description: A simple bar graph. --

-- Services -- local CoreGuiService = game:GetService('CoreGui')

-- Globals -- local BarZIndex = 1 local LineZIndex = 2

-- Modules -- local StatsUtils = require(CoreGuiService.RobloxGui.Modules.Stats.StatsUtils)

-- Classes -- local BarGraphClass = {} BarGraphClass.__index = BarGraphClass

function BarGraphClass.new(showExtras) local self = {} setmetatable(self, BarGraphClass)

self._barFrame = Instance.new("Frame") self._barFrame.Name = "PS_BarFrame" self._barFrame.BackgroundTransparency = 1.0

self._lineFrame = Instance.new("Frame") self._lineFrame.Name = "PS_LineFrame" self._lineFrame.BackgroundTransparency = 1.0

self._showExtras = showExtras

-- All of the values we are showing in the bar graph, in order. self._values = {} self._bars = {} -- Average of these values. self._average = 0 -- Suggested max for these values. self._target = 0

if self._showExtras then self:_addGraphTarget self:_addGraphAverage end

return self end

function BarGraphClass:SetZIndex(zIndex) self._barFrame.ZIndex = zIndex self._lineFrame.ZIndex = zIndex + 1 if self._showExtras then self._targetLine.ZIndex = self._lineFrame.ZIndex self._averageLine.ZIndex = self._lineFrame.ZIndex end end

function BarGraphClass:PlaceInParent(parent, size, position) self._barFrame.Position = position self._barFrame.Size = size self._barFrame.Parent = parent self._lineFrame.Position = position self._lineFrame.Size = size self._lineFrame.Parent = parent end

function BarGraphClass:SetAxisMax(axisMax) self._axisMax = axisMax end

function BarGraphClass:SetValues(values) self._values = values end

function BarGraphClass:SetAverage(average) self._average = average end

function BarGraphClass:SetTarget(target) -- Set the target value, move corresponding graph line -- accordingly (if present). self._target = target self:_moveGraphTarget end

function BarGraphClass:_updateBarCount(newBarCount) -- Make sure we have exactly this number of bars in _bars. -- Reuse old ones if possible. -- If we have more old ones than we need, delete them. local newBars = {} local currentBarCount = table.getn(self._bars) for i = 1, currentBarCount, 1 do   if (i <= currentBarCount) then table.insert(newBars, self._bars[i]) else self._bars[i].Destroy end end for i = currentBarCount + 1, newBarCount, 1 do    table.insert(newBars, self:_makeNthBar(i)) end self._bars = newBars end

function BarGraphClass:Render local numValues = table.getn(self._values) self:_updateBarCount(numValues) for i, value in ipairs(self._values) do   self:_updateBar(i, value, numValues) end

if self._showExtras then self:_moveGraphAverage end end

function BarGraphClass:_addGraphTarget -- Add the line used to mark target value. local line = Instance.new("ImageLabel") line.Name = "TargetLine" line.Size = UDim2.new(1, 0, 0, StatsUtils.GraphTargetLineInnerThickness)

line.Image = 'rbxasset://textures/ui/PerformanceStats/TargetLine.png' line.BackgroundTransparency = 1 line.Parent = self._lineFrame line.ZIndex = self._lineFrame.ZIndex line.BorderSizePixel = 0

line.Changed:connect(function     self:_updateTargetLineImageSize    end)

self._targetLine = line self:_updateTargetLineImageSize end

function BarGraphClass:_updateTargetLineImageSize self._targetLine.ImageRectSize = self._targetLine.AbsoluteSize end

function BarGraphClass:_addGraphAverage -- Add the line used to mark average of current values. local line = Instance.new("Frame") line.Name = "AverageLine" line.Size = UDim2.new(1, 0, 0, StatsUtils.GraphAverageLineInnerThickness)

line.Parent = self._lineFrame line.ZIndex = self._lineFrame.ZIndex

StatsUtils.StyleAverageLine(line)

self._averageLine = line end

function BarGraphClass:_moveGraphTarget -- Update position of graph target line, if present. if self._targetLine == nil then return end self._targetLine.Position = UDim2.new(0,    0, ( self._axisMax - self._target)/self._axisMax,   -StatsUtils.GraphTargetLineInnerThickness/2) end

function BarGraphClass:_moveGraphAverage -- Update position of graph average line, if present. if self._averageLine == nil then return end

-- Never let it go above axis max. local adjustedAverage = math.min(self._average, self._axisMax)

self._averageLine.Position = UDim2.new(0,    0,     (self._axisMax - adjustedAverage)/self._axisMax,    -StatsUtils.GraphAverageLineTotalThickness/2) end

function BarGraphClass:_makeNthBar(index) -- Make the nth bar in the bar graph. local realIndex = index-1 local bar = Instance.new("Frame") bar.Name = string.format("Bar_%d", realIndex) bar.Parent = self._barFrame bar.ZIndex = self._barFrame.ZIndex bar.BorderSizePixel = 0 return bar end

function BarGraphClass:_updateBar(i, value, numValues) -- Update nth bar in graph: size, position, and color. local bar = self._bars[i] local realIndex = i-1

-- Don't let it go off the chart. local clampedValue = math.max(0, math.min(value, self._axisMax))

bar.Position = UDim2.new(realIndex/numValues, 0,   (self._axisMax - clampedValue)/self._axisMax, 0) bar.Size = UDim2.new(1/numValues, 0,    clampedValue/self._axisMax, 0)

bar.BackgroundColor3 = StatsUtils.GetColorForValue(value, self._target) end

return BarGraphClass