--[[ Name: LibGraph-2.0 Revision: $Rev: 45 $ 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: 45 $"):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") end end 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 tinsert, tremove = tinsert, tremove local pairs, ipairs = pairs, ipairs 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 GetTime = GetTime -- 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) 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)--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.blp") 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.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) 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) 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) 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.blp") 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 Widthself.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) 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 tinsert(self.Data,{Points=data;Color=color}) 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 k,v 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 k,v 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 local k,v --Are we on the Pie Chart? if Dist12)) 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)) 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 i,j 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 i0 then local RecalcBars=self.BarNum-ShiftBars+1 for i=1,self.BarNum do if i0 and not (self.LastDataTime<(self.LastShift+self.XMin-self.TimeRadius)) then for i=1,self.BarNum do if i0.01 then self.YMax=MaxY self.NeedsUpdate=true end end self:SetBars() end if self.NeedsUpdate then self.NeedsUpdate=false self:RefreshGraph() end end --Line Graph function GraphFunctions:RefreshLineGraph() local k1, k2, series 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 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() 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) self:DrawLine(self,LastPoint.x,LastPoint.y,TPoint.x,TPoint.y,32,series.Color) 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() local k1, k2, series, point 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.blp") 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 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) 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") T:SetTexture(TextureDirectory.."line") 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:SetTexture(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=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 Reattime 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