--[[
Name : LibGraph - 2.0
Revision : $ Rev : 56 $
Author ( s ) : Cryect ( cryect @ gmail.com ) , Xinhuan
Website : http : // www.wowace . com /
Documentation : http : // www.wowace . com / wiki / GraphLib
SVN : http : // svn.wowace . com / root / trunk / GraphLib /
Description : Allows for easy creation of graphs
] ]
--Thanks to Nelson Minar for catching several errors where width was being used instead of height (damn copy and paste >_>)
local major = " LibGraph-2.0 "
local minor = 90000 + tonumber ( ( " $Revision: 58 $ " ) : match ( " (%d+) " ) )
--Search for just Addon\\ at the front since the interface part often gets trimmed
--Do this before anything else, so if it errors, any existing loaded copy of LibGraph-2.0
--doesn't get modified with a newer revision (this one)
local TextureDirectory
do
local path = string.match ( debugstack ( 1 , 1 , 0 ) , " AddOns \\ (.+)LibGraph%-2%.0%.lua " )
if path then
TextureDirectory = " Interface \\ AddOns \\ " .. path
else
--error(major.." cannot determine the folder it is located in because the path is too long and got truncated in the debugstack(1, 1, 0) function call")
--beta doing some errors here
if ( Details ) then
TextureDirectory = [[Interface\AddOns\Details\Libs\LibGraph-2.0]]
end
end
end
TextureDirectory = " Interface \\ Addons \\ Details \\ Libs \\ LibGraph-2.0 "
if not LibStub then error ( major .. " requires LibStub " ) end
local lib , oldLibMinor = LibStub : NewLibrary ( major , minor )
if not lib then return end
local GraphFunctions = { }
local gsub = gsub
local ipairs = ipairs
local pairs = pairs
local sqrt = sqrt
local table = table
local tinsert = tinsert
local tremove = tremove
local type = type
local math_max = math.max
local math_min = math.min
local math_ceil = math.ceil
local math_pi = math.pi
local math_floor = math.floor
local math_pow = math.pow
local math_random = math.random
local math_cos = math.cos
local math_sin = math.sin
local math_deg = math.deg
local math_atan = math.atan
local math_abs = math.abs
local math_fmod = math.fmod
local math_huge = math.huge
local CreateFrame = CreateFrame
local GetCursorPosition = GetCursorPosition
local GetTime = GetTime
local MouseIsOver = MouseIsOver
local UnitHealth = UnitHealth
local UIParent = UIParent
local DEFAULT_CHAT_FRAME = DEFAULT_CHAT_FRAME
-- lib upgrade stuff
lib.RegisteredGraphRealtime = lib.RegisteredGraphRealtime or { }
lib.RegisteredGraphLine = lib.RegisteredGraphLine or { }
lib.RegisteredGraphScatterPlot = lib.RegisteredGraphScatterPlot or { }
lib.RegisteredGraphPieChart = lib.RegisteredGraphPieChart or { }
--------------------------------------------------------------------------------
--Graph Creation Functions
--------------------------------------------------------------------------------
--Realtime Graph
local function SetupGraphRealtimeFunctions ( graph , upgrade )
local self = lib
--Set the various functions
graph.SetXAxis = GraphFunctions.SetXAxis
graph.SetYMax = GraphFunctions.SetYMax
graph.AddTimeData = GraphFunctions.AddTimeData
graph.OnUpdate = GraphFunctions.OnUpdateGraphRealtime
graph.CreateGridlines = GraphFunctions.CreateGridlines
graph.RefreshGraph = GraphFunctions.RefreshRealtimeGraph
graph.SetAxisDrawing = GraphFunctions.SetAxisDrawing
graph.SetGridSpacing = GraphFunctions.SetGridSpacing
graph.SetAxisColor = GraphFunctions.SetAxisColor
graph.SetGridColor = GraphFunctions.SetGridColor
graph.SetGridColorSecondary = GraphFunctions.SetGridColorSecondary
graph.SetGridSecondaryMultiple = GraphFunctions.SetGridSecondaryMultiple
graph.SetFilterRadius = GraphFunctions.SetFilterRadius
--graph.SetAutoscaleYAxis = GraphFunctions.SetAutoscaleYAxis
graph.SetBarColors = GraphFunctions.SetBarColors
graph.SetMode = GraphFunctions.SetMode
graph.SetAutoScale = GraphFunctions.SetAutoScale
if not upgrade then
-- This is the original frame:SetWidth() and frame:SetHeight()
-- standard frame functions
graph.OldSetWidth = graph.SetWidth
graph.OldSetHeight = graph.SetHeight
end
graph.SetWidth = GraphFunctions.RealtimeSetWidth
graph.SetHeight = GraphFunctions.RealtimeSetHeight
graph.SetBarColors = GraphFunctions.RealtimeSetColors
graph.GetMaxValue = GraphFunctions.GetMaxValue
graph.GetValue = GraphFunctions.RealtimeGetValue
graph.SetUpdateLimit = GraphFunctions.SetUpdateLimit
graph.SetDecay = GraphFunctions.SetDecay
graph.SetMinMaxY = GraphFunctions.SetMinMaxY
graph.AddBar = GraphFunctions.AddBar
graph.SetYLabels = GraphFunctions.SetYLabels
graph.DrawLine = self.DrawLine
graph.DrawHLine = self.DrawHLine
graph.DrawVLine = self.DrawVLine
graph.HideLines = self.HideLines
graph.HideFontStrings = GraphFunctions.HideFontStrings
graph.FindFontString = GraphFunctions.FindFontString
graph.SetBars = GraphFunctions.SetBars
--Set the update function
graph : SetScript ( " OnUpdate " , graph.OnUpdate )
end
function lib : CreateGraphRealtime ( name , parent , relative , relativeTo , offsetX , offsetY , Width , Height )
local graph
local i
graph = CreateFrame ( " Frame " , name , parent , BackdropTemplateMixin and " BackdropTemplate " )
Width = math_floor ( Width )
graph : SetPoint ( relative , parent , relativeTo , offsetX , offsetY )
graph : SetWidth ( Width )
graph : SetHeight ( Height )
graph : Show ( )
--Create the bars
graph.Bars = { }
graph.BarsUsing = { }
graph.BarNum = Width
graph.Height = Height
for i = 1 , Width do
local bar
bar = CreateFrame ( " StatusBar " , name .. " Bar " .. i , graph , BackdropTemplateMixin and " BackdropTemplate " ) --graph:CreateTexture(nil, "ARTWORK")
bar : SetPoint ( " BOTTOMLEFT " , graph , " BOTTOMLEFT " , i - 1 , 0 )
bar : SetHeight ( Height )
bar : SetWidth ( 1 )
bar : SetOrientation ( " VERTICAL " )
bar : SetMinMaxValues ( 0 , 1 )
bar : SetStatusBarTexture ( " Interface \\ Buttons \\ WHITE8X8 " )
bar : GetStatusBarTexture ( ) : SetHorizTile ( false )
bar : GetStatusBarTexture ( ) : SetVertTile ( false )
local t = bar : GetStatusBarTexture ( )
t : SetGradientAlpha ( " VERTICAL " , 0.2 , 0.0 , 0.0 , 0.5 , 1.0 , 0.0 , 0.0 , 1.0 )
bar : Show ( )
tinsert ( graph.Bars , bar )
tinsert ( graph.BarsUsing , bar )
end
SetupGraphRealtimeFunctions ( graph )
--Initialize Data
graph.GraphType = " REALTIME "
graph.YMax = 60
graph.YMin = 0
graph.XMax = - 0.75
graph.XMin = - 10
graph.TimeRadius = 0.5
graph.Mode = " FAST "
graph.Filter = " RECT "
graph.AxisColor = { 1.0 , 1.0 , 1.0 , 1.0 }
graph.GridColor = { 0.5 , 0.5 , 0.5 , 0.5 }
graph.BarColorTop = { 1.0 , 0.0 , 0.0 , 1.0 }
graph.BarColorBot = { 0.2 , 0.0 , 0.0 , 0.5 }
graph.AutoScale = false
graph.Data = { }
graph.MinMaxY = 0
graph.CurVal = 0
graph.LastDataTime = GetTime ( )
graph.Textures = { }
graph.TexturesUsed = { }
graph.LimitUpdates = 0
graph.NextUpdate = 0
graph.BarHeight = { }
graph.LastShift = GetTime ( )
graph.BarWidth = ( graph.XMax - graph.XMin ) / graph.BarNum
graph.DecaySet = 0.8
graph.Decay = math_pow ( graph.DecaySet , graph.BarWidth )
graph.ExpNorm = 1 / ( 1 - graph.Decay )
graph.FilterOverlap = math_max ( math_ceil ( ( graph.TimeRadius + graph.XMax ) / graph.BarWidth ) , 0 )
for i = 1 , graph.BarNum do
graph.BarHeight [ i ] = 0
end
graph.TextFrame = CreateFrame ( " Frame " , nil , graph )
graph.TextFrame : SetAllPoints ( graph )
graph.TextFrame : SetFrameLevel ( graph : GetFrameLevel ( ) + 2 )
tinsert ( self.RegisteredGraphRealtime , graph )
return graph
end
--Line Graph
local function SetupGraphLineFunctions ( graph )
local self = lib
--Set the various functions
graph.SetXAxis = GraphFunctions.SetXAxis
graph.SetYAxis = GraphFunctions.SetYAxis
graph.AddDataSeries = GraphFunctions.AddDataSeries
graph.AddFilledDataSeries = GraphFunctions.AddFilledDataSeries
graph.ResetData = GraphFunctions.ResetData
graph.RefreshGraph = GraphFunctions.RefreshLineGraph
graph.CreateGridlines = GraphFunctions.CreateGridlines
graph.SetAxisDrawing = GraphFunctions.SetAxisDrawing
graph.SetGridSpacing = GraphFunctions.SetGridSpacing
graph.SetAxisColor = GraphFunctions.SetAxisColor
graph.SetGridColor = GraphFunctions.SetGridColor
graph.SetGridColorSecondary = GraphFunctions.SetGridColorSecondary
graph.SetGridSecondaryMultiple = GraphFunctions.SetGridSecondaryMultiple
graph.SetAutoScale = GraphFunctions.SetAutoScale
graph.SetYLabels = GraphFunctions.SetYLabels
graph.OnUpdate = GraphFunctions.OnUpdateGraph
graph.SetLineTexture = GraphFunctions.SetLineTexture
graph.SetBorderSize = GraphFunctions.SetBorderSize
graph.LockXMin = GraphFunctions.LockXMin
graph.LockXMax = GraphFunctions.LockXMax
graph.LockYMin = GraphFunctions.LockYMin
graph.LockYMax = GraphFunctions.LockYMax
graph.DrawLine = self.DrawLine
graph.DrawHLine = self.DrawHLine
graph.DrawVLine = self.DrawVLine
graph.HideLines = self.HideLines
graph.DrawBar = self.DrawBar
graph.HideBars = self.HideBars
graph.HideFontStrings = GraphFunctions.HideFontStrings
graph.FindFontString = GraphFunctions.FindFontString
--Set the update function
graph : SetScript ( " OnUpdate " , graph.OnUpdate )
end
--TODO: Clip lines with the bounds
function lib : CreateGraphLine ( name , parent , relative , relativeTo , offsetX , offsetY , Width , Height )
local graph
local i
graph = CreateFrame ( " Frame " , name , parent , BackdropTemplateMixin and " BackdropTemplate " )
graph : SetPoint ( relative , parent , relativeTo , offsetX , offsetY )
graph : SetWidth ( Width )
graph : SetHeight ( Height )
graph : Show ( )
SetupGraphLineFunctions ( graph )
graph.NeedsUpdate = false
--Initialize Data
graph.GraphType = " LINE "
graph.YMax = 1
graph.YMin = - 1
graph.XMax = 1
graph.XMin = - 1
graph.AxisColor = { 1.0 , 1.0 , 1.0 , 1.0 }
graph.GridColor = { 0.5 , 0.5 , 0.5 , 0.5 }
graph.XGridInterval = 0.25
graph.YGridInterval = 0.25
graph.XAxisDrawn = true
graph.YAxisDrawn = true
graph.LockOnXMin = false
graph.LockOnXMax = false
graph.LockOnYMin = false
graph.LockOnYMax = false
graph.Data = { }
graph.FilledData = { }
graph.Textures = { }
graph.TexturesUsed = { }
graph.TextFrame = CreateFrame ( " Frame " , nil , graph )
graph.TextFrame : SetAllPoints ( graph )
tinsert ( self.RegisteredGraphLine , graph )
return graph
end
--Scatter Plot
local function SetupGraphScatterPlotFunctions ( graph )
local self = lib
--Set the various functions
graph.SetXAxis = GraphFunctions.SetXAxis
graph.SetYAxis = GraphFunctions.SetYAxis
graph.AddDataSeries = GraphFunctions.AddDataSeries
graph.ResetData = GraphFunctions.ResetData
graph.RefreshGraph = GraphFunctions.RefreshScatterPlot
graph.CreateGridlines = GraphFunctions.CreateGridlines
graph.OnUpdate = GraphFunctions.OnUpdateGraph
graph.LinearRegression = GraphFunctions.LinearRegression
graph.SetAxisDrawing = GraphFunctions.SetAxisDrawing
graph.SetGridSpacing = GraphFunctions.SetGridSpacing
graph.SetAxisColor = GraphFunctions.SetAxisColor
graph.SetGridColor = GraphFunctions.SetGridColor
graph.SetGridColorSecondary = GraphFunctions.SetGridColorSecondary
graph.SetGridSecondaryMultiple = GraphFunctions.SetGridSecondaryMultiple
graph.SetLinearFit = GraphFunctions.SetLinearFit
graph.SetAutoScale = GraphFunctions.SetAutoScale
graph.SetYLabels = GraphFunctions.SetYLabels
graph.LockXMin = GraphFunctions.LockXMin
graph.LockXMax = GraphFunctions.LockXMax
graph.LockYMin = GraphFunctions.LockYMin
graph.LockYMax = GraphFunctions.LockYMax
graph.DrawLine = self.DrawLine
graph.DrawHLine = self.DrawHLine
graph.DrawVLine = self.DrawVLine
graph.HideLines = self.HideLines
graph.HideTextures = GraphFunctions.HideTextures
graph.FindTexture = GraphFunctions.FindTexture
graph.HideFontStrings = GraphFunctions.HideFontStrings
graph.FindFontString = GraphFunctions.FindFontString
--Set the update function
graph : SetScript ( " OnUpdate " , graph.OnUpdate )
end
function lib : CreateGraphScatterPlot ( name , parent , relative , relativeTo , offsetX , offsetY , Width , Height )
local graph
local i
graph = CreateFrame ( " Frame " , name , parent , BackdropTemplateMixin and " BackdropTemplate " )
graph : SetPoint ( relative , parent , relativeTo , offsetX , offsetY )
graph : SetWidth ( Width )
graph : SetHeight ( Height )
graph : Show ( )
SetupGraphScatterPlotFunctions ( graph )
graph.NeedsUpdate = false
--Initialize Data
graph.GraphType = " SCATTER "
graph.YMax = 1
graph.YMin = - 1
graph.XMax = 1
graph.XMin = - 1
graph.AxisColor = { 1.0 , 1.0 , 1.0 , 1.0 }
graph.GridColor = { 0.5 , 0.5 , 0.5 , 0.5 }
graph.XGridInterval = 0.25
graph.YGridInterval = 0.25
graph.XAxisDrawn = true
graph.YAxisDrawn = true
graph.AutoScale = false
graph.LinearFit = false
graph.LockOnXMin = false
graph.LockOnXMax = false
graph.LockOnYMin = false
graph.LockOnYMax = false
graph.Data = { }
graph.Textures = { }
graph.TexturesUsed = { }
graph.TextFrame = CreateFrame ( " Frame " , nil , graph )
graph.TextFrame : SetAllPoints ( graph )
tinsert ( self.RegisteredGraphScatterPlot , graph )
return graph
end
--Pie Chart
local function SetupGraphPieChartFunctions ( graph )
local self = lib
--Set the various functions
graph.AddPie = GraphFunctions.AddPie
graph.CompletePie = GraphFunctions.CompletePie
graph.ResetPie = GraphFunctions.ResetPie
graph.DrawLine = self.DrawLine
graph.DrawHLine = self.DrawHLine
graph.DrawVLine = self.DrawVLine
graph.DrawLinePie = GraphFunctions.DrawLinePie
graph.HideLines = self.HideLines
graph.HideTextures = GraphFunctions.HideTextures
graph.FindTexture = GraphFunctions.FindTexture
graph.OnUpdate = GraphFunctions.PieChart_OnUpdate
graph.SetSelectionFunc = GraphFunctions.SetSelectionFunc
graph : SetScript ( " OnUpdate " , graph.OnUpdate )
end
function lib : CreateGraphPieChart ( name , parent , relative , relativeTo , offsetX , offsetY , Width , Height )
local graph
local i
graph = CreateFrame ( " Frame " , name , parent , BackdropTemplateMixin and " BackdropTemplate " )
graph : SetPoint ( relative , parent , relativeTo , offsetX , offsetY )
graph : SetWidth ( Width )
graph : SetHeight ( Height )
graph : Show ( )
SetupGraphPieChartFunctions ( graph )
--Initialize Data
graph.GraphType = " PIE "
graph.PieUsed = 0
graph.PercentOn = 0
graph.Remaining = 0
graph.Textures = { }
graph.Ratio = Width / Height
graph.Radius = 0.88 * ( Width / 2 )
graph.Radius = graph.Radius * graph.Radius
graph.Sections = { }
graph.Textures = { }
graph.TexturesUsed = { }
graph.LastSection = nil
graph.onColor = 1
graph.TotalSections = 0
tinsert ( self.RegisteredGraphPieChart , graph )
return graph
end
-------------------------------------------------------------------------------
--Functions for Realtime Graphs
-------------------------------------------------------------------------------
--AddTimeData - Adds a data value to the realtime graph at this moment in time
function GraphFunctions : AddTimeData ( value )
if type ( value ) ~= " number " then
return
end
local t = { }
t.Time = GetTime ( )
self.LastDataTime = t.Time
t.Value = value
tinsert ( self.Data , t )
end
--RefreshRealtimeGraph - Refreshes the gridlines for the realtime graph
function GraphFunctions : RefreshRealtimeGraph ( )
self : HideLines ( self )
self : CreateGridlines ( )
end
--SetFilterRadius - controls the radius of the filter
function GraphFunctions : SetFilterRadius ( radius )
self.TimeRadius = radius
end
--SetAutoscaleYAxis - If enabled the maximum y axis is adjusted to be 25% more than the max value
function GraphFunctions : SetAutoscaleYAxis ( scale )
self.AutoScale = scale
end
--SetBarColors -
function GraphFunctions : SetBarColors ( BotColor , TopColor )
local Temp
if BotColor.r then
Temp = BotColor
BotColor = { Temp.r , Temp.g , Temp.b , Temp.a }
end
if TopColor.r then
Temp = TopColor
TopColor = { Temp.r , Temp.g , Temp.b , Temp.a }
end
for i = 1 , self.BarNum do
local t = self.Bars [ i ] : GetStatusBarTexture ( )
t : SetGradientAlpha ( " VERTICAL " , BotColor [ 1 ] , BotColor [ 2 ] , BotColor [ 3 ] , BotColor [ 4 ] , TopColor [ 1 ] , TopColor [ 2 ] , TopColor [ 3 ] , TopColor [ 4 ] )
end
end
function GraphFunctions : SetMode ( mode )
self.Mode = mode
if mode ~= " SLOW " then
self.LastShift = GetTime ( ) + self.XMin
end
end
function GraphFunctions : RealtimeSetColors ( BotColor , TopColor )
local Temp
if BotColor.r then
Temp = BotColor
BotColor = { Temp.r , Temp.g , Temp.b , Temp.a }
end
if TopColor.r then
Temp = TopColor
TopColor = { Temp.r , Temp.g , Temp.b , Temp.a }
end
self.BarColorBot = BotColor
self.BarColorTop = TopColor
for _ , v in pairs ( self.Bars ) do
v : GetStatusBarTexture ( ) : SetGradientAlpha ( " VERTICAL " , self.BarColorBot [ 1 ] , self.BarColorBot [ 2 ] , self.BarColorBot [ 3 ] , self.BarColorBot [ 4 ] , self.BarColorTop [ 1 ] , self.BarColorTop [ 2 ] , self.BarColorTop [ 3 ] , self.BarColorTop [ 4 ] )
end
end
function GraphFunctions : RealtimeSetWidth ( Width )
Width = math_floor ( Width )
if Width == self.BarNum then
return
end
self.BarNum = Width
for i = 1 , Width do
if type ( self.Bars [ i ] ) == " nil " then
local bar
bar = CreateFrame ( " StatusBar " , self : GetName ( ) .. " Bar " .. i , self )
bar : SetPoint ( " BOTTOMLEFT " , self , " BOTTOMLEFT " , i - 1 , 0 )
bar : SetHeight ( self.Height )
bar : SetWidth ( 1 )
bar : SetOrientation ( " VERTICAL " )
bar : SetMinMaxValues ( 0 , 1 )
bar : SetStatusBarTexture ( " Interface \\ Buttons \\ WHITE8X8 " )
bar : GetStatusBarTexture ( ) : SetHorizTile ( false )
bar : GetStatusBarTexture ( ) : SetVertTile ( false )
local t = bar : GetStatusBarTexture ( )
t : SetGradientAlpha ( " VERTICAL " , self.BarColorBot [ 1 ] , self.BarColorBot [ 2 ] , self.BarColorBot [ 3 ] , self.BarColorBot [ 4 ] , self.BarColorTop [ 1 ] , self.BarColorTop [ 2 ] , self.BarColorTop [ 3 ] , self.BarColorTop [ 4 ] )
tinsert ( self.Bars , bar )
else
self.Bars [ i ] : SetPoint ( " BOTTOMLEFT " , self , " BOTTOMLEFT " , i - 1 , 0 )
end
self.BarHeight [ i ] = 0
end
local SizeOfBarsUsed = table.maxn ( self.BarsUsing )
if Width > SizeOfBarsUsed then
for i = SizeOfBarsUsed + 1 , Width do
tinsert ( self.BarsUsing , self.Bars [ i ] )
self.Bars [ i ] : Show ( )
end
elseif Width < SizeOfBarsUsed then
for i = Width + 1 , SizeOfBarsUsed do
tremove ( self.BarsUsing , Width + 1 )
self.Bars [ i ] : Hide ( )
end
end
self.BarWidth = ( self.XMax - self.XMin ) / self.BarNum
self.Decay = math_pow ( self.DecaySet , self.BarWidth )
self.ExpNorm = 1 / ( 1 - self.Decay ) / 0.95 --Actually a finite geometric series
self : OldSetWidth ( Width )
self : RefreshGraph ( )
end
function GraphFunctions : RealtimeSetHeight ( Height )
self.Height = Height
for i = 1 , self.BarNum do
--self.Bars[i]:Hide()
self.Bars [ i ] : SetValue ( 0 )
self.Bars [ i ] : SetHeight ( self.Height )
end
self : OldSetHeight ( Height )
self : RefreshGraph ( )
end
function GraphFunctions : GetMaxValue ( )
--Is there any data that could possibly be not zero?
if self.LastDataTime < ( self.LastShift + self.XMin - self.TimeRadius ) then
return 0
end
local MaxY = 0
for i = 1 , self.BarNum do
MaxY = math_max ( MaxY , self.BarHeight [ i ] )
end
return MaxY
end
function GraphFunctions : RealtimeGetValue ( Time )
local Bar
if Time < self.XMin or Time > self.XMax then
return 0
end
Bar = math_min ( math_max ( math_floor ( self.BarNum * ( Time - self.XMin ) / ( self.XMax - self.XMin ) + 0.5 ) , 1 ) , self.BarNum )
return self.BarHeight [ Bar ]
end
function GraphFunctions : SetUpdateLimit ( Time )
self.LimitUpdates = Time
end
function GraphFunctions : SetDecay ( decay )
self.DecaySet = decay
self.Decay = math_pow ( self.DecaySet , self.BarWidth )
self.ExpNorm = 1 / ( 1 - self.Decay ) / 0.95 --Actually a finite geometric series (divide 0.96 instead of 1 since seems doesn't quite work right)
end
function GraphFunctions : AddBar ( value )
for i = 1 , self.BarNum - 1 do
self.BarHeight [ i ] = self.BarHeight [ i + 1 ]
end
self.BarHeight [ self.BarNum ] = value
self.AddedBar = true
end
function GraphFunctions : SetBars ( )
local YHeight = self.YMax - self.YMin
for i , bar in pairs ( self.BarsUsing ) do
local h
h = ( self.BarHeight [ i ] - self.YMin ) / YHeight
bar : SetValue ( h )
end
end
-------------------------------------------------------------------------------
--Functions for Line Graph Data
-------------------------------------------------------------------------------
function GraphFunctions : AddDataSeries ( points , color , n2 , linetexture )
local data
--Make sure there is data points
if not points then
return
end
data = points
if n2 == nil then
n2 = false
end
if n2 or ( table.getn ( points ) == 2 and table.getn ( points [ 1 ] ) ~= 2 ) then
data = { }
for k , v in ipairs ( points [ 1 ] ) do
tinsert ( data , { v , points [ 2 ] [ k ] } )
end
end
if linetexture then
if not linetexture : find ( " \\ " ) and not linetexture : find ( " // " ) then
linetexture = TextureDirectory .. linetexture
end
end
tinsert ( self.Data , { Points = data ; Color = color ; LineTexture = linetexture } )
self.NeedsUpdate = true
end
function GraphFunctions : AddFilledDataSeries ( points , color , n2 )
local data
--Make sure there is data points
if not points or # points == 0 then
return
end
data = points
if n2 == nil then
n2 = false
end
if n2 or ( table.getn ( points ) == 2 and table.getn ( points [ 1 ] ) ~= 2 ) then
data = { }
for k , v in ipairs ( points [ 1 ] ) do
tinsert ( data , { v , points [ 2 ] [ k ] } )
end
end
tinsert ( self.FilledData , { Points = data ; Color = color } )
self.NeedsUpdate = true
end
function GraphFunctions : ResetData ( )
self.Data = { }
if self.FilledData then
self.FilledData = { }
end
self.NeedsUpdate = true
end
function GraphFunctions : SetLinearFit ( fit )
self.LinearFit = fit
self.NeedsUpdate = true
end
function GraphFunctions : HideTextures ( )
local k = # self.TexturesUsed
while k > 0 do
self.Textures [ # self.Textures + 1 ] = self.TexturesUsed [ k ]
self.TexturesUsed [ k ] : Hide ( )
self.TexturesUsed [ k ] = nil
k = k - 1
end
end
--Make sure to show a texture after you grab it or its free for anyone else to grab
function GraphFunctions : FindTexture ( )
local t
if # self.Textures > 0 then
t = self.Textures [ # self.Textures ]
self.TexturesUsed [ # self.TexturesUsed + 1 ] = t
self.Textures [ # self.Textures ] = nil
return t
end
local g = self : CreateTexture ( nil , " BACKGROUND " )
self.TexturesUsed [ # self.TexturesUsed + 1 ] = g
return g
end
function GraphFunctions : HideFontStrings ( )
if not self.FontStrings then
self.FontStrings = { }
end
for k , t in pairs ( self.FontStrings ) do
t : Hide ( )
end
end
--Make sure to show a fontstring after you grab it or its free for anyone else to grab
function GraphFunctions : FindFontString ( )
for k , t in pairs ( self.FontStrings ) do
if not t : IsShown ( ) then
return t
end
end
local g
if self.TextFrame then
g = self.TextFrame : CreateFontString ( nil , " OVERLAY " )
else
g = self : CreateFontString ( nil , " OVERLAY " )
end
tinsert ( self.FontStrings , g )
return g
end
--Linear Regression via Least Squares
function GraphFunctions : LinearRegression ( data )
local alpha , beta
local n , SX , SY , SXX , SXY = 0 , 0 , 0 , 0 , 0
for k , v in pairs ( data ) do
n = n + 1
SX = SX + v [ 1 ]
SXX = SXX + v [ 1 ] * v [ 1 ]
SY = SY + v [ 2 ]
SXY = SXY + v [ 1 ] * v [ 2 ]
end
beta = ( n * SXY - SX * SY ) / ( n * SXX - SX * SX )
alpha = ( SY - beta * SX ) / n
return alpha , beta
end
-------------------------------------------------------------------------------
--Functions for Pie Chart
-------------------------------------------------------------------------------
local PiePieces = {
" 1-2 " ,
" 1-4 " ,
" 1-8 " ,
" 1-16 " ,
" 1-32 " ,
" 1-64 " ,
" 1-128 "
}
--26 Colors
local ColorTable = {
{ 0.9 , 0.1 , 0.1 } ,
{ 0.1 , 0.9 , 0.1 } ,
{ 0.1 , 0.1 , 0.9 } ,
{ 0.9 , 0.9 , 0.1 } ,
{ 0.9 , 0.1 , 0.9 } ,
{ 0.1 , 0.9 , 0.9 } ,
{ 0.9 , 0.9 , 0.9 } ,
{ 0.5 , 0.1 , 0.1 } ,
{ 0.1 , 0.5 , 0.1 } ,
{ 0.1 , 0.1 , 0.5 } ,
{ 0.5 , 0.5 , 0.1 } ,
{ 0.5 , 0.1 , 0.5 } ,
{ 0.1 , 0.5 , 0.5 } ,
{ 0.5 , 0.5 , 0.5 } ,
{ 0.75 , 0.15 , 0.15 } ,
{ 0.15 , 0.75 , 0.15 } ,
{ 0.15 , 0.15 , 0.75 } ,
{ 0.75 , 0.75 , 0.15 } ,
{ 0.75 , 0.15 , 0.75 } ,
{ 0.15 , 0.75 , 0.75 } ,
{ 0.9 , 0.5 , 0.1 } ,
{ 0.1 , 0.5 , 0.9 } ,
{ 0.9 , 0.1 , 0.5 } ,
{ 0.5 , 0.9 , 0.1 } ,
{ 0.5 , 0.1 , 0.9 } ,
{ 0.1 , 0.9 , 0.5 } ,
}
function GraphFunctions : AddPie ( Percent , Color )
local PiePercent = self.PercentOn
local CurPiece = 50
local Angle = 180
local CurAngle = PiePercent * 360 / 100
self.TotalSections = self.TotalSections + 1
if type ( self.Sections [ self.TotalSections ] ) ~= " table " then
self.Sections [ self.TotalSections ] = { }
end
local Section = self.Sections [ self.TotalSections ]
Section.Textures = { }
if type ( Color ) ~= " table " then
if self.onColor <= table.maxn ( ColorTable ) then
Color = ColorTable [ self.onColor ]
else
Color = { math_random ( ) , math_random ( ) , math_random ( ) }
end
self.onColor = self.onColor + 1
end
if PiePercent == 0 then
self : DrawLinePie ( 0 )
end
Percent = Percent + self.Remaining
local LastPiece = 0
for k , v in pairs ( PiePieces ) do
if ( Percent + 0.1 ) > CurPiece then
local t = self : FindTexture ( )
t : SetTexture ( TextureDirectory .. v )
t : ClearAllPoints ( )
t : SetPoint ( " CENTER " , self , " CENTER " , 0 , 0 )
t : SetHeight ( self : GetHeight ( ) )
t : SetWidth ( self : GetWidth ( ) )
GraphFunctions : RotateTexture ( t , CurAngle )
t : Show ( )
t : SetVertexColor ( Color [ 1 ] , Color [ 2 ] , Color [ 3 ] , 1.0 )
Percent = Percent - CurPiece
PiePercent = PiePercent + CurPiece
CurAngle = CurAngle + Angle
tinsert ( Section.Textures , t )
if k == 7 then
LastPiece = 0.09
end
end
CurPiece = CurPiece / 2
Angle = Angle / 2
end
--Finish adding section data
Section.Color = Color
Section.Angle = CurAngle
self : DrawLinePie ( ( PiePercent + LastPiece ) * 360 / 100 )
self.PercentOn = PiePercent
self.Remaining = Percent
return Color
end
function GraphFunctions : CompletePie ( Color )
local Percent = 100 - self.PercentOn
local PiePercent = self.PercentOn
local CurPiece = 50
local Angle = 180
local CurAngle = PiePercent * 360 / 100
self.TotalSections = self.TotalSections + 1
if not self.Sections [ self.TotalSections ] then
self.Sections [ self.TotalSections ] = { }
end
local Section = self.Sections [ self.TotalSections ]
Section.Textures = { }
if type ( Color ) ~= " table " then
if self.onColor <= table.maxn ( ColorTable ) then
Color = ColorTable [ self.onColor ]
else
Color = { math_random ( ) , math_random ( ) , math_random ( ) }
end
self.onColor = self.onColor + 1
end
Percent = Percent + self.Remaining
if PiePercent ~= 0 then
for k , v in pairs ( PiePieces ) do
if ( Percent + 0.1 ) > CurPiece then
local t = self : FindTexture ( )
t : SetTexture ( TextureDirectory .. v )
t : ClearAllPoints ( )
t : SetPoint ( " CENTER " , self , " CENTER " , 0 , 0 )
t : SetHeight ( self : GetHeight ( ) )
t : SetWidth ( self : GetWidth ( ) )
GraphFunctions : RotateTexture ( t , CurAngle )
t : Show ( )
t : SetVertexColor ( Color [ 1 ] , Color [ 2 ] , Color [ 3 ] , 1.0 )
Percent = Percent - CurPiece
PiePercent = PiePercent + CurPiece
CurAngle = CurAngle + Angle
tinsert ( Section.Textures , t )
end
CurPiece = CurPiece / 2
Angle = Angle / 2
end
else --Special case if its by itself
local t = self : FindTexture ( )
t : SetTexture ( TextureDirectory .. " 1-1 " )
t : ClearAllPoints ( )
t : SetPoint ( " CENTER " , self , " CENTER " , 0 , 0 )
t : SetHeight ( self : GetHeight ( ) )
t : SetWidth ( self : GetWidth ( ) )
GraphFunctions : RotateTexture ( t , CurAngle )
t : Show ( )
t : SetVertexColor ( Color [ 1 ] , Color [ 2 ] , Color [ 3 ] , 1.0 )
tinsert ( Section.Textures , t )
end
--Finish adding section data
Section.Color = Color
Section.Angle = 360
self.PercentOn = PiePercent
self.Remaining = Percent
return Color
end
function GraphFunctions : ResetPie ( )
self : HideTextures ( )
self : HideLines ( self )
self.PieUsed = 0
self.PercentOn = 0
self.Remaining = 0
self.onColor = 1
self.LastSection = nil
self.TotalSections = 0
--self.Sections = {}
end
function GraphFunctions : DrawLinePie ( angle )
local sx , sy , ex , ey
local Radian = math_pi * ( 90 - angle ) / 180
local w , h
w = self : GetWidth ( ) / 2
h = self : GetHeight ( ) / 2
sx = w
sy = h
ex = sx + 0.88 * w * math_cos ( Radian )
ey = sx + 0.88 * h * math_sin ( Radian )
self : DrawLine ( self , sx , sy , ex , ey , 34 , { 0.0 , 0.0 , 0.0 , 1.0 } , " OVERLAY " )
end
--Used to rotate the pie slices
function GraphFunctions : RotateTexture ( texture , angle )
local Radian = math_pi * ( 45 - angle ) / 180
local Radian2 = math_pi * ( 45 + 90 - angle ) / 180
local Radius = 0.70710678118654752440084436210485
local tx , ty , tx2 , ty2
tx = Radius * math_cos ( Radian )
ty = Radius * math_sin ( Radian )
tx2 = - ty
ty2 = tx
texture : SetTexCoord ( 0.5 - tx , 0.5 - ty , 0.5 + tx2 , 0.5 + ty2 , 0.5 - tx2 , 0.5 - ty2 , 0.5 + tx , 0.5 + ty )
end
function GraphFunctions : SetSelectionFunc ( f )
self.SelectionFunc = f
end
--TODO: Pie chart pieces need to be clickable
function GraphFunctions : PieChart_OnUpdate ( )
if ( MouseIsOver ( self ) ) then
local sX , sY = self : GetCenter ( )
local Scale = self : GetEffectiveScale ( )
local mX , mY = GetCursorPosition ( )
local dX , dY
dX = mX / Scale - sX
dY = mY / Scale - sY
local Angle = 90 - math_deg ( math_atan ( dY / dX ) )
dY = dY * self.Ratio
local Dist = dX * dX + dY * dY
if dX < 0 then
Angle = Angle + 180
end
--Are we on the Pie Chart?
if Dist < self.Radius then
--What section are we on?
for k = 1 , self.TotalSections do
local v = self.Sections [ k ]
if Angle < v.Angle then
local Color
if k ~= self.LastSection then
if self.LastSection then
local Section = self.Sections [ self.LastSection ]
for _ , t in pairs ( Section.Textures ) do
Color = Section.Color
t : SetVertexColor ( Color [ 1 ] , Color [ 2 ] , Color [ 3 ] , 1.0 )
end
end
if self.SelectionFunc then
self : SelectionFunc ( k )
end
end
local ColorAdd = 0.15 * math_abs ( math_fmod ( GetTime ( ) , 3 ) - 1.5 ) - 0.1125
Color = { }
Color [ 1 ] = v.Color [ 1 ] + ColorAdd
Color [ 2 ] = v.Color [ 2 ] + ColorAdd
Color [ 3 ] = v.Color [ 3 ] + ColorAdd
for _ , t in pairs ( v.Textures ) do
t : SetVertexColor ( Color [ 1 ] , Color [ 2 ] , Color [ 3 ] , 1.0 )
end
self.LastSection = k
return
end
end
elseif self.LastSection then
local Section = self.Sections [ self.LastSection ]
for _ , t in pairs ( Section.Textures ) do
local Color = Section.Color
t : SetVertexColor ( Color [ 1 ] , Color [ 2 ] , Color [ 3 ] , 1.0 )
end
self.LastSection = nil
if self.SelectionFunc then
self : SelectionFunc ( nil )
end
end
else
if self.LastSection then
local Section = self.Sections [ self.LastSection ]
for _ , t in pairs ( Section.Textures ) do
local Color = Section.Color
t : SetVertexColor ( Color [ 1 ] , Color [ 2 ] , Color [ 3 ] , 1.0 )
end
self.LastSection = nil
if self.SelectionFunc then
self : SelectionFunc ( nil )
end
end
end
end
-------------------------------------------------------------------------------
--Axis Setting Functions
-------------------------------------------------------------------------------
function GraphFunctions : SetYMax ( ymax )
if ymax == self.YMax then
return
end
self.YMax = ymax
self.NeedsUpdate = true
end
function GraphFunctions : SetYAxis ( ymin , ymax )
if self.YMin == ymin and self.YMax == ymax then
return
end
self.YMin = ymin
self.YMax = ymax
self.NeedsUpdate = true
end
function GraphFunctions : SetMinMaxY ( val )
if self.MinMaxY == val then
return
end
self.MinMaxY = val
self.NeedsUpdate = true
end
function GraphFunctions : SetXAxis ( xmin , xmax )
if self.XMin == xmin and self.XMax == xmax then
return
end
self.XMin = xmin
self.XMax = xmax
self.NeedsUpdate = true
if self.GraphType == " REALTIME " then
self.BarWidth = ( xmax - xmin ) / self.BarNum
self.Decay = math_pow ( self.DecaySet , self.BarWidth )
self.FilterOverlap = math_max ( math_ceil ( ( self.TimeRadius + xmax ) / self.BarWidth ) , 0 )
self.LastShift = GetTime ( ) + xmin
end
end
function GraphFunctions : SetAutoScale ( auto )
self.AutoScale = auto
self.NeedsUpdate = true
end
--The various Lock Functions let you use Autoscale but holds the locked points in place
function GraphFunctions : LockXMin ( state )
if state == nil then
self.LockOnXMin = not self.LockOnXMin
return
end
self.LockOnXMin = state
end
function GraphFunctions : LockXMax ( state )
if state == nil then
self.LockOnXMax = not self.LockOnXMax
return
end
self.LockOnXMax = state
end
function GraphFunctions : LockYMin ( state )
if state == nil then
self.LockOnYMin = not self.LockOnYMin
return
end
self.LockOnYMin = state
end
function GraphFunctions : LockYMax ( state )
if state == nil then
self.LockOnYMax = not self.LockOnYMax
return
end
self.LockOnYMax = state
end
-------------------------------------------------------------------------------
--Grid & Axis Drawing Functions
-------------------------------------------------------------------------------
function GraphFunctions : SetAxisDrawing ( xaxis , yaxis )
if xaxis == self.XAxisDrawn and self.YAxisDrawn == yaxis then
return
end
self.XAxisDrawn = xaxis
self.YAxisDrawn = yaxis
self.NeedsUpdate = true
end
function GraphFunctions : SetGridSpacing ( xspacing , yspacing )
if xspacing == self.XGridInterval and self.YGridInterval == yspacing then
return
end
self.XGridInterval = xspacing
self.YGridInterval = yspacing
self.NeedsUpdate = true
end
function GraphFunctions : SetAxisColor ( color )
if self.AxisColor [ 1 ] == color [ 1 ] and self.AxisColor [ 2 ] == color [ 2 ] and self.AxisColor [ 3 ] == color [ 3 ] and self.AxisColor [ 4 ] == color [ 4 ] then
return
end
self.AxisColor = color
self.NeedsUpdate = true
end
function GraphFunctions : SetGridColor ( color )
if self.GridColor [ 1 ] == color [ 1 ] and self.GridColor [ 2 ] == color [ 2 ] and self.GridColor [ 3 ] == color [ 3 ] and self.GridColor [ 4 ] == color [ 4 ] then
return
end
self.GridColor = color
self.NeedsUpdate = true
end
function GraphFunctions : SetGridColorSecondary ( color )
if self.GridColorSecondary ~= nil and self.GridColorSecondary [ 1 ] == color [ 1 ] and self.GridColorSecondary [ 2 ] == color [ 2 ] and self.GridColorSecondary [ 3 ] == color [ 3 ] and self.GridColorSecondary [ 4 ] == color [ 4 ] then
return
end
self.GridColorSecondary = color
self.NeedsUpdate = true
end
function GraphFunctions : SetGridSecondaryMultiple ( XAxis , YAxis )
if type ( XAxis ) ~= " number " then
XAxis = 1
end
if type ( YAxis ) ~= " number " then
YAxis = 1
end
self.GridSecondaryX = XAxis
self.GridSecondaryY = YAxis
self.NeedsUpdate = true
end
function GraphFunctions : SetYLabels ( Left , Right )
self.YLabelsLeft = Left
self.YLabelsRight = Right
end
function GraphFunctions : SetLineTexture ( texture )
if ( type ( texture ) ~= " string " ) then
return assert ( false , " Parameter 1 for SetLineTexture must be a string " )
end
--full path
if ( texture : find ( " \\ " ) or texture : find ( " // " ) ) then
self.CustomLine = texture
--using an image inside lib-graph folder
else
self.CustomLine = TextureDirectory .. texture
end
end
function GraphFunctions : SetBorderSize ( border , size )
border = string.lower ( border )
if ( type ( size ) ~= " number " ) then
return assert ( false , " Parameter 2 for SetBorderSize must be a number " )
end
if ( border == " left " ) then
self.CustomLeftBorder = size
return true
elseif ( border == " right " ) then
self.CustomRightBorder = size
return true
elseif ( border == " top " ) then
self.CustomTopBorder = size
return true
elseif ( border == " bottom " ) then
self.CustomBottomBorder = size
return true
end
return assert ( false , " Usage: GraphObject:SetBorderSize (LEFT RIGHT TOP BOTTOM, SIZE) " )
end
function GraphFunctions : CreateGridlines ( )
local Width = self : GetWidth ( )
local Height = self : GetHeight ( )
local NoSecondary = ( self.GridSecondaryY == nil ) or ( self.GridSecondaryX == nil ) or ( type ( self.GridColorSecondary ) ~= " table " )
local F
self : HideLines ( self )
self : HideFontStrings ( )
if self.YGridInterval then
local LowerYGridLine , UpperYGridLine , TopSpace
LowerYGridLine = self.YMin / self.YGridInterval
LowerYGridLine = math_max ( math_floor ( LowerYGridLine ) , math_ceil ( LowerYGridLine ) )
UpperYGridLine = self.YMax / self.YGridInterval
UpperYGridLine = math_min ( math_floor ( UpperYGridLine ) , math_ceil ( UpperYGridLine ) )
--UpperYGridLine = math_min(UpperYGridLine, self.YGridMax or 16)
TopSpace = Height * ( 1 - ( UpperYGridLine * self.YGridInterval - self.YMin ) / ( self.YMax - self.YMin ) )
for i = LowerYGridLine , UpperYGridLine do
if i ~= 0 or not self.YAxisDrawn then
local YPos , T
YPos = Height * ( i * self.YGridInterval - self.YMin ) / ( self.YMax - self.YMin )
if NoSecondary or math_fmod ( i , self.GridSecondaryY ) == 0 then
T = self : DrawLine ( self , 0 , YPos , Width , YPos , 24 , self.GridColor , " BACKGROUND " )
else
T = self : DrawLine ( self , 0 , YPos , Width , YPos , 24 , self.GridColorSecondary , " BACKGROUND " )
end
if ( ( i ~= UpperYGridLine ) or ( TopSpace > 12 ) ) and ( NoSecondary or math_fmod ( i , self.GridSecondaryY ) == 0 ) then
if self.YLabelsLeft then
F = self : FindFontString ( )
F : SetFontObject ( " GameFontHighlightSmall " )
F : SetTextColor ( 1 , 1 , 1 )
F : ClearAllPoints ( )
F : SetPoint ( " BOTTOMLEFT " , T , " LEFT " , 2 , 2 )
F : SetText ( i * self.YGridInterval )
F : Show ( )
end
if self.YLabelsRight then
F = self : FindFontString ( )
F : SetFontObject ( " GameFontHighlightSmall " )
F : SetTextColor ( 1 , 1 , 1 )
F : ClearAllPoints ( )
F : SetPoint ( " BOTTOMRIGHT " , T , " RIGHT " , - 2 , 2 )
F : SetText ( i * self.YGridInterval )
F : Show ( )
end
end
end
end
end
if self.XGridInterval then
local LowerXGridLine , UpperXGridLine
LowerXGridLine = self.XMin / self.XGridInterval
LowerXGridLine = math_max ( math_floor ( LowerXGridLine ) , math_ceil ( LowerXGridLine ) )
UpperXGridLine = self.XMax / self.XGridInterval
UpperXGridLine = math_min ( math_floor ( UpperXGridLine ) , math_ceil ( UpperXGridLine ) )
--UpperXGridLine = math_min(UpperXGridLine, self.XGridMax or 16)
for i = LowerXGridLine , UpperXGridLine do
if i ~= 0 or not self.XAxisDrawn then
local XPos
XPos = Width * ( i * self.XGridInterval - self.XMin ) / ( self.XMax - self.XMin )
if NoSecondary or math_fmod ( i , self.GridSecondaryX ) == 0 then
self : DrawLine ( self , XPos , 0 , XPos , Height , 24 , self.GridColor , " BACKGROUND " )
else
self : DrawLine ( self , XPos , 0 , XPos , Height , 24 , self.GridColorSecondary , " BACKGROUND " )
end
end
end
end
if self.YAxisDrawn and self.YMax >= 0 and self.YMin <= 0 then
local YPos , T
YPos = Height * ( - self.YMin ) / ( self.YMax - self.YMin )
T = self : DrawLine ( self , 0 , YPos , Width , YPos , 24 , self.AxisColor , " BACKGROUND " )
if self.YLabelsLeft then
F = self : FindFontString ( )
F : SetFontObject ( " GameFontHighlightSmall " )
F : SetTextColor ( 1 , 1 , 1 )
F : ClearAllPoints ( )
F : SetPoint ( " BOTTOMLEFT " , T , " LEFT " , 2 , 2 )
F : SetText ( 0 )
F : Show ( )
end
if self.YLabelsRight then
F = self : FindFontString ( )
F : SetFontObject ( " GameFontHighlightSmall " )
F : SetTextColor ( 1 , 1 , 1 )
F : ClearAllPoints ( )
F : SetPoint ( " BOTTOMRIGHT " , T , " RIGHT " , - 2 , 2 )
F : SetText ( 0 )
F : Show ( )
end
end
if self.XAxisDrawn and self.XMax >= 0 and self.XMin <= 0 then
local XPos
XPos = Width * ( - self.XMin ) / ( self.XMax - self.XMin )
self : DrawLine ( self , XPos , 0 , XPos , Height , 24 , self.AxisColor , " BACKGROUND " )
end
end
--------------------------------------------------------------------------------
--Refresh functions
--------------------------------------------------------------------------------
function GraphFunctions : OnUpdateGraph ( )
if self.NeedsUpdate and self.RefreshGraph then
self : RefreshGraph ( )
self.NeedsUpdate = false
end
end
--Performs a convolution in realtime allowing to graph Framerate, DPS, or any other data you want graphed in realtime
function GraphFunctions : OnUpdateGraphRealtime ( )
local CurTime = GetTime ( )
local BarsChanged
if self.NextUpdate > CurTime or ( self.Mode == " RAW " and not ( self.NeedsUpdate or self.AddedBar ) ) then
return
end
self.NextUpdate = CurTime + self.LimitUpdates
--Slow Mode performs an entire convolution every frame
if self.Mode == " SLOW " then
--Initialize Bar Data
self.BarHeight = { }
for i = 1 , self.BarNum do
self.BarHeight [ i ] = 0
end
local k , v
local BarTimeRadius = ( self.XMax - self.XMin ) / self.BarNum
local DataValue = 1 / ( 2 * self.TimeRadius )
if self.Filter == " RECT " then
--Take the convolution of the dataset on to the bars wtih a rectangular filter
local DataValue = 1 / ( 2 * self.TimeRadius )
for k , v in pairs ( self.Data ) do
if v.Time < ( CurTime + self.XMin - self.TimeRadius ) then
tremove ( self.Data , k )
else
local DataTime = v.Time - CurTime
local LowestBar = math_max ( math_floor ( ( DataTime - self.XMin - self.TimeRadius ) / BarTimeRadius ) , 1 )
local HighestBar = math_min ( math_ceil ( ( DataTime - self.XMin + self.TimeRadius ) / BarTimeRadius ) , self.BarNum )
for i = LowestBar , HighestBar do
self.BarHeight [ i ] = self.BarHeight [ i ] + v.Value * DataValue
end
end
end
elseif self.Filter == " TRI " then
--Needs optimization badly
--Take the convolution of the dataset on to the bars wtih a triangular filter
local DataValue = 1 / ( self.TimeRadius )
for k , v in pairs ( self.Data ) do
local Temp
if v.Time < ( CurTime + self.XMin - self.TimeRadius ) then
tremove ( self.Data , k )
else
local DataTime = v.Time - CurTime
local LowestBar = math_max ( math_floor ( ( DataTime - self.XMin - self.TimeRadius ) / BarTimeRadius ) , 1 )
local HighestBar = math_min ( math_ceil ( ( DataTime - self.XMin + self.TimeRadius ) / BarTimeRadius ) , self.BarNum )
for i = LowestBar , HighestBar do
self.BarHeight [ i ] = self.BarHeight [ i ] + v.Value * DataValue * math_abs ( BarTimeRadius * i + self.XMin - DataTime )
end
end
end
end
BarsChanged = true
elseif self.Mode == " FAST " then
local ShiftBars = math_floor ( ( CurTime - self.LastShift ) / self.BarWidth )
if ShiftBars > 0 and not ( self.LastDataTime < ( self.LastShift + self.XMin - self.TimeRadius * 2 ) ) then
local RecalcBars = self.BarNum - ( ShiftBars + self.FilterOverlap ) + 1
for i = 1 , self.BarNum do
if i < RecalcBars then
self.BarHeight [ i ] = self.BarHeight [ i + ShiftBars ]
else
self.BarHeight [ i ] = 0
end
end
local BarTimeRadius = ( self.XMax - self.XMin ) / self.BarNum
local DataValue = 1 / ( 2 * self.TimeRadius )
local TimeDiff = CurTime - self.LastShift
CurTime = self.LastShift + ShiftBars * self.BarWidth
self.LastShift = CurTime
if self.Filter == " RECT " then
--Take the convolution of the dataset on to the bars wtih a rectangular filter
local DataValue = 1 / ( 2 * self.TimeRadius )
for k , v in pairs ( self.Data ) do
if v.Time < ( CurTime + self.XMax - self.TimeRadius - TimeDiff ) then
tremove ( self.Data , k )
else
local DataTime = v.Time - CurTime
local LowestBar = math_max ( math_max ( math_floor ( ( DataTime - self.XMin - self.TimeRadius ) / BarTimeRadius ) , RecalcBars ) , 1 )
local HighestBar = math_min ( math_ceil ( ( DataTime - self.XMin + self.TimeRadius ) / BarTimeRadius ) , self.BarNum )
if LowestBar <= HighestBar then
for i = LowestBar , HighestBar do
self.BarHeight [ i ] = self.BarHeight [ i ] + v.Value * DataValue
end
end
end
end
end
BarsChanged = true
else
CurTime = self.LastShift + ShiftBars * self.BarWidth
self.LastShift = CurTime
end
elseif self.Mode == " EXP " then
local ShiftBars = math_floor ( ( CurTime - self.LastShift ) / self.BarWidth )
if ShiftBars > 0 then
local RecalcBars = self.BarNum - ShiftBars + 1
for i = 1 , self.BarNum do
if i < RecalcBars then
self.BarHeight [ i ] = self.BarHeight [ i + ShiftBars ]
end
end
--Now to calculate the new bars
local Total
local Weight = 1 / self.TimeRadius / self.ExpNorm
for i = RecalcBars , self.BarNum do
Total = 0
--Implement an EXPFAST which does this only once instead of for each bar
for k , v in pairs ( self.Data ) do
Total = Total + v.Value * Weight
if v.Time < ( self.LastShift - self.TimeRadius ) then
tremove ( self.Data , k )
end
end
self.CurVal = self.Decay * self.CurVal + Total
self.BarHeight [ i ] = self.CurVal
self.LastShift = self.LastShift + self.BarWidth
end
if self.CurVal < 0.1 then
self.CurVal = 0
end
BarsChanged = true
else
self.LastShift = self.LastShift + self.BarWidth * ShiftBars
end
elseif self.Mode == " EXPFAST " then
local ShiftBars = math_floor ( ( CurTime - self.LastShift ) / self.BarWidth )
local RecalcBars = self.BarNum - ShiftBars + 1
if ShiftBars > 0 and not ( self.LastDataTime < ( self.LastShift + self.XMin - self.TimeRadius ) ) then
for i = 1 , self.BarNum do
if i < RecalcBars then
self.BarHeight [ i ] = self.BarHeight [ i + ShiftBars ]
end
end
--Now to calculate the new bars
local Total
local Weight = 1 / self.TimeRadius / self.ExpNorm
Total = 0
--Implement an EXPFAST which does this only once instead of for each bar
for k , v in pairs ( self.Data ) do
Total = Total + v.Value * Weight
if v.Time < ( self.LastShift - self.TimeRadius ) then
tremove ( self.Data , k )
end
end
--self.LastShift = self.LastShift+self.BarWidth*ShiftBars
if self.CurVal ~= 0 or Total ~= 0 then
for i = RecalcBars , self.BarNum do
self.CurVal = self.Decay * self.CurVal + Total
self.BarHeight [ i ] = self.CurVal
end
self.LastDataTime = self.LastShift + self.BarWidth * ShiftBars
else
for i = RecalcBars , self.BarNum do
self.BarHeight [ i ] = 0
end
end
if self.CurVal < 0.1 then
self.CurVal = 0
end
BarsChanged = true
end
self.LastShift = self.LastShift + self.BarWidth * ShiftBars
elseif self.Mode == " RAW " then
--Do nothing really
--Using .AddedBar so we cut down on updating the grid
self.AddedBar = false
BarsChanged = true
end
if BarsChanged then
if self.AutoScale then
local MaxY = 0
for i = 1 , self.BarNum do
MaxY = math_max ( MaxY , self.BarHeight [ i ] )
end
MaxY = 1.25 * MaxY
MaxY = math_max ( MaxY , self.MinMaxY )
if MaxY ~= 0 and math_abs ( self.YMax - MaxY ) > 0.01 then
self.YMax = MaxY
self.NeedsUpdate = true
local Spacing
if self.YMax < 25 then
Spacing = - 1
else
Spacing = math.log ( self.YMax / 100 ) / math.log ( 2 )
end
self.YGridInterval = 25 * math.pow ( 2 , math.floor ( Spacing ) )
end
end
self : SetBars ( )
end
if self.NeedsUpdate then
self.NeedsUpdate = false
self : RefreshGraph ( )
end
end
--Line Graph
function GraphFunctions : RefreshLineGraph ( )
self : HideLines ( self )
self : HideBars ( self )
if self.AutoScale and self.Data then
local MinX , MaxX , MinY , MaxY = math_huge , - math_huge , math_huge , - math_huge
--Go through line data first
for k1 , series in pairs ( self.Data ) do
for k2 , point in pairs ( series.Points ) do
MinX = math_min ( point [ 1 ] , MinX )
MaxX = math_max ( point [ 1 ] , MaxX )
MinY = math_min ( point [ 2 ] , MinY )
MaxY = math_max ( point [ 2 ] , MaxY )
end
end
--Now through the Filled Lines
for k1 , series in pairs ( self.FilledData ) do
for k2 , point in pairs ( series.Points ) do
MinX = math_min ( point [ 1 ] , MinX )
MaxX = math_max ( point [ 1 ] , MaxX )
MinY = math_min ( point [ 2 ] , MinY )
MaxY = math_max ( point [ 2 ] , MaxY )
end
end
local XBorder , YBorder
XBorder = 0.1 * ( MaxX - MinX )
YBorder = 0.1 * ( MaxY - MinY )
if not self.LockOnXMin then
if ( self.CustomLeftBorder ) then
self.XMin = MinX + self.CustomLeftBorder --custom size of left border
else
self.XMin = MinX - XBorder
end
end
if not self.LockOnXMax then
if ( self.CustomRightBorder ) then
self.XMax = MaxX + self.CustomRightBorder --custom size of right border
else
self.XMax = MaxX + XBorder
end
end
if not self.LockOnYMin then
if ( self.CustomBottomBorder ) then
self.YMin = MinY + self.CustomBottomBorder --custom size of bottom border
else
self.YMin = MinY - YBorder
end
end
if not self.LockOnYMax then
if ( self.CustomTopBorder ) then
self.YMax = MaxY + self.CustomTopBorder --custom size of top border
else
self.YMax = MaxY + YBorder
end
end
end
self : CreateGridlines ( )
local Width = self : GetWidth ( )
local Height = self : GetHeight ( )
for k1 , series in pairs ( self.Data ) do
local LastPoint
LastPoint = nil
for k2 , point in pairs ( series.Points ) do
if LastPoint then
local TPoint = { x = point [ 1 ] ; y = point [ 2 ] }
TPoint.x = Width * ( TPoint.x - self.XMin ) / ( self.XMax - self.XMin )
TPoint.y = Height * ( TPoint.y - self.YMin ) / ( self.YMax - self.YMin )
--tercioo: send the data index to DrawLine so custom draw functions know what they are drawing
self : DrawLine ( self , LastPoint.x , LastPoint.y , TPoint.x , TPoint.y , 32 , series.Color , nil , series.LineTexture , k1 )
LastPoint = TPoint
else
LastPoint = { x = point [ 1 ] ; y = point [ 2 ] }
LastPoint.x = Width * ( LastPoint.x - self.XMin ) / ( self.XMax - self.XMin )
LastPoint.y = Height * ( LastPoint.y - self.YMin ) / ( self.YMax - self.YMin )
end
end
end
--Filled Line Graphs
for k1 , series in pairs ( self.FilledData ) do
local LastPoint
LastPoint = nil
for k2 , point in pairs ( series.Points ) do
if LastPoint then
local TPoint = { x = point [ 1 ] ; y = point [ 2 ] }
TPoint.x = Width * ( TPoint.x - self.XMin ) / ( self.XMax - self.XMin )
TPoint.y = Height * ( TPoint.y - self.YMin ) / ( self.YMax - self.YMin )
self : DrawBar ( self , LastPoint.x , LastPoint.y , TPoint.x , TPoint.y , series.Color , k1 )
LastPoint = TPoint
else
LastPoint = { x = point [ 1 ] ; y = point [ 2 ] }
LastPoint.x = Width * ( LastPoint.x - self.XMin ) / ( self.XMax - self.XMin )
LastPoint.y = Height * ( LastPoint.y - self.YMin ) / ( self.YMax - self.YMin )
end
end
end
end
--Scatter Plot Refresh
function GraphFunctions : RefreshScatterPlot ( )
self : HideLines ( self )
if self.AutoScale and self.Data then
local MinX , MaxX , MinY , MaxY = math_huge , - math_huge , math_huge , - math_huge
for k1 , series in pairs ( self.Data ) do
for k2 , point in pairs ( series.Points ) do
MinX = math_min ( point [ 1 ] , MinX )
MaxX = math_max ( point [ 1 ] , MaxX )
MinY = math_min ( point [ 2 ] , MinY )
MaxY = math_max ( point [ 2 ] , MaxY )
end
end
local XBorder , YBorder
XBorder = 0.1 * ( MaxX - MinX )
YBorder = 0.1 * ( MaxY - MinY )
if not self.LockOnXMin then
self.XMin = MinX - XBorder
end
if not self.LockOnXMax then
self.XMax = MaxX + XBorder
end
if not self.LockOnYMin then
self.YMin = MinY - YBorder
end
if not self.LockOnYMax then
self.YMax = MaxY + YBorder
end
end
self : CreateGridlines ( )
local Width = self : GetWidth ( )
local Height = self : GetHeight ( )
self : HideTextures ( )
for k1 , series in pairs ( self.Data ) do
local MinX , MaxX = self.XMax , self.XMin
for k2 , point in pairs ( series.Points ) do
local x , y
MinX = math_min ( point [ 1 ] , MinX )
MaxX = math_max ( point [ 1 ] , MaxX )
x = Width * ( point [ 1 ] - self.XMin ) / ( self.XMax - self.XMin )
y = Height * ( point [ 2 ] - self.YMin ) / ( self.YMax - self.YMin )
local g = self : FindTexture ( )
g : SetTexture ( " Spells \\ GENERICGLOW2_64 " )
g : SetWidth ( 6 )
g : SetHeight ( 6 )
g : ClearAllPoints ( )
g : SetPoint ( " CENTER " , self , " BOTTOMLEFT " , x , y )
g : SetVertexColor ( series.Color [ 1 ] , series.Color [ 2 ] , series.Color [ 3 ] , series.Color [ 4 ] )
g : Show ( )
end
if self.LinearFit then
local alpha , beta = self : LinearRegression ( series.Points )
local sx , sy , ex , ey
sx = MinX
sy = beta * sx + alpha
ex = MaxX
ey = beta * ex + alpha
sx = Width * ( sx - self.XMin ) / ( self.XMax - self.XMin )
sy = Height * ( sy - self.YMin ) / ( self.YMax - self.YMin )
ex = Width * ( ex - self.XMin ) / ( self.XMax - self.XMin )
ey = Height * ( ey - self.YMin ) / ( self.YMax - self.YMin )
self : DrawLine ( self , sx , sy , ex , ey , 32 , series.Color )
end
end
end
--Copied from Blizzard's TaxiFrame code and modifed for IMBA then remodified for GraphLib
-- The following function is used with permission from Daniel Stephens <iriel@vigilance-committee.org>
local TAXIROUTE_LINEFACTOR = 128 / 126 -- Multiplying factor for texture coordinates
local TAXIROUTE_LINEFACTOR_2 = TAXIROUTE_LINEFACTOR / 2 -- Half of that
-- T - Texture
-- C - Canvas Frame (for anchoring)
-- sx, sy - Coordinate of start of line
-- ex, ey - Coordinate of end of line
-- w - Width of line
-- relPoint - Relative point on canvas to interpret coords (Default BOTTOMLEFT)
function lib : DrawLine ( C , sx , sy , ex , ey , w , color , layer , linetexture )
local relPoint = " BOTTOMLEFT "
if sx == ex then
if sy == ey then
return
else
return self : DrawVLine ( C , sx , sy , ey , w , color , layer )
end
elseif sy == ey then
return self : DrawHLine ( C , sx , ex , sy , w , color , layer )
end
if not C.GraphLib_Lines then
C.GraphLib_Lines = { }
C.GraphLib_Lines_Used = { }
end
local T = tremove ( C.GraphLib_Lines ) or C : CreateTexture ( nil , " ARTWORK " )
if linetexture then --this data series texture
T : SetTexture ( linetexture )
elseif C.CustomLine then --overall chart texture
T : SetTexture ( C.CustomLine )
else --no texture assigned, use default
T : SetTexture ( TextureDirectory .. " line " )
end
tinsert ( C.GraphLib_Lines_Used , T )
T : SetDrawLayer ( layer or " ARTWORK " )
T : SetVertexColor ( color [ 1 ] , color [ 2 ] , color [ 3 ] , color [ 4 ] )
-- Determine dimensions and center point of line
local dx , dy = ex - sx , ey - sy
local cx , cy = ( sx + ex ) / 2 , ( sy + ey ) / 2
-- Normalize direction if necessary
if ( dx < 0 ) then
dx , dy = - dx , - dy
end
-- Calculate actual length of line
local l = sqrt ( ( dx * dx ) + ( dy * dy ) )
-- Sin and Cosine of rotation, and combination (for later)
local s , c = - dy / l , dx / l
local sc = s * c
-- Calculate bounding box size and texture coordinates
local Bwid , Bhgt , BLx , BLy , TLx , TLy , TRx , TRy , BRx , BRy
if ( dy >= 0 ) then
Bwid = ( ( l * c ) - ( w * s ) ) * TAXIROUTE_LINEFACTOR_2
Bhgt = ( ( w * c ) - ( l * s ) ) * TAXIROUTE_LINEFACTOR_2
BLx , BLy , BRy = ( w / l ) * sc , s * s , ( l / w ) * sc
BRx , TLx , TLy , TRx = 1 - BLy , BLy , 1 - BRy , 1 - BLx
TRy = BRx
else
Bwid = ( ( l * c ) + ( w * s ) ) * TAXIROUTE_LINEFACTOR_2
Bhgt = ( ( w * c ) + ( l * s ) ) * TAXIROUTE_LINEFACTOR_2
BLx , BLy , BRx = s * s , - ( l / w ) * sc , 1 + ( w / l ) * sc
BRy , TLx , TLy , TRy = BLx , 1 - BRx , 1 - BLx , 1 - BLy
TRx = TLy
end
-- Thanks Blizzard for adding (-)10000 as a hard-cap and throwing errors!
-- The cap was added in 3.1.0 and I think it was upped in 3.1.1
-- (way less chance to get the error)
if TLx > 10000 then TLx = 10000 elseif TLx < - 10000 then TLx = - 10000 end
if TLy > 10000 then TLy = 10000 elseif TLy < - 10000 then TLy = - 10000 end
if BLx > 10000 then BLx = 10000 elseif BLx < - 10000 then BLx = - 10000 end
if BLy > 10000 then BLy = 10000 elseif BLy < - 10000 then BLy = - 10000 end
if TRx > 10000 then TRx = 10000 elseif TRx < - 10000 then TRx = - 10000 end
if TRy > 10000 then TRy = 10000 elseif TRy < - 10000 then TRy = - 10000 end
if BRx > 10000 then BRx = 10000 elseif BRx < - 10000 then BRx = - 10000 end
if BRy > 10000 then BRy = 10000 elseif BRy < - 10000 then BRy = - 10000 end
-- Set texture coordinates and anchors
T : ClearAllPoints ( )
T : SetTexCoord ( TLx , TLy , BLx , BLy , TRx , TRy , BRx , BRy )
T : SetPoint ( " BOTTOMLEFT " , C , relPoint , cx - Bwid , cy - Bhgt )
T : SetPoint ( " TOPRIGHT " , C , relPoint , cx + Bwid , cy + Bhgt )
T : Show ( )
return T
end
--Thanks to Celandro
function lib : DrawVLine ( C , x , sy , ey , w , color , layer )
local relPoint = " BOTTOMLEFT "
if not C.GraphLib_Lines then
C.GraphLib_Lines = { }
C.GraphLib_Lines_Used = { }
end
local T = tremove ( C.GraphLib_Lines ) or C : CreateTexture ( nil , " ARTWORK " )
T : SetTexture ( TextureDirectory .. " sline " )
tinsert ( C.GraphLib_Lines_Used , T )
T : SetDrawLayer ( layer or " ARTWORK " )
T : SetVertexColor ( color [ 1 ] , color [ 2 ] , color [ 3 ] , color [ 4 ] )
if sy > ey then
sy , ey = ey , sy
end
-- Set texture coordinates and anchors
T : ClearAllPoints ( )
T : SetTexCoord ( 1 , 0 , 0 , 0 , 1 , 1 , 0 , 1 )
T : SetPoint ( " BOTTOMLEFT " , C , relPoint , x - w / 2 , sy )
T : SetPoint ( " TOPRIGHT " , C , relPoint , x + w / 2 , ey )
T : Show ( )
return T
end
function lib : DrawHLine ( C , sx , ex , y , w , color , layer )
local relPoint = " BOTTOMLEFT "
if not C.GraphLib_Lines then
C.GraphLib_Lines = { }
C.GraphLib_Lines_Used = { }
end
local T = tremove ( C.GraphLib_Lines ) or C : CreateTexture ( nil , " ARTWORK " )
T : SetTexture ( TextureDirectory .. " sline " )
tinsert ( C.GraphLib_Lines_Used , T )
T : SetDrawLayer ( layer or " ARTWORK " )
T : SetVertexColor ( color [ 1 ] , color [ 2 ] , color [ 3 ] , color [ 4 ] )
if sx > ex then
sx , ex = ex , sx
end
-- Set texture coordinates and anchors
T : ClearAllPoints ( )
T : SetTexCoord ( 0 , 0 , 0 , 1 , 1 , 0 , 1 , 1 )
T : SetPoint ( " BOTTOMLEFT " , C , relPoint , sx , y - w / 2 )
T : SetPoint ( " TOPRIGHT " , C , relPoint , ex , y + w / 2 )
T : Show ( )
return T
end
function lib : HideLines ( C )
if C.GraphLib_Lines then
for i = # C.GraphLib_Lines_Used , 1 , - 1 do
C.GraphLib_Lines_Used [ i ] : Hide ( )
tinsert ( C.GraphLib_Lines , tremove ( C.GraphLib_Lines_Used ) )
end
end
end
--Two parts to each bar
function lib : DrawBar ( C , sx , sy , ex , ey , color , level )
local Bar , Tri , barNum , MinY , MaxY
--Want sx <= ex if not then flip them
if sx > ex then
sx , ex = ex , sx
sy , ey = ey , sy
end
if not C.GraphLib_Bars then
C.GraphLib_Bars = { }
C.GraphLib_Tris = { }
C.GraphLib_Bars_Used = { }
C.GraphLib_Tris_Used = { }
C.GraphLib_Frames = { }
end
if ( # C.GraphLib_Bars ) > 0 then
Bar = C.GraphLib_Bars [ # C.GraphLib_Bars ]
tremove ( C.GraphLib_Bars , # C.GraphLib_Bars )
Bar : Show ( )
Tri = C.GraphLib_Tris [ # C.GraphLib_Tris ]
tremove ( C.GraphLib_Tris , # C.GraphLib_Tris )
Tri : Show ( )
end
if not Bar then
Bar = C : CreateTexture ( nil , " ARTWORK " )
Bar : SetColorTexture ( 1 , 1 , 1 , 1 )
Tri = C : CreateTexture ( nil , " ARTWORK " )
Tri : SetTexture ( TextureDirectory .. " triangle " )
end
tinsert ( C.GraphLib_Bars_Used , Bar )
tinsert ( C.GraphLib_Tris_Used , Tri )
if level then
if type ( C.GraphLib_Frames [ level ] ) == " nil " then
local newLevel = C : GetFrameLevel ( ) + level
C.GraphLib_Frames [ level ] = CreateFrame ( " Frame " , nil , C )
C.GraphLib_Frames [ level ] : SetFrameLevel ( newLevel )
C.GraphLib_Frames [ level ] : SetAllPoints ( C )
if C.TextFrame and C.TextFrame : GetFrameLevel ( ) <= newLevel then
C.TextFrame : SetFrameLevel ( newLevel + 1 )
self.NeedsUpdate = true
end
end
Bar : SetParent ( C.GraphLib_Frames [ level ] )
Tri : SetParent ( C.GraphLib_Frames [ level ] )
end
Bar : SetVertexColor ( color [ 1 ] , color [ 2 ] , color [ 3 ] , color [ 4 ] )
Tri : SetVertexColor ( color [ 1 ] , color [ 2 ] , color [ 3 ] , color [ 4 ] )
if sy < ey then
Tri : SetTexCoord ( 0 , 0 , 0 , 1 , 1 , 0 , 1 , 1 )
MinY = sy
MaxY = ey
else
Tri : SetTexCoord ( 1 , 0 , 1 , 1 , 0 , 0 , 0 , 1 )
MinY = ey
MaxY = sy
end
--Has to be at least 1 wide
if MinY <= 1 then
MinY = 1
end
Bar : ClearAllPoints ( )
Bar : SetPoint ( " BOTTOMLEFT " , C , " BOTTOMLEFT " , sx , 0 )
local Width = ex - sx
if Width < 1 then
Width = 1
end
Bar : SetWidth ( Width )
Bar : SetHeight ( MinY )
if ( MaxY - MinY ) >= 1 then
Tri : ClearAllPoints ( )
Tri : SetPoint ( " BOTTOMLEFT " , C , " BOTTOMLEFT " , sx , MinY )
Tri : SetWidth ( Width )
Tri : SetHeight ( MaxY - MinY )
else
Tri : Hide ( )
end
end
function lib : HideBars ( C )
if not C.GraphLib_Bars then
return
end
while ( # C.GraphLib_Bars_Used ) > 0 do
C.GraphLib_Bars [ # C.GraphLib_Bars + 1 ] = C.GraphLib_Bars_Used [ # C.GraphLib_Bars_Used ]
C.GraphLib_Bars [ # C.GraphLib_Bars ] : Hide ( )
C.GraphLib_Bars_Used [ # C.GraphLib_Bars_Used ] = nil
C.GraphLib_Tris [ # C.GraphLib_Tris + 1 ] = C.GraphLib_Tris_Used [ # C.GraphLib_Tris_Used ]
C.GraphLib_Tris [ # C.GraphLib_Tris ] : Hide ( )
C.GraphLib_Tris_Used [ # C.GraphLib_Tris_Used ] = nil
end
end
-- lib upgrade stuff, overwrite the old function references in
-- existing graphs with the ones in this newer library
for _ , graph in ipairs ( lib.RegisteredGraphRealtime ) do
SetupGraphRealtimeFunctions ( graph , true )
end
for _ , graph in ipairs ( lib.RegisteredGraphLine ) do
SetupGraphLineFunctions ( graph )
end
for _ , graph in ipairs ( lib.RegisteredGraphScatterPlot ) do
SetupGraphScatterPlotFunctions ( graph )
end
for _ , graph in ipairs ( lib.RegisteredGraphPieChart ) do
SetupGraphPieChartFunctions ( graph )
end
---------------------------------------------------
--Test Functions, for reference for addon authors to test, use and copy
--To test the library do /script LibStub("LibGraph-2.0"):TestGraph2Lib()
local function TestRealtimeGraph ( )
local Graph = LibStub ( major )
local g = Graph : CreateGraphRealtime ( " TestRealtimeGraph " , UIParent , " CENTER " , " CENTER " , - 90 , 90 , 150 , 150 )
g : SetAutoScale ( true )
g : SetGridSpacing ( 1.0 , 10.0 )
g : SetYMax ( 120 )
g : SetXAxis ( - 11 , - 1 )
g : SetFilterRadius ( 1 )
g : SetBarColors ( { 0.2 , 0.0 , 0.0 , 0.4 } , { 1.0 , 0.0 , 0.0 , 1.0 } )
local f = CreateFrame ( " Frame " )
f : SetScript ( " OnUpdate " , function ( )
g : AddTimeData ( 1 )
end )
f : Show ( )
DEFAULT_CHAT_FRAME : AddMessage ( " Testing Realtime Graph " )
end
local function TestRealtimeGraphRaw ( )
local Graph = LibStub ( major )
local g = Graph : CreateGraphRealtime ( " TestRealtimeGraph " , UIParent , " TOP " , " TOP " , 0 , 0 , 150 , 150 )
g : SetAutoScale ( true )
g : SetGridSpacing ( 1.0 , 10.0 )
g : SetYMax ( 120 )
g : SetXAxis ( - 10 , 0 )
g : SetMode ( " RAW " )
g : SetBarColors ( { 0.2 , 0.0 , 0.0 , 0.4 } , { 1.0 , 0.0 , 0.0 , 1.0 } )
local f = CreateFrame ( " Frame " )
f.frames = 0
f.NextUpdate = GetTime ( )
f : SetScript ( " OnUpdate " , function ( )
if f.NextUpdate > GetTime ( ) then
return
end
g : AddBar ( UnitHealth ( " player " ) )
f.NextUpdate = f.NextUpdate + g.BarWidth
end )
f : Show ( )
DEFAULT_CHAT_FRAME : AddMessage ( " Testing 0 " )
end
local function TestLineGraph ( )
local Graph = LibStub ( major )
local g = Graph : CreateGraphLine ( " TestLineGraph " , UIParent , " CENTER " , " CENTER " , 90 , 90 , 150 , 150 )
g : SetXAxis ( - 1 , 1 )
g : SetYAxis ( - 1 , 1 )
g : SetGridSpacing ( 0.25 , 0.25 )
g : SetGridColor ( { 0.5 , 0.5 , 0.5 , 0.5 } )
g : SetAxisDrawing ( true , true )
g : SetAxisColor ( { 1.0 , 1.0 , 1.0 , 1.0 } )
g : SetAutoScale ( true )
local Data1 = { { 0.05 , 0.05 } , { 0.2 , 0.3 } , { 0.4 , 0.2 } , { 0.9 , 0.6 } }
local Data2 = { { 0.05 , 0.8 } , { 0.3 , 0.1 } , { 0.5 , 0.4 } , { 0.95 , 0.05 } }
g : AddDataSeries ( Data1 , { 1.0 , 0.0 , 0.0 , 0.8 } )
g : AddDataSeries ( Data2 , { 0.0 , 1.0 , 0.0 , 0.8 } )
DEFAULT_CHAT_FRAME : AddMessage ( " Testing Line Graph " )
end
local function TestScatterPlot ( )
local Graph = LibStub ( major )
local g = Graph : CreateGraphScatterPlot ( " TestScatterPlot " , UIParent , " CENTER " , " CENTER " , 90 , - 90 , 150 , 150 )
g : SetXAxis ( - 1 , 1 )
g : SetYAxis ( - 1 , 1 )
g : SetGridSpacing ( 0.25 , 0.25 )
g : SetGridColor ( { 0.5 , 0.5 , 0.5 , 0.5 } )
g : SetAxisDrawing ( true , true )
g : SetAxisColor ( { 1.0 , 1.0 , 1.0 , 1.0 } )
g : SetLinearFit ( true )
g : SetAutoScale ( true )
local Data1 = { { 0.05 , 0.05 } , { 0.2 , 0.3 } , { 0.4 , 0.2 } , { 0.9 , 0.6 } }
local Data2 = { { 0.05 , 0.8 } , { 0.3 , 0.1 } , { 0.5 , 0.4 } , { 0.95 , 0.05 } }
g : AddDataSeries ( Data1 , { 1.0 , 0.0 , 0.0 , 0.8 } )
g : AddDataSeries ( Data2 , { 0.0 , 1.0 , 0.0 , 0.8 } )
DEFAULT_CHAT_FRAME : AddMessage ( " Testing Scatter Plot " )
end
local function TestPieChart ( )
local Graph = LibStub ( major )
local g = Graph : CreateGraphPieChart ( " TestPieChart " , UIParent , " CENTER " , " CENTER " , - 90 , - 90 , 150 , 150 )
g : AddPie ( 35 , { 1.0 , 0.0 , 0.0 } )
g : AddPie ( 21 , { 0.0 , 1.0 , 0.0 } )
g : AddPie ( 10 , { 1.0 , 1.0 , 1.0 } )
g : CompletePie ( { 0.2 , 0.2 , 1.0 } )
DEFAULT_CHAT_FRAME : AddMessage ( " Testing Pie Chart " )
end
function lib : TestGraph2Lib ( )
DEFAULT_CHAT_FRAME : AddMessage ( " Testing " .. major .. " , " .. gsub ( minor , " %$ " , " " ) )
TestRealtimeGraph ( )
TestLineGraph ( )
TestScatterPlot ( )
TestPieChart ( )
end